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