1/* 2 * Copyright (C) 2011 Leo Yang <leoyang@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 29namespace WebCore { 30 31inline SVGAltGlyphDefElement::SVGAltGlyphDefElement(Document& document) 32 : SVGElement(SVGNames::altGlyphDefTag, document) 33{ 34 ScriptWrappable::init(this); 35} 36 37PassRefPtr<SVGAltGlyphDefElement> SVGAltGlyphDefElement::create(Document& document) 38{ 39 return adoptRef(new SVGAltGlyphDefElement(document)); 40} 41 42bool SVGAltGlyphDefElement::hasValidGlyphElements(Vector<String>& glyphNames) const 43{ 44 // Spec: http://www.w3.org/TR/SVG/text.html#AltGlyphDefElement 45 // An 'altGlyphDef' can contain either of the following: 46 // 47 // 1. In the simplest case, an 'altGlyphDef' contains one or more 'glyphRef' elements. 48 // Each 'glyphRef' element references a single glyph within a particular font. 49 // If all of the referenced glyphs are available, then these glyphs are rendered 50 // instead of the character(s) inside of the referencing 'altGlyph' element. 51 // If any of the referenced glyphs are unavailable, then the character(s) that are 52 // inside of the 'altGlyph' element are rendered as if there were not an 'altGlyph' 53 // element surrounding those characters. 54 // 55 // 2. In the more complex case, an 'altGlyphDef' contains one or more 'altGlyphItem' elements. 56 // Each 'altGlyphItem' represents a candidate set of substitute glyphs. Each 'altGlyphItem' 57 // contains one or more 'glyphRef' elements. Each 'glyphRef' element references a single 58 // glyph within a particular font. The first 'altGlyphItem' in which all referenced glyphs 59 // are available is chosen. The glyphs referenced from this 'altGlyphItem' are rendered 60 // instead of the character(s) that are inside of the referencing 'altGlyph' element. 61 // If none of the 'altGlyphItem' elements result in a successful match (i.e., none of the 62 // 'altGlyphItem' elements has all of its referenced glyphs available), then the character(s) 63 // that are inside of the 'altGlyph' element are rendered as if there were not an 'altGlyph' 64 // element surrounding those characters. 65 // 66 // The spec doesn't tell how to deal with the mixing of <glyphRef> and <altGlyItem>. 67 // However, we determine content model by the the type of the first appearing element 68 // just like Opera 11 does. After the content model is determined we skip elements 69 // which don't comform to it. For example: 70 // a. <altGlyphDef> 71 // <glyphRef id="g1" /> 72 // <altGlyphItem id="i1"> ... </altGlyphItem> 73 // <glyphRef id="g2" /> 74 // </altGlyphDef> 75 // 76 // b. <altGlyphDef> 77 // <altGlyphItem id="i1"> ... </altGlyphItem> 78 // <altGlyphItem id="i2"> ... </altGlyphItem> 79 // <glyphRef id="g1" /> 80 // <glyphRef id="g2" /> 81 // </altGlyphDef> 82 // For a), the content model is 1), so we will use "g1" and "g2" if they are all valid 83 // and "i1" is skipped. 84 // For b), the content model is 2), so we will use <glyphRef> elements contained in 85 // "i1" if they are valid and "g1" and "g2" are skipped. 86 87 // These 2 variables are used to determine content model. 88 bool fountFirstGlyphRef = false; 89 bool foundFirstAltGlyphItem = false; 90 91 for (Node* child = firstChild(); child; child = child->nextSibling()) { 92 if (!foundFirstAltGlyphItem && child->hasTagName(SVGNames::glyphRefTag)) { 93 fountFirstGlyphRef = true; 94 String referredGlyphName; 95 96 if (toSVGGlyphRefElement(child)->hasValidGlyphElement(referredGlyphName)) 97 glyphNames.append(referredGlyphName); 98 else { 99 // As the spec says "If any of the referenced glyphs are unavailable, 100 // then the character(s) that are inside of the 'altGlyph' element are 101 // rendered as if there were not an 'altGlyph' element surrounding 102 // those characters.". 103 glyphNames.clear(); 104 return false; 105 } 106 } else if (!fountFirstGlyphRef && child->hasTagName(SVGNames::altGlyphItemTag)) { 107 foundFirstAltGlyphItem = true; 108 Vector<String> referredGlyphNames; 109 110 // As the spec says "The first 'altGlyphItem' in which all referenced glyphs 111 // are available is chosen." 112 if (static_cast<SVGAltGlyphItemElement*>(child)->hasValidGlyphElements(glyphNames) && !glyphNames.isEmpty()) 113 return true; 114 } 115 } 116 return !glyphNames.isEmpty(); 117} 118 119} 120 121#endif 122