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

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

Issue 2598393002: Do not skip ink for ideographic scripts (Closed)
Patch Set: Fix not to compute twice Created 3 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) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2000 Dirk Mueller (mueller@kde.org) 4 * (C) 2000 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. 5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved.
6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved. 6 * Copyright (c) 2007, 2008, 2010 Google Inc. All rights reserved.
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public 9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
250 STACK_ALLOCATED() 250 STACK_ALLOCATED()
251 public: 251 public:
252 GlyphBufferBloberizer(const GlyphBuffer& buffer, 252 GlyphBufferBloberizer(const GlyphBuffer& buffer,
253 const Font* font, 253 const Font* font,
254 float deviceScaleFactor) 254 float deviceScaleFactor)
255 : m_buffer(buffer), 255 : m_buffer(buffer),
256 m_font(font), 256 m_font(font),
257 m_deviceScaleFactor(deviceScaleFactor), 257 m_deviceScaleFactor(deviceScaleFactor),
258 m_hasVerticalOffsets(buffer.hasVerticalOffsets()), 258 m_hasVerticalOffsets(buffer.hasVerticalOffsets()),
259 m_index(0), 259 m_index(0),
260 m_endIndex(m_buffer.size()),
260 m_blobCount(0), 261 m_blobCount(0),
261 m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation( 262 m_rotation(buffer.isEmpty() ? NoRotation : computeBlobRotation(
262 buffer.fontDataAt(0))) {} 263 buffer.fontDataAt(0))),
264 m_skipGlyphs(nullptr) {}
263 265
264 bool done() const { return m_index >= m_buffer.size(); } 266 bool done() const { return m_index >= m_endIndex; }
265 unsigned blobCount() const { return m_blobCount; } 267 unsigned blobCount() const { return m_blobCount; }
266 268
267 std::pair<sk_sp<SkTextBlob>, BlobRotation> next() { 269 std::pair<sk_sp<SkTextBlob>, BlobRotation> next() {
268 ASSERT(!done()); 270 ASSERT(!done());
269 const BlobRotation currentRotation = m_rotation; 271 const BlobRotation currentRotation = m_rotation;
270 272
271 while (m_index < m_buffer.size()) { 273 while (m_index < m_endIndex) {
274 if (m_skipGlyphs) {
275 while (m_index < m_endIndex && (*m_skipGlyphs)[m_index])
276 m_index++;
277 }
278
272 const SimpleFontData* fontData = m_buffer.fontDataAt(m_index); 279 const SimpleFontData* fontData = m_buffer.fontDataAt(m_index);
273 ASSERT(fontData); 280 ASSERT(fontData);
274 281
275 const BlobRotation newRotation = computeBlobRotation(fontData); 282 const BlobRotation newRotation = computeBlobRotation(fontData);
276 if (newRotation != m_rotation) { 283 if (newRotation != m_rotation) {
277 // We're switching to an orientation which requires a different rotation 284 // We're switching to an orientation which requires a different rotation
278 // => emit the pending blob (and start a new one with the new 285 // => emit the pending blob (and start a new one with the new
279 // rotation). 286 // rotation).
280 m_rotation = newRotation; 287 m_rotation = newRotation;
281 break; 288 break;
282 } 289 }
283 290
284 const unsigned start = m_index++; 291 const unsigned start = m_index++;
285 while (m_index < m_buffer.size() && 292 while (m_index < m_endIndex && m_buffer.fontDataAt(m_index) == fontData &&
286 m_buffer.fontDataAt(m_index) == fontData) 293 !(m_skipGlyphs && (*m_skipGlyphs)[m_index]))
287 m_index++; 294 m_index++;
288 295
289 appendRun(start, m_index - start, fontData); 296 appendRun(start, m_index - start, fontData);
290 } 297 }
291 298
292 m_blobCount++; 299 m_blobCount++;
293 return std::make_pair(m_builder.make(), currentRotation); 300 return std::make_pair(m_builder.make(), currentRotation);
294 } 301 }
295 302
303 void setSkipGlyphs(const Vector<bool>* skipGlyphs) {
304 m_skipGlyphs = skipGlyphs;
305 m_endIndex = m_buffer.size();
306 if (m_skipGlyphs) {
307 while (m_endIndex > 0 && (*m_skipGlyphs)[m_endIndex - 1])
308 m_endIndex--;
309 }
310 }
311
296 private: 312 private:
297 static BlobRotation computeBlobRotation(const SimpleFontData* font) { 313 static BlobRotation computeBlobRotation(const SimpleFontData* font) {
298 // For vertical upright text we need to compensate the inherited 90deg CW 314 // For vertical upright text we need to compensate the inherited 90deg CW
299 // rotation (using a 90deg CCW rotation). 315 // rotation (using a 90deg CCW rotation).
300 return (font->platformData().isVerticalAnyUpright() && font->verticalData()) 316 return (font->platformData().isVerticalAnyUpright() && font->verticalData())
301 ? CCWRotation 317 ? CCWRotation
302 : NoRotation; 318 : NoRotation;
303 } 319 }
304 320
305 void appendRun(unsigned start, 321 void appendRun(unsigned start,
(...skipping 30 matching lines...) Expand all
336 } 352 }
337 } 353 }
338 354
339 const GlyphBuffer& m_buffer; 355 const GlyphBuffer& m_buffer;
340 const Font* m_font; 356 const Font* m_font;
341 const float m_deviceScaleFactor; 357 const float m_deviceScaleFactor;
342 const bool m_hasVerticalOffsets; 358 const bool m_hasVerticalOffsets;
343 359
344 SkTextBlobBuilder m_builder; 360 SkTextBlobBuilder m_builder;
345 unsigned m_index; 361 unsigned m_index;
362 unsigned m_endIndex;
346 unsigned m_blobCount; 363 unsigned m_blobCount;
347 BlobRotation m_rotation; 364 BlobRotation m_rotation;
365 const Vector<bool>* m_skipGlyphs;
348 }; 366 };
349 367
350 } // anonymous namespace 368 } // anonymous namespace
351 369
352 void Font::drawGlyphBuffer(SkCanvas* canvas, 370 void Font::drawGlyphBuffer(SkCanvas* canvas,
353 const SkPaint& paint, 371 const SkPaint& paint,
354 const TextRunPaintInfo& runInfo, 372 const TextRunPaintInfo& runInfo,
355 const GlyphBuffer& glyphBuffer, 373 const GlyphBuffer& glyphBuffer,
356 const FloatPoint& point, 374 const FloatPoint& point,
357 float deviceScaleFactor) const { 375 float deviceScaleFactor) const {
(...skipping 21 matching lines...) Expand all
379 // 2) the glyph buffer is encoded as a single blob, and 397 // 2) the glyph buffer is encoded as a single blob, and
380 // 3) the blob is not upright/rotated 398 // 3) the blob is not upright/rotated
381 if (runInfo.cachedTextBlob && bloberizer.blobCount() == 1 && 399 if (runInfo.cachedTextBlob && bloberizer.blobCount() == 1 &&
382 blob.second == NoRotation) { 400 blob.second == NoRotation) {
383 ASSERT(!*runInfo.cachedTextBlob); 401 ASSERT(!*runInfo.cachedTextBlob);
384 *runInfo.cachedTextBlob = std::move(blob.first); 402 *runInfo.cachedTextBlob = std::move(blob.first);
385 ASSERT(*runInfo.cachedTextBlob); 403 ASSERT(*runInfo.cachedTextBlob);
386 } 404 }
387 } 405 }
388 406
407 static std::unique_ptr<Vector<bool>> glyphsToSkipIntercepts(
408 const TextRun& run,
409 const GlyphBuffer& glyphBuffer) {
410 // Skipping ink leads to undesirable renderings for some scripts. Determine
411 // glyphs not to skip ink on a character-by-character basis.
412 DCHECK(!run.is8Bit());
413 std::unique_ptr<Vector<bool>> skipIndexes =
414 WTF::makeUnique<Vector<bool>>(glyphBuffer.size());
415 bool hasAnySkip = false;
416 for (unsigned index = 0; index < glyphBuffer.size(); index++) {
417 unsigned characterIndex = glyphBuffer.characterIndex(index);
418 UChar32 baseCharacter = run.codepointAt(characterIndex);
drott 2017/01/02 15:07:45 Can we reuse Character::isCJKIdeographOrSymbol for
419 UBlockCode blockCode = ublock_getCode(baseCharacter);
420 switch (blockCode) {
421 case UBLOCK_BOPOMOFO:
422 case UBLOCK_BOPOMOFO_EXTENDED:
423 case UBLOCK_CJK_COMPATIBILITY:
424 case UBLOCK_CJK_COMPATIBILITY_FORMS:
425 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
426 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
427 case UBLOCK_CJK_RADICALS_SUPPLEMENT:
428 case UBLOCK_CJK_STROKES:
429 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
430 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
431 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
432 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
433 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
434 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
435 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E:
436 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
437 case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
438 case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
439 case UBLOCK_HANGUL_JAMO:
440 case UBLOCK_HANGUL_JAMO_EXTENDED_A:
441 case UBLOCK_HANGUL_JAMO_EXTENDED_B:
442 case UBLOCK_HANGUL_SYLLABLES:
443 case UBLOCK_HIRAGANA:
444 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
445 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION:
446 case UBLOCK_KATAKANA:
447 case UBLOCK_LINEAR_B_IDEOGRAMS:
448 case UBLOCK_TANGUT:
449 case UBLOCK_TANGUT_COMPONENTS:
450 (*skipIndexes)[index] = true;
451 hasAnySkip = true;
452 break;
453 default:
454 break;
455 }
456 }
457 if (!hasAnySkip)
458 return nullptr;
459 return skipIndexes;
460 }
461
389 static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer, 462 static int getInterceptsFromBloberizer(const GlyphBuffer& glyphBuffer,
390 const Font* font, 463 const Font* font,
391 const SkPaint& paint, 464 const SkPaint& paint,
392 float deviceScaleFactor, 465 float deviceScaleFactor,
393 const std::tuple<float, float>& bounds, 466 const std::tuple<float, float>& bounds,
467 const Vector<bool>* skipGlyphs,
394 SkScalar* interceptsBuffer) { 468 SkScalar* interceptsBuffer) {
395 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)}; 469 SkScalar boundsArray[2] = {std::get<0>(bounds), std::get<1>(bounds)};
396 GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor); 470 GlyphBufferBloberizer bloberizer(glyphBuffer, font, deviceScaleFactor);
471 bloberizer.setSkipGlyphs(skipGlyphs);
397 std::pair<sk_sp<SkTextBlob>, BlobRotation> blob; 472 std::pair<sk_sp<SkTextBlob>, BlobRotation> blob;
398 473
399 int numIntervals = 0; 474 int numIntervals = 0;
400 while (!bloberizer.done()) { 475 while (!bloberizer.done()) {
401 blob = bloberizer.next(); 476 blob = bloberizer.next();
402 DCHECK(blob.first); 477 DCHECK(blob.first);
403 478
404 // GlyphBufferBloberizer splits for a new blob rotation, but does not split 479 // GlyphBufferBloberizer splits for a new blob rotation, but does not split
405 // for a change in font. A TextBlob can contain runs with differing fonts 480 // for a change in font. A TextBlob can contain runs with differing fonts
406 // and the getTextBlobIntercepts method handles multiple fonts for us. For 481 // and the getTextBlobIntercepts method handles multiple fonts for us. For
(...skipping 25 matching lines...) Expand all
432 if (!numIntervals) 507 if (!numIntervals)
433 return; 508 return;
434 DCHECK_EQ(numIntervals % 2, 0); 509 DCHECK_EQ(numIntervals % 2, 0);
435 intercepts.resize(numIntervals / 2); 510 intercepts.resize(numIntervals / 2);
436 paint.getTextBlobIntercepts(runInfo.cachedTextBlob->get(), boundsArray, 511 paint.getTextBlobIntercepts(runInfo.cachedTextBlob->get(), boundsArray,
437 reinterpret_cast<SkScalar*>(intercepts.data())); 512 reinterpret_cast<SkScalar*>(intercepts.data()));
438 return; 513 return;
439 } 514 }
440 515
441 GlyphBuffer glyphBuffer; 516 GlyphBuffer glyphBuffer;
442 buildGlyphBuffer(runInfo, glyphBuffer); 517 std::unique_ptr<Vector<bool>> skipGlyphs;
518 if (runInfo.run.is8Bit()) {
519 buildGlyphBuffer(runInfo, glyphBuffer);
520 } else {
521 glyphBuffer.saveCharacterIndexes();
522 buildGlyphBuffer(runInfo, glyphBuffer);
523 skipGlyphs = glyphsToSkipIntercepts(runInfo.run, glyphBuffer);
524 }
443 525
444 // Get the number of intervals, without copying the actual values by 526 // Get the number of intervals, without copying the actual values by
445 // specifying nullptr for the buffer, following the Skia allocation model for 527 // specifying nullptr for the buffer, following the Skia allocation model for
446 // retrieving text intercepts. 528 // retrieving text intercepts.
447 int numIntervals = getInterceptsFromBloberizer( 529 int numIntervals =
448 glyphBuffer, this, paint, deviceScaleFactor, bounds, nullptr); 530 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor,
531 bounds, skipGlyphs.get(), nullptr);
449 if (!numIntervals) 532 if (!numIntervals)
450 return; 533 return;
451 DCHECK_EQ(numIntervals % 2, 0); 534 DCHECK_EQ(numIntervals % 2, 0);
452 intercepts.resize(numIntervals / 2); 535 intercepts.resize(numIntervals / 2);
453 536
454 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor, 537 getInterceptsFromBloberizer(glyphBuffer, this, paint, deviceScaleFactor,
455 bounds, 538 bounds, skipGlyphs.get(),
456 reinterpret_cast<SkScalar*>(intercepts.data())); 539 reinterpret_cast<SkScalar*>(intercepts.data()));
457 } 540 }
458 541
459 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) { 542 static inline FloatRect pixelSnappedSelectionRect(FloatRect rect) {
460 // Using roundf() rather than ceilf() for the right edge as a compromise to 543 // Using roundf() rather than ceilf() for the right edge as a compromise to
461 // ensure correct caret positioning. 544 // ensure correct caret positioning.
462 float roundedX = roundf(rect.x()); 545 float roundedX = roundf(rect.x());
463 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX), 546 return FloatRect(roundedX, rect.y(), roundf(rect.maxX() - roundedX),
464 rect.height()); 547 rect.height());
465 } 548 }
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 703
621 bool Font::loadingCustomFonts() const { 704 bool Font::loadingCustomFonts() const {
622 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts(); 705 return m_fontFallbackList && m_fontFallbackList->loadingCustomFonts();
623 } 706 }
624 707
625 bool Font::isFallbackValid() const { 708 bool Font::isFallbackValid() const {
626 return !m_fontFallbackList || m_fontFallbackList->isValid(); 709 return !m_fontFallbackList || m_fontFallbackList->isValid();
627 } 710 }
628 711
629 } // namespace blink 712 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698