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

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

Issue 2372493002: Workaround for setComposition styling clobber (Closed)
Patch Set: Address changwan@'s review 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 size_t InputMethodController::computeCommonGraphemeClusterPrefixLengthForSetComp osition(const String& newText) const
342 {
343 String oldText = composingText();
344 size_t oldLength = oldText.length();
345 size_t newLength = newText.length();
346 size_t commonPrefixLength = 0;
347
348 while (commonPrefixLength < oldLength && commonPrefixLength < newLength && o ldText[commonPrefixLength] == newText[commonPrefixLength])
yosin_UTC9 2016/10/04 09:00:05 Could you move this part to another function, e.g.
yabinh 2016/10/11 01:42:19 Done.
349 commonPrefixLength++;
yosin_UTC9 2016/10/04 09:00:05 nit: We prefer |++commonPrefixLength|
yabinh 2016/10/11 01:42:22 Done.
350
351 // For multi-code text, we should adjust it for grapheme boundary.
352 Element* rootEditableElement = frame().selection().rootEditableElement();
353 if (!rootEditableElement)
354 return 0;
355 const EphemeralRange range = PlainTextRange(0, commonPrefixLength).createRan ge(*rootEditableElement);
yosin_UTC9 2016/10/04 09:00:05 nit: s/const EphemeralRange/const EphemeralRange&/
yabinh 2016/10/11 01:42:19 Done.
356 if (range.isNull())
357 return 0;
358 Position position = range.endPosition();
yosin_UTC9 2016/10/04 09:00:05 nit: s/Position/const Position&/
yabinh 2016/10/11 01:42:22 Done.
359 Position adjustedPosition = previousPositionOf(nextPositionOf(position, Posi tionMoveType::GraphemeCluster), PositionMoveType::GraphemeCluster);
yosin_UTC9 2016/10/04 09:00:05 nit: s/Position/const Position&/
yabinh 2016/10/11 01:42:19 Done.
360 int diff = position.computeOffsetInContainerNode() - adjustedPosition.comput eOffsetInContainerNode();
yosin_UTC9 2016/10/04 09:00:05 We should support position.containerNode() != adju
yabinh 2016/10/11 01:42:19 It seems that we couldn't find such a case. As we
361
362 return commonPrefixLength - static_cast<size_t>(diff);
363 }
364
341 void InputMethodController::setComposition(const String& text, const Vector<Comp ositionUnderline>& underlines, int selectionStart, int selectionEnd) 365 void InputMethodController::setComposition(const String& text, const Vector<Comp ositionUnderline>& underlines, int selectionStart, int selectionEnd)
342 { 366 {
343 Editor::RevealSelectionScope revealSelectionScope(&editor()); 367 Editor::RevealSelectionScope revealSelectionScope(&editor());
344 368
345 // Updates styles before setting selection for composition to prevent 369 // Updates styles before setting selection for composition to prevent
346 // inserting the previous composition text into text nodes oddly. 370 // inserting the previous composition text into text nodes oddly.
347 // See https://bugs.webkit.org/show_bug.cgi?id=46868 371 // See https://bugs.webkit.org/show_bug.cgi?id=46868
348 frame().document()->updateStyleAndLayoutTree(); 372 frame().document()->updateStyleAndLayoutTree();
349 373
374 // When the IME only wants to change a few characters at the end of the
375 // composition, only touch those characters in order to preserve rich text
376 // substructure.
377 if (hasComposition() && text.length()) {
378 size_t composingLength = composingText().length();
yosin_UTC9 2016/10/04 09:00:05 Please move this part to another function. This pa
yabinh 2016/10/11 01:42:22 Done.
379 size_t commonPrefixLength = computeCommonGraphemeClusterPrefixLengthForS etComposition(text);
380
381 bool appending = text.length() > commonPrefixLength;
yosin_UTC9 2016/10/04 09:00:05 nit: s/bool/const bool/
yabinh 2016/10/11 01:42:21 Done.
382 bool backspacing = composingLength > commonPrefixLength;
yosin_UTC9 2016/10/04 09:00:05 nit: s/bool/const bool/; since this variable used
yabinh 2016/10/11 01:42:20 Done.
383 if (appending || backspacing) {
384 const EphemeralRange range = compositionEphemeralRange();
yosin_UTC9 2016/10/04 09:00:05 s/const EphemeralRange/const EphemeralRange&/ Bet
yabinh 2016/10/11 01:42:21 Done.
385 Element* editable = frame().selection().rootEditableElement();
386 if (!editable)
387 return;
388
389 // Move selection to the end of the composition.
390 PlainTextRange compositionPlainOffsets = PlainTextRange::create(*edi table, range);
391 VisibleSelection selection;
392 selection.setWithoutValidation(range.endPosition(), range.endPositio n());
393 frame().selection().setSelection(selection, 0);
394 clear();
395
396 Element* target = frame().document()->focusedElement();
397 if (!target)
398 return;
399
400 // Apply the incremental change. Select the text to be deleted (if
401 // needed) and replace it with the incremental text (or empty text).
402 if (backspacing) {
403 PlainTextRange selectionOffsets(getSelectionOffsets());
404 size_t deletedLength = composingLength - commonPrefixLength;
405 setEditableSelectionOffsets(PlainTextRange(selectionOffsets.star t() - deletedLength, selectionOffsets.end()), NotUserTriggered);
406 }
407 insertTextDuringCompositionWithEvents(frame(), text.substring(common PrefixLength), TypingCommand::PreventSpellChecking, TypingCommand::TextCompositi onUpdate);
408
409 // Event handlers might destroy document.
410 if (!frame().document())
411 return;
412
413 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStyleshe ets
414 // needs to be audited. see http://crbug.com/590369 for more details .
415 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
416
417 // Now recreate the composition starting at its original start, and
418 // apply the specified final selection offsets.
419 setCompositionFromExistingText(underlines, compositionPlainOffsets.s tart(), compositionPlainOffsets.start() + text.length());
420 selectComposition();
421 PlainTextRange selectedRange = createSelectionRangeForSetComposition (selectionStart, selectionEnd, text.length());
yosin_UTC9 2016/10/04 09:00:05 nit: s/PalinTextRange/const PlainTextRange&/
yabinh 2016/10/11 01:42:22 Done.
422 // We shouldn't close typing in the middle of setComposition.
423 setEditableSelectionOffsets(selectedRange, NotUserTriggered);
424 m_isDirty = true;
425 return;
426 }
427 }
428
350 selectComposition(); 429 selectComposition();
351 430
352 if (frame().selection().isNone()) 431 if (frame().selection().isNone())
353 return; 432 return;
354 433
355 Element* target = frame().document()->focusedElement(); 434 Element* target = frame().document()->focusedElement();
356 if (!target) 435 if (!target)
357 return; 436 return;
358 437
359 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets 438 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 439
368 // Dispatch an appropriate composition event to the focused node. 440 // Dispatch an appropriate composition event to the focused node.
369 // We check the composition status and choose an appropriate composition eve nt since this 441 // We check the composition status and choose an appropriate composition eve nt since this
370 // function is used for three purposes: 442 // function is used for three purposes:
371 // 1. Starting a new composition. 443 // 1. Starting a new composition.
372 // Send a compositionstart and a compositionupdate event when this functi on creates 444 // Send a compositionstart and a compositionupdate event when this functi on creates
373 // a new composition node, i.e. 445 // a new composition node, i.e.
374 // !hasComposition() && !text.isEmpty(). 446 // !hasComposition() && !text.isEmpty().
375 // Sending a compositionupdate event at this time ensures that at least o ne 447 // Sending a compositionupdate event at this time ensures that at least o ne
376 // compositionupdate event is dispatched. 448 // compositionupdate event is dispatched.
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 for (const auto& underline : underlines) { 531 for (const auto& underline : underlines) {
460 unsigned underlineStart = baseOffset + underline.startOffset(); 532 unsigned underlineStart = baseOffset + underline.startOffset();
461 unsigned underlineEnd = baseOffset + underline.endOffset(); 533 unsigned underlineEnd = baseOffset + underline.endOffset();
462 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd)); 534 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd));
463 if (ephemeralLineRange.isNull()) 535 if (ephemeralLineRange.isNull())
464 continue; 536 continue;
465 frame().document()->markers().addCompositionMarker(ephemeralLineRange.st artPosition(), ephemeralLineRange.endPosition(), underline.color(), underline.th ick(), underline.backgroundColor()); 537 frame().document()->markers().addCompositionMarker(ephemeralLineRange.st artPosition(), ephemeralLineRange.endPosition(), underline.color(), underline.th ick(), underline.backgroundColor());
466 } 538 }
467 } 539 }
468 540
541 PlainTextRange InputMethodController::createSelectionRangeForSetComposition(int selectionStart, int selectionEnd, size_t textLength) const
542 {
543 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
544 // needs to be audited. see http://crbug.com/590369 for more details.
545 frame().document()->updateStyleAndLayoutIgnorePendingStylesheets();
546
547 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start());
548 int start = selectionOffsetsStart + selectionStart;
549 int end = selectionOffsetsStart + selectionEnd;
550 return createRangeForSelection(start, end, textLength);
551 }
552
469 void InputMethodController::setCompositionFromExistingText(const Vector<Composit ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd) 553 void InputMethodController::setCompositionFromExistingText(const Vector<Composit ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd)
470 { 554 {
471 Element* editable = frame().selection().rootEditableElement(); 555 Element* editable = frame().selection().rootEditableElement();
472 if (!editable) 556 if (!editable)
473 return; 557 return;
474 558
475 DCHECK(!editable->document().needsLayoutTreeUpdate()); 559 DCHECK(!editable->document().needsLayoutTreeUpdate());
476 560
477 const EphemeralRange range = PlainTextRange(compositionStart, compositionEnd ).createRange(*editable); 561 const EphemeralRange range = PlainTextRange(compositionStart, compositionEnd ).createRange(*editable);
478 if (range.isNull()) 562 if (range.isNull())
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 TypingCommand::deleteSelection(*frame().document()); 713 TypingCommand::deleteSelection(*frame().document());
630 } 714 }
631 715
632 DEFINE_TRACE(InputMethodController) 716 DEFINE_TRACE(InputMethodController)
633 { 717 {
634 visitor->trace(m_frame); 718 visitor->trace(m_frame);
635 visitor->trace(m_compositionRange); 719 visitor->trace(m_compositionRange);
636 } 720 }
637 721
638 } // namespace blink 722 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698