static CSSValuePair* buildSerializablePositionOffset(CSSValue* offset, CSSValueID defaultSide) { CSSValueID side = defaultSide; CSSPrimitiveValue* amount = nullptr; if (!offset) { side = CSSValueCenter; } else if (offset->isPrimitiveValue() && toCSSPrimitiveValue(offset)->isValueID()) { side = toCSSPrimitiveValue(offset)->getValueID(); } else if (offset->isValuePair()) { side = toCSSPrimitiveValue(toCSSValuePair(*offset).first()).getValueID(); amount = &toCSSPrimitiveValue(toCSSValuePair(*offset).second()); if ((side == CSSValueRight || side == CSSValueBottom) && amount->isPercentage()) { side = defaultSide; amount = cssValuePool().createValue(100 - amount->getFloatValue(), CSSPrimitiveValue::UnitType::Percentage); } } else { amount = toCSSPrimitiveValue(offset); } if (side == CSSValueCenter) { side = defaultSide; amount = cssValuePool().createValue(50, CSSPrimitiveValue::UnitType::Percentage); } else if (!amount || (amount->isLength() && !amount->getFloatValue())) { if (side == CSSValueRight || side == CSSValueBottom) amount = cssValuePool().createValue(100, CSSPrimitiveValue::UnitType::Percentage); else amount = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Percentage); side = defaultSide; } return CSSValuePair::create(cssValuePool().createIdentifierValue(side), amount, CSSValuePair::KeepIdenticalValues); }
CSSPrimitiveValue* consumeAngle(CSSParserTokenRange& range) { const CSSParserToken& token = range.peek(); if (token.type() == DimensionToken) { switch (token.unitType()) { case CSSPrimitiveValue::UnitType::Degrees: case CSSPrimitiveValue::UnitType::Radians: case CSSPrimitiveValue::UnitType::Gradians: case CSSPrimitiveValue::UnitType::Turns: return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), token.unitType()); default: return nullptr; } } if (token.type() == NumberToken && token.numericValue() == 0) { range.consumeIncludingWhitespace(); return cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::Degrees); } CalcParser calcParser(range, ValueRangeAll); if (const CSSCalcValue* calculation = calcParser.value()) { if (calculation->category() == CalcAngle) return calcParser.consumeValue(); } return nullptr; }
PassRefPtrWillBeRawPtr<CSSValue> CSSParserFastPaths::parseColor(const String& string, bool quirksMode) { ASSERT(!string.isEmpty()); CSSParserString cssString; cssString.init(string); CSSValueID valueID = cssValueKeywordID(cssString); if (valueID == CSSValueWebkitText || valueID == CSSValueCurrentcolor || valueID == CSSValueGrey || (valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) return cssValuePool().createIdentifierValue(valueID); RGBA32 color; // Fast path for hex colors and rgb()/rgba() colors bool parseResult; if (string.is8Bit()) parseResult = fastParseColorInternal(color, string.characters8(), string.length(), quirksMode); else parseResult = fastParseColorInternal(color, string.characters16(), string.length(), quirksMode); if (parseResult) return cssValuePool().createColorValue(color); Color namedColor; if (!namedColor.setNamedColor(string)) return nullptr; return cssValuePool().createColorValue(namedColor.rgb()); }
static PassRefPtrWillBeRawPtr<CSSValue> parseKeywordValue(CSSPropertyID propertyId, const String& string) { ASSERT(!string.isEmpty()); if (!CSSParserFastPaths::isKeywordPropertyID(propertyId)) { // All properties accept the values of "initial" and "inherit". String lowerCaseString = string.lower(); if (lowerCaseString != "initial" && lowerCaseString != "inherit") return nullptr; // Parse initial/inherit shorthands using the CSSPropertyParser. if (shorthandForProperty(propertyId).length()) return nullptr; } CSSParserString cssString; cssString.init(string); CSSValueID valueID = cssValueKeywordID(cssString); if (!valueID) return nullptr; if (valueID == CSSValueInherit) return cssValuePool().createInheritedValue(); if (valueID == CSSValueInitial) return cssValuePool().createExplicitInitialValue(); if (CSSParserFastPaths::isValidKeywordPropertyAndValue(propertyId, valueID)) return cssValuePool().createIdentifierValue(valueID); return nullptr; }
static PassRefPtrWillBeRawPtr<CSSValue> parseColorValue(CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode) { ASSERT(!string.isEmpty()); bool quirksMode = isQuirksModeBehavior(cssParserMode); if (!isColorPropertyID(propertyId)) return nullptr; CSSParserString cssString; cssString.init(string); CSSValueID valueID = cssValueKeywordID(cssString); bool validPrimitive = false; if (valueID == CSSValueWebkitText) { validPrimitive = true; } else if (valueID == CSSValueCurrentcolor) { validPrimitive = true; } else if ((valueID >= CSSValueAqua && valueID <= CSSValueWindowtext) || valueID == CSSValueMenu || (quirksMode && valueID >= CSSValueWebkitFocusRingColor && valueID < CSSValueWebkitText)) { validPrimitive = true; } if (validPrimitive) return cssValuePool().createIdentifierValue(valueID); RGBA32 color; if (!CSSPropertyParser::fastParseColor(color, string, !quirksMode && string[0] != '#')) return nullptr; return cssValuePool().createColorValue(color); }
CSSIdentifierValue* CSSIdentifierValue::create(CSSValueID valueID) { CSSIdentifierValue* cssValue = cssValuePool().identifierCacheValue(valueID); if (!cssValue) { cssValue = cssValuePool().setIdentifierCacheValue( valueID, new CSSIdentifierValue(valueID)); } return cssValue; }
PassRefPtrWillBeRawPtr<CSSFunctionValue> ScaleTransformComponent::toCSSValue() const { RefPtrWillBeRawPtr<CSSFunctionValue> result = CSSFunctionValue::create(m_is2D ? CSSValueScale : CSSValueScale3d); result->append(cssValuePool().createValue(m_x, CSSPrimitiveValue::UnitType::Number)); result->append(cssValuePool().createValue(m_y, CSSPrimitiveValue::UnitType::Number)); if (!m_is2D) result->append(cssValuePool().createValue(m_z, CSSPrimitiveValue::UnitType::Number)); return result.release(); }
RawPtr<CSSValue> CSSVariableResolver::resolveVariableReferences(StyleVariableData* styleVariableData, CSSPropertyID id, const CSSVariableReferenceValue& value) { ASSERT(!isShorthandProperty(id)); CSSVariableResolver resolver(styleVariableData); Vector<CSSParserToken> tokens; if (!resolver.resolveTokenRange(value.variableDataValue()->tokens(), tokens)) return cssValuePool().createUnsetValue(); RawPtr<CSSValue> result = CSSPropertyParser::parseSingleValue(id, tokens, strictCSSParserContext()); if (!result) return cssValuePool().createUnsetValue(); return result.release(); }
CSSPrimitiveValue* consumeLength(CSSParserTokenRange& range, CSSParserMode cssParserMode, ValueRange valueRange, UnitlessQuirk unitless) { const CSSParserToken& token = range.peek(); if (token.type() == DimensionToken) { switch (token.unitType()) { case CSSPrimitiveValue::UnitType::QuirkyEms: if (cssParserMode != UASheetMode) return nullptr; /* fallthrough intentional */ case CSSPrimitiveValue::UnitType::Ems: case CSSPrimitiveValue::UnitType::Rems: case CSSPrimitiveValue::UnitType::Chs: case CSSPrimitiveValue::UnitType::Exs: case CSSPrimitiveValue::UnitType::Pixels: case CSSPrimitiveValue::UnitType::Centimeters: case CSSPrimitiveValue::UnitType::Millimeters: case CSSPrimitiveValue::UnitType::Inches: case CSSPrimitiveValue::UnitType::Points: case CSSPrimitiveValue::UnitType::Picas: case CSSPrimitiveValue::UnitType::UserUnits: case CSSPrimitiveValue::UnitType::ViewportWidth: case CSSPrimitiveValue::UnitType::ViewportHeight: case CSSPrimitiveValue::UnitType::ViewportMin: case CSSPrimitiveValue::UnitType::ViewportMax: break; default: return nullptr; } if (valueRange == ValueRangeNonNegative && token.numericValue() < 0) return nullptr; return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), token.unitType()); } if (token.type() == NumberToken) { if (!shouldAcceptUnitlessLength(token.numericValue(), cssParserMode, unitless) || (valueRange == ValueRangeNonNegative && token.numericValue() < 0)) return nullptr; CSSPrimitiveValue::UnitType unitType = CSSPrimitiveValue::UnitType::Pixels; if (cssParserMode == SVGAttributeMode) unitType = CSSPrimitiveValue::UnitType::UserUnits; return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), unitType); } if (cssParserMode == SVGAttributeMode) return nullptr; CalcParser calcParser(range, valueRange); if (calcParser.value() && calcParser.value()->category() == CalcLength) return calcParser.consumeValue(); return nullptr; }
SVGLength::SVGLength(SVGLengthMode mode) : SVGPropertyBase(classType()) , m_value(cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::UserUnits)) , m_unitMode(static_cast<unsigned>(mode)) { ASSERT(unitMode() == mode); }
bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitType unit) { ASSERT(isStyledElement()); ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createValue(value, unit)); inlineStyleChanged(); return true; }
bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier) { ASSERT(isStyledElement()); ensureMutableInlineStyle().setProperty(propertyID, cssValuePool().createIdentifierValue(identifier)); inlineStyleChanged(); return true; }
static PassRefPtrWillBeRawPtr<CSSValue> parseSimpleLengthValue(CSSPropertyID propertyId, const String& string, CSSParserMode cssParserMode) { ASSERT(!string.isEmpty()); bool acceptsNegativeNumbers = false; // In @viewport, width and height are shorthands, not simple length values. if (isCSSViewportParsingEnabledForMode(cssParserMode) || !isSimpleLengthPropertyID(propertyId, acceptsNegativeNumbers)) return nullptr; unsigned length = string.length(); double number; CSSPrimitiveValue::UnitType unit = CSSPrimitiveValue::CSS_NUMBER; if (string.is8Bit()) { if (!parseSimpleLength(string.characters8(), length, unit, number)) return nullptr; } else { if (!parseSimpleLength(string.characters16(), length, unit, number)) return nullptr; } if (unit == CSSPrimitiveValue::CSS_NUMBER) { bool quirksMode = isQuirksModeBehavior(cssParserMode); if (number && !quirksMode) return nullptr; unit = CSSPrimitiveValue::CSS_PX; } if (number < 0 && !acceptsNegativeNumbers) return nullptr; return cssValuePool().createValue(number, unit); }
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()); }
CSSColorValue* CSSColorValue::create(RGBA32 color) { // These are the empty and deleted values of the hash table. if (color == Color::transparent) return cssValuePool().transparentColor(); if (color == Color::white) return cssValuePool().whiteColor(); // Just because it is common. if (color == Color::black) return cssValuePool().blackColor(); CSSValuePool::ColorValueCache::AddResult entry = cssValuePool().getColorCacheEntry(color); if (entry.isNewEntry) entry.storedValue->value = new CSSColorValue(color); return entry.storedValue->value; }
static void positionFromOneValue(CSSPrimitiveValue* value, CSSValue*& resultX, CSSValue*& resultY) { bool valueAppliesToYAxisOnly = isVerticalPositionKeywordOnly(*value); resultX = value; resultY = cssValuePool().createIdentifierValue(CSSValueCenter); if (valueAppliesToYAxisOnly) std::swap(resultX, resultY); }
CSSPrimitiveValue* consumeNumber() { if (!m_calcValue) return nullptr; m_sourceRange = m_range; CSSPrimitiveValue::UnitType unitType = m_calcValue->isInt() ? CSSPrimitiveValue::UnitType::Integer : CSSPrimitiveValue::UnitType::Number; return cssValuePool().createValue(m_calcValue->doubleValue(), unitType); }
PassRefPtrWillBeRawPtr<SVGPropertyBase> SVGLength::cloneForAnimation(const String& value) const { RefPtrWillBeRawPtr<SVGLength> length = create(); length->m_unitMode = m_unitMode; if (length->setValueAsString(value) != SVGParseStatus::NoError) length->m_value = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::UserUnits); return length.release(); }
SVGPropertyBase* SVGLength::cloneForAnimation(const String& value) const { SVGLength* length = create(); length->m_unitMode = m_unitMode; if (length->setValueAsString(value) != SVGParseStatus::NoError) length->m_value = cssValuePool().createValue(0, CSSPrimitiveValue::UnitType::UserUnits); return length; }
CSSFunctionValue* MatrixTransformComponent::toCSSValue() const { CSSFunctionValue* result = CSSFunctionValue::create(m_is2D ? CSSValueMatrix : CSSValueMatrix3d); if (m_is2D) { double values[6] = {a(), b(), c(), d(), e(), f()}; for (double value : values) { result->append(cssValuePool().createValue(value, CSSPrimitiveValue::UnitType::Number)); } } else { double values[16] = {m11(), m12(), m13(), m14(), m21(), m22(), m23(), m24(), m31(), m32(), m33(), m34(), m41(), m42(), m43(), m44() }; for (double value : values) { result->append(cssValuePool().createValue(value, CSSPrimitiveValue::UnitType::Number)); } } return result; }
static PassRefPtr<CSSPrimitiveValue> buildSerializablePositionOffset(PassRefPtr<CSSPrimitiveValue> offset, CSSValueID defaultSide) { CSSValueID side = defaultSide; RefPtr<CSSPrimitiveValue> amount; if (!offset) side = CSSValueCenter; else if (offset->isValueID()) side = offset->getValueID(); else if (Pair* pair = offset->getPairValue()) { side = pair->first()->getValueID(); amount = pair->second(); } else amount = offset; if (side == CSSValueCenter) { side = defaultSide; amount = cssValuePool().createValue(Length(50, Percent)); } else if ((side == CSSValueRight || side == CSSValueBottom) && amount->isPercentage()) { side = defaultSide; amount = cssValuePool().createValue(Length(100 - amount->getFloatValue(), Percent)); } else if (amount->isLength() && !amount->getFloatValue()) { if (side == CSSValueRight || side == CSSValueBottom) amount = cssValuePool().createValue(Length(100, Percent)); else amount = cssValuePool().createValue(Length(0, Percent)); side = defaultSide; } return cssValuePool().createValue(Pair::create(cssValuePool().createValue(side), amount.release())); }
CSSValue* consumeColor(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool acceptQuirkyColors) { CSSValueID id = range.peek().id(); if (CSSPropertyParser::isColorKeyword(id)) { if (!isValueAllowedInMode(id, cssParserMode)) return nullptr; return consumeIdent(range); } RGBA32 color = Color::transparent; if (!parseHexColor(range, color, acceptQuirkyColors) && !parseColorFunction(range, color)) return nullptr; return cssValuePool().createColorValue(color); }
CSSPrimitiveValue* consumePercent(CSSParserTokenRange& range, ValueRange valueRange) { const CSSParserToken& token = range.peek(); if (token.type() == PercentageToken) { if (valueRange == ValueRangeNonNegative && token.numericValue() < 0) return nullptr; return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Percentage); } CalcParser calcParser(range, valueRange); if (const CSSCalcValue* calculation = calcParser.value()) { if (calculation->category() == CalcPercent) return calcParser.consumeValue(); } return nullptr; }
PassRefPtrWillBeRawPtr<StylePropertySet> HTMLTableElement::createSharedCellStyle() { RefPtrWillBeRawPtr<MutableStylePropertySet> style = MutableStylePropertySet::create(); switch (cellBorders()) { case SolidBordersColsOnly: style->setProperty(CSSPropertyBorderLeftWidth, CSSValueThin); style->setProperty(CSSPropertyBorderRightWidth, CSSValueThin); style->setProperty(CSSPropertyBorderLeftStyle, CSSValueSolid); style->setProperty(CSSPropertyBorderRightStyle, CSSValueSolid); style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue()); break; case SolidBordersRowsOnly: style->setProperty(CSSPropertyBorderTopWidth, CSSValueThin); style->setProperty(CSSPropertyBorderBottomWidth, CSSValueThin); style->setProperty(CSSPropertyBorderTopStyle, CSSValueSolid); style->setProperty(CSSPropertyBorderBottomStyle, CSSValueSolid); style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue()); break; case SolidBorders: style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX)); style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueSolid)); style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue()); break; case InsetBorders: style->setProperty(CSSPropertyBorderWidth, cssValuePool().createValue(1, CSSPrimitiveValue::CSS_PX)); style->setProperty(CSSPropertyBorderStyle, cssValuePool().createIdentifierValue(CSSValueInset)); style->setProperty(CSSPropertyBorderColor, cssValuePool().createInheritedValue()); break; case NoBorders: // If 'rules=none' then allow any borders set at cell level to take effect. break; } if (m_padding) style->setProperty(CSSPropertyPadding, cssValuePool().createValue(m_padding, CSSPrimitiveValue::CSS_PX)); return style.release(); }
static bool parseTransformNumberArguments(CharType*& pos, CharType* end, unsigned expectedCount, CSSFunctionValue* transformValue) { while (expectedCount) { size_t delimiter = WTF::find(pos, end - pos, expectedCount == 1 ? ')' : ','); if (delimiter == kNotFound) return false; unsigned argumentLength = static_cast<unsigned>(delimiter); bool ok; double number = charactersToDouble(pos, argumentLength, &ok); if (!ok) return false; transformValue->append(cssValuePool().createValue(number, CSSPrimitiveValue::CSS_NUMBER)); pos += argumentLength + 1; --expectedCount; } return true; }
PassRefPtrWillBeRawPtr<CSSValue> CSSComputedStyleDeclaration::getFontSizeCSSValuePreferringKeyword() const { if (!m_node) return nullptr; m_node->document().updateLayoutIgnorePendingStylesheets(); const ComputedStyle* style = m_node->ensureComputedStyle(m_pseudoElementSpecifier); if (!style) return nullptr; if (int keywordSize = style->fontDescription().keywordSize()) return cssValuePool().createIdentifierValue(cssIdentifierForFontSizeKeyword(keywordSize)); return zoomAdjustedPixelValue(style->fontDescription().computedPixelSize(), *style); }
CSSPrimitiveValue* consumeTime(CSSParserTokenRange& range, ValueRange valueRange) { const CSSParserToken& token = range.peek(); if (token.type() == DimensionToken) { if (valueRange == ValueRangeNonNegative && token.numericValue() < 0) return nullptr; CSSPrimitiveValue::UnitType unit = token.unitType(); if (unit == CSSPrimitiveValue::UnitType::Milliseconds || unit == CSSPrimitiveValue::UnitType::Seconds) return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), token.unitType()); return nullptr; } CalcParser calcParser(range, valueRange); if (const CSSCalcValue* calculation = calcParser.value()) { if (calculation->category() == CalcTime) return calcParser.consumeValue(); } return nullptr; }
// TODO(timloh): Work out if this can just call consumeNumberRaw CSSPrimitiveValue* consumeNumber(CSSParserTokenRange& range, ValueRange valueRange) { const CSSParserToken& token = range.peek(); if (token.type() == NumberToken) { if (valueRange == ValueRangeNonNegative && token.numericValue() < 0) return nullptr; return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), token.unitType()); } CalcParser calcParser(range, ValueRangeAll); if (const CSSCalcValue* calculation = calcParser.value()) { // TODO(rwlbuis) Calcs should not be subject to parse time range checks. // spec: https://drafts.csswg.org/css-values-3/#calc-range if (calculation->category() != CalcNumber || (valueRange == ValueRangeNonNegative && calculation->isNegative())) return nullptr; return calcParser.consumeNumber(); } return nullptr; }
CSSPrimitiveValue* consumeInteger(CSSParserTokenRange& range, double minimumValue) { const CSSParserToken& token = range.peek(); if (token.type() == NumberToken) { if (token.numericValueType() == NumberValueType || token.numericValue() < minimumValue) return nullptr; return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), CSSPrimitiveValue::UnitType::Integer); } CalcParser calcParser(range); if (const CSSCalcValue* calculation = calcParser.value()) { if (calculation->category() != CalcNumber || !calculation->isInt()) return nullptr; double value = calculation->doubleValue(); if (value < minimumValue) return nullptr; return calcParser.consumeNumber(); } return nullptr; }
// Color parsing that matches HTML's "rules for parsing a legacy color value" void HTMLElement::addHTMLColorToStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& attributeValue) { // An empty string doesn't apply a color. (One containing only whitespace does, which is why this check occurs before stripping.) if (attributeValue.isEmpty()) return; String colorString = attributeValue.stripWhiteSpace(); // "transparent" doesn't apply a color either. if (equalIgnoringCase(colorString, "transparent")) return; // If the string is a named CSS color or a 3/6-digit hex color, use that. Color parsedColor; if (!parsedColor.setFromString(colorString)) parsedColor.setRGB(parseColorStringWithCrazyLegacyRules(colorString)); style->setProperty(propertyID, cssValuePool().createColorValue(parsedColor.rgb())); }