OLD | NEW |
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" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/stl_util.h" | 12 #include "base/stl_util.h" |
13 #include "third_party/skia/include/core/SkTypeface.h" | 13 #include "third_party/skia/include/core/SkTypeface.h" |
14 #include "third_party/skia/include/effects/SkGradientShader.h" | 14 #include "third_party/skia/include/effects/SkGradientShader.h" |
| 15 #include "ui/base/text/utf16_indexing.h" |
15 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
16 #include "ui/gfx/canvas_skia.h" | 17 #include "ui/gfx/canvas_skia.h" |
17 #include "ui/gfx/native_theme.h" | 18 #include "ui/gfx/native_theme.h" |
18 #include "unicode/uchar.h" | |
19 | 19 |
20 namespace { | 20 namespace { |
21 | 21 |
| 22 // All chars are replaced by this char when the password style is set. |
| 23 // TODO(benrg): GTK uses the first of U+25CF, U+2022, U+2731, U+273A, '*' |
| 24 // that's available in the font (find_invisible_char() in gtkentry.c). |
| 25 const char16 kPasswordReplacementChar = '*'; |
| 26 |
22 // Default color used for the cursor. | 27 // Default color used for the cursor. |
23 const SkColor kDefaultCursorColor = SK_ColorBLACK; | 28 const SkColor kDefaultCursorColor = SK_ColorBLACK; |
24 | 29 |
25 #ifndef NDEBUG | 30 #ifndef NDEBUG |
26 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. | 31 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. |
27 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { | 32 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { |
28 if (length == 0) { | 33 if (length == 0) { |
29 DCHECK(style_ranges.empty()) << "Style ranges exist for empty text."; | 34 DCHECK(style_ranges.empty()) << "Style ranges exist for empty text."; |
30 return; | 35 return; |
31 } | 36 } |
(...skipping 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 | 372 |
368 const Font& RenderText::GetFont() const { | 373 const Font& RenderText::GetFont() const { |
369 return font_list_.GetFonts()[0]; | 374 return font_list_.GetFonts()[0]; |
370 } | 375 } |
371 | 376 |
372 void RenderText::ToggleInsertMode() { | 377 void RenderText::ToggleInsertMode() { |
373 insert_mode_ = !insert_mode_; | 378 insert_mode_ = !insert_mode_; |
374 cached_bounds_and_offset_valid_ = false; | 379 cached_bounds_and_offset_valid_ = false; |
375 } | 380 } |
376 | 381 |
| 382 void RenderText::SetObscured(bool obscured) { |
| 383 if (obscured != obscured_) { |
| 384 obscured_ = obscured; |
| 385 cached_bounds_and_offset_valid_ = false; |
| 386 UpdateLayout(); |
| 387 } |
| 388 } |
| 389 |
377 void RenderText::SetDisplayRect(const Rect& r) { | 390 void RenderText::SetDisplayRect(const Rect& r) { |
378 display_rect_ = r; | 391 display_rect_ = r; |
379 cached_bounds_and_offset_valid_ = false; | 392 cached_bounds_and_offset_valid_ = false; |
380 UpdateLayout(); | 393 UpdateLayout(); |
381 } | 394 } |
382 | 395 |
383 size_t RenderText::GetCursorPosition() const { | 396 size_t RenderText::GetCursorPosition() const { |
384 return selection_model_.selection_end(); | 397 return selection_model_.selection_end(); |
385 } | 398 } |
386 | 399 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
490 SetSelectionModel(sel); | 503 SetSelectionModel(sel); |
491 } | 504 } |
492 | 505 |
493 void RenderText::SelectAll() { | 506 void RenderText::SelectAll() { |
494 SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); | 507 SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); |
495 sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); | 508 sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); |
496 SetSelectionModel(sel); | 509 SetSelectionModel(sel); |
497 } | 510 } |
498 | 511 |
499 void RenderText::SelectWord() { | 512 void RenderText::SelectWord() { |
| 513 if (obscured_) { |
| 514 SelectAll(); |
| 515 return; |
| 516 } |
| 517 |
500 size_t cursor_position = GetCursorPosition(); | 518 size_t cursor_position = GetCursorPosition(); |
501 | 519 |
502 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 520 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
503 bool success = iter.Init(); | 521 bool success = iter.Init(); |
504 DCHECK(success); | 522 DCHECK(success); |
505 if (!success) | 523 if (!success) |
506 return; | 524 return; |
507 | 525 |
508 size_t selection_start = cursor_position; | 526 size_t selection_start = cursor_position; |
509 for (; selection_start != 0; --selection_start) { | 527 for (; selection_start != 0; --selection_start) { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
609 } | 627 } |
610 | 628 |
611 RenderText::RenderText() | 629 RenderText::RenderText() |
612 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), | 630 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), |
613 cursor_enabled_(true), | 631 cursor_enabled_(true), |
614 cursor_visible_(false), | 632 cursor_visible_(false), |
615 insert_mode_(true), | 633 insert_mode_(true), |
616 cursor_color_(kDefaultCursorColor), | 634 cursor_color_(kDefaultCursorColor), |
617 focused_(false), | 635 focused_(false), |
618 composition_range_(ui::Range::InvalidRange()), | 636 composition_range_(ui::Range::InvalidRange()), |
| 637 obscured_(false), |
619 fade_head_(false), | 638 fade_head_(false), |
620 fade_tail_(false), | 639 fade_tail_(false), |
621 background_is_transparent_(false), | 640 background_is_transparent_(false), |
622 cached_bounds_and_offset_valid_(false) { | 641 cached_bounds_and_offset_valid_(false) { |
623 } | 642 } |
624 | 643 |
625 const Point& RenderText::GetUpdatedDisplayOffset() { | 644 const Point& RenderText::GetUpdatedDisplayOffset() { |
626 UpdateCachedBoundsAndOffset(); | 645 UpdateCachedBoundsAndOffset(); |
627 return display_offset_; | 646 return display_offset_; |
628 } | 647 } |
(...skipping 17 matching lines...) Expand all Loading... |
646 selection_model_.set_selection_start(model.selection_start()); | 665 selection_model_.set_selection_start(model.selection_start()); |
647 DCHECK_LE(model.selection_end(), text().length()); | 666 DCHECK_LE(model.selection_end(), text().length()); |
648 selection_model_.set_selection_end(model.selection_end()); | 667 selection_model_.set_selection_end(model.selection_end()); |
649 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1)); | 668 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1)); |
650 selection_model_.set_caret_pos(model.caret_pos()); | 669 selection_model_.set_caret_pos(model.caret_pos()); |
651 selection_model_.set_caret_placement(model.caret_placement()); | 670 selection_model_.set_caret_placement(model.caret_placement()); |
652 | 671 |
653 cached_bounds_and_offset_valid_ = false; | 672 cached_bounds_and_offset_valid_ = false; |
654 } | 673 } |
655 | 674 |
| 675 string16 RenderText::GetDisplayText() const { |
| 676 if (!obscured_) |
| 677 return text_; |
| 678 size_t obscured_text_length = |
| 679 static_cast<size_t>(ui::UTF16IndexToOffset(text_, 0, text_.length())); |
| 680 return string16(obscured_text_length, kPasswordReplacementChar); |
| 681 } |
| 682 |
656 void RenderText::ApplyCompositionAndSelectionStyles( | 683 void RenderText::ApplyCompositionAndSelectionStyles( |
657 StyleRanges* style_ranges) { | 684 StyleRanges* style_ranges) { |
658 // TODO(msw): This pattern ought to be reconsidered; what about composition | 685 // TODO(msw): This pattern ought to be reconsidered; what about composition |
659 // and selection overlaps, retain existing local style features? | 686 // and selection overlaps, retain existing local style features? |
660 // Apply a composition style override to a copy of the style ranges. | 687 // Apply a composition style override to a copy of the style ranges. |
661 if (composition_range_.IsValid() && !composition_range_.is_empty()) { | 688 if (composition_range_.IsValid() && !composition_range_.is_empty()) { |
662 StyleRange composition_style(default_style_); | 689 StyleRange composition_style(default_style_); |
663 composition_style.underline = true; | 690 composition_style.underline = true; |
664 composition_style.range.set_start(composition_range_.start()); | 691 composition_style.range.set_start(composition_range_.start()); |
665 composition_style.range.set_end(composition_range_.end()); | 692 composition_style.range.set_end(composition_range_.end()); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
857 if (cursor_enabled() && cursor_visible() && focused()) { | 884 if (cursor_enabled() && cursor_visible() && focused()) { |
858 const Rect& bounds = GetUpdatedCursorBounds(); | 885 const Rect& bounds = GetUpdatedCursorBounds(); |
859 if (bounds.width() != 0) | 886 if (bounds.width() != 0) |
860 canvas->FillRect(bounds, cursor_color_); | 887 canvas->FillRect(bounds, cursor_color_); |
861 else | 888 else |
862 canvas->DrawRect(bounds, cursor_color_); | 889 canvas->DrawRect(bounds, cursor_color_); |
863 } | 890 } |
864 } | 891 } |
865 | 892 |
866 } // namespace gfx | 893 } // namespace gfx |
OLD | NEW |