initial import
[vuplus_webkit] / Source / WebCore / svg / SVGTextContentElement.cpp
1 /*
2  * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(SVG)
24 #include "SVGTextContentElement.h"
25
26 #include "CSSPropertyNames.h"
27 #include "CSSValueKeywords.h"
28 #include "Frame.h"
29 #include "FrameSelection.h"
30 #include "RenderObject.h"
31 #include "RenderSVGResource.h"
32 #include "RenderSVGText.h"
33 #include "SVGDocumentExtensions.h"
34 #include "SVGElementInstance.h"
35 #include "SVGNames.h"
36 #include "SVGTextQuery.h"
37 #include "XMLNames.h"
38
39 namespace WebCore {
40  
41 // Define custom animated property 'textLength'.
42 const SVGPropertyInfo* SVGTextContentElement::textLengthPropertyInfo()
43 {
44     static const SVGPropertyInfo* s_propertyInfo = 0;
45     if (!s_propertyInfo) {
46         s_propertyInfo = new SVGPropertyInfo(AnimatedLength,
47                                              SVGNames::textLengthAttr,
48                                              SVGNames::textLengthAttr.localName(),
49                                              &SVGTextContentElement::synchronizeTextLength,
50                                              &SVGTextContentElement::lookupOrCreateTextLengthWrapper);
51     }
52     return s_propertyInfo;
53 }
54
55 // Animated property definitions
56 DEFINE_ANIMATED_ENUMERATION(SVGTextContentElement, SVGNames::lengthAdjustAttr, LengthAdjust, lengthAdjust, SVGLengthAdjustType)
57 DEFINE_ANIMATED_BOOLEAN(SVGTextContentElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
58
59 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGTextContentElement)
60     REGISTER_LOCAL_ANIMATED_PROPERTY(textLength)
61     REGISTER_LOCAL_ANIMATED_PROPERTY(lengthAdjust)
62     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
63     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGStyledElement)
64     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGTests)
65 END_REGISTER_ANIMATED_PROPERTIES
66
67 SVGTextContentElement::SVGTextContentElement(const QualifiedName& tagName, Document* document)
68     : SVGStyledElement(tagName, document)
69     , m_textLength(LengthModeOther)
70     , m_specifiedTextLength(LengthModeOther)
71     , m_lengthAdjust(SVGLengthAdjustSpacing)
72 {
73     registerAnimatedPropertiesForSVGTextContentElement();
74 }
75
76 void SVGTextContentElement::synchronizeTextLength(void* contextElement)
77 {
78     ASSERT(contextElement);
79     SVGTextContentElement* ownerType = static_cast<SVGTextContentElement*>(contextElement);
80     if (!ownerType->m_textLength.shouldSynchronize)
81         return;
82     AtomicString value(SVGPropertyTraits<SVGLength>::toString(ownerType->m_specifiedTextLength));
83     SVGAnimatedPropertySynchronizer<true>::synchronize(ownerType, textLengthPropertyInfo()->attributeName, value);
84 }
85
86 PassRefPtr<SVGAnimatedProperty> SVGTextContentElement::lookupOrCreateTextLengthWrapper(void* contextElement)
87 {
88     ASSERT(contextElement);
89     SVGTextContentElement* ownerType = static_cast<SVGTextContentElement*>(contextElement);
90     return SVGAnimatedProperty::lookupOrCreateWrapper<SVGTextContentElement, SVGAnimatedLength, SVGLength, true>
91            (ownerType, textLengthPropertyInfo(), ownerType->m_textLength.value);
92 }
93
94 PassRefPtr<SVGAnimatedLength> SVGTextContentElement::textLengthAnimated()
95 {
96     DEFINE_STATIC_LOCAL(SVGLength, defaultTextLength, (LengthModeOther));
97     if (m_specifiedTextLength == defaultTextLength) {
98         ExceptionCode ec = 0;
99         m_textLength.value.newValueSpecifiedUnits(LengthTypeNumber, getComputedTextLength(), ec);
100         ASSERT(!ec);
101     }
102
103     m_textLength.shouldSynchronize = true;
104     return static_pointer_cast<SVGAnimatedLength>(lookupOrCreateTextLengthWrapper(this));
105
106 }
107
108 unsigned SVGTextContentElement::getNumberOfChars()
109 {
110     document()->updateLayoutIgnorePendingStylesheets();
111     return SVGTextQuery(renderer()).numberOfCharacters();
112 }
113
114 float SVGTextContentElement::getComputedTextLength()
115 {
116     document()->updateLayoutIgnorePendingStylesheets();
117     return SVGTextQuery(renderer()).textLength();
118 }
119
120 float SVGTextContentElement::getSubStringLength(unsigned charnum, unsigned nchars, ExceptionCode& ec)
121 {
122     document()->updateLayoutIgnorePendingStylesheets();
123
124     unsigned numberOfChars = getNumberOfChars();
125     if (charnum >= numberOfChars) {
126         ec = INDEX_SIZE_ERR;
127         return 0.0f;
128     }
129
130     return SVGTextQuery(renderer()).subStringLength(charnum, nchars);
131 }
132
133 FloatPoint SVGTextContentElement::getStartPositionOfChar(unsigned charnum, ExceptionCode& ec)
134 {
135     document()->updateLayoutIgnorePendingStylesheets();
136
137     if (charnum > getNumberOfChars()) {
138         ec = INDEX_SIZE_ERR;
139         return FloatPoint();
140     }
141
142     return SVGTextQuery(renderer()).startPositionOfCharacter(charnum);
143 }
144
145 FloatPoint SVGTextContentElement::getEndPositionOfChar(unsigned charnum, ExceptionCode& ec)
146 {
147     document()->updateLayoutIgnorePendingStylesheets();
148
149     if (charnum > getNumberOfChars()) {
150         ec = INDEX_SIZE_ERR;
151         return FloatPoint();
152     }
153
154     return SVGTextQuery(renderer()).endPositionOfCharacter(charnum);
155 }
156
157 FloatRect SVGTextContentElement::getExtentOfChar(unsigned charnum, ExceptionCode& ec)
158 {
159     document()->updateLayoutIgnorePendingStylesheets();
160
161     if (charnum > getNumberOfChars()) {
162         ec = INDEX_SIZE_ERR;
163         return FloatRect();
164     }
165
166     return SVGTextQuery(renderer()).extentOfCharacter(charnum);
167 }
168
169 float SVGTextContentElement::getRotationOfChar(unsigned charnum, ExceptionCode& ec)
170 {
171     document()->updateLayoutIgnorePendingStylesheets();
172
173     if (charnum > getNumberOfChars()) {
174         ec = INDEX_SIZE_ERR;
175         return 0.0f;
176     }
177
178     return SVGTextQuery(renderer()).rotationOfCharacter(charnum);
179 }
180
181 int SVGTextContentElement::getCharNumAtPosition(const FloatPoint& point)
182 {
183     document()->updateLayoutIgnorePendingStylesheets();
184     return SVGTextQuery(renderer()).characterNumberAtPosition(point);
185 }
186
187 void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionCode& ec)
188 {
189     unsigned numberOfChars = getNumberOfChars();
190     if (charnum >= numberOfChars) {
191         ec = INDEX_SIZE_ERR;
192         return;
193     }
194
195     if (nchars > numberOfChars - charnum)
196         nchars = numberOfChars - charnum;
197
198     ASSERT(document());
199     ASSERT(document()->frame());
200
201     FrameSelection* selection = document()->frame()->selection();
202     if (!selection)
203         return;
204
205     // Find selection start
206     VisiblePosition start(firstPositionInNode(const_cast<SVGTextContentElement*>(this)));
207     for (unsigned i = 0; i < charnum; ++i)
208         start = start.next();
209
210     // Find selection end
211     VisiblePosition end(start);
212     for (unsigned i = 0; i < nchars; ++i)
213         end = end.next();
214
215     selection->setSelection(VisibleSelection(start, end));
216 }
217
218 bool SVGTextContentElement::isSupportedAttribute(const QualifiedName& attrName)
219 {
220     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
221     if (supportedAttributes.isEmpty()) {
222         SVGTests::addSupportedAttributes(supportedAttributes);
223         SVGLangSpace::addSupportedAttributes(supportedAttributes);
224         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
225         supportedAttributes.add(SVGNames::lengthAdjustAttr);
226         supportedAttributes.add(SVGNames::textLengthAttr);
227     }
228     return supportedAttributes.contains(attrName);
229 }
230
231 void SVGTextContentElement::parseMappedAttribute(Attribute* attr)
232 {
233     SVGParsingError parseError = NoError;
234
235     if (!isSupportedAttribute(attr->name()))
236         SVGStyledElement::parseMappedAttribute(attr);
237     else if (attr->name() == SVGNames::lengthAdjustAttr) {
238         SVGLengthAdjustType propertyValue = SVGPropertyTraits<SVGLengthAdjustType>::fromString(attr->value());
239         if (propertyValue > 0)
240             setLengthAdjustBaseValue(propertyValue);
241     } else if (attr->name() == SVGNames::textLengthAttr) {
242         m_textLength.value = SVGLength::construct(LengthModeOther, attr->value(), parseError, ForbidNegativeLengths);
243     } else if (SVGTests::parseMappedAttribute(attr)
244                || SVGExternalResourcesRequired::parseMappedAttribute(attr)) {
245     } else if (SVGLangSpace::parseMappedAttribute(attr)) {
246         if (attr->name().matches(XMLNames::spaceAttr)) {
247             DEFINE_STATIC_LOCAL(const AtomicString, preserveString, ("preserve"));
248
249             if (attr->value() == preserveString)
250                 addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValuePre);
251             else
252                 addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValueNowrap);
253         }
254     } else
255         ASSERT_NOT_REACHED();
256
257     reportAttributeParsingError(parseError, attr);
258 }
259
260 void SVGTextContentElement::svgAttributeChanged(const QualifiedName& attrName)
261 {
262     if (!isSupportedAttribute(attrName)) {
263         SVGStyledElement::svgAttributeChanged(attrName);
264         return;
265     }
266
267     SVGElementInstance::InvalidationGuard invalidationGuard(this);
268
269     if (SVGTests::handleAttributeChange(this, attrName))
270         return;
271
272     if (attrName == SVGNames::textLengthAttr)
273         m_specifiedTextLength = m_textLength.value;
274
275     if (RenderObject* renderer = this->renderer())
276         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
277 }
278
279 bool SVGTextContentElement::selfHasRelativeLengths() const
280 {
281     // Any element of the <text> subtree is advertized as using relative lengths.
282     // On any window size change, we have to relayout the text subtree, as the
283     // effective 'on-screen' font size may change.
284     return true;
285 }
286
287 SVGTextContentElement* SVGTextContentElement::elementFromRenderer(RenderObject* renderer)
288 {
289     if (!renderer)
290         return 0;
291
292     if (!renderer->isSVGText() && !renderer->isSVGInline())
293         return 0;
294
295     Node* node = renderer->node();
296     ASSERT(node);
297     ASSERT(node->isSVGElement());
298
299     if (!node->hasTagName(SVGNames::textTag)
300         && !node->hasTagName(SVGNames::tspanTag)
301 #if ENABLE(SVG_FONTS)
302         && !node->hasTagName(SVGNames::altGlyphTag)
303 #endif
304         && !node->hasTagName(SVGNames::trefTag)
305         && !node->hasTagName(SVGNames::textPathTag))
306         return 0;
307
308     return static_cast<SVGTextContentElement*>(node);
309 }
310
311 void SVGTextContentElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
312 {
313     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
314
315     if (changedByParser || !renderer())
316         return;
317
318     if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(renderer()))
319         textRenderer->setNeedsPositioningValuesUpdate();
320 }
321
322 }
323
324 #endif // ENABLE(SVG)