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