Home | History | Annotate | Download | only in css
      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