Esempio n. 1
0
static void ConcreteInfoFree(ConcreteInfo *info)
{
    DFTableRelease(info->structure);
    CSSPropertiesRelease(info->tableProperties);
    CSSPropertiesRelease(info->cellProperties);
    free(info);
}
Esempio n. 2
0
static ImageInfo *getImageInfoObject(DFNode *concrete)
{
    DFNode *shape = DFChildWithTag(concrete,VML_SHAPE);
    DFNode *imageData = DFChildWithTag(shape,VML_IMAGEDATA);
    const char *cssText = DFGetAttribute(shape,NULL_STYLE);
    const char *rId = DFGetAttribute(imageData,OREL_ID);
    if ((shape == NULL) || (imageData == NULL) || (cssText == NULL) || (rId == NULL))
        return NULL;

    CSSProperties *imgProperties = CSSPropertiesNewWithString(cssText);
    CSSLength width = CSSLengthFromString(CSSGet(imgProperties,"width"));
    CSSLength height = CSSLengthFromString(CSSGet(imgProperties,"height"));
    CSSPropertiesRelease(imgProperties);

    if (!CSSLengthIsValid(width) || !CSSLengthIsAbsolute(width))
        return NULL;

    if (!CSSLengthIsValid(height) || !CSSLengthIsAbsolute(height))
        return NULL;

    double widthPts = convertBetweenUnits(width.value,width.units,UnitsPt);
    double heightPts = convertBetweenUnits(height.value,height.units,UnitsPt);

    ImageInfo *info = ImageInfoNew(rId,widthPts,heightPts);

    DFNode *oleObject = DFChildWithTag(concrete,MSOFFICE_OLEOBJECT);
    info->progId = DFGetAttribute(oleObject,NULL_PROGID);

    return info;
}
Esempio n. 3
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);
}
Esempio n. 4
0
static void WordPutNumPr(DFNode *concrete, CSSProperties *newp)
{
    DFNode *children[PREDEFINED_TAG_COUNT];
    childrenToArray(concrete,children);

    CSSProperties *oldp = CSSPropertiesNew();
    WordGetNumPr(concrete,oldp);

    if (!DFStringEquals(CSSGet(oldp,"-word-numId"),CSSGet(newp,"-word-numId")) ||
        !DFStringEquals(CSSGet(oldp,"-word-ilvl"),CSSGet(newp,"-word-ilvl"))) {
        if (CSSGet(newp,"-word-numId") != NULL) {
            children[WORD_NUMID] = DFCreateElement(concrete->doc,WORD_NUMID);
            DFSetAttribute(children[WORD_NUMID],WORD_VAL,CSSGet(newp,"-word-numId"));

            if (CSSGet(newp,"-word-ilvl") != NULL) {
                children[WORD_ILVL] = DFCreateElement(concrete->doc,WORD_ILVL);
                DFSetAttribute(children[WORD_ILVL],WORD_VAL,CSSGet(newp,"-word-ilvl"));
            }
            else {
                children[WORD_ILVL] = NULL;
            }
        }
        else {
            children[WORD_NUMID] = NULL;
            children[WORD_ILVL] = NULL;
        }
    }

    replaceChildrenFromArray(concrete,children,WordNumPr_Children);
    CSSPropertiesRelease(oldp);
}
CSSStyle *WordSetupTableGridStyle(CSSSheet *styleSheet, int *changed)
{
    CSSStyle *style = CSSSheetLookupElement(styleSheet,"table","Table_Grid",0,0);
    if (style == NULL) {
        style = CSSSheetLookupElement(styleSheet,"table","Table_Grid",1,0);

        CSSProperties *border = CSSPropertiesNewWithString("border: 1px solid black");

        DFHashTable *collapsed = CSSCollapseProperties(border);
        CSSPropertiesUpdateFromRaw(CSSStyleRule(style),collapsed);
        CSSPropertiesUpdateFromRaw(CSSStyleCell(style),collapsed);
        DFHashTableRelease(collapsed);
        CSSPut(CSSStyleRule(style),"margin-left","auto");
        CSSPut(CSSStyleRule(style),"margin-right","auto");

        // These must be set last, as updateRaw clears them when modifying rule
        CSSStyleSetParent(style,"table.Normal_Table");
        CSSStyleSetDisplayName(style,"Table Grid");

        if (changed != NULL)
            *changed = 1;

        CSSPropertiesRelease(border);
    }

    return style;
}
Esempio n. 6
0
static ListDimensions listIndent(WordConverter *conv, const char *numId, const char *ilvl)
{
    CSSProperties *properties = CSSPropertiesNew();
    listProperties(conv,numId,ilvl,properties);
    ListDimensions result = cssPropertiesIndent(properties);
    CSSPropertiesRelease(properties);
    return result;
}
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);
    }
}
Esempio n. 8
0
static ListDimensions paragraphIndent(DFNode *p)
{
    if (p->tag < MIN_ELEMENT_TAG)
        return ListDimensionsZero;;
    const char *cssText = DFGetAttribute(p,HTML_STYLE);
    CSSProperties *properties = CSSPropertiesNewWithString(cssText);
    ListDimensions result = cssPropertiesIndent(properties);
    CSSPropertiesRelease(properties);
    return result;
}
Esempio n. 9
0
static void updateFromRawCSSRules(CSSSheet *sheet, DFHashTable *rules)
{
    // FIXME: Handle class names containing escape sequences
    DFHashTableRelease(sheet->_styles);
    sheet->_styles = DFHashTableNew((DFCopyFunction)CSSStyleRetain,(DFFreeFunction)CSSStyleRelease);

    const char **sortedSelectors = DFHashTableCopyKeys(rules);
    DFSortStringsCaseInsensitive(sortedSelectors);
    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *constSelector = sortedSelectors[selIndex];

        // Treat any selectors specifying the class name only as paragraph styles
        char *selector;
        if (!strncmp(constSelector,".",1))
            selector = DFFormatString("p%s",constSelector); // FIXME: Not covered by tests
        else
            selector = xstrdup(constSelector);

        DFHashTable *raw = DFHashTableLookup(rules,constSelector);
        char *baseId = NULL;
        char *suffix = NULL;
        CSSParseSelector(selector,&baseId,&suffix);

        CSSStyle *style = CSSSheetLookupSelector(sheet,baseId,0,0);
        if (style == NULL) {
            style = CSSStyleNew(baseId);
            CSSSheetAddStyle(sheet,style);
            CSSStyleRelease(style);
        }

        CSSProperties *properties = CSSStyleRuleForSuffix(style,suffix);
        CSSProperties *expanded = CSSPropertiesNewWithRaw(raw);

        const char **allNames = CSSPropertiesCopyNames(expanded);
        for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) {
            const char *name = allNames[nameIndex];
            CSSPut(properties,name,CSSGet(expanded,name));
        }
        free(allNames);

        if (!strcmp(suffix,"")) {
            const char *defaultVal = CSSGet(properties,"-uxwrite-default");
            if ((defaultVal != NULL) && DFStringEqualsCI(defaultVal,"true"))
                CSSSheetSetDefaultStyle(sheet,style,StyleFamilyFromHTMLTag(style->tag));
        }
        CSSPropertiesRelease(expanded);
        free(baseId);
        free(suffix);
        free(selector);
    }
    free(sortedSelectors);
    removeRedundantProperties(sheet);
}
Esempio n. 10
0
static DFNode *imageWithFilename(WordGetData *get, const char *filename, double widthPts, DFNode *concrete)
{
    const char *concretePath = get->conv->concretePath;
    const char *abstractPath = get->conv->abstractPath;

    char *abstractImagesPath = DFAppendPathComponent(abstractPath,"images");
    char *lastComponent = DFPathBaseName(filename);
    char *srcImagePath = DFAppendPathComponent(concretePath,filename);
    char *dstImagePath = DFAppendPathComponent(abstractImagesPath,lastComponent);

    if (DFFileExists(dstImagePath))
        DFDeleteFile(dstImagePath,NULL);

    DFError *error = NULL;
    DFNode *imageNode = NULL;

    if (!DFFileExists(abstractImagesPath) &&
        !DFCreateDirectory(abstractImagesPath,1,&error)) {
        WordConverterWarning(get->conv,"Create %s: %s",abstractImagesPath,DFErrorMessage(&error));
        DFErrorRelease(error);
        imageNode = createAbstractPlaceholder(get,"[Error reading image]",concrete);
    }
    else if (!DFCopyFile(srcImagePath,dstImagePath,&error)) {
        WordConverterWarning(get->conv,"Copy %s to %s: %s",srcImagePath,dstImagePath,DFErrorMessage(&error));
        DFErrorRelease(error);
        imageNode = createAbstractPlaceholder(get,"[Error reading image]",concrete);
    }
    else {
        imageNode = WordConverterCreateAbstract(get,HTML_IMG,concrete);
        DFFormatAttribute(imageNode,HTML_SRC,"images/%s",lastComponent);

        double contentWidthPts = WordSectionContentWidthPts(get->conv->mainSection);
        if (contentWidthPts > 0) {
            double widthPct = widthPts/contentWidthPts*100.0;
            CSSProperties *properties = CSSPropertiesNew();
            char buf[100];
            CSSPut(properties,"width",DFFormatDoublePct(buf,100,widthPct));
            char *propertiesText = CSSPropertiesCopyDescription(properties);
            DFSetAttribute(imageNode,HTML_STYLE,propertiesText);
            free(propertiesText);
            CSSPropertiesRelease(properties);
        }
    }

    free(abstractImagesPath);
    free(lastComponent);
    free(srcImagePath);
    free(dstImagePath);
    return imageNode;
}
Esempio n. 11
0
// FIXME: make private to this file
double listDesiredIndent(WordConverter *conv, const char *numId, const char *ilvl)
{
    CSSProperties *properties = CSSPropertiesNew();
    listProperties(conv,numId,ilvl,properties);
    double result = 0.0;

    if (CSSGet(properties,"margin-left") != NULL) {
        CSSLength length = CSSLengthFromString(CSSGet(properties,"margin-left"));
        if (CSSLengthIsValid(length) && (length.units == UnitsPct))
            result += length.value;
    }

    CSSPropertiesRelease(properties);
    return result;
}
Esempio n. 12
0
static DFNode *WordTcCreateAbstractNode(WordGetData *get, DFNode *concrete)
{
    DFNode *td = WordConverterCreateAbstract(get,HTML_TD,concrete);

    CSSProperties *properties = CSSPropertiesNew();
    DFNode *tcPr = DFChildWithTag(concrete,WORD_TCPR);
    if (tcPr != NULL)
        WordGetTcPr(tcPr,properties);;
    DFHashTable *collapsed = CSSCollapseProperties(properties);
    char *styleValue = CSSSerializeProperties(collapsed);
    DFHashTableRelease(collapsed);
    if (strlen(styleValue) > 0)
        DFSetAttribute(td,HTML_STYLE,styleValue);
    free(styleValue);

    CSSPropertiesRelease(properties);
    return td;
}
Esempio n. 13
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);
}
Esempio n. 14
0
static DFNode *WordRunGet(WordGetData *get, DFNode *concrete)
{
    assert(concrete->tag == WORD_R);

    // First check the run to see if it's a footnote or endnote reference. These need to be handled specially,
    // as we place the actual content of the footnote or endnote in-line in the HTML output.
    DFNode *note = WordRunGetNote(get,concrete);
    if (note != NULL)
        return note;

    // If we didn't find a footnote or endnote reference, treat it as a normal content run
    assert(concrete->tag == WORD_R);
    DFNode *rPr = DFChildWithTag(concrete,WORD_RPR);
    CSSProperties *properties = CSSPropertiesNew();
    const char *styleId = NULL;
    if (rPr != NULL)
        WordGetRPr(rPr,properties,&styleId,get->conv->theme);;

    const char *selector = WordSheetSelectorForStyleId(get->conv->styles,"character",styleId);
    Tag elementName = (selector == NULL) ? HTML_SPAN : CSSSelectorGetTag(selector);
    char *className = (selector == NULL) ? NULL : CSSSelectorCopyClassName(selector);
    DFNode *abstract = WordConverterCreateAbstract(get,elementName,concrete);
    DFSetAttribute(abstract,HTML_CLASS,className);
    free(className);

    DFHashTable *collapsed = CSSCollapseProperties(properties);
    char *styleValue = CSSSerializeProperties(collapsed);
    DFHashTableRelease(collapsed);
    if (strlen(styleValue) > 0)
        DFSetAttribute(abstract,HTML_STYLE,styleValue);
    free(styleValue);

    CSSPropertiesRelease(properties);

    WordContainerGet(get,&WordRunContentLens,abstract,concrete);
    return abstract;
}
Esempio n. 15
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);
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
static void adjustMarginLeft(DFNode *element, double adjustPct, int noTextIndent)
{
    if ((element->tag != HTML_TABLE) && !HTML_isParagraphTag(element->tag))
        return;;

    const char *cssText = DFGetAttribute(element,HTML_STYLE);
    CSSProperties *properties = CSSPropertiesNewWithString(cssText);

    double oldMarginLeft = 0;
    if (CSSGet(properties,"margin-left") != NULL) {
        CSSLength length = CSSLengthFromString(CSSGet(properties,"margin-left"));
        if (CSSLengthIsValid(length) && (length.units == UnitsPct))
            oldMarginLeft = length.value;

        if (CSSGet(properties,"width") != NULL) {
            CSSLength length = CSSLengthFromString(CSSGet(properties,"width"));
            if (CSSLengthIsValid(length) && (length.units == UnitsPct)) {
                double oldWidth = length.value;
                double newWidth = oldWidth + oldMarginLeft;
                char buf[100];
                CSSPut(properties,"width",DFFormatDoublePct(buf,100,newWidth));
            }
        }
    }

    double oldTextIndent = 0;
    if (CSSGet(properties,"text-indent") != NULL) {
        CSSLength length = CSSLengthFromString(CSSGet(properties,"text-indent"));
        if (CSSLengthIsValid(length) && (length.units == UnitsPct))
            oldTextIndent = length.value;
    }

    double newMarginLeft = oldMarginLeft + adjustPct;
    double newTextIndent = oldTextIndent;

    if (newMarginLeft < 0)
        newMarginLeft = 0;
    if (fabs(newMarginLeft) >= 0.01) {
        char buf[100];
        CSSPut(properties,"margin-left",DFFormatDoublePct(buf,100,newMarginLeft));
    }
    else {
        CSSPut(properties,"margin-left",NULL);
    }

    if (noTextIndent) {
        CSSPut(properties,"text-indent",NULL);
    }
    else if (newTextIndent < -newMarginLeft) {
        // Don't allow negative text-indent
        newTextIndent = -newMarginLeft;
        if (fabs(newTextIndent) >= 0.01) {
            char buf[100];
            CSSPut(properties,"text-indent",DFFormatDoublePct(buf,100,newTextIndent));
        }
        else {
            CSSPut(properties,"text-indent",NULL);
        }
    }

    char *propertiesText = CSSPropertiesCopyDescription(properties);
    if (strlen(propertiesText) == 0)
        DFRemoveAttribute(element,HTML_STYLE);
    else
        DFSetAttribute(element,HTML_STYLE,propertiesText);
    free(propertiesText);

    CSSPropertiesRelease(properties);
}
Esempio n. 18
0
void WordPutPPr(DFNode *pPr, CSSProperties *properties, const char *styleId, WordSection *section, int outlineLvl)
{
    assert(pPr->tag == WORD_PPR);

    // The child elements of pPr have to be in a specific order. So we build up a structure based
    // on the existing elements (updated as appropriate from newProperties), and then rebuild
    // from that

    CSSProperties *oldp = CSSPropertiesNew();
    CSSProperties *newp = properties;
    const char *oldStyleId = NULL;
    const char *newStyleId = styleId;
    WordGetPPr(pPr,oldp,&oldStyleId,section);

    {
        DFNode *children[PREDEFINED_TAG_COUNT];
        childrenToArray(pPr,children);

        int existingOutlineLvl = -1;
        if (children[WORD_OUTLINELVL] != NULL) {
            const char *value = DFGetAttribute(children[WORD_OUTLINELVL],WORD_VAL);
            if (value != NULL)
                existingOutlineLvl = atoi(value);
        }

        // Style name
        if (!DFStringEquals(oldStyleId,newStyleId)) {
            if (newStyleId != NULL) {
                children[WORD_PSTYLE] = DFCreateElement(pPr->doc,WORD_PSTYLE);
                DFSetAttribute(children[WORD_PSTYLE],WORD_VAL,newStyleId);
            }
            else {
                children[WORD_PSTYLE] = NULL;
            }
        }

        // Paragraph border (pBdr)

        if (children[WORD_PBDR] == NULL)
            children[WORD_PBDR] = DFCreateElement(pPr->doc,WORD_PBDR);

        WordPutPBdr(children[WORD_PBDR],oldp,newp);

        if (children[WORD_PBDR]->first == NULL)
            children[WORD_PBDR] = NULL;

        // Numbering and outline level
        // Don't change these properties for styles with outline level >= 6, as these can't be
        // represented with the standard HTML heading elements, which only go from h1 - h6
        // (outline levels 0 - 5)
        if (existingOutlineLvl < 6) {
            if (children[WORD_NUMPR] == NULL)
                children[WORD_NUMPR] = DFCreateElement(pPr->doc,WORD_NUMPR);

            WordPutNumPr(children[WORD_NUMPR],newp);

            if (children[WORD_NUMPR]->first == NULL)
                children[WORD_NUMPR] = NULL;

            if ((outlineLvl >= 0) && (outlineLvl <= 5)) {
                if (children[WORD_OUTLINELVL] == NULL)
                    children[WORD_OUTLINELVL] = DFCreateElement(pPr->doc,WORD_OUTLINELVL);
                DFFormatAttribute(children[WORD_OUTLINELVL],WORD_VAL,"%d",outlineLvl);
            }
            else {
                children[WORD_OUTLINELVL] = NULL;
            }
        }

        // background-color

        char *oldBackgroundColor = CSSHexColor(CSSGet(oldp,"background-color"),0);
        char *newBackgroundColor = CSSHexColor(CSSGet(newp,"background-color"),0);
        if (!DFStringEquals(oldBackgroundColor,newBackgroundColor))
            WordPutShd(pPr->doc,&children[WORD_SHD],newBackgroundColor);
        free(oldBackgroundColor);
        free(newBackgroundColor);

        // text-align

        if (!DFStringEquals(CSSGet(oldp,"text-align"),CSSGet(newp,"text-align"))) {
            const char *newTextAlign = CSSGet(newp,"text-align");
            if (newTextAlign != NULL) {
                const char *val = NULL;
                if (!strcmp(newTextAlign,"left"))
                    val = "left";
                else if (!strcmp(newTextAlign,"right"))
                    val = "right";
                else if (!strcmp(newTextAlign,"center"))
                    val = "center";
                else if (!strcmp(newTextAlign,"justify"))
                    val = "both";
                if (val != NULL) {
                    children[WORD_JC] = DFCreateElement(pPr->doc,WORD_JC);
                    DFSetAttribute(children[WORD_JC],WORD_VAL,val);
                }
            }
            else {
                children[WORD_JC] = NULL;
            }
        }

        if ((section != NULL) && (WordSectionContentWidth(section) >= 0)) {
            const char *oldMarginLeft = CSSGet(oldp,"margin-left");
            const char *oldMarginRight = CSSGet(oldp,"margin-right");
            const char *oldTextIndent = CSSGet(oldp,"text-indent");
            const char *newMarginLeft = CSSGet(newp,"margin-left");
            const char *newMarginRight = CSSGet(newp,"margin-right");
            const char *newTextIndent = CSSGet(newp,"text-indent");

            // Special case of the List_Paragraph style, which is used by Word to ensure lists are indented. We
            // don't set this property for HTML, because it automatically indents lists. However we need to ensure
            // that it remains unchanged when updating the word document
            const char *newWordMarginLeft = CSSGet(newp,"-word-margin-left");
            if (newMarginLeft == NULL)
                newMarginLeft = newWordMarginLeft;

            if ((newMarginLeft == NULL) && (newMarginRight == NULL) && (newTextIndent == NULL)) {
                children[WORD_IND] = NULL;
            }
            else {
                if (children[WORD_IND] == NULL)
                    children[WORD_IND] = DFCreateElement(pPr->doc,WORD_IND);

                if (!DFStringEquals(oldMarginLeft,newMarginLeft)) {
                    if (newMarginLeft != NULL)
                        updateTwipsFromLength(children[WORD_IND],WORD_LEFT,newMarginLeft,WordSectionContentWidth(section));
                    else
                        DFRemoveAttribute(children[WORD_IND],WORD_LEFT);
                    DFRemoveAttribute(children[WORD_IND],WORD_START);
                }

                if (!DFStringEquals(oldMarginRight,newMarginRight)) {
                    if (newMarginRight != NULL)
                        updateTwipsFromLength(children[WORD_IND],WORD_RIGHT,newMarginRight,WordSectionContentWidth(section));
                    else
                        DFRemoveAttribute(children[WORD_IND],WORD_RIGHT);
                    DFRemoveAttribute(children[WORD_IND],WORD_END);
                }

                if (!DFStringEquals(oldTextIndent,newTextIndent)) {
                    if (newTextIndent != NULL) {
                        CSSLength length = CSSLengthFromString(newTextIndent);

                        if (CSSLengthIsValid(length)) {
                            double pts = CSSLengthToPts(length,WordSectionContentWidthPts(section));
                            int twips = (int)round(pts*20);

                            if (twips >= 0) {
                                DFFormatAttribute(children[WORD_IND],WORD_FIRSTLINE,"%d",twips);
                                DFRemoveAttribute(children[WORD_IND],WORD_HANGING);
                            }
                            else {
                                DFFormatAttribute(children[WORD_IND],WORD_HANGING,"%d",-twips);
                                DFRemoveAttribute(children[WORD_IND],WORD_FIRSTLINE);
                            }
                        }
                    }
                    else {
                        DFRemoveAttribute(children[WORD_IND],WORD_FIRSTLINE);
                        DFRemoveAttribute(children[WORD_IND],WORD_HANGING);
                    }
                }

            }
        }

        if (!DFStringEquals(CSSGet(oldp,"margin-top"),CSSGet(newp,"margin-top")) ||
            !DFStringEquals(CSSGet(oldp,"margin-bottom"),CSSGet(newp,"margin-bottom")) ||
            !DFStringEquals(CSSGet(oldp,"line-height"),CSSGet(newp,"line-height"))) {

            if ((CSSGet(newp,"margin-top") == NULL) &&
                (CSSGet(newp,"margin-bottom") == NULL) &&
                (CSSGet(newp,"line-height") == NULL)) {
                children[WORD_SPACING] = NULL;
            }
            else {
                children[WORD_SPACING] = DFCreateElement(pPr->doc,WORD_SPACING);

                if (DFStringEquals(CSSGet(newp,"margin-top"),"-word-auto")) {
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFORE,"100");
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFOREAUTOSPACING,"1");
                }
                else {
                    char *before = twipsFromCSS(CSSGet(newp,"margin-top"),WordSectionContentWidth(section));
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFORE,before);
                    DFSetAttribute(children[WORD_SPACING],WORD_BEFOREAUTOSPACING,NULL);
                    free(before);
                }

                if (DFStringEquals(CSSGet(newp,"margin-bottom"),"-word-auto")) {
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTER,"100");
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTERAUTOSPACING,"1");
                }
                else {
                    char *after = twipsFromCSS(CSSGet(newp,"margin-bottom"),WordSectionContentWidth(section));
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTER,after);
                    DFSetAttribute(children[WORD_SPACING],WORD_AFTERAUTOSPACING,NULL);
                    free(after);
                }

                CSSLength lineHeight = CSSLengthFromString(CSSGet(newp,"line-height"));
                if (CSSLengthIsValid(lineHeight) && (lineHeight.units == UnitsPct)) {
                    int value = (int)round(lineHeight.value*2.4);
                    DFFormatAttribute(children[WORD_SPACING],WORD_LINE,"%d",value);
                }
                
                if (children[WORD_SPACING]->attrsCount == 0)
                    children[WORD_SPACING] = NULL;
            }
        }
        
        replaceChildrenFromArray(pPr,children,WordPPR_Children);
    }
    CSSPropertiesRelease(oldp);
}
Esempio n. 19
0
int WordConverterUpdateFromHTML(WordConverter *converter, DFError **error)
{
    if (converter->package->document == NULL) {
        DFErrorFormat(error,"document.xml not found");
        return 0;
    }

    DFNode *wordDocument = DFChildWithTag(converter->package->document->docNode,WORD_DOCUMENT);
    if (wordDocument == NULL) {
        DFErrorFormat(error,"word:document not found");
        return 0;
    }

    // FIXME: Need a more reliable way of telling whether this is a new document or not - it could be that the
    // document already existed (with styles set up) but did not have any content
    DFNode *wordBody = DFChildWithTag(wordDocument,WORD_BODY);
    int creating = ((wordBody == NULL) || (wordBody->first == NULL));

    converter->haveFields = Word_simplifyFields(converter->package);
    Word_mergeRuns(converter->package);

    assert(converter->package->styles);

    CSSSheetRelease(converter->styleSheet);
    converter->styleSheet = CSSSheetNew();

    char *cssText = HTMLCopyCSSText(converter->html);
    CSSSheetUpdateFromCSSText(converter->styleSheet,cssText);
    free(cssText);

    addMissingDefaultStyles(converter);
    CSSEnsureReferencedStylesPresent(converter->html,converter->styleSheet);
    if (creating)
        CSSSetHTMLDefaults(converter->styleSheet);
    CSSEnsureUnique(converter->styleSheet,converter->html,creating);

    CSSStyle *pageStyle = CSSSheetLookupElement(converter->styleSheet,"@page",NULL,0,0);
    CSSStyle *bodyStyle = CSSSheetLookupElement(converter->styleSheet,"body",NULL,1,0);
    CSSProperties *page = (pageStyle != NULL) ? CSSPropertiesRetain(CSSStyleRule(pageStyle)) : CSSPropertiesNew();
    CSSProperties *body = (bodyStyle != NULL) ? CSSPropertiesRetain(CSSStyleRule(bodyStyle)) : CSSPropertiesNew();

    if (CSSGet(body,"margin-left") == NULL)
        CSSPut(body,"margin-left","10%");
    if (CSSGet(body,"margin-right") == NULL)
        CSSPut(body,"margin-right","10%");
    if (CSSGet(body,"margin-top") == NULL)
        CSSPut(body,"margin-top","10%");
    if (CSSGet(body,"margin-bottom") == NULL)
        CSSPut(body,"margin-bottom","10%");

    WordSectionUpdateFromCSSPage(converter->mainSection,page,body);

    WordPutData put;
    put.conv = converter;
    put.numIdByHtmlId = DFHashTableNew((DFCopyFunction)strdup,free);
    put.htmlIdByNumId = DFHashTableNew((DFCopyFunction)strdup,free);

    // Make sure we update styles.xml from the CSS stylesheet *before* doing any conversion of the content,
    // since the latter requires a full mapping of CSS selectors to styleIds to be in place.
    WordUpdateStyles(converter,converter->styleSheet);

    Word_preProcessHTMLDoc(converter,converter->html);
    buildListMapFromHTML(&put,converter->html->docNode);
    updateListTypes(&put);
    WordBookmarks_removeCaptionBookmarks(converter->package->document);
    WordObjectsCollapseBookmarks(converter->objects);
    WordObjectsScan(converter->objects);
    Word_setupBookmarkLinks(&put);
    WordObjectsAnalyzeBookmarks(converter->objects,converter->styles);
    WordDocumentLens.put(&put,converter->html->root,wordDocument);
    WordObjectsExpandBookmarks(converter->objects);
    WordRemoveNbsps(converter->package->document);

    // Make sure the updateFields flag is set
    Word_updateSettings(converter->package,converter->haveFields);

    // Remove any abstract numbering definitions that are no longer referenced from concrete
    // numbering definitions
    WordNumberingRemoveUnusedAbstractNums(converter->numbering);

    // Remove any relationships and images that have been removed from the HTML file and no longer
    // have any other references pointing to them
    WordGarbageCollect(converter->package);

    CSSPropertiesRelease(page);
    CSSPropertiesRelease(body);
    DFHashTableRelease(put.numIdByHtmlId);
    DFHashTableRelease(put.htmlIdByNumId);

    return 1;
}