2 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
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.
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.
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.
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"
41 using namespace WTF::Unicode
;
45 static inline float convertEmUnitToPixel(float fontSize
, float unitsPerEm
, float value
)
47 if (unitsPerEm
== 0.0f
)
50 return value
* fontSize
/ unitsPerEm
;
53 static inline bool isVerticalWritingMode(const SVGRenderStyle
* style
)
55 return style
->writingMode() == WM_TBRL
|| style
->writingMode() == WM_TB
;
58 // Helper functions to determine the arabic character forms (initial, medial, terminal, isolated)
59 enum ArabicCharShapingMode
{
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 */
82 static inline SVGGlyphIdentifier::ArabicForm
processArabicFormDetection(const UChar
& curChar
, bool& lastCharShapesRight
, SVGGlyphIdentifier::ArabicForm
* prevForm
)
84 SVGGlyphIdentifier::ArabicForm curForm
;
86 ArabicCharShapingMode shapingMode
= SNone
;
87 if (curChar
>= 0x0622 && curChar
<= 0x06FF)
88 shapingMode
= s_arabicCharShapingMode
[curChar
- 0x0622];
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 };
94 if (lastCharShapesRight
&& shapingMode
== SDual
) {
96 int correctedForm
= (int) *prevForm
+ 1;
97 ASSERT(correctedForm
>= SVGGlyphIdentifier::None
&& correctedForm
<= SVGGlyphIdentifier::Medial
);
98 *prevForm
= static_cast<SVGGlyphIdentifier::ArabicForm
>(correctedForm
);
101 curForm
= SVGGlyphIdentifier::Initial
;
103 curForm
= shapingMode
== SNone
? SVGGlyphIdentifier::None
: SVGGlyphIdentifier::Isolated
;
105 lastCharShapesRight
= shapingMode
!= SNone
;
109 static Vector
<SVGGlyphIdentifier::ArabicForm
> charactersWithArabicForm(const String
& input
, bool rtl
)
111 Vector
<SVGGlyphIdentifier::ArabicForm
> forms
;
112 unsigned int length
= input
.length();
114 bool containsArabic
= false;
115 for (unsigned int i
= 0; i
< length
; ++i
) {
116 if (isArabicChar(input
[i
])) {
117 containsArabic
= true;
125 bool lastCharShapesRight
= false;
127 // Start identifying arabic forms
129 for (int i
= length
- 1; i
>= 0; --i
)
130 forms
.prepend(processArabicFormDetection(input
[i
], lastCharShapesRight
, forms
.isEmpty() ? 0 : &forms
.first()));
132 for (unsigned int i
= 0; i
< length
; ++i
)
133 forms
.append(processArabicFormDetection(input
[i
], lastCharShapesRight
, forms
.isEmpty() ? 0 : &forms
.last()));
138 static inline bool isCompatibleArabicForm(const SVGGlyphIdentifier
& identifier
, const Vector
<SVGGlyphIdentifier::ArabicForm
>& chars
, unsigned int startPosition
, unsigned int endPosition
)
143 Vector
<SVGGlyphIdentifier::ArabicForm
>::const_iterator it
= chars
.begin() + startPosition
;
144 Vector
<SVGGlyphIdentifier::ArabicForm
>::const_iterator end
= chars
.begin() + endPosition
;
146 ASSERT(end
<= chars
.end());
147 for (; it
!= end
; ++it
) {
148 if ((*it
) != identifier
.arabicForm
&& (*it
) != SVGGlyphIdentifier::None
)
155 static inline bool isCompatibleGlyph(const SVGGlyphIdentifier
& identifier
, bool isVerticalText
, const String
& language
,
156 const Vector
<SVGGlyphIdentifier::ArabicForm
>& chars
, unsigned int startPosition
, unsigned int endPosition
)
160 // Check whether orientation if glyph fits within the request
161 switch (identifier
.orientation
) {
162 case SVGGlyphIdentifier::Vertical
:
163 valid
= isVerticalText
;
165 case SVGGlyphIdentifier::Horizontal
:
166 valid
= !isVerticalText
;
168 case SVGGlyphIdentifier::Both
:
175 // Check whether languages are compatible
176 if (!identifier
.languages
.isEmpty()) {
177 // This glyph exists only in certain languages, if we're not specifying a
178 // language on the referencing element we're unable to use this glyph.
179 if (language
.isEmpty())
182 // Split subcode from language, if existent.
183 String languagePrefix
;
185 int subCodeSeparator
= language
.find('-');
186 if (subCodeSeparator
!= -1)
187 languagePrefix
= language
.left(subCodeSeparator
);
189 Vector
<String
>::const_iterator it
= identifier
.languages
.begin();
190 Vector
<String
>::const_iterator end
= identifier
.languages
.end();
193 for (; it
!= end
; ++it
) {
196 if (cur
== language
|| cur
== languagePrefix
) {
206 // Check whether arabic form is compatible
207 return isCompatibleArabicForm(identifier
, chars
, startPosition
, endPosition
);
210 static inline const SVGFontData
* svgFontAndFontFaceElementForFontData(const SimpleFontData
* fontData
, SVGFontFaceElement
*& fontFace
, SVGFontElement
*& font
)
212 ASSERT(fontData
->isCustomFont());
213 ASSERT(fontData
->isSVGFont());
215 const SVGFontData
* svgFontData
= static_cast<const SVGFontData
*>(fontData
->svgFontData());
217 fontFace
= svgFontData
->svgFontFaceElement();
220 font
= fontFace
->associatedFontElement();
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
&);
231 SVGTextRunWalker(const SVGFontData
* fontData
, SVGFontElement
* fontElement
, SVGTextRunData
& data
,
232 SVGTextRunWalkerCallback callback
, SVGTextRunWalkerMissingGlyphCallback missingGlyphCallback
)
233 : m_fontData(fontData
)
234 , m_fontElement(fontElement
)
236 , m_walkerCallback(callback
)
237 , m_walkerMissingGlyphCallback(missingGlyphCallback
)
241 void walk(const TextRun
& run
, bool isVerticalText
, const String
& language
, int from
, int to
)
243 // Should hold true for SVG text, otherwhise sth. is wrong
244 ASSERT(to
- from
== run
.length());
246 Vector
<SVGGlyphIdentifier::ArabicForm
> chars(charactersWithArabicForm(String(run
.data(from
), run
.length()), run
.rtl()));
248 SVGGlyphIdentifier identifier
;
249 bool foundGlyph
= false;
250 int characterLookupRange
;
251 int endOfScanRange
= to
+ m_walkerData
.extraCharsAvailable
;
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();
260 altGlyphIdentifier
= glyphElement
->buildGlyphIdentifier();
261 altGlyphIdentifier
.isValid
= true;
262 altGlyphIdentifier
.nameLength
= to
- from
;
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 whether 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
;
273 String
lookupString(run
.data(i
), characterLookupRange
);
274 Vector
<SVGGlyphIdentifier
> glyphs
;
276 glyphs
.append(altGlyphIdentifier
);
278 m_fontElement
->getGlyphIdentifiersForString(lookupString
, glyphs
);
280 Vector
<SVGGlyphIdentifier
>::iterator it
= glyphs
.begin();
281 Vector
<SVGGlyphIdentifier
>::iterator end
= glyphs
.end();
283 for (; it
!= end
; ++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
;
292 SVGGlyphElement::inheritUnspecifiedAttributes(identifier
, m_fontData
);
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;
305 // Fallback to system font fallback
307 subRun
.setText(subRun
.data(i
), 1);
309 (*m_walkerMissingGlyphCallback
)(subRun
, m_walkerData
);
314 if (!(*m_walkerCallback
)(identifier
, m_walkerData
))
322 const SVGFontData
* m_fontData
;
323 SVGFontElement
* m_fontElement
;
324 SVGTextRunData
& m_walkerData
;
325 SVGTextRunWalkerCallback m_walkerCallback
;
326 SVGTextRunWalkerMissingGlyphCallback m_walkerMissingGlyphCallback
;
329 // Callback & data structures to compute the width of text using SVG Fonts
330 struct SVGTextRunWalkerMeasuredLengthData
{
334 int extraCharsAvailable
;
343 bool floatWidthUsingSVGFontCallback(const SVGGlyphIdentifier
& identifier
, SVGTextRunWalkerMeasuredLengthData
& data
)
345 if (data
.at
>= data
.from
&& data
.at
< data
.to
)
346 data
.length
+= identifier
.horizontalAdvanceX
* data
.scale
;
349 return data
.at
< data
.to
;
352 void floatWidthMissingGlyphCallback(const TextRun
& run
, SVGTextRunWalkerMeasuredLengthData
& data
)
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());
360 data
.length
+= font
.floatWidth(run
);
364 SVGFontElement
* Font::svgFont() const
369 SVGFontElement
* fontElement
= 0;
370 SVGFontFaceElement
* fontFaceElement
= 0;
371 if (svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement
, fontElement
))
377 static float floatWidthOfSubStringUsingSVGFont(const Font
* font
, const TextRun
& run
, int extraCharsAvailable
, int from
, int to
, int& charsConsumed
, String
& glyphName
)
379 int newFrom
= to
> from
? from
: to
;
380 int newTo
= to
> from
? to
: from
;
385 SVGFontElement
* fontElement
= 0;
386 SVGFontFaceElement
* fontFaceElement
= 0;
388 if (const SVGFontData
* fontData
= svgFontAndFontFaceElementForFontData(font
->primaryFont(), fontFaceElement
, fontElement
)) {
392 SVGTextRunWalkerMeasuredLengthData data
;
398 data
.extraCharsAvailable
= extraCharsAvailable
;
399 data
.charsConsumed
= 0;
400 data
.scale
= convertEmUnitToPixel(font
->size(), fontFaceElement
->unitsPerEm(), 1.0f
);
404 bool isVerticalText
= false; // Holds true for HTML text
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());
410 if (SVGElement
* element
= static_cast<SVGElement
*>(renderObject
->element()))
411 language
= element
->getAttribute(XMLNames::langAttr
);
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
;
424 float Font::floatWidthUsingSVGFont(const TextRun
& run
) const
428 return floatWidthOfSubStringUsingSVGFont(this, run
, 0, 0, run
.length(), charsConsumed
, glyphName
);
431 float Font::floatWidthUsingSVGFont(const TextRun
& run
, int extraCharsAvailable
, int& charsConsumed
, String
& glyphName
) const
433 return floatWidthOfSubStringUsingSVGFont(this, run
, extraCharsAvailable
, 0, run
.length(), charsConsumed
, glyphName
);
436 // Callback & data structures to draw text using SVG Fonts
437 struct SVGTextRunWalkerDrawTextData
{
438 int extraCharsAvailable
;
441 Vector
<SVGGlyphIdentifier
> glyphIdentifiers
;
442 Vector
<UChar
> fallbackCharacters
;
445 bool drawTextUsingSVGFontCallback(const SVGGlyphIdentifier
& identifier
, SVGTextRunWalkerDrawTextData
& data
)
447 data
.glyphIdentifiers
.append(identifier
);
451 void drawTextMissingGlyphCallback(const TextRun
& run
, SVGTextRunWalkerDrawTextData
& data
)
453 ASSERT(run
.length() == 1);
454 data
.glyphIdentifiers
.append(SVGGlyphIdentifier());
455 data
.fallbackCharacters
.append(run
[0]);
458 void Font::drawTextUsingSVGFont(GraphicsContext
* context
, const TextRun
& run
,
459 const FloatPoint
& point
, int from
, int to
) const
461 SVGFontElement
* fontElement
= 0;
462 SVGFontFaceElement
* fontFaceElement
= 0;
464 if (const SVGFontData
* fontData
= svgFontAndFontFaceElementForFontData(primaryFont(), fontFaceElement
, fontElement
)) {
468 SVGTextRunWalkerDrawTextData data
;
469 FloatPoint currentPoint
= point
;
470 float scale
= convertEmUnitToPixel(size(), fontFaceElement
->unitsPerEm(), 1.0f
);
472 SVGPaintServer
* activePaintServer
= run
.activePaintServer();
474 // If renderObject is not set, we're dealing for HTML text rendered using SVG Fonts.
475 if (!run
.referencingRenderObject()) {
476 ASSERT(!activePaintServer
);
478 // TODO: We're only supporting simple filled HTML text so far.
479 SVGPaintServerSolid
* solidPaintServer
= SVGPaintServer::sharedSolidPaintServer();
480 solidPaintServer
->setColor(context
->fillColor());
482 activePaintServer
= solidPaintServer
;
485 ASSERT(activePaintServer
);
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
;
495 // TODO: language matching & svg glyphs should be possible for HTML text, too.
496 if (run
.referencingRenderObject()) {
497 isVerticalText
= isVerticalWritingMode(run
.referencingRenderObject()->style()->svgStyle());
499 if (SVGElement
* element
= static_cast<SVGElement
*>(run
.referencingRenderObject()->element()))
500 language
= element
->getAttribute(XMLNames::langAttr
);
503 if (!isVerticalText
) {
504 glyphOrigin
.setX(fontData
->horizontalOriginX() * scale
);
505 glyphOrigin
.setY(fontData
->horizontalOriginY() * scale
);
508 data
.extraCharsAvailable
= 0;
510 SVGTextRunWalker
<SVGTextRunWalkerDrawTextData
> runWalker(fontData
, fontElement
, data
, drawTextUsingSVGFontCallback
, drawTextMissingGlyphCallback
);
511 runWalker
.walk(run
, isVerticalText
, language
, from
, to
);
513 SVGPaintTargetType targetType
= context
->textDrawingMode() == cTextStroke
? ApplyToStrokeTargetType
: ApplyToFillTargetType
;
515 unsigned numGlyphs
= data
.glyphIdentifiers
.size();
516 unsigned fallbackCharacterIndex
= 0;
517 for (unsigned i
= 0; i
< numGlyphs
; ++i
) {
518 const SVGGlyphIdentifier
& identifier
= data
.glyphIdentifiers
[run
.rtl() ? numGlyphs
- i
- 1 : i
];
519 if (identifier
.isValid
) {
520 // FIXME: Support arbitrary SVG content as glyph (currently limited to <glyph d="..."> situations).
521 if (!identifier
.pathData
.isEmpty()) {
524 if (isVerticalText
) {
525 glyphOrigin
.setX(identifier
.verticalOriginX
* scale
);
526 glyphOrigin
.setY(identifier
.verticalOriginY
* scale
);
529 context
->translate(xStartOffset
+ currentPoint
.x() + glyphOrigin
.x(), currentPoint
.y() + glyphOrigin
.y());
530 context
->scale(FloatSize(scale
, -scale
));
532 context
->beginPath();
533 context
->addPath(identifier
.pathData
);
535 if (activePaintServer
->setup(context
, run
.referencingRenderObject(), targetType
)) {
536 // Spec: Any properties specified on a text elements which represents a length, such as the
537 // 'stroke-width' property, might produce surprising results since the length value will be
538 // processed in the coordinate system of the glyph. (TODO: What other lengths? miter-limit? dash-offset?)
539 if (targetType
== ApplyToStrokeTargetType
&& scale
!= 0.0f
)
540 context
->setStrokeThickness(context
->strokeThickness() / scale
);
542 activePaintServer
->renderPath(context
, run
.referencingRenderObject(), targetType
);
543 activePaintServer
->teardown(context
, run
.referencingRenderObject(), targetType
);
550 currentPoint
.move(0.0f
, identifier
.verticalAdvanceY
* scale
);
552 currentPoint
.move(identifier
.horizontalAdvanceX
* scale
, 0.0f
);
554 // Handle system font fallback
555 FontDescription
fontDescription(context
->font().fontDescription());
556 fontDescription
.setFamily(FontFamily());
557 Font
font(fontDescription
, 0, 0); // spacing handled by SVG text code.
558 font
.update(context
->font().fontSelector());
560 TextRun
fallbackCharacterRun(run
);
561 fallbackCharacterRun
.setText(&data
.fallbackCharacters
[run
.rtl() ? data
.fallbackCharacters
.size() - fallbackCharacterIndex
- 1 : fallbackCharacterIndex
], 1);
562 font
.drawText(context
, fallbackCharacterRun
, currentPoint
);
565 currentPoint
.move(0.0f
, font
.floatWidth(fallbackCharacterRun
));
567 currentPoint
.move(font
.floatWidth(fallbackCharacterRun
), 0.0f
);
569 fallbackCharacterIndex
++;
575 FloatRect
Font::selectionRectForTextUsingSVGFont(const TextRun
& run
, const IntPoint
& point
, int height
, int from
, int to
) const
580 return FloatRect(point
.x() + floatWidthOfSubStringUsingSVGFont(this, run
, 0, run
.rtl() ? to
: 0, run
.rtl() ? run
.length() : from
, charsConsumed
, glyphName
),
581 point
.y(), floatWidthOfSubStringUsingSVGFont(this, run
, 0, from
, to
, charsConsumed
, glyphName
), height
);
584 int Font::offsetForPositionForTextUsingSVGFont(const TextRun
&, int position
, bool includePartialGlyphs
) const
586 // TODO: Fix text selection when HTML text is drawn using a SVG Font
587 // We need to integrate the SVG text selection code in the offsetForPosition() framework.
588 // This will also fix a major issue, that SVG Text code can't select arabic strings properly.