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

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

Issue 2020973002: Reland: Fix setComposingText with empty text when newCursorPosition != 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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 303 matching lines...) Expand 10 before | Expand all | Expand 10 after
314 314
315 selectComposition(); 315 selectComposition();
316 316
317 if (frame().selection().isNone()) 317 if (frame().selection().isNone())
318 return; 318 return;
319 319
320 Element* target = frame().document()->focusedElement(); 320 Element* target = frame().document()->focusedElement();
321 if (!target) 321 if (!target)
322 return; 322 return;
323 323
324 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start());
325 int start = selectionOffsetsStart + selectionStart;
326 int end = selectionOffsetsStart + selectionEnd;
327
324 // Dispatch an appropriate composition event to the focused node. 328 // Dispatch an appropriate composition event to the focused node.
325 // We check the composition status and choose an appropriate composition eve nt since this 329 // We check the composition status and choose an appropriate composition eve nt since this
326 // function is used for three purposes: 330 // function is used for three purposes:
327 // 1. Starting a new composition. 331 // 1. Starting a new composition.
328 // Send a compositionstart and a compositionupdate event when this functi on creates 332 // Send a compositionstart and a compositionupdate event when this functi on creates
329 // a new composition node, i.e. 333 // a new composition node, i.e.
330 // !hasComposition() && !text.isEmpty(). 334 // !hasComposition() && !text.isEmpty().
331 // Sending a compositionupdate event at this time ensures that at least o ne 335 // Sending a compositionupdate event at this time ensures that at least o ne
332 // compositionupdate event is dispatched. 336 // compositionupdate event is dispatched.
333 // 2. Updating the existing composition node. 337 // 2. Updating the existing composition node.
334 // Send a compositionupdate event when this function updates the existing composition 338 // Send a compositionupdate event when this function updates the existing composition
335 // node, i.e. hasComposition() && !text.isEmpty(). 339 // node, i.e. hasComposition() && !text.isEmpty().
336 // 3. Canceling the ongoing composition. 340 // 3. Canceling the ongoing composition.
337 // Send a compositionend event when function deletes the existing composi tion node, i.e. 341 // Send a compositionend event when function deletes the existing composi tion node, i.e.
338 // !hasComposition() && test.isEmpty(). 342 // !hasComposition() && test.isEmpty().
339 if (text.isEmpty()) { 343 if (text.isEmpty()) {
340 if (hasComposition()) { 344 if (hasComposition()) {
341 confirmComposition(emptyString()); 345 confirmComposition(emptyString());
346 setEditableSelectionOffsetsWithBoundaryCheck(start, end);
342 return; 347 return;
343 } 348 }
344 // It's weird to call |setComposition()| with empty text outside composi tion, however some IME 349 // It's weird to call |setComposition()| with empty text outside composi tion, however some IME
345 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selection wi thout sending extra events. 350 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selection wi thout sending extra events.
346 TypingCommand::deleteSelection(*frame().document(), TypingCommand::Preve ntSpellChecking); 351 TypingCommand::deleteSelection(*frame().document(), TypingCommand::Preve ntSpellChecking);
352 setEditableSelectionOffsetsWithBoundaryCheck(start, end);
347 return; 353 return;
348 } 354 }
349 355
350 // We should send a 'compositionstart' event only when the given text is not empty because this 356 // We should send a 'compositionstart' event only when the given text is not empty because this
351 // function doesn't create a composition node when the text is empty. 357 // function doesn't create a composition node when the text is empty.
352 if (!hasComposition()) { 358 if (!hasComposition()) {
353 target->dispatchEvent(CompositionEvent::create(EventTypeNames::compositi onstart, frame().domWindow(), frame().selectedText())); 359 target->dispatchEvent(CompositionEvent::create(EventTypeNames::compositi onstart, frame().domWindow(), frame().selectedText()));
354 if (!frame().document()) 360 if (!frame().document())
355 return; 361 return;
356 } 362 }
(...skipping 26 matching lines...) Expand all
383 m_isDirty = true; 389 m_isDirty = true;
384 m_hasComposition = true; 390 m_hasComposition = true;
385 if (!m_compositionRange) 391 if (!m_compositionRange)
386 m_compositionRange = Range::create(baseNode->document()); 392 m_compositionRange = Range::create(baseNode->document());
387 m_compositionRange->setStart(baseNode, baseOffset); 393 m_compositionRange->setStart(baseNode, baseOffset);
388 m_compositionRange->setEnd(baseNode, extentOffset); 394 m_compositionRange->setEnd(baseNode, extentOffset);
389 395
390 if (baseNode->layoutObject()) 396 if (baseNode->layoutObject())
391 baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); 397 baseNode->layoutObject()->setShouldDoFullPaintInvalidation();
392 398
393 // In case of exceeding the left boundary. 399 setEditableSelectionOffsetsWithBoundaryCheck(start, end);
394 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start());
395 int start = std::max(selectionOffsetsStart + selectionStart, 0);
396 int end = std::max(selectionOffsetsStart + selectionEnd, start);
397
398 Element* rootEditableElement = frame().selection().rootEditableElement();
399 if (!rootEditableElement)
400 return;
401
402 // In case of exceeding the right boundary.
403 // If both |value1| and |value2| exceed right boundary,
404 // PlainTextRange(value1, value2)::createRange() will return a default
405 // value, which is [0,0]. In order to get the correct Position in that case,
406 // we should make sure |value1| is within range at least.
407 const EphemeralRange& startRange = PlainTextRange(0, start).createRange(*roo tEditableElement);
408 const EphemeralRange& endRange = PlainTextRange(0, end).createRange(*rootEdi tableElement);
409
410 // TODO(yabinh): There should be a better way to create |startPosition| and
411 // |endPosition|. But for now, since we can't get |anchorNode| and |offset|,
412 // we can't create the 2 Position objects directly. So we use
413 // PlainTextRange::createRange as a workaround.
414 const Position& startPosition = startRange.endPosition();
415 const Position& endPosition = endRange.endPosition();
416 Range* selectedRange = Range::create(rootEditableElement->document(), startP osition, endPosition);
417 frame().selection().setSelectedRange(selectedRange, TextAffinity::Downstream , SelectionDirectionalMode::NonDirectional, NotUserTriggered);
418 400
419 if (underlines.isEmpty()) { 401 if (underlines.isEmpty()) {
420 frame().document()->markers().addCompositionMarker(m_compositionRange->s tartPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTh eme::theme().platformDefaultCompositionBackgroundColor()); 402 frame().document()->markers().addCompositionMarker(m_compositionRange->s tartPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTh eme::theme().platformDefaultCompositionBackgroundColor());
421 return; 403 return;
422 } 404 }
423 for (const auto& underline : underlines) { 405 for (const auto& underline : underlines) {
424 unsigned underlineStart = baseOffset + underline.startOffset; 406 unsigned underlineStart = baseOffset + underline.startOffset;
425 unsigned underlineEnd = baseOffset + underline.endOffset; 407 unsigned underlineEnd = baseOffset + underline.endOffset;
426 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd)); 408 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un derlineStart), Position(baseNode, underlineEnd));
427 if (ephemeralLineRange.isNull()) 409 if (ephemeralLineRange.isNull())
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, Sele ctionDirectionalMode::NonDirectional, FrameSelection::CloseTyping); 490 return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, Sele ctionDirectionalMode::NonDirectional, FrameSelection::CloseTyping);
509 } 491 }
510 492
511 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se lectionOffsets) 493 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se lectionOffsets)
512 { 494 {
513 if (!editor().canEdit()) 495 if (!editor().canEdit())
514 return false; 496 return false;
515 return setSelectionOffsets(selectionOffsets); 497 return setSelectionOffsets(selectionOffsets);
516 } 498 }
517 499
500 bool InputMethodController::setEditableSelectionOffsetsWithBoundaryCheck(int sta rt, int end)
Changwan Ryu 2016/05/30 08:18:22 could you check if you can replace setEditableSele
yabinh 2016/05/31 01:53:59 Please see patch set 2.
501 {
502 if (!editor().canEdit())
503 return false;
504
505 Element* rootEditableElement = frame().selection().rootEditableElement();
506 if (!rootEditableElement)
507 return false;
508
509 // In case of exceeding the left boundary.
510 start = std::max(start, 0);
511 end = std::max(end, start);
512
513 // In case of exceeding the right boundary.
514 // If both |value1| and |value2| exceed right boundary,
515 // PlainTextRange(value1, value2)::createRange() will return a default
516 // value, which is [0,0]. In order to get the correct Position in that case,
517 // we should make sure |value1| is within range at least.
518 const EphemeralRange& startRange = PlainTextRange(0, start).createRange(*roo tEditableElement);
519 if (startRange.isNull())
520 return false;
521 const EphemeralRange& endRange = PlainTextRange(0, end).createRange(*rootEdi tableElement);
522 if (endRange.isNull())
523 return false;
524
525 // TODO(yabinh): There should be a better way to create |startPosition| and
526 // |endPosition|. But for now, since we can't get |anchorNode| and |offset|,
527 // we can't create the 2 Position objects directly. So we use
528 // PlainTextRange::createRange as a workaround.
529 const Position& startPosition = startRange.endPosition();
530 const Position& endPosition = endRange.endPosition();
531 const EphemeralRange& range = EphemeralRange(startPosition, endPosition);
532 if (range.isNull())
533 return false;
534
535 return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, Sele ctionDirectionalMode::NonDirectional, FrameSelection::CloseTyping);
536 }
537
518 void InputMethodController::extendSelectionAndDelete(int before, int after) 538 void InputMethodController::extendSelectionAndDelete(int before, int after)
519 { 539 {
520 if (!editor().canEdit()) 540 if (!editor().canEdit())
521 return; 541 return;
522 PlainTextRange selectionOffsets(getSelectionOffsets()); 542 PlainTextRange selectionOffsets(getSelectionOffsets());
523 if (selectionOffsets.isNull()) 543 if (selectionOffsets.isNull())
524 return; 544 return;
525 545
526 // A common call of before=1 and after=0 will fail if the last character 546 // A common call of before=1 and after=0 will fail if the last character
527 // is multi-code-word UTF-16, including both multi-16bit code-points and 547 // is multi-code-word UTF-16, including both multi-16bit code-points and
(...skipping 19 matching lines...) Expand all
547 TypingCommand::deleteSelection(*frame().document()); 567 TypingCommand::deleteSelection(*frame().document());
548 } 568 }
549 569
550 DEFINE_TRACE(InputMethodController) 570 DEFINE_TRACE(InputMethodController)
551 { 571 {
552 visitor->trace(m_frame); 572 visitor->trace(m_frame);
553 visitor->trace(m_compositionRange); 573 visitor->trace(m_compositionRange);
554 } 574 }
555 575
556 } // namespace blink 576 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698