Пример #1
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;
}
Пример #2
0
static OPCRelationship *addImageRelationship(WordConverter *converter, const char *src, DFError **error)
{
    const char *mediaDir = DFAppendPathComponent(converter->concretePath,"word/media");

    if (!DFFileExists(mediaDir) && !DFCreateDirectory(mediaDir,1,error))
        return NULL;

    char *ext = DFPathExtension(src);
    char *filename = genImageFilename(mediaDir,ext,error);
    free(ext);
    if (filename == NULL)
        return NULL;

    char *abstractPathSlash = DFFormatString("%s/",converter->abstractPath);
    char *unescapedSrc = DFRemovePercentEncoding(src);
    char *srcPath = DFPathResolveAbsolute(abstractPathSlash,unescapedSrc);
    char *destPath = DFAppendPathComponent(mediaDir,filename);

    OPCRelationship *result = NULL;
    if (DFCopyFile(srcPath,destPath,error)) {
        OPCRelationshipSet *rels = converter->package->documentPart->relationships;
        char *relPath = DFFormatString("/word/media/%s",filename);
        result = OPCRelationshipSetAddType(rels,WORDREL_IMAGE,relPath,0);
        free(relPath);
    }

    free(filename);
    free(abstractPathSlash);
    free(unescapedSrc);
    free(srcPath);
    free(destPath);
    return result;
}
Пример #3
0
DFNode *WordConverterCreateAbstract(WordGetData *get, Tag tag, DFNode *concrete)
{
    DFNode *element = DFCreateElement(get->conv->html,tag);
    if (concrete != NULL) {
        char *idStr;
        if (concrete->doc == get->conv->package->document)
            idStr = DFFormatString("%s%u",get->conv->idPrefix,concrete->seqNo);
        else
            idStr = DFFormatString("%s%u-%s",get->conv->idPrefix,concrete->seqNo,DFNodeName(concrete->doc->root));
        DFSetAttribute(element,HTML_ID,idStr);
        free(idStr);
    }
    return element;
}
Пример #4
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;
}
Пример #5
0
static char *computeDocumentRelsPath(const char *documentPath)
{
    char *documentParent = DFPathDirName(documentPath);
    char *documentFilename = DFPathBaseName(documentPath);
    char *documentRelsPath = DFFormatString("%s/_rels/%s.rels",documentParent,documentFilename);
    free(documentParent);
    free(documentFilename);
    return documentRelsPath;
}
Пример #6
0
char *Word_toPlain(DFStorage *rawStorage, DFHashTable *parts)
{
    DFError *error = NULL;
    char *result = Word_toPlainFromDir(rawStorage,parts,&error);
    if (result == NULL) {
        result = DFFormatString("%s\n",DFErrorMessage(&error));
        DFErrorRelease(error);
    }
    return result;
}
Пример #7
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);
}
Пример #8
0
static int getImageFile(WordConverter *converter, const char *src, PixelSize *size)
{
    size->widthPx = 0;
    size->heightPx = 0;

    char *unescapedSrc = DFRemovePercentEncoding(src);
    char *abstractPathSlash = DFFormatString("%s/",converter->abstractPath);
    char *newSrcPath = DFPathResolveAbsolute(abstractPathSlash,unescapedSrc);

    int ok = DFPlatformGetImageDimensions(newSrcPath,&size->widthPx,&size->heightPx);
    free(abstractPathSlash);
    free(unescapedSrc);
    free(newSrcPath);
    return ok;
}
Пример #9
0
static void disableNumberingForStyle(CSSStyle *style, int explicitly)
{
    CSSProperties *rule = CSSStyleRule(style);
    CSSProperties *before = CSSStyleBefore(style);
    if (explicitly) {
        // FIXME: Not covered by tests
        char *increment = DFFormatString("h%d 0",style->headingLevel);
        CSSPut(rule,"counter-increment",increment);
        CSSPut(rule,"counter-reset","null");
        CSSPut(before,"content","\"\"");
        style->latent = 0;
        free(increment);
    }
    else {
        CSSPut(rule,"counter-increment",NULL);
        CSSPut(rule,"counter-reset",NULL);
        CSSPut(before,"content",NULL);
    }
}
Пример #10
0
static void parseDocumentRels(const char *documentPath, DFDocument *relsDoc, DFHashTable *rels, DFError **error)
{
    if (relsDoc == NULL)
        return;;
    const char *basePrefix = (documentPath[0] == '/') ? "" : "/";
    char *basePath = DFFormatString("%s%s",basePrefix,documentPath);
    for (DFNode *child = relsDoc->root->first; child != NULL; child = child->next) {
        if (child->tag != REL_RELATIONSHIP)
            continue;
        const char *type = DFGetAttribute(child,NULL_Type);
        const char *target = DFGetAttribute(child,NULL_TARGET);
        if ((type == NULL) || (target == NULL))
            continue;

        char *absTarget = DFPathResolveAbsolute(basePath,target);
        DFHashTableAdd(rels,type,absTarget);
        free(absTarget);
    }
    free(basePath);
}
Пример #11
0
DFNode *WordDrawingGet(WordGetData *get, DFNode *concrete)
{
    ImageInfo *info = getImageInfo(concrete);
    if (info == NULL)
        return createAbstractPlaceholder(get,"[Unsupported object]",concrete);

    int validFileType = 0;

    const char *filename = WordPackageTargetForDocumentRel(get->conv->package,info->rId);
    if (filename != NULL) {
        char *origExtension = DFPathExtension(filename);
        char *lowerExtension = DFLowerCase(origExtension);
        if (DFHashTableLookup(get->conv->supportedContentTypes,lowerExtension) != NULL)
            validFileType = 1;
        free(origExtension);
        free(lowerExtension);
    }

    DFNode *result = NULL;
    if (!validFileType) {
        if (info->progId != NULL) {
            char *message = DFFormatString("[Unsupported object: %s]",info->progId);
            DFNode *placeholder = createAbstractPlaceholder(get,message,concrete);
            free(message);
            result = placeholder;
        }
        else {
            result = createAbstractPlaceholder(get,"[Unsupported object]",concrete);
        }

    }

    if (result == NULL)
        result = imageWithFilename(get,filename,info->widthPts,concrete);

    ImageInfoFree(info);
    return result;
}
Пример #12
0
static void fixWordLists(DFNode *node, WordConverter *conv)
{
    for (DFNode *child = node->first; child != NULL; child = child->next)
        fixWordLists(child,conv);

    int haveParagraphs = 0;
    for (DFNode *child = node->first; child != NULL; child = child->next) {
        if (child->tag == WORD_P) {
            haveParagraphs = 1;
            break;
        }
    }

    if (!haveParagraphs)
        return;

    int createdHashTables = 0;
    DFHashTable *replacementNumIds = NULL;
    DFHashTable *itemNoByListKey = NULL;
    DFHashTable *lastNumIdByIlvl = NULL;
    DFHashTable *itemNoByIlvl = NULL;
    int maxIlvl = -1;

    for (DFNode *child = node->first; child != NULL; child = child->next) {
        if (child->tag != WORD_P)
            continue;
        DFNode *pPrElem = DFChildWithTag(child,WORD_PPR);
        DFNode *numPrElem = DFChildWithTag(pPrElem,WORD_NUMPR);
        DFNode *numIdElem = DFChildWithTag(numPrElem,WORD_NUMID);
        DFNode *ilvlElem = DFChildWithTag(numPrElem,WORD_ILVL);
        const char *numId = DFGetAttribute(numIdElem,WORD_VAL);
        const char *ilvl = DFGetAttribute(ilvlElem,WORD_VAL);

        if ((numId == NULL) || (atoi(numId) == 0))
            continue;

        if (!createdHashTables) {
            replacementNumIds = DFHashTableNew((DFCopyFunction)xstrdup,free);
            itemNoByListKey = DFHashTableNew((DFCopyFunction)xstrdup,free);
            lastNumIdByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
            itemNoByIlvl = DFHashTableNew((DFCopyFunction)xstrdup,free);
            createdHashTables = 1;
        }

        if (ilvl == NULL)
            ilvl = "0";;

        WordConcreteNum *concreteNum = WordNumberingConcreteWithId(conv->numbering,numId); // may be NULL
        WordNumLevel *numLevel = WordConcreteNumGetLevel(concreteNum,atoi(ilvl)); // may be NULL

        const char *levelStart = NULL;

        if (numLevel != NULL) {
            for (DFNode *lvlChild = numLevel->element->first; lvlChild != NULL; lvlChild = lvlChild->next) {
                switch (lvlChild->tag) {
                    case WORD_START:
                        levelStart = DFGetAttribute(lvlChild,WORD_VAL);
                        break;
                }
            }
        }

        char *listKey = DFFormatString("%s:%s",numId,ilvl);
        char *itemNo = DFStrDup(DFHashTableLookup(itemNoByListKey,listKey));
        if (itemNo == NULL) {
            itemNo = xstrdup("1");

            if ((levelStart != NULL) && (atoi(levelStart) > 1) && (atoi(ilvl) <= maxIlvl)) {
                const char *prevNumId = DFHashTableLookup(lastNumIdByIlvl,ilvl);
                const char *prevItemNo = DFHashTableLookup(itemNoByIlvl,ilvl);

                if ((prevNumId != NULL) && (prevItemNo != NULL)) {
                    DFHashTableAdd(replacementNumIds,numId,prevNumId);
                    free(itemNo);
                    itemNo = DFFormatString("%d",atoi(prevItemNo)+1);
                }
            }
        }
        else {
            int intValue = atoi(itemNo);
            free(itemNo);
            itemNo = DFFormatString("%d",intValue+1);
        }
        DFHashTableAdd(itemNoByListKey,listKey,itemNo);

        const char *replNumId = DFHashTableLookup(replacementNumIds,numId);
        if (replNumId != NULL) {
            numId = replNumId;
            DFSetAttribute(numIdElem,WORD_VAL,numId);
        }

        DFHashTableAdd(lastNumIdByIlvl,ilvl,numId);
        DFHashTableAdd(itemNoByIlvl,ilvl,itemNo);
        maxIlvl = atoi(ilvl);
        free(listKey);
        free(itemNo);
    }
    DFHashTableRelease(replacementNumIds);
    DFHashTableRelease(itemNoByListKey);
    DFHashTableRelease(lastNumIdByIlvl);
    DFHashTableRelease(itemNoByIlvl);
}
Пример #13
0
static void populateDrawingElement(WordConverter *converter, DFNode *root, double widthPts,
                                   double heightPts, const char *drawingId, const char *rId)
{
    EMUSize size;
    size.widthEmu = round(widthPts*EMUS_PER_POINT);
    size.heightEmu = round(heightPts*EMUS_PER_POINT);

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

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

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

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

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

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

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

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

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


    (void)cNvPicPr;
    (void)fillRect;
    free(docName);
}
Пример #14
0
static int processParts(DFHashTable *parts, const char *documentPath, DFDocument *relsDoc,
                        DFHashTable *documentRels,
                        DFBuffer *output, DFStorage *storage, DFError **error)
{
    int ok = 0;
    DFHashTable *includeTypes = DFHashTableNew((DFCopyFunction)xstrdup,free);
    DFHashTableAdd(includeTypes,WORDREL_HYPERLINK,"");
    DFHashTableAdd(includeTypes,WORDREL_IMAGE,"");

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

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

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

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

    ok = 1;

end:
    return ok;
}
Пример #15
0
// FIXME: This won't work now for Word documents, where styles always have class names
// FIXME: Not covered by tests
void CSSSheetSetHeadingNumbering(CSSSheet *sheet, int enabled)
{
    CSSStyle *defaultStyle = CSSSheetDefaultStyleForFamily(sheet,StyleFamilyParagraph);

    if (enabled) {
        DFHashTable *stylesByHeadingLevel = getStylesByHeadingLevel(sheet);
        for (int level = 1; level <= 6; level++) {

            StyleList *styles = DFHashTableLookupInt(stylesByHeadingLevel,level);
            int haveClassless = 0;

            for (StyleList *item = styles; item != NULL; item = item->next) {
                if (item->style->className == NULL)
                    haveClassless = 1;
            }

            // If there exists a style at level n which has no class name, then that is the parent of all other
            // heading styles. Set the numbering on that. Alternatively, if there no styles exist at level n, then
            // create a new one with no class name, and set the numbering information on that.
            if ((styles == NULL) || haveClassless) {
                char *elementName = DFFormatString("h%d",level);
                CSSStyle *style = CSSSheetLookupElement(sheet,elementName,NULL,1,0);
                enableNumberingForStyle(style);
                free(elementName);
            }
            else {
                // There are multiple heading styles at level n, all of which have a class name associated with them.
                // Set the numbering information on those which either have no parentId, or whose parentId is the
                // default paragraph style. This caters for situations like the "HeadingXUnnumbered" styles we used
                // to have, which were based on the corresponding "HeadingX" style.
                for (StyleList *item = styles; item != NULL; item = item->next) {
                    char *parentSelector = CSSStyleCopyParent(item->style);
                    if ((parentSelector == NULL) || !strcmp(parentSelector,defaultStyle->selector)) {
                        enableNumberingForStyle(item->style);
                    }
                    else {
                        disableNumberingForStyle(item->style,1);
                    }
                    free(parentSelector);
                }
            }

            StyleList *next;
            for (; styles != NULL; styles = next) {
                next = styles->next;
                CSSStyleRelease(styles->style);
                free(styles);
            }
        }
        DFHashTableRelease(stylesByHeadingLevel);
    }
    else {
        // Clear all numbering information on all heading styles
        const char **allSelectors = CSSSheetCopySelectors(sheet);
        for (int i = 0; allSelectors[i]; i++) {
            CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[i],0,0);
            if (style->headingLevel > 0) {
                CSSPut(CSSStyleRule(style),"counter-increment",NULL);
                CSSPut(CSSStyleRule(style),"counter-reset",NULL);
                CSSPut(CSSStyleBefore(style),"content",NULL);
            }
        }
        free(allSelectors);
    }
}
Пример #16
0
static void WordGetStyle(DFNode *concrete, CSSStyle *style, WordConverter *converter)
{
    WordSection *section = converter->mainSection;
    for (DFNode *child = concrete->first; child != NULL; child = child->next) {
        const char *styleId = NULL;
        switch (child->tag) {
            case WORD_NAME:
                CSSStyleSetDisplayName(style,DFGetAttribute(child,WORD_VAL));
                break;
            case WORD_NEXT: {
                // FIXME: do he need to handle style types other than paragraph here?
                const char *nextName = DFGetAttribute(child,WORD_VAL);
                if (nextName == NULL)
                    continue;
                WordStyle *nextStyle = WordSheetStyleForTypeId(converter->styles,"paragraph",nextName);
                if (nextStyle == NULL)
                    continue;
                CSSStyleSetNext(style,nextStyle->selector);
                break;
            }
            case WORD_RPR:
                WordGetRPr(child,CSSStyleRule(style),&styleId,converter->theme);
                break;
            case WORD_PPR: {
                WordGetPPr(child,CSSStyleRule(style),&styleId,section);
                if (style->headingLevel > 0) {
                    DFNode *numPr = DFChildWithTag(child,WORD_NUMPR);
                    if (numPr != NULL)
                        WordGetNumPrStyle(numPr,style,converter);
                }
                break;
            }
            case WORD_TBLPR:
                WordGetTblPr(child,CSSStyleRule(style),CSSStyleCell(style),section,&styleId);
                break;
            case WORD_TRPR:
                // FIXME
                break;
            case WORD_TCPR:
                WordGetTcPr(child,CSSStyleRule(style));
                break;
            case WORD_TBLSTYLEPR:
                WordGetTblStylePr(child,style,section,converter->theme);
                break;
        }
    }

    // Special case: The ListParagraph style that word automatically adds specifies an indentation
    // of 36pt. We don't actually want this, because HTML automatically indents lists anyway. If
    // we see this, clear it, but keep the old value around for when we update the word document.
    StyleFamily family = WordStyleFamilyForSelector(style->selector);
    const char *name = WordSheetStyleIdForSelector(converter->styles,style->selector);
    if ((family == StyleFamilyParagraph) && DFStringEquals(name,"ListParagraph")) {
        CSSProperties *properties = CSSStyleRule(style);
        const char *wordMarginLeft = CSSGet(properties,"margin-left");
        CSSPut(properties,"-word-margin-left",wordMarginLeft);
        CSSPut(properties,"margin-left",NULL);
    }

    DFNode *pPr = DFChildWithTag(concrete,WORD_PPR);
    DFNode *numPr = DFChildWithTag(pPr,WORD_NUMPR);
    const char *numId = DFGetChildAttribute(numPr,WORD_NUMID,WORD_VAL);
    if ((numId != NULL) && (atoi(numId) == 0)) {
        switch (style->tag) {
            case HTML_H1:
            case HTML_H2:
            case HTML_H3:
            case HTML_H4:
            case HTML_H5:
            case HTML_H6:
            case HTML_FIGURE:
            case HTML_TABLE: {
                char *counterIncrement = DFFormatString("%s 0",style->elementName);
                CSSPut(CSSStyleRule(style),"counter-reset","null");
                CSSPut(CSSStyleRule(style),"counter-increment",counterIncrement);
                CSSPut(CSSStyleBefore(style),"content","none");
                free(counterIncrement);
            }
        }
    }
}
Пример #17
0
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);
}
Пример #18
0
char *WordStyleIdForStyle(CSSStyle *style)
{
    const char *selector = style->selector;
    char *resStyleId = NULL;

    if (!strcmp(selector,"table.Normal_Table"))
        return strdup("TableNormal");
    if (!strcmp(selector,"table.Table_Grid"))
        return strdup("TableGrid");
    if (!strcmp(selector,"span.Default_Paragraph_Font"))
        return strdup("DefaultParagraphFont");
    if (!strcmp(selector,"p.List_Paragraph"))
        return strdup("ListParagraph");

    int headingLevel = CSSSelectorHeadingLevel(selector);
    if (headingLevel != 0) {
        char *prefix = DFFormatString("heading_%d",headingLevel);
        if ((style->className != NULL) && DFStringHasPrefix(style->className,prefix)) {
            char *rest = DFSubstring(style->className,strlen(prefix),strlen(style->className));
            char *result = DFFormatString("Heading%d%s",headingLevel,rest);
            free(rest);
            free(prefix);
            return result;
        }
        free(prefix);
    }

    if (!strcmp(selector,"span.Heading1Char"))
        return strdup("Heading1Char");
    if (!strcmp(selector,"span.Heading2Char"))
        return strdup("Heading2Char");
    if (!strcmp(selector,"span.Heading3Char"))
        return strdup("Heading3Char");
    if (!strcmp(selector,"span.Heading4Char"))
        return strdup("Heading4Char");
    if (!strcmp(selector,"span.Heading5Char"))
        return strdup("Heading5Char");
    if (!strcmp(selector,"span.Heading6Char"))
        return strdup("Heading6Char");
    if (!strcmp(selector,"span.Heading7Char"))
        return strdup("Heading7Char");
    if (!strcmp(selector,"span.Heading8Char"))
        return strdup("Heading8Char");
    if (!strcmp(selector,"span.Heading9Char"))
        return strdup("Heading9Char");

    char *className = CSSSelectorCopyClassName(selector);
    switch (CSSSelectorGetTag(selector)) {
        case HTML_FIGURE: {
            resStyleId = DFStrDup("Figure");
            break;
        }
        case HTML_CAPTION: {
            resStyleId = DFStrDup("Caption");
            break;
        }
        case HTML_H1:
        case HTML_H2:
        case HTML_H3:
        case HTML_H4:
        case HTML_H5:
        case HTML_H6: {
            if ((className == NULL) || (strlen(className) == 0)) {
                int level = CSSSelectorHeadingLevel(selector);
                if ((level >= 1) && (level <= 6)) {
                    // FIXME: we shouldn't rely on the specific word "Heading" here - instead using the localised name
                    // FIXME: not covered by tests
                    resStyleId = DFFormatString("Heading%d",level);
                }
            }
            else {
                resStyleId = DFStrDup(className);
            }
            break;
        }
        case HTML_P:
            resStyleId = DFStrDup(className);
            break;
        case HTML_SPAN:
            resStyleId = DFStrDup(className);
            break;
        case HTML_TABLE:
            resStyleId = DFStrDup(className);
            break;
    }
    free(className);

    if (resStyleId == NULL) {
        // Note: selector here may start with . (i.e. applies to all elements)
        // FIXME: not covered by tests
        resStyleId = strdup(selector);
    }

    return resStyleId;
}