Index: ui/gfx/render_text_harfbuzz.cc |
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc |
index 5628b9b5c8d0dbd4dc239ec6cca623299c3622eb..508655b61bf2c04b773b3ab34014bac55d5511b8 100644 |
--- a/ui/gfx/render_text_harfbuzz.cc |
+++ b/ui/gfx/render_text_harfbuzz.cc |
@@ -25,6 +25,9 @@ |
#include "ui/gfx/font_fallback_win.h" |
#endif |
+using gfx::internal::RangeF; |
+using gfx::internal::RoundRangeF; |
+ |
namespace gfx { |
namespace { |
@@ -461,6 +464,11 @@ void GetClusterAtImpl(size_t pos, |
namespace internal { |
+Range RoundRangeF(const RangeF& range_f) { |
+ return Range(std::floor(range_f.first + 0.5f), |
+ std::floor(range_f.second + 0.5f)); |
+} |
+ |
TextRunHarfBuzz::TextRunHarfBuzz() |
: width(0.0f), |
preceding_run_widths(0.0f), |
@@ -522,21 +530,19 @@ size_t TextRunHarfBuzz::CountMissingGlyphs() const { |
return missing; |
} |
-Range TextRunHarfBuzz::GetGraphemeBounds( |
+RangeF TextRunHarfBuzz::GetGraphemeBounds( |
base::i18n::BreakIterator* grapheme_iterator, |
size_t text_index) { |
DCHECK_LT(text_index, range.end()); |
- // TODO(msw): Support floating point grapheme bounds. |
- const int preceding_run_widths_int = SkScalarRoundToInt(preceding_run_widths); |
if (glyph_count == 0) |
- return Range(preceding_run_widths_int, preceding_run_widths_int + width); |
+ return RangeF(preceding_run_widths, preceding_run_widths + width); |
Range chars; |
Range glyphs; |
GetClusterAt(text_index, &chars, &glyphs); |
- const int cluster_begin_x = SkScalarRoundToInt(positions[glyphs.start()].x()); |
- const int cluster_end_x = glyphs.end() < glyph_count ? |
- SkScalarRoundToInt(positions[glyphs.end()].x()) : width; |
+ const float cluster_begin_x = positions[glyphs.start()].x(); |
+ const float cluster_end_x = glyphs.end() < glyph_count ? |
+ positions[glyphs.end()].x() : SkFloatToScalar(width); |
// A cluster consists of a number of code points and corresponds to a number |
// of glyphs that should be drawn together. A cluster can contain multiple |
@@ -563,13 +569,13 @@ Range TextRunHarfBuzz::GetGraphemeBounds( |
cluster_width * before / static_cast<float>(total)); |
const int grapheme_end_x = cluster_begin_x + static_cast<int>(0.5f + |
cluster_width * (before + 1) / static_cast<float>(total)); |
- return Range(preceding_run_widths_int + grapheme_begin_x, |
- preceding_run_widths_int + grapheme_end_x); |
+ return RangeF(preceding_run_widths + grapheme_begin_x, |
+ preceding_run_widths + grapheme_end_x); |
} |
} |
- return Range(preceding_run_widths_int + cluster_begin_x, |
- preceding_run_widths_int + cluster_end_x); |
+ return RangeF(preceding_run_widths + cluster_begin_x, |
+ preceding_run_widths + cluster_end_x); |
} |
} // namespace internal |
@@ -596,7 +602,7 @@ SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) { |
EnsureLayout(); |
int x = ToTextPoint(point).x(); |
- int offset = 0; |
+ float offset = 0; |
size_t run_index = GetRunContainingXCoord(x, &offset); |
if (run_index >= runs_.size()) |
return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT); |
@@ -646,8 +652,15 @@ Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) { |
return Range(GetStringSize().width()); |
const size_t layout_index = TextIndexToLayoutIndex(index); |
internal::TextRunHarfBuzz* run = runs_[run_index]; |
- Range bounds = run->GetGraphemeBounds(grapheme_iterator_.get(), layout_index); |
- return run->is_rtl ? Range(bounds.end(), bounds.start()) : bounds; |
+ RangeF bounds = |
+ run->GetGraphemeBounds(grapheme_iterator_.get(), 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 && |
+ 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() { |
@@ -778,12 +791,12 @@ std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) { |
if (!intersection.IsValid()) |
continue; |
DCHECK(!intersection.is_reversed()); |
- const Range leftmost_character_x = run->GetGraphemeBounds( |
+ const Range leftmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
grapheme_iterator_.get(), |
- run->is_rtl ? intersection.end() - 1 : intersection.start()); |
- const Range rightmost_character_x = run->GetGraphemeBounds( |
+ run->is_rtl ? intersection.end() - 1 : intersection.start())); |
+ const Range rightmost_character_x = RoundRangeF(run->GetGraphemeBounds( |
grapheme_iterator_.get(), |
- run->is_rtl ? intersection.start() : intersection.end() - 1); |
+ run->is_rtl ? intersection.start() : intersection.end() - 1)); |
Range range_x(leftmost_character_x.start(), rightmost_character_x.end()); |
DCHECK(!range_x.is_reversed()); |
if (range_x.is_empty()) |
@@ -911,7 +924,6 @@ void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
ApplyTextShadows(&renderer); |
ApplyCompositionAndSelectionStyles(); |
- int current_x = 0; |
const Vector2d line_offset = GetLineOffset(0); |
for (size_t i = 0; i < runs_.size(); ++i) { |
const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]]; |
@@ -920,11 +932,12 @@ void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
renderer.SetFontRenderParams(run.render_params, |
background_is_transparent()); |
- Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline); |
+ Vector2d origin = line_offset + Vector2d(0, lines()[0].baseline); |
scoped_ptr<SkPoint[]> positions(new SkPoint[run.glyph_count]); |
for (size_t j = 0; j < run.glyph_count; ++j) { |
positions[j] = run.positions[j]; |
- positions[j].offset(SkIntToScalar(origin.x()), SkIntToScalar(origin.y())); |
+ positions[j].offset(SkIntToScalar(origin.x()) + run.preceding_run_widths, |
+ SkIntToScalar(origin.y())); |
} |
for (BreakList<SkColor>::const_iterator it = |
@@ -946,13 +959,11 @@ void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) { |
colored_glyphs.length()); |
int start_x = SkScalarRoundToInt(positions[colored_glyphs.start()].x()); |
int end_x = SkScalarRoundToInt((colored_glyphs.end() == run.glyph_count) ? |
- (run.width + SkIntToScalar(origin.x())) : |
+ (run.width + run.preceding_run_widths + SkIntToScalar(origin.x())) : |
positions[colored_glyphs.end()].x()); |
renderer.DrawDecorations(start_x, origin.y(), end_x - start_x, |
run.underline, run.strike, run.diagonal_strike); |
} |
- |
- current_x += run.width; |
} |
renderer.EndDiagonalStrike(); |
@@ -972,12 +983,13 @@ size_t RenderTextHarfBuzz::GetRunContainingCaret( |
return runs_.size(); |
} |
-size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const { |
+size_t RenderTextHarfBuzz::GetRunContainingXCoord(float x, |
+ float* offset) const { |
DCHECK(!needs_layout_); |
if (x < 0) |
return runs_.size(); |
// Find the text run containing the argument point (assumed already offset). |
- int current_x = 0; |
+ 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; |