Index: ui/gfx/render_text_linux.cc |
diff --git a/ui/gfx/render_text_linux.cc b/ui/gfx/render_text_linux.cc |
index 133bd4eb63d435ff7daf451b8f08f9fb4a889b0d..c10548ebb8972ac74fce35998375a15a32a8798c 100644 |
--- a/ui/gfx/render_text_linux.cc |
+++ b/ui/gfx/render_text_linux.cc |
@@ -11,12 +11,11 @@ |
#include "base/i18n/break_iterator.h" |
#include "base/logging.h" |
+#include "base/utf_offset_string_conversions.h" |
#include "third_party/skia/include/core/SkTypeface.h" |
#include "ui/gfx/canvas_skia.h" |
#include "ui/gfx/font.h" |
#include "ui/gfx/pango_util.h" |
-#include "unicode/uchar.h" |
-#include "unicode/ustring.h" |
namespace gfx { |
@@ -58,7 +57,9 @@ RenderTextLinux::RenderTextLinux() |
log_attrs_(NULL), |
num_log_attrs_(0), |
layout_text_(NULL), |
- layout_text_len_(0) { |
+ layout_text_len_(0), |
+ last_text_index_(0), |
+ last_layout_pointer_(NULL) { |
} |
RenderTextLinux::~RenderTextLinux() { |
@@ -99,22 +100,15 @@ SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { |
else if (p.x() > GetStringWidth()) |
return EdgeSelectionModel(CURSOR_RIGHT); |
- int caret_pos, trailing; |
+ int caret_pos_in_layout, trailing; |
msw
2012/02/22 00:33:26
Init these locals to 0, please.
benrg
2012/02/24 19:07:44
I backed out all changes to this code; should I st
|
pango_layout_xy_to_index(layout_, p.x() * PANGO_SCALE, p.y() * PANGO_SCALE, |
- &caret_pos, &trailing); |
- |
- size_t selection_end = caret_pos; |
- if (trailing > 0) { |
- const char* ch = g_utf8_offset_to_pointer(layout_text_ + caret_pos, |
- trailing); |
- DCHECK_GE(ch, layout_text_); |
- DCHECK_LE(ch, layout_text_ + layout_text_len_); |
- selection_end = ch - layout_text_; |
- } |
- |
+ &caret_pos_in_layout, &trailing); |
+ size_t caret_pos = LayoutIndexToTextIndex(caret_pos_in_layout); |
+ size_t selection_end = Utf16OffsetToIndex(text(), caret_pos, trailing); |
+ DCHECK_LE(caret_pos, selection_end); |
+ DCHECK_LE(selection_end, text().length()); |
return SelectionModel( |
- Utf8IndexToUtf16Index(selection_end), |
- Utf8IndexToUtf16Index(caret_pos), |
+ selection_end, caret_pos, |
msw
2012/02/22 00:33:26
|caret_pos| belongs on its own line.
|
trailing > 0 ? SelectionModel::TRAILING : SelectionModel::LEADING); |
} |
@@ -125,7 +119,7 @@ Rect RenderTextLinux::GetCursorBounds(const SelectionModel& selection, |
size_t caret_pos = insert_mode ? selection.caret_pos() : |
selection.selection_end(); |
PangoRectangle pos; |
- pango_layout_index_to_pos(layout_, Utf16IndexToUtf8Index(caret_pos), &pos); |
+ pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(caret_pos), &pos); |
SelectionModel::CaretPlacement caret_placement = selection.caret_placement(); |
int x = pos.x; |
@@ -172,8 +166,8 @@ SelectionModel RenderTextLinux::AdjacentCharSelectionModel( |
PangoLayoutRun* layout_run = reinterpret_cast<PangoLayoutRun*>(run->data); |
PangoItem* item = layout_run->item; |
- size_t run_start = Utf8IndexToUtf16Index(item->offset); |
- size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); |
+ size_t run_start = LayoutIndexToTextIndex(item->offset); |
+ size_t run_end = LayoutIndexToTextIndex(item->offset + item->length); |
if (!IsForwardMotion(direction, item)) { |
if (caret_placement == SelectionModel::TRAILING) |
@@ -209,6 +203,9 @@ SelectionModel RenderTextLinux::AdjacentCharSelectionModel( |
SelectionModel RenderTextLinux::AdjacentWordSelectionModel( |
const SelectionModel& selection, |
VisualCursorDirection direction) { |
+ if (is_obscured()) |
+ return EdgeSelectionModel(direction); |
+ |
base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
bool success = iter.Init(); |
DCHECK(success); |
@@ -243,12 +240,12 @@ SelectionModel RenderTextLinux::EdgeSelectionModel( |
PangoLayoutRun* end_run = reinterpret_cast<PangoLayoutRun*>(run->data); |
PangoItem* item = end_run->item; |
if (IsForwardMotion(direction, item)) { |
- size_t caret = Utf8IndexToUtf16Index( |
- Utf8IndexOfAdjacentGrapheme(item->offset + item->length, |
- CURSOR_BACKWARD)); |
+ size_t caret = IndexOfAdjacentGrapheme( |
+ LayoutIndexToTextIndex(item->offset + item->length), |
+ CURSOR_BACKWARD); |
return SelectionModel(text().length(), caret, SelectionModel::TRAILING); |
} else { |
- size_t caret = Utf8IndexToUtf16Index(item->offset); |
+ size_t caret = LayoutIndexToTextIndex(item->offset); |
return SelectionModel(text().length(), caret, SelectionModel::LEADING); |
} |
} |
@@ -281,12 +278,12 @@ std::vector<Rect> RenderTextLinux::GetSubstringBounds(size_t from, size_t to) { |
} |
bool RenderTextLinux::IsCursorablePosition(size_t position) { |
- if (position == 0 && text().empty()) |
+ if (position == 0) |
return true; |
- |
+ if (position > text().length()) |
+ return false; |
EnsureLayout(); |
- return (position < static_cast<size_t>(num_log_attrs_) && |
- log_attrs_[position].is_cursor_position); |
+ return log_attrs_[Utf16IndexToOffset(text(), 0, position)].is_cursor_position; |
} |
void RenderTextLinux::UpdateLayout() { |
@@ -302,7 +299,7 @@ void RenderTextLinux::EnsureLayout() { |
layout_ = pango_cairo_create_layout(cr); |
SetupPangoLayoutWithFontDescription( |
layout_, |
- text(), |
+ GetDisplayText(), |
font_list().GetFontDescriptionString(), |
display_rect().width(), |
base::i18n::GetFirstStrongCharacterDirection(text()), |
@@ -315,7 +312,6 @@ void RenderTextLinux::EnsureLayout() { |
// TODO(xji): If RenderText will be used for displaying purpose, such as |
// label, we will need to remove the single-line-mode setting. |
pango_layout_set_single_paragraph_mode(layout_, true); |
- SetupPangoAttributes(layout_); |
current_line_ = pango_layout_get_line_readonly(layout_, 0); |
pango_layout_line_ref(current_line_); |
@@ -324,6 +320,11 @@ void RenderTextLinux::EnsureLayout() { |
layout_text_ = pango_layout_get_text(layout_); |
layout_text_len_ = strlen(layout_text_); |
+ |
+ last_text_index_ = 0; |
+ last_layout_pointer_ = layout_text_; |
+ |
+ SetupPangoAttributes(layout_); |
} |
} |
@@ -345,8 +346,8 @@ void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { |
derived_font_list.GetFontDescriptionString().c_str()); |
PangoAttribute* pango_attr = pango_attr_font_desc_new(desc); |
- pango_attr->start_index = Utf16IndexToUtf8Index(i->range.start()); |
- pango_attr->end_index = Utf16IndexToUtf8Index(i->range.end()); |
+ pango_attr->start_index = TextIndexToLayoutIndex(i->range.start()); |
+ pango_attr->end_index = TextIndexToLayoutIndex(i->range.end()); |
pango_attr_list_insert(attrs, pango_attr); |
pango_font_description_free(desc); |
} |
@@ -369,17 +370,6 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
StyleRanges styles(style_ranges()); |
ApplyCompositionAndSelectionStyles(&styles); |
- // Pre-calculate UTF8 indices from UTF16 indices. |
- // TODO(asvitkine): Can we cache these? |
- std::vector<ui::Range> style_ranges_utf8; |
- style_ranges_utf8.reserve(styles.size()); |
- size_t start_index = 0; |
- for (size_t i = 0; i < styles.size(); ++i) { |
- size_t end_index = Utf16IndexToUtf8Index(styles[i].range.end()); |
- style_ranges_utf8.push_back(ui::Range(start_index, end_index)); |
- start_index = end_index; |
- } |
xji
2012/02/18 01:28:47
will removing this cause performance hit if we do
|
- |
internal::SkiaTextRenderer renderer(canvas); |
ApplyFadeEffects(&renderer); |
@@ -390,14 +380,15 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
continue; |
size_t run_start = run->item->offset; |
- size_t first_glyph_byte_index = run_start + run->glyphs->log_clusters[0]; |
+ size_t first_glyph_index = |
+ LayoutIndexToTextIndex(run_start + run->glyphs->log_clusters[0]); |
size_t style_increment = IsForwardMotion(CURSOR_RIGHT, run->item) ? 1 : -1; |
// Find the initial style for this run. |
// TODO(asvitkine): Can we avoid looping here, e.g. by caching this per run? |
int style = -1; |
- for (size_t i = 0; i < style_ranges_utf8.size(); ++i) { |
- if (IndexInRange(style_ranges_utf8[i], first_glyph_byte_index)) { |
+ for (size_t i = 0; i < styles.size(); ++i) { |
+ if (IndexInRange(styles[i].range, first_glyph_index)) { |
style = i; |
break; |
} |
@@ -431,10 +422,11 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
// If this glyph is beyond the current style, draw the glyphs so far and |
// advance to the next style. |
- size_t glyph_byte_index = run_start + run->glyphs->log_clusters[i]; |
+ size_t glyph_index = |
+ LayoutIndexToTextIndex(run_start + run->glyphs->log_clusters[i]); |
DCHECK_GE(style, 0); |
DCHECK_LT(style, static_cast<int>(styles.size())); |
- if (!IndexInRange(style_ranges_utf8[style], glyph_byte_index)) { |
+ if (!IndexInRange(styles[style].range, glyph_index)) { |
// TODO(asvitkine): For cases like "fi", where "fi" is a single glyph |
// but can span multiple styles, Pango splits the |
// styles evenly over the glyph. We can do this too by |
@@ -450,7 +442,7 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { |
do { |
style += style_increment; |
} while (style >= 0 && style < static_cast<int>(styles.size()) && |
- !IndexInRange(style_ranges_utf8[style], glyph_byte_index)); |
+ !IndexInRange(styles[style].range, glyph_index)); |
} |
} |
@@ -469,31 +461,8 @@ size_t RenderTextLinux::IndexOfAdjacentGrapheme( |
if (index > text().length()) |
return text().length(); |
EnsureLayout(); |
- return Utf8IndexToUtf16Index( |
- Utf8IndexOfAdjacentGrapheme(Utf16IndexToUtf8Index(index), direction)); |
-} |
- |
-GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { |
- GSList* run = current_line_->runs; |
- while (run) { |
- PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
- size_t run_start = Utf8IndexToUtf16Index(item->offset); |
- size_t run_end = Utf8IndexToUtf16Index(item->offset + item->length); |
- if (position >= run_start && position < run_end) |
- return run; |
- run = run->next; |
- } |
- return NULL; |
-} |
- |
-size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( |
- size_t utf8_index_of_current_grapheme, |
- LogicalCursorDirection direction) const { |
- const char* ch = layout_text_ + utf8_index_of_current_grapheme; |
- int char_offset = static_cast<int>(g_utf8_pointer_to_offset(layout_text_, |
- ch)); |
- int start_char_offset = char_offset; |
+ ptrdiff_t char_offset = Utf16IndexToOffset(text(), 0, index); |
if (direction == CURSOR_BACKWARD) { |
if (char_offset > 0) { |
do { |
@@ -508,23 +477,31 @@ size_t RenderTextLinux::Utf8IndexOfAdjacentGrapheme( |
!log_attrs_[char_offset].is_cursor_position); |
} |
} |
+ return Utf16OffsetToIndex(text(), 0, char_offset); |
+} |
- ch = g_utf8_offset_to_pointer(ch, char_offset - start_char_offset); |
- return static_cast<size_t>(ch - layout_text_); |
+GSList* RenderTextLinux::GetRunContainingPosition(size_t position) const { |
+ position = TextIndexToLayoutIndex(position); |
+ for (GSList* run = current_line_->runs; run; run = run->next) { |
+ PangoItem* item = reinterpret_cast<PangoLayoutRun*>(run->data)->item; |
+ if (position >= static_cast<size_t>(item->offset) && |
+ position < static_cast<size_t>(item->offset + item->length)) |
+ return run; |
+ } |
+ return NULL; |
xji
2012/02/18 01:28:47
Ah, nice!
|
} |
SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( |
- const PangoItem* item) const { |
- size_t caret = Utf8IndexToUtf16Index(item->offset); |
- size_t cursor = Utf8IndexToUtf16Index( |
- Utf8IndexOfAdjacentGrapheme(item->offset, CURSOR_FORWARD)); |
+ const PangoItem* item) { |
+ size_t caret = LayoutIndexToTextIndex(item->offset); |
+ size_t cursor = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD); |
return SelectionModel(cursor, caret, SelectionModel::TRAILING); |
} |
SelectionModel RenderTextLinux::LastSelectionModelInsideRun( |
- const PangoItem* item) const { |
- size_t caret = Utf8IndexToUtf16Index(Utf8IndexOfAdjacentGrapheme( |
- item->offset + item->length, CURSOR_BACKWARD)); |
+ const PangoItem* item) { |
+ size_t caret = IndexOfAdjacentGrapheme( |
+ LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); |
return SelectionModel(caret, caret, SelectionModel::LEADING); |
} |
@@ -548,39 +525,40 @@ void RenderTextLinux::ResetLayout() { |
selection_visual_bounds_.clear(); |
layout_text_ = NULL; |
layout_text_len_ = 0; |
+ last_text_index_ = 0; |
+ last_layout_pointer_ = NULL; |
} |
-size_t RenderTextLinux::Utf16IndexToUtf8Index(size_t index) const { |
- int32_t utf8_index = 0; |
- UErrorCode ec = U_ZERO_ERROR; |
- u_strToUTF8(NULL, 0, &utf8_index, text().data(), index, &ec); |
- // Even given a destination buffer as NULL and destination capacity as 0, |
- // if the output length is equal to or greater than the capacity, then the |
- // UErrorCode is set to U_STRING_NOT_TERMINATED_WARNING or |
- // U_BUFFER_OVERFLOW_ERROR respectively. |
- // Please refer to |
- // http://userguide.icu-project.org/strings#TOC-Using-C-Strings:-NUL-Terminated-vs |
- // for detail (search for "Note that" below "Preflighting"). |
- DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
- ec == U_STRING_NOT_TERMINATED_WARNING); |
- return utf8_index; |
+size_t RenderTextLinux::TextIndexToLayoutIndex(size_t text_index) const { |
+ // If the text is obscured then |layout_text_| is not the same as |text()|, |
+ // but whether or not the text is obscured, the character (code point) offset |
+ // in |layout_text_| is the same as that in |text()|. |
+ DCHECK(layout_); |
+ ptrdiff_t offset = Utf16IndexToOffset(text(), last_text_index_, text_index); |
+ const char* layout_pointer = g_utf8_offset_to_pointer(last_layout_pointer_, |
+ offset); |
+ last_text_index_ = text_index; |
+ last_layout_pointer_ = layout_pointer; |
+ return (layout_pointer - layout_text_); |
} |
-size_t RenderTextLinux::Utf8IndexToUtf16Index(size_t index) const { |
- int32_t utf16_index = 0; |
- UErrorCode ec = U_ZERO_ERROR; |
- u_strFromUTF8(NULL, 0, &utf16_index, layout_text_, index, &ec); |
- DCHECK(ec == U_BUFFER_OVERFLOW_ERROR || |
- ec == U_STRING_NOT_TERMINATED_WARNING); |
- return utf16_index; |
+size_t RenderTextLinux::LayoutIndexToTextIndex(size_t layout_index) const { |
+ // See |TextIndexToLayoutIndex()|. |
+ DCHECK(layout_); |
+ const char* layout_pointer = layout_text_ + layout_index; |
+ glong offset = g_utf8_pointer_to_offset(last_layout_pointer_, layout_pointer); |
+ size_t text_index = Utf16OffsetToIndex(text(), last_text_index_, offset); |
+ last_text_index_ = text_index; |
+ last_layout_pointer_ = layout_pointer; |
+ return text_index; |
} |
std::vector<Rect> RenderTextLinux::CalculateSubstringBounds(size_t from, |
size_t to) { |
int* ranges; |
int n_ranges; |
- size_t from_in_utf8 = Utf16IndexToUtf8Index(from); |
- size_t to_in_utf8 = Utf16IndexToUtf8Index(to); |
+ size_t from_in_utf8 = TextIndexToLayoutIndex(from); |
+ size_t to_in_utf8 = TextIndexToLayoutIndex(to); |
pango_layout_line_get_x_ranges( |
current_line_, |
std::min(from_in_utf8, to_in_utf8), |