• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
convertEmUnitToPixel(float fontSize,float unitsPerEm,float value)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 
isVerticalWritingMode(const SVGRenderStyle * style)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 
processArabicFormDetection(const UChar & curChar,bool & lastCharShapesRight,SVGGlyphIdentifier::ArabicForm * prevForm)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 
charactersWithArabicForm(const String & input,bool rtl)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 
isCompatibleArabicForm(const SVGGlyphIdentifier & identifier,const Vector<SVGGlyphIdentifier::ArabicForm> & chars,unsigned startPosition,unsigned endPosition)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 
isCompatibleGlyph(const SVGGlyphIdentifier & identifier,bool isVerticalText,const String & language,const Vector<SVGGlyphIdentifier::ArabicForm> & chars,unsigned startPosition,unsigned endPosition)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 
svgFontAndFontFaceElementForFontData(const SimpleFontData * fontData,SVGFontFaceElement * & fontFace,SVGFontElement * & font)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 
SVGTextRunWalkerWebCore::SVGTextRunWalker231     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 
walkWebCore::SVGTextRunWalker241     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 
floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier & identifier,SVGTextRunWalkerMeasuredLengthData & data)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 
floatWidthMissingGlyphCallback(const TextRun & run,SVGTextRunWalkerMeasuredLengthData & data)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 
svgFont() const365 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 
floatWidthOfSubStringUsingSVGFont(const Font * font,const TextRun & run,int extraCharsAvailable,int from,int to,int & charsConsumed,String & glyphName)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 
floatWidthUsingSVGFont(const TextRun & run) const425 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 
floatWidthUsingSVGFont(const TextRun & run,int extraCharsAvailable,int & charsConsumed,String & glyphName) const432 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 
drawTextUsingSVGFontCallback(const SVGGlyphIdentifier & identifier,SVGTextRunWalkerDrawTextData & data)446 static bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier& identifier, SVGTextRunWalkerDrawTextData& data)
447 {
448     data.glyphIdentifiers.append(identifier);
449     return true;
450 }
451 
drawTextMissingGlyphCallback(const TextRun & run,SVGTextRunWalkerDrawTextData & data)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 
drawTextUsingSVGFont(GraphicsContext * context,const TextRun & run,const FloatPoint & point,int from,int to) const459 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 
selectionRectForTextUsingSVGFont(const TextRun & run,const IntPoint & point,int height,int from,int to) const580 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 
offsetForPositionForTextUsingSVGFont(const TextRun &,int,bool) const589 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