1 /* 2 * Copyright (C) 2007 Eric Seidel <eric (at) webkit.org> 3 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann (at) kde.org> 4 * Copyright (C) 2008 Rob Buis <buis (at) kde.org> 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22 #include "config.h" 23 24 #if ENABLE(SVG_FONTS) 25 #include "SVGGlyphElement.h" 26 27 #include "Attribute.h" 28 #include "SVGFontData.h" 29 #include "SVGFontElement.h" 30 #include "SVGFontFaceElement.h" 31 #include "SVGNames.h" 32 #include "SVGPathParserFactory.h" 33 #include "SimpleFontData.h" 34 #include "XMLNames.h" 35 36 namespace WebCore { 37 38 using namespace SVGNames; 39 40 inline SVGGlyphElement::SVGGlyphElement(const QualifiedName& tagName, Document* document) 41 : SVGStyledElement(tagName, document) 42 { 43 } 44 45 PassRefPtr<SVGGlyphElement> SVGGlyphElement::create(const QualifiedName& tagName, Document* document) 46 { 47 return adoptRef(new SVGGlyphElement(tagName, document)); 48 } 49 50 void SVGGlyphElement::invalidateGlyphCache() 51 { 52 ContainerNode* fontNode = parentNode(); 53 if (fontNode && fontNode->hasTagName(SVGNames::fontTag)) { 54 if (SVGFontElement* element = static_cast<SVGFontElement*>(fontNode)) 55 element->invalidateGlyphCache(); 56 } 57 } 58 59 void SVGGlyphElement::parseMappedAttribute(Attribute* attr) 60 { 61 if (attr->name() == SVGNames::dAttr) 62 invalidateGlyphCache(); 63 else 64 SVGStyledElement::parseMappedAttribute(attr); 65 } 66 67 void SVGGlyphElement::insertedIntoDocument() 68 { 69 invalidateGlyphCache(); 70 SVGStyledElement::insertedIntoDocument(); 71 } 72 73 void SVGGlyphElement::removedFromDocument() 74 { 75 invalidateGlyphCache(); 76 SVGStyledElement::removedFromDocument(); 77 } 78 79 static inline SVGGlyphIdentifier::ArabicForm parseArabicForm(const AtomicString& value) 80 { 81 if (value == "medial") 82 return SVGGlyphIdentifier::Medial; 83 if (value == "terminal") 84 return SVGGlyphIdentifier::Terminal; 85 if (value == "isolated") 86 return SVGGlyphIdentifier::Isolated; 87 if (value == "initial") 88 return SVGGlyphIdentifier::Initial; 89 90 return SVGGlyphIdentifier::None; 91 } 92 93 static inline SVGGlyphIdentifier::Orientation parseOrientation(const AtomicString& value) 94 { 95 if (value == "h") 96 return SVGGlyphIdentifier::Horizontal; 97 if (value == "v") 98 return SVGGlyphIdentifier::Vertical; 99 100 return SVGGlyphIdentifier::Both; 101 } 102 103 static inline Path parsePathData(const AtomicString& value) 104 { 105 Path result; 106 SVGPathParserFactory* factory = SVGPathParserFactory::self(); 107 factory->buildPathFromString(value, result); 108 return result; 109 } 110 111 void SVGGlyphElement::inheritUnspecifiedAttributes(SVGGlyphIdentifier& identifier, const SVGFontData* svgFontData) 112 { 113 if (identifier.horizontalAdvanceX == SVGGlyphIdentifier::inheritedValue()) 114 identifier.horizontalAdvanceX = svgFontData->horizontalAdvanceX(); 115 116 if (identifier.verticalOriginX == SVGGlyphIdentifier::inheritedValue()) 117 identifier.verticalOriginX = svgFontData->verticalOriginX(); 118 119 if (identifier.verticalOriginY == SVGGlyphIdentifier::inheritedValue()) 120 identifier.verticalOriginY = svgFontData->verticalOriginY(); 121 122 if (identifier.verticalAdvanceY == SVGGlyphIdentifier::inheritedValue()) 123 identifier.verticalAdvanceY = svgFontData->verticalAdvanceY(); 124 } 125 126 static inline float parseSVGGlyphAttribute(const SVGElement* element, const WebCore::QualifiedName& name) 127 { 128 AtomicString value(element->getAttribute(name)); 129 if (value.isEmpty()) 130 return SVGGlyphIdentifier::inheritedValue(); 131 132 return value.toFloat(); 133 } 134 135 AttributeToPropertyTypeMap& SVGGlyphElement::attributeToPropertyTypeMap() 136 { 137 DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ()); 138 return s_attributeToPropertyTypeMap; 139 } 140 141 void SVGGlyphElement::fillAttributeToPropertyTypeMap() 142 { 143 AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap(); 144 145 SVGStyledElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap); 146 attributeToPropertyTypeMap.set(SVGNames::dAttr, AnimatedPath); 147 } 148 149 SVGGlyphIdentifier SVGGlyphElement::buildGenericGlyphIdentifier(const SVGElement* element) 150 { 151 SVGGlyphIdentifier identifier; 152 identifier.pathData = parsePathData(element->getAttribute(dAttr)); 153 154 // Spec: The horizontal advance after rendering the glyph in horizontal orientation. 155 // If the attribute is not specified, the effect is as if the attribute were set to the 156 // value of the font's horiz-adv-x attribute. Glyph widths are required to be non-negative, 157 // even if the glyph is typically rendered right-to-left, as in Hebrew and Arabic scripts. 158 identifier.horizontalAdvanceX = parseSVGGlyphAttribute(element, horiz_adv_xAttr); 159 160 // Spec: The X-coordinate in the font coordinate system of the origin of the glyph to be 161 // used when drawing vertically oriented text. If the attribute is not specified, the effect 162 // is as if the attribute were set to the value of the font's vert-origin-x attribute. 163 identifier.verticalOriginX = parseSVGGlyphAttribute(element, vert_origin_xAttr); 164 165 // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be 166 // used when drawing vertically oriented text. If the attribute is not specified, the effect 167 // is as if the attribute were set to the value of the font's vert-origin-y attribute. 168 identifier.verticalOriginY = parseSVGGlyphAttribute(element, vert_origin_yAttr); 169 170 // Spec: The vertical advance after rendering a glyph in vertical orientation. 171 // If the attribute is not specified, the effect is as if the attribute were set to the 172 // value of the font's vert-adv-y attribute. 173 identifier.verticalAdvanceY = parseSVGGlyphAttribute(element, vert_adv_yAttr); 174 175 return identifier; 176 } 177 178 SVGGlyphIdentifier SVGGlyphElement::buildGlyphIdentifier() const 179 { 180 SVGGlyphIdentifier identifier(buildGenericGlyphIdentifier(this)); 181 identifier.glyphName = getAttribute(glyph_nameAttr); 182 identifier.orientation = parseOrientation(getAttribute(orientationAttr)); 183 identifier.arabicForm = parseArabicForm(getAttribute(arabic_formAttr)); 184 185 String language = getAttribute(SVGNames::langAttr); 186 if (!language.isEmpty()) 187 identifier.languages = parseDelimitedString(language, ','); 188 189 return identifier; 190 } 191 192 } 193 194 #endif // ENABLE(SVG_FONTS) 195