Commit 0d717603 authored by msw@chromium.org's avatar msw@chromium.org

Implement Uniscribe RenderText for Windows.

Follow the I18N recommendations for BiDi text editing.
Visual cursor movement and logical selection over BiDi text.
Cleanup some common RenderText code and interfaces.
Fixup TextfieldExample for views_examples.

Known issues:
Word breaking is not well implemented.
Font sizes and vertical alignments are slightly off.
Text styles break runs (colors can affect glyph shaping).
Composition/selection ranges aren't stylized.

BUG=90426
TEST=--use-pure-views text editing

Review URL: http://codereview.chromium.org/7458014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98785 0039d316-1c4b-4281-b951-d872f2087c98
parent 139212d9
...@@ -164,14 +164,8 @@ void RenderText::SetText(const string16& text) { ...@@ -164,14 +164,8 @@ void RenderText::SetText(const string16& text) {
cached_bounds_and_offset_valid_ = false; cached_bounds_and_offset_valid_ = false;
} }
void RenderText::SetSelectionModel(const SelectionModel& sel) { void RenderText::ToggleInsertMode() {
size_t start = sel.selection_start(); insert_mode_ = !insert_mode_;
size_t end = sel.selection_end();
selection_model_.set_selection_start(std::min(start, text().length()));
selection_model_.set_selection_end(std::min(end, text().length()));
selection_model_.set_caret_pos(std::min(sel.caret_pos(), text().length()));
selection_model_.set_caret_placement(sel.caret_placement());
cached_bounds_and_offset_valid_ = false; cached_bounds_and_offset_valid_ = false;
} }
...@@ -184,13 +178,8 @@ size_t RenderText::GetCursorPosition() const { ...@@ -184,13 +178,8 @@ size_t RenderText::GetCursorPosition() const {
return selection_model_.selection_end(); return selection_model_.selection_end();
} }
void RenderText::SetCursorPosition(const size_t position) { void RenderText::SetCursorPosition(size_t position) {
SelectionModel sel(selection_model()); MoveCursorTo(position, false);
sel.set_selection_start(position);
sel.set_selection_end(position);
sel.set_caret_pos(GetIndexOfPreviousGrapheme(position));
sel.set_caret_placement(SelectionModel::TRAILING);
SetSelectionModel(sel);
} }
void RenderText::MoveCursorLeft(BreakType break_type, bool select) { void RenderText::MoveCursorLeft(BreakType break_type, bool select) {
...@@ -237,9 +226,26 @@ void RenderText::MoveCursorRight(BreakType break_type, bool select) { ...@@ -237,9 +226,26 @@ void RenderText::MoveCursorRight(BreakType break_type, bool select) {
MoveCursorTo(position); MoveCursorTo(position);
} }
bool RenderText::MoveCursorTo(const SelectionModel& selection) { bool RenderText::MoveCursorTo(const SelectionModel& selection_model) {
bool changed = !selection.Equals(selection_model_); SelectionModel sel(selection_model);
SetSelectionModel(selection); size_t text_length = text().length();
// Enforce valid selection model components.
if (sel.selection_start() > text_length)
sel.set_selection_start(text_length);
if (sel.selection_end() > text_length)
sel.set_selection_end(text_length);
// The current model only supports caret positions at valid character indices.
if (text_length == 0) {
sel.set_caret_pos(0);
sel.set_caret_placement(SelectionModel::LEADING);
} else if (sel.caret_pos() >= text_length) {
SelectionModel end = GetTextDirection() == base::i18n::RIGHT_TO_LEFT ?
LeftEndSelectionModel() : RightEndSelectionModel();
sel.set_caret_pos(end.caret_pos());
sel.set_caret_placement(end.caret_placement());
}
bool changed = !sel.Equals(selection_model_);
SetSelectionModel(sel);
return changed; return changed;
} }
...@@ -251,6 +257,8 @@ bool RenderText::MoveCursorTo(const Point& point, bool select) { ...@@ -251,6 +257,8 @@ bool RenderText::MoveCursorTo(const Point& point, bool select) {
} }
bool RenderText::IsPointInSelection(const Point& point) { bool RenderText::IsPointInSelection(const Point& point) {
if (EmptySelection())
return false;
// TODO(xji): should this check whether the point is inside the visual // TODO(xji): should this check whether the point is inside the visual
// selection bounds? In case of "abcFED", if "ED" is selected, |point| points // selection bounds? In case of "abcFED", if "ED" is selected, |point| points
// to the right half of 'c', is the point in selection? // to the right half of 'c', is the point in selection?
...@@ -265,8 +273,8 @@ void RenderText::ClearSelection() { ...@@ -265,8 +273,8 @@ void RenderText::ClearSelection() {
} }
void RenderText::SelectAll() { void RenderText::SelectAll() {
SelectionModel sel(0, text().length(), SelectionModel sel(RightEndSelectionModel());
text().length(), SelectionModel::LEADING); sel.set_selection_start(LeftEndSelectionModel().selection_start());
SetSelectionModel(sel); SetSelectionModel(sel);
} }
...@@ -308,12 +316,8 @@ void RenderText::SelectWord() { ...@@ -308,12 +316,8 @@ void RenderText::SelectWord() {
break; break;
} }
SelectionModel sel(selection_model()); MoveCursorTo(selection_start, false);
sel.set_selection_start(selection_start); MoveCursorTo(cursor_position, true);
sel.set_selection_end(cursor_position);
sel.set_caret_pos(GetIndexOfPreviousGrapheme(cursor_position));
sel.set_caret_placement(SelectionModel::TRAILING);
SetSelectionModel(sel);
} }
const ui::Range& RenderText::GetCompositionRange() const { const ui::Range& RenderText::GetCompositionRange() const {
...@@ -350,8 +354,8 @@ void RenderText::ApplyDefaultStyle() { ...@@ -350,8 +354,8 @@ void RenderText::ApplyDefaultStyle() {
} }
base::i18n::TextDirection RenderText::GetTextDirection() const { base::i18n::TextDirection RenderText::GetTextDirection() const {
// TODO(msw): Bidi implementation, intended to replace the functionality added if (base::i18n::IsRTL())
// in crrev.com/91881 (discussed in codereview.chromium.org/7324011). return base::i18n::RIGHT_TO_LEFT;
return base::i18n::LEFT_TO_RIGHT; return base::i18n::LEFT_TO_RIGHT;
} }
...@@ -443,20 +447,6 @@ SelectionModel RenderText::FindCursorPosition(const Point& point) { ...@@ -443,20 +447,6 @@ SelectionModel RenderText::FindCursorPosition(const Point& point) {
return SelectionModel(left_pos); return SelectionModel(left_pos);
} }
std::vector<Rect> RenderText::GetSubstringBounds(size_t from, size_t to) {
size_t start = std::min(from, to);
size_t end = std::max(from, to);
const Font& font = default_style_.font;
int start_x = font.GetStringWidth(text().substr(0, start));
int end_x = font.GetStringWidth(text().substr(0, end));
Rect rect(start_x, 0, end_x - start_x, font.GetHeight());
rect.Offset(display_rect_.origin());
rect.Offset(GetUpdatedDisplayOffset());
// Center the rect vertically in |display_rect_|.
rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2));
return std::vector<Rect>(1, rect);
}
Rect RenderText::GetCursorBounds(const SelectionModel& selection, Rect RenderText::GetCursorBounds(const SelectionModel& selection,
bool insert_mode) { bool insert_mode) {
size_t from = selection.selection_end(); size_t from = selection.selection_end();
...@@ -549,9 +539,35 @@ SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, ...@@ -549,9 +539,35 @@ SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
return SelectionModel(pos, pos, SelectionModel::LEADING); return SelectionModel(pos, pos, SelectionModel::LEADING);
} }
SelectionModel RenderText::LeftEndSelectionModel() {
return SelectionModel(0, 0, SelectionModel::LEADING);
}
SelectionModel RenderText::RightEndSelectionModel() {
size_t cursor = text().length();
size_t caret_pos = GetIndexOfPreviousGrapheme(cursor);
SelectionModel::CaretPlacement placement = (caret_pos == cursor) ?
SelectionModel::LEADING : SelectionModel::TRAILING;
return SelectionModel(cursor, caret_pos, placement);
}
size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) { size_t RenderText::GetIndexOfPreviousGrapheme(size_t position) {
// TODO(msw): Handle complex script. // TODO(msw): Handle complex script.
return std::max(static_cast<int>(position - 1), static_cast<int>(0)); return std::max(static_cast<long>(position - 1), static_cast<long>(0));
}
std::vector<Rect> RenderText::GetSubstringBounds(size_t from, size_t to) {
size_t start = std::min(from, to);
size_t end = std::max(from, to);
const Font& font = default_style_.font;
int start_x = font.GetStringWidth(text().substr(0, start));
int end_x = font.GetStringWidth(text().substr(0, end));
Rect rect(start_x, 0, end_x - start_x, font.GetHeight());
rect.Offset(display_rect_.origin());
rect.Offset(GetUpdatedDisplayOffset());
// Center the rect vertically in |display_rect_|.
rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2));
return std::vector<Rect>(1, rect);
} }
void RenderText::ApplyCompositionAndSelectionStyles( void RenderText::ApplyCompositionAndSelectionStyles(
...@@ -576,6 +592,45 @@ void RenderText::ApplyCompositionAndSelectionStyles( ...@@ -576,6 +592,45 @@ void RenderText::ApplyCompositionAndSelectionStyles(
} }
} }
Point RenderText::ToTextPoint(const Point& point) {
Point p(point.Subtract(display_rect().origin()));
p = p.Subtract(GetUpdatedDisplayOffset());
if (base::i18n::IsRTL())
p.Offset(GetStringWidth() - display_rect().width() + 1, 0);
return p;
}
Point RenderText::ToViewPoint(const Point& point) {
Point p(point.Add(display_rect().origin()));
p = p.Add(GetUpdatedDisplayOffset());
if (base::i18n::IsRTL())
p.Offset(display_rect().width() - GetStringWidth() - 1, 0);
return p;
}
void RenderText::SetSelectionModel(const SelectionModel& selection_model) {
DCHECK_LE(selection_model.selection_start(), text().length());
selection_model_.set_selection_start(selection_model.selection_start());
DCHECK_LE(selection_model.selection_end(), text().length());
selection_model_.set_selection_end(selection_model.selection_end());
DCHECK_LT(selection_model.caret_pos(),
std::max(text().length(), static_cast<size_t>(1)));
selection_model_.set_caret_pos(selection_model.caret_pos());
selection_model_.set_caret_placement(selection_model.caret_placement());
cached_bounds_and_offset_valid_ = false;
}
void RenderText::MoveCursorTo(size_t position, bool select) {
size_t cursor = std::min(position, text().length());
size_t caret_pos = GetIndexOfPreviousGrapheme(cursor);
SelectionModel::CaretPlacement placement = (caret_pos == cursor) ?
SelectionModel::LEADING : SelectionModel::TRAILING;
size_t selection_start = select ? GetSelectionStart() : cursor;
SelectionModel sel(selection_start, cursor, caret_pos, placement);
SetSelectionModel(sel);
}
bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) {
return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) ||
(!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos]));
...@@ -589,7 +644,6 @@ void RenderText::UpdateCachedBoundsAndOffset() { ...@@ -589,7 +644,6 @@ void RenderText::UpdateCachedBoundsAndOffset() {
// function will set |cursor_bounds_| and |display_offset_| to correct values. // function will set |cursor_bounds_| and |display_offset_| to correct values.
cached_bounds_and_offset_valid_ = true; cached_bounds_and_offset_valid_ = true;
cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1));
// Update |display_offset_| to ensure the current cursor is visible. // Update |display_offset_| to ensure the current cursor is visible.
int display_width = display_rect_.width(); int display_width = display_rect_.width();
int string_width = GetStringWidth(); int string_width = GetStringWidth();
......
...@@ -154,13 +154,12 @@ class UI_EXPORT RenderText { ...@@ -154,13 +154,12 @@ class UI_EXPORT RenderText {
virtual void SetText(const string16& text); virtual void SetText(const string16& text);
const SelectionModel& selection_model() const { return selection_model_; } const SelectionModel& selection_model() const { return selection_model_; }
void SetSelectionModel(const SelectionModel& sel);
bool cursor_visible() const { return cursor_visible_; } bool cursor_visible() const { return cursor_visible_; }
void set_cursor_visible(bool visible) { cursor_visible_ = visible; } void set_cursor_visible(bool visible) { cursor_visible_ = visible; }
bool insert_mode() const { return insert_mode_; } bool insert_mode() const { return insert_mode_; }
void toggle_insert_mode() { insert_mode_ = !insert_mode_; } void ToggleInsertMode();
bool focused() const { return focused_; } bool focused() const { return focused_; }
void set_focused(bool focused) { focused_ = focused; } void set_focused(bool focused) { focused_ = focused; }
...@@ -176,7 +175,7 @@ class UI_EXPORT RenderText { ...@@ -176,7 +175,7 @@ class UI_EXPORT RenderText {
// edits take place, and doesn't necessarily correspond to // edits take place, and doesn't necessarily correspond to
// SelectionModel::caret_pos. // SelectionModel::caret_pos.
size_t GetCursorPosition() const; size_t GetCursorPosition() const;
void SetCursorPosition(const size_t position); void SetCursorPosition(size_t position);
void SetCaretPlacement(SelectionModel::CaretPlacement placement) { void SetCaretPlacement(SelectionModel::CaretPlacement placement) {
selection_model_.set_caret_placement(placement); selection_model_.set_caret_placement(placement);
...@@ -184,16 +183,18 @@ class UI_EXPORT RenderText { ...@@ -184,16 +183,18 @@ class UI_EXPORT RenderText {
// Moves the cursor left or right. Cursor movement is visual, meaning that // Moves the cursor left or right. Cursor movement is visual, meaning that
// left and right are relative to screen, not the directionality of the text. // left and right are relative to screen, not the directionality of the text.
// If |select| is false, the selection range is emptied at the new position. // If |select| is false, the selection start is moved to the same position.
void MoveCursorLeft(BreakType break_type, bool select); void MoveCursorLeft(BreakType break_type, bool select);
void MoveCursorRight(BreakType break_type, bool select); void MoveCursorRight(BreakType break_type, bool select);
// Set the selection_model_ to the value of |selection|. // Set the selection_model_ to the value of |selection|.
// The selection model components are modified if invalid.
// Returns true if the cursor position or selection range changed. // Returns true if the cursor position or selection range changed.
bool MoveCursorTo(const SelectionModel& selection); bool MoveCursorTo(const SelectionModel& selection_model);
// Move the cursor to the position associated with the clicked point. // Move the cursor to the position associated with the clicked point.
// If |select| is false, the selection range is emptied at the new position. // If |select| is false, the selection start is moved to the same position.
// Returns true if the cursor position or selection range changed.
bool MoveCursorTo(const Point& point, bool select); bool MoveCursorTo(const Point& point, bool select);
size_t GetSelectionStart() const { size_t GetSelectionStart() const {
...@@ -236,13 +237,6 @@ class UI_EXPORT RenderText { ...@@ -236,13 +237,6 @@ class UI_EXPORT RenderText {
// Gets the SelectionModel from a visual point in local coordinates. // Gets the SelectionModel from a visual point in local coordinates.
virtual SelectionModel FindCursorPosition(const Point& point); virtual SelectionModel FindCursorPosition(const Point& point);
// Get the visual bounds containing the logical substring within |from| to
// |to|. These bounds could be visually discontinuous if the substring is
// split by a LTR/RTL level change. These bounds are in local coordinates, but
// may be outside the visible region if the text is longer than the textfield.
// Subsequent text, cursor, or bounds changes may invalidate returned values.
virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to);
// Get the visual bounds of a cursor at |selection|. These bounds typically // Get the visual bounds of a cursor at |selection|. These bounds typically
// represent a vertical line, but if |insert_mode| is true they contain the // represent a vertical line, but if |insert_mode| is true they contain the
// bounds of the associated glyph. These bounds are in local coordinates, but // bounds of the associated glyph. These bounds are in local coordinates, but
...@@ -274,13 +268,31 @@ class UI_EXPORT RenderText { ...@@ -274,13 +268,31 @@ class UI_EXPORT RenderText {
virtual SelectionModel GetRightSelectionModel(const SelectionModel& current, virtual SelectionModel GetRightSelectionModel(const SelectionModel& current,
BreakType break_type); BreakType break_type);
// Get the SelectionModels corresponding to visual text ends.
// The returned value represents a cursor/caret position without a selection.
virtual SelectionModel LeftEndSelectionModel();
virtual SelectionModel RightEndSelectionModel();
// Get the logical index of the grapheme preceeding the argument |position|. // Get the logical index of the grapheme preceeding the argument |position|.
virtual size_t GetIndexOfPreviousGrapheme(size_t position); virtual size_t GetIndexOfPreviousGrapheme(size_t position);
// Get the visual bounds containing the logical substring within |from| to
// |to|. These bounds could be visually discontinuous if the substring is
// split by a LTR/RTL level change. These bounds are in local coordinates, but
// may be outside the visible region if the text is longer than the textfield.
// Subsequent text, cursor, or bounds changes may invalidate returned values.
// TODO(msw) Re-evaluate this function's necessity and signature.
virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to);
// Apply composition style (underline) to composition range and selection // Apply composition style (underline) to composition range and selection
// style (foreground) to selection range. // style (foreground) to selection range.
void ApplyCompositionAndSelectionStyles(StyleRanges* style_ranges) const; void ApplyCompositionAndSelectionStyles(StyleRanges* style_ranges) const;
// Convert points from the text space to the view space and back.
// Handles the display area, display offset, and the application LTR/RTL mode.
Point ToTextPoint(const Point& point);
Point ToViewPoint(const Point& point);
private: private:
friend class RenderTextTest; friend class RenderTextTest;
...@@ -289,8 +301,13 @@ class UI_EXPORT RenderText { ...@@ -289,8 +301,13 @@ class UI_EXPORT RenderText {
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ApplyStyleRange); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ApplyStyleRange);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, StyleRangesAdjust); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, StyleRangesAdjust);
// Clear out |style_ranges_|. // Sets the selection model, the argument is assumed to be valid.
void ClearStyleRanges(); void SetSelectionModel(const SelectionModel& selection_model);
// Set the cursor to |position|, with the caret trailing the previous
// grapheme, or if there is no previous grapheme, leading the cursor position.
// If |select| is false, the selection start is moved to the same position.
void MoveCursorTo(size_t position, bool select);
bool IsPositionAtWordSelectionBoundary(size_t pos); bool IsPositionAtWordSelectionBoundary(size_t pos);
...@@ -328,9 +345,8 @@ class UI_EXPORT RenderText { ...@@ -328,9 +345,8 @@ class UI_EXPORT RenderText {
// Get this point with GetUpdatedDisplayOffset (or risk using a stale value). // Get this point with GetUpdatedDisplayOffset (or risk using a stale value).
Point display_offset_; Point display_offset_;
// The cached bounds and offset are invalidated by operations such as // The cached bounds and offset are invalidated by changes to the cursor,
// SetCursorPosition, SetSelectionModel, Font related style change, and other // selection, font, and other operations that adjust the visible text bounds.
// operations that adjust the visible text bounds.
bool cached_bounds_and_offset_valid_; bool cached_bounds_and_offset_valid_;
DISALLOW_COPY_AND_ASSIGN(RenderText); DISALLOW_COPY_AND_ASSIGN(RenderText);
......
This diff is collapsed.
...@@ -6,17 +6,121 @@ ...@@ -6,17 +6,121 @@
#define UI_GFX_RENDER_TEXT_WIN_H_ #define UI_GFX_RENDER_TEXT_WIN_H_
#pragma once #pragma once
#include <usp10.h>
#include "base/memory/scoped_ptr.h"
#include "ui/gfx/render_text.h" #include "ui/gfx/render_text.h"
namespace gfx { namespace gfx {
namespace internal {
struct TextRun {
TextRun();
ui::Range range;
Font font;
// TODO(msw): Disambiguate color, strike, etc. from TextRuns.
// Otherwise, this breaks the glyph shaping process.
// See the example at: http://www.catch22.net/tuts/neatpad/12.
SkColor foreground;
bool strike;
int width;
// The cumulative widths of preceding runs.
int preceding_run_widths;
SCRIPT_ANALYSIS script_analysis;
scoped_array<WORD> glyphs;
scoped_array<WORD> logical_clusters;
scoped_array<SCRIPT_VISATTR> visible_attributes;
int glyph_count;
scoped_array<int> advance_widths;
scoped_array<GOFFSET> offsets;
ABC abc_widths;
private:
DISALLOW_COPY_AND_ASSIGN(TextRun);
};
} // namespace internal
// RenderTextWin is the Windows implementation of RenderText using Uniscribe. // RenderTextWin is the Windows implementation of RenderText using Uniscribe.
class RenderTextWin : public RenderText { class RenderTextWin : public RenderText {
public: public:
RenderTextWin(); RenderTextWin();
virtual ~RenderTextWin(); virtual ~RenderTextWin();
// Overridden from RenderText:
virtual void SetText(const string16& text) OVERRIDE;
virtual void SetDisplayRect(const Rect& r) OVERRIDE;
virtual void ApplyStyleRange(StyleRange style_range) OVERRIDE;
virtual void ApplyDefaultStyle() OVERRIDE;
virtual int GetStringWidth() OVERRIDE;
virtual void Draw(Canvas* canvas) OVERRIDE;
virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE;
virtual Rect GetCursorBounds(const SelectionModel& selection,
bool insert_mode) OVERRIDE;
protected:
// Overridden from RenderText:
virtual SelectionModel GetLeftSelectionModel(const SelectionModel& current,
BreakType break_type) OVERRIDE;
virtual SelectionModel GetRightSelectionModel(const SelectionModel& current,
BreakType break_type) OVERRIDE;
virtual SelectionModel LeftEndSelectionModel() OVERRIDE;
virtual SelectionModel RightEndSelectionModel() OVERRIDE;
virtual size_t GetIndexOfPreviousGrapheme(size_t position) OVERRIDE;
virtual std::vector<Rect> GetSubstringBounds(size_t from, size_t to) OVERRIDE;
private: private:
void ItemizeLogicalText();
void LayoutVisualText(HDC hdc);
// Return the run index that contains the argument; or the length of the
// |runs_| vector if argument exceeds the text length or width.
size_t GetRunContainingPosition(size_t position) const;
size_t GetRunContainingPoint(const Point& point) const;
// Return an index belonging to the |next| or previous logical grapheme.
// The return value is bounded by 0 and the text length, inclusive.
size_t IndexOfAdjacentGrapheme(size_t index, bool next) const;
// Given a |run|, returns the SelectionModel that contains the logical first
// or last caret position inside (not at a boundary of) the run.
// The returned value represents a cursor/caret position without a selection.
SelectionModel FirstSelectionModelInsideRun(internal::TextRun*) const;
SelectionModel LastSelectionModelInsideRun(internal::TextRun*) const;
// Get the selection model visually left/right of |selection| by one grapheme.
// The returned value represents a cursor/caret position without a selection.
SelectionModel LeftSelectionModel(const SelectionModel& selection);
SelectionModel RightSelectionModel(const SelectionModel& selection);
// Draw the text, cursor, and selection.
void DrawSelection(Canvas* canvas);
void DrawVisualText(Canvas* canvas);
void DrawCursor(Canvas* canvas);
bool text_is_dirty_;
bool style_is_dirty_;
// National Language Support native digit and digit substitution settings.
SCRIPT_DIGITSUBSTITUTE digit_substitute_;
SCRIPT_CONTROL script_control_;
SCRIPT_STATE script_state_;
SCRIPT_CACHE script_cache_;
std::vector<internal::TextRun*> runs_;
int string_width_;
scoped_array<int> visual_to_logical_;
scoped_array<int> logical_to_visual_;
DISALLOW_COPY_AND_ASSIGN(RenderTextWin); DISALLOW_COPY_AND_ASSIGN(RenderTextWin);
}; };
......
...@@ -874,11 +874,12 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -874,11 +874,12 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = true; cursor_changed = true;
break; break;
case ui::VKEY_END: case ui::VKEY_END:
model_->MoveCursorRight(gfx::LINE_BREAK, selection);
cursor_changed = true;
break;
case ui::VKEY_HOME: case ui::VKEY_HOME:
model_->MoveCursorLeft(gfx::LINE_BREAK, selection); if ((key_code == ui::VKEY_HOME) ==
(GetRenderText()->GetTextDirection() == base::i18n::RIGHT_TO_LEFT))
model_->MoveCursorRight(gfx::LINE_BREAK, selection);
else
model_->MoveCursorLeft(gfx::LINE_BREAK, selection);
cursor_changed = true; cursor_changed = true;
break; break;
case ui::VKEY_BACK: case ui::VKEY_BACK:
...@@ -921,7 +922,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { ...@@ -921,7 +922,7 @@ bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
cursor_changed = text_changed = model_->Delete(); cursor_changed = text_changed = model_->Delete();
break; break;
case ui::VKEY_INSERT: case ui::VKEY_INSERT:
GetRenderText()->toggle_insert_mode(); GetRenderText()->ToggleInsertMode();
cursor_changed = true; cursor_changed = true;
break; break;
default: default:
......
...@@ -398,11 +398,6 @@ bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) { ...@@ -398,11 +398,6 @@ bool TextfieldViewsModel::MoveCursorTo(const gfx::Point& point, bool select) {
return render_text_->MoveCursorTo(point, select); return render_text_->MoveCursorTo(point, select);
} }
std::vector<gfx::Rect> TextfieldViewsModel::GetSelectionBounds() const {
return render_text_->GetSubstringBounds(render_text_->GetSelectionStart(),
render_text_->GetCursorPosition());
}
string16 TextfieldViewsModel::GetSelectedText() const { string16 TextfieldViewsModel::GetSelectedText() const {
return GetText().substr(render_text_->MinOfSelection(), return GetText().substr(render_text_->MinOfSelection(),
(render_text_->MaxOfSelection() - render_text_->MinOfSelection())); (render_text_->MaxOfSelection() - render_text_->MinOfSelection()));
...@@ -421,7 +416,7 @@ void TextfieldViewsModel::SelectRange(const ui::Range& range) { ...@@ -421,7 +416,7 @@ void TextfieldViewsModel::SelectRange(const ui::Range& range) {
void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) { void TextfieldViewsModel::SelectSelectionModel(const gfx::SelectionModel& sel) {
if (HasCompositionText()) if (HasCompositionText())
ConfirmCompositionText(); ConfirmCompositionText();
render_text_->SetSelectionModel(sel); render_text_->MoveCursorTo(sel);
} }
void TextfieldViewsModel::SelectAll() { void TextfieldViewsModel::SelectAll() {
...@@ -509,7 +504,7 @@ bool TextfieldViewsModel::Cut() { ...@@ -509,7 +504,7 @@ bool TextfieldViewsModel::Cut() {
render_text_->GetSelectionStart(), render_text_->GetSelectionStart(),
render_text_->GetSelectionStart(), render_text_->GetSelectionStart(),
gfx::SelectionModel::LEADING); gfx::SelectionModel::LEADING);
render_text_->SetSelectionModel(sel); render_text_->MoveCursorTo(sel);
DeleteSelection(); DeleteSelection();
return true; return true;
} }
...@@ -589,7 +584,7 @@ void TextfieldViewsModel::SetCompositionText( ...@@ -589,7 +584,7 @@ void TextfieldViewsModel::SetCompositionText(
size_t end = size_t end =
std::min(range.start() + composition.selection.end(), range.end()); std::min(range.start() + composition.selection.end(), range.end());
gfx::SelectionModel sel(start, end); gfx::SelectionModel sel(start, end);
render_text_->SetSelectionModel(sel); render_text_->MoveCursorTo(sel);
} else { } else {
render_text_->SetCursorPosition(range.end()); render_text_->SetCursorPosition(range.end());
} }
...@@ -662,7 +657,7 @@ void TextfieldViewsModel::ReplaceTextInternal(const string16& text, ...@@ -662,7 +657,7 @@ void TextfieldViewsModel::ReplaceTextInternal(const string16& text,
size_t cursor = GetCursorPosition(); size_t cursor = GetCursorPosition();
gfx::SelectionModel sel(render_text_->selection_model()); gfx::SelectionModel sel(render_text_->selection_model());
sel.set_selection_start(cursor + text.length()); sel.set_selection_start(cursor + text.length());
render_text_->SetSelectionModel(sel); render_text_->MoveCursorTo(sel);
} }
// Edit history is recorded in InsertText. // Edit history is recorded in InsertText.
InsertTextInternal(text, mergeable); InsertTextInternal(text, mergeable);
......
...@@ -143,9 +143,6 @@ class VIEWS_EXPORT TextfieldViewsModel { ...@@ -143,9 +143,6 @@ class VIEWS_EXPORT TextfieldViewsModel {
// Helper function to call MoveCursorTo on the TextfieldViewsModel. // Helper function to call MoveCursorTo on the TextfieldViewsModel.
bool MoveCursorTo(const gfx::Point& point, bool select); bool MoveCursorTo(const gfx::Point& point, bool select);
// Returns the bounds of selected text.
std::vector<gfx::Rect> GetSelectionBounds() const;
// Selection related method // Selection related method
// Returns the selected text. // Returns the selected text.
......
...@@ -90,22 +90,27 @@ void TextfieldExample::ButtonPressed(views::Button* sender, ...@@ -90,22 +90,27 @@ void TextfieldExample::ButtonPressed(views::Button* sender,
} else if (sender == set_) { } else if (sender == set_) {
name_->SetText(WideToUTF16(L"[set]")); name_->SetText(WideToUTF16(L"[set]"));
} else if (sender == set_style_) { } else if (sender == set_style_) {
gfx::StyleRange color; if (!name_->text().empty()) {
color.foreground = SK_ColorYELLOW; gfx::StyleRange color;
color.range = ui::Range(0, 11); color.foreground = SK_ColorYELLOW;
name_->ApplyStyleRange(color); color.range = ui::Range(0, name_->text().length());
name_->ApplyStyleRange(color);
gfx::StyleRange underline; if (name_->text().length() >= 5) {
underline.underline = true; size_t fifth = name_->text().length() / 5;
underline.foreground = SK_ColorBLUE; gfx::StyleRange underline;
underline.range = ui::Range(1, 7); underline.underline = true;
name_->ApplyStyleRange(underline); underline.foreground = SK_ColorBLUE;
underline.range = ui::Range(1 * fifth, 4 * fifth);
name_->ApplyStyleRange(underline);
gfx::StyleRange strike; gfx::StyleRange strike;
strike.strike = true; strike.strike = true;
strike.foreground = SK_ColorRED; strike.foreground = SK_ColorRED;
strike.range = ui::Range(6, 9); strike.range = ui::Range(2 * fifth, 3 * fifth);
name_->ApplyStyleRange(strike); name_->ApplyStyleRange(strike);
}
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment