blob: b6bddaeb3e3d9ea2c6e002f796c4479f510ae056 [file] [log] [blame]
/*
* Copyright (C) 2004 Zack Rusin <zack@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc.
* All rights reserved.
* Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
* Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
* Copyright (C) 2011 Sencha, Inc. All rights reserved.
* Copyright (C) 2015 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include "core/css/ComputedStyleCSSValueMapping.h"
#include "core/StylePropertyShorthand.h"
#include "core/animation/css/CSSAnimationData.h"
#include "core/animation/css/CSSTransitionData.h"
#include "core/css/BasicShapeFunctions.h"
#include "core/css/CSSBasicShapeValues.h"
#include "core/css/CSSBorderImage.h"
#include "core/css/CSSBorderImageSliceValue.h"
#include "core/css/CSSColorValue.h"
#include "core/css/CSSCounterValue.h"
#include "core/css/CSSCursorImageValue.h"
#include "core/css/CSSCustomIdentValue.h"
#include "core/css/CSSCustomPropertyDeclaration.h"
#include "core/css/CSSFontFamilyValue.h"
#include "core/css/CSSFontFeatureValue.h"
#include "core/css/CSSFontVariationValue.h"
#include "core/css/CSSFunctionValue.h"
#include "core/css/CSSGridLineNamesValue.h"
#include "core/css/CSSGridTemplateAreasValue.h"
#include "core/css/CSSIdentifierValue.h"
#include "core/css/CSSInitialValue.h"
#include "core/css/CSSPathValue.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSPrimitiveValueMappings.h"
#include "core/css/CSSQuadValue.h"
#include "core/css/CSSReflectValue.h"
#include "core/css/CSSShadowValue.h"
#include "core/css/CSSStringValue.h"
#include "core/css/CSSTimingFunctionValue.h"
#include "core/css/CSSURIValue.h"
#include "core/css/CSSValueList.h"
#include "core/css/CSSValuePair.h"
#include "core/css/PropertyRegistry.h"
#include "core/layout/LayoutBlock.h"
#include "core/layout/LayoutBox.h"
#include "core/layout/LayoutGrid.h"
#include "core/layout/LayoutObject.h"
#include "core/style/ComputedStyle.h"
#include "core/style/ContentData.h"
#include "core/style/CursorData.h"
#include "core/style/QuotesData.h"
#include "core/style/ShadowList.h"
#include "core/style/StyleInheritedVariables.h"
#include "core/style/StyleNonInheritedVariables.h"
#include "platform/LengthFunctions.h"
namespace blink {
inline static bool isFlexOrGrid(const ComputedStyle* style) {
return style && style->isDisplayFlexibleOrGridBox();
}
inline static CSSPrimitiveValue* zoomAdjustedPixelValue(
double value,
const ComputedStyle& style) {
return CSSPrimitiveValue::create(adjustFloatForAbsoluteZoom(value, style),
CSSPrimitiveValue::UnitType::Pixels);
}
inline static CSSValue* zoomAdjustedPixelValueOrAuto(
const Length& length,
const ComputedStyle& style) {
if (length.isAuto())
return CSSIdentifierValue::create(CSSValueAuto);
return zoomAdjustedPixelValue(length.value(), style);
}
static CSSValue* zoomAdjustedPixelValueForLength(const Length& length,
const ComputedStyle& style) {
if (length.isFixed())
return zoomAdjustedPixelValue(length.value(), style);
return CSSValue::create(length, style.effectiveZoom());
}
static CSSValue* pixelValueForUnzoomedLength(
const UnzoomedLength& unzoomedLength,
const ComputedStyle& style) {
const Length& length = unzoomedLength.length();
if (length.isFixed())
return CSSPrimitiveValue::create(length.value(),
CSSPrimitiveValue::UnitType::Pixels);
return CSSValue::create(length, style.effectiveZoom());
}
static CSSValueList* createPositionListForLayer(CSSPropertyID propertyID,
const FillLayer& layer,
const ComputedStyle& style) {
CSSValueList* positionList = CSSValueList::createSpaceSeparated();
if (layer.isBackgroundXOriginSet()) {
DCHECK(propertyID == CSSPropertyBackgroundPosition ||
propertyID == CSSPropertyWebkitMaskPosition);
positionList->append(
*CSSIdentifierValue::create(layer.backgroundXOrigin()));
}
positionList->append(
*zoomAdjustedPixelValueForLength(layer.xPosition(), style));
if (layer.isBackgroundYOriginSet()) {
ASSERT(propertyID == CSSPropertyBackgroundPosition ||
propertyID == CSSPropertyWebkitMaskPosition);
positionList->append(
*CSSIdentifierValue::create(layer.backgroundYOrigin()));
}
positionList->append(
*zoomAdjustedPixelValueForLength(layer.yPosition(), style));
return positionList;
}
CSSValue* ComputedStyleCSSValueMapping::currentColorOrValidColor(
const ComputedStyle& style,
const StyleColor& color) {
// This function does NOT look at visited information, so that computed style
// doesn't expose that.
return CSSColorValue::create(color.resolve(style.color()).rgb());
}
static CSSValue* valueForFillSize(const FillSize& fillSize,
const ComputedStyle& style) {
if (fillSize.type == Contain)
return CSSIdentifierValue::create(CSSValueContain);
if (fillSize.type == Cover)
return CSSIdentifierValue::create(CSSValueCover);
if (fillSize.size.height().isAuto())
return zoomAdjustedPixelValueForLength(fillSize.size.width(), style);
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*zoomAdjustedPixelValueForLength(fillSize.size.width(), style));
list->append(*zoomAdjustedPixelValueForLength(fillSize.size.height(), style));
return list;
}
static CSSValue* valueForFillRepeat(EFillRepeat xRepeat, EFillRepeat yRepeat) {
// For backwards compatibility, if both values are equal, just return one of
// them. And if the two values are equivalent to repeat-x or repeat-y, just
// return the shorthand.
if (xRepeat == yRepeat)
return CSSIdentifierValue::create(xRepeat);
if (xRepeat == RepeatFill && yRepeat == NoRepeatFill)
return CSSIdentifierValue::create(CSSValueRepeatX);
if (xRepeat == NoRepeatFill && yRepeat == RepeatFill)
return CSSIdentifierValue::create(CSSValueRepeatY);
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*CSSIdentifierValue::create(xRepeat));
list->append(*CSSIdentifierValue::create(yRepeat));
return list;
}
static CSSValue* valueForFillSourceType(EMaskSourceType type) {
switch (type) {
case MaskAlpha:
return CSSIdentifierValue::create(CSSValueAlpha);
case MaskLuminance:
return CSSIdentifierValue::create(CSSValueLuminance);
}
ASSERT_NOT_REACHED();
return nullptr;
}
static CSSValue* valueForPositionOffset(const ComputedStyle& style,
CSSPropertyID propertyID,
const LayoutObject* layoutObject) {
Length offset, opposite;
switch (propertyID) {
case CSSPropertyLeft:
offset = style.left();
opposite = style.right();
break;
case CSSPropertyRight:
offset = style.right();
opposite = style.left();
break;
case CSSPropertyTop:
offset = style.top();
opposite = style.bottom();
break;
case CSSPropertyBottom:
offset = style.bottom();
opposite = style.top();
break;
default:
return nullptr;
}
if (offset.isPercentOrCalc() && layoutObject && layoutObject->isBox() &&
layoutObject->isPositioned()) {
LayoutUnit containingBlockSize =
(propertyID == CSSPropertyLeft || propertyID == CSSPropertyRight)
? toLayoutBox(layoutObject)->containingBlockLogicalWidthForContent()
: toLayoutBox(layoutObject)
->containingBlockLogicalHeightForGetComputedStyle();
return zoomAdjustedPixelValue(valueForLength(offset, containingBlockSize),
style);
}
if (offset.isAuto() && layoutObject) {
// If the property applies to a positioned element and the resolved value of
// the display property is not none, the resolved value is the used value.
if (layoutObject->isInFlowPositioned()) {
// If e.g. left is auto and right is not auto, then left's computed value
// is negative right. So we get the opposite length unit and see if it is
// auto.
if (opposite.isAuto())
return CSSPrimitiveValue::create(0,
CSSPrimitiveValue::UnitType::Pixels);
if (opposite.isPercentOrCalc()) {
if (layoutObject->isBox()) {
LayoutUnit containingBlockSize =
(propertyID == CSSPropertyLeft || propertyID == CSSPropertyRight)
? toLayoutBox(layoutObject)
->containingBlockLogicalWidthForContent()
: toLayoutBox(layoutObject)
->containingBlockLogicalHeightForGetComputedStyle();
return zoomAdjustedPixelValue(
-floatValueForLength(opposite, containingBlockSize), style);
}
// FIXME: fall back to auto for position:relative, display:inline
return CSSIdentifierValue::create(CSSValueAuto);
}
// Length doesn't provide operator -, so multiply by -1.
opposite *= -1.f;
return zoomAdjustedPixelValueForLength(opposite, style);
}
if (layoutObject->isOutOfFlowPositioned() && layoutObject->isBox()) {
// For fixed and absolute positioned elements, the top, left, bottom, and
// right are defined relative to the corresponding sides of the containing
// block.
LayoutBlock* container = layoutObject->containingBlock();
const LayoutBox* layoutBox = toLayoutBox(layoutObject);
// clientOffset is the distance from this object's border edge to the
// container's padding edge. Thus it includes margins which we subtract
// below.
const LayoutSize clientOffset =
layoutBox->locationOffset() -
LayoutSize(container->clientLeft(), container->clientTop());
LayoutUnit position;
switch (propertyID) {
case CSSPropertyLeft:
position = clientOffset.width() - layoutBox->marginLeft();
break;
case CSSPropertyTop:
position = clientOffset.height() - layoutBox->marginTop();
break;
case CSSPropertyRight:
position = container->clientWidth() - layoutBox->marginRight() -
(layoutBox->offsetWidth() + clientOffset.width());
break;
case CSSPropertyBottom:
position = container->clientHeight() - layoutBox->marginBottom() -
(layoutBox->offsetHeight() + clientOffset.height());
break;
default:
ASSERT_NOT_REACHED();
}
return zoomAdjustedPixelValue(position, style);
}
}
if (offset.isAuto())
return CSSIdentifierValue::create(CSSValueAuto);
return zoomAdjustedPixelValueForLength(offset, style);
}
static CSSBorderImageSliceValue* valueForNinePieceImageSlice(
const NinePieceImage& image) {
// Create the slices.
CSSPrimitiveValue* top = nullptr;
CSSPrimitiveValue* right = nullptr;
CSSPrimitiveValue* bottom = nullptr;
CSSPrimitiveValue* left = nullptr;
// TODO(alancutter): Make this code aware of calc lengths.
if (image.imageSlices().top().isPercentOrCalc())
top = CSSPrimitiveValue::create(image.imageSlices().top().value(),
CSSPrimitiveValue::UnitType::Percentage);
else
top = CSSPrimitiveValue::create(image.imageSlices().top().value(),
CSSPrimitiveValue::UnitType::Number);
if (image.imageSlices().right() == image.imageSlices().top() &&
image.imageSlices().bottom() == image.imageSlices().top() &&
image.imageSlices().left() == image.imageSlices().top()) {
right = top;
bottom = top;
left = top;
} else {
if (image.imageSlices().right().isPercentOrCalc())
right =
CSSPrimitiveValue::create(image.imageSlices().right().value(),
CSSPrimitiveValue::UnitType::Percentage);
else
right = CSSPrimitiveValue::create(image.imageSlices().right().value(),
CSSPrimitiveValue::UnitType::Number);
if (image.imageSlices().bottom() == image.imageSlices().top() &&
image.imageSlices().right() == image.imageSlices().left()) {
bottom = top;
left = right;
} else {
if (image.imageSlices().bottom().isPercentOrCalc())
bottom =
CSSPrimitiveValue::create(image.imageSlices().bottom().value(),
CSSPrimitiveValue::UnitType::Percentage);
else
bottom = CSSPrimitiveValue::create(image.imageSlices().bottom().value(),
CSSPrimitiveValue::UnitType::Number);
if (image.imageSlices().left() == image.imageSlices().right()) {
left = right;
} else {
if (image.imageSlices().left().isPercentOrCalc())
left = CSSPrimitiveValue::create(
image.imageSlices().left().value(),
CSSPrimitiveValue::UnitType::Percentage);
else
left = CSSPrimitiveValue::create(image.imageSlices().left().value(),
CSSPrimitiveValue::UnitType::Number);
}
}
}
return CSSBorderImageSliceValue::create(
CSSQuadValue::create(top, right, bottom, left,
CSSQuadValue::SerializeAsQuad),
image.fill());
}
static CSSValue* valueForBorderImageLength(
const BorderImageLength& borderImageLength,
const ComputedStyle& style) {
if (borderImageLength.isNumber())
return CSSPrimitiveValue::create(borderImageLength.number(),
CSSPrimitiveValue::UnitType::Number);
return CSSValue::create(borderImageLength.length(), style.effectiveZoom());
}
static CSSQuadValue* valueForNinePieceImageQuad(const BorderImageLengthBox& box,
const ComputedStyle& style) {
// Create the slices.
CSSValue* top = nullptr;
CSSValue* right = nullptr;
CSSValue* bottom = nullptr;
CSSValue* left = nullptr;
top = valueForBorderImageLength(box.top(), style);
if (box.right() == box.top() && box.bottom() == box.top() &&
box.left() == box.top()) {
right = top;
bottom = top;
left = top;
} else {
right = valueForBorderImageLength(box.right(), style);
if (box.bottom() == box.top() && box.right() == box.left()) {
bottom = top;
left = right;
} else {
bottom = valueForBorderImageLength(box.bottom(), style);
if (box.left() == box.right())
left = right;
else
left = valueForBorderImageLength(box.left(), style);
}
}
return CSSQuadValue::create(top, right, bottom, left,
CSSQuadValue::SerializeAsQuad);
}
static CSSValueID valueForRepeatRule(int rule) {
switch (rule) {
case RepeatImageRule:
return CSSValueRepeat;
case RoundImageRule:
return CSSValueRound;
case SpaceImageRule:
return CSSValueSpace;
default:
return CSSValueStretch;
}
}
static CSSValue* valueForNinePieceImageRepeat(const NinePieceImage& image) {
CSSIdentifierValue* horizontalRepeat = nullptr;
CSSIdentifierValue* verticalRepeat = nullptr;
horizontalRepeat =
CSSIdentifierValue::create(valueForRepeatRule(image.horizontalRule()));
if (image.horizontalRule() == image.verticalRule()) {
verticalRepeat = horizontalRepeat;
} else {
verticalRepeat =
CSSIdentifierValue::create(valueForRepeatRule(image.verticalRule()));
}
return CSSValuePair::create(horizontalRepeat, verticalRepeat,
CSSValuePair::DropIdenticalValues);
}
static CSSValue* valueForNinePieceImage(const NinePieceImage& image,
const ComputedStyle& style) {
if (!image.hasImage())
return CSSIdentifierValue::create(CSSValueNone);
// Image first.
CSSValue* imageValue = nullptr;
if (image.image())
imageValue = image.image()->computedCSSValue();
// Create the image slice.
CSSBorderImageSliceValue* imageSlices = valueForNinePieceImageSlice(image);
// Create the border area slices.
CSSValue* borderSlices =
valueForNinePieceImageQuad(image.borderSlices(), style);
// Create the border outset.
CSSValue* outset = valueForNinePieceImageQuad(image.outset(), style);
// Create the repeat rules.
CSSValue* repeat = valueForNinePieceImageRepeat(image);
return createBorderImageValue(imageValue, imageSlices, borderSlices, outset,
repeat);
}
static CSSValue* valueForReflection(const StyleReflection* reflection,
const ComputedStyle& style) {
if (!reflection)
return CSSIdentifierValue::create(CSSValueNone);
CSSPrimitiveValue* offset = nullptr;
// TODO(alancutter): Make this work correctly for calc lengths.
if (reflection->offset().isPercentOrCalc())
offset = CSSPrimitiveValue::create(reflection->offset().percent(),
CSSPrimitiveValue::UnitType::Percentage);
else
offset = zoomAdjustedPixelValue(reflection->offset().value(), style);
CSSIdentifierValue* direction = nullptr;
switch (reflection->direction()) {
case ReflectionBelow:
direction = CSSIdentifierValue::create(CSSValueBelow);
break;
case ReflectionAbove:
direction = CSSIdentifierValue::create(CSSValueAbove);
break;
case ReflectionLeft:
direction = CSSIdentifierValue::create(CSSValueLeft);
break;
case ReflectionRight:
direction = CSSIdentifierValue::create(CSSValueRight);
break;
}
return CSSReflectValue::create(
direction, offset, valueForNinePieceImage(reflection->mask(), style));
}
static CSSValueList* valueForItemPositionWithOverflowAlignment(
const StyleSelfAlignmentData& data) {
CSSValueList* result = CSSValueList::createSpaceSeparated();
if (data.positionType() == LegacyPosition)
result->append(*CSSIdentifierValue::create(CSSValueLegacy));
// To avoid needing to copy the RareNonInheritedData, we repurpose the 'auto'
// flag to not just mean 'auto' prior to running the StyleAdjuster but also
// mean 'normal' after running it.
result->append(*CSSIdentifierValue::create(
data.position() == ItemPositionAuto
? ComputedStyle::initialDefaultAlignment().position()
: data.position()));
if (data.position() >= ItemPositionCenter &&
data.overflow() != OverflowAlignmentDefault)
result->append(*CSSIdentifierValue::create(data.overflow()));
ASSERT(result->length() <= 2);
return result;
}
static CSSValueList* valuesForGridShorthand(
const StylePropertyShorthand& shorthand,
const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
CSSValueList* list = CSSValueList::createSlashSeparated();
for (size_t i = 0; i < shorthand.length(); ++i) {
const CSSValue* value = ComputedStyleCSSValueMapping::get(
shorthand.properties()[i], style, layoutObject, styledNode,
allowVisitedStyle);
ASSERT(value);
list->append(*value);
}
return list;
}
static CSSValueList* valuesForShorthandProperty(
const StylePropertyShorthand& shorthand,
const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (size_t i = 0; i < shorthand.length(); ++i) {
const CSSValue* value = ComputedStyleCSSValueMapping::get(
shorthand.properties()[i], style, layoutObject, styledNode,
allowVisitedStyle);
ASSERT(value);
list->append(*value);
}
return list;
}
static CSSValue* expandNoneLigaturesValue() {
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*CSSIdentifierValue::create(CSSValueNoCommonLigatures));
list->append(*CSSIdentifierValue::create(CSSValueNoDiscretionaryLigatures));
list->append(*CSSIdentifierValue::create(CSSValueNoHistoricalLigatures));
list->append(*CSSIdentifierValue::create(CSSValueNoContextual));
return list;
}
static CSSValue* valuesForFontVariantProperty(const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
enum VariantShorthandCases { AllNormal, NoneLigatures, ConcatenateNonNormal };
VariantShorthandCases shorthandCase = AllNormal;
for (size_t i = 0; i < fontVariantShorthand().length(); ++i) {
const CSSValue* value = ComputedStyleCSSValueMapping::get(
fontVariantShorthand().properties()[i], style, layoutObject, styledNode,
allowVisitedStyle);
if (shorthandCase == AllNormal && value->isIdentifierValue() &&
toCSSIdentifierValue(value)->getValueID() == CSSValueNone &&
fontVariantShorthand().properties()[i] ==
CSSPropertyFontVariantLigatures) {
shorthandCase = NoneLigatures;
} else if (!(value->isIdentifierValue() &&
toCSSIdentifierValue(value)->getValueID() == CSSValueNormal)) {
shorthandCase = ConcatenateNonNormal;
break;
}
}
switch (shorthandCase) {
case AllNormal:
return CSSIdentifierValue::create(CSSValueNormal);
case NoneLigatures:
return CSSIdentifierValue::create(CSSValueNone);
case ConcatenateNonNormal: {
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (size_t i = 0; i < fontVariantShorthand().length(); ++i) {
const CSSValue* value = ComputedStyleCSSValueMapping::get(
fontVariantShorthand().properties()[i], style, layoutObject,
styledNode, allowVisitedStyle);
ASSERT(value);
if (value->isIdentifierValue() &&
toCSSIdentifierValue(value)->getValueID() == CSSValueNone) {
list->append(*expandNoneLigaturesValue());
} else if (!(value->isIdentifierValue() &&
toCSSIdentifierValue(value)->getValueID() ==
CSSValueNormal)) {
list->append(*value);
}
}
return list;
}
default:
NOTREACHED();
return nullptr;
}
}
static CSSValueList* valuesForBackgroundShorthand(
const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
CSSValueList* ret = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next()) {
CSSValueList* list = CSSValueList::createSlashSeparated();
CSSValueList* beforeSlash = CSSValueList::createSpaceSeparated();
if (!currLayer->next()) { // color only for final layer
const CSSValue* value = ComputedStyleCSSValueMapping::get(
CSSPropertyBackgroundColor, style, layoutObject, styledNode,
allowVisitedStyle);
ASSERT(value);
beforeSlash->append(*value);
}
beforeSlash->append(currLayer->image()
? *currLayer->image()->computedCSSValue()
: *CSSIdentifierValue::create(CSSValueNone));
beforeSlash->append(
*valueForFillRepeat(currLayer->repeatX(), currLayer->repeatY()));
beforeSlash->append(*CSSIdentifierValue::create(currLayer->attachment()));
beforeSlash->append(*createPositionListForLayer(
CSSPropertyBackgroundPosition, *currLayer, style));
list->append(*beforeSlash);
CSSValueList* afterSlash = CSSValueList::createSpaceSeparated();
afterSlash->append(*valueForFillSize(currLayer->size(), style));
afterSlash->append(*CSSIdentifierValue::create(currLayer->origin()));
afterSlash->append(*CSSIdentifierValue::create(currLayer->clip()));
list->append(*afterSlash);
ret->append(*list);
}
return ret;
}
static CSSValueList*
valueForContentPositionAndDistributionWithOverflowAlignment(
const StyleContentAlignmentData& data,
CSSValueID normalBehaviorValueID) {
CSSValueList* result = CSSValueList::createSpaceSeparated();
if (data.distribution() != ContentDistributionDefault)
result->append(*CSSIdentifierValue::create(data.distribution()));
if (data.distribution() == ContentDistributionDefault ||
data.position() != ContentPositionNormal) {
if (!RuntimeEnabledFeatures::cssGridLayoutEnabled() &&
data.position() == ContentPositionNormal)
result->append(*CSSIdentifierValue::create(normalBehaviorValueID));
else
result->append(*CSSIdentifierValue::create(data.position()));
}
if ((data.position() >= ContentPositionCenter ||
data.distribution() != ContentDistributionDefault) &&
data.overflow() != OverflowAlignmentDefault)
result->append(*CSSIdentifierValue::create(data.overflow()));
ASSERT(result->length() > 0);
ASSERT(result->length() <= 3);
return result;
}
static CSSValue* valueForLineHeight(const ComputedStyle& style) {
Length length = style.lineHeight();
if (length.isNegative())
return CSSIdentifierValue::create(CSSValueNormal);
return zoomAdjustedPixelValue(
floatValueForLength(length, style.getFontDescription().computedSize()),
style);
}
static CSSValue* valueForPosition(const LengthPoint& position,
const ComputedStyle& style) {
DCHECK((position.x() == Auto) == (position.y() == Auto));
if (position.x() == Auto) {
return CSSIdentifierValue::create(CSSValueAuto);
}
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*zoomAdjustedPixelValueForLength(position.x(), style));
list->append(*zoomAdjustedPixelValueForLength(position.y(), style));
return list;
}
static CSSValueID identifierForFamily(const AtomicString& family) {
if (family == FontFamilyNames::webkit_cursive)
return CSSValueCursive;
if (family == FontFamilyNames::webkit_fantasy)
return CSSValueFantasy;
if (family == FontFamilyNames::webkit_monospace)
return CSSValueMonospace;
if (family == FontFamilyNames::webkit_pictograph)
return CSSValueWebkitPictograph;
if (family == FontFamilyNames::webkit_sans_serif)
return CSSValueSansSerif;
if (family == FontFamilyNames::webkit_serif)
return CSSValueSerif;
return CSSValueInvalid;
}
static CSSValue* valueForFamily(const AtomicString& family) {
if (CSSValueID familyIdentifier = identifierForFamily(family))
return CSSIdentifierValue::create(familyIdentifier);
return CSSFontFamilyValue::create(family.getString());
}
static CSSValueList* valueForFontFamily(const ComputedStyle& style) {
const FontFamily& firstFamily = style.getFontDescription().family();
CSSValueList* list = CSSValueList::createCommaSeparated();
for (const FontFamily* family = &firstFamily; family; family = family->next())
list->append(*valueForFamily(family->family()));
return list;
}
static CSSPrimitiveValue* valueForFontSize(const ComputedStyle& style) {
return zoomAdjustedPixelValue(style.getFontDescription().computedSize(),
style);
}
static CSSIdentifierValue* valueForFontStretch(const ComputedStyle& style) {
return CSSIdentifierValue::create(style.getFontDescription().stretch());
}
static CSSIdentifierValue* valueForFontStyle(const ComputedStyle& style) {
return CSSIdentifierValue::create(style.getFontDescription().style());
}
static CSSIdentifierValue* valueForFontWeight(const ComputedStyle& style) {
return CSSIdentifierValue::create(style.getFontDescription().weight());
}
static CSSIdentifierValue* valueForFontVariantCaps(const ComputedStyle& style) {
FontDescription::FontVariantCaps variantCaps =
style.getFontDescription().variantCaps();
switch (variantCaps) {
case FontDescription::CapsNormal:
return CSSIdentifierValue::create(CSSValueNormal);
case FontDescription::SmallCaps:
return CSSIdentifierValue::create(CSSValueSmallCaps);
case FontDescription::AllSmallCaps:
return CSSIdentifierValue::create(CSSValueAllSmallCaps);
case FontDescription::PetiteCaps:
return CSSIdentifierValue::create(CSSValuePetiteCaps);
case FontDescription::AllPetiteCaps:
return CSSIdentifierValue::create(CSSValueAllPetiteCaps);
case FontDescription::Unicase:
return CSSIdentifierValue::create(CSSValueUnicase);
case FontDescription::TitlingCaps:
return CSSIdentifierValue::create(CSSValueTitlingCaps);
default:
NOTREACHED();
return nullptr;
}
}
static CSSValue* valueForFontVariantLigatures(const ComputedStyle& style) {
FontDescription::LigaturesState commonLigaturesState =
style.getFontDescription().commonLigaturesState();
FontDescription::LigaturesState discretionaryLigaturesState =
style.getFontDescription().discretionaryLigaturesState();
FontDescription::LigaturesState historicalLigaturesState =
style.getFontDescription().historicalLigaturesState();
FontDescription::LigaturesState contextualLigaturesState =
style.getFontDescription().contextualLigaturesState();
if (commonLigaturesState == FontDescription::NormalLigaturesState &&
discretionaryLigaturesState == FontDescription::NormalLigaturesState &&
historicalLigaturesState == FontDescription::NormalLigaturesState &&
contextualLigaturesState == FontDescription::NormalLigaturesState)
return CSSIdentifierValue::create(CSSValueNormal);
if (commonLigaturesState == FontDescription::DisabledLigaturesState &&
discretionaryLigaturesState == FontDescription::DisabledLigaturesState &&
historicalLigaturesState == FontDescription::DisabledLigaturesState &&
contextualLigaturesState == FontDescription::DisabledLigaturesState)
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* valueList = CSSValueList::createSpaceSeparated();
if (commonLigaturesState != FontDescription::NormalLigaturesState)
valueList->append(*CSSIdentifierValue::create(
commonLigaturesState == FontDescription::DisabledLigaturesState
? CSSValueNoCommonLigatures
: CSSValueCommonLigatures));
if (discretionaryLigaturesState != FontDescription::NormalLigaturesState)
valueList->append(*CSSIdentifierValue::create(
discretionaryLigaturesState == FontDescription::DisabledLigaturesState
? CSSValueNoDiscretionaryLigatures
: CSSValueDiscretionaryLigatures));
if (historicalLigaturesState != FontDescription::NormalLigaturesState)
valueList->append(*CSSIdentifierValue::create(
historicalLigaturesState == FontDescription::DisabledLigaturesState
? CSSValueNoHistoricalLigatures
: CSSValueHistoricalLigatures));
if (contextualLigaturesState != FontDescription::NormalLigaturesState)
valueList->append(*CSSIdentifierValue::create(
contextualLigaturesState == FontDescription::DisabledLigaturesState
? CSSValueNoContextual
: CSSValueContextual));
return valueList;
}
static CSSValue* valueForFontVariantNumeric(const ComputedStyle& style) {
FontVariantNumeric variantNumeric =
style.getFontDescription().variantNumeric();
if (variantNumeric.isAllNormal())
return CSSIdentifierValue::create(CSSValueNormal);
CSSValueList* valueList = CSSValueList::createSpaceSeparated();
if (variantNumeric.numericFigureValue() != FontVariantNumeric::NormalFigure)
valueList->append(*CSSIdentifierValue::create(
variantNumeric.numericFigureValue() == FontVariantNumeric::LiningNums
? CSSValueLiningNums
: CSSValueOldstyleNums));
if (variantNumeric.numericSpacingValue() !=
FontVariantNumeric::NormalSpacing) {
valueList->append(
*CSSIdentifierValue::create(variantNumeric.numericSpacingValue() ==
FontVariantNumeric::ProportionalNums
? CSSValueProportionalNums
: CSSValueTabularNums));
}
if (variantNumeric.numericFractionValue() !=
FontVariantNumeric::NormalFraction)
valueList->append(*CSSIdentifierValue::create(
variantNumeric.numericFractionValue() ==
FontVariantNumeric::DiagonalFractions
? CSSValueDiagonalFractions
: CSSValueStackedFractions));
if (variantNumeric.ordinalValue() == FontVariantNumeric::OrdinalOn)
valueList->append(*CSSIdentifierValue::create(CSSValueOrdinal));
if (variantNumeric.slashedZeroValue() == FontVariantNumeric::SlashedZeroOn)
valueList->append(*CSSIdentifierValue::create(CSSValueSlashedZero));
return valueList;
}
static CSSValue* specifiedValueForGridTrackBreadth(
const GridLength& trackBreadth,
const ComputedStyle& style) {
if (!trackBreadth.isLength())
return CSSPrimitiveValue::create(trackBreadth.flex(),
CSSPrimitiveValue::UnitType::Fraction);
const Length& trackBreadthLength = trackBreadth.length();
if (trackBreadthLength.isAuto())
return CSSIdentifierValue::create(CSSValueAuto);
return zoomAdjustedPixelValueForLength(trackBreadthLength, style);
}
static CSSValue* specifiedValueForGridTrackSize(const GridTrackSize& trackSize,
const ComputedStyle& style) {
switch (trackSize.type()) {
case LengthTrackSizing:
return specifiedValueForGridTrackBreadth(trackSize.minTrackBreadth(),
style);
case MinMaxTrackSizing: {
if (trackSize.minTrackBreadth().isAuto() &&
trackSize.maxTrackBreadth().isFlex()) {
return CSSPrimitiveValue::create(trackSize.maxTrackBreadth().flex(),
CSSPrimitiveValue::UnitType::Fraction);
}
auto* minMaxTrackBreadths = CSSFunctionValue::create(CSSValueMinmax);
minMaxTrackBreadths->append(*specifiedValueForGridTrackBreadth(
trackSize.minTrackBreadth(), style));
minMaxTrackBreadths->append(*specifiedValueForGridTrackBreadth(
trackSize.maxTrackBreadth(), style));
return minMaxTrackBreadths;
}
case FitContentTrackSizing: {
auto* fitContentTrackBreadth =
CSSFunctionValue::create(CSSValueFitContent);
fitContentTrackBreadth->append(*specifiedValueForGridTrackBreadth(
trackSize.fitContentTrackBreadth(), style));
return fitContentTrackBreadth;
}
}
ASSERT_NOT_REACHED();
return nullptr;
}
class OrderedNamedLinesCollector {
STACK_ALLOCATED();
WTF_MAKE_NONCOPYABLE(OrderedNamedLinesCollector);
public:
OrderedNamedLinesCollector(const ComputedStyle& style,
bool isRowAxis,
size_t autoRepeatTracksCount)
: m_orderedNamedGridLines(isRowAxis ? style.orderedNamedGridColumnLines()
: style.orderedNamedGridRowLines()),
m_orderedNamedAutoRepeatGridLines(
isRowAxis ? style.autoRepeatOrderedNamedGridColumnLines()
: style.autoRepeatOrderedNamedGridRowLines()),
m_insertionPoint(isRowAxis ? style.gridAutoRepeatColumnsInsertionPoint()
: style.gridAutoRepeatRowsInsertionPoint()),
m_autoRepeatTotalTracks(autoRepeatTracksCount),
m_autoRepeatTrackListLength(isRowAxis
? style.gridAutoRepeatColumns().size()
: style.gridAutoRepeatRows().size()) {}
bool isEmpty() const {
return m_orderedNamedGridLines.isEmpty() &&
m_orderedNamedAutoRepeatGridLines.isEmpty();
}
void collectLineNamesForIndex(CSSGridLineNamesValue&, size_t index) const;
private:
enum NamedLinesType { NamedLines, AutoRepeatNamedLines };
void appendLines(CSSGridLineNamesValue&, size_t index, NamedLinesType) const;
const OrderedNamedGridLines& m_orderedNamedGridLines;
const OrderedNamedGridLines& m_orderedNamedAutoRepeatGridLines;
size_t m_insertionPoint;
size_t m_autoRepeatTotalTracks;
size_t m_autoRepeatTrackListLength;
};
void OrderedNamedLinesCollector::appendLines(
CSSGridLineNamesValue& lineNamesValue,
size_t index,
NamedLinesType type) const {
auto iter = type == NamedLines
? m_orderedNamedGridLines.find(index)
: m_orderedNamedAutoRepeatGridLines.find(index);
auto endIter = type == NamedLines ? m_orderedNamedGridLines.end()
: m_orderedNamedAutoRepeatGridLines.end();
if (iter == endIter)
return;
for (auto lineName : iter->value)
lineNamesValue.append(*CSSCustomIdentValue::create(AtomicString(lineName)));
}
void OrderedNamedLinesCollector::collectLineNamesForIndex(
CSSGridLineNamesValue& lineNamesValue,
size_t i) const {
DCHECK(!isEmpty());
if (m_orderedNamedAutoRepeatGridLines.isEmpty() || i < m_insertionPoint) {
appendLines(lineNamesValue, i, NamedLines);
return;
}
DCHECK(m_autoRepeatTotalTracks);
if (i > m_insertionPoint + m_autoRepeatTotalTracks) {
appendLines(lineNamesValue, i - (m_autoRepeatTotalTracks - 1), NamedLines);
return;
}
if (i == m_insertionPoint) {
appendLines(lineNamesValue, i, NamedLines);
appendLines(lineNamesValue, 0, AutoRepeatNamedLines);
return;
}
if (i == m_insertionPoint + m_autoRepeatTotalTracks) {
appendLines(lineNamesValue, m_autoRepeatTrackListLength,
AutoRepeatNamedLines);
appendLines(lineNamesValue, m_insertionPoint + 1, NamedLines);
return;
}
size_t autoRepeatIndexInFirstRepetition =
(i - m_insertionPoint) % m_autoRepeatTrackListLength;
if (!autoRepeatIndexInFirstRepetition && i > m_insertionPoint)
appendLines(lineNamesValue, m_autoRepeatTrackListLength,
AutoRepeatNamedLines);
appendLines(lineNamesValue, autoRepeatIndexInFirstRepetition,
AutoRepeatNamedLines);
}
static void addValuesForNamedGridLinesAtIndex(
OrderedNamedLinesCollector& collector,
size_t i,
CSSValueList& list) {
if (collector.isEmpty())
return;
CSSGridLineNamesValue* lineNames = CSSGridLineNamesValue::create();
collector.collectLineNamesForIndex(*lineNames, i);
if (lineNames->length())
list.append(*lineNames);
}
static CSSValue* valueForGridTrackSizeList(GridTrackSizingDirection direction,
const ComputedStyle& style) {
const Vector<GridTrackSize>& autoTrackSizes =
direction == ForColumns ? style.gridAutoColumns() : style.gridAutoRows();
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (auto& trackSize : autoTrackSizes)
list->append(*specifiedValueForGridTrackSize(trackSize, style));
return list;
}
static CSSValue* valueForGridTrackList(GridTrackSizingDirection direction,
const LayoutObject* layoutObject,
const ComputedStyle& style) {
bool isRowAxis = direction == ForColumns;
const Vector<GridTrackSize>& trackSizes =
isRowAxis ? style.gridTemplateColumns() : style.gridTemplateRows();
const Vector<GridTrackSize>& autoRepeatTrackSizes =
isRowAxis ? style.gridAutoRepeatColumns() : style.gridAutoRepeatRows();
bool isLayoutGrid = layoutObject && layoutObject->isLayoutGrid();
// Handle the 'none' case.
bool trackListIsEmpty =
trackSizes.isEmpty() && autoRepeatTrackSizes.isEmpty();
if (isLayoutGrid && trackListIsEmpty) {
// For grids we should consider every listed track, whether implicitly or
// explicitly created. Empty grids have a sole grid line per axis.
auto& positions = isRowAxis ? toLayoutGrid(layoutObject)->columnPositions()
: toLayoutGrid(layoutObject)->rowPositions();
trackListIsEmpty = positions.size() == 1;
}
if (trackListIsEmpty)
return CSSIdentifierValue::create(CSSValueNone);
size_t autoRepeatTotalTracks =
isLayoutGrid
? toLayoutGrid(layoutObject)->autoRepeatCountForDirection(direction)
: 0;
OrderedNamedLinesCollector collector(style, isRowAxis, autoRepeatTotalTracks);
CSSValueList* list = CSSValueList::createSpaceSeparated();
size_t insertionIndex;
if (isLayoutGrid) {
const auto* grid = toLayoutGrid(layoutObject);
Vector<LayoutUnit> computedTrackSizes =
grid->trackSizesForComputedStyle(direction);
size_t numTracks = computedTrackSizes.size();
for (size_t i = 0; i < numTracks; ++i) {
addValuesForNamedGridLinesAtIndex(collector, i, *list);
list->append(*zoomAdjustedPixelValue(computedTrackSizes[i], style));
}
addValuesForNamedGridLinesAtIndex(collector, numTracks + 1, *list);
insertionIndex = numTracks;
} else {
for (size_t i = 0; i < trackSizes.size(); ++i) {
addValuesForNamedGridLinesAtIndex(collector, i, *list);
list->append(*specifiedValueForGridTrackSize(trackSizes[i], style));
}
insertionIndex = trackSizes.size();
}
// Those are the trailing <string>* allowed in the syntax.
addValuesForNamedGridLinesAtIndex(collector, insertionIndex, *list);
return list;
}
static CSSValue* valueForGridPosition(const GridPosition& position) {
if (position.isAuto())
return CSSIdentifierValue::create(CSSValueAuto);
if (position.isNamedGridArea())
return CSSCustomIdentValue::create(position.namedGridLine());
CSSValueList* list = CSSValueList::createSpaceSeparated();
if (position.isSpan()) {
list->append(*CSSIdentifierValue::create(CSSValueSpan));
list->append(*CSSPrimitiveValue::create(
position.spanPosition(), CSSPrimitiveValue::UnitType::Number));
} else {
list->append(*CSSPrimitiveValue::create(
position.integerPosition(), CSSPrimitiveValue::UnitType::Number));
}
if (!position.namedGridLine().isNull())
list->append(*CSSCustomIdentValue::create(position.namedGridLine()));
return list;
}
static LayoutRect sizingBox(const LayoutObject* layoutObject) {
if (!layoutObject->isBox())
return LayoutRect();
const LayoutBox* box = toLayoutBox(layoutObject);
return box->style()->boxSizing() == BoxSizingBorderBox
? box->borderBoxRect()
: box->computedCSSContentBoxRect();
}
static CSSValue* renderTextDecorationFlagsToCSSValue(int textDecoration) {
// Blink value is ignored.
CSSValueList* list = CSSValueList::createSpaceSeparated();
if (textDecoration & TextDecorationUnderline)
list->append(*CSSIdentifierValue::create(CSSValueUnderline));
if (textDecoration & TextDecorationOverline)
list->append(*CSSIdentifierValue::create(CSSValueOverline));
if (textDecoration & TextDecorationLineThrough)
list->append(*CSSIdentifierValue::create(CSSValueLineThrough));
if (!list->length())
return CSSIdentifierValue::create(CSSValueNone);
return list;
}
static CSSValue* valueForTextDecorationStyle(
TextDecorationStyle textDecorationStyle) {
switch (textDecorationStyle) {
case TextDecorationStyleSolid:
return CSSIdentifierValue::create(CSSValueSolid);
case TextDecorationStyleDouble:
return CSSIdentifierValue::create(CSSValueDouble);
case TextDecorationStyleDotted:
return CSSIdentifierValue::create(CSSValueDotted);
case TextDecorationStyleDashed:
return CSSIdentifierValue::create(CSSValueDashed);
case TextDecorationStyleWavy:
return CSSIdentifierValue::create(CSSValueWavy);
}
ASSERT_NOT_REACHED();
return CSSInitialValue::create();
}
static CSSValue* valueForTextDecorationSkip(
TextDecorationSkip textDecorationSkip) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
if (textDecorationSkip & TextDecorationSkipObjects)
list->append(*CSSIdentifierValue::create(CSSValueObjects));
if (textDecorationSkip & TextDecorationSkipInk)
list->append(*CSSIdentifierValue::create(CSSValueInk));
DCHECK(list->length());
return list;
}
static CSSValue* touchActionFlagsToCSSValue(TouchAction touchAction) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
if (touchAction == TouchActionAuto) {
list->append(*CSSIdentifierValue::create(CSSValueAuto));
} else if (touchAction == TouchActionNone) {
list->append(*CSSIdentifierValue::create(CSSValueNone));
} else if (touchAction == TouchActionManipulation) {
list->append(*CSSIdentifierValue::create(CSSValueManipulation));
} else {
if ((touchAction & TouchActionPanX) == TouchActionPanX)
list->append(*CSSIdentifierValue::create(CSSValuePanX));
else if (touchAction & TouchActionPanLeft)
list->append(*CSSIdentifierValue::create(CSSValuePanLeft));
else if (touchAction & TouchActionPanRight)
list->append(*CSSIdentifierValue::create(CSSValuePanRight));
if ((touchAction & TouchActionPanY) == TouchActionPanY)
list->append(*CSSIdentifierValue::create(CSSValuePanY));
else if (touchAction & TouchActionPanUp)
list->append(*CSSIdentifierValue::create(CSSValuePanUp));
else if (touchAction & TouchActionPanDown)
list->append(*CSSIdentifierValue::create(CSSValuePanDown));
if ((touchAction & TouchActionPinchZoom) == TouchActionPinchZoom)
list->append(*CSSIdentifierValue::create(CSSValuePinchZoom));
}
ASSERT(list->length());
return list;
}
static CSSValue* valueForWillChange(
const Vector<CSSPropertyID>& willChangeProperties,
bool willChangeContents,
bool willChangeScrollPosition) {
CSSValueList* list = CSSValueList::createCommaSeparated();
if (willChangeContents)
list->append(*CSSIdentifierValue::create(CSSValueContents));
if (willChangeScrollPosition)
list->append(*CSSIdentifierValue::create(CSSValueScrollPosition));
for (size_t i = 0; i < willChangeProperties.size(); ++i)
list->append(*CSSCustomIdentValue::create(willChangeProperties[i]));
if (!list->length())
list->append(*CSSIdentifierValue::create(CSSValueAuto));
return list;
}
static CSSValue* valueForAnimationDelay(const CSSTimingData* timingData) {
CSSValueList* list = CSSValueList::createCommaSeparated();
if (timingData) {
for (size_t i = 0; i < timingData->delayList().size(); ++i)
list->append(*CSSPrimitiveValue::create(
timingData->delayList()[i], CSSPrimitiveValue::UnitType::Seconds));
} else {
list->append(*CSSPrimitiveValue::create(
CSSTimingData::initialDelay(), CSSPrimitiveValue::UnitType::Seconds));
}
return list;
}
static CSSValue* valueForAnimationDirection(
Timing::PlaybackDirection direction) {
switch (direction) {
case Timing::PlaybackDirection::NORMAL:
return CSSIdentifierValue::create(CSSValueNormal);
case Timing::PlaybackDirection::ALTERNATE_NORMAL:
return CSSIdentifierValue::create(CSSValueAlternate);
case Timing::PlaybackDirection::REVERSE:
return CSSIdentifierValue::create(CSSValueReverse);
case Timing::PlaybackDirection::ALTERNATE_REVERSE:
return CSSIdentifierValue::create(CSSValueAlternateReverse);
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
static CSSValue* valueForAnimationDuration(const CSSTimingData* timingData) {
CSSValueList* list = CSSValueList::createCommaSeparated();
if (timingData) {
for (size_t i = 0; i < timingData->durationList().size(); ++i)
list->append(*CSSPrimitiveValue::create(
timingData->durationList()[i], CSSPrimitiveValue::UnitType::Seconds));
} else {
list->append(
*CSSPrimitiveValue::create(CSSTimingData::initialDuration(),
CSSPrimitiveValue::UnitType::Seconds));
}
return list;
}
static CSSValue* valueForAnimationFillMode(Timing::FillMode fillMode) {
switch (fillMode) {
case Timing::FillMode::NONE:
return CSSIdentifierValue::create(CSSValueNone);
case Timing::FillMode::FORWARDS:
return CSSIdentifierValue::create(CSSValueForwards);
case Timing::FillMode::BACKWARDS:
return CSSIdentifierValue::create(CSSValueBackwards);
case Timing::FillMode::BOTH:
return CSSIdentifierValue::create(CSSValueBoth);
default:
ASSERT_NOT_REACHED();
return nullptr;
}
}
static CSSValue* valueForAnimationIterationCount(double iterationCount) {
if (iterationCount == std::numeric_limits<double>::infinity())
return CSSIdentifierValue::create(CSSValueInfinite);
return CSSPrimitiveValue::create(iterationCount,
CSSPrimitiveValue::UnitType::Number);
}
static CSSValue* valueForAnimationPlayState(EAnimPlayState playState) {
if (playState == AnimPlayStatePlaying)
return CSSIdentifierValue::create(CSSValueRunning);
ASSERT(playState == AnimPlayStatePaused);
return CSSIdentifierValue::create(CSSValuePaused);
}
static CSSValue* createTimingFunctionValue(
const TimingFunction* timingFunction) {
switch (timingFunction->getType()) {
case TimingFunction::Type::CUBIC_BEZIER: {
const CubicBezierTimingFunction* bezierTimingFunction =
toCubicBezierTimingFunction(timingFunction);
if (bezierTimingFunction->getEaseType() !=
CubicBezierTimingFunction::EaseType::CUSTOM) {
CSSValueID valueId = CSSValueInvalid;
switch (bezierTimingFunction->getEaseType()) {
case CubicBezierTimingFunction::EaseType::EASE:
valueId = CSSValueEase;
break;
case CubicBezierTimingFunction::EaseType::EASE_IN:
valueId = CSSValueEaseIn;
break;
case CubicBezierTimingFunction::EaseType::EASE_OUT:
valueId = CSSValueEaseOut;
break;
case CubicBezierTimingFunction::EaseType::EASE_IN_OUT:
valueId = CSSValueEaseInOut;
break;
default:
ASSERT_NOT_REACHED();
return nullptr;
}
return CSSIdentifierValue::create(valueId);
}
return CSSCubicBezierTimingFunctionValue::create(
bezierTimingFunction->x1(), bezierTimingFunction->y1(),
bezierTimingFunction->x2(), bezierTimingFunction->y2());
}
case TimingFunction::Type::STEPS: {
const StepsTimingFunction* stepsTimingFunction =
toStepsTimingFunction(timingFunction);
StepsTimingFunction::StepPosition position =
stepsTimingFunction->getStepPosition();
int steps = stepsTimingFunction->numberOfSteps();
DCHECK(position == StepsTimingFunction::StepPosition::START ||
position == StepsTimingFunction::StepPosition::END);
if (steps > 1)
return CSSStepsTimingFunctionValue::create(steps, position);
CSSValueID valueId = position == StepsTimingFunction::StepPosition::START
? CSSValueStepStart
: CSSValueStepEnd;
return CSSIdentifierValue::create(valueId);
}
default:
return CSSIdentifierValue::create(CSSValueLinear);
}
}
static CSSValue* valueForAnimationTimingFunction(
const CSSTimingData* timingData) {
CSSValueList* list = CSSValueList::createCommaSeparated();
if (timingData) {
for (size_t i = 0; i < timingData->timingFunctionList().size(); ++i)
list->append(*createTimingFunctionValue(
timingData->timingFunctionList()[i].get()));
} else {
list->append(*createTimingFunctionValue(
CSSTimingData::initialTimingFunction().get()));
}
return list;
}
static CSSValueList* valuesForBorderRadiusCorner(LengthSize radius,
const ComputedStyle& style) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
if (radius.width().type() == Percent)
list->append(*CSSPrimitiveValue::create(
radius.width().percent(), CSSPrimitiveValue::UnitType::Percentage));
else
list->append(*zoomAdjustedPixelValueForLength(radius.width(), style));
if (radius.height().type() == Percent)
list->append(*CSSPrimitiveValue::create(
radius.height().percent(), CSSPrimitiveValue::UnitType::Percentage));
else
list->append(*zoomAdjustedPixelValueForLength(radius.height(), style));
return list;
}
static const CSSValue& valueForBorderRadiusCorner(LengthSize radius,
const ComputedStyle& style) {
CSSValueList& list = *valuesForBorderRadiusCorner(radius, style);
if (list.item(0).equals(list.item(1)))
return list.item(0);
return list;
}
static CSSFunctionValue* valueForMatrixTransform(TransformationMatrix transform,
const ComputedStyle& style) {
CSSFunctionValue* transformValue = nullptr;
transform.zoom(1 / style.effectiveZoom());
if (transform.isAffine()) {
transformValue = CSSFunctionValue::create(CSSValueMatrix);
transformValue->append(*CSSPrimitiveValue::create(
transform.a(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.b(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.c(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.d(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.e(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.f(), CSSPrimitiveValue::UnitType::Number));
} else {
transformValue = CSSFunctionValue::create(CSSValueMatrix3d);
transformValue->append(*CSSPrimitiveValue::create(
transform.m11(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m12(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m13(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m14(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m21(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m22(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m23(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m24(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m31(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m32(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m33(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m34(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m41(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m42(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m43(), CSSPrimitiveValue::UnitType::Number));
transformValue->append(*CSSPrimitiveValue::create(
transform.m44(), CSSPrimitiveValue::UnitType::Number));
}
return transformValue;
}
static CSSValue* computedTransform(const LayoutObject* layoutObject,
const ComputedStyle& style) {
if (!layoutObject || !style.hasTransform())
return CSSIdentifierValue::create(CSSValueNone);
IntRect box;
if (layoutObject->isBox())
box = pixelSnappedIntRect(toLayoutBox(layoutObject)->borderBoxRect());
TransformationMatrix transform;
style.applyTransform(transform, LayoutSize(box.size()),
ComputedStyle::ExcludeTransformOrigin,
ComputedStyle::ExcludeMotionPath,
ComputedStyle::ExcludeIndependentTransformProperties);
// FIXME: Need to print out individual functions
// (https://bugs.webkit.org/show_bug.cgi?id=23924)
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*valueForMatrixTransform(transform, style));
return list;
}
static CSSValue* createTransitionPropertyValue(
const CSSTransitionData::TransitionProperty& property) {
if (property.propertyType == CSSTransitionData::TransitionNone)
return CSSIdentifierValue::create(CSSValueNone);
if (property.propertyType == CSSTransitionData::TransitionUnknownProperty)
return CSSCustomIdentValue::create(property.propertyString);
ASSERT(property.propertyType == CSSTransitionData::TransitionKnownProperty);
return CSSCustomIdentValue::create(
getPropertyNameAtomicString(property.unresolvedProperty));
}
static CSSValue* valueForTransitionProperty(
const CSSTransitionData* transitionData) {
CSSValueList* list = CSSValueList::createCommaSeparated();
if (transitionData) {
for (size_t i = 0; i < transitionData->propertyList().size(); ++i)
list->append(
*createTransitionPropertyValue(transitionData->propertyList()[i]));
} else {
list->append(*CSSIdentifierValue::create(CSSValueAll));
}
return list;
}
CSSValueID valueForQuoteType(const QuoteType quoteType) {
switch (quoteType) {
case NO_OPEN_QUOTE:
return CSSValueNoOpenQuote;
case NO_CLOSE_QUOTE:
return CSSValueNoCloseQuote;
case CLOSE_QUOTE:
return CSSValueCloseQuote;
case OPEN_QUOTE:
return CSSValueOpenQuote;
}
ASSERT_NOT_REACHED();
return CSSValueInvalid;
}
static CSSValue* valueForContentData(const ComputedStyle& style) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (const ContentData* contentData = style.contentData(); contentData;
contentData = contentData->next()) {
if (contentData->isCounter()) {
const CounterContent* counter =
toCounterContentData(contentData)->counter();
ASSERT(counter);
CSSCustomIdentValue* identifier =
CSSCustomIdentValue::create(counter->identifier());
CSSStringValue* separator = CSSStringValue::create(counter->separator());
CSSValueID listStyleIdent = CSSValueNone;
if (counter->listStyle() != EListStyleType::None) {
// TODO(sashab): Change this to use a converter instead of
// CSSPrimitiveValueMappings.
listStyleIdent =
CSSIdentifierValue::create(counter->listStyle())->getValueID();
}
CSSIdentifierValue* listStyle =
CSSIdentifierValue::create(listStyleIdent);
list->append(*CSSCounterValue::create(identifier, listStyle, separator));
} else if (contentData->isImage()) {
const StyleImage* image = toImageContentData(contentData)->image();
ASSERT(image);
list->append(*image->computedCSSValue());
} else if (contentData->isText()) {
list->append(
*CSSStringValue::create(toTextContentData(contentData)->text()));
} else if (contentData->isQuote()) {
const QuoteType quoteType = toQuoteContentData(contentData)->quote();
list->append(*CSSIdentifierValue::create(valueForQuoteType(quoteType)));
} else {
ASSERT_NOT_REACHED();
}
}
return list;
}
static CSSValue* valueForCounterDirectives(const ComputedStyle& style,
CSSPropertyID propertyID) {
const CounterDirectiveMap* map = style.counterDirectives();
if (!map)
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (const auto& item : *map) {
bool isValidCounterValue = propertyID == CSSPropertyCounterIncrement
? item.value.isIncrement()
: item.value.isReset();
if (!isValidCounterValue)
continue;
list->append(*CSSCustomIdentValue::create(item.key));
short number = propertyID == CSSPropertyCounterIncrement
? item.value.incrementValue()
: item.value.resetValue();
list->append(*CSSPrimitiveValue::create(
(double)number, CSSPrimitiveValue::UnitType::Integer));
}
if (!list->length())
return CSSIdentifierValue::create(CSSValueNone);
return list;
}
static CSSValue* valueForShape(const ComputedStyle& style,
ShapeValue* shapeValue) {
if (!shapeValue)
return CSSIdentifierValue::create(CSSValueNone);
if (shapeValue->type() == ShapeValue::Box)
return CSSIdentifierValue::create(shapeValue->cssBox());
if (shapeValue->type() == ShapeValue::Image) {
if (shapeValue->image())
return shapeValue->image()->computedCSSValue();
return CSSIdentifierValue::create(CSSValueNone);
}
ASSERT(shapeValue->type() == ShapeValue::Shape);
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*valueForBasicShape(style, shapeValue->shape()));
if (shapeValue->cssBox() != BoxMissing)
list->append(*CSSIdentifierValue::create(shapeValue->cssBox()));
return list;
}
static CSSValueList* valuesForSidesShorthand(
const StylePropertyShorthand& shorthand,
const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
// Assume the properties are in the usual order top, right, bottom, left.
const CSSValue* topValue = ComputedStyleCSSValueMapping::get(
shorthand.properties()[0], style, layoutObject, styledNode,
allowVisitedStyle);
const CSSValue* rightValue = ComputedStyleCSSValueMapping::get(
shorthand.properties()[1], style, layoutObject, styledNode,
allowVisitedStyle);
const CSSValue* bottomValue = ComputedStyleCSSValueMapping::get(
shorthand.properties()[2], style, layoutObject, styledNode,
allowVisitedStyle);
const CSSValue* leftValue = ComputedStyleCSSValueMapping::get(
shorthand.properties()[3], style, layoutObject, styledNode,
allowVisitedStyle);
// All 4 properties must be specified.
if (!topValue || !rightValue || !bottomValue || !leftValue)
return nullptr;
bool showLeft = !compareCSSValuePtr(rightValue, leftValue);
bool showBottom = !compareCSSValuePtr(topValue, bottomValue) || showLeft;
bool showRight = !compareCSSValuePtr(topValue, rightValue) || showBottom;
list->append(*topValue);
if (showRight)
list->append(*rightValue);
if (showBottom)
list->append(*bottomValue);
if (showLeft)
list->append(*leftValue);
return list;
}
static CSSValueList* valueForBorderRadiusShorthand(const ComputedStyle& style) {
CSSValueList* list = CSSValueList::createSlashSeparated();
bool showHorizontalBottomLeft = style.borderTopRightRadius().width() !=
style.borderBottomLeftRadius().width();
bool showHorizontalBottomRight =
showHorizontalBottomLeft || (style.borderBottomRightRadius().width() !=
style.borderTopLeftRadius().width());
bool showHorizontalTopRight =
showHorizontalBottomRight || (style.borderTopRightRadius().width() !=
style.borderTopLeftRadius().width());
bool showVerticalBottomLeft = style.borderTopRightRadius().height() !=
style.borderBottomLeftRadius().height();
bool showVerticalBottomRight =
showVerticalBottomLeft || (style.borderBottomRightRadius().height() !=
style.borderTopLeftRadius().height());
bool showVerticalTopRight =
showVerticalBottomRight || (style.borderTopRightRadius().height() !=
style.borderTopLeftRadius().height());
CSSValueList* topLeftRadius =
valuesForBorderRadiusCorner(style.borderTopLeftRadius(), style);
CSSValueList* topRightRadius =
valuesForBorderRadiusCorner(style.borderTopRightRadius(), style);
CSSValueList* bottomRightRadius =
valuesForBorderRadiusCorner(style.borderBottomRightRadius(), style);
CSSValueList* bottomLeftRadius =
valuesForBorderRadiusCorner(style.borderBottomLeftRadius(), style);
CSSValueList* horizontalRadii = CSSValueList::createSpaceSeparated();
horizontalRadii->append(topLeftRadius->item(0));
if (showHorizontalTopRight)
horizontalRadii->append(topRightRadius->item(0));
if (showHorizontalBottomRight)
horizontalRadii->append(bottomRightRadius->item(0));
if (showHorizontalBottomLeft)
horizontalRadii->append(bottomLeftRadius->item(0));
list->append(*horizontalRadii);
CSSValueList* verticalRadii = CSSValueList::createSpaceSeparated();
verticalRadii->append(topLeftRadius->item(1));
if (showVerticalTopRight)
verticalRadii->append(topRightRadius->item(1));
if (showVerticalBottomRight)
verticalRadii->append(bottomRightRadius->item(1));
if (showVerticalBottomLeft)
verticalRadii->append(bottomLeftRadius->item(1));
if (!verticalRadii->equals(toCSSValueList(list->item(0))))
list->append(*verticalRadii);
return list;
}
static CSSValue* strokeDashArrayToCSSValueList(const SVGDashArray& dashes,
const ComputedStyle& style) {
if (dashes.isEmpty())
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* list = CSSValueList::createCommaSeparated();
for (const Length& dashLength : dashes.vector())
list->append(*zoomAdjustedPixelValueForLength(dashLength, style));
return list;
}
static CSSValue* paintOrderToCSSValueList(const SVGComputedStyle& svgStyle) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
for (int i = 0; i < 3; i++) {
EPaintOrderType paintOrderType = svgStyle.paintOrderType(i);
switch (paintOrderType) {
case PT_FILL:
case PT_STROKE:
case PT_MARKERS:
list->append(*CSSIdentifierValue::create(paintOrderType));
break;
case PT_NONE:
default:
ASSERT_NOT_REACHED();
break;
}
}
return list;
}
static CSSValue* adjustSVGPaintForCurrentColor(SVGPaintType paintType,
const String& url,
const Color& color,
const Color& currentColor) {
if (paintType >= SVG_PAINTTYPE_URI_NONE) {
CSSValueList* values = CSSValueList::createSpaceSeparated();
values->append(*CSSURIValue::create(url));
if (paintType == SVG_PAINTTYPE_URI_NONE)
values->append(*CSSIdentifierValue::create(CSSValueNone));
else if (paintType == SVG_PAINTTYPE_URI_CURRENTCOLOR)
values->append(*CSSColorValue::create(currentColor.rgb()));
else if (paintType == SVG_PAINTTYPE_URI_RGBCOLOR)
values->append(*CSSColorValue::create(color.rgb()));
return values;
}
if (paintType == SVG_PAINTTYPE_NONE)
return CSSIdentifierValue::create(CSSValueNone);
if (paintType == SVG_PAINTTYPE_CURRENTCOLOR)
return CSSColorValue::create(currentColor.rgb());
return CSSColorValue::create(color.rgb());
}
static inline String serializeAsFragmentIdentifier(
const AtomicString& resource) {
return "#" + resource;
}
CSSValue* ComputedStyleCSSValueMapping::valueForShadowData(
const ShadowData& shadow,
const ComputedStyle& style,
bool useSpread) {
CSSPrimitiveValue* x = zoomAdjustedPixelValue(shadow.x(), style);
CSSPrimitiveValue* y = zoomAdjustedPixelValue(shadow.y(), style);
CSSPrimitiveValue* blur = zoomAdjustedPixelValue(shadow.blur(), style);
CSSPrimitiveValue* spread =
useSpread ? zoomAdjustedPixelValue(shadow.spread(), style) : nullptr;
CSSIdentifierValue* shadowStyle =
shadow.style() == Normal ? nullptr
: CSSIdentifierValue::create(CSSValueInset);
CSSValue* color = currentColorOrValidColor(style, shadow.color());
return CSSShadowValue::create(x, y, blur, spread, shadowStyle, color);
}
CSSValue* ComputedStyleCSSValueMapping::valueForShadowList(
const ShadowList* shadowList,
const ComputedStyle& style,
bool useSpread) {
if (!shadowList)
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* list = CSSValueList::createCommaSeparated();
size_t shadowCount = shadowList->shadows().size();
for (size_t i = 0; i < shadowCount; ++i)
list->append(
*valueForShadowData(shadowList->shadows()[i], style, useSpread));
return list;
}
CSSValue* ComputedStyleCSSValueMapping::valueForFilter(
const ComputedStyle& style,
const FilterOperations& filterOperations) {
if (filterOperations.operations().isEmpty())
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* list = CSSValueList::createSpaceSeparated();
CSSFunctionValue* filterValue = nullptr;
for (const auto& operation : filterOperations.operations()) {
FilterOperation* filterOperation = operation.get();
switch (filterOperation->type()) {
case FilterOperation::REFERENCE:
filterValue = CSSFunctionValue::create(CSSValueUrl);
filterValue->append(*CSSStringValue::create(
toReferenceFilterOperation(filterOperation)->url()));
break;
case FilterOperation::GRAYSCALE:
filterValue = CSSFunctionValue::create(CSSValueGrayscale);
filterValue->append(*CSSPrimitiveValue::create(
toBasicColorMatrixFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::SEPIA:
filterValue = CSSFunctionValue::create(CSSValueSepia);
filterValue->append(*CSSPrimitiveValue::create(
toBasicColorMatrixFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::SATURATE:
filterValue = CSSFunctionValue::create(CSSValueSaturate);
filterValue->append(*CSSPrimitiveValue::create(
toBasicColorMatrixFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::HUE_ROTATE:
filterValue = CSSFunctionValue::create(CSSValueHueRotate);
filterValue->append(*CSSPrimitiveValue::create(
toBasicColorMatrixFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Degrees));
break;
case FilterOperation::INVERT:
filterValue = CSSFunctionValue::create(CSSValueInvert);
filterValue->append(*CSSPrimitiveValue::create(
toBasicComponentTransferFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::OPACITY:
filterValue = CSSFunctionValue::create(CSSValueOpacity);
filterValue->append(*CSSPrimitiveValue::create(
toBasicComponentTransferFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::BRIGHTNESS:
filterValue = CSSFunctionValue::create(CSSValueBrightness);
filterValue->append(*CSSPrimitiveValue::create(
toBasicComponentTransferFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::CONTRAST:
filterValue = CSSFunctionValue::create(CSSValueContrast);
filterValue->append(*CSSPrimitiveValue::create(
toBasicComponentTransferFilterOperation(filterOperation)->amount(),
CSSPrimitiveValue::UnitType::Number));
break;
case FilterOperation::BLUR:
filterValue = CSSFunctionValue::create(CSSValueBlur);
filterValue->append(*zoomAdjustedPixelValue(
toBlurFilterOperation(filterOperation)->stdDeviation().value(),
style));
break;
case FilterOperation::DROP_SHADOW: {
const auto& dropShadowOperation =
toDropShadowFilterOperation(*filterOperation);
filterValue = CSSFunctionValue::create(CSSValueDropShadow);
// We want our computed style to look like that of a text shadow (has
// neither spread nor inset style).
filterValue->append(
*valueForShadowData(dropShadowOperation.shadow(), style, false));
break;
}
default:
ASSERT_NOT_REACHED();
break;
}
list->append(*filterValue);
}
return list;
}
CSSValue* ComputedStyleCSSValueMapping::valueForFont(
const ComputedStyle& style) {
// Add a slash between size and line-height.
CSSValueList* sizeAndLineHeight = CSSValueList::createSlashSeparated();
sizeAndLineHeight->append(*valueForFontSize(style));
sizeAndLineHeight->append(*valueForLineHeight(style));
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*valueForFontStyle(style));
// Check that non-initial font-variant subproperties are not conflicting with
// this serialization.
CSSValue* ligaturesValue = valueForFontVariantLigatures(style);
CSSValue* numericValue = valueForFontVariantNumeric(style);
if (!ligaturesValue->equals(*CSSIdentifierValue::create(CSSValueNormal)) ||
!numericValue->equals(*CSSIdentifierValue::create(CSSValueNormal)))
return nullptr;
CSSIdentifierValue* capsValue = valueForFontVariantCaps(style);
if (capsValue->getValueID() != CSSValueNormal &&
capsValue->getValueID() != CSSValueSmallCaps)
return nullptr;
list->append(*capsValue);
list->append(*valueForFontWeight(style));
list->append(*valueForFontStretch(style));
list->append(*sizeAndLineHeight);
list->append(*valueForFontFamily(style));
return list;
}
static CSSValue* valueForScrollSnapDestination(const LengthPoint& destination,
const ComputedStyle& style) {
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(*zoomAdjustedPixelValueForLength(destination.x(), style));
list->append(*zoomAdjustedPixelValueForLength(destination.y(), style));
return list;
}
static CSSValue* valueForScrollSnapPoints(const ScrollSnapPoints& points,
const ComputedStyle& style) {
if (points.hasRepeat) {
CSSFunctionValue* repeat = CSSFunctionValue::create(CSSValueRepeat);
repeat->append(
*zoomAdjustedPixelValueForLength(points.repeatOffset, style));
return repeat;
}
return CSSIdentifierValue::create(CSSValueNone);
}
static CSSValue* valueForScrollSnapCoordinate(
const Vector<LengthPoint>& coordinates,
const ComputedStyle& style) {
if (coordinates.isEmpty())
return CSSIdentifierValue::create(CSSValueNone);
CSSValueList* list = CSSValueList::createCommaSeparated();
for (auto& coordinate : coordinates) {
auto pair = CSSValueList::createSpaceSeparated();
pair->append(*zoomAdjustedPixelValueForLength(coordinate.x(), style));
pair->append(*zoomAdjustedPixelValueForLength(coordinate.y(), style));
list->append(*pair);
}
return list;
}
static EBreak mapToPageBreakValue(EBreak genericBreakValue) {
switch (genericBreakValue) {
case BreakAvoidColumn:
case BreakColumn:
case BreakRecto:
case BreakVerso:
return BreakAuto;
case BreakPage:
return BreakAlways;
case BreakAvoidPage:
return BreakAvoid;
default:
return genericBreakValue;
}
}
static EBreak mapToColumnBreakValue(EBreak genericBreakValue) {
switch (genericBreakValue) {
case BreakAvoidPage:
case BreakLeft:
case BreakPage:
case BreakRecto:
case BreakRight:
case BreakVerso:
return BreakAuto;
case BreakColumn:
return BreakAlways;
case BreakAvoidColumn:
return BreakAvoid;
default:
return genericBreakValue;
}
}
const CSSValue* ComputedStyleCSSValueMapping::get(
const AtomicString customPropertyName,
const ComputedStyle& style,
const PropertyRegistry* registry) {
if (registry) {
const PropertyRegistry::Registration* registration =
registry->registration(customPropertyName);
if (registration) {
const CSSValue* result = nullptr;
if (registration->inherits()) {
if (StyleInheritedVariables* variables = style.inheritedVariables())
result = variables->registeredVariable(customPropertyName);
} else {
if (StyleNonInheritedVariables* variables =
style.nonInheritedVariables())
result = variables->registeredVariable(customPropertyName);
}
if (result)
return result;
return registration->initial();
}
}
StyleInheritedVariables* variables = style.inheritedVariables();
if (!variables)
return nullptr;
CSSVariableData* data = variables->getVariable(customPropertyName);
if (!data)
return nullptr;
return CSSCustomPropertyDeclaration::create(customPropertyName, data);
}
std::unique_ptr<HashMap<AtomicString, RefPtr<CSSVariableData>>>
ComputedStyleCSSValueMapping::getVariables(const ComputedStyle& style) {
// TODO(timloh): Also return non-inherited variables
StyleInheritedVariables* variables = style.inheritedVariables();
if (variables)
return variables->getVariables();
return nullptr;
}
const CSSValue* ComputedStyleCSSValueMapping::get(
CSSPropertyID propertyID,
const ComputedStyle& style,
const LayoutObject* layoutObject,
Node* styledNode,
bool allowVisitedStyle) {
const SVGComputedStyle& svgStyle = style.svgStyle();
propertyID = CSSProperty::resolveDirectionAwareProperty(
propertyID, style.direction(), style.getWritingMode());
switch (propertyID) {
case CSSPropertyInvalid:
return nullptr;
case CSSPropertyBackgroundColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyBackgroundColor)
.rgb())
: currentColorOrValidColor(style, style.backgroundColor());
case CSSPropertyBackgroundImage:
case CSSPropertyWebkitMaskImage: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskImage
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next()) {
if (currLayer->image())
list->append(*currLayer->image()->computedCSSValue());
else
list->append(*CSSIdentifierValue::create(CSSValueNone));
}
return list;
}
case CSSPropertyBackgroundSize:
case CSSPropertyWebkitMaskSize: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskSize
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(*valueForFillSize(currLayer->size(), style));
return list;
}
case CSSPropertyBackgroundRepeat:
case CSSPropertyWebkitMaskRepeat: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskRepeat
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(
*valueForFillRepeat(currLayer->repeatX(), currLayer->repeatY()));
return list;
}
case CSSPropertyMaskSourceType: {
CSSValueList* list = CSSValueList::createCommaSeparated();
for (const FillLayer* currLayer = &style.maskLayers(); currLayer;
currLayer = currLayer->next())
list->append(*valueForFillSourceType(currLayer->maskSourceType()));
return list;
}
case CSSPropertyWebkitMaskComposite: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskComposite
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(*CSSIdentifierValue::create(currLayer->composite()));
return list;
}
case CSSPropertyBackgroundAttachment: {
CSSValueList* list = CSSValueList::createCommaSeparated();
for (const FillLayer* currLayer = &style.backgroundLayers(); currLayer;
currLayer = currLayer->next())
list->append(*CSSIdentifierValue::create(currLayer->attachment()));
return list;
}
case CSSPropertyBackgroundClip:
case CSSPropertyBackgroundOrigin:
case CSSPropertyWebkitBackgroundClip:
case CSSPropertyWebkitBackgroundOrigin:
case CSSPropertyWebkitMaskClip:
case CSSPropertyWebkitMaskOrigin: {
bool isClip = propertyID == CSSPropertyBackgroundClip ||
propertyID == CSSPropertyWebkitBackgroundClip ||
propertyID == CSSPropertyWebkitMaskClip;
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = (propertyID == CSSPropertyWebkitMaskClip ||
propertyID == CSSPropertyWebkitMaskOrigin)
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next()) {
EFillBox box = isClip ? currLayer->clip() : currLayer->origin();
list->append(*CSSIdentifierValue::create(box));
}
return list;
}
case CSSPropertyBackgroundPosition:
case CSSPropertyWebkitMaskPosition: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskPosition
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(
*createPositionListForLayer(propertyID, *currLayer, style));
return list;
}
case CSSPropertyBackgroundPositionX:
case CSSPropertyWebkitMaskPositionX: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskPositionX
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(
*zoomAdjustedPixelValueForLength(currLayer->xPosition(), style));
return list;
}
case CSSPropertyBackgroundPositionY:
case CSSPropertyWebkitMaskPositionY: {
CSSValueList* list = CSSValueList::createCommaSeparated();
const FillLayer* currLayer = propertyID == CSSPropertyWebkitMaskPositionY
? &style.maskLayers()
: &style.backgroundLayers();
for (; currLayer; currLayer = currLayer->next())
list->append(
*zoomAdjustedPixelValueForLength(currLayer->yPosition(), style));
return list;
}
case CSSPropertyBorderCollapse:
if (style.borderCollapse() == EBorderCollapse::Collapse)
return CSSIdentifierValue::create(CSSValueCollapse);
return CSSIdentifierValue::create(CSSValueSeparate);
case CSSPropertyBorderSpacing: {
CSSValueList* list = CSSValueList::createSpaceSeparated();
list->append(
*zoomAdjustedPixelValue(style.horizontalBorderSpacing(), style));
list->append(
*zoomAdjustedPixelValue(style.verticalBorderSpacing(), style));
return list;
}
case CSSPropertyWebkitBorderHorizontalSpacing:
return zoomAdjustedPixelValue(style.horizontalBorderSpacing(), style);
case CSSPropertyWebkitBorderVerticalSpacing:
return zoomAdjustedPixelValue(style.verticalBorderSpacing(), style);
case CSSPropertyBorderImageSource:
if (style.borderImageSource())
return style.borderImageSource()->computedCSSValue();
return CSSIdentifierValue::create(CSSValueNone);
case CSSPropertyBorderTopColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyBorderTopColor)
.rgb())
: currentColorOrValidColor(style, style.borderTopColor());
case CSSPropertyBorderRightColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyBorderRightColor)
.rgb())
: currentColorOrValidColor(style, style.borderRightColor());
case CSSPropertyBorderBottomColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyBorderBottomColor)
.rgb())
: currentColorOrValidColor(style, style.borderBottomColor());
case CSSPropertyBorderLeftColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyBorderLeftColor)
.rgb())
: currentColorOrValidColor(style, style.borderLeftColor());
case CSSPropertyBorderTopStyle:
return CSSIdentifierValue::create(style.borderTopStyle());
case CSSPropertyBorderRightStyle:
return CSSIdentifierValue::create(style.borderRightStyle());
case CSSPropertyBorderBottomStyle:
return CSSIdentifierValue::create(style.borderBottomStyle());
case CSSPropertyBorderLeftStyle:
return CSSIdentifierValue::create(style.borderLeftStyle());
case CSSPropertyBorderTopWidth:
return zoomAdjustedPixelValue(style.borderTopWidth(), style);
case CSSPropertyBorderRightWidth:
return zoomAdjustedPixelValue(style.borderRightWidth(), style);
case CSSPropertyBorderBottomWidth:
return zoomAdjustedPixelValue(style.borderBottomWidth(), style);
case CSSPropertyBorderLeftWidth:
return zoomAdjustedPixelValue(style.borderLeftWidth(), style);
case CSSPropertyBottom:
return valueForPositionOffset(style, CSSPropertyBottom, layoutObject);
case CSSPropertyWebkitBoxAlign:
return CSSIdentifierValue::create(style.boxAlign());
case CSSPropertyWebkitBoxDecorationBreak:
if (style.boxDecorationBreak() == BoxDecorationBreakSlice)
return CSSIdentifierValue::create(CSSValueSlice);
return CSSIdentifierValue::create(CSSValueClone);
case CSSPropertyWebkitBoxDirection:
return CSSIdentifierValue::create(style.boxDirection());
case CSSPropertyWebkitBoxFlex:
return CSSPrimitiveValue::create(style.boxFlex(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyWebkitBoxFlexGroup:
return CSSPrimitiveValue::create(style.boxFlexGroup(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyWebkitBoxLines:
return CSSIdentifierValue::create(style.boxLines());
case CSSPropertyWebkitBoxOrdinalGroup:
return CSSPrimitiveValue::create(style.boxOrdinalGroup(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyWebkitBoxOrient:
return CSSIdentifierValue::create(style.boxOrient());
case CSSPropertyWebkitBoxPack:
return CSSIdentifierValue::create(style.boxPack());
case CSSPropertyWebkitBoxReflect:
return valueForReflection(style.boxReflect(), style);
case CSSPropertyBoxShadow:
return valueForShadowList(style.boxShadow(), style, true);
case CSSPropertyCaptionSide:
return CSSIdentifierValue::create(style.captionSide());
case CSSPropertyCaretColor:
if (style.caretColor().isCurrentColor())
return CSSIdentifierValue::create(CSSValueCurrentcolor);
if (style.caretColor().isAutoColor())
return CSSIdentifierValue::create(CSSValueAuto);
return CSSColorValue::create(style.caretColor().color().rgb());
case CSSPropertyClear:
return CSSIdentifierValue::create(style.clear());
case CSSPropertyColor:
return CSSColorValue::create(
allowVisitedStyle
? style.visitedDependentColor(CSSPropertyColor).rgb()
: style.color().rgb());
case CSSPropertyWebkitPrintColorAdjust:
return CSSIdentifierValue::create(style.printColorAdjust());
case CSSPropertyColumnCount:
if (style.hasAutoColumnCount())
return CSSIdentifierValue::create(CSSValueAuto);
return CSSPrimitiveValue::create(style.columnCount(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyColumnFill:
return CSSIdentifierValue::create(style.getColumnFill());
case CSSPropertyColumnGap:
if (style.hasNormalColumnGap())
return CSSIdentifierValue::create(CSSValueNormal);
return zoomAdjustedPixelValue(style.columnGap(), style);
case CSSPropertyColumnRuleColor:
return allowVisitedStyle
? CSSColorValue::create(
style.visitedDependentColor(CSSPropertyOutlineColor)
.rgb())
: currentColorOrValidColor(style, style.columnRuleColor());
case CSSPropertyColumnRuleStyle:
return CSSIdentifierValue::create(style.columnRuleStyle());
case CSSPropertyColumnRuleWidth:
return zoomAdjustedPixelValue(style.columnRuleWidth(), style);
case CSSPropertyColumnSpan:
return CSSIdentifierValue::create(style.getColumnSpan() ? CSSValueAll
: CSSValueNone);
case CSSPropertyWebkitColumnBreakAfter:
return CSSIdentifierValue::create(
mapToColumnBreakValue(style.breakAfter()));
case CSSPropertyWebkitColumnBreakBefore:
return CSSIdentifierValue::create(
mapToColumnBreakValue(style.breakBefore()));
case CSSPropertyWebkitColumnBreakInside:
return CSSIdentifierValue::create(
mapToColumnBreakValue(style.breakInside()));
case CSSPropertyColumnWidth:
if (style.hasAutoColumnWidth())
return CSSIdentifierValue::create(CSSValueAuto);
return zoomAdjustedPixelValue(style.columnWidth(), style);
case CSSPropertyTabSize:
return CSSPrimitiveValue::create(
style.getTabSize().getPixelSize(1.0),
style.getTabSize().isSpaces() ? CSSPrimitiveValue::UnitType::Number
: CSSPrimitiveValue::UnitType::Pixels);
case CSSPropertyTextSizeAdjust:
if (style.getTextSizeAdjust().isAuto())
return CSSIdentifierValue::create(CSSValueAuto);
return CSSPrimitiveValue::create(
style.getTextSizeAdjust().multiplier() * 100,
CSSPrimitiveValue::UnitType::Percentage);
case CSSPropertyCursor: {
CSSValueList* list = nullptr;
CursorList* cursors = style.cursors();
if (cursors && cursors->size() > 0) {
list = CSSValueList::createCommaSeparated();
for (const CursorData& cursor : *cursors) {
if (StyleImage* image = cursor.image()) {
list->append(*CSSCursorImageValue::create(
*image->computedCSSValue(), cursor.hotSpotSpecified(),
cursor.hotSpot()));
}
}
}
CSSValue* value = CSSIdentifierValue::create(style.cursor());
if (list) {
list->append(*value);
return list;
}
return value;
}
case CSSPropertyDirection:
return CSSIdentifierValue::create(style.direction());
case CSSPropertyDisplay:
return CSSIdentifierValue::create(style.display());
case CSSPropertyEmptyCells:
return CSSIdentifierValue::create(style.emptyCells());
case CSSPropertyAlignContent:
return valueForContentPositionAndDistributionWithOverflowAlignment(
style.alignContent(), CSSValueStretch);
case CSSPropertyAlignItems:
return valueForItemPositionWithOverflowAlignment(style.alignItems());
case CSSPropertyAlignSelf:
return valueForItemPositionWithOverflowAlignment(style.alignSelf());
case CSSPropertyFlex:
return valuesForShorthandProperty(flexShorthand(), style, layoutObject,
styledNode, allowVisitedStyle);
case CSSPropertyFlexBasis:
return zoomAdjustedPixelValueForLength(style.flexBasis(), style);
case CSSPropertyFlexDirection:
return CSSIdentifierValue::create(style.flexDirection());
case CSSPropertyFlexFlow:
return valuesForShorthandProperty(flexFlowShorthand(), style,
layoutObject, styledNode,
allowVisitedStyle);
case CSSPropertyFlexGrow:
return CSSPrimitiveValue::create(style.flexGrow(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyFlexShrink:
return CSSPrimitiveValue::create(style.flexShrink(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyFlexWrap:
return CSSIdentifierValue::create(style.flexWrap());
case CSSPropertyJustifyContent:
return valueForContentPositionAndDistributionWithOverflowAlignment(
style.justifyContent(), CSSValueFlexStart);
case CSSPropertyOrder:
return CSSPrimitiveValue::create(style.order(),
CSSPrimitiveValue::UnitType::Number);
case CSSPropertyFloat:
if (style.display() != EDisplay::None && style.hasOutOfFlowPosition())
return CSSIdentifierValue::create(CSSValueNone);
return CSSIdentifierValue::create(style.floating());
case CSSPropertyFont:
return valueForFont(style);
case CSSPropertyFontFamily:
return valueForFontFamily(style);
case CSSPropertyFontSize:
return valueForFontSize(style);
case CSSPropertyFontSizeAdjust:
if (style.hasFontSizeAdjust())
return CSSPrimitiveValue::create(style.fontSizeAdjust(),
CSSPrimitiveValue::UnitType::Number);
return CSSIdentifierValue::create(CSSValueNone);
case CSSPropertyFontStretch:
return valueForFontStretch(style);
case CSSPropertyFontStyle:
return valueForFontStyle(style);
case CSSPropertyFontVariant:
return valuesForFontVariantProperty(style, layoutObject, styledNode,
allowVisitedStyle);
case CSSPropertyFontWeight:
return valueForFontWeight(style);
case CSSPropertyFontFeatureSettings: {
const FontFeatureSettings* featureSettings =
style.getFontDescription().featureSettings();
if (!featureSettings || !featureSettings->size())
return CSSIdentifierValue::create(CSSValueNormal);
CSSValueList* list = CSSValueList::createCommaSeparated();
for (unsigned i = 0; i < featureSettings->size(); ++i) {
const FontFeature& feature = featureSettings->at(i);
CSSFontFeatureValue* featureValue =
CSSFontFeatureValue::create(feature.tag(), feature.value());
list->append(*featureValue);
}
return list;
}
case CSSPropertyFontVariationSettings: {
DCHECK(RuntimeEnabledFeatures::cssVariableFontsEnabled());
const FontVariationSettings* variationSettings =
style.getFontDescription().variationSettings();
if (!variationSettings || !variationSettings->size())
return CSSIdentifierValue::create(CSSValueNormal);
CSSValueList* list = CSSValueList::createCommaSeparated();
for (unsigned i = 0; i < variationSettings->size(); ++i) {
const FontVariationAxis& variationAxis = variationSettings->at(i);
CSSFontVariationValue* variationValue = CSSFontVariationValue::create(
variationAxis.tag(), variationAxis.value());
list->append(*variationValue);
}
return list;
}
case CSSPropertyGridAutoFlow: {
CSSValueList* list = CSSValueList::createSpaceSeparated();
switch (style.getGridAutoFlow()) {
case AutoFlowRow:
case AutoFlowRowDense:
list->append(*CSSIdentifierValue::create(CSSValueRow));
break;
case AutoFlowColumn:
case AutoFlowColumnDense:
list->append(*CSSIdentifierValue::create(CSSValueColumn));
break;
default:
ASSERT_NOT_REACHED();
}
switch (style.getGridAutoFlow()) {
case AutoFlowRowDense:
case AutoFlowColumnDense:
list->append(*CSSIdentifierValue::create(CSSValueDense));
break;
default:
// Do nothing.
break;
}
return list;