2010-10-23 Nikolas Zimmermann <nzimmermann@rim.com>
[WebKit-https.git] / WebCore / svg / SVGAngle.cpp
index 6702904..6475064 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
  * Copyright (C) 2004, 2005, 2006 Rob Buis <buis@kde.org>
+ * Copyright (C) Research In Motion Limited 2010. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  */
 
 #include "config.h"
-#include "SVGAngle.h"
 
 #if ENABLE(SVG)
+#include "SVGAngle.h"
 
+#include "SVGParserUtilities.h"
+#include <wtf/text/StringConcatenate.h>
 #include <wtf/MathExtras.h>
 
 namespace WebCore {
 
 SVGAngle::SVGAngle()
-    : m_unitType(SVG_ANGLETYPE_UNKNOWN)
-    , m_value(0)
+    : m_unitType(SVG_ANGLETYPE_UNSPECIFIED)
     , m_valueInSpecifiedUnits(0)
 {
 }
 
+float SVGAngle::value() const
+{
+    switch (m_unitType) {
+    case SVG_ANGLETYPE_GRAD:
+        return grad2deg(m_valueInSpecifiedUnits);
+    case SVG_ANGLETYPE_RAD:
+        return rad2deg(m_valueInSpecifiedUnits);
+    case SVG_ANGLETYPE_UNSPECIFIED:
+    case SVG_ANGLETYPE_UNKNOWN:
+    case SVG_ANGLETYPE_DEG:
+        return m_valueInSpecifiedUnits;
+    }
+
+    ASSERT_NOT_REACHED();
+    return 0;
+}
+
 void SVGAngle::setValue(float value)
 {
-    m_value = value;
+    switch (m_unitType) {
+    case SVG_ANGLETYPE_GRAD:
+        m_valueInSpecifiedUnits = deg2grad(value);
+        break;
+    case SVG_ANGLETYPE_RAD:
+        m_valueInSpecifiedUnits = deg2rad(value);
+        break;
+    case SVG_ANGLETYPE_UNSPECIFIED:
+    case SVG_ANGLETYPE_UNKNOWN:
+    case SVG_ANGLETYPE_DEG:
+        m_valueInSpecifiedUnits = value;
+        break;
+    }
+}
+
+inline SVGAngle::SVGAngleType stringToAngleType(const UChar*& ptr, const UChar* end)
+{
+    // If there's no unit given, the angle type is unspecified.
+    if (ptr == end)
+        return SVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
+
+    const UChar firstChar = *ptr;
+    
+    // If the unit contains only one character, the angle type is unknown.
+    ++ptr;
+    if (ptr == end)
+        return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
+
+    const UChar secondChar = *ptr;
+    // If the unit contains only two characters, the angle type is unknown.
+    ++ptr;
+    if (ptr == end)
+        return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
+
+    const UChar thirdChar = *ptr;
+    if (firstChar == 'd' && secondChar == 'e' && thirdChar == 'g')
+        return SVGAngle::SVG_ANGLETYPE_DEG;
+    if (firstChar == 'r' && secondChar == 'a' && thirdChar == 'd')
+        return SVGAngle::SVG_ANGLETYPE_RAD;
+
+    // If the unit contains three characters, but is not deg or rad, then it's unknown.
+    ++ptr;
+    if (ptr == end)
+        return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
+
+    const UChar fourthChar = *ptr;
+
+    if (firstChar == 'g' && secondChar == 'r' && thirdChar == 'a' && fourthChar == 'd')
+        return SVGAngle::SVG_ANGLETYPE_GRAD;
+
+    return SVGAngle::SVG_ANGLETYPE_UNKNOWN;
 }
 
-// calc m_value
-void SVGAngle::calculate()
+String SVGAngle::valueAsString() const
 {
-    if (m_unitType == SVG_ANGLETYPE_GRAD)
-        m_value = grad2deg(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_RAD)
-        m_value = rad2deg(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_UNSPECIFIED || m_unitType == SVG_ANGLETYPE_DEG)
-        m_value = m_valueInSpecifiedUnits;
+    switch (m_unitType) {
+    case SVG_ANGLETYPE_DEG:
+        return makeString(String::number(m_valueInSpecifiedUnits), "deg");
+    case SVG_ANGLETYPE_RAD:
+        return makeString(String::number(m_valueInSpecifiedUnits), "rad");
+    case SVG_ANGLETYPE_GRAD:
+        return makeString(String::number(m_valueInSpecifiedUnits), "grad");
+    case SVG_ANGLETYPE_UNSPECIFIED:
+    case SVG_ANGLETYPE_UNKNOWN:
+        return makeString(String::number(m_valueInSpecifiedUnits));
+    }
+
+    ASSERT_NOT_REACHED();
+    return String();
 }
 
-void SVGAngle::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+void SVGAngle::setValueAsString(const String& value, ExceptionCode& ec)
 {
+    if (value.isEmpty()) {
+        m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
+        return;
+    }
+
+    float valueInSpecifiedUnits = 0;
+    const UChar* ptr = value.characters();
+    const UChar* end = ptr + value.length();
+
+    if (!parseNumber(ptr, end, valueInSpecifiedUnits, false)) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    SVGAngleType unitType = stringToAngleType(ptr, end);
+    if (unitType == SVG_ANGLETYPE_UNKNOWN) {
+        ec = SYNTAX_ERR;
+        return;
+    }
+
+    m_unitType = unitType;
     m_valueInSpecifiedUnits = valueInSpecifiedUnits;
-    calculate();
 }
 
-void SVGAngle::setValueAsString(const String& s)
+void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits, ExceptionCode& ec)
 {
-    m_valueAsString = s;
-
-    bool bOK;
-    m_valueInSpecifiedUnits = m_valueAsString.toFloat(&bOK);
-    m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
-
-    if (!bOK) {
-        if (m_valueAsString.endsWith("deg"))
-            m_unitType = SVG_ANGLETYPE_DEG;
-        else if (m_valueAsString.endsWith("grad"))
-            m_unitType = SVG_ANGLETYPE_GRAD;
-        else if (m_valueAsString.endsWith("rad"))
-            m_unitType = SVG_ANGLETYPE_RAD;
+    if (unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
     }
-    
-    calculate();
+
+    if (unitType != m_unitType)
+        m_unitType = static_cast<SVGAngleType>(unitType);
+
+    m_valueInSpecifiedUnits = valueInSpecifiedUnits;
 }
 
-String SVGAngle::valueAsString() const
+void SVGAngle::convertToSpecifiedUnits(unsigned short unitType, ExceptionCode& ec)
 {
-    m_valueAsString = String::number(m_valueInSpecifiedUnits);
+    if (unitType == SVG_ANGLETYPE_UNKNOWN || m_unitType == SVG_ANGLETYPE_UNKNOWN || unitType > SVG_ANGLETYPE_GRAD) {
+        ec = NOT_SUPPORTED_ERR;
+        return;
+    }
+
+    if (unitType == m_unitType)
+        return;
 
     switch (m_unitType) {
+    case SVG_ANGLETYPE_RAD:
+        switch (unitType) {
+        case SVG_ANGLETYPE_GRAD:
+            m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
+            break;
+        case SVG_ANGLETYPE_UNSPECIFIED:
+        case SVG_ANGLETYPE_DEG:
+            m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
+            break;
+        case SVG_ANGLETYPE_RAD:
+        case SVG_ANGLETYPE_UNKNOWN:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+        break;
+    case SVG_ANGLETYPE_GRAD:
+        switch (unitType) {
+        case SVG_ANGLETYPE_RAD:
+            m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
+            break;
         case SVG_ANGLETYPE_UNSPECIFIED:
         case SVG_ANGLETYPE_DEG:
-            m_valueAsString += "deg";
+            m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
+            break;
+        case SVG_ANGLETYPE_GRAD:
+        case SVG_ANGLETYPE_UNKNOWN:
+            ASSERT_NOT_REACHED();
             break;
+        }
+        break;
+    case SVG_ANGLETYPE_UNSPECIFIED:
+        // Spec: For angles, a unitless value is treated the same as if degrees were specified.
+    case SVG_ANGLETYPE_DEG:
+        switch (unitType) {
         case SVG_ANGLETYPE_RAD:
-            m_valueAsString += "rad";
+            m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
             break;
         case SVG_ANGLETYPE_GRAD:
-            m_valueAsString += "grad";
+            m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
             break;
+        case SVG_ANGLETYPE_UNSPECIFIED:
+            break;
+        case SVG_ANGLETYPE_DEG:
         case SVG_ANGLETYPE_UNKNOWN:
+            ASSERT_NOT_REACHED();
             break;
+        }
+        break;
+    case SVG_ANGLETYPE_UNKNOWN:
+        ASSERT_NOT_REACHED();
+        break;
     }
-    
-    return m_valueAsString;
-}
-
-void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
-{
-    m_unitType = (SVGAngleType)unitType;
-    m_valueInSpecifiedUnits = valueInSpecifiedUnits;
-    calculate();
-}
-
-void SVGAngle::convertToSpecifiedUnits(unsigned short unitType)
-{
-    if (m_unitType == unitType)
-        return;
 
-    if (m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_RAD)
-        m_valueInSpecifiedUnits = deg2rad(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_RAD)
-        m_valueInSpecifiedUnits = grad2rad(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_GRAD)
-        m_valueInSpecifiedUnits = deg2grad(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_GRAD)
-        m_valueInSpecifiedUnits = rad2grad(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_DEG)
-        m_valueInSpecifiedUnits = rad2deg(m_valueInSpecifiedUnits);
-    else if (m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_DEG)
-        m_valueInSpecifiedUnits = grad2deg(m_valueInSpecifiedUnits);
-
-    m_unitType = (SVGAngleType)unitType;
+    m_unitType = static_cast<SVGAngleType>(unitType);
 }
 
 }