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; }
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); }
static void removeRedundantProperties(CSSSheet *sheet) { // Remove any properties set on a style that have the same value as the corresponding property // on the parent style. This is necessary because CSS doesn't support style inheritance (in // the sense of Word & ODF's styles), so when we save out a HTML file, every style has all // properties of its ancestors. After reading in a HTML file for the purposes of updating the // original Word or ODF style, we don't want these extra property settings to remain, so that // we can avoid adding spurious extra redundant property settings to the original file. breakCycles(sheet); const char **sortedSelectors = reverseTopologicalSortedSelectors(sheet); for (size_t selIndex = 0; sortedSelectors[selIndex]; selIndex++) { const char *selector = sortedSelectors[selIndex]; CSSStyle *child = CSSSheetLookupSelector(sheet,selector,0,0); CSSStyle *parent = CSSSheetGetStyleParent(sheet,child); if (parent == NULL) continue; const char **allSuffixes = CSSStyleCopySuffixes(child); for (int suffixIndex = 0; allSuffixes[suffixIndex]; suffixIndex++) { const char *suffix = allSuffixes[suffixIndex]; int isCell = !strcmp(suffix," > * > tr > td"); CSSProperties *childProperties = CSSStyleRuleForSuffix(child,suffix); CSSProperties *parentProperties = CSSStyleRuleForSuffix(parent,suffix); const char **allNames = CSSPropertiesCopyNames(childProperties); for (int nameIndex = 0; allNames[nameIndex]; nameIndex++) { const char *name = allNames[nameIndex]; // In docx's styles.xml, the tblCellMar values in table styles are not inherited // (this seems like a bug in word, as isn't inconsistent with all other properties) // So keep these ones. if (isCell && DFStringHasPrefix(name,"padding-")) continue; const char *childVal = CSSGet(childProperties,name); const char *parentVal = CSSGet(parentProperties,name); if ((childVal != NULL) && (parentVal != NULL) && DFStringEquals(childVal,parentVal)) CSSPut(childProperties,name,NULL); } free(allNames); } free(allSuffixes); } free(sortedSelectors); }