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

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

Issue 8747001: Reintroduce password support to NativeTextfieldViews (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: make password in RenderText an instance property and disable cut, copy, D&D, and word skipping Created 9 years 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"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "ui/gfx/canvas.h" 12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/canvas_skia.h" 13 #include "ui/gfx/canvas_skia.h"
14 #include "unicode/uchar.h" 14 #include "unicode/uchar.h"
15 15
16 namespace { 16 namespace {
17 17
18 // All chars are replaced by this char when the password style is set.
19 // TODO(benrg): GTK uses the first of U+25CF, U+2022, U+2731, U+273A, '*'
20 // that's available in the font (find_invisible_char() in gtkentry.c).
21 const char16 PASSWORD_REPLACEMENT_CHAR = '*';
msw 2011/12/03 00:22:40 Is this the correct style for a const char identif
benrg 2011/12/06 17:21:30 Done. (I misremembered the coding guidelines.)
22
23 // Color settings for text, backgrounds and cursor.
24 // These are tentative, and should be derived from theme, system
25 // settings and current settings.
26 // TODO(oshima): Change this to match the standard chrome
27 // before dogfooding textfield views.
28 const SkColor kSelectedTextColor = SK_ColorWHITE;
29 const SkColor kFocusedSelectionColor = SkColorSetRGB(30, 144, 255);
30 const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY;
31 const SkColor kCursorColor = SK_ColorBLACK;
32
18 #ifndef NDEBUG 33 #ifndef NDEBUG
19 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges. 34 // Check StyleRanges invariant conditions: sorted and non-overlapping ranges.
20 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) { 35 void CheckStyleRanges(const gfx::StyleRanges& style_ranges, size_t length) {
21 if (length == 0) { 36 if (length == 0) {
22 DCHECK(style_ranges.empty()) << "Style ranges exist for empty text."; 37 DCHECK(style_ranges.empty()) << "Style ranges exist for empty text.";
23 return; 38 return;
24 } 39 }
25 for (gfx::StyleRanges::size_type i = 0; i < style_ranges.size() - 1; i++) { 40 for (gfx::StyleRanges::size_type i = 0; i < style_ranges.size() - 1; i++) {
26 const ui::Range& former = style_ranges[i].range; 41 const ui::Range& former = style_ranges[i].range;
27 const ui::Range& latter = style_ranges[i + 1].range; 42 const ui::Range& latter = style_ranges[i + 1].range;
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 #endif 135 #endif
121 cached_bounds_and_offset_valid_ = false; 136 cached_bounds_and_offset_valid_ = false;
122 137
123 // Reset selection model. SetText should always followed by SetSelectionModel 138 // Reset selection model. SetText should always followed by SetSelectionModel
124 // or SetCursorPosition in upper layer. 139 // or SetCursorPosition in upper layer.
125 SetSelectionModel(SelectionModel(0, 0, SelectionModel::LEADING)); 140 SetSelectionModel(SelectionModel(0, 0, SelectionModel::LEADING));
126 141
127 UpdateLayout(); 142 UpdateLayout();
128 } 143 }
129 144
145 string16 RenderText::GetCensoredText() const {
146 string16 txt = text();
147 if (password_) {
148 // TODO(benrg): There should probably be one bullet/asterisk per
149 // cursorable character, not one per UTF-16 word. However, I'm not sure
150 // it's worth the effort. GTK appears to use one per code point. Do people
151 // use non-BMP code points and combining diacritics in their passwords?
152 std::fill(txt.begin(), txt.end(), PASSWORD_REPLACEMENT_CHAR);
153 }
154 return txt;
155 }
156
130 void RenderText::ToggleInsertMode() { 157 void RenderText::ToggleInsertMode() {
131 insert_mode_ = !insert_mode_; 158 insert_mode_ = !insert_mode_;
132 cached_bounds_and_offset_valid_ = false; 159 cached_bounds_and_offset_valid_ = false;
133 } 160 }
134 161
162 void RenderText::SetIsPassword(bool password) {
163 password_ = password;
164 cached_bounds_and_offset_valid_ = false;
165 UpdateLayout();
166 }
167
135 void RenderText::SetDisplayRect(const Rect& r) { 168 void RenderText::SetDisplayRect(const Rect& r) {
136 display_rect_ = r; 169 display_rect_ = r;
137 cached_bounds_and_offset_valid_ = false; 170 cached_bounds_and_offset_valid_ = false;
138 UpdateLayout(); 171 UpdateLayout();
139 } 172 }
140 173
141 size_t RenderText::GetCursorPosition() const { 174 size_t RenderText::GetCursorPosition() const {
142 return selection_model_.selection_end(); 175 return selection_model_.selection_end();
143 } 176 }
144 177
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 299
267 void RenderText::SelectAll() { 300 void RenderText::SelectAll() {
268 SelectionModel sel(RightEndSelectionModel()); 301 SelectionModel sel(RightEndSelectionModel());
269 sel.set_selection_start(LeftEndSelectionModel().selection_start()); 302 sel.set_selection_start(LeftEndSelectionModel().selection_start());
270 SetSelectionModel(sel); 303 SetSelectionModel(sel);
271 } 304 }
272 305
273 void RenderText::SelectWord() { 306 void RenderText::SelectWord() {
274 size_t cursor_position = GetCursorPosition(); 307 size_t cursor_position = GetCursorPosition();
275 308
276 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 309 string16 txt = GetCensoredText();
310 base::i18n::BreakIterator iter(txt, base::i18n::BreakIterator::BREAK_WORD);
277 bool success = iter.Init(); 311 bool success = iter.Init();
278 DCHECK(success); 312 DCHECK(success);
279 if (!success) 313 if (!success)
280 return; 314 return;
281 315
282 size_t selection_start = cursor_position; 316 size_t selection_start = cursor_position;
283 for (; selection_start != 0; --selection_start) { 317 for (; selection_start != 0; --selection_start) {
284 if (iter.IsStartOfWord(selection_start) || 318 if (iter.IsStartOfWord(selection_start) ||
285 iter.IsEndOfWord(selection_start)) 319 iter.IsEndOfWord(selection_start))
286 break; 320 break;
287 } 321 }
288 322
289 if (selection_start == cursor_position) 323 if (selection_start == cursor_position)
290 ++cursor_position; 324 ++cursor_position;
291 325
292 for (; cursor_position < text().length(); ++cursor_position) { 326 for (; cursor_position < txt.length(); ++cursor_position) {
293 if (iter.IsEndOfWord(cursor_position) || 327 if (iter.IsEndOfWord(cursor_position) ||
294 iter.IsStartOfWord(cursor_position)) 328 iter.IsStartOfWord(cursor_position))
295 break; 329 break;
296 } 330 }
297 331
298 MoveCursorTo(selection_start, false); 332 MoveCursorTo(selection_start, false);
299 MoveCursorTo(cursor_position, true); 333 MoveCursorTo(cursor_position, true);
300 } 334 }
301 335
302 const ui::Range& RenderText::GetCompositionRange() const { 336 const ui::Range& RenderText::GetCompositionRange() const {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 UpdateLayout(); 369 UpdateLayout();
336 } 370 }
337 371
338 base::i18n::TextDirection RenderText::GetTextDirection() { 372 base::i18n::TextDirection RenderText::GetTextDirection() {
339 if (base::i18n::IsRTL()) 373 if (base::i18n::IsRTL())
340 return base::i18n::RIGHT_TO_LEFT; 374 return base::i18n::RIGHT_TO_LEFT;
341 return base::i18n::LEFT_TO_RIGHT; 375 return base::i18n::LEFT_TO_RIGHT;
342 } 376 }
343 377
344 int RenderText::GetStringWidth() { 378 int RenderText::GetStringWidth() {
345 return default_style_.font.GetStringWidth(text()); 379 return default_style_.font.GetStringWidth(text());
msw 2011/12/03 00:22:40 Shouldn't this use GetCensoredText()?
xji 2011/12/06 01:24:04 guess since it could be pure virtual, it does not
benrg 2011/12/06 17:21:30 This code is dead, see below.
346 } 380 }
347 381
348 void RenderText::Draw(Canvas* canvas) { 382 void RenderText::Draw(Canvas* canvas) {
349 EnsureLayout(); 383 EnsureLayout();
350 384
351 if (!text().empty()) { 385 if (!text().empty()) {
352 DrawSelection(canvas); 386 DrawSelection(canvas);
353 DrawVisualText(canvas); 387 DrawVisualText(canvas);
354 } 388 }
355 DrawCursor(canvas); 389 DrawCursor(canvas);
356 } 390 }
357 391
358 SelectionModel RenderText::FindCursorPosition(const Point& point) { 392 SelectionModel RenderText::FindCursorPosition(const Point& point) {
359 const Font& font = default_style_.font; 393 const Font& font = default_style_.font;
360 int left = 0; 394 int left = 0;
361 int left_pos = 0; 395 int left_pos = 0;
362 int right = font.GetStringWidth(text()); 396 int right = font.GetStringWidth(text());
msw 2011/12/03 00:22:40 Shouldn't this use GetCensoredText()?
benrg 2011/12/06 17:21:30 This code is dead and seems unlikely to ever be re
363 int right_pos = text().length(); 397 int right_pos = text().length();
364 398
365 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x()); 399 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x());
366 if (x <= left) return SelectionModel(left_pos); 400 if (x <= left) return SelectionModel(left_pos);
367 if (x >= right) return SelectionModel(right_pos); 401 if (x >= right) return SelectionModel(right_pos);
368 // binary searching the cursor position. 402 // binary searching the cursor position.
369 // TODO(oshima): use the center of character instead of edge. 403 // TODO(oshima): use the center of character instead of edge.
370 // Binary search may not work for language like Arabic. 404 // Binary search may not work for language like Arabic.
371 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) { 405 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) {
372 int pivot_pos = left_pos + (right_pos - left_pos) / 2; 406 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
373 int pivot = font.GetStringWidth(text().substr(0, pivot_pos)); 407 int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
msw 2011/12/03 00:22:40 Shouldn't this use GetCensoredText()?
374 if (pivot < x) { 408 if (pivot < x) {
375 left = pivot; 409 left = pivot;
376 left_pos = pivot_pos; 410 left_pos = pivot_pos;
377 } else if (pivot == x) { 411 } else if (pivot == x) {
378 return SelectionModel(pivot_pos); 412 return SelectionModel(pivot_pos);
379 } else { 413 } else {
380 right = pivot; 414 right = pivot;
381 right_pos = pivot_pos; 415 right_pos = pivot_pos;
382 } 416 }
383 } 417 }
(...skipping 25 matching lines...) Expand all
409 443
410 RenderText::RenderText() 444 RenderText::RenderText()
411 : text_(), 445 : text_(),
412 selection_model_(), 446 selection_model_(),
413 cursor_bounds_(), 447 cursor_bounds_(),
414 cursor_visible_(false), 448 cursor_visible_(false),
415 insert_mode_(true), 449 insert_mode_(true),
416 composition_range_(ui::Range::InvalidRange()), 450 composition_range_(ui::Range::InvalidRange()),
417 style_ranges_(), 451 style_ranges_(),
418 default_style_(), 452 default_style_(),
453 password_(false),
419 display_rect_(), 454 display_rect_(),
420 display_offset_(), 455 display_offset_(),
421 cached_bounds_and_offset_valid_(false) { 456 cached_bounds_and_offset_valid_(false) {
422 } 457 }
423 458
424 const Point& RenderText::GetUpdatedDisplayOffset() { 459 const Point& RenderText::GetUpdatedDisplayOffset() {
425 UpdateCachedBoundsAndOffset(); 460 UpdateCachedBoundsAndOffset();
426 return display_offset_; 461 return display_offset_;
427 } 462 }
428 463
429 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current, 464 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
430 BreakType break_type) { 465 BreakType break_type) {
431 if (break_type == LINE_BREAK) 466 if (break_type == LINE_BREAK)
432 return LeftEndSelectionModel(); 467 return LeftEndSelectionModel();
433 size_t pos = std::max(static_cast<long>(current.selection_end() - 1), 468 size_t pos = std::max(static_cast<long>(current.selection_end() - 1),
434 static_cast<long>(0)); 469 static_cast<long>(0));
435 if (break_type == CHARACTER_BREAK) 470 if (break_type == CHARACTER_BREAK)
436 return SelectionModel(pos, pos, SelectionModel::LEADING); 471 return SelectionModel(pos, pos, SelectionModel::LEADING);
437 472
438 // Notes: We always iterate words from the beginning. 473 // Notes: We always iterate words from the beginning.
439 // This is probably fast enough for our usage, but we may 474 // This is probably fast enough for our usage, but we may
440 // want to modify WordIterator so that it can start from the 475 // want to modify WordIterator so that it can start from the
441 // middle of string and advance backwards. 476 // middle of string and advance backwards.
442 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 477 string16 txt = GetCensoredText();
478 base::i18n::BreakIterator iter(txt, base::i18n::BreakIterator::BREAK_WORD);
443 bool success = iter.Init(); 479 bool success = iter.Init();
444 DCHECK(success); 480 DCHECK(success);
445 if (!success) 481 if (!success)
446 return current; 482 return current;
447 while (iter.Advance()) { 483 while (iter.Advance()) {
448 if (iter.IsWord()) { 484 if (iter.IsWord()) {
449 size_t begin = iter.pos() - iter.GetString().length(); 485 size_t begin = iter.pos() - iter.GetString().length();
450 if (begin == current.selection_end()) { 486 if (begin == current.selection_end()) {
451 // The cursor is at the beginning of a word. 487 // The cursor is at the beginning of a word.
452 // Move to previous word. 488 // Move to previous word.
(...skipping 15 matching lines...) Expand all
468 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current, 504 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
469 BreakType break_type) { 505 BreakType break_type) {
470 if (text_.empty()) 506 if (text_.empty())
471 return SelectionModel(0, 0, SelectionModel::LEADING); 507 return SelectionModel(0, 0, SelectionModel::LEADING);
472 if (break_type == LINE_BREAK) 508 if (break_type == LINE_BREAK)
473 return RightEndSelectionModel(); 509 return RightEndSelectionModel();
474 size_t pos = std::min(current.selection_end() + 1, text().length()); 510 size_t pos = std::min(current.selection_end() + 1, text().length());
475 if (break_type == CHARACTER_BREAK) 511 if (break_type == CHARACTER_BREAK)
476 return SelectionModel(pos, pos, SelectionModel::LEADING); 512 return SelectionModel(pos, pos, SelectionModel::LEADING);
477 513
478 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD); 514 string16 txt = GetCensoredText();
515 base::i18n::BreakIterator iter(txt, base::i18n::BreakIterator::BREAK_WORD);
479 bool success = iter.Init(); 516 bool success = iter.Init();
480 DCHECK(success); 517 DCHECK(success);
481 if (!success) 518 if (!success)
482 return current; 519 return current;
483 while (iter.Advance()) { 520 while (iter.Advance()) {
484 pos = iter.pos(); 521 pos = iter.pos();
485 if (iter.IsWord() && pos > current.selection_end()) 522 if (iter.IsWord() && pos > current.selection_end())
486 break; 523 break;
487 } 524 }
488 return SelectionModel(pos, pos, SelectionModel::LEADING); 525 return SelectionModel(pos, pos, SelectionModel::LEADING);
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after
611 void RenderText::DrawCursor(Canvas* canvas) { 648 void RenderText::DrawCursor(Canvas* canvas) {
612 // Paint cursor. Replace cursor is drawn as rectangle for now. 649 // Paint cursor. Replace cursor is drawn as rectangle for now.
613 // TODO(msw): Draw a better cursor with a better indication of association. 650 // TODO(msw): Draw a better cursor with a better indication of association.
614 if (cursor_visible() && focused()) { 651 if (cursor_visible() && focused()) {
615 Rect r(GetUpdatedCursorBounds()); 652 Rect r(GetUpdatedCursorBounds());
616 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); 653 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
617 } 654 }
618 } 655 }
619 656
620 } // namespace gfx 657 } // namespace gfx
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698