KHTML
SVGLength.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 2007 Apple Inc. All rights reserved. 00005 00006 This file is part of the KDE project 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 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 /*#include "FrameView.h"*/ 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 // Helper functions 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 /*RenderStyle* style = 0; 00146 if (m_context && m_context->renderer()) 00147 style = m_context->renderer()->style(); 00148 if (style) { 00149 float useSize = style->fontSize(); 00150 ASSERT(useSize > 0); 00151 if (type == LengthTypeEMS) 00152 return m_valueInSpecifiedUnits * useSize; 00153 else { 00154 float xHeight = style->font().xHeight(); 00155 // Use of ceil allows a pixel match to the W3Cs expected output of coords-units-03-b.svg 00156 // if this causes problems in real world cases maybe it would be best to remove this 00157 return m_valueInSpecifiedUnits * ceilf(xHeight); 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 // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed 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 //return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit)); 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 // We have to ask the canvas for the full "canvas size"... 00295 RenderView* view = static_cast<RenderView*>(doc->renderer()); 00296 if (view && view->view()) { 00297 width = view->view()->visibleWidth(); // TODO: recheck! 00298 height = view->view()->visibleHeight(); // TODO: recheck! 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 // vim:ts=4:noet
KDE 4.6 API Reference