2 Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 2007 Apple Inc. All rights reserved.
6 This file is part of the KDE project
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
25 #include "wtf/Platform.h"
28 #include "SVGLength.h"
30 #include "css/csshelper.h"
31 #include "FloatConversion.h"
32 /*#include "FrameView.h"*/
33 #include "RenderObject.h"
34 #include "RenderView.h"
35 #include "SVGParserUtilities.h"
36 #include "SVGSVGElement.h"
37 #include "SVGStyledElement.h"
40 #include <wtf/Assertions.h>
45 static inline unsigned int storeUnit(SVGLengthMode mode
, SVGLengthType type
)
47 return (mode
<< 4) | type
;
50 static inline SVGLengthMode
extractMode(unsigned int unit
)
52 unsigned int mode
= unit
>> 4;
53 return static_cast<SVGLengthMode
>(mode
);
56 static inline SVGLengthType
extractType(unsigned int unit
)
58 unsigned int mode
= unit
>> 4;
59 unsigned int type
= unit
^ (mode
<< 4);
60 return static_cast<SVGLengthType
>(type
);
63 static inline String
lengthTypeToString(SVGLengthType type
)
66 case LengthTypeUnknown
:
67 case LengthTypeNumber
:
69 case LengthTypePercentage
:
92 inline SVGLengthType
stringToLengthType(const String
& string
)
94 if (string
.endsWith("%"))
95 return LengthTypePercentage
;
96 else if (string
.endsWith("em"))
98 else if (string
.endsWith("ex"))
100 else if (string
.endsWith("px"))
102 else if (string
.endsWith("cm"))
104 else if (string
.endsWith("mm"))
106 else if (string
.endsWith("in"))
108 else if (string
.endsWith("pt"))
110 else if (string
.endsWith("pc"))
112 else if (!string
.isEmpty())
113 return LengthTypeNumber
;
115 return LengthTypeUnknown
;
118 SVGLength::SVGLength(const SVGStyledElement
* context
, SVGLengthMode mode
, const String
& valueAsString
)
119 : m_valueInSpecifiedUnits(0.0f
)
120 , m_unit(storeUnit(mode
, LengthTypeNumber
))
123 setValueAsString(valueAsString
);
126 SVGLengthType
SVGLength::unitType() const
128 return extractType(m_unit
);
131 float SVGLength::value() const
133 SVGLengthType type
= extractType(m_unit
);
134 if (type
== LengthTypeUnknown
)
138 case LengthTypeNumber
:
139 return m_valueInSpecifiedUnits
;
140 case LengthTypePercentage
:
141 return SVGLength::PercentageOfViewport(m_valueInSpecifiedUnits
/ 100.0f
, m_context
, extractMode(m_unit
));
145 /*RenderStyle* style = 0;
146 if (m_context && m_context->renderer())
147 style = m_context->renderer()->style();
149 float useSize = style->fontSize();
151 if (type == LengthTypeEMS)
152 return m_valueInSpecifiedUnits * useSize;
154 float xHeight = style->font().xHeight();
155 // Use of ceil allows a pixel match to the W3Cs expected output of coords-units-03-b.svg
156 // if this causes problems in real world cases maybe it would be best to remove this
157 return m_valueInSpecifiedUnits * ceilf(xHeight);
163 return m_valueInSpecifiedUnits
;
165 return m_valueInSpecifiedUnits
/ 2.54f
* cssPixelsPerInch
;
167 return m_valueInSpecifiedUnits
/ 25.4f
* cssPixelsPerInch
;
169 return m_valueInSpecifiedUnits
* cssPixelsPerInch
;
171 return m_valueInSpecifiedUnits
/ 72.0f
* cssPixelsPerInch
;
173 return m_valueInSpecifiedUnits
/ 6.0f
* cssPixelsPerInch
;
178 ASSERT_NOT_REACHED();
182 void SVGLength::setValue(float value
)
184 SVGLengthType type
= extractType(m_unit
);
185 ASSERT(type
!= LengthTypeUnknown
);
188 case LengthTypeNumber
:
189 m_valueInSpecifiedUnits
= value
;
191 case LengthTypePercentage
:
194 ASSERT_NOT_REACHED();
197 m_valueInSpecifiedUnits
= value
;
200 m_valueInSpecifiedUnits
= value
* 2.54f
/ cssPixelsPerInch
;
203 m_valueInSpecifiedUnits
= value
* 25.4f
/ cssPixelsPerInch
;
206 m_valueInSpecifiedUnits
= value
/ cssPixelsPerInch
;
209 m_valueInSpecifiedUnits
= value
* 72.0f
/ cssPixelsPerInch
;
212 m_valueInSpecifiedUnits
= value
/ 6.0f
* cssPixelsPerInch
;
219 void SVGLength::setValueInSpecifiedUnits(float value
)
221 m_valueInSpecifiedUnits
= value
;
224 float SVGLength::valueInSpecifiedUnits() const
226 return m_valueInSpecifiedUnits
;
229 float SVGLength::valueAsPercentage() const
231 // 100% = 100.0 instead of 1.0 for historical reasons, this could eventually be changed
232 if (extractType(m_unit
) == LengthTypePercentage
)
233 return valueInSpecifiedUnits() / 100.0f
;
235 return valueInSpecifiedUnits();
238 bool SVGLength::setValueAsString(const String
& s
)
243 float convertedNumber
= 0.0f
;
244 const UChar
* ptr
= s
.characters();
245 const UChar
* end
= ptr
+ s
.length();
247 if (!parseNumber(ptr
, end
, convertedNumber
, false))
250 SVGLengthType type
= stringToLengthType(s
);
251 if (ptr
!= end
&& type
== LengthTypeNumber
)
254 m_unit
= storeUnit(extractMode(m_unit
), type
);
255 m_valueInSpecifiedUnits
= convertedNumber
;
259 String
SVGLength::valueAsString() const
261 //return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit));
266 void SVGLength::newValueSpecifiedUnits(unsigned short type
, float value
)
268 ASSERT(type
<= LengthTypePC
);
270 m_unit
= storeUnit(extractMode(m_unit
), (SVGLengthType
) type
);
271 m_valueInSpecifiedUnits
= value
;
274 void SVGLength::convertToSpecifiedUnits(unsigned short type
)
276 ASSERT(type
<= LengthTypePC
);
278 float valueInUserUnits
= value();
279 m_unit
= storeUnit(extractMode(m_unit
), (SVGLengthType
) type
);
280 setValue(valueInUserUnits
);
283 float SVGLength::PercentageOfViewport(float value
, const SVGStyledElement
* context
, SVGLengthMode mode
)
287 float width
= 0.0f
, height
= 0.0f
;
288 SVGElement
* viewportElement
= context
->viewportElement();
290 Document
* doc
= context
->document();
291 if (doc
->documentElement() == context
) {
292 // We have to ask the canvas for the full "canvas size"...
293 RenderView
* view
= static_cast<RenderView
*>(doc
->renderer());
294 if (view
&& view
->view()) {
295 width
= view
->view()->visibleWidth(); // TODO: recheck!
296 height
= view
->view()->visibleHeight(); // TODO: recheck!
298 } else if (viewportElement
&& viewportElement
->isSVG()) {
299 const SVGSVGElement
* svg
= static_cast<const SVGSVGElement
*>(viewportElement
);
300 if (svg
->hasAttribute(SVGNames::viewBoxAttr
)) {
301 width
= svg
->viewBox().width();
302 height
= svg
->viewBox().height();
304 width
= svg
->width().value();
305 height
= svg
->height().value();
307 } else if (context
->parent() && !context
->parent()->isSVGElement()) {
308 if (RenderObject
* renderer
= context
->renderer()) {
309 width
= renderer
->width();
310 height
= renderer
->height();
314 if (mode
== LengthModeWidth
)
315 return value
* width
;
316 else if (mode
== LengthModeHeight
)
317 return value
* height
;
318 else if (mode
== LengthModeOther
)
319 return value
* sqrtf(powf(width
, 2) + powf(height
, 2)) / sqrtf(2.0f
);
326 #endif // ENABLE(SVG)