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 m_unit = storeUnit(extractMode(m_unit), type);
00255 m_valueInSpecifiedUnits = convertedNumber;
00256 return true;
00257 }
00258
00259 String SVGLength::valueAsString() const
00260 {
00261
00262 ASSERT(false);
00263 return "";
00264 }
00265
00266 void SVGLength::newValueSpecifiedUnits(unsigned short type, float value)
00267 {
00268 ASSERT(type <= LengthTypePC);
00269
00270 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
00271 m_valueInSpecifiedUnits = value;
00272 }
00273
00274 void SVGLength::convertToSpecifiedUnits(unsigned short type)
00275 {
00276 ASSERT(type <= LengthTypePC);
00277
00278 float valueInUserUnits = value();
00279 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
00280 setValue(valueInUserUnits);
00281 }
00282
00283 float SVGLength::PercentageOfViewport(float value, const SVGStyledElement* context, SVGLengthMode mode)
00284 {
00285 ASSERT(context);
00286
00287 float width = 0.0f, height = 0.0f;
00288 SVGElement* viewportElement = context->viewportElement();
00289
00290 Document* doc = context->document();
00291 if (doc->documentElement() == context) {
00292
00293 RenderView* view = static_cast<RenderView*>(doc->renderer());
00294 if (view && view->view()) {
00295 width = view->view()->visibleWidth();
00296 height = view->view()->visibleHeight();
00297 }
00298 } else if (viewportElement && viewportElement->isSVG()) {
00299 const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(viewportElement);
00300 if (svg->hasAttribute(SVGNames::viewBoxAttr)) {
00301 width = svg->viewBox().width();
00302 height = svg->viewBox().height();
00303 } else {
00304 width = svg->width().value();
00305 height = svg->height().value();
00306 }
00307 } else if (context->parent() && !context->parent()->isSVGElement()) {
00308 if (RenderObject* renderer = context->renderer()) {
00309 width = renderer->width();
00310 height = renderer->height();
00311 }
00312 }
00313
00314 if (mode == LengthModeWidth)
00315 return value * width;
00316 else if (mode == LengthModeHeight)
00317 return value * height;
00318 else if (mode == LengthModeOther)
00319 return value * sqrtf(powf(width, 2) + powf(height, 2)) / sqrtf(2.0f);
00320
00321 return 0.0f;
00322 }
00323
00324 }
00325
00326 #endif // ENABLE(SVG)
00327
00328