File indexing completed on 2024-04-28 15:24:34
0001 /* 0002 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org> 0003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 0004 2007 Apple Inc. All rights reserved. 0005 0006 This file is part of the KDE project 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #include "wtf/Platform.h" 0025 0026 #if ENABLE(SVG) 0027 #include "SVGLength.h" 0028 0029 #include "css/csshelper.h" 0030 #include "FloatConversion.h" 0031 /*#include "FrameView.h"*/ 0032 #include "RenderObject.h" 0033 #include "RenderView.h" 0034 #include "SVGParserUtilities.h" 0035 #include "SVGSVGElement.h" 0036 #include "SVGStyledElement.h" 0037 0038 #include <math.h> 0039 #include <wtf/Assertions.h> 0040 0041 namespace WebCore 0042 { 0043 0044 // Helper functions 0045 static inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type) 0046 { 0047 return (mode << 4) | type; 0048 } 0049 0050 static inline SVGLengthMode extractMode(unsigned int unit) 0051 { 0052 unsigned int mode = unit >> 4; 0053 return static_cast<SVGLengthMode>(mode); 0054 } 0055 0056 static inline SVGLengthType extractType(unsigned int unit) 0057 { 0058 unsigned int mode = unit >> 4; 0059 unsigned int type = unit ^ (mode << 4); 0060 return static_cast<SVGLengthType>(type); 0061 } 0062 0063 static inline String lengthTypeToString(SVGLengthType type) 0064 { 0065 switch (type) { 0066 case LengthTypeUnknown: 0067 case LengthTypeNumber: 0068 return ""; 0069 case LengthTypePercentage: 0070 return "%"; 0071 case LengthTypeEMS: 0072 return "em"; 0073 case LengthTypeEXS: 0074 return "ex"; 0075 case LengthTypePX: 0076 return "px"; 0077 case LengthTypeCM: 0078 return "cm"; 0079 case LengthTypeMM: 0080 return "mm"; 0081 case LengthTypeIN: 0082 return "in"; 0083 case LengthTypePT: 0084 return "pt"; 0085 case LengthTypePC: 0086 return "pc"; 0087 } 0088 0089 return String(); 0090 } 0091 0092 inline SVGLengthType stringToLengthType(const String &string) 0093 { 0094 if (string.endsWith("%")) { 0095 return LengthTypePercentage; 0096 } else if (string.endsWith("em")) { 0097 return LengthTypeEMS; 0098 } else if (string.endsWith("ex")) { 0099 return LengthTypeEXS; 0100 } else if (string.endsWith("px")) { 0101 return LengthTypePX; 0102 } else if (string.endsWith("cm")) { 0103 return LengthTypeCM; 0104 } else if (string.endsWith("mm")) { 0105 return LengthTypeMM; 0106 } else if (string.endsWith("in")) { 0107 return LengthTypeIN; 0108 } else if (string.endsWith("pt")) { 0109 return LengthTypePT; 0110 } else if (string.endsWith("pc")) { 0111 return LengthTypePC; 0112 } else if (!string.isEmpty()) { 0113 return LengthTypeNumber; 0114 } 0115 0116 return LengthTypeUnknown; 0117 } 0118 0119 SVGLength::SVGLength(const SVGStyledElement *context, SVGLengthMode mode, const String &valueAsString) 0120 : m_valueInSpecifiedUnits(0.0f) 0121 , m_unit(storeUnit(mode, LengthTypeNumber)) 0122 , m_context(context) 0123 { 0124 setValueAsString(valueAsString); 0125 } 0126 0127 SVGLengthType SVGLength::unitType() const 0128 { 0129 return extractType(m_unit); 0130 } 0131 0132 float SVGLength::value() const 0133 { 0134 SVGLengthType type = extractType(m_unit); 0135 if (type == LengthTypeUnknown) { 0136 return 0.0f; 0137 } 0138 0139 switch (type) { 0140 case LengthTypeNumber: 0141 return m_valueInSpecifiedUnits; 0142 case LengthTypePercentage: 0143 return SVGLength::PercentageOfViewport(m_valueInSpecifiedUnits / 100.0f, m_context, extractMode(m_unit)); 0144 case LengthTypeEMS: 0145 case LengthTypeEXS: { 0146 /*RenderStyle* style = 0; 0147 if (m_context && m_context->renderer()) 0148 style = m_context->renderer()->style(); 0149 if (style) { 0150 float useSize = style->fontSize(); 0151 ASSERT(useSize > 0); 0152 if (type == LengthTypeEMS) 0153 return m_valueInSpecifiedUnits * useSize; 0154 else { 0155 float xHeight = style->font().xHeight(); 0156 // Use of ceil allows a pixel match to the W3Cs expected output of coords-units-03-b.svg 0157 // if this causes problems in real world cases maybe it would be best to remove this 0158 return m_valueInSpecifiedUnits * ceilf(xHeight); 0159 } 0160 }*/ 0161 return 0.0f; 0162 } 0163 case LengthTypePX: 0164 return m_valueInSpecifiedUnits; 0165 case LengthTypeCM: 0166 return m_valueInSpecifiedUnits / 2.54f * cssPixelsPerInch; 0167 case LengthTypeMM: 0168 return m_valueInSpecifiedUnits / 25.4f * cssPixelsPerInch; 0169 case LengthTypeIN: 0170 return m_valueInSpecifiedUnits * cssPixelsPerInch; 0171 case LengthTypePT: 0172 return m_valueInSpecifiedUnits / 72.0f * cssPixelsPerInch; 0173 case LengthTypePC: 0174 return m_valueInSpecifiedUnits / 6.0f * cssPixelsPerInch; 0175 default: 0176 break; 0177 } 0178 0179 ASSERT_NOT_REACHED(); 0180 return 0.0f; 0181 } 0182 0183 void SVGLength::setValue(float value) 0184 { 0185 SVGLengthType type = extractType(m_unit); 0186 ASSERT(type != LengthTypeUnknown); 0187 0188 switch (type) { 0189 case LengthTypeNumber: 0190 m_valueInSpecifiedUnits = value; 0191 break; 0192 case LengthTypePercentage: 0193 case LengthTypeEMS: 0194 case LengthTypeEXS: 0195 ASSERT_NOT_REACHED(); 0196 break; 0197 case LengthTypePX: 0198 m_valueInSpecifiedUnits = value; 0199 break; 0200 case LengthTypeCM: 0201 m_valueInSpecifiedUnits = value * 2.54f / cssPixelsPerInch; 0202 break; 0203 case LengthTypeMM: 0204 m_valueInSpecifiedUnits = value * 25.4f / cssPixelsPerInch; 0205 break; 0206 case LengthTypeIN: 0207 m_valueInSpecifiedUnits = value / cssPixelsPerInch; 0208 break; 0209 case LengthTypePT: 0210 m_valueInSpecifiedUnits = value * 72.0f / cssPixelsPerInch; 0211 break; 0212 case LengthTypePC: 0213 m_valueInSpecifiedUnits = value / 6.0f * cssPixelsPerInch; 0214 break; 0215 default: 0216 break; 0217 } 0218 } 0219 0220 void SVGLength::setValueInSpecifiedUnits(float value) 0221 { 0222 m_valueInSpecifiedUnits = value; 0223 } 0224 0225 float SVGLength::valueInSpecifiedUnits() const 0226 { 0227 return m_valueInSpecifiedUnits; 0228 } 0229 0230 float SVGLength::valueAsPercentage() const 0231 { 0232 // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed 0233 if (extractType(m_unit) == LengthTypePercentage) { 0234 return valueInSpecifiedUnits() / 100.0f; 0235 } 0236 0237 return valueInSpecifiedUnits(); 0238 } 0239 0240 bool SVGLength::setValueAsString(const String &s) 0241 { 0242 if (s.isEmpty()) { 0243 return false; 0244 } 0245 0246 float convertedNumber = 0.0f; 0247 const UChar *ptr = s.characters(); 0248 const UChar *end = ptr + s.length(); 0249 0250 if (!parseNumber(ptr, end, convertedNumber, false)) { 0251 return false; 0252 } 0253 0254 SVGLengthType type = stringToLengthType(s); 0255 if (ptr != end && type == LengthTypeNumber) { 0256 return false; 0257 } 0258 0259 // qCDebug(KHTML_LOG) << convertedNumber << type; 0260 0261 m_unit = storeUnit(extractMode(m_unit), type); 0262 m_valueInSpecifiedUnits = convertedNumber; 0263 return true; 0264 } 0265 0266 String SVGLength::valueAsString() const 0267 { 0268 //return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit)); 0269 ASSERT(false); 0270 return ""; 0271 } 0272 0273 void SVGLength::newValueSpecifiedUnits(unsigned short type, float value) 0274 { 0275 ASSERT(type <= LengthTypePC); 0276 0277 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type); 0278 m_valueInSpecifiedUnits = value; 0279 } 0280 0281 void SVGLength::convertToSpecifiedUnits(unsigned short type) 0282 { 0283 ASSERT(type <= LengthTypePC); 0284 0285 float valueInUserUnits = value(); 0286 m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type); 0287 setValue(valueInUserUnits); 0288 } 0289 0290 float SVGLength::PercentageOfViewport(float value, const SVGStyledElement *context, SVGLengthMode mode) 0291 { 0292 ASSERT(context); 0293 0294 float width = 0.0f, height = 0.0f; 0295 SVGElement *viewportElement = context->viewportElement(); 0296 0297 Document *doc = context->document(); 0298 if (doc->documentElement() == context) { 0299 // We have to ask the canvas for the full "canvas size"... 0300 RenderView *view = static_cast<RenderView *>(doc->renderer()); 0301 if (view && view->view()) { 0302 width = view->view()->visibleWidth(); // TODO: recheck! 0303 height = view->view()->visibleHeight(); // TODO: recheck! 0304 } 0305 } else if (viewportElement && viewportElement->isSVG()) { 0306 const SVGSVGElement *svg = static_cast<const SVGSVGElement *>(viewportElement); 0307 if (svg->hasAttribute(SVGNames::viewBoxAttr)) { 0308 width = svg->viewBox().width(); 0309 height = svg->viewBox().height(); 0310 } else { 0311 width = svg->width().value(); 0312 height = svg->height().value(); 0313 } 0314 } else if (context->parent() && !context->parent()->isSVGElement()) { 0315 if (RenderObject *renderer = context->renderer()) { 0316 width = renderer->width(); 0317 height = renderer->height(); 0318 } 0319 } 0320 0321 if (mode == LengthModeWidth) { 0322 return value * width; 0323 } else if (mode == LengthModeHeight) { 0324 return value * height; 0325 } else if (mode == LengthModeOther) { 0326 return value * sqrtf(powf(width, 2) + powf(height, 2)) / sqrtf(2.0f); 0327 } 0328 0329 return 0.0f; 0330 } 0331 0332 } 0333 0334 #endif // ENABLE(SVG) 0335