Implement vw/vh/vmin (viewport sizes) from CSS3 Values and Units
[WebKit-https.git] / Source / WebCore / css / CSSPrimitiveValue.h
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 CSSPrimitiveValue_h
23 #define CSSPrimitiveValue_h
24
25 #include "CSSValue.h"
26 #include "Color.h"
27 #include <wtf/Forward.h>
28 #include <wtf/MathExtras.h>
29 #include <wtf/PassRefPtr.h>
30
31 namespace WebCore {
32
33 class CSSCalcValue;
34 class Counter;
35 class DashboardRegion;
36 class Pair;
37 class Quad;
38 class RGBColor;
39 class Rect;
40 class RenderStyle;
41 class CSSWrapShape;
42
43 struct Length;
44
45 template<typename T> inline T roundForImpreciseConversion(double value)
46 {
47     // Dimension calculations are imprecise, often resulting in values of e.g.
48     // 44.99998.  We need to go ahead and round if we're really close to the
49     // next integer value.
50     value += (value < 0) ? -0.01 : +0.01;
51     return ((value > std::numeric_limits<T>::max()) || (value < std::numeric_limits<T>::min())) ? 0 : static_cast<T>(value);
52 }
53
54 class CSSPrimitiveValue : public CSSValue {
55 public:
56     enum UnitTypes {
57         CSS_UNKNOWN = 0,
58         CSS_NUMBER = 1,
59         CSS_PERCENTAGE = 2,
60         CSS_EMS = 3,
61         CSS_EXS = 4,
62         CSS_PX = 5,
63         CSS_CM = 6,
64         CSS_MM = 7,
65         CSS_IN = 8,
66         CSS_PT = 9,
67         CSS_PC = 10,
68         CSS_DEG = 11,
69         CSS_RAD = 12,
70         CSS_GRAD = 13,
71         CSS_MS = 14,
72         CSS_S = 15,
73         CSS_HZ = 16,
74         CSS_KHZ = 17,
75         CSS_DIMENSION = 18,
76         CSS_STRING = 19,
77         CSS_URI = 20,
78         CSS_IDENT = 21,
79         CSS_ATTR = 22,
80         CSS_COUNTER = 23,
81         CSS_RECT = 24,
82         CSS_RGBCOLOR = 25,
83         // From CSS Values and Units. Viewport Relative Lengths (vw/vh/vmin).
84         CSS_VW = 26,
85         CSS_VH = 27,
86         CSS_VMIN = 28,
87         CSS_PAIR = 100, // We envision this being exposed as a means of getting computed style values for pairs (border-spacing/radius, background-position, etc.)
88         CSS_DASHBOARD_REGION = 101, // FIXME: Dashboard region should not be a primitive value.
89         CSS_UNICODE_RANGE = 102,
90
91         // These next types are just used internally to allow us to translate back and forth from CSSPrimitiveValues to CSSParserValues.
92         CSS_PARSER_OPERATOR = 103,
93         CSS_PARSER_INTEGER = 104,
94         CSS_PARSER_HEXCOLOR = 105,
95
96         // This is used internally for unknown identifiers
97         CSS_PARSER_IDENTIFIER = 106,
98
99         // These are from CSS3 Values and Units, but that isn't a finished standard yet
100         CSS_TURN = 107,
101         CSS_REMS = 108,
102
103         // This is used internally for counter names (as opposed to counter values)
104         CSS_COUNTER_NAME = 109,
105
106         // This is used by the CSS Exclusions draft
107         CSS_SHAPE = 110,
108
109         // Used by border images.
110         CSS_QUAD = 111,
111
112         CSS_CALC = 112,
113         CSS_CALC_PERCENTAGE_WITH_NUMBER = 113,
114         CSS_CALC_PERCENTAGE_WITH_LENGTH = 114
115     };
116
117     // This enum follows the CSSParser::Units enum augmented with UNIT_FREQUENCY for frequencies.
118     enum UnitCategory {
119         UNumber,
120         UPercent,
121         ULength,
122         UAngle,
123         UTime,
124         UFrequency,
125         UViewportRelativeLength,
126         UOther
127     };
128
129     bool isAngle() const
130     {
131         return m_primitiveUnitType == CSS_DEG
132                || m_primitiveUnitType == CSS_RAD
133                || m_primitiveUnitType == CSS_GRAD
134                || m_primitiveUnitType == CSS_TURN;
135     }
136     bool isAttr() const { return m_primitiveUnitType == CSS_ATTR; }
137     bool isCounter() const { return m_primitiveUnitType == CSS_COUNTER; }
138     bool isFontIndependentLength() const { return m_primitiveUnitType >= CSS_PX && m_primitiveUnitType <= CSS_PC; }
139     bool isFontRelativeLength() const
140     {
141         return m_primitiveUnitType == CSS_EMS || m_primitiveUnitType == CSS_EXS || m_primitiveUnitType == CSS_REMS;
142     }
143     bool isIdent() const { return m_primitiveUnitType == CSS_IDENT; }
144     bool isLength() const
145     {
146         unsigned short type = primitiveType();
147         return (type >= CSS_EMS && type <= CSS_PC) || type == CSS_REMS;
148     }
149     bool isNumber() const { return primitiveType() == CSS_NUMBER; }
150     bool isPercentage() const { return primitiveType() == CSS_PERCENTAGE; }
151     bool isPx() const { return primitiveType() == CSS_PX; }
152     bool isRect() const { return m_primitiveUnitType == CSS_RECT; }
153     bool isRGBColor() const { return m_primitiveUnitType == CSS_RGBCOLOR; }
154     bool isShape() const { return m_primitiveUnitType == CSS_SHAPE; }
155     bool isString() const { return m_primitiveUnitType == CSS_STRING; }
156     bool isTime() const { return m_primitiveUnitType == CSS_S || m_primitiveUnitType == CSS_MS; }
157     bool isURI() const { return m_primitiveUnitType == CSS_URI; }
158     bool isCalculated() const { return m_primitiveUnitType == CSS_CALC; }
159     bool isCalculatedPercentageWithNumber() const { return primitiveType() == CSS_CALC_PERCENTAGE_WITH_NUMBER; }
160     bool isCalculatedPercentageWithLength() const { return primitiveType() == CSS_CALC_PERCENTAGE_WITH_LENGTH; }
161     bool isViewportRelativeLength() const { return m_primitiveUnitType >= CSS_VW && m_primitiveUnitType <= CSS_VMIN; }
162
163     static PassRefPtr<CSSPrimitiveValue> createIdentifier(int identifier) { return adoptRef(new CSSPrimitiveValue(identifier)); }
164     static PassRefPtr<CSSPrimitiveValue> createColor(unsigned rgbValue) { return adoptRef(new CSSPrimitiveValue(rgbValue)); }
165     static PassRefPtr<CSSPrimitiveValue> create(double value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); }
166     static PassRefPtr<CSSPrimitiveValue> create(const String& value, UnitTypes type) { return adoptRef(new CSSPrimitiveValue(value, type)); }
167
168     template<typename T> static PassRefPtr<CSSPrimitiveValue> create(T value)
169     {
170         return adoptRef(new CSSPrimitiveValue(value));
171     }
172
173     // This value is used to handle quirky margins in reflow roots (body, td, and th) like WinIE.
174     // The basic idea is that a stylesheet can use the value __qem (for quirky em) instead of em.
175     // When the quirky value is used, if you're in quirks mode, the margin will collapse away
176     // inside a table cell.
177     static PassRefPtr<CSSPrimitiveValue> createAllowingMarginQuirk(double value, UnitTypes type)
178     {
179         CSSPrimitiveValue* quirkValue = new CSSPrimitiveValue(value, type);
180         quirkValue->m_isQuirkValue = true;
181         return adoptRef(quirkValue);
182     }
183
184     ~CSSPrimitiveValue();
185
186     void cleanup();
187
188     unsigned short primitiveType() const;
189
190     double computeDegrees();
191
192     enum TimeUnit { Seconds, Milliseconds };
193     template <typename T, TimeUnit timeUnit> T computeTime()
194     {
195         if (timeUnit == Seconds && m_primitiveUnitType == CSS_S)
196             return getValue<T>();
197         if (timeUnit == Seconds && m_primitiveUnitType == CSS_MS)
198             return getValue<T>() / 1000;
199         if (timeUnit == Milliseconds && m_primitiveUnitType == CSS_MS)
200             return getValue<T>();
201         if (timeUnit == Milliseconds && m_primitiveUnitType == CSS_S)
202             return getValue<T>() * 1000;
203         ASSERT_NOT_REACHED();
204         return 0;
205     }
206
207     /*
208      * computes a length in pixels out of the given CSSValue. Need the RenderStyle to get
209      * the fontinfo in case val is defined in em or ex.
210      *
211      * The metrics have to be a bit different for screen and printer output.
212      * For screen output we assume 1 inch == 72 px, for printer we assume 300 dpi
213      *
214      * this is screen/printer dependent, so we probably need a config option for this,
215      * and some tool to calibrate.
216      */
217     template<typename T> T computeLength(RenderStyle* currStyle, RenderStyle* rootStyle, float multiplier = 1.0f, bool computingFontSize = false);
218
219     // Converts to a Length, mapping various unit types appropriately.
220     template<int> Length convertToLength(RenderStyle* currStyle, RenderStyle* rootStyle, double multiplier = 1.0, bool computingFontSize = false);
221
222     // use with care!!!
223     void setPrimitiveType(unsigned short type) { m_primitiveUnitType = type; }
224
225     double getDoubleValue(unsigned short unitType, ExceptionCode&) const;
226     double getDoubleValue(unsigned short unitType) const;
227     double getDoubleValue() const;
228
229     void setFloatValue(unsigned short unitType, double floatValue, ExceptionCode&);
230     float getFloatValue(unsigned short unitType, ExceptionCode& ec) const { return getValue<float>(unitType, ec); }
231     float getFloatValue(unsigned short unitType) const { return getValue<float>(unitType); }
232     float getFloatValue() const { return getValue<float>(); }
233
234     int getIntValue(unsigned short unitType, ExceptionCode& ec) const { return getValue<int>(unitType, ec); }
235     int getIntValue(unsigned short unitType) const { return getValue<int>(unitType); }
236     int getIntValue() const { return getValue<int>(); }
237
238     template<typename T> inline T getValue(unsigned short unitType, ExceptionCode& ec) const { return clampTo<T>(getDoubleValue(unitType, ec)); }
239     template<typename T> inline T getValue(unsigned short unitType) const { return clampTo<T>(getDoubleValue(unitType)); }
240     template<typename T> inline T getValue() const { return clampTo<T>(getDoubleValue()); }
241
242     void setStringValue(unsigned short stringType, const String& stringValue, ExceptionCode&);
243     String getStringValue(ExceptionCode&) const;
244     String getStringValue() const;
245
246     Counter* getCounterValue(ExceptionCode&) const;
247     Counter* getCounterValue() const { return m_primitiveUnitType != CSS_COUNTER ? 0 : m_value.counter; }
248
249     Rect* getRectValue(ExceptionCode&) const;
250     Rect* getRectValue() const { return m_primitiveUnitType != CSS_RECT ? 0 : m_value.rect; }
251
252     Quad* getQuadValue(ExceptionCode&) const;
253     Quad* getQuadValue() const { return m_primitiveUnitType != CSS_QUAD ? 0 : m_value.quad; }
254
255     PassRefPtr<RGBColor> getRGBColorValue(ExceptionCode&) const;
256     RGBA32 getRGBA32Value() const { return m_primitiveUnitType != CSS_RGBCOLOR ? 0 : m_value.rgbcolor; }
257
258     Pair* getPairValue(ExceptionCode&) const;
259     Pair* getPairValue() const { return m_primitiveUnitType != CSS_PAIR ? 0 : m_value.pair; }
260
261     DashboardRegion* getDashboardRegionValue() const { return m_primitiveUnitType != CSS_DASHBOARD_REGION ? 0 : m_value.region; }
262
263     CSSWrapShape* getShapeValue() const { return m_primitiveUnitType != CSS_SHAPE ? 0 : m_value.shape; }
264     
265     CSSCalcValue* cssCalcValue() const { return m_primitiveUnitType != CSS_CALC ? 0 : m_value.calc; }
266
267     int getIdent() const { return m_primitiveUnitType == CSS_IDENT ? m_value.ident : 0; }
268
269     template<typename T> inline operator T() const; // Defined in CSSPrimitiveValueMappings.h
270
271     String customCssText() const;
272
273     bool isQuirkValue() { return m_isQuirkValue; }
274
275     void addSubresourceStyleURLs(ListHashSet<KURL>&, const CSSStyleSheet*);
276
277     Length viewportRelativeLength();
278
279 private:
280     // FIXME: int vs. unsigned overloading is too subtle to distinguish the color and identifier cases.
281     CSSPrimitiveValue(int ident);
282     CSSPrimitiveValue(unsigned color); // RGB value
283     CSSPrimitiveValue(const Length&);
284     CSSPrimitiveValue(const String&, UnitTypes);
285     CSSPrimitiveValue(double, UnitTypes);
286
287     template<typename T> CSSPrimitiveValue(T); // Defined in CSSPrimitiveValueMappings.h
288     template<typename T> CSSPrimitiveValue(T* val)
289         : CSSValue(PrimitiveClass)
290     {
291         init(PassRefPtr<T>(val));
292     }
293
294     template<typename T> CSSPrimitiveValue(PassRefPtr<T> val)
295         : CSSValue(PrimitiveClass)
296     {
297         init(val);
298     }
299
300     static void create(int); // compile-time guard
301     static void create(unsigned); // compile-time guard
302     template<typename T> operator T*(); // compile-time guard
303
304     static UnitTypes canonicalUnitTypeForCategory(UnitCategory category);
305
306     void init(PassRefPtr<Counter>);
307     void init(PassRefPtr<Rect>);
308     void init(PassRefPtr<Pair>);
309     void init(PassRefPtr<Quad>);
310     void init(PassRefPtr<DashboardRegion>); // FIXME: Dashboard region should not be a primitive value.
311     void init(PassRefPtr<CSSWrapShape>);
312     void init(PassRefPtr<CSSCalcValue>);
313     bool getDoubleValueInternal(UnitTypes targetUnitType, double* result) const;
314
315     double computeLengthDouble(RenderStyle* currentStyle, RenderStyle* rootStyle, float multiplier, bool computingFontSize);
316
317     union {
318         int ident;
319         double num;
320         StringImpl* string;
321         Counter* counter;
322         Rect* rect;
323         Quad* quad;
324         unsigned rgbcolor;
325         Pair* pair;
326         DashboardRegion* region;
327         CSSWrapShape* shape;
328         CSSCalcValue* calc;
329     } m_value;
330 };
331
332 } // namespace WebCore
333
334 #endif // CSSPrimitiveValue_h