String StylePropertySet::getPropertyValue(T property) const { RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(property); if (value) return value->cssText(); return serializeShorthand(*this, property); }
String StylePropertySerializer::getShorthandValue(const StylePropertyShorthand& shorthand) const { String commonValue; StringBuilder result; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!m_propertySet.isPropertyImplicit(shorthand.properties()[i])) { RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(shorthand.properties()[i]); if (!value) return String(); String valueText = value->cssText(); if (!i) commonValue = valueText; else if (!commonValue.isNull() && commonValue != valueText) commonValue = String(); if (value->isInitialValue()) continue; if (!result.isEmpty()) result.append(' '); result.append(valueText); } else commonValue = String(); } if (isInitialOrInherit(commonValue)) return commonValue; if (result.isEmpty()) return String(); return result.toString(); }
void V8CSSStyleDeclaration::namedPropertyGetterCustom(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) { if (!name->IsString()) return; // First look for API defined attributes on the style declaration object. if (v8CallBoolean(info.Holder()->HasRealNamedCallbackProperty(info.GetIsolate()->GetCurrentContext(), name.As<v8::String>()))) return; // Search the style declaration. CSSPropertyInfo* propInfo = cssPropertyInfo(name.As<v8::String>(), info.GetIsolate()); // Do not handle non-property names. if (!propInfo) return; CSSStyleDeclaration* impl = V8CSSStyleDeclaration::toImpl(info.Holder()); RefPtrWillBeRawPtr<CSSValue> cssValue = impl->getPropertyCSSValueInternal(static_cast<CSSPropertyID>(propInfo->propID)); if (cssValue) { v8SetReturnValueStringOrNull(info, cssValue->cssText(), info.GetIsolate()); return; } String result = impl->getPropertyValueInternal(static_cast<CSSPropertyID>(propInfo->propID)); v8SetReturnValueString(info, result, info.GetIsolate()); }
String StylePropertySerializer::borderSpacingValue(const StylePropertyShorthand& shorthand) const { RefPtrWillBeRawPtr<CSSValue> horizontalValue = m_propertySet.getPropertyCSSValue(shorthand.properties()[0]); RefPtrWillBeRawPtr<CSSValue> verticalValue = m_propertySet.getPropertyCSSValue(shorthand.properties()[1]); // While standard border-spacing property does not allow specifying border-spacing-vertical without // specifying border-spacing-horizontal <http://www.w3.org/TR/CSS21/tables.html#separated-borders>, // -webkit-border-spacing-vertical can be set without -webkit-border-spacing-horizontal. if (!horizontalValue || !verticalValue) return String(); String horizontalValueCSSText = horizontalValue->cssText(); String verticalValueCSSText = verticalValue->cssText(); if (horizontalValueCSSText == verticalValueCSSText) return horizontalValueCSSText; return horizontalValueCSSText + ' ' + verticalValueCSSText; }
String StylePropertySet::getPropertyValue(CSSPropertyID propertyID) const { RefPtrWillBeRawPtr<CSSValue> value = getPropertyCSSValue(propertyID); if (value) return value->cssText(); return StylePropertySerializer(*this).getPropertyValue(propertyID); }
String StylePropertySerializer::backgroundRepeatPropertyValue() const { RefPtrWillBeRawPtr<CSSValue> repeatX = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundRepeatX); RefPtrWillBeRawPtr<CSSValue> repeatY = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundRepeatY); if (!repeatX || !repeatY) return String(); if (repeatX->cssValueType() != repeatY->cssValueType()) return String(); if (m_propertySet.propertyIsImportant(CSSPropertyBackgroundRepeatX) != m_propertySet.propertyIsImportant(CSSPropertyBackgroundRepeatY)) return String(); StringBuilder builder; switch (repeatX->cssValueType()) { case CSSValue::CSS_INHERIT: case CSSValue::CSS_INITIAL: return repeatX->cssText(); case CSSValue::CSS_PRIMITIVE_VALUE: { CSSValueID repeatXValueId = toCSSPrimitiveValue(repeatX.get())->getValueID(); CSSValueID repeatYValueId = toCSSPrimitiveValue(repeatY.get())->getValueID(); if (repeatXValueId == repeatYValueId) return repeatX->cssText(); if (repeatXValueId == CSSValueNoRepeat && repeatYValueId == CSSValueRepeat) { builder.append("repeat-y"); break; } if (repeatXValueId == CSSValueRepeat && repeatYValueId == CSSValueNoRepeat) { builder.append("repeat-x"); break; } // Fall through intentional. } case CSSValue::CSS_CUSTOM: case CSSValue::CSS_VALUE_LIST: default: builder.append(repeatX->cssText()); builder.append(' '); builder.append(repeatY->cssText()); break; } return builder.toString(); }
// only returns a non-null value if all properties have the same, non-null value String StylePropertySerializer::getCommonValue(const StylePropertyShorthand& shorthand) const { String res; bool lastPropertyWasImportant = false; for (unsigned i = 0; i < shorthand.length(); ++i) { RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(shorthand.properties()[i]); // FIXME: CSSInitialValue::cssText should generate the right value. if (!value) return String(); String text = value->cssText(); if (text.isNull()) return String(); if (res.isNull()) res = text; else if (res != text) return String(); bool currentPropertyIsImportant = m_propertySet.propertyIsImportant(shorthand.properties()[i]); if (i && lastPropertyWasImportant != currentPropertyIsImportant) return String(); lastPropertyWasImportant = currentPropertyIsImportant; } return res; }
void StylePropertySerializer::appendBackgroundPropertyAsText(StringBuilder& result, unsigned& numDecls) const { if (isPropertyShorthandAvailable(backgroundShorthand())) { String backgroundValue = getPropertyValue(CSSPropertyBackground); bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundImage); result.append(getPropertyText(CSSPropertyBackground, backgroundValue, isImportant, numDecls++)); return; } if (shorthandHasOnlyInitialOrInheritedValue(backgroundShorthand())) { RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundImage); bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundImage); result.append(getPropertyText(CSSPropertyBackground, value->cssText(), isImportant, numDecls++)); return; } // backgroundShorthandProperty without layered shorhand properties const CSSPropertyID backgroundPropertyIds[] = { CSSPropertyBackgroundImage, CSSPropertyBackgroundAttachment, CSSPropertyBackgroundColor, CSSPropertyBackgroundSize, CSSPropertyBackgroundOrigin, CSSPropertyBackgroundClip }; for (unsigned i = 0; i < WTF_ARRAY_LENGTH(backgroundPropertyIds); ++i) { CSSPropertyID propertyID = backgroundPropertyIds[i]; RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(propertyID); if (!value) continue; result.append(getPropertyText(propertyID, value->cssText(), m_propertySet.propertyIsImportant(propertyID), numDecls++)); } // 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 (shorthandHasOnlyInitialOrInheritedValue(backgroundPositionShorthand())) { RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundPositionX); bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundPositionX); result.append(getPropertyText(CSSPropertyBackgroundPosition, value->cssText(), isImportant, numDecls++)); } else if (isPropertyShorthandAvailable(backgroundPositionShorthand())) { String positionValue = m_propertySet.getPropertyValue(CSSPropertyBackgroundPosition); bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundPositionX); if (!positionValue.isNull()) result.append(getPropertyText(CSSPropertyBackgroundPosition, positionValue, isImportant, numDecls++)); } else { // should check background-position-x or background-position-y. if (RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundPositionX)) { if (!value->isImplicitInitialValue()) { bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundPositionX); result.append(getPropertyText(CSSPropertyBackgroundPositionX, value->cssText(), isImportant, numDecls++)); } } if (RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(CSSPropertyBackgroundPositionY)) { if (!value->isImplicitInitialValue()) { bool isImportant = m_propertySet.propertyIsImportant(CSSPropertyBackgroundPositionY); result.append(getPropertyText(CSSPropertyBackgroundPositionY, value->cssText(), isImportant, numDecls++)); } } } String repeatValue = m_propertySet.getPropertyValue(CSSPropertyBackgroundRepeat); if (!repeatValue.isNull()) result.append(getPropertyText(CSSPropertyBackgroundRepeat, repeatValue, m_propertySet.propertyIsImportant(CSSPropertyBackgroundRepeatX), numDecls++)); }
String StylePropertySerializer::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const { StringBuilder result; const unsigned size = shorthand.length(); // Begin by collecting the properties into an array. WillBeHeapVector<RefPtrWillBeMember<CSSValue> > values(size); size_t numLayers = 0; for (unsigned i = 0; i < size; ++i) { values[i] = m_propertySet.getPropertyCSSValue(shorthand.properties()[i]); if (values[i]) { if (values[i]->isBaseValueList()) { CSSValueList* valueList = toCSSValueList(values[i].get()); numLayers = max(valueList->length(), numLayers); } else numLayers = max<size_t>(1U, numLayers); } } String commonValue; bool commonValueInitialized = false; // Now stitch the properties together. Implicit initial values are flagged as such and // can safely be omitted. for (size_t i = 0; i < numLayers; i++) { StringBuilder layerResult; bool useRepeatXShorthand = false; bool useRepeatYShorthand = false; bool useSingleWordShorthand = false; bool foundPositionYCSSProperty = false; for (unsigned j = 0; j < size; j++) { RefPtrWillBeRawPtr<CSSValue> value = nullptr; if (values[j]) { if (values[j]->isBaseValueList()) value = toCSSValueList(values[j].get())->item(i); else { value = values[j]; // Color only belongs in the last layer. if (shorthand.properties()[j] == CSSPropertyBackgroundColor) { if (i != numLayers - 1) value = nullptr; } else if (i) { // Other singletons only belong in the first layer. value = nullptr; } } } // We need to report background-repeat as it was written in the CSS. If the property is implicit, // then it was written with only one value. Here we figure out which value that was so we can // report back correctly. if ((shorthand.properties()[j] == CSSPropertyBackgroundRepeatX && m_propertySet.isPropertyImplicit(shorthand.properties()[j])) || (shorthand.properties()[j] == CSSPropertyWebkitMaskRepeatX && m_propertySet.isPropertyImplicit(shorthand.properties()[j]))) { // BUG 49055: make sure the value was not reset in the layer check just above. if ((j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyBackgroundRepeatY && value) || (j < size - 1 && shorthand.properties()[j + 1] == CSSPropertyWebkitMaskRepeatY && value)) { RefPtrWillBeRawPtr<CSSValue> yValue = nullptr; RefPtrWillBeRawPtr<CSSValue> nextValue = values[j + 1]; if (nextValue->isValueList()) yValue = toCSSValueList(nextValue.get())->itemWithoutBoundsCheck(i); else yValue = nextValue; // background-repeat-x(y) or mask-repeat-x(y) may be like this : "initial, repeat". We can omit the implicit initial values // before starting to compare their values. if (value->isImplicitInitialValue() || yValue->isImplicitInitialValue()) continue; // FIXME: At some point we need to fix this code to avoid returning an invalid shorthand, // since some longhand combinations are not serializable into a single shorthand. if (!value->isPrimitiveValue() || !yValue->isPrimitiveValue()) continue; CSSValueID xId = toCSSPrimitiveValue(value.get())->getValueID(); CSSValueID yId = toCSSPrimitiveValue(yValue.get())->getValueID(); if (xId != yId) { if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) { useRepeatXShorthand = true; ++j; } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) { useRepeatYShorthand = true; continue; } } else { useSingleWordShorthand = true; ++j; } } } String valueText; if (value && !value->isImplicitInitialValue()) { if (!layerResult.isEmpty()) layerResult.append(' '); if (foundPositionYCSSProperty && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize)) layerResult.appendLiteral("/ "); if (!foundPositionYCSSProperty && (shorthand.properties()[j] == CSSPropertyBackgroundSize || shorthand.properties()[j] == CSSPropertyWebkitMaskSize)) continue; if (useRepeatXShorthand) { useRepeatXShorthand = false; layerResult.append(getValueName(CSSValueRepeatX)); } else if (useRepeatYShorthand) { useRepeatYShorthand = false; layerResult.append(getValueName(CSSValueRepeatY)); } else { if (useSingleWordShorthand) useSingleWordShorthand = false; valueText = value->cssText(); layerResult.append(valueText); } if (shorthand.properties()[j] == CSSPropertyBackgroundPositionY || shorthand.properties()[j] == CSSPropertyWebkitMaskPositionY) { foundPositionYCSSProperty = true; // background-position is a special case: if only the first offset is specified, // the second one defaults to "center", not the same value. if (commonValueInitialized && commonValue != "initial" && commonValue != "inherit") commonValue = String(); } } if (!commonValueInitialized) { commonValue = valueText; commonValueInitialized = true; } else if (!commonValue.isNull() && commonValue != valueText) commonValue = String(); } if (!layerResult.isEmpty()) { if (!result.isEmpty()) result.appendLiteral(", "); result.append(layerResult); } } if (isInitialOrInherit(commonValue)) return commonValue; if (result.isEmpty()) return String(); return result.toString(); }
String StylePropertySerializer::getPropertyValue(CSSPropertyID propertyID) const { // Shorthand and 4-values properties switch (propertyID) { case CSSPropertyAnimation: return getLayeredShorthandValue(animationShorthand()); case CSSPropertyBorderSpacing: return borderSpacingValue(borderSpacingShorthand()); case CSSPropertyBackgroundPosition: return getLayeredShorthandValue(backgroundPositionShorthand()); case CSSPropertyBackgroundRepeat: return backgroundRepeatPropertyValue(); case CSSPropertyBackground: return getLayeredShorthandValue(backgroundShorthand()); case CSSPropertyBorder: return borderPropertyValue(OmitUncommonValues); case CSSPropertyBorderTop: return getShorthandValue(borderTopShorthand()); case CSSPropertyBorderRight: return getShorthandValue(borderRightShorthand()); case CSSPropertyBorderBottom: return getShorthandValue(borderBottomShorthand()); case CSSPropertyBorderLeft: return getShorthandValue(borderLeftShorthand()); case CSSPropertyOutline: return getShorthandValue(outlineShorthand()); case CSSPropertyBorderColor: return get4Values(borderColorShorthand()); case CSSPropertyBorderWidth: return get4Values(borderWidthShorthand()); case CSSPropertyBorderStyle: return get4Values(borderStyleShorthand()); case CSSPropertyWebkitColumnRule: return getShorthandValue(webkitColumnRuleShorthand()); case CSSPropertyWebkitColumns: return getShorthandValue(webkitColumnsShorthand()); case CSSPropertyFlex: return getShorthandValue(flexShorthand()); case CSSPropertyFlexFlow: return getShorthandValue(flexFlowShorthand()); case CSSPropertyGridColumn: return getShorthandValue(gridColumnShorthand()); case CSSPropertyGridRow: return getShorthandValue(gridRowShorthand()); case CSSPropertyGridArea: return getShorthandValue(gridAreaShorthand()); case CSSPropertyFont: return fontValue(); case CSSPropertyMargin: return get4Values(marginShorthand()); case CSSPropertyWebkitMarginCollapse: return getShorthandValue(webkitMarginCollapseShorthand()); case CSSPropertyOverflow: return getCommonValue(overflowShorthand()); case CSSPropertyPadding: return get4Values(paddingShorthand()); case CSSPropertyTransition: return getLayeredShorthandValue(transitionShorthand()); case CSSPropertyListStyle: return getShorthandValue(listStyleShorthand()); case CSSPropertyWebkitMaskPosition: return getLayeredShorthandValue(webkitMaskPositionShorthand()); case CSSPropertyWebkitMaskRepeat: return getLayeredShorthandValue(webkitMaskRepeatShorthand()); case CSSPropertyWebkitMask: return getLayeredShorthandValue(webkitMaskShorthand()); case CSSPropertyWebkitTextEmphasis: return getShorthandValue(webkitTextEmphasisShorthand()); case CSSPropertyWebkitTextStroke: return getShorthandValue(webkitTextStrokeShorthand()); case CSSPropertyTransformOrigin: case CSSPropertyWebkitTransformOrigin: return getShorthandValue(webkitTransformOriginShorthand()); case CSSPropertyWebkitTransition: return getLayeredShorthandValue(webkitTransitionShorthand()); case CSSPropertyWebkitAnimation: return getLayeredShorthandValue(webkitAnimationShorthand()); case CSSPropertyMarker: { RefPtrWillBeRawPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(CSSPropertyMarkerStart); if (value) return value->cssText(); return String(); } case CSSPropertyBorderRadius: return get4Values(borderRadiusShorthand()); default: return String(); } }