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

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

Issue 2465743002: Trybot test for losing style (Closed)
Patch Set: donnot clear 14:38 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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 << "compositionType should be TextCompositionUpdate or " 90 << "compositionType should be TextCompositionUpdate or "
91 "TextCompositionConfirm or TextCompositionCancel, but got " 91 "TextCompositionConfirm or TextCompositionCancel, but got "
92 << static_cast<int>(compositionType); 92 << static_cast<int>(compositionType);
93 if (!frame.document()) 93 if (!frame.document())
94 return; 94 return;
95 95
96 Element* target = frame.document()->focusedElement(); 96 Element* target = frame.document()->focusedElement();
97 if (!target) 97 if (!target)
98 return; 98 return;
99 99
100 // LOG(ERROR)<<"aba: tagName:"<<target->tagName().utf8().data();
101 // LOG(ERROR)<<"aba: oldText:"<<oldText.utf8().data();
102 /*
103 String oldText2 = oldText;
104 // No need to preserve style for 'input' element, so we can delete the
105 // existing composition and insert new text.
106 if(target->tagName() == String("INPUT"))
107 oldText2 = emptyString();
108
109 if(!newText.isEmpty() && !oldText2.isEmpty()) {
110 DCHECK(oldText2 == frame.selectedText())<<"oldText:["<<oldText.utf8().data()
111 <<"] selected:["<<frame.selectedText().utf8().data()<<"]";
112 }
113
114 */
100 // TODO(chongz): Fire 'beforeinput' for the composed text being 115 // TODO(chongz): Fire 'beforeinput' for the composed text being
101 // replaced/deleted. 116 // replaced/deleted.
102 117
103 // Only the last confirmed text is cancelable. 118 // Only the last confirmed text is cancelable.
104 InputEvent::EventCancelable beforeInputCancelable = 119 InputEvent::EventCancelable beforeInputCancelable =
105 (compositionType == 120 (compositionType ==
106 TypingCommand::TextCompositionType::TextCompositionUpdate) 121 TypingCommand::TextCompositionType::TextCompositionUpdate)
107 ? InputEvent::EventCancelable::NotCancelable 122 ? InputEvent::EventCancelable::NotCancelable
108 : InputEvent::EventCancelable::IsCancelable; 123 : InputEvent::EventCancelable::IsCancelable;
109 DispatchEventResult result = dispatchBeforeInputFromComposition( 124 DispatchEventResult result = dispatchBeforeInputFromComposition(
110 target, InputEvent::InputType::InsertText, text, beforeInputCancelable); 125 target, InputEvent::InputType::InsertText, text, beforeInputCancelable);
111 126
112 if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable && 127 if (beforeInputCancelable == InputEvent::EventCancelable::IsCancelable &&
113 result != DispatchEventResult::NotCanceled) 128 result != DispatchEventResult::NotCanceled)
114 return; 129 return;
115 130
116 // 'beforeinput' event handler may destroy document. 131 // 'beforeinput' event handler may destroy document.
117 if (!frame.document()) 132 if (!frame.document())
118 return; 133 return;
119 134
120 dispatchCompositionUpdateEvent(frame, text); 135 dispatchCompositionUpdateEvent(frame, text);
121 // 'compositionupdate' event handler may destroy document. 136 // 'compositionupdate' event handler may destroy document.
122 if (!frame.document()) 137 if (!frame.document())
123 return; 138 return;
124 139
140 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
141 // needs to be audited. see http://crbug.com/590369 for more details.
142 frame.document()->updateStyleAndLayoutIgnorePendingStylesheets();
143
144 // needIncrementalInsertion?
145 const bool isIncrementalInsertion =
146 !frame.selectedText().isEmpty() && !text.isEmpty();
147 // or
148 // !frame.selectedText().isEmpty();
149 // patch set 30 works...
150
125 switch (compositionType) { 151 switch (compositionType) {
126 case TypingCommand::TextCompositionType::TextCompositionUpdate: 152 case TypingCommand::TextCompositionType::TextCompositionUpdate:
153 case TypingCommand::TextCompositionType::TextCompositionConfirm:
127 TypingCommand::insertText(*frame.document(), text, options, 154 TypingCommand::insertText(*frame.document(), text, options,
128 compositionType); 155 compositionType, isIncrementalInsertion);
129 break; 156 break;
130 case TypingCommand::TextCompositionType::TextCompositionConfirm:
131 case TypingCommand::TextCompositionType::TextCompositionCancel: 157 case TypingCommand::TextCompositionType::TextCompositionCancel:
132 // TODO(chongz): Use TypingCommand::insertText after TextEvent was 158 // TODO(chongz): Use TypingCommand::insertText after TextEvent was
133 // removed. (Removed from spec since 2012) 159 // removed. (Removed from spec since 2012)
134 // See TextEvent.idl. 160 // See TextEvent.idl.
135 frame.eventHandler().handleTextInputEvent(text, 0, 161 frame.eventHandler().handleTextInputEvent(text, 0,
136 TextEventInputComposition); 162 TextEventInputComposition);
137 break; 163 break;
138 default: 164 default:
139 NOTREACHED(); 165 NOTREACHED();
140 } 166 }
(...skipping 23 matching lines...) Expand all
164 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower(); 190 return element->fastGetAttribute(HTMLNames::inputmodeAttr).lower();
165 } 191 }
166 192
167 } // anonymous namespace 193 } // anonymous namespace
168 194
169 InputMethodController* InputMethodController::create(LocalFrame& frame) { 195 InputMethodController* InputMethodController::create(LocalFrame& frame) {
170 return new InputMethodController(frame); 196 return new InputMethodController(frame);
171 } 197 }
172 198
173 InputMethodController::InputMethodController(LocalFrame& frame) 199 InputMethodController::InputMethodController(LocalFrame& frame)
174 : m_frame(&frame), m_isDirty(false), m_hasComposition(false) {} 200 : m_frame(&frame), m_hasComposition(false) {}
175 201
176 InputMethodController::~InputMethodController() = default; 202 InputMethodController::~InputMethodController() = default;
177 203
178 bool InputMethodController::isAvailable() const { 204 bool InputMethodController::isAvailable() const {
179 return frame().document(); 205 return frame().document();
180 } 206 }
181 207
182 Document& InputMethodController::document() const { 208 Document& InputMethodController::document() const {
183 DCHECK(isAvailable()); 209 DCHECK(isAvailable());
184 return *frame().document(); 210 return *frame().document();
185 } 211 }
186 212
187 bool InputMethodController::hasComposition() const { 213 bool InputMethodController::hasComposition() const {
188 return m_hasComposition && !m_compositionRange->collapsed() && 214 return m_hasComposition && !m_compositionRange->collapsed() &&
189 m_compositionRange->isConnected(); 215 m_compositionRange->isConnected();
190 } 216 }
191 217
192 inline Editor& InputMethodController::editor() const { 218 inline Editor& InputMethodController::editor() const {
193 return frame().editor(); 219 return frame().editor();
194 } 220 }
195 221
196 void InputMethodController::clear() { 222 void InputMethodController::clear() {
197 m_hasComposition = false; 223 m_hasComposition = false;
198 if (m_compositionRange) { 224 if (m_compositionRange) {
199 m_compositionRange->setStart(&document(), 0); 225 m_compositionRange->setStart(&document(), 0);
200 m_compositionRange->collapse(true); 226 m_compositionRange->collapse(true);
201 } 227 }
202 document().markers().removeMarkers(DocumentMarker::Composition); 228 document().markers().removeMarkers(DocumentMarker::Composition);
203 m_isDirty = false;
204 } 229 }
205 230
206 void InputMethodController::contextDestroyed() { 231 void InputMethodController::contextDestroyed() {
207 clear(); 232 clear();
208 m_compositionRange = nullptr; 233 m_compositionRange = nullptr;
209 } 234 }
210 235
211 void InputMethodController::documentAttached(Document* document) { 236 void InputMethodController::documentAttached(Document* document) {
212 DCHECK(document); 237 DCHECK(document);
213 setContext(document); 238 setContext(document);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 // duplicate selection change event. 287 // duplicate selection change event.
263 if (!text.length() && !relativeCaretPosition) 288 if (!text.length() && !relativeCaretPosition)
264 return false; 289 return false;
265 return insertTextAndMoveCaret(text, relativeCaretPosition); 290 return insertTextAndMoveCaret(text, relativeCaretPosition);
266 } 291 }
267 292
268 bool InputMethodController::replaceComposition(const String& text) { 293 bool InputMethodController::replaceComposition(const String& text) {
269 if (!hasComposition()) 294 if (!hasComposition())
270 return false; 295 return false;
271 296
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. 297 // Select the text that will be deleted or replaced.
281 selectComposition(); 298 selectComposition();
282 299
283 if (frame().selection().isNone()) 300 if (frame().selection().isNone())
284 return false; 301 return false;
285 302
286 if (!isAvailable()) 303 if (!isAvailable())
287 return false; 304 return false;
288 305
306 // ???
307 // clear(); // do we need clear???
yabinh 2017/02/08 09:59:59 It turns out that we should clear.
308
289 // If text is empty, then delete the old composition here. If text is 309 // If text is empty, then delete the old composition here. If text is
290 // non-empty, InsertTextCommand::input will delete the old composition with 310 // non-empty, InsertTextCommand::input will delete the old composition with
291 // an optimized replace operation. 311 // an optimized replace operation.
292 if (text.isEmpty()) 312 if (text.isEmpty()) {
293 TypingCommand::deleteSelection(document(), 0); 313 TypingCommand::deleteSelection(document(), 0);
294 314
295 clear(); 315 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
316 // needs to be audited. see http://crbug.com/590369 for more details.
317 document().updateStyleAndLayoutIgnorePendingStylesheets();
318 }
296 319
320 // LOG(ERROR) << "hyb: frame().selectedText():"
321 //<< frame().selectedText().utf8().data();
297 insertTextDuringCompositionWithEvents( 322 insertTextDuringCompositionWithEvents(
298 frame(), text, 0, 323 frame(), text, 0,
299 TypingCommand::TextCompositionType::TextCompositionConfirm); 324 TypingCommand::TextCompositionType::TextCompositionConfirm);
300 // Event handler might destroy document. 325 // Event handler might destroy document.
301 if (!isAvailable()) 326 if (!isAvailable())
302 return false; 327 return false;
303 328
304 return true; 329 return true;
305 } 330 }
306 331
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 return; 398 return;
374 399
375 clear(); 400 clear();
376 401
377 // TODO(chongz): Figure out which InputType should we use here. 402 // TODO(chongz): Figure out which InputType should we use here.
378 dispatchBeforeInputFromComposition( 403 dispatchBeforeInputFromComposition(
379 document().focusedElement(), 404 document().focusedElement(),
380 InputEvent::InputType::DeleteComposedCharacterBackward, nullAtom, 405 InputEvent::InputType::DeleteComposedCharacterBackward, nullAtom,
381 InputEvent::EventCancelable::NotCancelable); 406 InputEvent::EventCancelable::NotCancelable);
382 dispatchCompositionUpdateEvent(frame(), emptyString()); 407 dispatchCompositionUpdateEvent(frame(), emptyString());
408
409 // LOG(ERROR) << "hyb: frame().selectedText():"
410 //<< frame().selectedText().utf8().data();
383 insertTextDuringCompositionWithEvents( 411 insertTextDuringCompositionWithEvents(
384 frame(), emptyString(), 0, 412 frame(), emptyString(), 0,
385 TypingCommand::TextCompositionType::TextCompositionCancel); 413 TypingCommand::TextCompositionType::TextCompositionCancel);
386 // Event handler might destroy document. 414 // Event handler might destroy document.
387 if (!isAvailable()) 415 if (!isAvailable())
388 return; 416 return;
389 417
390 // An open typing command that disagrees about current selection would cause 418 // An open typing command that disagrees about current selection would cause
391 // issues with typing later on. 419 // issues with typing later on.
392 TypingCommand::closeTyping(m_frame); 420 TypingCommand::closeTyping(m_frame);
(...skipping 11 matching lines...) Expand all
404 if (!selection.isNone() && !m_compositionRange->collapsed()) { 432 if (!selection.isNone() && !m_compositionRange->collapsed()) {
405 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 && 433 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 &&
406 selection.end().compareTo(m_compositionRange->endPosition()) <= 0) 434 selection.end().compareTo(m_compositionRange->endPosition()) <= 0)
407 return; 435 return;
408 } 436 }
409 437
410 cancelComposition(); 438 cancelComposition();
411 frame().chromeClient().didCancelCompositionOnSelectionChange(); 439 frame().chromeClient().didCancelCompositionOnSelectionChange();
412 } 440 }
413 441
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 442 // If current position is at grapheme boundary, return 0; otherwise, return the
437 // distance to its nearest left grapheme boundary. 443 // distance to its nearest left grapheme boundary.
438 static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) { 444 static size_t computeDistanceToLeftGraphemeBoundary(const Position& position) {
439 const Position& adjustedPosition = previousPositionOf( 445 const Position& adjustedPosition = previousPositionOf(
440 nextPositionOf(position, PositionMoveType::GraphemeCluster), 446 nextPositionOf(position, PositionMoveType::GraphemeCluster),
441 PositionMoveType::GraphemeCluster); 447 PositionMoveType::GraphemeCluster);
442 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode()); 448 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
443 DCHECK_GE(position.computeOffsetInContainerNode(), 449 DCHECK_GE(position.computeOffsetInContainerNode(),
444 adjustedPosition.computeOffsetInContainerNode()); 450 adjustedPosition.computeOffsetInContainerNode());
445 return static_cast<size_t>(position.computeOffsetInContainerNode() - 451 return static_cast<size_t>(position.computeOffsetInContainerNode() -
446 adjustedPosition.computeOffsetInContainerNode()); 452 adjustedPosition.computeOffsetInContainerNode());
447 } 453 }
448 454
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 455 // If current position is at grapheme boundary, return 0; otherwise, return the
467 // distance to its nearest right grapheme boundary. 456 // distance to its nearest right grapheme boundary.
468 static size_t computeDistanceToRightGraphemeBoundary(const Position& position) { 457 static size_t computeDistanceToRightGraphemeBoundary(const Position& position) {
469 const Position& adjustedPosition = nextPositionOf( 458 const Position& adjustedPosition = nextPositionOf(
470 previousPositionOf(position, PositionMoveType::GraphemeCluster), 459 previousPositionOf(position, PositionMoveType::GraphemeCluster),
471 PositionMoveType::GraphemeCluster); 460 PositionMoveType::GraphemeCluster);
472 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode()); 461 DCHECK_EQ(position.anchorNode(), adjustedPosition.anchorNode());
473 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(), 462 DCHECK_GE(adjustedPosition.computeOffsetInContainerNode(),
474 position.computeOffsetInContainerNode()); 463 position.computeOffsetInContainerNode());
475 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() - 464 return static_cast<size_t>(adjustedPosition.computeOffsetInContainerNode() -
476 position.computeOffsetInContainerNode()); 465 position.computeOffsetInContainerNode());
477 } 466 }
478 467
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( 468 void InputMethodController::setComposition(
581 const String& text, 469 const String& text,
582 const Vector<CompositionUnderline>& underlines, 470 const Vector<CompositionUnderline>& underlines,
583 int selectionStart, 471 int selectionStart,
584 int selectionEnd) { 472 int selectionEnd) {
585 Editor::RevealSelectionScope revealSelectionScope(&editor()); 473 Editor::RevealSelectionScope revealSelectionScope(&editor());
586 474
587 // Updates styles before setting selection for composition to prevent 475 // Updates styles before setting selection for composition to prevent
588 // inserting the previous composition text into text nodes oddly. 476 // inserting the previous composition text into text nodes oddly.
589 // See https://bugs.webkit.org/show_bug.cgi?id=46868 477 // See https://bugs.webkit.org/show_bug.cgi?id=46868
590 document().updateStyleAndLayoutTree(); 478 document().updateStyleAndLayoutTree();
591 479
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(); 480 selectComposition();
601 481
602 if (frame().selection().isNone()) 482 if (frame().selection().isNone())
603 return; 483 return;
604 484
605 Element* target = document().focusedElement(); 485 Element* target = document().focusedElement();
606 if (!target) 486 if (!target)
607 return; 487 return;
608 488
609 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 489 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
656 if (!hasComposition()) { 536 if (!hasComposition()) {
657 target->dispatchEvent( 537 target->dispatchEvent(
658 CompositionEvent::create(EventTypeNames::compositionstart, 538 CompositionEvent::create(EventTypeNames::compositionstart,
659 frame().domWindow(), frame().selectedText())); 539 frame().domWindow(), frame().selectedText()));
660 if (!isAvailable()) 540 if (!isAvailable())
661 return; 541 return;
662 } 542 }
663 543
664 DCHECK(!text.isEmpty()); 544 DCHECK(!text.isEmpty());
665 545
546 // const String& composing = composingText();
666 clear(); 547 clear();
667 548
549 // LOG(ERROR) << "hyb: frame().selectedText():"
550 //<< frame().selectedText().utf8().data();
668 insertTextDuringCompositionWithEvents( 551 insertTextDuringCompositionWithEvents(
669 frame(), text, 552 frame(), text,
670 TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking, 553 TypingCommand::SelectInsertedText | TypingCommand::PreventSpellChecking,
671 TypingCommand::TextCompositionUpdate); 554 TypingCommand::TextCompositionUpdate);
672 // Event handlers might destroy document. 555 // Event handlers might destroy document.
673 if (!isAvailable()) 556 if (!isAvailable())
674 return; 557 return;
675 558
676 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets 559 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
677 // needs to be audited. see http://crbug.com/590369 for more details. 560 // needs to be audited. see http://crbug.com/590369 for more details.
678 document().updateStyleAndLayoutIgnorePendingStylesheets(); 561 document().updateStyleAndLayoutIgnorePendingStylesheets();
679 562
680 // Find out what node has the composition now. 563 // Find out what node has the composition now.
681 Position base = mostForwardCaretPosition(frame().selection().base()); 564 Position base = mostForwardCaretPosition(frame().selection().base());
682 Node* baseNode = base.anchorNode(); 565 Node* baseNode = base.anchorNode();
683 if (!baseNode || !baseNode->isTextNode()) 566 if (!baseNode || !baseNode->isTextNode())
684 return; 567 return;
685 568
686 Position extent = frame().selection().extent(); 569 Position extent = frame().selection().extent();
687 Node* extentNode = extent.anchorNode(); 570 Node* extentNode = extent.anchorNode();
688 if (baseNode != extentNode)
689 return;
690 571
691 unsigned extentOffset = extent.computeOffsetInContainerNode(); 572 unsigned extentOffset = extent.computeOffsetInContainerNode();
692 unsigned baseOffset = base.computeOffsetInContainerNode(); 573 unsigned baseOffset = base.computeOffsetInContainerNode();
693 if (baseOffset + text.length() != extentOffset)
694 return;
695 574
696 m_isDirty = true;
697 m_hasComposition = true; 575 m_hasComposition = true;
698 if (!m_compositionRange) 576 if (!m_compositionRange)
699 m_compositionRange = Range::create(document()); 577 m_compositionRange = Range::create(document());
700 m_compositionRange->setStart(baseNode, baseOffset); 578 m_compositionRange->setStart(baseNode, baseOffset);
701 m_compositionRange->setEnd(baseNode, extentOffset); 579 m_compositionRange->setEnd(extentNode, extentOffset);
702 580
703 if (baseNode->layoutObject()) 581 if (baseNode->layoutObject())
704 baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); 582 baseNode->layoutObject()->setShouldDoFullPaintInvalidation();
705 583
706 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 584 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
707 // needs to be audited. see http://crbug.com/590369 for more details. 585 // needs to be audited. see http://crbug.com/590369 for more details.
708 document().updateStyleAndLayoutIgnorePendingStylesheets(); 586 document().updateStyleAndLayoutIgnorePendingStylesheets();
709 587
710 // We shouldn't close typing in the middle of setComposition. 588 // We shouldn't close typing in the middle of setComposition.
711 setEditableSelectionOffsets(selectedRange, NotUserTriggered); 589 setEditableSelectionOffsets(selectedRange, NotUserTriggered);
(...skipping 481 matching lines...) Expand 10 before | Expand all | Expand 10 after
1193 return WebTextInputTypeNone; 1071 return WebTextInputTypeNone;
1194 } 1072 }
1195 1073
1196 DEFINE_TRACE(InputMethodController) { 1074 DEFINE_TRACE(InputMethodController) {
1197 visitor->trace(m_frame); 1075 visitor->trace(m_frame);
1198 visitor->trace(m_compositionRange); 1076 visitor->trace(m_compositionRange);
1199 SynchronousMutationObserver::trace(visitor); 1077 SynchronousMutationObserver::trace(visitor);
1200 } 1078 }
1201 1079
1202 } // namespace blink 1080 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698