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