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