File indexing completed on 2024-04-28 15:24:33

0001 /**
0002  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  *
0019  */
0020 
0021 #if ENABLE(SVG_FONTS)
0022 #include "Font.h"
0023 
0024 #include "CSSFontSelector.h"
0025 #include "GraphicsContext.h"
0026 #include "RenderObject.h"
0027 #include "SimpleFontData.h"
0028 #include "SVGAltGlyphElement.h"
0029 #include "SVGFontData.h"
0030 #include "SVGGlyphElement.h"
0031 #include "SVGGlyphMap.h"
0032 #include "SVGFontElement.h"
0033 #include "SVGFontFaceElement.h"
0034 #include "SVGMissingGlyphElement.h"
0035 #include "SVGPaintServer.h"
0036 #include "SVGPaintServerSolid.h"
0037 #include "XMLNames.h"
0038 
0039 using namespace WTF::Unicode;
0040 
0041 namespace WebCore
0042 {
0043 
0044 static inline float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value)
0045 {
0046     if (unitsPerEm == 0.0f) {
0047         return 0.0f;
0048     }
0049 
0050     return value * fontSize / unitsPerEm;
0051 }
0052 
0053 static inline bool isVerticalWritingMode(const SVGRenderStyle *style)
0054 {
0055     return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB;
0056 }
0057 
0058 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
0059 enum ArabicCharShapingMode {
0060     SNone = 0,
0061     SRight = 1,
0062     SDual = 2
0063 };
0064 
0065 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = {
0066     SRight, SRight, SRight, SRight, SDual, SRight, SDual, SRight, SDual, SDual, SDual, SDual, SDual, SRight,                 /* 0x0622 - 0x062F */
0067     SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SNone, SNone, SNone, SNone, SNone, /* 0x0630 - 0x063F */
0068     SNone, SDual, SDual, SDual, SDual, SDual, SDual, SRight, SDual, SDual, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0640 - 0x064F */
0069     SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0650 - 0x065F */
0070     SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x0660 - 0x066F */
0071     SNone, SRight, SRight, SRight, SNone, SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x0670 - 0x067F */
0072     SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */
0073     SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x0690 - 0x069F */
0074     SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x06A0 - 0x06AF */
0075     SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, SDual, /* 0x06B0 - 0x06BF */
0076     SRight, SDual, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual, SRight, SDual, SRight, /* 0x06C0 - 0x06CF */
0077     SDual, SDual, SRight, SRight, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x06D0 - 0x06DF */
0078     SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, /* 0x06E0 - 0x06EF */
0079     SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SNone, SDual, SDual, SDual, SNone, SNone, SNone   /* 0x06F0 - 0x06FF */
0080 };
0081 
0082 static inline SVGGlyphIdentifier::ArabicForm processArabicFormDetection(const UChar &curChar, bool &lastCharShapesRight, SVGGlyphIdentifier::ArabicForm *prevForm)
0083 {
0084     SVGGlyphIdentifier::ArabicForm curForm;
0085 
0086     ArabicCharShapingMode shapingMode = SNone;
0087     if (curChar >= 0x0622 && curChar <= 0x06FF) {
0088         shapingMode = s_arabicCharShapingMode[curChar - 0x0622];
0089     }
0090 
0091     // Use a simple state machine to identify the actual arabic form
0092     // It depends on the order of the arabic form enum:
0093     // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial };
0094 
0095     if (lastCharShapesRight && shapingMode == SDual) {
0096         if (prevForm) {
0097             int correctedForm = (int) * prevForm + 1;
0098             ASSERT(correctedForm >= SVGGlyphIdentifier::None && correctedForm <= SVGGlyphIdentifier::Medial);
0099             *prevForm = static_cast<SVGGlyphIdentifier::ArabicForm>(correctedForm);
0100         }
0101 
0102         curForm = SVGGlyphIdentifier::Initial;
0103     } else {
0104         curForm = shapingMode == SNone ? SVGGlyphIdentifier::None : SVGGlyphIdentifier::Isolated;
0105     }
0106 
0107     lastCharShapesRight = shapingMode != SNone;
0108     return curForm;
0109 }
0110 
0111 static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String &input, bool rtl)
0112 {
0113     Vector<SVGGlyphIdentifier::ArabicForm> forms;
0114     unsigned int length = input.length();
0115 
0116     bool containsArabic = false;
0117     for (unsigned int i = 0; i < length; ++i) {
0118         if (isArabicChar(input[i])) {
0119             containsArabic = true;
0120             break;
0121         }
0122     }
0123 
0124     if (!containsArabic) {
0125         return forms;
0126     }
0127 
0128     bool lastCharShapesRight = false;
0129 
0130     // Start identifying arabic forms
0131     if (rtl)
0132         for (int i = length - 1; i >= 0; --i) {
0133             forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
0134         }
0135     else
0136         for (unsigned int i = 0; i < length; ++i) {
0137             forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
0138         }
0139 
0140     return forms;
0141 }
0142 
0143 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier &identifier, const Vector<SVGGlyphIdentifier::ArabicForm> &chars, unsigned int startPosition, unsigned int endPosition)
0144 {
0145     if (chars.isEmpty()) {
0146         return true;
0147     }
0148 
0149     Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator it = chars.begin() + startPosition;
0150     Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator end = chars.begin() + endPosition;
0151 
0152     ASSERT(end <= chars.end());
0153     for (; it != end; ++it) {
0154         if ((*it) != identifier.arabicForm && (*it) != SVGGlyphIdentifier::None) {
0155             return false;
0156         }
0157     }
0158 
0159     return true;
0160 }
0161 
0162 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier &identifier, bool isVerticalText, const String &language,
0163                                      const Vector<SVGGlyphIdentifier::ArabicForm> &chars, unsigned int startPosition, unsigned int endPosition)
0164 {
0165     bool valid = true;
0166 
0167     // Check whether orientation if glyph fits within the request
0168     switch (identifier.orientation) {
0169     case SVGGlyphIdentifier::Vertical:
0170         valid = isVerticalText;
0171         break;
0172     case SVGGlyphIdentifier::Horizontal:
0173         valid = !isVerticalText;
0174         break;
0175     case SVGGlyphIdentifier::Both:
0176         break;
0177     }
0178 
0179     if (!valid) {
0180         return false;
0181     }
0182 
0183     // Check whether languages are compatible
0184     if (!identifier.languages.isEmpty()) {
0185         // This glyph exists only in certain languages, if we're not specifying a
0186         // language on the referencing element we're unable to use this glyph.
0187         if (language.isEmpty()) {
0188             return false;
0189         }
0190 
0191         // Split subcode from language, if existent.
0192         String languagePrefix;
0193 
0194         int subCodeSeparator = language.find('-');
0195         if (subCodeSeparator != -1) {
0196             languagePrefix = language.left(subCodeSeparator);
0197         }
0198 
0199         Vector<String>::const_iterator it = identifier.languages.begin();
0200         Vector<String>::const_iterator end = identifier.languages.end();
0201 
0202         bool found = false;
0203         for (; it != end; ++it) {
0204             String cur = (*it);
0205 
0206             if (cur == language || cur == languagePrefix) {
0207                 found = true;
0208                 break;
0209             }
0210         }
0211 
0212         if (!found) {
0213             return false;
0214         }
0215     }
0216 
0217     // Check whether arabic form is compatible
0218     return isCompatibleArabicForm(identifier, chars, startPosition, endPosition);
0219 }
0220 
0221 static inline const SVGFontData *svgFontAndFontFaceElementForFontData(const SimpleFontData *fontData, SVGFontFaceElement *&fontFace, SVGFontElement *&font)
0222 {
0223     ASSERT(fontData->isCustomFont());
0224     ASSERT(fontData->isSVGFont());
0225 
0226     const SVGFontData *svgFontData = static_cast<const SVGFontData *>(fontData->svgFontData());
0227 
0228     fontFace = svgFontData->svgFontFaceElement();
0229     ASSERT(fontFace);
0230 
0231     font = fontFace->associatedFontElement();
0232     return svgFontData;
0233 }
0234 
0235 // Helper class to walk a text run. Lookup a SVGGlyphIdentifier for each character
0236 // - also respecting possibly defined ligatures - and invoke a callback for each found glyph.
0237 template<typename SVGTextRunData>
0238 struct SVGTextRunWalker {
0239     typedef bool (*SVGTextRunWalkerCallback)(const SVGGlyphIdentifier &, SVGTextRunData &);
0240     typedef void (*SVGTextRunWalkerMissingGlyphCallback)(const TextRun &, SVGTextRunData &);
0241 
0242     SVGTextRunWalker(const SVGFontData *fontData, SVGFontElement *fontElement, SVGTextRunData &data,
0243                      SVGTextRunWalkerCallback callback, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback)
0244         : m_fontData(fontData)
0245         , m_fontElement(fontElement)
0246         , m_walkerData(data)
0247         , m_walkerCallback(callback)
0248         , m_walkerMissingGlyphCallback(missingGlyphCallback)
0249     {
0250     }
0251 
0252     void walk(const TextRun &run, bool isVerticalText, const String &language, int from, int to)
0253     {
0254         // Should hold true for SVG text, otherwhise sth. is wrong
0255         ASSERT(to - from == run.length());
0256 
0257         Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl()));
0258 
0259         SVGGlyphIdentifier identifier;
0260         bool foundGlyph = false;
0261         int characterLookupRange;
0262         int endOfScanRange = to + m_walkerData.extraCharsAvailable;
0263 
0264         bool haveAltGlyph = false;
0265         SVGGlyphIdentifier altGlyphIdentifier;
0266         if (RenderObject *renderObject = run.referencingRenderObject()) {
0267             if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) {
0268                 SVGGlyphElement *glyphElement = static_cast<SVGAltGlyphElement *>(renderObject->element())->glyphElement();
0269                 if (glyphElement) {
0270                     haveAltGlyph = true;
0271                     altGlyphIdentifier = glyphElement->buildGlyphIdentifier();
0272                     altGlyphIdentifier.isValid = true;
0273                     altGlyphIdentifier.nameLength = to - from;
0274                 }
0275             }
0276         }
0277 
0278         for (int i = from; i < to; ++i) {
0279             // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1).
0280             // We have to check whether the current character & the next character define a ligature. This needs to be
0281             // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature.
0282             characterLookupRange = endOfScanRange - i;
0283 
0284             String lookupString(run.data(i), characterLookupRange);
0285             Vector<SVGGlyphIdentifier> glyphs;
0286             if (haveAltGlyph) {
0287                 glyphs.append(altGlyphIdentifier);
0288             } else {
0289                 m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);
0290             }
0291 
0292             Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin();
0293             Vector<SVGGlyphIdentifier>::iterator end = glyphs.end();
0294 
0295             for (; it != end; ++it) {
0296                 identifier = *it;
0297                 if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) {
0298                     ASSERT(characterLookupRange > 0);
0299                     i += identifier.nameLength - 1;
0300                     m_walkerData.charsConsumed += identifier.nameLength;
0301                     m_walkerData.glyphName = identifier.glyphName;
0302 
0303                     foundGlyph = true;
0304                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
0305                     break;
0306                 }
0307             }
0308 
0309             if (!foundGlyph) {
0310                 ++m_walkerData.charsConsumed;
0311                 if (SVGMissingGlyphElement *element = m_fontElement->firstMissingGlyphElement()) {
0312                     // <missing-glyph> element support
0313                     identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
0314                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
0315                     identifier.isValid = true;
0316                 } else {
0317                     // Fallback to system font fallback
0318                     TextRun subRun(run);
0319                     subRun.setText(subRun.data(i), 1);
0320 
0321                     (*m_walkerMissingGlyphCallback)(subRun, m_walkerData);
0322                     continue;
0323                 }
0324             }
0325 
0326             if (!(*m_walkerCallback)(identifier, m_walkerData)) {
0327                 break;
0328             }
0329 
0330             foundGlyph = false;
0331         }
0332     }
0333 
0334 private:
0335     const SVGFontData *m_fontData;
0336     SVGFontElement *m_fontElement;
0337     SVGTextRunData &m_walkerData;
0338     SVGTextRunWalkerCallback m_walkerCallback;
0339     SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback;
0340 };
0341 
0342 // Callback & data structures to compute the width of text using SVG Fonts
0343 struct SVGTextRunWalkerMeasuredLengthData {
0344     int at;
0345     int from;
0346     int to;
0347     int extraCharsAvailable;
0348     int charsConsumed;
0349     String glyphName;
0350 
0351     float scale;
0352     float length;
0353     const Font *font;
0354 };
0355 
0356 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier &identifier, SVGTextRunWalkerMeasuredLengthData &data)
0357 {
0358     if (data.at >= data.from && data.at < data.to) {
0359         data.length += identifier.horizontalAdvanceX * data.scale;
0360     }
0361 
0362     data.at++;
0363     return data.at < data.to;
0364 }
0365 
0366 void floatWidthMissingGlyphCallback(const TextRun &run, SVGTextRunWalkerMeasuredLengthData &data)
0367 {
0368     // Handle system font fallback
0369     FontDescription fontDescription(data.font->fontDescription());
0370     fontDescription.setFamily(FontFamily());
0371     Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
0372     font.update(data.font->fontSelector());
0373 
0374     data.length += font.floatWidth(run);
0375 }
0376 
0377 SVGFontElement *Font::svgFont() const
0378 {
0379     if (!isSVGFont()) {
0380         return 0;
0381     }
0382 
0383     SVGFontElement *fontElement = 0;
0384     SVGFontFaceElement *fontFaceElement = 0;
0385     if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
0386         return fontElement;
0387     }
0388 
0389     return 0;
0390 }
0391 
0392 static float floatWidthOfSubStringUsingSVGFont(const Font *font, const TextRun &run, int extraCharsAvailable, int from, int to, int &charsConsumed, String &glyphName)
0393 {
0394     int newFrom = to > from ? from : to;
0395     int newTo = to > from ? to : from;
0396 
0397     from = newFrom;
0398     to = newTo;
0399 
0400     SVGFontElement *fontElement = 0;
0401     SVGFontFaceElement *fontFaceElement = 0;
0402 
0403     if (const SVGFontData *fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) {
0404         if (!fontElement) {
0405             return 0.0f;
0406         }
0407 
0408         SVGTextRunWalkerMeasuredLengthData data;
0409 
0410         data.font = font;
0411         data.at = from;
0412         data.from = from;
0413         data.to = to;
0414         data.extraCharsAvailable = extraCharsAvailable;
0415         data.charsConsumed = 0;
0416         data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
0417         data.length = 0.0f;
0418 
0419         String language;
0420         bool isVerticalText = false; // Holds true for HTML text
0421 
0422         // TODO: language matching & svg glyphs should be possible for HTML text, too.
0423         if (RenderObject *renderObject = run.referencingRenderObject()) {
0424             isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle());
0425 
0426             if (SVGElement *element = static_cast<SVGElement *>(renderObject->element())) {
0427                 language = element->getAttribute(XMLNames::langAttr);
0428             }
0429         }
0430 
0431         SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
0432         runWalker.walk(run, isVerticalText, language, 0, run.length());
0433         charsConsumed = data.charsConsumed;
0434         glyphName = data.glyphName;
0435         return data.length;
0436     }
0437 
0438     return 0.0f;
0439 }
0440 
0441 float Font::floatWidthUsingSVGFont(const TextRun &run) const
0442 {
0443     int charsConsumed;
0444     String glyphName;
0445     return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName);
0446 }
0447 
0448 float Font::floatWidthUsingSVGFont(const TextRun &run, int extraCharsAvailable, int &charsConsumed, String &glyphName) const
0449 {
0450     return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName);
0451 }
0452 
0453 // Callback & data structures to draw text using SVG Fonts
0454 struct SVGTextRunWalkerDrawTextData {
0455     int extraCharsAvailable;
0456     int charsConsumed;
0457     String glyphName;
0458     Vector<SVGGlyphIdentifier> glyphIdentifiers;
0459     Vector<UChar> fallbackCharacters;
0460 };
0461 
0462 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier &identifier, SVGTextRunWalkerDrawTextData &data)
0463 {
0464     data.glyphIdentifiers.append(identifier);
0465     return true;
0466 }
0467 
0468 void drawTextMissingGlyphCallback(const TextRun &run, SVGTextRunWalkerDrawTextData &data)
0469 {
0470     ASSERT(run.length() == 1);
0471     data.glyphIdentifiers.append(SVGGlyphIdentifier());
0472     data.fallbackCharacters.append(run[0]);
0473 }
0474 
0475 void Font::drawTextUsingSVGFont(GraphicsContext *context, const TextRun &run,
0476                                 const FloatPoint &point, int from, int to) const
0477 {
0478     SVGFontElement *fontElement = 0;
0479     SVGFontFaceElement *fontFaceElement = 0;
0480 
0481     if (const SVGFontData *fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
0482         if (!fontElement) {
0483             return;
0484         }
0485 
0486         SVGTextRunWalkerDrawTextData data;
0487         FloatPoint currentPoint = point;
0488         float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);
0489 
0490         SVGPaintServer *activePaintServer = run.activePaintServer();
0491 
0492         // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
0493         if (!run.referencingRenderObject()) {
0494             ASSERT(!activePaintServer);
0495 
0496             // TODO: We're only supporting simple filled HTML text so far.
0497             SVGPaintServerSolid *solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
0498             solidPaintServer->setColor(context->fillColor());
0499 
0500             activePaintServer = solidPaintServer;
0501         }
0502 
0503         ASSERT(activePaintServer);
0504 
0505         int charsConsumed;
0506         String glyphName;
0507         bool isVerticalText = false;
0508         float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
0509         FloatPoint glyphOrigin;
0510 
0511         String language;
0512 
0513         // TODO: language matching & svg glyphs should be possible for HTML text, too.
0514         if (run.referencingRenderObject()) {
0515             isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());
0516 
0517             if (SVGElement *element = static_cast<SVGElement *>(run.referencingRenderObject()->element())) {
0518                 language = element->getAttribute(XMLNames::langAttr);
0519             }
0520         }
0521 
0522         if (!isVerticalText) {
0523             glyphOrigin.setX(fontData->horizontalOriginX() * scale);
0524             glyphOrigin.setY(fontData->horizontalOriginY() * scale);
0525         }
0526 
0527         data.extraCharsAvailable = 0;
0528 
0529         SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
0530         runWalker.walk(run, isVerticalText, language, from, to);
0531 
0532         SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;
0533 
0534         unsigned numGlyphs = data.glyphIdentifiers.size();
0535         unsigned fallbackCharacterIndex = 0;
0536         for (unsigned i = 0; i < numGlyphs; ++i) {
0537             const SVGGlyphIdentifier &identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
0538             if (identifier.isValid) {
0539                 // FIXME: Support arbitrary SVG content as glyph (currently limited to <glyph d="..."> situations).
0540                 if (!identifier.pathData.isEmpty()) {
0541                     context->save();
0542 
0543                     if (isVerticalText) {
0544                         glyphOrigin.setX(identifier.verticalOriginX * scale);
0545                         glyphOrigin.setY(identifier.verticalOriginY * scale);
0546                     }
0547 
0548                     context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
0549                     context->scale(FloatSize(scale, -scale));
0550 
0551                     context->beginPath();
0552                     context->addPath(identifier.pathData);
0553 
0554                     if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
0555                         // Spec: Any properties specified on a text elements which represents a length, such as the
0556                         // 'stroke-width' property, might produce surprising results since the length value will be
0557                         // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
0558                         if (targetType == ApplyToStrokeTargetType && scale != 0.0f) {
0559                             context->setStrokeThickness(context->strokeThickness() / scale);
0560                         }
0561 
0562                         activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
0563                         activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
0564                     }
0565 
0566                     context->restore();
0567                 }
0568 
0569                 if (isVerticalText) {
0570                     currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
0571                 } else {
0572                     currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
0573                 }
0574             } else {
0575                 // Handle system font fallback
0576                 FontDescription fontDescription(context->font().fontDescription());
0577                 fontDescription.setFamily(FontFamily());
0578                 Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
0579                 font.update(context->font().fontSelector());
0580 
0581                 TextRun fallbackCharacterRun(run);
0582                 fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
0583                 font.drawText(context, fallbackCharacterRun, currentPoint);
0584 
0585                 if (isVerticalText) {
0586                     currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
0587                 } else {
0588                     currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);
0589                 }
0590 
0591                 fallbackCharacterIndex++;
0592             }
0593         }
0594     }
0595 }
0596 
0597 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun &run, const IntPoint &point, int height, int from, int to) const
0598 {
0599     int charsConsumed;
0600     String glyphName;
0601 
0602     return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName),
0603                      point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);
0604 }
0605 
0606 int Font::offsetForPositionForTextUsingSVGFont(const TextRun &, int position, bool includePartialGlyphs) const
0607 {
0608     // TODO: Fix text selection when HTML text is drawn using a SVG Font
0609     // We need to integrate the SVG text selection code in the offsetForPosition() framework.
0610     // This will also fix a major issue, that SVG Text code can't select arabic strings properly.
0611     return 0;
0612 }
0613 
0614 }
0615 
0616 #endif