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

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

Issue 9390022: Simplify handling of BiDi cursor movement (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 10 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/i18n/break_iterator.h" 10 #include "base/i18n/break_iterator.h"
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
325 // range ends beyond text_.length, it must be the last one. 325 // range ends beyond text_.length, it must be the last one.
326 style_ranges_.back().range.set_end(text_.length()); 326 style_ranges_.back().range.set_end(text_.length());
327 } 327 }
328 #ifndef NDEBUG 328 #ifndef NDEBUG
329 CheckStyleRanges(style_ranges_, text_.length()); 329 CheckStyleRanges(style_ranges_, text_.length());
330 #endif 330 #endif
331 cached_bounds_and_offset_valid_ = false; 331 cached_bounds_and_offset_valid_ = false;
332 332
333 // Reset selection model. SetText should always followed by SetSelectionModel 333 // Reset selection model. SetText should always followed by SetSelectionModel
334 // or SetCursorPosition in upper layer. 334 // or SetCursorPosition in upper layer.
335 SetSelectionModel(SelectionModel(0, 0, SelectionModel::LEADING)); 335 SetSelectionModel(SelectionModel());
336 336
337 UpdateLayout(); 337 UpdateLayout();
338 } 338 }
339 339
340 void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) { 340 void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) {
341 if (horizontal_alignment_ != alignment) { 341 if (horizontal_alignment_ != alignment) {
342 horizontal_alignment_ = alignment; 342 horizontal_alignment_ = alignment;
343 display_offset_ = Point(); 343 display_offset_ = Point();
344 cached_bounds_and_offset_valid_ = false; 344 cached_bounds_and_offset_valid_ = false;
345 } 345 }
(...skipping 24 matching lines...) Expand all
370 insert_mode_ = !insert_mode_; 370 insert_mode_ = !insert_mode_;
371 cached_bounds_and_offset_valid_ = false; 371 cached_bounds_and_offset_valid_ = false;
372 } 372 }
373 373
374 void RenderText::SetDisplayRect(const Rect& r) { 374 void RenderText::SetDisplayRect(const Rect& r) {
375 display_rect_ = r; 375 display_rect_ = r;
376 cached_bounds_and_offset_valid_ = false; 376 cached_bounds_and_offset_valid_ = false;
377 UpdateLayout(); 377 UpdateLayout();
378 } 378 }
379 379
380 size_t RenderText::GetCursorPosition() const {
381 return selection_model_.selection_end();
382 }
383
384 void RenderText::SetCursorPosition(size_t position) { 380 void RenderText::SetCursorPosition(size_t position) {
385 MoveCursorTo(position, false); 381 MoveCursorTo(position, false);
386 } 382 }
387 383
388 void RenderText::MoveCursor(BreakType break_type, 384 void RenderText::MoveCursor(BreakType break_type,
389 VisualCursorDirection direction, 385 VisualCursorDirection direction,
390 bool select) { 386 bool select) {
391 SelectionModel position(selection_model()); 387 SelectionModel position(cursor_position(), selection_model_.caret_affinity());
392 position.set_selection_start(GetCursorPosition());
393 // Cancelling a selection moves to the edge of the selection. 388 // Cancelling a selection moves to the edge of the selection.
394 if (break_type != LINE_BREAK && !EmptySelection() && !select) { 389 if (break_type != LINE_BREAK && !selection().is_empty() && !select) {
395 SelectionModel selection_start = GetSelectionModelForSelectionStart(); 390 SelectionModel selection_start = GetSelectionModelForSelectionStart();
396 int start_x = GetCursorBounds(selection_start, true).x(); 391 int start_x = GetCursorBounds(selection_start, true).x();
397 int cursor_x = GetCursorBounds(position, true).x(); 392 int cursor_x = GetCursorBounds(position, true).x();
398 // Use the selection start if it is left (when |direction| is CURSOR_LEFT) 393 // Use the selection start if it is left (when |direction| is CURSOR_LEFT)
399 // or right (when |direction| is CURSOR_RIGHT) of the selection end. 394 // or right (when |direction| is CURSOR_RIGHT) of the selection end.
400 if (direction == CURSOR_RIGHT ? start_x > cursor_x : start_x < cursor_x) 395 if (direction == CURSOR_RIGHT ? start_x > cursor_x : start_x < cursor_x)
401 position = selection_start; 396 position = selection_start;
402 // For word breaks, use the nearest word boundary in the appropriate 397 // For word breaks, use the nearest word boundary in the appropriate
403 // |direction|. 398 // |direction|.
404 if (break_type == WORD_BREAK) 399 if (break_type == WORD_BREAK)
405 position = GetAdjacentSelectionModel(position, break_type, direction); 400 position = GetAdjacentSelectionModel(position, break_type, direction);
406 } else { 401 } else {
407 position = GetAdjacentSelectionModel(position, break_type, direction); 402 position = GetAdjacentSelectionModel(position, break_type, direction);
408 } 403 }
409 if (select) 404 if (select)
410 position.set_selection_start(GetSelectionStart()); 405 position.set_selection_start(selection().start());
411 MoveCursorTo(position); 406 MoveCursorTo(position);
412 } 407 }
413 408
414 bool RenderText::MoveCursorTo(const SelectionModel& model) { 409 bool RenderText::MoveCursorTo(const SelectionModel& model) {
415 SelectionModel sel(model); 410 // Enforce valid selection model components.
416 size_t text_length = text().length(); 411 size_t text_length = text().length();
417 // Enforce valid selection model components. 412 ui::Range range(std::min(model.selection().start(), text_length),
418 if (sel.selection_start() > text_length) 413 std::min(model.caret_pos(), text_length));
419 sel.set_selection_start(text_length); 414 LogicalCursorDirection affinity = model.caret_affinity();
420 if (sel.selection_end() > text_length) 415 if (model.caret_pos() > text_length)
421 sel.set_selection_end(text_length); 416 // Make the cursor appear at the edge of the text, not next to the final
417 // grapheme.
418 affinity = CURSOR_FORWARD;
419
422 // The current model only supports caret positions at valid character indices. 420 // The current model only supports caret positions at valid character indices.
423 if (text_length == 0) { 421 if (!IsCursorablePosition(range.start()) ||
424 sel.set_caret_pos(0); 422 !IsCursorablePosition(range.end()))
425 sel.set_caret_placement(SelectionModel::LEADING);
426 } else if (sel.caret_pos() >= text_length) {
427 SelectionModel end_selection =
428 EdgeSelectionModel(GetVisualDirectionOfLogicalEnd());
429 sel.set_caret_pos(end_selection.caret_pos());
430 sel.set_caret_placement(end_selection.caret_placement());
431 }
432
433 if (!IsCursorablePosition(sel.selection_start()) ||
434 !IsCursorablePosition(sel.selection_end()) ||
435 !IsCursorablePosition(sel.caret_pos()))
436 return false; 423 return false;
437 424
438 bool changed = !sel.Equals(selection_model_); 425 SelectionModel sel(range, affinity);
426 bool changed = sel != selection_model_;
439 SetSelectionModel(sel); 427 SetSelectionModel(sel);
440 return changed; 428 return changed;
441 } 429 }
442 430
443 bool RenderText::MoveCursorTo(const Point& point, bool select) { 431 bool RenderText::MoveCursorTo(const Point& point, bool select) {
444 SelectionModel selection = FindCursorPosition(point); 432 SelectionModel position = FindCursorPosition(point);
445 if (select) 433 if (select)
446 selection.set_selection_start(GetSelectionStart()); 434 position.set_selection_start(selection().start());
447 return MoveCursorTo(selection); 435 return MoveCursorTo(position);
448 } 436 }
449 437
450 bool RenderText::SelectRange(const ui::Range& range) { 438 bool RenderText::SelectRange(const ui::Range& range) {
451 size_t text_length = text().length(); 439 ui::Range sel(std::min(range.start(), text().length()),
452 size_t start = std::min(range.start(), text_length); 440 std::min(range.end(), text().length()));
453 size_t end = std::min(range.end(), text_length); 441 if (!IsCursorablePosition(sel.start()) || !IsCursorablePosition(sel.end()))
454
455 if (!IsCursorablePosition(start) || !IsCursorablePosition(end))
456 return false; 442 return false;
457 443 LogicalCursorDirection affinity =
458 size_t pos = end; 444 (sel.is_reversed() || (sel.is_empty() && sel.start() != 0)) ?
459 SelectionModel::CaretPlacement placement = SelectionModel::LEADING; 445 CURSOR_FORWARD : CURSOR_BACKWARD;
460 if (start < end) { 446 SetSelectionModel(SelectionModel(sel, affinity));
461 pos = IndexOfAdjacentGrapheme(end, CURSOR_BACKWARD);
462 DCHECK_LT(pos, end);
463 placement = SelectionModel::TRAILING;
464 } else if (end == text_length) {
465 SelectionModel end_selection =
466 EdgeSelectionModel(GetVisualDirectionOfLogicalEnd());
467 pos = end_selection.caret_pos();
468 placement = end_selection.caret_placement();
469 }
470 SetSelectionModel(SelectionModel(start, end, pos, placement));
471 return true; 447 return true;
472 } 448 }
473 449
474 bool RenderText::IsPointInSelection(const Point& point) { 450 bool RenderText::IsPointInSelection(const Point& point) {
475 if (EmptySelection()) 451 if (selection().is_empty())
476 return false; 452 return false;
477 // TODO(xji): should this check whether the point is inside the visual 453 SelectionModel cursor = FindCursorPosition(point);
478 // selection bounds? In case of "abcFED", if "ED" is selected, |point| points 454 size_t caret_pos = cursor.caret_pos();
479 // to the right half of 'c', is the point in selection? 455 bool forward = cursor.caret_affinity() == CURSOR_FORWARD;
480 size_t pos = FindCursorPosition(point).selection_end(); 456 // NB: exploits unsigned wraparound (0 - 1).
481 return (pos >= MinOfSelection() && pos < MaxOfSelection()); 457 ui::Range range(caret_pos, forward ? caret_pos + 1 : caret_pos - 1);
458 return selection().Contains(range);
482 } 459 }
483 460
484 void RenderText::ClearSelection() { 461 void RenderText::ClearSelection() {
485 SelectionModel sel(selection_model()); 462 SetSelectionModel(SelectionModel(selection_model_.caret_pos(),
486 sel.set_selection_start(GetCursorPosition()); 463 selection_model_.caret_affinity()));
487 SetSelectionModel(sel);
488 } 464 }
489 465
490 void RenderText::SelectAll() { 466 void RenderText::SelectAll() {
491 SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); 467 SelectionModel all;
492 sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); 468 if (GetTextDirection() == base::i18n::LEFT_TO_RIGHT)
493 SetSelectionModel(sel); 469 all = SelectionModel(ui::Range(0, text().length()), CURSOR_FORWARD);
470 else
471 all = SelectionModel(ui::Range(text().length(), 0), CURSOR_BACKWARD);
472 SetSelectionModel(all);
494 } 473 }
495 474
496 void RenderText::SelectWord() { 475 void RenderText::SelectWord() {
497 size_t cursor_position = GetCursorPosition(); 476 size_t cursor_position = selection_model_.caret_pos();
498 477
499 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 478 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
500 bool success = iter.Init(); 479 bool success = iter.Init();
501 DCHECK(success); 480 DCHECK(success);
502 if (!success) 481 if (!success)
503 return; 482 return;
504 483
505 size_t selection_start = cursor_position; 484 size_t selection_start = cursor_position;
506 for (; selection_start != 0; --selection_start) { 485 for (; selection_start != 0; --selection_start) {
507 if (iter.IsStartOfWord(selection_start) || 486 if (iter.IsStartOfWord(selection_start) ||
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 557
579 DrawCursor(canvas); 558 DrawCursor(canvas);
580 559
581 if (!text().empty()) { 560 if (!text().empty()) {
582 TRACE_EVENT0("gfx", "RenderText::Draw draw text"); 561 TRACE_EVENT0("gfx", "RenderText::Draw draw text");
583 DrawVisualText(canvas); 562 DrawVisualText(canvas);
584 } 563 }
585 canvas->Restore(); 564 canvas->Restore();
586 } 565 }
587 566
567 Rect RenderText::GetCursorBounds(const SelectionModel& selection,
568 bool insert_mode) {
569 EnsureLayout();
570
571 size_t caret_pos = selection.caret_pos();
572 LogicalCursorDirection caret_affinity = selection.caret_affinity();
573 int x, width, height;
574 if (caret_pos == (caret_affinity == CURSOR_BACKWARD ? 0 : text().length())) {
575 // The caret is attached to the boundary. Always return a zero-width caret,
576 // since there is nothing to overstrike.
577 Size size = GetStringSize();
578 if ((GetTextDirection() == base::i18n::LEFT_TO_RIGHT) == (caret_pos == 0))
579 x = 0;
580 else
581 x = size.width();
582 width = 0;
583 height = size.height();
584 } else {
585 if (caret_affinity == CURSOR_BACKWARD)
586 caret_pos = IndexOfAdjacentGrapheme(caret_pos, CURSOR_BACKWARD);
587 ui::Range xspan;
588 GetGlyphBounds(caret_pos, &xspan, &height);
589 if (insert_mode) {
590 x = (caret_affinity == CURSOR_BACKWARD) ? xspan.end() : xspan.start();
591 width = 0;
592 } else { // overstrike mode
593 x = xspan.GetMin();
594 width = xspan.length();
595 }
596 }
597 height = std::min(height, display_rect().height());
598 int y = (display_rect().height() - height) / 2;
599 return Rect(ToViewPoint(Point(x, y)), Size(width, height));
600 }
601
588 const Rect& RenderText::GetUpdatedCursorBounds() { 602 const Rect& RenderText::GetUpdatedCursorBounds() {
589 UpdateCachedBoundsAndOffset(); 603 UpdateCachedBoundsAndOffset();
590 return cursor_bounds_; 604 return cursor_bounds_;
591 } 605 }
592 606
593 SelectionModel RenderText::GetSelectionModelForSelectionStart() { 607 SelectionModel RenderText::GetSelectionModelForSelectionStart() {
594 size_t selection_start = GetSelectionStart(); 608 const ui::Range& selection = selection_model_.selection();
595 size_t selection_end = GetCursorPosition(); 609 if (selection.is_empty()) {
596 if (selection_start < selection_end) 610 return selection_model_;
597 return SelectionModel(selection_start, 611 } else {
598 selection_start,
599 SelectionModel::LEADING);
600 else if (selection_start > selection_end)
601 return SelectionModel( 612 return SelectionModel(
602 selection_start, 613 selection.start(),
603 IndexOfAdjacentGrapheme(selection_start, CURSOR_BACKWARD), 614 selection.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD);
604 SelectionModel::TRAILING); 615 }
605 return selection_model_;
606 } 616 }
607 617
608 RenderText::RenderText() 618 RenderText::RenderText()
609 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), 619 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT),
610 cursor_enabled_(true), 620 cursor_enabled_(true),
611 cursor_visible_(false), 621 cursor_visible_(false),
612 insert_mode_(true), 622 insert_mode_(true),
613 focused_(false), 623 focused_(false),
614 composition_range_(ui::Range::InvalidRange()), 624 composition_range_(ui::Range::InvalidRange()),
615 fade_head_(false), 625 fade_head_(false),
(...skipping 13 matching lines...) Expand all
629 EnsureLayout(); 639 EnsureLayout();
630 640
631 if (break_type == LINE_BREAK || text().empty()) 641 if (break_type == LINE_BREAK || text().empty())
632 return EdgeSelectionModel(direction); 642 return EdgeSelectionModel(direction);
633 if (break_type == CHARACTER_BREAK) 643 if (break_type == CHARACTER_BREAK)
634 return AdjacentCharSelectionModel(current, direction); 644 return AdjacentCharSelectionModel(current, direction);
635 DCHECK(break_type == WORD_BREAK); 645 DCHECK(break_type == WORD_BREAK);
636 return AdjacentWordSelectionModel(current, direction); 646 return AdjacentWordSelectionModel(current, direction);
637 } 647 }
638 648
649 SelectionModel RenderText::EdgeSelectionModel(
650 VisualCursorDirection direction) {
651 if (direction == GetVisualDirectionOfLogicalEnd())
652 return SelectionModel(text().length(), CURSOR_FORWARD);
653 else
654 return SelectionModel(0, CURSOR_BACKWARD);
655 }
656
639 void RenderText::SetSelectionModel(const SelectionModel& model) { 657 void RenderText::SetSelectionModel(const SelectionModel& model) {
640 DCHECK_LE(model.selection_start(), text().length()); 658 DCHECK_LE(model.selection().GetMax(), text().length());
641 selection_model_.set_selection_start(model.selection_start()); 659 selection_model_ = model;
642 DCHECK_LE(model.selection_end(), text().length());
643 selection_model_.set_selection_end(model.selection_end());
644 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1));
645 selection_model_.set_caret_pos(model.caret_pos());
646 selection_model_.set_caret_placement(model.caret_placement());
647
648 cached_bounds_and_offset_valid_ = false; 660 cached_bounds_and_offset_valid_ = false;
649 } 661 }
650 662
651 void RenderText::ApplyCompositionAndSelectionStyles( 663 void RenderText::ApplyCompositionAndSelectionStyles(
652 StyleRanges* style_ranges) { 664 StyleRanges* style_ranges) {
653 // TODO(msw): This pattern ought to be reconsidered; what about composition 665 // TODO(msw): This pattern ought to be reconsidered; what about composition
654 // and selection overlaps, retain existing local style features? 666 // and selection overlaps, retain existing local style features?
655 // Apply a composition style override to a copy of the style ranges. 667 // Apply a composition style override to a copy of the style ranges.
656 if (composition_range_.IsValid() && !composition_range_.is_empty()) { 668 if (composition_range_.IsValid() && !composition_range_.is_empty()) {
657 StyleRange composition_style(default_style_); 669 StyleRange composition_style(default_style_);
658 composition_style.underline = true; 670 composition_style.underline = true;
659 composition_style.range.set_start(composition_range_.start()); 671 composition_style.range = composition_range_;
660 composition_style.range.set_end(composition_range_.end());
661 ApplyStyleRangeImpl(style_ranges, composition_style); 672 ApplyStyleRangeImpl(style_ranges, composition_style);
662 } 673 }
663 // Apply a selection style override to a copy of the style ranges. 674 // Apply a selection style override to a copy of the style ranges.
664 if (!EmptySelection()) { 675 if (!selection().is_empty()) {
665 StyleRange selection_style(default_style_); 676 StyleRange selection_style(default_style_);
666 selection_style.foreground = NativeTheme::instance()->GetSystemColor( 677 selection_style.foreground = NativeTheme::instance()->GetSystemColor(
667 NativeTheme::kColorId_TextfieldSelectionColor); 678 NativeTheme::kColorId_TextfieldSelectionColor);
668 selection_style.range.set_start(MinOfSelection()); 679 selection_style.range = ui::Range(selection().GetMin(),
669 selection_style.range.set_end(MaxOfSelection()); 680 selection().GetMax());
670 ApplyStyleRangeImpl(style_ranges, selection_style); 681 ApplyStyleRangeImpl(style_ranges, selection_style);
671 } 682 }
672 // Apply replacement-mode style override to a copy of the style ranges. 683 // Apply replacement-mode style override to a copy of the style ranges.
673 // 684 //
674 // TODO(xji): NEED TO FIX FOR WINDOWS ASAP. Windows call this function (to 685 // TODO(xji): NEED TO FIX FOR WINDOWS ASAP. Windows call this function (to
675 // apply styles) in ItemizeLogicalText(). In order for the cursor's underline 686 // apply styles) in ItemizeLogicalText(). In order for the cursor's underline
676 // character to be drawn correctly, we will need to re-layout the text. It's 687 // character to be drawn correctly, we will need to re-layout the text. It's
677 // not practical to do layout on every cursor blink. We need to fix Windows 688 // not practical to do layout on every cursor blink. We need to fix Windows
678 // port to apply styles during drawing phase like Linux port does. 689 // port to apply styles during drawing phase like Linux port does.
679 // http://crbug.com/110109 690 // http://crbug.com/110109
680 if (!insert_mode_ && cursor_visible() && focused()) { 691 if (!insert_mode_ && cursor_visible() && focused()) {
681 StyleRange replacement_mode_style(default_style_); 692 StyleRange replacement_mode_style(default_style_);
682 replacement_mode_style.foreground = NativeTheme::instance()->GetSystemColor( 693 replacement_mode_style.foreground = NativeTheme::instance()->GetSystemColor(
683 NativeTheme::kColorId_TextfieldSelectionColor); 694 NativeTheme::kColorId_TextfieldSelectionColor);
684 size_t cursor = GetCursorPosition(); 695 size_t cursor = cursor_position();
685 replacement_mode_style.range.set_start(cursor); 696 replacement_mode_style.range.set_start(cursor);
686 replacement_mode_style.range.set_end( 697 replacement_mode_style.range.set_end(
687 IndexOfAdjacentGrapheme(cursor, CURSOR_FORWARD)); 698 IndexOfAdjacentGrapheme(cursor, CURSOR_FORWARD));
688 ApplyStyleRangeImpl(style_ranges, replacement_mode_style); 699 ApplyStyleRangeImpl(style_ranges, replacement_mode_style);
689 } 700 }
690 } 701 }
691 702
692 Point RenderText::GetTextOrigin() { 703 Point RenderText::GetTextOrigin() {
693 Point origin = display_rect().origin(); 704 Point origin = display_rect().origin();
694 origin = origin.Add(GetUpdatedDisplayOffset()); 705 origin = origin.Add(GetUpdatedDisplayOffset());
695 origin = origin.Add(GetAlignmentOffset()); 706 origin = origin.Add(GetAlignmentOffset());
696 return origin; 707 return origin;
697 } 708 }
698 709
699 Point RenderText::ToTextPoint(const Point& point) { 710 Point RenderText::ToTextPoint(const Point& point) {
700 return point.Subtract(GetTextOrigin()); 711 return point.Subtract(GetTextOrigin());
701 } 712 }
702 713
703 Point RenderText::ToViewPoint(const Point& point) { 714 Point RenderText::ToViewPoint(const Point& point) {
704 return point.Add(GetTextOrigin()); 715 return point.Add(GetTextOrigin());
705 } 716 }
706 717
707 int RenderText::GetContentWidth() { 718 int RenderText::GetContentWidth() {
708 return GetStringWidth() + (cursor_enabled_ ? 1 : 0); 719 return GetStringSize().width() + (cursor_enabled_ ? 1 : 0);
709 } 720 }
710 721
711 Point RenderText::GetAlignmentOffset() { 722 Point RenderText::GetAlignmentOffset() {
712 if (horizontal_alignment() != ALIGN_LEFT) { 723 if (horizontal_alignment() != ALIGN_LEFT) {
713 int x_offset = display_rect().width() - GetContentWidth(); 724 int x_offset = display_rect().width() - GetContentWidth();
714 if (horizontal_alignment() == ALIGN_CENTER) 725 if (horizontal_alignment() == ALIGN_CENTER)
715 x_offset /= 2; 726 x_offset /= 2;
716 return Point(x_offset, 0); 727 return Point(x_offset, 0);
717 } 728 }
718 return Point(); 729 return Point();
719 } 730 }
720 731
721 Point RenderText::GetOriginForSkiaDrawing() { 732 Point RenderText::GetOriginForSkiaDrawing() {
722 Point origin(GetTextOrigin()); 733 Point origin(GetTextOrigin());
723 // TODO(msw): Establish a vertical baseline for strings of mixed font heights. 734 // TODO(msw): Establish a vertical baseline for strings of mixed font heights.
724 const Font& font = GetFont(); 735 const Font& font = GetFont();
725 int height = font.GetHeight(); 736 int height = font.GetHeight();
726 DCHECK_LE(height, display_rect().height()); 737 DCHECK_LE(height, display_rect().height());
727 // Center the text vertically in the display area. 738 // Center the text vertically in the display area.
728 origin.Offset(0, (display_rect().height() - height) / 2); 739 origin.Offset(0, (display_rect().height() - height) / 2);
729 // Offset by the font size to account for Skia expecting y to be the bottom. 740 // Offset by the font size to account for Skia expecting y to be the bottom.
730 origin.Offset(0, font.GetFontSize()); 741 origin.Offset(0, font.GetFontSize());
731 return origin; 742 return origin;
732 } 743 }
733 744
734 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) { 745 void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
735 if (!fade_head() && !fade_tail()) 746 if (!fade_head() && !fade_tail())
736 return; 747 return;
737 748
738 const int text_width = GetStringWidth(); 749 const int text_width = GetStringSize().width();
739 const int display_width = display_rect().width(); 750 const int display_width = display_rect().width();
740 751
741 // If the text fits as-is, no need to fade. 752 // If the text fits as-is, no need to fade.
742 if (text_width <= display_width) 753 if (text_width <= display_width)
743 return; 754 return;
744 755
745 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width); 756 int gradient_width = CalculateFadeGradientWidth(GetFont(), display_width);
746 if (gradient_width == 0) 757 if (gradient_width == 0)
747 return; 758 return;
748 759
(...skipping 24 matching lines...) Expand all
773 SkAutoTUnref<SkShader> shader( 784 SkAutoTUnref<SkShader> shader(
774 CreateFadeShader(text_rect, left_part, right_part, color)); 785 CreateFadeShader(text_rect, left_part, right_part, color));
775 if (shader.get()) { 786 if (shader.get()) {
776 // |renderer| adds its own ref. So don't |release()| it from the ref ptr. 787 // |renderer| adds its own ref. So don't |release()| it from the ref ptr.
777 renderer->SetShader(shader.get()); 788 renderer->SetShader(shader.get());
778 } 789 }
779 } 790 }
780 791
781 void RenderText::MoveCursorTo(size_t position, bool select) { 792 void RenderText::MoveCursorTo(size_t position, bool select) {
782 size_t cursor = std::min(position, text().length()); 793 size_t cursor = std::min(position, text().length());
783 size_t caret_pos = IndexOfAdjacentGrapheme(cursor, CURSOR_BACKWARD);
784 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ?
785 SelectionModel::LEADING : SelectionModel::TRAILING;
786 size_t selection_start = select ? GetSelectionStart() : cursor;
787 if (IsCursorablePosition(cursor)) { 794 if (IsCursorablePosition(cursor)) {
788 SelectionModel sel(selection_start, cursor, caret_pos, placement); 795 ui::Range pos(cursor);
789 SetSelectionModel(sel); 796 if (select)
797 pos.set_start(selection().start());
798 LogicalCursorDirection affinity = cursor ? CURSOR_BACKWARD : CURSOR_FORWARD;
799 SetSelectionModel(SelectionModel(pos, affinity));
790 } 800 }
791 } 801 }
792 802
793 void RenderText::UpdateCachedBoundsAndOffset() { 803 void RenderText::UpdateCachedBoundsAndOffset() {
794 if (cached_bounds_and_offset_valid_) 804 if (cached_bounds_and_offset_valid_)
795 return; 805 return;
796 806
797 // First, set the valid flag true to calculate the current cursor bounds using 807 // First, set the valid flag true to calculate the current cursor bounds using
798 // the stale |display_offset_|. Applying |delta_offset| at the end of this 808 // the stale |display_offset_|. Applying |delta_offset| at the end of this
799 // function will set |cursor_bounds_| and |display_offset_| to correct values. 809 // function will set |cursor_bounds_| and |display_offset_| to correct values.
(...skipping 29 matching lines...) Expand all
829 const int offset = negate_rtl * display_offset_.x(); 839 const int offset = negate_rtl * display_offset_.x();
830 if (display_width > (content_width + offset)) 840 if (display_width > (content_width + offset))
831 delta_offset = negate_rtl * (display_width - (content_width + offset)); 841 delta_offset = negate_rtl * (display_width - (content_width + offset));
832 } 842 }
833 843
834 display_offset_.Offset(delta_offset, 0); 844 display_offset_.Offset(delta_offset, 0);
835 cursor_bounds_.Offset(delta_offset, 0); 845 cursor_bounds_.Offset(delta_offset, 0);
836 } 846 }
837 847
838 void RenderText::DrawSelection(Canvas* canvas) { 848 void RenderText::DrawSelection(Canvas* canvas) {
839 std::vector<Rect> sel = GetSubstringBounds( 849 std::vector<Rect> sel = GetSubstringBounds(selection());
840 GetSelectionStart(), GetCursorPosition());
841 NativeTheme::ColorId color_id = focused() ? 850 NativeTheme::ColorId color_id = focused() ?
842 NativeTheme::kColorId_TextfieldSelectionBackgroundFocused : 851 NativeTheme::kColorId_TextfieldSelectionBackgroundFocused :
843 NativeTheme::kColorId_TextfieldSelectionBackgroundUnfocused; 852 NativeTheme::kColorId_TextfieldSelectionBackgroundUnfocused;
844 SkColor color = NativeTheme::instance()->GetSystemColor(color_id); 853 SkColor color = NativeTheme::instance()->GetSystemColor(color_id);
845 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i) 854 for (std::vector<Rect>::const_iterator i = sel.begin(); i < sel.end(); ++i)
846 canvas->FillRect(*i, color); 855 canvas->FillRect(*i, color);
847 } 856 }
848 857
849 void RenderText::DrawCursor(Canvas* canvas) { 858 void RenderText::DrawCursor(Canvas* canvas) {
850 // Paint cursor. Replace cursor is drawn as rectangle for now. 859 // Paint cursor. Replace cursor is drawn as rectangle for now.
851 // TODO(msw): Draw a better cursor with a better indication of association. 860 // TODO(msw): Draw a better cursor with a better indication of association.
852 if (cursor_enabled() && cursor_visible() && focused()) { 861 if (cursor_enabled() && cursor_visible() && focused()) {
853 const Rect& bounds = GetUpdatedCursorBounds(); 862 const Rect& bounds = GetUpdatedCursorBounds();
854 if (bounds.width() != 0) 863 if (bounds.width() != 0)
855 canvas->FillRect(bounds, kCursorColor); 864 canvas->FillRect(bounds, kCursorColor);
856 else 865 else
857 canvas->DrawRect(bounds, kCursorColor); 866 canvas->DrawRect(bounds, kCursorColor);
858 } 867 }
859 } 868 }
860 869
861 } // namespace gfx 870 } // 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_linux.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698