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

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

Issue 2372493002: Workaround for setComposition styling clobber (Closed)
Patch Set: test Created 4 years, 2 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
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 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 if (!selection.isNone() && !m_compositionRange->collapsed()) { 331 if (!selection.isNone() && !m_compositionRange->collapsed()) {
332 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0 332 if (selection.start().compareTo(m_compositionRange->startPosition()) >= 0
333 && selection.end().compareTo(m_compositionRange->endPosition()) <= 0 ) 333 && selection.end().compareTo(m_compositionRange->endPosition()) <= 0 )
334 return; 334 return;
335 } 335 }
336 336
337 cancelComposition(); 337 cancelComposition();
338 frame().chromeClient().didCancelCompositionOnSelectionChange(); 338 frame().chromeClient().didCancelCompositionOnSelectionChange();
339 } 339 }
340 340
341 static size_t computeCommonPrefixLength(const String& str1, const String& str2)
342 {
343 size_t commonPrefixLength = 0;
344 size_t length1 = str1.length();
345 size_t length2 = str2.length();
346 while (commonPrefixLength < length1 && commonPrefixLength < length2 && str1[ commonPrefixLength] == str2[commonPrefixLength])
Changwan Ryu 2016/09/27 05:23:03 Can you skip a loop for surrogate pairs? Things ca
yabinh 2016/09/27 08:47:20 Done.
347 commonPrefixLength++;
348 return commonPrefixLength;
349 }
350
341 void InputMethodController::setComposition(const String& text, const Vector<Comp ositionUnderline>& underlines, int selectionStart, int selectionEnd) 351 void InputMethodController::setComposition(const String& text, const Vector<Comp ositionUnderline>& underlines, int selectionStart, int selectionEnd)
342 { 352 {
343 Editor::RevealSelectionScope revealSelectionScope(&editor()); 353 Editor::RevealSelectionScope revealSelectionScope(&editor());
344 354
345 // Updates styles before setting selection for composition to prevent 355 // Updates styles before setting selection for composition to prevent
346 // inserting the previous composition text into text nodes oddly. 356 // inserting the previous composition text into text nodes oddly.
347 // See https://bugs.webkit.org/show_bug.cgi?id=46868 357 // See https://bugs.webkit.org/show_bug.cgi?id=46868
348 frame().document()->updateStyleAndLayoutTree(); 358 frame().document()->updateStyleAndLayoutTree();
349 359
360 // When the IME only wants to change a few characters at the end of the
361 // composition, only touch those characters in order to preserve rich text
362 // substructure.
363 if (hasComposition() && text.length()) {
364 String composing = composingText();
365 size_t commonPrefixLength = computeCommonPrefixLength(composing, text);
366
367 bool appending = text.length() > commonPrefixLength;
368 bool backspacing = composing.length() > commonPrefixLength;
369 if (appending || backspacing) {
370 const EphemeralRange range = compositionEphemeralRange();
371 Element* editable = frame().selection().rootEditableElement();
372 if (!editable)
373 return;
374
375 // Move selection to the end of the composition.
376 PlainTextRange compositionPlainOffsets = PlainTextRange::create(*edi table, range);
377 VisibleSelection selection;
378 selection.setWithoutValidation(range.endPosition(), range.endPositio n());
379 frame().selection().setSelection(selection, 0);
380 clear();
381
382 Element* target = frame().document()->focusedElement();
383 if (!target)
384 return;
385
386 // Apply the incremental change.
387 if (backspacing)
388 extendSelectionAndDelete(composing.length() - commonPrefixLength , 0);
aelias_OOO_until_Jul13 2016/09/27 04:55:58 Hmm, this has the same JS event problem as the oth
yabinh 2016/09/27 08:47:20 Done.
389 if (appending)
390 insertTextDuringCompositionWithEvents(frame(), text.substring(co mmonPrefixLength), TypingCommand::PreventSpellChecking, TypingCommand::TextCompo sitionUpdate);
391
392 // Event handlers might destroy document.
393 if (!frame().document())
394 return;
395
396 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStyleshe ets
397 // needs to be audited. see http://crbug.com/590369 for more details .
398 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
399
400 // Now recreate the composition starting at its original start, and
401 // apply the specified final selection offsets.
402 setCompositionFromExistingText(underlines, compositionPlainOffsets.s tart(), compositionPlainOffsets.start() + text.length());
403 selectComposition();
404 PlainTextRange selectedRange = createSelectionRangeForSetComposition (selectionStart, selectionEnd, text.length());
405 // We shouldn't close typing in the middle of setComposition.
406 setEditableSelectionOffsets(selectedRange, NotUserTriggered);
407 m_isDirty = true;
408 return;
409 }
410 }
411
350 selectComposition(); 412 selectComposition();
351 413
352 if (frame().selection().isNone()) 414 if (frame().selection().isNone())
353 return; 415 return;
354 416
355 Element* target = frame().document()->focusedElement(); 417 Element* target = frame().document()->focusedElement();
356 if (!target) 418 if (!target)
357 return; 419 return;
358 420
359 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 421 PlainTextRange selectedRange = createSelectionRangeForSetComposition(selecti onStart, selectionEnd, text.length());
360 // needs to be audited. see http://crbug.com/590369 for more details.
361 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
362
363 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start());
364 int start = selectionOffsetsStart + selectionStart;
365 int end = selectionOffsetsStart + selectionEnd;
366 PlainTextRange selectedRange = createRangeForSelection(start, end, text.leng th());
367 422
368 // Dispatch an appropriate composition event to the focused node. 423 // Dispatch an appropriate composition event to the focused node.
369 // We check the composition status and choose an appropriate composition eve nt since this 424 // We check the composition status and choose an appropriate composition eve nt since this
370 // function is used for three purposes: 425 // function is used for three purposes:
371 // 1. Starting a new composition. 426 // 1. Starting a new composition.
372 // Send a compositionstart and a compositionupdate event when this functi on creates 427 // Send a compositionstart and a compositionupdate event when this functi on creates
373 // a new composition node, i.e. 428 // a new composition node, i.e.
374 // !hasComposition() && !text.isEmpty(). 429 // !hasComposition() && !text.isEmpty().
375 // Sending a compositionupdate event at this time ensures that at least o ne 430 // Sending a compositionupdate event at this time ensures that at least o ne
376 // compositionupdate event is dispatched. 431 // compositionupdate event is dispatched.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 for (const auto& underline : underlines) { 514 for (const auto& underline : underlines) {
460 unsigned underlineStart = baseOffset + underline.startOffset(); 515 unsigned underlineStart = baseOffset + underline.startOffset();
461 unsigned underlineEnd = baseOffset + underline.endOffset(); 516 unsigned underlineEnd = baseOffset + underline.endOffset();
462 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd)); 517 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd));
463 if (ephemeralLineRange.isNull()) 518 if (ephemeralLineRange.isNull())
464 continue; 519 continue;
465 frame().document()->markers().addCompositionMarker(ephemeralLineRange.st artPosition(), ephemeralLineRange.endPosition(), underline.color(), underline.th ick(), underline.backgroundColor()); 520 frame().document()->markers().addCompositionMarker(ephemeralLineRange.st artPosition(), ephemeralLineRange.endPosition(), underline.color(), underline.th ick(), underline.backgroundColor());
466 } 521 }
467 } 522 }
468 523
524 PlainTextRange InputMethodController::createSelectionRangeForSetComposition(int selectionStart, int selectionEnd, size_t textLength) const
525 {
526 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
527 // needs to be audited. see http://crbug.com/590369 for more details.
528 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
529
530 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start());
531 int start = selectionOffsetsStart + selectionStart;
532 int end = selectionOffsetsStart + selectionEnd;
533 return createRangeForSelection(start, end, textLength);
534 }
535
469 void InputMethodController::setCompositionFromExistingText(const Vector<Composit ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd) 536 void InputMethodController::setCompositionFromExistingText(const Vector<Composit ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd)
470 { 537 {
471 Element* editable = frame().selection().rootEditableElement(); 538 Element* editable = frame().selection().rootEditableElement();
472 if (!editable) 539 if (!editable)
473 return; 540 return;
474 541
475 DCHECK(!editable->document().needsLayoutTreeUpdate()); 542 DCHECK(!editable->document().needsLayoutTreeUpdate());
476 543
477 const EphemeralRange range = PlainTextRange(compositionStart, compositionEnd ).createRange(*editable); 544 const EphemeralRange range = PlainTextRange(compositionStart, compositionEnd ).createRange(*editable);
478 if (range.isNull()) 545 if (range.isNull())
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 TypingCommand::deleteSelection(*frame().document()); 696 TypingCommand::deleteSelection(*frame().document());
630 } 697 }
631 698
632 DEFINE_TRACE(InputMethodController) 699 DEFINE_TRACE(InputMethodController)
633 { 700 {
634 visitor->trace(m_frame); 701 visitor->trace(m_frame);
635 visitor->trace(m_compositionRange); 702 visitor->trace(m_compositionRange);
636 } 703 }
637 704
638 } // namespace blink 705 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698