Home | History | Annotate | Download | only in svg
      1 /**
      2  * Copyright (C) 2007, 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 
     21 #include "config.h"
     22 
     23 #if ENABLE(SVG_FONTS)
     24 #include "Font.h"
     25 
     26 #include "CSSFontSelector.h"
     27 #include "GraphicsContext.h"
     28 #include "RenderObject.h"
     29 #include "SimpleFontData.h"
     30 #include "SVGAltGlyphElement.h"
     31 #include "SVGFontData.h"
     32 #include "SVGGlyphElement.h"
     33 #include "SVGGlyphMap.h"
     34 #include "SVGFontElement.h"
     35 #include "SVGFontFaceElement.h"
     36 #include "SVGMissingGlyphElement.h"
     37 #include "SVGPaintServer.h"
     38 #include "SVGPaintServerSolid.h"
     39 #include "XMLNames.h"
     40 
     41 using namespace WTF::Unicode;
     42 
     43 namespace WebCore {
     44 
     45 static inline float convertEmUnitToPixel(float fontSize, float unitsPerEm, float value)
     46 {
     47     if (unitsPerEm == 0.0f)
     48         return 0.0f;
     49 
     50     return value * fontSize / unitsPerEm;
     51 }
     52 
     53 static inline bool isVerticalWritingMode(const SVGRenderStyle* style)
     54 {
     55     return style->writingMode() == WM_TBRL || style->writingMode() == WM_TB;
     56 }
     57 
     58 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
     59 enum ArabicCharShapingMode {
     60     SNone = 0,
     61     SRight = 1,
     62     SDual = 2
     63 };
     64 
     65 static const ArabicCharShapingMode s_arabicCharShapingMode[222] = {
     66     SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, SDual , SDual , SDual , SDual , SDual , SRight,                 /* 0x0622 - 0x062F */
     67     SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SNone , SNone , SNone , SNone , SNone , /* 0x0630 - 0x063F */
     68     SNone , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SDual , SDual , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0640 - 0x064F */
     69     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0650 - 0x065F */
     70     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x0660 - 0x066F */
     71     SNone , SRight, SRight, SRight, SNone , SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0670 - 0x067F */
     72     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, /* 0x0680 - 0x068F */
     73     SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SDual , SDual , SDual , SDual , SDual , /* 0x0690 - 0x069F */
     74     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06A0 - 0x06AF */
     75     SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , SDual , /* 0x06B0 - 0x06BF */
     76     SRight, SDual , SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SRight, SDual , SRight, SDual , SRight, /* 0x06C0 - 0x06CF */
     77     SDual , SDual , SRight, SRight, SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06D0 - 0x06DF */
     78     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , /* 0x06E0 - 0x06EF */
     79     SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SNone , SDual , SDual , SDual , SNone , SNone , SNone   /* 0x06F0 - 0x06FF */
     80 };
     81 
     82 static inline SVGGlyphIdentifier::ArabicForm processArabicFormDetection(const UChar& curChar, bool& lastCharShapesRight, SVGGlyphIdentifier::ArabicForm* prevForm)
     83 {
     84     SVGGlyphIdentifier::ArabicForm curForm;
     85 
     86     ArabicCharShapingMode shapingMode = SNone;
     87     if (curChar >= 0x0622 && curChar <= 0x06FF)
     88         shapingMode = s_arabicCharShapingMode[curChar - 0x0622];
     89 
     90     // Use a simple state machine to identify the actual arabic form
     91     // It depends on the order of the arabic form enum:
     92     // enum ArabicForm { None = 0, Isolated, Terminal, Initial, Medial };
     93 
     94     if (lastCharShapesRight && shapingMode == SDual) {
     95         if (prevForm) {
     96             int correctedForm = (int) *prevForm + 1;
     97             ASSERT(correctedForm >= SVGGlyphIdentifier::None && correctedForm <= SVGGlyphIdentifier::Medial);
     98             *prevForm = static_cast<SVGGlyphIdentifier::ArabicForm>(correctedForm);
     99         }
    100 
    101         curForm = SVGGlyphIdentifier::Initial;
    102     } else
    103         curForm = shapingMode == SNone ? SVGGlyphIdentifier::None : SVGGlyphIdentifier::Isolated;
    104 
    105     lastCharShapesRight = shapingMode != SNone;
    106     return curForm;
    107 }
    108 
    109 static Vector<SVGGlyphIdentifier::ArabicForm> charactersWithArabicForm(const String& input, bool rtl)
    110 {
    111     Vector<SVGGlyphIdentifier::ArabicForm> forms;
    112     unsigned length = input.length();
    113 
    114     bool containsArabic = false;
    115     for (unsigned i = 0; i < length; ++i) {
    116         if (isArabicChar(input[i])) {
    117             containsArabic = true;
    118             break;
    119         }
    120     }
    121 
    122     if (!containsArabic)
    123         return forms;
    124 
    125     bool lastCharShapesRight = false;
    126 
    127     // Start identifying arabic forms
    128     if (rtl) {
    129         for (int i = length - 1; i >= 0; --i)
    130             forms.prepend(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.first()));
    131     } else {
    132         for (unsigned i = 0; i < length; ++i)
    133             forms.append(processArabicFormDetection(input[i], lastCharShapesRight, forms.isEmpty() ? 0 : &forms.last()));
    134     }
    135 
    136     return forms;
    137 }
    138 
    139 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier& identifier, const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
    140 {
    141     if (chars.isEmpty())
    142         return true;
    143 
    144     Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator it = chars.begin() + startPosition;
    145     Vector<SVGGlyphIdentifier::ArabicForm>::const_iterator end = chars.begin() + endPosition;
    146 
    147     ASSERT(end <= chars.end());
    148     for (; it != end; ++it) {
    149         if (*it != static_cast<SVGGlyphIdentifier::ArabicForm>(identifier.arabicForm) && *it != SVGGlyphIdentifier::None)
    150             return false;
    151     }
    152 
    153     return true;
    154 }
    155 
    156 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier& identifier, bool isVerticalText, const String& language,
    157                                      const Vector<SVGGlyphIdentifier::ArabicForm>& chars, unsigned startPosition, unsigned endPosition)
    158 {
    159     bool valid = true;
    160 
    161     // Check wheter orientation if glyph fits within the request
    162     switch (identifier.orientation) {
    163     case SVGGlyphIdentifier::Vertical:
    164         valid = isVerticalText;
    165         break;
    166     case SVGGlyphIdentifier::Horizontal:
    167         valid = !isVerticalText;
    168         break;
    169     case SVGGlyphIdentifier::Both:
    170         break;
    171     }
    172 
    173     if (!valid)
    174         return false;
    175 
    176     // Check wheter languages are compatible
    177     if (!identifier.languages.isEmpty()) {
    178         // This glyph exists only in certain languages, if we're not specifying a
    179         // language on the referencing element we're unable to use this glyph.
    180         if (language.isEmpty())
    181             return false;
    182 
    183         // Split subcode from language, if existant.
    184         String languagePrefix;
    185 
    186         int subCodeSeparator = language.find('-');
    187         if (subCodeSeparator != -1)
    188             languagePrefix = language.left(subCodeSeparator);
    189 
    190         Vector<String>::const_iterator it = identifier.languages.begin();
    191         Vector<String>::const_iterator end = identifier.languages.end();
    192 
    193         bool found = false;
    194         for (; it != end; ++it) {
    195             const String& cur = *it;
    196             if (cur == language || cur == languagePrefix) {
    197                 found = true;
    198                 break;
    199             }
    200         }
    201 
    202         if (!found)
    203             return false;
    204     }
    205 
    206     // Check wheter arabic form is compatible
    207     return isCompatibleArabicForm(identifier, chars, startPosition, endPosition);
    208 }
    209 
    210 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font)
    211 {
    212     ASSERT(fontData->isCustomFont());
    213     ASSERT(fontData->isSVGFont());
    214 
    215     const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->svgFontData());
    216 
    217     fontFace = svgFontData->svgFontFaceElement();
    218     ASSERT(fontFace);
    219 
    220     font = fontFace->associatedFontElement();
    221     return svgFontData;
    222 }
    223 
    224 // Helper class to walk a text run. Lookup a SVGGlyphIdentifier for each character
    225 // - also respecting possibly defined ligatures - and invoke a callback for each found glyph.
    226 template<typename SVGTextRunData>
    227 struct SVGTextRunWalker {
    228     typedef bool (*SVGTextRunWalkerCallback)(const SVGGlyphIdentifier&, SVGTextRunData&);
    229     typedef void (*SVGTextRunWalkerMissingGlyphCallback)(const TextRun&, SVGTextRunData&);
    230 
    231     SVGTextRunWalker(const SVGFontData* fontData, SVGFontElement* fontElement, SVGTextRunData& data,
    232                      SVGTextRunWalkerCallback callback, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback)
    233         : m_fontData(fontData)
    234         , m_fontElement(fontElement)
    235         , m_walkerData(data)
    236         , m_walkerCallback(callback)
    237         , m_walkerMissingGlyphCallback(missingGlyphCallback)
    238     {
    239     }
    240 
    241     void walk(const TextRun& run, bool isVerticalText, const String& language, int from, int to)
    242     {
    243         ASSERT(0 <= from && from <= to && to - from <= run.length());
    244 
    245         const String text = Font::normalizeSpaces(String(run.data(from), run.length()));
    246         Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(text, run.rtl()));
    247 
    248         SVGGlyphIdentifier identifier;
    249         bool foundGlyph = false;
    250         int characterLookupRange;
    251         int endOfScanRange = to + m_walkerData.extraCharsAvailable;
    252 
    253         bool haveAltGlyph = false;
    254         SVGGlyphIdentifier altGlyphIdentifier;
    255         if (RenderObject* renderObject = run.referencingRenderObject()) {
    256             if (renderObject->node() && renderObject->node()->hasTagName(SVGNames::altGlyphTag)) {
    257                 SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->node())->glyphElement();
    258                 if (glyphElement) {
    259                     haveAltGlyph = true;
    260                     altGlyphIdentifier = glyphElement->buildGlyphIdentifier();
    261                     altGlyphIdentifier.isValid = true;
    262                     altGlyphIdentifier.nameLength = to - from;
    263                 }
    264             }
    265         }
    266 
    267         for (int i = from; i < to; ++i) {
    268             // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1).
    269             // We have to check wheter the current character & the next character define a ligature. This needs to be
    270             // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature.
    271             characterLookupRange = endOfScanRange - i;
    272 
    273             String lookupString = Font::normalizeSpaces(String(run.data(i), characterLookupRange));
    274 
    275             Vector<SVGGlyphIdentifier> glyphs;
    276             if (haveAltGlyph)
    277                 glyphs.append(altGlyphIdentifier);
    278             else
    279                 m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);
    280 
    281             Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin();
    282             Vector<SVGGlyphIdentifier>::iterator end = glyphs.end();
    283 
    284             for (; it != end; ++it) {
    285                 identifier = *it;
    286                 if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) {
    287                     ASSERT(characterLookupRange > 0);
    288                     i += identifier.nameLength - 1;
    289                     m_walkerData.charsConsumed += identifier.nameLength;
    290                     m_walkerData.glyphName = identifier.glyphName;
    291 
    292                     foundGlyph = true;
    293                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
    294                     break;
    295                 }
    296             }
    297 
    298             if (!foundGlyph) {
    299                 ++m_walkerData.charsConsumed;
    300                 if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) {
    301                     // <missing-glyph> element support
    302                     identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
    303                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
    304                     identifier.isValid = true;
    305                 } else {
    306                     // Fallback to system font fallback
    307                     TextRun subRun(run);
    308                     subRun.setText(subRun.data(i), 1);
    309 
    310                     (*m_walkerMissingGlyphCallback)(subRun, m_walkerData);
    311                     continue;
    312                 }
    313             }
    314 
    315             if (!(*m_walkerCallback)(identifier, m_walkerData))
    316                 break;
    317 
    318             foundGlyph = false;
    319         }
    320     }
    321 
    322 private:
    323     const SVGFontData* m_fontData;
    324     SVGFontElement* m_fontElement;
    325     SVGTextRunData& m_walkerData;
    326     SVGTextRunWalkerCallback m_walkerCallback;
    327     SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback;
    328 };
    329 
    330 // Callback & data structures to compute the width of text using SVG Fonts
    331 struct SVGTextRunWalkerMeasuredLengthData {
    332     int at;
    333     int from;
    334     int to;
    335     int extraCharsAvailable;
    336     int charsConsumed;
    337     String glyphName;
    338 
    339     float scale;
    340     float length;
    341     const Font* font;
    342 };
    343 
    344 static bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerMeasuredLengthData& data)
    345 {
    346     if (data.at >= data.from && data.at < data.to)
    347         data.length += identifier.horizontalAdvanceX * data.scale;
    348 
    349     data.at++;
    350     return data.at < data.to;
    351 }
    352 
    353 static void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data)
    354 {
    355     // Handle system font fallback
    356     FontDescription fontDescription(data.font->fontDescription());
    357     fontDescription.setFamily(FontFamily());
    358     Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
    359     font.update(data.font->fontSelector());
    360 
    361     data.length += font.floatWidth(run);
    362 }
    363 
    364 
    365 SVGFontElement* Font::svgFont() const
    366 {
    367     if (!isSVGFont())
    368         return 0;
    369 
    370     SVGFontElement* fontElement = 0;
    371     SVGFontFaceElement* fontFaceElement = 0;
    372     if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement))
    373         return fontElement;
    374 
    375     return 0;
    376 }
    377 
    378 static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed, String& glyphName)
    379 {
    380     int newFrom = to > from ? from : to;
    381     int newTo = to > from ? to : from;
    382 
    383     from = newFrom;
    384     to = newTo;
    385 
    386     SVGFontElement* fontElement = 0;
    387     SVGFontFaceElement* fontFaceElement = 0;
    388 
    389     if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) {
    390         if (!fontElement)
    391             return 0.0f;
    392 
    393         SVGTextRunWalkerMeasuredLengthData data;
    394 
    395         data.font = font;
    396         data.at = from;
    397         data.from = from;
    398         data.to = to;
    399         data.extraCharsAvailable = extraCharsAvailable;
    400         data.charsConsumed = 0;
    401         data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
    402         data.length = 0.0f;
    403 
    404         String language;
    405         bool isVerticalText = false; // Holds true for HTML text
    406 
    407         // TODO: language matching & svg glyphs should be possible for HTML text, too.
    408         if (RenderObject* renderObject = run.referencingRenderObject()) {
    409             isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle());
    410 
    411             if (SVGElement* element = static_cast<SVGElement*>(renderObject->node()))
    412                 language = element->getAttribute(XMLNames::langAttr);
    413         }
    414 
    415         SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
    416         runWalker.walk(run, isVerticalText, language, 0, run.length());
    417         charsConsumed = data.charsConsumed;
    418         glyphName = data.glyphName;
    419         return data.length;
    420     }
    421 
    422     return 0.0f;
    423 }
    424 
    425 float Font::floatWidthUsingSVGFont(const TextRun& run) const
    426 {
    427     int charsConsumed;
    428     String glyphName;
    429     return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName);
    430 }
    431 
    432 float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
    433 {
    434     return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName);
    435 }
    436 
    437 // Callback & data structures to draw text using SVG Fonts
    438 struct SVGTextRunWalkerDrawTextData {
    439     int extraCharsAvailable;
    440     int charsConsumed;
    441     String glyphName;
    442     Vector<SVGGlyphIdentifier> glyphIdentifiers;
    443     Vector<UChar> fallbackCharacters;
    444 };
    445 
    446 static bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data)
    447 {
    448     data.glyphIdentifiers.append(identifier);
    449     return true;
    450 }
    451 
    452 static void drawTextMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerDrawTextData& data)
    453 {
    454     ASSERT(run.length() == 1);
    455     data.glyphIdentifiers.append(SVGGlyphIdentifier());
    456     data.fallbackCharacters.append(run[0]);
    457 }
    458 
    459 void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run,
    460                                 const FloatPoint& point, int from, int to) const
    461 {
    462     SVGFontElement* fontElement = 0;
    463     SVGFontFaceElement* fontFaceElement = 0;
    464 
    465     if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
    466         if (!fontElement)
    467             return;
    468 
    469         SVGTextRunWalkerDrawTextData data;
    470         FloatPoint currentPoint = point;
    471         float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);
    472 
    473         SVGPaintServer* activePaintServer = run.activePaintServer();
    474 
    475         // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
    476         if (!run.referencingRenderObject()) {
    477             ASSERT(!activePaintServer);
    478 
    479             // TODO: We're only supporting simple filled HTML text so far.
    480             SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
    481             solidPaintServer->setColor(context->fillColor());
    482 
    483             activePaintServer = solidPaintServer;
    484         }
    485 
    486         ASSERT(activePaintServer);
    487 
    488         int charsConsumed;
    489         String glyphName;
    490         bool isVerticalText = false;
    491         float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
    492         FloatPoint glyphOrigin;
    493 
    494         String language;
    495 
    496         // TODO: language matching & svg glyphs should be possible for HTML text, too.
    497         if (run.referencingRenderObject()) {
    498             isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());
    499 
    500             if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->node()))
    501                 language = element->getAttribute(XMLNames::langAttr);
    502         }
    503 
    504         if (!isVerticalText) {
    505             glyphOrigin.setX(fontData->horizontalOriginX() * scale);
    506             glyphOrigin.setY(fontData->horizontalOriginY() * scale);
    507         }
    508 
    509         data.extraCharsAvailable = 0;
    510         data.charsConsumed = 0;
    511 
    512         SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
    513         runWalker.walk(run, isVerticalText, language, from, to);
    514 
    515         SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;
    516 
    517         unsigned numGlyphs = data.glyphIdentifiers.size();
    518         unsigned fallbackCharacterIndex = 0;
    519         for (unsigned i = 0; i < numGlyphs; ++i) {
    520             const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
    521             if (identifier.isValid) {
    522                 // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
    523                 if (!identifier.pathData.isEmpty()) {
    524                     context->save();
    525 
    526                     if (isVerticalText) {
    527                         glyphOrigin.setX(identifier.verticalOriginX * scale);
    528                         glyphOrigin.setY(identifier.verticalOriginY * scale);
    529                     }
    530 
    531                     context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
    532                     context->scale(FloatSize(scale, -scale));
    533 
    534                     context->beginPath();
    535                     context->addPath(identifier.pathData);
    536 
    537                     // FIXME: setup() tries to get objectBoundingBox() from run.referencingRenderObject()
    538                     // which is wrong.  We need to change setup() to take a bounding box instead, or pass
    539                     // a RenderObject which would return the bounding box for identifier.pathData
    540                     if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
    541                         // Spec: Any properties specified on a text elements which represents a length, such as the
    542                         // 'stroke-width' property, might produce surprising results since the length value will be
    543                         // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
    544                         if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
    545                             context->setStrokeThickness(context->strokeThickness() / scale);
    546 
    547                         activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
    548                         activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
    549                     }
    550 
    551                     context->restore();
    552                 }
    553 
    554                 if (isVerticalText)
    555                     currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
    556                 else
    557                     currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
    558             } else {
    559                 // Handle system font fallback
    560                 FontDescription fontDescription(m_fontDescription);
    561                 fontDescription.setFamily(FontFamily());
    562                 Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
    563                 font.update(fontSelector());
    564 
    565                 TextRun fallbackCharacterRun(run);
    566                 fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
    567                 font.drawText(context, fallbackCharacterRun, currentPoint);
    568 
    569                 if (isVerticalText)
    570                     currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
    571                 else
    572                     currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);
    573 
    574                 fallbackCharacterIndex++;
    575             }
    576         }
    577     }
    578 }
    579 
    580 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const
    581 {
    582     int charsConsumed;
    583     String glyphName;
    584 
    585     return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName),
    586                      point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);
    587 }
    588 
    589 int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int, bool) const
    590 {
    591     // TODO: Fix text selection when HTML text is drawn using a SVG Font
    592     // We need to integrate the SVG text selection code in the offsetForPosition() framework.
    593     // This will also fix a major issue, that SVG Text code can't select arabic strings properly.
    594     return 0;
    595 }
    596 
    597 }
    598 
    599 #endif
    600