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

Side by Side Diff: ui/gfx/render_text_harfbuzz.cc

Issue 738363002: Enable subpixel positioning for UI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 6 years 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 // 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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698