Oilpan: fix build after r202625.
[chromium-blink-merge.git] / third_party / WebKit / Source / core / css / CSSPrimitiveValue.cpp
blobf862828c1ff50e89566563ea50ef2a67a3804bf3
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/StyleSheetContents.h"
30 #include "core/dom/Node.h"
31 #include "core/style/ComputedStyle.h"
32 #include "platform/LayoutUnit.h"
33 #include "platform/fonts/FontMetrics.h"
34 #include "wtf/StdLibExtras.h"
35 #include "wtf/ThreadSpecific.h"
36 #include "wtf/Threading.h"
37 #include "wtf/text/StringBuffer.h"
38 #include "wtf/text/StringBuilder.h"
40 using namespace WTF;
42 namespace blink {
44 namespace {
46 // Max/min values for CSS, needs to slightly smaller/larger than the true max/min values to allow for rounding without overflowing.
47 // Subtract two (rather than one) to allow for values to be converted to float and back without exceeding the LayoutUnit::max.
48 const int maxValueForCssLength = INT_MAX / kFixedPointDenominator - 2;
49 const int minValueForCssLength = INT_MIN / kFixedPointDenominator + 2;
51 using StringToUnitTable = HashMap<String, CSSPrimitiveValue::UnitType>;
53 StringToUnitTable createStringToUnitTable()
55 StringToUnitTable table;
56 table.set(String("em"), CSSPrimitiveValue::UnitType::Ems);
57 table.set(String("ex"), CSSPrimitiveValue::UnitType::Exs);
58 table.set(String("px"), CSSPrimitiveValue::UnitType::Pixels);
59 table.set(String("cm"), CSSPrimitiveValue::UnitType::Centimeters);
60 table.set(String("mm"), CSSPrimitiveValue::UnitType::Millimeters);
61 table.set(String("in"), CSSPrimitiveValue::UnitType::Inches);
62 table.set(String("pt"), CSSPrimitiveValue::UnitType::Points);
63 table.set(String("pc"), CSSPrimitiveValue::UnitType::Picas);
64 table.set(String("deg"), CSSPrimitiveValue::UnitType::Degrees);
65 table.set(String("rad"), CSSPrimitiveValue::UnitType::Radians);
66 table.set(String("grad"), CSSPrimitiveValue::UnitType::Gradians);
67 table.set(String("ms"), CSSPrimitiveValue::UnitType::Milliseconds);
68 table.set(String("s"), CSSPrimitiveValue::UnitType::Seconds);
69 table.set(String("hz"), CSSPrimitiveValue::UnitType::Hertz);
70 table.set(String("khz"), CSSPrimitiveValue::UnitType::Kilohertz);
71 table.set(String("dpi"), CSSPrimitiveValue::UnitType::DotsPerInch);
72 table.set(String("dpcm"), CSSPrimitiveValue::UnitType::DotsPerCentimeter);
73 table.set(String("dppx"), CSSPrimitiveValue::UnitType::DotsPerPixel);
74 table.set(String("vw"), CSSPrimitiveValue::UnitType::ViewportWidth);
75 table.set(String("vh"), CSSPrimitiveValue::UnitType::ViewportHeight);
76 table.set(String("vmin"), CSSPrimitiveValue::UnitType::ViewportMin);
77 table.set(String("vmax"), CSSPrimitiveValue::UnitType::ViewportMax);
78 table.set(String("rem"), CSSPrimitiveValue::UnitType::Rems);
79 table.set(String("fr"), CSSPrimitiveValue::UnitType::Fraction);
80 table.set(String("turn"), CSSPrimitiveValue::UnitType::Turns);
81 table.set(String("ch"), CSSPrimitiveValue::UnitType::Chs);
82 table.set(String("__qem"), CSSPrimitiveValue::UnitType::QuirkyEms);
83 return table;
86 StringToUnitTable& unitTable()
88 DEFINE_STATIC_LOCAL(StringToUnitTable, unitTable, (createStringToUnitTable()));
89 return unitTable;
92 } // namespace
94 float CSSPrimitiveValue::clampToCSSLengthRange(double value)
96 return clampTo<float>(value, minValueForCssLength, maxValueForCssLength);
99 void CSSPrimitiveValue::initUnitTable()
101 // Make sure we initialize this during blink initialization
102 // to avoid racy static local initialization.
103 unitTable();
106 CSSPrimitiveValue::UnitType CSSPrimitiveValue::fromName(const String& unit)
108 return unitTable().get(unit.lower());
111 CSSPrimitiveValue::UnitCategory CSSPrimitiveValue::unitCategory(UnitType type)
113 switch (type) {
114 case UnitType::Number:
115 return CSSPrimitiveValue::UNumber;
116 case UnitType::Percentage:
117 return CSSPrimitiveValue::UPercent;
118 case UnitType::Pixels:
119 case UnitType::Centimeters:
120 case UnitType::Millimeters:
121 case UnitType::Inches:
122 case UnitType::Points:
123 case UnitType::Picas:
124 return CSSPrimitiveValue::ULength;
125 case UnitType::Milliseconds:
126 case UnitType::Seconds:
127 return CSSPrimitiveValue::UTime;
128 case UnitType::Degrees:
129 case UnitType::Radians:
130 case UnitType::Gradians:
131 case UnitType::Turns:
132 return CSSPrimitiveValue::UAngle;
133 case UnitType::Hertz:
134 case UnitType::Kilohertz:
135 return CSSPrimitiveValue::UFrequency;
136 case UnitType::DotsPerPixel:
137 case UnitType::DotsPerInch:
138 case UnitType::DotsPerCentimeter:
139 return CSSPrimitiveValue::UResolution;
140 default:
141 return CSSPrimitiveValue::UOther;
145 bool CSSPrimitiveValue::colorIsDerivedFromElement() const
147 int valueID = getValueID();
148 switch (valueID) {
149 case CSSValueWebkitText:
150 case CSSValueWebkitLink:
151 case CSSValueWebkitActivelink:
152 case CSSValueCurrentcolor:
153 return true;
154 default:
155 return false;
159 using CSSTextCache = HashMap<const CSSPrimitiveValue*, String>;
160 static CSSTextCache& cssTextCache()
162 AtomicallyInitializedStaticReference(ThreadSpecific<CSSTextCache>, cache, new ThreadSpecific<CSSTextCache>());
163 return *cache;
166 CSSPrimitiveValue::UnitType CSSPrimitiveValue::typeWithCalcResolved() const
168 if (type() != UnitType::Calc)
169 return type();
171 switch (m_value.calc->category()) {
172 case CalcAngle:
173 return UnitType::Degrees;
174 case CalcFrequency:
175 return UnitType::Hertz;
176 case CalcNumber:
177 return UnitType::Number;
178 case CalcPercent:
179 return UnitType::Percentage;
180 case CalcLength:
181 return UnitType::Pixels;
182 case CalcPercentNumber:
183 return UnitType::CalcPercentageWithNumber;
184 case CalcPercentLength:
185 return UnitType::CalcPercentageWithLength;
186 case CalcTime:
187 return UnitType::Milliseconds;
188 case CalcOther:
189 return UnitType::Unknown;
191 return UnitType::Unknown;
194 static const AtomicString& propertyName(CSSPropertyID propertyID)
196 return getPropertyNameAtomicString(propertyID);
199 static const AtomicString& valueName(CSSValueID valueID)
201 ASSERT_ARG(valueID, valueID >= 0);
202 ASSERT_ARG(valueID, valueID < numCSSValueKeywords);
204 if (valueID < 0)
205 return nullAtom;
207 static AtomicString* keywordStrings = new AtomicString[numCSSValueKeywords]; // Leaked intentionally.
208 AtomicString& keywordString = keywordStrings[valueID];
209 if (keywordString.isNull())
210 keywordString = getValueName(valueID);
211 return keywordString;
214 CSSPrimitiveValue::CSSPrimitiveValue(CSSValueID valueID)
215 : CSSValue(PrimitiveClass)
217 init(UnitType::ValueID);
218 m_value.valueID = valueID;
221 CSSPrimitiveValue::CSSPrimitiveValue(CSSPropertyID propertyID)
222 : CSSValue(PrimitiveClass)
224 init(UnitType::PropertyID);
225 m_value.propertyID = propertyID;
228 CSSPrimitiveValue::CSSPrimitiveValue(double num, UnitType type)
229 : CSSValue(PrimitiveClass)
231 init(type);
232 ASSERT(std::isfinite(num));
233 m_value.num = num;
236 CSSPrimitiveValue::CSSPrimitiveValue(const String& str, UnitType type)
237 : CSSValue(PrimitiveClass)
239 init(type);
240 m_value.string = str.impl();
241 if (m_value.string)
242 m_value.string->ref();
245 CSSPrimitiveValue::CSSPrimitiveValue(RGBA32 color)
246 : CSSValue(PrimitiveClass)
248 init(UnitType::RGBColor);
249 m_value.rgbcolor = color;
252 CSSPrimitiveValue::CSSPrimitiveValue(const Length& length, float zoom)
253 : CSSValue(PrimitiveClass)
255 switch (length.type()) {
256 case Auto:
257 init(UnitType::ValueID);
258 m_value.valueID = CSSValueAuto;
259 break;
260 case Intrinsic:
261 init(UnitType::ValueID);
262 m_value.valueID = CSSValueIntrinsic;
263 break;
264 case MinIntrinsic:
265 init(UnitType::ValueID);
266 m_value.valueID = CSSValueMinIntrinsic;
267 break;
268 case MinContent:
269 init(UnitType::ValueID);
270 m_value.valueID = CSSValueMinContent;
271 break;
272 case MaxContent:
273 init(UnitType::ValueID);
274 m_value.valueID = CSSValueMaxContent;
275 break;
276 case FillAvailable:
277 init(UnitType::ValueID);
278 m_value.valueID = CSSValueWebkitFillAvailable;
279 break;
280 case FitContent:
281 init(UnitType::ValueID);
282 m_value.valueID = CSSValueFitContent;
283 break;
284 case ExtendToZoom:
285 init(UnitType::ValueID);
286 m_value.valueID = CSSValueInternalExtendToZoom;
287 break;
288 case Percent:
289 init(UnitType::Percentage);
290 ASSERT(std::isfinite(length.percent()));
291 m_value.num = length.percent();
292 break;
293 case Fixed:
294 init(UnitType::Pixels);
295 m_value.num = length.value() / zoom;
296 break;
297 case Calculated: {
298 const CalculationValue& calc = length.calculationValue();
299 if (calc.pixels() && calc.percent()) {
300 init(CSSCalcValue::create(
301 CSSCalcValue::createExpressionNode(calc.pixels() / zoom, calc.percent()),
302 calc.valueRange()));
303 break;
305 if (calc.percent()) {
306 init(UnitType::Percentage);
307 m_value.num = calc.percent();
308 } else {
309 init(UnitType::Pixels);
310 m_value.num = calc.pixels() / zoom;
312 if (m_value.num < 0 && calc.isNonNegative())
313 m_value.num = 0;
314 break;
316 case DeviceWidth:
317 case DeviceHeight:
318 case MaxSizeNone:
319 ASSERT_NOT_REACHED();
320 break;
324 void CSSPrimitiveValue::init(UnitType type)
326 m_primitiveUnitType = static_cast<unsigned>(type);
329 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSCalcValue> c)
331 init(UnitType::Calc);
332 m_hasCachedCSSText = false;
333 m_value.calc = c.leakRef();
336 void CSSPrimitiveValue::init(PassRefPtrWillBeRawPtr<CSSBasicShape> shape)
338 init(UnitType::Shape);
339 m_hasCachedCSSText = false;
340 m_value.shape = shape.leakRef();
343 CSSPrimitiveValue::~CSSPrimitiveValue()
345 cleanup();
348 void CSSPrimitiveValue::cleanup()
350 switch (type()) {
351 case UnitType::CustomIdentifier:
352 case UnitType::String:
353 case UnitType::URI:
354 if (m_value.string)
355 m_value.string->deref();
356 break;
357 case UnitType::Calc:
358 // We must not call deref() when oilpan is enabled because m_value.calc is traced.
359 #if !ENABLE(OILPAN)
360 m_value.calc->deref();
361 #endif
362 break;
363 case UnitType::CalcPercentageWithNumber:
364 case UnitType::CalcPercentageWithLength:
365 ASSERT_NOT_REACHED();
366 break;
367 case UnitType::Shape:
368 // We must not call deref() when oilpan is enabled because m_value.shape is traced.
369 #if !ENABLE(OILPAN)
370 m_value.shape->deref();
371 #endif
372 break;
373 case UnitType::Number:
374 case UnitType::Integer:
375 case UnitType::Percentage:
376 case UnitType::Ems:
377 case UnitType::QuirkyEms:
378 case UnitType::Exs:
379 case UnitType::Rems:
380 case UnitType::Chs:
381 case UnitType::Pixels:
382 case UnitType::Centimeters:
383 case UnitType::Millimeters:
384 case UnitType::Inches:
385 case UnitType::Points:
386 case UnitType::Picas:
387 case UnitType::Degrees:
388 case UnitType::Radians:
389 case UnitType::Gradians:
390 case UnitType::Milliseconds:
391 case UnitType::Seconds:
392 case UnitType::Hertz:
393 case UnitType::Kilohertz:
394 case UnitType::Turns:
395 case UnitType::ViewportWidth:
396 case UnitType::ViewportHeight:
397 case UnitType::ViewportMin:
398 case UnitType::ViewportMax:
399 case UnitType::DotsPerPixel:
400 case UnitType::DotsPerInch:
401 case UnitType::DotsPerCentimeter:
402 case UnitType::Fraction:
403 case UnitType::RGBColor:
404 case UnitType::Unknown:
405 case UnitType::PropertyID:
406 case UnitType::ValueID:
407 break;
409 if (m_hasCachedCSSText) {
410 cssTextCache().remove(this);
411 m_hasCachedCSSText = false;
415 double CSSPrimitiveValue::computeSeconds() const
417 ASSERT(isTime() || (isCalculated() && cssCalcValue()->category() == CalcTime));
418 UnitType currentType = isCalculated() ? cssCalcValue()->expressionNode()->typeWithCalcResolved() : type();
419 if (currentType == UnitType::Seconds)
420 return getDoubleValue();
421 if (currentType == UnitType::Milliseconds)
422 return getDoubleValue() / 1000;
423 ASSERT_NOT_REACHED();
424 return 0;
427 double CSSPrimitiveValue::computeDegrees() const
429 ASSERT(isAngle() || (isCalculated() && cssCalcValue()->category() == CalcAngle));
430 UnitType currentType = isCalculated() ? cssCalcValue()->expressionNode()->typeWithCalcResolved() : type();
431 switch (currentType) {
432 case UnitType::Degrees:
433 return getDoubleValue();
434 case UnitType::Radians:
435 return rad2deg(getDoubleValue());
436 case UnitType::Gradians:
437 return grad2deg(getDoubleValue());
438 case UnitType::Turns:
439 return turn2deg(getDoubleValue());
440 default:
441 ASSERT_NOT_REACHED();
442 return 0;
446 template<> int CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
448 return roundForImpreciseConversion<int>(computeLengthDouble(conversionData));
451 template<> unsigned CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
453 return roundForImpreciseConversion<unsigned>(computeLengthDouble(conversionData));
456 template<> Length CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
458 return Length(clampToCSSLengthRange(computeLengthDouble(conversionData)), Fixed);
461 template<> short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
463 return roundForImpreciseConversion<short>(computeLengthDouble(conversionData));
466 template<> unsigned short CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
468 return roundForImpreciseConversion<unsigned short>(computeLengthDouble(conversionData));
471 template<> float CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
473 return static_cast<float>(computeLengthDouble(conversionData));
476 template<> double CSSPrimitiveValue::computeLength(const CSSToLengthConversionData& conversionData) const
478 return computeLengthDouble(conversionData);
481 double CSSPrimitiveValue::computeLengthDouble(const CSSToLengthConversionData& conversionData) const
483 // The logic in this function is duplicated in MediaValues::computeLength
484 // because MediaValues::computeLength needs nearly identical logic, but we haven't found a way to make
485 // CSSPrimitiveValue::computeLengthDouble more generic (to solve both cases) without hurting performance.
486 if (type() == UnitType::Calc)
487 return m_value.calc->computeLengthPx(conversionData);
489 double factor;
491 switch (type()) {
492 case UnitType::Ems:
493 case UnitType::QuirkyEms:
494 factor = conversionData.emFontSize();
495 break;
496 case UnitType::Exs:
497 factor = conversionData.exFontSize();
498 break;
499 case UnitType::Rems:
500 factor = conversionData.remFontSize();
501 break;
502 case UnitType::Chs:
503 factor = conversionData.chFontSize();
504 break;
505 case UnitType::Pixels:
506 factor = 1.0;
507 break;
508 case UnitType::Centimeters:
509 factor = cssPixelsPerCentimeter;
510 break;
511 case UnitType::Millimeters:
512 factor = cssPixelsPerMillimeter;
513 break;
514 case UnitType::Inches:
515 factor = cssPixelsPerInch;
516 break;
517 case UnitType::Points:
518 factor = cssPixelsPerPoint;
519 break;
520 case UnitType::Picas:
521 factor = cssPixelsPerPica;
522 break;
523 case UnitType::ViewportWidth:
524 factor = conversionData.viewportWidthPercent();
525 break;
526 case UnitType::ViewportHeight:
527 factor = conversionData.viewportHeightPercent();
528 break;
529 case UnitType::ViewportMin:
530 factor = conversionData.viewportMinPercent();
531 break;
532 case UnitType::ViewportMax:
533 factor = conversionData.viewportMaxPercent();
534 break;
535 case UnitType::CalcPercentageWithLength:
536 case UnitType::CalcPercentageWithNumber:
537 ASSERT_NOT_REACHED();
538 return -1.0;
539 default:
540 ASSERT_NOT_REACHED();
541 return -1.0;
544 // We do not apply the zoom factor when we are computing the value of the font-size property. The zooming
545 // for font sizes is much more complicated, since we have to worry about enforcing the minimum font size preference
546 // as well as enforcing the implicit "smart minimum."
547 double result = getDoubleValue() * factor;
548 if (isFontRelativeLength())
549 return result;
551 return result * conversionData.zoom();
554 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, CSSLengthTypeArray& lengthTypeArray, double multiplier) const
556 ASSERT(lengthArray.size() == LengthUnitTypeCount);
558 if (type() == UnitType::Calc) {
559 cssCalcValue()->accumulateLengthArray(lengthArray, lengthTypeArray, multiplier);
560 return;
563 LengthUnitType lengthType;
564 if (unitTypeToLengthUnitType(type(), lengthType)) {
565 lengthArray.at(lengthType) += m_value.num * conversionToCanonicalUnitsScaleFactor(type()) * multiplier;
566 lengthTypeArray.set(lengthType);
570 void CSSPrimitiveValue::accumulateLengthArray(CSSLengthArray& lengthArray, double multiplier) const
572 CSSLengthTypeArray lengthTypeArray;
573 lengthTypeArray.resize(CSSPrimitiveValue::LengthUnitTypeCount);
574 for (size_t i = 0; i < CSSPrimitiveValue::LengthUnitTypeCount; ++i)
575 lengthTypeArray.clear(i);
576 return CSSPrimitiveValue::accumulateLengthArray(lengthArray, lengthTypeArray, multiplier);
579 double CSSPrimitiveValue::conversionToCanonicalUnitsScaleFactor(UnitType unitType)
581 double factor = 1.0;
582 // FIXME: the switch can be replaced by an array of scale factors.
583 switch (unitType) {
584 // These are "canonical" units in their respective categories.
585 case UnitType::Pixels:
586 case UnitType::Degrees:
587 case UnitType::Milliseconds:
588 case UnitType::Hertz:
589 break;
590 case UnitType::Centimeters:
591 factor = cssPixelsPerCentimeter;
592 break;
593 case UnitType::DotsPerCentimeter:
594 factor = 1 / cssPixelsPerCentimeter;
595 break;
596 case UnitType::Millimeters:
597 factor = cssPixelsPerMillimeter;
598 break;
599 case UnitType::Inches:
600 factor = cssPixelsPerInch;
601 break;
602 case UnitType::DotsPerInch:
603 factor = 1 / cssPixelsPerInch;
604 break;
605 case UnitType::Points:
606 factor = cssPixelsPerPoint;
607 break;
608 case UnitType::Picas:
609 factor = cssPixelsPerPica;
610 break;
611 case UnitType::Radians:
612 factor = 180 / piDouble;
613 break;
614 case UnitType::Gradians:
615 factor = 0.9;
616 break;
617 case UnitType::Turns:
618 factor = 360;
619 break;
620 case UnitType::Seconds:
621 case UnitType::Kilohertz:
622 factor = 1000;
623 break;
624 default:
625 break;
628 return factor;
631 Length CSSPrimitiveValue::convertToLength(const CSSToLengthConversionData& conversionData) const
633 if (isLength())
634 return computeLength<Length>(conversionData);
635 if (isPercentage())
636 return Length(getDoubleValue(), Percent);
637 ASSERT(isCalculated());
638 return Length(cssCalcValue()->toCalcValue(conversionData));
641 double CSSPrimitiveValue::getDoubleValue() const
643 return type() != UnitType::Calc ? m_value.num : m_value.calc->doubleValue();
646 CSSPrimitiveValue::UnitType CSSPrimitiveValue::canonicalUnitTypeForCategory(UnitCategory category)
648 // The canonical unit type is chosen according to the way CSSPropertyParser::validUnit() chooses the default unit
649 // in each category (based on unitflags).
650 switch (category) {
651 case UNumber:
652 return UnitType::Number;
653 case ULength:
654 return UnitType::Pixels;
655 case UPercent:
656 return UnitType::Unknown; // Cannot convert between numbers and percent.
657 case UTime:
658 return UnitType::Milliseconds;
659 case UAngle:
660 return UnitType::Degrees;
661 case UFrequency:
662 return UnitType::Hertz;
663 case UResolution:
664 return UnitType::DotsPerPixel;
665 default:
666 return UnitType::Unknown;
670 bool CSSPrimitiveValue::unitTypeToLengthUnitType(UnitType unitType, LengthUnitType& lengthType)
672 switch (unitType) {
673 case CSSPrimitiveValue::UnitType::Pixels:
674 case CSSPrimitiveValue::UnitType::Centimeters:
675 case CSSPrimitiveValue::UnitType::Millimeters:
676 case CSSPrimitiveValue::UnitType::Inches:
677 case CSSPrimitiveValue::UnitType::Points:
678 case CSSPrimitiveValue::UnitType::Picas:
679 lengthType = UnitTypePixels;
680 return true;
681 case CSSPrimitiveValue::UnitType::Ems:
682 case CSSPrimitiveValue::UnitType::QuirkyEms:
683 lengthType = UnitTypeFontSize;
684 return true;
685 case CSSPrimitiveValue::UnitType::Exs:
686 lengthType = UnitTypeFontXSize;
687 return true;
688 case CSSPrimitiveValue::UnitType::Rems:
689 lengthType = UnitTypeRootFontSize;
690 return true;
691 case CSSPrimitiveValue::UnitType::Chs:
692 lengthType = UnitTypeZeroCharacterWidth;
693 return true;
694 case CSSPrimitiveValue::UnitType::Percentage:
695 lengthType = UnitTypePercentage;
696 return true;
697 case CSSPrimitiveValue::UnitType::ViewportWidth:
698 lengthType = UnitTypeViewportWidth;
699 return true;
700 case CSSPrimitiveValue::UnitType::ViewportHeight:
701 lengthType = UnitTypeViewportHeight;
702 return true;
703 case CSSPrimitiveValue::UnitType::ViewportMin:
704 lengthType = UnitTypeViewportMin;
705 return true;
706 case CSSPrimitiveValue::UnitType::ViewportMax:
707 lengthType = UnitTypeViewportMax;
708 return true;
709 default:
710 return false;
714 CSSPrimitiveValue::UnitType CSSPrimitiveValue::lengthUnitTypeToUnitType(LengthUnitType type)
716 switch (type) {
717 case UnitTypePixels:
718 return CSSPrimitiveValue::UnitType::Pixels;
719 case UnitTypeFontSize:
720 return CSSPrimitiveValue::UnitType::Ems;
721 case UnitTypeFontXSize:
722 return CSSPrimitiveValue::UnitType::Exs;
723 case UnitTypeRootFontSize:
724 return CSSPrimitiveValue::UnitType::Rems;
725 case UnitTypeZeroCharacterWidth:
726 return CSSPrimitiveValue::UnitType::Chs;
727 case UnitTypePercentage:
728 return CSSPrimitiveValue::UnitType::Percentage;
729 case UnitTypeViewportWidth:
730 return CSSPrimitiveValue::UnitType::ViewportWidth;
731 case UnitTypeViewportHeight:
732 return CSSPrimitiveValue::UnitType::ViewportHeight;
733 case UnitTypeViewportMin:
734 return CSSPrimitiveValue::UnitType::ViewportMin;
735 case UnitTypeViewportMax:
736 return CSSPrimitiveValue::UnitType::ViewportMax;
737 case LengthUnitTypeCount:
738 break;
740 ASSERT_NOT_REACHED();
741 return CSSPrimitiveValue::UnitType::Unknown;
744 String CSSPrimitiveValue::getStringValue() const
746 switch (type()) {
747 case UnitType::CustomIdentifier:
748 case UnitType::String:
749 case UnitType::URI:
750 return m_value.string;
751 default:
752 break;
755 ASSERT_NOT_REACHED();
756 return String();
759 static String formatNumber(double number, const char* suffix, unsigned suffixLength)
761 #if OS(WIN) && _MSC_VER < 1900
762 unsigned oldFormat = _set_output_format(_TWO_DIGIT_EXPONENT);
763 #endif
764 String result = String::format("%.6g", number);
765 #if OS(WIN) && _MSC_VER < 1900
766 _set_output_format(oldFormat);
767 #endif
768 result.append(suffix, suffixLength);
769 return result;
772 template <unsigned characterCount>
773 ALWAYS_INLINE static String formatNumber(double number, const char (&characters)[characterCount])
775 return formatNumber(number, characters, characterCount - 1);
778 static String formatNumber(double number, const char* characters)
780 return formatNumber(number, characters, strlen(characters));
783 const char* CSSPrimitiveValue::unitTypeToString(UnitType type)
785 switch (type) {
786 case UnitType::Number:
787 case UnitType::Integer:
788 return "";
789 case UnitType::Percentage:
790 return "%";
791 case UnitType::Ems:
792 case UnitType::QuirkyEms:
793 return "em";
794 case UnitType::Exs:
795 return "ex";
796 case UnitType::Rems:
797 return "rem";
798 case UnitType::Chs:
799 return "ch";
800 case UnitType::Pixels:
801 return "px";
802 case UnitType::Centimeters:
803 return "cm";
804 case UnitType::DotsPerPixel:
805 return "dppx";
806 case UnitType::DotsPerInch:
807 return "dpi";
808 case UnitType::DotsPerCentimeter:
809 return "dpcm";
810 case UnitType::Millimeters:
811 return "mm";
812 case UnitType::Inches:
813 return "in";
814 case UnitType::Points:
815 return "pt";
816 case UnitType::Picas:
817 return "pc";
818 case UnitType::Degrees:
819 return "deg";
820 case UnitType::Radians:
821 return "rad";
822 case UnitType::Gradians:
823 return "grad";
824 case UnitType::Milliseconds:
825 return "ms";
826 case UnitType::Seconds:
827 return "s";
828 case UnitType::Hertz:
829 return "hz";
830 case UnitType::Kilohertz:
831 return "khz";
832 case UnitType::Turns:
833 return "turn";
834 case UnitType::Fraction:
835 return "fr";
836 case UnitType::ViewportWidth:
837 return "vw";
838 case UnitType::ViewportHeight:
839 return "vh";
840 case UnitType::ViewportMin:
841 return "vmin";
842 case UnitType::ViewportMax:
843 return "vmax";
844 case UnitType::Unknown:
845 case UnitType::CustomIdentifier:
846 case UnitType::String:
847 case UnitType::URI:
848 case UnitType::ValueID:
849 case UnitType::PropertyID:
850 case UnitType::RGBColor:
851 case UnitType::Calc:
852 case UnitType::Shape:
853 case UnitType::CalcPercentageWithNumber:
854 case UnitType::CalcPercentageWithLength:
855 break;
857 ASSERT_NOT_REACHED();
858 return "";
861 String CSSPrimitiveValue::customCSSText() const
863 if (m_hasCachedCSSText) {
864 ASSERT(cssTextCache().contains(this));
865 return cssTextCache().get(this);
868 String text;
869 switch (type()) {
870 case UnitType::Unknown:
871 // FIXME
872 break;
873 case UnitType::Integer:
874 text = String::format("%d", getIntValue());
875 break;
876 case UnitType::Number:
877 case UnitType::Percentage:
878 case UnitType::Ems:
879 case UnitType::QuirkyEms:
880 case UnitType::Exs:
881 case UnitType::Rems:
882 case UnitType::Chs:
883 case UnitType::Pixels:
884 case UnitType::Centimeters:
885 case UnitType::DotsPerPixel:
886 case UnitType::DotsPerInch:
887 case UnitType::DotsPerCentimeter:
888 case UnitType::Millimeters:
889 case UnitType::Inches:
890 case UnitType::Points:
891 case UnitType::Picas:
892 case UnitType::Degrees:
893 case UnitType::Radians:
894 case UnitType::Gradians:
895 case UnitType::Milliseconds:
896 case UnitType::Seconds:
897 case UnitType::Hertz:
898 case UnitType::Kilohertz:
899 case UnitType::Turns:
900 case UnitType::Fraction:
901 case UnitType::ViewportWidth:
902 case UnitType::ViewportHeight:
903 case UnitType::ViewportMin:
904 case UnitType::ViewportMax:
905 text = formatNumber(m_value.num, unitTypeToString(type()));
906 break;
907 case UnitType::CustomIdentifier:
908 text = quoteCSSStringIfNeeded(m_value.string);
909 break;
910 case UnitType::String: {
911 text = serializeString(m_value.string);
912 break;
914 case UnitType::URI:
915 text = "url(" + quoteCSSURLIfNeeded(m_value.string) + ")";
916 break;
917 case UnitType::ValueID:
918 text = valueName(m_value.valueID);
919 break;
920 case UnitType::PropertyID:
921 text = propertyName(m_value.propertyID);
922 break;
923 case UnitType::RGBColor: {
924 text = Color(m_value.rgbcolor).serializedAsCSSComponentValue();
925 break;
927 case UnitType::Calc:
928 text = m_value.calc->customCSSText();
929 break;
930 case UnitType::Shape:
931 text = m_value.shape->cssText();
932 break;
933 case UnitType::CalcPercentageWithNumber:
934 case UnitType::CalcPercentageWithLength:
935 ASSERT_NOT_REACHED();
936 break;
939 ASSERT(!cssTextCache().contains(this));
940 cssTextCache().set(this, text);
941 m_hasCachedCSSText = true;
942 return text;
945 bool CSSPrimitiveValue::equals(const CSSPrimitiveValue& other) const
947 if (type() != other.type())
948 return false;
950 switch (type()) {
951 case UnitType::Unknown:
952 return false;
953 case UnitType::Number:
954 case UnitType::Percentage:
955 case UnitType::Ems:
956 case UnitType::Exs:
957 case UnitType::Rems:
958 case UnitType::Pixels:
959 case UnitType::Centimeters:
960 case UnitType::DotsPerPixel:
961 case UnitType::DotsPerInch:
962 case UnitType::DotsPerCentimeter:
963 case UnitType::Millimeters:
964 case UnitType::Inches:
965 case UnitType::Points:
966 case UnitType::Picas:
967 case UnitType::Degrees:
968 case UnitType::Radians:
969 case UnitType::Gradians:
970 case UnitType::Milliseconds:
971 case UnitType::Seconds:
972 case UnitType::Hertz:
973 case UnitType::Kilohertz:
974 case UnitType::Turns:
975 case UnitType::ViewportWidth:
976 case UnitType::ViewportHeight:
977 case UnitType::ViewportMin:
978 case UnitType::ViewportMax:
979 case UnitType::Fraction:
980 return m_value.num == other.m_value.num;
981 case UnitType::PropertyID:
982 return m_value.propertyID == other.m_value.propertyID;
983 case UnitType::ValueID:
984 return m_value.valueID == other.m_value.valueID;
985 case UnitType::CustomIdentifier:
986 case UnitType::String:
987 case UnitType::URI:
988 return equal(m_value.string, other.m_value.string);
989 case UnitType::RGBColor:
990 return m_value.rgbcolor == other.m_value.rgbcolor;
991 case UnitType::Calc:
992 return m_value.calc && other.m_value.calc && m_value.calc->equals(*other.m_value.calc);
993 case UnitType::Shape:
994 return m_value.shape && other.m_value.shape && m_value.shape->equals(*other.m_value.shape);
995 case UnitType::Integer:
996 case UnitType::Chs:
997 case UnitType::CalcPercentageWithNumber:
998 case UnitType::CalcPercentageWithLength:
999 case UnitType::QuirkyEms:
1000 return false;
1002 return false;
1005 DEFINE_TRACE_AFTER_DISPATCH(CSSPrimitiveValue)
1007 #if ENABLE(OILPAN)
1008 switch (type()) {
1009 case UnitType::Calc:
1010 visitor->trace(m_value.calc);
1011 break;
1012 case UnitType::Shape:
1013 visitor->trace(m_value.shape);
1014 break;
1015 default:
1016 break;
1018 #endif
1019 CSSValue::traceAfterDispatch(visitor);
1022 } // namespace blink