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

Unified Diff: ui/gfx/render_text_harfbuzz.cc

Issue 916203002: Reduce the number of text reshaping in RenderText (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 10 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_mac.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/gfx/render_text_harfbuzz.cc
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index e4469a6fdfa2500f117317a0b22e84bfac6deb4c..7e916ff3ae21142a633c45521e402b3b1b44ebc8 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -10,6 +10,8 @@
#include "base/i18n/break_iterator.h"
#include "base/i18n/char_iterator.h"
#include "base/profiler/scoped_tracker.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
#include "third_party/harfbuzz-ng/src/hb.h"
#include "third_party/icu/source/common/unicode/ubidi.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -574,11 +576,48 @@ RangeF TextRunHarfBuzz::GetGraphemeBounds(
preceding_run_widths + cluster_end_x);
}
+TextRunList::TextRunList() : width_(0.0f) {}
+
+TextRunList::~TextRunList() {}
+
+void TextRunList::Reset() {
+ runs_.clear();
+ width_ = 0.0f;
+}
+
+void TextRunList::InitIndexMap() {
+ if (runs_.size() == 1) {
+ visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0);
+ return;
+ }
+ const size_t num_runs = runs_.size();
+ std::vector<UBiDiLevel> levels(num_runs);
+ for (size_t i = 0; i < num_runs; ++i)
+ levels[i] = runs_[i]->level;
+ visual_to_logical_.resize(num_runs);
+ ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]);
+ logical_to_visual_.resize(num_runs);
+ ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]);
+}
+
+void TextRunList::ComputePrecedingRunWidths() {
+ // Precalculate run width information.
+ width_ = 0.0f;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ run->preceding_run_widths = width_;
+ width_ += run->width;
+ }
+}
+
} // namespace internal
RenderTextHarfBuzz::RenderTextHarfBuzz()
: RenderText(),
- needs_layout_(false),
+ update_layout_run_list_(false),
+ update_display_run_list_(false),
+ update_grapheme_iterator_(false),
+ update_display_text_(false),
glyph_width_for_test_(0u) {
set_truncate_length(kMaxTextLength);
}
@@ -589,6 +628,25 @@ scoped_ptr<RenderText> RenderTextHarfBuzz::CreateInstanceOfSameType() const {
return scoped_ptr<RenderTextHarfBuzz>(new RenderTextHarfBuzz);
}
+const base::string16& RenderTextHarfBuzz::GetDisplayText() {
+ // TODO(oshima): Consider supporting eliding multi-line text.
+ // This requires max_line support first.
+ if (multiline() ||
+ elide_behavior() == NO_ELIDE ||
+ elide_behavior() == FADE_TAIL) {
+ // Call UpdateDisplayText to clear |display_text_| and |text_elided_|
+ // on the RenderText class.
+ UpdateDisplayText(0);
+ update_display_text_ = false;
+ display_run_list_.reset();
+ return layout_text();
+ }
+
+ EnsureLayoutRunList();
+ DCHECK(!update_display_text_);
+ return text_elided() ? display_text() : layout_text();
+}
+
Size RenderTextHarfBuzz::GetStringSize() {
const SizeF size_f = GetStringSizeF();
return Size(std::ceil(size_f.width()), size_f.height());
@@ -605,22 +663,23 @@ SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) {
int x = ToTextPoint(point).x();
float offset = 0;
size_t run_index = GetRunContainingXCoord(x, &offset);
- if (run_index >= runs_.size())
- return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
- const internal::TextRunHarfBuzz& run = *runs_[run_index];
+ internal::TextRunList* run_list = GetRunList();
+ if (run_index >= run_list->size())
+ return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
+ const internal::TextRunHarfBuzz& run = *run_list->runs()[run_index];
for (size_t i = 0; i < run.glyph_count; ++i) {
const SkScalar end =
i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x();
const SkScalar middle = (end + run.positions[i].x()) / 2;
if (offset < middle) {
- return SelectionModel(LayoutIndexToTextIndex(
+ return SelectionModel(DisplayIndexToTextIndex(
run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)),
(run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD));
}
if (offset < end) {
- return SelectionModel(LayoutIndexToTextIndex(
+ return SelectionModel(DisplayIndexToTextIndex(
run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)),
(run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD));
}
@@ -631,14 +690,16 @@ SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) {
std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() {
EnsureLayout();
+ internal::TextRunList* run_list = GetRunList();
std::vector<RenderText::FontSpan> spans;
- for (size_t i = 0; i < runs_.size(); ++i) {
+ for (auto* run : run_list->runs()) {
SkString family_name;
- runs_[i]->skia_face->getFamilyName(&family_name);
- Font font(family_name.c_str(), runs_[i]->font_size);
- spans.push_back(RenderText::FontSpan(font,
- Range(LayoutIndexToTextIndex(runs_[i]->range.start()),
- LayoutIndexToTextIndex(runs_[i]->range.end()))));
+ run->skia_face->getFamilyName(&family_name);
+ Font font(family_name.c_str(), run->font_size);
+ spans.push_back(RenderText::FontSpan(
+ font,
+ Range(DisplayIndexToTextIndex(run->range.start()),
+ DisplayIndexToTextIndex(run->range.end()))));
}
return spans;
@@ -648,23 +709,24 @@ Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) {
EnsureLayout();
const size_t run_index =
GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
+ internal::TextRunList* run_list = GetRunList();
// Return edge bounds if the index is invalid or beyond the layout text size.
- if (run_index >= runs_.size())
+ if (run_index >= run_list->size())
return Range(GetStringSize().width());
- const size_t layout_index = TextIndexToLayoutIndex(index);
- internal::TextRunHarfBuzz* run = runs_[run_index];
+ const size_t layout_index = TextIndexToDisplayIndex(index);
+ internal::TextRunHarfBuzz* run = run_list->runs()[run_index];
RangeF bounds =
- run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index);
+ run->GetGraphemeBounds(GetGraphemeIterator(), layout_index);
// If cursor is enabled, extend the last glyph up to the rightmost cursor
// position since clients expect them to be contiguous.
- if (cursor_enabled() && run_index == runs_.size() - 1 &&
+ if (cursor_enabled() && run_index == run_list->size() - 1 &&
index == (run->is_rtl ? run->range.start() : run->range.end() - 1))
bounds.second = std::ceil(bounds.second);
return RoundRangeF(run->is_rtl ?
RangeF(bounds.second, bounds.first) : bounds);
}
-int RenderTextHarfBuzz::GetLayoutTextBaseline() {
+int RenderTextHarfBuzz::GetDisplayTextBaseline() {
EnsureLayout();
return lines()[0].baseline;
}
@@ -672,39 +734,42 @@ int RenderTextHarfBuzz::GetLayoutTextBaseline() {
SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel(
const SelectionModel& selection,
VisualCursorDirection direction) {
- DCHECK(!needs_layout_);
+ DCHECK(!update_display_run_list_);
+
+ internal::TextRunList* run_list = GetRunList();
internal::TextRunHarfBuzz* run;
+
size_t run_index = GetRunContainingCaret(selection);
- if (run_index >= runs_.size()) {
+ if (run_index >= run_list->size()) {
// The cursor is not in any run: we're at the visual and logical edge.
SelectionModel edge = EdgeSelectionModel(direction);
if (edge.caret_pos() == selection.caret_pos())
return edge;
- int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1;
- run = runs_[visual_to_logical_[visual_index]];
+ int visual_index = (direction == CURSOR_RIGHT) ? 0 : run_list->size() - 1;
+ run = run_list->runs()[run_list->visual_to_logical(visual_index)];
} else {
// If the cursor is moving within the current run, just move it by one
// grapheme in the appropriate direction.
- run = runs_[run_index];
+ run = run_list->runs()[run_index];
size_t caret = selection.caret_pos();
bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
if (forward_motion) {
- if (caret < LayoutIndexToTextIndex(run->range.end())) {
+ if (caret < DisplayIndexToTextIndex(run->range.end())) {
caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
return SelectionModel(caret, CURSOR_BACKWARD);
}
} else {
- if (caret > LayoutIndexToTextIndex(run->range.start())) {
+ if (caret > DisplayIndexToTextIndex(run->range.start())) {
caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
return SelectionModel(caret, CURSOR_FORWARD);
}
}
// The cursor is at the edge of a run; move to the visually adjacent run.
- int visual_index = logical_to_visual_[run_index];
+ int visual_index = run_list->logical_to_visual(run_index);
visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
- if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size()))
+ if (visual_index < 0 || visual_index >= static_cast<int>(run_list->size()))
return EdgeSelectionModel(direction);
- run = runs_[visual_to_logical_[visual_index]];
+ run = run_list->runs()[run_list->visual_to_logical(visual_index)];
}
bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
return forward_motion ? FirstSelectionModelInsideRun(run) :
@@ -758,13 +823,15 @@ SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
}
return SelectionModel(pos, CURSOR_FORWARD);
#else
+ internal::TextRunList* run_list = GetRunList();
SelectionModel cur(selection);
for (;;) {
cur = AdjacentCharSelectionModel(cur, direction);
size_t run = GetRunContainingCaret(cur);
- if (run == runs_.size())
+ if (run == run_list->size())
break;
- const bool is_forward = runs_[run]->is_rtl == (direction == CURSOR_LEFT);
+ const bool is_forward =
+ run_list->runs()[run]->is_rtl == (direction == CURSOR_LEFT);
size_t cursor = cur.caret_pos();
if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor))
break;
@@ -774,29 +841,32 @@ SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
}
std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
- DCHECK(!needs_layout_);
+ DCHECK(!update_display_run_list_);
DCHECK(Range(0, text().length()).Contains(range));
- Range layout_range(TextIndexToLayoutIndex(range.start()),
- TextIndexToLayoutIndex(range.end()));
- DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range));
+ Range layout_range(TextIndexToDisplayIndex(range.start()),
+ TextIndexToDisplayIndex(range.end()));
+ DCHECK(Range(0, GetDisplayText().length()).Contains(layout_range));
std::vector<Rect> rects;
if (layout_range.is_empty())
return rects;
std::vector<Range> bounds;
+ internal::TextRunList* run_list = GetRunList();
+
// Add a Range for each run/selection intersection.
- for (size_t i = 0; i < runs_.size(); ++i) {
- internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ for (size_t i = 0; i < run_list->size(); ++i) {
+ internal::TextRunHarfBuzz* run =
+ run_list->runs()[run_list->visual_to_logical(i)];
Range intersection = run->range.Intersect(layout_range);
if (!intersection.IsValid())
continue;
DCHECK(!intersection.is_reversed());
const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds(
- grapheme_iterator_.get(),
+ GetGraphemeIterator(),
run->is_rtl ? intersection.end() - 1 : intersection.start()));
const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds(
- grapheme_iterator_.get(),
+ GetGraphemeIterator(),
run->is_rtl ? intersection.start() : intersection.end() - 1));
Range range_x(leftmost_character_x.start(), rightmost_character_x.end());
DCHECK(!range_x.is_reversed());
@@ -811,26 +881,20 @@ std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
}
bounds.push_back(range_x);
}
- for (size_t i = 0; i < bounds.size(); ++i) {
- std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]);
+ for (Range& bound : bounds) {
+ std::vector<Rect> current_rects = TextBoundsToViewBounds(bound);
rects.insert(rects.end(), current_rects.begin(), current_rects.end());
}
return rects;
}
-size_t RenderTextHarfBuzz::TextIndexToLayoutIndex(size_t index) const {
- DCHECK_LE(index, text().length());
- ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
- CHECK_GE(i, 0);
- // Clamp layout indices to the length of the text actually used for layout.
- return std::min<size_t>(GetLayoutText().length(), i);
+size_t RenderTextHarfBuzz::TextIndexToDisplayIndex(size_t index) {
+ return TextIndexToGivenTextIndex(GetDisplayText(), index);
}
-size_t RenderTextHarfBuzz::LayoutIndexToTextIndex(size_t index) const {
+size_t RenderTextHarfBuzz::DisplayIndexToTextIndex(size_t index) {
if (!obscured())
return index;
-
- DCHECK_LE(index, GetLayoutText().length());
const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
DCHECK_LE(text_index, text().length());
return text_index;
@@ -841,12 +905,18 @@ bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) {
return true;
if (!IsValidLogicalIndex(index))
return false;
- EnsureLayout();
- return !grapheme_iterator_ || grapheme_iterator_->IsGraphemeBoundary(index);
+ base::i18n::BreakIterator* grapheme_iterator = GetGraphemeIterator();
+ return !grapheme_iterator || grapheme_iterator->IsGraphemeBoundary(index);
+}
+
+void RenderTextHarfBuzz::OnLayoutTextAttributeChanged(bool text_changed) {
+ update_layout_run_list_ = true;
+ OnDisplayTextAttributeChanged();
}
-void RenderTextHarfBuzz::ResetLayout() {
- needs_layout_ = true;
+void RenderTextHarfBuzz::OnDisplayTextAttributeChanged() {
+ update_display_text_ = true;
+ update_grapheme_iterator_ = true;
}
void RenderTextHarfBuzz::EnsureLayout() {
@@ -855,61 +925,37 @@ void RenderTextHarfBuzz::EnsureLayout() {
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::EnsureLayout"));
- if (needs_layout_) {
- runs_.clear();
- grapheme_iterator_.reset();
+ EnsureLayoutRunList();
- if (!GetLayoutText().empty()) {
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile1(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "431326 RenderTextHarfBuzz::EnsureLayout1"));
+ if (update_display_run_list_) {
+ DCHECK(text_elided());
+ const base::string16& display_text = GetDisplayText();
+ display_run_list_.reset(new internal::TextRunList);
- grapheme_iterator_.reset(new base::i18n::BreakIterator(GetLayoutText(),
- base::i18n::BreakIterator::BREAK_CHARACTER));
- if (!grapheme_iterator_->Init())
- grapheme_iterator_.reset();
+ if (!display_text.empty()) {
+ TRACE_EVENT0("ui", "RenderTextHarfBuzz:EnsureLayout1");
// TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
// fixed.
- tracked_objects::ScopedTracker tracking_profile11(
+ tracked_objects::ScopedTracker tracking_profile1(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "431326 RenderTextHarfBuzz::EnsureLayout11"));
-
- ItemizeText();
+ "431326 RenderTextHarfBuzz::EnsureLayout1"));
+ ItemizeTextToRuns(display_text, display_run_list_.get());
// TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
// fixed.
- tracked_objects::ScopedTracker tracking_profile12(
+ tracked_objects::ScopedTracker tracking_profile2(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::EnsureLayout12"));
-
- for (size_t i = 0; i < runs_.size(); ++i)
- ShapeRun(runs_[i]);
-
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile13(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "431326 RenderTextHarfBuzz::EnsureLayout13"));
-
- // Precalculate run width information.
- float preceding_run_widths = 0.0f;
- for (size_t i = 0; i < runs_.size(); ++i) {
- internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
- run->preceding_run_widths = preceding_run_widths;
- preceding_run_widths += run->width;
- }
+ ShapeRunList(display_text, display_run_list_.get());
}
+ update_display_run_list_ = false;
// TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
// fixed.
tracked_objects::ScopedTracker tracking_profile14(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::EnsureLayout14"));
-
- needs_layout_ = false;
std::vector<internal::Line> empty_lines;
set_lines(&empty_lines);
}
@@ -920,18 +966,21 @@ void RenderTextHarfBuzz::EnsureLayout() {
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::EnsureLayout2"));
+ internal::TextRunList* run_list = GetRunList();
HarfBuzzLineBreaker line_breaker(
display_rect().width(), font_list().GetBaseline(),
std::max(font_list().GetHeight(), min_line_height()), multiline(),
- GetLayoutText(), multiline() ? &GetLineBreaks() : nullptr, runs_);
+ GetDisplayText(), multiline() ? &GetLineBreaks() : nullptr,
+ run_list->runs());
// TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
tracked_objects::ScopedTracker tracking_profile3(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::EnsureLayout3"));
- for (size_t i = 0; i < runs_.size(); ++i)
- line_breaker.AddRun(visual_to_logical_[i]);
+ for (size_t i = 0; i < run_list->size(); ++i)
+ line_breaker.AddRun(run_list->visual_to_logical(i));
+
std::vector<internal::Line> lines;
line_breaker.Finalize(&lines, &total_size_);
set_lines(&lines);
@@ -939,7 +988,9 @@ void RenderTextHarfBuzz::EnsureLayout() {
}
void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
- DCHECK(!needs_layout_);
+ DCHECK(!update_layout_run_list_);
+ DCHECK(!update_display_run_list_);
+ DCHECK(!update_display_text_);
if (lines().empty())
return;
@@ -948,12 +999,13 @@ void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
ApplyTextShadows(&renderer);
ApplyCompositionAndSelectionStyles();
+ internal::TextRunList* run_list = GetRunList();
for (size_t i = 0; i < lines().size(); ++i) {
const internal::Line& line = lines()[i];
const Vector2d origin = GetLineOffset(i) + Vector2d(0, line.baseline);
SkScalar preceding_segment_widths = 0;
for (const internal::LineSegment& segment : line.segments) {
- const internal::TextRunHarfBuzz& run = *runs_[segment.run];
+ const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run];
renderer.SetTypeface(run.skia_face.get());
renderer.SetTextSize(SkIntToScalar(run.font_size));
renderer.SetFontRenderParams(run.render_params,
@@ -1009,52 +1061,56 @@ void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
}
size_t RenderTextHarfBuzz::GetRunContainingCaret(
- const SelectionModel& caret) const {
- DCHECK(!needs_layout_);
- size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
+ const SelectionModel& caret) {
+ DCHECK(!update_display_run_list_);
+ size_t layout_position = TextIndexToDisplayIndex(caret.caret_pos());
LogicalCursorDirection affinity = caret.caret_affinity();
- for (size_t run = 0; run < runs_.size(); ++run) {
- if (RangeContainsCaret(runs_[run]->range, layout_position, affinity))
- return run;
+ internal::TextRunList* run_list = GetRunList();
+ for (size_t i = 0; i < run_list->size(); ++i) {
+ internal::TextRunHarfBuzz* run = run_list->runs()[i];
+ if (RangeContainsCaret(run->range, layout_position, affinity))
+ return i;
}
- return runs_.size();
+ return run_list->size();
}
size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x,
float* offset) const {
- DCHECK(!needs_layout_);
+ DCHECK(!update_display_run_list_);
+ const internal::TextRunList* run_list = GetRunList();
if (x < 0)
- return runs_.size();
+ return run_list->size();
// Find the text run containing the argument point (assumed already offset).
float current_x = 0;
- for (size_t i = 0; i < runs_.size(); ++i) {
- size_t run = visual_to_logical_[i];
- current_x += runs_[run]->width;
+ for (size_t i = 0; i < run_list->size(); ++i) {
+ size_t run = run_list->visual_to_logical(i);
+ current_x += run_list->runs()[run]->width;
if (x < current_x) {
- *offset = x - (current_x - runs_[run]->width);
+ *offset = x - (current_x - run_list->runs()[run]->width);
return run;
}
}
- return runs_.size();
+ return run_list->size();
}
SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun(
const internal::TextRunHarfBuzz* run) {
- size_t position = LayoutIndexToTextIndex(run->range.start());
+ size_t position = DisplayIndexToTextIndex(run->range.start());
position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD);
return SelectionModel(position, CURSOR_BACKWARD);
}
SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun(
const internal::TextRunHarfBuzz* run) {
- size_t position = LayoutIndexToTextIndex(run->range.end());
+ size_t position = DisplayIndexToTextIndex(run->range.end());
position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
return SelectionModel(position, CURSOR_FORWARD);
}
-void RenderTextHarfBuzz::ItemizeText() {
- const base::string16& text = GetLayoutText();
- const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+void RenderTextHarfBuzz::ItemizeTextToRuns(
+ const base::string16& text,
+ internal::TextRunList* run_list_out) {
+ const bool is_text_rtl = GetTextDirection(text) == base::i18n::RIGHT_TO_LEFT;
DCHECK_NE(0U, text.length());
// If ICU fails to itemize the text, we create a run that spans the entire
@@ -1064,8 +1120,8 @@ void RenderTextHarfBuzz::ItemizeText() {
if (!bidi_iterator.Open(text, is_text_rtl, false)) {
internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
run->range = Range(0, text.length());
- runs_.push_back(run);
- visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0);
+ run_list_out->add(run);
+ run_list_out->InitIndexMap();
return;
}
@@ -1086,7 +1142,6 @@ void RenderTextHarfBuzz::ItemizeText() {
run->strike = style.style(STRIKE);
run->diagonal_strike = style.style(DIAGONAL_STRIKE);
run->underline = style.style(UNDERLINE);
-
int32 script_item_break = 0;
bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level);
// Odd BiDi embedding levels correspond to RTL runs.
@@ -1096,8 +1151,9 @@ void RenderTextHarfBuzz::ItemizeText() {
script_item_break - run_break, &run->script) + run_break;
// Find the next break and advance the iterators as needed.
- run_break = std::min(static_cast<size_t>(script_item_break),
- TextIndexToLayoutIndex(style.GetRange().end()));
+ run_break = std::min(
+ static_cast<size_t>(script_item_break),
+ TextIndexToGivenTextIndex(text, style.GetRange().end()));
// Break runs at certain characters that need to be rendered separately to
// prevent either an unusual character from forcing a fallback font on the
@@ -1107,33 +1163,27 @@ void RenderTextHarfBuzz::ItemizeText() {
run_break = FindRunBreakingCharacter(text, run->range.start(), run_break);
DCHECK(IsValidCodePointIndex(text, run_break));
- style.UpdatePosition(LayoutIndexToTextIndex(run_break));
+ style.UpdatePosition(DisplayIndexToTextIndex(run_break));
run->range.set_end(run_break);
- runs_.push_back(run);
+ run_list_out->add(run);
}
// Undo the temporarily applied composition underlines and selection colors.
UndoCompositionAndSelectionStyles();
- const size_t num_runs = runs_.size();
- std::vector<UBiDiLevel> levels(num_runs);
- for (size_t i = 0; i < num_runs; ++i)
- levels[i] = runs_[i]->level;
- visual_to_logical_.resize(num_runs);
- ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]);
- logical_to_visual_.resize(num_runs);
- ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]);
+ run_list_out->InitIndexMap();
}
bool RenderTextHarfBuzz::CompareFamily(
- internal::TextRunHarfBuzz* run,
+ const base::string16& text,
const std::string& family,
const gfx::FontRenderParams& render_params,
+ internal::TextRunHarfBuzz* run,
std::string* best_family,
gfx::FontRenderParams* best_render_params,
size_t* best_missing_glyphs) {
- if (!ShapeRunWithFont(run, family, render_params))
+ if (!ShapeRunWithFont(text, family, render_params, run))
return false;
const size_t missing_glyphs = run->CountMissingGlyphs();
@@ -1145,7 +1195,15 @@ bool RenderTextHarfBuzz::CompareFamily(
return missing_glyphs == 0;
}
-void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
+void RenderTextHarfBuzz::ShapeRunList(const base::string16& text,
+ internal::TextRunList* run_list) {
+ for (auto* run : run_list->runs())
+ ShapeRun(text, run);
+ run_list->ComputePrecedingRunWidths();
+}
+
+void RenderTextHarfBuzz::ShapeRun(const base::string16& text,
+ internal::TextRunHarfBuzz* run) {
const Font& primary_font = font_list().GetPrimaryFont();
const std::string primary_family = primary_font.GetFontName();
run->font_size = primary_font.GetFontSize();
@@ -1155,20 +1213,21 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
size_t best_missing_glyphs = std::numeric_limits<size_t>::max();
for (const Font& font : font_list().GetFonts()) {
- if (CompareFamily(run, font.GetFontName(), font.GetFontRenderParams(),
- &best_family, &best_render_params, &best_missing_glyphs))
+ if (CompareFamily(text, font.GetFontName(), font.GetFontRenderParams(),
+ run, &best_family, &best_render_params,
+ &best_missing_glyphs))
return;
}
#if defined(OS_WIN)
Font uniscribe_font;
std::string uniscribe_family;
- const base::char16* run_text = &(GetLayoutText()[run->range.start()]);
+ const base::char16* run_text = &(text[run->range.start()]);
if (GetUniscribeFallbackFont(primary_font, run_text, run->range.length(),
&uniscribe_font)) {
uniscribe_family = uniscribe_font.GetFontName();
- if (CompareFamily(run, uniscribe_family,
- uniscribe_font.GetFontRenderParams(),
+ if (CompareFamily(text, uniscribe_family,
+ uniscribe_font.GetFontRenderParams(), run,
&best_family, &best_render_params, &best_missing_glyphs))
return;
}
@@ -1200,29 +1259,29 @@ void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
query.pixel_size = run->font_size;
query.style = run->font_style;
FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL);
- if (CompareFamily(run, family, fallback_render_params, &best_family,
+ if (CompareFamily(text, family, fallback_render_params, run, &best_family,
&best_render_params, &best_missing_glyphs))
return;
}
if (!best_family.empty() &&
(best_family == run->family ||
- ShapeRunWithFont(run, best_family, best_render_params)))
+ ShapeRunWithFont(text, best_family, best_render_params, run)))
return;
run->glyph_count = 0;
run->width = 0.0f;
}
-bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run,
+bool RenderTextHarfBuzz::ShapeRunWithFont(const base::string16& text,
const std::string& font_family,
- const FontRenderParams& params) {
+ const FontRenderParams& params,
+ internal::TextRunHarfBuzz* run) {
// TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is fixed.
tracked_objects::ScopedTracker tracking_profile0(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"431326 RenderTextHarfBuzz::ShapeRunWithFont0"));
- const base::string16& text = GetLayoutText();
skia::RefPtr<SkTypeface> skia_face =
internal::CreateSkiaTypeface(font_family, run->font_style);
if (skia_face == NULL)
@@ -1330,4 +1389,78 @@ bool RenderTextHarfBuzz::ShapeRunWithFont(internal::TextRunHarfBuzz* run,
return true;
}
+void RenderTextHarfBuzz::EnsureLayoutRunList() {
+ if (update_layout_run_list_) {
+ layout_run_list_.Reset();
+
+ const base::string16& text = layout_text();
+ if (!text.empty()) {
+ TRACE_EVENT0("ui", "RenderTextHarfBuzz:EnsureLayoutRunList");
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "431326 RenderTextHarfBuzz::EnsureLayout1"));
+ ItemizeTextToRuns(text, &layout_run_list_);
+
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "431326 RenderTextHarfBuzz::EnsureLayout12"));
+ ShapeRunList(text, &layout_run_list_);
+ }
+
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/431326 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile14(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "431326 RenderTextHarfBuzz::EnsureLayout14"));
+
+ std::vector<internal::Line> empty_lines;
+ set_lines(&empty_lines);
+ display_run_list_.reset();
+ update_display_text_ = true;
+ update_layout_run_list_ = false;
+ }
+ if (update_display_text_) {
+ UpdateDisplayText(multiline() ? 0 : layout_run_list_.width());
+ update_display_text_ = false;
+ update_display_run_list_ = text_elided();
+ }
+}
+
+base::i18n::BreakIterator* RenderTextHarfBuzz::GetGraphemeIterator() {
+ if (update_grapheme_iterator_) {
+ update_grapheme_iterator_ = false;
+ grapheme_iterator_.reset(new base::i18n::BreakIterator(
+ GetDisplayText(),
+ base::i18n::BreakIterator::BREAK_CHARACTER));
+ if (!grapheme_iterator_->Init())
+ grapheme_iterator_.reset();
+ }
+ return grapheme_iterator_.get();
+}
+
+size_t RenderTextHarfBuzz::TextIndexToGivenTextIndex(
+ const base::string16& given_text,
+ size_t index) {
+ DCHECK(given_text == layout_text() || given_text == display_text());
+ DCHECK_LE(index, text().length());
+ ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
+ CHECK_GE(i, 0);
+ // Clamp indices to the length of the given layout or display text.
+ return std::min<size_t>(given_text.length(), i);
+}
+
+internal::TextRunList* RenderTextHarfBuzz::GetRunList() {
+ DCHECK(!update_layout_run_list_);
+ DCHECK(!update_display_run_list_);
+ return text_elided() ? display_run_list_.get() : &layout_run_list_;
+}
+
+const internal::TextRunList* RenderTextHarfBuzz::GetRunList() const {
+ return const_cast<RenderTextHarfBuzz*>(this)->GetRunList();
+}
+
} // namespace gfx
« no previous file with comments | « ui/gfx/render_text_harfbuzz.h ('k') | ui/gfx/render_text_mac.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698