Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp

Issue 1561633002: Relocate ShapeResult's GlyphBuffer helpers to ShapeResultBuffer (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 Google Inc. All rights reserved. 2 * Copyright (c) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 14 matching lines...) Expand all
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32 #include "platform/fonts/shaping/ShapeResult.h" 32 #include "platform/fonts/shaping/ShapeResult.h"
33 33
34 #include "platform/fonts/Font.h" 34 #include "platform/fonts/Font.h"
35 #include "platform/fonts/GlyphBuffer.h"
36 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 35 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
37 #include "platform/text/TextBreakIterator.h"
38 36
39 namespace blink { 37 namespace blink {
40 38
41 float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const 39 float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const
42 { 40 {
43 ASSERT(offset < m_numCharacters); 41 ASSERT(offset < m_numCharacters);
44 if (rtl()) 42 if (rtl())
45 offset = m_numCharacters - offset - 1; 43 offset = m_numCharacters - offset - 1;
46 return xPositionForOffset(offset); 44 return xPositionForOffset(offset);
47 } 45 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 , m_numGlyphs(0) 121 , m_numGlyphs(0)
124 , m_direction(direction) 122 , m_direction(direction)
125 , m_hasVerticalOffsets(0) 123 , m_hasVerticalOffsets(0)
126 { 124 {
127 } 125 }
128 126
129 ShapeResult::~ShapeResult() 127 ShapeResult::~ShapeResult()
130 { 128 {
131 } 129 }
132 130
133 static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
134 hb_direction_t direction, const SimpleFontData* fontData,
135 const HarfBuzzRunGlyphData& glyphData)
136 {
137 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
138 ? FloatPoint(advance, 0)
139 : FloatPoint(0, advance);
140 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
141 }
142
143 template<TextDirection direction>
144 float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
145 const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
146 unsigned runOffset)
147 {
148 if (!run)
149 return 0;
150 float advanceSoFar = initialAdvance;
151 const unsigned numGlyphs = run->m_glyphData.size();
152 for (unsigned i = 0; i < numGlyphs; ++i) {
153 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
154 uint16_t currentCharacterIndex = run->m_startIndex +
155 glyphData.characterIndex + runOffset;
156 if ((direction == RTL && currentCharacterIndex >= to)
157 || (direction == LTR && currentCharacterIndex < from)) {
158 advanceSoFar += glyphData.advance;
159 } else if ((direction == RTL && currentCharacterIndex >= from)
160 || (direction == LTR && currentCharacterIndex < to)) {
161 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
162 run->m_fontData.get(), glyphData);
163 advanceSoFar += glyphData.advance;
164 }
165 }
166 return advanceSoFar - initialAdvance;
167 }
168
169 static inline unsigned countGraphemesInCluster(const UChar* str,
170 unsigned strLength, uint16_t startIndex, uint16_t endIndex)
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)
215 {
216 if (!run)
217 return 0;
218
219 unsigned graphemesInCluster = 1;
220 float clusterAdvance = 0;
221
222 FloatPoint glyphCenter = emphasisData->fontData->
223 boundsForGlyph(emphasisData->glyph).center();
224
225 TextDirection direction = textRun.direction();
226
227 // A "cluster" in this context means a cluster as it is used by HarfBuzz:
228 // The minimal group of characters and corresponding glyphs, that cannot be broken
229 // down further from a text shaping point of view.
230 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall y
231 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu sters,
232 // then linearly split the sum of corresponding glyph advances by the number of
233 // grapheme clusters in order to find positions for emphasis mark drawing.
234 uint16_t clusterStart = static_cast<uint16_t>(direction == RTL
235 ? run->m_startIndex + run->m_numCharacters + runOffset
236 : run->glyphToCharacterIndex(0) + runOffset);
237
238 float advanceSoFar = initialAdvance;
239 const unsigned numGlyphs = run->m_glyphData.size();
240 for (unsigned i = 0; i < numGlyphs; ++i) {
241 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
242 uint16_t currentCharacterIndex = run->m_startIndex + glyphData.character Index + runOffset;
243 bool isRunEnd = (i + 1 == numGlyphs);
244 bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) + ru nOffset != currentCharacterIndex);
245
246 if ((direction == RTL && currentCharacterIndex >= to) || (direction != R TL && currentCharacterIndex < from)) {
247 advanceSoFar += glyphData.advance;
248 direction == RTL ? --clusterStart : ++clusterStart;
249 continue;
250 }
251
252 clusterAdvance += glyphData.advance;
253
254 if (textRun.is8Bit()) {
255 float glyphAdvanceX = glyphData.advance;
256 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex] )) {
257 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceS oFar + glyphAdvanceX / 2);
258 }
259 advanceSoFar += glyphAdvanceX;
260 } else if (isClusterEnd) {
261 uint16_t clusterEnd;
262 if (direction == RTL)
263 clusterEnd = currentCharacterIndex;
264 else
265 clusterEnd = static_cast<uint16_t>(isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffs et);
266
267 graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
268 if (!graphemesInCluster || !clusterAdvance)
269 continue;
270
271 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
272 for (unsigned j = 0; j < graphemesInCluster; ++j) {
273 // Do not put emphasis marks on space, separator, and control ch aracters.
274 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIn dex]))
275 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, adva nceSoFar + glyphAdvanceX / 2);
276 advanceSoFar += glyphAdvanceX;
277 }
278 clusterStart = clusterEnd;
279 clusterAdvance = 0;
280 }
281 }
282 return advanceSoFar - initialAdvance;
283 }
284
285 float ShapeResult::fillFastHorizontalGlyphBuffer(const ShapeResultBuffer& result sBuffer,
286 GlyphBuffer* glyphBuffer, TextDirection dir)
287 {
288 ASSERT(!resultsBuffer.hasVerticalOffsets());
289
290 const auto& results = resultsBuffer.results();
291 float advance = 0;
292
293 for (unsigned i = 0; i < results.size(); ++i) {
294 const auto& wordResult =
295 isLeftToRightDirection(dir) ? results[i] : results[results.size() - 1 - i];
296 ASSERT(!wordResult->hasVerticalOffsets());
297
298 for (const auto& run : wordResult->m_runs) {
299 ASSERT(run);
300 ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction));
301
302 for (const auto& glyphData : run->m_glyphData) {
303 ASSERT(!glyphData.offset.height());
304
305 glyphBuffer->add(glyphData.glyph, run->m_fontData.get(),
306 advance + glyphData.offset.width());
307 advance += glyphData.advance;
308 }
309 }
310 }
311
312 ASSERT(!glyphBuffer->hasVerticalOffsets());
313
314 return advance;
315 }
316
317 float ShapeResult::fillGlyphBuffer(const ShapeResultBuffer& resultsBuffer,
318 GlyphBuffer* glyphBuffer, const TextRun& textRun,
319 unsigned from, unsigned to)
320 {
321 // Fast path: full run with no vertical offsets
322 if (!from && to == static_cast<unsigned>(textRun.length()) && !resultsBuffer .hasVerticalOffsets())
323 return fillFastHorizontalGlyphBuffer(resultsBuffer, glyphBuffer, textRun .direction());
324
325 const auto& results = resultsBuffer.results();
326 float advance = 0;
327
328 if (textRun.rtl()) {
329 unsigned wordOffset = textRun.length();
330 for (unsigned j = 0; j < results.size(); j++) {
331 unsigned resolvedIndex = results.size() - 1 - j;
332 const RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
333 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
334 advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
335 wordResult->m_runs[i].get(), advance, from, to,
336 wordOffset - wordResult->numCharacters());
337 }
338 wordOffset -= wordResult->numCharacters();
339 }
340 } else {
341 unsigned wordOffset = 0;
342 for (unsigned j = 0; j < results.size(); j++) {
343 const RefPtr<ShapeResult>& wordResult = results[j];
344 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
345 advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
346 wordResult->m_runs[i].get(), advance, from, to, wordOffset);
347 }
348 wordOffset += wordResult->numCharacters();
349 }
350 }
351
352 return advance;
353 }
354
355 float ShapeResult::fillGlyphBufferForTextEmphasis(const ShapeResultBuffer& resul tsBuffer,
356 GlyphBuffer* glyphBuffer, const TextRun& textRun, const GlyphData* emphasisD ata,
357 unsigned from, unsigned to)
358 {
359 const auto& results = resultsBuffer.results();
360 float advance = 0;
361 unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
362
363 for (unsigned j = 0; j < results.size(); j++) {
364 unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
365 const RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
366 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
367 unsigned resolvedOffset = wordOffset -
368 (textRun.rtl() ? wordResult->numCharacters() : 0);
369 advance += wordResult->fillGlyphBufferForTextEmphasisRun(
370 glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
371 advance, from, to, resolvedOffset);
372 }
373 wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
374 }
375
376 return advance;
377 }
378
379 FloatRect ShapeResult::selectionRect(const ShapeResultBuffer& resultsBuffer,
380 TextDirection direction, float totalWidth, const FloatPoint& point,
381 int height, unsigned absoluteFrom, unsigned absoluteTo)
382 {
383 const auto& results = resultsBuffer.results();
384 float currentX = 0;
385 float fromX = 0;
386 float toX = 0;
387 bool foundFromX = false;
388 bool foundToX = false;
389
390 if (direction == RTL)
391 currentX = totalWidth;
392
393 // The absoluteFrom and absoluteTo arguments represent the start/end offset
394 // for the entire run, from/to are continuously updated to be relative to
395 // the current word (ShapeResult instance).
396 int from = absoluteFrom;
397 int to = absoluteTo;
398
399 unsigned totalNumCharacters = 0;
400 for (unsigned j = 0; j < results.size(); j++) {
401 const RefPtr<ShapeResult> result = results[j];
402 if (direction == RTL) {
403 // Convert logical offsets to visual offsets, because results are in
404 // logical order while runs are in visual order.
405 if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result ->numCharacters())
406 from = result->numCharacters() - from - 1;
407 if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numC haracters())
408 to = result->numCharacters() - to - 1;
409 currentX -= result->width();
410 }
411 for (unsigned i = 0; i < result->m_runs.size(); i++) {
412 if (!result->m_runs[i])
413 continue;
414 ASSERT((direction == RTL) == result->m_runs[i]->rtl());
415 int numCharacters = result->m_runs[i]->m_numCharacters;
416 if (!foundFromX && from >= 0 && from < numCharacters) {
417 fromX = result->m_runs[i]->xPositionForVisualOffset(from) + curr entX;
418 foundFromX = true;
419 } else {
420 from -= numCharacters;
421 }
422
423 if (!foundToX && to >= 0 && to < numCharacters) {
424 toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX ;
425 foundToX = true;
426 } else {
427 to -= numCharacters;
428 }
429
430 if (foundFromX && foundToX)
431 break;
432 currentX += result->m_runs[i]->m_width;
433 }
434 if (direction == RTL)
435 currentX -= result->width();
436 totalNumCharacters += result->numCharacters();
437 }
438
439 // The position in question might be just after the text.
440 if (!foundFromX && absoluteFrom == totalNumCharacters) {
441 fromX = direction == RTL ? 0 : totalWidth;
442 foundFromX = true;
443 }
444 if (!foundToX && absoluteTo == totalNumCharacters) {
445 toX = direction == RTL ? 0 : totalWidth;
446 foundToX = true;
447 }
448 if (!foundFromX)
449 fromX = 0;
450 if (!foundToX)
451 toX = direction == RTL ? 0 : totalWidth;
452
453 // None of our runs is part of the selection, possibly invalid arguments.
454 if (!foundToX && !foundFromX)
455 fromX = toX = 0;
456 if (fromX < toX)
457 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
458 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
459 }
460
461 size_t ShapeResult::byteSize() 131 size_t ShapeResult::byteSize()
462 { 132 {
463 size_t selfByteSize = sizeof(this); 133 size_t selfByteSize = sizeof(this);
464 for (unsigned i = 0; i < m_runs.size(); ++i) { 134 for (unsigned i = 0; i < m_runs.size(); ++i) {
465 selfByteSize += m_runs[i]->byteSize(); 135 selfByteSize += m_runs[i]->byteSize();
466 } 136 }
467 return selfByteSize; 137 return selfByteSize;
468 } 138 }
469 139
470 int ShapeResult::offsetForPosition(const ShapeResultBuffer& resultsBuffer, 140 int ShapeResult::offsetForPosition(float targetX) const
471 const TextRun& run, float targetX)
472 {
473 const auto& results = resultsBuffer.results();
474 unsigned totalOffset;
475 if (run.rtl()) {
476 totalOffset = run.length();
477 for (unsigned i = results.size(); i; --i) {
478 const RefPtr<ShapeResult>& wordResult = results[i - 1];
479 if (!wordResult)
480 continue;
481 totalOffset -= wordResult->numCharacters();
482 if (targetX >= 0 && targetX <= wordResult->width()) {
483 int offsetForWord = wordResult->offsetForPosition(targetX);
484 return totalOffset + offsetForWord;
485 }
486 targetX -= wordResult->width();
487 }
488 } else {
489 totalOffset = 0;
490 for (const auto& wordResult : results) {
491 if (!wordResult)
492 continue;
493 int offsetForWord = wordResult->offsetForPosition(targetX);
494 ASSERT(offsetForWord >= 0);
495 totalOffset += offsetForWord;
496 if (targetX >= 0 && targetX <= wordResult->width())
497 return totalOffset;
498 targetX -= wordResult->width();
499 }
500 }
501 return totalOffset;
502 }
503
504 int ShapeResult::offsetForPosition(float targetX)
505 { 141 {
506 int charactersSoFar = 0; 142 int charactersSoFar = 0;
507 float currentX = 0; 143 float currentX = 0;
508 144
509 if (m_direction == RTL) { 145 if (m_direction == RTL) {
510 charactersSoFar = m_numCharacters; 146 charactersSoFar = m_numCharacters;
511 for (unsigned i = 0; i < m_runs.size(); ++i) { 147 for (unsigned i = 0; i < m_runs.size(); ++i) {
512 if (!m_runs[i]) 148 if (!m_runs[i])
513 continue; 149 continue;
514 charactersSoFar -= m_runs[i]->m_numCharacters; 150 charactersSoFar -= m_runs[i]->m_numCharacters;
(...skipping 30 matching lines...) Expand all
545 ASSERT(m_primaryFont); 181 ASSERT(m_primaryFont);
546 for (unsigned i = 0; i < m_runs.size(); ++i) { 182 for (unsigned i = 0; i < m_runs.size(); ++i) {
547 if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont 183 if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont
548 && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont .get())) { 184 && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont .get())) {
549 fallback->add(m_runs[i]->m_fontData.get()); 185 fallback->add(m_runs[i]->m_fontData.get());
550 } 186 }
551 } 187 }
552 } 188 }
553 189
554 } // namespace blink 190 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698