Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / rendering / svg / SVGTextMetricsBuilder.cpp
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
22 #include "core/rendering/svg/SVGTextMetricsBuilder.h"
23
24 #include "core/rendering/svg/RenderSVGInline.h"
25 #include "core/rendering/svg/RenderSVGInlineText.h"
26 #include "core/rendering/svg/RenderSVGText.h"
27 #include "core/rendering/svg/SVGTextMetrics.h"
28 #include "platform/fonts/GlyphBuffer.h"
29 #include "platform/fonts/shaping/SimpleShaper.h"
30 #include "platform/text/BidiCharacterRun.h"
31 #include "platform/text/BidiResolver.h"
32 #include "platform/text/TextDirection.h"
33 #include "platform/text/TextPath.h"
34 #include "platform/text/TextRun.h"
35 #include "platform/text/TextRunIterator.h"
36 #include "wtf/Vector.h"
37
38 namespace blink {
39
40 class SVGTextMetricsCalculator {
41 public:
42     SVGTextMetricsCalculator(RenderSVGInlineText*);
43     ~SVGTextMetricsCalculator();
44
45     SVGTextMetrics computeMetricsForCharacter(unsigned textPosition);
46     unsigned textLength() const { return static_cast<unsigned>(m_run.charactersLength()); }
47
48     bool characterStartsSurrogatePair(unsigned textPosition) const
49     {
50         return U16_IS_LEAD(m_run[textPosition]) && textPosition + 1 < textLength() && U16_IS_TRAIL(m_run[textPosition + 1]);
51     }
52     bool characterIsWhiteSpace(unsigned textPosition) const
53     {
54         return m_run[textPosition] == ' ';
55     }
56
57 private:
58     void setupBidiRuns();
59     SVGTextMetrics computeMetricsForCharacterSimple(unsigned textPosition);
60     SVGTextMetrics computeMetricsForCharacterComplex(unsigned textPosition);
61
62     RenderSVGInlineText* m_text;
63     BidiCharacterRun* m_bidiRun;
64     TextRun m_run;
65     BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver;
66     bool m_isComplexText;
67     float m_totalWidth;
68     TextDirection m_textDirection;
69
70     // Simple text only.
71     OwnPtr<SimpleShaper> m_simpleShaper;
72 };
73
74 SVGTextMetricsCalculator::SVGTextMetricsCalculator(RenderSVGInlineText* text)
75     : m_text(text)
76     , m_bidiRun(0)
77     , m_run(SVGTextMetrics::constructTextRun(text, 0, text->textLength()))
78     , m_isComplexText(false)
79     , m_totalWidth(0)
80 {
81     const Font& scaledFont = text->scaledFont();
82     CodePath codePath = scaledFont.codePath(TextRunPaintInfo(m_run));
83     m_isComplexText = codePath == ComplexPath;
84     m_run.setCharacterScanForCodePath(!m_isComplexText);
85     m_run.setUseComplexCodePath(m_isComplexText);
86
87     if (!m_isComplexText)
88         m_simpleShaper = adoptPtr(new SimpleShaper(&scaledFont, m_run));
89     else
90         setupBidiRuns();
91 }
92
93 SVGTextMetricsCalculator::~SVGTextMetricsCalculator()
94 {
95     if (m_bidiRun)
96         m_bidiResolver.runs().deleteRuns();
97 }
98
99 void SVGTextMetricsCalculator::setupBidiRuns()
100 {
101     RenderStyle* style = m_text->style();
102     m_textDirection = style->direction();
103     if (isOverride(style->unicodeBidi()))
104         return;
105
106     BidiStatus status(LTR, false);
107     status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
108     m_bidiResolver.setStatus(status);
109     m_bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&m_run, 0));
110     const bool hardLineBreak = false;
111     const bool reorderRuns = false;
112     m_bidiResolver.createBidiRunsForLine(TextRunIterator(&m_run, m_run.length()), NoVisualOverride, hardLineBreak, reorderRuns);
113     BidiRunList<BidiCharacterRun>& bidiRuns = m_bidiResolver.runs();
114     m_bidiRun = bidiRuns.firstRun();
115 }
116
117 SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterSimple(unsigned textPosition)
118 {
119     GlyphBuffer glyphBuffer;
120     unsigned metricsLength = m_simpleShaper->advance(textPosition + 1, &glyphBuffer);
121     if (!metricsLength)
122         return SVGTextMetrics();
123
124     float currentWidth = m_simpleShaper->runWidthSoFar() - m_totalWidth;
125     m_totalWidth = m_simpleShaper->runWidthSoFar();
126
127     return SVGTextMetrics(m_text, textPosition, metricsLength, currentWidth);
128 }
129
130 SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacterComplex(unsigned textPosition)
131 {
132     unsigned metricsLength = characterStartsSurrogatePair(textPosition) ? 2 : 1;
133     SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(m_text, textPosition, metricsLength, m_textDirection);
134     ASSERT(metrics.length() == metricsLength);
135
136     unsigned startPosition = m_bidiRun ? m_bidiRun->start() : 0;
137     ASSERT(startPosition <= textPosition);
138     SVGTextMetrics complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, startPosition, textPosition - startPosition + metricsLength, m_textDirection);
139     // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken
140     // when rendering the glyph "in context" (with it's surrounding characters) it changes due to shaping.
141     // So whenever currentWidth != currentMetrics.width(), we are processing a text run whose length is
142     // not equal to the sum of the individual lengths of the glyphs, when measuring them isolated.
143     float currentWidth = complexStartToCurrentMetrics.width() - m_totalWidth;
144     if (currentWidth != metrics.width())
145         metrics.setWidth(currentWidth);
146
147     m_totalWidth = complexStartToCurrentMetrics.width();
148     return metrics;
149 }
150
151 SVGTextMetrics SVGTextMetricsCalculator::computeMetricsForCharacter(unsigned textPosition)
152 {
153     if (m_bidiRun) {
154         if (textPosition >= static_cast<unsigned>(m_bidiRun->stop())) {
155             m_bidiRun = m_bidiRun->next();
156             // New BiDi run means new reference position for measurements, so reset |m_totalWidth|.
157             m_totalWidth = 0;
158         }
159         ASSERT(m_bidiRun);
160         ASSERT(static_cast<int>(textPosition) < m_bidiRun->stop());
161         m_textDirection = m_bidiRun->direction();
162     }
163
164     if (m_isComplexText)
165         return computeMetricsForCharacterComplex(textPosition);
166
167     return computeMetricsForCharacterSimple(textPosition);
168 }
169
170 struct MeasureTextData {
171     MeasureTextData(SVGCharacterDataMap* characterDataMap)
172         : allCharactersMap(characterDataMap)
173         , lastCharacterWasWhiteSpace(true)
174         , valueListPosition(0)
175     {
176     }
177
178     SVGCharacterDataMap* allCharactersMap;
179     bool lastCharacterWasWhiteSpace;
180     unsigned valueListPosition;
181 };
182
183 static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer)
184 {
185     ASSERT(text);
186
187     SVGTextLayoutAttributes* attributes = text->layoutAttributes();
188     Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
189     if (processRenderer) {
190         if (data->allCharactersMap)
191             attributes->clear();
192         else
193             textMetricsValues->clear();
194     }
195
196     SVGTextMetricsCalculator calculator(text);
197     bool preserveWhiteSpace = text->style()->whiteSpace() == PRE;
198     unsigned surrogatePairCharacters = 0;
199     unsigned skippedCharacters = 0;
200     unsigned textPosition = 0;
201     unsigned textLength = calculator.textLength();
202
203     SVGTextMetrics currentMetrics;
204     for (; textPosition < textLength; textPosition += currentMetrics.length()) {
205         currentMetrics = calculator.computeMetricsForCharacter(textPosition);
206         if (!currentMetrics.length())
207             break;
208
209         bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition);
210         if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) {
211             if (processRenderer)
212                 textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
213             if (data->allCharactersMap)
214                 skippedCharacters += currentMetrics.length();
215             continue;
216         }
217
218         if (processRenderer) {
219             if (data->allCharactersMap) {
220                 const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1);
221                 if (it != data->allCharactersMap->end())
222                     attributes->characterDataMap().set(textPosition + 1, it->value);
223             }
224             textMetricsValues->append(currentMetrics);
225         }
226
227         if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition))
228             surrogatePairCharacters++;
229
230         data->lastCharacterWasWhiteSpace = characterIsWhiteSpace;
231     }
232
233     if (!data->allCharactersMap)
234         return;
235
236     data->valueListPosition += textPosition - skippedCharacters;
237 }
238
239 static void walkTree(RenderSVGText* start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data)
240 {
241     RenderObject* child = start->firstChild();
242     while (child) {
243         if (child->isSVGInlineText()) {
244             RenderSVGInlineText* text = toRenderSVGInlineText(child);
245             measureTextRenderer(text, data, !stopAtLeaf || stopAtLeaf == text);
246             if (stopAtLeaf && stopAtLeaf == text)
247                 return;
248         } else if (child->isSVGInline()) {
249             // Visit children of text content elements.
250             if (RenderObject* inlineChild = toRenderSVGInline(child)->firstChild()) {
251                 child = inlineChild;
252                 continue;
253             }
254         }
255         child = child->nextInPreOrderAfterChildren(start);
256     }
257 }
258
259 void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text)
260 {
261     ASSERT(text);
262
263     RenderSVGText* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text);
264     if (!textRoot)
265         return;
266
267     MeasureTextData data(0);
268     walkTree(textRoot, text, &data);
269 }
270
271 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(RenderSVGText* textRoot, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap)
272 {
273     ASSERT(textRoot);
274     MeasureTextData data(&allCharactersMap);
275     walkTree(textRoot, stopAtLeaf, &data);
276 }
277
278 }