Rename AtomicString to AtomString
[WebKit-https.git] / Source / WebCore / css / CSSPrimitiveValue.cpp
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012, 2013 Apple Inc. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22 #include "CSSPrimitiveValue.h"
23
24 #include "CSSBasicShapes.h"
25 #include "CSSCalculationValue.h"
26 #include "CSSFontFamily.h"
27 #include "CSSHelper.h"
28 #include "CSSMarkup.h"
29 #include "CSSPrimitiveValueMappings.h"
30 #include "CSSPropertyNames.h"
31 #include "CSSToLengthConversionData.h"
32 #include "CSSValueKeywords.h"
33 #include "CalculationValue.h"
34 #include "Color.h"
35 #include "Counter.h"
36 #include "DeprecatedCSSOMPrimitiveValue.h"
37 #include "FontCascade.h"
38 #include "Node.h"
39 #include "Pair.h"
40 #include "RGBColor.h"
41 #include "Rect.h"
42 #include "RenderStyle.h"
43 #include <wtf/NeverDestroyed.h>
44 #include <wtf/StdLibExtras.h>
45 #include <wtf/text/StringBuilder.h>
46 #include <wtf/text/StringConcatenateNumbers.h>
47
48 namespace WebCore {
49
50 static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitType unitType)
51 {
52     switch (unitType) {
53     case CSSPrimitiveValue::CSS_CALC:
54     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
55     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
56     case CSSPrimitiveValue::CSS_CHS:
57     case CSSPrimitiveValue::CSS_CM:
58     case CSSPrimitiveValue::CSS_DEG:
59     case CSSPrimitiveValue::CSS_DIMENSION:
60     case CSSPrimitiveValue::CSS_EMS:
61     case CSSPrimitiveValue::CSS_QUIRKY_EMS:
62     case CSSPrimitiveValue::CSS_EXS:
63     case CSSPrimitiveValue::CSS_FR:
64     case CSSPrimitiveValue::CSS_GRAD:
65     case CSSPrimitiveValue::CSS_HZ:
66     case CSSPrimitiveValue::CSS_IN:
67     case CSSPrimitiveValue::CSS_KHZ:
68     case CSSPrimitiveValue::CSS_MM:
69     case CSSPrimitiveValue::CSS_MS:
70     case CSSPrimitiveValue::CSS_NUMBER:
71     case CSSPrimitiveValue::CSS_PC:
72     case CSSPrimitiveValue::CSS_PERCENTAGE:
73     case CSSPrimitiveValue::CSS_PT:
74     case CSSPrimitiveValue::CSS_PX:
75     case CSSPrimitiveValue::CSS_RAD:
76     case CSSPrimitiveValue::CSS_REMS:
77     case CSSPrimitiveValue::CSS_S:
78     case CSSPrimitiveValue::CSS_TURN:
79     case CSSPrimitiveValue::CSS_VH:
80     case CSSPrimitiveValue::CSS_VMAX:
81     case CSSPrimitiveValue::CSS_VMIN:
82     case CSSPrimitiveValue::CSS_VW:
83         return true;
84     case CSSPrimitiveValue::CSS_DPCM:
85     case CSSPrimitiveValue::CSS_DPI:
86     case CSSPrimitiveValue::CSS_DPPX:
87 #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
88         return true;
89 #else
90         return false;
91 #endif
92     case CSSPrimitiveValue::CSS_ATTR:
93     case CSSPrimitiveValue::CSS_COUNTER:
94     case CSSPrimitiveValue::CSS_COUNTER_NAME:
95     case CSSPrimitiveValue::CSS_FONT_FAMILY:
96     case CSSPrimitiveValue::CSS_IDENT:
97     case CSSPrimitiveValue::CSS_PAIR:
98     case CSSPrimitiveValue::CSS_PROPERTY_ID:
99     case CSSPrimitiveValue::CSS_QUAD:
100     case CSSPrimitiveValue::CSS_RECT:
101     case CSSPrimitiveValue::CSS_RGBCOLOR:
102     case CSSPrimitiveValue::CSS_SHAPE:
103     case CSSPrimitiveValue::CSS_STRING:
104     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
105     case CSSPrimitiveValue::CSS_UNKNOWN:
106     case CSSPrimitiveValue::CSS_URI:
107     case CSSPrimitiveValue::CSS_VALUE_ID:
108         return false;
109     }
110
111     ASSERT_NOT_REACHED();
112     return false;
113 }
114
115 #if !ASSERT_DISABLED
116
117 static inline bool isStringType(CSSPrimitiveValue::UnitType type)
118 {
119     switch (type) {
120     case CSSPrimitiveValue::CSS_STRING:
121     case CSSPrimitiveValue::CSS_URI:
122     case CSSPrimitiveValue::CSS_ATTR:
123     case CSSPrimitiveValue::CSS_COUNTER_NAME:
124     case CSSPrimitiveValue::CSS_DIMENSION:
125         return true;
126     case CSSPrimitiveValue::CSS_CALC:
127     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
128     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
129     case CSSPrimitiveValue::CSS_CHS:
130     case CSSPrimitiveValue::CSS_CM:
131     case CSSPrimitiveValue::CSS_COUNTER:
132     case CSSPrimitiveValue::CSS_DEG:
133     case CSSPrimitiveValue::CSS_DPCM:
134     case CSSPrimitiveValue::CSS_DPI:
135     case CSSPrimitiveValue::CSS_DPPX:
136     case CSSPrimitiveValue::CSS_EMS:
137     case CSSPrimitiveValue::CSS_QUIRKY_EMS:
138     case CSSPrimitiveValue::CSS_EXS:
139     case CSSPrimitiveValue::CSS_FONT_FAMILY:
140     case CSSPrimitiveValue::CSS_FR:
141     case CSSPrimitiveValue::CSS_GRAD:
142     case CSSPrimitiveValue::CSS_HZ:
143     case CSSPrimitiveValue::CSS_IDENT:
144     case CSSPrimitiveValue::CSS_IN:
145     case CSSPrimitiveValue::CSS_KHZ:
146     case CSSPrimitiveValue::CSS_MM:
147     case CSSPrimitiveValue::CSS_MS:
148     case CSSPrimitiveValue::CSS_NUMBER:
149     case CSSPrimitiveValue::CSS_PAIR:
150     case CSSPrimitiveValue::CSS_PC:
151     case CSSPrimitiveValue::CSS_PERCENTAGE:
152     case CSSPrimitiveValue::CSS_PROPERTY_ID:
153     case CSSPrimitiveValue::CSS_PT:
154     case CSSPrimitiveValue::CSS_PX:
155     case CSSPrimitiveValue::CSS_QUAD:
156     case CSSPrimitiveValue::CSS_RAD:
157     case CSSPrimitiveValue::CSS_RECT:
158     case CSSPrimitiveValue::CSS_REMS:
159     case CSSPrimitiveValue::CSS_RGBCOLOR:
160     case CSSPrimitiveValue::CSS_S:
161     case CSSPrimitiveValue::CSS_SHAPE:
162     case CSSPrimitiveValue::CSS_TURN:
163     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
164     case CSSPrimitiveValue::CSS_UNKNOWN:
165     case CSSPrimitiveValue::CSS_VALUE_ID:
166     case CSSPrimitiveValue::CSS_VH:
167     case CSSPrimitiveValue::CSS_VMAX:
168     case CSSPrimitiveValue::CSS_VMIN:
169     case CSSPrimitiveValue::CSS_VW:
170         return false;
171     }
172
173     ASSERT_NOT_REACHED();
174     return false;
175 }
176
177 #endif // !ASSERT_DISABLED
178
179 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(CSSPrimitiveValue::UnitType type)
180 {
181     // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
182     // between CSS_PX and relative lengths (see cssPixelsPerInch comment in CSSHelper.h for the topic treatment).
183     switch (type) {
184     case CSS_NUMBER:
185         return UNumber;
186     case CSS_PERCENTAGE:
187         return UPercent;
188     case CSS_PX:
189     case CSS_CM:
190     case CSS_MM:
191     case CSS_IN:
192     case CSS_PT:
193     case CSS_PC:
194         return ULength;
195     case CSS_MS:
196     case CSS_S:
197         return UTime;
198     case CSS_DEG:
199     case CSS_RAD:
200     case CSS_GRAD:
201     case CSS_TURN:
202         return UAngle;
203     case CSS_HZ:
204     case CSS_KHZ:
205         return UFrequency;
206 #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
207     case CSS_DPPX:
208     case CSS_DPI:
209     case CSS_DPCM:
210         return UResolution;
211 #endif
212     default:
213         return UOther;
214     }
215 }
216
217 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
218 static CSSTextCache& cssTextCache()
219 {
220     static NeverDestroyed<CSSTextCache> cache;
221     return cache;
222 }
223
224 unsigned short CSSPrimitiveValue::primitiveType() const
225 {
226     if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID)
227         return CSS_IDENT;
228
229     // Web-exposed content expects font family values to have CSS_STRING primitive type
230     // so we need to map our internal CSS_FONT_FAMILY type here.
231     if (m_primitiveUnitType == CSS_FONT_FAMILY)
232         return CSS_STRING;
233
234     if (m_primitiveUnitType != CSSPrimitiveValue::CSS_CALC)
235         return m_primitiveUnitType;
236
237     switch (m_value.calc->category()) {
238     case CalculationCategory::Number:
239         return CSSPrimitiveValue::CSS_NUMBER;
240     case CalculationCategory::Length:
241         return CSSPrimitiveValue::CSS_PX;
242     case CalculationCategory::Percent:
243         return CSSPrimitiveValue::CSS_PERCENTAGE;
244     case CalculationCategory::PercentNumber:
245         return CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER;
246     case CalculationCategory::PercentLength:
247         return CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH;
248     case CalculationCategory::Angle:
249     case CalculationCategory::Time:
250     case CalculationCategory::Frequency:
251         return m_value.calc->primitiveType();
252     case CalculationCategory::Other:
253         return CSSPrimitiveValue::CSS_UNKNOWN;
254     }
255     return CSSPrimitiveValue::CSS_UNKNOWN;
256 }
257
258 static const AtomString& propertyName(CSSPropertyID propertyID)
259 {
260     ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties));
261
262     return getPropertyNameAtomString(propertyID);
263 }
264
265 static const AtomString& valueName(CSSValueID valueID)
266 {
267     ASSERT_ARG(valueID, (valueID >= firstCSSValueKeyword && valueID <= lastCSSValueKeyword));
268
269     return getValueNameAtomString(valueID);
270 }
271
272 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
273     : CSSValue(PrimitiveClass)
274 {
275     m_primitiveUnitType = CSS_VALUE_ID;
276     m_value.valueID = valueID;
277 }
278
279 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
280     : CSSValue(PrimitiveClass)
281 {
282     m_primitiveUnitType = CSS_PROPERTY_ID;
283     m_value.propertyID = propertyID;
284 }
285
286 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type)
287     : CSSValue(PrimitiveClass)
288 {
289     m_primitiveUnitType = type;
290     ASSERT(std::isfinite(num));
291     m_value.num = num;
292 }
293
294 CSSPrimitiveValue::CSSPrimitiveValue(const String& string, UnitType type)
295     : CSSValue(PrimitiveClass)
296 {
297     ASSERT(isStringType(type));
298     m_primitiveUnitType = type;
299     if ((m_value.string = string.impl()))
300         m_value.string->ref();
301 }
302
303 CSSPrimitiveValue::CSSPrimitiveValue(const Color& color)
304     : CSSValue(PrimitiveClass)
305 {
306     m_primitiveUnitType = CSS_RGBCOLOR;
307     m_value.color = new Color(color);
308 }
309
310 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length)
311     : CSSValue(PrimitiveClass)
312 {
313     init(length);
314 }
315
316 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, const RenderStyle& style)
317     : CSSValue(PrimitiveClass)
318 {
319     switch (length.type()) {
320     case Auto:
321     case Intrinsic:
322     case MinIntrinsic:
323     case MinContent:
324     case MaxContent:
325     case FillAvailable:
326     case FitContent:
327     case Percent:
328         init(length);
329         return;
330     case Fixed:
331         m_primitiveUnitType = CSS_PX;
332         m_value.num = adjustFloatForAbsoluteZoom(length.value(), style);
333         return;
334     case Calculated: {
335         init(CSSCalcValue::create(length.calculationValue(), style));
336         return;
337     }
338     case Relative:
339     case Undefined:
340         ASSERT_NOT_REACHED();
341         return;
342     }
343     ASSERT_NOT_REACHED();
344 }
345
346 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize, const RenderStyle& style)
347     : CSSValue(PrimitiveClass)
348 {
349     init(lengthSize, style);
350 }
351
352 void CSSPrimitiveValue::init(const Length& length)
353 {
354     switch (length.type()) {
355     case Auto:
356         m_primitiveUnitType = CSS_VALUE_ID;
357         m_value.valueID = CSSValueAuto;
358         return;
359     case WebCore::Fixed:
360         m_primitiveUnitType = CSS_PX;
361         m_value.num = length.value();
362         return;
363     case Intrinsic:
364         m_primitiveUnitType = CSS_VALUE_ID;
365         m_value.valueID = CSSValueIntrinsic;
366         return;
367     case MinIntrinsic:
368         m_primitiveUnitType = CSS_VALUE_ID;
369         m_value.valueID = CSSValueMinIntrinsic;
370         return;
371     case MinContent:
372         m_primitiveUnitType = CSS_VALUE_ID;
373         m_value.valueID = CSSValueMinContent;
374         return;
375     case MaxContent:
376         m_primitiveUnitType = CSS_VALUE_ID;
377         m_value.valueID = CSSValueMaxContent;
378         return;
379     case FillAvailable:
380         m_primitiveUnitType = CSS_VALUE_ID;
381         m_value.valueID = CSSValueWebkitFillAvailable;
382         return;
383     case FitContent:
384         m_primitiveUnitType = CSS_VALUE_ID;
385         m_value.valueID = CSSValueFitContent;
386         return;
387     case Percent:
388         m_primitiveUnitType = CSS_PERCENTAGE;
389         ASSERT(std::isfinite(length.percent()));
390         m_value.num = length.percent();
391         return;
392     case Calculated:
393     case Relative:
394     case Undefined:
395         ASSERT_NOT_REACHED();
396         return;
397     }
398     ASSERT_NOT_REACHED();
399 }
400
401 void CSSPrimitiveValue::init(const LengthSize& lengthSize, const RenderStyle& style)
402 {
403     m_primitiveUnitType = CSS_PAIR;
404     m_hasCachedCSSText = false;
405     m_value.pair = &Pair::create(create(lengthSize.width, style), create(lengthSize.height, style)).leakRef();
406 }
407
408 void CSSPrimitiveValue::init(Ref<Counter>&& counter)
409 {
410     m_primitiveUnitType = CSS_COUNTER;
411     m_hasCachedCSSText = false;
412     m_value.counter = &counter.leakRef();
413 }
414
415 void CSSPrimitiveValue::init(Ref<Rect>&& r)
416 {
417     m_primitiveUnitType = CSS_RECT;
418     m_hasCachedCSSText = false;
419     m_value.rect = &r.leakRef();
420 }
421
422 void CSSPrimitiveValue::init(Ref<Quad>&& quad)
423 {
424     m_primitiveUnitType = CSS_QUAD;
425     m_hasCachedCSSText = false;
426     m_value.quad = &quad.leakRef();
427 }
428
429 void CSSPrimitiveValue::init(Ref<Pair>&& p)
430 {
431     m_primitiveUnitType = CSS_PAIR;
432     m_hasCachedCSSText = false;
433     m_value.pair = &p.leakRef();
434 }
435
436 void CSSPrimitiveValue::init(Ref<CSSBasicShape>&& shape)
437 {
438     m_primitiveUnitType = CSS_SHAPE;
439     m_hasCachedCSSText = false;
440     m_value.shape = &shape.leakRef();
441 }
442
443 void CSSPrimitiveValue::init(RefPtr<CSSCalcValue>&& c)
444 {
445     m_primitiveUnitType = CSS_CALC;
446     m_hasCachedCSSText = false;
447     m_value.calc = c.leakRef();
448 }
449
450 CSSPrimitiveValue::~CSSPrimitiveValue()
451 {
452     cleanup();
453 }
454
455 void CSSPrimitiveValue::cleanup()
456 {
457     auto type = static_cast<UnitType>(m_primitiveUnitType);
458     switch (type) {
459     case CSS_STRING:
460     case CSS_URI:
461     case CSS_ATTR:
462     case CSS_COUNTER_NAME:
463         if (m_value.string)
464             m_value.string->deref();
465         break;
466     case CSS_DIMENSION:
467     case CSS_COUNTER:
468         m_value.counter->deref();
469         break;
470     case CSS_RECT:
471         m_value.rect->deref();
472         break;
473     case CSS_QUAD:
474         m_value.quad->deref();
475         break;
476     case CSS_PAIR:
477         m_value.pair->deref();
478         break;
479     case CSS_CALC:
480         m_value.calc->deref();
481         break;
482     case CSS_CALC_PERCENTAGE_WITH_NUMBER:
483     case CSS_CALC_PERCENTAGE_WITH_LENGTH:
484         ASSERT_NOT_REACHED();
485         break;
486     case CSS_SHAPE:
487         m_value.shape->deref();
488         break;
489     case CSS_FONT_FAMILY:
490         ASSERT(m_value.fontFamily);
491         delete m_value.fontFamily;
492         m_value.fontFamily = nullptr;
493         break;
494     case CSS_RGBCOLOR:
495         ASSERT(m_value.color);
496         delete m_value.color;
497         m_value.color = nullptr;
498         break;
499     case CSS_NUMBER:
500     case CSS_PERCENTAGE:
501     case CSS_EMS:
502     case CSS_QUIRKY_EMS:
503     case CSS_EXS:
504     case CSS_REMS:
505     case CSS_CHS:
506     case CSS_PX:
507     case CSS_CM:
508     case CSS_MM:
509     case CSS_IN:
510     case CSS_PT:
511     case CSS_PC:
512     case CSS_DEG:
513     case CSS_RAD:
514     case CSS_GRAD:
515     case CSS_MS:
516     case CSS_S:
517     case CSS_HZ:
518     case CSS_KHZ:
519     case CSS_TURN:
520     case CSS_VW:
521     case CSS_VH:
522     case CSS_VMIN:
523     case CSS_VMAX:
524     case CSS_DPPX:
525     case CSS_DPI:
526     case CSS_DPCM:
527     case CSS_FR:
528     case CSS_IDENT:
529     case CSS_UNKNOWN:
530     case CSS_UNICODE_RANGE:
531     case CSS_PROPERTY_ID:
532     case CSS_VALUE_ID:
533         ASSERT(!isStringType(type));
534         break;
535     }
536     m_primitiveUnitType = 0;
537     if (m_hasCachedCSSText) {
538         cssTextCache().remove(this);
539         m_hasCachedCSSText = false;
540     }
541 }
542
543 double CSSPrimitiveValue::computeDegrees() const
544 {
545     switch (primitiveType()) {
546     case CSS_DEG:
547         return doubleValue();
548     case CSS_RAD:
549         return rad2deg(doubleValue());
550     case CSS_GRAD:
551         return grad2deg(doubleValue());
552     case CSS_TURN:
553         return turn2deg(doubleValue());
554     default:
555         ASSERT_NOT_REACHED();
556         return 0;
557     }
558 }
559
560 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
561 {
562     return roundForImpreciseConversion<int>(computeLengthDouble(conversionData));
563 }
564
565 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
566 {
567     return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData));
568 }
569
570 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
571 {
572     return Length(clampTo<float>(computeLengthDouble(conversionData), minValueForCssLength, maxValueForCssLength), Fixed);
573 }
574
575 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
576 {
577     return roundForImpreciseConversion<short>(computeLengthDouble(conversionData));
578 }
579
580 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
581 {
582     return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData));
583 }
584
585 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
586 {
587     return static_cast<float>(computeLengthDouble(conversionData));
588 }
589
590 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
591 {
592     return computeLengthDouble(conversionData);
593 }
594
595 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const
596 {
597     if (m_primitiveUnitType == CSS_CALC)
598         // The multiplier and factor is applied to each value in the calc expression individually
599         return m_value.calc->computeLengthPx(conversionData);
600
601     return computeNonCalcLengthDouble(conversionData, static_cast<UnitType>(primitiveType()), m_value.num);
602 }
603
604 double CSSPrimitiveValue::computeNonCalcLengthDouble(const CSSToLengthConversionData& conversionData, UnitType primitiveType, double value)
605 {
606     double factor;
607     bool applyZoom = true;
608
609     switch (primitiveType) {
610     case CSS_EMS:
611     case CSS_QUIRKY_EMS:
612         ASSERT(conversionData.style());
613         factor = conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize();
614         break;
615     case CSS_EXS:
616         ASSERT(conversionData.style());
617         // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
618         // We really need to compute EX using fontMetrics for the original specifiedSize and not use
619         // our actual constructed rendering font.
620         if (conversionData.style()->fontMetrics().hasXHeight())
621             factor = conversionData.style()->fontMetrics().xHeight();
622         else
623             factor = (conversionData.computingFontSize() ? conversionData.style()->fontDescription().specifiedSize() : conversionData.style()->fontDescription().computedSize()) / 2.0;
624         break;
625     case CSS_REMS:
626         if (conversionData.rootStyle())
627             factor = conversionData.computingFontSize() ? conversionData.rootStyle()->fontDescription().specifiedSize() : conversionData.rootStyle()->fontDescription().computedSize();
628         else
629             factor = 1.0;
630         break;
631     case CSS_CHS:
632         ASSERT(conversionData.style());
633         factor = conversionData.style()->fontMetrics().zeroWidth();
634         break;
635     case CSS_PX:
636         factor = 1.0;
637         break;
638     case CSS_CM:
639         factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
640         break;
641     case CSS_MM:
642         factor = cssPixelsPerInch / 25.4;
643         break;
644     case CSS_IN:
645         factor = cssPixelsPerInch;
646         break;
647     case CSS_PT:
648         factor = cssPixelsPerInch / 72.0;
649         break;
650     case CSS_PC:
651         // 1 pc == 12 pt
652         factor = cssPixelsPerInch * 12.0 / 72.0;
653         break;
654     case CSS_CALC_PERCENTAGE_WITH_LENGTH:
655     case CSS_CALC_PERCENTAGE_WITH_NUMBER:
656         ASSERT_NOT_REACHED();
657         return -1.0;
658     case CSS_VH:
659         factor = conversionData.viewportHeightFactor();
660         applyZoom = false;
661         break;
662     case CSS_VW:
663         factor = conversionData.viewportWidthFactor();
664         applyZoom = false;
665         break;
666     case CSS_VMAX:
667         factor = conversionData.viewportMaxFactor();
668         applyZoom = false;
669         break;
670     case CSS_VMIN:
671         factor = conversionData.viewportMinFactor();
672         applyZoom = false;
673         break;
674     default:
675         ASSERT_NOT_REACHED();
676         return -1.0;
677     }
678
679     // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
680     // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
681     // as well as enforcing the implicit "smart minimum."
682     double result = value * factor;
683     if (conversionData.computingFontSize() || isFontRelativeLength(primitiveType))
684         return result;
685
686     if (applyZoom)
687         result *= conversionData.zoom();
688
689     return result;
690 }
691
692 ExceptionOr<void> CSSPrimitiveValue::setFloatValue(unsigned short, double)
693 {
694     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
695     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
696     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
697     return Exception { NoModificationAllowedError };
698 }
699
700 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType)
701 {
702     double factor = 1.0;
703     // FIXME: the switch can be replaced by an array of scale factors.
704     switch (unitType) {
705     // These are "canonical" units in their respective categories.
706     case CSS_PX:
707     case CSS_DEG:
708     case CSS_MS:
709     case CSS_HZ:
710         break;
711     case CSS_CM:
712         factor = cssPixelsPerInch / 2.54; // (2.54 cm/in)
713         break;
714     case CSS_DPCM:
715         factor = 2.54 / cssPixelsPerInch; // (2.54 cm/in)
716         break;
717     case CSS_MM:
718         factor = cssPixelsPerInch / 25.4;
719         break;
720     case CSS_IN:
721         factor = cssPixelsPerInch;
722         break;
723     case CSS_DPI:
724         factor = 1 / cssPixelsPerInch;
725         break;
726     case CSS_PT:
727         factor = cssPixelsPerInch / 72.0;
728         break;
729     case CSS_PC:
730         factor = cssPixelsPerInch * 12.0 / 72.0; // 1 pc == 12 pt
731         break;
732     case CSS_RAD:
733         factor = 180 / piDouble;
734         break;
735     case CSS_GRAD:
736         factor = 0.9;
737         break;
738     case CSS_TURN:
739         factor = 360;
740         break;
741     case CSS_S:
742     case CSS_KHZ:
743         factor = 1000;
744         break;
745     default:
746         break;
747     }
748
749     return factor;
750 }
751
752 ExceptionOr<float> CSSPrimitiveValue::getFloatValue(unsigned short unitType) const
753 {
754     auto result = doubleValueInternal(static_cast<UnitType>(unitType));
755     if (!result)
756         return Exception { InvalidAccessError };
757     return clampTo<float>(result.value());
758 }
759
760 double CSSPrimitiveValue::doubleValue(UnitType unitType) const
761 {
762     return doubleValueInternal(unitType).valueOr(0);
763 }
764
765 double CSSPrimitiveValue::doubleValue() const
766 {
767     return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue();
768 }
769
770
771 CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
772 {
773     // The canonical unit type is chosen according to the way CSSParser::validUnit() chooses the default unit
774     // in each category (based on unitflags).
775     switch (category) {
776     case UNumber:
777         return CSS_NUMBER;
778     case ULength:
779         return CSS_PX;
780     case UPercent:
781         return CSS_UNKNOWN; // Cannot convert between numbers and percent.
782     case UTime:
783         return CSS_MS;
784     case UAngle:
785         return CSS_DEG;
786     case UFrequency:
787         return CSS_HZ;
788 #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
789     case UResolution:
790         return CSS_DPPX;
791 #endif
792     default:
793         return CSS_UNKNOWN;
794     }
795 }
796
797 Optional<double> CSSPrimitiveValue::doubleValueInternal(UnitType requestedUnitType) const
798 {
799     if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitType>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType))
800         return WTF::nullopt;
801
802     UnitType sourceUnitType = static_cast<UnitType>(primitiveType());
803     if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION)
804         return doubleValue();
805
806     UnitCategory sourceCategory = unitCategory(sourceUnitType);
807     ASSERT(sourceCategory != UOther);
808
809     UnitType targetUnitType = requestedUnitType;
810     UnitCategory targetCategory = unitCategory(targetUnitType);
811     ASSERT(targetCategory != UOther);
812
813     // Cannot convert between unrelated unit categories if one of them is not UNumber.
814     if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
815         return WTF::nullopt;
816
817     if (targetCategory == UNumber) {
818         // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
819         targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
820         if (targetUnitType == CSS_UNKNOWN)
821             return WTF::nullopt;
822     }
823
824     if (sourceUnitType == CSS_NUMBER) {
825         // We interpret conversion from CSS_NUMBER in the same way as CSSParser::validUnit() while using non-strict mode.
826         sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
827         if (sourceUnitType == CSS_UNKNOWN)
828             return WTF::nullopt;
829     }
830
831     double convertedValue = doubleValue();
832
833     // First convert the value from m_primitiveUnitType to canonical type.
834     double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
835     convertedValue *= factor;
836
837     // Now convert from canonical type to the target unitType.
838     factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
839     convertedValue /= factor;
840
841     return convertedValue;
842 }
843
844 ExceptionOr<void> CSSPrimitiveValue::setStringValue(unsigned short, const String&)
845 {
846     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
847     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
848     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
849     return Exception { NoModificationAllowedError };
850 }
851
852 ExceptionOr<String> CSSPrimitiveValue::getStringValue() const
853 {
854     switch (m_primitiveUnitType) {
855     case CSS_STRING:
856     case CSS_ATTR:
857     case CSS_URI:
858         return m_value.string;
859     case CSS_FONT_FAMILY:
860         return String { m_value.fontFamily->familyName };
861     case CSS_VALUE_ID:
862         return String { valueName(m_value.valueID).string() };
863     case CSS_PROPERTY_ID:
864         return String { propertyName(m_value.propertyID).string() };
865     default:
866         return Exception { InvalidAccessError };
867     }
868 }
869
870 String CSSPrimitiveValue::stringValue() const
871 {
872     switch (m_primitiveUnitType) {
873     case CSS_STRING:
874     case CSS_ATTR:
875     case CSS_URI:
876         return m_value.string;
877     case CSS_FONT_FAMILY:
878         return m_value.fontFamily->familyName;
879     case CSS_VALUE_ID:
880         return valueName(m_value.valueID);
881     case CSS_PROPERTY_ID:
882         return propertyName(m_value.propertyID);
883     default:
884         return String();
885     }
886 }
887
888 ExceptionOr<Counter&> CSSPrimitiveValue::getCounterValue() const
889 {
890     if (m_primitiveUnitType != CSS_COUNTER)
891         return Exception { InvalidAccessError };
892     return *m_value.counter;
893 }
894
895 ExceptionOr<Rect&> CSSPrimitiveValue::getRectValue() const
896 {
897     if (m_primitiveUnitType != CSS_RECT)
898         return Exception { InvalidAccessError };
899     return *m_value.rect;
900 }
901
902 ExceptionOr<Ref<RGBColor>> CSSPrimitiveValue::getRGBColorValue() const
903 {
904     if (m_primitiveUnitType != CSS_RGBCOLOR)
905         return Exception { InvalidAccessError };
906
907     // FIXME: This should not return a new object for each invocation.
908     return RGBColor::create(m_value.color->rgb());
909 }
910
911 NEVER_INLINE String CSSPrimitiveValue::formatNumberValue(StringView suffix) const
912 {
913     return makeString(m_value.num, suffix);
914 }
915
916 ALWAYS_INLINE String CSSPrimitiveValue::formatNumberForCustomCSSText() const
917 {
918     switch (m_primitiveUnitType) {
919     case CSS_UNKNOWN:
920         return String();
921     case CSS_NUMBER:
922         return formatNumberValue("");
923     case CSS_PERCENTAGE:
924         return formatNumberValue("%");
925     case CSS_EMS:
926     case CSS_QUIRKY_EMS:
927         return formatNumberValue("em");
928     case CSS_EXS:
929         return formatNumberValue("ex");
930     case CSS_REMS:
931         return formatNumberValue("rem");
932     case CSS_CHS:
933         return formatNumberValue("ch");
934     case CSS_PX:
935         return formatNumberValue("px");
936     case CSS_CM:
937         return formatNumberValue("cm");
938 #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
939     case CSS_DPPX:
940         return formatNumberValue("dppx");
941     case CSS_DPI:
942         return formatNumberValue("dpi");
943     case CSS_DPCM:
944         return formatNumberValue("dpcm");
945 #endif
946     case CSS_MM:
947         return formatNumberValue("mm");
948     case CSS_IN:
949         return formatNumberValue("in");
950     case CSS_PT:
951         return formatNumberValue("pt");
952     case CSS_PC:
953         return formatNumberValue("pc");
954     case CSS_DEG:
955         return formatNumberValue("deg");
956     case CSS_RAD:
957         return formatNumberValue("rad");
958     case CSS_GRAD:
959         return formatNumberValue("grad");
960     case CSS_MS:
961         return formatNumberValue("ms");
962     case CSS_S:
963         return formatNumberValue("s");
964     case CSS_HZ:
965         return formatNumberValue("hz");
966     case CSS_KHZ:
967         return formatNumberValue("khz");
968     case CSS_TURN:
969         return formatNumberValue("turn");
970     case CSS_FR:
971         return formatNumberValue("fr");
972     case CSS_DIMENSION:
973         // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store
974         // the actual dimension, just the numeric value as a string.
975     case CSS_STRING:
976         // FIME-NEWPARSER: Once we have CSSCustomIdentValue hooked up, this can just be
977         // serializeString, since custom identifiers won't be the same value as strings
978         // any longer.
979         return serializeAsStringOrCustomIdent(m_value.string);
980     case CSS_FONT_FAMILY:
981         return serializeFontFamily(m_value.fontFamily->familyName);
982     case CSS_URI:
983         return serializeURL(m_value.string);
984     case CSS_VALUE_ID:
985         return valueName(m_value.valueID);
986     case CSS_PROPERTY_ID:
987         return propertyName(m_value.propertyID);
988     case CSS_ATTR:
989         return "attr(" + String(m_value.string) + ')';
990     case CSS_COUNTER_NAME:
991         return "counter(" + String(m_value.string) + ')';
992     case CSS_COUNTER: {
993         StringBuilder result;
994         String separator = m_value.counter->separator();
995         if (separator.isEmpty())
996             result.appendLiteral("counter(");
997         else
998             result.appendLiteral("counters(");
999
1000         result.append(m_value.counter->identifier());
1001         if (!separator.isEmpty()) {
1002             result.appendLiteral(", ");
1003             serializeString(separator, result);
1004         }
1005         String listStyle = m_value.counter->listStyle();
1006         if (!listStyle.isEmpty()) {
1007             result.appendLiteral(", ");
1008             result.append(listStyle);
1009         }
1010         result.append(')');
1011
1012         return result.toString();
1013     }
1014     case CSS_RECT:
1015         return rectValue()->cssText();
1016     case CSS_QUAD:
1017         return quadValue()->cssText();
1018     case CSS_RGBCOLOR:
1019         return color().cssText();
1020     case CSS_PAIR:
1021         return pairValue()->cssText();
1022     case CSS_CALC:
1023         return m_value.calc->cssText();
1024     case CSS_SHAPE:
1025         return m_value.shape->cssText();
1026     case CSS_VW:
1027         return formatNumberValue("vw");
1028     case CSS_VH:
1029         return formatNumberValue("vh");
1030     case CSS_VMIN:
1031         return formatNumberValue("vmin");
1032     case CSS_VMAX:
1033         return formatNumberValue("vmax");
1034     }
1035     return String();
1036 }
1037
1038 String CSSPrimitiveValue::customCSSText() const
1039 {
1040     // FIXME: return the original value instead of a generated one (e.g. color
1041     // name if it was specified) - check what spec says about this
1042
1043     CSSTextCache& cssTextCache = WebCore::cssTextCache();
1044
1045     if (m_hasCachedCSSText) {
1046         ASSERT(cssTextCache.contains(this));
1047         return cssTextCache.get(this);
1048     }
1049
1050     String text = formatNumberForCustomCSSText();
1051
1052     ASSERT(!cssTextCache.contains(this));
1053     m_hasCachedCSSText = true;
1054     cssTextCache.set(this, text);
1055     return text;
1056 }
1057
1058 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
1059 {
1060     if (m_primitiveUnitType != other.m_primitiveUnitType)
1061         return false;
1062
1063     switch (m_primitiveUnitType) {
1064     case CSS_UNKNOWN:
1065         return false;
1066     case CSS_NUMBER:
1067     case CSS_PERCENTAGE:
1068     case CSS_EMS:
1069     case CSS_QUIRKY_EMS:
1070     case CSS_EXS:
1071     case CSS_REMS:
1072     case CSS_PX:
1073     case CSS_CM:
1074 #if ENABLE(CSS_IMAGE_RESOLUTION) || ENABLE(RESOLUTION_MEDIA_QUERY)
1075     case CSS_DPPX:
1076     case CSS_DPI:
1077     case CSS_DPCM:
1078 #endif
1079     case CSS_MM:
1080     case CSS_IN:
1081     case CSS_PT:
1082     case CSS_PC:
1083     case CSS_DEG:
1084     case CSS_RAD:
1085     case CSS_GRAD:
1086     case CSS_MS:
1087     case CSS_S:
1088     case CSS_HZ:
1089     case CSS_KHZ:
1090     case CSS_TURN:
1091     case CSS_VW:
1092     case CSS_VH:
1093     case CSS_VMIN:
1094     case CSS_FR:
1095         return m_value.num == other.m_value.num;
1096     case CSS_PROPERTY_ID:
1097         return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID);
1098     case CSS_VALUE_ID:
1099         return valueName(m_value.valueID) == valueName(other.m_value.valueID);
1100     case CSS_DIMENSION:
1101     case CSS_STRING:
1102     case CSS_URI:
1103     case CSS_ATTR:
1104     case CSS_COUNTER_NAME:
1105         return equal(m_value.string, other.m_value.string);
1106     case CSS_COUNTER:
1107         return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter);
1108     case CSS_RECT:
1109         return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect);
1110     case CSS_QUAD:
1111         return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad);
1112     case CSS_RGBCOLOR:
1113         return color() == other.color();
1114     case CSS_PAIR:
1115         return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair);
1116     case CSS_CALC:
1117         return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
1118     case CSS_SHAPE:
1119         return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
1120     case CSS_FONT_FAMILY:
1121         return fontFamily() == other.fontFamily();
1122     }
1123     return false;
1124 }
1125
1126 Ref<DeprecatedCSSOMPrimitiveValue> CSSPrimitiveValue::createDeprecatedCSSOMPrimitiveWrapper(CSSStyleDeclaration& styleDeclaration) const
1127 {
1128     return DeprecatedCSSOMPrimitiveValue::create(*this, styleDeclaration);
1129 }
1130
1131 // https://drafts.css-houdini.org/css-properties-values-api/#dependency-cycles-via-relative-units
1132 void CSSPrimitiveValue::collectDirectComputationalDependencies(HashSet<CSSPropertyID>& values) const
1133 {
1134     switch (m_primitiveUnitType) {
1135     case CSS_EMS:
1136     case CSS_QUIRKY_EMS:
1137     case CSS_EXS:
1138     case CSS_CHS:
1139         values.add(CSSPropertyFontSize);
1140         break;
1141     case CSS_CALC:
1142         m_value.calc->collectDirectComputationalDependencies(values);
1143         break;
1144     }
1145 }
1146
1147 void CSSPrimitiveValue::collectDirectRootComputationalDependencies(HashSet<CSSPropertyID>& values) const
1148 {
1149     switch (m_primitiveUnitType) {
1150     case CSS_REMS:
1151         values.add(CSSPropertyFontSize);
1152         break;
1153     case CSS_CALC:
1154         m_value.calc->collectDirectRootComputationalDependencies(values);
1155         break;
1156     }
1157 }
1158
1159 } // namespace WebCore