String StylePropertySet::get4Values(const StylePropertyShorthand& shorthand) const { // Assume the properties are in the usual order top, right, bottom, left. int topValueIndex = findPropertyIndex(shorthand.properties()[0]); int rightValueIndex = findPropertyIndex(shorthand.properties()[1]); int bottomValueIndex = findPropertyIndex(shorthand.properties()[2]); int leftValueIndex = findPropertyIndex(shorthand.properties()[3]); if (topValueIndex == -1 || rightValueIndex == -1 || bottomValueIndex == -1 || leftValueIndex == -1) return String(); PropertyReference top = propertyAt(topValueIndex); PropertyReference right = propertyAt(rightValueIndex); PropertyReference bottom = propertyAt(bottomValueIndex); PropertyReference left = propertyAt(leftValueIndex); // All 4 properties must be specified. if (!top.value() || !right.value() || !bottom.value() || !left.value()) return String(); if (top.isInherited() && right.isInherited() && bottom.isInherited() && left.isInherited()) return getValueName(CSSValueInherit); if (top.value()->isInitialValue() || right.value()->isInitialValue() || bottom.value()->isInitialValue() || left.value()->isInitialValue()) { if (top.value()->isInitialValue() && right.value()->isInitialValue() && bottom.value()->isInitialValue() && left.value()->isInitialValue() && !top.isImplicit()) { // All components are "initial" and "top" is not implicit. return getValueName(CSSValueInitial); } return String(); } if (top.isImportant() != right.isImportant() || right.isImportant() != bottom.isImportant() || bottom.isImportant() != left.isImportant()) return String(); bool showLeft = !right.value()->equals(*left.value()); bool showBottom = !top.value()->equals(*bottom.value()) || showLeft; bool showRight = !top.value()->equals(*right.value()) || showBottom; StringBuilder result; result.append(top.value()->cssText()); if (showRight) { result.append(' '); result.append(right.value()->cssText()); } if (showBottom) { result.append(' '); result.append(bottom.value()->cssText()); } if (showLeft) { result.append(' '); result.append(left.value()->cssText()); } return result.toString(); }
String StylePropertySet::asText() const { StringBuilder result; int positionXPropertyIndex = -1; int positionYPropertyIndex = -1; int repeatXPropertyIndex = -1; int repeatYPropertyIndex = -1; BitArray<numCSSProperties> shorthandPropertyUsed; BitArray<numCSSProperties> shorthandPropertyAppeared; unsigned size = propertyCount(); unsigned numDecls = 0; for (unsigned n = 0; n < size; ++n) { PropertyReference property = propertyAt(n); CSSPropertyID propertyID = property.id(); CSSPropertyID shorthandPropertyID = CSSPropertyInvalid; CSSPropertyID borderFallbackShorthandProperty = CSSPropertyInvalid; String value; switch (propertyID) { #if ENABLE(CSS_VARIABLES) case CSSPropertyVariable: if (numDecls++) result.append(' '); result.append(property.cssText()); continue; #endif case CSSPropertyBackgroundPositionX: positionXPropertyIndex = n; continue; case CSSPropertyBackgroundPositionY: positionYPropertyIndex = n; continue; case CSSPropertyBackgroundRepeatX: repeatXPropertyIndex = n; continue; case CSSPropertyBackgroundRepeatY: repeatYPropertyIndex = n; continue; case CSSPropertyBorderTopWidth: case CSSPropertyBorderRightWidth: case CSSPropertyBorderBottomWidth: case CSSPropertyBorderLeftWidth: if (!borderFallbackShorthandProperty) borderFallbackShorthandProperty = CSSPropertyBorderWidth; case CSSPropertyBorderTopStyle: case CSSPropertyBorderRightStyle: case CSSPropertyBorderBottomStyle: case CSSPropertyBorderLeftStyle: if (!borderFallbackShorthandProperty) borderFallbackShorthandProperty = CSSPropertyBorderStyle; case CSSPropertyBorderTopColor: case CSSPropertyBorderRightColor: case CSSPropertyBorderBottomColor: case CSSPropertyBorderLeftColor: if (!borderFallbackShorthandProperty) borderFallbackShorthandProperty = CSSPropertyBorderColor; // FIXME: Deal with cases where only some of border-(top|right|bottom|left) are specified. if (!shorthandPropertyAppeared.get(CSSPropertyBorder - firstCSSProperty)) { value = borderPropertyValue(ReturnNullOnUncommonValues); if (value.isNull()) shorthandPropertyAppeared.set(CSSPropertyBorder - firstCSSProperty); else shorthandPropertyID = CSSPropertyBorder; } else if (shorthandPropertyUsed.get(CSSPropertyBorder - firstCSSProperty)) shorthandPropertyID = CSSPropertyBorder; if (!shorthandPropertyID) shorthandPropertyID = borderFallbackShorthandProperty; break; case CSSPropertyWebkitBorderHorizontalSpacing: case CSSPropertyWebkitBorderVerticalSpacing: shorthandPropertyID = CSSPropertyBorderSpacing; break; case CSSPropertyFontFamily: case CSSPropertyLineHeight: case CSSPropertyFontSize: case CSSPropertyFontStyle: case CSSPropertyFontVariant: case CSSPropertyFontWeight: // Don't use CSSPropertyFont because old UAs can't recognize them but are important for editing. break; case CSSPropertyListStyleType: case CSSPropertyListStylePosition: case CSSPropertyListStyleImage: shorthandPropertyID = CSSPropertyListStyle; break; case CSSPropertyMarginTop: case CSSPropertyMarginRight: case CSSPropertyMarginBottom: case CSSPropertyMarginLeft: shorthandPropertyID = CSSPropertyMargin; break; case CSSPropertyOutlineWidth: case CSSPropertyOutlineStyle: case CSSPropertyOutlineColor: shorthandPropertyID = CSSPropertyOutline; break; case CSSPropertyOverflowX: case CSSPropertyOverflowY: shorthandPropertyID = CSSPropertyOverflow; break; case CSSPropertyPaddingTop: case CSSPropertyPaddingRight: case CSSPropertyPaddingBottom: case CSSPropertyPaddingLeft: shorthandPropertyID = CSSPropertyPadding; break; case CSSPropertyWebkitAnimationName: case CSSPropertyWebkitAnimationDuration: case CSSPropertyWebkitAnimationTimingFunction: case CSSPropertyWebkitAnimationDelay: case CSSPropertyWebkitAnimationIterationCount: case CSSPropertyWebkitAnimationDirection: case CSSPropertyWebkitAnimationFillMode: shorthandPropertyID = CSSPropertyWebkitAnimation; break; case CSSPropertyWebkitFlexDirection: case CSSPropertyWebkitFlexWrap: shorthandPropertyID = CSSPropertyWebkitFlexFlow; break; case CSSPropertyWebkitFlexBasis: case CSSPropertyWebkitFlexGrow: case CSSPropertyWebkitFlexShrink: shorthandPropertyID = CSSPropertyWebkitFlex; break; case CSSPropertyWebkitMaskPositionX: case CSSPropertyWebkitMaskPositionY: case CSSPropertyWebkitMaskRepeatX: case CSSPropertyWebkitMaskRepeatY: case CSSPropertyWebkitMaskImage: case CSSPropertyWebkitMaskRepeat: case CSSPropertyWebkitMaskPosition: case CSSPropertyWebkitMaskClip: case CSSPropertyWebkitMaskOrigin: shorthandPropertyID = CSSPropertyWebkitMask; break; case CSSPropertyWebkitTransformOriginX: case CSSPropertyWebkitTransformOriginY: case CSSPropertyWebkitTransformOriginZ: shorthandPropertyID = CSSPropertyWebkitTransformOrigin; break; case CSSPropertyWebkitTransitionProperty: case CSSPropertyWebkitTransitionDuration: case CSSPropertyWebkitTransitionTimingFunction: case CSSPropertyWebkitTransitionDelay: shorthandPropertyID = CSSPropertyWebkitTransition; break; #if ENABLE(CSS_EXCLUSIONS) case CSSPropertyWebkitWrapFlow: case CSSPropertyWebkitShapeMargin: case CSSPropertyWebkitShapePadding: shorthandPropertyID = CSSPropertyWebkitWrap; break; #endif default: break; } unsigned shortPropertyIndex = shorthandPropertyID - firstCSSProperty; if (shorthandPropertyID) { if (shorthandPropertyUsed.get(shortPropertyIndex)) continue; if (!shorthandPropertyAppeared.get(shortPropertyIndex) && value.isNull()) value = getPropertyValue(shorthandPropertyID); shorthandPropertyAppeared.set(shortPropertyIndex); } if (!value.isNull()) { propertyID = shorthandPropertyID; shorthandPropertyUsed.set(shortPropertyIndex); } else value = property.value()->cssText(); if (value == "initial" && !CSSProperty::isInheritedProperty(propertyID)) continue; if (numDecls++) result.append(' '); result.append(getPropertyName(propertyID)); result.appendLiteral(": "); result.append(value); if (property.isImportant()) result.appendLiteral(" !important"); result.append(';'); } // FIXME: This is a not-so-nice way to turn x/y positions into single background-position in output. // It is required because background-position-x/y are non-standard properties and WebKit generated output // would not work in Firefox (<rdar://problem/5143183>) // It would be a better solution if background-position was CSS_PAIR. if (positionXPropertyIndex != -1 && positionYPropertyIndex != -1 && propertyAt(positionXPropertyIndex).isImportant() == propertyAt(positionYPropertyIndex).isImportant()) { PropertyReference positionXProperty = propertyAt(positionXPropertyIndex); PropertyReference positionYProperty = propertyAt(positionYPropertyIndex); if (numDecls++) result.append(' '); result.appendLiteral("background-position: "); if (positionXProperty.value()->isValueList() || positionYProperty.value()->isValueList()) result.append(getLayeredShorthandValue(backgroundPositionShorthand())); else { result.append(positionXProperty.value()->cssText()); result.append(' '); result.append(positionYProperty.value()->cssText()); } if (positionXProperty.isImportant()) result.appendLiteral(" !important"); result.append(';'); } else { if (positionXPropertyIndex != -1) { if (numDecls++) result.append(' '); result.append(propertyAt(positionXPropertyIndex).cssText()); } if (positionYPropertyIndex != -1) { if (numDecls++) result.append(' '); result.append(propertyAt(positionYPropertyIndex).cssText()); } } // FIXME: We need to do the same for background-repeat. if (repeatXPropertyIndex != -1 && repeatYPropertyIndex != -1 && propertyAt(repeatXPropertyIndex).isImportant() == propertyAt(repeatYPropertyIndex).isImportant()) { PropertyReference repeatXProperty = propertyAt(repeatXPropertyIndex); PropertyReference repeatYProperty = propertyAt(repeatYPropertyIndex); if (numDecls++) result.append(' '); result.appendLiteral("background-repeat: "); if (repeatXProperty.value()->isValueList() || repeatYProperty.value()->isValueList()) result.append(getLayeredShorthandValue(backgroundRepeatShorthand())); else { result.append(repeatXProperty.value()->cssText()); result.append(' '); result.append(repeatYProperty.value()->cssText()); } if (repeatXProperty.isImportant()) result.appendLiteral(" !important"); result.append(';'); } else { if (repeatXPropertyIndex != -1) { if (numDecls++) result.append(' '); result.append(propertyAt(repeatXPropertyIndex).cssText()); } if (repeatYPropertyIndex != -1) { if (numDecls++) result.append(' '); result.append(propertyAt(repeatYPropertyIndex).cssText()); } } ASSERT(!numDecls ^ !result.isEmpty()); return result.toString(); }