void parseContent(const char *content)
{
    DFArray *parts = CSSParseContent(content);
    printf("parts.count = %zu\n",DFArrayCount(parts));
    for (size_t i = 0; i < DFArrayCount(parts); i++) {
        ContentPart *part = DFArrayItemAt(parts,i);
        char *quotedValue = DFQuote(part->value);
        printf("%s %s\n",ContentPartTypeString(part->type),quotedValue);
        free(quotedValue);
    }
    DFArrayRelease(parts);
}
Example #2
0
static void Word_addContentParts(DFNode *child, const char *content, WordCaption *caption)
{
    if (content == NULL)
        return;
    DFNode *nextSibling = child->first;
    DFArray *parts = CSSParseContent(content);
    for (int i = 0; i < DFArrayCount(parts); i++) {
        ContentPart *part = DFArrayItemAt(parts,i);
        switch (part->type) {
            case ContentPartString: {
                DFNode *text = DFCreateTextNode(child->doc,part->value);
                if (strlen(part->value) > 0) {
                    DFNode *span = DFCreateElement(child->doc,HTML_SPAN);
                    DFAppendChild(span,text);
                    DFInsertBefore(child,span,nextSibling);
                }
                break;
            }
            case ContentPartCounter: {
                if (DFStringEquals(part->value,"figure")) {
                    DFNode *span = DFCreateElement(child->doc,HTML_SPAN);
                    DFSetAttribute(span,HTML_CLASS,DFFieldClass);
                    DFCreateChildTextNode(span," SEQ Figure \\* ARABIC ");
                    DFInsertBefore(child,span,nextSibling);
                    caption->number = span;
                }
                else if (DFStringEquals(part->value,"table")) {
                    DFNode *span = DFCreateElement(child->doc,HTML_SPAN);
                    DFSetAttribute(span,HTML_CLASS,DFFieldClass);
                    DFCreateChildTextNode(span," SEQ Table \\* ARABIC ");
                    DFInsertBefore(child,span,nextSibling);
                    caption->number = span;
                }
                break;
            default:
                break;
            }
        }
    }
    DFArrayRelease(parts);
}
Example #3
0
void CSSSheetUpdateFromCSSText(CSSSheet *sheet, const char *cssText)
{
    DFHashTable *rules = DFHashTableNew((DFCopyFunction)DFHashTableRetain,(DFFreeFunction)DFHashTableRelease);

    CSSParser *parser = CSSParserNew(cssText);
    DFHashTable *top = CSSParserRules(parser);
    CSSParserFree(parser);

    const char **allSelectorsText = DFHashTableCopyKeys(top);
    for (int i = 0; allSelectorsText[i]; i++) {
        const char *selectorsText = allSelectorsText[i];
        const char *propertiesText = DFHashTableLookup(top,selectorsText);

        parser = CSSParserNew(selectorsText);
        DFArray *selectors = CSSParserSelectors(parser);
        CSSParserFree(parser);
        if (selectors == NULL)
            continue;

        parser = CSSParserNew(propertiesText);
        DFHashTable *properties = CSSParserProperties(parser);
        CSSParserFree(parser);
        if (properties == NULL) {
            DFArrayRelease(selectors);
            continue;
        }

        for (size_t selIndex = 0; selIndex < DFArrayCount(selectors); selIndex++) {
            const char *selector = DFArrayItemAt(selectors,selIndex);
            DFHashTableAdd(rules,selector,properties);
        }

        DFHashTableRelease(properties);
        DFArrayRelease(selectors);
    }

    updateFromRawCSSRules(sheet,rules);
    free(allSelectorsText);
    DFHashTableRelease(top);
    DFHashTableRelease(rules);
}
Example #4
0
int CSSSheetHeadingNumbering(CSSSheet *sheet)
{
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int i = 0; allSelectors[i]; i++) {
        CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[i],0,0);
        if (style->headingLevel == 0)
            continue;
        if (CSSGet(CSSStyleBefore(style),"content") == NULL)
            continue;
        DFArray *contentParts = CSSParseContent(CSSGet(CSSStyleBefore(style),"content"));
        for (size_t partIndex = 0; partIndex < DFArrayCount(contentParts); partIndex++) {
            ContentPart *part = DFArrayItemAt(contentParts,partIndex);
            if (part->type == ContentPartCounter) {
                free(allSelectors);
                DFArrayRelease(contentParts);
                return 1;
            }
        }
        DFArrayRelease(contentParts);
    }
    free(allSelectors);
    return 0;
}
Example #5
0
CaptionParts WordBookmarkGetCaptionParts(WordBookmark *bookmark)
{
    CaptionParts parts;
    parts.beforeNum = 0;
    parts.num = 0;
    parts.afterNum = 0;

    // FIXME: Check if the following line is still relevant with the new bookmarks model
    if (bookmark->element == NULL)
        return parts;

    DFArray *nodes = DFArrayNew(NULL,NULL);
    findAllNodes(bookmark->element,nodes);

    for (size_t i = 0; i < DFArrayCount(nodes); i++) {
        DFNode *node = DFArrayItemAt(nodes,i);
        if (node->tag == WORD_FLDSIMPLE) {
            const char *instr = DFGetAttribute(node,WORD_INSTR);
            if (instr != NULL) {
                const char **args = Word_parseField(instr);
                if ((args[0] != NULL) && !strcmp(args[0],"SEQ"))
                    parts.num = 1;
                free(args);
            }
        }
        else if (node->tag != WORD_BOOKMARK) {
            if (!parts.num)
                parts.beforeNum = 1;
            else
                parts.afterNum = 1;
        }
    }
    DFArrayRelease(nodes);

    return parts;
}
static void WordPutSectPr(DFNode *concrete, CSSSheet *styleSheet, WordSection *section)
{
    // Note: The sectPr element can potentially contain one or more headerReference or
    // footerReference elements at the start, before the elements in WordSectPr_Children.
    // So the straight childrenToArray/replaceChildrenFromArray method used elsewhere doesn't
    // work here - we need to make sure these other elements are maintained

    DFNode *children[PREDEFINED_TAG_COUNT];
    childrenToArray(concrete,children);



    CSSProperties *oldBody = CSSPropertiesNew();
    CSSProperties *oldPage = CSSPropertiesNew();
    WordGetSectPr(concrete,oldBody,oldPage,section);

    CSSProperties *newBody = CSSSheetBodyProperties(styleSheet);
    CSSProperties *newPage = CSSSheetPageProperties(styleSheet);


    // Page size
    if (children[WORD_PGSZ] == NULL)
        children[WORD_PGSZ] = DFCreateElement(concrete->doc,WORD_PGSZ);

    int updatePageSize = 0;
    const char *widthStr = DFGetAttribute(children[WORD_PGSZ],WORD_W);
    const char *heightStr = DFGetAttribute(children[WORD_PGSZ],WORD_H);
    int widthTwips;
    int heightTwips;
    if ((widthStr == NULL) || (atoi(widthStr) <= 0) ||
        (heightStr == NULL) || (atoi(heightStr) <= 0)) {
        // Invalid or missing page size: Set to A4 portrait
        widthTwips = A4_WIDTH_TWIPS;
        heightTwips = A4_HEIGHT_TWIPS;
        updatePageSize = 1;
    }
    else {
        widthTwips = atoi(widthStr);
        heightTwips = atoi(heightStr);
    }

    if (!DFStringEquals(CSSGet(oldPage,"size"),CSSGet(newPage,"size"))) {
        const char *newSize = CSSGet(newPage,"size");
        if (DFStringEqualsCI(newSize,"A4 portrait")) {
            widthTwips = A4_WIDTH_TWIPS;
            heightTwips = A4_HEIGHT_TWIPS;
        }
        else if (DFStringEqualsCI(newSize,"A4 landscape")) {
            widthTwips = A4_HEIGHT_TWIPS;
            heightTwips = A4_WIDTH_TWIPS;
        }
        else if (DFStringEqualsCI(newSize,"letter portrait")) {
            widthTwips = LETTER_WIDTH_TWIPS;
            heightTwips = LETTER_HEIGHT_TWIPS;
        }
        else if (DFStringEqualsCI(newSize,"letter landscape")) {
            widthTwips = LETTER_HEIGHT_TWIPS;
            heightTwips = LETTER_WIDTH_TWIPS;
        }
        else {
            widthTwips = A4_WIDTH_TWIPS;
            heightTwips = A4_HEIGHT_TWIPS;
        }
        updatePageSize = 1;
    }

    if (updatePageSize) {
        DFFormatAttribute(children[WORD_PGSZ],WORD_W,"%d",widthTwips);
        DFFormatAttribute(children[WORD_PGSZ],WORD_H,"%d",heightTwips);

        if (widthTwips > heightTwips)
            DFSetAttribute(children[WORD_PGSZ],WORD_ORIENT,"landscape");
        else
            DFRemoveAttribute(children[WORD_PGSZ],WORD_ORIENT);
    }

    if (children[WORD_PGMAR] == NULL)
        children[WORD_PGMAR] = DFCreateElement(concrete->doc,WORD_PGMAR);

    // Page margins
    if (!DFStringEquals(CSSGet(oldBody,"margin-left"),CSSGet(newBody,"margin-left")) || updatePageSize)
        updateTwipsFromLength(children[WORD_PGMAR],WORD_LEFT,CSSGet(newBody,"margin-left"),widthTwips);

    if (!DFStringEquals(CSSGet(oldBody,"margin-right"),CSSGet(newBody,"margin-right")) || updatePageSize)
        updateTwipsFromLength(children[WORD_PGMAR],WORD_RIGHT,CSSGet(newBody,"margin-right"),widthTwips);

    if (!DFStringEquals(CSSGet(oldBody,"margin-top"),CSSGet(newBody,"margin-top")) || updatePageSize)
        updateTwipsFromLength(children[WORD_PGMAR],WORD_TOP,CSSGet(newBody,"margin-top"),widthTwips);

    if (!DFStringEquals(CSSGet(oldBody,"margin-bottom"),CSSGet(newBody,"margin-bottom")) || updatePageSize)
        updateTwipsFromLength(children[WORD_PGMAR],WORD_BOTTOM,CSSGet(newBody,"margin-bottom"),widthTwips);

    if (children[WORD_PGMAR]->attrsCount == 0)
        children[WORD_PGMAR] = NULL;;

    DFArray *extra = DFArrayNew(NULL,NULL);
    for (DFNode *child = concrete->first; child != NULL; child = child->next) {
        switch (child->tag) {
            case WORD_HEADERREFERENCE:
            case WORD_FOOTERREFERENCE:
                DFArrayAppend(extra,child);
                break;
        }
    }
    replaceChildrenFromArray(concrete,children,WordSectPr_Children);
    for (long i = (long)(DFArrayCount(extra)-1); i >= 0; i--) {
        DFNode *child = DFArrayItemAt(extra,i);
        DFInsertBefore(concrete,child,concrete->first);
    }

    DFArrayRelease(extra);
    CSSPropertiesRelease(oldBody);
    CSSPropertiesRelease(oldPage);
}
Example #7
0
static void collapseRecursive(DFNode *node, DFHashTable *bookmarksById)
{

    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;

        switch (child->tag) {
            case WORD_BOOKMARKSTART:
            case WORD_BOOKMARKEND: {
                DFArray *startElements = DFArrayNew(NULL,NULL);
                DFArray *endElements = DFArrayNew(NULL,NULL);
                DFHashTable *startIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
                DFHashTable *endIds = DFHashTableNew((DFCopyFunction)strdup,(DFFreeFunction)free);
                DFNode *n;
                for (n = child;
                     (n != NULL) && ((n->tag == WORD_BOOKMARKSTART) || (n->tag == WORD_BOOKMARKEND));
                     n = n->next) {

                    if (n->tag == WORD_BOOKMARKSTART) {
                        const char *idValue = DFGetAttribute(n,WORD_ID);
                        if (idValue == NULL)
                            idValue = "";

                        DFHashTableAdd(startIds,idValue,idValue);
                        DFArrayAppend(startElements,n);
                    }
                    else {
                        const char *idValue = DFGetAttribute(n,WORD_ID);
                        if (idValue == NULL)
                            idValue = "";

                        DFHashTableAdd(endIds,idValue,idValue);
                        DFArrayAppend(endElements,n);
                    }
                }
                next = n;

                DFArraySort(startElements,bookmarksById,compareStartElements);

                for (size_t endIndex = 0; endIndex < DFArrayCount(endElements); endIndex++) {
                    DFNode *elem = DFArrayItemAt(endElements,endIndex);
                    const char *endId = DFGetAttribute(elem,WORD_ID);
                    int found = 0;
                    DFNode *ancestor;
                    for (ancestor = elem->parent; (ancestor != NULL) && !found; ancestor = ancestor->parent) {
                        if ((ancestor->tag == WORD_BOOKMARK) && DFStringEquals(DFGetAttribute(ancestor,WORD_ID),endId)) {
                            found = 1;
                            break;
                        }
                    }

                    if (found) {
                        DFNode *before = ancestor->next;
                        DFNode *nnext;
                        for (DFNode *n = child; n != NULL; n = nnext) {
                            nnext = n->next;
                            DFInsertBefore(ancestor->parent,n,before);
                        }
                    }
                }

                size_t x = 0;
                while (x < DFArrayCount(startElements)) {
                    DFNode *element = DFArrayItemAt(startElements,x);
                    const char *bookmarkId = DFGetAttribute(element,WORD_ID);
                    if (bookmarkId == NULL)
                        bookmarkId = "";
                    if (DFHashTableLookup(endIds,bookmarkId) != NULL) {
                        element->tag = WORD_BOOKMARK;
                        DFArrayRemove(startElements,x);
                    }
                    else {
                        x++;
                    }
                }

                if (DFArrayCount(startElements) > 0) {
                    for (size_t i = 1; i < DFArrayCount(startElements); i++) {
                        DFNode *tempParent = DFArrayItemAt(startElements,i-1);
                        DFNode *tempChild = DFArrayItemAt(startElements,i);
                        DFAppendChild(tempParent,tempChild);
                    }

                    DFNode *last = DFArrayItemAt(startElements,DFArrayCount(startElements)-1);
                    while (next != NULL) {
                        DFNode *tempChild = next;
                        next = next->next;
                        DFAppendChild(last,tempChild);
                    }
                }

                for (size_t eIndex = 0; eIndex < DFArrayCount(startElements); eIndex++) {
                    DFNode *e = DFArrayItemAt(startElements,eIndex);
                    e->tag = WORD_BOOKMARK;
                }
                for (size_t eIndex = 0; eIndex < DFArrayCount(endElements); eIndex++) {
                    DFNode *e = DFArrayItemAt(endElements,eIndex);
                    DFRemoveNode(e);
                }

                if (DFArrayCount(startElements) > 0) {
                    DFNode *last = DFArrayItemAt(startElements,DFArrayCount(startElements)-1);
                    collapseRecursive(last,bookmarksById);
                }

                DFArrayRelease(startElements);
                DFArrayRelease(endElements);
                DFHashTableRelease(startIds);
                DFHashTableRelease(endIds);
                break;
            }
            default:
                collapseRecursive(child,bookmarksById);
                break;
        }
    }
}
Example #8
0
void Word_setupBookmarkLinks(WordPutData *put)
{
    DFHashTable *referencesById = findReferences(put->conv->html);
    const char **sortedIds = DFHashTableCopyKeys(referencesById);
    DFSortStringsCaseSensitive(sortedIds);
    for (int idIndex = 0; sortedIds[idIndex]; idIndex++) {
        const char *targetId = sortedIds[idIndex];
        DFArray *references = DFHashTableLookup(referencesById,targetId);
        DFNode *targetElem = DFElementForIdAttr(put->conv->html,targetId);
        if (targetElem == NULL)
            continue;

        // The following is only relevant for figures and tables
        int refText = 0;
        int refLabelNum = 0;
        int refCaptionText = 0;

        for (int refIndex = 0; refIndex < DFArrayCount(references); refIndex++) {
            DFNode *a = DFArrayItemAt(references,refIndex);
            const char *className = DFGetAttribute(a,HTML_CLASS);
            if (DFStringEquals(className,DFRefTextClass))
                refText = 1;
            else if (DFStringEquals(className,DFRefLabelNumClass))
                refLabelNum = 1;
            else if (DFStringEquals(className,DFRefCaptionTextClass))
                refCaptionText = 1;
        }

        DFNode *concrete = WordConverterGetConcrete(put,targetElem);
        switch (targetElem->tag) {
            case HTML_H1:
            case HTML_H2:
            case HTML_H3:
            case HTML_H4:
            case HTML_H5:
            case HTML_H6: {
                const char *bookmarkId = NULL;
                const char *bookmarkName = NULL;
                DFNode *bookmarkElem = NULL;
                if ((concrete != NULL) && (concrete->tag == WORD_P)) {

                    // FIXME: We only want to consider the bookmark to be the headings "correct"
                    // bookmark in the case where it contains all of the heading's content, though
                    // excluding other bookmarks that might come before or after it.

                    // If you have the cursor inside a heading bookmark when you save the document,
                    // word puts a bookmark called _GoBack there, and we of course don't want to
                    // confuse that with the actual heading's bookmark (if any).

                    // For now as a temporary hack we just explicitly filter out _GoBack; but there
                    // needs to be a more general fix, as there may be other bookmarks that end up
                    // in the heading.

                    for (DFNode *child = concrete->first; child != NULL; child = child->next) {
                        if ((child->tag == WORD_BOOKMARK) &&
                            !DFStringEquals(DFGetAttribute(child,WORD_NAME),"_GoBack")) {
                            bookmarkElem = child;
                            bookmarkId = DFGetAttribute(bookmarkElem,WORD_ID);
                            bookmarkName = DFGetAttribute(bookmarkElem,WORD_NAME);
                            break;
                        }
                    }
                }

                if ((bookmarkElem == NULL) || (bookmarkId == NULL) || (bookmarkName == NULL)) {
                    // New bookmark
                    WordBookmark *bookmark = WordObjectsAddBookmark(put->conv->objects);
                    bookmarkId =bookmark->bookmarkId;
                    bookmarkName = bookmark->bookmarkName;
                }

                DFNode *bookmarkSpan = DFCreateElement(put->conv->package->document,HTML_SPAN);
                DFSetAttribute(bookmarkSpan,HTML_CLASS,DFBookmarkClass);

                if (bookmarkElem != NULL) {
                    // FIXME: Not covered by tests
                    DFFormatAttribute(bookmarkSpan,HTML_ID,"%s%u",put->conv->idPrefix,bookmarkElem->seqNo);
                }

                DFSetAttribute(bookmarkSpan,WORD_NAME,bookmarkName);
                DFSetAttribute(bookmarkSpan,WORD_ID,bookmarkId);

                while (targetElem->first != NULL)
                    DFAppendChild(bookmarkSpan,targetElem->first);
                DFAppendChild(targetElem,bookmarkSpan);

                break;
            }
            case HTML_TABLE:
            case HTML_FIGURE: {
                WordCaption *caption = WordObjectsCaptionForTarget(put->conv->objects,targetElem);
                if (caption == NULL)
                    break;

                assert(caption->element != NULL);
                assert((caption->number == NULL) || (caption->number->parent == caption->element));
                assert((caption->contentStart == NULL) || (caption->contentStart->parent == caption->element));

                // Note: caption.number may be null (i.e. if the caption is unnumbered)
                //       caption.contentStart may be null (if there is no text in the caption)

                WordBookmark *captionTextBookmark = NULL;
                WordBookmark *labelNumBookmark = NULL;
                WordBookmark *textBookmark = NULL;

                if (!refCaptionText && !refLabelNum && !refText)
                    refText = 1;

                if (refCaptionText) {
                    captionTextBookmark = createBookmark(put->conv);
                    DFNode *nnext;
                    for (DFNode *n = caption->contentStart; n != NULL; n = nnext) {
                        nnext = n->next;
                        DFAppendChild(captionTextBookmark->element,n);
                    }
                    DFAppendChild(caption->element,captionTextBookmark->element);
                }
                if (refLabelNum && (caption->number != NULL)) {
                    labelNumBookmark = createBookmark(put->conv);
                    DFNode *numberNext = caption->number->next;
                    DFNode *nnext;
                    for (DFNode *n = caption->element->first; (n != NULL) && (n != numberNext); n = nnext) {
                        nnext = n->next;
                        DFAppendChild(labelNumBookmark->element,n);
                    }
                    DFInsertBefore(caption->element,labelNumBookmark->element,caption->element->first);
                }
                if (refText) {
                    textBookmark = createBookmark(put->conv);
                    DFNode *nnext;
                    for (DFNode *n = caption->element->first; n != NULL; n = nnext) {
                        nnext = n->next;
                        DFAppendChild(textBookmark->element,n);
                    }
                    DFAppendChild(caption->element,textBookmark->element);
                }

                caption->captionTextBookmark = captionTextBookmark;
                caption->labelNumBookmark = labelNumBookmark;
                caption->textBookmark = textBookmark;

                break;
            }
        }
    }
    free(sortedIds);
    DFHashTableRelease(referencesById);
}