text-decoration-skip: ink does not skip over SVG fonts
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Feb 2014 00:22:32 +0000 (00:22 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 28 Feb 2014 00:22:32 +0000 (00:22 +0000)
https://bugs.webkit.org/show_bug.cgi?id=128936

Reviewed by Darin Adler.

Source/WebCore:

When drawing glyphs in an SVG font, the glyphs are converted to paths and then filled. This patch moves
the glyph -> path conversion into a helper class, GlyphToPathTranslator, and creates an implementation
for the SVG drawing code. Once this helper class is created, it can be used to trace paths in order
to make underlines skip over SVG glyphs. This helper class also has an implementation for non-SVG glyphs,
which allows for the glyph tracing code to be paramaterized over the implementation of the helper class
rather than if the FontData itself is SVG or not.

Tests: fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html

* platform/graphics/Font.h:
(WebCore::GlyphToPathTranslator::~GlyphToPathTranslator): Virtual implementation of helper class
* platform/graphics/cg/PathCG.cpp:
(WebCore::Path::Path): Created constructor that takes a RefPtr<CGMutablePathRef>
* platform/graphics/Path.h:
* platform/graphics/TextRun.h: Give RenderingContext a factory function to create the helper class
instance
* platform/graphics/mac/FontMac.mm: Implementation of helper class used for skipping underlines on
regular (CoreText) glyphs
(WebCore::MacGlyphToPathTranslator::MacGlyphToPathTranslator):
(WebCore::MacGlyphToPathTranslator::moveToNextValidGlyph):
(WebCore::MacGlyphToPathTranslator::incrementIndex):
(WebCore::Font::dashesForIntersectionsWithRect): Call the relevant factory function, and use it
to successively generate Paths
* rendering/svg/SVGTextRunRenderingContext.cpp: Implementation of helper class used for SVG fonts
(WebCore::SVGGlyphToPathTranslator::SVGGlyphToPathTranslator):
(WebCore::SVGGlyphToPathTranslator::moveToNextValidGlyph):
(WebCore::SVGGlyphToPathTranslator::incrementIndex):
(WebCore::SVGTextRunRenderingContext::createGlyphToPathTranslator):
(WebCore::SVGTextRunRenderingContext::drawSVGGlyphs): Use the above implementation
* rendering/svg/SVGTextRunRenderingContext.h: Factory function declaration

LayoutTests:

This font simply draws some underlined text with a SVG font and makes sure the underline skips.

* fast/css3-text/css3-text-decoration/text-decoration-skip/resources/Litherum.svg: Added.
* fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg-expected.html: Added.
* fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@164842 268f45cc-cd09-0410-ab3c-d52691b4dbfc

12 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/resources/Litherum.svg [new file with mode: 0644]
LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg-expected.html [new file with mode: 0644]
LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Font.h
Source/WebCore/platform/graphics/Path.h
Source/WebCore/platform/graphics/TextRun.h
Source/WebCore/platform/graphics/cg/PathCG.cpp
Source/WebCore/platform/graphics/mac/FontMac.mm
Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp
Source/WebCore/rendering/svg/SVGTextRunRenderingContext.h

index 10cded2..2bf0065 100644 (file)
@@ -1,3 +1,16 @@
+2014-02-17  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        text-decoration-skip: ink does not skip over SVG fonts
+        https://bugs.webkit.org/show_bug.cgi?id=128936
+
+        Reviewed by Darin Adler.
+
+        This font simply draws some underlined text with a SVG font and makes sure the underline skips.
+
+        * fast/css3-text/css3-text-decoration/text-decoration-skip/resources/Litherum.svg: Added.
+        * fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg-expected.html: Added.
+        * fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html: Added.
+
 2014-02-27  Thiago de Barros Lacerda  <thiago.lacerda@openbossa.org>
 
         [WebRTC] Removing MediaConstraints argument from RTCPeerConnection addStream, updateIce methods and constructor
diff --git a/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/resources/Litherum.svg b/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/resources/Litherum.svg
new file mode 100644 (file)
index 0000000..042c7ed
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata></metadata>
+<defs>
+<font id="Litherum" horiz-adv-x="1024">
+<font-face units-per-em="14" ascent="14" descent="-7"/>
+<glyph unicode="|" horiz-adv-x="14" d="M5 -7v21h4v-21z"/>
+</font>
+</defs>
+</svg>
diff --git a/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg-expected.html b/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg-expected.html
new file mode 100644 (file)
index 0000000..d29cad1
--- /dev/null
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+This test draws a giant character with an SVG font and positions the viewport
+in the gap where the underline should be skipping over the character. It should appear
+white.
+</body>
+</html>
diff --git a/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html b/LayoutTests/fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html
new file mode 100644 (file)
index 0000000..213ac11
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+@font-face {
+    font-family: 'Litherum';
+    src: url("./resources/Litherum.svg") format(svg)
+}
+#p {
+    font: 1000px 'Litherum';
+    text-decoration: underline;
+}
+</style>
+</head>
+<body>
+This test draws a giant character with an SVG font and positions the viewport
+in the gap where the underline should be skipping over the character. It should appear
+white.
+<div style="position: absolute; width: 62px; height: 100px; overflow: hidden;">
+<div style="position: absolute; left: -295px; top: -1100px;">
+<div id="p">|</div>
+</div>
+</div>
+</body>
+</html>
index 40b9e5f..d5f4ac2 100644 (file)
@@ -1,3 +1,41 @@
+2014-02-17  Myles C. Maxfield  <mmaxfield@apple.com>
+
+        text-decoration-skip: ink does not skip over SVG fonts
+        https://bugs.webkit.org/show_bug.cgi?id=128936
+
+        Reviewed by Darin Adler.
+
+        When drawing glyphs in an SVG font, the glyphs are converted to paths and then filled. This patch moves
+        the glyph -> path conversion into a helper class, GlyphToPathTranslator, and creates an implementation
+        for the SVG drawing code. Once this helper class is created, it can be used to trace paths in order
+        to make underlines skip over SVG glyphs. This helper class also has an implementation for non-SVG glyphs,
+        which allows for the glyph tracing code to be paramaterized over the implementation of the helper class
+        rather than if the FontData itself is SVG or not.
+
+        Tests: fast/css3-text/css3-text-decoration/text-decoration-skip/text-decoration-skip-ink-svg.html
+
+        * platform/graphics/Font.h:
+        (WebCore::GlyphToPathTranslator::~GlyphToPathTranslator): Virtual implementation of helper class
+        * platform/graphics/cg/PathCG.cpp:
+        (WebCore::Path::Path): Created constructor that takes a RefPtr<CGMutablePathRef>
+        * platform/graphics/Path.h:
+        * platform/graphics/TextRun.h: Give RenderingContext a factory function to create the helper class
+        instance
+        * platform/graphics/mac/FontMac.mm: Implementation of helper class used for skipping underlines on
+        regular (CoreText) glyphs
+        (WebCore::MacGlyphToPathTranslator::MacGlyphToPathTranslator):
+        (WebCore::MacGlyphToPathTranslator::moveToNextValidGlyph):
+        (WebCore::MacGlyphToPathTranslator::incrementIndex):
+        (WebCore::Font::dashesForIntersectionsWithRect): Call the relevant factory function, and use it
+        to successively generate Paths
+        * rendering/svg/SVGTextRunRenderingContext.cpp: Implementation of helper class used for SVG fonts
+        (WebCore::SVGGlyphToPathTranslator::SVGGlyphToPathTranslator):
+        (WebCore::SVGGlyphToPathTranslator::moveToNextValidGlyph):
+        (WebCore::SVGGlyphToPathTranslator::incrementIndex):
+        (WebCore::SVGTextRunRenderingContext::createGlyphToPathTranslator):
+        (WebCore::SVGTextRunRenderingContext::drawSVGGlyphs): Use the above implementation
+        * rendering/svg/SVGTextRunRenderingContext.h: Factory function declaration
+
 2014-02-27  Thiago de Barros Lacerda  <thiago.lacerda@openbossa.org>
 
         [WebRTC] Removing MediaConstraints argument from RTCPeerConnection addStream, updateIce methods and constructor
index 1ad36ac..adffce8 100644 (file)
@@ -28,6 +28,7 @@
 #include "DashArray.h"
 #include "FontDescription.h"
 #include "FontGlyphs.h"
+#include "Path.h"
 #include "SimpleFontData.h"
 #include "TextDirection.h"
 #include "TypesettingFeatures.h"
@@ -75,6 +76,12 @@ struct GlyphOverflow {
     bool computeBounds;
 };
 
+class GlyphToPathTranslator {
+public:
+    virtual bool containsMorePaths() = 0;
+    virtual Path nextPath() = 0;
+    virtual ~GlyphToPathTranslator() { }
+};
 
 class Font {
 public:
index 161f846..55f0f6e 100644 (file)
@@ -33,6 +33,8 @@
 #include <wtf/Forward.h>
 
 #if USE(CG)
+#include <wtf/RetainPtr.h>
+#include <CoreGraphics/CGPath.h>
 typedef struct CGPath PlatformPath;
 #elif USE(CAIRO)
 namespace WebCore {
@@ -82,6 +84,9 @@ namespace WebCore {
         WTF_MAKE_FAST_ALLOCATED;
     public:
         Path();
+#if USE(CG)
+        Path(RetainPtr<CGMutablePathRef>);
+#endif
         ~Path();
 
         Path(const Path&);
index 8eb9d9c..230bdf3 100644 (file)
@@ -35,6 +35,7 @@ class FloatRect;
 class Font;
 class GraphicsContext;
 class GlyphBuffer;
+class GlyphToPathTranslator;
 class SimpleFontData;
 struct GlyphData;
 struct WidthIterator;
@@ -188,6 +189,7 @@ public:
 
     class RenderingContext : public RefCounted<RenderingContext> {
     public:
+        virtual std::unique_ptr<GlyphToPathTranslator> createGlyphToPathTranslator(const SimpleFontData&, const GlyphBuffer&, int from, int numGlyphs, const FloatPoint&) const = 0;
         virtual ~RenderingContext() { }
 
 #if ENABLE(SVG_FONTS)
index 9f39ccc..9d20edf 100644 (file)
@@ -78,6 +78,11 @@ Path::Path()
 {
 }
 
+Path::Path(RetainPtr<CGMutablePathRef> p)
+    : m_path(p.leakRef())
+{
+}
+
 Path::~Path()
 {
     if (m_path)
index c6d6204..7244e1a 100644 (file)
@@ -436,33 +436,95 @@ static void findPathIntersections(void* stateAsVoidPointer, const CGPathElement*
     state.currentPoint = point;
 }
 
+class MacGlyphToPathTranslator final : public GlyphToPathTranslator {
+public:
+    MacGlyphToPathTranslator(const GlyphBuffer& glyphBuffer, const FloatPoint& textOrigin)
+        : m_index(0)
+        , m_glyphBuffer(glyphBuffer)
+        , m_fontData(glyphBuffer.fontDataAt(m_index))
+        , m_translation(CGAffineTransformScale(CGAffineTransformMakeTranslation(textOrigin.x(), textOrigin.y()), 1, -1))
+    {
+        moveToNextValidGlyph();
+    }
+private:
+    virtual bool containsMorePaths() override
+    {
+        return m_index != m_glyphBuffer.size();
+    }
+    virtual Path nextPath() override;
+    void moveToNextValidGlyph();
+    void incrementIndex();
+
+    int m_index;
+    const GlyphBuffer& m_glyphBuffer;
+    const SimpleFontData* m_fontData;
+    CGAffineTransform m_translation;
+};
+
+Path MacGlyphToPathTranslator::nextPath()
+{
+    RetainPtr<CGPathRef> result = adoptCF(CTFontCreatePathForGlyph(m_fontData->platformData().ctFont(), m_glyphBuffer.glyphAt(m_index), &m_translation));
+    incrementIndex();
+    return adoptCF(CGPathCreateMutableCopy(result.get()));
+}
+
+void MacGlyphToPathTranslator::moveToNextValidGlyph()
+{
+    if (!m_fontData->isSVGFont())
+        return;
+    incrementIndex();
+}
+
+void MacGlyphToPathTranslator::incrementIndex()
+{
+    do {
+        GlyphBufferAdvance advance = m_glyphBuffer.advanceAt(m_index);
+        m_translation = CGAffineTransformTranslate(m_translation, advance.width(), advance.height());
+        ++m_index;
+        if (m_index >= m_glyphBuffer.size())
+            break;
+        m_fontData = m_glyphBuffer.fontDataAt(m_index);
+    } while (m_fontData->isSVGFont() && m_index < m_glyphBuffer.size());
+}
+
 DashArray Font::dashesForIntersectionsWithRect(const TextRun& run, const FloatPoint& textOrigin, const FloatRect& lineExtents) const
 {
     if (loadingCustomFonts())
         return DashArray();
 
-    float deltaX;
     GlyphBuffer glyphBuffer;
-    if (codePath(run) != Complex)
+    float deltaX;
+    if (codePath(run) != Font::Complex)
         deltaX = getGlyphsAndAdvancesForSimpleText(run, 0, run.length(), glyphBuffer);
     else
         deltaX = getGlyphsAndAdvancesForComplexText(run, 0, run.length(), glyphBuffer);
-    CGAffineTransform translation = CGAffineTransformMakeTranslation(textOrigin.x() + deltaX, textOrigin.y());
-    translation = CGAffineTransformScale(translation, 1, -1);
+
+    if (!glyphBuffer.size())
+        return DashArray();
+    
+    // FIXME: Handle SVG + non-SVG interleaved runs
+    const SimpleFontData* fontData = glyphBuffer.fontDataAt(0);
+    std::unique_ptr<GlyphToPathTranslator> translator;
+    bool isSVG = false;
+    FloatPoint origin = FloatPoint(textOrigin.x() + deltaX, textOrigin.y());
+    if (!fontData->isSVGFont())
+        translator = std::move(std::make_unique<MacGlyphToPathTranslator>(glyphBuffer, origin));
+    else {
+        translator = std::move(run.renderingContext()->createGlyphToPathTranslator(*fontData, glyphBuffer, 0, run.length(), origin));
+        isSVG = true;
+    }
     DashArray result;
-    for (int i = 0; i < glyphBuffer.size(); ++i) {
+    for (int index = 0; translator->containsMorePaths(); ++index) {
         GlyphIterationState info = GlyphIterationState(CGPointMake(0, 0), CGPointMake(0, 0), lineExtents.y(), lineExtents.y() + lineExtents.height(), lineExtents.x() + lineExtents.width(), lineExtents.x());
-        const SimpleFontData* fontData = glyphBuffer.fontDataAt(i);
-        if (fontData->isSVGFont())
-            continue;
-        RetainPtr<CGPathRef> path = adoptCF(CTFontCreatePathForGlyph(fontData->platformData().ctFont(), glyphBuffer.glyphAt(i), &translation));
-        CGPathApply(path.get(), &info, &findPathIntersections);
+        const SimpleFontData* localFontData = glyphBuffer.fontDataAt(index);
+        if (!localFontData || (!isSVG && localFontData->isSVGFont()) || (isSVG && localFontData != fontData))
+            break; // The advances will get all messed up if we do anything other than bail here.
+        Path path = translator->nextPath();
+        CGPathApply(path.platformPath(), &info, &findPathIntersections);
         if (info.minX < info.maxX) {
             result.append(info.minX - lineExtents.x());
             result.append(info.maxX - lineExtents.x());
         }
-        GlyphBufferAdvance advance = glyphBuffer.advanceAt(i);
-        translation = CGAffineTransformTranslate(translation, advance.width(), advance.height());
     }
     return result;
 }
index 3b2561a..d73a2a4 100644 (file)
@@ -101,15 +101,132 @@ bool SVGTextRunRenderingContext::applySVGKerning(const SimpleFontData* fontData,
     return true;
 }
 
-void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
+class SVGGlyphToPathTranslator final : public GlyphToPathTranslator {
+public:
+    SVGGlyphToPathTranslator(const GlyphBuffer& glyphBuffer, const FloatPoint& point, const SVGFontData& svgFontData, SVGFontElement& fontElement, const int from, const int numGlyphs, float scale, bool isVerticalText);
+private:
+    virtual bool containsMorePaths() override
+    {
+        return m_index != m_stoppingPoint;
+    }
+    virtual Path nextPath() override;
+    void moveToNextValidGlyph();
+    void incrementIndex();
+
+    const GlyphBuffer& m_glyphBuffer;
+    const SVGFontData& m_svgFontData;
+    FloatPoint m_currentPoint;
+    FloatPoint m_glyphOrigin;
+    SVGGlyph m_svgGlyph;
+    int m_index;
+    Glyph m_glyph;
+    SVGFontElement& m_fontElement;
+    const float m_stoppingPoint;
+    const float m_scale;
+    const bool m_isVerticalText;
+};
+
+SVGGlyphToPathTranslator::SVGGlyphToPathTranslator(const GlyphBuffer& glyphBuffer, const FloatPoint& point, const SVGFontData& svgFontData, SVGFontElement& fontElement, const int from, const int numGlyphs, float scale, bool isVerticalText)
+    : m_glyphBuffer(glyphBuffer)
+    , m_svgFontData(svgFontData)
+    , m_currentPoint(point)
+    , m_glyphOrigin(m_svgFontData.horizontalOriginX() * scale, m_svgFontData.horizontalOriginY() * scale)
+    , m_index(from)
+    , m_glyph(glyphBuffer.glyphAt(m_index))
+    , m_fontElement(fontElement)
+    , m_stoppingPoint(numGlyphs + from)
+    , m_scale(scale)
+    , m_isVerticalText(isVerticalText)
+{
+    ASSERT(glyphBuffer.size() > m_index);
+    if (m_glyph) {
+        m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
+        ASSERT(!m_svgGlyph.isPartOfLigature);
+        ASSERT(m_svgGlyph.tableEntry == m_glyph);
+        SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
+    }
+    moveToNextValidGlyph();
+}
+
+Path SVGGlyphToPathTranslator::nextPath()
+{
+    if (m_isVerticalText) {
+        m_glyphOrigin.setX(m_svgGlyph.verticalOriginX * m_scale);
+        m_glyphOrigin.setY(m_svgGlyph.verticalOriginY * m_scale);
+    }
+
+    AffineTransform glyphPathTransform;
+    glyphPathTransform.translate(m_currentPoint.x() + m_glyphOrigin.x(), m_currentPoint.y() + m_glyphOrigin.y());
+    glyphPathTransform.scale(m_scale, -m_scale);
+
+    Path glyphPath = m_svgGlyph.pathData;
+    glyphPath.transform(glyphPathTransform);
+    incrementIndex();
+    return glyphPath;
+}
+
+void SVGGlyphToPathTranslator::moveToNextValidGlyph()
+{
+    if (m_glyph && !m_svgGlyph.pathData.isEmpty())
+        return;
+    incrementIndex();
+}
+
+void SVGGlyphToPathTranslator::incrementIndex()
+{
+    do {
+        if (m_glyph) {
+            float advance = m_glyphBuffer.advanceAt(m_index).width();
+            if (m_isVerticalText)
+                m_currentPoint.move(0, advance);
+            else
+                m_currentPoint.move(advance, 0);
+        }
+
+        ++m_index;
+        if (m_index >= m_stoppingPoint)
+            break;
+        m_glyph = m_glyphBuffer.glyphAt(m_index);
+        if (!m_glyph)
+            continue;
+        m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
+        ASSERT(!m_svgGlyph.isPartOfLigature);
+        ASSERT(m_svgGlyph.tableEntry == m_glyph);
+        SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
+    } while ((!m_glyph || m_svgGlyph.pathData.isEmpty()) && m_index < m_stoppingPoint);
+}
+
+class DummyGlyphToPathTranslator final : public GlyphToPathTranslator {
+    virtual bool containsMorePaths() override
+    {
+        return false;
+    }
+    virtual Path nextPath() override
+    {
+        return Path();
+    }
+};
+
+std::unique_ptr<GlyphToPathTranslator> SVGTextRunRenderingContext::createGlyphToPathTranslator(const SimpleFontData& fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
 {
     SVGFontElement* fontElement = 0;
     SVGFontFaceElement* fontFaceElement = 0;
 
-    const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
+    const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(&fontData, fontFaceElement, fontElement);
     if (!fontElement || !fontFaceElement)
-        return;
+        return std::make_unique<DummyGlyphToPathTranslator>();
 
+    auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent();
+    RenderStyle& style = elementRenderer.style();
+    bool isVerticalText = style.svgStyle().isVerticalWritingMode();
+
+    float scale = scaleEmToUnits(fontData.platformData().size(), fontFaceElement->unitsPerEm());
+
+    return std::make_unique<SVGGlyphToPathTranslator>(glyphBuffer, point, *svgFontData, *fontElement, from, numGlyphs, scale, isVerticalText);
+}
+
+void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
+{
     auto activePaintingResource = this->activePaintingResource();
     if (!activePaintingResource) {
         // TODO: We're only supporting simple filled HTML text so far.
@@ -120,50 +237,13 @@ void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const S
 
     auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent();
     RenderStyle& style = elementRenderer.style();
-    bool isVerticalText = style.svgStyle().isVerticalWritingMode();
 
-    float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());
     ASSERT(activePaintingResource);
 
-    FloatPoint glyphOrigin;
-    glyphOrigin.setX(svgFontData->horizontalOriginX() * scale);
-    glyphOrigin.setY(svgFontData->horizontalOriginY() * scale);
-
-    FloatPoint currentPoint = point;
     RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;
-    for (int i = 0; i < numGlyphs; ++i) {
-        Glyph glyph = glyphBuffer.glyphAt(from + i);
-        if (!glyph)
-            continue;
-
-        float advance = glyphBuffer.advanceAt(from + i).width();
-        SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
-        ASSERT(!svgGlyph.isPartOfLigature);
-        ASSERT(svgGlyph.tableEntry == glyph);
-
-        SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData);
-
-        // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations).
-        if (svgGlyph.pathData.isEmpty()) {
-            if (isVerticalText)
-                currentPoint.move(0, advance);
-            else
-                currentPoint.move(advance, 0);
-            continue;
-         }
-
-        if (isVerticalText) {
-            glyphOrigin.setX(svgGlyph.verticalOriginX * scale);
-            glyphOrigin.setY(svgGlyph.verticalOriginY * scale);
-         }
-
-        AffineTransform glyphPathTransform;
-        glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y());
-        glyphPathTransform.scale(scale, -scale);
-
-        Path glyphPath = svgGlyph.pathData;
-        glyphPath.transform(glyphPathTransform);
-
+    auto translator(createGlyphToPathTranslator(*fontData, glyphBuffer, from, numGlyphs, point));
+    while (translator->containsMorePaths()) {
+        Path glyphPath = translator->nextPath();
         if (activePaintingResource->applyResource(elementRenderer, style, context, resourceMode)) {
             float strokeThickness = context->strokeThickness();
             if (renderer().isSVGInlineText())
@@ -171,11 +251,6 @@ void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const S
             activePaintingResource->postApplyResource(elementRenderer, context, resourceMode, &glyphPath, 0);
             context->setStrokeThickness(strokeThickness);
         }
-
-        if (isVerticalText)
-            currentPoint.move(0, advance);
-        else
-            currentPoint.move(advance, 0);
     }
 }
 
index e1270c1..b6e259f 100644 (file)
@@ -59,6 +59,8 @@ private:
 
     virtual ~SVGTextRunRenderingContext() { }
 
+    virtual std::unique_ptr<GlyphToPathTranslator> createGlyphToPathTranslator(const SimpleFontData&, const GlyphBuffer&, int from, int numGlyphs, const FloatPoint&) const override;
+
     RenderObject& m_renderer;
 
 #if ENABLE(SVG_FONTS)