예제 #1
0
static void Word_mergeRunsRecursive(DFNode *node)
{
    DFNode *current = node->first;
    while (current != NULL) {
        DFNode *next = current->next;

        if ((current->tag == WORD_R) && (next != NULL) && (next->tag == WORD_R)) {
            DFNode *currentRPr = DFChildWithTag(current,WORD_RPR);
            DFNode *nextRPr = DFChildWithTag(next,WORD_RPR);
            if (nodesEqual(currentRPr,nextRPr)) {
                while (next->first != NULL) {
                    if (next->first->tag == WORD_RPR)
                        DFRemoveNode(next->first);
                    else
                        DFAppendChild(current,next->first);
                }
                DFRemoveNode(next);
                continue;
            }
        }

        current = next;
    }

    for (current = node->first; current != NULL; current = current->next)
        Word_mergeRunsRecursive(current);
}
예제 #2
0
static void updateDefaults(WordConverter *converter, CSSSheet *styleSheet)
{
    DFNode *root = converter->package->styles->root;
    CSSStyle *bodyStyle = CSSSheetLookupElement(converter->styleSheet,"body",NULL,0,0);
    if (bodyStyle != NULL) {

        // Remove margin properties
        DFHashTable *collapsed = CSSCollapseProperties(CSSStyleRule(bodyStyle));
        CSSProperties *copy = CSSPropertiesNewWithRaw(collapsed);
        DFHashTableRelease(collapsed);
        CSSPut(copy,"margin-top",NULL);
        CSSPut(copy,"margin-bottom",NULL);
        CSSPut(copy,"margin-left",NULL);
        CSSPut(copy,"margin-right",NULL);

        DFNode *docDefaults = DFChildWithTag(root,WORD_DOCDEFAULTS);
        DFNode *rPrDefault = DFChildWithTag(docDefaults,WORD_RPRDEFAULT);
        DFNode *pPrDefault = DFChildWithTag(docDefaults,WORD_PPRDEFAULT);
        DFNode *rPr = DFChildWithTag(rPrDefault,WORD_RPR);
        DFNode *pPr = DFChildWithTag(pPrDefault,WORD_PPR);

        int hadEmptyRPrDefault = ((rPrDefault != NULL) && (rPrDefault->first == NULL));
        int hadEmptyPPrDefault = ((pPrDefault != NULL) && (pPrDefault->first == NULL));

        if (docDefaults == NULL)
            docDefaults = DFCreateElement(converter->package->styles,WORD_DOCDEFAULTS);
        if (rPrDefault == NULL)
            rPrDefault = DFCreateElement(converter->package->styles,WORD_RPRDEFAULT);
        if (pPrDefault == NULL)
            pPrDefault = DFCreateElement(converter->package->styles,WORD_PPRDEFAULT);
        if (rPr == NULL)
            rPr = DFCreateChildElement(rPrDefault,WORD_RPR);
        if (pPr == NULL)
            pPr = DFCreateChildElement(pPrDefault,WORD_PPR);

        DFAppendChild(docDefaults,rPrDefault);
        DFAppendChild(docDefaults,pPrDefault);
        DFInsertBefore(root,docDefaults,root->first);

        WordPutPPr(pPr,copy,NULL,converter->mainSection,-1);

        if (rPr->first == NULL)
            DFRemoveNode(rPr);
        if (pPr->first == NULL)
            DFRemoveNode(pPr);

        if ((rPrDefault->first == NULL) && !hadEmptyRPrDefault)
            DFRemoveNode(rPrDefault);
        if ((pPrDefault->first == NULL) && !hadEmptyPPrDefault)
            DFRemoveNode(pPrDefault);

        if (docDefaults->first == NULL)
            DFRemoveNode(docDefaults);

        CSSPropertiesRelease(copy);
    }
}
예제 #3
0
static void putInParagraphsRecursive(DFNode *node)
{
    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;
        putInParagraphsRecursive(child);
    }

    if (((node->tag == WORD_BOOKMARKSTART) || (node->tag == WORD_BOOKMARKEND)) &&
        (node->parent->tag != WORD_P)) {
        DFNode *forwards = findParagraphForwards(node);
        if (forwards != NULL) {
            DFNode *pPr = DFChildWithTag(forwards,WORD_PPR);
            if (pPr != NULL)
                DFInsertBefore(forwards,node,pPr->next);
            else
                DFInsertBefore(forwards,node,forwards->first);
            return;
        }

        DFNode *backwards = findParagraphBackwards(node);
        if (backwards != NULL) {
            DFAppendChild(backwards,node);
            return;
        }

        DFRemoveNode(node);
    }
}
예제 #4
0
void DFInsertBefore(DFNode *parent, DFNode *newChild, DFNode *refChild)
{
    assert(newChild->doc == parent->doc);
    assert((refChild == NULL) || (refChild->doc == parent->doc));

    if (newChild == refChild)
        return;

    if (newChild->parent != NULL)
        DFRemoveNode(newChild);

    assert(newChild->prev == NULL);
    assert(newChild->next == NULL);
    assert((refChild == NULL) || (refChild->parent == parent));
    assert(((parent->first == NULL) && (parent->last == NULL)) ||
           ((parent->first != NULL) && (parent->last != NULL)));
    assert((parent->first != NULL) || (refChild == NULL));

    newChild->prev = (refChild != NULL) ? refChild->prev : parent->last;
    newChild->next = refChild;

    if (newChild->prev != NULL)
        newChild->prev->next = newChild;
    if (newChild->next != NULL)
        newChild->next->prev = newChild;

    if (refChild == parent->first)
        parent->first = newChild;
    if (refChild == NULL)
        parent->last = newChild;

    newChild->parent = parent;
}
예제 #5
0
static void WordRunPut(WordPutData *put, DFNode *abstract, DFNode *concrete)
{
    if ((abstract->tag != HTML_SPAN) || (concrete->tag != WORD_R))
        return;

    if (WordRunPutNote(put,abstract,concrete))
        return;

    WordContainerPut(put,&WordRunContentLens,abstract,concrete);

    DFNode *rPr = DFChildWithTag(concrete,WORD_RPR);
    if (rPr == NULL)
        rPr = DFCreateElement(put->contentDoc,WORD_RPR);
    DFInsertBefore(concrete,rPr,concrete->first); // Ensure first, in case [super put] moved it

    char *selector = CSSMakeNodeSelector(abstract);
    const char *styleId = WordSheetStyleIdForSelector(put->conv->styles,selector);

    const char *inlineCSSText = DFGetAttribute(abstract,HTML_STYLE);
    CSSProperties *properties = CSSPropertiesNewWithString(inlineCSSText);
    WordPutRPr(rPr,properties,styleId,put->conv->theme);
    CSSPropertiesRelease(properties);

    if (rPr->first == NULL)
        DFRemoveNode(rPr);

    free(selector);
}
예제 #6
0
void DFRemoveNodeButKeepChildren(DFNode *node)
{
    DFNode *parent = node->parent;
    assert(parent != NULL);
    while (node->first != NULL)
        DFInsertBefore(parent,node->first,node);
    DFRemoveNode(node);
}
예제 #7
0
void replaceChildrenFromArray(DFNode *node, DFNode **children, Tag *tags)
{
    while (node->first != NULL)
        DFRemoveNode(node->first);

    for (int i = 0; tags[i] != 0; i++) {
        if (children[tags[i]])
            DFAppendChild(node,children[tags[i]]);
    }
}
예제 #8
0
static void removeNodes(DFNode *beginNode, DFNode *endNode)
{
    CommonAncestorInfo common = findCommonAncestor(beginNode,endNode);
    assert(common.commonAncestor != NULL);
    assert(common.beginAncestor != NULL);
    assert(common.endAncestor != NULL);

    DFNode *begin = beginNode;
    while (begin != common.beginAncestor) {
        DFNode *parent = begin->parent;
        if (begin->next != NULL)
            DFRemoveNode(begin->next);
        else
            begin = parent;
    }

    DFNode *end = endNode;
    while (end != common.endAncestor) {
        DFNode *parent = end->parent;
        if (end->prev != NULL)
            DFRemoveNode(end->prev);
        else
            end = parent;
    }

    if (common.beginAncestor != common.endAncestor) {
        while (common.beginAncestor->next != common.endAncestor)
            DFRemoveNode(common.beginAncestor->next);
    }

    while ((beginNode != NULL) && (beginNode->first == NULL) && (beginNode->tag != WORD_DOCUMENT)) {
        DFNode *parent = beginNode->parent;
        DFRemoveNode(beginNode);
        beginNode = parent;
    }

    while ((endNode != NULL) && (endNode->first == NULL) && (endNode->tag != WORD_DOCUMENT)) {
        DFNode *parent = endNode->parent;
        DFRemoveNode(endNode);
        endNode = parent;
    }
}
예제 #9
0
void DFRemoveWhitespaceNodes(DFNode *node)
{
    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next  = child->next;
        switch (child->tag) {
            case DOM_TEXT:
            case DOM_CDATA: {
                if (DFStringIsWhitespace(child->value))
                    DFRemoveNode(child);
                break;
            }
            case DOM_COMMENT:
                DFRemoveNode(child);
                break;
            default:
                DFRemoveWhitespaceNodes(child);
                break;
        }
    }
}
예제 #10
0
static void updateTrJc(DFNode *wordTr, const char *oldJc, const char *newJc)
{
    DFNode *tblPrEx = DFChildWithTag(wordTr,WORD_TBLPREX);
    DFNode *trPr = DFChildWithTag(wordTr,WORD_TRPR);

    if (tblPrEx != NULL)
        DFRemoveNode(tblPrEx);
    if (trPr != NULL)
        DFRemoveNode(trPr);

    if (trPr == NULL)
        trPr = DFCreateElement(wordTr->doc,WORD_TRPR);

    WordPutTrPr(trPr,oldJc,newJc);

    if (trPr->first == NULL)
        trPr = NULL;;

    DFNode *first = wordTr->first;
    if (tblPrEx != NULL)
        DFInsertBefore(wordTr,tblPrEx,first);
    if (trPr != NULL)
        DFInsertBefore(wordTr,trPr,first);
}
예제 #11
0
static DFNode *concreteRowForAbstractRow(WordPutData *put, DFNode *htmlTr)
{
    DFNode *wordTr = WordConverterGetConcrete(put,htmlTr);
    if (wordTr == NULL) {
        wordTr = DFCreateElement(put->contentDoc,WORD_TR);
    }
    else {
        // We're reusing an existing row element, but we first need to clear all the cells in
        // it, because we'll be rebuilding the cell list
        DFNode *next;
        for (DFNode *child = wordTr->first; child != NULL; child = next) {
            next = child->next;
            if (child->tag == WORD_TC)
                DFRemoveNode(child);
        }
    }
    return wordTr;
}
예제 #12
0
static void Word_flattenList(WordConverter *word, DFNode *list, int ilvl, DFNode *parent, DFNode *nextSibling)
{
    const char *type = (list->tag == HTML_OL) ? "decimal" : "disc";
    const char *cssText = DFGetAttribute(list,HTML_STYLE);
    CSSProperties *properties = CSSPropertiesNewWithString(cssText);
    if (CSSGet(properties,"list-style-type") != NULL)
        type = CSSGet(properties,"list-style-type");

    DFFormatAttribute(list,CONV_LISTNUM,"%u",list->seqNo);
    DFFormatAttribute(list,CONV_ILVL,"%d",ilvl);
    DFSetAttribute(list,CONV_LISTTYPE,type);

    for (DFNode *li = list->first; li != NULL; li = li->next) {

        DFNode *first = li->first;
        DFNode *liChildNext;
        for (DFNode *liChild = li->first; liChild != NULL; liChild = liChildNext) {
            liChildNext = liChild->next;

            if ((liChild->tag == HTML_UL) || (liChild->tag == HTML_OL)) {
                Word_flattenList(word,liChild,ilvl+1,parent,nextSibling);
            }
            else {
                if (liChild->tag == HTML_P) {
                    DFFormatAttribute(liChild,CONV_LISTNUM,"%u",list->seqNo);
                    DFFormatAttribute(liChild,CONV_ILVL,"%d",ilvl);
                    DFSetAttribute(liChild,CONV_LISTTYPE,type);
                    if (liChild == first)
                        DFSetAttribute(liChild,CONV_LISTITEM,"true");
                }
                DFInsertBefore(parent,liChild,nextSibling);
                Word_preProcessLists(word,liChild,ilvl);
            }
        }
    }

    DFRemoveNode(list);
    CSSPropertiesRelease(properties);
}
예제 #13
0
void DFStripWhitespace(DFNode *node)
{
    if (node->tag == DOM_TEXT) {
        char *trimmed = DFStringTrimWhitespace(node->value);
        if ((strlen(trimmed) == 0) && (node->parent != NULL))
            DFRemoveNode(node);
        else
            DFSetNodeValue(node,trimmed);
        free(trimmed);
    }
    else {
        if (node->tag >= MIN_ELEMENT_TAG) {
            const char *space = DFGetAttribute(node,XML_SPACE);
            if ((space != NULL) && !strcmp(space,"preserve"))
                return;
        }
        DFNode *next;
        for (DFNode *child = node->first; child != NULL; child = next) {
            next = child->next;
            DFStripWhitespace(child);
        }
    }
}
예제 #14
0
static void WordTblPut(WordPutData *put, DFNode *abstract, DFNode *concrete)
{
    if ((abstract->tag != HTML_TABLE) || (concrete->tag != WORD_TBL))
        return;;

    DFTable *abstractStructure = HTML_tableStructure(abstract);
    const char *inlineCSSText = DFGetAttribute(abstract,HTML_STYLE);
    CSSProperties *tableProperties = CSSPropertiesNewWithString(inlineCSSText);
    CSSProperties *cellProperties = CSSPropertiesNew();
    const char *className = DFGetAttribute(abstract,HTML_CLASS);
    char *selector = CSSMakeSelector("table",className);
    WordStyle *style = WordSheetStyleForSelector(put->conv->styles,selector);
    CellPadding padding = getPadding(put->conv->styleSheet,style,cellProperties);

    DFNode *tblPr = DFChildWithTag(concrete,WORD_TBLPR);
    if (tblPr == NULL)
        tblPr = DFCreateElement(concrete->doc,WORD_TBLPR);;

    DFNode *tblGrid = DFChildWithTag(concrete,WORD_TBLGRID);
    if (tblGrid == NULL)
        tblGrid = DFCreateElement(concrete->doc,WORD_TBLGRID);

    while (concrete->first != NULL)
        DFRemoveNode(concrete->first);

    const char *oldJc = DFGetChildAttribute(tblPr,WORD_JC,WORD_VAL);
    WordPutTblPr(tblPr,tableProperties,NULL,put->conv->mainSection,style != NULL ? style->styleId : NULL);
    const char *newJc = DFGetChildAttribute(tblPr,WORD_JC,WORD_VAL);

    double tableWidthPct = 100;
    if (CSSGet(tableProperties,"width") != NULL) {
        CSSLength length = CSSLengthFromString(CSSGet(tableProperties,"width"));
        if (CSSLengthIsValid(length) && (length.units == UnitsPct))
            tableWidthPct = length.value;
    }

    double contentWidthPts = WordSectionContentWidthPts(put->conv->mainSection);
    double totalWidthPts = (contentWidthPts+padding.leftPts+padding.rightPts)*(tableWidthPct/100.0);

    while (tblGrid->first != NULL)
        DFRemoveNode(tblGrid->first);
    for (unsigned int i = 0; i < abstractStructure->cols; i++) {
        DFNode *gridCol = DFCreateChildElement(tblGrid,WORD_GRIDCOL);

        double colWidthPct = DFTablePctWidthForCol(abstractStructure,i);
        double colWidthPts = totalWidthPts*colWidthPct/100.0;
        int colWidthTwips = (int)round(colWidthPts*20);

        DFFormatAttribute(gridCol,WORD_W,"%d",colWidthTwips);
    }

    DFAppendChild(concrete,tblPr);
    DFAppendChild(concrete,tblGrid);
    for (unsigned int row = 0; row < abstractStructure->rows; row++) {
        DFNode *htmlTr = DFTableGetRowElement(abstractStructure,row);
        DFNode *wordTr = concreteRowForAbstractRow(put,htmlTr);
        updateTrJc(wordTr,oldJc,newJc);
        DFAppendChild(concrete,wordTr);
        unsigned int col = 0;
        while (col < abstractStructure->cols) {

            DFCell *cell = DFTableGetCell(abstractStructure,row,col);
            assert(cell != NULL);

            DFNode *tc = WordConverterGetConcrete(put,cell->element);
            if ((tc == NULL) || (row != cell->row))
                tc = DFCreateElement(concrete->doc,WORD_TC);
            DFAppendChild(wordTr,tc);

            if (cell->row == row)
                WordTcPut(put,cell->element,tc);;

            const char *vMerge = NULL;
            if (cell->rowSpan > 1) {
                if (row == cell->row)
                    vMerge = "restart";
                else
                    vMerge = "continue";
            }

            DFNode *tcPr = DFChildWithTag(tc,WORD_TCPR);
            if (tcPr == NULL)
                tcPr = DFCreateElement(concrete->doc,WORD_TCPR);
            // Make sure tcPr comes first
            DFInsertBefore(tc,tcPr,tc->first);

            WordPutTcPr2(tcPr,cell->colSpan,vMerge);

            const char *inlineCSSText = DFGetAttribute(cell->element,HTML_STYLE);
            CSSProperties *innerCellProperties = CSSPropertiesNewWithString(inlineCSSText);

            if ((row == cell->row) && (totalWidthPts > 0)) {
                double spannedWidthPct = 0;
                for (unsigned int c = col; c < col + cell->colSpan; c++)
                    spannedWidthPct += DFTablePctWidthForCol(abstractStructure,c);
                char buf[100];
                CSSPut(innerCellProperties,"width",DFFormatDoublePct(buf,100,spannedWidthPct));
            }

            WordPutTcPr1(tcPr,innerCellProperties);

            int haveBlockLevelElement = 0;
            for (DFNode *tcChild = tc->first; tcChild != NULL; tcChild = tcChild->next) {
                if (WordBlockLevelLens.isVisible(put,tcChild))
                    haveBlockLevelElement = 1;
            }

            // Every cell must contain at least one block-level element
            if (!haveBlockLevelElement) {
                DFNode *p = DFCreateElement(concrete->doc,WORD_P);
                DFAppendChild(tc,p);
            }

            col += cell->colSpan;
            CSSPropertiesRelease(innerCellProperties);
        }
    }

    free(selector);
    DFTableRelease(abstractStructure);
    CSSPropertiesRelease(tableProperties);
    CSSPropertiesRelease(cellProperties);
}
예제 #15
0
static int processParts(DFHashTable *parts, const char *documentPath, DFDocument *relsDoc,
                        DFHashTable *documentRels,
                        DFBuffer *output, DFStorage *storage, DFError **error)
{
    int ok = 0;
    DFHashTable *includeTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
    DFHashTableAdd(includeTypes,WORDREL_HYPERLINK,"");
    DFHashTableAdd(includeTypes,WORDREL_IMAGE,"");

    if ((parts == NULL) || (DFHashTableLookup(parts,"document") != NULL)) {
        DFDocument *doc = DFParseXMLStorage(storage,documentPath,error);
        if (doc == NULL)
            goto end;
        addStrippedSerializedDoc(output,doc,"document.xml");
        DFDocumentRelease(doc);
    }

    if ((parts == NULL) || (DFHashTableLookup(parts,"styles") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_STYLES,"styles.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"numbering") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_NUMBERING,"numbering.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"footnotes") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_FOOTNOTES,"footnotes.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts == NULL) || (DFHashTableLookup(parts,"endnotes") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_ENDNOTES,"endnotes.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts != NULL) && (DFHashTableLookup(parts,"settings") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_SETTINGS,"settings.xml",output,includeTypes,storage,error))
            goto end;
    }
    if ((parts != NULL) && (DFHashTableLookup(parts,"theme") != NULL)) {
        if (!addRelatedDoc(parts,documentRels,WORDREL_THEME,"theme.xml",output,includeTypes,storage,error))
            goto end;
    }

    if ((DFHashTableLookup(documentRels,WORDREL_HYPERLINK) != NULL) ||
        (DFHashTableLookup(documentRels,WORDREL_IMAGE) != NULL) ||
        ((parts != NULL) && (DFHashTableLookup(parts,"documentRels") != NULL))) {
        if (relsDoc == NULL) {
            DFErrorFormat(error,"document.xml.rels does not exist");
            goto end;
        }
        DFNode *next;
        for (DFNode *child = relsDoc->root->first; child != NULL; child = next) {
            next = child->next;
            if (child->tag != REL_RELATIONSHIP)
                continue;
            const char *type = DFGetAttribute(child,NULL_Type);
            if ((type != NULL) && (DFHashTableLookup(includeTypes,type) == NULL)) {
                DFRemoveNode(child);
            }
        }
        addSerializedDoc(output,relsDoc,"document.xml.rels");
    }

    const char **entries = DFStorageList(storage,NULL);
    if (entries != NULL) { // FIXME: Should really report an error if this is not the case
        for (int i = 0; entries[i]; i++) {
            const char *filename = entries[i];
            char *extension = DFPathExtension(filename);
            if (DFStringEqualsCI(extension,"png") || DFStringEqualsCI(extension,"jpg")) {
                char *absFilename;
                if (!DFStringHasSuffix(filename,"/"))
                    absFilename = DFFormatString("/%s",filename);
                else
                    absFilename = xstrdup(filename);
                DFBuffer *data = DFBufferReadFromStorage(storage,absFilename,NULL);
                addSerializedBinary(output,data,absFilename);
                DFBufferRelease(data);
                free(absFilename);
            }
            free(extension);
        }
    }
    free(entries);
    DFHashTableRelease(includeTypes);

    ok = 1;

end:
    return ok;
}
예제 #16
0
static void Word_preProcessHTML(WordConverter *word, DFNode *node)
{
    switch (node->tag) {
        case HTML_TABLE:
        case HTML_FIGURE: {
            DFNode *next;
            for (DFNode *child = node->first; child != NULL; child = next) {
                next = child->next;

                if ((child->tag != HTML_CAPTION) && (child->tag != HTML_FIGCAPTION))
                    continue;

                WordCaption *caption = WordCaptionNew(child);
                WordObjectsSetCaption(word->objects,caption,node);
                caption->contentStart = child->first;
                WordCaptionRelease(caption);

                const char *className = DFGetAttribute(child,HTML_CLASS);
                CSSStyle *style;
                if (child->tag == HTML_CAPTION)
                    style = CSSSheetLookupElement(word->styleSheet,"caption",className,0,0);
                else
                    style = CSSSheetLookupElement(word->styleSheet,"figcaption",className,0,0);

                CSSProperties *before = CSSStyleBefore(style);
                if (CSSGet(before,"content") != NULL)
                    Word_addContentParts(child,CSSGet(before,"content"),caption);

                child->tag = HTML_P;
                DFSetAttribute(child,HTML_CLASS,"Caption");
                DFInsertBefore(node->parent,child,node->next);
                Word_preProcessHTML(word,child);
            }

            // The HTML normalization process ensures that apart from the <figcaption> element,
            // all children of a <figure> are paragraphs or containers. Currently the editor only
            // lets you create figures that contain a single image, so it's always a single
            // paragraph. Since the HTML <figure> element gets mapped to a single <w:p> element
            // by WordParagraphLens, we want to make sure it only contains inline children.

            for (DFNode *child = node->first; child != NULL; child = next) {
                next = child->next;
                if (HTML_isParagraphTag(child->tag))
                    DFRemoveNodeButKeepChildren(child);
            }

            // FIXME: Handle <div>, <pre>, lists, tables etc which could also theoretically
            // exist inside the <figure> element

            break;
        }
        case HTML_NAV: {
            const char *className = DFGetAttribute(node,HTML_CLASS);
            const char *instr = NULL;
            if (DFStringEquals(className,DFTableOfContentsClass))
                instr = " TOC \\o \"1-3\" ";
            else if (DFStringEquals(className,DFListOfFiguresClass))
                instr = " TOC \\c \"Figure\" ";
            else if (DFStringEquals(className,DFListOfTablesClass))
                instr = " TOC \\c \"Table\" ";

            if (instr != NULL) {
                DFNode *p = DFCreateElement(word->html,HTML_P);
                DFNode *field = DFCreateChildElement(p,HTML_SPAN);
                DFSetAttribute(field,HTML_CLASS,DFFieldClass);
                DFCreateChildTextNode(field,instr);
                DFInsertBefore(node->parent,p,node);
                DFRemoveNode(node);
            }
            break;
        }
    }

    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;
        Word_preProcessHTML(word,child);
    }
}
예제 #17
0
static void extractPrefixRecursive(DFNode *node, const char *counterName, DFBuffer *result,
                                   int *foundSeq, int *foundContent)
{
    if (isSeqField(node)) {
        if (result->len > 0)
            DFBufferFormat(result," ");
        DFBufferFormat(result,"counter(%s)",counterName);
        *foundSeq = 1;
        DFRemoveNode(node);
        return;
    }

    if (node->tag == DOM_TEXT) {
        size_t valueLen = strlen(node->value);
        size_t pos = 0;

        if (*foundSeq) {
            size_t offset = 0;
            uint32_t ch;
            do {
                pos = offset;
                ch = DFNextChar(node->value,&offset);
            } while ((ch != 0) && (DFCharIsWhitespaceOrNewline(ch) || DFCharIsPunctuation(ch)));
        }
        else {
            pos = valueLen;
        }

        if (pos == valueLen) {
            if (result->len > 0)
                DFBufferFormat(result," ");
            char *quotedValue = DFQuote(node->value);
            DFBufferFormat(result,"%s",quotedValue);
            free(quotedValue);
            DFRemoveNode(node);
            if (*foundSeq)
                *foundContent = 1;
            return;
        }
        else if (pos > 0) {
            char *first = DFSubstring(node->value,0,pos);
            char *rest = DFSubstring(node->value,pos,valueLen);
            if (result->len > 0)
                DFBufferFormat(result," ");
            char *quotedFirst = DFQuote(first);
            DFBufferFormat(result,"%s",quotedFirst);
            free(quotedFirst);
            DFSetNodeValue(node,rest);
            if (*foundSeq)
                *foundContent = 1;
            free(first);
            free(rest);
            return;
        }
    }

    int wasEmpty = (node->first == NULL);
    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;
        if (*foundContent)
            break;
        extractPrefixRecursive(child,counterName,result,foundSeq,foundContent);
    }
    int isEmpty = (node->first == NULL);
    if ((node->tag == HTML_SPAN) && isEmpty && !wasEmpty)
        DFRemoveNode(node);
}
예제 #18
0
static void Word_postProcessHTML(WordConverter *conv, DFNode *node)
{
    DFNode *next;
    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;

        switch (child->tag) {
            case HTML_SPAN: {
                const char *className = DFGetAttribute(child,HTML_CLASS);
                if (DFStringEquals(className,DFBookmarkClass)) {
                    if (child->first != NULL)
                        next = child->first;
                    DFRemoveNodeButKeepChildren(child);
                }
                break;
            }
            case HTML_CAPTION: {
                const char *counterName = NULL;

                if ((child->prev != NULL) && (child->prev->tag == HTML_FIGURE) &&
                    (DFChildWithTag(child->prev,HTML_FIGCAPTION) == NULL)) {
                    child->tag = HTML_FIGCAPTION;
                    counterName = "figure";
                    DFAppendChild(child->prev,child);
                }
                else if ((child->prev != NULL) && (child->prev->tag == HTML_TABLE) &&
                         (DFChildWithTag(child->prev,HTML_CAPTION) == NULL)) {
                    counterName = "table";
                    DFInsertBefore(child->prev,child,child->prev->first);
                }
                else if ((child->next != NULL) && (child->next->tag == HTML_FIGURE) &&
                         (DFChildWithTag(child->next,HTML_FIGCAPTION) == NULL)) {
                    child->tag = HTML_FIGCAPTION;
                    counterName = "figure";
                    DFInsertBefore(child->next,child,child->next->first);
                }
                else if ((child->next != NULL) && (child->next->tag == HTML_TABLE) &&
                         (DFChildWithTag(child->next,HTML_CAPTION) == NULL)) {
                    counterName = "table";
                    DFSetAttribute(child,HTML_STYLE,"caption-side: top");
                    DFInsertBefore(child->next,child,child->next->first);
                }

                if (counterName != NULL) {
                    char *beforeText = extractPrefix(child,counterName);
                    if (beforeText != NULL) {
                        CSSStyle *style = CSSSheetLookupElement(conv->styleSheet,DFNodeName(child),NULL,1,0);
                        if (CSSGet(CSSStyleBefore(style),"content") == NULL) {
                            CSSPut(CSSStyleRule(style),"counter-increment",counterName);
                            CSSPut(CSSStyleBefore(style),"content",beforeText);
                        }
                    }
                    free(beforeText);
                }
                break;
            }
            case HTML_NAV: {
                if (HTML_isParagraphTag(node->tag)) {

                    if (child->prev != NULL) {
                        DFNode *beforeP = DFCreateElement(conv->package->document,node->tag);
                        while (child->prev != NULL)
                            DFInsertBefore(beforeP,child->prev,beforeP->first);
                        DFInsertBefore(node->parent,beforeP,node);
                    }
                    DFInsertBefore(node->parent,child,node);

                    if ((node->first == NULL) ||
                        ((node->first->tag == HTML_BR) && (node->first->next == NULL))) {
                        DFRemoveNode(node);
                        return;
                    }
                    next = NULL;
                }
                break;
            }
        }
    }

    for (DFNode *child = node->first; child != NULL; child = next) {
        next = child->next;
        Word_postProcessHTML(conv,child);
    }
}
예제 #19
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;
        }
    }
}
예제 #20
0
static void populateDrawingElement(WordConverter *converter, DFNode *root, double widthPts,
                                   double heightPts, const char *drawingId, const char *rId)
{
    EMUSize size;
    size.widthEmu = round(widthPts*EMUS_PER_POINT);
    size.heightEmu = round(heightPts*EMUS_PER_POINT);

    root->tag = WORD_DRAWING;
    DFRemoveAllAttributes(root);

    while (root->first != NULL)
        DFRemoveNode(root->first);

    char *docName = DFFormatString("Picture %s",drawingId);
    const char *imgName = "image";
    const char *imgId = "0";
    DFNode *inlin = DFCreateChildElement(root,DML_WP_INLINE);

    DFNode *extent = DFCreateChildElement(inlin,DML_WP_EXTENT); // a_CT_PositiveSize2D
    DFFormatAttribute(extent,NULL_CX,"%llu",size.widthEmu);
    DFFormatAttribute(extent,NULL_CY,"%llu",size.heightEmu);
    DFNode *docPr = DFCreateChildElement(inlin,DML_WP_DOCPR); // a_CT_NonVisualDrawingProps
    DFSetAttribute(docPr,NULL_ID,drawingId);
    DFSetAttribute(docPr,NULL_NAME,docName);
    DFNode *cNvGraphicFramePr = DFCreateChildElement(inlin,DML_WP_CNVGRAPHICFRAMEPR);
    DFNode *graphicFrameLocks = DFCreateChildElement(cNvGraphicFramePr,DML_MAIN_GRAPHICFRAMELOCKS);
    DFSetAttribute(graphicFrameLocks,NULL_NOCHANGEASPECT,"1");

    DFNode *graphic = DFCreateChildElement(inlin,DML_MAIN_GRAPHIC);
    DFNode *graphicData = DFCreateChildElement(graphic,DML_MAIN_GRAPHICDATA);
    DFSetAttribute(graphicData,NULL_URI,"http://schemas.openxmlformats.org/drawingml/2006/picture");

    DFNode *pic = DFCreateChildElement(graphicData,DML_PICTURE_PIC);
    DFNode *nvPicPr = DFCreateChildElement(pic,DML_PICTURE_NVPICPR);
    DFNode *blipFill = DFCreateChildElement(pic,DML_PICTURE_BLIPFILL); // a_CT_BlipFillProperties
    DFNode *spPr = DFCreateChildElement(pic,DML_PICTURE_SPPR); // a_CT_ShapeProperties

    // Graphic - Non-visual properties
    DFNode *cNvPr = DFCreateChildElement(nvPicPr,DML_PICTURE_CNVPR);
    DFNode *cNvPicPr = DFCreateChildElement(nvPicPr,DML_PICTURE_CNVPICPR);
    DFSetAttribute(cNvPr,NULL_ID,imgId);
    DFSetAttribute(cNvPr,NULL_NAME,imgName);

    // Blip
    DFNode *blip = DFCreateChildElement(blipFill,DML_MAIN_BLIP);
    DFSetAttribute(blip,OREL_EMBED,rId);
    DFNode *stretch = DFCreateChildElement(blipFill,DML_MAIN_STRETCH);
    DFNode *fillRect = DFCreateChildElement(stretch,DML_MAIN_FILLRECT);

    // Shape properties
    DFNode *xfrm = DFCreateChildElement(spPr,DML_MAIN_XFRM);
    DFNode *off = DFCreateChildElement(xfrm,DML_MAIN_OFF);
    DFSetAttribute(off,NULL_X,"0");
    DFSetAttribute(off,NULL_Y,"0");
    DFNode *ext = DFCreateChildElement(xfrm,DML_MAIN_EXT);
    DFFormatAttribute(ext,NULL_CX,"%llu",size.widthEmu);
    DFFormatAttribute(ext,NULL_CY,"%llu",size.heightEmu);
    DFNode *prstGeom = DFCreateChildElement(spPr,DML_MAIN_PRSTGEOM);
    DFSetAttribute(prstGeom,NULL_PRST,"rect");


    (void)cNvPicPr;
    (void)fillRect;
    free(docName);
}