• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@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 
convertEmUnitToPixel(float fontSize,float unitsPerEm,float value)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 
isVerticalWritingMode(const SVGRenderStyle * style)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 
processArabicFormDetection(const UChar & curChar,bool & lastCharShapesRight,SVGGlyphIdentifier::ArabicForm * prevForm)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 
charactersWithArabicForm(const String & input,bool rtl)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 
isCompatibleArabicForm(const SVGGlyphIdentifier & identifier,const Vector<SVGGlyphIdentifier::ArabicForm> & chars,unsigned startPosition,unsigned endPosition)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 
isCompatibleGlyph(const SVGGlyphIdentifier & identifier,bool isVerticalText,const String & language,const Vector<SVGGlyphIdentifier::ArabicForm> & chars,unsigned startPosition,unsigned endPosition)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 
svgFontAndFontFaceElementForFontData(const SimpleFontData * fontData,SVGFontFaceElement * & fontFace,SVGFontElement * & font)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 
SVGTextRunWalkerWebCore::SVGTextRunWalker233     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 
walkWebCore::SVGTextRunWalker243     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 
floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier & identifier,SVGTextRunWalkerMeasuredLengthData & data)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 
floatWidthMissingGlyphCallback(const TextRun & run,SVGTextRunWalkerMeasuredLengthData & data)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 
svgFont() const369 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 
floatWidthOfSubStringUsingSVGFont(const Font * font,const TextRun & run,int extraCharsAvailable,int from,int to,int & charsConsumed,String & glyphName)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 
floatWidthUsingSVGFont(const TextRun & run) const431 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 
floatWidthUsingSVGFont(const TextRun & run,int extraCharsAvailable,int & charsConsumed,String & glyphName) const438 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 
drawTextUsingSVGFontCallback(const SVGGlyphIdentifier & identifier,SVGTextRunWalkerDrawTextData & data)452 static bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data)
453 {
454     data.glyphIdentifiers.append(identifier);
455     return true;
456 }
457 
drawTextMissingGlyphCallback(const TextRun & run,SVGTextRunWalkerDrawTextData & data)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 
drawTextUsingSVGFont(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const465 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 
selectionRectForTextUsingSVGFont(const TextRun & run,const FloatPoint & point,int height,int from,int to) const586 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 
offsetForPositionForTextUsingSVGFont(const TextRun &,float,bool) const595 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