static void updateListTypes(WordPutData *put) { const char **htmlIds = DFHashTableCopyKeys(put->numIdByHtmlId); for (int i = 0; htmlIds[i]; i++) { const char *htmlId = htmlIds[i]; const char *numId = DFHashTableLookup(put->numIdByHtmlId,htmlId); WordConcreteNum *num = WordNumberingConcreteWithId(put->conv->numbering,numId); if (num == NULL) continue; // FIXME: remove entry from both maps so it is re-created DFNode *listNode = DFNodeForSeqNo(put->conv->html,(unsigned int)atoi(htmlId)); assert(listNode != NULL); const char *htmlType = DFGetAttribute(listNode,CONV_LISTTYPE); const char *htmlIlvl = DFGetAttribute(listNode,CONV_ILVL); WordNumLevel *level = WordConcreteNumGetLevel(num,atoi(htmlIlvl)); if (level == NULL) continue; // FIXME: remove entry from both maps so it is re-created const char *wordType = WordNumLevelToListStyleType(level); if (!DFStringEquals(wordType,htmlType)) { // Make a copy of numId, as it may be freed during the first call to DFHashTableRemove char *numIdCopy = strdup(numId); DFHashTableRemove(put->numIdByHtmlId,htmlId); DFHashTableRemove(put->htmlIdByNumId,numIdCopy); free(numIdCopy); if (num->referenceCount == 1) WordNumberingRemoveConcrete(put->conv->numbering,num); } } free(htmlIds); }
void DFSetAttribute(DFNode *element, Tag tag, const char *value) { if (value == NULL) { DFRemoveAttribute(element,tag); return; } if (tag == HTML_ID) { const char *oldIdAttr = DFGetAttribute(element,HTML_ID); if (oldIdAttr != NULL) DFHashTableRemove(element->doc->nodesByIdAttr,oldIdAttr); DFHashTableAdd(element->doc->nodesByIdAttr,value,element); } // Is there an existing attribute with this tag? If so, replace it for (unsigned int i = 0; i < element->attrsCount; i++) { if (element->attrs[i].tag == tag) { element->attrs[i].value = DFCopyString(element->doc,value); return; } } // No existing attribute with this tag - add it if (element->attrsCount == element->attrsAlloc) { element->attrsAlloc = (element->attrsAlloc == 0) ? 8 : (2*element->attrsAlloc); element->attrs = (DFAttribute *)xrealloc(element->attrs,element->attrsAlloc*sizeof(DFAttribute)); } element->attrs[element->attrsCount].tag = tag; element->attrs[element->attrsCount].value = DFCopyString(element->doc,value); element->attrsCount++; }
void CSSPut(CSSProperties *properties, const char *name, const char *value) { if (properties == NULL) return; assert(properties->retainCount > 0); if (value == NULL) DFHashTableRemove(properties->hashTable,name); else DFHashTableAdd(properties->hashTable,name,(void *)value); if (!properties->dirty) // Minimise KVO notifications properties->dirty = 1; DFCallbackInvoke(properties->changeCallbacks,properties,NULL); }
void DFRemoveAttribute(DFNode *element, Tag tag) { if (tag == HTML_ID) { const char *oldIdAttr = DFGetAttribute(element,HTML_ID); if (oldIdAttr != NULL) DFHashTableRemove(element->doc->nodesByIdAttr,oldIdAttr); } for (unsigned int i = 0; i < element->attrsCount; i++) { if (element->attrs[i].tag == tag) { if (i+1 < element->attrsCount) { // Move the last attribute into this slot element->attrs[i].tag = element->attrs[element->attrsCount-1].tag; element->attrs[i].value = element->attrs[element->attrsCount-1].value; } element->attrsCount--; return; } } }
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); }
void CSSSheetRemoveStyle(CSSSheet *sheet, CSSStyle *style) { DFHashTableRemove(sheet->_styles,style->selector); }