Serialize zIndex as an integer
[chromium-blink-merge.git] / third_party / WebKit / Source / core / css / CSSPrimitiveValue.cpp
bloba4eb31adb59c44b655d1fcb7e70f63912d60a1b1
1 /*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2012 Apple Inc. All rights reserved.
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.
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.
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.
21 #include "config.h"
22 #include "core/css/CSSPrimitiveValue.h"
24 #include "core/css/CSSBasicShapes.h"
25 #include "core/css/CSSCalculationValue.h"
26 #include "core/css/CSSHelper.h"
27 #include "core/css/CSSMarkup.h"
28 #include "core/css/CSSToLengthConversionData.h"
29 #include "core/css/Counter.h"
30 #include "core/css/Pair.h"
31 #include "core/css/Rect.h"
32 #include "core/css/StyleSheetContents.h"
33 #include "core/dom/Node.h"
34 #include "core/style/ComputedStyle.h"
35 #include "platform/LayoutUnit.h"
36 #include "platform/fonts/FontMetrics.h"
37 #include "wtf/StdLibExtras.h"
38 #include "wtf/ThreadSpecific.h"
39 #include "wtf/Threading.h"
40 #include "wtf/text/StringBuffer.h"
41 #include "wtf/text/StringBuilder.h"
43 using namespace WTF;
45 namespace blink {
47 namespace {
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;
54 typedef HashMap<String, CSSPrimitiveValue::UnitType> StringToUnitTable;
56 StringToUnitTable createStringToUnitTable()
58 StringToUnitTable table;
59 table.set(String("em"), CSSPrimitiveValue::CSS_EMS);
60 table.set(String("ex"), CSSPrimitiveValue::CSS_EXS);
61 table.set(String("px"), CSSPrimitiveValue::CSS_PX);
62 table.set(String("cm"), CSSPrimitiveValue::CSS_CM);
63 table.set(String("mm"), CSSPrimitiveValue::CSS_MM);
64 table.set(String("in"), CSSPrimitiveValue::CSS_IN);
65 table.set(String("pt"), CSSPrimitiveValue::CSS_PT);
66 table.set(String("pc"), CSSPrimitiveValue::CSS_PC);
67 table.set(String("deg"), CSSPrimitiveValue::CSS_DEG);
68 table.set(String("rad"), CSSPrimitiveValue::CSS_RAD);
69 table.set(String("grad"), CSSPrimitiveValue::CSS_GRAD);
70 table.set(String("ms"), CSSPrimitiveValue::CSS_MS);
71 table.set(String("s"), CSSPrimitiveValue::CSS_S);
72 table.set(String("hz"), CSSPrimitiveValue::CSS_HZ);
73 table.set(String("khz"), CSSPrimitiveValue::CSS_KHZ);
74 table.set(String("dpi"), CSSPrimitiveValue::CSS_DPI);
75 table.set(String("dpcm"), CSSPrimitiveValue::CSS_DPCM);
76 table.set(String("dppx"), CSSPrimitiveValue::CSS_DPPX);
77 table.set(String("vw"), CSSPrimitiveValue::CSS_VW);
78 table.set(String("vh"), CSSPrimitiveValue::CSS_VH);
79 table.set(String("vmin"), CSSPrimitiveValue::CSS_VMIN);
80 table.set(String("vmax"), CSSPrimitiveValue::CSS_VMAX);
81 table.set(String("rem"), CSSPrimitiveValue::CSS_REMS);
82 table.set(String("fr"), CSSPrimitiveValue::CSS_FR);
83 table.set(String("turn"), CSSPrimitiveValue::CSS_TURN);
84 table.set(String("ch"), CSSPrimitiveValue::CSS_CHS);
85 table.set(String("__qem"), CSSPrimitiveValue::CSS_QEM);
86 return table;
89 StringToUnitTable& unitTable()
91 DEFINE_STATIC_LOCAL(StringToUnitTable, unitTable, (createStringToUnitTable()));
92 return unitTable;
95 } // namespace
97 float CSSPrimitiveValue::clampToCSSLengthRange(double value)
99 return clampTo<float>(value, minValueForCssLength, maxValueForCssLength);
102 void CSSPrimitiveValue::initUnitTable()
104 // Make sure we initialize this during blink initialization
105 // to avoid racy static local initialization.
106 unitTable();
109 CSSPrimitiveValue::UnitType CSSPrimitiveValue::fromName(const String& unit)
111 return unitTable().get(unit.lower());
114 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(UnitType type)
116 switch (type) {
117 case CSS_NUMBER:
118 return CSSPrimitiveValue::UNumber;
119 case CSS_PERCENTAGE:
120 return CSSPrimitiveValue::UPercent;
121 case CSS_PX:
122 case CSS_CM:
123 case CSS_MM:
124 case CSS_IN:
125 case CSS_PT:
126 case CSS_PC:
127 return CSSPrimitiveValue::ULength;
128 case CSS_MS:
129 case CSS_S:
130 return CSSPrimitiveValue::UTime;
131 case CSS_DEG:
132 case CSS_RAD:
133 case CSS_GRAD:
134 case CSS_TURN:
135 return CSSPrimitiveValue::UAngle;
136 case CSS_HZ:
137 case CSS_KHZ:
138 return CSSPrimitiveValue::UFrequency;
139 case CSS_DPPX:
140 case CSS_DPI:
141 case CSS_DPCM:
142 return CSSPrimitiveValue::UResolution;
143 default:
144 return CSSPrimitiveValue::UOther;
148 bool CSSPrimitiveValue::colorIsDerivedFromElement() const
150 int valueID = getValueID();
151 switch (valueID) {
152 case CSSValueWebkitText:
153 case CSSValueWebkitLink:
154 case CSSValueWebkitActivelink:
155 case CSSValueCurrentcolor:
156 return true;
157 default:
158 return false;
162 typedef HashMap<const CSSPrimitiveValue*, String> CSSTextCache;
163 static CSSTextCache& cssTextCache()
165 AtomicallyInitializedStaticReference(ThreadSpecific<CSSTextCache>, cache, new ThreadSpecific<CSSTextCache>());
166 return *cache;
169 CSSPrimitiveValue::UnitType CSSPrimitiveValue::primitiveType() const
171 if (m_primitiveUnitType == CSS_PROPERTY_ID || m_primitiveUnitType == CSS_VALUE_ID)
172 return CSS_IDENT;
174 if (m_primitiveUnitType != CSS_CALC)
175 return static_cast<UnitType>(m_primitiveUnitType);
177 switch (m_value.calc->category()) {
178 case CalcAngle:
179 return CSS_DEG;
180 case CalcFrequency:
181 return CSS_HZ;
182 case CalcNumber:
183 return CSS_NUMBER;
184 case CalcPercent:
185 return CSS_PERCENTAGE;
186 case CalcLength:
187 return CSS_PX;
188 case CalcPercentNumber:
189 return CSS_CALC_PERCENTAGE_WITH_NUMBER;
190 case CalcPercentLength:
191 return CSS_CALC_PERCENTAGE_WITH_LENGTH;
192 case CalcTime:
193 return CSS_MS;
194 case CalcOther:
195 return CSS_UNKNOWN;
197 return CSS_UNKNOWN;
200 static const AtomicString& propertyName(CSSPropertyID propertyID)
202 return getPropertyNameAtomicString(propertyID);
205 static const AtomicString& valueName(CSSValueID valueID)
207 ASSERT_ARG(valueID, valueID >= 0);
208 ASSERT_ARG(valueID, valueID < numCSSValueKeywords);
210 if (valueID < 0)
211 return nullAtom;
213 static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally.
214 AtomicString& keywordString = keywordStrings[valueID];
215 if (keywordString.isNull())
216 keywordString = getValueName(valueID);
217 return keywordString;
220 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
221 : CSSValue(PrimitiveClass)
223 m_primitiveUnitType = CSS_VALUE_ID;
224 m_value.valueID = valueID;
227 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
228 : CSSValue(PrimitiveClass)
230 m_primitiveUnitType = CSS_PROPERTY_ID;
231 m_value.propertyID = propertyID;
234 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type)
235 : CSSValue(PrimitiveClass)
237 m_primitiveUnitType = type;
238 ASSERT(std::isfinite(num));
239 m_value.num = num;
242 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitType type)
243 : CSSValue(PrimitiveClass)
245 m_primitiveUnitType = type;
246 m_value.string = str.impl();
247 if (m_value.string)
248 m_value.string->ref();
251 CSSPrimitiveValue::CSSPrimitiveValue(const LengthSize& lengthSize, const ComputedStyle& style)
252 : CSSValue(PrimitiveClass)
254 init(lengthSize, style);
257 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
258 : CSSValue(PrimitiveClass)
260 m_primitiveUnitType = CSS_RGBCOLOR;
261 m_value.rgbcolor = color;
264 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, float zoom)
265 : CSSValue(PrimitiveClass)
267 switch (length.type()) {
268 case Auto:
269 m_primitiveUnitType = CSS_VALUE_ID;
270 m_value.valueID = CSSValueAuto;
271 break;
272 case Intrinsic:
273 m_primitiveUnitType = CSS_VALUE_ID;
274 m_value.valueID = CSSValueIntrinsic;
275 break;
276 case MinIntrinsic:
277 m_primitiveUnitType = CSS_VALUE_ID;
278 m_value.valueID = CSSValueMinIntrinsic;
279 break;
280 case MinContent:
281 m_primitiveUnitType = CSS_VALUE_ID;
282 m_value.valueID = CSSValueMinContent;
283 break;
284 case MaxContent:
285 m_primitiveUnitType = CSS_VALUE_ID;
286 m_value.valueID = CSSValueMaxContent;
287 break;
288 case FillAvailable:
289 m_primitiveUnitType = CSS_VALUE_ID;
290 m_value.valueID = CSSValueWebkitFillAvailable;
291 break;
292 case FitContent:
293 m_primitiveUnitType = CSS_VALUE_ID;
294 m_value.valueID = CSSValueWebkitFitContent;
295 break;
296 case ExtendToZoom:
297 m_primitiveUnitType = CSS_VALUE_ID;
298 m_value.valueID = CSSValueInternalExtendToZoom;
299 break;
300 case Percent:
301 m_primitiveUnitType = CSS_PERCENTAGE;
302 ASSERT(std::isfinite(length.percent()));
303 m_value.num = length.percent();
304 break;
305 case Fixed:
306 m_primitiveUnitType = CSS_PX;
307 m_value.num = length.value() / zoom;
308 break;
309 case Calculated: {
310 const CalculationValue& calc = length.calculationValue();
311 if (calc.pixels() && calc.percent()) {
312 init(CSSCalcValue::create(
313 CSSCalcValue::createExpressionNode(calc.pixels() / zoom, calc.percent()),
314 calc.isNonNegative() ? ValueRangeNonNegative : ValueRangeAll));
315 break;
317 if (calc.percent()) {
318 m_primitiveUnitType = CSS_PERCENTAGE;
319 m_value.num = calc.percent();
320 } else {
321 m_primitiveUnitType = CSS_PX;
322 m_value.num = calc.pixels() / zoom;
324 if (m_value.num < 0 && calc.isNonNegative())
325 m_value.num = 0;
326 break;
328 case DeviceWidth:
329 case DeviceHeight:
330 case MaxSizeNone:
331 ASSERT_NOT_REACHED();
332 break;
336 void CSSPrimitiveValue::init(const LengthSize& lengthSize, const ComputedStyle& style)
338 m_primitiveUnitType = CSS_PAIR;
339 m_hasCachedCSSText = false;
340 m_value.pair = Pair::create(create(lengthSize.width(), style.effectiveZoom()), create(lengthSize.height(), style.effectiveZoom()), Pair::KeepIdenticalValues).leakRef();
343 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Counter> c)
345 m_primitiveUnitType = CSS_COUNTER;
346 m_hasCachedCSSText = false;
347 m_value.counter = c.leakRef();
350 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Rect> r)
352 m_primitiveUnitType = CSS_RECT;
353 m_hasCachedCSSText = false;
354 m_value.rect = r.leakRef();
357 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Quad> quad)
359 m_primitiveUnitType = CSS_QUAD;
360 m_hasCachedCSSText = false;
361 m_value.quad = quad.leakRef();
364 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<Pair> p)
366 m_primitiveUnitType = CSS_PAIR;
367 m_hasCachedCSSText = false;
368 m_value.pair = p.leakRef();
371 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSCalcValue> c)
373 m_primitiveUnitType = CSS_CALC;
374 m_hasCachedCSSText = false;
375 m_value.calc = c.leakRef();
378 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSBasicShape> shape)
380 m_primitiveUnitType = CSS_SHAPE;
381 m_hasCachedCSSText = false;
382 m_value.shape = shape.leakRef();
385 CSSPrimitiveValue::~CSSPrimitiveValue()
387 cleanup();
390 void CSSPrimitiveValue::cleanup()
392 switch (static_cast<UnitType>(m_primitiveUnitType)) {
393 case CSS_CUSTOM_IDENT:
394 case CSS_STRING:
395 case CSS_URI:
396 case CSS_ATTR:
397 if (m_value.string)
398 m_value.string->deref();
399 break;
400 case CSS_COUNTER:
401 // We must not call deref() when oilpan is enabled because m_value.counter is traced.
402 #if !ENABLE(OILPAN)
403 m_value.counter->deref();
404 #endif
405 break;
406 case CSS_RECT:
407 // We must not call deref() when oilpan is enabled because m_value.rect is traced.
408 #if !ENABLE(OILPAN)
409 m_value.rect->deref();
410 #endif
411 break;
412 case CSS_QUAD:
413 // We must not call deref() when oilpan is enabled because m_value.quad is traced.
414 #if !ENABLE(OILPAN)
415 m_value.quad->deref();
416 #endif
417 break;
418 case CSS_PAIR:
419 // We must not call deref() when oilpan is enabled because m_value.pair is traced.
420 #if !ENABLE(OILPAN)
421 m_value.pair->deref();
422 #endif
423 break;
424 case CSS_CALC:
425 // We must not call deref() when oilpan is enabled because m_value.calc is traced.
426 #if !ENABLE(OILPAN)
427 m_value.calc->deref();
428 #endif
429 break;
430 case CSS_CALC_PERCENTAGE_WITH_NUMBER:
431 case CSS_CALC_PERCENTAGE_WITH_LENGTH:
432 ASSERT_NOT_REACHED();
433 break;
434 case CSS_SHAPE:
435 // We must not call deref() when oilpan is enabled because m_value.shape is traced.
436 #if !ENABLE(OILPAN)
437 m_value.shape->deref();
438 #endif
439 break;
440 case CSS_NUMBER:
441 case CSS_INTEGER:
442 case CSS_PERCENTAGE:
443 case CSS_EMS:
444 case CSS_QEM:
445 case CSS_EXS:
446 case CSS_REMS:
447 case CSS_CHS:
448 case CSS_PX:
449 case CSS_CM:
450 case CSS_MM:
451 case CSS_IN:
452 case CSS_PT:
453 case CSS_PC:
454 case CSS_DEG:
455 case CSS_RAD:
456 case CSS_GRAD:
457 case CSS_MS:
458 case CSS_S:
459 case CSS_HZ:
460 case CSS_KHZ:
461 case CSS_TURN:
462 case CSS_VW:
463 case CSS_VH:
464 case CSS_VMIN:
465 case CSS_VMAX:
466 case CSS_DPPX:
467 case CSS_DPI:
468 case CSS_DPCM:
469 case CSS_FR:
470 case CSS_IDENT:
471 case CSS_RGBCOLOR:
472 case CSS_UNKNOWN:
473 case CSS_PROPERTY_ID:
474 case CSS_VALUE_ID:
475 break;
477 m_primitiveUnitType = 0;
478 if (m_hasCachedCSSText) {
479 cssTextCache().remove(this);
480 m_hasCachedCSSText = false;
484 double CSSPrimitiveValue::computeSeconds()
486 ASSERT(isTime() || (isCalculated() && cssCalcValue()->category() == CalcTime));
487 UnitType currentType = isCalculated() ? cssCalcValue()->expressionNode()->primitiveType() : static_cast<UnitType>(m_primitiveUnitType);
488 if (currentType == CSS_S)
489 return getDoubleValue();
490 if (currentType == CSS_MS)
491 return getDoubleValue() / 1000;
492 ASSERT_NOT_REACHED();
493 return 0;
496 double CSSPrimitiveValue::computeDegrees() const
498 ASSERT(isAngle() || (isCalculated() && cssCalcValue()->category() == CalcAngle));
499 UnitType currentType = isCalculated() ? cssCalcValue()->expressionNode()->primitiveType() : static_cast<UnitType>(m_primitiveUnitType);
500 switch (currentType) {
501 case CSS_DEG:
502 return getDoubleValue();
503 case CSS_RAD:
504 return rad2deg(getDoubleValue());
505 case CSS_GRAD:
506 return grad2deg(getDoubleValue());
507 case CSS_TURN:
508 return turn2deg(getDoubleValue());
509 default:
510 ASSERT_NOT_REACHED();
511 return 0;
515 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
517 return roundForImpreciseConversion<int>(computeLengthDouble(conversionData));
520 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
522 return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData));
525 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
527 return Length(clampToCSSLengthRange(computeLengthDouble(conversionData)), Fixed);
530 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
532 return roundForImpreciseConversion<short>(computeLengthDouble(conversionData));
535 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
537 return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData));
540 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
542 return static_cast<float>(computeLengthDouble(conversionData));
545 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData)
547 return computeLengthDouble(conversionData);
550 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData)
552 // The logic in this function is duplicated in MediaValues::computeLength
553 // because MediaValues::computeLength needs nearly identical logic, but we haven't found a way to make
554 // CSSPrimitiveValue::computeLengthDouble more generic (to solve both cases) without hurting performance.
555 if (m_primitiveUnitType == CSS_CALC)
556 return m_value.calc->computeLengthPx(conversionData);
558 double factor;
560 switch (primitiveType()) {
561 case CSS_EMS:
562 factor = conversionData.emFontSize();
563 break;
564 case CSS_EXS:
565 factor = conversionData.exFontSize();
566 break;
567 case CSS_REMS:
568 factor = conversionData.remFontSize();
569 break;
570 case CSS_CHS:
571 factor = conversionData.chFontSize();
572 break;
573 case CSS_PX:
574 factor = 1.0;
575 break;
576 case CSS_CM:
577 factor = cssPixelsPerCentimeter;
578 break;
579 case CSS_MM:
580 factor = cssPixelsPerMillimeter;
581 break;
582 case CSS_IN:
583 factor = cssPixelsPerInch;
584 break;
585 case CSS_PT:
586 factor = cssPixelsPerPoint;
587 break;
588 case CSS_PC:
589 factor = cssPixelsPerPica;
590 break;
591 case CSS_VW:
592 factor = conversionData.viewportWidthPercent();
593 break;
594 case CSS_VH:
595 factor = conversionData.viewportHeightPercent();
596 break;
597 case CSS_VMIN:
598 factor = conversionData.viewportMinPercent();
599 break;
600 case CSS_VMAX:
601 factor = conversionData.viewportMaxPercent();
602 break;
603 case CSS_CALC_PERCENTAGE_WITH_LENGTH:
604 case CSS_CALC_PERCENTAGE_WITH_NUMBER:
605 ASSERT_NOT_REACHED();
606 return -1.0;
607 default:
608 ASSERT_NOT_REACHED();
609 return -1.0;
612 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
613 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
614 // as well as enforcing the implicit "smart minimum."
615 double result = getDoubleValue() * factor;
616 if (isFontRelativeLength())
617 return result;
619 return result * conversionData.zoom();
622 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, CSSLengthTypeArray& lengthTypeArray, double multiplier) const
624 ASSERT(lengthArray.size() == LengthUnitTypeCount);
626 if (m_primitiveUnitType == CSS_CALC) {
627 cssCalcValue()->accumulateLengthArray(lengthArray, lengthTypeArray, multiplier);
628 return;
631 LengthUnitType lengthType;
632 if (unitTypeToLengthUnitType(static_cast<UnitType>(m_primitiveUnitType), lengthType)) {
633 lengthArray.at(lengthType) += m_value.num * conversionToCanonicalUnitsScaleFactor(static_cast<UnitType>(m_primitiveUnitType)) * multiplier;
634 lengthTypeArray.set(lengthType);
638 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const
640 CSSLengthTypeArray lengthTypeArray;
641 lengthTypeArray.resize(CSSPrimitiveValue::LengthUnitTypeCount);
642 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; ++i)
643 lengthTypeArray.clear(i);
644 return CSSPrimitiveValue::accumulateLengthArray(lengthArray, lengthTypeArray, multiplier);
647 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType)
649 double factor = 1.0;
650 // FIXME: the switch can be replaced by an array of scale factors.
651 switch (unitType) {
652 // These are "canonical" units in their respective categories.
653 case CSS_PX:
654 case CSS_DEG:
655 case CSS_MS:
656 case CSS_HZ:
657 break;
658 case CSS_CM:
659 factor = cssPixelsPerCentimeter;
660 break;
661 case CSS_DPCM:
662 factor = 1 / cssPixelsPerCentimeter;
663 break;
664 case CSS_MM:
665 factor = cssPixelsPerMillimeter;
666 break;
667 case CSS_IN:
668 factor = cssPixelsPerInch;
669 break;
670 case CSS_DPI:
671 factor = 1 / cssPixelsPerInch;
672 break;
673 case CSS_PT:
674 factor = cssPixelsPerPoint;
675 break;
676 case CSS_PC:
677 factor = cssPixelsPerPica;
678 break;
679 case CSS_RAD:
680 factor = 180 / piDouble;
681 break;
682 case CSS_GRAD:
683 factor = 0.9;
684 break;
685 case CSS_TURN:
686 factor = 360;
687 break;
688 case CSS_S:
689 case CSS_KHZ:
690 factor = 1000;
691 break;
692 default:
693 break;
696 return factor;
699 Length CSSPrimitiveValue::convertToLength(const CSSToLengthConversionData& conversionData)
701 if (isLength())
702 return computeLength<Length>(conversionData);
703 if (isPercentage())
704 return Length(getDoubleValue(), Percent);
705 ASSERT(isCalculated());
706 return Length(cssCalcValue()->toCalcValue(conversionData));
709 double CSSPrimitiveValue::getDoubleValue() const
711 return m_primitiveUnitType != CSS_CALC ? m_value.num : m_value.calc->doubleValue();
714 CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
716 // The canonical unit type is chosen according to the way CSSPropertyParser::validUnit() chooses the default unit
717 // in each category (based on unitflags).
718 switch (category) {
719 case UNumber:
720 return CSS_NUMBER;
721 case ULength:
722 return CSS_PX;
723 case UPercent:
724 return CSS_UNKNOWN; // Cannot convert between numbers and percent.
725 case UTime:
726 return CSS_MS;
727 case UAngle:
728 return CSS_DEG;
729 case UFrequency:
730 return CSS_HZ;
731 case UResolution:
732 return CSS_DPPX;
733 default:
734 return CSS_UNKNOWN;
738 bool CSSPrimitiveValue::unitTypeToLengthUnitType(UnitType unitType, LengthUnitType& lengthType)
740 switch (unitType) {
741 case CSSPrimitiveValue::CSS_PX:
742 case CSSPrimitiveValue::CSS_CM:
743 case CSSPrimitiveValue::CSS_MM:
744 case CSSPrimitiveValue::CSS_IN:
745 case CSSPrimitiveValue::CSS_PT:
746 case CSSPrimitiveValue::CSS_PC:
747 lengthType = UnitTypePixels;
748 return true;
749 case CSSPrimitiveValue::CSS_EMS:
750 lengthType = UnitTypeFontSize;
751 return true;
752 case CSSPrimitiveValue::CSS_EXS:
753 lengthType = UnitTypeFontXSize;
754 return true;
755 case CSSPrimitiveValue::CSS_REMS:
756 lengthType = UnitTypeRootFontSize;
757 return true;
758 case CSSPrimitiveValue::CSS_CHS:
759 lengthType = UnitTypeZeroCharacterWidth;
760 return true;
761 case CSSPrimitiveValue::CSS_PERCENTAGE:
762 lengthType = UnitTypePercentage;
763 return true;
764 case CSSPrimitiveValue::CSS_VW:
765 lengthType = UnitTypeViewportWidth;
766 return true;
767 case CSSPrimitiveValue::CSS_VH:
768 lengthType = UnitTypeViewportHeight;
769 return true;
770 case CSSPrimitiveValue::CSS_VMIN:
771 lengthType = UnitTypeViewportMin;
772 return true;
773 case CSSPrimitiveValue::CSS_VMAX:
774 lengthType = UnitTypeViewportMax;
775 return true;
776 default:
777 return false;
781 CSSPrimitiveValue::UnitType CSSPrimitiveValue::lengthUnitTypeToUnitType(LengthUnitType type)
783 switch (type) {
784 case UnitTypePixels:
785 return CSSPrimitiveValue::CSS_PX;
786 case UnitTypeFontSize:
787 return CSSPrimitiveValue::CSS_EMS;
788 case UnitTypeFontXSize:
789 return CSSPrimitiveValue::CSS_EXS;
790 case UnitTypeRootFontSize:
791 return CSSPrimitiveValue::CSS_REMS;
792 case UnitTypeZeroCharacterWidth:
793 return CSSPrimitiveValue::CSS_CHS;
794 case UnitTypePercentage:
795 return CSSPrimitiveValue::CSS_PERCENTAGE;
796 case UnitTypeViewportWidth:
797 return CSSPrimitiveValue::CSS_VW;
798 case UnitTypeViewportHeight:
799 return CSSPrimitiveValue::CSS_VH;
800 case UnitTypeViewportMin:
801 return CSSPrimitiveValue::CSS_VMIN;
802 case UnitTypeViewportMax:
803 return CSSPrimitiveValue::CSS_VMAX;
804 case LengthUnitTypeCount:
805 break;
807 ASSERT_NOT_REACHED();
808 return CSSPrimitiveValue::CSS_UNKNOWN;
811 String CSSPrimitiveValue::getStringValue() const
813 switch (m_primitiveUnitType) {
814 case CSS_CUSTOM_IDENT:
815 case CSS_STRING:
816 case CSS_ATTR:
817 case CSS_URI:
818 return m_value.string;
819 case CSS_VALUE_ID:
820 return valueName(m_value.valueID);
821 case CSS_PROPERTY_ID:
822 return propertyName(m_value.propertyID);
823 default:
824 break;
827 return String();
830 static String formatNumber(double number, const char* suffix, unsigned suffixLength)
832 #if OS(WIN) && _MSC_VER < 1900
833 unsigned oldFormat = _set_output_format(_TWO_DIGIT_EXPONENT);
834 #endif
835 String result = String::format("%.6g", number);
836 #if OS(WIN) && _MSC_VER < 1900
837 _set_output_format(oldFormat);
838 #endif
839 result.append(suffix, suffixLength);
840 return result;
843 template <unsigned characterCount>
844 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount])
846 return formatNumber(number, characters, characterCount - 1);
849 static String formatNumber(double number, const char* characters)
851 return formatNumber(number, characters, strlen(characters));
854 const char* CSSPrimitiveValue::unitTypeToString(UnitType type)
856 switch (type) {
857 case CSS_NUMBER:
858 case CSS_INTEGER:
859 return "";
860 case CSS_PERCENTAGE:
861 return "%";
862 case CSS_EMS:
863 return "em";
864 case CSS_EXS:
865 return "ex";
866 case CSS_REMS:
867 return "rem";
868 case CSS_CHS:
869 return "ch";
870 case CSS_PX:
871 return "px";
872 case CSS_CM:
873 return "cm";
874 case CSS_DPPX:
875 return "dppx";
876 case CSS_DPI:
877 return "dpi";
878 case CSS_DPCM:
879 return "dpcm";
880 case CSS_MM:
881 return "mm";
882 case CSS_IN:
883 return "in";
884 case CSS_PT:
885 return "pt";
886 case CSS_PC:
887 return "pc";
888 case CSS_DEG:
889 return "deg";
890 case CSS_RAD:
891 return "rad";
892 case CSS_GRAD:
893 return "grad";
894 case CSS_MS:
895 return "ms";
896 case CSS_S:
897 return "s";
898 case CSS_HZ:
899 return "hz";
900 case CSS_KHZ:
901 return "khz";
902 case CSS_TURN:
903 return "turn";
904 case CSS_FR:
905 return "fr";
906 case CSS_VW:
907 return "vw";
908 case CSS_VH:
909 return "vh";
910 case CSS_VMIN:
911 return "vmin";
912 case CSS_VMAX:
913 return "vmax";
914 case CSS_UNKNOWN:
915 case CSS_CUSTOM_IDENT:
916 case CSS_STRING:
917 case CSS_URI:
918 case CSS_VALUE_ID:
919 case CSS_PROPERTY_ID:
920 case CSS_ATTR:
921 case CSS_COUNTER:
922 case CSS_RECT:
923 case CSS_QUAD:
924 case CSS_RGBCOLOR:
925 case CSS_PAIR:
926 case CSS_CALC:
927 case CSS_SHAPE:
928 case CSS_IDENT:
929 case CSS_CALC_PERCENTAGE_WITH_NUMBER:
930 case CSS_CALC_PERCENTAGE_WITH_LENGTH:
931 case CSS_QEM:
932 break;
934 ASSERT_NOT_REACHED();
935 return "";
938 String CSSPrimitiveValue::customCSSText() const
940 if (m_hasCachedCSSText) {
941 ASSERT(cssTextCache().contains(this));
942 return cssTextCache().get(this);
945 String text;
946 switch (m_primitiveUnitType) {
947 case CSS_UNKNOWN:
948 // FIXME
949 break;
950 case CSS_INTEGER:
951 text = String::format("%d", getIntValue());
952 break;
953 case CSS_NUMBER:
954 case CSS_PERCENTAGE:
955 case CSS_EMS:
956 case CSS_EXS:
957 case CSS_REMS:
958 case CSS_CHS:
959 case CSS_PX:
960 case CSS_CM:
961 case CSS_DPPX:
962 case CSS_DPI:
963 case CSS_DPCM:
964 case CSS_MM:
965 case CSS_IN:
966 case CSS_PT:
967 case CSS_PC:
968 case CSS_DEG:
969 case CSS_RAD:
970 case CSS_GRAD:
971 case CSS_MS:
972 case CSS_S:
973 case CSS_HZ:
974 case CSS_KHZ:
975 case CSS_TURN:
976 case CSS_FR:
977 case CSS_VW:
978 case CSS_VH:
979 case CSS_VMIN:
980 case CSS_VMAX:
981 text = formatNumber(m_value.num, unitTypeToString((UnitType)m_primitiveUnitType));
982 break;
983 case CSS_CUSTOM_IDENT:
984 text = quoteCSSStringIfNeeded(m_value.string);
985 break;
986 case CSS_STRING: {
987 text = serializeString(m_value.string);
988 break;
990 case CSS_URI:
991 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
992 break;
993 case CSS_VALUE_ID:
994 text = valueName(m_value.valueID);
995 break;
996 case CSS_PROPERTY_ID:
997 text = propertyName(m_value.propertyID);
998 break;
999 case CSS_ATTR: {
1000 StringBuilder result;
1001 result.reserveCapacity(6 + m_value.string->length());
1002 result.appendLiteral("attr(");
1003 result.append(m_value.string);
1004 result.append(')');
1006 text = result.toString();
1007 break;
1009 case CSS_COUNTER: {
1010 StringBuilder result;
1011 String separator = m_value.counter->separator();
1012 if (separator.isEmpty())
1013 result.appendLiteral("counter(");
1014 else
1015 result.appendLiteral("counters(");
1017 result.append(m_value.counter->identifier());
1018 if (!separator.isEmpty()) {
1019 result.appendLiteral(", ");
1020 result.append(serializeString(separator));
1022 String listStyle = m_value.counter->listStyle();
1023 bool isDefaultListStyle = m_value.counter->listStyleIdent() == CSSValueDecimal;
1024 if (!listStyle.isEmpty() && !isDefaultListStyle) {
1025 result.appendLiteral(", ");
1026 result.append(listStyle);
1028 result.append(')');
1030 text = result.toString();
1031 break;
1033 case CSS_RECT:
1034 text = getRectValue()->cssText();
1035 break;
1036 case CSS_QUAD:
1037 text = getQuadValue()->cssText();
1038 break;
1039 case CSS_RGBCOLOR: {
1040 text = Color(m_value.rgbcolor).serializedAsCSSComponentValue();
1041 break;
1043 case CSS_PAIR:
1044 text = getPairValue()->cssText();
1045 break;
1046 case CSS_CALC:
1047 text = m_value.calc->cssText();
1048 break;
1049 case CSS_SHAPE:
1050 text = m_value.shape->cssText();
1051 break;
1054 ASSERT(!cssTextCache().contains(this));
1055 cssTextCache().set(this, text);
1056 m_hasCachedCSSText = true;
1057 return text;
1060 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
1062 if (m_primitiveUnitType != other.m_primitiveUnitType)
1063 return false;
1065 switch (m_primitiveUnitType) {
1066 case CSS_UNKNOWN:
1067 return false;
1068 case CSS_NUMBER:
1069 case CSS_PERCENTAGE:
1070 case CSS_EMS:
1071 case CSS_EXS:
1072 case CSS_REMS:
1073 case CSS_PX:
1074 case CSS_CM:
1075 case CSS_DPPX:
1076 case CSS_DPI:
1077 case CSS_DPCM:
1078 case CSS_MM:
1079 case CSS_IN:
1080 case CSS_PT:
1081 case CSS_PC:
1082 case CSS_DEG:
1083 case CSS_RAD:
1084 case CSS_GRAD:
1085 case CSS_MS:
1086 case CSS_S:
1087 case CSS_HZ:
1088 case CSS_KHZ:
1089 case CSS_TURN:
1090 case CSS_VW:
1091 case CSS_VH:
1092 case CSS_VMIN:
1093 case CSS_VMAX:
1094 case CSS_FR:
1095 return m_value.num == other.m_value.num;
1096 case CSS_PROPERTY_ID:
1097 return m_value.propertyID == other.m_value.propertyID;
1098 case CSS_VALUE_ID:
1099 return m_value.valueID == other.m_value.valueID;
1100 case CSS_CUSTOM_IDENT:
1101 case CSS_STRING:
1102 case CSS_URI:
1103 case CSS_ATTR:
1104 return equal(m_value.string, other.m_value.string);
1105 case CSS_COUNTER:
1106 return m_value.counter && other.m_value.counter && m_value.counter->equals(*other.m_value.counter);
1107 case CSS_RECT:
1108 return m_value.rect && other.m_value.rect && m_value.rect->equals(*other.m_value.rect);
1109 case CSS_QUAD:
1110 return m_value.quad && other.m_value.quad && m_value.quad->equals(*other.m_value.quad);
1111 case CSS_RGBCOLOR:
1112 return m_value.rgbcolor == other.m_value.rgbcolor;
1113 case CSS_PAIR:
1114 return m_value.pair && other.m_value.pair && m_value.pair->equals(*other.m_value.pair);
1115 case CSS_CALC:
1116 return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
1117 case CSS_SHAPE:
1118 return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
1120 return false;
1123 DEFINE_TRACE_AFTER_DISPATCH(CSSPrimitiveValue)
1125 #if ENABLE(OILPAN)
1126 switch (m_primitiveUnitType) {
1127 case CSS_COUNTER:
1128 visitor->trace(m_value.counter);
1129 break;
1130 case CSS_RECT:
1131 visitor->trace(m_value.rect);
1132 break;
1133 case CSS_QUAD:
1134 visitor->trace(m_value.quad);
1135 break;
1136 case CSS_PAIR:
1137 visitor->trace(m_value.pair);
1138 break;
1139 case CSS_CALC:
1140 visitor->trace(m_value.calc);
1141 break;
1142 case CSS_SHAPE:
1143 visitor->trace(m_value.shape);
1144 break;
1145 default:
1146 break;
1148 #endif
1149 CSSValue::traceAfterDispatch(visitor);
1152 } // namespace blink