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 static bool characterStartsSurrogatePair(const TextRun& run, unsigned index) | |
fs
2016/03/31 09:01:41
Nit: No 'static' needed here (in unnamed namespace
| |
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(LayoutSVGInlineText*); | 50 SVGTextMetricsCalculator(LayoutSVGInlineText*); |
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 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
327 walkTree(textRoot, text); | 348 walkTree(textRoot, text); |
328 } | 349 } |
329 | 350 |
330 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) | 351 void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(LayoutSVGText* textR oot, LayoutSVGInlineText* stopAtText, SVGCharacterDataMap& allCharactersMap) |
331 { | 352 { |
332 ASSERT(textRoot); | 353 ASSERT(textRoot); |
333 walkTree(textRoot, stopAtText, &allCharactersMap); | 354 walkTree(textRoot, stopAtText, &allCharactersMap); |
334 } | 355 } |
335 | 356 |
336 } // namespace blink | 357 } // namespace blink |
OLD | NEW |