Revert r170413 and r170390
[WebKit-https.git] / Source / WebCore / rendering / svg / SVGTextRunRenderingContext.cpp
1 /*
2  * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3  * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #if ENABLE(SVG_FONTS)
24 #include "SVGTextRunRenderingContext.h"
25
26 #include "GlyphBuffer.h"
27 #include "GraphicsContext.h"
28 #include "RenderObject.h"
29 #include "RenderSVGInlineText.h"
30 #include "RenderSVGResourceSolidColor.h"
31 #include "SVGFontData.h"
32 #include "SVGFontElement.h"
33 #include "SVGFontFaceElement.h"
34 #include "SVGGlyphElement.h"
35 #include "SVGNames.h"
36 #include "WidthIterator.h"
37
38 namespace WebCore {
39
40 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font)
41 {
42     ASSERT(fontData);
43     ASSERT(fontData->isCustomFont());
44     ASSERT(fontData->isSVGFont());
45
46     const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->fontData());
47
48     fontFace = svgFontData->svgFontFaceElement();
49     ASSERT(fontFace);
50
51     font = fontFace->associatedFontElement();
52     return svgFontData;
53 }
54
55 float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, String& glyphName) const
56 {
57     WidthIterator it(&font, run);
58     GlyphBuffer glyphBuffer;
59     charsConsumed += it.advance(run.length(), &glyphBuffer);
60     glyphName = it.lastGlyphName();
61     return it.runWidthSoFar();
62 }
63
64 bool SVGTextRunRenderingContext::applySVGKerning(const SimpleFontData* fontData, WidthIterator& iterator, GlyphBuffer* glyphBuffer, int from) const
65 {
66     ASSERT(glyphBuffer);
67     ASSERT(glyphBuffer->size() > 1);
68     SVGFontElement* fontElement = 0;
69     SVGFontFaceElement* fontFaceElement = 0;
70
71     svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
72     if (!fontElement || !fontFaceElement)
73         return false;
74
75     float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());
76
77     String lastGlyphName;
78     String lastUnicodeString;
79     int characterOffset = iterator.m_currentCharacter;
80     String text = iterator.run().string();
81     const int glyphCount = glyphBuffer->size() - from;
82     GlyphBufferAdvance* advances = glyphBuffer->advances(from);
83
84     for (int i = 0; i < glyphCount; ++i) {
85         Glyph glyph = glyphBuffer->glyphAt(from + i);
86         if (!glyph)
87             continue;
88         float kerning = 0;
89         SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
90         String unicodeString = text.substring(characterOffset, svgGlyph.unicodeStringLength);
91         if (i >= 1) {
92             // FIXME: Support vertical text.
93             kerning = fontElement->horizontalKerningForPairOfStringsAndGlyphs(lastUnicodeString, lastGlyphName, unicodeString, svgGlyph.glyphName);
94             advances[i - 1].setWidth(advances[i - 1].width() - kerning * scale);
95         }
96         lastGlyphName = svgGlyph.glyphName;
97         lastUnicodeString = unicodeString;
98         characterOffset += svgGlyph.unicodeStringLength;
99     }
100
101     return true;
102 }
103
104 class SVGGlyphToPathTranslator final : public GlyphToPathTranslator {
105 public:
106     SVGGlyphToPathTranslator(const TextRun* const, const GlyphBuffer&, const FloatPoint&, const SVGFontData&, SVGFontElement&, const int from, const int numGlyphs, float scale, bool isVerticalText);
107 private:
108     virtual bool containsMorePaths() override
109     {
110         return m_index != m_stoppingPoint;
111     }
112
113     virtual Path path() override;
114     virtual std::pair<float, float> extents() override;
115     virtual GlyphUnderlineType underlineType() override;
116     virtual void advance() override;
117     void moveToNextValidGlyph();
118     AffineTransform transform();
119
120     const TextRun* const m_textRun;
121     const GlyphBuffer& m_glyphBuffer;
122     const SVGFontData& m_svgFontData;
123     FloatPoint m_currentPoint;
124     FloatPoint m_glyphOrigin;
125     SVGGlyph m_svgGlyph;
126     int m_index;
127     Glyph m_glyph;
128     SVGFontElement& m_fontElement;
129     const float m_stoppingPoint;
130     const float m_scale;
131     const bool m_isVerticalText;
132 };
133
134 SVGGlyphToPathTranslator::SVGGlyphToPathTranslator(const TextRun* const textRun, const GlyphBuffer& glyphBuffer, const FloatPoint& point, const SVGFontData& svgFontData, SVGFontElement& fontElement, const int from, const int numGlyphs, float scale, bool isVerticalText)
135     : m_textRun(textRun)
136     , m_glyphBuffer(glyphBuffer)
137     , m_svgFontData(svgFontData)
138     , m_currentPoint(point)
139     , m_glyphOrigin(m_svgFontData.horizontalOriginX() * scale, m_svgFontData.horizontalOriginY() * scale)
140     , m_index(from)
141     , m_glyph(glyphBuffer.glyphAt(m_index))
142     , m_fontElement(fontElement)
143     , m_stoppingPoint(numGlyphs + from)
144     , m_scale(scale)
145     , m_isVerticalText(isVerticalText)
146 {
147     ASSERT(glyphBuffer.size() > m_index);
148     if (m_glyph) {
149         m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
150         ASSERT(!m_svgGlyph.isPartOfLigature);
151         ASSERT(m_svgGlyph.tableEntry == m_glyph);
152         SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
153     }
154     moveToNextValidGlyph();
155 }
156
157 AffineTransform SVGGlyphToPathTranslator::transform()
158 {
159     AffineTransform glyphPathTransform;
160     glyphPathTransform.translate(m_currentPoint.x() + m_glyphOrigin.x(), m_currentPoint.y() + m_glyphOrigin.y());
161     glyphPathTransform.scale(m_scale, -m_scale);
162     return glyphPathTransform;
163 }
164
165 Path SVGGlyphToPathTranslator::path()
166 {
167     Path glyphPath = m_svgGlyph.pathData;
168     glyphPath.transform(transform());
169     return glyphPath;
170 }
171
172 std::pair<float, float> SVGGlyphToPathTranslator::extents()
173 {
174     AffineTransform glyphPathTransform = transform();
175     FloatPoint beginning = glyphPathTransform.mapPoint(m_currentPoint);
176     FloatSize end = glyphPathTransform.mapSize(FloatSize(m_glyphBuffer.advanceAt(m_index)));
177     return std::make_pair(beginning.x(), beginning.x() + end.width());
178 }
179
180 auto SVGGlyphToPathTranslator::underlineType() -> GlyphUnderlineType
181 {
182     ASSERT(m_textRun);
183     return computeUnderlineType(*m_textRun, m_glyphBuffer, m_index);
184 }
185
186 void SVGGlyphToPathTranslator::moveToNextValidGlyph()
187 {
188     if (m_glyph && !m_svgGlyph.pathData.isEmpty())
189         return;
190     advance();
191 }
192
193 void SVGGlyphToPathTranslator::advance()
194 {
195     do {
196         if (m_glyph) {
197             float advance = m_glyphBuffer.advanceAt(m_index).width();
198             if (m_isVerticalText)
199                 m_currentPoint.move(0, advance);
200             else
201                 m_currentPoint.move(advance, 0);
202         }
203
204         ++m_index;
205         if (m_index >= m_stoppingPoint || !m_glyphBuffer.fontDataAt(m_index)->isSVGFont())
206             break;
207         m_glyph = m_glyphBuffer.glyphAt(m_index);
208         if (!m_glyph)
209             continue;
210         m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
211         ASSERT(!m_svgGlyph.isPartOfLigature);
212         ASSERT(m_svgGlyph.tableEntry == m_glyph);
213         SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
214     } while ((!m_glyph || m_svgGlyph.pathData.isEmpty()) && m_index < m_stoppingPoint);
215
216     if (containsMorePaths() && m_isVerticalText) {
217         m_glyphOrigin.setX(m_svgGlyph.verticalOriginX * m_scale);
218         m_glyphOrigin.setY(m_svgGlyph.verticalOriginY * m_scale);
219     }
220 }
221
222 class DummyGlyphToPathTranslator final : public GlyphToPathTranslator {
223     virtual bool containsMorePaths() override
224     {
225         return false;
226     }
227     virtual Path path() override
228     {
229         return Path();
230     }
231     virtual std::pair<float, float> extents() override
232     {
233         return std::make_pair(0.f, 0.f);
234     }
235     virtual GlyphUnderlineType underlineType() override
236     {
237         return GlyphUnderlineType::DrawOverGlyph;
238     }
239     virtual void advance() override
240     {
241     }
242 };
243
244 std::unique_ptr<GlyphToPathTranslator> SVGTextRunRenderingContext::createGlyphToPathTranslator(const SimpleFontData& fontData, const TextRun* textRun, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
245 {
246     SVGFontElement* fontElement = 0;
247     SVGFontFaceElement* fontFaceElement = 0;
248
249     const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(&fontData, fontFaceElement, fontElement);
250     if (!fontElement || !fontFaceElement)
251         return std::make_unique<DummyGlyphToPathTranslator>();
252
253     auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent();
254     RenderStyle& style = elementRenderer.style();
255     bool isVerticalText = style.svgStyle().isVerticalWritingMode();
256
257     float scale = scaleEmToUnits(fontData.platformData().size(), fontFaceElement->unitsPerEm());
258
259     return std::make_unique<SVGGlyphToPathTranslator>(textRun, glyphBuffer, point, *svgFontData, *fontElement, from, numGlyphs, scale, isVerticalText);
260 }
261
262 void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
263 {
264     auto activePaintingResource = this->activePaintingResource();
265     if (!activePaintingResource) {
266         // TODO: We're only supporting simple filled HTML text so far.
267         RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource();
268         solidPaintingResource->setColor(context->fillColor());
269         activePaintingResource = solidPaintingResource;
270     }
271
272     auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent();
273     RenderStyle& style = elementRenderer.style();
274
275     ASSERT(activePaintingResource);
276
277     RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;
278     for (auto translator = createGlyphToPathTranslator(*fontData, nullptr, glyphBuffer, from, numGlyphs, point); translator->containsMorePaths(); translator->advance()) {
279         Path glyphPath = translator->path();
280         if (activePaintingResource->applyResource(elementRenderer, style, context, resourceMode)) {
281             float strokeThickness = context->strokeThickness();
282             if (renderer().isSVGInlineText())
283                 context->setStrokeThickness(strokeThickness * toRenderSVGInlineText(renderer()).scalingFactor());
284             activePaintingResource->postApplyResource(elementRenderer, context, resourceMode, &glyphPath, 0);
285             context->setStrokeThickness(strokeThickness);
286         }
287     }
288 }
289
290 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength)
291 {
292     const SimpleFontData* primaryFont = font.primaryFont();
293     ASSERT(primaryFont);
294
295     std::pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror, AutoVariant);
296     GlyphData glyphData = pair.first;
297
298     // Check if we have the missing glyph data, in which case we can just return.
299     GlyphData missingGlyphData = primaryFont->missingGlyphData();
300     if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missingGlyphData.fontData) {
301         ASSERT(glyphData.fontData);
302         return glyphData;
303     }
304
305     // Save data fromt he font fallback list because we may modify it later. Do this before the
306     // potential change to glyphData.fontData below.
307     FontGlyphs* glyph = font.glyphs();
308     ASSERT(glyph);
309     FontGlyphs::GlyphPagesStateSaver glyphPagesSaver(*glyph);
310
311     // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage.
312     const SimpleFontData* originalFontData = glyphData.fontData;
313     if (glyphData.fontData && !glyphData.fontData->isSVGFont()) {
314         auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent();
315         if (Element* parentRendererElement = elementRenderer.element()) {
316             if (parentRendererElement->hasTagName(SVGNames::altGlyphTag))
317                 glyphData.fontData = primaryFont;
318         }
319     }
320
321     const SimpleFontData* fontData = glyphData.fontData;
322     if (fontData) {
323         if (!fontData->isSVGFont())
324             return glyphData;
325
326         SVGFontElement* fontElement = 0;
327         SVGFontFaceElement* fontFaceElement = 0;
328
329         const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement);
330         if (!fontElement || !fontFaceElement)
331             return glyphData;
332
333         // If we got here, we're dealing with a glyph defined in a SVG Font.
334         // The returned glyph by glyphDataAndPageForCharacter() is a glyph stored in the SVG Font glyph table.
335         // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its
336         // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that.
337         if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength))
338             return glyphData;
339     }
340
341     GlyphPage* page = pair.second;
342     ASSERT(page);
343
344     // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.)
345     // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily
346     // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly.
347     page->setGlyphDataForCharacter(character, 0, 0);
348
349     // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before.
350     GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror);
351     ASSERT(fallbackGlyphData.fontData != fontData);
352
353     // Restore original state of the SVG Font glyph table and the current font fallback list,
354     // to assure the next lookup of the same glyph won't immediately return the fallback glyph.
355     page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData);
356     ASSERT(fallbackGlyphData.fontData);
357     return fallbackGlyphData;
358 }
359
360 }
361
362 #endif