SVGTextContentElement.cpp revision cad810f21b803229eb11403f9209855525a25d57
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 "RenderObject.h" 30#include "SVGNames.h" 31#include "SVGTextQuery.h" 32#include "SelectionController.h" 33#include "XMLNames.h" 34 35namespace WebCore { 36 37// Animated property definitions 38DEFINE_ANIMATED_LENGTH(SVGTextContentElement, SVGNames::textLengthAttr, TextLength, textLength) 39DEFINE_ANIMATED_ENUMERATION(SVGTextContentElement, SVGNames::lengthAdjustAttr, LengthAdjust, lengthAdjust) 40DEFINE_ANIMATED_BOOLEAN(SVGTextContentElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 41 42SVGTextContentElement::SVGTextContentElement(const QualifiedName& tagName, Document* document) 43 : SVGStyledElement(tagName, document) 44 , m_textLength(LengthModeOther) 45 , m_lengthAdjust(LENGTHADJUST_SPACING) 46{ 47} 48 49unsigned SVGTextContentElement::getNumberOfChars() const 50{ 51 document()->updateLayoutIgnorePendingStylesheets(); 52 return SVGTextQuery(renderer()).numberOfCharacters(); 53} 54 55float SVGTextContentElement::getComputedTextLength() const 56{ 57 document()->updateLayoutIgnorePendingStylesheets(); 58 return SVGTextQuery(renderer()).textLength(); 59} 60 61float SVGTextContentElement::getSubStringLength(unsigned charnum, unsigned nchars, ExceptionCode& ec) const 62{ 63 document()->updateLayoutIgnorePendingStylesheets(); 64 65 unsigned numberOfChars = getNumberOfChars(); 66 if (charnum >= numberOfChars) { 67 ec = INDEX_SIZE_ERR; 68 return 0.0f; 69 } 70 71 return SVGTextQuery(renderer()).subStringLength(charnum, nchars); 72} 73 74FloatPoint SVGTextContentElement::getStartPositionOfChar(unsigned charnum, ExceptionCode& ec) const 75{ 76 document()->updateLayoutIgnorePendingStylesheets(); 77 78 if (charnum > getNumberOfChars()) { 79 ec = INDEX_SIZE_ERR; 80 return FloatPoint(); 81 } 82 83 return SVGTextQuery(renderer()).startPositionOfCharacter(charnum); 84} 85 86FloatPoint SVGTextContentElement::getEndPositionOfChar(unsigned charnum, ExceptionCode& ec) const 87{ 88 document()->updateLayoutIgnorePendingStylesheets(); 89 90 if (charnum > getNumberOfChars()) { 91 ec = INDEX_SIZE_ERR; 92 return FloatPoint(); 93 } 94 95 return SVGTextQuery(renderer()).endPositionOfCharacter(charnum); 96} 97 98FloatRect SVGTextContentElement::getExtentOfChar(unsigned charnum, ExceptionCode& ec) const 99{ 100 document()->updateLayoutIgnorePendingStylesheets(); 101 102 if (charnum > getNumberOfChars()) { 103 ec = INDEX_SIZE_ERR; 104 return FloatRect(); 105 } 106 107 return SVGTextQuery(renderer()).extentOfCharacter(charnum); 108} 109 110float SVGTextContentElement::getRotationOfChar(unsigned charnum, ExceptionCode& ec) const 111{ 112 document()->updateLayoutIgnorePendingStylesheets(); 113 114 if (charnum > getNumberOfChars()) { 115 ec = INDEX_SIZE_ERR; 116 return 0.0f; 117 } 118 119 return SVGTextQuery(renderer()).rotationOfCharacter(charnum); 120} 121 122int SVGTextContentElement::getCharNumAtPosition(const FloatPoint& point) const 123{ 124 document()->updateLayoutIgnorePendingStylesheets(); 125 return SVGTextQuery(renderer()).characterNumberAtPosition(point); 126} 127 128void SVGTextContentElement::selectSubString(unsigned charnum, unsigned nchars, ExceptionCode& ec) const 129{ 130 unsigned numberOfChars = getNumberOfChars(); 131 if (charnum >= numberOfChars) { 132 ec = INDEX_SIZE_ERR; 133 return; 134 } 135 136 if (nchars > numberOfChars - charnum) 137 nchars = numberOfChars - charnum; 138 139 ASSERT(document()); 140 ASSERT(document()->frame()); 141 142 SelectionController* controller = document()->frame()->selection(); 143 if (!controller) 144 return; 145 146 // Find selection start 147 VisiblePosition start(const_cast<SVGTextContentElement*>(this), 0, SEL_DEFAULT_AFFINITY); 148 for (unsigned i = 0; i < charnum; ++i) 149 start = start.next(); 150 151 // Find selection end 152 VisiblePosition end(start); 153 for (unsigned i = 0; i < nchars; ++i) 154 end = end.next(); 155 156 controller->setSelection(VisibleSelection(start, end)); 157} 158 159void SVGTextContentElement::parseMappedAttribute(Attribute* attr) 160{ 161 if (attr->name() == SVGNames::lengthAdjustAttr) { 162 if (attr->value() == "spacing") 163 setLengthAdjustBaseValue(LENGTHADJUST_SPACING); 164 else if (attr->value() == "spacingAndGlyphs") 165 setLengthAdjustBaseValue(LENGTHADJUST_SPACINGANDGLYPHS); 166 } else if (attr->name() == SVGNames::textLengthAttr) { 167 setTextLengthBaseValue(SVGLength(LengthModeOther, attr->value())); 168 if (textLengthBaseValue().value(this) < 0.0) 169 document()->accessSVGExtensions()->reportError("A negative value for text attribute <textLength> is not allowed"); 170 } else { 171 if (SVGTests::parseMappedAttribute(attr)) 172 return; 173 if (SVGLangSpace::parseMappedAttribute(attr)) { 174 if (attr->name().matches(XMLNames::spaceAttr)) { 175 DEFINE_STATIC_LOCAL(const AtomicString, preserveString, ("preserve")); 176 177 if (attr->value() == preserveString) 178 addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValuePre); 179 else 180 addCSSProperty(attr, CSSPropertyWhiteSpace, CSSValueNowrap); 181 } 182 return; 183 } 184 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 185 return; 186 187 SVGStyledElement::parseMappedAttribute(attr); 188 } 189} 190 191void SVGTextContentElement::synchronizeProperty(const QualifiedName& attrName) 192{ 193 SVGStyledElement::synchronizeProperty(attrName); 194 195 if (attrName == anyQName()) { 196 synchronizeLengthAdjust(); 197 synchronizeTextLength(); 198 synchronizeExternalResourcesRequired(); 199 SVGTests::synchronizeProperties(this, attrName); 200 return; 201 } 202 203 if (attrName == SVGNames::lengthAdjustAttr) 204 synchronizeLengthAdjust(); 205 else if (attrName == SVGNames::textLengthAttr) 206 synchronizeTextLength(); 207 else if (SVGExternalResourcesRequired::isKnownAttribute(attrName)) 208 synchronizeExternalResourcesRequired(); 209 else if (SVGTests::isKnownAttribute(attrName)) 210 SVGTests::synchronizeProperties(this, attrName); 211} 212 213void SVGTextContentElement::svgAttributeChanged(const QualifiedName& attrName) 214{ 215 SVGStyledElement::svgAttributeChanged(attrName); 216 217 if (SVGTests::handleAttributeChange(this, attrName)) 218 return; 219 220 // FIXME: also handle attribute changes for lengthAdjust and textLength 221} 222 223bool SVGTextContentElement::isKnownAttribute(const QualifiedName& attrName) 224{ 225 return attrName.matches(SVGNames::lengthAdjustAttr) 226 || attrName.matches(SVGNames::textLengthAttr) 227 || SVGLangSpace::isKnownAttribute(attrName) 228 || SVGExternalResourcesRequired::isKnownAttribute(attrName) 229 || SVGStyledElement::isKnownAttribute(attrName); 230} 231 232bool SVGTextContentElement::selfHasRelativeLengths() const 233{ 234 return textLength().isRelative(); 235} 236 237SVGTextContentElement* SVGTextContentElement::elementFromRenderer(RenderObject* renderer) 238{ 239 if (!renderer) 240 return 0; 241 242 if (!renderer->isSVGText() && !renderer->isSVGInline()) 243 return 0; 244 245 Node* node = renderer->node(); 246 ASSERT(node); 247 ASSERT(node->isSVGElement()); 248 249 if (!node->hasTagName(SVGNames::textTag) 250 && !node->hasTagName(SVGNames::tspanTag) 251#if ENABLE(SVG_FONTS) 252 && !node->hasTagName(SVGNames::altGlyphTag) 253#endif 254 && !node->hasTagName(SVGNames::trefTag) 255 && !node->hasTagName(SVGNames::textPathTag)) 256 return 0; 257 258 return static_cast<SVGTextContentElement*>(node); 259} 260 261} 262 263#endif // ENABLE(SVG) 264