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