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

Side by Side Diff: views/controls/textfield/native_textfield_views.cc

Issue 7265011: RenderText API Outline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Exclude Mac, fix font comparison. Created 9 years, 5 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) 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 "views/controls/textfield/native_textfield_views.h" 5 #include "views/controls/textfield/native_textfield_views.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/message_loop.h" 11 #include "base/message_loop.h"
12 #include "base/utf_string_conversions.h" 12 #include "base/utf_string_conversions.h"
13 #include "grit/ui_strings.h" 13 #include "grit/ui_strings.h"
14 #include "ui/base/clipboard/clipboard.h" 14 #include "ui/base/clipboard/clipboard.h"
15 #include "ui/base/dragdrop/drag_drop_types.h" 15 #include "ui/base/dragdrop/drag_drop_types.h"
16 #include "ui/base/range/range.h" 16 #include "ui/base/range/range.h"
17 #include "ui/gfx/canvas.h" 17 #include "ui/gfx/canvas.h"
18 #include "ui/gfx/insets.h" 18 #include "ui/gfx/insets.h"
19 #include "ui/gfx/render_text.h"
19 #include "views/background.h" 20 #include "views/background.h"
20 #include "views/border.h" 21 #include "views/border.h"
21 #include "views/controls/focusable_border.h" 22 #include "views/controls/focusable_border.h"
22 #include "views/controls/menu/menu_item_view.h" 23 #include "views/controls/menu/menu_item_view.h"
23 #include "views/controls/menu/menu_model_adapter.h" 24 #include "views/controls/menu/menu_model_adapter.h"
24 #include "views/controls/textfield/text_style.h"
25 #include "views/controls/textfield/textfield.h" 25 #include "views/controls/textfield/textfield.h"
26 #include "views/controls/textfield/textfield_controller.h" 26 #include "views/controls/textfield/textfield_controller.h"
27 #include "views/controls/textfield/textfield_views_model.h" 27 #include "views/controls/textfield/textfield_views_model.h"
28 #include "views/events/event.h" 28 #include "views/events/event.h"
29 #include "views/ime/input_method.h" 29 #include "views/ime/input_method.h"
30 #include "views/metrics.h" 30 #include "views/metrics.h"
31 #include "views/views_delegate.h" 31 #include "views/views_delegate.h"
32 #include "views/widget/widget.h" 32 #include "views/widget/widget.h"
33 33
34 #if defined(OS_LINUX) 34 #if defined(OS_LINUX)
35 #include "ui/gfx/gtk_util.h" 35 #include "ui/gfx/gtk_util.h"
36 #endif 36 #endif
37 37
38 namespace { 38 namespace {
39 39
40 // Color settings for text, backgrounds and cursor. 40 // Text color for read only.
41 // These are tentative, and should be derived from theme, system 41 const SkColor kReadonlyTextColor = SK_ColorDKGRAY;
42 // settings and current settings.
43 // TODO(oshima): Change this to match the standard chrome
44 // before dogfooding textfield views.
45 const SkColor kSelectedTextColor = SK_ColorWHITE;
46 const SkColor kFocusedSelectionColor = SK_ColorCYAN;
47 const SkColor kUnfocusedSelectionColor = SK_ColorLTGRAY;
48 const SkColor kCursorColor = SK_ColorBLACK;
49 42
50 // Parameters to control cursor blinking. 43 // Parameters to control cursor blinking.
51 const int kCursorVisibleTimeMs = 800; 44 const int kCursorVisibleTimeMs = 800;
52 const int kCursorInvisibleTimeMs = 500; 45 const int kCursorInvisibleTimeMs = 500;
53 46
54 } // namespace 47 } // namespace
55 48
56 namespace views { 49 namespace views {
57 50
58 const char NativeTextfieldViews::kViewClassName[] = 51 const char NativeTextfieldViews::kViewClassName[] =
59 "views/NativeTextfieldViews"; 52 "views/NativeTextfieldViews";
60 53
61 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent) 54 NativeTextfieldViews::NativeTextfieldViews(Textfield* parent)
62 : textfield_(parent), 55 : textfield_(parent),
63 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))), 56 ALLOW_THIS_IN_INITIALIZER_LIST(model_(new TextfieldViewsModel(this))),
64 text_border_(new FocusableBorder()), 57 text_border_(new FocusableBorder()),
65 text_offset_(0),
66 insert_(true),
67 is_cursor_visible_(false), 58 is_cursor_visible_(false),
68 skip_input_method_cancel_composition_(false), 59 skip_input_method_cancel_composition_(false),
69 initiating_drag_(false), 60 initiating_drag_(false),
70 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)), 61 ALLOW_THIS_IN_INITIALIZER_LIST(cursor_timer_(this)),
71 aggregated_clicks_(0), 62 aggregated_clicks_(0),
72 last_click_time_(base::Time::FromInternalValue(0)), 63 last_click_time_(base::Time::FromInternalValue(0)),
73 last_click_location_(0, 0) { 64 last_click_location_(0, 0) {
74 set_border(text_border_); 65 set_border(text_border_);
75 66
76 // Lowercase is not supported. 67 // Lowercase is not supported.
77 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE); 68 DCHECK_NE(parent->style(), Textfield::STYLE_LOWERCASE);
78 69
70 // Set the default text style.
71 gfx::StyleRange default_style;
72 default_style.font = textfield_->font();
73 default_style.foreground = textfield_->text_color();
74 GetRenderText()->set_default_style(default_style);
75
79 set_context_menu_controller(this); 76 set_context_menu_controller(this);
80 set_drag_controller(this); 77 set_drag_controller(this);
81 } 78 }
82 79
83 NativeTextfieldViews::~NativeTextfieldViews() { 80 NativeTextfieldViews::~NativeTextfieldViews() {
84 } 81 }
85 82
86 //////////////////////////////////////////////////////////////////////////////// 83 ////////////////////////////////////////////////////////////////////////////////
87 // NativeTextfieldViews, View overrides: 84 // NativeTextfieldViews, View overrides:
88 85
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) { 169 bool NativeTextfieldViews::CanDrop(const OSExchangeData& data) {
173 return textfield_->IsEnabled() && !textfield_->read_only() && 170 return textfield_->IsEnabled() && !textfield_->read_only() &&
174 data.HasString(); 171 data.HasString();
175 } 172 }
176 173
177 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) { 174 int NativeTextfieldViews::OnDragUpdated(const DropTargetEvent& event) {
178 DCHECK(CanDrop(event.data())); 175 DCHECK(CanDrop(event.data()));
179 bool is_point_in_selection = IsPointInSelection(event.location()); 176 bool is_point_in_selection = IsPointInSelection(event.location());
180 is_drop_cursor_visible_ = !is_point_in_selection; 177 is_drop_cursor_visible_ = !is_point_in_selection;
181 // TODO(msw): Pan over text when the user drags to the visible text edge. 178 // TODO(msw): Pan over text when the user drags to the visible text edge.
182 UpdateCursorBoundsAndTextOffset(FindCursorPosition(event.location()), true); 179 OnCaretBoundsChanged();
183 SchedulePaint(); 180 SchedulePaint();
184 181
185 if (initiating_drag_) { 182 if (initiating_drag_) {
186 if (is_point_in_selection) 183 if (is_point_in_selection)
187 return ui::DragDropTypes::DRAG_NONE; 184 return ui::DragDropTypes::DRAG_NONE;
188 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY : 185 return event.IsControlDown() ? ui::DragDropTypes::DRAG_COPY :
189 ui::DragDropTypes::DRAG_MOVE; 186 ui::DragDropTypes::DRAG_MOVE;
190 } 187 }
191 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE; 188 return ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_MOVE;
192 } 189 }
193 190
194 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) { 191 int NativeTextfieldViews::OnPerformDrop(const DropTargetEvent& event) {
195 DCHECK(CanDrop(event.data())); 192 DCHECK(CanDrop(event.data()));
196 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location())); 193 DCHECK(!initiating_drag_ || !IsPointInSelection(event.location()));
197 OnBeforeUserAction(); 194 OnBeforeUserAction();
198 skip_input_method_cancel_composition_ = true; 195 skip_input_method_cancel_composition_ = true;
199 196
200 size_t drop_destination = FindCursorPosition(event.location()); 197 size_t drop_destination =
198 GetRenderText()->FindCursorPosition(event.location());
201 string16 text; 199 string16 text;
202 event.data().GetString(&text); 200 event.data().GetString(&text);
203 201
204 // We'll delete the current selection for a drag and drop within this view. 202 // We'll delete the current selection for a drag and drop within this view.
205 bool move = initiating_drag_ && !event.IsControlDown() && 203 bool move = initiating_drag_ && !event.IsControlDown() &&
206 event.source_operations() & ui::DragDropTypes::DRAG_MOVE; 204 event.source_operations() & ui::DragDropTypes::DRAG_MOVE;
207 if (move) { 205 if (move) {
208 ui::Range selected_range; 206 ui::Range selected_range;
209 model_->GetSelectedRange(&selected_range); 207 model_->GetSelectedRange(&selected_range);
210 // Adjust the drop destination if it is on or after the current selection. 208 // Adjust the drop destination if it is on or after the current selection.
211 if (selected_range.GetMax() <= drop_destination) 209 if (selected_range.GetMax() <= drop_destination)
212 drop_destination -= selected_range.length(); 210 drop_destination -= selected_range.length();
213 else if (selected_range.GetMin() <= drop_destination) 211 else if (selected_range.GetMin() <= drop_destination)
214 drop_destination = selected_range.GetMin(); 212 drop_destination = selected_range.GetMin();
215 model_->DeleteSelectionAndInsertTextAt(text, drop_destination); 213 model_->DeleteSelectionAndInsertTextAt(text, drop_destination);
216 } else { 214 } else {
217 model_->MoveCursorTo(drop_destination, false); 215 model_->MoveCursorTo(drop_destination, false);
218 // Drop always inserts a text even if insert_ == false. 216 // Drop always inserts text even if the textfield is not in insert mode.
219 model_->InsertText(text); 217 model_->InsertText(text);
220 } 218 }
221 skip_input_method_cancel_composition_ = false; 219 skip_input_method_cancel_composition_ = false;
222 UpdateAfterChange(true, true); 220 UpdateAfterChange(true, true);
223 OnAfterUserAction(); 221 OnAfterUserAction();
224 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY; 222 return move ? ui::DragDropTypes::DRAG_MOVE : ui::DragDropTypes::DRAG_COPY;
225 } 223 }
226 224
227 void NativeTextfieldViews::OnDragDone() { 225 void NativeTextfieldViews::OnDragDone() {
228 initiating_drag_ = false; 226 initiating_drag_ = false;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 bool NativeTextfieldViews::CanStartDragForView(View* sender, 290 bool NativeTextfieldViews::CanStartDragForView(View* sender,
293 const gfx::Point& press_pt, 291 const gfx::Point& press_pt,
294 const gfx::Point& p) { 292 const gfx::Point& p) {
295 return IsPointInSelection(press_pt); 293 return IsPointInSelection(press_pt);
296 } 294 }
297 295
298 ///////////////////////////////////////////////////////////////// 296 /////////////////////////////////////////////////////////////////
299 // NativeTextfieldViews, NativeTextifieldWrapper overrides: 297 // NativeTextfieldViews, NativeTextifieldWrapper overrides:
300 298
301 string16 NativeTextfieldViews::GetText() const { 299 string16 NativeTextfieldViews::GetText() const {
302 return model_->text(); 300 return model_->GetText();
303 } 301 }
304 302
305 void NativeTextfieldViews::UpdateText() { 303 void NativeTextfieldViews::UpdateText() {
306 model_->SetText(textfield_->text()); 304 model_->SetText(textfield_->text());
307 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 305 OnCaretBoundsChanged();
308 SchedulePaint(); 306 SchedulePaint();
309 } 307 }
310 308
311 void NativeTextfieldViews::AppendText(const string16& text) { 309 void NativeTextfieldViews::AppendText(const string16& text) {
312 if (text.empty()) 310 if (text.empty())
313 return; 311 return;
314 model_->Append(text); 312 model_->Append(text);
315 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 313 OnCaretBoundsChanged();
316 SchedulePaint(); 314 SchedulePaint();
317 } 315 }
318 316
319 string16 NativeTextfieldViews::GetSelectedText() const { 317 string16 NativeTextfieldViews::GetSelectedText() const {
320 return model_->GetSelectedText(); 318 return model_->GetSelectedText();
321 } 319 }
322 320
323 void NativeTextfieldViews::SelectAll() { 321 void NativeTextfieldViews::SelectAll() {
324 model_->SelectAll(); 322 model_->SelectAll();
325 SchedulePaint(); 323 SchedulePaint();
(...skipping 20 matching lines...) Expand all
346 } 344 }
347 345
348 void NativeTextfieldViews::UpdateBackgroundColor() { 346 void NativeTextfieldViews::UpdateBackgroundColor() {
349 // TODO(oshima): Background has to match the border's shape. 347 // TODO(oshima): Background has to match the border's shape.
350 set_background( 348 set_background(
351 Background::CreateSolidBackground(textfield_->background_color())); 349 Background::CreateSolidBackground(textfield_->background_color()));
352 SchedulePaint(); 350 SchedulePaint();
353 } 351 }
354 352
355 void NativeTextfieldViews::UpdateReadOnly() { 353 void NativeTextfieldViews::UpdateReadOnly() {
354 // Update the default text style.
355 gfx::StyleRange default_style(GetRenderText()->get_default_style());
356 default_style.foreground = textfield_->read_only() ? kReadonlyTextColor :
357 textfield_->text_color();
358 GetRenderText()->set_default_style(default_style);
359 GetRenderText()->ApplyDefaultStyle();
360
356 SchedulePaint(); 361 SchedulePaint();
357 OnTextInputTypeChanged(); 362 OnTextInputTypeChanged();
358 } 363 }
359 364
360 void NativeTextfieldViews::UpdateFont() { 365 void NativeTextfieldViews::UpdateFont() {
361 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 366 OnCaretBoundsChanged();
362 } 367 }
363 368
364 void NativeTextfieldViews::UpdateIsPassword() { 369 void NativeTextfieldViews::UpdateIsPassword() {
365 model_->set_is_password(textfield_->IsPassword()); 370 model_->set_is_password(textfield_->IsPassword());
366 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 371 OnCaretBoundsChanged();
367 SchedulePaint(); 372 SchedulePaint();
368 OnTextInputTypeChanged(); 373 OnTextInputTypeChanged();
369 } 374 }
370 375
371 void NativeTextfieldViews::UpdateEnabled() { 376 void NativeTextfieldViews::UpdateEnabled() {
372 SetEnabled(textfield_->IsEnabled()); 377 SetEnabled(textfield_->IsEnabled());
373 SchedulePaint(); 378 SchedulePaint();
374 OnTextInputTypeChanged(); 379 OnTextInputTypeChanged();
375 } 380 }
376 381
377 gfx::Insets NativeTextfieldViews::CalculateInsets() { 382 gfx::Insets NativeTextfieldViews::CalculateInsets() {
378 return GetInsets(); 383 return GetInsets();
379 } 384 }
380 385
381 void NativeTextfieldViews::UpdateHorizontalMargins() { 386 void NativeTextfieldViews::UpdateHorizontalMargins() {
382 int left, right; 387 int left, right;
383 if (!textfield_->GetHorizontalMargins(&left, &right)) 388 if (!textfield_->GetHorizontalMargins(&left, &right))
384 return; 389 return;
385 gfx::Insets inset = GetInsets(); 390 gfx::Insets inset = GetInsets();
386 391
387 text_border_->SetInsets(inset.top(), left, inset.bottom(), right); 392 text_border_->SetInsets(inset.top(), left, inset.bottom(), right);
388 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 393 OnCaretBoundsChanged();
389 } 394 }
390 395
391 void NativeTextfieldViews::UpdateVerticalMargins() { 396 void NativeTextfieldViews::UpdateVerticalMargins() {
392 int top, bottom; 397 int top, bottom;
393 if (!textfield_->GetVerticalMargins(&top, &bottom)) 398 if (!textfield_->GetVerticalMargins(&top, &bottom))
394 return; 399 return;
395 gfx::Insets inset = GetInsets(); 400 gfx::Insets inset = GetInsets();
396
397 text_border_->SetInsets(top, inset.left(), bottom, inset.right()); 401 text_border_->SetInsets(top, inset.left(), bottom, inset.right());
398 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 402 OnCaretBoundsChanged();
399 } 403 }
400 404
401 bool NativeTextfieldViews::SetFocus() { 405 bool NativeTextfieldViews::SetFocus() {
402 return false; 406 return false;
403 } 407 }
404 408
405 View* NativeTextfieldViews::GetView() { 409 View* NativeTextfieldViews::GetView() {
406 return this; 410 return this;
407 } 411 }
408 412
409 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const { 413 gfx::NativeView NativeTextfieldViews::GetTestingHandle() const {
410 NOTREACHED(); 414 NOTREACHED();
411 return NULL; 415 return NULL;
412 } 416 }
413 417
414 bool NativeTextfieldViews::IsIMEComposing() const { 418 bool NativeTextfieldViews::IsIMEComposing() const {
415 return model_->HasCompositionText(); 419 return model_->HasCompositionText();
416 } 420 }
417 421
418 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const { 422 void NativeTextfieldViews::GetSelectedRange(ui::Range* range) const {
419 model_->GetSelectedRange(range); 423 model_->GetSelectedRange(range);
420 } 424 }
421 425
422 void NativeTextfieldViews::SelectRange(const ui::Range& range) { 426 void NativeTextfieldViews::SelectRange(const ui::Range& range) {
423 model_->SelectRange(range); 427 model_->SelectRange(range);
424 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 428 OnCaretBoundsChanged();
425 SchedulePaint(); 429 SchedulePaint();
426 } 430 }
427 431
428 size_t NativeTextfieldViews::GetCursorPosition() const { 432 size_t NativeTextfieldViews::GetCursorPosition() const {
429 return model_->cursor_pos(); 433 return model_->GetCursorPosition();
430 } 434 }
431 435
432 bool NativeTextfieldViews::HandleKeyPressed(const KeyEvent& e) { 436 bool NativeTextfieldViews::HandleKeyPressed(const KeyEvent& e) {
433 TextfieldController* controller = textfield_->GetController(); 437 TextfieldController* controller = textfield_->GetController();
434 bool handled = false; 438 bool handled = false;
435 if (controller) 439 if (controller)
436 handled = controller->HandleKeyEvent(textfield_, e); 440 handled = controller->HandleKeyEvent(textfield_, e);
437 return handled || HandleKeyEvent(e); 441 return handled || HandleKeyEvent(e);
438 } 442 }
439 443
440 bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) { 444 bool NativeTextfieldViews::HandleKeyReleased(const KeyEvent& e) {
441 return true; 445 return true;
442 } 446 }
443 447
444 void NativeTextfieldViews::HandleFocus() { 448 void NativeTextfieldViews::HandleFocus() {
449 GetRenderText()->set_focused(true);
445 is_cursor_visible_ = true; 450 is_cursor_visible_ = true;
446 SchedulePaint(); 451 SchedulePaint();
447 OnCaretBoundsChanged(); 452 OnCaretBoundsChanged();
448 // Start blinking cursor. 453 // Start blinking cursor.
449 MessageLoop::current()->PostDelayedTask( 454 MessageLoop::current()->PostDelayedTask(
450 FROM_HERE, 455 FROM_HERE,
451 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), 456 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor),
452 kCursorVisibleTimeMs); 457 kCursorVisibleTimeMs);
453 } 458 }
454 459
455 void NativeTextfieldViews::HandleBlur() { 460 void NativeTextfieldViews::HandleBlur() {
461 GetRenderText()->set_focused(false);
456 // Stop blinking cursor. 462 // Stop blinking cursor.
457 cursor_timer_.RevokeAll(); 463 cursor_timer_.RevokeAll();
458 if (is_cursor_visible_) { 464 if (is_cursor_visible_) {
459 is_cursor_visible_ = false; 465 is_cursor_visible_ = false;
460 RepaintCursor(); 466 RepaintCursor();
461 } 467 }
462 } 468 }
463 469
464 TextInputClient* NativeTextfieldViews::GetTextInputClient() { 470 TextInputClient* NativeTextfieldViews::GetTextInputClient() {
465 return textfield_->read_only() ? NULL : this; 471 return textfield_->read_only() ? NULL : this;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
529 default: 535 default:
530 NOTREACHED() << "unknown command: " << command_id; 536 NOTREACHED() << "unknown command: " << command_id;
531 break; 537 break;
532 } 538 }
533 539
534 // The cursor must have changed if text changed during cut/paste/delete. 540 // The cursor must have changed if text changed during cut/paste/delete.
535 UpdateAfterChange(text_changed, text_changed); 541 UpdateAfterChange(text_changed, text_changed);
536 OnAfterUserAction(); 542 OnAfterUserAction();
537 } 543 }
538 544
539 TextStyle* NativeTextfieldViews::CreateTextStyle() { 545 void NativeTextfieldViews::ApplyStyleRange(const gfx::StyleRange& style) {
540 return model_->CreateTextStyle(); 546 GetRenderText()->ApplyStyleRange(style);
541 }
542
543 void NativeTextfieldViews::ApplyTextStyle(const TextStyle* style,
544 const ui::Range& range) {
545 model_->ApplyTextStyle(style, range);
546 SchedulePaint(); 547 SchedulePaint();
547 } 548 }
548 549
549 void NativeTextfieldViews::ClearAllTextStyles() { 550 void NativeTextfieldViews::ApplyDefaultStyle() {
550 model_->ClearAllTextStyles(); 551 GetRenderText()->ApplyDefaultStyle();
551 SchedulePaint(); 552 SchedulePaint();
552 } 553 }
553 554
554 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { 555 void NativeTextfieldViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
555 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 556 // Set the RenderText display area.
557 gfx::Insets insets = GetInsets();
558 gfx::Rect display_rect(insets.left(),
559 insets.top(),
560 width() - insets.width(),
561 height() - insets.height());
562 GetRenderText()->set_display_rect(display_rect);
563 OnCaretBoundsChanged();
556 } 564 }
557 565
558 /////////////////////////////////////////////////////////////////////////////// 566 ///////////////////////////////////////////////////////////////////////////////
559 // NativeTextfieldViews, TextInputClient implementation, private: 567 // NativeTextfieldViews, TextInputClient implementation, private:
560 568
561 void NativeTextfieldViews::SetCompositionText( 569 void NativeTextfieldViews::SetCompositionText(
562 const ui::CompositionText& composition) { 570 const ui::CompositionText& composition) {
563 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE) 571 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE)
564 return; 572 return;
565 573
(...skipping 29 matching lines...) Expand all
595 OnAfterUserAction(); 603 OnAfterUserAction();
596 } 604 }
597 605
598 void NativeTextfieldViews::InsertText(const string16& text) { 606 void NativeTextfieldViews::InsertText(const string16& text) {
599 // TODO(suzhe): Filter invalid characters. 607 // TODO(suzhe): Filter invalid characters.
600 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty()) 608 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || text.empty())
601 return; 609 return;
602 610
603 OnBeforeUserAction(); 611 OnBeforeUserAction();
604 skip_input_method_cancel_composition_ = true; 612 skip_input_method_cancel_composition_ = true;
605 if (insert_) 613 if (GetRenderText()->get_insert_mode())
606 model_->InsertText(text); 614 model_->InsertText(text);
607 else 615 else
608 model_->ReplaceText(text); 616 model_->ReplaceText(text);
609 skip_input_method_cancel_composition_ = false; 617 skip_input_method_cancel_composition_ = false;
610 UpdateAfterChange(true, true); 618 UpdateAfterChange(true, true);
611 OnAfterUserAction(); 619 OnAfterUserAction();
612 } 620 }
613 621
614 void NativeTextfieldViews::InsertChar(char16 ch, int flags) { 622 void NativeTextfieldViews::InsertChar(char16 ch, int flags) {
615 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE || 623 if (GetTextInputType() == ui::TEXT_INPUT_TYPE_NONE ||
616 !ShouldInsertChar(ch, flags)) { 624 !ShouldInsertChar(ch, flags)) {
617 return; 625 return;
618 } 626 }
619 627
620 OnBeforeUserAction(); 628 OnBeforeUserAction();
621 skip_input_method_cancel_composition_ = true; 629 skip_input_method_cancel_composition_ = true;
622 if (insert_) 630 if (GetRenderText()->get_insert_mode())
623 model_->InsertChar(ch); 631 model_->InsertChar(ch);
624 else 632 else
625 model_->ReplaceChar(ch); 633 model_->ReplaceChar(ch);
626 skip_input_method_cancel_composition_ = false; 634 skip_input_method_cancel_composition_ = false;
627 UpdateAfterChange(true, true); 635 UpdateAfterChange(true, true);
628 OnAfterUserAction(); 636 OnAfterUserAction();
629 } 637 }
630 638
631 ui::TextInputType NativeTextfieldViews::GetTextInputType() { 639 ui::TextInputType NativeTextfieldViews::GetTextInputType() {
632 if (textfield_->read_only() || !textfield_->IsEnabled()) 640 if (textfield_->read_only() || !textfield_->IsEnabled())
633 return ui::TEXT_INPUT_TYPE_NONE; 641 return ui::TEXT_INPUT_TYPE_NONE;
634 else if (textfield_->IsPassword()) 642 else if (textfield_->IsPassword())
635 return ui::TEXT_INPUT_TYPE_PASSWORD; 643 return ui::TEXT_INPUT_TYPE_PASSWORD;
636 return ui::TEXT_INPUT_TYPE_TEXT; 644 return ui::TEXT_INPUT_TYPE_TEXT;
637 } 645 }
638 646
639 gfx::Rect NativeTextfieldViews::GetCaretBounds() { 647 gfx::Rect NativeTextfieldViews::GetCaretBounds() {
640 return cursor_bounds_; 648 gfx::RenderText* render_text = GetRenderText();
649 return render_text->GetCursorBounds(render_text->GetCursor(),
650 render_text->get_insert_mode());
641 } 651 }
642 652
643 bool NativeTextfieldViews::HasCompositionText() { 653 bool NativeTextfieldViews::HasCompositionText() {
644 return model_->HasCompositionText(); 654 return model_->HasCompositionText();
645 } 655 }
646 656
647 bool NativeTextfieldViews::GetTextRange(ui::Range* range) { 657 bool NativeTextfieldViews::GetTextRange(ui::Range* range) {
648 // We don't allow the input method to retrieve or delete content from a 658 // We don't allow the input method to retrieve or delete content from a
649 // password box. 659 // password box.
650 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT) 660 if (GetTextInputType() != ui::TEXT_INPUT_TYPE_TEXT)
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
718 return textfield_; 728 return textfield_;
719 } 729 }
720 730
721 void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() { 731 void NativeTextfieldViews::OnCompositionTextConfirmedOrCleared() {
722 if (skip_input_method_cancel_composition_) 732 if (skip_input_method_cancel_composition_)
723 return; 733 return;
724 DCHECK(textfield_->GetInputMethod()); 734 DCHECK(textfield_->GetInputMethod());
725 textfield_->GetInputMethod()->CancelComposition(textfield_); 735 textfield_->GetInputMethod()->CancelComposition(textfield_);
726 } 736 }
727 737
728 const gfx::Font& NativeTextfieldViews::GetFont() const { 738 gfx::RenderText* NativeTextfieldViews::GetRenderText() const {
729 return textfield_->font(); 739 return model_->get_render_text();
730 }
731
732 SkColor NativeTextfieldViews::GetTextColor() const {
733 return textfield_->text_color();
734 } 740 }
735 741
736 void NativeTextfieldViews::UpdateCursor() { 742 void NativeTextfieldViews::UpdateCursor() {
737 is_cursor_visible_ = !is_cursor_visible_; 743 is_cursor_visible_ = !is_cursor_visible_;
738 RepaintCursor(); 744 RepaintCursor();
739 MessageLoop::current()->PostDelayedTask( 745 MessageLoop::current()->PostDelayedTask(
740 FROM_HERE, 746 FROM_HERE,
741 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor), 747 cursor_timer_.NewRunnableMethod(&NativeTextfieldViews::UpdateCursor),
742 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs); 748 is_cursor_visible_ ? kCursorVisibleTimeMs : kCursorInvisibleTimeMs);
743 } 749 }
744 750
745 void NativeTextfieldViews::RepaintCursor() { 751 void NativeTextfieldViews::RepaintCursor() {
746 gfx::Rect r = cursor_bounds_; 752 gfx::Rect r(GetCaretBounds());
747 r.Inset(-1, -1, -1, -1); 753 r.Inset(-1, -1, -1, -1);
748 SchedulePaintInRect(r); 754 SchedulePaintInRect(r);
749 } 755 }
750 756
751 gfx::Rect NativeTextfieldViews::GetCursorBounds(size_t cursor_pos,
752 bool insert_mode) const {
753 string16 text = model_->GetVisibleText();
754 const gfx::Font& font = GetFont();
755 int x = font.GetStringWidth(text.substr(0U, cursor_pos));
756 DCHECK_GE(x, 0);
757 int h = std::min(height() - GetInsets().height(), font.GetHeight());
758 gfx::Rect bounds(x, (height() - h) / 2, 0, h);
759 if (!insert_mode && text.length() != cursor_pos)
760 bounds.set_width(font.GetStringWidth(text.substr(0, cursor_pos + 1)) - x);
761 return bounds;
762 }
763
764
765 void NativeTextfieldViews::UpdateCursorBoundsAndTextOffset(size_t cursor_pos,
xji 2011/07/20 01:33:33 So, the cursor_bounds_ is updated inside RepaintCu
msw 2011/07/20 09:22:46 The visual cursor bounds aren't cached anywhere cu
766 bool insert_mode) {
767 if (bounds().IsEmpty())
768 return;
769
770 // TODO(oshima): bidi
771 int width = bounds().width() - GetInsets().width();
772 int full_width = GetFont().GetStringWidth(model_->GetVisibleText());
773 cursor_bounds_ = GetCursorBounds(cursor_pos, insert_mode);
774
775 if (full_width < width) {
776 // Show all text whenever the text fits to the size.
777 text_offset_ = 0;
778 } else if ((text_offset_ + cursor_bounds_.right()) > width) {
779 // when the cursor overflows to the right
780 text_offset_ = width - cursor_bounds_.right();
781 } else if ((text_offset_ + cursor_bounds_.x()) < 0) {
782 // when the cursor overflows to the left
783 text_offset_ = -cursor_bounds_.x();
784 } else if (full_width > width && text_offset_ + full_width < width) {
785 // when the cursor moves within the textfield with the text
786 // longer than the field.
787 text_offset_ = width - full_width;
788 } else {
789 // move cursor freely.
790 }
791 // shift cursor bounds to fit insets.
792 cursor_bounds_.set_x(cursor_bounds_.x() + text_offset_ + GetInsets().left());
793
794 OnCaretBoundsChanged();
795 }
796
797 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) { 757 void NativeTextfieldViews::PaintTextAndCursor(gfx::Canvas* canvas) {
798 gfx::Insets insets = GetInsets();
799
800 canvas->Save(); 758 canvas->Save();
801 canvas->ClipRectInt(insets.left(), insets.top(), 759 GetRenderText()->set_cursor_visible(is_drop_cursor_visible_ ||
802 width() - insets.width(), height() - insets.height()); 760 (is_cursor_visible_ && !model_->HasSelection()));
803 761 // Draw the text, cursor, and selection.
804 // TODO(oshima): bidi support 762 GetRenderText()->Draw(canvas);
805 // TODO(varunjain): re-implement this so only that dirty text is painted.
806 TextfieldViewsModel::TextFragments fragments;
807 model_->GetFragments(&fragments);
808 int x_offset = text_offset_ + insets.left();
809 int y = insets.top();
810 int text_height = height() - insets.height();
811 SkColor selection_color =
812 textfield_->HasFocus() ?
813 kFocusedSelectionColor : kUnfocusedSelectionColor;
814 gfx::Font font = GetFont();
815 gfx::Rect selection_bounds = model_->GetSelectionBounds(font);
816
817 if (!selection_bounds.IsEmpty()) {
818 canvas->FillRectInt(selection_color,
819 x_offset + selection_bounds.x(),
820 (height() - selection_bounds.height()) / 2,
821 selection_bounds.width(),
822 selection_bounds.height());
823 }
824
825 for (TextfieldViewsModel::TextFragments::const_iterator iter =
826 fragments.begin();
827 iter != fragments.end();
828 iter++) {
829 string16 text = model_->GetVisibleText(iter->range.start(),
830 iter->range.end());
831 // TODO(oshima): This does not give the accurate position due to
832 // kerning. Figure out how to do.
833 int width = font.GetStringWidth(text);
834 iter->style->DrawString(canvas, text, font, textfield_->read_only(),
835 x_offset, y, width, text_height);
836 x_offset += width;
837 }
838 canvas->Restore(); 763 canvas->Restore();
839
840 // Paint cursor. Replace cursor is drawn as rectangle for now.
841 if (textfield_->IsEnabled() && (is_drop_cursor_visible_ ||
842 (is_cursor_visible_ && !model_->HasSelection())))
843 canvas->DrawRectInt(kCursorColor,
844 cursor_bounds_.x(),
845 cursor_bounds_.y(),
846 cursor_bounds_.width(),
847 cursor_bounds_.height());
848 } 764 }
849 765
850 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) { 766 bool NativeTextfieldViews::HandleKeyEvent(const KeyEvent& key_event) {
851 // TODO(oshima): Refactor and consolidate with ExecuteCommand. 767 // TODO(oshima): Refactor and consolidate with ExecuteCommand.
852 if (key_event.type() == ui::ET_KEY_PRESSED) { 768 if (key_event.type() == ui::ET_KEY_PRESSED) {
853 ui::KeyboardCode key_code = key_event.key_code(); 769 ui::KeyboardCode key_code = key_event.key_code();
854 // TODO(oshima): shift-tab does not work. Figure out why and fix. 770 // TODO(oshima): shift-tab does not work. Figure out why and fix.
855 if (key_code == ui::VKEY_TAB) 771 if (key_code == ui::VKEY_TAB)
856 return false; 772 return false;
857 773
(...skipping 24 matching lines...) Expand all
882 break; 798 break;
883 case ui::VKEY_C: 799 case ui::VKEY_C:
884 if (control) 800 if (control)
885 model_->Copy(); 801 model_->Copy();
886 break; 802 break;
887 case ui::VKEY_V: 803 case ui::VKEY_V:
888 if (control && editable) 804 if (control && editable)
889 cursor_changed = text_changed = Paste(); 805 cursor_changed = text_changed = Paste();
890 break; 806 break;
891 case ui::VKEY_RIGHT: 807 case ui::VKEY_RIGHT:
892 control ? model_->MoveCursorToNextWord(selection) 808 control ? model_->MoveCursorRightByWord(selection)
893 : model_->MoveCursorRight(selection); 809 : model_->MoveCursorRight(selection);
894 cursor_changed = true; 810 cursor_changed = true;
895 break; 811 break;
896 case ui::VKEY_LEFT: 812 case ui::VKEY_LEFT:
897 control ? model_->MoveCursorToPreviousWord(selection) 813 control ? model_->MoveCursorLeftByWord(selection)
898 : model_->MoveCursorLeft(selection); 814 : model_->MoveCursorLeft(selection);
899 cursor_changed = true; 815 cursor_changed = true;
900 break; 816 break;
901 case ui::VKEY_END: 817 case ui::VKEY_END:
902 model_->MoveCursorToEnd(selection); 818 model_->MoveCursorToRightEnd(selection);
903 cursor_changed = true; 819 cursor_changed = true;
904 break; 820 break;
905 case ui::VKEY_HOME: 821 case ui::VKEY_HOME:
906 model_->MoveCursorToHome(selection); 822 model_->MoveCursorToLeftEnd(selection);
907 cursor_changed = true; 823 cursor_changed = true;
908 break; 824 break;
909 case ui::VKEY_BACK: 825 case ui::VKEY_BACK:
910 if (!editable) 826 if (!editable)
911 break; 827 break;
912 if (!model_->HasSelection()) { 828 if (!model_->HasSelection()) {
913 if (selection && control) { 829 if (selection && control) {
914 // If both shift and control are pressed, then erase upto the 830 // If both shift and control are pressed, then erase upto the
915 // beginning of the buffer in ChromeOS. In windows, do nothing. 831 // beginning of the buffer in ChromeOS. In windows, do nothing.
916 #if defined(OS_WIN) 832 #if defined(OS_WIN)
917 break; 833 break;
918 #else 834 #else
919 model_->MoveCursorToHome(true); 835 model_->MoveCursorToLeftEnd(true);
920 #endif 836 #endif
921 } else if (control) { 837 } else if (control) {
922 // If only control is pressed, then erase the previous word. 838 // If only control is pressed, then erase the previous word.
923 model_->MoveCursorToPreviousWord(true); 839 model_->MoveCursorLeftByWord(true);
924 } 840 }
925 } 841 }
926 text_changed = model_->Backspace(); 842 text_changed = model_->Backspace();
927 cursor_changed = true; 843 cursor_changed = true;
928 break; 844 break;
929 case ui::VKEY_DELETE: 845 case ui::VKEY_DELETE:
930 if (!editable) 846 if (!editable)
931 break; 847 break;
932 if (!model_->HasSelection()) { 848 if (!model_->HasSelection()) {
933 if (selection && control) { 849 if (selection && control) {
934 // If both shift and control are pressed, then erase upto the 850 // If both shift and control are pressed, then erase upto the
935 // end of the buffer in ChromeOS. In windows, do nothing. 851 // end of the buffer in ChromeOS. In windows, do nothing.
936 #if defined(OS_WIN) 852 #if defined(OS_WIN)
937 break; 853 break;
938 #else 854 #else
939 model_->MoveCursorToEnd(true); 855 model_->MoveCursorToRightEnd(true);
940 #endif 856 #endif
941 } else if (control) { 857 } else if (control) {
942 // If only control is pressed, then erase the next word. 858 // If only control is pressed, then erase the next word.
943 model_->MoveCursorToNextWord(true); 859 model_->MoveCursorRightByWord(true);
944 } 860 }
945 } 861 }
946 cursor_changed = text_changed = model_->Delete(); 862 cursor_changed = text_changed = model_->Delete();
947 break; 863 break;
948 case ui::VKEY_INSERT: 864 case ui::VKEY_INSERT:
949 insert_ = !insert_; 865 GetRenderText()->toggle_insert_mode();
950 cursor_changed = true; 866 cursor_changed = true;
951 break; 867 break;
952 default: 868 default:
953 break; 869 break;
954 } 870 }
955 871
956 // We must have input method in order to support text input. 872 // We must have input method in order to support text input.
957 DCHECK(textfield_->GetInputMethod()); 873 DCHECK(textfield_->GetInputMethod());
958 874
959 UpdateAfterChange(text_changed, cursor_changed); 875 UpdateAfterChange(text_changed, cursor_changed);
960 OnAfterUserAction(); 876 OnAfterUserAction();
961 return (text_changed || cursor_changed); 877 return (text_changed || cursor_changed);
962 } 878 }
963 return false; 879 return false;
964 } 880 }
965 881
966 size_t NativeTextfieldViews::FindCursorPosition(const gfx::Point& point) const {
967 // TODO(oshima): BIDI/i18n support.
968 gfx::Font font = GetFont();
969 gfx::Insets insets = GetInsets();
970 string16 text = model_->GetVisibleText();
971 int left = 0;
972 int left_pos = 0;
973 int right = font.GetStringWidth(text);
974 int right_pos = text.length();
975
976 int x = point.x() - insets.left() - text_offset_;
977 if (x <= left) return left_pos;
978 if (x >= right) return right_pos;
979 // binary searching the cursor position.
980 // TODO(oshima): use the center of character instead of edge.
981 // Binary search may not work for language like arabic.
982 while (std::abs(static_cast<long>(right_pos - left_pos) > 1)) {
983 int pivot_pos = left_pos + (right_pos - left_pos) / 2;
984 int pivot = font.GetStringWidth(text.substr(0, pivot_pos));
985 if (pivot < x) {
986 left = pivot;
987 left_pos = pivot_pos;
988 } else if (pivot == x) {
989 return pivot_pos;
990 } else {
991 right = pivot;
992 right_pos = pivot_pos;
993 }
994 }
995 return left_pos;
996 }
997
998 bool NativeTextfieldViews::IsPointInSelection(const gfx::Point& point) const { 882 bool NativeTextfieldViews::IsPointInSelection(const gfx::Point& point) const {
999 ui::Range range; 883 ui::Range range;
1000 GetSelectedRange(&range); 884 GetSelectedRange(&range);
1001 size_t pos = FindCursorPosition(point); 885 size_t pos = GetRenderText()->FindCursorPosition(point);
1002 return (pos >= range.GetMin() && pos < range.GetMax()); 886 return (pos >= range.GetMin() && pos < range.GetMax());
1003 } 887 }
1004 888
1005 bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) { 889 bool NativeTextfieldViews::MoveCursorTo(const gfx::Point& point, bool select) {
1006 size_t pos = FindCursorPosition(point); 890 size_t pos = GetRenderText()->FindCursorPosition(point);
1007 if (model_->MoveCursorTo(pos, select)) { 891 if (model_->MoveCursorTo(pos, select)) {
1008 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 892 OnCaretBoundsChanged();
1009 return true; 893 return true;
1010 } 894 }
1011 return false; 895 return false;
1012 } 896 }
1013 897
1014 void NativeTextfieldViews::PropagateTextChange() { 898 void NativeTextfieldViews::PropagateTextChange() {
1015 textfield_->SyncText(); 899 textfield_->SyncText();
1016 } 900 }
1017 901
1018 void NativeTextfieldViews::UpdateAfterChange(bool text_changed, 902 void NativeTextfieldViews::UpdateAfterChange(bool text_changed,
1019 bool cursor_changed) { 903 bool cursor_changed) {
1020 if (text_changed) 904 if (text_changed)
1021 PropagateTextChange(); 905 PropagateTextChange();
1022 if (cursor_changed) { 906 if (cursor_changed) {
1023 is_cursor_visible_ = true; 907 is_cursor_visible_ = true;
1024 RepaintCursor(); 908 RepaintCursor();
1025 } 909 }
1026 if (text_changed || cursor_changed) { 910 if (text_changed || cursor_changed) {
1027 UpdateCursorBoundsAndTextOffset(model_->cursor_pos(), insert_); 911 OnCaretBoundsChanged();
1028 SchedulePaint(); 912 SchedulePaint();
1029 } 913 }
1030 } 914 }
1031 915
1032 void NativeTextfieldViews::UpdateContextMenu() { 916 void NativeTextfieldViews::UpdateContextMenu() {
1033 if (!context_menu_contents_.get()) { 917 if (!context_menu_contents_.get()) {
1034 context_menu_contents_.reset(new ui::SimpleMenuModel(this)); 918 context_menu_contents_.reset(new ui::SimpleMenuModel(this));
1035 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); 919 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT);
1036 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); 920 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY);
1037 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); 921 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE);
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
1071 TextfieldController* controller = textfield_->GetController(); 955 TextfieldController* controller = textfield_->GetController();
1072 if (controller) 956 if (controller)
1073 controller->OnAfterUserAction(textfield_); 957 controller->OnAfterUserAction(textfield_);
1074 } 958 }
1075 959
1076 bool NativeTextfieldViews::Paste() { 960 bool NativeTextfieldViews::Paste() {
1077 const bool success = model_->Paste(); 961 const bool success = model_->Paste();
1078 962
1079 // Calls TextfieldController::ContentsChanged() explicitly if the paste action 963 // Calls TextfieldController::ContentsChanged() explicitly if the paste action
1080 // did not change the content at all. See http://crbug.com/79002 964 // did not change the content at all. See http://crbug.com/79002
1081 if (success && model_->text() == textfield_->text()) { 965 if (success && GetText() == textfield_->text()) {
1082 TextfieldController* controller = textfield_->GetController(); 966 TextfieldController* controller = textfield_->GetController();
1083 if (controller) 967 if (controller)
1084 controller->ContentsChanged(textfield_, textfield_->text()); 968 controller->ContentsChanged(textfield_, textfield_->text());
1085 } 969 }
1086 return success; 970 return success;
1087 } 971 }
1088 972
1089 // static 973 // static
1090 bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) { 974 bool NativeTextfieldViews::ShouldInsertChar(char16 ch, int flags) {
1091 // Filter out all control characters, including tab and new line characters, 975 // Filter out all control characters, including tab and new line characters,
1092 // and all characters with Alt modifier. But we need to allow characters with 976 // and all characters with Alt modifier. But we need to allow characters with
1093 // AltGr modifier. 977 // AltGr modifier.
1094 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different 978 // On Windows AltGr is represented by Alt+Ctrl, and on Linux it's a different
1095 // flag that we don't care about. 979 // flag that we don't care about.
1096 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) && 980 return ((ch >= 0x20 && ch < 0x7F) || ch > 0x9F) &&
1097 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN; 981 (flags & ~(ui::EF_SHIFT_DOWN | ui::EF_CAPS_LOCK_DOWN)) != ui::EF_ALT_DOWN;
1098 } 982 }
1099 983
1100 } // namespace views 984 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698