OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |