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 18 matching lines...) Expand all Loading... |
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 { | 37 namespace { |
38 | 38 |
| 39 inline bool characterStartsSurrogatePair(const TextRun& run, unsigned index) |
| 40 { |
| 41 if (!U16_IS_LEAD(run[index])) |
| 42 return false; |
| 43 if (index + 1 >= static_cast<unsigned>(run.charactersLength())) |
| 44 return false; |
| 45 return U16_IS_TRAIL(run[index + 1]); |
| 46 } |
| 47 |
39 class SVGTextMetricsCalculator { | 48 class SVGTextMetricsCalculator { |
40 public: | 49 public: |
41 SVGTextMetricsCalculator(LineLayoutSVGInlineText); | 50 SVGTextMetricsCalculator(LineLayoutSVGInlineText); |
42 ~SVGTextMetricsCalculator(); | 51 ~SVGTextMetricsCalculator(); |
43 | 52 |
44 bool advancePosition(); | 53 bool advancePosition(); |
45 unsigned currentPosition() const { return m_currentPosition; } | 54 unsigned currentPosition() const { return m_currentPosition; } |
46 | 55 |
47 SVGTextMetrics currentCharacterMetrics(); | 56 SVGTextMetrics currentCharacterMetrics(); |
48 | 57 |
49 // TODO(pdr): Character-based iteration is ambiguous and error-prone. It | 58 // TODO(pdr): Character-based iteration is ambiguous and error-prone. It |
50 // should be unified under a single concept. See: https://crbug.com/593570 | 59 // should be unified under a single concept. See: https://crbug.com/593570 |
51 bool currentCharacterStartsSurrogatePair() const | 60 bool currentCharacterStartsSurrogatePair() const |
52 { | 61 { |
53 return U16_IS_LEAD(m_run[m_currentPosition]) && m_currentPosition + 1 <
characterCount() && U16_IS_TRAIL(m_run[m_currentPosition + 1]); | 62 return characterStartsSurrogatePair(m_run, m_currentPosition); |
54 } | 63 } |
55 bool currentCharacterIsWhiteSpace() const | 64 bool currentCharacterIsWhiteSpace() const |
56 { | 65 { |
57 return m_run[m_currentPosition] == ' '; | 66 return m_run[m_currentPosition] == ' '; |
58 } | 67 } |
59 unsigned characterCount() const | 68 unsigned characterCount() const |
60 { | 69 { |
61 return static_cast<unsigned>(m_run.charactersLength()); | 70 return static_cast<unsigned>(m_run.charactersLength()); |
62 } | 71 } |
63 | 72 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
151 } | 160 } |
152 m_bidiRun = bidiRuns.firstRun(); | 161 m_bidiRun = bidiRuns.firstRun(); |
153 } | 162 } |
154 | 163 |
155 bool SVGTextMetricsCalculator::advancePosition() | 164 bool SVGTextMetricsCalculator::advancePosition() |
156 { | 165 { |
157 m_currentPosition += currentCharacterStartsSurrogatePair() ? 2 : 1; | 166 m_currentPosition += currentCharacterStartsSurrogatePair() ? 2 : 1; |
158 return m_currentPosition < characterCount(); | 167 return m_currentPosition < characterCount(); |
159 } | 168 } |
160 | 169 |
| 170 // TODO(pdr): We only have per-glyph data so we need to synthesize per-grapheme |
| 171 // data. E.g., if 'fi' is shaped into a single glyph, we do not know the 'i' |
| 172 // position. The code below synthesizes an average glyph width when characters |
| 173 // share a single position. This will incorrectly split combining diacritics. |
| 174 // See: https://crbug.com/473476. |
| 175 static void synthesizeGraphemeWidths(const TextRun& run, Vector<CharacterRange>&
ranges) |
| 176 { |
| 177 unsigned distributeCount = 0; |
| 178 for (int rangeIndex = static_cast<int>(ranges.size()) - 1; rangeIndex >= 0;
--rangeIndex) { |
| 179 CharacterRange& currentRange = ranges[rangeIndex]; |
| 180 if (currentRange.width() == 0) { |
| 181 distributeCount++; |
| 182 } else if (distributeCount != 0) { |
| 183 // Only count surrogate pairs as a single character. |
| 184 bool surrogatePair = characterStartsSurrogatePair(run, rangeIndex); |
| 185 if (!surrogatePair) |
| 186 distributeCount++; |
| 187 |
| 188 float newWidth = currentRange.width() / distributeCount; |
| 189 currentRange.end = currentRange.start + newWidth; |
| 190 float lastEndPosition = currentRange.end; |
| 191 for (unsigned distribute = 1; distribute < distributeCount; distribu
te++) { |
| 192 // This surrogate pair check will skip processing of the second |
| 193 // character forming the surrogate pair. |
| 194 unsigned distributeIndex = rangeIndex + distribute + (surrogateP
air ? 1 : 0); |
| 195 ranges[distributeIndex].start = lastEndPosition; |
| 196 ranges[distributeIndex].end = lastEndPosition + newWidth; |
| 197 lastEndPosition = ranges[distributeIndex].end; |
| 198 } |
| 199 |
| 200 distributeCount = 0; |
| 201 } |
| 202 } |
| 203 } |
| 204 |
161 unsigned SVGTextMetricsCalculator::updateSubrunRangesForCurrentPosition() | 205 unsigned SVGTextMetricsCalculator::updateSubrunRangesForCurrentPosition() |
162 { | 206 { |
163 ASSERT(m_bidiRun); | 207 ASSERT(m_bidiRun); |
164 if (m_currentPosition >= static_cast<unsigned>(m_bidiRun->stop())) { | 208 if (m_currentPosition >= static_cast<unsigned>(m_bidiRun->stop())) { |
165 m_bidiRun = m_bidiRun->next(); | 209 m_bidiRun = m_bidiRun->next(); |
166 // Ensure new subrange ranges are computed below. | 210 // Ensure new subrange ranges are computed below. |
167 m_subrunRanges.clear(); | 211 m_subrunRanges.clear(); |
168 } | 212 } |
169 ASSERT(m_bidiRun); | 213 ASSERT(m_bidiRun); |
170 ASSERT(static_cast<int>(m_currentPosition) < m_bidiRun->stop()); | 214 ASSERT(static_cast<int>(m_currentPosition) < m_bidiRun->stop()); |
171 | 215 |
172 unsigned positionInRun = m_currentPosition - m_bidiRun->start(); | 216 unsigned positionInRun = m_currentPosition - m_bidiRun->start(); |
173 if (positionInRun >= m_subrunRanges.size()) { | 217 if (positionInRun >= m_subrunRanges.size()) { |
174 TextRun subRun = constructTextRun(m_text, | 218 TextRun subRun = constructTextRun(m_text, m_bidiRun->start(), |
175 m_bidiRun->start(), m_bidiRun->stop() - m_bidiRun->start(), m_bidiRu
n->direction()); | 219 m_bidiRun->stop() - m_bidiRun->start(), m_bidiRun->direction()); |
176 m_subrunRanges = m_text.scaledFont().individualCharacterRanges(subRun); | 220 m_subrunRanges = m_text.scaledFont().individualCharacterRanges(subRun); |
177 | 221 synthesizeGraphemeWidths(subRun, m_subrunRanges); |
178 // TODO(pdr): We only have per-glyph data so we need to synthesize per- | |
179 // grapheme data. E.g., if 'fi' is shaped into a single glyph, we do not | |
180 // know the 'i' position. The code below synthesizes an average glyph | |
181 // width when characters share a position. This will incorrectly split | |
182 // combining diacritics. See: https://crbug.com/473476. | |
183 unsigned distributeCount = 0; | |
184 for (int rangeIndex = static_cast<int>(m_subrunRanges.size()) - 1; range
Index >= 0; --rangeIndex) { | |
185 CharacterRange& currentRange = m_subrunRanges[rangeIndex]; | |
186 if (currentRange.width() == 0) { | |
187 distributeCount++; | |
188 } else if (distributeCount != 0) { | |
189 distributeCount++; | |
190 float newWidth = currentRange.width() / distributeCount; | |
191 currentRange.end = currentRange.start + newWidth; | |
192 for (unsigned distribute = 1; distribute < distributeCount; dist
ribute++) { | |
193 unsigned distributeIndex = rangeIndex + distribute; | |
194 float newStartPosition = m_subrunRanges[distributeIndex - 1]
.end; | |
195 m_subrunRanges[distributeIndex].start = newStartPosition; | |
196 m_subrunRanges[distributeIndex].end = newStartPosition + new
Width; | |
197 } | |
198 distributeCount = 0; | |
199 } | |
200 } | |
201 } | 222 } |
202 | 223 |
203 ASSERT(m_subrunRanges.size() && positionInRun < m_subrunRanges.size()); | 224 ASSERT(m_subrunRanges.size() && positionInRun < m_subrunRanges.size()); |
204 return positionInRun; | 225 return positionInRun; |
205 } | 226 } |
206 | 227 |
207 SVGTextMetrics SVGTextMetricsCalculator::currentCharacterMetrics() | 228 SVGTextMetrics SVGTextMetricsCalculator::currentCharacterMetrics() |
208 { | 229 { |
209 unsigned currentSubrunPosition = updateSubrunRangesForCurrentPosition(); | 230 unsigned currentSubrunPosition = updateSubrunRangesForCurrentPosition(); |
210 unsigned length = currentCharacterStartsSurrogatePair() ? 2 : 1; | 231 unsigned length = currentCharacterStartsSurrogatePair() ? 2 : 1; |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 walkTree(textRoot, text); | 349 walkTree(textRoot, text); |
329 } | 350 } |
330 | 351 |
331 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR
oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) | 352 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR
oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) |
332 { | 353 { |
333 ASSERT(textRoot); | 354 ASSERT(textRoot); |
334 walkTree(textRoot, stopAtText, &allCharactersMap); | 355 walkTree(textRoot, stopAtText, &allCharactersMap); |
335 } | 356 } |
336 | 357 |
337 } // namespace blink | 358 } // namespace blink |
OLD | NEW |