Exemplo n.º 1
0
void DFNameMapFree(DFNameMap *map)
{
    DFHashTableRelease(map->namespacesByID);
    DFHashTableRelease(map->namespacesByURI);
    DFHashTableRelease(map->tagsByID);
    DFNameHashTableFree(map->localTagsByNameURI);
    free(map);
}
Exemplo n.º 2
0
void CSSSheetRelease(CSSSheet *sheet)
{
    if ((sheet == NULL) || (--sheet->retainCount > 0))
        return;

    DFHashTableRelease(sheet->_styles);
    DFHashTableRelease(sheet->_defaultStyles);
    free(sheet);
}
Exemplo n.º 3
0
char *CSSPropertiesCopyDescription(CSSProperties *properties)
{
    DFHashTable *collapsed = CSSCollapseProperties(properties);
    char *result = CSSSerializeProperties(collapsed);
    DFHashTableRelease(collapsed);
    return result;
}
Exemplo n.º 4
0
CSSProperties *CSSPropertiesNewWithString(const char *string)
{
    DFHashTable *raw = CSSParseProperties(string);
    CSSProperties *result = CSSPropertiesNewWithRaw(raw);
    DFHashTableRelease(raw);
    return result;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
static char *genImageFilename(const char *mediaDir, const char *extension, DFError **error)
{
    const char **names = DFContentsOfDirectory(mediaDir,0,error);
    if (names == NULL)
        return NULL;

    DFHashTable *existingNames = DFHashTableNew((DFCopyFunction)strdup,free);
    for (int i = 0; names[i]; i++) {
        const char *filename = names[i];
        char *lowerFilename = DFLowerCase(filename);
        char *noExtension = DFPathWithoutExtension(lowerFilename);
        DFHashTableAdd(existingNames,noExtension,noExtension);
        free(lowerFilename);
        free(noExtension);
    }

    int num = 1;
    char *candidate = NULL;
    do {
        free(candidate);
        candidate = DFFormatString("image%d",num);
        num++;
    } while (DFHashTableLookup(existingNames,candidate) != NULL);

    char *result = DFFormatString("%s.%s",candidate,extension);

    free(candidate);
    free(names);
    DFHashTableRelease(existingNames);
    return result;
}
Exemplo n.º 7
0
CSSProperties *CSSPropertiesNewWithExtra(CSSProperties *orig, const char *string)
{
    DFHashTable *extra = CSSParseProperties(string);
    CSSExpandProperties(extra);

    CSSProperties *result = (CSSProperties *)calloc(1,sizeof(CSSProperties));
    result->retainCount = 1;
    result->hashTable = DFHashTableNew((DFCopyFunction)strdup,free);
    const char **names = DFHashTableCopyKeys(orig->hashTable);
    for (int i = 0; names[i]; i++) {
        const char *value = DFHashTableLookup(orig->hashTable,names[i]);
        DFHashTableAdd(result->hashTable,names[i],(void *)value);
    }
    free(names);

    const char **keys = DFHashTableCopyKeys(extra);
    for (int i = 0; keys[i]; i++) {
        const char *key = keys[i];
        const char *value = DFHashTableLookup(extra,key);
        DFHashTableAdd(result->hashTable,key,value);
    }
    free(keys);

    DFHashTableRelease(extra);
    return result;
}
Exemplo n.º 8
0
char *CSSSheetCopyCSSText(CSSSheet *sheet)
{
    DFHashTable *hashRules = CSSSheetRules(sheet);
    char *cssText = CSSCopyStylesheetTextFromRules(hashRules);
    DFHashTableRelease(hashRules);
    return cssText;
}
Exemplo n.º 9
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;
}
Exemplo n.º 10
0
void WordGarbageCollect(WordPackage *package)
{
    assert(package->documentPart != NULL);
    assert(package->document != NULL);
    DFHashTable *referencedIds = DFHashTableNew(NULL,NULL); // used as a set
    collect(package,referencedIds);
    DFHashTableRelease(referencedIds);
}
Exemplo n.º 11
0
void WordBookmarks_collapseNew(DFDocument *doc)
{
    putInParagraphsRecursive(doc->docNode);
    DFHashTable *bookmarksById = DFHashTableNew(NULL,(DFFreeFunction)WordRawBookmarkFree);
    int offset = 0;
    findBookmarkSizes(doc->root,bookmarksById,&offset);
    collapseRecursive(doc->root,bookmarksById);
    DFHashTableRelease(bookmarksById);
}
Exemplo n.º 12
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);
    }
}
Exemplo n.º 13
0
void ODFManifestRelease(ODFManifest *manifest)
{
    if ((manifest == NULL) || (--manifest->retainCount > 0))
        return;

    DFDocumentRelease(manifest->doc);
    DFHashTableRelease(manifest->entriesByPath);
    free(manifest);
}
Exemplo n.º 14
0
void CSSPropertiesUpdateFromRaw(CSSProperties *properties, DFHashTable *raw)
{
    DFHashTableRelease(properties->hashTable);
    properties->hashTable = DFHashTableCopy(raw);
    CSSExpandProperties(properties->hashTable);
    if (!properties->dirty) // Minimise KVO notifications
        properties->dirty = 1;
    DFCallbackInvoke(properties->changeCallbacks,properties,NULL);
}
void DFMarkupCompatibilityPop(DFMarkupCompatibility *mc)
{
    assert(mc->depth > 0);
    if (mc->depth < MAX_DEPTH) {
        MCRecord *record = &mc->records[mc->depth-1];
        free(record->decls);
        DFHashTableRelease(record->namespaces);
    }
    mc->depth--;
}
Exemplo n.º 16
0
void CSSPropertiesRelease(CSSProperties *properties)
{
    assert((properties == NULL) || (properties->retainCount > 0));
    if ((properties == NULL) || (--properties->retainCount > 0))
        return;

    assert(properties->changeCallbacks == NULL);
    DFHashTableRelease(properties->hashTable);
    free(properties);
}
Exemplo n.º 17
0
void TextPackageRelease(TextPackage *package)
{
    if ((package == NULL) || (--package->retainCount > 0))
        return;

    for (int i = 0; i < package->nkeys; i++)
        free(package->keys[i]);
    free(package->keys);
    DFHashTableRelease(package->items);
    free(package);
}
Exemplo n.º 18
0
void CSSSheetUpdateFromCSSText(CSSSheet *sheet, const char *cssText)
{
    DFHashTable *rules = DFHashTableNew((DFCopyFunction)DFHashTableRetain,(DFFreeFunction)DFHashTableRelease);

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

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

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

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

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

        DFHashTableRelease(properties);
        DFArrayRelease(selectors);
    }

    updateFromRawCSSRules(sheet,rules);
    free(allSelectorsText);
    DFHashTableRelease(top);
    DFHashTableRelease(rules);
}
Exemplo n.º 19
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);
}
Exemplo n.º 20
0
DFHashTable *CSSParserProperties(CSSParser *p)
{
    DFHashTable *result = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    while (p->pos < p->length) {
        size_t start = p->pos;
        int invalid = 0;
        if (!matchBefore(p,':',&invalid)) {
            DFHashTableRelease(result);
            return NULL;
        }
        char *name = trimmedSubstring(p,start,p->pos);
        if (strlen(name) == 0) {
            free(name);
            break;
        }
        if (!match(p,':')) {
            CSSParserSetError(p,"Missing :");
            DFHashTableRelease(result);
            free(name);
            return NULL;
        }
        start = p->pos;
        if (!matchBefore(p,';',&invalid)) {
            DFHashTableRelease(result);
            free(name);
            return NULL;
        }
        if (!invalid) {
            char *value = trimmedSubstring(p,start,p->pos);
            DFHashTableAdd(result,name,value);
            free(value);
        }
        match(p,';');
        free(name);
    }
    return result;
}
Exemplo n.º 21
0
void DFDocumentRelease(DFDocument *doc)
{
    if (doc == NULL)
        return;
    assert(doc->retainCount > 0);
    doc->retainCount--;
    if (doc->retainCount == 0) {
        DFHashTableRelease(doc->nodesByIdAttr);
        DFClearSeqNoHash(doc);
        for (size_t i = 0; i < doc->nodesCount; i++)
            free(doc->nodes[i]->attrs);
        free(doc->nodes);
        DFNameMapFree(doc->map);
        DFAllocatorFree(doc->allocator);
        free(doc);
    }
}
Exemplo n.º 22
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;
}
Exemplo n.º 23
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;
}
Exemplo n.º 24
0
static char *Word_toPlainFromDir(DFStorage *storage, DFHashTable *parts, DFError **error)
{
    char *documentPath = NULL;
    DFHashTable *rels = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
    DFBuffer *output = DFBufferNew();
    char *relsPathRel = NULL;
    DFDocument *relsDoc = NULL;
    int ok = 0;


    documentPath = findDocumentPath(storage,error);
    if (documentPath == NULL) {
        DFErrorFormat(error,"findDocumentPath: %s",DFErrorMessage(error));
        goto end;
    }

    relsPathRel = computeDocumentRelsPath(documentPath);
    if (DFStorageExists(storage,relsPathRel) && ((relsDoc = DFParseXMLStorage(storage,relsPathRel,error)) == NULL)) {
        DFErrorFormat(error,"%s: %s",relsPathRel,DFErrorMessage(error));
        goto end;
    }

    parseDocumentRels(documentPath,relsDoc,rels,error);

    if (!processParts(parts,documentPath,relsDoc,rels,output,storage,error))
        goto end;

    ok = 1;

end:
    free(relsPathRel);
    free(documentPath);
    DFHashTableRelease(rels);
    DFDocumentRelease(relsDoc);
    if (!ok) {
        DFBufferRelease(output);
        return NULL;
    }
    else {
        char *result = xstrdup(output->data);
        DFBufferRelease(output);
        return result;
    }
}
Exemplo n.º 25
0
void WordConverterFree(WordConverter *converter)
{
    DFDocumentRelease(converter->html);
    free(converter->abstractPath);
    free(converter->concretePath);
    free(converter->idPrefix);
    WordSheetFree(converter->styles);
    WordNumberingFree(converter->numbering);
    WordThemeFree(converter->theme);
    WordSectionFree(converter->mainSection);
    WordObjectsFree(converter->objects);
    WordNoteGroupRelease(converter->footnotes);
    WordNoteGroupRelease(converter->endnotes);
    DFHashTableRelease(converter->supportedContentTypes);
    DFBufferRelease(converter->warnings);
    CSSSheetRelease(converter->styleSheet);
    WordPackageRelease(converter->package);
    free(converter);
}
Exemplo n.º 26
0
static void breakCycles(CSSSheet *sheet)
{
    // FIXME: Not covered by tests
    const char **allSelectors = CSSSheetCopySelectors(sheet);
    for (int i = 0; allSelectors[i]; i++) {
        const char *selector = allSelectors[i];
        CSSStyle *style = CSSSheetLookupSelector(sheet,selector,0,0);
        DFHashTable *visited = DFHashTableNew((DFCopyFunction)xstrdup,(DFFreeFunction)free);
        int depth = 0;

        while (style != NULL) {
            if (DFHashTableLookup(visited,style->selector) != NULL) {
                CSSStyleSetParent(style,NULL);
                break;
            }
            DFHashTableAdd(visited,style->selector,"");
            style = CSSSheetGetStyleParent(sheet,style);
            depth++;
        }
        DFHashTableRelease(visited);
    }
    free(allSelectors);
}
Exemplo n.º 27
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;
}
Exemplo n.º 28
0
void WordUpdateStyles(WordConverter *converter, CSSSheet *styleSheet)
{
    CSSStyle *paraDefault = CSSSheetDefaultStyleForFamily(styleSheet,StyleFamilyParagraph);
    if (CSSGet(CSSStyleRule(paraDefault),"margin-top") == NULL)
        CSSPut(CSSStyleRule(paraDefault),"margin-top","-word-auto");

    if (CSSGet(CSSStyleRule(paraDefault),"margin-bottom") == NULL)
        CSSPut(CSSStyleRule(paraDefault),"margin-bottom","-word-auto");

    if (converter->package->styles == NULL) // FIXME: create this document
        return;;
    DFNode *root = converter->package->styles->root;
    if ((root == NULL) || (root->tag != WORD_STYLES))
        return;;

    DFHashTable *remainingSelectors = DFHashTableNew(NULL,NULL); // Used as a set
    const char **allSelectors = CSSSheetCopySelectors(styleSheet);
    for (int i = 0; allSelectors[i]; i++) {
        const char *selector = allSelectors[i];
        DFHashTableAdd(remainingSelectors,selector,"");
    }
    free(allSelectors);

    WordSheet *sheet = converter->styles;
    DFHashTable *oldConcreteNumIds = WordSheetFindUsedConcreteNumIds(sheet);
    updateNumbering(converter,styleSheet);

    // Update or remove existing styles
    const char **allIdents = WordSheetCopyIdents(sheet);
    for (int i = 0; allIdents[i]; i++) {
        WordStyle *wordStyle = WordSheetStyleForIdent(sheet,allIdents[i]);
        DFNode *element = wordStyle->element;

        if (WordStyleIsProtected(wordStyle)) {
            DFHashTableRemove(remainingSelectors,wordStyle->selector);
            continue;
        }

        if (!DFStringEquals(wordStyle->type,"paragraph") &&
            !DFStringEquals(wordStyle->type,"character") &&
            !DFStringEquals(wordStyle->type,"table"))
            continue;

        CSSStyle *cssStyle = CSSSheetLookupSelector(styleSheet,wordStyle->selector,0,0);
        if (cssStyle == NULL) {
            // Remove style
            WordSheetRemoveStyle(sheet,wordStyle);
            continue;
        }

        // Update style
        WordPutStyle(element,cssStyle,converter);
        updateDefault(cssStyle,element,styleSheet,converter);
        DFHashTableRemove(remainingSelectors,wordStyle->selector);
    }
    free(allIdents);

    // Sort the list of new styles, so that test output is deterministic
    const char **sortedSelectors = DFHashTableCopyKeys(remainingSelectors);
    DFSortStringsCaseInsensitive(sortedSelectors);

    // Add new styles. We do this in two stages - first creating the styles, and then setting their properties.
    // This is because the second stage depends on referenced styles (e.g. based on and next) to be already
    // present.
    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *selector = sortedSelectors[selIndex];
        CSSStyle *style = CSSSheetLookupSelector(styleSheet,selector,0,0);
        const char *familyStr = NULL;

        StyleFamily family = WordStyleFamilyForSelector(selector);
        if (family == StyleFamilyParagraph)
            familyStr = "paragraph";
        else if (family == StyleFamilyCharacter)
            familyStr = "character";
        else if (family == StyleFamilyTable)
            familyStr = "table";
        else
            continue;

        char *styleId = WordStyleIdForStyle(style);
        char *name = WordStyleNameForStyle(style);
        if (name == NULL)
            name = xstrdup(styleId);;
        WordStyle *wordStyle = WordSheetAddStyle(sheet,familyStr,styleId,name,selector);
        DFCreateChildElement(wordStyle->element,WORD_QFORMAT);
        free(styleId);
        free(name);
    }

    for (int selIndex = 0; sortedSelectors[selIndex]; selIndex++) {
        const char *selector = sortedSelectors[selIndex];
        StyleFamily family = WordStyleFamilyForSelector(selector);
        if ((family != StyleFamilyParagraph) &&
            (family != StyleFamilyCharacter) &&
            (family != StyleFamilyTable))
            continue;

        CSSStyle *style = CSSSheetLookupSelector(styleSheet,selector,0,0);
        WordStyle *wordStyle = WordSheetStyleForSelector(converter->styles,selector);
        assert(wordStyle != NULL);

        CSSStyleAddDefaultHTMLProperties(style);
        // FIXME: language
        // FIXME: not covered by tests
        if ((style->headingLevel >= 1) && (style->headingLevel <= 6))
            CSSStyleSetNext(style,"p.Normal");

        WordPutStyle(wordStyle->element,style,converter);
        updateDefault(style,wordStyle->element,styleSheet,converter);
    }
    free(sortedSelectors);

    // Update body style (document defaults)
    updateDefaults(converter,styleSheet);

    updateBody(converter,styleSheet);

    DFHashTable *newConcreteNumIds = WordSheetFindUsedConcreteNumIds(sheet);
    const char **oldKeys = DFHashTableCopyKeys(oldConcreteNumIds);
    for (int oldIndex = 0; oldKeys[oldIndex]; oldIndex++) {
        const char *numId = oldKeys[oldIndex];
        if (DFHashTableLookup(newConcreteNumIds,numId) == NULL) {
            WordConcreteNum *concreteNum = WordNumberingConcreteWithId(converter->numbering,numId);
            if (concreteNum != NULL)
                WordNumberingRemoveConcrete(converter->numbering,concreteNum);
        }
    }
    free(oldKeys);
    DFHashTableRelease(remainingSelectors);
    DFHashTableRelease(oldConcreteNumIds);
    DFHashTableRelease(newConcreteNumIds);
}
Exemplo n.º 29
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;
        }
    }
}
Exemplo n.º 30
0
void Word_setupBookmarkLinks(WordPutData *put)
{
    DFHashTable *referencesById = findReferences(put->conv->html);
    const char **sortedIds = DFHashTableCopyKeys(referencesById);
    DFSortStringsCaseSensitive(sortedIds);
    for (int idIndex = 0; sortedIds[idIndex]; idIndex++) {
        const char *targetId = sortedIds[idIndex];
        DFArray *references = DFHashTableLookup(referencesById,targetId);
        DFNode *targetElem = DFElementForIdAttr(put->conv->html,targetId);
        if (targetElem == NULL)
            continue;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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