Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) Research In Motion Limited 2010. 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 #if ENABLE(SVG)
     25 #include "SVGAngle.h"
     26 
     27 #include "SVGParserUtilities.h"
     28 #include <wtf/MathExtras.h>
     29 #include <wtf/text/StringConcatenate.h>
     30 
     31 namespace WebCore {
     32 
     33 SVGAngle::SVGAngle()
     34     : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
     35     , m_valueInSpecifiedUnits(0)
     36 {
     37 }
     38 
     39 float SVGAngle::value() const
     40 {
     41     switch (m_unitType) {
     42     case SVG_ANGLETYPE_GRAD:
     43         return grad2deg(m_valueInSpecifiedUnits);
     44     case SVG_ANGLETYPE_RAD:
     45         return rad2deg(m_valueInSpecifiedUnits);
     46     case SVG_ANGLETYPE_UNSPECIFIED:
     47     case SVG_ANGLETYPE_UNKNOWN:
     48     case SVG_ANGLETYPE_DEG:
     49         return m_valueInSpecifiedUnits;
     50     }
     51 
     52     ASSERT_NOT_REACHED();
     53     return 0;
     54 }
     55 
     56 void SVGAngle::setValue(float value)
     57 {
     58     switch (m_unitType) {
     59     case SVG_ANGLETYPE_GRAD:
     60         m_valueInSpecifiedUnits = deg2grad(value);
     61         break;
     62     case SVG_ANGLETYPE_RAD:
     63         m_valueInSpecifiedUnits = deg2rad(value);
     64         break;
     65     case SVG_ANGLETYPE_UNSPECIFIED:
     66     case SVG_ANGLETYPE_UNKNOWN:
     67     case SVG_ANGLETYPE_DEG:
     68         m_valueInSpecifiedUnits = value;
     69         break;
     70     }
     71 }
     72 
     73 inline SVGAngle::SVGAngleType stringToAngleType(const UChar*& ptr, const UChar* end)
     74 {
     75     // If there's no unit given, the angle type is unspecified.
     76     if (ptr == end)
     77         return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
     78 
     79     const UChar firstChar = *ptr;
     80 
     81     // If the unit contains only one character, the angle type is unknown.
     82     ++ptr;
     83     if (ptr == end)
     84         return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
     85 
     86     const UChar secondChar = *ptr;
     87 
     88     // If the unit contains only two characters, the angle type is unknown.
     89     ++ptr;
     90     if (ptr == end)
     91         return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
     92 
     93     const UChar thirdChar = *ptr;
     94     if (firstChar == 'd' && secondChar == 'e' && thirdChar == 'g')
     95         return SVGAngle::SVG_ANGLETYPE_DEG;
     96     if (firstChar == 'r' && secondChar == 'a' && thirdChar == 'd')
     97         return SVGAngle::SVG_ANGLETYPE_RAD;
     98 
     99     // If the unit contains three characters, but is not deg or rad, then it's unknown.
    100     ++ptr;
    101     if (ptr == end)
    102         return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
    103 
    104     const UChar fourthChar = *ptr;
    105 
    106     if (firstChar == 'g' && secondChar == 'r' && thirdChar == 'a' && fourthChar == 'd')
    107         return SVGAngle::SVG_ANGLETYPE_GRAD;
    108 
    109     return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
    110 }
    111 
    112 String SVGAngle::valueAsString() const
    113 {
    114     switch (m_unitType) {
    115     case SVG_ANGLETYPE_DEG:
    116         return makeString(String::number(m_valueInSpecifiedUnits), "deg");
    117     case SVG_ANGLETYPE_RAD:
    118         return makeString(String::number(m_valueInSpecifiedUnits), "rad");
    119     case SVG_ANGLETYPE_GRAD:
    120         return makeString(String::number(m_valueInSpecifiedUnits), "grad");
    121     case SVG_ANGLETYPE_UNSPECIFIED:
    122     case SVG_ANGLETYPE_UNKNOWN:
    123         return makeString(String::number(m_valueInSpecifiedUnits));
    124     }
    125 
    126     ASSERT_NOT_REACHED();
    127     return String();
    128 }
    129 
    130 void SVGAngle::setValueAsString(const String& value, ExceptionCode& ec)
    131 {
    132     if (value.isEmpty()) {
    133         m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
    134         return;
    135     }
    136 
    137     float valueInSpecifiedUnits = 0;
    138     const UChar* ptr = value.characters();
    139     const UChar* end = ptr + value.length();
    140 
    141     if (!parseNumber(ptr, end, valueInSpecifiedUnits, false)) {
    142         ec = SYNTAX_ERR;
    143         return;
    144     }
    145 
    146     SVGAngleType unitType = stringToAngleType(ptr, end);
    147     if (unitType == SVG_ANGLETYPE_UNKNOWN) {
    148         ec = SYNTAX_ERR;
    149         return;
    150     }
    151 
    152     m_unitType = unitType;
    153     m_valueInSpecifiedUnits = valueInSpecifiedUnits;
    154 }
    155 
    156 void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionCode& ec)
    157 {
    158     if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
    159         ec = NOT_SUPPORTED_ERR;
    160         return;
    161     }
    162 
    163     if (unitType != m_unitType)
    164         m_unitType = static_cast<SVGAngleType>(unitType);
    165 
    166     m_valueInSpecifiedUnits = valueInSpecifiedUnits;
    167 }
    168 
    169 void SVGAngle::convertToSpecifiedUnits(unsigned short unitType, ExceptionCode& ec)
    170 {
    171     if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
    172         ec = NOT_SUPPORTED_ERR;
    173         return;
    174     }
    175 
    176     if (unitType == m_unitType)
    177         return;
    178 
    179     switch (m_unitType) {
    180     case SVG_ANGLETYPE_RAD:
    181         switch (unitType) {
    182         case SVG_ANGLETYPE_GRAD:
    183             m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
    184             break;
    185         case SVG_ANGLETYPE_UNSPECIFIED:
    186         case SVG_ANGLETYPE_DEG:
    187             m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
    188             break;
    189         case SVG_ANGLETYPE_RAD:
    190         case SVG_ANGLETYPE_UNKNOWN:
    191             ASSERT_NOT_REACHED();
    192             break;
    193         }
    194         break;
    195     case SVG_ANGLETYPE_GRAD:
    196         switch (unitType) {
    197         case SVG_ANGLETYPE_RAD:
    198             m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
    199             break;
    200         case SVG_ANGLETYPE_UNSPECIFIED:
    201         case SVG_ANGLETYPE_DEG:
    202             m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
    203             break;
    204         case SVG_ANGLETYPE_GRAD:
    205         case SVG_ANGLETYPE_UNKNOWN:
    206             ASSERT_NOT_REACHED();
    207             break;
    208         }
    209         break;
    210     case SVG_ANGLETYPE_UNSPECIFIED:
    211         // Spec: For angles, a unitless value is treated the same as if degrees were specified.
    212     case SVG_ANGLETYPE_DEG:
    213         switch (unitType) {
    214         case SVG_ANGLETYPE_RAD:
    215             m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
    216             break;
    217         case SVG_ANGLETYPE_GRAD:
    218             m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
    219             break;
    220         case SVG_ANGLETYPE_UNSPECIFIED:
    221             break;
    222         case SVG_ANGLETYPE_DEG:
    223         case SVG_ANGLETYPE_UNKNOWN:
    224             ASSERT_NOT_REACHED();
    225             break;
    226         }
    227         break;
    228     case SVG_ANGLETYPE_UNKNOWN:
    229         ASSERT_NOT_REACHED();
    230         break;
    231     }
    232 
    233     m_unitType = static_cast<SVGAngleType>(unitType);
    234 }
    235 
    236 }
    237 
    238 #endif // ENABLE(SVG)
    239