aaa7aa8bb68928c40d1f2aa6e89c455ea1346397
[WebKit-https.git] / WebCore / svg / SVGFont.cpp
1 /**
2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  *
19  */
20
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         // Should hold true for SVG text, otherwhise sth. is wrong
244         ASSERT(to - from == run.length());
245
246         Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), 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->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) {
257                 SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->element())->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(run.data(i), characterLookupRange);
274             Vector<SVGGlyphIdentifier> glyphs;
275             if (haveAltGlyph)
276                 glyphs.append(altGlyphIdentifier);
277             else
278                 m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs);
279
280             Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin();
281             Vector<SVGGlyphIdentifier>::iterator end = glyphs.end();
282             
283             for (; it != end; ++it) {
284                 identifier = *it;
285                 if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) {
286                     ASSERT(characterLookupRange > 0);
287                     i += identifier.nameLength - 1;
288                     m_walkerData.charsConsumed += identifier.nameLength;
289                     m_walkerData.glyphName = identifier.glyphName;
290
291                     foundGlyph = true;
292                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
293                     break;
294                 }
295             }
296
297             if (!foundGlyph) {
298                 ++m_walkerData.charsConsumed;
299                 if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) {
300                     // <missing-glyph> element support
301                     identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element);
302                     SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData);
303                     identifier.isValid = true;
304                 } else {
305                     // Fallback to system font fallback
306                     TextRun subRun(run);
307                     subRun.setText(subRun.data(i), 1);
308
309                     (*m_walkerMissingGlyphCallback)(subRun, m_walkerData);
310                     continue;
311                 }
312             }
313
314             if (!(*m_walkerCallback)(identifier, m_walkerData))
315                 break;
316
317             foundGlyph = false;
318         }
319     }
320
321 private:
322     const SVGFontData* m_fontData;
323     SVGFontElement* m_fontElement;
324     SVGTextRunData& m_walkerData;
325     SVGTextRunWalkerCallback m_walkerCallback;
326     SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback;
327 };
328
329 // Callback & data structures to compute the width of text using SVG Fonts
330 struct SVGTextRunWalkerMeasuredLengthData {
331     int at;
332     int from;
333     int to;
334     int extraCharsAvailable;
335     int charsConsumed;
336     String glyphName;
337
338     float scale;
339     float length;
340     const Font* font;
341 };
342
343 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerMeasuredLengthData& data)
344 {
345     if (data.at >= data.from && data.at < data.to)
346         data.length += identifier.horizontalAdvanceX * data.scale;
347
348     data.at++;
349     return data.at < data.to;
350 }
351
352 void floatWidthMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerMeasuredLengthData& data)
353 {
354     // Handle system font fallback
355     FontDescription fontDescription(data.font->fontDescription());
356     fontDescription.setFamily(FontFamily());
357     Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
358     font.update(data.font->fontSelector());
359
360     data.length += font.floatWidth(run);
361 }
362
363
364 SVGFontElement* Font::svgFont() const
365
366     if (!isSVGFont())
367         return 0;
368
369     SVGFontElement* fontElement = 0;
370     SVGFontFaceElement* fontFaceElement = 0;
371     if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement))
372         return fontElement;
373     
374     return 0;
375 }
376
377 static float floatWidthOfSubStringUsingSVGFont(const Font* font, const TextRun& run, int extraCharsAvailable, int from, int to, int& charsConsumed, String& glyphName)
378 {
379     int newFrom = to > from ? from : to;
380     int newTo = to > from ? to : from;
381
382     from = newFrom;
383     to = newTo;
384
385     SVGFontElement* fontElement = 0;
386     SVGFontFaceElement* fontFaceElement = 0;
387
388     if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(font->primaryFont(), fontFaceElement, fontElement)) {
389         if (!fontElement)
390             return 0.0f;
391
392         SVGTextRunWalkerMeasuredLengthData data;
393
394         data.font = font;
395         data.at = from;
396         data.from = from;
397         data.to = to;
398         data.extraCharsAvailable = extraCharsAvailable;
399         data.charsConsumed = 0;
400         data.scale = convertEmUnitToPixel(font->size(), fontFaceElement->unitsPerEm(), 1.0f);
401         data.length = 0.0f;
402
403         String language;
404         bool isVerticalText = false; // Holds true for HTML text
405
406         // TODO: language matching & svg glyphs should be possible for HTML text, too.
407         if (RenderObject* renderObject = run.referencingRenderObject()) {
408             isVerticalText = isVerticalWritingMode(renderObject->style()->svgStyle());
409
410             if (SVGElement* element = static_cast<SVGElement*>(renderObject->element()))
411                 language = element->getAttribute(XMLNames::langAttr);
412         }
413
414         SVGTextRunWalker<SVGTextRunWalkerMeasuredLengthData> runWalker(fontData, fontElement, data, floatWidthUsingSVGFontCallback, floatWidthMissingGlyphCallback);
415         runWalker.walk(run, isVerticalText, language, 0, run.length());
416         charsConsumed = data.charsConsumed;
417         glyphName = data.glyphName;
418         return data.length;
419     }
420
421     return 0.0f;
422 }
423
424 float Font::floatWidthUsingSVGFont(const TextRun& run) const
425 {
426     int charsConsumed;
427     String glyphName;
428     return floatWidthOfSubStringUsingSVGFont(this, run, 0, 0, run.length(), charsConsumed, glyphName);
429 }
430
431 float Font::floatWidthUsingSVGFont(const TextRun& run, int extraCharsAvailable, int& charsConsumed, String& glyphName) const
432 {
433     return floatWidthOfSubStringUsingSVGFont(this, run, extraCharsAvailable, 0, run.length(), charsConsumed, glyphName);
434 }
435
436 // Callback & data structures to draw text using SVG Fonts
437 struct SVGTextRunWalkerDrawTextData {
438     int extraCharsAvailable;
439     int charsConsumed;
440     String glyphName;
441     Vector<SVGGlyphIdentifier> glyphIdentifiers;
442     Vector<UChar> fallbackCharacters;
443 };
444
445 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data)
446 {
447     data.glyphIdentifiers.append(identifier);
448     return true;
449 }
450
451 void drawTextMissingGlyphCallback(const TextRun& run, SVGTextRunWalkerDrawTextData& data)
452 {
453     ASSERT(run.length() == 1);
454     data.glyphIdentifiers.append(SVGGlyphIdentifier());
455     data.fallbackCharacters.append(run[0]);
456 }
457
458 void Font::drawTextUsingSVGFont(GraphicsContext* context, const TextRun& run, 
459                                 const FloatPoint& point, int from, int to) const
460 {
461     SVGFontElement* fontElement = 0;
462     SVGFontFaceElement* fontFaceElement = 0;
463
464     if (const SVGFontData* fontData = svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement, fontElement)) {
465         if (!fontElement)
466             return;
467
468         SVGTextRunWalkerDrawTextData data;
469         FloatPoint currentPoint = point;
470         float scale = convertEmUnitToPixel(size(), fontFaceElement->unitsPerEm(), 1.0f);
471
472         SVGPaintServer* activePaintServer = run.activePaintServer();
473
474         // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
475         if (!run.referencingRenderObject()) {
476             ASSERT(!activePaintServer);
477
478             // TODO: We're only supporting simple filled HTML text so far.
479             SVGPaintServerSolid* solidPaintServer = SVGPaintServer::sharedSolidPaintServer();
480             solidPaintServer->setColor(context->fillColor());
481
482             activePaintServer = solidPaintServer;
483         }
484
485         ASSERT(activePaintServer);
486
487         int charsConsumed;
488         String glyphName;
489         bool isVerticalText = false;
490         float xStartOffset = floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName);
491         FloatPoint glyphOrigin;
492
493         String language;
494
495         // TODO: language matching & svg glyphs should be possible for HTML text, too.
496         if (run.referencingRenderObject()) {
497             isVerticalText = isVerticalWritingMode(run.referencingRenderObject()->style()->svgStyle());    
498
499             if (SVGElement* element = static_cast<SVGElement*>(run.referencingRenderObject()->element()))
500                 language = element->getAttribute(XMLNames::langAttr);
501         }
502
503         if (!isVerticalText) {
504             glyphOrigin.setX(fontData->horizontalOriginX() * scale);
505             glyphOrigin.setY(fontData->horizontalOriginY() * scale);
506         }
507
508         data.extraCharsAvailable = 0;
509         data.charsConsumed = 0;
510
511         SVGTextRunWalker<SVGTextRunWalkerDrawTextData> runWalker(fontData, fontElement, data, drawTextUsingSVGFontCallback, drawTextMissingGlyphCallback);
512         runWalker.walk(run, isVerticalText, language, from, to);
513
514         SVGPaintTargetType targetType = context->textDrawingMode() == cTextStroke ? ApplyToStrokeTargetType : ApplyToFillTargetType;
515
516         unsigned numGlyphs = data.glyphIdentifiers.size();
517         unsigned fallbackCharacterIndex = 0;
518         for (unsigned i = 0; i < numGlyphs; ++i) {
519             const SVGGlyphIdentifier& identifier = data.glyphIdentifiers[run.rtl() ? numGlyphs - i - 1 : i];
520             if (identifier.isValid) {
521                 // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
522                 if (!identifier.pathData.isEmpty()) {
523                     context->save();
524
525                     if (isVerticalText) {
526                         glyphOrigin.setX(identifier.verticalOriginX * scale);
527                         glyphOrigin.setY(identifier.verticalOriginY * scale);
528                     }
529
530                     context->translate(xStartOffset + currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
531                     context->scale(FloatSize(scale, -scale));
532
533                     context->beginPath();
534                     context->addPath(identifier.pathData);
535
536                     if (activePaintServer->setup(context, run.referencingRenderObject(), targetType)) {
537                         // Spec: Any properties specified on a text elements which represents a length, such as the
538                         // 'stroke-width' property, might produce surprising results since the length value will be
539                         // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
540                         if (targetType == ApplyToStrokeTargetType && scale != 0.0f)
541                             context->setStrokeThickness(context->strokeThickness() / scale);
542
543                         activePaintServer->renderPath(context, run.referencingRenderObject(), targetType);
544                         activePaintServer->teardown(context, run.referencingRenderObject(), targetType);
545                     }
546
547                     context->restore();
548                 }
549
550                 if (isVerticalText)
551                     currentPoint.move(0.0f, identifier.verticalAdvanceY * scale);
552                 else
553                     currentPoint.move(identifier.horizontalAdvanceX * scale, 0.0f);
554             } else {
555                 // Handle system font fallback
556                 FontDescription fontDescription(m_fontDescription);
557                 fontDescription.setFamily(FontFamily());
558                 Font font(fontDescription, 0, 0); // spacing handled by SVG text code.
559                 font.update(fontSelector());
560
561                 TextRun fallbackCharacterRun(run);
562                 fallbackCharacterRun.setText(&data.fallbackCharacters[run.rtl() ? data.fallbackCharacters.size() - fallbackCharacterIndex - 1 : fallbackCharacterIndex], 1);
563                 font.drawText(context, fallbackCharacterRun, currentPoint);
564
565                 if (isVerticalText)
566                     currentPoint.move(0.0f, font.floatWidth(fallbackCharacterRun));
567                 else
568                     currentPoint.move(font.floatWidth(fallbackCharacterRun), 0.0f);
569
570                 fallbackCharacterIndex++;
571             }
572         }
573     }
574 }
575
576 FloatRect Font::selectionRectForTextUsingSVGFont(const TextRun& run, const IntPoint& point, int height, int from, int to) const
577 {
578     int charsConsumed;
579     String glyphName;
580
581     return FloatRect(point.x() + floatWidthOfSubStringUsingSVGFont(this, run, 0, run.rtl() ? to : 0, run.rtl() ? run.length() : from, charsConsumed, glyphName),
582                      point.y(), floatWidthOfSubStringUsingSVGFont(this, run, 0, from, to, charsConsumed, glyphName), height);
583 }
584
585 int Font::offsetForPositionForTextUsingSVGFont(const TextRun&, int, bool) const
586 {
587     // TODO: Fix text selection when HTML text is drawn using a SVG Font
588     // We need to integrate the SVG text selection code in the offsetForPosition() framework.
589     // This will also fix a major issue, that SVG Text code can't select arabic strings properly.
590     return 0;
591 }
592
593 }
594
595 #endif