static void Word_mergeRunsRecursive(DFNode *node) { DFNode *current = node->first; while (current != NULL) { DFNode *next = current->next; if ((current->tag == WORD_R) && (next != NULL) && (next->tag == WORD_R)) { DFNode *currentRPr = DFChildWithTag(current,WORD_RPR); DFNode *nextRPr = DFChildWithTag(next,WORD_RPR); if (nodesEqual(currentRPr,nextRPr)) { while (next->first != NULL) { if (next->first->tag == WORD_RPR) DFRemoveNode(next->first); else DFAppendChild(current,next->first); } DFRemoveNode(next); continue; } } current = next; } for (current = node->first; current != NULL; current = current->next) Word_mergeRunsRecursive(current); }
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); } }
static void putInParagraphsRecursive(DFNode *node) { DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; putInParagraphsRecursive(child); } if (((node->tag == WORD_BOOKMARKSTART) || (node->tag == WORD_BOOKMARKEND)) && (node->parent->tag != WORD_P)) { DFNode *forwards = findParagraphForwards(node); if (forwards != NULL) { DFNode *pPr = DFChildWithTag(forwards,WORD_PPR); if (pPr != NULL) DFInsertBefore(forwards,node,pPr->next); else DFInsertBefore(forwards,node,forwards->first); return; } DFNode *backwards = findParagraphBackwards(node); if (backwards != NULL) { DFAppendChild(backwards,node); return; } DFRemoveNode(node); } }
void DFInsertBefore(DFNode *parent, DFNode *newChild, DFNode *refChild) { assert(newChild->doc == parent->doc); assert((refChild == NULL) || (refChild->doc == parent->doc)); if (newChild == refChild) return; if (newChild->parent != NULL) DFRemoveNode(newChild); assert(newChild->prev == NULL); assert(newChild->next == NULL); assert((refChild == NULL) || (refChild->parent == parent)); assert(((parent->first == NULL) && (parent->last == NULL)) || ((parent->first != NULL) && (parent->last != NULL))); assert((parent->first != NULL) || (refChild == NULL)); newChild->prev = (refChild != NULL) ? refChild->prev : parent->last; newChild->next = refChild; if (newChild->prev != NULL) newChild->prev->next = newChild; if (newChild->next != NULL) newChild->next->prev = newChild; if (refChild == parent->first) parent->first = newChild; if (refChild == NULL) parent->last = newChild; newChild->parent = parent; }
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); }
void DFRemoveNodeButKeepChildren(DFNode *node) { DFNode *parent = node->parent; assert(parent != NULL); while (node->first != NULL) DFInsertBefore(parent,node->first,node); DFRemoveNode(node); }
void replaceChildrenFromArray(DFNode *node, DFNode **children, Tag *tags) { while (node->first != NULL) DFRemoveNode(node->first); for (int i = 0; tags[i] != 0; i++) { if (children[tags[i]]) DFAppendChild(node,children[tags[i]]); } }
static void removeNodes(DFNode *beginNode, DFNode *endNode) { CommonAncestorInfo common = findCommonAncestor(beginNode,endNode); assert(common.commonAncestor != NULL); assert(common.beginAncestor != NULL); assert(common.endAncestor != NULL); DFNode *begin = beginNode; while (begin != common.beginAncestor) { DFNode *parent = begin->parent; if (begin->next != NULL) DFRemoveNode(begin->next); else begin = parent; } DFNode *end = endNode; while (end != common.endAncestor) { DFNode *parent = end->parent; if (end->prev != NULL) DFRemoveNode(end->prev); else end = parent; } if (common.beginAncestor != common.endAncestor) { while (common.beginAncestor->next != common.endAncestor) DFRemoveNode(common.beginAncestor->next); } while ((beginNode != NULL) && (beginNode->first == NULL) && (beginNode->tag != WORD_DOCUMENT)) { DFNode *parent = beginNode->parent; DFRemoveNode(beginNode); beginNode = parent; } while ((endNode != NULL) && (endNode->first == NULL) && (endNode->tag != WORD_DOCUMENT)) { DFNode *parent = endNode->parent; DFRemoveNode(endNode); endNode = parent; } }
void DFRemoveWhitespaceNodes(DFNode *node) { DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; switch (child->tag) { case DOM_TEXT: case DOM_CDATA: { if (DFStringIsWhitespace(child->value)) DFRemoveNode(child); break; } case DOM_COMMENT: DFRemoveNode(child); break; default: DFRemoveWhitespaceNodes(child); break; } } }
static void updateTrJc(DFNode *wordTr, const char *oldJc, const char *newJc) { DFNode *tblPrEx = DFChildWithTag(wordTr,WORD_TBLPREX); DFNode *trPr = DFChildWithTag(wordTr,WORD_TRPR); if (tblPrEx != NULL) DFRemoveNode(tblPrEx); if (trPr != NULL) DFRemoveNode(trPr); if (trPr == NULL) trPr = DFCreateElement(wordTr->doc,WORD_TRPR); WordPutTrPr(trPr,oldJc,newJc); if (trPr->first == NULL) trPr = NULL;; DFNode *first = wordTr->first; if (tblPrEx != NULL) DFInsertBefore(wordTr,tblPrEx,first); if (trPr != NULL) DFInsertBefore(wordTr,trPr,first); }
static DFNode *concreteRowForAbstractRow(WordPutData *put, DFNode *htmlTr) { DFNode *wordTr = WordConverterGetConcrete(put,htmlTr); if (wordTr == NULL) { wordTr = DFCreateElement(put->contentDoc,WORD_TR); } else { // We're reusing an existing row element, but we first need to clear all the cells in // it, because we'll be rebuilding the cell list DFNode *next; for (DFNode *child = wordTr->first; child != NULL; child = next) { next = child->next; if (child->tag == WORD_TC) DFRemoveNode(child); } } return wordTr; }
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); }
void DFStripWhitespace(DFNode *node) { if (node->tag == DOM_TEXT) { char *trimmed = DFStringTrimWhitespace(node->value); if ((strlen(trimmed) == 0) && (node->parent != NULL)) DFRemoveNode(node); else DFSetNodeValue(node,trimmed); free(trimmed); } else { if (node->tag >= MIN_ELEMENT_TAG) { const char *space = DFGetAttribute(node,XML_SPACE); if ((space != NULL) && !strcmp(space,"preserve")) return; } DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; DFStripWhitespace(child); } } }
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); }
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; }
static void Word_preProcessHTML(WordConverter *word, DFNode *node) { switch (node->tag) { case HTML_TABLE: case HTML_FIGURE: { DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; if ((child->tag != HTML_CAPTION) && (child->tag != HTML_FIGCAPTION)) continue; WordCaption *caption = WordCaptionNew(child); WordObjectsSetCaption(word->objects,caption,node); caption->contentStart = child->first; WordCaptionRelease(caption); const char *className = DFGetAttribute(child,HTML_CLASS); CSSStyle *style; if (child->tag == HTML_CAPTION) style = CSSSheetLookupElement(word->styleSheet,"caption",className,0,0); else style = CSSSheetLookupElement(word->styleSheet,"figcaption",className,0,0); CSSProperties *before = CSSStyleBefore(style); if (CSSGet(before,"content") != NULL) Word_addContentParts(child,CSSGet(before,"content"),caption); child->tag = HTML_P; DFSetAttribute(child,HTML_CLASS,"Caption"); DFInsertBefore(node->parent,child,node->next); Word_preProcessHTML(word,child); } // The HTML normalization process ensures that apart from the <figcaption> element, // all children of a <figure> are paragraphs or containers. Currently the editor only // lets you create figures that contain a single image, so it's always a single // paragraph. Since the HTML <figure> element gets mapped to a single <w:p> element // by WordParagraphLens, we want to make sure it only contains inline children. for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; if (HTML_isParagraphTag(child->tag)) DFRemoveNodeButKeepChildren(child); } // FIXME: Handle <div>, <pre>, lists, tables etc which could also theoretically // exist inside the <figure> element break; } case HTML_NAV: { const char *className = DFGetAttribute(node,HTML_CLASS); const char *instr = NULL; if (DFStringEquals(className,DFTableOfContentsClass)) instr = " TOC \\o \"1-3\" "; else if (DFStringEquals(className,DFListOfFiguresClass)) instr = " TOC \\c \"Figure\" "; else if (DFStringEquals(className,DFListOfTablesClass)) instr = " TOC \\c \"Table\" "; if (instr != NULL) { DFNode *p = DFCreateElement(word->html,HTML_P); DFNode *field = DFCreateChildElement(p,HTML_SPAN); DFSetAttribute(field,HTML_CLASS,DFFieldClass); DFCreateChildTextNode(field,instr); DFInsertBefore(node->parent,p,node); DFRemoveNode(node); } break; } } DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; Word_preProcessHTML(word,child); } }
static void extractPrefixRecursive(DFNode *node, const char *counterName, DFBuffer *result, int *foundSeq, int *foundContent) { if (isSeqField(node)) { if (result->len > 0) DFBufferFormat(result," "); DFBufferFormat(result,"counter(%s)",counterName); *foundSeq = 1; DFRemoveNode(node); return; } if (node->tag == DOM_TEXT) { size_t valueLen = strlen(node->value); size_t pos = 0; if (*foundSeq) { size_t offset = 0; uint32_t ch; do { pos = offset; ch = DFNextChar(node->value,&offset); } while ((ch != 0) && (DFCharIsWhitespaceOrNewline(ch) || DFCharIsPunctuation(ch))); } else { pos = valueLen; } if (pos == valueLen) { if (result->len > 0) DFBufferFormat(result," "); char *quotedValue = DFQuote(node->value); DFBufferFormat(result,"%s",quotedValue); free(quotedValue); DFRemoveNode(node); if (*foundSeq) *foundContent = 1; return; } else if (pos > 0) { char *first = DFSubstring(node->value,0,pos); char *rest = DFSubstring(node->value,pos,valueLen); if (result->len > 0) DFBufferFormat(result," "); char *quotedFirst = DFQuote(first); DFBufferFormat(result,"%s",quotedFirst); free(quotedFirst); DFSetNodeValue(node,rest); if (*foundSeq) *foundContent = 1; free(first); free(rest); return; } } int wasEmpty = (node->first == NULL); DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; if (*foundContent) break; extractPrefixRecursive(child,counterName,result,foundSeq,foundContent); } int isEmpty = (node->first == NULL); if ((node->tag == HTML_SPAN) && isEmpty && !wasEmpty) DFRemoveNode(node); }
static void Word_postProcessHTML(WordConverter *conv, DFNode *node) { DFNode *next; for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; switch (child->tag) { case HTML_SPAN: { const char *className = DFGetAttribute(child,HTML_CLASS); if (DFStringEquals(className,DFBookmarkClass)) { if (child->first != NULL) next = child->first; DFRemoveNodeButKeepChildren(child); } break; } case HTML_CAPTION: { const char *counterName = NULL; if ((child->prev != NULL) && (child->prev->tag == HTML_FIGURE) && (DFChildWithTag(child->prev,HTML_FIGCAPTION) == NULL)) { child->tag = HTML_FIGCAPTION; counterName = "figure"; DFAppendChild(child->prev,child); } else if ((child->prev != NULL) && (child->prev->tag == HTML_TABLE) && (DFChildWithTag(child->prev,HTML_CAPTION) == NULL)) { counterName = "table"; DFInsertBefore(child->prev,child,child->prev->first); } else if ((child->next != NULL) && (child->next->tag == HTML_FIGURE) && (DFChildWithTag(child->next,HTML_FIGCAPTION) == NULL)) { child->tag = HTML_FIGCAPTION; counterName = "figure"; DFInsertBefore(child->next,child,child->next->first); } else if ((child->next != NULL) && (child->next->tag == HTML_TABLE) && (DFChildWithTag(child->next,HTML_CAPTION) == NULL)) { counterName = "table"; DFSetAttribute(child,HTML_STYLE,"caption-side: top"); DFInsertBefore(child->next,child,child->next->first); } if (counterName != NULL) { char *beforeText = extractPrefix(child,counterName); if (beforeText != NULL) { CSSStyle *style = CSSSheetLookupElement(conv->styleSheet,DFNodeName(child),NULL,1,0); if (CSSGet(CSSStyleBefore(style),"content") == NULL) { CSSPut(CSSStyleRule(style),"counter-increment",counterName); CSSPut(CSSStyleBefore(style),"content",beforeText); } } free(beforeText); } break; } case HTML_NAV: { if (HTML_isParagraphTag(node->tag)) { if (child->prev != NULL) { DFNode *beforeP = DFCreateElement(conv->package->document,node->tag); while (child->prev != NULL) DFInsertBefore(beforeP,child->prev,beforeP->first); DFInsertBefore(node->parent,beforeP,node); } DFInsertBefore(node->parent,child,node); if ((node->first == NULL) || ((node->first->tag == HTML_BR) && (node->first->next == NULL))) { DFRemoveNode(node); return; } next = NULL; } break; } } } for (DFNode *child = node->first; child != NULL; child = next) { next = child->next; Word_postProcessHTML(conv,child); } }
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; } } }
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); }