2
* Copyright (C) 2013 Google Inc. All rights reserved.
3
* Copyright (C) 2014 Apple Inc. All rights reserved.
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
14
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24
* THE POSSIBILITY OF SUCH DAMAGE.
29
#include "BasicShapeFunctions.h"
30
#include "CSSCalculationValue.h"
31
#include "CSSContentDistributionValue.h"
32
#include "CSSFontFeatureValue.h"
33
#include "CSSFontStyleValue.h"
34
#include "CSSFontVariationValue.h"
35
#include "CSSFunctionValue.h"
36
#include "CSSGridAutoRepeatValue.h"
37
#include "CSSGridIntegerRepeatValue.h"
38
#include "CSSGridLineNamesValue.h"
39
#include "CSSImageGeneratorValue.h"
40
#include "CSSImageSetValue.h"
41
#include "CSSImageValue.h"
42
#include "CSSPrimitiveValue.h"
43
#include "CSSPrimitiveValueMappings.h"
44
#include "CSSReflectValue.h"
45
#include "FontSelectionValueInlines.h"
47
#include "GridPositionsResolver.h"
50
#include "QuotesData.h"
51
#include "RuntimeEnabledFeatures.h"
52
#include "SVGURIReference.h"
54
#include "StyleBuilderState.h"
55
#include "StyleScrollSnapPoints.h"
57
#include "TouchAction.h"
58
#include "TransformFunctions.h"
59
#include <wtf/Optional.h>
64
// Note that we assume the CSS parser only allows valid CSSValue types.
65
class BuilderConverter {
67
static Length convertLength(const BuilderState&, const CSSValue&);
68
static Length convertLengthOrAuto(const BuilderState&, const CSSValue&);
69
static Length convertLengthSizing(const BuilderState&, const CSSValue&);
70
static Length convertLengthMaxSizing(const BuilderState&, const CSSValue&);
71
static TabSize convertTabSize(const BuilderState&, const CSSValue&);
72
template<typename T> static T convertComputedLength(BuilderState&, const CSSValue&);
73
template<typename T> static T convertLineWidth(BuilderState&, const CSSValue&);
74
static float convertSpacing(BuilderState&, const CSSValue&);
75
static LengthSize convertRadius(BuilderState&, const CSSValue&);
76
static LengthPoint convertObjectPosition(BuilderState&, const CSSValue&);
77
static OptionSet<TextDecoration> convertTextDecoration(BuilderState&, const CSSValue&);
78
template<typename T> static T convertNumber(BuilderState&, const CSSValue&);
79
template<typename T> static T convertNumberOrAuto(BuilderState&, const CSSValue&);
80
static short convertWebkitHyphenateLimitLines(BuilderState&, const CSSValue&);
81
template<CSSPropertyID> static NinePieceImage convertBorderImage(BuilderState&, CSSValue&);
82
template<CSSPropertyID> static NinePieceImage convertBorderMask(BuilderState&, CSSValue&);
83
template<CSSPropertyID> static RefPtr<StyleImage> convertStyleImage(BuilderState&, CSSValue&);
84
static ImageOrientation convertImageOrientation(BuilderState&, const CSSValue&);
85
static TransformOperations convertTransform(BuilderState&, const CSSValue&);
86
#if ENABLE(DARK_MODE_CSS)
87
static StyleColorScheme convertColorScheme(BuilderState&, const CSSValue&);
89
static String convertString(BuilderState&, const CSSValue&);
90
static String convertStringOrAuto(BuilderState&, const CSSValue&);
91
static String convertStringOrNone(BuilderState&, const CSSValue&);
92
static OptionSet<TextEmphasisPosition> convertTextEmphasisPosition(BuilderState&, const CSSValue&);
93
static TextAlignMode convertTextAlign(BuilderState&, const CSSValue&);
94
static RefPtr<ClipPathOperation> convertClipPath(BuilderState&, const CSSValue&);
95
static Resize convertResize(BuilderState&, const CSSValue&);
96
static int convertMarqueeRepetition(BuilderState&, const CSSValue&);
97
static int convertMarqueeSpeed(BuilderState&, const CSSValue&);
98
static Ref<QuotesData> convertQuotes(BuilderState&, const CSSValue&);
99
static TextUnderlinePosition convertTextUnderlinePosition(BuilderState&, const CSSValue&);
100
static TextUnderlineOffset convertTextUnderlineOffset(BuilderState&, const CSSValue&);
101
static TextDecorationThickness convertTextDecorationThickness(BuilderState&, const CSSValue&);
102
static RefPtr<StyleReflection> convertReflection(BuilderState&, const CSSValue&);
103
static IntSize convertInitialLetter(BuilderState&, const CSSValue&);
104
static float convertTextStrokeWidth(BuilderState&, const CSSValue&);
105
static OptionSet<LineBoxContain> convertLineBoxContain(BuilderState&, const CSSValue&);
106
static OptionSet<TextDecorationSkip> convertTextDecorationSkip(BuilderState&, const CSSValue&);
107
static RefPtr<ShapeValue> convertShapeValue(BuilderState&, CSSValue&);
108
#if ENABLE(CSS_SCROLL_SNAP)
109
static ScrollSnapType convertScrollSnapType(BuilderState&, const CSSValue&);
110
static ScrollSnapAlign convertScrollSnapAlign(BuilderState&, const CSSValue&);
112
static GridTrackSize convertGridTrackSize(BuilderState&, const CSSValue&);
113
static Vector<GridTrackSize> convertGridTrackSizeList(BuilderState&, const CSSValue&);
114
static Optional<GridPosition> convertGridPosition(BuilderState&, const CSSValue&);
115
static GridAutoFlow convertGridAutoFlow(BuilderState&, const CSSValue&);
116
static Optional<Length> convertWordSpacing(BuilderState&, const CSSValue&);
117
static Optional<float> convertPerspective(BuilderState&, const CSSValue&);
118
static Optional<Length> convertMarqueeIncrement(BuilderState&, const CSSValue&);
119
static Optional<FilterOperations> convertFilterOperations(BuilderState&, const CSSValue&);
120
#if PLATFORM(IOS_FAMILY)
121
static bool convertTouchCallout(BuilderState&, const CSSValue&);
123
#if ENABLE(TOUCH_EVENTS)
124
static Color convertTapHighlightColor(BuilderState&, const CSSValue&);
126
#if ENABLE(POINTER_EVENTS)
127
static OptionSet<TouchAction> convertTouchAction(BuilderState&, const CSSValue&);
129
#if ENABLE(OVERFLOW_SCROLLING_TOUCH)
130
static bool convertOverflowScrolling(BuilderState&, const CSSValue&);
132
static FontFeatureSettings convertFontFeatureSettings(BuilderState&, const CSSValue&);
133
static bool convertSmoothScrolling(BuilderState&, const CSSValue&);
134
static FontSelectionValue convertFontWeightFromValue(const CSSValue&);
135
static FontSelectionValue convertFontStretchFromValue(const CSSValue&);
136
static Optional<FontSelectionValue> convertFontStyleFromValue(const CSSValue&);
137
static FontSelectionValue convertFontWeight(BuilderState&, const CSSValue&);
138
static FontSelectionValue convertFontStretch(BuilderState&, const CSSValue&);
139
static FontSelectionValue convertFontStyle(BuilderState&, const CSSValue&);
140
#if ENABLE(VARIATION_FONTS)
141
static FontVariationSettings convertFontVariationSettings(BuilderState&, const CSSValue&);
143
static SVGLengthValue convertSVGLengthValue(BuilderState&, const CSSValue&);
144
static Vector<SVGLengthValue> convertSVGLengthVector(BuilderState&, const CSSValue&);
145
static Vector<SVGLengthValue> convertStrokeDashArray(BuilderState&, const CSSValue&);
146
static PaintOrder convertPaintOrder(BuilderState&, const CSSValue&);
147
static float convertOpacity(BuilderState&, const CSSValue&);
148
static String convertSVGURIReference(BuilderState&, const CSSValue&);
149
static Color convertSVGColor(BuilderState&, const CSSValue&);
150
static StyleSelfAlignmentData convertSelfOrDefaultAlignmentData(BuilderState&, const CSSValue&);
151
static StyleContentAlignmentData convertContentAlignmentData(BuilderState&, const CSSValue&);
152
static GlyphOrientation convertGlyphOrientation(BuilderState&, const CSSValue&);
153
static GlyphOrientation convertGlyphOrientationOrAuto(BuilderState&, const CSSValue&);
154
static Optional<Length> convertLineHeight(BuilderState&, const CSSValue&, float multiplier = 1.f);
155
static FontSynthesis convertFontSynthesis(BuilderState&, const CSSValue&);
157
static BreakBetween convertPageBreakBetween(BuilderState&, const CSSValue&);
158
static BreakInside convertPageBreakInside(BuilderState&, const CSSValue&);
159
static BreakBetween convertColumnBreakBetween(BuilderState&, const CSSValue&);
160
static BreakInside convertColumnBreakInside(BuilderState&, const CSSValue&);
162
static OptionSet<HangingPunctuation> convertHangingPunctuation(BuilderState&, const CSSValue&);
164
static OptionSet<SpeakAs> convertSpeakAs(BuilderState&, const CSSValue&);
166
static Length convertPositionComponentX(BuilderState&, const CSSValue&);
167
static Length convertPositionComponentY(BuilderState&, const CSSValue&);
169
static GapLength convertGapLength(BuilderState&, const CSSValue&);
172
friend class BuilderCustom;
174
static Length convertToRadiusLength(CSSToLengthConversionData&, const CSSPrimitiveValue&);
175
static OptionSet<TextEmphasisPosition> valueToEmphasisPosition(const CSSPrimitiveValue&);
176
static OptionSet<TextDecorationSkip> valueToDecorationSkip(const CSSPrimitiveValue&);
177
#if ENABLE(CSS_SCROLL_SNAP)
178
static Length parseSnapCoordinate(BuilderState&, const CSSValue&);
181
#if ENABLE(DARK_MODE_CSS)
182
static void updateColorScheme(const CSSPrimitiveValue&, StyleColorScheme&);
185
static Length convertTo100PercentMinusLength(const Length&);
186
template<CSSValueID, CSSValueID> static Length convertPositionComponent(BuilderState&, const CSSPrimitiveValue&);
188
static GridLength createGridTrackBreadth(const CSSPrimitiveValue&, BuilderState&);
189
static GridTrackSize createGridTrackSize(const CSSValue&, BuilderState&);
191
static bool createGridTrackList(const CSSValue&, TracksData&, BuilderState&);
192
static bool createGridPosition(const CSSValue&, GridPosition&);
193
static void createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap&, NamedGridLinesMap&, GridTrackSizingDirection);
194
static CSSToLengthConversionData csstoLengthConversionDataWithTextZoomFactor(BuilderState&);
197
inline Length BuilderConverter::convertLength(const BuilderState& builderState, const CSSValue& value)
199
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
200
CSSToLengthConversionData conversionData = builderState.useSVGZoomRulesForLength() ?
201
builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
202
: builderState.cssToLengthConversionData();
204
if (primitiveValue.isLength()) {
205
Length length = primitiveValue.computeLength<Length>(conversionData);
206
length.setHasQuirk(primitiveValue.isQuirkValue());
210
if (primitiveValue.isPercentage())
211
return Length(primitiveValue.doubleValue(), Percent);
213
if (primitiveValue.isCalculatedPercentageWithLength())
214
return Length(primitiveValue.cssCalcValue()->createCalculationValue(conversionData));
216
ASSERT_NOT_REACHED();
217
return Length(0, Fixed);
220
inline Length BuilderConverter::convertLengthOrAuto(const BuilderState& builderState, const CSSValue& value)
222
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
224
return convertLength(builderState, value);
227
inline Length BuilderConverter::convertLengthSizing(const BuilderState& builderState, const CSSValue& value)
229
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
230
switch (primitiveValue.valueID()) {
231
case CSSValueInvalid:
232
return convertLength(builderState, value);
233
case CSSValueIntrinsic:
234
return Length(Intrinsic);
235
case CSSValueMinIntrinsic:
236
return Length(MinIntrinsic);
237
case CSSValueMinContent:
238
case CSSValueWebkitMinContent:
239
return Length(MinContent);
240
case CSSValueMaxContent:
241
case CSSValueWebkitMaxContent:
242
return Length(MaxContent);
243
case CSSValueWebkitFillAvailable:
244
return Length(FillAvailable);
245
case CSSValueFitContent:
246
case CSSValueWebkitFitContent:
247
return Length(FitContent);
251
ASSERT_NOT_REACHED();
256
inline Length BuilderConverter::convertLengthMaxSizing(const BuilderState& builderState, const CSSValue& value)
258
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
259
return Length(Undefined);
260
return convertLengthSizing(builderState, value);
263
inline TabSize BuilderConverter::convertTabSize(const BuilderState& builderState, const CSSValue& value)
265
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
266
if (primitiveValue.isNumber())
267
return TabSize(primitiveValue.floatValue(), SpaceValueType);
268
return TabSize(primitiveValue.computeLength<float>(builderState.cssToLengthConversionData()), LengthValueType);
272
inline T BuilderConverter::convertComputedLength(BuilderState& builderState, const CSSValue& value)
274
return downcast<CSSPrimitiveValue>(value).computeLength<T>(builderState.cssToLengthConversionData());
278
inline T BuilderConverter::convertLineWidth(BuilderState& builderState, const CSSValue& value)
280
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
281
switch (primitiveValue.valueID()) {
288
case CSSValueInvalid: {
289
// Any original result that was >= 1 should not be allowed to fall below 1.
290
// This keeps border lines from vanishing.
291
T result = convertComputedLength<T>(builderState, value);
292
if (builderState.style().effectiveZoom() < 1.0f && result < 1.0) {
293
T originalLength = primitiveValue.computeLength<T>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0));
294
if (originalLength >= 1.0)
297
float minimumLineWidth = 1 / builderState.document().deviceScaleFactor();
298
if (result > 0 && result < minimumLineWidth)
299
return minimumLineWidth;
300
return floorToDevicePixel(result, builderState.document().deviceScaleFactor());
303
ASSERT_NOT_REACHED();
308
inline float BuilderConverter::convertSpacing(BuilderState& builderState, const CSSValue& value)
310
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
311
if (primitiveValue.valueID() == CSSValueNormal)
314
CSSToLengthConversionData conversionData = builderState.useSVGZoomRulesForLength() ?
315
builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f)
316
: builderState.cssToLengthConversionData();
317
return primitiveValue.computeLength<float>(conversionData);
320
inline Length BuilderConverter::convertToRadiusLength(CSSToLengthConversionData& conversionData, const CSSPrimitiveValue& value)
322
if (value.isPercentage())
323
return Length(value.doubleValue(), Percent);
324
if (value.isCalculatedPercentageWithLength())
325
return Length(value.cssCalcValue()->createCalculationValue(conversionData));
326
return value.computeLength<Length>(conversionData);
329
inline LengthSize BuilderConverter::convertRadius(BuilderState& builderState, const CSSValue& value)
331
auto* pair = downcast<CSSPrimitiveValue>(value).pairValue();
332
if (!pair || !pair->first() || !pair->second())
333
return { { 0, Fixed }, { 0, Fixed } };
335
CSSToLengthConversionData conversionData = builderState.cssToLengthConversionData();
336
LengthSize radius { convertToRadiusLength(conversionData, *pair->first()), convertToRadiusLength(conversionData, *pair->second()) };
338
ASSERT(!radius.width.isNegative());
339
ASSERT(!radius.height.isNegative());
340
if (radius.width.isZero() || radius.height.isZero())
341
return { { 0, Fixed }, { 0, Fixed } };
346
inline Length BuilderConverter::convertTo100PercentMinusLength(const Length& length)
348
if (length.isPercent())
349
return Length(100 - length.value(), Percent);
351
// Turn this into a calc expression: calc(100% - length)
352
Vector<std::unique_ptr<CalcExpressionNode>> lengths;
353
lengths.reserveInitialCapacity(2);
354
lengths.uncheckedAppend(makeUnique<CalcExpressionLength>(Length(100, Percent)));
355
lengths.uncheckedAppend(makeUnique<CalcExpressionLength>(length));
356
auto op = makeUnique<CalcExpressionOperation>(WTFMove(lengths), CalcOperator::Subtract);
357
return Length(CalculationValue::create(WTFMove(op), ValueRangeAll));
360
inline Length BuilderConverter::convertPositionComponentX(BuilderState& builderState, const CSSValue& value)
362
return convertPositionComponent<CSSValueLeft, CSSValueRight>(builderState, downcast<CSSPrimitiveValue>(value));
365
inline Length BuilderConverter::convertPositionComponentY(BuilderState& builderState, const CSSValue& value)
367
return convertPositionComponent<CSSValueTop, CSSValueBottom>(builderState, downcast<CSSPrimitiveValue>(value));
370
template<CSSValueID cssValueFor0, CSSValueID cssValueFor100>
371
inline Length BuilderConverter::convertPositionComponent(BuilderState& builderState, const CSSPrimitiveValue& value)
375
auto* lengthValue = &value;
376
bool relativeToTrailingEdge = false;
378
if (value.isPair()) {
379
auto& first = *value.pairValue()->first();
380
if (first.valueID() == CSSValueRight || first.valueID() == CSSValueBottom)
381
relativeToTrailingEdge = true;
382
lengthValue = value.pairValue()->second();
385
if (value.isValueID()) {
386
switch (value.valueID()) {
388
return Length(0, Percent);
390
return Length(100, Percent);
392
return Length(50, Percent);
394
ASSERT_NOT_REACHED();
398
length = convertLength(builderState, *lengthValue);
400
if (relativeToTrailingEdge)
401
length = convertTo100PercentMinusLength(length);
406
inline LengthPoint BuilderConverter::convertObjectPosition(BuilderState& builderState, const CSSValue& value)
408
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
409
Pair* pair = primitiveValue.pairValue();
410
if (!pair || !pair->first() || !pair->second())
411
return RenderStyle::initialObjectPosition();
413
Length lengthX = convertPositionComponent<CSSValueLeft, CSSValueRight>(builderState, *pair->first());
414
Length lengthY = convertPositionComponent<CSSValueTop, CSSValueBottom>(builderState, *pair->second());
416
return LengthPoint(lengthX, lengthY);
419
inline OptionSet<TextDecoration> BuilderConverter::convertTextDecoration(BuilderState&, const CSSValue& value)
421
auto result = RenderStyle::initialTextDecoration();
422
if (is<CSSValueList>(value)) {
423
for (auto& currentValue : downcast<CSSValueList>(value))
424
result.add(downcast<CSSPrimitiveValue>(currentValue.get()));
430
inline T BuilderConverter::convertNumber(BuilderState&, const CSSValue& value)
432
return downcast<CSSPrimitiveValue>(value).value<T>(CSSUnitType::CSS_NUMBER);
436
inline T BuilderConverter::convertNumberOrAuto(BuilderState& builderState, const CSSValue& value)
438
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
440
return convertNumber<T>(builderState, value);
443
inline short BuilderConverter::convertWebkitHyphenateLimitLines(BuilderState&, const CSSValue& value)
445
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
446
if (primitiveValue.valueID() == CSSValueNoLimit)
448
return primitiveValue.value<short>(CSSUnitType::CSS_NUMBER);
451
template<CSSPropertyID property>
452
inline NinePieceImage BuilderConverter::convertBorderImage(BuilderState& builderState, CSSValue& value)
454
NinePieceImage image;
455
builderState.styleMap().mapNinePieceImage(property, &value, image);
459
template<CSSPropertyID property>
460
inline NinePieceImage BuilderConverter::convertBorderMask(BuilderState& builderState, CSSValue& value)
462
NinePieceImage image(NinePieceImage::Type::Mask);
463
builderState.styleMap().mapNinePieceImage(property, &value, image);
467
template<CSSPropertyID>
468
inline RefPtr<StyleImage> BuilderConverter::convertStyleImage(BuilderState& builderState, CSSValue& value)
470
return builderState.createStyleImage(value);
473
inline ImageOrientation BuilderConverter::convertImageOrientation(BuilderState&, const CSSValue& value)
475
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
476
if (primitiveValue.valueID() == CSSValueFromImage)
477
return ImageOrientation::FromImage;
478
return ImageOrientation::None;
481
inline TransformOperations BuilderConverter::convertTransform(BuilderState& builderState, const CSSValue& value)
483
TransformOperations operations;
484
transformsForValue(value, builderState.cssToLengthConversionData(), operations);
488
#if ENABLE(DARK_MODE_CSS)
489
inline void BuilderConverter::updateColorScheme(const CSSPrimitiveValue& primitiveValue, StyleColorScheme& colorScheme)
491
ASSERT(primitiveValue.isValueID());
493
switch (primitiveValue.valueID()) {
495
colorScheme = StyleColorScheme();
498
colorScheme.setAllowsTransformations(false);
501
colorScheme.add(ColorScheme::Light);
504
colorScheme.add(ColorScheme::Dark);
507
// Unknown identifiers are allowed and ignored.
512
inline StyleColorScheme BuilderConverter::convertColorScheme(BuilderState&, const CSSValue& value)
514
StyleColorScheme colorScheme;
516
if (is<CSSValueList>(value)) {
517
for (auto& currentValue : downcast<CSSValueList>(value))
518
updateColorScheme(downcast<CSSPrimitiveValue>(currentValue.get()), colorScheme);
519
} else if (is<CSSPrimitiveValue>(value))
520
updateColorScheme(downcast<CSSPrimitiveValue>(value), colorScheme);
522
// If the value was just "only", that is synonymous for "only light".
523
if (colorScheme.isOnly())
524
colorScheme.add(ColorScheme::Light);
530
inline String BuilderConverter::convertString(BuilderState&, const CSSValue& value)
532
return downcast<CSSPrimitiveValue>(value).stringValue();
535
inline String BuilderConverter::convertStringOrAuto(BuilderState& builderState, const CSSValue& value)
537
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
539
return convertString(builderState, value);
542
inline String BuilderConverter::convertStringOrNone(BuilderState& builderState, const CSSValue& value)
544
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone)
546
return convertString(builderState, value);
549
inline OptionSet<TextEmphasisPosition> BuilderConverter::valueToEmphasisPosition(const CSSPrimitiveValue& primitiveValue)
551
ASSERT(primitiveValue.isValueID());
553
switch (primitiveValue.valueID()) {
555
return TextEmphasisPosition::Over;
557
return TextEmphasisPosition::Under;
559
return TextEmphasisPosition::Left;
561
return TextEmphasisPosition::Right;
566
ASSERT_NOT_REACHED();
567
return RenderStyle::initialTextEmphasisPosition();
570
inline OptionSet<TextEmphasisPosition> BuilderConverter::convertTextEmphasisPosition(BuilderState&, const CSSValue& value)
572
if (is<CSSPrimitiveValue>(value))
573
return valueToEmphasisPosition(downcast<CSSPrimitiveValue>(value));
575
OptionSet<TextEmphasisPosition> position;
576
for (auto& currentValue : downcast<CSSValueList>(value))
577
position.add(valueToEmphasisPosition(downcast<CSSPrimitiveValue>(currentValue.get())));
581
inline TextAlignMode BuilderConverter::convertTextAlign(BuilderState& builderState, const CSSValue& value)
583
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
584
ASSERT(primitiveValue.isValueID());
586
if (primitiveValue.valueID() != CSSValueWebkitMatchParent)
587
return primitiveValue;
589
auto& parentStyle = builderState.parentStyle();
590
if (parentStyle.textAlign() == TextAlignMode::Start)
591
return parentStyle.isLeftToRightDirection() ? TextAlignMode::Left : TextAlignMode::Right;
592
if (parentStyle.textAlign() == TextAlignMode::End)
593
return parentStyle.isLeftToRightDirection() ? TextAlignMode::Right : TextAlignMode::Left;
594
return parentStyle.textAlign();
597
inline RefPtr<ClipPathOperation> BuilderConverter::convertClipPath(BuilderState& builderState, const CSSValue& value)
599
if (is<CSSPrimitiveValue>(value)) {
600
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
601
if (primitiveValue.primitiveType() == CSSUnitType::CSS_URI) {
602
String cssURLValue = primitiveValue.stringValue();
603
String fragment = SVGURIReference::fragmentIdentifierFromIRIString(cssURLValue, builderState.document());
604
// FIXME: It doesn't work with external SVG references (see https://bugs.webkit.org/show_bug.cgi?id=126133)
605
return ReferenceClipPathOperation::create(cssURLValue, fragment);
607
ASSERT(primitiveValue.valueID() == CSSValueNone);
611
CSSBoxType referenceBox = CSSBoxType::BoxMissing;
612
RefPtr<ClipPathOperation> operation;
614
for (auto& currentValue : downcast<CSSValueList>(value)) {
615
auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
616
if (primitiveValue.isShape()) {
618
operation = ShapeClipPathOperation::create(basicShapeForValue(builderState.cssToLengthConversionData(), *primitiveValue.shapeValue()));
620
ASSERT(primitiveValue.valueID() == CSSValueContentBox
621
|| primitiveValue.valueID() == CSSValueBorderBox
622
|| primitiveValue.valueID() == CSSValuePaddingBox
623
|| primitiveValue.valueID() == CSSValueMarginBox
624
|| primitiveValue.valueID() == CSSValueFillBox
625
|| primitiveValue.valueID() == CSSValueStrokeBox
626
|| primitiveValue.valueID() == CSSValueViewBox);
627
ASSERT(referenceBox == CSSBoxType::BoxMissing);
628
referenceBox = primitiveValue;
632
downcast<ShapeClipPathOperation>(*operation).setReferenceBox(referenceBox);
634
ASSERT(referenceBox != CSSBoxType::BoxMissing);
635
operation = BoxClipPathOperation::create(referenceBox);
641
inline Resize BuilderConverter::convertResize(BuilderState& builderState, const CSSValue& value)
643
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
645
Resize resize = Resize::None;
646
if (primitiveValue.valueID() == CSSValueAuto)
647
resize = builderState.document().settings().textAreasAreResizable() ? Resize::Both : Resize::None;
649
resize = primitiveValue;
654
inline int BuilderConverter::convertMarqueeRepetition(BuilderState&, const CSSValue& value)
656
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
657
if (primitiveValue.valueID() == CSSValueInfinite)
658
return -1; // -1 means repeat forever.
660
ASSERT(primitiveValue.isNumber());
661
return primitiveValue.intValue();
664
inline int BuilderConverter::convertMarqueeSpeed(BuilderState&, const CSSValue& value)
666
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
667
if (primitiveValue.isTime())
668
return primitiveValue.computeTime<int, CSSPrimitiveValue::Milliseconds>();
669
// For scrollamount support.
670
ASSERT(primitiveValue.isNumber());
671
return primitiveValue.intValue();
674
inline Ref<QuotesData> BuilderConverter::convertQuotes(BuilderState&, const CSSValue& value)
676
if (is<CSSPrimitiveValue>(value)) {
677
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
678
return QuotesData::create(Vector<std::pair<String, String>>());
681
auto& list = downcast<CSSValueList>(value);
682
Vector<std::pair<String, String>> quotes;
683
quotes.reserveInitialCapacity(list.length() / 2);
684
for (unsigned i = 0; i < list.length(); i += 2) {
685
const CSSValue* first = list.itemWithoutBoundsCheck(i);
686
// item() returns null if out of bounds so this is safe.
687
const CSSValue* second = list.item(i + 1);
690
String startQuote = downcast<CSSPrimitiveValue>(*first).stringValue();
691
String endQuote = downcast<CSSPrimitiveValue>(*second).stringValue();
692
quotes.append(std::make_pair(startQuote, endQuote));
694
return QuotesData::create(quotes);
697
inline TextUnderlinePosition BuilderConverter::convertTextUnderlinePosition(BuilderState&, const CSSValue& value)
699
ASSERT(is<CSSPrimitiveValue>(value));
700
return downcast<CSSPrimitiveValue>(value);
703
inline TextUnderlineOffset BuilderConverter::convertTextUnderlineOffset(BuilderState& builderState, const CSSValue& value)
705
ASSERT(is<CSSPrimitiveValue>(value));
706
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
707
switch (primitiveValue.valueID()) {
709
return TextUnderlineOffset::createWithAuto();
711
ASSERT(primitiveValue.isLength());
712
auto computedLength = convertComputedLength<float>(builderState, primitiveValue);
713
return TextUnderlineOffset::createWithLength(computedLength);
717
inline TextDecorationThickness BuilderConverter::convertTextDecorationThickness(BuilderState& builderState, const CSSValue& value)
719
ASSERT(is<CSSPrimitiveValue>(value));
720
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
721
switch (primitiveValue.valueID()) {
723
return TextDecorationThickness::createWithAuto();
724
case CSSValueFromFont:
725
return TextDecorationThickness::createFromFont();
727
ASSERT(primitiveValue.isLength());
728
auto computedLength = convertComputedLength<float>(builderState, primitiveValue);
729
return TextDecorationThickness::createWithLength(computedLength);
733
inline RefPtr<StyleReflection> BuilderConverter::convertReflection(BuilderState& builderState, const CSSValue& value)
735
if (is<CSSPrimitiveValue>(value)) {
736
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
740
auto& reflectValue = downcast<CSSReflectValue>(value);
742
auto reflection = StyleReflection::create();
743
reflection->setDirection(reflectValue.direction());
744
reflection->setOffset(reflectValue.offset().convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(builderState.cssToLengthConversionData()));
746
NinePieceImage mask(NinePieceImage::Type::Mask);
747
builderState.styleMap().mapNinePieceImage(CSSPropertyWebkitBoxReflect, reflectValue.mask(), mask);
748
reflection->setMask(mask);
753
inline IntSize BuilderConverter::convertInitialLetter(BuilderState&, const CSSValue& value)
755
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
757
if (primitiveValue.valueID() == CSSValueNormal)
760
Pair* pair = primitiveValue.pairValue();
762
ASSERT(pair->first());
763
ASSERT(pair->second());
765
return IntSize(pair->first()->intValue(), pair->second()->intValue());
768
inline float BuilderConverter::convertTextStrokeWidth(BuilderState& builderState, const CSSValue& value)
770
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
773
switch (primitiveValue.valueID()) {
776
case CSSValueThick: {
777
double result = 1.0 / 48;
778
if (primitiveValue.valueID() == CSSValueMedium)
780
else if (primitiveValue.valueID() == CSSValueThick)
782
Ref<CSSPrimitiveValue> emsValue(CSSPrimitiveValue::create(result, CSSUnitType::CSS_EMS));
783
width = convertComputedLength<float>(builderState, emsValue);
786
case CSSValueInvalid: {
787
width = convertComputedLength<float>(builderState, primitiveValue);
791
ASSERT_NOT_REACHED();
798
inline OptionSet<LineBoxContain> BuilderConverter::convertLineBoxContain(BuilderState&, const CSSValue& value)
800
if (is<CSSPrimitiveValue>(value)) {
801
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
805
return downcast<CSSLineBoxContainValue>(value).value();
808
inline OptionSet<TextDecorationSkip> BuilderConverter::valueToDecorationSkip(const CSSPrimitiveValue& primitiveValue)
810
ASSERT(primitiveValue.isValueID());
812
switch (primitiveValue.valueID()) {
814
return TextDecorationSkip::Auto;
816
return OptionSet<TextDecorationSkip> { };
818
return TextDecorationSkip::Ink;
819
case CSSValueObjects:
820
return TextDecorationSkip::Objects;
825
ASSERT_NOT_REACHED();
826
return OptionSet<TextDecorationSkip> { };
829
inline OptionSet<TextDecorationSkip> BuilderConverter::convertTextDecorationSkip(BuilderState&, const CSSValue& value)
831
if (is<CSSPrimitiveValue>(value))
832
return valueToDecorationSkip(downcast<CSSPrimitiveValue>(value));
834
OptionSet<TextDecorationSkip> skip;
835
for (auto& currentValue : downcast<CSSValueList>(value))
836
skip.add(valueToDecorationSkip(downcast<CSSPrimitiveValue>(currentValue.get())));
840
static inline bool isImageShape(const CSSValue& value)
842
return is<CSSImageValue>(value) || is<CSSImageSetValue>(value) || is<CSSImageGeneratorValue>(value);
845
inline RefPtr<ShapeValue> BuilderConverter::convertShapeValue(BuilderState& builderState, CSSValue& value)
847
if (is<CSSPrimitiveValue>(value)) {
848
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
852
if (isImageShape(value))
853
return ShapeValue::create(builderState.createStyleImage(value).releaseNonNull());
855
RefPtr<BasicShape> shape;
856
CSSBoxType referenceBox = CSSBoxType::BoxMissing;
857
for (auto& currentValue : downcast<CSSValueList>(value)) {
858
auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
859
if (primitiveValue.isShape())
860
shape = basicShapeForValue(builderState.cssToLengthConversionData(), *primitiveValue.shapeValue());
861
else if (primitiveValue.valueID() == CSSValueContentBox
862
|| primitiveValue.valueID() == CSSValueBorderBox
863
|| primitiveValue.valueID() == CSSValuePaddingBox
864
|| primitiveValue.valueID() == CSSValueMarginBox)
865
referenceBox = primitiveValue;
867
ASSERT_NOT_REACHED();
873
return ShapeValue::create(shape.releaseNonNull(), referenceBox);
875
if (referenceBox != CSSBoxType::BoxMissing)
876
return ShapeValue::create(referenceBox);
878
ASSERT_NOT_REACHED();
882
#if ENABLE(CSS_SCROLL_SNAP)
884
inline ScrollSnapType BuilderConverter::convertScrollSnapType(BuilderState&, const CSSValue& value)
887
auto& values = downcast<CSSValueList>(value);
888
auto& firstValue = downcast<CSSPrimitiveValue>(*values.item(0));
889
if (values.length() == 2) {
890
type.axis = firstValue;
891
type.strictness = downcast<CSSPrimitiveValue>(*values.item(1));
895
switch (firstValue.valueID()) {
897
case CSSValueMandatory:
898
case CSSValueProximity:
899
type.strictness = firstValue;
902
type.axis = firstValue;
903
type.strictness = ScrollSnapStrictness::Proximity;
909
inline ScrollSnapAlign BuilderConverter::convertScrollSnapAlign(BuilderState&, const CSSValue& value)
911
auto& values = downcast<CSSValueList>(value);
912
ScrollSnapAlign alignment;
913
alignment.x = downcast<CSSPrimitiveValue>(*values.item(0));
914
if (values.length() == 1)
915
alignment.y = alignment.x;
917
alignment.y = downcast<CSSPrimitiveValue>(*values.item(1));
923
inline GridLength BuilderConverter::createGridTrackBreadth(const CSSPrimitiveValue& primitiveValue, BuilderState& builderState)
925
if (primitiveValue.valueID() == CSSValueMinContent || primitiveValue.valueID() == CSSValueWebkitMinContent)
926
return Length(MinContent);
928
if (primitiveValue.valueID() == CSSValueMaxContent || primitiveValue.valueID() == CSSValueWebkitMaxContent)
929
return Length(MaxContent);
932
if (primitiveValue.isFlex())
933
return GridLength(primitiveValue.doubleValue());
935
return primitiveValue.convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion | AutoConversion>(builderState.cssToLengthConversionData());
938
inline GridTrackSize BuilderConverter::createGridTrackSize(const CSSValue& value, BuilderState& builderState)
940
if (is<CSSPrimitiveValue>(value))
941
return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(value), builderState));
943
ASSERT(is<CSSFunctionValue>(value));
944
const auto& function = downcast<CSSFunctionValue>(value);
946
if (function.length() == 1)
947
return GridTrackSize(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), builderState), FitContentTrackSizing);
949
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(function.length() == 2);
950
GridLength minTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(0)), builderState));
951
GridLength maxTrackBreadth(createGridTrackBreadth(downcast<CSSPrimitiveValue>(*function.itemWithoutBoundsCheck(1)), builderState));
952
return GridTrackSize(minTrackBreadth, maxTrackBreadth);
955
static void createGridLineNamesList(const CSSValue& value, unsigned currentNamedGridLine, NamedGridLinesMap& namedGridLines, OrderedNamedGridLinesMap& orderedNamedGridLines)
957
ASSERT(value.isGridLineNamesValue());
959
for (auto& namedGridLineValue : downcast<CSSGridLineNamesValue>(value)) {
960
String namedGridLine = downcast<CSSPrimitiveValue>(namedGridLineValue.get()).stringValue();
961
auto result = namedGridLines.add(namedGridLine, Vector<unsigned>());
962
result.iterator->value.append(currentNamedGridLine);
963
auto orderedResult = orderedNamedGridLines.add(currentNamedGridLine, Vector<String>());
964
orderedResult.iterator->value.append(namedGridLine);
968
struct BuilderConverter::TracksData {
969
WTF_MAKE_NONCOPYABLE(TracksData); WTF_MAKE_FAST_ALLOCATED;
971
TracksData() = default;
973
Vector<GridTrackSize> m_trackSizes;
974
NamedGridLinesMap m_namedGridLines;
975
OrderedNamedGridLinesMap m_orderedNamedGridLines;
976
Vector<GridTrackSize> m_autoRepeatTrackSizes;
977
NamedGridLinesMap m_autoRepeatNamedGridLines;
978
OrderedNamedGridLinesMap m_autoRepeatOrderedNamedGridLines;
979
unsigned m_autoRepeatInsertionPoint { RenderStyle::initialGridAutoRepeatInsertionPoint() };
980
AutoRepeatType m_autoRepeatType { RenderStyle::initialGridAutoRepeatType() };
983
inline bool BuilderConverter::createGridTrackList(const CSSValue& value, TracksData& tracksData, BuilderState& builderState)
986
if (is<CSSPrimitiveValue>(value))
987
return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone;
989
if (!is<CSSValueList>(value))
992
unsigned currentNamedGridLine = 0;
993
auto handleLineNameOrTrackSize = [&](const CSSValue& currentValue) {
994
if (is<CSSGridLineNamesValue>(currentValue))
995
createGridLineNamesList(currentValue, currentNamedGridLine, tracksData.m_namedGridLines, tracksData.m_orderedNamedGridLines);
997
++currentNamedGridLine;
998
tracksData.m_trackSizes.append(createGridTrackSize(currentValue, builderState));
1002
for (auto& currentValue : downcast<CSSValueList>(value)) {
1003
if (is<CSSGridAutoRepeatValue>(currentValue)) {
1004
ASSERT(tracksData.m_autoRepeatTrackSizes.isEmpty());
1005
unsigned autoRepeatIndex = 0;
1006
CSSValueID autoRepeatID = downcast<CSSGridAutoRepeatValue>(currentValue.get()).autoRepeatID();
1007
ASSERT(autoRepeatID == CSSValueAutoFill || autoRepeatID == CSSValueAutoFit);
1008
tracksData.m_autoRepeatType = autoRepeatID == CSSValueAutoFill ? AutoRepeatType::Fill : AutoRepeatType::Fit;
1009
for (auto& autoRepeatValue : downcast<CSSValueList>(currentValue.get())) {
1010
if (is<CSSGridLineNamesValue>(autoRepeatValue)) {
1011
createGridLineNamesList(autoRepeatValue.get(), autoRepeatIndex, tracksData.m_autoRepeatNamedGridLines, tracksData.m_autoRepeatOrderedNamedGridLines);
1015
tracksData.m_autoRepeatTrackSizes.append(createGridTrackSize(autoRepeatValue.get(), builderState));
1017
tracksData.m_autoRepeatInsertionPoint = currentNamedGridLine++;
1021
if (is<CSSGridIntegerRepeatValue>(currentValue)) {
1022
size_t repetitions = downcast<CSSGridIntegerRepeatValue>(currentValue.get()).repetitions();
1023
for (size_t i = 0; i < repetitions; ++i) {
1024
for (auto& integerRepeatValue : downcast<CSSValueList>(currentValue.get()))
1025
handleLineNameOrTrackSize(integerRepeatValue);
1030
handleLineNameOrTrackSize(currentValue);
1033
// The parser should have rejected any <track-list> without any <track-size> as
1034
// this is not conformant to the syntax.
1035
ASSERT(!tracksData.m_trackSizes.isEmpty() || !tracksData.m_autoRepeatTrackSizes.isEmpty());
1039
inline bool BuilderConverter::createGridPosition(const CSSValue& value, GridPosition& position)
1041
// We accept the specification's grammar:
1042
// auto | <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
1043
if (is<CSSPrimitiveValue>(value)) {
1044
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1045
// We translate <ident> to <string> during parsing as it makes handling it simpler.
1046
if (primitiveValue.isString()) {
1047
position.setNamedGridArea(primitiveValue.stringValue());
1051
ASSERT(primitiveValue.valueID() == CSSValueAuto);
1055
auto& values = downcast<CSSValueList>(value);
1056
ASSERT(values.length());
1058
auto it = values.begin();
1059
const CSSPrimitiveValue* currentValue = &downcast<CSSPrimitiveValue>(it->get());
1060
bool isSpanPosition = false;
1061
if (currentValue->valueID() == CSSValueSpan) {
1062
isSpanPosition = true;
1064
currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
1067
int gridLineNumber = 0;
1068
if (currentValue && currentValue->isNumber()) {
1069
gridLineNumber = currentValue->intValue();
1071
currentValue = it != values.end() ? &downcast<CSSPrimitiveValue>(it->get()) : nullptr;
1074
String gridLineName;
1075
if (currentValue && currentValue->isString()) {
1076
gridLineName = currentValue->stringValue();
1080
ASSERT(it == values.end());
1082
position.setSpanPosition(gridLineNumber ? gridLineNumber : 1, gridLineName);
1084
position.setExplicitPosition(gridLineNumber, gridLineName);
1089
inline void BuilderConverter::createImplicitNamedGridLinesFromGridArea(const NamedGridAreaMap& namedGridAreas, NamedGridLinesMap& namedGridLines, GridTrackSizingDirection direction)
1091
for (auto& area : namedGridAreas) {
1092
GridSpan areaSpan = direction == ForRows ? area.value.rows : area.value.columns;
1094
auto& startVector = namedGridLines.add(area.key + "-start", Vector<unsigned>()).iterator->value;
1095
startVector.append(areaSpan.startLine());
1096
std::sort(startVector.begin(), startVector.end());
1099
auto& endVector = namedGridLines.add(area.key + "-end", Vector<unsigned>()).iterator->value;
1100
endVector.append(areaSpan.endLine());
1101
std::sort(endVector.begin(), endVector.end());
1106
inline Vector<GridTrackSize> BuilderConverter::convertGridTrackSizeList(BuilderState& builderState, const CSSValue& value)
1108
ASSERT(value.isValueList());
1109
auto& valueList = downcast<CSSValueList>(value);
1110
Vector<GridTrackSize> trackSizes;
1111
trackSizes.reserveInitialCapacity(valueList.length());
1112
for (auto& currValue : valueList) {
1113
ASSERT(!currValue->isGridLineNamesValue());
1114
ASSERT(!currValue->isGridAutoRepeatValue());
1115
ASSERT(!currValue->isGridIntegerRepeatValue());
1116
trackSizes.uncheckedAppend(convertGridTrackSize(builderState, currValue));
1121
inline GridTrackSize BuilderConverter::convertGridTrackSize(BuilderState& builderState, const CSSValue& value)
1123
return createGridTrackSize(value, builderState);
1126
inline Optional<GridPosition> BuilderConverter::convertGridPosition(BuilderState&, const CSSValue& value)
1128
GridPosition gridPosition;
1129
if (createGridPosition(value, gridPosition))
1130
return gridPosition;
1131
return WTF::nullopt;
1134
inline GridAutoFlow BuilderConverter::convertGridAutoFlow(BuilderState&, const CSSValue& value)
1136
auto& list = downcast<CSSValueList>(value);
1138
return RenderStyle::initialGridAutoFlow();
1140
auto& first = downcast<CSSPrimitiveValue>(*list.item(0));
1141
auto* second = downcast<CSSPrimitiveValue>(list.item(1));
1143
GridAutoFlow autoFlow;
1144
switch (first.valueID()) {
1146
if (second && second->valueID() == CSSValueDense)
1147
autoFlow = AutoFlowRowDense;
1149
autoFlow = AutoFlowRow;
1151
case CSSValueColumn:
1152
if (second && second->valueID() == CSSValueDense)
1153
autoFlow = AutoFlowColumnDense;
1155
autoFlow = AutoFlowColumn;
1158
if (second && second->valueID() == CSSValueColumn)
1159
autoFlow = AutoFlowColumnDense;
1161
autoFlow = AutoFlowRowDense;
1164
ASSERT_NOT_REACHED();
1165
autoFlow = RenderStyle::initialGridAutoFlow();
1172
inline CSSToLengthConversionData BuilderConverter::csstoLengthConversionDataWithTextZoomFactor(BuilderState& builderState)
1174
if (auto* frame = builderState.document().frame()) {
1175
float textZoomFactor = builderState.style().textZoom() != TextZoom::Reset ? frame->textZoomFactor() : 1.0f;
1176
return builderState.cssToLengthConversionData().copyWithAdjustedZoom(builderState.style().effectiveZoom() * textZoomFactor);
1178
return builderState.cssToLengthConversionData();
1181
inline Optional<Length> BuilderConverter::convertWordSpacing(BuilderState& builderState, const CSSValue& value)
1183
Optional<Length> wordSpacing;
1184
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1185
if (primitiveValue.valueID() == CSSValueNormal)
1186
wordSpacing = RenderStyle::initialWordSpacing();
1187
else if (primitiveValue.isLength())
1188
wordSpacing = primitiveValue.computeLength<Length>(csstoLengthConversionDataWithTextZoomFactor(builderState));
1189
else if (primitiveValue.isPercentage())
1190
wordSpacing = Length(clampTo<float>(primitiveValue.doubleValue(), minValueForCssLength, maxValueForCssLength), Percent);
1191
else if (primitiveValue.isNumber())
1192
wordSpacing = Length(primitiveValue.doubleValue(), Fixed);
1197
inline Optional<float> BuilderConverter::convertPerspective(BuilderState& builderState, const CSSValue& value)
1199
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1200
if (primitiveValue.valueID() == CSSValueNone)
1203
float perspective = -1;
1204
if (primitiveValue.isLength())
1205
perspective = primitiveValue.computeLength<float>(builderState.cssToLengthConversionData());
1206
else if (primitiveValue.isNumber())
1207
perspective = primitiveValue.doubleValue() * builderState.cssToLengthConversionData().zoom();
1209
ASSERT_NOT_REACHED();
1211
return perspective < 0 ? Optional<float>(WTF::nullopt) : Optional<float>(perspective);
1214
inline Optional<Length> BuilderConverter::convertMarqueeIncrement(BuilderState& builderState, const CSSValue& value)
1216
Length length = downcast<CSSPrimitiveValue>(value).convertToLength<FixedIntegerConversion | PercentConversion | CalculatedConversion>(builderState.cssToLengthConversionData().copyWithAdjustedZoom(1.0f));
1217
if (length.isUndefined())
1218
return WTF::nullopt;
1222
inline Optional<FilterOperations> BuilderConverter::convertFilterOperations(BuilderState& builderState, const CSSValue& value)
1224
FilterOperations operations;
1225
if (builderState.createFilterOperations(value, operations))
1227
return WTF::nullopt;
1230
inline FontFeatureSettings BuilderConverter::convertFontFeatureSettings(BuilderState&, const CSSValue& value)
1232
if (is<CSSPrimitiveValue>(value)) {
1233
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1237
FontFeatureSettings settings;
1238
for (auto& item : downcast<CSSValueList>(value)) {
1239
auto& feature = downcast<CSSFontFeatureValue>(item.get());
1240
settings.insert(FontFeature(feature.tag(), feature.value()));
1245
inline FontSelectionValue BuilderConverter::convertFontWeightFromValue(const CSSValue& value)
1247
ASSERT(is<CSSPrimitiveValue>(value));
1248
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1250
if (primitiveValue.isNumber())
1251
return FontSelectionValue::clampFloat(primitiveValue.floatValue());
1253
ASSERT(primitiveValue.isValueID());
1254
switch (primitiveValue.valueID()) {
1255
case CSSValueNormal:
1256
return normalWeightValue();
1258
case CSSValueBolder:
1259
return boldWeightValue();
1260
case CSSValueLighter:
1261
return lightWeightValue();
1263
ASSERT_NOT_REACHED();
1264
return normalWeightValue();
1268
inline FontSelectionValue BuilderConverter::convertFontStretchFromValue(const CSSValue& value)
1270
ASSERT(is<CSSPrimitiveValue>(value));
1271
const auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1273
if (primitiveValue.isPercentage())
1274
return FontSelectionValue::clampFloat(primitiveValue.floatValue());
1276
ASSERT(primitiveValue.isValueID());
1277
if (auto value = fontStretchValue(primitiveValue.valueID()))
1278
return value.value();
1279
ASSERT_NOT_REACHED();
1280
return normalStretchValue();
1283
// The input value needs to parsed and valid, this function returns WTF::nullopt if the input was "normal".
1284
inline Optional<FontSelectionValue> BuilderConverter::convertFontStyleFromValue(const CSSValue& value)
1286
ASSERT(is<CSSFontStyleValue>(value));
1287
const auto& fontStyleValue = downcast<CSSFontStyleValue>(value);
1289
auto valueID = fontStyleValue.fontStyleValue->valueID();
1290
if (valueID == CSSValueNormal)
1291
return WTF::nullopt;
1292
if (valueID == CSSValueItalic)
1293
return italicValue();
1294
ASSERT(valueID == CSSValueOblique);
1295
if (auto* obliqueValue = fontStyleValue.obliqueValue.get())
1296
return FontSelectionValue(obliqueValue->value<float>(CSSUnitType::CSS_DEG));
1297
return italicValue();
1300
inline FontSelectionValue BuilderConverter::convertFontWeight(BuilderState& builderState, const CSSValue& value)
1302
ASSERT(is<CSSPrimitiveValue>(value));
1303
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1304
if (primitiveValue.isValueID()) {
1305
auto valueID = primitiveValue.valueID();
1306
if (valueID == CSSValueBolder)
1307
return FontCascadeDescription::bolderWeight(builderState.parentStyle().fontDescription().weight());
1308
if (valueID == CSSValueLighter)
1309
return FontCascadeDescription::lighterWeight(builderState.parentStyle().fontDescription().weight());
1311
return convertFontWeightFromValue(value);
1314
inline FontSelectionValue BuilderConverter::convertFontStretch(BuilderState&, const CSSValue& value)
1316
return convertFontStretchFromValue(value);
1319
#if ENABLE(VARIATION_FONTS)
1320
inline FontVariationSettings BuilderConverter::convertFontVariationSettings(BuilderState&, const CSSValue& value)
1322
if (is<CSSPrimitiveValue>(value)) {
1323
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1327
FontVariationSettings settings;
1328
for (auto& item : downcast<CSSValueList>(value)) {
1329
auto& feature = downcast<CSSFontVariationValue>(item.get());
1330
settings.insert({ feature.tag(), feature.value() });
1336
#if PLATFORM(IOS_FAMILY)
1337
inline bool BuilderConverter::convertTouchCallout(BuilderState&, const CSSValue& value)
1339
return !equalLettersIgnoringASCIICase(downcast<CSSPrimitiveValue>(value).stringValue(), "none");
1343
#if ENABLE(TOUCH_EVENTS)
1344
inline Color BuilderConverter::convertTapHighlightColor(BuilderState& builderState, const CSSValue& value)
1346
return builderState.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1350
#if ENABLE(POINTER_EVENTS)
1351
inline OptionSet<TouchAction> BuilderConverter::convertTouchAction(BuilderState&, const CSSValue& value)
1353
if (is<CSSPrimitiveValue>(value))
1354
return downcast<CSSPrimitiveValue>(value);
1356
if (is<CSSValueList>(value)) {
1357
OptionSet<TouchAction> touchActions;
1358
for (auto& currentValue : downcast<CSSValueList>(value)) {
1359
auto& primitiveValue = downcast<CSSPrimitiveValue>(currentValue.get());
1360
auto primitiveValueID = primitiveValue.valueID();
1361
if (primitiveValueID != CSSValuePanX && primitiveValueID != CSSValuePanY && primitiveValueID != CSSValuePinchZoom)
1362
return RenderStyle::initialTouchActions();
1363
touchActions.add(primitiveValue);
1365
return touchActions;
1368
return RenderStyle::initialTouchActions();
1372
#if ENABLE(OVERFLOW_SCROLLING_TOUCH)
1373
inline bool BuilderConverter::convertOverflowScrolling(BuilderState&, const CSSValue& value)
1375
return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueTouch;
1379
inline bool BuilderConverter::convertSmoothScrolling(BuilderState&, const CSSValue& value)
1381
return downcast<CSSPrimitiveValue>(value).valueID() == CSSValueSmooth;
1384
inline SVGLengthValue BuilderConverter::convertSVGLengthValue(BuilderState&, const CSSValue& value)
1386
return SVGLengthValue::fromCSSPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1389
inline Vector<SVGLengthValue> BuilderConverter::convertSVGLengthVector(BuilderState& builderState, const CSSValue& value)
1391
auto& valueList = downcast<CSSValueList>(value);
1393
Vector<SVGLengthValue> svgLengths;
1394
svgLengths.reserveInitialCapacity(valueList.length());
1395
for (auto& item : valueList)
1396
svgLengths.uncheckedAppend(convertSVGLengthValue(builderState, item));
1401
inline Vector<SVGLengthValue> BuilderConverter::convertStrokeDashArray(BuilderState& builderState, const CSSValue& value)
1403
if (is<CSSPrimitiveValue>(value)) {
1404
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
1405
return SVGRenderStyle::initialStrokeDashArray();
1408
return convertSVGLengthVector(builderState, value);
1411
inline PaintOrder BuilderConverter::convertPaintOrder(BuilderState&, const CSSValue& value)
1413
if (is<CSSPrimitiveValue>(value)) {
1414
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal);
1415
return PaintOrder::Normal;
1418
auto& orderTypeList = downcast<CSSValueList>(value);
1419
switch (downcast<CSSPrimitiveValue>(*orderTypeList.itemWithoutBoundsCheck(0)).valueID()) {
1421
return orderTypeList.length() > 1 ? PaintOrder::FillMarkers : PaintOrder::Fill;
1422
case CSSValueStroke:
1423
return orderTypeList.length() > 1 ? PaintOrder::StrokeMarkers : PaintOrder::Stroke;
1424
case CSSValueMarkers:
1425
return orderTypeList.length() > 1 ? PaintOrder::MarkersStroke : PaintOrder::Markers;
1427
ASSERT_NOT_REACHED();
1428
return PaintOrder::Normal;
1432
inline float BuilderConverter::convertOpacity(BuilderState&, const CSSValue& value)
1434
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1435
float opacity = primitiveValue.floatValue();
1436
if (primitiveValue.isPercentage())
1438
return std::max(0.0f, std::min(1.0f, opacity));
1441
inline String BuilderConverter::convertSVGURIReference(BuilderState& builderState, const CSSValue& value)
1444
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1445
if (primitiveValue.isURI())
1446
s = primitiveValue.stringValue();
1448
return SVGURIReference::fragmentIdentifierFromIRIString(s, builderState.document());
1451
inline Color BuilderConverter::convertSVGColor(BuilderState& builderState, const CSSValue& value)
1453
return builderState.colorFromPrimitiveValue(downcast<CSSPrimitiveValue>(value));
1456
inline StyleSelfAlignmentData BuilderConverter::convertSelfOrDefaultAlignmentData(BuilderState&, const CSSValue& value)
1458
StyleSelfAlignmentData alignmentData = RenderStyle::initialSelfAlignment();
1459
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1460
if (Pair* pairValue = primitiveValue.pairValue()) {
1461
if (pairValue->first()->valueID() == CSSValueLegacy) {
1462
alignmentData.setPositionType(ItemPositionType::Legacy);
1463
alignmentData.setPosition(*pairValue->second());
1464
} else if (pairValue->first()->valueID() == CSSValueFirst)
1465
alignmentData.setPosition(ItemPosition::Baseline);
1466
else if (pairValue->first()->valueID() == CSSValueLast)
1467
alignmentData.setPosition(ItemPosition::LastBaseline);
1469
alignmentData.setOverflow(*pairValue->first());
1470
alignmentData.setPosition(*pairValue->second());
1473
alignmentData.setPosition(primitiveValue);
1474
return alignmentData;
1477
inline StyleContentAlignmentData BuilderConverter::convertContentAlignmentData(BuilderState&, const CSSValue& value)
1479
StyleContentAlignmentData alignmentData = RenderStyle::initialContentAlignment();
1480
if (!is<CSSContentDistributionValue>(value))
1481
return alignmentData;
1482
auto& contentValue = downcast<CSSContentDistributionValue>(value);
1483
if (contentValue.distribution()->valueID() != CSSValueInvalid)
1484
alignmentData.setDistribution(contentValue.distribution().get());
1485
if (contentValue.position()->valueID() != CSSValueInvalid)
1486
alignmentData.setPosition(contentValue.position().get());
1487
if (contentValue.overflow()->valueID() != CSSValueInvalid)
1488
alignmentData.setOverflow(contentValue.overflow().get());
1489
return alignmentData;
1492
inline GlyphOrientation BuilderConverter::convertGlyphOrientation(BuilderState&, const CSSValue& value)
1494
float angle = fabsf(fmodf(downcast<CSSPrimitiveValue>(value).floatValue(), 360.0f));
1495
if (angle <= 45.0f || angle > 315.0f)
1496
return GlyphOrientation::Degrees0;
1497
if (angle > 45.0f && angle <= 135.0f)
1498
return GlyphOrientation::Degrees90;
1499
if (angle > 135.0f && angle <= 225.0f)
1500
return GlyphOrientation::Degrees180;
1501
return GlyphOrientation::Degrees270;
1504
inline GlyphOrientation BuilderConverter::convertGlyphOrientationOrAuto(BuilderState& builderState, const CSSValue& value)
1506
if (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueAuto)
1507
return GlyphOrientation::Auto;
1508
return convertGlyphOrientation(builderState, value);
1511
inline Optional<Length> BuilderConverter::convertLineHeight(BuilderState& builderState, const CSSValue& value, float multiplier)
1513
auto& primitiveValue = downcast<CSSPrimitiveValue>(value);
1514
if (primitiveValue.valueID() == CSSValueNormal)
1515
return RenderStyle::initialLineHeight();
1517
if (primitiveValue.isLength()) {
1518
Length length = primitiveValue.computeLength<Length>(BuilderConverter::csstoLengthConversionDataWithTextZoomFactor(builderState));
1519
if (multiplier != 1.f)
1520
length = Length(length.value() * multiplier, Fixed);
1524
// Line-height percentages need to inherit as if they were Fixed pixel values. In the example:
1525
// <div style="font-size: 10px; line-height: 150%;"><div style="font-size: 100px;"></div></div>
1526
// the inner element should have line-height of 15px. However, in this example:
1527
// <div style="font-size: 10px; line-height: 1.5;"><div style="font-size: 100px;"></div></div>
1528
// the inner element should have a line-height of 150px. Therefore, we map percentages to Fixed
1529
// values and raw numbers to percentages.
1530
if (primitiveValue.isPercentage()) {
1531
// FIXME: percentage should not be restricted to an integer here.
1532
return Length((builderState.style().computedFontSize() * primitiveValue.intValue()) / 100, Fixed);
1534
if (primitiveValue.isNumber())
1535
return Length(primitiveValue.doubleValue() * 100.0, Percent);
1537
// FIXME: The parser should only emit the above types, so this should never be reached. We should change the
1538
// type of this function to return just a Length (and not an Optional).
1539
return WTF::nullopt;
1542
inline FontSynthesis BuilderConverter::convertFontSynthesis(BuilderState&, const CSSValue& value)
1544
if (is<CSSPrimitiveValue>(value)) {
1545
ASSERT(downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNone);
1546
return FontSynthesisNone;
1549
FontSynthesis result = FontSynthesisNone;
1550
ASSERT(is<CSSValueList>(value));
1551
for (const CSSValue& v : downcast<CSSValueList>(value)) {
1552
switch (downcast<CSSPrimitiveValue>(v).valueID()) {
1553
case CSSValueWeight:
1554
result |= FontSynthesisWeight;
1557
result |= FontSynthesisStyle;
1559
case CSSValueSmallCaps:
1560
result |= FontSynthesisSmallCaps;
1563
ASSERT_NOT_REACHED();
1571
inline OptionSet<SpeakAs> BuilderConverter::convertSpeakAs(BuilderState&, const CSSValue& value)
1573
auto result = RenderStyle::initialSpeakAs();
1574
if (is<CSSValueList>(value)) {
1575
for (auto& currentValue : downcast<CSSValueList>(value))
1576
result.add(downcast<CSSPrimitiveValue>(currentValue.get()));
1581
inline OptionSet<HangingPunctuation> BuilderConverter::convertHangingPunctuation(BuilderState&, const CSSValue& value)
1583
auto result = RenderStyle::initialHangingPunctuation();
1584
if (is<CSSValueList>(value)) {
1585
for (auto& currentValue : downcast<CSSValueList>(value))
1586
result.add(downcast<CSSPrimitiveValue>(currentValue.get()));
1591
inline GapLength BuilderConverter::convertGapLength(BuilderState& builderState, const CSSValue& value)
1593
return (downcast<CSSPrimitiveValue>(value).valueID() == CSSValueNormal) ? GapLength() : GapLength(convertLength(builderState, value));