1 /* 2 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann (at) kde.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/SVGFontData.h" 24 25 #include "SVGNames.h" 26 #include "XMLNames.h" 27 #include "core/platform/graphics/SVGGlyph.h" 28 #include "core/platform/graphics/TextRun.h" 29 #include "core/platform/graphics/WidthIterator.h" 30 #include "core/rendering/RenderObject.h" 31 #include "core/rendering/svg/SVGTextRunRenderingContext.h" 32 #include "core/svg/SVGAltGlyphElement.h" 33 #include "core/svg/SVGFontElement.h" 34 #include "core/svg/SVGFontFaceElement.h" 35 #include "core/svg/SVGGlyphElement.h" 36 #include "wtf/text/StringBuilder.h" 37 #include "wtf/unicode/CharacterNames.h" 38 #include "wtf/unicode/Unicode.h" 39 40 using namespace WTF; 41 using namespace Unicode; 42 43 namespace WebCore { 44 45 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement) 46 : m_svgFontFaceElement(fontFaceElement) 47 , m_horizontalOriginX(fontFaceElement->horizontalOriginX()) 48 , m_horizontalOriginY(fontFaceElement->horizontalOriginY()) 49 , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX()) 50 , m_verticalOriginX(fontFaceElement->verticalOriginX()) 51 , m_verticalOriginY(fontFaceElement->verticalOriginY()) 52 , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY()) 53 { 54 ASSERT_ARG(fontFaceElement, fontFaceElement); 55 } 56 57 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize) 58 { 59 ASSERT(fontData); 60 61 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); 62 ASSERT(svgFontFaceElement); 63 64 SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement(); 65 ASSERT(svgFontElement); 66 GlyphData missingGlyphData; 67 missingGlyphData.fontData = fontData; 68 missingGlyphData.glyph = svgFontElement->missingGlyph(); 69 fontData->setMissingGlyphData(missingGlyphData); 70 71 fontData->setZeroWidthSpaceGlyph(0); 72 fontData->determinePitch(); 73 74 unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); 75 float scale = scaleEmToUnits(fontSize, unitsPerEm); 76 float xHeight = svgFontFaceElement->xHeight() * scale; 77 float ascent = svgFontFaceElement->ascent() * scale; 78 float descent = svgFontFaceElement->descent() * scale; 79 float lineGap = 0.1f * fontSize; 80 81 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page(); 82 83 if (!xHeight && glyphPageZero) { 84 // Fallback if x_heightAttr is not specified for the font element. 85 Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph; 86 xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3; 87 } 88 89 FontMetrics& fontMetrics = fontData->fontMetrics(); 90 fontMetrics.setUnitsPerEm(unitsPerEm); 91 fontMetrics.setAscent(ascent); 92 fontMetrics.setDescent(descent); 93 fontMetrics.setLineGap(lineGap); 94 fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); 95 fontMetrics.setXHeight(xHeight); 96 97 if (!glyphPageZero) { 98 fontData->setSpaceGlyph(0); 99 fontData->setSpaceWidth(0); 100 fontData->setAvgCharWidth(0); 101 fontData->setMaxCharWidth(ascent); 102 return; 103 } 104 105 // Calculate space width. 106 Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph; 107 fontData->setSpaceGlyph(spaceGlyph); 108 fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph)); 109 110 // Estimate average character width. 111 Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph; 112 fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth()); 113 114 // Estimate maximum character width. 115 Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph; 116 fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent); 117 } 118 119 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const 120 { 121 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); 122 ASSERT(svgFontFaceElement); 123 124 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); 125 ASSERT(associatedFontElement); 126 127 SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph); 128 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this); 129 return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm()); 130 } 131 132 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const 133 { 134 const TextRun& run = iterator.run(); 135 Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms(); 136 ASSERT(int(run.charactersLength()) >= currentCharacter); 137 138 // Associate text with arabic forms, if needed. 139 String remainingTextInRun; 140 141 if (run.is8Bit()) { 142 remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter); 143 remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length()); 144 } else { 145 remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter); 146 remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length()); 147 } 148 149 if (mirror) 150 remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun); 151 if (!currentCharacter && arabicForms.isEmpty()) 152 arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); 153 154 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); 155 ASSERT(svgFontFaceElement); 156 157 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); 158 ASSERT(associatedFontElement); 159 160 RenderObject* renderObject = 0; 161 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) 162 renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); 163 164 String language; 165 bool isVerticalText = false; 166 Vector<String> altGlyphNames; 167 168 if (renderObject) { 169 RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; 170 ASSERT(parentRenderObject); 171 172 isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode(); 173 if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { 174 language = parentRenderObjectElement->getAttribute(XMLNames::langAttr); 175 176 if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) { 177 SVGAltGlyphElement* altGlyph = static_cast<SVGAltGlyphElement*>(parentRenderObjectElement); 178 if (!altGlyph->hasValidGlyphElements(altGlyphNames)) 179 altGlyphNames.clear(); 180 } 181 } 182 } 183 184 Vector<SVGGlyph> glyphs; 185 size_t altGlyphNamesSize = altGlyphNames.size(); 186 if (altGlyphNamesSize) { 187 for (size_t index = 0; index < altGlyphNamesSize; ++index) 188 associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs); 189 190 // Assign the unicodeStringLength now that its known. 191 size_t glyphsSize = glyphs.size(); 192 for (size_t i = 0; i < glyphsSize; ++i) 193 glyphs[i].unicodeStringLength = run.length(); 194 195 // Do not check alt glyphs for compatibility. Just return the first one. 196 // Later code will fail if we do not do this and the glyph is incompatible. 197 if (glyphsSize) { 198 SVGGlyph& svgGlyph = glyphs[0]; 199 iterator.setLastGlyphName(svgGlyph.glyphName); 200 glyphData.glyph = svgGlyph.tableEntry; 201 advanceLength = svgGlyph.unicodeStringLength; 202 return true; 203 } 204 } else 205 associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs); 206 207 size_t glyphsSize = glyphs.size(); 208 for (size_t i = 0; i < glyphsSize; ++i) { 209 SVGGlyph& svgGlyph = glyphs[i]; 210 if (svgGlyph.isPartOfLigature) 211 continue; 212 if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength)) 213 continue; 214 iterator.setLastGlyphName(svgGlyph.glyphName); 215 glyphData.glyph = svgGlyph.tableEntry; 216 advanceLength = svgGlyph.unicodeStringLength; 217 return true; 218 } 219 220 iterator.setLastGlyphName(String()); 221 return false; 222 } 223 224 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const 225 { 226 ASSERT(fontData->isCustomFont()); 227 ASSERT(fontData->isSVGFont()); 228 229 SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement(); 230 ASSERT(fontFaceElement); 231 232 SVGFontElement* fontElement = fontFaceElement->associatedFontElement(); 233 ASSERT(fontElement); 234 235 if (bufferLength == length) 236 return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); 237 238 ASSERT(bufferLength == 2 * length); 239 return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); 240 } 241 242 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const 243 { 244 bool haveGlyphs = false; 245 Vector<SVGGlyph> glyphs; 246 for (unsigned i = 0; i < length; ++i) { 247 String lookupString(buffer + i, 1); 248 fontElement->collectGlyphsForString(lookupString, glyphs); 249 if (glyphs.isEmpty()) { 250 pageToFill->setGlyphDataForIndex(offset + i, 0, 0); 251 continue; 252 } 253 254 // Associate entry in glyph page with first valid SVGGlyph. 255 // If there are multiple valid ones, just take the first one. WidthIterator will take 256 // care of matching to the correct glyph, if multiple ones are available, as that's 257 // only possible within the context of a string (eg. arabic form matching). 258 haveGlyphs = true; 259 pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData); 260 glyphs.clear(); 261 } 262 263 return haveGlyphs; 264 } 265 266 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const 267 { 268 bool haveGlyphs = false; 269 Vector<SVGGlyph> glyphs; 270 for (unsigned i = 0; i < length; ++i) { 271 // Each character here consists of a surrogate pair 272 String lookupString(buffer + i * 2, 2); 273 fontElement->collectGlyphsForString(lookupString, glyphs); 274 if (glyphs.isEmpty()) { 275 pageToFill->setGlyphDataForIndex(offset + i, 0, 0); 276 continue; 277 } 278 279 // Associate entry in glyph page with first valid SVGGlyph. 280 // If there are multiple valid ones, just take the first one. WidthIterator will take 281 // care of matching to the correct glyph, if multiple ones are available, as that's 282 // only possible within the context of a string (eg. arabic form matching). 283 haveGlyphs = true; 284 pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData); 285 glyphs.clear(); 286 } 287 288 return haveGlyphs; 289 } 290 291 String SVGFontData::createStringWithMirroredCharacters(const String& string) const 292 { 293 if (string.isEmpty()) 294 return emptyString(); 295 296 unsigned length = string.length(); 297 298 StringBuilder mirroredCharacters; 299 mirroredCharacters.reserveCapacity(length); 300 301 if (string.is8Bit()) { 302 const LChar* characters = string.characters8(); 303 for (unsigned i = 0; i < length; ++i) 304 mirroredCharacters.append(mirroredChar(characters[i])); 305 } else { 306 const UChar* characters = string.characters16(); 307 unsigned i = 0; 308 while (i < length) { 309 UChar32 character; 310 U16_NEXT(characters, i, length, character); 311 mirroredCharacters.append(mirroredChar(character)); 312 } 313 } 314 315 return mirroredCharacters.toString(); 316 } 317 318 } // namespace WebCore 319 320 #endif 321