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

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: delete more dead code, address recent comments 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
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 kPasswordReplacementChar = '*';
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::GetObscuredText() const {
146 string16 txt = text();
147 if (obscured_) {
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?
xji 2011/12/22 01:11:20 Ben and I just talked about how to map obscured te
benrg 2011/12/22 02:14:21 xji wrote:
152 std::fill(txt.begin(), txt.end(), kPasswordReplacementChar);
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::SetObscured(bool obscured) {
163 obscured_ = obscured;
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 = GetObscuredText();
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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 cached_bounds_and_offset_valid_ = false; 368 cached_bounds_and_offset_valid_ = false;
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() {
345 return default_style_.font.GetStringWidth(text());
346 }
347
348 void RenderText::Draw(Canvas* canvas) { 378 void RenderText::Draw(Canvas* canvas) {
349 EnsureLayout(); 379 EnsureLayout();
350 380
351 if (!text().empty()) { 381 if (!text().empty()) {
352 DrawSelection(canvas); 382 DrawSelection(canvas);
353 DrawVisualText(canvas); 383 DrawVisualText(canvas);
354 } 384 }
355 DrawCursor(canvas); 385 DrawCursor(canvas);
356 } 386 }
357 387
358 SelectionModel RenderText::FindCursorPosition(const Point& point) {
359 const Font& font = default_style_.font;
360 int left = 0;
361 int left_pos = 0;
362 int right = font.GetStringWidth(text());
363 int right_pos = text().length();
364
365 int x = point.x() - (display_rect_.x() + GetUpdatedDisplayOffset().x());
366 if (x <= left) return SelectionModel(left_pos);
367 if (x >= right) return SelectionModel(right_pos);
368 // binary searching the cursor position.
369 // TODO(oshima): use the center of character instead of edge.
370 // Binary search may not work for language like Arabic.
371 while (std::abs(static_cast<long>(right_pos - left_pos)) > 1) {
372 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
373 int pivot = font.GetStringWidth(text().substr(0, pivot_pos));
374 if (pivot < x) {
375 left = pivot;
376 left_pos = pivot_pos;
377 } else if (pivot == x) {
378 return SelectionModel(pivot_pos);
379 } else {
380 right = pivot;
381 right_pos = pivot_pos;
382 }
383 }
384 return SelectionModel(left_pos);
385 }
386
387 const Rect& RenderText::GetUpdatedCursorBounds() { 388 const Rect& RenderText::GetUpdatedCursorBounds() {
388 UpdateCachedBoundsAndOffset(); 389 UpdateCachedBoundsAndOffset();
389 return cursor_bounds_; 390 return cursor_bounds_;
390 } 391 }
391 392
392 size_t RenderText::GetIndexOfNextGrapheme(size_t position) { 393 size_t RenderText::GetIndexOfNextGrapheme(size_t position) {
393 return IndexOfAdjacentGrapheme(position, true); 394 return IndexOfAdjacentGrapheme(position, true);
394 } 395 }
395 396
396 SelectionModel RenderText::GetSelectionModelForSelectionStart() { 397 SelectionModel RenderText::GetSelectionModelForSelectionStart() {
(...skipping 12 matching lines...) Expand all
409 410
410 RenderText::RenderText() 411 RenderText::RenderText()
411 : text_(), 412 : text_(),
412 selection_model_(), 413 selection_model_(),
413 cursor_bounds_(), 414 cursor_bounds_(),
414 cursor_visible_(false), 415 cursor_visible_(false),
415 insert_mode_(true), 416 insert_mode_(true),
416 composition_range_(ui::Range::InvalidRange()), 417 composition_range_(ui::Range::InvalidRange()),
417 style_ranges_(), 418 style_ranges_(),
418 default_style_(), 419 default_style_(),
420 obscured_(false),
419 display_rect_(), 421 display_rect_(),
420 display_offset_(), 422 display_offset_(),
421 cached_bounds_and_offset_valid_(false) { 423 cached_bounds_and_offset_valid_(false) {
422 } 424 }
423 425
424 const Point& RenderText::GetUpdatedDisplayOffset() { 426 const Point& RenderText::GetUpdatedDisplayOffset() {
425 UpdateCachedBoundsAndOffset(); 427 UpdateCachedBoundsAndOffset();
426 return display_offset_; 428 return display_offset_;
427 } 429 }
428 430
429 SelectionModel RenderText::GetLeftSelectionModel(const SelectionModel& current,
430 BreakType break_type) {
431 if (break_type == LINE_BREAK)
432 return LeftEndSelectionModel();
433 size_t pos = std::max(static_cast<long>(current.selection_end() - 1),
434 static_cast<long>(0));
435 if (break_type == CHARACTER_BREAK)
436 return SelectionModel(pos, pos, SelectionModel::LEADING);
437
438 // Notes: We always iterate words from the beginning.
439 // This is probably fast enough for our usage, but we may
440 // want to modify WordIterator so that it can start from the
441 // middle of string and advance backwards.
442 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
443 bool success = iter.Init();
444 DCHECK(success);
445 if (!success)
446 return current;
447 while (iter.Advance()) {
448 if (iter.IsWord()) {
449 size_t begin = iter.pos() - iter.GetString().length();
450 if (begin == current.selection_end()) {
451 // The cursor is at the beginning of a word.
452 // Move to previous word.
453 break;
454 } else if (iter.pos() >= current.selection_end()) {
455 // The cursor is in the middle or at the end of a word.
456 // Move to the top of current word.
457 pos = begin;
458 break;
459 } else {
460 pos = iter.pos() - iter.GetString().length();
461 }
462 }
463 }
464
465 return SelectionModel(pos, pos, SelectionModel::LEADING);
466 }
467
468 SelectionModel RenderText::GetRightSelectionModel(const SelectionModel& current,
469 BreakType break_type) {
470 if (text_.empty())
471 return SelectionModel(0, 0, SelectionModel::LEADING);
472 if (break_type == LINE_BREAK)
473 return RightEndSelectionModel();
474 size_t pos = std::min(current.selection_end() + 1, text().length());
475 if (break_type == CHARACTER_BREAK)
476 return SelectionModel(pos, pos, SelectionModel::LEADING);
477
478 base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
479 bool success = iter.Init();
480 DCHECK(success);
481 if (!success)
482 return current;
483 while (iter.Advance()) {
484 pos = iter.pos();
485 if (iter.IsWord() && pos > current.selection_end())
486 break;
487 }
488 return SelectionModel(pos, pos, SelectionModel::LEADING);
489 }
490
491 SelectionModel RenderText::LeftEndSelectionModel() {
492 return SelectionModel(0, 0, SelectionModel::LEADING);
493 }
494
495 SelectionModel RenderText::RightEndSelectionModel() {
496 size_t cursor = text().length();
497 size_t caret_pos = GetIndexOfPreviousGrapheme(cursor);
498 SelectionModel::CaretPlacement placement = (caret_pos == cursor) ?
499 SelectionModel::LEADING : SelectionModel::TRAILING;
500 return SelectionModel(cursor, caret_pos, placement);
501 }
502
503 void RenderText::SetSelectionModel(const SelectionModel& model) { 431 void RenderText::SetSelectionModel(const SelectionModel& model) {
504 DCHECK_LE(model.selection_start(), text().length()); 432 DCHECK_LE(model.selection_start(), text().length());
505 selection_model_.set_selection_start(model.selection_start()); 433 selection_model_.set_selection_start(model.selection_start());
506 DCHECK_LE(model.selection_end(), text().length()); 434 DCHECK_LE(model.selection_end(), text().length());
507 selection_model_.set_selection_end(model.selection_end()); 435 selection_model_.set_selection_end(model.selection_end());
508 DCHECK_LT(model.caret_pos(), 436 DCHECK_LT(model.caret_pos(),
509 std::max(text().length(), static_cast<size_t>(1))); 437 std::max(text().length(), static_cast<size_t>(1)));
510 selection_model_.set_caret_pos(model.caret_pos()); 438 selection_model_.set_caret_pos(model.caret_pos());
511 selection_model_.set_caret_placement(model.caret_placement()); 439 selection_model_.set_caret_placement(model.caret_placement());
512 440
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
612 void RenderText::DrawCursor(Canvas* canvas) { 540 void RenderText::DrawCursor(Canvas* canvas) {
613 // Paint cursor. Replace cursor is drawn as rectangle for now. 541 // Paint cursor. Replace cursor is drawn as rectangle for now.
614 // TODO(msw): Draw a better cursor with a better indication of association. 542 // TODO(msw): Draw a better cursor with a better indication of association.
615 if (cursor_visible() && focused()) { 543 if (cursor_visible() && focused()) {
616 Rect r(GetUpdatedCursorBounds()); 544 Rect r(GetUpdatedCursorBounds());
617 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height()); 545 canvas->DrawRectInt(kCursorColor, r.x(), r.y(), r.width(), r.height());
618 } 546 }
619 } 547 }
620 548
621 } // namespace gfx 549 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/render_text.h ('k') | ui/gfx/render_text_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698