• 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