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 "base/utf_offset_string_conversions.h" |
13 #include "third_party/skia/include/core/SkTypeface.h" | 14 #include "third_party/skia/include/core/SkTypeface.h" |
14 #include "third_party/skia/include/effects/SkGradientShader.h" | 15 #include "third_party/skia/include/effects/SkGradientShader.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 // Color settings for text, backgrounds and cursor. | 27 // Color settings for text, backgrounds and cursor. |
23 // These are tentative, and should be derived from theme, system | 28 // These are tentative, and should be derived from theme, system |
24 // settings and current settings. | 29 // settings and current settings. |
25 // TODO(oshima): Change this to match the standard chrome | 30 // TODO(oshima): Change this to match the standard chrome |
26 // before dogfooding textfield views. | 31 // before dogfooding textfield views. |
27 const SkColor kCursorColor = SK_ColorBLACK; | 32 const SkColor kCursorColor = SK_ColorBLACK; |
28 | 33 |
29 #ifndef NDEBUG | 34 #ifndef NDEBUG |
30 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. | 35 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. |
31 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { | 36 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { |
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
371 | 376 |
372 const Font& RenderText::GetFont() const { | 377 const Font& RenderText::GetFont() const { |
373 return font_list_.GetFonts()[0]; | 378 return font_list_.GetFonts()[0]; |
374 } | 379 } |
375 | 380 |
376 void RenderText::ToggleInsertMode() { | 381 void RenderText::ToggleInsertMode() { |
377 insert_mode_ = !insert_mode_; | 382 insert_mode_ = !insert_mode_; |
378 cached_bounds_and_offset_valid_ = false; | 383 cached_bounds_and_offset_valid_ = false; |
379 } | 384 } |
380 | 385 |
| 386 void RenderText::SetObscured(bool obscured) { |
| 387 if (obscured != obscured_) { |
| 388 obscured_ = obscured; |
| 389 cached_bounds_and_offset_valid_ = false; |
| 390 UpdateLayout(); |
| 391 } |
| 392 } |
| 393 |
381 void RenderText::SetDisplayRect(const Rect& r) { | 394 void RenderText::SetDisplayRect(const Rect& r) { |
382 display_rect_ = r; | 395 display_rect_ = r; |
383 cached_bounds_and_offset_valid_ = false; | 396 cached_bounds_and_offset_valid_ = false; |
384 UpdateLayout(); | 397 UpdateLayout(); |
385 } | 398 } |
386 | 399 |
387 size_t RenderText::GetCursorPosition() const { | 400 size_t RenderText::GetCursorPosition() const { |
388 return selection_model_.selection_end(); | 401 return selection_model_.selection_end(); |
389 } | 402 } |
390 | 403 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 SetSelectionModel(sel); | 507 SetSelectionModel(sel); |
495 } | 508 } |
496 | 509 |
497 void RenderText::SelectAll() { | 510 void RenderText::SelectAll() { |
498 SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); | 511 SelectionModel sel = EdgeSelectionModel(CURSOR_RIGHT); |
499 sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); | 512 sel.set_selection_start(EdgeSelectionModel(CURSOR_LEFT).selection_start()); |
500 SetSelectionModel(sel); | 513 SetSelectionModel(sel); |
501 } | 514 } |
502 | 515 |
503 void RenderText::SelectWord() { | 516 void RenderText::SelectWord() { |
| 517 if (obscured_) { |
| 518 SelectAll(); |
| 519 return; |
| 520 } |
| 521 |
504 size_t cursor_position = GetCursorPosition(); | 522 size_t cursor_position = GetCursorPosition(); |
505 | 523 |
506 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); | 524 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); |
507 bool success = iter.Init(); | 525 bool success = iter.Init(); |
508 DCHECK(success); | 526 DCHECK(success); |
509 if (!success) | 527 if (!success) |
510 return; | 528 return; |
511 | 529 |
512 size_t selection_start = cursor_position; | 530 size_t selection_start = cursor_position; |
513 for (; selection_start != 0; --selection_start) { | 531 for (; selection_start != 0; --selection_start) { |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
612 return selection_model_; | 630 return selection_model_; |
613 } | 631 } |
614 | 632 |
615 RenderText::RenderText() | 633 RenderText::RenderText() |
616 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), | 634 : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), |
617 cursor_enabled_(true), | 635 cursor_enabled_(true), |
618 cursor_visible_(false), | 636 cursor_visible_(false), |
619 insert_mode_(true), | 637 insert_mode_(true), |
620 focused_(false), | 638 focused_(false), |
621 composition_range_(ui::Range::InvalidRange()), | 639 composition_range_(ui::Range::InvalidRange()), |
| 640 obscured_(false), |
622 fade_head_(false), | 641 fade_head_(false), |
623 fade_tail_(false), | 642 fade_tail_(false), |
624 cached_bounds_and_offset_valid_(false) { | 643 cached_bounds_and_offset_valid_(false) { |
625 } | 644 } |
626 | 645 |
627 const Point& RenderText::GetUpdatedDisplayOffset() { | 646 const Point& RenderText::GetUpdatedDisplayOffset() { |
628 UpdateCachedBoundsAndOffset(); | 647 UpdateCachedBoundsAndOffset(); |
629 return display_offset_; | 648 return display_offset_; |
630 } | 649 } |
631 | 650 |
(...skipping 16 matching lines...) Expand all Loading... |
648 selection_model_.set_selection_start(model.selection_start()); | 667 selection_model_.set_selection_start(model.selection_start()); |
649 DCHECK_LE(model.selection_end(), text().length()); | 668 DCHECK_LE(model.selection_end(), text().length()); |
650 selection_model_.set_selection_end(model.selection_end()); | 669 selection_model_.set_selection_end(model.selection_end()); |
651 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1)); | 670 DCHECK_LT(model.caret_pos(), std::max<size_t>(text().length(), 1)); |
652 selection_model_.set_caret_pos(model.caret_pos()); | 671 selection_model_.set_caret_pos(model.caret_pos()); |
653 selection_model_.set_caret_placement(model.caret_placement()); | 672 selection_model_.set_caret_placement(model.caret_placement()); |
654 | 673 |
655 cached_bounds_and_offset_valid_ = false; | 674 cached_bounds_and_offset_valid_ = false; |
656 } | 675 } |
657 | 676 |
| 677 string16 RenderText::GetDisplayText() const { |
| 678 if (!obscured_) |
| 679 return text_; |
| 680 size_t obscured_text_length = |
| 681 static_cast<size_t>(Utf16IndexToOffset(text_, 0, text_.length())); |
| 682 return string16(obscured_text_length, kPasswordReplacementChar); |
| 683 } |
| 684 |
658 void RenderText::ApplyCompositionAndSelectionStyles( | 685 void RenderText::ApplyCompositionAndSelectionStyles( |
659 StyleRanges* style_ranges) { | 686 StyleRanges* style_ranges) { |
660 // TODO(msw): This pattern ought to be reconsidered; what about composition | 687 // TODO(msw): This pattern ought to be reconsidered; what about composition |
661 // and selection overlaps, retain existing local style features? | 688 // and selection overlaps, retain existing local style features? |
662 // Apply a composition style override to a copy of the style ranges. | 689 // Apply a composition style override to a copy of the style ranges. |
663 if (composition_range_.IsValid() && !composition_range_.is_empty()) { | 690 if (composition_range_.IsValid() && !composition_range_.is_empty()) { |
664 StyleRange composition_style(default_style_); | 691 StyleRange composition_style(default_style_); |
665 composition_style.underline = true; | 692 composition_style.underline = true; |
666 composition_style.range.set_start(composition_range_.start()); | 693 composition_style.range.set_start(composition_range_.start()); |
667 composition_style.range.set_end(composition_range_.end()); | 694 composition_style.range.set_end(composition_range_.end()); |
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
859 if (cursor_enabled() && cursor_visible() && focused()) { | 886 if (cursor_enabled() && cursor_visible() && focused()) { |
860 const Rect& bounds = GetUpdatedCursorBounds(); | 887 const Rect& bounds = GetUpdatedCursorBounds(); |
861 if (bounds.width() != 0) | 888 if (bounds.width() != 0) |
862 canvas->FillRect(bounds, kCursorColor); | 889 canvas->FillRect(bounds, kCursorColor); |
863 else | 890 else |
864 canvas->DrawRect(bounds, kCursorColor); | 891 canvas->DrawRect(bounds, kCursorColor); |
865 } | 892 } |
866 } | 893 } |
867 | 894 |
868 } // namespace gfx | 895 } // namespace gfx |
OLD | NEW |