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 10cded261135d3e16a4c107dbe52e7ff8b9898e9..2bf006560d617d638052acd0e0aa31e78a4adbc8 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 40b9e5f3cff213e3fc218857caf9959a947c6a4f..d5f4ac24aeae248b47e12af26776014fcc5391d4 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 1ad36ace2ea59b27f43b06852acfc0a1d3ba2b2b..adffce8501ec9f5bd42882c388c7772c94a282b8 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 161f846aee4d8bcb7d8570a88970d762710defde..55f0f6e2eab7548062c2e3e1bcba147e46ec79a6 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 8eb9d9cc5a663366ba140209e0129c2e97cad35b..230bdf34ec6a1b50d0bb9f781d6cf8bbdcd705cb 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 9f39ccca1d1ad12bb8774f9dc11fc6beda17c3c1..9d20edfa595e43f1ed7b60629d13ca83ae3ba16a 100644 (file)
@@ -78,6 +78,11 @@ Path::Path()
 {
 }
 
+Path::Path(RetainPtr<CGMutablePathRef> p)
+    : m_path(p.leakRef())
+{
+}
+
 Path::~Path()
 {
     if (m_path)
index c6d62043e96d7a2c578f029a5e86637cb7273ceb..7244e1a888664d05fb7ab93421cca68fb4d94bd9 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 3b2561af8c160df3bbe92b033e8af3582cc09162..d73a2a416b0c3c43292b094a37deeeae9f7de844 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 e1270c19ea2624e2197c3d08809bc7d8e03e1c8e..b6e259f0ca9ea177fcee52944ece79d369df9cb1 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)