char *CSSSheetCopyText(CSSSheet *sheet) { DFBuffer *result = DFBufferNew(); const char **allSelectors = CSSSheetCopySelectors(sheet); DFSortStringsCaseInsensitive(allSelectors); for (int selIndex = 0; allSelectors[selIndex]; selIndex++) { CSSStyle *style = CSSSheetLookupSelector(sheet,allSelectors[selIndex],0,0); DFBufferFormat(result,"%s\n",style->selector); const char **sortedSuffixes = CSSStyleCopySuffixes(style); DFSortStringsCaseInsensitive(sortedSuffixes); for (int suffixIndex = 0; sortedSuffixes[suffixIndex]; suffixIndex++) { const char *suffix = sortedSuffixes[suffixIndex]; char *quotedSuffix = DFQuote(suffix); DFBufferFormat(result," %s\n",quotedSuffix); free(quotedSuffix); CSSProperties *properties = CSSStyleRuleForSuffix(style,suffix); const char **sortedNames = CSSPropertiesCopyNames(properties); DFSortStringsCaseInsensitive(sortedNames); for (int nameIndex = 0; sortedNames[nameIndex]; nameIndex++) { const char *name = sortedNames[nameIndex]; const char *value = CSSGet(properties,name); DFBufferFormat(result," %s = %s\n",name,value); } free(sortedNames); } free(sortedSuffixes); } free(allSelectors); char *str = xstrdup(result->data); DFBufferRelease(result); return str; }
void CSSPropertiesPrint(CSSProperties *properties, const char *indent) { const char **allNames = CSSPropertiesCopyNames(properties); DFSortStringsCaseInsensitive(allNames); for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) { const char *name = allNames[nameIndex]; const char *value = CSSGet(properties,name); printf("%s%s = %s\n",indent,name,value); } free(allNames); }
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); }
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); }