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

Side by Side Diff: third_party/WebKit/Source/core/editing/InputMethodController.cpp

Issue 2530843003: Introduce InsertIncrementalTextCommand to respect existing style for composition (Closed)
Patch Set: Introduce InsertIncrementalTextCommand Created 4 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
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) 3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
61 void dispatchCompositionEndEvent(LocalFrame& frame, const String& text) { 61 void dispatchCompositionEndEvent(LocalFrame& frame, const String& text) {
62 Element* target = frame.document()->focusedElement(); 62 Element* target = frame.document()->focusedElement();
63 if (!target) 63 if (!target)
64 return; 64 return;
65 65
66 CompositionEvent* event = CompositionEvent::create( 66 CompositionEvent* event = CompositionEvent::create(
67 EventTypeNames::compositionend, frame.domWindow(), text); 67 EventTypeNames::compositionend, frame.domWindow(), text);
68 target->dispatchEvent(event); 68 target->dispatchEvent(event);
69 } 69 }
70 70
71 bool static needsIncrementalInsertion(const LocalFrame& frame,
chongz 2016/12/02 20:34:44 I was under the impression that the style guide pr
yabinh 2016/12/05 08:09:39 Done.
72 const String& newText) {
73 DCHECK(frame.document());
74
75 // Since 'input' element doesn't support formated text, there is no need to
76 // apply incremental insertion.
77 if (frame.document()->focusedElement()->tagName() == String("INPUT"))
chongz 2016/12/02 20:34:44 Maybe |!frame.editor().canEditRichly()|? e.g. We d
yabinh 2016/12/05 08:09:39 Done.
78 return false;
79
80 // No need to apply incremental insertion if the old text (text to be
81 // replaced) or the new text (text to be inserted) is empty.
82 if (frame.selectedText().isEmpty() || newText.isEmpty())
83 return false;
84
85 return true;
86 }
87
71 // Used to insert/replace text during composition update and confirm 88 // Used to insert/replace text during composition update and confirm
72 // composition. 89 // composition.
73 // Procedure: 90 // Procedure:
74 // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and 91 // 1. Fire 'beforeinput' event for (TODO(chongz): deleted composed text) and
75 // inserted text 92 // inserted text
76 // 2. Fire 'compositionupdate' event 93 // 2. Fire 'compositionupdate' event
77 // 3. Fire TextEvent and modify DOM 94 // 3. Fire TextEvent and modify DOM
78 // TODO(chongz): 4. Fire 'input' event 95 // TODO(chongz): 4. Fire 'input' event
79 void insertTextDuringCompositionWithEvents( 96 void insertTextDuringCompositionWithEvents(
80 LocalFrame& frame, 97 LocalFrame& frame,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 132
116 // 'beforeinput' event handler may destroy document. 133 // 'beforeinput' event handler may destroy document.
117 if (!frame.document()) 134 if (!frame.document())
118 return; 135 return;
119 136
120 dispatchCompositionUpdateEvent(frame, text); 137 dispatchCompositionUpdateEvent(frame, text);
121 // 'compositionupdate' event handler may destroy document. 138 // 'compositionupdate' event handler may destroy document.
122 if (!frame.document()) 139 if (!frame.document())
123 return; 140 return;
124 141
142 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
143 // needs to be audited. see http://crbug.com/590369 for more details.
144 frame.document()->updateStyleAndLayoutIgnorePendingStylesheets();
145
146 const bool isIncrementalInsertion = needsIncrementalInsertion(frame, text);
147
125 switch (compositionType) { 148 switch (compositionType) {
126 case TypingCommand::TextCompositionType::TextCompositionUpdate: 149 case TypingCommand::TextCompositionType::TextCompositionUpdate:
150 case TypingCommand::TextCompositionType::TextCompositionConfirm:
chongz 2016/12/02 20:34:44 Sorry for the confusion from https://crbug.com/620
yabinh 2016/12/05 08:09:39 Sorry I still don't understand why we can't switch
chongz 2016/12/05 09:01:46 My concerns are: 1. Moving |TextEvent| into |Typin
127 TypingCommand::insertText(*frame.document(), text, options, 151 TypingCommand::insertText(*frame.document(), text, options,
128 compositionType); 152 compositionType, isIncrementalInsertion);
129 break; 153 break;
130 case TypingCommand::TextCompositionType::TextCompositionConfirm:
131 case TypingCommand::TextCompositionType::TextCompositionCancel: 154 case TypingCommand::TextCompositionType::TextCompositionCancel:
132 // TODO(chongz): Use TypingCommand::insertText after TextEvent was 155 // TODO(chongz): Use TypingCommand::insertText after TextEvent was
133 // removed. (Removed from spec since 2012) 156 // removed. (Removed from spec since 2012)
134 // See TextEvent.idl. 157 // See TextEvent.idl.
135 frame.eventHandler().handleTextInputEvent(text, 0, 158 frame.eventHandler().handleTextInputEvent(text, 0,
136 TextEventInputComposition); 159 TextEventInputComposition);
137 break; 160 break;
138 default: 161 default:
139 NOTREACHED(); 162 NOTREACHED();
140 } 163 }
(...skipping 23 matching lines...) Expand all
164 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); 187 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
165 } 188 }
166 189
167 } // anonymous namespace 190 } // anonymous namespace
168 191
169 InputMethodController* InputMethodController::create(LocalFrame& frame) { 192 InputMethodController* InputMethodController::create(LocalFrame& frame) {
170 return new InputMethodController(frame); 193 return new InputMethodController(frame);
171 } 194 }
172 195
173 InputMethodController::InputMethodController(LocalFrame& frame) 196 InputMethodController::InputMethodController(LocalFrame& frame)
174 : m_frame(&frame), m_isDirty(false), m_hasComposition(false) {} 197 : m_frame(&frame), m_hasComposition(false) {}
175 198
176 InputMethodController::~InputMethodController() = default; 199 InputMethodController::~InputMethodController() = default;
177 200
178 bool InputMethodController::isAvailable() const { 201 bool InputMethodController::isAvailable() const {
179 return frame().document(); 202 return frame().document();
180 } 203 }
181 204
182 Document& InputMethodController::document() const { 205 Document& InputMethodController::document() const {
183 DCHECK(isAvailable()); 206 DCHECK(isAvailable());
184 return *frame().document(); 207 return *frame().document();
185 } 208 }
186 209
187 bool InputMethodController::hasComposition() const { 210 bool InputMethodController::hasComposition() const {
188 return m_hasComposition && !m_compositionRange->collapsed() && 211 return m_hasComposition && !m_compositionRange->collapsed() &&
189 m_compositionRange->isConnected(); 212 m_compositionRange->isConnected();
190 } 213 }
191 214
192 inline Editor& InputMethodController::editor() const { 215 inline Editor& InputMethodController::editor() const {
193 return frame().editor(); 216 return frame().editor();
194 } 217 }
195 218
196 void InputMethodController::clear() { 219 void InputMethodController::clear() {
197 m_hasComposition = false; 220 m_hasComposition = false;
198 if (m_compositionRange) { 221 if (m_compositionRange) {
199 m_compositionRange->setStart(&document(), 0); 222 m_compositionRange->setStart(&document(), 0);
200 m_compositionRange->collapse(true); 223 m_compositionRange->collapse(true);
201 } 224 }
202 document().markers().removeMarkers(DocumentMarker::Composition); 225 document().markers().removeMarkers(DocumentMarker::Composition);
203 m_isDirty = false;
204 } 226 }
205 227
206 void InputMethodController::contextDestroyed() { 228 void InputMethodController::contextDestroyed() {
207 clear(); 229 clear();
208 m_compositionRange = nullptr; 230 m_compositionRange = nullptr;
209 } 231 }
210 232
211 void InputMethodController::documentAttached(Document* document) { 233 void InputMethodController::documentAttached(Document* document) {
212 DCHECK(document); 234 DCHECK(document);
213 setContext(document); 235 setContext(document);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 // duplicate selection change event. 284 // duplicate selection change event.
263 if (!text.length() && !relativeCaretPosition) 285 if (!text.length() && !relativeCaretPosition)
264 return false; 286 return false;
265 return insertTextAndMoveCaret(text, relativeCaretPosition); 287 return insertTextAndMoveCaret(text, relativeCaretPosition);
266 } 288 }
267 289
268 bool InputMethodController::replaceComposition(const String& text) { 290 bool InputMethodController::replaceComposition(const String& text) {
269 if (!hasComposition()) 291 if (!hasComposition())
270 return false; 292 return false;
271 293
272 // If the composition was set from existing text and didn't change, then
273 // there's nothing to do here (and we should avoid doing anything as that
274 // may clobber multi-node styled text).
275 if (!m_isDirty && composingText() == text) {
276 clear();
277 return true;
278 }
279
280 // Select the text that will be deleted or replaced. 294 // Select the text that will be deleted or replaced.
281 selectComposition(); 295 selectComposition();
282 296
283 if (frame().selection().isNone()) 297 if (frame().selection().isNone())
284 return false; 298 return false;
285 299
286 if (!isAvailable()) 300 if (!isAvailable())
287 return false; 301 return false;
288 302
289 // If text is empty, then delete the old composition here. If text is 303 // If text is empty, then delete the old composition here. If text is
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
404 if (!selection.isNone() && !m_compositionRange->collapsed()) { 418 if (!selection.isNone() && !m_compositionRange->collapsed()) {
405 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 && 419 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 &&
406 selection.end().compareTo(m_compositionRange->endPosition()) <= 0) 420 selection.end().compareTo(m_compositionRange->endPosition()) <= 0)
407 return; 421 return;
408 } 422 }
409 423
410 cancelComposition(); 424 cancelComposition();
411 frame().chromeClient().didCancelCompositionOnSelectionChange(); 425 frame().chromeClient().didCancelCompositionOnSelectionChange();
412 } 426 }
413 427
414 static size_t computeCommonPrefixLength(const String& str1,
415 const String& str2) {
416 const size_t maxCommonPrefixLength = std::min(str1.length(), str2.length());
417 for (size_t index = 0; index < maxCommonPrefixLength; ++index) {
418 if (str1[index] != str2[index])
419 return index;
420 }
421 return maxCommonPrefixLength;
422 }
423
424 static size_t computeCommonSuffixLength(const String& str1,
425 const String& str2) {
426 const size_t length1 = str1.length();
427 const size_t length2 = str2.length();
428 const size_t maxCommonSuffixLength = std::min(length1, length2);
429 for (size_t index = 0; index < maxCommonSuffixLength; ++index) {
430 if (str1[length1 - index - 1] != str2[length2 - index - 1])
431 return index;
432 }
433 return maxCommonSuffixLength;
434 }
435
436 // If current position is at grapheme boundary, return 0; otherwise, return the 428 // If current position is at grapheme boundary, return 0; otherwise, return the
437 // distance to its nearest left grapheme boundary. 429 // distance to its nearest left grapheme boundary.
438 static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) { 430 static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) {
439 const Position& adjustedPosition = previousPositionOf( 431 const Position& adjustedPosition = previousPositionOf(
440 nextPositionOf(position, PositionMoveType::GraphemeCluster), 432 nextPositionOf(position, PositionMoveType::GraphemeCluster),
441 PositionMoveType::GraphemeCluster); 433 PositionMoveType::GraphemeCluster);
442 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode()); 434 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
443 DCHECK_GE(position.computeOffsetInContainerNode(), 435 DCHECK_GE(position.computeOffsetInContainerNode(),
444 adjustedPosition.computeOffsetInContainerNode()); 436 adjustedPosition.computeOffsetInContainerNode());
445 return static_cast<size_t>(position.computeOffsetInContainerNode() - 437 return static_cast<size_t>(position.computeOffsetInContainerNode() -
446 adjustedPosition.computeOffsetInContainerNode()); 438 adjustedPosition.computeOffsetInContainerNode());
447 } 439 }
448 440
449 static size_t computeCommonGraphemeClusterPrefixLengthForSetComposition(
450 const String& oldText,
451 const String& newText,
452 const Element* rootEditableElement) {
453 const size_t commonPrefixLength = computeCommonPrefixLength(oldText, newText);
454
455 // For grapheme cluster, we should adjust it for grapheme boundary.
456 const EphemeralRange& range =
457 PlainTextRange(0, commonPrefixLength).createRange(*rootEditableElement);
458 if (range.isNull())
459 return 0;
460 const Position& position = range.endPosition();
461 const size_t diff = computeDistanceToLeftGraphemeBoundary(position);
462 DCHECK_GE(commonPrefixLength, diff);
463 return commonPrefixLength - diff;
464 }
465
466 // If current position is at grapheme boundary, return 0; otherwise, return the 441 // If current position is at grapheme boundary, return 0; otherwise, return the
467 // distance to its nearest right grapheme boundary. 442 // distance to its nearest right grapheme boundary.
468 static size_t computeDistanceToRightGraphemeBoundary(const Position& position) { 443 static size_t computeDistanceToRightGraphemeBoundary(const Position& position) {
469 const Position& adjustedPosition = nextPositionOf( 444 const Position& adjustedPosition = nextPositionOf(
470 previousPositionOf(position, PositionMoveType::GraphemeCluster), 445 previousPositionOf(position, PositionMoveType::GraphemeCluster),
471 PositionMoveType::GraphemeCluster); 446 PositionMoveType::GraphemeCluster);
472 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode()); 447 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
473 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(), 448 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(),
474 position.computeOffsetInContainerNode()); 449 position.computeOffsetInContainerNode());
475 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() - 450 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() -
476 position.computeOffsetInContainerNode()); 451 position.computeOffsetInContainerNode());
477 } 452 }
478 453
479 static size_t computeCommonGraphemeClusterSuffixLengthForSetComposition(
480 const String& oldText,
481 const String& newText,
482 const Element* rootEditableElement) {
483 const size_t commonSuffixLength = computeCommonSuffixLength(oldText, newText);
484
485 // For grapheme cluster, we should adjust it for grapheme boundary.
486 const EphemeralRange& range =
487 PlainTextRange(0, oldText.length() - commonSuffixLength)
488 .createRange(*rootEditableElement);
489 if (range.isNull())
490 return 0;
491 const Position& position = range.endPosition();
492 const size_t diff = computeDistanceToRightGraphemeBoundary(position);
493 DCHECK_GE(commonSuffixLength, diff);
494 return commonSuffixLength - diff;
495 }
496
497 void InputMethodController::setCompositionWithIncrementalText(
498 const String& text,
499 const Vector<CompositionUnderline>& underlines,
500 int selectionStart,
501 int selectionEnd) {
502 Element* editable = frame().selection().rootEditableElement();
503 if (!editable)
504 return;
505
506 DCHECK_LE(selectionStart, selectionEnd);
507 String composing = composingText();
508 const size_t commonPrefixLength =
509 computeCommonGraphemeClusterPrefixLengthForSetComposition(composing, text,
510 editable);
511
512 // We should ignore common prefix when finding common suffix.
513 const size_t commonSuffixLength =
514 computeCommonGraphemeClusterSuffixLengthForSetComposition(
515 composing.right(composing.length() - commonPrefixLength),
516 text.right(text.length() - commonPrefixLength), editable);
517
518 const bool inserting =
519 text.length() > commonPrefixLength + commonSuffixLength;
520 const bool deleting =
521 composing.length() > commonPrefixLength + commonSuffixLength;
522
523 if (inserting || deleting) {
524 // Select the text to be deleted.
525 const size_t compositionStart =
526 PlainTextRange::create(*editable, compositionEphemeralRange()).start();
527 const size_t deletionStart = compositionStart + commonPrefixLength;
528 const size_t deletionEnd =
529 compositionStart + composing.length() - commonSuffixLength;
530 const EphemeralRange& deletionRange =
531 PlainTextRange(deletionStart, deletionEnd).createRange(*editable);
532 Document& currentDocument = document();
533 frame().selection().setSelection(
534 SelectionInDOMTree::Builder().setBaseAndExtent(deletionRange).build(),
535 0);
536 clear();
537
538 // FrameSeleciton::setSelection() can change document associate to |frame|.
539 if (!isAvailable() || currentDocument != document())
540 return;
541 if (!currentDocument.focusedElement())
542 return;
543
544 // Insert the incremental text.
545 const size_t insertionLength =
546 text.length() - commonPrefixLength - commonSuffixLength;
547 const String& insertingText =
548 text.substring(commonPrefixLength, insertionLength);
549 insertTextDuringCompositionWithEvents(frame(), insertingText,
550 TypingCommand::PreventSpellChecking,
551 TypingCommand::TextCompositionUpdate);
552
553 // Event handlers might destroy document.
554 if (!isAvailable() || currentDocument != document())
555 return;
556
557 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
558 // needs to be audited. see http://crbug.com/590369 for more details.
559 document().updateStyleAndLayoutIgnorePendingStylesheets();
560
561 // Now recreate the composition starting at its original start, and
562 // apply the specified final selection offsets.
563 setCompositionFromExistingText(underlines, compositionStart,
564 compositionStart + text.length());
565 }
566
567 selectComposition();
568
569 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
570 // needs to be audited. see http://crbug.com/590369 for more details.
571 document().updateStyleAndLayoutIgnorePendingStylesheets();
572
573 const PlainTextRange& selectedRange = createSelectionRangeForSetComposition(
574 selectionStart, selectionEnd, text.length());
575 // We shouldn't close typing in the middle of setComposition.
576 setEditableSelectionOffsets(selectedRange, NotUserTriggered);
577 m_isDirty = true;
578 }
579
580 void InputMethodController::setComposition( 454 void InputMethodController::setComposition(
581 const String& text, 455 const String& text,
582 const Vector<CompositionUnderline>& underlines, 456 const Vector<CompositionUnderline>& underlines,
583 int selectionStart, 457 int selectionStart,
584 int selectionEnd) { 458 int selectionEnd) {
585 Editor::RevealSelectionScope revealSelectionScope(&editor()); 459 Editor::RevealSelectionScope revealSelectionScope(&editor());
586 460
587 // Updates styles before setting selection for composition to prevent 461 // Updates styles before setting selection for composition to prevent
588 // inserting the previous composition text into text nodes oddly. 462 // inserting the previous composition text into text nodes oddly.
589 // See https://bugs.webkit.org/show_bug.cgi?id=46868 463 // See https://bugs.webkit.org/show_bug.cgi?id=46868
590 document().updateStyleAndLayoutTree(); 464 document().updateStyleAndLayoutTree();
591 465
592 // When the IME only wants to change a few characters at the end of the
593 // composition, only touch those characters in order to preserve rich text
594 // substructure.
595 if (hasComposition() && text.length()) {
596 return setCompositionWithIncrementalText(text, underlines, selectionStart,
597 selectionEnd);
598 }
599
600 selectComposition(); 466 selectComposition();
601 467
602 if (frame().selection().isNone()) 468 if (frame().selection().isNone())
603 return; 469 return;
604 470
605 Element* target = document().focusedElement(); 471 Element* target = document().focusedElement();
606 if (!target) 472 if (!target)
607 return; 473 return;
608 474
609 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 475 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
678 document().updateStyleAndLayoutIgnorePendingStylesheets(); 544 document().updateStyleAndLayoutIgnorePendingStylesheets();
679 545
680 // Find out what node has the composition now. 546 // Find out what node has the composition now.
681 Position base = mostForwardCaretPosition(frame().selection().base()); 547 Position base = mostForwardCaretPosition(frame().selection().base());
682 Node* baseNode = base.anchorNode(); 548 Node* baseNode = base.anchorNode();
683 if (!baseNode || !baseNode->isTextNode()) 549 if (!baseNode || !baseNode->isTextNode())
684 return; 550 return;
685 551
686 Position extent = frame().selection().extent(); 552 Position extent = frame().selection().extent();
687 Node* extentNode = extent.anchorNode(); 553 Node* extentNode = extent.anchorNode();
688 if (baseNode != extentNode)
689 return;
690 554
691 unsigned extentOffset = extent.computeOffsetInContainerNode(); 555 unsigned extentOffset = extent.computeOffsetInContainerNode();
692 unsigned baseOffset = base.computeOffsetInContainerNode(); 556 unsigned baseOffset = base.computeOffsetInContainerNode();
693 if (baseOffset + text.length() != extentOffset)
694 return;
695 557
696 m_isDirty = true;
697 m_hasComposition = true; 558 m_hasComposition = true;
698 if (!m_compositionRange) 559 if (!m_compositionRange)
699 m_compositionRange = Range::create(document()); 560 m_compositionRange = Range::create(document());
700 m_compositionRange->setStart(baseNode, baseOffset); 561 m_compositionRange->setStart(baseNode, baseOffset);
701 m_compositionRange->setEnd(baseNode, extentOffset); 562 m_compositionRange->setEnd(extentNode, extentOffset);
702 563
703 if (baseNode->layoutObject()) 564 if (baseNode->layoutObject())
704 baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); 565 baseNode->layoutObject()->setShouldDoFullPaintInvalidation();
705 566
706 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 567 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
707 // needs to be audited. see http://crbug.com/590369 for more details. 568 // needs to be audited. see http://crbug.com/590369 for more details.
708 document().updateStyleAndLayoutIgnorePendingStylesheets(); 569 document().updateStyleAndLayoutIgnorePendingStylesheets();
709 570
710 // We shouldn't close typing in the middle of setComposition. 571 // We shouldn't close typing in the middle of setComposition.
711 setEditableSelectionOffsets(selectedRange, NotUserTriggered); 572 setEditableSelectionOffsets(selectedRange, NotUserTriggered);
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after
1193 return WebTextInputTypeNone; 1054 return WebTextInputTypeNone;
1194 } 1055 }
1195 1056
1196 DEFINE_TRACE(InputMethodController) { 1057 DEFINE_TRACE(InputMethodController) {
1197 visitor->trace(m_frame); 1058 visitor->trace(m_frame);
1198 visitor->trace(m_compositionRange); 1059 visitor->trace(m_compositionRange);
1199 SynchronousMutationObserver::trace(visitor); 1060 SynchronousMutationObserver::trace(visitor);
1200 } 1061 }
1201 1062
1202 } // namespace blink 1063 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698