OLD | NEW |
1 /* | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 * Copyright (c) 2012 Google Inc. All rights reserved. | 2 // Use of this source code is governed by a BSD-style license that can be |
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. | 3 // found in the LICENSE file. |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are | |
7 * met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above | |
12 * copyright notice, this list of conditions and the following disclaimer | |
13 * in the documentation and/or other materials provided with the | |
14 * distribution. | |
15 * * Neither the name of Google Inc. nor the names of its | |
16 * contributors may be used to endorse or promote products derived from | |
17 * this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 */ | |
31 | 4 |
32 #include "platform/fonts/shaping/ShapeResult.h" | 5 #include "platform/fonts/shaping/ShapeResultBuffer.h" |
33 | 6 |
34 #include "platform/fonts/Font.h" | 7 #include "platform/fonts/Character.h" |
35 #include "platform/fonts/GlyphBuffer.h" | 8 #include "platform/fonts/GlyphBuffer.h" |
| 9 #include "platform/fonts/SimpleFontData.h" |
36 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" | 10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" |
| 11 #include "platform/geometry/FloatPoint.h" |
37 #include "platform/text/TextBreakIterator.h" | 12 #include "platform/text/TextBreakIterator.h" |
| 13 #include "platform/text/TextDirection.h" |
38 | 14 |
39 namespace blink { | 15 namespace blink { |
40 | 16 |
41 float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const | 17 namespace { |
42 { | |
43 ASSERT(offset < m_numCharacters); | |
44 if (rtl()) | |
45 offset = m_numCharacters - offset - 1; | |
46 return xPositionForOffset(offset); | |
47 } | |
48 | 18 |
49 float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const | 19 inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance, hb_directi
on_t direction, |
50 { | 20 const SimpleFontData* fontData, const HarfBuzzRunGlyphData& glyphData) |
51 ASSERT(offset <= m_numCharacters); | |
52 const unsigned numGlyphs = m_glyphData.size(); | |
53 unsigned glyphIndex = 0; | |
54 float position = 0; | |
55 if (rtl()) { | |
56 while (glyphIndex < numGlyphs && m_glyphData[glyphIndex].characterIndex
> offset) { | |
57 position += m_glyphData[glyphIndex].advance; | |
58 ++glyphIndex; | |
59 } | |
60 // For RTL, we need to return the right side boundary of the character. | |
61 // Add advance of glyphs which are part of the character. | |
62 while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIn
dex == m_glyphData[glyphIndex + 1].characterIndex) { | |
63 position += m_glyphData[glyphIndex].advance; | |
64 ++glyphIndex; | |
65 } | |
66 position += m_glyphData[glyphIndex].advance; | |
67 } else { | |
68 while (glyphIndex < numGlyphs && m_glyphData[glyphIndex].characterIndex
< offset) { | |
69 position += m_glyphData[glyphIndex].advance; | |
70 ++glyphIndex; | |
71 } | |
72 } | |
73 return position; | |
74 } | |
75 | |
76 int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const | |
77 { | |
78 ASSERT(targetX <= m_width); | |
79 const unsigned numGlyphs = m_glyphData.size(); | |
80 float currentX = 0; | |
81 float currentAdvance = m_glyphData[0].advance; | |
82 unsigned glyphIndex = 0; | |
83 | |
84 // Sum up advances that belong to the first character. | |
85 while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex
== m_glyphData[glyphIndex + 1].characterIndex) | |
86 currentAdvance += m_glyphData[++glyphIndex].advance; | |
87 currentAdvance = currentAdvance / 2.0; | |
88 if (targetX <= currentAdvance) | |
89 return rtl() ? m_numCharacters : 0; | |
90 | |
91 currentX = currentAdvance; | |
92 ++glyphIndex; | |
93 while (glyphIndex < numGlyphs) { | |
94 unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex
; | |
95 float prevAdvance = currentAdvance; | |
96 currentAdvance = m_glyphData[glyphIndex].advance; | |
97 while (glyphIndex < numGlyphs - 1 && m_glyphData[glyphIndex].characterIn
dex == m_glyphData[glyphIndex + 1].characterIndex) | |
98 currentAdvance += m_glyphData[++glyphIndex].advance; | |
99 currentAdvance = currentAdvance / 2.0; | |
100 float nextX = currentX + prevAdvance + currentAdvance; | |
101 if (currentX <= targetX && targetX <= nextX) | |
102 return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characte
rIndex; | |
103 currentX = nextX; | |
104 ++glyphIndex; | |
105 } | |
106 | |
107 return rtl() ? 0 : m_numCharacters; | |
108 } | |
109 | |
110 void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index, | |
111 uint16_t glyphId, float advance, float offsetX, float offsetY) | |
112 { | |
113 HarfBuzzRunGlyphData& data = m_glyphData[index]; | |
114 data.glyph = glyphId; | |
115 data.advance = advance; | |
116 data.offset = FloatSize(offsetX, offsetY); | |
117 } | |
118 | |
119 ShapeResult::ShapeResult(const Font* font, unsigned numCharacters, TextDirection
direction) | |
120 : m_width(0) | |
121 , m_primaryFont(const_cast<SimpleFontData*>(font->primaryFont())) | |
122 , m_numCharacters(numCharacters) | |
123 , m_numGlyphs(0) | |
124 , m_direction(direction) | |
125 , m_hasVerticalOffsets(0) | |
126 { | |
127 } | |
128 | |
129 ShapeResult::~ShapeResult() | |
130 { | |
131 } | |
132 | |
133 static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance, | |
134 hb_direction_t direction, const SimpleFontData* fontData, | |
135 const HarfBuzzRunGlyphData& glyphData) | |
136 { | 21 { |
137 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) | 22 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) |
138 ? FloatPoint(advance, 0) | 23 ? FloatPoint(advance, 0) |
139 : FloatPoint(0, advance); | 24 : FloatPoint(0, advance); |
140 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); | 25 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); |
141 } | 26 } |
142 | 27 |
| 28 inline void addEmphasisMark(GlyphBuffer* buffer, |
| 29 const GlyphData* emphasisData, FloatPoint glyphCenter, |
| 30 float midGlyphOffset) |
| 31 { |
| 32 ASSERT(buffer); |
| 33 ASSERT(emphasisData); |
| 34 |
| 35 const SimpleFontData* emphasisFontData = emphasisData->fontData; |
| 36 ASSERT(emphasisFontData); |
| 37 |
| 38 bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright() |
| 39 && emphasisFontData->verticalData(); |
| 40 |
| 41 if (!isVertical) { |
| 42 buffer->add(emphasisData->glyph, emphasisFontData, |
| 43 midGlyphOffset - glyphCenter.x()); |
| 44 } else { |
| 45 buffer->add(emphasisData->glyph, emphasisFontData, |
| 46 FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y())); |
| 47 } |
| 48 } |
| 49 |
| 50 inline unsigned countGraphemesInCluster(const UChar* str, unsigned strLength, |
| 51 uint16_t startIndex, uint16_t endIndex) |
| 52 { |
| 53 if (startIndex > endIndex) { |
| 54 uint16_t tempIndex = startIndex; |
| 55 startIndex = endIndex; |
| 56 endIndex = tempIndex; |
| 57 } |
| 58 uint16_t length = endIndex - startIndex; |
| 59 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength); |
| 60 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde
x], length); |
| 61 |
| 62 int cursorPos = cursorPosIterator->current(); |
| 63 int numGraphemes = -1; |
| 64 while (0 <= cursorPos) { |
| 65 cursorPos = cursorPosIterator->next(); |
| 66 numGraphemes++; |
| 67 } |
| 68 return std::max(0, numGraphemes); |
| 69 } |
| 70 |
| 71 } // anonymous namespace |
| 72 |
143 template<TextDirection direction> | 73 template<TextDirection direction> |
144 float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, | 74 float ShapeResultBuffer::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, |
145 const RunInfo* run, float initialAdvance, unsigned from, unsigned to, | 75 const ShapeResult::RunInfo* run, float initialAdvance, unsigned from, unsign
ed to, |
146 unsigned runOffset) | 76 unsigned runOffset) |
147 { | 77 { |
148 if (!run) | 78 if (!run) |
149 return 0; | 79 return 0; |
150 float advanceSoFar = initialAdvance; | 80 float advanceSoFar = initialAdvance; |
151 const unsigned numGlyphs = run->m_glyphData.size(); | 81 const unsigned numGlyphs = run->m_glyphData.size(); |
152 for (unsigned i = 0; i < numGlyphs; ++i) { | 82 for (unsigned i = 0; i < numGlyphs; ++i) { |
153 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; | 83 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; |
154 uint16_t currentCharacterIndex = run->m_startIndex + | 84 uint16_t currentCharacterIndex = run->m_startIndex + |
155 glyphData.characterIndex + runOffset; | 85 glyphData.characterIndex + runOffset; |
156 if ((direction == RTL && currentCharacterIndex >= to) | 86 if ((direction == RTL && currentCharacterIndex >= to) |
157 || (direction == LTR && currentCharacterIndex < from)) { | 87 || (direction == LTR && currentCharacterIndex < from)) { |
158 advanceSoFar += glyphData.advance; | 88 advanceSoFar += glyphData.advance; |
159 } else if ((direction == RTL && currentCharacterIndex >= from) | 89 } else if ((direction == RTL && currentCharacterIndex >= from) |
160 || (direction == LTR && currentCharacterIndex < to)) { | 90 || (direction == LTR && currentCharacterIndex < to)) { |
161 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, | 91 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, |
162 run->m_fontData.get(), glyphData); | 92 run->m_fontData.get(), glyphData); |
163 advanceSoFar += glyphData.advance; | 93 advanceSoFar += glyphData.advance; |
164 } | 94 } |
165 } | 95 } |
166 return advanceSoFar - initialAdvance; | 96 return advanceSoFar - initialAdvance; |
167 } | 97 } |
168 | 98 |
169 static inline unsigned countGraphemesInCluster(const UChar* str, | 99 float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuf
fer, |
170 unsigned strLength, uint16_t startIndex, uint16_t endIndex) | 100 const ShapeResult::RunInfo* run, const TextRun& textRun, const GlyphData* em
phasisData, |
171 { | |
172 if (startIndex > endIndex) { | |
173 uint16_t tempIndex = startIndex; | |
174 startIndex = endIndex; | |
175 endIndex = tempIndex; | |
176 } | |
177 uint16_t length = endIndex - startIndex; | |
178 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength); | |
179 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde
x], length); | |
180 | |
181 int cursorPos = cursorPosIterator->current(); | |
182 int numGraphemes = -1; | |
183 while (0 <= cursorPos) { | |
184 cursorPos = cursorPosIterator->next(); | |
185 numGraphemes++; | |
186 } | |
187 return std::max(0, numGraphemes); | |
188 } | |
189 | |
190 static inline void addEmphasisMark(GlyphBuffer* buffer, | |
191 const GlyphData* emphasisData, FloatPoint glyphCenter, | |
192 float midGlyphOffset) | |
193 { | |
194 ASSERT(buffer); | |
195 ASSERT(emphasisData); | |
196 | |
197 const SimpleFontData* emphasisFontData = emphasisData->fontData; | |
198 ASSERT(emphasisFontData); | |
199 | |
200 bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright() | |
201 && emphasisFontData->verticalData(); | |
202 | |
203 if (!isVertical) { | |
204 buffer->add(emphasisData->glyph, emphasisFontData, | |
205 midGlyphOffset - glyphCenter.x()); | |
206 } else { | |
207 buffer->add(emphasisData->glyph, emphasisFontData, | |
208 FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y())); | |
209 } | |
210 } | |
211 | |
212 float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer, | |
213 const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData, | |
214 float initialAdvance, unsigned from, unsigned to, unsigned runOffset) | 101 float initialAdvance, unsigned from, unsigned to, unsigned runOffset) |
215 { | 102 { |
216 if (!run) | 103 if (!run) |
217 return 0; | 104 return 0; |
218 | 105 |
219 unsigned graphemesInCluster = 1; | 106 unsigned graphemesInCluster = 1; |
220 float clusterAdvance = 0; | 107 float clusterAdvance = 0; |
221 | 108 |
222 FloatPoint glyphCenter = emphasisData->fontData-> | 109 FloatPoint glyphCenter = emphasisData->fontData-> |
223 boundsForGlyph(emphasisData->glyph).center(); | 110 boundsForGlyph(emphasisData->glyph).center(); |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
275 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, adva
nceSoFar + glyphAdvanceX / 2); | 162 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, adva
nceSoFar + glyphAdvanceX / 2); |
276 advanceSoFar += glyphAdvanceX; | 163 advanceSoFar += glyphAdvanceX; |
277 } | 164 } |
278 clusterStart = clusterEnd; | 165 clusterStart = clusterEnd; |
279 clusterAdvance = 0; | 166 clusterAdvance = 0; |
280 } | 167 } |
281 } | 168 } |
282 return advanceSoFar - initialAdvance; | 169 return advanceSoFar - initialAdvance; |
283 } | 170 } |
284 | 171 |
285 float ShapeResult::fillFastHorizontalGlyphBuffer(const ShapeResultBuffer& result
sBuffer, | 172 float ShapeResultBuffer::fillFastHorizontalGlyphBuffer(GlyphBuffer* glyphBuffer, |
286 GlyphBuffer* glyphBuffer, TextDirection dir) | 173 TextDirection dir) const |
287 { | 174 { |
288 ASSERT(!resultsBuffer.hasVerticalOffsets()); | 175 ASSERT(!hasVerticalOffsets()); |
289 | 176 |
290 const auto& results = resultsBuffer.results(); | |
291 float advance = 0; | 177 float advance = 0; |
292 | 178 |
293 for (unsigned i = 0; i < results.size(); ++i) { | 179 for (unsigned i = 0; i < m_results.size(); ++i) { |
294 const auto& wordResult = | 180 const auto& wordResult = |
295 isLeftToRightDirection(dir) ? results[i] : results[results.size() -
1 - i]; | 181 isLeftToRightDirection(dir) ? m_results[i] : m_results[m_results.siz
e() - 1 - i]; |
296 ASSERT(!wordResult->hasVerticalOffsets()); | 182 ASSERT(!wordResult->hasVerticalOffsets()); |
297 | 183 |
298 for (const auto& run : wordResult->m_runs) { | 184 for (const auto& run : wordResult->m_runs) { |
299 ASSERT(run); | 185 ASSERT(run); |
300 ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction)); | 186 ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction)); |
301 | 187 |
302 for (const auto& glyphData : run->m_glyphData) { | 188 for (const auto& glyphData : run->m_glyphData) { |
303 ASSERT(!glyphData.offset.height()); | 189 ASSERT(!glyphData.offset.height()); |
304 | 190 |
305 glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), | 191 glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), |
306 advance + glyphData.offset.width()); | 192 advance + glyphData.offset.width()); |
307 advance += glyphData.advance; | 193 advance += glyphData.advance; |
308 } | 194 } |
309 } | 195 } |
310 } | 196 } |
311 | 197 |
312 ASSERT(!glyphBuffer->hasVerticalOffsets()); | 198 ASSERT(!glyphBuffer->hasVerticalOffsets()); |
313 | 199 |
314 return advance; | 200 return advance; |
315 } | 201 } |
316 | 202 |
317 float ShapeResult::fillGlyphBuffer(const ShapeResultBuffer& resultsBuffer, | 203 float ShapeResultBuffer::fillGlyphBuffer(GlyphBuffer* glyphBuffer, const TextRun
& textRun, |
318 GlyphBuffer* glyphBuffer, const TextRun& textRun, | 204 unsigned from, unsigned to) const |
319 unsigned from, unsigned to) | |
320 { | 205 { |
321 // Fast path: full run with no vertical offsets | 206 // Fast path: full run with no vertical offsets |
322 if (!from && to == static_cast<unsigned>(textRun.length()) && !resultsBuffer
.hasVerticalOffsets()) | 207 if (!from && to == static_cast<unsigned>(textRun.length()) && !hasVerticalOf
fsets()) |
323 return fillFastHorizontalGlyphBuffer(resultsBuffer, glyphBuffer, textRun
.direction()); | 208 return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun.direction()); |
324 | 209 |
325 const auto& results = resultsBuffer.results(); | |
326 float advance = 0; | 210 float advance = 0; |
327 | 211 |
328 if (textRun.rtl()) { | 212 if (textRun.rtl()) { |
329 unsigned wordOffset = textRun.length(); | 213 unsigned wordOffset = textRun.length(); |
330 for (unsigned j = 0; j < results.size(); j++) { | 214 for (unsigned j = 0; j < m_results.size(); j++) { |
331 unsigned resolvedIndex = results.size() - 1 - j; | 215 unsigned resolvedIndex = m_results.size() - 1 - j; |
332 const RefPtr<ShapeResult>& wordResult = results[resolvedIndex]; | 216 const RefPtr<ShapeResult>& wordResult = m_results[resolvedIndex]; |
333 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 217 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
334 advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer, | 218 advance += fillGlyphBufferForRun<RTL>(glyphBuffer, |
335 wordResult->m_runs[i].get(), advance, from, to, | 219 wordResult->m_runs[i].get(), advance, from, to, |
336 wordOffset - wordResult->numCharacters()); | 220 wordOffset - wordResult->numCharacters()); |
337 } | 221 } |
338 wordOffset -= wordResult->numCharacters(); | 222 wordOffset -= wordResult->numCharacters(); |
339 } | 223 } |
340 } else { | 224 } else { |
341 unsigned wordOffset = 0; | 225 unsigned wordOffset = 0; |
342 for (unsigned j = 0; j < results.size(); j++) { | 226 for (unsigned j = 0; j < m_results.size(); j++) { |
343 const RefPtr<ShapeResult>& wordResult = results[j]; | 227 const RefPtr<ShapeResult>& wordResult = m_results[j]; |
344 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 228 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
345 advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer, | 229 advance += fillGlyphBufferForRun<LTR>(glyphBuffer, |
346 wordResult->m_runs[i].get(), advance, from, to, wordOffset); | 230 wordResult->m_runs[i].get(), advance, from, to, wordOffset); |
347 } | 231 } |
348 wordOffset += wordResult->numCharacters(); | 232 wordOffset += wordResult->numCharacters(); |
349 } | 233 } |
350 } | 234 } |
351 | 235 |
352 return advance; | 236 return advance; |
353 } | 237 } |
354 | 238 |
355 float ShapeResult::fillGlyphBufferForTextEmphasis(const ShapeResultBuffer& resul
tsBuffer, | 239 float ShapeResultBuffer::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer
, |
356 GlyphBuffer* glyphBuffer, const TextRun& textRun, const GlyphData* emphasisD
ata, | 240 const TextRun& textRun, const GlyphData* emphasisData, unsigned from, unsign
ed to) const |
357 unsigned from, unsigned to) | |
358 { | 241 { |
359 const auto& results = resultsBuffer.results(); | |
360 float advance = 0; | 242 float advance = 0; |
361 unsigned wordOffset = textRun.rtl() ? textRun.length() : 0; | 243 unsigned wordOffset = textRun.rtl() ? textRun.length() : 0; |
362 | 244 |
363 for (unsigned j = 0; j < results.size(); j++) { | 245 for (unsigned j = 0; j < m_results.size(); j++) { |
364 unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j; | 246 unsigned resolvedIndex = textRun.rtl() ? m_results.size() - 1 - j : j; |
365 const RefPtr<ShapeResult>& wordResult = results[resolvedIndex]; | 247 const RefPtr<ShapeResult>& wordResult = m_results[resolvedIndex]; |
366 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 248 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
367 unsigned resolvedOffset = wordOffset - | 249 unsigned resolvedOffset = wordOffset - |
368 (textRun.rtl() ? wordResult->numCharacters() : 0); | 250 (textRun.rtl() ? wordResult->numCharacters() : 0); |
369 advance += wordResult->fillGlyphBufferForTextEmphasisRun( | 251 advance += fillGlyphBufferForTextEmphasisRun( |
370 glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData, | 252 glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData, |
371 advance, from, to, resolvedOffset); | 253 advance, from, to, resolvedOffset); |
372 } | 254 } |
373 wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1); | 255 wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1); |
374 } | 256 } |
375 | 257 |
376 return advance; | 258 return advance; |
377 } | 259 } |
378 | 260 |
379 FloatRect ShapeResult::selectionRect(const ShapeResultBuffer& resultsBuffer, | 261 FloatRect ShapeResultBuffer::selectionRect(TextDirection direction, float totalW
idth, |
380 TextDirection direction, float totalWidth, const FloatPoint& point, | 262 const FloatPoint& point, int height, unsigned absoluteFrom, unsigned absolut
eTo) const |
381 int height, unsigned absoluteFrom, unsigned absoluteTo) | |
382 { | 263 { |
383 const auto& results = resultsBuffer.results(); | |
384 float currentX = 0; | 264 float currentX = 0; |
385 float fromX = 0; | 265 float fromX = 0; |
386 float toX = 0; | 266 float toX = 0; |
387 bool foundFromX = false; | 267 bool foundFromX = false; |
388 bool foundToX = false; | 268 bool foundToX = false; |
389 | 269 |
390 if (direction == RTL) | 270 if (direction == RTL) |
391 currentX = totalWidth; | 271 currentX = totalWidth; |
392 | 272 |
393 // The absoluteFrom and absoluteTo arguments represent the start/end offset | 273 // The absoluteFrom and absoluteTo arguments represent the start/end offset |
394 // for the entire run, from/to are continuously updated to be relative to | 274 // for the entire run, from/to are continuously updated to be relative to |
395 // the current word (ShapeResult instance). | 275 // the current word (ShapeResult instance). |
396 int from = absoluteFrom; | 276 int from = absoluteFrom; |
397 int to = absoluteTo; | 277 int to = absoluteTo; |
398 | 278 |
399 unsigned totalNumCharacters = 0; | 279 unsigned totalNumCharacters = 0; |
400 for (unsigned j = 0; j < results.size(); j++) { | 280 for (unsigned j = 0; j < m_results.size(); j++) { |
401 const RefPtr<ShapeResult> result = results[j]; | 281 const RefPtr<ShapeResult> result = m_results[j]; |
402 if (direction == RTL) { | 282 if (direction == RTL) { |
403 // Convert logical offsets to visual offsets, because results are in | 283 // Convert logical offsets to visual offsets, because results are in |
404 // logical order while runs are in visual order. | 284 // logical order while runs are in visual order. |
405 if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result
->numCharacters()) | 285 if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result
->numCharacters()) |
406 from = result->numCharacters() - from - 1; | 286 from = result->numCharacters() - from - 1; |
407 if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numC
haracters()) | 287 if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numC
haracters()) |
408 to = result->numCharacters() - to - 1; | 288 to = result->numCharacters() - to - 1; |
409 currentX -= result->width(); | 289 currentX -= result->width(); |
410 } | 290 } |
411 for (unsigned i = 0; i < result->m_runs.size(); i++) { | 291 for (unsigned i = 0; i < result->m_runs.size(); i++) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 toX = direction == RTL ? 0 : totalWidth; | 331 toX = direction == RTL ? 0 : totalWidth; |
452 | 332 |
453 // None of our runs is part of the selection, possibly invalid arguments. | 333 // None of our runs is part of the selection, possibly invalid arguments. |
454 if (!foundToX && !foundFromX) | 334 if (!foundToX && !foundFromX) |
455 fromX = toX = 0; | 335 fromX = toX = 0; |
456 if (fromX < toX) | 336 if (fromX < toX) |
457 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); | 337 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); |
458 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); | 338 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); |
459 } | 339 } |
460 | 340 |
461 size_t ShapeResult::byteSize() | 341 int ShapeResultBuffer::offsetForPosition(const TextRun& run, float targetX) cons
t |
462 { | 342 { |
463 size_t selfByteSize = sizeof(this); | |
464 for (unsigned i = 0; i < m_runs.size(); ++i) { | |
465 selfByteSize += m_runs[i]->byteSize(); | |
466 } | |
467 return selfByteSize; | |
468 } | |
469 | |
470 int ShapeResult::offsetForPosition(const ShapeResultBuffer& resultsBuffer, | |
471 const TextRun& run, float targetX) | |
472 { | |
473 const auto& results = resultsBuffer.results(); | |
474 unsigned totalOffset; | 343 unsigned totalOffset; |
475 if (run.rtl()) { | 344 if (run.rtl()) { |
476 totalOffset = run.length(); | 345 totalOffset = run.length(); |
477 for (unsigned i = results.size(); i; --i) { | 346 for (unsigned i = m_results.size(); i; --i) { |
478 const RefPtr<ShapeResult>& wordResult = results[i - 1]; | 347 const RefPtr<ShapeResult>& wordResult = m_results[i - 1]; |
479 if (!wordResult) | 348 if (!wordResult) |
480 continue; | 349 continue; |
481 totalOffset -= wordResult->numCharacters(); | 350 totalOffset -= wordResult->numCharacters(); |
482 if (targetX >= 0 && targetX <= wordResult->width()) { | 351 if (targetX >= 0 && targetX <= wordResult->width()) { |
483 int offsetForWord = wordResult->offsetForPosition(targetX); | 352 int offsetForWord = wordResult->offsetForPosition(targetX); |
484 return totalOffset + offsetForWord; | 353 return totalOffset + offsetForWord; |
485 } | 354 } |
486 targetX -= wordResult->width(); | 355 targetX -= wordResult->width(); |
487 } | 356 } |
488 } else { | 357 } else { |
489 totalOffset = 0; | 358 totalOffset = 0; |
490 for (const auto& wordResult : results) { | 359 for (const auto& wordResult : m_results) { |
491 if (!wordResult) | 360 if (!wordResult) |
492 continue; | 361 continue; |
493 int offsetForWord = wordResult->offsetForPosition(targetX); | 362 int offsetForWord = wordResult->offsetForPosition(targetX); |
494 ASSERT(offsetForWord >= 0); | 363 ASSERT(offsetForWord >= 0); |
495 totalOffset += offsetForWord; | 364 totalOffset += offsetForWord; |
496 if (targetX >= 0 && targetX <= wordResult->width()) | 365 if (targetX >= 0 && targetX <= wordResult->width()) |
497 return totalOffset; | 366 return totalOffset; |
498 targetX -= wordResult->width(); | 367 targetX -= wordResult->width(); |
499 } | 368 } |
500 } | 369 } |
501 return totalOffset; | 370 return totalOffset; |
502 } | 371 } |
503 | 372 |
504 int ShapeResult::offsetForPosition(float targetX) | |
505 { | |
506 int charactersSoFar = 0; | |
507 float currentX = 0; | |
508 | |
509 if (m_direction == RTL) { | |
510 charactersSoFar = m_numCharacters; | |
511 for (unsigned i = 0; i < m_runs.size(); ++i) { | |
512 if (!m_runs[i]) | |
513 continue; | |
514 charactersSoFar -= m_runs[i]->m_numCharacters; | |
515 float nextX = currentX + m_runs[i]->m_width; | |
516 float offsetForRun = targetX - currentX; | |
517 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) { | |
518 // The x value in question is within this script run. | |
519 const unsigned index = m_runs[i]->characterIndexForXPosition(off
setForRun); | |
520 return charactersSoFar + index; | |
521 } | |
522 currentX = nextX; | |
523 } | |
524 } else { | |
525 for (unsigned i = 0; i < m_runs.size(); ++i) { | |
526 if (!m_runs[i]) | |
527 continue; | |
528 float nextX = currentX + m_runs[i]->m_width; | |
529 float offsetForRun = targetX - currentX; | |
530 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) { | |
531 const unsigned index = m_runs[i]->characterIndexForXPosition(off
setForRun); | |
532 return charactersSoFar + index; | |
533 } | |
534 charactersSoFar += m_runs[i]->m_numCharacters; | |
535 currentX = nextX; | |
536 } | |
537 } | |
538 | |
539 return charactersSoFar; | |
540 } | |
541 | |
542 void ShapeResult::fallbackFonts(HashSet<const SimpleFontData*>* fallback) const | |
543 { | |
544 ASSERT(fallback); | |
545 ASSERT(m_primaryFont); | |
546 for (unsigned i = 0; i < m_runs.size(); ++i) { | |
547 if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont | |
548 && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont
.get())) { | |
549 fallback->add(m_runs[i]->m_fontData.get()); | |
550 } | |
551 } | |
552 } | |
553 | |
554 } // namespace blink | 373 } // namespace blink |
OLD | NEW |