Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gfx/render_text_harfbuzz.h" | 5 #include "ui/gfx/render_text_harfbuzz.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <map> | 8 #include <map> |
| 9 | 9 |
| 10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
| 11 #include "base/i18n/break_iterator.h" | 11 #include "base/i18n/break_iterator.h" |
| 12 #include "base/i18n/char_iterator.h" | 12 #include "base/i18n/char_iterator.h" |
| 13 #include "base/lazy_instance.h" | 13 #include "base/lazy_instance.h" |
| 14 #include "third_party/harfbuzz-ng/src/hb.h" | 14 #include "third_party/harfbuzz-ng/src/hb.h" |
| 15 #include "third_party/icu/source/common/unicode/ubidi.h" | 15 #include "third_party/icu/source/common/unicode/ubidi.h" |
| 16 #include "third_party/skia/include/core/SkColor.h" | 16 #include "third_party/skia/include/core/SkColor.h" |
| 17 #include "third_party/skia/include/core/SkTypeface.h" | 17 #include "third_party/skia/include/core/SkTypeface.h" |
| 18 #include "ui/gfx/canvas.h" | 18 #include "ui/gfx/canvas.h" |
| 19 #include "ui/gfx/font_fallback.h" | 19 #include "ui/gfx/font_fallback.h" |
| 20 #include "ui/gfx/font_render_params.h" | 20 #include "ui/gfx/font_render_params.h" |
| 21 #include "ui/gfx/utf16_indexing.h" | 21 #include "ui/gfx/utf16_indexing.h" |
| 22 | 22 |
| 23 #if defined(OS_WIN) | 23 #if defined(OS_WIN) |
| 24 #include "ui/gfx/font_fallback_win.h" | 24 #include "ui/gfx/font_fallback_win.h" |
| 25 #endif | 25 #endif |
| 26 | 26 |
| 27 using gfx::internal::RangeF; | |
| 28 using gfx::internal::RoundRangeF; | |
| 29 | |
| 27 namespace gfx { | 30 namespace gfx { |
| 28 | 31 |
| 29 namespace { | 32 namespace { |
| 30 | 33 |
| 31 // Text length limit. Longer strings are slow and not fully tested. | 34 // Text length limit. Longer strings are slow and not fully tested. |
| 32 const size_t kMaxTextLength = 10000; | 35 const size_t kMaxTextLength = 10000; |
| 33 | 36 |
| 34 // The maximum number of scripts a Unicode character can belong to. This value | 37 // The maximum number of scripts a Unicode character can belong to. This value |
| 35 // is arbitrarily chosen to be a good limit because it is unlikely for a single | 38 // is arbitrarily chosen to be a good limit because it is unlikely for a single |
| 36 // character to belong to more scripts. | 39 // character to belong to more scripts. |
| (...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 453 DCHECK(!chars->is_reversed()); | 456 DCHECK(!chars->is_reversed()); |
| 454 DCHECK(!chars->is_empty()); | 457 DCHECK(!chars->is_empty()); |
| 455 DCHECK(!glyphs->is_reversed()); | 458 DCHECK(!glyphs->is_reversed()); |
| 456 DCHECK(!glyphs->is_empty()); | 459 DCHECK(!glyphs->is_empty()); |
| 457 } | 460 } |
| 458 | 461 |
| 459 } // namespace | 462 } // namespace |
| 460 | 463 |
| 461 namespace internal { | 464 namespace internal { |
| 462 | 465 |
| 466 Range RoundRangeF(const RangeF& range_f) { | |
| 467 return Range(std::round(range_f.first), std::round(range_f.second)); | |
| 468 } | |
| 469 | |
| 463 TextRunHarfBuzz::TextRunHarfBuzz() | 470 TextRunHarfBuzz::TextRunHarfBuzz() |
| 464 : width(0.0f), | 471 : width(0.0f), |
| 465 preceding_run_widths(0.0f), | 472 preceding_run_widths(0.0f), |
| 466 is_rtl(false), | 473 is_rtl(false), |
| 467 level(0), | 474 level(0), |
| 468 script(USCRIPT_INVALID_CODE), | 475 script(USCRIPT_INVALID_CODE), |
| 469 glyph_count(static_cast<size_t>(-1)), | 476 glyph_count(static_cast<size_t>(-1)), |
| 470 font_size(0), | 477 font_size(0), |
| 471 font_style(0), | 478 font_style(0), |
| 472 strike(false), | 479 strike(false), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 } | 521 } |
| 515 | 522 |
| 516 size_t TextRunHarfBuzz::CountMissingGlyphs() const { | 523 size_t TextRunHarfBuzz::CountMissingGlyphs() const { |
| 517 static const int kMissingGlyphId = 0; | 524 static const int kMissingGlyphId = 0; |
| 518 size_t missing = 0; | 525 size_t missing = 0; |
| 519 for (size_t i = 0; i < glyph_count; ++i) | 526 for (size_t i = 0; i < glyph_count; ++i) |
| 520 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; | 527 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; |
| 521 return missing; | 528 return missing; |
| 522 } | 529 } |
| 523 | 530 |
| 524 Range TextRunHarfBuzz::GetGraphemeBounds( | 531 RangeF TextRunHarfBuzz::GetGraphemeBounds( |
| 525 base::i18n::BreakIterator* grapheme_iterator, | 532 base::i18n::BreakIterator* grapheme_iterator, |
| 526 size_t text_index) { | 533 size_t text_index) { |
| 527 DCHECK_LT(text_index, range.end()); | 534 DCHECK_LT(text_index, range.end()); |
| 528 // TODO(msw): Support floating point grapheme bounds. | |
| 529 const int preceding_run_widths_int = SkScalarRoundToInt(preceding_run_widths); | |
| 530 if (glyph_count == 0) | 535 if (glyph_count == 0) |
| 531 return Range(preceding_run_widths_int, preceding_run_widths_int + width); | 536 return RangeF(preceding_run_widths, preceding_run_widths + width); |
| 532 | 537 |
| 533 Range chars; | 538 Range chars; |
| 534 Range glyphs; | 539 Range glyphs; |
| 535 GetClusterAt(text_index, &chars, &glyphs); | 540 GetClusterAt(text_index, &chars, &glyphs); |
| 536 const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); | 541 const float cluster_begin_x = positions[glyphs.start()].x(); |
| 537 const int cluster_end_x = glyphs.end() < glyph_count ? | 542 const float cluster_end_x = glyphs.end() < glyph_count ? |
| 538 SkScalarRoundToInt(positions[glyphs.end()].x()) : width; | 543 positions[glyphs.end()].x() : SkFloatToScalar(width); |
| 539 | 544 |
| 540 // A cluster consists of a number of code points and corresponds to a number | 545 // A cluster consists of a number of code points and corresponds to a number |
| 541 // of glyphs that should be drawn together. A cluster can contain multiple | 546 // of glyphs that should be drawn together. A cluster can contain multiple |
| 542 // graphemes. In order to place the cursor at a grapheme boundary inside the | 547 // graphemes. In order to place the cursor at a grapheme boundary inside the |
| 543 // cluster, we simply divide the cluster width by the number of graphemes. | 548 // cluster, we simply divide the cluster width by the number of graphemes. |
| 544 if (chars.length() > 1 && grapheme_iterator) { | 549 if (chars.length() > 1 && grapheme_iterator) { |
| 545 int before = 0; | 550 int before = 0; |
| 546 int total = 0; | 551 int total = 0; |
| 547 for (size_t i = chars.start(); i < chars.end(); ++i) { | 552 for (size_t i = chars.start(); i < chars.end(); ++i) { |
| 548 if (grapheme_iterator->IsGraphemeBoundary(i)) { | 553 if (grapheme_iterator->IsGraphemeBoundary(i)) { |
| 549 if (i < text_index) | 554 if (i < text_index) |
| 550 ++before; | 555 ++before; |
| 551 ++total; | 556 ++total; |
| 552 } | 557 } |
| 553 } | 558 } |
| 554 DCHECK_GT(total, 0); | 559 DCHECK_GT(total, 0); |
| 555 if (total > 1) { | 560 if (total > 1) { |
| 556 if (is_rtl) | 561 if (is_rtl) |
| 557 before = total - before - 1; | 562 before = total - before - 1; |
| 558 DCHECK_GE(before, 0); | 563 DCHECK_GE(before, 0); |
| 559 DCHECK_LT(before, total); | 564 DCHECK_LT(before, total); |
| 560 const int cluster_width = cluster_end_x - cluster_begin_x; | 565 const int cluster_width = cluster_end_x - cluster_begin_x; |
| 561 const int grapheme_begin_x = cluster_begin_x + static_cast<int>(0.5f + | 566 const int grapheme_begin_x = cluster_begin_x + static_cast<int>(0.5f + |
| 562 cluster_width * before / static_cast<float>(total)); | 567 cluster_width * before / static_cast<float>(total)); |
| 563 const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + | 568 const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + |
| 564 cluster_width * (before + 1) / static_cast<float>(total)); | 569 cluster_width * (before + 1) / static_cast<float>(total)); |
| 565 return Range(preceding_run_widths_int + grapheme_begin_x, | 570 return RangeF(preceding_run_widths + grapheme_begin_x, |
| 566 preceding_run_widths_int + grapheme_end_x); | 571 preceding_run_widths + grapheme_end_x); |
| 567 } | 572 } |
| 568 } | 573 } |
| 569 | 574 |
| 570 return Range(preceding_run_widths_int + cluster_begin_x, | 575 return RangeF(preceding_run_widths + cluster_begin_x, |
| 571 preceding_run_widths_int + cluster_end_x); | 576 preceding_run_widths + cluster_end_x); |
| 572 } | 577 } |
| 573 | 578 |
| 574 } // namespace internal | 579 } // namespace internal |
| 575 | 580 |
| 576 RenderTextHarfBuzz::RenderTextHarfBuzz() | 581 RenderTextHarfBuzz::RenderTextHarfBuzz() |
| 577 : RenderText(), | 582 : RenderText(), |
| 578 needs_layout_(false) { | 583 needs_layout_(false) { |
| 579 set_truncate_length(kMaxTextLength); | 584 set_truncate_length(kMaxTextLength); |
| 580 } | 585 } |
| 581 | 586 |
| 582 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} | 587 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} |
| 583 | 588 |
| 584 Size RenderTextHarfBuzz::GetStringSize() { | 589 Size RenderTextHarfBuzz::GetStringSize() { |
| 585 const SizeF size_f = GetStringSizeF(); | 590 const SizeF size_f = GetStringSizeF(); |
| 586 return Size(std::ceil(size_f.width()), size_f.height()); | 591 return Size(std::ceil(size_f.width()), size_f.height()); |
| 587 } | 592 } |
| 588 | 593 |
| 589 SizeF RenderTextHarfBuzz::GetStringSizeF() { | 594 SizeF RenderTextHarfBuzz::GetStringSizeF() { |
| 590 EnsureLayout(); | 595 EnsureLayout(); |
| 591 return lines()[0].size; | 596 return lines()[0].size; |
| 592 } | 597 } |
| 593 | 598 |
| 594 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { | 599 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { |
| 595 EnsureLayout(); | 600 EnsureLayout(); |
| 596 | 601 |
| 597 int x = ToTextPoint(point).x(); | 602 int x = ToTextPoint(point).x(); |
| 598 int offset = 0; | 603 float offset = 0; |
| 599 size_t run_index = GetRunContainingXCoord(x, &offset); | 604 size_t run_index = GetRunContainingXCoord(x, &offset); |
| 600 if (run_index >= runs_.size()) | 605 if (run_index >= runs_.size()) |
| 601 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); | 606 return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); |
| 602 const internal::TextRunHarfBuzz& run = *runs_[run_index]; | 607 const internal::TextRunHarfBuzz& run = *runs_[run_index]; |
| 603 | 608 |
| 604 for (size_t i = 0; i < run.glyph_count; ++i) { | 609 for (size_t i = 0; i < run.glyph_count; ++i) { |
| 605 const SkScalar end = | 610 const SkScalar end = |
| 606 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); | 611 i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x(); |
| 607 const SkScalar middle = (end + run.positions[i].x()) / 2; | 612 const SkScalar middle = (end + run.positions[i].x()) / 2; |
| 608 | 613 |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 638 | 643 |
| 639 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { | 644 Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { |
| 640 EnsureLayout(); | 645 EnsureLayout(); |
| 641 const size_t run_index = | 646 const size_t run_index = |
| 642 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); | 647 GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD)); |
| 643 // Return edge bounds if the index is invalid or beyond the layout text size. | 648 // Return edge bounds if the index is invalid or beyond the layout text size. |
| 644 if (run_index >= runs_.size()) | 649 if (run_index >= runs_.size()) |
| 645 return Range(GetStringSize().width()); | 650 return Range(GetStringSize().width()); |
| 646 const size_t layout_index = TextIndexToLayoutIndex(index); | 651 const size_t layout_index = TextIndexToLayoutIndex(index); |
| 647 internal::TextRunHarfBuzz* run = runs_[run_index]; | 652 internal::TextRunHarfBuzz* run = runs_[run_index]; |
| 648 Range bounds = run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); | 653 RangeF bounds = |
| 649 return run->is_rtl ? Range(bounds.end(), bounds.start()) : bounds; | 654 run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); |
| 655 if (cursor_enabled() && run_index == runs_.size() - 1 && | |
| 656 index == (run->is_rtl ? run->range.start() : run->range.end() - 1)) | |
| 657 bounds.second = std::ceil(bounds.second); | |
|
msw
2014/11/24 21:51:00
Add a comment here explaining why this is necessar
ckocagil
2014/11/25 01:39:47
Done.
msw
2014/11/25 04:52:05
Acknowledged.
| |
| 658 return RoundRangeF(run->is_rtl ? | |
| 659 RangeF(bounds.second, bounds.first) : bounds); | |
| 650 } | 660 } |
| 651 | 661 |
| 652 int RenderTextHarfBuzz::GetLayoutTextBaseline() { | 662 int RenderTextHarfBuzz::GetLayoutTextBaseline() { |
| 653 EnsureLayout(); | 663 EnsureLayout(); |
| 654 return lines()[0].baseline; | 664 return lines()[0].baseline; |
| 655 } | 665 } |
| 656 | 666 |
| 657 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( | 667 SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel( |
| 658 const SelectionModel& selection, | 668 const SelectionModel& selection, |
| 659 VisualCursorDirection direction) { | 669 VisualCursorDirection direction) { |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 770 return rects; | 780 return rects; |
| 771 std::vector<Range> bounds; | 781 std::vector<Range> bounds; |
| 772 | 782 |
| 773 // Add a Range for each run/selection intersection. | 783 // Add a Range for each run/selection intersection. |
| 774 for (size_t i = 0; i < runs_.size(); ++i) { | 784 for (size_t i = 0; i < runs_.size(); ++i) { |
| 775 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; | 785 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; |
| 776 Range intersection = run->range.Intersect(layout_range); | 786 Range intersection = run->range.Intersect(layout_range); |
| 777 if (!intersection.IsValid()) | 787 if (!intersection.IsValid()) |
| 778 continue; | 788 continue; |
| 779 DCHECK(!intersection.is_reversed()); | 789 DCHECK(!intersection.is_reversed()); |
| 780 const Range leftmost_character_x = run->GetGraphemeBounds( | 790 const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
| 781 grapheme_iterator_.get(), | 791 grapheme_iterator_.get(), |
| 782 run->is_rtl ? intersection.end() - 1 : intersection.start()); | 792 run->is_rtl ? intersection.end() - 1 : intersection.start())); |
| 783 const Range rightmost_character_x = run->GetGraphemeBounds( | 793 const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
| 784 grapheme_iterator_.get(), | 794 grapheme_iterator_.get(), |
| 785 run->is_rtl ? intersection.start() : intersection.end() - 1); | 795 run->is_rtl ? intersection.start() : intersection.end() - 1)); |
| 786 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); | 796 Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); |
| 787 DCHECK(!range_x.is_reversed()); | 797 DCHECK(!range_x.is_reversed()); |
| 788 if (range_x.is_empty()) | 798 if (range_x.is_empty()) |
| 789 continue; | 799 continue; |
| 790 | 800 |
| 791 // Union this with the last range if they're adjacent. | 801 // Union this with the last range if they're adjacent. |
| 792 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); | 802 DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin()); |
| 793 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { | 803 if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) { |
| 794 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); | 804 range_x = Range(bounds.back().GetMin(), range_x.GetMax()); |
| 795 bounds.pop_back(); | 805 bounds.pop_back(); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 898 } | 908 } |
| 899 } | 909 } |
| 900 | 910 |
| 901 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 911 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
| 902 DCHECK(!needs_layout_); | 912 DCHECK(!needs_layout_); |
| 903 internal::SkiaTextRenderer renderer(canvas); | 913 internal::SkiaTextRenderer renderer(canvas); |
| 904 ApplyFadeEffects(&renderer); | 914 ApplyFadeEffects(&renderer); |
| 905 ApplyTextShadows(&renderer); | 915 ApplyTextShadows(&renderer); |
| 906 ApplyCompositionAndSelectionStyles(); | 916 ApplyCompositionAndSelectionStyles(); |
| 907 | 917 |
| 908 int current_x = 0; | |
| 909 const Vector2d line_offset = GetLineOffset(0); | 918 const Vector2d line_offset = GetLineOffset(0); |
| 910 for (size_t i = 0; i < runs_.size(); ++i) { | 919 for (size_t i = 0; i < runs_.size(); ++i) { |
| 911 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; | 920 const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; |
| 912 renderer.SetTypeface(run.skia_face.get()); | 921 renderer.SetTypeface(run.skia_face.get()); |
| 913 renderer.SetTextSize(SkIntToScalar(run.font_size)); | 922 renderer.SetTextSize(SkIntToScalar(run.font_size)); |
| 914 renderer.SetFontRenderParams(run.render_params, | 923 renderer.SetFontRenderParams(run.render_params, |
| 915 background_is_transparent()); | 924 background_is_transparent()); |
| 916 | 925 |
| 917 Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); | 926 Vector2d origin = line_offset + Vector2d(0, lines()[0].baseline); |
| 918 scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); | 927 scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); |
| 919 for (size_t j = 0; j < run.glyph_count; ++j) { | 928 for (size_t j = 0; j < run.glyph_count; ++j) { |
| 920 positions[j] = run.positions[j]; | 929 positions[j] = run.positions[j]; |
| 921 positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); | 930 positions[j].offset(SkIntToScalar(origin.x()) + run.preceding_run_widths, |
| 931 SkIntToScalar(origin.y())); | |
| 922 } | 932 } |
| 923 | 933 |
| 924 for (BreakList<SkColor>::const_iterator it = | 934 for (BreakList<SkColor>::const_iterator it = |
| 925 colors().GetBreak(run.range.start()); | 935 colors().GetBreak(run.range.start()); |
| 926 it != colors().breaks().end() && it->first < run.range.end(); | 936 it != colors().breaks().end() && it->first < run.range.end(); |
| 927 ++it) { | 937 ++it) { |
| 928 const Range intersection = colors().GetRange(it).Intersect(run.range); | 938 const Range intersection = colors().GetRange(it).Intersect(run.range); |
| 929 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); | 939 const Range colored_glyphs = run.CharRangeToGlyphRange(intersection); |
| 930 // The range may be empty if a portion of a multi-character grapheme is | 940 // The range may be empty if a portion of a multi-character grapheme is |
| 931 // selected, yielding two colors for a single glyph. For now, this just | 941 // selected, yielding two colors for a single glyph. For now, this just |
| 932 // paints the glyph with a single style, but it should paint it twice, | 942 // paints the glyph with a single style, but it should paint it twice, |
| 933 // clipped according to selection bounds. See http://crbug.com/366786 | 943 // clipped according to selection bounds. See http://crbug.com/366786 |
| 934 if (colored_glyphs.is_empty()) | 944 if (colored_glyphs.is_empty()) |
| 935 continue; | 945 continue; |
| 936 | 946 |
| 937 renderer.SetForegroundColor(it->second); | 947 renderer.SetForegroundColor(it->second); |
| 938 renderer.DrawPosText(&positions[colored_glyphs.start()], | 948 renderer.DrawPosText(&positions[colored_glyphs.start()], |
| 939 &run.glyphs[colored_glyphs.start()], | 949 &run.glyphs[colored_glyphs.start()], |
| 940 colored_glyphs.length()); | 950 colored_glyphs.length()); |
| 941 int start_x = SkScalarRoundToInt(positions[colored_glyphs.start()].x()); | 951 int start_x = SkScalarRoundToInt(positions[colored_glyphs.start()].x()); |
| 942 int end_x = SkScalarRoundToInt((colored_glyphs.end() == run.glyph_count) ? | 952 int end_x = SkScalarRoundToInt((colored_glyphs.end() == run.glyph_count) ? |
| 943 (run.width + SkIntToScalar(origin.x())) : | 953 (run.width + run.preceding_run_widths + SkIntToScalar(origin.x())) : |
| 944 positions[colored_glyphs.end()].x()); | 954 positions[colored_glyphs.end()].x()); |
| 945 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, | 955 renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, |
| 946 run.underline, run.strike, run.diagonal_strike); | 956 run.underline, run.strike, run.diagonal_strike); |
| 947 } | 957 } |
| 948 | |
| 949 current_x += run.width; | |
| 950 } | 958 } |
| 951 | 959 |
| 952 renderer.EndDiagonalStrike(); | 960 renderer.EndDiagonalStrike(); |
| 953 | 961 |
| 954 UndoCompositionAndSelectionStyles(); | 962 UndoCompositionAndSelectionStyles(); |
| 955 } | 963 } |
| 956 | 964 |
| 957 size_t RenderTextHarfBuzz::GetRunContainingCaret( | 965 size_t RenderTextHarfBuzz::GetRunContainingCaret( |
| 958 const SelectionModel& caret) const { | 966 const SelectionModel& caret) const { |
| 959 DCHECK(!needs_layout_); | 967 DCHECK(!needs_layout_); |
| 960 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); | 968 size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos()); |
| 961 LogicalCursorDirection affinity = caret.caret_affinity(); | 969 LogicalCursorDirection affinity = caret.caret_affinity(); |
| 962 for (size_t run = 0; run < runs_.size(); ++run) { | 970 for (size_t run = 0; run < runs_.size(); ++run) { |
| 963 if (RangeContainsCaret(runs_[run]->range, layout_position, affinity)) | 971 if (RangeContainsCaret(runs_[run]->range, layout_position, affinity)) |
| 964 return run; | 972 return run; |
| 965 } | 973 } |
| 966 return runs_.size(); | 974 return runs_.size(); |
| 967 } | 975 } |
| 968 | 976 |
| 969 size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const { | 977 size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x, |
| 978 float* offset) const { | |
| 970 DCHECK(!needs_layout_); | 979 DCHECK(!needs_layout_); |
| 971 if (x < 0) | 980 if (x < 0) |
| 972 return runs_.size(); | 981 return runs_.size(); |
| 973 // Find the text run containing the argument point (assumed already offset). | 982 // Find the text run containing the argument point (assumed already offset). |
| 974 int current_x = 0; | 983 float current_x = 0; |
| 975 for (size_t i = 0; i < runs_.size(); ++i) { | 984 for (size_t i = 0; i < runs_.size(); ++i) { |
| 976 size_t run = visual_to_logical_[i]; | 985 size_t run = visual_to_logical_[i]; |
| 977 current_x += runs_[run]->width; | 986 current_x += runs_[run]->width; |
| 978 if (x < current_x) { | 987 if (x < current_x) { |
| 979 *offset = x - (current_x - runs_[run]->width); | 988 *offset = x - (current_x - runs_[run]->width); |
| 980 return run; | 989 return run; |
| 981 } | 990 } |
| 982 } | 991 } |
| 983 return runs_.size(); | 992 return runs_.size(); |
| 984 } | 993 } |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1126 // Append fonts in the fallback list of the Uniscribe font. | 1135 // Append fonts in the fallback list of the Uniscribe font. |
| 1127 if (!uniscribe_family.empty()) { | 1136 if (!uniscribe_family.empty()) { |
| 1128 std::vector<std::string> uniscribe_fallbacks = | 1137 std::vector<std::string> uniscribe_fallbacks = |
| 1129 GetFallbackFontFamilies(uniscribe_family); | 1138 GetFallbackFontFamilies(uniscribe_family); |
| 1130 fallback_families.insert(fallback_families.end(), | 1139 fallback_families.insert(fallback_families.end(), |
| 1131 uniscribe_fallbacks.begin(), uniscribe_fallbacks.end()); | 1140 uniscribe_fallbacks.begin(), uniscribe_fallbacks.end()); |
| 1132 } | 1141 } |
| 1133 #endif | 1142 #endif |
| 1134 | 1143 |
| 1135 // Try shaping with the fallback fonts. | 1144 // Try shaping with the fallback fonts. |
| 1136 for (auto family : fallback_families) { | 1145 for (const auto& family : fallback_families) { |
| 1137 if (family == primary_family) | 1146 if (family == primary_family) |
| 1138 continue; | 1147 continue; |
| 1139 #if defined(OS_WIN) | 1148 #if defined(OS_WIN) |
| 1140 if (family == uniscribe_family) | 1149 if (family == uniscribe_family) |
| 1141 continue; | 1150 continue; |
| 1142 #endif | 1151 #endif |
| 1143 FontRenderParamsQuery query(false); | 1152 FontRenderParamsQuery query(false); |
| 1144 query.families.push_back(family); | 1153 query.families.push_back(family); |
| 1145 query.pixel_size = run->font_size; | 1154 query.pixel_size = run->font_size; |
| 1146 query.style = run->font_style; | 1155 query.style = run->font_style; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1211 if (!run->render_params.subpixel_positioning) | 1220 if (!run->render_params.subpixel_positioning) |
| 1212 run->width = std::floor(run->width + 0.5f); | 1221 run->width = std::floor(run->width + 0.5f); |
| 1213 } | 1222 } |
| 1214 | 1223 |
| 1215 hb_buffer_destroy(buffer); | 1224 hb_buffer_destroy(buffer); |
| 1216 hb_font_destroy(harfbuzz_font); | 1225 hb_font_destroy(harfbuzz_font); |
| 1217 return true; | 1226 return true; |
| 1218 } | 1227 } |
| 1219 | 1228 |
| 1220 } // namespace gfx | 1229 } // namespace gfx |
| OLD | NEW |