KHTML
SVGLength.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "wtf/Platform.h"
00026
00027 #if ENABLE(SVG)
00028 #include "SVGLength.h"
00029
00030 #include "css/csshelper.h"
00031 #include "FloatConversion.h"
00032
00033 #include "RenderObject.h"
00034 #include "RenderView.h"
00035 #include "SVGParserUtilities.h"
00036 #include "SVGSVGElement.h"
00037 #include "SVGStyledElement.h"
00038
00039 #include <math.h>
00040 #include <wtf/Assertions.h>
00041
00042 namespace WebCore {
00043
00044
00045 static inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type)
00046 {
00047 return (mode << 4) | type;
00048 }
00049
00050 static inline SVGLengthMode extractMode(unsigned int unit)
00051 {
00052 unsigned int mode = unit >> 4;
00053 return static_cast<SVGLengthMode>(mode);
00054 }
00055
00056 static inline SVGLengthType extractType(unsigned int unit)
00057 {
00058 unsigned int mode = unit >> 4;
00059 unsigned int type = unit ^ (mode << 4);
00060 return static_cast<SVGLengthType>(type);
00061 }
00062
00063 static inline String lengthTypeToString(SVGLengthType type)
00064 {
00065 switch (type) {
00066 case LengthTypeUnknown:
00067 case LengthTypeNumber:
00068 return "";
00069 case LengthTypePercentage:
00070 return "%";
00071 case LengthTypeEMS:
00072 return "em";
00073 case LengthTypeEXS:
00074 return "ex";
00075 case LengthTypePX:
00076 return "px";
00077 case LengthTypeCM:
00078 return "cm";
00079 case LengthTypeMM:
00080 return "mm";
00081 case LengthTypeIN:
00082 return "in";
00083 case LengthTypePT:
00084 return "pt";
00085 case LengthTypePC:
00086 return "pc";
00087 }
00088
00089 return String();
00090 }
00091
00092 inline SVGLengthType stringToLengthType(const String& string)
00093 {
00094 if (string.endsWith("%"))
00095 return LengthTypePercentage;
00096 else if (string.endsWith("em"))
00097 return LengthTypeEMS;
00098 else if (string.endsWith("ex"))
00099 return LengthTypeEXS;
00100 else if (string.endsWith("px"))
00101 return LengthTypePX;
00102 else if (string.endsWith("cm"))
00103 return LengthTypeCM;
00104 else if (string.endsWith("mm"))
00105 return LengthTypeMM;
00106 else if (string.endsWith("in"))
00107 return LengthTypeIN;
00108 else if (string.endsWith("pt"))
00109 return LengthTypePT;
00110 else if (string.endsWith("pc"))
00111 return LengthTypePC;
00112 else if (!string.isEmpty())
00113 return LengthTypeNumber;
00114
00115 return LengthTypeUnknown;
00116 }
00117
00118 SVGLength::SVGLength(const SVGStyledElement* context, SVGLengthMode mode, const String& valueAsString)
00119 : m_valueInSpecifiedUnits(0.0f)
00120 , m_unit(storeUnit(mode, LengthTypeNumber))
00121 , m_context(context)
00122 {
00123 setValueAsString(valueAsString);
00124 }
00125
00126 SVGLengthType SVGLength::unitType() const
00127 {
00128 return extractType(m_unit);
00129 }
00130
00131 float SVGLength::value() const
00132 {
00133 SVGLengthType type = extractType(m_unit);
00134 if (type == LengthTypeUnknown)
00135 return 0.0f;
00136
00137 switch (type) {
00138 case LengthTypeNumber:
00139 return m_valueInSpecifiedUnits;
00140 case LengthTypePercentage:
00141 return SVGLength::PercentageOfViewport(m_valueInSpecifiedUnits / 100.0f, m_context, extractMode(m_unit));
00142 case LengthTypeEMS:
00143 case LengthTypeEXS:
00144 {
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160 return 0.0f;
00161 }
00162 case LengthTypePX:
00163 return m_valueInSpecifiedUnits;
00164 case LengthTypeCM:
00165 return m_valueInSpecifiedUnits / 2.54f * cssPixelsPerInch;
00166 case LengthTypeMM:
00167 return m_valueInSpecifiedUnits / 25.4f * cssPixelsPerInch;
00168 case LengthTypeIN:
00169 return m_valueInSpecifiedUnits * cssPixelsPerInch;
00170 case LengthTypePT:
00171 return m_valueInSpecifiedUnits / 72.0f * cssPixelsPerInch;
00172 case LengthTypePC:
00173 return m_valueInSpecifiedUnits / 6.0f * cssPixelsPerInch;
00174 default:
00175 break;
00176 }
00177
00178 ASSERT_NOT_REACHED();
00179 return 0.0f;
00180 }
00181
00182 void SVGLength::setValue(float value)
00183 {
00184 SVGLengthType type = extractType(m_unit);
00185 ASSERT(type != LengthTypeUnknown);
00186
00187 switch (type) {
00188 case LengthTypeNumber:
00189 m_valueInSpecifiedUnits = value;
00190 break;
00191 case LengthTypePercentage:
00192 case LengthTypeEMS:
00193 case LengthTypeEXS:
00194 ASSERT_NOT_REACHED();
00195 break;
00196 case LengthTypePX:
00197 m_valueInSpecifiedUnits = value;
00198 break;
00199 case LengthTypeCM:
00200 m_valueInSpecifiedUnits = value * 2.54f / cssPixelsPerInch;
00201 break;
00202 case LengthTypeMM:
00203 m_valueInSpecifiedUnits = value * 25.4f / cssPixelsPerInch;
00204 break;
00205 case LengthTypeIN:
00206 m_valueInSpecifiedUnits = value / cssPixelsPerInch;
00207 break;
00208 case LengthTypePT:
00209 m_valueInSpecifiedUnits = value * 72.0f / cssPixelsPerInch;
00210 break;
00211 case LengthTypePC:
00212 m_valueInSpecifiedUnits = value / 6.0f * cssPixelsPerInch;
00213 break;
00214 default:
00215 break;
00216 }
00217 }
00218
00219 void SVGLength::setValueInSpecifiedUnits(float value)
00220 {
00221 m_valueInSpecifiedUnits = value;
00222 }
00223
00224 float SVGLength::valueInSpecifiedUnits() const
00225 {
00226 return m_valueInSpecifiedUnits;
00227 }
00228
00229 float SVGLength::valueAsPercentage() const
00230 {
00231
00232 if (extractType(m_unit) == LengthTypePercentage)
00233 return valueInSpecifiedUnits() / 100.0f;
00234
00235 return valueInSpecifiedUnits();
00236 }
00237
00238 bool SVGLength::setValueAsString(const String& s)
00239 {
00240 if (s.isEmpty())
00241 return false;
00242
00243 float convertedNumber = 0.0f;
00244 const UChar* ptr = s.characters();
00245 const UChar* end = ptr + s.length();
00246
00247 if (!parseNumber(ptr, end, convertedNumber, false))
00248 return false;
00249
00250 SVGLengthType type = stringToLengthType(s);
00251 if (ptr != end && type == LengthTypeNumber)
00252 return false;
00253
00254 kDebug() << convertedNumber << type;
00255
00256 m_unit = storeUnit(extractMode(m_unit), type);
00257 m_valueInSpecifiedUnits = convertedNumber;
00258 return true;
00259 }
00260
00261 String SVGLength::valueAsString() const
00262 {
00263
00264 ASSERT(false);
00265 return "";
00266 }
00267
00268 void SVGLength::newValueSpecifiedUnits(unsigned short type, float value)
00269 {
00270 ASSERT(type <= LengthTypePC);
00271
00272 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
00273 m_valueInSpecifiedUnits = value;
00274 }
00275
00276 void SVGLength::convertToSpecifiedUnits(unsigned short type)
00277 {
00278 ASSERT(type <= LengthTypePC);
00279
00280 float valueInUserUnits = value();
00281 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
00282 setValue(valueInUserUnits);
00283 }
00284
00285 float SVGLength::PercentageOfViewport(float value, const SVGStyledElement* context, SVGLengthMode mode)
00286 {
00287 ASSERT(context);
00288
00289 float width = 0.0f, height = 0.0f;
00290 SVGElement* viewportElement = context->viewportElement();
00291
00292 Document* doc = context->document();
00293 if (doc->documentElement() == context) {
00294
00295 RenderView* view = static_cast<RenderView*>(doc->renderer());
00296 if (view && view->view()) {
00297 width = view->view()->visibleWidth();
00298 height = view->view()->visibleHeight();
00299 }
00300 } else if (viewportElement && viewportElement->isSVG()) {
00301 const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(viewportElement);
00302 if (svg->hasAttribute(SVGNames::viewBoxAttr)) {
00303 width = svg->viewBox().width();
00304 height = svg->viewBox().height();
00305 } else {
00306 width = svg->width().value();
00307 height = svg->height().value();
00308 }
00309 } else if (context->parent() && !context->parent()->isSVGElement()) {
00310 if (RenderObject* renderer = context->renderer()) {
00311 width = renderer->width();
00312 height = renderer->height();
00313 }
00314 }
00315
00316 if (mode == LengthModeWidth)
00317 return value * width;
00318 else if (mode == LengthModeHeight)
00319 return value * height;
00320 else if (mode == LengthModeOther)
00321 return value * sqrtf(powf(width, 2) + powf(height, 2)) / sqrtf(2.0f);
00322
00323 return 0.0f;
00324 }
00325
00326 }
00327
00328 #endif // ENABLE(SVG)
00329
00330