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 |