• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 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 "core/css/CSSPrimitiveValue.h"
23 
24 #include "bindings/v8/ExceptionState.h"
25 #include "core/css/CSSBasicShapes.h"
26 #include "core/css/CSSCalculationValue.h"
27 #include "core/css/CSSHelper.h"
28 #include "core/css/CSSMarkup.h"
29 #include "core/css/CSSToLengthConversionData.h"
30 #include "core/css/Counter.h"
31 #include "core/css/Pair.h"
32 #include "core/css/RGBColor.h"
33 #include "core/css/Rect.h"
34 #include "core/css/StyleSheetContents.h"
35 #include "core/dom/ExceptionCode.h"
36 #include "core/dom/Node.h"
37 #include "core/rendering/style/RenderStyle.h"
38 #include "platform/Decimal.h"
39 #include "platform/LayoutUnit.h"
40 #include "platform/fonts/FontMetrics.h"
41 #include "wtf/StdLibExtras.h"
42 #include "wtf/text/StringBuffer.h"
43 #include "wtf/text/StringBuilder.h"
44 
45 using namespace WTF;
46 
47 namespace WebCore {
48 
49 // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing.
50 // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max.
51 const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2;
52 const int minValueForCssLength = INT_MIN / kFixedPointDenominator + 2;
53 
isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitType unitType)54 static inline bool isValidCSSUnitTypeForDoubleConversion(CSSPrimitiveValue::UnitType unitType)
55 {
56     switch (unitType) {
57     case CSSPrimitiveValue::CSS_CALC:
58     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_NUMBER:
59     case CSSPrimitiveValue::CSS_CALC_PERCENTAGE_WITH_LENGTH:
60     case CSSPrimitiveValue::CSS_CM:
61     case CSSPrimitiveValue::CSS_DEG:
62     case CSSPrimitiveValue::CSS_DIMENSION:
63     case CSSPrimitiveValue::CSS_DPPX:
64     case CSSPrimitiveValue::CSS_DPI:
65     case CSSPrimitiveValue::CSS_DPCM:
66     case CSSPrimitiveValue::CSS_EMS:
67     case CSSPrimitiveValue::CSS_EXS:
68     case CSSPrimitiveValue::CSS_GRAD:
69     case CSSPrimitiveValue::CSS_HZ:
70     case CSSPrimitiveValue::CSS_IN:
71     case CSSPrimitiveValue::CSS_KHZ:
72     case CSSPrimitiveValue::CSS_MM:
73     case CSSPrimitiveValue::CSS_MS:
74     case CSSPrimitiveValue::CSS_NUMBER:
75     case CSSPrimitiveValue::CSS_PERCENTAGE:
76     case CSSPrimitiveValue::CSS_PC:
77     case CSSPrimitiveValue::CSS_PT:
78     case CSSPrimitiveValue::CSS_PX:
79     case CSSPrimitiveValue::CSS_RAD:
80     case CSSPrimitiveValue::CSS_REMS:
81     case CSSPrimitiveValue::CSS_CHS:
82     case CSSPrimitiveValue::CSS_S:
83     case CSSPrimitiveValue::CSS_TURN:
84     case CSSPrimitiveValue::CSS_VW:
85     case CSSPrimitiveValue::CSS_VH:
86     case CSSPrimitiveValue::CSS_VMIN:
87     case CSSPrimitiveValue::CSS_VMAX:
88     case CSSPrimitiveValue::CSS_FR:
89         return true;
90     case CSSPrimitiveValue::CSS_ATTR:
91     case CSSPrimitiveValue::CSS_COUNTER:
92     case CSSPrimitiveValue::CSS_COUNTER_NAME:
93     case CSSPrimitiveValue::CSS_IDENT:
94     case CSSPrimitiveValue::CSS_PROPERTY_ID:
95     case CSSPrimitiveValue::CSS_VALUE_ID:
96     case CSSPrimitiveValue::CSS_PAIR:
97     case CSSPrimitiveValue::CSS_PARSER_HEXCOLOR:
98     case CSSPrimitiveValue::CSS_PARSER_IDENTIFIER:
99     case CSSPrimitiveValue::CSS_PARSER_INTEGER:
100     case CSSPrimitiveValue::CSS_PARSER_OPERATOR:
101     case CSSPrimitiveValue::CSS_RECT:
102     case CSSPrimitiveValue::CSS_QUAD:
103     case CSSPrimitiveValue::CSS_RGBCOLOR:
104     case CSSPrimitiveValue::CSS_SHAPE:
105     case CSSPrimitiveValue::CSS_STRING:
106     case CSSPrimitiveValue::CSS_UNICODE_RANGE:
107     case CSSPrimitiveValue::CSS_UNKNOWN:
108     case CSSPrimitiveValue::CSS_URI:
109         return false;
110     }
111 
112     ASSERT_NOT_REACHED();
113     return false;
114 }
115 
116 typedef HashMap<String, CSSPrimitiveValue::UnitType> StringToUnitTable;
117 
createStringToUnitTable()118 StringToUnitTable createStringToUnitTable()
119 {
120     StringToUnitTable table;
121     table.set(String("em"), CSSPrimitiveValue::CSS_EMS);
122     table.set(String("ex"), CSSPrimitiveValue::CSS_EXS);
123     table.set(String("px"), CSSPrimitiveValue::CSS_PX);
124     table.set(String("cm"), CSSPrimitiveValue::CSS_CM);
125     table.set(String("mm"), CSSPrimitiveValue::CSS_MM);
126     table.set(String("in"), CSSPrimitiveValue::CSS_IN);
127     table.set(String("pt"), CSSPrimitiveValue::CSS_PT);
128     table.set(String("pc"), CSSPrimitiveValue::CSS_PC);
129     table.set(String("deg"), CSSPrimitiveValue::CSS_DEG);
130     table.set(String("rad"), CSSPrimitiveValue::CSS_RAD);
131     table.set(String("grad"), CSSPrimitiveValue::CSS_GRAD);
132     table.set(String("ms"), CSSPrimitiveValue::CSS_MS);
133     table.set(String("s"), CSSPrimitiveValue::CSS_S);
134     table.set(String("hz"), CSSPrimitiveValue::CSS_HZ);
135     table.set(String("khz"), CSSPrimitiveValue::CSS_KHZ);
136     table.set(String("dpi"), CSSPrimitiveValue::CSS_DPI);
137     table.set(String("dpcm"), CSSPrimitiveValue::CSS_DPCM);
138     table.set(String("dppx"), CSSPrimitiveValue::CSS_DPPX);
139     table.set(String("vw"), CSSPrimitiveValue::CSS_VW);
140     table.set(String("vh"), CSSPrimitiveValue::CSS_VH);
141     table.set(String("vmax"), CSSPrimitiveValue::CSS_VMIN);
142     table.set(String("vmin"), CSSPrimitiveValue::CSS_VMAX);
143     return table;
144 }
145 
146 
fromName(const String & unit)147 CSSPrimitiveValue::UnitType CSSPrimitiveValue::fromName(const String& unit)
148 {
149     DEFINE_STATIC_LOCAL(StringToUnitTable, unitTable, (createStringToUnitTable()));
150     return unitTable.get(unit.lower());
151 }
152 
unitCategory(UnitType type)153 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(UnitType type)
154 {
155     // Here we violate the spec (http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSPrimitiveValue) and allow conversions
156     // between CSS_PX and relative lengths (see cssPixelsPerInch comment in core/css/CSSHelper.h for the topic treatment).
157     switch (type) {
158     case CSS_NUMBER:
159         return CSSPrimitiveValue::UNumber;
160     case CSS_PERCENTAGE:
161         return CSSPrimitiveValue::UPercent;
162     case CSS_PX:
163     case CSS_CM:
164     case CSS_MM:
165     case CSS_IN:
166     case CSS_PT:
167     case CSS_PC:
168         return CSSPrimitiveValue::ULength;
169     case CSS_MS:
170     case CSS_S:
171         return CSSPrimitiveValue::UTime;
172     case CSS_DEG:
173     case CSS_RAD:
174     case CSS_GRAD:
175     case CSS_TURN:
176         return CSSPrimitiveValue::UAngle;
177     case CSS_HZ:
178     case CSS_KHZ:
179         return CSSPrimitiveValue::UFrequency;
180     case CSS_DPPX:
181     case CSS_DPI:
182     case CSS_DPCM:
183         return CSSPrimitiveValue::UResolution;
184     default:
185         return CSSPrimitiveValue::UOther;
186     }
187 }
188 
colorIsDerivedFromElement() const189 bool CSSPrimitiveValue::colorIsDerivedFromElement() const
190 {
191     int valueID = getValueID();
192     switch (valueID) {
193     case CSSValueWebkitText:
194     case CSSValueWebkitLink:
195     case CSSValueWebkitActivelink:
196     case CSSValueCurrentcolor:
197         return true;
198     default:
199         return false;
200     }
201 }
202 
203 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
cssTextCache()204 static CSSTextCache& cssTextCache()
205 {
206     DEFINE_STATIC_LOCAL(CSSTextCache, cache, ());
207     return cache;
208 }
209 
primitiveType() const210 CSSPrimitiveValue::UnitType CSSPrimitiveValue::primitiveType() const
211 {
212     if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID)
213         return CSS_IDENT;
214 
215     if (m_primitiveUnitType != CSS_CALC)
216         return static_cast<UnitType>(m_primitiveUnitType);
217 
218     switch (m_value.calc->category()) {
219     case CalcNumber:
220         return CSS_NUMBER;
221     case CalcPercent:
222         return CSS_PERCENTAGE;
223     case CalcLength:
224         return CSS_PX;
225     case CalcPercentNumber:
226         return CSS_CALC_PERCENTAGE_WITH_NUMBER;
227     case CalcPercentLength:
228         return CSS_CALC_PERCENTAGE_WITH_LENGTH;
229     case CalcOther:
230         return CSS_UNKNOWN;
231     }
232     return CSS_UNKNOWN;
233 }
234 
propertyName(CSSPropertyID propertyID)235 static const AtomicString& propertyName(CSSPropertyID propertyID)
236 {
237     ASSERT_ARG(propertyID, propertyID >= 0);
238     ASSERT_ARG(propertyID, (propertyID >= firstCSSProperty && propertyID < firstCSSProperty + numCSSProperties));
239 
240     if (propertyID < 0)
241         return nullAtom;
242 
243     return getPropertyNameAtomicString(propertyID);
244 }
245 
valueName(CSSValueID valueID)246 static const AtomicString& valueName(CSSValueID valueID)
247 {
248     ASSERT_ARG(valueID, valueID >= 0);
249     ASSERT_ARG(valueID, valueID < numCSSValueKeywords);
250 
251     if (valueID < 0)
252         return nullAtom;
253 
254     static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally.
255     AtomicString& keywordString = keywordStrings[valueID];
256     if (keywordString.isNull())
257         keywordString = getValueName(valueID);
258     return keywordString;
259 }
260 
CSSPrimitiveValue(CSSValueID valueID)261 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
262     : CSSValue(PrimitiveClass)
263 {
264     m_primitiveUnitType = CSS_VALUE_ID;
265     m_value.valueID = valueID;
266 }
267 
CSSPrimitiveValue(CSSPropertyID propertyID)268 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
269     : CSSValue(PrimitiveClass)
270 {
271     m_primitiveUnitType = CSS_PROPERTY_ID;
272     m_value.propertyID = propertyID;
273 }
274 
CSSPrimitiveValue(int parserOperator,UnitType type)275 CSSPrimitiveValue::CSSPrimitiveValue(int parserOperator, UnitType type)
276     : CSSValue(PrimitiveClass)
277 {
278     ASSERT(type == CSS_PARSER_OPERATOR);
279     m_primitiveUnitType = CSS_PARSER_OPERATOR;
280     m_value.parserOperator = parserOperator;
281 }
282 
CSSPrimitiveValue(double num,UnitType type)283 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type)
284     : CSSValue(PrimitiveClass)
285 {
286     m_primitiveUnitType = type;
287     ASSERT(std::isfinite(num));
288     m_value.num = num;
289 }
290 
CSSPrimitiveValue(const String & str,UnitType type)291 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitType type)
292     : CSSValue(PrimitiveClass)
293 {
294     m_primitiveUnitType = type;
295     if ((m_value.string = str.impl()))
296         m_value.string->ref();
297 }
298 
CSSPrimitiveValue(const LengthSize & lengthSize,const RenderStyle & style)299 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize, const RenderStyle& style)
300     : CSSValue(PrimitiveClass)
301 {
302     init(lengthSize, style);
303 }
304 
CSSPrimitiveValue(RGBA32 color,UnitType type)305 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color, UnitType type)
306     : CSSValue(PrimitiveClass)
307 {
308     ASSERT(type == CSS_RGBCOLOR);
309     m_primitiveUnitType = CSS_RGBCOLOR;
310     m_value.rgbcolor = color;
311 }
312 
CSSPrimitiveValue(const Length & length,float zoom)313 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, float zoom)
314     : CSSValue(PrimitiveClass)
315 {
316     switch (length.type()) {
317     case Auto:
318         m_primitiveUnitType = CSS_VALUE_ID;
319         m_value.valueID = CSSValueAuto;
320         break;
321     case Intrinsic:
322         m_primitiveUnitType = CSS_VALUE_ID;
323         m_value.valueID = CSSValueIntrinsic;
324         break;
325     case MinIntrinsic:
326         m_primitiveUnitType = CSS_VALUE_ID;
327         m_value.valueID = CSSValueMinIntrinsic;
328         break;
329     case MinContent:
330         m_primitiveUnitType = CSS_VALUE_ID;
331         m_value.valueID = CSSValueMinContent;
332         break;
333     case MaxContent:
334         m_primitiveUnitType = CSS_VALUE_ID;
335         m_value.valueID = CSSValueMaxContent;
336         break;
337     case FillAvailable:
338         m_primitiveUnitType = CSS_VALUE_ID;
339         m_value.valueID = CSSValueWebkitFillAvailable;
340         break;
341     case FitContent:
342         m_primitiveUnitType = CSS_VALUE_ID;
343         m_value.valueID = CSSValueWebkitFitContent;
344         break;
345     case ExtendToZoom:
346         m_primitiveUnitType = CSS_VALUE_ID;
347         m_value.valueID = CSSValueInternalExtendToZoom;
348         break;
349     case Percent:
350         m_primitiveUnitType = CSS_PERCENTAGE;
351         ASSERT(std::isfinite(length.percent()));
352         m_value.num = length.percent();
353         break;
354     case Fixed:
355         m_primitiveUnitType = CSS_PX;
356         m_value.num = length.value() / zoom;
357         break;
358     case Calculated: {
359         const CalculationValue& calc = length.calculationValue();
360         if (calc.pixels() && calc.percent()) {
361             init(CSSCalcValue::create(
362                 CSSCalcValue::createExpressionNode(calc.pixels() / zoom, calc.percent()),
363                 calc.isNonNegative() ? ValueRangeNonNegative : ValueRangeAll));
364             break;
365         }
366         if (calc.percent()) {
367             m_primitiveUnitType = CSS_PERCENTAGE;
368             m_value.num = calc.percent();
369         } else {
370             m_primitiveUnitType = CSS_PX;
371             m_value.num = calc.pixels() / zoom;
372         }
373         if (m_value.num < 0 && calc.isNonNegative())
374             m_value.num = 0;
375         break;
376     }
377     case DeviceWidth:
378     case DeviceHeight:
379     case Undefined:
380         ASSERT_NOT_REACHED();
381         break;
382     }
383 }
384 
init(const LengthSize & lengthSize,const RenderStyle & style)385 void CSSPrimitiveValue::init(const LengthSize& lengthSize, const RenderStyle& style)
386 {
387     m_primitiveUnitType = CSS_PAIR;
388     m_hasCachedCSSText = false;
389     m_value.pair = Pair::create(create(lengthSize.width(), style.effectiveZoom()), create(lengthSize.height(), style.effectiveZoom()), Pair::KeepIdenticalValues).leakRef();
390 }
391 
init(PassRefPtrWillBeRawPtr<Counter> c)392 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Counter> c)
393 {
394     m_primitiveUnitType = CSS_COUNTER;
395     m_hasCachedCSSText = false;
396     m_value.counter = c.leakRef();
397 }
398 
init(PassRefPtrWillBeRawPtr<Rect> r)399 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Rect> r)
400 {
401     m_primitiveUnitType = CSS_RECT;
402     m_hasCachedCSSText = false;
403     m_value.rect = r.leakRef();
404 }
405 
init(PassRefPtrWillBeRawPtr<Quad> quad)406 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Quad> quad)
407 {
408     m_primitiveUnitType = CSS_QUAD;
409     m_hasCachedCSSText = false;
410     m_value.quad = quad.leakRef();
411 }
412 
init(PassRefPtrWillBeRawPtr<Pair> p)413 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Pair> p)
414 {
415     m_primitiveUnitType = CSS_PAIR;
416     m_hasCachedCSSText = false;
417     m_value.pair = p.leakRef();
418 }
419 
init(PassRefPtrWillBeRawPtr<CSSCalcValue> c)420 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSCalcValue> c)
421 {
422     m_primitiveUnitType = CSS_CALC;
423     m_hasCachedCSSText = false;
424     m_value.calc = c.leakRef();
425 }
426 
init(PassRefPtrWillBeRawPtr<CSSBasicShape> shape)427 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSBasicShape> shape)
428 {
429     m_primitiveUnitType = CSS_SHAPE;
430     m_hasCachedCSSText = false;
431     m_value.shape = shape.leakRef();
432 }
433 
~CSSPrimitiveValue()434 CSSPrimitiveValue::~CSSPrimitiveValue()
435 {
436     cleanup();
437 }
438 
cleanup()439 void CSSPrimitiveValue::cleanup()
440 {
441     switch (static_cast<UnitType>(m_primitiveUnitType)) {
442     case CSS_STRING:
443     case CSS_URI:
444     case CSS_ATTR:
445     case CSS_COUNTER_NAME:
446     case CSS_PARSER_HEXCOLOR:
447         if (m_value.string)
448             m_value.string->deref();
449         break;
450     case CSS_COUNTER:
451         // We must not call deref() when oilpan is enabled because m_value.counter is traced.
452 #if !ENABLE(OILPAN)
453         m_value.counter->deref();
454 #endif
455         break;
456     case CSS_RECT:
457         // We must not call deref() when oilpan is enabled because m_value.rect is traced.
458 #if !ENABLE(OILPAN)
459         m_value.rect->deref();
460 #endif
461         break;
462     case CSS_QUAD:
463         // We must not call deref() when oilpan is enabled because m_value.quad is traced.
464 #if !ENABLE(OILPAN)
465         m_value.quad->deref();
466 #endif
467         break;
468     case CSS_PAIR:
469         // We must not call deref() when oilpan is enabled because m_value.pair is traced.
470 #if !ENABLE(OILPAN)
471         m_value.pair->deref();
472 #endif
473         break;
474     case CSS_CALC:
475         // We must not call deref() when oilpan is enabled because m_value.calc is traced.
476 #if !ENABLE(OILPAN)
477         m_value.calc->deref();
478 #endif
479         break;
480     case CSS_CALC_PERCENTAGE_WITH_NUMBER:
481     case CSS_CALC_PERCENTAGE_WITH_LENGTH:
482         ASSERT_NOT_REACHED();
483         break;
484     case CSS_SHAPE:
485         // We must not call deref() when oilpan is enabled because m_value.shape is traced.
486 #if !ENABLE(OILPAN)
487         m_value.shape->deref();
488 #endif
489         break;
490     case CSS_NUMBER:
491     case CSS_PARSER_INTEGER:
492     case CSS_PERCENTAGE:
493     case CSS_EMS:
494     case CSS_EXS:
495     case CSS_REMS:
496     case CSS_CHS:
497     case CSS_PX:
498     case CSS_CM:
499     case CSS_MM:
500     case CSS_IN:
501     case CSS_PT:
502     case CSS_PC:
503     case CSS_DEG:
504     case CSS_RAD:
505     case CSS_GRAD:
506     case CSS_MS:
507     case CSS_S:
508     case CSS_HZ:
509     case CSS_KHZ:
510     case CSS_TURN:
511     case CSS_VW:
512     case CSS_VH:
513     case CSS_VMIN:
514     case CSS_VMAX:
515     case CSS_DPPX:
516     case CSS_DPI:
517     case CSS_DPCM:
518     case CSS_FR:
519     case CSS_IDENT:
520     case CSS_RGBCOLOR:
521     case CSS_DIMENSION:
522     case CSS_UNKNOWN:
523     case CSS_UNICODE_RANGE:
524     case CSS_PARSER_OPERATOR:
525     case CSS_PARSER_IDENTIFIER:
526     case CSS_PROPERTY_ID:
527     case CSS_VALUE_ID:
528         break;
529     }
530     m_primitiveUnitType = 0;
531     if (m_hasCachedCSSText) {
532         cssTextCache().remove(this);
533         m_hasCachedCSSText = false;
534     }
535 }
536 
computeDegrees()537 double CSSPrimitiveValue::computeDegrees()
538 {
539     switch (m_primitiveUnitType) {
540     case CSS_DEG:
541         return getDoubleValue();
542     case CSS_RAD:
543         return rad2deg(getDoubleValue());
544     case CSS_GRAD:
545         return grad2deg(getDoubleValue());
546     case CSS_TURN:
547         return turn2deg(getDoubleValue());
548     default:
549         ASSERT_NOT_REACHED();
550         return 0;
551     }
552 }
553 
computeLength(const CSSToLengthConversionData & conversionData)554 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
555 {
556     return roundForImpreciseConversion<int>(computeLengthDouble(conversionData));
557 }
558 
computeLength(const CSSToLengthConversionData & conversionData)559 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
560 {
561     return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData));
562 }
563 
computeLength(const CSSToLengthConversionData & conversionData)564 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
565 {
566     return Length(clampTo<float>(computeLengthDouble(conversionData), minValueForCssLength, maxValueForCssLength), Fixed);
567 }
568 
computeLength(const CSSToLengthConversionData & conversionData)569 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
570 {
571     return roundForImpreciseConversion<short>(computeLengthDouble(conversionData));
572 }
573 
computeLength(const CSSToLengthConversionData & conversionData)574 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
575 {
576     return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData));
577 }
578 
computeLength(const CSSToLengthConversionData & conversionData)579 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
580 {
581     return static_cast<float>(computeLengthDouble(conversionData));
582 }
583 
computeLength(const CSSToLengthConversionData & conversionData)584 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
585 {
586     return computeLengthDouble(conversionData);
587 }
588 
computeLengthDouble(const CSSToLengthConversionData & conversionData)589 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData)
590 {
591     // The logic in this function is duplicated in MediaValues::computeLength
592     // because MediaValues::computeLength needs nearly identical logic, but we haven't found a way to make
593     // CSSPrimitiveValue::computeLengthDouble more generic (to solve both cases) without hurting performance.
594     if (m_primitiveUnitType == CSS_CALC)
595         return m_value.calc->computeLengthPx(conversionData);
596 
597     const RenderStyle& style = conversionData.style();
598     const RenderStyle* rootStyle = conversionData.rootStyle();
599     bool computingFontSize = conversionData.computingFontSize();
600 
601     double factor;
602 
603     switch (primitiveType()) {
604         case CSS_EMS:
605             factor = computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize();
606             break;
607         case CSS_EXS:
608             // FIXME: We have a bug right now where the zoom will be applied twice to EX units.
609             // We really need to compute EX using fontMetrics for the original specifiedSize and not use
610             // our actual constructed rendering font.
611             if (style.fontMetrics().hasXHeight())
612                 factor = style.fontMetrics().xHeight();
613             else
614                 factor = (computingFontSize ? style.fontDescription().specifiedSize() : style.fontDescription().computedSize()) / 2.0;
615             break;
616         case CSS_REMS:
617             if (rootStyle)
618                 factor = computingFontSize ? rootStyle->fontDescription().specifiedSize() : rootStyle->fontDescription().computedSize();
619             else
620                 factor = 1.0;
621             break;
622         case CSS_CHS:
623             factor = style.fontMetrics().zeroWidth();
624             break;
625         case CSS_PX:
626             factor = 1.0;
627             break;
628         case CSS_CM:
629             factor = cssPixelsPerCentimeter;
630             break;
631         case CSS_MM:
632             factor = cssPixelsPerMillimeter;
633             break;
634         case CSS_IN:
635             factor = cssPixelsPerInch;
636             break;
637         case CSS_PT:
638             factor = cssPixelsPerPoint;
639             break;
640         case CSS_PC:
641             factor = cssPixelsPerPica;
642             break;
643         case CSS_VW:
644             factor = conversionData.viewportWidthPercent();
645             break;
646         case CSS_VH:
647             factor = conversionData.viewportHeightPercent();
648             break;
649         case CSS_VMIN:
650             factor = conversionData.viewportMinPercent();
651             break;
652         case CSS_VMAX:
653             factor = conversionData.viewportMaxPercent();
654             break;
655         case CSS_CALC_PERCENTAGE_WITH_LENGTH:
656         case CSS_CALC_PERCENTAGE_WITH_NUMBER:
657             ASSERT_NOT_REACHED();
658             return -1.0;
659         default:
660             ASSERT_NOT_REACHED();
661             return -1.0;
662     }
663 
664     // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
665     // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
666     // as well as enforcing the implicit "smart minimum."
667     double result = getDoubleValue() * factor;
668     if (computingFontSize || isFontRelativeLength())
669         return result;
670 
671     return result * conversionData.zoom();
672 }
673 
accumulateLengthArray(CSSLengthArray & lengthArray,double multiplier) const674 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const
675 {
676     ASSERT(lengthArray.size() == LengthUnitTypeCount);
677 
678     if (m_primitiveUnitType == CSS_CALC) {
679         cssCalcValue()->accumulateLengthArray(lengthArray, multiplier);
680         return;
681     }
682 
683     LengthUnitType lengthType;
684     if (unitTypeToLengthUnitType(static_cast<UnitType>(m_primitiveUnitType), lengthType))
685         lengthArray.at(lengthType) += m_value.num * conversionToCanonicalUnitsScaleFactor(static_cast<UnitType>(m_primitiveUnitType)) * multiplier;
686 }
687 
setFloatValue(unsigned short,double,ExceptionState & exceptionState)688 void CSSPrimitiveValue::setFloatValue(unsigned short, double, ExceptionState& exceptionState)
689 {
690     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
691     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
692     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
693     exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only.");
694 }
695 
conversionToCanonicalUnitsScaleFactor(UnitType unitType)696 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType)
697 {
698     double factor = 1.0;
699     // FIXME: the switch can be replaced by an array of scale factors.
700     switch (unitType) {
701     // These are "canonical" units in their respective categories.
702     case CSS_PX:
703     case CSS_DEG:
704     case CSS_MS:
705     case CSS_HZ:
706         break;
707     case CSS_CM:
708         factor = cssPixelsPerCentimeter;
709         break;
710     case CSS_DPCM:
711         factor = 1 / cssPixelsPerCentimeter;
712         break;
713     case CSS_MM:
714         factor = cssPixelsPerMillimeter;
715         break;
716     case CSS_IN:
717         factor = cssPixelsPerInch;
718         break;
719     case CSS_DPI:
720         factor = 1 / cssPixelsPerInch;
721         break;
722     case CSS_PT:
723         factor = cssPixelsPerPoint;
724         break;
725     case CSS_PC:
726         factor = cssPixelsPerPica;
727         break;
728     case CSS_RAD:
729         factor = 180 / piDouble;
730         break;
731     case CSS_GRAD:
732         factor = 0.9;
733         break;
734     case CSS_TURN:
735         factor = 360;
736         break;
737     case CSS_S:
738     case CSS_KHZ:
739         factor = 1000;
740         break;
741     default:
742         break;
743     }
744 
745     return factor;
746 }
747 
getDoubleValue(UnitType unitType,ExceptionState & exceptionState) const748 double CSSPrimitiveValue::getDoubleValue(UnitType unitType, ExceptionState& exceptionState) const
749 {
750     double result = 0;
751     bool success = getDoubleValueInternal(unitType, &result);
752     if (!success) {
753         exceptionState.throwDOMException(InvalidAccessError, "Failed to obtain a double value.");
754         return 0.0;
755     }
756 
757     return result;
758 }
759 
getDoubleValue(UnitType unitType) const760 double CSSPrimitiveValue::getDoubleValue(UnitType unitType) const
761 {
762     double result = 0;
763     getDoubleValueInternal(unitType, &result);
764     return result;
765 }
766 
getDoubleValue() const767 double CSSPrimitiveValue::getDoubleValue() const
768 {
769     return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue();
770 }
771 
canonicalUnitTypeForCategory(UnitCategory category)772 CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
773 {
774     // The canonical unit type is chosen according to the way BisonCSSParser::validUnit() chooses the default unit
775     // in each category (based on unitflags).
776     switch (category) {
777     case UNumber:
778         return CSS_NUMBER;
779     case ULength:
780         return CSS_PX;
781     case UPercent:
782         return CSS_UNKNOWN; // Cannot convert between numbers and percent.
783     case UTime:
784         return CSS_MS;
785     case UAngle:
786         return CSS_DEG;
787     case UFrequency:
788         return CSS_HZ;
789     case UResolution:
790         return CSS_DPPX;
791     default:
792         return CSS_UNKNOWN;
793     }
794 }
795 
getDoubleValueInternal(UnitType requestedUnitType,double * result) const796 bool CSSPrimitiveValue::getDoubleValueInternal(UnitType requestedUnitType, double* result) const
797 {
798     if (!isValidCSSUnitTypeForDoubleConversion(static_cast<UnitType>(m_primitiveUnitType)) || !isValidCSSUnitTypeForDoubleConversion(requestedUnitType))
799         return false;
800 
801     UnitType sourceUnitType = primitiveType();
802     if (requestedUnitType == sourceUnitType || requestedUnitType == CSS_DIMENSION) {
803         *result = getDoubleValue();
804         return true;
805     }
806 
807     UnitCategory sourceCategory = unitCategory(sourceUnitType);
808     ASSERT(sourceCategory != UOther);
809 
810     UnitType targetUnitType = requestedUnitType;
811     UnitCategory targetCategory = unitCategory(targetUnitType);
812     ASSERT(targetCategory != UOther);
813 
814     // Cannot convert between unrelated unit categories if one of them is not UNumber.
815     if (sourceCategory != targetCategory && sourceCategory != UNumber && targetCategory != UNumber)
816         return false;
817 
818     if (targetCategory == UNumber) {
819         // We interpret conversion to CSS_NUMBER as conversion to a canonical unit in this value's category.
820         targetUnitType = canonicalUnitTypeForCategory(sourceCategory);
821         if (targetUnitType == CSS_UNKNOWN)
822             return false;
823     }
824 
825     if (sourceUnitType == CSS_NUMBER) {
826         // We interpret conversion from CSS_NUMBER in the same way as BisonCSSParser::validUnit() while using non-strict mode.
827         sourceUnitType = canonicalUnitTypeForCategory(targetCategory);
828         if (sourceUnitType == CSS_UNKNOWN)
829             return false;
830     }
831 
832     double convertedValue = getDoubleValue();
833 
834     // First convert the value from m_primitiveUnitType to canonical type.
835     double factor = conversionToCanonicalUnitsScaleFactor(sourceUnitType);
836     convertedValue *= factor;
837 
838     // Now convert from canonical type to the target unitType.
839     factor = conversionToCanonicalUnitsScaleFactor(targetUnitType);
840     convertedValue /= factor;
841 
842     *result = convertedValue;
843     return true;
844 }
845 
unitTypeToLengthUnitType(UnitType unitType,LengthUnitType & lengthType)846 bool CSSPrimitiveValue::unitTypeToLengthUnitType(UnitType unitType, LengthUnitType& lengthType)
847 {
848     switch (unitType) {
849     case CSSPrimitiveValue::CSS_PX:
850     case CSSPrimitiveValue::CSS_CM:
851     case CSSPrimitiveValue::CSS_MM:
852     case CSSPrimitiveValue::CSS_IN:
853     case CSSPrimitiveValue::CSS_PT:
854     case CSSPrimitiveValue::CSS_PC:
855         lengthType = UnitTypePixels;
856         return true;
857     case CSSPrimitiveValue::CSS_EMS:
858         lengthType = UnitTypeFontSize;
859         return true;
860     case CSSPrimitiveValue::CSS_EXS:
861         lengthType = UnitTypeFontXSize;
862         return true;
863     case CSSPrimitiveValue::CSS_REMS:
864         lengthType = UnitTypeRootFontSize;
865         return true;
866     case CSSPrimitiveValue::CSS_CHS:
867         lengthType = UnitTypeZeroCharacterWidth;
868         return true;
869     case CSSPrimitiveValue::CSS_PERCENTAGE:
870         lengthType = UnitTypePercentage;
871         return true;
872     case CSSPrimitiveValue::CSS_VW:
873         lengthType = UnitTypeViewportWidth;
874         return true;
875     case CSSPrimitiveValue::CSS_VH:
876         lengthType = UnitTypeViewportHeight;
877         return true;
878     case CSSPrimitiveValue::CSS_VMIN:
879         lengthType = UnitTypeViewportMin;
880         return true;
881     case CSSPrimitiveValue::CSS_VMAX:
882         lengthType = UnitTypeViewportMax;
883         return true;
884     default:
885         return false;
886     }
887 }
888 
lengthUnitTypeToUnitType(LengthUnitType type)889 CSSPrimitiveValue::UnitType CSSPrimitiveValue::lengthUnitTypeToUnitType(LengthUnitType type)
890 {
891     switch (type) {
892     case UnitTypePixels:
893         return CSSPrimitiveValue::CSS_PX;
894     case UnitTypeFontSize:
895         return CSSPrimitiveValue::CSS_EMS;
896     case UnitTypeFontXSize:
897         return CSSPrimitiveValue::CSS_EXS;
898     case UnitTypeRootFontSize:
899         return CSSPrimitiveValue::CSS_REMS;
900     case UnitTypeZeroCharacterWidth:
901         return CSSPrimitiveValue::CSS_CHS;
902     case UnitTypePercentage:
903         return CSSPrimitiveValue::CSS_PERCENTAGE;
904     case UnitTypeViewportWidth:
905         return CSSPrimitiveValue::CSS_VW;
906     case UnitTypeViewportHeight:
907         return CSSPrimitiveValue::CSS_VH;
908     case UnitTypeViewportMin:
909         return CSSPrimitiveValue::CSS_VMIN;
910     case UnitTypeViewportMax:
911         return CSSPrimitiveValue::CSS_VMAX;
912     case LengthUnitTypeCount:
913         break;
914     }
915     ASSERT_NOT_REACHED();
916     return CSSPrimitiveValue::CSS_UNKNOWN;
917 }
918 
setStringValue(unsigned short,const String &,ExceptionState & exceptionState)919 void CSSPrimitiveValue::setStringValue(unsigned short, const String&, ExceptionState& exceptionState)
920 {
921     // Keeping values immutable makes optimizations easier and allows sharing of the primitive value objects.
922     // No other engine supports mutating style through this API. Computed style is always read-only anyway.
923     // Supporting setter would require making primitive value copy-on-write and taking care of style invalidation.
924     exceptionState.throwDOMException(NoModificationAllowedError, "CSSPrimitiveValue objects are read-only.");
925 }
926 
getStringValue(ExceptionState & exceptionState) const927 String CSSPrimitiveValue::getStringValue(ExceptionState& exceptionState) const
928 {
929     switch (m_primitiveUnitType) {
930         case CSS_STRING:
931         case CSS_ATTR:
932         case CSS_URI:
933             return m_value.string;
934         case CSS_VALUE_ID:
935             return valueName(m_value.valueID);
936         case CSS_PROPERTY_ID:
937             return propertyName(m_value.propertyID);
938         default:
939             exceptionState.throwDOMException(InvalidAccessError, "This object's value cannot be represented as a string.");
940             break;
941     }
942 
943     return String();
944 }
945 
getStringValue() const946 String CSSPrimitiveValue::getStringValue() const
947 {
948     switch (m_primitiveUnitType) {
949         case CSS_STRING:
950         case CSS_ATTR:
951         case CSS_URI:
952             return m_value.string;
953         case CSS_VALUE_ID:
954             return valueName(m_value.valueID);
955         case CSS_PROPERTY_ID:
956             return propertyName(m_value.propertyID);
957         default:
958             break;
959     }
960 
961     return String();
962 }
963 
getCounterValue(ExceptionState & exceptionState) const964 Counter* CSSPrimitiveValue::getCounterValue(ExceptionState& exceptionState) const
965 {
966     if (m_primitiveUnitType != CSS_COUNTER) {
967         exceptionState.throwDOMException(InvalidAccessError, "This object is not a counter value.");
968         return 0;
969     }
970 
971     return m_value.counter;
972 }
973 
getRectValue(ExceptionState & exceptionState) const974 Rect* CSSPrimitiveValue::getRectValue(ExceptionState& exceptionState) const
975 {
976     if (m_primitiveUnitType != CSS_RECT) {
977         exceptionState.throwDOMException(InvalidAccessError, "This object is not a rect value.");
978         return 0;
979     }
980 
981     return m_value.rect;
982 }
983 
getQuadValue(ExceptionState & exceptionState) const984 Quad* CSSPrimitiveValue::getQuadValue(ExceptionState& exceptionState) const
985 {
986     if (m_primitiveUnitType != CSS_QUAD) {
987         exceptionState.throwDOMException(InvalidAccessError, "This object is not a quad value.");
988         return 0;
989     }
990 
991     return m_value.quad;
992 }
993 
getRGBColorValue(ExceptionState & exceptionState) const994 PassRefPtrWillBeRawPtr<RGBColor> CSSPrimitiveValue::getRGBColorValue(ExceptionState& exceptionState) const
995 {
996     if (m_primitiveUnitType != CSS_RGBCOLOR) {
997         exceptionState.throwDOMException(InvalidAccessError, "This object is not an RGB color value.");
998         return nullptr;
999     }
1000 
1001     // FIMXE: This should not return a new object for each invocation.
1002     return RGBColor::create(m_value.rgbcolor);
1003 }
1004 
getPairValue(ExceptionState & exceptionState) const1005 Pair* CSSPrimitiveValue::getPairValue(ExceptionState& exceptionState) const
1006 {
1007     if (m_primitiveUnitType != CSS_PAIR) {
1008         exceptionState.throwDOMException(InvalidAccessError, "This object is not a pair value.");
1009         return 0;
1010     }
1011 
1012     return m_value.pair;
1013 }
1014 
formatNumber(double number,const char * suffix,unsigned suffixLength)1015 static String formatNumber(double number, const char* suffix, unsigned suffixLength)
1016 {
1017     Decimal decimal = Decimal::fromDouble(number);
1018     String result = decimal.toString();
1019     result.append(suffix, suffixLength);
1020     return result;
1021 }
1022 
1023 template <unsigned characterCount>
formatNumber(double number,const char (& characters)[characterCount])1024 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount])
1025 {
1026     return formatNumber(number, characters, characterCount - 1);
1027 }
1028 
formatNumber(double number,const char * characters)1029 static String formatNumber(double number, const char* characters)
1030 {
1031     return formatNumber(number, characters, strlen(characters));
1032 }
1033 
unitTypeToString(UnitType type)1034 const char* CSSPrimitiveValue::unitTypeToString(UnitType type)
1035 {
1036     switch (type) {
1037     case CSS_NUMBER:
1038     case CSS_PARSER_INTEGER:
1039         return "";
1040     case CSS_PERCENTAGE:
1041         return "%";
1042     case CSS_EMS:
1043         return "em";
1044     case CSS_EXS:
1045         return "ex";
1046     case CSS_REMS:
1047         return "rem";
1048     case CSS_CHS:
1049         return "ch";
1050     case CSS_PX:
1051         return "px";
1052     case CSS_CM:
1053         return "cm";
1054     case CSS_DPPX:
1055         return "dppx";
1056     case CSS_DPI:
1057         return "dpi";
1058     case CSS_DPCM:
1059         return "dpcm";
1060     case CSS_MM:
1061         return "mm";
1062     case CSS_IN:
1063         return "in";
1064     case CSS_PT:
1065         return "pt";
1066     case CSS_PC:
1067         return "pc";
1068     case CSS_DEG:
1069         return "deg";
1070     case CSS_RAD:
1071         return "rad";
1072     case CSS_GRAD:
1073         return "grad";
1074     case CSS_MS:
1075         return "ms";
1076     case CSS_S:
1077         return "s";
1078     case CSS_HZ:
1079         return "hz";
1080     case CSS_KHZ:
1081         return "khz";
1082     case CSS_TURN:
1083         return "turn";
1084     case CSS_FR:
1085         return "fr";
1086     case CSS_VW:
1087         return "vw";
1088     case CSS_VH:
1089         return "vh";
1090     case CSS_VMIN:
1091         return "vmin";
1092     case CSS_VMAX:
1093         return "vmax";
1094     case CSS_UNKNOWN:
1095     case CSS_DIMENSION:
1096     case CSS_STRING:
1097     case CSS_URI:
1098     case CSS_VALUE_ID:
1099     case CSS_PROPERTY_ID:
1100     case CSS_ATTR:
1101     case CSS_COUNTER_NAME:
1102     case CSS_COUNTER:
1103     case CSS_RECT:
1104     case CSS_QUAD:
1105     case CSS_RGBCOLOR:
1106     case CSS_PARSER_HEXCOLOR:
1107     case CSS_PAIR:
1108     case CSS_PARSER_OPERATOR:
1109     case CSS_PARSER_IDENTIFIER:
1110     case CSS_CALC:
1111     case CSS_SHAPE:
1112     case CSS_IDENT:
1113     case CSS_UNICODE_RANGE:
1114     case CSS_CALC_PERCENTAGE_WITH_NUMBER:
1115     case CSS_CALC_PERCENTAGE_WITH_LENGTH:
1116         break;
1117     };
1118     ASSERT_NOT_REACHED();
1119     return "";
1120 }
1121 
customCSSText(CSSTextFormattingFlags formattingFlag) const1122 String CSSPrimitiveValue::customCSSText(CSSTextFormattingFlags formattingFlag) const
1123 {
1124     // FIXME: return the original value instead of a generated one (e.g. color
1125     // name if it was specified) - check what spec says about this
1126 
1127     if (m_hasCachedCSSText) {
1128         ASSERT(cssTextCache().contains(this));
1129         return cssTextCache().get(this);
1130     }
1131 
1132     String text;
1133     switch (m_primitiveUnitType) {
1134         case CSS_UNKNOWN:
1135             // FIXME
1136             break;
1137         case CSS_NUMBER:
1138         case CSS_PARSER_INTEGER:
1139         case CSS_PERCENTAGE:
1140         case CSS_EMS:
1141         case CSS_EXS:
1142         case CSS_REMS:
1143         case CSS_CHS:
1144         case CSS_PX:
1145         case CSS_CM:
1146         case CSS_DPPX:
1147         case CSS_DPI:
1148         case CSS_DPCM:
1149         case CSS_MM:
1150         case CSS_IN:
1151         case CSS_PT:
1152         case CSS_PC:
1153         case CSS_DEG:
1154         case CSS_RAD:
1155         case CSS_GRAD:
1156         case CSS_MS:
1157         case CSS_S:
1158         case CSS_HZ:
1159         case CSS_KHZ:
1160         case CSS_TURN:
1161         case CSS_FR:
1162         case CSS_VW:
1163         case CSS_VH:
1164         case CSS_VMIN:
1165         case CSS_VMAX:
1166             text = formatNumber(m_value.num, unitTypeToString((UnitType)m_primitiveUnitType));
1167         case CSS_DIMENSION:
1168             // FIXME: We currently don't handle CSS_DIMENSION properly as we don't store
1169             // the actual dimension, just the numeric value as a string.
1170             break;
1171         case CSS_STRING:
1172             text = formattingFlag == AlwaysQuoteCSSString ? quoteCSSString(m_value.string) : quoteCSSStringIfNeeded(m_value.string);
1173             break;
1174         case CSS_URI:
1175             text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
1176             break;
1177         case CSS_VALUE_ID:
1178             text = valueName(m_value.valueID);
1179             break;
1180         case CSS_PROPERTY_ID:
1181             text = propertyName(m_value.propertyID);
1182             break;
1183         case CSS_ATTR: {
1184             StringBuilder result;
1185             result.reserveCapacity(6 + m_value.string->length());
1186             result.appendLiteral("attr(");
1187             result.append(m_value.string);
1188             result.append(')');
1189 
1190             text = result.toString();
1191             break;
1192         }
1193         case CSS_COUNTER_NAME:
1194             text = "counter(" + String(m_value.string) + ')';
1195             break;
1196         case CSS_COUNTER: {
1197             StringBuilder result;
1198             String separator = m_value.counter->separator();
1199             if (separator.isEmpty())
1200                 result.appendLiteral("counter(");
1201             else
1202                 result.appendLiteral("counters(");
1203 
1204             result.append(m_value.counter->identifier());
1205             if (!separator.isEmpty()) {
1206                 result.appendLiteral(", ");
1207                 result.append(quoteCSSStringIfNeeded(separator));
1208             }
1209             String listStyle = m_value.counter->listStyle();
1210             if (!listStyle.isEmpty()) {
1211                 result.appendLiteral(", ");
1212                 result.append(listStyle);
1213             }
1214             result.append(')');
1215 
1216             text = result.toString();
1217             break;
1218         }
1219         case CSS_RECT:
1220             text = getRectValue()->cssText();
1221             break;
1222         case CSS_QUAD:
1223             text = getQuadValue()->cssText();
1224             break;
1225         case CSS_RGBCOLOR:
1226         case CSS_PARSER_HEXCOLOR: {
1227             RGBA32 rgbColor = m_value.rgbcolor;
1228             if (m_primitiveUnitType == CSS_PARSER_HEXCOLOR)
1229                 Color::parseHexColor(m_value.string, rgbColor);
1230             Color color(rgbColor);
1231             text = color.serializedAsCSSComponentValue();
1232             break;
1233         }
1234         case CSS_PAIR:
1235             text = getPairValue()->cssText();
1236             break;
1237         case CSS_PARSER_OPERATOR: {
1238             char c = static_cast<char>(m_value.parserOperator);
1239             text = String(&c, 1U);
1240             break;
1241         }
1242         case CSS_PARSER_IDENTIFIER:
1243             text = quoteCSSStringIfNeeded(m_value.string);
1244             break;
1245         case CSS_CALC:
1246             text = m_value.calc->cssText();
1247             break;
1248         case CSS_SHAPE:
1249             text = m_value.shape->cssText();
1250             break;
1251     }
1252 
1253     ASSERT(!cssTextCache().contains(this));
1254     cssTextCache().set(this, text);
1255     m_hasCachedCSSText = true;
1256     return text;
1257 }
1258 
cloneForCSSOM() const1259 PassRefPtrWillBeRawPtr<CSSPrimitiveValue> CSSPrimitiveValue::cloneForCSSOM() const
1260 {
1261     RefPtrWillBeRawPtr<CSSPrimitiveValue> result = nullptr;
1262 
1263     switch (m_primitiveUnitType) {
1264     case CSS_STRING:
1265     case CSS_URI:
1266     case CSS_ATTR:
1267     case CSS_COUNTER_NAME:
1268         result = CSSPrimitiveValue::create(m_value.string, static_cast<UnitType>(m_primitiveUnitType));
1269         break;
1270     case CSS_COUNTER:
1271         result = CSSPrimitiveValue::create(m_value.counter->cloneForCSSOM());
1272         break;
1273     case CSS_RECT:
1274         result = CSSPrimitiveValue::create(m_value.rect->cloneForCSSOM());
1275         break;
1276     case CSS_QUAD:
1277         result = CSSPrimitiveValue::create(m_value.quad->cloneForCSSOM());
1278         break;
1279     case CSS_PAIR:
1280         // Pair is not exposed to the CSSOM, no need for a deep clone.
1281         result = CSSPrimitiveValue::create(m_value.pair);
1282         break;
1283     case CSS_CALC:
1284         // CSSCalcValue is not exposed to the CSSOM, no need for a deep clone.
1285         result = CSSPrimitiveValue::create(m_value.calc);
1286         break;
1287     case CSS_SHAPE:
1288         // CSSShapeValue is not exposed to the CSSOM, no need for a deep clone.
1289         result = CSSPrimitiveValue::create(m_value.shape);
1290         break;
1291     case CSS_NUMBER:
1292     case CSS_PARSER_INTEGER:
1293     case CSS_PERCENTAGE:
1294     case CSS_EMS:
1295     case CSS_EXS:
1296     case CSS_REMS:
1297     case CSS_CHS:
1298     case CSS_PX:
1299     case CSS_CM:
1300     case CSS_MM:
1301     case CSS_IN:
1302     case CSS_PT:
1303     case CSS_PC:
1304     case CSS_DEG:
1305     case CSS_RAD:
1306     case CSS_GRAD:
1307     case CSS_MS:
1308     case CSS_S:
1309     case CSS_HZ:
1310     case CSS_KHZ:
1311     case CSS_TURN:
1312     case CSS_VW:
1313     case CSS_VH:
1314     case CSS_VMIN:
1315     case CSS_VMAX:
1316     case CSS_DPPX:
1317     case CSS_DPI:
1318     case CSS_DPCM:
1319     case CSS_FR:
1320         result = CSSPrimitiveValue::create(m_value.num, static_cast<UnitType>(m_primitiveUnitType));
1321         break;
1322     case CSS_PROPERTY_ID:
1323         result = CSSPrimitiveValue::createIdentifier(m_value.propertyID);
1324         break;
1325     case CSS_VALUE_ID:
1326         result = CSSPrimitiveValue::createIdentifier(m_value.valueID);
1327         break;
1328     case CSS_RGBCOLOR:
1329         result = CSSPrimitiveValue::createColor(m_value.rgbcolor);
1330         break;
1331     case CSS_DIMENSION:
1332     case CSS_UNKNOWN:
1333     case CSS_PARSER_OPERATOR:
1334     case CSS_PARSER_IDENTIFIER:
1335     case CSS_PARSER_HEXCOLOR:
1336         ASSERT_NOT_REACHED();
1337         break;
1338     }
1339     if (result)
1340         result->setCSSOMSafe();
1341 
1342     return result;
1343 }
1344 
equals(const CSSPrimitiveValue & other) const1345 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
1346 {
1347     if (m_primitiveUnitType != other.m_primitiveUnitType)
1348         return false;
1349 
1350     switch (m_primitiveUnitType) {
1351     case CSS_UNKNOWN:
1352         return false;
1353     case CSS_NUMBER:
1354     case CSS_PARSER_INTEGER:
1355     case CSS_PERCENTAGE:
1356     case CSS_EMS:
1357     case CSS_EXS:
1358     case CSS_REMS:
1359     case CSS_PX:
1360     case CSS_CM:
1361     case CSS_DPPX:
1362     case CSS_DPI:
1363     case CSS_DPCM:
1364     case CSS_MM:
1365     case CSS_IN:
1366     case CSS_PT:
1367     case CSS_PC:
1368     case CSS_DEG:
1369     case CSS_RAD:
1370     case CSS_GRAD:
1371     case CSS_MS:
1372     case CSS_S:
1373     case CSS_HZ:
1374     case CSS_KHZ:
1375     case CSS_TURN:
1376     case CSS_VW:
1377     case CSS_VH:
1378     case CSS_VMIN:
1379     case CSS_VMAX:
1380     case CSS_DIMENSION:
1381     case CSS_FR:
1382         return m_value.num == other.m_value.num;
1383     case CSS_PROPERTY_ID:
1384         return propertyName(m_value.propertyID) == propertyName(other.m_value.propertyID);
1385     case CSS_VALUE_ID:
1386         return valueName(m_value.valueID) == valueName(other.m_value.valueID);
1387     case CSS_STRING:
1388     case CSS_URI:
1389     case CSS_ATTR:
1390     case CSS_COUNTER_NAME:
1391     case CSS_PARSER_IDENTIFIER:
1392     case CSS_PARSER_HEXCOLOR:
1393         return equal(m_value.string, other.m_value.string);
1394     case CSS_COUNTER:
1395         return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter);
1396     case CSS_RECT:
1397         return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect);
1398     case CSS_QUAD:
1399         return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad);
1400     case CSS_RGBCOLOR:
1401         return m_value.rgbcolor == other.m_value.rgbcolor;
1402     case CSS_PAIR:
1403         return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair);
1404     case CSS_PARSER_OPERATOR:
1405         return m_value.parserOperator == other.m_value.parserOperator;
1406     case CSS_CALC:
1407         return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
1408     case CSS_SHAPE:
1409         return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
1410     }
1411     return false;
1412 }
1413 
traceAfterDispatch(Visitor * visitor)1414 void CSSPrimitiveValue::traceAfterDispatch(Visitor* visitor)
1415 {
1416     switch (m_primitiveUnitType) {
1417     case CSS_COUNTER:
1418         visitor->trace(m_value.counter);
1419         break;
1420     case CSS_RECT:
1421         visitor->trace(m_value.rect);
1422         break;
1423     case CSS_QUAD:
1424         visitor->trace(m_value.quad);
1425         break;
1426     case CSS_PAIR:
1427         visitor->trace(m_value.pair);
1428         break;
1429     case CSS_CALC:
1430         visitor->trace(m_value.calc);
1431         break;
1432     case CSS_SHAPE:
1433         visitor->trace(m_value.shape);
1434         break;
1435     default:
1436         break;
1437     }
1438     CSSValue::traceAfterDispatch(visitor);
1439 }
1440 
1441 } // namespace WebCore
1442