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

Side by Side Diff: ui/gfx/render_text.cc

Issue 7598014: Adjust GetLeft/RightSelectionModel return, cursor on edit. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix caret placement API for RTL text edits. Created 9 years, 4 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 unified diff | Download patch | Annotate | Revision Log
« ui/gfx/render_text.h ('K') | « ui/gfx/render_text.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 } 175 }
176 176
177 size_t RenderText::GetCursorPosition() const { 177 size_t RenderText::GetCursorPosition() const {
178 return selection_model_.selection_end(); 178 return selection_model_.selection_end();
179 } 179 }
180 180
181 void RenderText::SetCursorPosition(const size_t position) { 181 void RenderText::SetCursorPosition(const size_t position) {
182 SelectionModel sel(selection_model()); 182 SelectionModel sel(selection_model());
183 sel.set_selection_start(position); 183 sel.set_selection_start(position);
184 sel.set_selection_end(position); 184 sel.set_selection_end(position);
185 sel.set_caret_pos(GetPreviousGrapheme(position));
186 sel.set_caret_placement(SelectionModel::TRAILING);
xji 2011/08/08 23:56:13 RenderText::ClearSelection() probably wont work af
msw 2011/08/09 01:07:42 Done.
185 SetSelectionModel(sel); 187 SetSelectionModel(sel);
186 } 188 }
187 189
188 void RenderText::MoveCursorLeft(BreakType break_type, bool select) { 190 void RenderText::MoveCursorLeft(BreakType break_type, bool select) {
189 if (break_type == LINE_BREAK) { 191 SelectionModel position = SelectionModel(GetCursorPosition(),
190 SelectionModel selection(GetSelectionStart(), 0, 192 GetCursorPosition(), SelectionModel::LEADING);
xji 2011/08/08 23:56:13 should the position be selection_model_? or select
msw 2011/08/09 01:07:42 Done.
191 0, SelectionModel::LEADING);
192 if (!select)
193 selection.set_selection_start(selection.selection_end());
194 MoveCursorTo(selection);
195 return;
196 }
197 SelectionModel position = selection_model_;
198 // Cancelling a selection moves to the edge of the selection. 193 // Cancelling a selection moves to the edge of the selection.
199 if (!EmptySelection() && !select) { 194 if (!EmptySelection() && !select) {
200 // Use the selection start if it is left of the selection end. 195 // Use the selection start if it is left of the selection end.
201 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 196 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(),
202 GetSelectionStart(), SelectionModel::LEADING); 197 SelectionModel::LEADING);
203 if (GetCursorBounds(selection_start, false).x() < 198 if (GetCursorBounds(selection_start, false).x() <
204 GetCursorBounds(position, false).x()) 199 GetCursorBounds(position, false).x())
205 position = selection_start; 200 position = selection_start;
206 // If |move_by_word|, use the nearest word boundary left of the selection. 201 // For word and line breaks, the cursor moves beyond the selection edge.
207 if (break_type == WORD_BREAK) 202 if (break_type != CHARACTER_BREAK)
208 position = GetLeftCursorPosition(position, true); 203 position = GetLeftSelectionModel(position, break_type);
209 } else { 204 } else {
210 position = GetLeftCursorPosition(position, break_type == WORD_BREAK); 205 position = GetLeftSelectionModel(position, break_type);
211 } 206 }
212 if (!select) 207 if (select)
213 position.set_selection_start(position.selection_end()); 208 position.set_selection_start(GetSelectionStart());
214 MoveCursorTo(position); 209 MoveCursorTo(position);
215 } 210 }
216 211
217 void RenderText::MoveCursorRight(BreakType break_type, bool select) { 212 void RenderText::MoveCursorRight(BreakType break_type, bool select) {
218 if (break_type == LINE_BREAK) { 213 SelectionModel position = SelectionModel(GetCursorPosition(),
219 SelectionModel selection(GetSelectionStart(), text().length(), 214 GetCursorPosition(), SelectionModel::LEADING);
xji 2011/08/08 23:56:13 ditto
msw 2011/08/09 01:07:42 Done.
220 text().length(), SelectionModel::PREVIOUS_GRAPHEME_TRAILING);
221 if (!select)
222 selection.set_selection_start(selection.selection_end());
223 MoveCursorTo(selection);
224 return;
225 }
226 SelectionModel position = selection_model_;
227 // Cancelling a selection moves to the edge of the selection. 215 // Cancelling a selection moves to the edge of the selection.
228 if (!EmptySelection() && !select) { 216 if (!EmptySelection() && !select) {
229 // Use the selection start if it is right of the selection end. 217 // Use the selection start if it is right of the selection end.
230 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(), 218 SelectionModel selection_start(GetSelectionStart(), GetSelectionStart(),
231 GetSelectionStart(), SelectionModel::LEADING); 219 SelectionModel::LEADING);
232 if (GetCursorBounds(selection_start, false).x() > 220 if (GetCursorBounds(selection_start, false).x() >
233 GetCursorBounds(position, false).x()) 221 GetCursorBounds(position, false).x())
234 position = selection_start; 222 position = selection_start;
235 // If |move_by_word|, use the nearest word boundary right of the selection. 223 // For word and line breaks, the cursor moves beyond the selection edge.
236 if (break_type == WORD_BREAK) 224 if (break_type != CHARACTER_BREAK)
237 position = GetRightCursorPosition(position, true); 225 position = GetRightSelectionModel(position, break_type);
238 } else { 226 } else {
239 position = GetRightCursorPosition(position, break_type == WORD_BREAK); 227 position = GetRightSelectionModel(position, break_type);
240 } 228 }
241 if (!select) 229 if (select)
242 position.set_selection_start(position.selection_end()); 230 position.set_selection_start(GetSelectionStart());
243 MoveCursorTo(position); 231 MoveCursorTo(position);
244 } 232 }
245 233
246 bool RenderText::MoveCursorTo(const SelectionModel& selection) { 234 bool RenderText::MoveCursorTo(const SelectionModel& selection) {
247 bool changed = !selection.Equals(selection_model_); 235 bool changed = !selection.Equals(selection_model_);
248 SetSelectionModel(selection); 236 SetSelectionModel(selection);
249 return changed; 237 return changed;
250 } 238 }
251 239
252 bool RenderText::MoveCursorTo(const Point& point, bool select) { 240 bool RenderText::MoveCursorTo(const Point& point, bool select) {
253 SelectionModel selection = FindCursorPosition(point); 241 SelectionModel selection = FindCursorPosition(point);
254 if (select) 242 if (select)
255 selection.set_selection_start(GetSelectionStart()); 243 selection.set_selection_start(GetSelectionStart());
256 else
257 selection.set_selection_start(selection.selection_end());
258 return MoveCursorTo(selection); 244 return MoveCursorTo(selection);
259 } 245 }
260 246
261 bool RenderText::IsPointInSelection(const Point& point) { 247 bool RenderText::IsPointInSelection(const Point& point) {
262 // TODO(xji): should this check whether the point is inside the visual 248 // TODO(xji): should this check whether the point is inside the visual
263 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points 249 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points
264 // to the right half of 'c', is the point in selection? 250 // to the right half of 'c', is the point in selection?
265 size_t pos = FindCursorPosition(point).selection_end(); 251 size_t pos = FindCursorPosition(point).selection_end();
266 return (pos >= MinOfSelection() && pos < MaxOfSelection()); 252 return (pos >= MinOfSelection() && pos < MaxOfSelection());
267 } 253 }
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
496 cursor_bounds_valid_(false), 482 cursor_bounds_valid_(false),
497 cursor_visible_(false), 483 cursor_visible_(false),
498 insert_mode_(true), 484 insert_mode_(true),
499 composition_range_(), 485 composition_range_(),
500 style_ranges_(), 486 style_ranges_(),
501 default_style_(), 487 default_style_(),
502 display_rect_(), 488 display_rect_(),
503 display_offset_() { 489 display_offset_() {
504 } 490 }
505 491
506 SelectionModel RenderText::GetLeftCursorPosition(const SelectionModel& current, 492 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
507 bool move_by_word) { 493 BreakType break_type) {
508 size_t position = current.selection_end(); 494 if (break_type == LINE_BREAK)
509 SelectionModel left = current; 495 return SelectionModel(0, 0, SelectionModel::LEADING);
510 if (!move_by_word) { 496 size_t pos = std::max(static_cast<long>(current.selection_end() - 1),
511 left.set_selection_end(std::max(static_cast<long>(position - 1), 497 static_cast<long>(0));
512 static_cast<long>(0))); 498 if (break_type == CHARACTER_BREAK)
513 return left; 499 return SelectionModel(pos, pos, SelectionModel::LEADING);
514 } 500
515 // Notes: We always iterate words from the begining. 501 // Notes: We always iterate words from the begining.
516 // This is probably fast enough for our usage, but we may 502 // This is probably fast enough for our usage, but we may
517 // want to modify WordIterator so that it can start from the 503 // want to modify WordIterator so that it can start from the
518 // middle of string and advance backwards. 504 // middle of string and advance backwards.
519 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 505 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
520 bool success = iter.Init(); 506 bool success = iter.Init();
521 DCHECK(success); 507 DCHECK(success);
522 if (!success) { 508 if (!success)
523 left.set_selection_end(position); 509 return current;
524 return left;
525 }
526 int last = 0;
527 while (iter.Advance()) { 510 while (iter.Advance()) {
528 if (iter.IsWord()) { 511 if (iter.IsWord()) {
529 size_t begin = iter.pos() - iter.GetString().length(); 512 size_t begin = iter.pos() - iter.GetString().length();
530 if (begin == position) { 513 if (begin == current.selection_end()) {
531 // The cursor is at the beginning of a word. 514 // The cursor is at the beginning of a word.
532 // Move to previous word. 515 // Move to previous word.
533 break; 516 break;
534 } else if (iter.pos() >= position) { 517 } else if (iter.pos() >= current.selection_end()) {
535 // The cursor is in the middle or at the end of a word. 518 // The cursor is in the middle or at the end of a word.
536 // Move to the top of current word. 519 // Move to the top of current word.
537 last = begin; 520 pos = begin;
538 break; 521 break;
539 } else { 522 } else {
540 last = iter.pos() - iter.GetString().length(); 523 pos = iter.pos() - iter.GetString().length();
541 } 524 }
542 } 525 }
543 } 526 }
544 527
545 left.set_selection_end(last); 528 return SelectionModel(pos, pos, SelectionModel::LEADING);
546 return left;
547 } 529 }
548 530
549 SelectionModel RenderText::GetRightCursorPosition(const SelectionModel& current, 531 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
550 bool move_by_word) { 532 BreakType break_type) {
551 size_t position = current.selection_end(); 533 if (break_type == LINE_BREAK)
552 SelectionModel right = current; 534 return SelectionModel(text().length(), text().length(),
553 535 SelectionModel::LEADING);
xji 2011/08/08 23:56:13 this will return the rightmost visual extreme of t
msw 2011/08/09 01:07:42 Done.
554 if (!move_by_word) { 536 size_t pos = std::min(current.selection_end() + 1, text().length());
555 right.set_selection_end(std::min(position + 1, text().length())); 537 if (break_type == CHARACTER_BREAK)
556 return right; 538 return SelectionModel(pos, pos, SelectionModel::LEADING);
557 }
558 539
559 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 540 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
560 bool success = iter.Init(); 541 bool success = iter.Init();
561 DCHECK(success); 542 DCHECK(success);
562 if (!success) { 543 if (!success)
563 right.set_selection_end(position); 544 return current;
564 return right;
565 }
566 size_t pos = 0;
567 while (iter.Advance()) { 545 while (iter.Advance()) {
568 pos = iter.pos(); 546 pos = iter.pos();
569 if (iter.IsWord() && pos > position) { 547 if (iter.IsWord() && pos > current.selection_end())
570 break; 548 break;
571 }
572 } 549 }
573 right.set_selection_end(pos); 550 return SelectionModel(pos, pos, SelectionModel::LEADING);
574 return right; 551 }
552
553 size_t RenderText::GetPreviousGrapheme(size_t position) const {
554 // TODO(msw): Handle complex script.
555 return std::max(static_cast<int>(position - 1), static_cast<int>(0));
575 } 556 }
576 557
577 void RenderText::ApplyCompositionAndSelectionStyles( 558 void RenderText::ApplyCompositionAndSelectionStyles(
578 StyleRanges* style_ranges) const { 559 StyleRanges* style_ranges) const {
579 // TODO(msw): This pattern ought to be reconsidered; what about composition 560 // TODO(msw): This pattern ought to be reconsidered; what about composition
580 // and selection overlaps, retain existing local style features? 561 // and selection overlaps, retain existing local style features?
581 // Apply a composition style override to a copy of the style ranges. 562 // Apply a composition style override to a copy of the style ranges.
582 if (composition_range_.IsValid() && !composition_range_.is_empty()) { 563 if (composition_range_.IsValid() && !composition_range_.is_empty()) {
583 StyleRange composition_style(default_style_); 564 StyleRange composition_style(default_style_);
584 composition_style.underline = true; 565 composition_style.underline = true;
(...skipping 27 matching lines...) Expand all
612 } else if ((display_offset_.x() + cursor_bounds_.right()) > display_width) { 593 } else if ((display_offset_.x() + cursor_bounds_.right()) > display_width) {
613 // Pan to show the cursor when it overflows to the right, 594 // Pan to show the cursor when it overflows to the right,
614 display_offset_.set_x(display_width - cursor_bounds_.right()); 595 display_offset_.set_x(display_width - cursor_bounds_.right());
615 } else if ((display_offset_.x() + cursor_bounds_.x()) < 0) { 596 } else if ((display_offset_.x() + cursor_bounds_.x()) < 0) {
616 // Pan to show the cursor when it overflows to the left. 597 // Pan to show the cursor when it overflows to the left.
617 display_offset_.set_x(-cursor_bounds_.x()); 598 display_offset_.set_x(-cursor_bounds_.x());
618 } 599 }
619 } 600 }
620 601
621 } // namespace gfx 602 } // namespace gfx
OLDNEW
« ui/gfx/render_text.h ('K') | « ui/gfx/render_text.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698