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