Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2007 Apple Inc. All rights reserved.
      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 #include "config.h"
     23 
     24 #include "core/svg/SVGLength.h"
     25 
     26 #include "SVGNames.h"
     27 #include "bindings/v8/ExceptionStatePlaceholder.h"
     28 #include "core/css/CSSPrimitiveValue.h"
     29 #include "core/dom/ExceptionCode.h"
     30 #include "core/svg/SVGParserUtilities.h"
     31 #include "wtf/MathExtras.h"
     32 #include "wtf/text/WTFString.h"
     33 
     34 namespace WebCore {
     35 
     36 static inline SVGLengthMode toSVGLengthMode(unsigned short mode)
     37 {
     38     ASSERT(mode >= LengthModeWidth && mode <= LengthModeOther);
     39     return static_cast<SVGLengthMode>(mode);
     40 }
     41 
     42 static inline SVGLengthType toSVGLengthType(unsigned short type)
     43 {
     44     ASSERT(type >= LengthTypeUnknown && type <= LengthTypePC);
     45     return static_cast<SVGLengthType>(type);
     46 }
     47 
     48 static inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type)
     49 {
     50     return (mode << 4) | type;
     51 }
     52 
     53 static inline SVGLengthMode extractMode(unsigned int unit)
     54 {
     55     unsigned int mode = unit >> 4;
     56     return toSVGLengthMode(mode);
     57 }
     58 
     59 static inline SVGLengthType extractType(unsigned int unit)
     60 {
     61     unsigned int mode = unit >> 4;
     62     unsigned int type = unit ^ (mode << 4);
     63     return toSVGLengthType(type);
     64 }
     65 
     66 static inline String lengthTypeToString(SVGLengthType type)
     67 {
     68     switch (type) {
     69     case LengthTypeUnknown:
     70     case LengthTypeNumber:
     71         return "";
     72     case LengthTypePercentage:
     73         return "%";
     74     case LengthTypeEMS:
     75         return "em";
     76     case LengthTypeEXS:
     77         return "ex";
     78     case LengthTypePX:
     79         return "px";
     80     case LengthTypeCM:
     81         return "cm";
     82     case LengthTypeMM:
     83         return "mm";
     84     case LengthTypeIN:
     85         return "in";
     86     case LengthTypePT:
     87         return "pt";
     88     case LengthTypePC:
     89         return "pc";
     90     }
     91 
     92     ASSERT_NOT_REACHED();
     93     return String();
     94 }
     95 
     96 template<typename CharType>
     97 static SVGLengthType stringToLengthType(const CharType*& ptr, const CharType* end)
     98 {
     99     if (ptr == end)
    100         return LengthTypeNumber;
    101 
    102     const UChar firstChar = *ptr;
    103 
    104     if (++ptr == end)
    105         return firstChar == '%' ? LengthTypePercentage : LengthTypeUnknown;
    106 
    107     const UChar secondChar = *ptr;
    108 
    109     if (++ptr != end)
    110         return LengthTypeUnknown;
    111 
    112     if (firstChar == 'e' && secondChar == 'm')
    113         return LengthTypeEMS;
    114     if (firstChar == 'e' && secondChar == 'x')
    115         return LengthTypeEXS;
    116     if (firstChar == 'p' && secondChar == 'x')
    117         return LengthTypePX;
    118     if (firstChar == 'c' && secondChar == 'm')
    119         return LengthTypeCM;
    120     if (firstChar == 'm' && secondChar == 'm')
    121         return LengthTypeMM;
    122     if (firstChar == 'i' && secondChar == 'n')
    123         return LengthTypeIN;
    124     if (firstChar == 'p' && secondChar == 't')
    125         return LengthTypePT;
    126     if (firstChar == 'p' && secondChar == 'c')
    127         return LengthTypePC;
    128 
    129     return LengthTypeUnknown;
    130 }
    131 
    132 SVGLength::SVGLength(SVGLengthMode mode, const String& valueAsString)
    133     : m_valueInSpecifiedUnits(0)
    134     , m_unit(storeUnit(mode, LengthTypeNumber))
    135 {
    136     setValueAsString(valueAsString, IGNORE_EXCEPTION);
    137 }
    138 
    139 SVGLength::SVGLength(const SVGLengthContext& context, float value, SVGLengthMode mode, SVGLengthType unitType)
    140     : m_valueInSpecifiedUnits(0)
    141     , m_unit(storeUnit(mode, unitType))
    142 {
    143     setValue(value, context, ASSERT_NO_EXCEPTION);
    144 }
    145 
    146 SVGLength::SVGLength(const SVGLength& other)
    147     : m_valueInSpecifiedUnits(other.m_valueInSpecifiedUnits)
    148     , m_unit(other.m_unit)
    149 {
    150 }
    151 
    152 void SVGLength::setValueAsString(const String& valueAsString, SVGLengthMode mode, ExceptionState& exceptionState)
    153 {
    154     m_valueInSpecifiedUnits = 0;
    155     m_unit = storeUnit(mode, LengthTypeNumber);
    156     setValueAsString(valueAsString, exceptionState);
    157 }
    158 
    159 bool SVGLength::operator==(const SVGLength& other) const
    160 {
    161     return m_unit == other.m_unit
    162         && m_valueInSpecifiedUnits == other.m_valueInSpecifiedUnits;
    163 }
    164 
    165 bool SVGLength::operator!=(const SVGLength& other) const
    166 {
    167     return !operator==(other);
    168 }
    169 
    170 SVGLength SVGLength::construct(SVGLengthMode mode, const String& valueAsString, SVGParsingError& parseError, SVGLengthNegativeValuesMode negativeValuesMode)
    171 {
    172     TrackExceptionState exceptionState;
    173     SVGLength length(mode);
    174 
    175     length.setValueAsString(valueAsString, exceptionState);
    176 
    177     if (exceptionState.hadException())
    178         parseError = ParsingAttributeFailedError;
    179     else if (negativeValuesMode == ForbidNegativeLengths && length.valueInSpecifiedUnits() < 0)
    180         parseError = NegativeValueForbiddenError;
    181 
    182     return length;
    183 }
    184 
    185 SVGLengthType SVGLength::unitType() const
    186 {
    187     return extractType(m_unit);
    188 }
    189 
    190 SVGLengthMode SVGLength::unitMode() const
    191 {
    192     return extractMode(m_unit);
    193 }
    194 
    195 float SVGLength::value(const SVGLengthContext& context) const
    196 {
    197     return value(context, IGNORE_EXCEPTION);
    198 }
    199 
    200 float SVGLength::value(const SVGLengthContext& context, ExceptionState& exceptionState) const
    201 {
    202     return context.convertValueToUserUnits(m_valueInSpecifiedUnits, extractMode(m_unit), extractType(m_unit), exceptionState);
    203 }
    204 
    205 void SVGLength::setValue(const SVGLengthContext& context, float value, SVGLengthMode mode, SVGLengthType unitType, ExceptionState& exceptionState)
    206 {
    207     m_unit = storeUnit(mode, unitType);
    208     setValue(value, context, exceptionState);
    209 }
    210 
    211 void SVGLength::setValue(float value, const SVGLengthContext& context, ExceptionState& exceptionState)
    212 {
    213     // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed
    214     if (extractType(m_unit) == LengthTypePercentage)
    215         value = value / 100;
    216 
    217     float convertedValue = context.convertValueFromUserUnits(value, extractMode(m_unit), extractType(m_unit), exceptionState);
    218     if (!exceptionState.hadException())
    219         m_valueInSpecifiedUnits = convertedValue;
    220 }
    221 float SVGLength::valueAsPercentage() const
    222 {
    223     // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed
    224     if (extractType(m_unit) == LengthTypePercentage)
    225         return m_valueInSpecifiedUnits / 100;
    226 
    227     return m_valueInSpecifiedUnits;
    228 }
    229 
    230 template<typename CharType>
    231 static bool parseValueInternal(const String& string, float& convertedNumber, SVGLengthType& type)
    232 {
    233     const CharType* ptr = string.getCharacters<CharType>();
    234     const CharType* end = ptr + string.length();
    235 
    236     if (!parseNumber(ptr, end, convertedNumber, false))
    237         return false;
    238 
    239     type = stringToLengthType(ptr, end);
    240     ASSERT(ptr <= end);
    241     if (type == LengthTypeUnknown)
    242         return false;
    243 
    244     return true;
    245 }
    246 
    247 void SVGLength::setValueAsString(const String& string, ExceptionState& exceptionState)
    248 {
    249     if (string.isEmpty())
    250         return;
    251 
    252     float convertedNumber = 0;
    253     SVGLengthType type = LengthTypeUnknown;
    254 
    255     bool success = string.is8Bit() ?
    256         parseValueInternal<LChar>(string, convertedNumber, type) :
    257         parseValueInternal<UChar>(string, convertedNumber, type);
    258 
    259     if (!success) {
    260         exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
    261         return;
    262     }
    263 
    264     m_unit = storeUnit(extractMode(m_unit), type);
    265     m_valueInSpecifiedUnits = convertedNumber;
    266 }
    267 
    268 String SVGLength::valueAsString() const
    269 {
    270     return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit));
    271 }
    272 
    273 void SVGLength::newValueSpecifiedUnits(unsigned short type, float value, ExceptionState& exceptionState)
    274 {
    275     if (type == LengthTypeUnknown || type > LengthTypePC) {
    276         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
    277         return;
    278     }
    279 
    280     m_unit = storeUnit(extractMode(m_unit), toSVGLengthType(type));
    281     m_valueInSpecifiedUnits = value;
    282 }
    283 
    284 void SVGLength::convertToSpecifiedUnits(unsigned short type, const SVGLengthContext& context, ExceptionState& exceptionState)
    285 {
    286     if (type == LengthTypeUnknown || type > LengthTypePC) {
    287         exceptionState.throwUninformativeAndGenericDOMException(NotSupportedError);
    288         return;
    289     }
    290 
    291     float valueInUserUnits = value(context, exceptionState);
    292     if (exceptionState.hadException())
    293         return;
    294 
    295     unsigned int originalUnitAndType = m_unit;
    296     m_unit = storeUnit(extractMode(m_unit), toSVGLengthType(type));
    297     setValue(valueInUserUnits, context, exceptionState);
    298     if (!exceptionState.hadException())
    299         return;
    300 
    301     // Eventually restore old unit and type
    302     m_unit = originalUnitAndType;
    303 }
    304 
    305 SVGLength SVGLength::fromCSSPrimitiveValue(CSSPrimitiveValue* value)
    306 {
    307     ASSERT(value);
    308 
    309     SVGLengthType svgType;
    310     switch (value->primitiveType()) {
    311     case CSSPrimitiveValue::CSS_NUMBER:
    312         svgType = LengthTypeNumber;
    313         break;
    314     case CSSPrimitiveValue::CSS_PERCENTAGE:
    315         svgType = LengthTypePercentage;
    316         break;
    317     case CSSPrimitiveValue::CSS_EMS:
    318         svgType = LengthTypeEMS;
    319         break;
    320     case CSSPrimitiveValue::CSS_EXS:
    321         svgType = LengthTypeEXS;
    322         break;
    323     case CSSPrimitiveValue::CSS_PX:
    324         svgType = LengthTypePX;
    325         break;
    326     case CSSPrimitiveValue::CSS_CM:
    327         svgType = LengthTypeCM;
    328         break;
    329     case CSSPrimitiveValue::CSS_MM:
    330         svgType = LengthTypeMM;
    331         break;
    332     case CSSPrimitiveValue::CSS_IN:
    333         svgType = LengthTypeIN;
    334         break;
    335     case CSSPrimitiveValue::CSS_PT:
    336         svgType = LengthTypePT;
    337         break;
    338     case CSSPrimitiveValue::CSS_PC:
    339         svgType = LengthTypePC;
    340         break;
    341     case CSSPrimitiveValue::CSS_UNKNOWN:
    342     default:
    343         svgType = LengthTypeUnknown;
    344         break;
    345     };
    346 
    347     if (svgType == LengthTypeUnknown)
    348         return SVGLength();
    349 
    350     TrackExceptionState exceptionState;
    351     SVGLength length;
    352     length.newValueSpecifiedUnits(svgType, value->getFloatValue(), exceptionState);
    353     if (exceptionState.hadException())
    354         return SVGLength();
    355 
    356     return length;
    357 }
    358 
    359 PassRefPtr<CSSPrimitiveValue> SVGLength::toCSSPrimitiveValue(const SVGLength& length)
    360 {
    361     CSSPrimitiveValue::UnitTypes cssType = CSSPrimitiveValue::CSS_UNKNOWN;
    362     switch (length.unitType()) {
    363     case LengthTypeUnknown:
    364         break;
    365     case LengthTypeNumber:
    366         cssType = CSSPrimitiveValue::CSS_NUMBER;
    367         break;
    368     case LengthTypePercentage:
    369         cssType = CSSPrimitiveValue::CSS_PERCENTAGE;
    370         break;
    371     case LengthTypeEMS:
    372         cssType = CSSPrimitiveValue::CSS_EMS;
    373         break;
    374     case LengthTypeEXS:
    375         cssType = CSSPrimitiveValue::CSS_EXS;
    376         break;
    377     case LengthTypePX:
    378         cssType = CSSPrimitiveValue::CSS_PX;
    379         break;
    380     case LengthTypeCM:
    381         cssType = CSSPrimitiveValue::CSS_CM;
    382         break;
    383     case LengthTypeMM:
    384         cssType = CSSPrimitiveValue::CSS_MM;
    385         break;
    386     case LengthTypeIN:
    387         cssType = CSSPrimitiveValue::CSS_IN;
    388         break;
    389     case LengthTypePT:
    390         cssType = CSSPrimitiveValue::CSS_PT;
    391         break;
    392     case LengthTypePC:
    393         cssType = CSSPrimitiveValue::CSS_PC;
    394         break;
    395     };
    396 
    397     return CSSPrimitiveValue::create(length.valueInSpecifiedUnits(), cssType);
    398 }
    399 
    400 SVGLengthMode SVGLength::lengthModeForAnimatedLengthAttribute(const QualifiedName& attrName)
    401 {
    402     typedef HashMap<QualifiedName, SVGLengthMode> LengthModeForLengthAttributeMap;
    403     DEFINE_STATIC_LOCAL(LengthModeForLengthAttributeMap, s_lengthModeMap, ());
    404 
    405     if (s_lengthModeMap.isEmpty()) {
    406         s_lengthModeMap.set(SVGNames::xAttr, LengthModeWidth);
    407         s_lengthModeMap.set(SVGNames::yAttr, LengthModeHeight);
    408         s_lengthModeMap.set(SVGNames::cxAttr, LengthModeWidth);
    409         s_lengthModeMap.set(SVGNames::cyAttr, LengthModeHeight);
    410         s_lengthModeMap.set(SVGNames::dxAttr, LengthModeWidth);
    411         s_lengthModeMap.set(SVGNames::dyAttr, LengthModeHeight);
    412         s_lengthModeMap.set(SVGNames::fxAttr, LengthModeWidth);
    413         s_lengthModeMap.set(SVGNames::fyAttr, LengthModeHeight);
    414         s_lengthModeMap.set(SVGNames::rAttr, LengthModeOther);
    415         s_lengthModeMap.set(SVGNames::widthAttr, LengthModeWidth);
    416         s_lengthModeMap.set(SVGNames::heightAttr, LengthModeHeight);
    417         s_lengthModeMap.set(SVGNames::x1Attr, LengthModeWidth);
    418         s_lengthModeMap.set(SVGNames::x2Attr, LengthModeWidth);
    419         s_lengthModeMap.set(SVGNames::y1Attr, LengthModeHeight);
    420         s_lengthModeMap.set(SVGNames::y2Attr, LengthModeHeight);
    421         s_lengthModeMap.set(SVGNames::refXAttr, LengthModeWidth);
    422         s_lengthModeMap.set(SVGNames::refYAttr, LengthModeHeight);
    423         s_lengthModeMap.set(SVGNames::markerWidthAttr, LengthModeWidth);
    424         s_lengthModeMap.set(SVGNames::markerHeightAttr, LengthModeHeight);
    425         s_lengthModeMap.set(SVGNames::textLengthAttr, LengthModeWidth);
    426         s_lengthModeMap.set(SVGNames::startOffsetAttr, LengthModeWidth);
    427     }
    428 
    429     if (s_lengthModeMap.contains(attrName))
    430         return s_lengthModeMap.get(attrName);
    431 
    432     return LengthModeOther;
    433 }
    434 
    435 }
    436