1 /* 2 * Copyright (C) 2011 Leo Yang <leoyang (at) webkit.org> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this library; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 */ 19 20 #include "config.h" 21 22 #if ENABLE(SVG_FONTS) 23 #include "core/svg/SVGAltGlyphDefElement.h" 24 25 #include "SVGNames.h" 26 #include "core/svg/SVGAltGlyphItemElement.h" 27 #include "core/svg/SVGGlyphRefElement.h" 28 29 namespace WebCore { 30 31 inline SVGAltGlyphDefElement::SVGAltGlyphDefElement(const QualifiedName& tagName, Document* document) 32 : SVGElement(tagName, document) 33 { 34 ASSERT(hasTagName(SVGNames::altGlyphDefTag)); 35 ScriptWrappable::init(this); 36 } 37 38 PassRefPtr<SVGAltGlyphDefElement> SVGAltGlyphDefElement::create(const QualifiedName& tagName, Document* document) 39 { 40 return adoptRef(new SVGAltGlyphDefElement(tagName, document)); 41 } 42 43 bool SVGAltGlyphDefElement::hasValidGlyphElements(Vector<String>& glyphNames) const 44 { 45 // Spec: http://www.w3.org/TR/SVG/text.html#AltGlyphDefElement 46 // An 'altGlyphDef' can contain either of the following: 47 // 48 // 1. In the simplest case, an 'altGlyphDef' contains one or more 'glyphRef' elements. 49 // Each 'glyphRef' element references a single glyph within a particular font. 50 // If all of the referenced glyphs are available, then these glyphs are rendered 51 // instead of the character(s) inside of the referencing 'altGlyph' element. 52 // If any of the referenced glyphs are unavailable, then the character(s) that are 53 // inside of the 'altGlyph' element are rendered as if there were not an 'altGlyph' 54 // element surrounding those characters. 55 // 56 // 2. In the more complex case, an 'altGlyphDef' contains one or more 'altGlyphItem' elements. 57 // Each 'altGlyphItem' represents a candidate set of substitute glyphs. Each 'altGlyphItem' 58 // contains one or more 'glyphRef' elements. Each 'glyphRef' element references a single 59 // glyph within a particular font. The first 'altGlyphItem' in which all referenced glyphs 60 // are available is chosen. The glyphs referenced from this 'altGlyphItem' are rendered 61 // instead of the character(s) that are inside of the referencing 'altGlyph' element. 62 // If none of the 'altGlyphItem' elements result in a successful match (i.e., none of the 63 // 'altGlyphItem' elements has all of its referenced glyphs available), then the character(s) 64 // that are inside of the 'altGlyph' element are rendered as if there were not an 'altGlyph' 65 // element surrounding those characters. 66 // 67 // The spec doesn't tell how to deal with the mixing of <glyphRef> and <altGlyItem>. 68 // However, we determine content model by the the type of the first appearing element 69 // just like Opera 11 does. After the content model is determined we skip elements 70 // which don't comform to it. For example: 71 // a. <altGlyphDef> 72 // <glyphRef id="g1" /> 73 // <altGlyphItem id="i1"> ... </altGlyphItem> 74 // <glyphRef id="g2" /> 75 // </altGlyphDef> 76 // 77 // b. <altGlyphDef> 78 // <altGlyphItem id="i1"> ... </altGlyphItem> 79 // <altGlyphItem id="i2"> ... </altGlyphItem> 80 // <glyphRef id="g1" /> 81 // <glyphRef id="g2" /> 82 // </altGlyphDef> 83 // For a), the content model is 1), so we will use "g1" and "g2" if they are all valid 84 // and "i1" is skipped. 85 // For b), the content model is 2), so we will use <glyphRef> elements contained in 86 // "i1" if they are valid and "g1" and "g2" are skipped. 87 88 // These 2 variables are used to determine content model. 89 bool fountFirstGlyphRef = false; 90 bool foundFirstAltGlyphItem = false; 91 92 for (Node* child = firstChild(); child; child = child->nextSibling()) { 93 if (!foundFirstAltGlyphItem && child->hasTagName(SVGNames::glyphRefTag)) { 94 fountFirstGlyphRef = true; 95 String referredGlyphName; 96 97 if (static_cast<SVGGlyphRefElement*>(child)->hasValidGlyphElement(referredGlyphName)) 98 glyphNames.append(referredGlyphName); 99 else { 100 // As the spec says "If any of the referenced glyphs are unavailable, 101 // then the character(s) that are inside of the 'altGlyph' element are 102 // rendered as if there were not an 'altGlyph' element surrounding 103 // those characters.". 104 glyphNames.clear(); 105 return false; 106 } 107 } else if (!fountFirstGlyphRef && child->hasTagName(SVGNames::altGlyphItemTag)) { 108 foundFirstAltGlyphItem = true; 109 Vector<String> referredGlyphNames; 110 111 // As the spec says "The first 'altGlyphItem' in which all referenced glyphs 112 // are available is chosen." 113 if (static_cast<SVGAltGlyphItemElement*>(child)->hasValidGlyphElements(glyphNames) && !glyphNames.isEmpty()) 114 return true; 115 } 116 } 117 return !glyphNames.isEmpty(); 118 } 119 120 } 121 122 #endif 123