Font::primaryFontData() should return a reference
[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     if (fontElement->horizontalKerningMapIsEmpty())
76         return true;
77
78     float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm());
79
80     String lastGlyphName;
81     String lastUnicodeString;
82     int characterOffset = iterator.m_currentCharacter;
83     String text = iterator.run().string();
84     const int glyphCount = glyphBuffer->size() - from;
85     GlyphBufferAdvance* advances = glyphBuffer->advances(from);
86
87     for (int i = 0; i < glyphCount; ++i) {
88         Glyph glyph = glyphBuffer->glyphAt(from + i);
89         if (!glyph)
90             continue;
91         float kerning = 0;
92         SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph);
93         String unicodeString = text.substring(characterOffset, svgGlyph.unicodeStringLength);
94         if (i >= 1) {
95             // FIXME: Support vertical text.
96             kerning = fontElement->horizontalKerningForPairOfStringsAndGlyphs(lastUnicodeString, lastGlyphName, unicodeString, svgGlyph.glyphName);
97             advances[i - 1].setWidth(advances[i - 1].width() - kerning * scale);
98         }
99         lastGlyphName = svgGlyph.glyphName;
100         lastUnicodeString = unicodeString;
101         characterOffset += svgGlyph.unicodeStringLength;
102     }
103
104     return true;
105 }
106
107 class SVGGlyphToPathTranslator final : public GlyphToPathTranslator {
108 public:
109     SVGGlyphToPathTranslator(const TextRun* const, const GlyphBuffer&, const FloatPoint&, const SVGFontData&, SVGFontElement&, const int from, const int numGlyphs, float scale, bool isVerticalText);
110 private:
111     virtual bool containsMorePaths() override
112     {
113         return m_index != m_stoppingPoint;
114     }
115
116     virtual Path path() override;
117     virtual std::pair<float, float> extents() override;
118     virtual GlyphUnderlineType underlineType() override;
119     virtual void advance() override;
120     void moveToNextValidGlyph();
121     AffineTransform transform();
122
123     const TextRun* const m_textRun;
124     const GlyphBuffer& m_glyphBuffer;
125     const SVGFontData& m_svgFontData;
126     FloatPoint m_currentPoint;
127     FloatPoint m_glyphOrigin;
128     SVGGlyph m_svgGlyph;
129     int m_index;
130     Glyph m_glyph;
131     SVGFontElement& m_fontElement;
132     const float m_stoppingPoint;
133     const float m_scale;
134     const bool m_isVerticalText;
135 };
136
137 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)
138     : m_textRun(textRun)
139     , m_glyphBuffer(glyphBuffer)
140     , m_svgFontData(svgFontData)
141     , m_currentPoint(point)
142     , m_glyphOrigin(m_svgFontData.horizontalOriginX() * scale, m_svgFontData.horizontalOriginY() * scale)
143     , m_index(from)
144     , m_glyph(glyphBuffer.glyphAt(m_index))
145     , m_fontElement(fontElement)
146     , m_stoppingPoint(numGlyphs + from)
147     , m_scale(scale)
148     , m_isVerticalText(isVerticalText)
149 {
150     ASSERT(glyphBuffer.size() > m_index);
151     if (m_glyph) {
152         m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
153         ASSERT(!m_svgGlyph.isPartOfLigature);
154         ASSERT(m_svgGlyph.tableEntry == m_glyph);
155         SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
156     }
157     moveToNextValidGlyph();
158 }
159
160 AffineTransform SVGGlyphToPathTranslator::transform()
161 {
162     AffineTransform glyphPathTransform;
163     glyphPathTransform.translate(m_currentPoint.x() + m_glyphOrigin.x(), m_currentPoint.y() + m_glyphOrigin.y());
164     glyphPathTransform.scale(m_scale, -m_scale);
165     return glyphPathTransform;
166 }
167
168 Path SVGGlyphToPathTranslator::path()
169 {
170     Path glyphPath = m_svgGlyph.pathData;
171     glyphPath.transform(transform());
172     return glyphPath;
173 }
174
175 std::pair<float, float> SVGGlyphToPathTranslator::extents()
176 {
177     AffineTransform glyphPathTransform = transform();
178     FloatPoint beginning = glyphPathTransform.mapPoint(m_currentPoint);
179     FloatSize end = glyphPathTransform.mapSize(FloatSize(m_glyphBuffer.advanceAt(m_index)));
180     return std::make_pair(beginning.x(), beginning.x() + end.width());
181 }
182
183 auto SVGGlyphToPathTranslator::underlineType() -> GlyphUnderlineType
184 {
185     ASSERT(m_textRun);
186     return computeUnderlineType(*m_textRun, m_glyphBuffer, m_index);
187 }
188
189 void SVGGlyphToPathTranslator::moveToNextValidGlyph()
190 {
191     if (m_glyph && !m_svgGlyph.pathData.isEmpty())
192         return;
193     advance();
194 }
195
196 void SVGGlyphToPathTranslator::advance()
197 {
198     do {
199         if (m_glyph) {
200             float advance = m_glyphBuffer.advanceAt(m_index).width();
201             if (m_isVerticalText)
202                 m_currentPoint.move(0, advance);
203             else
204                 m_currentPoint.move(advance, 0);
205         }
206
207         ++m_index;
208         if (m_index >= m_stoppingPoint || !m_glyphBuffer.fontDataAt(m_index)->isSVGFont())
209             break;
210         m_glyph = m_glyphBuffer.glyphAt(m_index);
211         if (!m_glyph)
212             continue;
213         m_svgGlyph = m_fontElement.svgGlyphForGlyph(m_glyph);
214         ASSERT(!m_svgGlyph.isPartOfLigature);
215         ASSERT(m_svgGlyph.tableEntry == m_glyph);
216         SVGGlyphElement::inheritUnspecifiedAttributes(m_svgGlyph, &m_svgFontData);
217     } while ((!m_glyph || m_svgGlyph.pathData.isEmpty()) && m_index < m_stoppingPoint);
218
219     if (containsMorePaths() && m_isVerticalText) {
220         m_glyphOrigin.setX(m_svgGlyph.verticalOriginX * m_scale);
221         m_glyphOrigin.setY(m_svgGlyph.verticalOriginY * m_scale);
222     }
223 }
224
225 class DummyGlyphToPathTranslator final : public GlyphToPathTranslator {
226     virtual bool containsMorePaths() override
227     {
228         return false;
229     }
230     virtual Path path() override
231     {
232         return Path();
233     }
234     virtual std::pair<float, float> extents() override
235     {
236         return std::make_pair(0.f, 0.f);
237     }
238     virtual GlyphUnderlineType underlineType() override
239     {
240         return GlyphUnderlineType::DrawOverGlyph;
241     }
242     virtual void advance() override
243     {
244     }
245 };
246
247 std::unique_ptr<GlyphToPathTranslator> SVGTextRunRenderingContext::createGlyphToPathTranslator(const SimpleFontData& fontData, const TextRun* textRun, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
248 {
249     SVGFontElement* fontElement = nullptr;
250     SVGFontFaceElement* fontFaceElement = nullptr;
251
252     const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(&fontData, fontFaceElement, fontElement);
253     if (!fontElement || !fontFaceElement)
254         return std::make_unique<DummyGlyphToPathTranslator>();
255
256     auto& elementRenderer = is<RenderElement>(renderer()) ? downcast<RenderElement>(renderer()) : *renderer().parent();
257     RenderStyle& style = elementRenderer.style();
258     bool isVerticalText = style.svgStyle().isVerticalWritingMode();
259
260     float scale = scaleEmToUnits(fontData.platformData().size(), fontFaceElement->unitsPerEm());
261
262     return std::make_unique<SVGGlyphToPathTranslator>(textRun, glyphBuffer, point, *svgFontData, *fontElement, from, numGlyphs, scale, isVerticalText);
263 }
264
265 void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const
266 {
267     auto activePaintingResource = this->activePaintingResource();
268     if (!activePaintingResource) {
269         // TODO: We're only supporting simple filled HTML text so far.
270         RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource();
271         solidPaintingResource->setColor(context->fillColor());
272         activePaintingResource = solidPaintingResource;
273     }
274
275     auto& elementRenderer = is<RenderElement>(renderer()) ? downcast<RenderElement>(renderer()) : *renderer().parent();
276     RenderStyle& style = elementRenderer.style();
277
278     ASSERT(activePaintingResource);
279
280     RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode;
281     for (auto translator = createGlyphToPathTranslator(*fontData, nullptr, glyphBuffer, from, numGlyphs, point); translator->containsMorePaths(); translator->advance()) {
282         Path glyphPath = translator->path();
283         if (activePaintingResource->applyResource(elementRenderer, style, context, resourceMode)) {
284             float strokeThickness = context->strokeThickness();
285             if (is<RenderSVGInlineText>(renderer()))
286                 context->setStrokeThickness(strokeThickness * downcast<RenderSVGInlineText>(renderer()).scalingFactor());
287             activePaintingResource->postApplyResource(elementRenderer, context, resourceMode, &glyphPath, nullptr);
288             context->setStrokeThickness(strokeThickness);
289         }
290     }
291 }
292
293 static GlyphData missingGlyphForFont(const Font& font)
294 {
295     const SimpleFontData& primaryFontData = font.primaryFontData();
296     if (!primaryFontData.isSVGFont())
297         return GlyphData();
298     SVGFontElement* fontElement;
299     SVGFontFaceElement* fontFaceElement;
300     svgFontAndFontFaceElementForFontData(&primaryFontData, fontFaceElement, fontElement);
301     return GlyphData(fontElement->missingGlyph(), &primaryFontData);
302 }
303
304 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength, String& normalizedSpacesStringCache)
305 {
306     GlyphData glyphData = font.glyphDataForCharacter(character, mirror, AutoVariant);
307     if (!glyphData.glyph)
308         return missingGlyphForFont(font);
309
310     ASSERT(glyphData.fontData);
311
312     // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage.
313     if (!glyphData.fontData->isSVGFont()) {
314         auto& elementRenderer = is<RenderElement>(renderer()) ? downcast<RenderElement>(renderer()) : *renderer().parent();
315         if (Element* parentRendererElement = elementRenderer.element()) {
316             if (is<SVGAltGlyphElement>(*parentRendererElement))
317                 glyphData.fontData = &font.primaryFontData();
318         }
319     }
320
321     if (!glyphData.fontData->isSVGFont())
322         return glyphData;
323
324     SVGFontElement* fontElement = nullptr;
325     SVGFontFaceElement* fontFaceElement = nullptr;
326     const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(glyphData.fontData, fontFaceElement, fontElement);
327     if (!svgFontData)
328         return glyphData;
329
330     // If we got here, we're dealing with a glyph defined in a SVG Font.
331     // The returned glyph by glyphDataForCharacter() is a glyph stored in the SVG Font glyph table.
332     // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its
333     // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that.
334     if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength, normalizedSpacesStringCache))
335         return glyphData;
336
337     GlyphData missingGlyphData = missingGlyphForFont(font);
338     if (missingGlyphData.glyph)
339         return missingGlyphData;
340
341     // SVG font context sensitive selection failed and there is no defined missing glyph. Drop down to a default font.
342     // The behavior does not seem to be specified. For simplicity we don't try to resolve font fallbacks context-sensitively.
343     FontDescription fallbackDescription = font.fontDescription();
344     fallbackDescription.setFamilies(Vector<AtomicString> { sansSerifFamily });
345     Font fallbackFont(fallbackDescription, font.letterSpacing(), font.wordSpacing());
346     fallbackFont.update(font.fontSelector());
347
348     return fallbackFont.glyphDataForCharacter(character, mirror, AutoVariant);
349 }
350
351 }
352
353 #endif