1 | /* |
2 | * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. |
3 | * |
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. |
8 | * |
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. |
13 | * |
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. |
18 | */ |
19 | |
20 | #include "config.h" |
21 | #include "SVGTextMetricsBuilder.h" |
22 | |
23 | #include "RenderChildIterator.h" |
24 | #include "RenderSVGInline.h" |
25 | #include "RenderSVGInlineText.h" |
26 | #include "RenderSVGText.h" |
27 | |
28 | namespace WebCore { |
29 | |
30 | SVGTextMetricsBuilder::SVGTextMetricsBuilder() |
31 | : m_text(0) |
32 | , m_run(StringView()) |
33 | , m_textPosition(0) |
34 | , m_isComplexText(false) |
35 | , m_totalWidth(0) |
36 | { |
37 | } |
38 | |
39 | inline bool SVGTextMetricsBuilder::currentCharacterStartsSurrogatePair() const |
40 | { |
41 | return U16_IS_LEAD(m_run[m_textPosition]) && (m_textPosition + 1) < m_run.length() && U16_IS_TRAIL(m_run[m_textPosition + 1]); |
42 | } |
43 | |
44 | bool SVGTextMetricsBuilder::advance() |
45 | { |
46 | m_textPosition += m_currentMetrics.length(); |
47 | if (m_textPosition >= m_run.length()) |
48 | return false; |
49 | |
50 | if (m_isComplexText) |
51 | advanceComplexText(); |
52 | else |
53 | advanceSimpleText(); |
54 | |
55 | return m_currentMetrics.length() > 0; |
56 | } |
57 | |
58 | void SVGTextMetricsBuilder::advanceSimpleText() |
59 | { |
60 | GlyphBuffer glyphBuffer; |
61 | unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1, &glyphBuffer); |
62 | if (!metricsLength) { |
63 | m_currentMetrics = SVGTextMetrics(); |
64 | return; |
65 | } |
66 | |
67 | float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth; |
68 | m_totalWidth = m_simpleWidthIterator->runWidthSoFar(); |
69 | |
70 | m_currentMetrics = SVGTextMetrics(*m_text, metricsLength, currentWidth); |
71 | } |
72 | |
73 | void SVGTextMetricsBuilder::advanceComplexText() |
74 | { |
75 | unsigned metricsLength = currentCharacterStartsSurrogatePair() ? 2 : 1; |
76 | m_currentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, m_textPosition, metricsLength); |
77 | m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, 0, m_textPosition + metricsLength); |
78 | ASSERT(m_currentMetrics.length() == metricsLength); |
79 | |
80 | // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken |
81 | // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping. |
82 | // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is |
83 | // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated. |
84 | float currentWidth = m_complexStartToCurrentMetrics.width() - m_totalWidth; |
85 | if (currentWidth != m_currentMetrics.width()) |
86 | m_currentMetrics.setWidth(currentWidth); |
87 | |
88 | m_totalWidth = m_complexStartToCurrentMetrics.width(); |
89 | } |
90 | |
91 | void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText& text) |
92 | { |
93 | m_text = &text; |
94 | m_textPosition = 0; |
95 | m_currentMetrics = SVGTextMetrics(); |
96 | m_complexStartToCurrentMetrics = SVGTextMetrics(); |
97 | m_totalWidth = 0; |
98 | |
99 | const FontCascade& scaledFont = text.scaledFont(); |
100 | m_run = SVGTextMetrics::constructTextRun(text); |
101 | m_isComplexText = scaledFont.codePath(m_run) == FontCascade::Complex; |
102 | |
103 | if (m_isComplexText) |
104 | m_simpleWidthIterator = nullptr; |
105 | else |
106 | m_simpleWidthIterator = std::make_unique<WidthIterator>(&scaledFont, m_run); |
107 | } |
108 | |
109 | struct MeasureTextData { |
110 | MeasureTextData(SVGCharacterDataMap* characterDataMap) |
111 | : allCharactersMap(characterDataMap) |
112 | , lastCharacter(0) |
113 | , processRenderer(false) |
114 | , valueListPosition(0) |
115 | , skippedCharacters(0) |
116 | { |
117 | } |
118 | |
119 | SVGCharacterDataMap* allCharactersMap; |
120 | UChar lastCharacter; |
121 | bool processRenderer; |
122 | unsigned valueListPosition; |
123 | unsigned skippedCharacters; |
124 | }; |
125 | |
126 | void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText& text, MeasureTextData* data) |
127 | { |
128 | SVGTextLayoutAttributes* attributes = text.layoutAttributes(); |
129 | Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues(); |
130 | if (data->processRenderer) { |
131 | if (data->allCharactersMap) |
132 | attributes->clear(); |
133 | else |
134 | textMetricsValues->clear(); |
135 | } |
136 | |
137 | initializeMeasurementWithTextRenderer(text); |
138 | bool preserveWhiteSpace = text.style().whiteSpace() == WhiteSpace::Pre; |
139 | int surrogatePairCharacters = 0; |
140 | |
141 | while (advance()) { |
142 | UChar currentCharacter = m_run[m_textPosition]; |
143 | if (currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || data->lastCharacter == ' ')) { |
144 | if (data->processRenderer) |
145 | textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); |
146 | if (data->allCharactersMap) |
147 | data->skippedCharacters += m_currentMetrics.length(); |
148 | continue; |
149 | } |
150 | |
151 | if (data->processRenderer) { |
152 | if (data->allCharactersMap) { |
153 | const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters - surrogatePairCharacters + 1); |
154 | if (it != data->allCharactersMap->end()) |
155 | attributes->characterDataMap().set(m_textPosition + 1, it->value); |
156 | } |
157 | textMetricsValues->append(m_currentMetrics); |
158 | } |
159 | |
160 | if (data->allCharactersMap && currentCharacterStartsSurrogatePair()) |
161 | surrogatePairCharacters++; |
162 | |
163 | data->lastCharacter = currentCharacter; |
164 | } |
165 | |
166 | if (!data->allCharactersMap) |
167 | return; |
168 | |
169 | data->valueListPosition += m_textPosition - data->skippedCharacters; |
170 | data->skippedCharacters = 0; |
171 | } |
172 | |
173 | void SVGTextMetricsBuilder::walkTree(RenderElement& start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) |
174 | { |
175 | for (auto& child : childrenOfType<RenderObject>(start)) { |
176 | if (is<RenderSVGInlineText>(child)) { |
177 | auto& text = downcast<RenderSVGInlineText>(child); |
178 | if (stopAtLeaf && stopAtLeaf != &text) { |
179 | data->processRenderer = false; |
180 | measureTextRenderer(text, data); |
181 | continue; |
182 | } |
183 | |
184 | data->processRenderer = true; |
185 | measureTextRenderer(text, data); |
186 | if (stopAtLeaf) |
187 | return; |
188 | |
189 | continue; |
190 | } |
191 | |
192 | if (!is<RenderSVGInline>(child)) |
193 | continue; |
194 | |
195 | walkTree(downcast<RenderSVGInline>(child), stopAtLeaf, data); |
196 | } |
197 | } |
198 | |
199 | void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText& text) |
200 | { |
201 | auto* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text); |
202 | if (!textRoot) |
203 | return; |
204 | |
205 | MeasureTextData data(nullptr); |
206 | walkTree(*textRoot, &text, &data); |
207 | } |
208 | |
209 | void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(RenderSVGText& textRoot, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap) |
210 | { |
211 | MeasureTextData data(&allCharactersMap); |
212 | walkTree(textRoot, stopAtLeaf, &data); |
213 | } |
214 | |
215 | } |
216 | |