- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 #include "core/svg/SVGTextContentElement.h"
23
24 #include "CSSPropertyNames.h"
25 #include "CSSValueKeywords.h"
26 #include "SVGNames.h"
27 #include "XMLNames.h"
28 #include "bindings/v8/ExceptionState.h"
29 #include "bindings/v8/ExceptionStatePlaceholder.h"
30 #include "core/editing/FrameSelection.h"
31 #include "core/frame/Frame.h"
32 #include "core/rendering/RenderObject.h"
33 #include "core/rendering/svg/RenderSVGResource.h"
34 #include "core/rendering/svg/SVGTextQuery.h"
35 #include "core/svg/SVGElementInstance.h"
36
37 namespace WebCore {
38
39 // Define custom animated property 'textLength'.
40 const SVGPropertyInfo* SVGTextContentElement::textLengthPropertyInfo()
41 {
42     static const SVGPropertyInfo* s_propertyInfo = 0;
43     if (!s_propertyInfo) {
44         s_propertyInfo = new SVGPropertyInfo(AnimatedLength,
45                                              PropertyIsReadWrite,
46                                              SVGNames::textLengthAttr,
47                                              SVGNames::textLengthAttr.localName(),
48                                              &SVGTextContentElement::synchronizeTextLength,
49                                              &SVGTextContentElement::lookupOrCreateTextLengthWrapper);
50     }
51     return s_propertyInfo;
52 }
53
54 // Animated property definitions
55 DEFINE_ANIMATED_ENUMERATION(SVGTextContentElement, SVGNames::lengthAdjustAttr, LengthAdjust, lengthAdjust, SVGLengthAdjustType)
56 DEFINE_ANIMATED_BOOLEAN(SVGTextContentElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired)
57
58 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGTextContentElement)
59     REGISTER_LOCAL_ANIMATED_PROPERTY(textLength)
60     REGISTER_LOCAL_ANIMATED_PROPERTY(lengthAdjust)
61     REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired)
62     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGraphicsElement)
63 END_REGISTER_ANIMATED_PROPERTIES
64
65 SVGTextContentElement::SVGTextContentElement(const QualifiedName& tagName, Document& document)
66     : SVGGraphicsElement(tagName, document)
67     , m_textLength(LengthModeOther)
68     , m_specifiedTextLength(LengthModeOther)
69     , m_lengthAdjust(SVGLengthAdjustSpacing)
70 {
71     ScriptWrappable::init(this);
72     registerAnimatedPropertiesForSVGTextContentElement();
73 }
74
75 void SVGTextContentElement::synchronizeTextLength(SVGElement* contextElement)
76 {
77     ASSERT(contextElement);
78     SVGTextContentElement* ownerType = toSVGTextContentElement(contextElement);
79     if (!ownerType->m_textLength.shouldSynchronize)
80         return;
81     AtomicString value(SVGPropertyTraits<SVGLength>::toString(ownerType->m_specifiedTextLength));
82     ownerType->m_textLength.synchronize(ownerType, textLengthPropertyInfo()->attributeName, value);
83 }
84
85 PassRefPtr<SVGAnimatedProperty> SVGTextContentElement::lookupOrCreateTextLengthWrapper(SVGElement* contextElement)
86 {
87     ASSERT(contextElement);
88     SVGTextContentElement* ownerType = toSVGTextContentElement(contextElement);
89     return SVGAnimatedProperty::lookupOrCreateWrapper<SVGTextContentElement, SVGAnimatedLength, SVGLength>
90            (ownerType, textLengthPropertyInfo(), ownerType->m_textLength.value);
91 }
92
93 PassRefPtr<SVGAnimatedLength> SVGTextContentElement::textLength()
94 {
95     DEFINE_STATIC_LOCAL(SVGLength, defaultTextLength, (LengthModeOther));
96     if (m_specifiedTextLength == defaultTextLength)
97         m_textLength.value.newValueSpecifiedUnits(LengthTypeNumber, getComputedTextLength(), ASSERT_NO_EXCEPTION);
98
99     m_textLength.shouldSynchronize = true;
100     return static_pointer_cast<SVGAnimatedLength>(lookupOrCreateTextLengthWrapper(this));
101
102 }
103
104 unsigned SVGTextContentElement::getNumberOfChars()
105 {
106     document().updateLayoutIgnorePendingStylesheets();
107     return SVGTextQuery(renderer()).numberOfCharacters();
108 }
109
110 float SVGTextContentElement::getComputedTextLength()
111 {
112     document().updateLayoutIgnorePendingStylesheets();
113     return SVGTextQuery(renderer()).textLength();
114 }
115
116 float SVGTextContentElement::getSubStringLength(unsigned charnum, unsigned nchars, ExceptionState& es)
117 {
118     document().updateLayoutIgnorePendingStylesheets();
119
120     unsigned numberOfChars = getNumberOfChars();
121     if (charnum >= numberOfChars) {
122         es.throwUninformativeAndGenericDOMException(IndexSizeError);
123         return 0.0f;
124     }
125
126     if (nchars > numberOfChars - charnum)
127         nchars = numberOfChars - charnum;
128
129     return SVGTextQuery(renderer()).subStringLength(charnum, nchars);
130 }
131
132 SVGPoint SVGTextContentElement::getStartPositionOfChar(unsigned charnum, ExceptionState& es)
133 {
134     document().updateLayoutIgnorePendingStylesheets();
135
136     if (charnum > getNumberOfChars()) {
137         es.throwUninformativeAndGenericDOMException(IndexSizeError);
138         return FloatPoint();
139     }
140
141     return SVGTextQuery(renderer()).startPositionOfCharacter(charnum);
142 }
143
144 SVGPoint SVGTextContentElement::getEndPositionOfChar(unsigned charnum, ExceptionState& es)
145 {
146     document().updateLayoutIgnorePendingStylesheets();
147
148     if (charnum > getNumberOfChars()) {
149         es.throwUninformativeAndGenericDOMException(IndexSizeError);
150         return FloatPoint();
151     }
152
153     return SVGTextQuery(renderer()).endPositionOfCharacter(charnum);
154 }
155
156 SVGRect SVGTextContentElement::getExtentOfChar(unsigned charnum, ExceptionState& es)
157 {
158     document().updateLayoutIgnorePendingStylesheets();
159
160     if (charnum > getNumberOfChars()) {
161         es.throwUninformativeAndGenericDOMException(IndexSizeError);
162         return SVGRect();
163     }
164
165     return SVGTextQuery(renderer()).extentOfCharacter(charnum);
166 }
167
168 float SVGTextContentElement::getRotationOfChar(unsigned charnum, ExceptionState& es)
169 {
170     document().updateLayoutIgnorePendingStylesheets();
171
172     if (charnum > getNumberOfChars()) {
173         es.throwUninformativeAndGenericDOMException(IndexSizeError);
174         return 0.0f;
175     }
176
177     return SVGTextQuery(renderer()).rotationOfCharacter(charnum);
178 }
179
180 int SVGTextContentElement::getCharNumAtPosition(const SVGPoint& point)
181 {
182     document().updateLayoutIgnorePendingStylesheets();
183     return SVGTextQuery(renderer()).characterNumberAtPosition(point);
184 }
185
186 void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionState& es)
187 {
188     unsigned numberOfChars = getNumberOfChars();
189     if (charnum >= numberOfChars) {
190         es.throwUninformativeAndGenericDOMException(IndexSizeError);
191         return;
192     }
193
194     if (nchars > numberOfChars - charnum)
195         nchars = numberOfChars - charnum;
196
197     ASSERT(document().frame());
198
199     // Find selection start
200     VisiblePosition start(firstPositionInNode(const_cast<SVGTextContentElement*>(this)));
201     for (unsigned i = 0; i < charnum; ++i)
202         start = start.next();
203
204     // Find selection end
205     VisiblePosition end(start);
206     for (unsigned i = 0; i < nchars; ++i)
207         end = end.next();
208
209     document().frame()->selection().setSelection(VisibleSelection(start, end));
210 }
211
212 bool SVGTextContentElement::isSupportedAttribute(const QualifiedName& attrName)
213 {
214     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
215     if (supportedAttributes.isEmpty()) {
216         SVGLangSpace::addSupportedAttributes(supportedAttributes);
217         SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes);
218         supportedAttributes.add(SVGNames::lengthAdjustAttr);
219         supportedAttributes.add(SVGNames::textLengthAttr);
220     }
221     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
222 }
223
224 bool SVGTextContentElement::isPresentationAttribute(const QualifiedName& name) const
225 {
226     if (name.matches(XMLNames::spaceAttr))
227         return true;
228     return SVGGraphicsElement::isPresentationAttribute(name);
229 }
230
231 void SVGTextContentElement::collectStyleForPresentationAttribute(const QualifiedName& name, const AtomicString& value, MutableStylePropertySet* style)
232 {
233     if (!isSupportedAttribute(name))
234         SVGGraphicsElement::collectStyleForPresentationAttribute(name, value, style);
235     else if (name.matches(XMLNames::spaceAttr)) {
236         DEFINE_STATIC_LOCAL(const AtomicString, preserveString, ("preserve", AtomicString::ConstructFromLiteral));
237
238         if (value == preserveString)
239             addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValuePre);
240         else
241             addPropertyToPresentationAttributeStyle(style, CSSPropertyWhiteSpace, CSSValueNowrap);
242     }
243 }
244
245 void SVGTextContentElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
246 {
247     SVGParsingError parseError = NoError;
248
249     if (!isSupportedAttribute(name))
250         SVGGraphicsElement::parseAttribute(name, value);
251     else if (name == SVGNames::lengthAdjustAttr) {
252         SVGLengthAdjustType propertyValue = SVGPropertyTraits<SVGLengthAdjustType>::fromString(value);
253         if (propertyValue > 0)
254             setLengthAdjustBaseValue(propertyValue);
255     } else if (name == SVGNames::textLengthAttr) {
256         m_textLength.value = SVGLength::construct(LengthModeOther, value, parseError, ForbidNegativeLengths);
257     } else if (SVGExternalResourcesRequired::parseAttribute(name, value)) {
258     } else if (SVGLangSpace::parseAttribute(name, value)) {
259     } else
260         ASSERT_NOT_REACHED();
261
262     reportAttributeParsingError(parseError, name, value);
263 }
264
265 void SVGTextContentElement::svgAttributeChanged(const QualifiedName& attrName)
266 {
267     if (!isSupportedAttribute(attrName)) {
268         SVGGraphicsElement::svgAttributeChanged(attrName);
269         return;
270     }
271
272     SVGElementInstance::InvalidationGuard invalidationGuard(this);
273
274     if (attrName == SVGNames::textLengthAttr)
275         m_specifiedTextLength = m_textLength.value;
276
277     if (RenderObject* renderer = this->renderer())
278         RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer);
279 }
280
281 bool SVGTextContentElement::selfHasRelativeLengths() const
282 {
283     // Any element of the <text> subtree is advertized as using relative lengths.
284     // On any window size change, we have to relayout the text subtree, as the
285     // effective 'on-screen' font size may change.
286     return true;
287 }
288
289 SVGTextContentElement* SVGTextContentElement::elementFromRenderer(RenderObject* renderer)
290 {
291     if (!renderer)
292         return 0;
293
294     if (!renderer->isSVGText() && !renderer->isSVGInline())
295         return 0;
296
297     SVGElement* element = toSVGElement(renderer->node());
298     ASSERT(element);
299
300     if (!element->isTextContent())
301         return 0;
302
303     return toSVGTextContentElement(element);
304 }
305
306 }