2
Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
3
2004, 2005, 2006 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., 59 Temple Place - Suite 330,
21
Boston, MA 02111-1307, USA.
27
#include "SVGLength.h"
29
#include "CSSHelper.h"
30
#include "DeprecatedString.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
inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type)
47
return (mode << 4) | type;
50
inline SVGLengthMode extractMode(unsigned int unit)
52
unsigned int mode = unit >> 4;
53
return static_cast<SVGLengthMode>(mode);
56
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
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
void SVGLength::setValueAsString(const String& s)
243
double convertedNumber = 0;
244
const UChar* ptr = s.characters();
245
const UChar* end = ptr + s.length();
246
parseNumber(ptr, end, convertedNumber, false);
248
m_unit = storeUnit(extractMode(m_unit), stringToLengthType(s));
249
m_valueInSpecifiedUnits = narrowPrecisionToFloat(convertedNumber);
252
String SVGLength::valueAsString() const
254
return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit));
257
void SVGLength::newValueSpecifiedUnits(unsigned short type, float value)
259
ASSERT(type <= LengthTypePC);
261
m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
262
m_valueInSpecifiedUnits = value;
265
void SVGLength::convertToSpecifiedUnits(unsigned short type)
267
ASSERT(type <= LengthTypePC);
269
float valueInUserUnits = value();
270
m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
271
setValue(valueInUserUnits);
274
float SVGLength::PercentageOfViewport(float value, const SVGStyledElement* context, SVGLengthMode mode)
278
float width = 0, height = 0;
279
SVGElement* viewportElement = context->viewportElement();
281
Document* doc = context->document();
282
if (doc->documentElement() == context) {
283
// We have to ask the canvas for the full "canvas size"...
284
RenderView* view = static_cast<RenderView*>(doc->renderer());
285
if (view && view->frameView()) {
286
width = view->frameView()->visibleWidth(); // TODO: recheck!
287
height = view->frameView()->visibleHeight(); // TODO: recheck!
289
} else if (viewportElement && viewportElement->isSVG()) {
290
const SVGSVGElement* svg = static_cast<const SVGSVGElement*>(viewportElement);
291
if (svg->hasAttribute(SVGNames::viewBoxAttr)) {
292
width = svg->viewBox().width();
293
height = svg->viewBox().height();
295
width = svg->width().value();
296
height = svg->height().value();
298
} else if (context->parent() && !context->parent()->isSVGElement()) {
299
if (RenderObject* renderer = context->renderer()) {
300
width = renderer->width();
301
height = renderer->height();
305
if (mode == LengthModeWidth)
306
return value * width;
307
else if (mode == LengthModeHeight)
308
return value * height;
309
else if (mode == LengthModeOther)
310
return value * sqrtf(powf(width, 2) + powf(height, 2)) / sqrtf(2.0f);
317
#endif // ENABLE(SVG)