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