~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to WebCore/ksvg2/svg/SVGLength.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
5
 
 
6
    This file is part of the KDE project
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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.
 
22
*/
 
23
 
 
24
#include "config.h"
 
25
 
 
26
#if ENABLE(SVG)
 
27
#include "SVGLength.h"
 
28
 
 
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"
 
38
 
 
39
#include <math.h>
 
40
#include <wtf/Assertions.h>
 
41
 
 
42
namespace WebCore {
 
43
 
 
44
// Helper functions
 
45
inline unsigned int storeUnit(SVGLengthMode mode, SVGLengthType type)
 
46
{
 
47
    return (mode << 4) | type;
 
48
}
 
49
 
 
50
inline SVGLengthMode extractMode(unsigned int unit)
 
51
{
 
52
    unsigned int mode = unit >> 4;    
 
53
    return static_cast<SVGLengthMode>(mode);
 
54
}
 
55
 
 
56
inline SVGLengthType extractType(unsigned int unit)
 
57
{
 
58
    unsigned int mode = unit >> 4;
 
59
    unsigned int type = unit ^ (mode << 4);
 
60
    return static_cast<SVGLengthType>(type);
 
61
}
 
62
 
 
63
inline String lengthTypeToString(SVGLengthType type)
 
64
{
 
65
    switch (type) {
 
66
    case LengthTypeUnknown:
 
67
    case LengthTypeNumber:
 
68
        return "";    
 
69
    case LengthTypePercentage:
 
70
        return "%";
 
71
    case LengthTypeEMS:
 
72
        return "em";
 
73
    case LengthTypeEXS:
 
74
        return "ex";
 
75
    case LengthTypePX:
 
76
        return "px";
 
77
    case LengthTypeCM:
 
78
        return "cm";
 
79
    case LengthTypeMM:
 
80
        return "mm";
 
81
    case LengthTypeIN:
 
82
        return "in";
 
83
    case LengthTypePT:
 
84
        return "pt";
 
85
    case LengthTypePC:
 
86
        return "pc";
 
87
    }
 
88
 
 
89
    return String();
 
90
}
 
91
 
 
92
inline SVGLengthType stringToLengthType(const String& string)
 
93
{
 
94
    if (string.endsWith("%"))
 
95
        return LengthTypePercentage;
 
96
    else if (string.endsWith("em"))
 
97
        return LengthTypeEMS;
 
98
    else if (string.endsWith("ex"))
 
99
        return LengthTypeEXS;
 
100
    else if (string.endsWith("px"))
 
101
        return LengthTypePX;
 
102
    else if (string.endsWith("cm"))
 
103
        return LengthTypeCM;
 
104
    else if (string.endsWith("mm"))
 
105
        return LengthTypeMM;
 
106
    else if (string.endsWith("in"))
 
107
        return LengthTypeIN;
 
108
    else if (string.endsWith("pt"))
 
109
        return LengthTypePT;
 
110
    else if (string.endsWith("pc"))
 
111
        return LengthTypePC;
 
112
    else if (!string.isEmpty())
 
113
        return LengthTypeNumber;
 
114
 
 
115
    return LengthTypeUnknown;
 
116
}
 
117
 
 
118
SVGLength::SVGLength(const SVGStyledElement* context, SVGLengthMode mode, const String& valueAsString)
 
119
    : m_valueInSpecifiedUnits(0.0f)
 
120
    , m_unit(storeUnit(mode, LengthTypeNumber))
 
121
    , m_context(context)
 
122
{
 
123
    setValueAsString(valueAsString);
 
124
}
 
125
 
 
126
SVGLengthType SVGLength::unitType() const
 
127
{
 
128
    return extractType(m_unit);
 
129
}
 
130
 
 
131
float SVGLength::value() const
 
132
{
 
133
    SVGLengthType type = extractType(m_unit);
 
134
    if (type == LengthTypeUnknown)
 
135
        return 0.0f;
 
136
 
 
137
    switch (type) {
 
138
    case LengthTypeNumber:
 
139
        return m_valueInSpecifiedUnits;
 
140
    case LengthTypePercentage:
 
141
        return SVGLength::PercentageOfViewport(m_valueInSpecifiedUnits / 100.0f, m_context, extractMode(m_unit));
 
142
    case LengthTypeEMS:
 
143
    case LengthTypeEXS:
 
144
    {
 
145
        RenderStyle* style = 0;
 
146
        if (m_context && m_context->renderer())
 
147
            style = m_context->renderer()->style();
 
148
        if (style) {
 
149
            float useSize = style->fontSize();
 
150
            ASSERT(useSize > 0);
 
151
            if (type == LengthTypeEMS)
 
152
                return m_valueInSpecifiedUnits * useSize;
 
153
            else {
 
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);
 
158
            }
 
159
        }
 
160
        return 0.0f;
 
161
    }
 
162
    case LengthTypePX:
 
163
        return m_valueInSpecifiedUnits;
 
164
    case LengthTypeCM:
 
165
        return m_valueInSpecifiedUnits / 2.54f * cssPixelsPerInch;
 
166
    case LengthTypeMM:
 
167
        return m_valueInSpecifiedUnits / 25.4f * cssPixelsPerInch;
 
168
    case LengthTypeIN:
 
169
        return m_valueInSpecifiedUnits * cssPixelsPerInch;
 
170
    case LengthTypePT:
 
171
        return m_valueInSpecifiedUnits / 72.0f * cssPixelsPerInch;
 
172
    case LengthTypePC:
 
173
        return m_valueInSpecifiedUnits / 6.0f * cssPixelsPerInch;
 
174
    default:
 
175
        break;
 
176
    }
 
177
 
 
178
    ASSERT_NOT_REACHED();
 
179
    return 0.0f;
 
180
}
 
181
 
 
182
void SVGLength::setValue(float value)
 
183
{
 
184
    SVGLengthType type = extractType(m_unit);
 
185
    ASSERT(type != LengthTypeUnknown);
 
186
 
 
187
    switch (type) {
 
188
    case LengthTypeNumber:
 
189
        m_valueInSpecifiedUnits = value;
 
190
        break;
 
191
    case LengthTypePercentage:
 
192
    case LengthTypeEMS:
 
193
    case LengthTypeEXS:
 
194
        ASSERT_NOT_REACHED();
 
195
        break;
 
196
    case LengthTypePX:
 
197
        m_valueInSpecifiedUnits = value;
 
198
        break;
 
199
    case LengthTypeCM:
 
200
        m_valueInSpecifiedUnits = value * 2.54f / cssPixelsPerInch;
 
201
        break;
 
202
    case LengthTypeMM:
 
203
        m_valueInSpecifiedUnits = value * 25.4f / cssPixelsPerInch;
 
204
        break;
 
205
    case LengthTypeIN:
 
206
        m_valueInSpecifiedUnits = value / cssPixelsPerInch;
 
207
        break;
 
208
    case LengthTypePT:
 
209
        m_valueInSpecifiedUnits = value * 72.0f / cssPixelsPerInch;
 
210
        break;
 
211
    case LengthTypePC:
 
212
        m_valueInSpecifiedUnits = value / 6.0f * cssPixelsPerInch;
 
213
        break;
 
214
    default:
 
215
        break;
 
216
    }
 
217
}
 
218
 
 
219
void SVGLength::setValueInSpecifiedUnits(float value)
 
220
{
 
221
    m_valueInSpecifiedUnits = value;
 
222
}
 
223
 
 
224
float SVGLength::valueInSpecifiedUnits() const
 
225
{
 
226
    return m_valueInSpecifiedUnits;
 
227
}
 
228
 
 
229
float SVGLength::valueAsPercentage() const
 
230
{
 
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;
 
234
 
 
235
    return valueInSpecifiedUnits();
 
236
}
 
237
 
 
238
void SVGLength::setValueAsString(const String& s)
 
239
{
 
240
    if (s.isEmpty())
 
241
        return;
 
242
 
 
243
    double convertedNumber = 0;
 
244
    const UChar* ptr = s.characters();
 
245
    const UChar* end = ptr + s.length();
 
246
    parseNumber(ptr, end, convertedNumber, false);
 
247
 
 
248
    m_unit = storeUnit(extractMode(m_unit), stringToLengthType(s));
 
249
    m_valueInSpecifiedUnits = narrowPrecisionToFloat(convertedNumber);
 
250
}
 
251
 
 
252
String SVGLength::valueAsString() const
 
253
{
 
254
    return String::number(m_valueInSpecifiedUnits) + lengthTypeToString(extractType(m_unit));
 
255
}
 
256
 
 
257
void SVGLength::newValueSpecifiedUnits(unsigned short type, float value)
 
258
{
 
259
    ASSERT(type <= LengthTypePC);
 
260
 
 
261
    m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
 
262
    m_valueInSpecifiedUnits = value;
 
263
}
 
264
 
 
265
void SVGLength::convertToSpecifiedUnits(unsigned short type)
 
266
{
 
267
    ASSERT(type <= LengthTypePC);
 
268
 
 
269
    float valueInUserUnits = value();
 
270
    m_unit = storeUnit(extractMode(m_unit), (SVGLengthType) type);
 
271
    setValue(valueInUserUnits);
 
272
}
 
273
 
 
274
float SVGLength::PercentageOfViewport(float value, const SVGStyledElement* context, SVGLengthMode mode)
 
275
{
 
276
    ASSERT(context);
 
277
 
 
278
    float width = 0, height = 0;
 
279
    SVGElement* viewportElement = context->viewportElement();
 
280
 
 
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!
 
288
         }
 
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();
 
294
        } else {
 
295
            width = svg->width().value();
 
296
            height = svg->height().value();
 
297
        }
 
298
    } else if (context->parent() && !context->parent()->isSVGElement()) {
 
299
        if (RenderObject* renderer = context->renderer()) {
 
300
            width = renderer->width();
 
301
            height = renderer->height();
 
302
        }
 
303
    }
 
304
 
 
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);
 
311
 
 
312
    return 0.0f;
 
313
}
 
314
 
 
315
}
 
316
 
 
317
#endif // ENABLE(SVG)
 
318
 
 
319
// vim:ts=4:noet