String StylePropertySet::getShorthandValue(const StylePropertyShorthand& shorthand) const { String commonValue; StringBuilder result; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!isPropertyImplicit(shorthand.properties()[i])) { RefPtr<CSSValue> value = 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(); }
bool StylePropertySet::removeShorthandProperty(CSSPropertyID propertyID) { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; return removePropertiesInSet(shorthand.properties(), shorthand.length()); }
String StylePropertySet::get4Values(const StylePropertyShorthand& shorthand) const { // Assume the properties are in the usual order top, right, bottom, left. const CSSProperty* top = findPropertyWithId(shorthand.properties()[0]); const CSSProperty* right = findPropertyWithId(shorthand.properties()[1]); const CSSProperty* bottom = findPropertyWithId(shorthand.properties()[2]); const CSSProperty* left = findPropertyWithId(shorthand.properties()[3]); // All 4 properties must be specified. if (!top || !top->value() || !right || !right->value() || !bottom || !bottom->value() || !left || !left->value()) return String(); if (top->value()->isInitialValue() || right->value()->isInitialValue() || bottom->value()->isInitialValue() || left->value()->isInitialValue()) return String(); if (top->isImportant() != right->isImportant() || right->isImportant() != bottom->isImportant() || bottom->isImportant() != left->isImportant()) return String(); bool showLeft = right->value()->cssText() != left->value()->cssText(); bool showBottom = (top->value()->cssText() != bottom->value()->cssText()) || showLeft; bool showRight = (top->value()->cssText() != right->value()->cssText()) || showBottom; String res = top->value()->cssText(); if (showRight) res += " " + right->value()->cssText(); if (showBottom) res += " " + bottom->value()->cssText(); if (showLeft) res += " " + left->value()->cssText(); return res; }
String StylePropertySet::get4Values(const StylePropertyShorthand& shorthand) const { // Assume the properties are in the usual order top, right, bottom, left. RefPtr<CSSValue> topValue = getPropertyCSSValue(shorthand.properties()[0]); RefPtr<CSSValue> rightValue = getPropertyCSSValue(shorthand.properties()[1]); RefPtr<CSSValue> bottomValue = getPropertyCSSValue(shorthand.properties()[2]); RefPtr<CSSValue> leftValue = getPropertyCSSValue(shorthand.properties()[3]); // All 4 properties must be specified. if (!topValue || !rightValue || !bottomValue || !leftValue) return String(); bool showLeft = rightValue->cssText() != leftValue->cssText(); bool showBottom = (topValue->cssText() != bottomValue->cssText()) || showLeft; bool showRight = (topValue->cssText() != rightValue->cssText()) || showBottom; String res = topValue->cssText(); if (showRight) res += " " + rightValue->cssText(); if (showBottom) res += " " + bottomValue->cssText(); if (showLeft) res += " " + leftValue->cssText(); return res; }
void CSSVariableResolver::resolveAndApplyVariableReferences(StyleResolverState& state, CSSPropertyID id, const CSSVariableReferenceValue& value) { CSSVariableResolver resolver(state.style()->variables()); Vector<CSSParserToken> tokens; if (resolver.resolveTokenRange(value.variableDataValue()->tokens(), tokens)) { CSSParserContext context(HTMLStandardMode, 0); HeapVector<CSSProperty, 256> parsedProperties; // TODO: Non-shorthands should just call CSSPropertyParser::parseSingleValue if (CSSPropertyParser::parseValue(id, false, CSSParserTokenRange(tokens), context, parsedProperties, StyleRule::RuleType::Style)) { unsigned parsedPropertiesCount = parsedProperties.size(); for (unsigned i = 0; i < parsedPropertiesCount; ++i) StyleBuilder::applyProperty(parsedProperties[i].id(), state, parsedProperties[i].value()); return; } } RawPtr<CSSUnsetValue> unset = cssValuePool().createUnsetValue(); if (isShorthandProperty(id)) { StylePropertyShorthand shorthand = shorthandForProperty(id); for (unsigned i = 0; i < shorthand.length(); i++) StyleBuilder::applyProperty(shorthand.properties()[i], state, unset.get()); return; } StyleBuilder::applyProperty(id, state, unset.get()); }
bool StylePropertySerializer::isPropertyShorthandAvailable(const StylePropertyShorthand& shorthand) const { ASSERT(shorthand.length() > 0); for (unsigned i = 0; i < shorthand.length(); ++i) { RefPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(shorthand.properties()[i]); if (!value || (value->isInitialValue() && !value->isImplicitInitialValue()) || value->isInheritedValue()) return false; } return true; }
bool StylePropertySet::shorthandIsImportant(CSSPropertyID propertyID) const { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!propertyIsImportant(shorthand.properties()[i])) return false; } return true; }
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(); }
bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const { const CSSProperty* property = findPropertyWithId(propertyID); if (property) return property->isImportant(); StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!propertyIsImportant(shorthand.properties()[i])) return false; } return true; }
String StylePropertySet::getShorthandValue(const StylePropertyShorthand& shorthand) const { String res; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!isPropertyImplicit(shorthand.properties()[i])) { RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); // FIXME: provide default value if !value or value is initial value if (value && !value->isInitialValue()) { if (!res.isNull()) res += " "; res += value->cssText(); } } } return res; }
bool StylePropertySet::propertyIsImportant(CSSPropertyID propertyID) const { int foundPropertyIndex = findPropertyIndex(propertyID); if (foundPropertyIndex != -1) return propertyAt(foundPropertyIndex).isImportant(); StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!propertyIsImportant(shorthand.properties()[i])) return false; } return true; }
bool StylePropertySerializer::shorthandHasOnlyInitialOrInheritedValue(const StylePropertyShorthand& shorthand) const { ASSERT(shorthand.length() > 0); bool isInitialValue = true; bool isInheritedValue = true; for (unsigned i = 0; i < shorthand.length(); ++i) { RefPtr<CSSValue> value = m_propertySet.getPropertyCSSValue(shorthand.properties()[i]); if (!value) return false; if (!value->isInitialValue()) isInitialValue = false; if (!value->isInheritedValue()) isInheritedValue = false; } return isInitialValue || isInheritedValue; }
String StylePropertySet::getShorthandValue(const StylePropertyShorthand& shorthand) const { String res; for (unsigned i = 0; i < shorthand.length(); ++i) { if (!isPropertyImplicit(shorthand.properties()[i])) { RefPtr<CSSValue> value = getPropertyCSSValue(shorthand.properties()[i]); if (!value) return String(); if (value->isInitialValue()) continue; if (!res.isNull()) res += " "; res += value->cssText(); } } return res; }
String StylePropertySet::borderSpacingValue(const StylePropertyShorthand& shorthand) const { RefPtr<CSSValue> horizontalValue = getPropertyCSSValue(shorthand.properties()[0]); RefPtr<CSSValue> verticalValue = 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; }
// only returns a non-null value if all properties have the same, non-null value String StylePropertySerializer::getCommonValue(const StylePropertyShorthand& shorthand) const { String res; for (unsigned i = 0; i < shorthand.length(); ++i) { RefPtr<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(); } return res; }
// only returns a non-null value if all properties have the same, non-null value String StylePropertySet::getCommonValue(const StylePropertyShorthand& shorthand) const { String res; bool lastPropertyWasImportant = false; for (unsigned i = 0; i < shorthand.length(); ++i) { RefPtr<CSSValue> value = 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 = propertyIsImportant(shorthand.properties()[i]); if (i && lastPropertyWasImportant != currentPropertyIsImportant) return String(); lastPropertyWasImportant = currentPropertyIsImportant; } return res; }
bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID) { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) return false; bool ret = removePropertiesInSet(shorthand.properties(), shorthand.length()); CSSPropertyID prefixingVariant = prefixingVariantForPropertyId(propertyID); if (prefixingVariant == propertyID) return ret; StylePropertyShorthand shorthandPrefixingVariant = shorthandForProperty(prefixingVariant); return removePropertiesInSet(shorthandPrefixingVariant.properties(), shorthandPrefixingVariant.length()); }
void MutableStylePropertySet::setProperty(CSSPropertyID propertyID, PassRefPtrWillBeRawPtr<CSSValue> prpValue, bool important) { StylePropertyShorthand shorthand = shorthandForProperty(propertyID); if (!shorthand.length()) { setProperty(CSSProperty(propertyID, prpValue, important)); return; } removePropertiesInSet(shorthand.properties(), shorthand.length()); RefPtrWillBeRawPtr<CSSValue> value = prpValue; for (unsigned i = 0; i < shorthand.length(); ++i) m_propertyVector.append(CSSProperty(shorthand.properties()[i], value, important)); }
String StylePropertySet::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const { String res; const unsigned size = shorthand.length(); // Begin by collecting the properties into an array. Vector< RefPtr<CSSValue> > values(size); size_t numLayers = 0; for (unsigned i = 0; i < size; ++i) { values[i] = getPropertyCSSValue(shorthand.properties()[i]); if (values[i]) { if (values[i]->isValueList()) { CSSValueList* valueList = static_cast<CSSValueList*>(values[i].get()); numLayers = max(valueList->length(), numLayers); } else numLayers = max<size_t>(1U, numLayers); } } // 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++) { String layerRes; bool useRepeatXShorthand = false; bool useRepeatYShorthand = false; bool useSingleWordShorthand = false; for (unsigned j = 0; j < size; j++) { RefPtr<CSSValue> value; if (values[j]) { if (values[j]->isValueList()) value = static_cast<CSSValueList*>(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 = 0; } else if (i != 0) // Other singletons only belong in the first layer. value = 0; } } // 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 && 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) { RefPtr<CSSValue> yValue; RefPtr<CSSValue> nextValue = values[j + 1]; if (nextValue->isValueList()) yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i); else yValue = nextValue; int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent(); int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent(); if (xId != yId) { if (xId == CSSValueRepeat && yId == CSSValueNoRepeat) { useRepeatXShorthand = true; ++j; } else if (xId == CSSValueNoRepeat && yId == CSSValueRepeat) { useRepeatYShorthand = true; continue; } } else { useSingleWordShorthand = true; ++j; } } } if (value && !value->isImplicitInitialValue()) { if (!layerRes.isNull()) layerRes += " "; if (useRepeatXShorthand) { useRepeatXShorthand = false; layerRes += getValueName(CSSValueRepeatX); } else if (useRepeatYShorthand) { useRepeatYShorthand = false; layerRes += getValueName(CSSValueRepeatY); } else if (useSingleWordShorthand) { useSingleWordShorthand = false; layerRes += value->cssText(); } else layerRes += value->cssText(); } } if (!layerRes.isNull()) { if (!res.isNull()) res += ", "; res += layerRes; } } return res; }
String StylePropertySet::getLayeredShorthandValue(const StylePropertyShorthand& shorthand) const { StringBuilder result; const unsigned size = shorthand.length(); // Begin by collecting the properties into an array. Vector< RefPtr<CSSValue> > values(size); size_t numLayers = 0; for (unsigned i = 0; i < size; ++i) { values[i] = getPropertyCSSValue(shorthand.properties()[i]); if (values[i]) { if (values[i]->isBaseValueList()) { CSSValueList* valueList = static_cast<CSSValueList*>(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++) { RefPtr<CSSValue> value; if (values[j]) { if (values[j]->isBaseValueList()) value = static_cast<CSSValueList*>(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 = 0; } else if (i != 0) // Other singletons only belong in the first layer. value = 0; } } // 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 && isPropertyImplicit(shorthand.properties()[j])) || (shorthand.properties()[j] == CSSPropertyWebkitMaskRepeatX && 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)) { RefPtr<CSSValue> yValue; RefPtr<CSSValue> nextValue = values[j + 1]; if (nextValue->isValueList()) yValue = static_cast<CSSValueList*>(nextValue.get())->itemWithoutBoundsCheck(i); else yValue = nextValue; int xId = static_cast<CSSPrimitiveValue*>(value.get())->getIdent(); int yId = static_cast<CSSPrimitiveValue*>(yValue.get())->getIdent(); 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(); }
static CSSPropertyID resolveToPhysicalProperty(TextDirection direction, WritingMode writingMode, LogicalBoxSide logicalSide, const StylePropertyShorthand& shorthand) { if (direction == LTR) { if (writingMode == TopToBottomWritingMode) { // The common case. The logical and physical box sides match. // Left = Start, Right = End, Before = Top, After = Bottom return shorthand.properties()[logicalSide]; } if (writingMode == BottomToTopWritingMode) { // Start = Left, End = Right, Before = Bottom, After = Top. switch (logicalSide) { case StartSide: return shorthand.properties()[LeftSide]; case EndSide: return shorthand.properties()[RightSide]; case BeforeSide: return shorthand.properties()[BottomSide]; default: return shorthand.properties()[TopSide]; } } if (writingMode == LeftToRightWritingMode) { // Start = Top, End = Bottom, Before = Left, After = Right. switch (logicalSide) { case StartSide: return shorthand.properties()[TopSide]; case EndSide: return shorthand.properties()[BottomSide]; case BeforeSide: return shorthand.properties()[LeftSide]; default: return shorthand.properties()[RightSide]; } } // Start = Top, End = Bottom, Before = Right, After = Left switch (logicalSide) { case StartSide: return shorthand.properties()[TopSide]; case EndSide: return shorthand.properties()[BottomSide]; case BeforeSide: return shorthand.properties()[RightSide]; default: return shorthand.properties()[LeftSide]; } } if (writingMode == TopToBottomWritingMode) { // Start = Right, End = Left, Before = Top, After = Bottom switch (logicalSide) { case StartSide: return shorthand.properties()[RightSide]; case EndSide: return shorthand.properties()[LeftSide]; case BeforeSide: return shorthand.properties()[TopSide]; default: return shorthand.properties()[BottomSide]; } } if (writingMode == BottomToTopWritingMode) { // Start = Right, End = Left, Before = Bottom, After = Top switch (logicalSide) { case StartSide: return shorthand.properties()[RightSide]; case EndSide: return shorthand.properties()[LeftSide]; case BeforeSide: return shorthand.properties()[BottomSide]; default: return shorthand.properties()[TopSide]; } } if (writingMode == LeftToRightWritingMode) { // Start = Bottom, End = Top, Before = Left, After = Right switch (logicalSide) { case StartSide: return shorthand.properties()[BottomSide]; case EndSide: return shorthand.properties()[TopSide]; case BeforeSide: return shorthand.properties()[LeftSide]; default: return shorthand.properties()[RightSide]; } } // Start = Bottom, End = Top, Before = Right, After = Left switch (logicalSide) { case StartSide: return shorthand.properties()[BottomSide]; case EndSide: return shorthand.properties()[TopSide]; case BeforeSide: return shorthand.properties()[RightSide]; default: return shorthand.properties()[LeftSide]; } }