OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. |
3 * | 3 * |
4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
8 * | 8 * |
9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "platform/fonts/CharacterRange.h" | 27 #include "platform/fonts/CharacterRange.h" |
28 #include "platform/text/BidiCharacterRun.h" | 28 #include "platform/text/BidiCharacterRun.h" |
29 #include "platform/text/BidiResolver.h" | 29 #include "platform/text/BidiResolver.h" |
30 #include "platform/text/TextDirection.h" | 30 #include "platform/text/TextDirection.h" |
31 #include "platform/text/TextRun.h" | 31 #include "platform/text/TextRun.h" |
32 #include "platform/text/TextRunIterator.h" | 32 #include "platform/text/TextRunIterator.h" |
33 #include "wtf/Vector.h" | 33 #include "wtf/Vector.h" |
34 | 34 |
35 namespace blink { | 35 namespace blink { |
36 | 36 |
| 37 namespace { |
| 38 |
37 class SVGTextMetricsCalculator { | 39 class SVGTextMetricsCalculator { |
38 public: | 40 public: |
39 SVGTextMetricsCalculator(LayoutSVGInlineText*); | 41 SVGTextMetricsCalculator(LayoutSVGInlineText*); |
40 ~SVGTextMetricsCalculator(); | 42 ~SVGTextMetricsCalculator(); |
41 | 43 |
42 bool advancePosition(); | 44 bool advancePosition(); |
43 unsigned currentPosition() const { return m_currentPosition; } | 45 unsigned currentPosition() const { return m_currentPosition; } |
44 | 46 |
45 SVGTextMetrics currentCharacterMetrics(); | 47 SVGTextMetrics currentCharacterMetrics(); |
46 | 48 |
47 // TODO(pdr): Character-based iteration is ambiguous and error-prone. It | 49 // TODO(pdr): Character-based iteration is ambiguous and error-prone. It |
48 // should be unified under a single concept. See: https://crbug.com/593570 | 50 // should be unified under a single concept. See: https://crbug.com/593570 |
49 bool currentCharacterStartsSurrogatePair() const | 51 bool currentCharacterStartsSurrogatePair() const |
50 { | 52 { |
51 return U16_IS_LEAD(m_run[m_currentPosition]) && m_currentPosition + 1 <
characterCount() && U16_IS_TRAIL(m_run[m_currentPosition + 1]); | 53 return U16_IS_LEAD(m_run[m_currentPosition]) && m_currentPosition + 1 <
characterCount() && U16_IS_TRAIL(m_run[m_currentPosition + 1]); |
52 } | 54 } |
53 bool currentCharacterIsWhiteSpace() const | 55 bool currentCharacterIsWhiteSpace() const |
54 { | 56 { |
55 return m_run[m_currentPosition] == ' '; | 57 return m_run[m_currentPosition] == ' '; |
56 } | 58 } |
57 unsigned characterCount() const | 59 unsigned characterCount() const |
58 { | 60 { |
59 return static_cast<unsigned>(m_run.charactersLength()); | 61 return static_cast<unsigned>(m_run.charactersLength()); |
60 } | 62 } |
61 | 63 |
62 private: | 64 private: |
63 void setupBidiRuns(); | 65 void setupBidiRuns(); |
64 | 66 |
| 67 static TextRun constructTextRun(LineLayoutSVGInlineText, unsigned position,
unsigned length, TextDirection); |
| 68 |
65 // Ensure |m_subrunRanges| is updated for the current bidi run, or the | 69 // Ensure |m_subrunRanges| is updated for the current bidi run, or the |
66 // complete m_run if no bidi runs are present. Returns the current position | 70 // complete m_run if no bidi runs are present. Returns the current position |
67 // in the subrun which can be used to index into |m_subrunRanges|. | 71 // in the subrun which can be used to index into |m_subrunRanges|. |
68 unsigned updateSubrunRangesForCurrentPosition(); | 72 unsigned updateSubrunRangesForCurrentPosition(); |
69 | 73 |
70 // Current character position in m_text. | 74 // Current character position in m_text. |
71 unsigned m_currentPosition; | 75 unsigned m_currentPosition; |
72 | 76 |
73 LineLayoutSVGInlineText m_text; | 77 LineLayoutSVGInlineText m_text; |
74 TextRun m_run; | 78 TextRun m_run; |
75 | 79 |
76 BidiCharacterRun* m_bidiRun; | 80 BidiCharacterRun* m_bidiRun; |
77 BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver; | 81 BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver; |
78 | 82 |
79 // Ranges for the current bidi run if present, or the entire run otherwise. | 83 // Ranges for the current bidi run if present, or the entire run otherwise. |
80 Vector<CharacterRange> m_subrunRanges; | 84 Vector<CharacterRange> m_subrunRanges; |
81 }; | 85 }; |
82 | 86 |
| 87 TextRun SVGTextMetricsCalculator::constructTextRun(LineLayoutSVGInlineText textL
ayoutItem, unsigned position, unsigned length, TextDirection textDirection) |
| 88 { |
| 89 const ComputedStyle& style = textLayoutItem.styleRef(); |
| 90 |
| 91 TextRun run(static_cast<const LChar*>(nullptr) // characters, will be set be
low if non-zero. |
| 92 , 0 // length, will be set below if non-zero. |
| 93 , 0 // xPos, only relevant with allowTabs=true |
| 94 , 0 // padding, only relevant for justified text, not relevant for SVG |
| 95 , TextRun::AllowTrailingExpansion |
| 96 , textDirection |
| 97 , isOverride(style.unicodeBidi()) /* directionalOverride */); |
| 98 |
| 99 if (length) { |
| 100 if (textLayoutItem.is8Bit()) |
| 101 run.setText(textLayoutItem.characters8() + position, length); |
| 102 else |
| 103 run.setText(textLayoutItem.characters16() + position, length); |
| 104 } |
| 105 |
| 106 // We handle letter & word spacing ourselves. |
| 107 run.disableSpacing(); |
| 108 |
| 109 // Propagate the maximum length of the characters buffer to the TextRun, eve
n when we're only processing a substring. |
| 110 run.setCharactersLength(textLayoutItem.textLength() - position); |
| 111 ASSERT(run.charactersLength() >= run.length()); |
| 112 return run; |
| 113 } |
| 114 |
83 SVGTextMetricsCalculator::SVGTextMetricsCalculator(LayoutSVGInlineText* text) | 115 SVGTextMetricsCalculator::SVGTextMetricsCalculator(LayoutSVGInlineText* text) |
84 : m_currentPosition(0) | 116 : m_currentPosition(0) |
85 , m_text(LineLayoutSVGInlineText(text)) | 117 , m_text(LineLayoutSVGInlineText(text)) |
86 , m_run(SVGTextMetrics::constructTextRun(m_text, 0, m_text.textLength(), m_t
ext.styleRef().direction())) | 118 , m_run(constructTextRun(m_text, 0, m_text.textLength(), m_text.styleRef().d
irection())) |
87 , m_bidiRun(nullptr) | 119 , m_bidiRun(nullptr) |
88 { | 120 { |
89 setupBidiRuns(); | 121 setupBidiRuns(); |
90 } | 122 } |
91 | 123 |
92 SVGTextMetricsCalculator::~SVGTextMetricsCalculator() | 124 SVGTextMetricsCalculator::~SVGTextMetricsCalculator() |
93 { | 125 { |
94 if (m_bidiRun) | 126 if (m_bidiRun) |
95 m_bidiResolver.runs().deleteRuns(); | 127 m_bidiResolver.runs().deleteRuns(); |
96 } | 128 } |
(...skipping 29 matching lines...) Expand all Loading... |
126 } | 158 } |
127 ASSERT(m_bidiRun); | 159 ASSERT(m_bidiRun); |
128 ASSERT(static_cast<int>(m_currentPosition) < m_bidiRun->stop()); | 160 ASSERT(static_cast<int>(m_currentPosition) < m_bidiRun->stop()); |
129 } | 161 } |
130 | 162 |
131 unsigned positionInRun = m_bidiRun ? m_currentPosition - m_bidiRun->start()
: m_currentPosition; | 163 unsigned positionInRun = m_bidiRun ? m_currentPosition - m_bidiRun->start()
: m_currentPosition; |
132 if (positionInRun >= m_subrunRanges.size()) { | 164 if (positionInRun >= m_subrunRanges.size()) { |
133 unsigned subrunStart = m_bidiRun ? m_bidiRun->start() : 0; | 165 unsigned subrunStart = m_bidiRun ? m_bidiRun->start() : 0; |
134 unsigned subrunEnd = m_bidiRun ? m_bidiRun->stop() : m_run.charactersLen
gth(); | 166 unsigned subrunEnd = m_bidiRun ? m_bidiRun->stop() : m_run.charactersLen
gth(); |
135 TextDirection subrunDirection = m_bidiRun ? m_bidiRun->direction() : m_t
ext.styleRef().direction(); | 167 TextDirection subrunDirection = m_bidiRun ? m_bidiRun->direction() : m_t
ext.styleRef().direction(); |
136 TextRun subRun = SVGTextMetrics::constructTextRun(m_text, subrunStart, s
ubrunEnd - subrunStart, subrunDirection); | 168 TextRun subRun = constructTextRun(m_text, subrunStart, subrunEnd - subru
nStart, subrunDirection); |
137 m_subrunRanges = m_text.scaledFont().individualCharacterRanges(subRun); | 169 m_subrunRanges = m_text.scaledFont().individualCharacterRanges(subRun); |
138 | 170 |
139 // TODO(pdr): We only have per-glyph data so we need to synthesize per- | 171 // TODO(pdr): We only have per-glyph data so we need to synthesize per- |
140 // grapheme data. E.g., if 'fi' is shaped into a single glyph, we do not | 172 // grapheme data. E.g., if 'fi' is shaped into a single glyph, we do not |
141 // know the 'i' position. The code below synthesizes an average glyph | 173 // know the 'i' position. The code below synthesizes an average glyph |
142 // width when characters share a position. This will incorrectly split | 174 // width when characters share a position. This will incorrectly split |
143 // combining diacritics. See: https://crbug.com/473476. | 175 // combining diacritics. See: https://crbug.com/473476. |
144 unsigned distributeCount = 0; | 176 unsigned distributeCount = 0; |
145 for (int rangeIndex = static_cast<int>(m_subrunRanges.size()) - 1; range
Index >= 0; --rangeIndex) { | 177 for (int rangeIndex = static_cast<int>(m_subrunRanges.size()) - 1; range
Index >= 0; --rangeIndex) { |
146 CharacterRange& currentRange = m_subrunRanges[rangeIndex]; | 178 CharacterRange& currentRange = m_subrunRanges[rangeIndex]; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 return; | 247 return; |
216 const SVGCharacterDataMap::const_iterator it = allCharactersMap->find(va
lueListPosition); | 248 const SVGCharacterDataMap::const_iterator it = allCharactersMap->find(va
lueListPosition); |
217 if (it != allCharactersMap->end()) | 249 if (it != allCharactersMap->end()) |
218 attributes.characterDataMap().set(currentTextPosition, it->value); | 250 attributes.characterDataMap().set(currentTextPosition, it->value); |
219 } | 251 } |
220 | 252 |
221 SVGTextLayoutAttributes& attributes; | 253 SVGTextLayoutAttributes& attributes; |
222 const SVGCharacterDataMap* allCharactersMap; | 254 const SVGCharacterDataMap* allCharactersMap; |
223 }; | 255 }; |
224 | 256 |
225 static void walkInlineText(LayoutSVGInlineText* text, TreeWalkTextState& textSta
te, UpdateAttributes* attributesToUpdate = nullptr) | 257 void walkInlineText(LayoutSVGInlineText* text, TreeWalkTextState& textState, Upd
ateAttributes* attributesToUpdate = nullptr) |
226 { | 258 { |
227 if (attributesToUpdate) | 259 if (attributesToUpdate) |
228 attributesToUpdate->clearExistingAttributes(); | 260 attributesToUpdate->clearExistingAttributes(); |
229 | 261 |
230 if (!text->textLength()) | 262 if (!text->textLength()) |
231 return; | 263 return; |
232 | 264 |
233 // TODO(pdr): This loop is too tightly coupled to SVGTextMetricsCalculator. | 265 // TODO(pdr): This loop is too tightly coupled to SVGTextMetricsCalculator. |
234 // We should refactor SVGTextMetricsCalculator to be a simple bidi run | 266 // We should refactor SVGTextMetricsCalculator to be a simple bidi run |
235 // iterator and move all subrun logic to a single function. | 267 // iterator and move all subrun logic to a single function. |
(...skipping 17 matching lines...) Expand all Loading... |
253 } | 285 } |
254 | 286 |
255 if (calculator.currentCharacterStartsSurrogatePair()) | 287 if (calculator.currentCharacterStartsSurrogatePair()) |
256 surrogatePairCharacters++; | 288 surrogatePairCharacters++; |
257 textState.lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace; | 289 textState.lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace; |
258 } while (calculator.advancePosition()); | 290 } while (calculator.advancePosition()); |
259 | 291 |
260 textState.valueListPosition += calculator.currentPosition() - skippedWhitesp
ace; | 292 textState.valueListPosition += calculator.currentPosition() - skippedWhitesp
ace; |
261 } | 293 } |
262 | 294 |
263 static void walkTree(LayoutSVGText* start, LayoutSVGInlineText* stopAtText, SVGC
haracterDataMap* allCharactersMap = nullptr) | 295 void walkTree(LayoutSVGText* start, LayoutSVGInlineText* stopAtText, SVGCharacte
rDataMap* allCharactersMap = nullptr) |
264 { | 296 { |
265 TreeWalkTextState textState; | 297 TreeWalkTextState textState; |
266 LayoutObject* child = start->firstChild(); | 298 LayoutObject* child = start->firstChild(); |
267 while (child) { | 299 while (child) { |
268 if (child->isSVGInlineText()) { | 300 if (child->isSVGInlineText()) { |
269 LayoutSVGInlineText* text = toLayoutSVGInlineText(child); | 301 LayoutSVGInlineText* text = toLayoutSVGInlineText(child); |
270 OwnPtr<UpdateAttributes> attributesToUpdate = nullptr; | 302 OwnPtr<UpdateAttributes> attributesToUpdate = nullptr; |
271 if (!stopAtText || stopAtText == text) | 303 if (!stopAtText || stopAtText == text) |
272 attributesToUpdate = adoptPtr(new UpdateAttributes(*text->layout
Attributes(), allCharactersMap)); | 304 attributesToUpdate = adoptPtr(new UpdateAttributes(*text->layout
Attributes(), allCharactersMap)); |
273 walkInlineText(text, textState, attributesToUpdate.get()); | 305 walkInlineText(text, textState, attributesToUpdate.get()); |
274 if (stopAtText == text) | 306 if (stopAtText == text) |
275 return; | 307 return; |
276 } else if (child->isSVGInline()) { | 308 } else if (child->isSVGInline()) { |
277 // Visit children of text content elements. | 309 // Visit children of text content elements. |
278 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild
()) { | 310 if (LayoutObject* inlineChild = toLayoutSVGInline(child)->firstChild
()) { |
279 child = inlineChild; | 311 child = inlineChild; |
280 continue; | 312 continue; |
281 } | 313 } |
282 } | 314 } |
283 child = child->nextInPreOrderAfterChildren(start); | 315 child = child->nextInPreOrderAfterChildren(start); |
284 } | 316 } |
285 } | 317 } |
286 | 318 |
| 319 } // namespace |
| 320 |
287 void SVGTextMetricsBuilder::measureTextLayoutObject(LayoutSVGInlineText* text) | 321 void SVGTextMetricsBuilder::measureTextLayoutObject(LayoutSVGInlineText* text) |
288 { | 322 { |
289 ASSERT(text); | 323 ASSERT(text); |
290 if (LayoutSVGText* textRoot = LayoutSVGText::locateLayoutSVGTextAncestor(tex
t)) | 324 if (LayoutSVGText* textRoot = LayoutSVGText::locateLayoutSVGTextAncestor(tex
t)) |
291 walkTree(textRoot, text); | 325 walkTree(textRoot, text); |
292 } | 326 } |
293 | 327 |
294 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR
oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) | 328 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR
oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) |
295 { | 329 { |
296 ASSERT(textRoot); | 330 ASSERT(textRoot); |
297 walkTree(textRoot, stopAtText, &allCharactersMap); | 331 walkTree(textRoot, stopAtText, &allCharactersMap); |
298 } | 332 } |
299 | 333 |
300 } // namespace blink | 334 } // namespace blink |
OLD | NEW |