1 /*
2 * (C) 1999-2003 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2008 Apple Inc. All rights reserved.
4 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
23 #define THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
24
25 #include <bitset>
26 #include "third_party/blink/renderer/core/core_export.h"
27 #include "third_party/blink/renderer/core/css/css_value.h"
28 #include "third_party/blink/renderer/platform/wtf/casting.h"
29 #include "third_party/blink/renderer/platform/wtf/forward.h"
30 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
31 #include "third_party/blink/renderer/platform/wtf/text/string_hash.h"
32 #include "third_party/blink/renderer/platform/wtf/text/string_view.h"
33
34 namespace blink {
35
36 class CSSToLengthConversionData;
37 class Length;
38
39 // Dimension calculations are imprecise, often resulting in values of e.g.
40 // 44.99998. We need to go ahead and round if we're really close to the next
41 // integer value.
42 template <typename T>
RoundForImpreciseConversion(double value)43 inline T RoundForImpreciseConversion(double value) {
44 value += (value < 0) ? -0.01 : +0.01;
45 return ((value > std::numeric_limits<T>::max()) ||
46 (value < std::numeric_limits<T>::min()))
47 ? 0
48 : static_cast<T>(value);
49 }
50
51 template <>
RoundForImpreciseConversion(double value)52 inline float RoundForImpreciseConversion(double value) {
53 double ceiled_value = ceil(value);
54 double proximity_to_next_int = ceiled_value - value;
55 if (proximity_to_next_int <= 0.01 && value > 0)
56 return static_cast<float>(ceiled_value);
57 if (proximity_to_next_int >= 0.99 && value < 0)
58 return static_cast<float>(floor(value));
59 return static_cast<float>(value);
60 }
61
62 // Common interface for numeric data types, including both literals (e.g. 1,
63 // 10px, 4%) and values involving math functions (e.g. calc(3px + 2em)).
64 class CORE_EXPORT CSSPrimitiveValue : public CSSValue {
65 public:
66 // These units are iterated through, so be careful when adding or changing the
67 // order.
68 enum class UnitType {
69 kUnknown,
70 kNumber,
71 kPercentage,
72 // Length units
73 kEms,
74 kExs,
75 kPixels,
76 kCentimeters,
77 kMillimeters,
78 kInches,
79 kPoints,
80 kPicas,
81 kQuarterMillimeters,
82 kViewportWidth,
83 kViewportHeight,
84 kViewportMin,
85 kViewportMax,
86 kRems,
87 kChs,
88 kUserUnits, // The SVG term for unitless lengths
89 // Angle units
90 kDegrees,
91 kRadians,
92 kGradians,
93 kTurns,
94 // Time units
95 kMilliseconds,
96 kSeconds,
97 kHertz,
98 kKilohertz,
99 // Resolution
100 kDotsPerPixel,
101 kDotsPerInch,
102 kDotsPerCentimeter,
103 // Other units
104 kFraction,
105 kInteger,
106
107 // This value is used to handle quirky margins in reflow roots (body, td,
108 // and th) like WinIE. The basic idea is that a stylesheet can use the value
109 // __qem (for quirky em) instead of em. When the quirky value is used, if
110 // you're in quirks mode, the margin will collapse away inside a table cell.
111 // This quirk is specified in the HTML spec but our impl is different.
112 // TODO: Remove this. crbug.com/443952
113 kQuirkyEms,
114 };
115
116 enum LengthUnitType {
117 kUnitTypePixels = 0,
118 kUnitTypePercentage,
119 kUnitTypeFontSize,
120 kUnitTypeFontXSize,
121 kUnitTypeRootFontSize,
122 kUnitTypeZeroCharacterWidth,
123 kUnitTypeViewportWidth,
124 kUnitTypeViewportHeight,
125 kUnitTypeViewportMin,
126 kUnitTypeViewportMax,
127
128 // This value must come after the last length unit type to enable iteration
129 // over the length unit types.
130 kLengthUnitTypeCount,
131 };
132
133 using LengthTypeFlags = std::bitset<kLengthUnitTypeCount>;
134 struct CSSLengthArray {
CSSLengthArrayCSSLengthArray135 CSSLengthArray() : values(kLengthUnitTypeCount) {
136 }
137
138 Vector<double, CSSPrimitiveValue::kLengthUnitTypeCount> values;
139 LengthTypeFlags type_flags;
140 };
141
142 // Returns false if the value cannot be represented as a length array, which
143 // happens when comparisons are involved (e.g., max(10px, 10%)).
144 bool AccumulateLengthArray(CSSLengthArray&, double multiplier = 1) const;
145
146 // Returns all types of length units involved in this value.
147 void AccumulateLengthUnitTypes(LengthTypeFlags& types) const;
148
149 enum UnitCategory {
150 kUNumber,
151 kUPercent,
152 kULength,
153 kUAngle,
154 kUTime,
155 kUFrequency,
156 kUResolution,
157 kUOther
158 };
159 static UnitCategory UnitTypeToUnitCategory(UnitType);
160 static float ClampToCSSLengthRange(double);
161
IsAngle(UnitType unit)162 static bool IsAngle(UnitType unit) {
163 return unit == UnitType::kDegrees || unit == UnitType::kRadians ||
164 unit == UnitType::kGradians || unit == UnitType::kTurns;
165 }
166 bool IsAngle() const;
IsViewportPercentageLength(UnitType type)167 static bool IsViewportPercentageLength(UnitType type) {
168 return type >= UnitType::kViewportWidth && type <= UnitType::kViewportMax;
169 }
IsLength(UnitType type)170 static bool IsLength(UnitType type) {
171 return (type >= UnitType::kEms && type <= UnitType::kUserUnits) ||
172 type == UnitType::kQuirkyEms;
173 }
IsRelativeUnit(UnitType type)174 static inline bool IsRelativeUnit(UnitType type) {
175 return type == UnitType::kPercentage || type == UnitType::kEms ||
176 type == UnitType::kExs || type == UnitType::kRems ||
177 type == UnitType::kChs || IsViewportPercentageLength(type);
178 }
179 bool IsLength() const;
180 bool IsNumber() const;
181 bool IsInteger() const;
182 bool IsPercentage() const;
183 bool IsPx() const;
IsTime(UnitType unit)184 static bool IsTime(UnitType unit) {
185 return unit == UnitType::kSeconds || unit == UnitType::kMilliseconds;
186 }
187 bool IsTime() const;
IsFrequency(UnitType unit)188 static bool IsFrequency(UnitType unit) {
189 return unit == UnitType::kHertz || unit == UnitType::kKilohertz;
190 }
IsCalculated()191 bool IsCalculated() const { return IsMathFunctionValue(); }
192 bool IsCalculatedPercentageWithLength() const;
IsResolution(UnitType type)193 static bool IsResolution(UnitType type) {
194 return type >= UnitType::kDotsPerPixel &&
195 type <= UnitType::kDotsPerCentimeter;
196 }
197 bool IsResolution() const;
IsFlex(UnitType unit)198 static bool IsFlex(UnitType unit) { return unit == UnitType::kFraction; }
199 bool IsFlex() const;
200
201 // https://drafts.css-houdini.org/css-properties-values-api-1/#computationally-independent
202 // A property value is computationally independent if it can be converted into
203 // a computed value using only the value of the property on the element, and
204 // "global" information that cannot be changed by CSS.
205 bool IsComputationallyIndependent() const;
206
207 // Creates either a |CSSNumericLiteralValue| or a |CSSMathFunctionValue|,
208 // depending on whether |value| is calculated or not. We should never create a
209 // |CSSPrimitiveValue| that's not of any of its subclasses.
210 static CSSPrimitiveValue* CreateFromLength(const Length& value, float zoom);
211
212 double ComputeDegrees() const;
213 double ComputeSeconds() const;
214 double ComputeDotsPerPixel() const;
215
216 // Computes a length in pixels, resolving relative lengths
217 template <typename T>
218 T ComputeLength(const CSSToLengthConversionData&) const;
219
220 // Converts to a Length (Fixed, Percent or Calculated)
221 Length ConvertToLength(const CSSToLengthConversionData&) const;
222
223 bool IsZero() const;
224
225 // TODO(crbug.com/979895): The semantics of these untyped getters are not very
226 // clear if |this| is a math function. Do not add new callers before further
227 // refactoring and cleanups.
228 // These getters can be called only when |this| is a numeric literal or a math
229 // expression can be resolved into a single numeric value *without any type
230 // conversion* (e.g., between px and em). Otherwise, it hits a DCHECK.
231 double GetDoubleValue() const;
GetFloatValue()232 float GetFloatValue() const { return GetValue<float>(); }
GetIntValue()233 int GetIntValue() const { return GetValue<int>(); }
234 template <typename T>
GetValue()235 inline T GetValue() const {
236 return clampTo<T>(GetDoubleValue());
237 }
238
239 template <typename T>
240 inline T ConvertTo() const; // Defined in CSSPrimitiveValueMappings.h
241
242 static const char* UnitTypeToString(UnitType);
StringToUnitType(StringView string)243 static UnitType StringToUnitType(StringView string) {
244 if (string.Is8Bit())
245 return StringToUnitType(string.Characters8(), string.length());
246 return StringToUnitType(string.Characters16(), string.length());
247 }
248
249 String CustomCSSText() const;
250
251 void TraceAfterDispatch(blink::Visitor*) const;
252
253 static UnitType CanonicalUnitTypeForCategory(UnitCategory);
254 static double ConversionToCanonicalUnitsScaleFactor(UnitType);
255
256 // Returns true and populates lengthUnitType, if unitType is a length unit.
257 // Otherwise, returns false.
258 static bool UnitTypeToLengthUnitType(UnitType, LengthUnitType&);
259 static UnitType LengthUnitTypeToUnitType(LengthUnitType);
260
261 protected:
262 explicit CSSPrimitiveValue(ClassType class_type);
263
264 // Code generated by css_primitive_value_unit_trie.cc.tmpl
265 static UnitType StringToUnitType(const LChar*, unsigned length);
266 static UnitType StringToUnitType(const UChar*, unsigned length);
267
268 double ComputeLengthDouble(const CSSToLengthConversionData&) const;
269 };
270
271 using CSSLengthArray = CSSPrimitiveValue::CSSLengthArray;
272
273 template <>
274 struct DowncastTraits<CSSPrimitiveValue> {
275 static bool AllowFrom(const CSSValue& value) {
276 return value.IsPrimitiveValue();
277 }
278 };
279
280 template <>
281 int CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
282
283 template <>
284 Length CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
285
286 template <>
287 unsigned CSSPrimitiveValue::ComputeLength(
288 const CSSToLengthConversionData&) const;
289
290 template <>
291 int16_t CSSPrimitiveValue::ComputeLength(
292 const CSSToLengthConversionData&) const;
293
294 template <>
295 CORE_EXPORT float CSSPrimitiveValue::ComputeLength(
296 const CSSToLengthConversionData&) const;
297
298 template <>
299 double CSSPrimitiveValue::ComputeLength(const CSSToLengthConversionData&) const;
300 } // namespace blink
301
302 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_CSS_CSS_PRIMITIVE_VALUE_H_
303