Chromium Code Reviews| 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 |