| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@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/shaping/SimpleShaper.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)->pag
e(); | |
| 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 * asc
ent / 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(numeral
ZeroGlyph) : fontData->spaceWidth()); | |
| 119 | |
| 120 // Estimate maximum character width. | |
| 121 Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W'); | |
| 122 fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyp
h) : 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 => Rende
rView::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 associatedFontEle
ment's one. | |
| 139 if (!svgFontFaceElement->inDocument()) | |
| 140 return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElemen
t->unitsPerEm()); | |
| 141 | |
| 142 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontEl
ement(); | |
| 143 ASSERT(associatedFontElement); | |
| 144 | |
| 145 SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph); | |
| 146 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this); | |
| 147 return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceEle
ment->unitsPerEm()); | |
| 148 } | |
| 149 | |
| 150 bool SVGFontData::applySVGGlyphSelection(SimpleShaper& shaper, GlyphData& glyphD
ata, bool mirror, int currentCharacter, unsigned& advanceLength) const | |
| 151 { | |
| 152 const TextRun& run = shaper.run(); | |
| 153 Vector<SVGGlyph::ArabicForm>& arabicForms = shaper.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.charactersL
ength() - currentCharacter); | |
| 161 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.chara
cters8(), remainingTextInRun.length()); | |
| 162 } else { | |
| 163 remainingTextInRun = String(run.data16(currentCharacter), run.characters
Length() - currentCharacter); | |
| 164 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.chara
cters16(), remainingTextInRun.length()); | |
| 165 } | |
| 166 | |
| 167 if (mirror) | |
| 168 remainingTextInRun = createStringWithMirroredCharacters(remainingTextInR
un); | |
| 169 if (!currentCharacter && arabicForms.isEmpty()) | |
| 170 arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); | |
| 171 | |
| 172 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); | |
| 173 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontEl
ement(); | |
| 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().isVerticalWriti
ngMode(); | |
| 189 if (Element* parentRenderObjectElement = toElement(parentRenderObject->n
ode())) { | |
| 190 language = parentRenderObjectElement->getAttribute(XMLNames::langAtt
r); | |
| 191 | |
| 192 if (isSVGAltGlyphElement(*parentRenderObjectElement)) { | |
| 193 if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGl
yphElements(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(altGlyphNam
es[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 incompatib
le. | |
| 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, unsig
ned 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, fo
ntData); | |
| 247 | |
| 248 ASSERT(bufferLength == 2 * length); | |
| 249 return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fon
tData); | |
| 250 } | |
| 251 | |
| 252 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFi
ll, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontD
ata) 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. SimpleShap
er 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 matchin
g). | |
| 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* pageT
oFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fo
ntData) 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. SimpleShap
er 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 matchin
g). | |
| 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) con
st | |
| 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 SVGFont
FaceElement. | |
| 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 | |
| OLD | NEW |