Esempio n. 1
0
CSSStyle *CSSSheetFlattenedStyle(CSSSheet *sheet, CSSStyle *orig)
{
    // FIXME: Need tests for parent cycles
    CSSStyle *ancestor = orig;
    CSSStyle *result = CSSStyleNew("temp");
    DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    const char **allSuffixes = NULL;
    while (1) {
        free(allSuffixes);
        allSuffixes = CSSStyleCopySuffixes(ancestor);
        for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = allSuffixes[suffixIndex];
            CSSProperties *origProperties = CSSStyleRuleForSuffix(ancestor,suffix);
            CSSProperties *collapsedProperties = CSSStyleRuleForSuffix(result,suffix);

            const char **allNames = CSSPropertiesCopyNames(origProperties);
            for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) {
                const char *name = allNames[nameIndex];
                if (!strcmp(name,"-uxwrite-default") && (ancestor != orig))
                    continue;
                if (CSSGet(collapsedProperties,name) == NULL)
                    CSSPut(collapsedProperties,name,CSSGet(origProperties,name));
            }
            free(allNames);
        }
        DFHashTableAdd(visited,ancestor->selector,"");
        ancestor = CSSSheetGetStyleParent(sheet,ancestor);
        if ((ancestor == NULL) || (DFHashTableLookup(visited,ancestor->selector) != NULL))
            break;
    }
    free(allSuffixes);
    DFHashTableRelease(visited);
    return result;
}
Esempio n. 2
0
char *CSSSheetCopyText(CSSSheet *sheet)
{
    DFBuffer *result = DFBufferNew();
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    DFSortStringsCaseInsensitive(allSelectors);
    for (int selIndex = 0; allSelectors[selIndex]; selIndex++) {
        CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[selIndex],0,0);
        DFBufferFormat(result,"%s\n",style->selector);

        const char **sortedSuffixes = CSSStyleCopySuffixes(style);
        DFSortStringsCaseInsensitive(sortedSuffixes);
        for (int suffixIndex = 0; sortedSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = sortedSuffixes[suffixIndex];
            char *quotedSuffix = DFQuote(suffix);
            DFBufferFormat(result,"    %s\n",quotedSuffix);
            free(quotedSuffix);
            CSSProperties *properties = CSSStyleRuleForSuffix(style,suffix);

            const char **sortedNames = CSSPropertiesCopyNames(properties);
            DFSortStringsCaseInsensitive(sortedNames);
            for (int nameIndex = 0; sortedNames[nameIndex]; nameIndex++) {
                const char *name = sortedNames[nameIndex];
                const char *value = CSSGet(properties,name);
                DFBufferFormat(result,"        %s = %s\n",name,value);
            }
            free(sortedNames);
        }
        free(sortedSuffixes);
    }
    free(allSelectors);
    char *str = xstrdup(result->data);
    DFBufferRelease(result);
    return str;
}
Esempio n. 3
0
static void removeRedundantProperties(CSSSheet *sheet)
{
    // Remove any properties set on a style that have the same value as the corresponding property
    // on the parent style. This is necessary because CSS doesn't support style inheritance (in
    // the sense of Word & ODF's styles), so when we save out a HTML file, every style has all
    // properties of its ancestors. After reading in a HTML file for the purposes of updating the
    // original Word or ODF style, we don't want these extra property settings to remain, so that
    // we can avoid adding spurious extra redundant property settings to the original file.

    breakCycles(sheet);
    const char **sortedSelectors = reverseTopologicalSortedSelectors(sheet);

    for (size_t selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *selector = sortedSelectors[selIndex];
        CSSStyle *child = CSSSheetLookupSelector(sheet,selector,0,0);
        CSSStyle *parent = CSSSheetGetStyleParent(sheet,child);
        if (parent == NULL)
            continue;
        const char **allSuffixes = CSSStyleCopySuffixes(child);
        for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = allSuffixes[suffixIndex];
            int isCell = !strcmp(suffix," > * > tr > td");
            CSSProperties *childProperties = CSSStyleRuleForSuffix(child,suffix);
            CSSProperties *parentProperties = CSSStyleRuleForSuffix(parent,suffix);

            const char **allNames = CSSPropertiesCopyNames(childProperties);
            for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) {
                const char *name = allNames[nameIndex];

                // In docx's styles.xml, the tblCellMar values in table styles are not inherited
                // (this seems like a bug in word, as isn't inconsistent with all other properties)
                // So keep these ones.
                if (isCell && DFStringHasPrefix(name,"padding-"))
                    continue;

                const char *childVal = CSSGet(childProperties,name);
                const char *parentVal = CSSGet(parentProperties,name);
                if ((childVal != NULL) && (parentVal != NULL) && DFStringEquals(childVal,parentVal))
                    CSSPut(childProperties,name,NULL);
            }
            free(allNames);
        }
        free(allSuffixes);
    }
    free(sortedSelectors);
}
Esempio n. 4
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. 5
0
DFHashTable *CSSSheetRules(CSSSheet *sheet)
{
    DFHashTable *result = DFHashTableNew((DFCopyFunction)DFHashTableRetain,(DFFreeFunction)DFHashTableRelease);
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int selIndex = 0; allSelectors[selIndex]; selIndex++) {
        const char *selector = allSelectors[selIndex];
        CSSStyle *origStyle = CSSSheetLookupSelector(sheet,selector,0,0);
        if ((origStyle == NULL) || origStyle->latent)
            continue;

        char *elementName = CSSSelectorCopyElementName(selector);
        char *className = CSSSelectorCopyClassName(selector);

        char *baseSelector;
        if (className != NULL) {
            char *escapedClassName = CSSEscapeIdent(className);
            baseSelector = DFFormatString("%s.%s",elementName,escapedClassName);
            free(escapedClassName);
        }
        else {
            baseSelector = xstrdup(elementName);
        }

        CSSStyle *flattenedStyle = CSSSheetFlattenedStyle(sheet,origStyle);
        const char **allSuffixes = CSSStyleCopySuffixes(flattenedStyle);
        for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) {
            const char *suffix = allSuffixes[suffixIndex];
            char *fullSelector = DFFormatString("%s%s",baseSelector,suffix);
            CSSProperties *properties = CSSStyleRuleForSuffix(flattenedStyle,suffix);
            DFHashTable *collapsed = CSSCollapseProperties(properties);
            if (!((DFHashTableCount(collapsed) == 0) && ((strlen(suffix) > 0) || CSSIsBuiltinSelector(selector))))
                DFHashTableAdd(result,fullSelector,collapsed);
            free(fullSelector);
            DFHashTableRelease(collapsed);
        }
        free(allSuffixes);

        CSSStyleRelease(flattenedStyle);
        free(elementName);
        free(className);
        free(baseSelector);
    }
    free(allSelectors);
    return result;
}
static void WordPutStyle(DFNode *concrete, CSSStyle *style, WordConverter *converter)
{
    // If we find a style with a counter-increment value of "<elementname> 0", this means that it's
    // an explicitly unnumbered paragraph. So we set the numbering id to 0, so word doesn't increment
    // the corresponding counter when encountering this style
    if (CSSGet(CSSStyleRule(style),"counter-increment") != NULL) {
        char *zeroIncrement = DFFormatString("%s 0",style->elementName);
        if (DFStringEquals(CSSGet(CSSStyleRule(style),"counter-increment"),zeroIncrement))
            CSSPut(CSSStyleRule(style),"-word-numId","0");
        free(zeroIncrement);
    }

    int outlineLvl = -1;
    if ((style->headingLevel >= 1) && (style->headingLevel <= 6)) {
        outlineLvl = style->headingLevel-1;
        char *nextSelector = CSSStyleCopyNext(style);
        if (nextSelector == NULL) {
            CSSStyle *def = CSSSheetDefaultStyleForFamily(converter->styleSheet,StyleFamilyParagraph);
            if (def != NULL)
                CSSStyleSetNext(style,def->selector);
        }
        free(nextSelector);
    }

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

    char *parentSelector = CSSStyleCopyParent(style);
    if (parentSelector == NULL) {
        if (style->className != NULL) {
            if ((style->tag != HTML_P) && (style->tag != HTML_SPAN) && (style->tag != HTML_TABLE)) {
                CSSStyle *parentStyle = CSSSheetLookupElement(converter->styleSheet,style->elementName,NULL,0,0);
                if ((parentStyle != NULL) && !parentStyle->latent)
                    parentSelector = xstrdup(style->elementName);
            }
        }
    }

    // Based on
    const char *basedOn = WordSheetStyleIdForSelector(converter->styles,parentSelector);
    if (basedOn == NULL) {
        children[WORD_BASEDON] = NULL;
    }
    else {
        children[WORD_BASEDON] = DFCreateElement(concrete->doc,WORD_BASEDON);
        DFSetAttribute(children[WORD_BASEDON],WORD_VAL,basedOn);
    }

    // Style for next paragraph
    children[WORD_NEXT] = NULL;
    char *nextSelector = CSSStyleCopyNext(style);
    if (nextSelector != NULL) {
        StyleFamily thisFamily = WordStyleFamilyForSelector(style->selector);
        StyleFamily nextFamily = WordStyleFamilyForSelector(nextSelector);
        if (nextFamily == thisFamily) {
            children[WORD_NEXT] = DFCreateElement(concrete->doc,WORD_NEXT);
            const char *nextStyleId = WordSheetStyleIdForSelector(converter->styles,nextSelector);
            DFSetAttribute(children[WORD_NEXT],WORD_VAL,nextStyleId);
        }
    }

    if (WordStyleFamilyForSelector(style->selector) == StyleFamilyTable) {
        // Table properties
        if (children[WORD_TBLPR] == NULL)
            children[WORD_TBLPR] = DFCreateElement(concrete->doc,WORD_TBLPR);;
        const char *oldJc = DFGetChildAttribute(children[WORD_TBLPR],WORD_JC,WORD_VAL);
        CSSProperties *wholeTable = CSSStyleRuleForSuffix(style,DFTableSuffixWholeTable);
        WordPutTblPr(children[WORD_TBLPR],wholeTable,CSSStyleCell(style),converter->mainSection,NULL);
        const char *newJc = DFGetChildAttribute(children[WORD_TBLPR],WORD_JC,WORD_VAL);
        if (children[WORD_TBLPR]->first == NULL)
            children[WORD_TBLPR] = NULL;

        if (children[WORD_TRPR] == NULL)
            children[WORD_TRPR] = DFCreateElement(concrete->doc,WORD_TRPR);
        WordPutTrPr(children[WORD_TRPR],oldJc,newJc);
        if (children[WORD_TRPR]->first == NULL)
            children[WORD_TRPR] = NULL;
    }
    else {
        // Paragraph properties
        if (children[WORD_PPR] == NULL)
            children[WORD_PPR] = DFCreateElement(concrete->doc,WORD_PPR);
        WordPutPPr(children[WORD_PPR],CSSStyleRule(style),NULL,converter->mainSection,outlineLvl);
        if (children[WORD_PPR]->first == NULL)
            children[WORD_PPR] = NULL;

        // Run properties
        if (children[WORD_RPR] == NULL)
            children[WORD_RPR] = DFCreateElement(concrete->doc,WORD_RPR);
        WordPutRPr(children[WORD_RPR],CSSStyleRule(style),NULL,converter->theme);
        if (children[WORD_RPR]->first == NULL)
            children[WORD_RPR] = NULL;
    }

    replaceChildrenFromArray(concrete,children,WordStyle_Children);
    free(parentSelector);
    free(nextSelector);
}