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

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

Issue 7841056: fix know issues in RenderText (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: aupdate RenderTextWin. update test for Win platform. upload RenderTextTest that was missed Created 9 years, 3 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
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 229 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 // The current model only supports caret positions at valid character indices. 240 // The current model only supports caret positions at valid character indices.
241 if (text_length == 0) { 241 if (text_length == 0) {
242 sel.set_caret_pos(0); 242 sel.set_caret_pos(0);
243 sel.set_caret_placement(SelectionModel::LEADING); 243 sel.set_caret_placement(SelectionModel::LEADING);
244 } else if (sel.caret_pos() >= text_length) { 244 } else if (sel.caret_pos() >= text_length) {
245 SelectionModel end = GetTextDirection() == base::i18n::RIGHT_TO_LEFT ? 245 SelectionModel end = GetTextDirection() == base::i18n::RIGHT_TO_LEFT ?
246 LeftEndSelectionModel() : RightEndSelectionModel(); 246 LeftEndSelectionModel() : RightEndSelectionModel();
247 sel.set_caret_pos(end.caret_pos()); 247 sel.set_caret_pos(end.caret_pos());
248 sel.set_caret_placement(end.caret_placement()); 248 sel.set_caret_placement(end.caret_placement());
249 } 249 }
250
251 if (!IsCursorablePosition(sel.selection_start()) ||
252 !IsCursorablePosition(sel.selection_end()) ||
253 !IsCursorablePosition(sel.caret_pos()))
254 return false;
255
250 bool changed = !sel.Equals(selection_model_); 256 bool changed = !sel.Equals(selection_model_);
251 SetSelectionModel(sel); 257 SetSelectionModel(sel);
252 return changed; 258 return changed;
253 } 259 }
254 260
255 bool RenderText::MoveCursorTo(const Point& point, bool select) { 261 bool RenderText::MoveCursorTo(const Point& point, bool select) {
256 SelectionModel selection = FindCursorPosition(point); 262 SelectionModel selection = FindCursorPosition(point);
257 if (select) 263 if (select)
258 selection.set_selection_start(GetSelectionStart()); 264 selection.set_selection_start(GetSelectionStart());
259 return MoveCursorTo(selection); 265 return MoveCursorTo(selection);
(...skipping 14 matching lines...) Expand all
274 sel.set_selection_start(GetCursorPosition()); 280 sel.set_selection_start(GetCursorPosition());
275 SetSelectionModel(sel); 281 SetSelectionModel(sel);
276 } 282 }
277 283
278 void RenderText::SelectAll() { 284 void RenderText::SelectAll() {
279 SelectionModel sel(RightEndSelectionModel()); 285 SelectionModel sel(RightEndSelectionModel());
280 sel.set_selection_start(LeftEndSelectionModel().selection_start()); 286 sel.set_selection_start(LeftEndSelectionModel().selection_start());
281 SetSelectionModel(sel); 287 SetSelectionModel(sel);
282 } 288 }
283 289
284 // TODO(xji): it does not work for languages do not use space as word breaker,
285 // such as Chinese. Should use BreakIterator.
286 void RenderText::SelectWord() { 290 void RenderText::SelectWord() {
287 size_t selection_start = GetSelectionStart();
288 size_t cursor_position = GetCursorPosition(); 291 size_t cursor_position = GetCursorPosition();
289 // First we setup selection_start_ and selection_end_. There are so many cases
290 // because we try to emulate what select-word looks like in a gtk textfield.
291 // See associated testcase for different cases.
292 if (cursor_position > 0 && cursor_position < text().length()) {
293 if (u_isalnum(text()[cursor_position])) {
294 selection_start = cursor_position;
295 cursor_position++;
296 } else
297 selection_start = cursor_position - 1;
298 } else if (cursor_position == 0) {
299 selection_start = cursor_position;
300 if (text().length() > 0)
301 cursor_position++;
302 } else {
303 selection_start = cursor_position - 1;
304 }
305 292
306 // Now we move selection_start_ to beginning of selection. Selection boundary 293 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
307 // is defined as the position where we have alpha-num character on one side 294 bool success = iter.Init();
308 // and non-alpha-num char on the other side. 295 DCHECK(success);
309 for (; selection_start > 0; selection_start--) { 296 if (!success)
310 if (IsPositionAtWordSelectionBoundary(selection_start)) 297 return;
298
299 size_t selection_start = cursor_position;
300 for (; selection_start != 0; --selection_start) {
301 if (iter.IsStartOfWord(selection_start) ||
302 iter.IsEndOfWord(selection_start))
311 break; 303 break;
312 } 304 }
313 305
314 // Now we move selection_end_ to end of selection. Selection boundary 306 if (selection_start == cursor_position)
315 // is defined as the position where we have alpha-num character on one side 307 ++cursor_position;
316 // and non-alpha-num char on the other side. 308
317 for (; cursor_position < text().length(); cursor_position++) { 309 for (; cursor_position < text().length(); ++cursor_position) {
318 if (IsPositionAtWordSelectionBoundary(cursor_position)) 310 if (iter.IsEndOfWord(cursor_position) ||
311 iter.IsStartOfWord(cursor_position))
319 break; 312 break;
320 } 313 }
321 314
322 MoveCursorTo(selection_start, false); 315 MoveCursorTo(selection_start, false);
323 MoveCursorTo(cursor_position, true); 316 MoveCursorTo(cursor_position, true);
324 } 317 }
325 318
326 const ui::Range& RenderText::GetCompositionRange() const { 319 const ui::Range& RenderText::GetCompositionRange() const {
327 return composition_range_; 320 return composition_range_;
328 } 321 }
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
455 size_t from = selection.selection_end(); 448 size_t from = selection.selection_end();
456 size_t to = insert_mode ? from : std::min(text_.length(), from + 1); 449 size_t to = insert_mode ? from : std::min(text_.length(), from + 1);
457 return GetSubstringBounds(from, to)[0]; 450 return GetSubstringBounds(from, to)[0];
458 } 451 }
459 452
460 const Rect& RenderText::GetUpdatedCursorBounds() { 453 const Rect& RenderText::GetUpdatedCursorBounds() {
461 UpdateCachedBoundsAndOffset(); 454 UpdateCachedBoundsAndOffset();
462 return cursor_bounds_; 455 return cursor_bounds_;
463 } 456 }
464 457
458 size_t RenderText::GetIndexOfNextGrapheme(size_t position) {
459 // TODO(xji): Handle complex script.
460 return std::min(static_cast<long>(position + 1),
msw 2011/09/14 02:43:48 Both of these static casts have lint errors: "Use
xji 2011/09/15 23:38:13 Merged win/linux impls.
461 static_cast<long>(text_.length()));
462 }
463
465 RenderText::RenderText() 464 RenderText::RenderText()
466 : text_(), 465 : text_(),
467 selection_model_(), 466 selection_model_(),
468 cursor_bounds_(), 467 cursor_bounds_(),
469 cursor_visible_(false), 468 cursor_visible_(false),
470 insert_mode_(true), 469 insert_mode_(true),
471 composition_range_(ui::Range::InvalidRange()), 470 composition_range_(ui::Range::InvalidRange()),
472 style_ranges_(), 471 style_ranges_(),
473 default_style_(), 472 default_style_(),
474 display_rect_(), 473 display_rect_(),
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 int start_x = font.GetStringWidth(text().substr(0, start)); 567 int start_x = font.GetStringWidth(text().substr(0, start));
569 int end_x = font.GetStringWidth(text().substr(0, end)); 568 int end_x = font.GetStringWidth(text().substr(0, end));
570 Rect rect(start_x, 0, end_x - start_x, font.GetHeight()); 569 Rect rect(start_x, 0, end_x - start_x, font.GetHeight());
571 rect.Offset(display_rect_.origin()); 570 rect.Offset(display_rect_.origin());
572 rect.Offset(GetUpdatedDisplayOffset()); 571 rect.Offset(GetUpdatedDisplayOffset());
573 // Center the rect vertically in |display_rect_|. 572 // Center the rect vertically in |display_rect_|.
574 rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2)); 573 rect.Offset(Point(0, (display_rect_.height() - rect.height()) / 2));
575 return std::vector<Rect>(1, rect); 574 return std::vector<Rect>(1, rect);
576 } 575 }
577 576
577 bool RenderText::IsCursorablePosition(size_t position) {
578 return true;
msw 2011/09/14 02:43:48 I think this can potentially be pure virtual, and
xji 2011/09/15 23:38:13 Done.
579 }
580
578 void RenderText::ApplyCompositionAndSelectionStyles( 581 void RenderText::ApplyCompositionAndSelectionStyles(
579 StyleRanges* style_ranges) const { 582 StyleRanges* style_ranges) const {
580 // TODO(msw): This pattern ought to be reconsidered; what about composition 583 // TODO(msw): This pattern ought to be reconsidered; what about composition
581 // and selection overlaps, retain existing local style features? 584 // and selection overlaps, retain existing local style features?
582 // Apply a composition style override to a copy of the style ranges. 585 // Apply a composition style override to a copy of the style ranges.
583 if (composition_range_.IsValid() && !composition_range_.is_empty()) { 586 if (composition_range_.IsValid() && !composition_range_.is_empty()) {
584 StyleRange composition_style(default_style_); 587 StyleRange composition_style(default_style_);
585 composition_style.underline = true; 588 composition_style.underline = true;
586 composition_style.range.set_start(composition_range_.start()); 589 composition_style.range.set_start(composition_range_.start());
587 composition_style.range.set_end(composition_range_.end()); 590 composition_style.range.set_end(composition_range_.end());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
625 628
626 cached_bounds_and_offset_valid_ = false; 629 cached_bounds_and_offset_valid_ = false;
627 } 630 }
628 631
629 void RenderText::MoveCursorTo(size_t position, bool select) { 632 void RenderText::MoveCursorTo(size_t position, bool select) {
630 size_t cursor = std::min(position, text().length()); 633 size_t cursor = std::min(position, text().length());
631 size_t caret_pos = GetIndexOfPreviousGrapheme(cursor); 634 size_t caret_pos = GetIndexOfPreviousGrapheme(cursor);
632 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ? 635 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ?
633 SelectionModel::LEADING : SelectionModel::TRAILING; 636 SelectionModel::LEADING : SelectionModel::TRAILING;
634 size_t selection_start = select ? GetSelectionStart() : cursor; 637 size_t selection_start = select ? GetSelectionStart() : cursor;
635 SelectionModel sel(selection_start, cursor, caret_pos, placement); 638 if (IsCursorablePosition(cursor)) {
636 SetSelectionModel(sel); 639 SelectionModel sel(selection_start, cursor, caret_pos, placement);
637 } 640 SetSelectionModel(sel);
638 641 }
639 bool RenderText::IsPositionAtWordSelectionBoundary(size_t pos) {
640 return pos == 0 || (u_isalnum(text()[pos - 1]) && !u_isalnum(text()[pos])) ||
641 (!u_isalnum(text()[pos - 1]) && u_isalnum(text()[pos]));
642 } 642 }
643 643
644 void RenderText::UpdateCachedBoundsAndOffset() { 644 void RenderText::UpdateCachedBoundsAndOffset() {
645 if (cached_bounds_and_offset_valid_) 645 if (cached_bounds_and_offset_valid_)
646 return; 646 return;
647 // First, set the valid flag true to calculate the current cursor bounds using 647 // First, set the valid flag true to calculate the current cursor bounds using
648 // the stale |display_offset_|. Applying |delta_offset| at the end of this 648 // the stale |display_offset_|. Applying |delta_offset| at the end of this
649 // function will set |cursor_bounds_| and |display_offset_| to correct values. 649 // function will set |cursor_bounds_| and |display_offset_| to correct values.
650 cached_bounds_and_offset_valid_ = true; 650 cached_bounds_and_offset_valid_ = true;
651 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_); 651 cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
(...skipping 30 matching lines...) Expand all
682 selection_start, 682 selection_start,
683 SelectionModel::LEADING); 683 SelectionModel::LEADING);
684 else if (selection_start > selection_end) 684 else if (selection_start > selection_end)
685 return SelectionModel(selection_start, 685 return SelectionModel(selection_start,
686 GetIndexOfPreviousGrapheme(selection_start), 686 GetIndexOfPreviousGrapheme(selection_start),
687 SelectionModel::TRAILING); 687 SelectionModel::TRAILING);
688 return selection_model_; 688 return selection_model_;
689 } 689 }
690 690
691 } // namespace gfx 691 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_linux.h » ('j') | ui/gfx/render_text_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698