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