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 <map> | 7 #include <map> |
8 | 8 |
9 #include "base/debug/leak_annotations.h" | 9 #include "base/debug/leak_annotations.h" |
10 #include "base/i18n/bidi_line_iterator.h" | 10 #include "base/i18n/bidi_line_iterator.h" |
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 DCHECK(!chars->is_empty()); | 426 DCHECK(!chars->is_empty()); |
427 DCHECK(!glyphs->is_reversed()); | 427 DCHECK(!glyphs->is_reversed()); |
428 DCHECK(!glyphs->is_empty()); | 428 DCHECK(!glyphs->is_empty()); |
429 } | 429 } |
430 | 430 |
431 } // namespace | 431 } // namespace |
432 | 432 |
433 namespace internal { | 433 namespace internal { |
434 | 434 |
435 TextRunHarfBuzz::TextRunHarfBuzz() | 435 TextRunHarfBuzz::TextRunHarfBuzz() |
436 : width(0), | 436 : width(0.0f), |
437 preceding_run_widths(0), | 437 preceding_run_widths(0.0f), |
438 is_rtl(false), | 438 is_rtl(false), |
439 level(0), | 439 level(0), |
440 script(USCRIPT_INVALID_CODE), | 440 script(USCRIPT_INVALID_CODE), |
441 glyph_count(static_cast<size_t>(-1)), | 441 glyph_count(static_cast<size_t>(-1)), |
442 font_size(0), | 442 font_size(0), |
443 font_style(0), | 443 font_style(0), |
444 strike(false), | 444 strike(false), |
445 diagonal_strike(false), | 445 diagonal_strike(false), |
446 underline(false) {} | 446 underline(false) {} |
447 | 447 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 size_t missing = 0; | 490 size_t missing = 0; |
491 for (size_t i = 0; i < glyph_count; ++i) | 491 for (size_t i = 0; i < glyph_count; ++i) |
492 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; | 492 missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0; |
493 return missing; | 493 return missing; |
494 } | 494 } |
495 | 495 |
496 Range TextRunHarfBuzz::GetGraphemeBounds( | 496 Range TextRunHarfBuzz::GetGraphemeBounds( |
497 base::i18n::BreakIterator* grapheme_iterator, | 497 base::i18n::BreakIterator* grapheme_iterator, |
498 size_t text_index) { | 498 size_t text_index) { |
499 DCHECK_LT(text_index, range.end()); | 499 DCHECK_LT(text_index, range.end()); |
| 500 // TODO(msw): Support floating point grapheme bounds. |
| 501 const int preceding_run_widths_int = SkScalarRoundToInt(preceding_run_widths); |
500 if (glyph_count == 0) | 502 if (glyph_count == 0) |
501 return Range(preceding_run_widths, preceding_run_widths + width); | 503 return Range(preceding_run_widths_int, preceding_run_widths_int + width); |
502 | 504 |
503 Range chars; | 505 Range chars; |
504 Range glyphs; | 506 Range glyphs; |
505 GetClusterAt(text_index, &chars, &glyphs); | 507 GetClusterAt(text_index, &chars, &glyphs); |
506 const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); | 508 const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); |
507 const int cluster_end_x = glyphs.end() < glyph_count ? | 509 const int cluster_end_x = glyphs.end() < glyph_count ? |
508 SkScalarRoundToInt(positions[glyphs.end()].x()) : width; | 510 SkScalarRoundToInt(positions[glyphs.end()].x()) : width; |
509 | 511 |
510 // A cluster consists of a number of code points and corresponds to a number | 512 // A cluster consists of a number of code points and corresponds to a number |
511 // of glyphs that should be drawn together. A cluster can contain multiple | 513 // of glyphs that should be drawn together. A cluster can contain multiple |
(...skipping 13 matching lines...) Expand all Loading... |
525 if (total > 1) { | 527 if (total > 1) { |
526 if (is_rtl) | 528 if (is_rtl) |
527 before = total - before - 1; | 529 before = total - before - 1; |
528 DCHECK_GE(before, 0); | 530 DCHECK_GE(before, 0); |
529 DCHECK_LT(before, total); | 531 DCHECK_LT(before, total); |
530 const int cluster_width = cluster_end_x - cluster_begin_x; | 532 const int cluster_width = cluster_end_x - cluster_begin_x; |
531 const int grapheme_begin_x = cluster_begin_x + static_cast<int>(0.5f + | 533 const int grapheme_begin_x = cluster_begin_x + static_cast<int>(0.5f + |
532 cluster_width * before / static_cast<float>(total)); | 534 cluster_width * before / static_cast<float>(total)); |
533 const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + | 535 const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + |
534 cluster_width * (before + 1) / static_cast<float>(total)); | 536 cluster_width * (before + 1) / static_cast<float>(total)); |
535 return Range(preceding_run_widths + grapheme_begin_x, | 537 return Range(preceding_run_widths_int + grapheme_begin_x, |
536 preceding_run_widths + grapheme_end_x); | 538 preceding_run_widths_int + grapheme_end_x); |
537 } | 539 } |
538 } | 540 } |
539 | 541 |
540 return Range(preceding_run_widths + cluster_begin_x, | 542 return Range(preceding_run_widths_int + cluster_begin_x, |
541 preceding_run_widths + cluster_end_x); | 543 preceding_run_widths_int + cluster_end_x); |
542 } | 544 } |
543 | 545 |
544 } // namespace internal | 546 } // namespace internal |
545 | 547 |
546 RenderTextHarfBuzz::RenderTextHarfBuzz() | 548 RenderTextHarfBuzz::RenderTextHarfBuzz() |
547 : RenderText(), | 549 : RenderText(), |
548 needs_layout_(false) {} | 550 needs_layout_(false) {} |
549 | 551 |
550 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} | 552 RenderTextHarfBuzz::~RenderTextHarfBuzz() {} |
551 | 553 |
552 Size RenderTextHarfBuzz::GetStringSize() { | 554 Size RenderTextHarfBuzz::GetStringSize() { |
| 555 const SizeF size_f = GetStringSizeF(); |
| 556 return Size(std::ceil(size_f.width()), size_f.height()); |
| 557 } |
| 558 |
| 559 SizeF RenderTextHarfBuzz::GetStringSizeF() { |
553 EnsureLayout(); | 560 EnsureLayout(); |
554 return lines()[0].size; | 561 return lines()[0].size; |
555 } | 562 } |
556 | 563 |
557 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { | 564 SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { |
558 EnsureLayout(); | 565 EnsureLayout(); |
559 | 566 |
560 int x = ToTextPoint(point).x(); | 567 int x = ToTextPoint(point).x(); |
561 int offset = 0; | 568 int offset = 0; |
562 size_t run_index = GetRunContainingXCoord(x, &offset); | 569 size_t run_index = GetRunContainingXCoord(x, &offset); |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
782 base::i18n::BreakIterator::BREAK_CHARACTER)); | 789 base::i18n::BreakIterator::BREAK_CHARACTER)); |
783 if (!grapheme_iterator_->Init()) | 790 if (!grapheme_iterator_->Init()) |
784 grapheme_iterator_.reset(); | 791 grapheme_iterator_.reset(); |
785 | 792 |
786 ItemizeText(); | 793 ItemizeText(); |
787 | 794 |
788 for (size_t i = 0; i < runs_.size(); ++i) | 795 for (size_t i = 0; i < runs_.size(); ++i) |
789 ShapeRun(runs_[i]); | 796 ShapeRun(runs_[i]); |
790 | 797 |
791 // Precalculate run width information. | 798 // Precalculate run width information. |
792 size_t preceding_run_widths = 0; | 799 float preceding_run_widths = 0.0f; |
793 for (size_t i = 0; i < runs_.size(); ++i) { | 800 for (size_t i = 0; i < runs_.size(); ++i) { |
794 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; | 801 internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]]; |
795 run->preceding_run_widths = preceding_run_widths; | 802 run->preceding_run_widths = preceding_run_widths; |
796 preceding_run_widths += run->width; | 803 preceding_run_widths += run->width; |
797 } | 804 } |
798 } | 805 } |
799 | 806 |
800 needs_layout_ = false; | 807 needs_layout_ = false; |
801 std::vector<internal::Line> empty_lines; | 808 std::vector<internal::Line> empty_lines; |
802 set_lines(&empty_lines); | 809 set_lines(&empty_lines); |
(...skipping 16 matching lines...) Expand all Loading... |
819 segment.run = i; | 826 segment.run = i; |
820 lines[0].segments.push_back(segment); | 827 lines[0].segments.push_back(segment); |
821 | 828 |
822 paint.setTypeface(run.skia_face.get()); | 829 paint.setTypeface(run.skia_face.get()); |
823 paint.setTextSize(run.font_size); | 830 paint.setTextSize(run.font_size); |
824 SkPaint::FontMetrics metrics; | 831 SkPaint::FontMetrics metrics; |
825 paint.getFontMetrics(&metrics); | 832 paint.getFontMetrics(&metrics); |
826 | 833 |
827 lines[0].size.set_width(lines[0].size.width() + run.width); | 834 lines[0].size.set_width(lines[0].size.width() + run.width); |
828 lines[0].size.set_height(std::max(lines[0].size.height(), | 835 lines[0].size.set_height(std::max(lines[0].size.height(), |
829 SkScalarRoundToInt(metrics.fDescent - metrics.fAscent))); | 836 metrics.fDescent - metrics.fAscent)); |
830 lines[0].baseline = std::max(lines[0].baseline, | 837 lines[0].baseline = std::max(lines[0].baseline, |
831 SkScalarRoundToInt(-metrics.fAscent)); | 838 SkScalarRoundToInt(-metrics.fAscent)); |
832 } | 839 } |
833 | 840 |
834 set_lines(&lines); | 841 set_lines(&lines); |
835 } | 842 } |
836 } | 843 } |
837 | 844 |
838 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { | 845 void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
839 DCHECK(!needs_layout_); | 846 DCHECK(!needs_layout_); |
(...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1064 best_font = current_font; | 1071 best_font = current_font; |
1065 } | 1072 } |
1066 } | 1073 } |
1067 | 1074 |
1068 if (!best_font.empty() && | 1075 if (!best_font.empty() && |
1069 (best_font == current_font || ShapeRunWithFont(run, best_font))) { | 1076 (best_font == current_font || ShapeRunWithFont(run, best_font))) { |
1070 return; | 1077 return; |
1071 } | 1078 } |
1072 | 1079 |
1073 run->glyph_count = 0; | 1080 run->glyph_count = 0; |
1074 run->width = 0; | 1081 run->width = 0.0f; |
1075 } | 1082 } |
1076 | 1083 |
1077 bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, | 1084 bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run, |
1078 const std::string& font_family) { | 1085 const std::string& font_family) { |
1079 const base::string16& text = GetLayoutText(); | 1086 const base::string16& text = GetLayoutText(); |
1080 skia::RefPtr<SkTypeface> skia_face = | 1087 skia::RefPtr<SkTypeface> skia_face = |
1081 internal::CreateSkiaTypeface(font_family, run->font_style); | 1088 internal::CreateSkiaTypeface(font_family, run->font_style); |
1082 if (skia_face == NULL) | 1089 if (skia_face == NULL) |
1083 return false; | 1090 return false; |
1084 run->skia_face = skia_face; | 1091 run->skia_face = skia_face; |
(...skipping 17 matching lines...) Expand all Loading... |
1102 | 1109 |
1103 // Populate the run fields with the resulting glyph data in the buffer. | 1110 // Populate the run fields with the resulting glyph data in the buffer. |
1104 unsigned int glyph_count = 0; | 1111 unsigned int glyph_count = 0; |
1105 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); | 1112 hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count); |
1106 run->glyph_count = glyph_count; | 1113 run->glyph_count = glyph_count; |
1107 hb_glyph_position_t* hb_positions = | 1114 hb_glyph_position_t* hb_positions = |
1108 hb_buffer_get_glyph_positions(buffer, NULL); | 1115 hb_buffer_get_glyph_positions(buffer, NULL); |
1109 run->glyphs.reset(new uint16[run->glyph_count]); | 1116 run->glyphs.reset(new uint16[run->glyph_count]); |
1110 run->glyph_to_char.resize(run->glyph_count); | 1117 run->glyph_to_char.resize(run->glyph_count); |
1111 run->positions.reset(new SkPoint[run->glyph_count]); | 1118 run->positions.reset(new SkPoint[run->glyph_count]); |
1112 run->width = 0; | 1119 run->width = 0.0f; |
1113 for (size_t i = 0; i < run->glyph_count; ++i) { | 1120 for (size_t i = 0; i < run->glyph_count; ++i) { |
1114 run->glyphs[i] = infos[i].codepoint; | 1121 run->glyphs[i] = infos[i].codepoint; |
1115 run->glyph_to_char[i] = infos[i].cluster; | 1122 run->glyph_to_char[i] = infos[i].cluster; |
1116 const int x_offset = | 1123 const int x_offset = SkFixedToScalar(hb_positions[i].x_offset); |
1117 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset)); | 1124 const int y_offset = SkFixedToScalar(hb_positions[i].y_offset); |
1118 const int y_offset = | |
1119 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset)); | |
1120 run->positions[i].set(run->width + x_offset, -y_offset); | 1125 run->positions[i].set(run->width + x_offset, -y_offset); |
1121 run->width += | 1126 run->width += SkFixedToScalar(hb_positions[i].x_advance); |
1122 SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance)); | |
1123 } | 1127 } |
1124 | 1128 |
1125 hb_buffer_destroy(buffer); | 1129 hb_buffer_destroy(buffer); |
1126 hb_font_destroy(harfbuzz_font); | 1130 hb_font_destroy(harfbuzz_font); |
1127 return true; | 1131 return true; |
1128 } | 1132 } |
1129 | 1133 |
1130 } // namespace gfx | 1134 } // namespace gfx |
OLD | NEW |