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

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: re-disable dwrite in tests, re-enable dwrite metrics 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 "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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698