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