OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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.h" | 5 #include "ui/gfx/render_text.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/i18n/break_iterator.h" | 9 #include "base/i18n/break_iterator.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
168 size_t start = sel.selection_start(); | 168 size_t start = sel.selection_start(); |
169 size_t end = sel.selection_end(); | 169 size_t end = sel.selection_end(); |
170 selection_model_.set_selection_start(std::min(start, text().length())); | 170 selection_model_.set_selection_start(std::min(start, text().length())); |
171 selection_model_.set_selection_end(std::min(end, text().length())); | 171 selection_model_.set_selection_end(std::min(end, text().length())); |
172 selection_model_.set_caret_pos(std::min(sel.caret_pos(), text().length())); | 172 selection_model_.set_caret_pos(std::min(sel.caret_pos(), text().length())); |
173 selection_model_.set_caret_placement(sel.caret_placement()); | 173 selection_model_.set_caret_placement(sel.caret_placement()); |
174 | 174 |
175 cached_bounds_and_offset_valid_ = false; | 175 cached_bounds_and_offset_valid_ = false; |
176 } | 176 } |
177 | 177 |
| 178 void RenderText::ToggleInsertMode() { |
| 179 insert_mode_ = !insert_mode_; |
| 180 cached_bounds_and_offset_valid_ = false; |
| 181 } |
| 182 |
178 void RenderText::SetDisplayRect(const Rect& r) { | 183 void RenderText::SetDisplayRect(const Rect& r) { |
179 display_rect_ = r; | 184 display_rect_ = r; |
180 cached_bounds_and_offset_valid_ = false; | 185 cached_bounds_and_offset_valid_ = false; |
181 } | 186 } |
182 | 187 |
183 size_t RenderText::GetCursorPosition() const { | 188 size_t RenderText::GetCursorPosition() const { |
184 return selection_model_.selection_end(); | 189 return selection_model_.selection_end(); |
185 } | 190 } |
186 | 191 |
187 void RenderText::SetCursorPosition(const size_t position) { | 192 void RenderText::SetCursorPosition(size_t position) { |
188 SelectionModel sel(selection_model()); | 193 MoveCursorTo(position, false); |
189 sel.set_selection_start(position); | |
190 sel.set_selection_end(position); | |
191 sel.set_caret_pos(GetIndexOfPreviousGrapheme(position)); | |
192 sel.set_caret_placement(SelectionModel::TRAILING); | |
193 SetSelectionModel(sel); | |
194 } | 194 } |
195 | 195 |
196 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { | 196 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { |
197 SelectionModel position(selection_model()); | 197 SelectionModel position(selection_model()); |
198 position.set_selection_start(GetCursorPosition()); | 198 position.set_selection_start(GetCursorPosition()); |
199 // Cancelling a selection moves to the edge of the selection. | 199 // Cancelling a selection moves to the edge of the selection. |
200 if (break_type != LINE_BREAK && !EmptySelection() && !select) { | 200 if (break_type != LINE_BREAK && !EmptySelection() && !select) { |
201 // Use the selection start if it is left of the selection end. | 201 // Use the selection start if it is left of the selection end. |
202 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), | 202 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), |
203 SelectionModel::LEADING); | 203 SelectionModel::LEADING); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 } | 244 } |
245 | 245 |
246 bool RenderText::MoveCursorTo(const Point& point, bool select) { | 246 bool RenderText::MoveCursorTo(const Point& point, bool select) { |
247 SelectionModel selection = FindCursorPosition(point); | 247 SelectionModel selection = FindCursorPosition(point); |
248 if (select) | 248 if (select) |
249 selection.set_selection_start(GetSelectionStart()); | 249 selection.set_selection_start(GetSelectionStart()); |
250 return MoveCursorTo(selection); | 250 return MoveCursorTo(selection); |
251 } | 251 } |
252 | 252 |
253 bool RenderText::IsPointInSelection(const Point& point) { | 253 bool RenderText::IsPointInSelection(const Point& point) { |
| 254 if (EmptySelection()) |
| 255 return false; |
254 // TODO(xji): should this check whether the point is inside the visual | 256 // TODO(xji): should this check whether the point is inside the visual |
255 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points | 257 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points |
256 // to the right half of 'c', is the point in selection? | 258 // to the right half of 'c', is the point in selection? |
257 size_t pos = FindCursorPosition(point).selection_end(); | 259 size_t pos = FindCursorPosition(point).selection_end(); |
258 return (pos >= MinOfSelection() && pos < MaxOfSelection()); | 260 return (pos >= MinOfSelection() && pos < MaxOfSelection()); |
259 } | 261 } |
260 | 262 |
261 void RenderText::ClearSelection() { | 263 void RenderText::ClearSelection() { |
262 SelectionModel sel(selection_model()); | 264 SelectionModel sel(selection_model()); |
263 sel.set_selection_start(GetCursorPosition()); | 265 sel.set_selection_start(GetCursorPosition()); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 } | 303 } |
302 | 304 |
303 // Now we move selection_end_ to end of selection. Selection boundary | 305 // Now we move selection_end_ to end of selection. Selection boundary |
304 // is defined as the position where we have alpha-num character on one side | 306 // is defined as the position where we have alpha-num character on one side |
305 // and non-alpha-num char on the other side. | 307 // and non-alpha-num char on the other side. |
306 for (; cursor_position < text().length(); cursor_position++) { | 308 for (; cursor_position < text().length(); cursor_position++) { |
307 if (IsPositionAtWordSelectionBoundary(cursor_position)) | 309 if (IsPositionAtWordSelectionBoundary(cursor_position)) |
308 break; | 310 break; |
309 } | 311 } |
310 | 312 |
311 SelectionModel sel(selection_model()); | 313 MoveCursorTo(selection_start, false); |
312 sel.set_selection_start(selection_start); | 314 MoveCursorTo(cursor_position, true); |
313 sel.set_selection_end(cursor_position); | |
314 sel.set_caret_pos(GetIndexOfPreviousGrapheme(cursor_position)); | |
315 sel.set_caret_placement(SelectionModel::TRAILING); | |
316 SetSelectionModel(sel); | |
317 } | 315 } |
318 | 316 |
319 const ui::Range& RenderText::GetCompositionRange() const { | 317 const ui::Range& RenderText::GetCompositionRange() const { |
320 return composition_range_; | 318 return composition_range_; |
321 } | 319 } |
322 | 320 |
323 void RenderText::SetCompositionRange(const ui::Range& composition_range) { | 321 void RenderText::SetCompositionRange(const ui::Range& composition_range) { |
324 CHECK(!composition_range.IsValid() || | 322 CHECK(!composition_range.IsValid() || |
325 ui::Range(0, text_.length()).Contains(composition_range)); | 323 ui::Range(0, text_.length()).Contains(composition_range)); |
326 composition_range_.set_end(composition_range.end()); | 324 composition_range_.set_end(composition_range.end()); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 // Apply a selection style override to a copy of the style ranges. | 567 // Apply a selection style override to a copy of the style ranges. |
570 if (!EmptySelection()) { | 568 if (!EmptySelection()) { |
571 StyleRange selection_style(default_style_); | 569 StyleRange selection_style(default_style_); |
572 selection_style.foreground = kSelectedTextColor; | 570 selection_style.foreground = kSelectedTextColor; |
573 selection_style.range.set_start(MinOfSelection()); | 571 selection_style.range.set_start(MinOfSelection()); |
574 selection_style.range.set_end(MaxOfSelection()); | 572 selection_style.range.set_end(MaxOfSelection()); |
575 ApplyStyleRangeImpl(style_ranges, selection_style); | 573 ApplyStyleRangeImpl(style_ranges, selection_style); |
576 } | 574 } |
577 } | 575 } |
578 | 576 |
| 577 void RenderText::MoveCursorTo(size_t position, bool select) { |
| 578 size_t caret_pos = GetIndexOfPreviousGrapheme(position); |
| 579 SelectionModel::CaretPlacement placement = (caret_pos == position) ? |
| 580 SelectionModel::LEADING : SelectionModel::TRAILING; |
| 581 size_t selection_start = select ? GetSelectionStart() : position; |
| 582 SelectionModel sel(selection_start, position, caret_pos, placement); |
| 583 SetSelectionModel(sel); |
| 584 } |
| 585 |
579 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { | 586 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) { |
580 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || | 587 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) || |
581 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); | 588 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos])); |
582 } | 589 } |
583 | 590 |
584 void RenderText::UpdateCachedBoundsAndOffset() { | 591 void RenderText::UpdateCachedBoundsAndOffset() { |
585 if (cached_bounds_and_offset_valid_) | 592 if (cached_bounds_and_offset_valid_) |
586 return; | 593 return; |
587 // First, set the valid flag true to calculate the current cursor bounds using | 594 // First, set the valid flag true to calculate the current cursor bounds using |
588 // the stale |display_offset_|. Applying |delta_offset| at the end of this | 595 // the stale |display_offset_|. Applying |delta_offset| at the end of this |
589 // function will set |cursor_bounds_| and |display_offset_| to correct values. | 596 // function will set |cursor_bounds_| and |display_offset_| to correct values. |
590 cached_bounds_and_offset_valid_ = true; | 597 cached_bounds_and_offset_valid_ = true; |
591 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); | 598 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); |
592 cursor_bounds_.set_width(std::max(cursor_bounds_.width(), 1)); | |
593 // Update |display_offset_| to ensure the current cursor is visible. | 599 // Update |display_offset_| to ensure the current cursor is visible. |
594 int display_width = display_rect_.width(); | 600 int display_width = display_rect_.width(); |
595 int string_width = GetStringWidth(); | 601 int string_width = GetStringWidth(); |
596 int delta_offset = 0; | 602 int delta_offset = 0; |
597 if (string_width < display_width) { | 603 if (string_width < display_width) { |
598 // Show all text whenever the text fits to the size. | 604 // Show all text whenever the text fits to the size. |
599 delta_offset = -display_offset_.x(); | 605 delta_offset = -display_offset_.x(); |
600 } else if (cursor_bounds_.right() > display_rect_.right()) { | 606 } else if (cursor_bounds_.right() > display_rect_.right()) { |
601 // Pan to show the cursor when it overflows to the right, | 607 // Pan to show the cursor when it overflows to the right, |
602 delta_offset = display_rect_.right() - cursor_bounds_.right(); | 608 delta_offset = display_rect_.right() - cursor_bounds_.right(); |
603 } else if (cursor_bounds_.x() < display_rect_.x()) { | 609 } else if (cursor_bounds_.x() < display_rect_.x()) { |
604 // Pan to show the cursor when it overflows to the left. | 610 // Pan to show the cursor when it overflows to the left. |
605 delta_offset = display_rect_.x() - cursor_bounds_.x(); | 611 delta_offset = display_rect_.x() - cursor_bounds_.x(); |
606 } | 612 } |
607 display_offset_.Offset(delta_offset, 0); | 613 display_offset_.Offset(delta_offset, 0); |
608 cursor_bounds_.Offset(delta_offset, 0); | 614 cursor_bounds_.Offset(delta_offset, 0); |
609 } | 615 } |
610 | 616 |
611 } // namespace gfx | 617 } // namespace gfx |
OLD | NEW |