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 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 PlainTextRange selectedRange = createRangeForSelection(start, end, text.leng
th()); | |
328 | |
329 // Dispatch an appropriate composition event to the focused node. | 324 // Dispatch an appropriate composition event to the focused node. |
330 // We check the composition status and choose an appropriate composition eve
nt since this | 325 // We check the composition status and choose an appropriate composition eve
nt since this |
331 // function is used for three purposes: | 326 // function is used for three purposes: |
332 // 1. Starting a new composition. | 327 // 1. Starting a new composition. |
333 // Send a compositionstart and a compositionupdate event when this functi
on creates | 328 // Send a compositionstart and a compositionupdate event when this functi
on creates |
334 // a new composition node, i.e. | 329 // a new composition node, i.e. |
335 // !hasComposition() && !text.isEmpty(). | 330 // !hasComposition() && !text.isEmpty(). |
336 // Sending a compositionupdate event at this time ensures that at least o
ne | 331 // Sending a compositionupdate event at this time ensures that at least o
ne |
337 // compositionupdate event is dispatched. | 332 // compositionupdate event is dispatched. |
338 // 2. Updating the existing composition node. | 333 // 2. Updating the existing composition node. |
339 // Send a compositionupdate event when this function updates the existing
composition | 334 // Send a compositionupdate event when this function updates the existing
composition |
340 // node, i.e. hasComposition() && !text.isEmpty(). | 335 // node, i.e. hasComposition() && !text.isEmpty(). |
341 // 3. Canceling the ongoing composition. | 336 // 3. Canceling the ongoing composition. |
342 // Send a compositionend event when function deletes the existing composi
tion node, i.e. | 337 // Send a compositionend event when function deletes the existing composi
tion node, i.e. |
343 // !hasComposition() && test.isEmpty(). | 338 // !hasComposition() && test.isEmpty(). |
344 if (text.isEmpty()) { | 339 if (text.isEmpty()) { |
345 if (hasComposition()) { | 340 if (hasComposition()) { |
346 confirmComposition(emptyString()); | 341 confirmComposition(emptyString()); |
347 } else { | 342 return; |
348 // It's weird to call |setComposition()| with empty text outside com
position, however some IME | |
349 // (e.g. Japanese IBus-Anthy) did this, so we simply delete selectio
n without sending extra events. | |
350 TypingCommand::deleteSelection(*frame().document(), TypingCommand::P
reventSpellChecking); | |
351 } | 343 } |
352 | 344 // It's weird to call |setComposition()| with empty text outside composi
tion, however some IME |
353 setEditableSelectionOffsets(selectedRange); | 345 // (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); |
354 return; | 347 return; |
355 } | 348 } |
356 | 349 |
357 // We should send a 'compositionstart' event only when the given text is not
empty because this | 350 // We should send a 'compositionstart' event only when the given text is not
empty because this |
358 // function doesn't create a composition node when the text is empty. | 351 // function doesn't create a composition node when the text is empty. |
359 if (!hasComposition()) { | 352 if (!hasComposition()) { |
360 target->dispatchEvent(CompositionEvent::create(EventTypeNames::compositi
onstart, frame().domWindow(), frame().selectedText())); | 353 target->dispatchEvent(CompositionEvent::create(EventTypeNames::compositi
onstart, frame().domWindow(), frame().selectedText())); |
361 if (!frame().document()) | 354 if (!frame().document()) |
362 return; | 355 return; |
363 } | 356 } |
(...skipping 30 matching lines...) Expand all Loading... |
394 m_isDirty = true; | 387 m_isDirty = true; |
395 m_hasComposition = true; | 388 m_hasComposition = true; |
396 if (!m_compositionRange) | 389 if (!m_compositionRange) |
397 m_compositionRange = Range::create(baseNode->document()); | 390 m_compositionRange = Range::create(baseNode->document()); |
398 m_compositionRange->setStart(baseNode, baseOffset); | 391 m_compositionRange->setStart(baseNode, baseOffset); |
399 m_compositionRange->setEnd(baseNode, extentOffset); | 392 m_compositionRange->setEnd(baseNode, extentOffset); |
400 | 393 |
401 if (baseNode->layoutObject()) | 394 if (baseNode->layoutObject()) |
402 baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); | 395 baseNode->layoutObject()->setShouldDoFullPaintInvalidation(); |
403 | 396 |
404 setEditableSelectionOffsets(selectedRange); | 397 // In case of exceeding the left boundary. |
| 398 int selectionOffsetsStart = static_cast<int>(getSelectionOffsets().start()); |
| 399 int start = std::max(selectionOffsetsStart + selectionStart, 0); |
| 400 int end = std::max(selectionOffsetsStart + selectionEnd, start); |
| 401 |
| 402 Element* rootEditableElement = frame().selection().rootEditableElement(); |
| 403 if (!rootEditableElement) |
| 404 return; |
| 405 |
| 406 // In case of exceeding the right boundary. |
| 407 // If both |value1| and |value2| exceed right boundary, |
| 408 // PlainTextRange(value1, value2)::createRange() will return a default |
| 409 // value, which is [0,0]. In order to get the correct Position in that case, |
| 410 // we should make sure |value1| is within range at least. |
| 411 const EphemeralRange& startRange = PlainTextRange(0, start).createRange(*roo
tEditableElement); |
| 412 const EphemeralRange& endRange = PlainTextRange(0, end).createRange(*rootEdi
tableElement); |
| 413 |
| 414 // TODO(yabinh): There should be a better way to create |startPosition| and |
| 415 // |endPosition|. But for now, since we can't get |anchorNode| and |offset|, |
| 416 // we can't create the 2 Position objects directly. So we use |
| 417 // PlainTextRange::createRange as a workaround. |
| 418 const Position& startPosition = startRange.endPosition(); |
| 419 const Position& endPosition = endRange.endPosition(); |
| 420 const EphemeralRange selectedRange(startPosition, endPosition); |
| 421 frame().selection().setSelectedRange(selectedRange, TextAffinity::Downstream
, SelectionDirectionalMode::NonDirectional, NotUserTriggered); |
405 | 422 |
406 if (underlines.isEmpty()) { | 423 if (underlines.isEmpty()) { |
407 frame().document()->markers().addCompositionMarker(m_compositionRange->s
tartPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTh
eme::theme().platformDefaultCompositionBackgroundColor()); | 424 frame().document()->markers().addCompositionMarker(m_compositionRange->s
tartPosition(), m_compositionRange->endPosition(), Color::black, false, LayoutTh
eme::theme().platformDefaultCompositionBackgroundColor()); |
408 return; | 425 return; |
409 } | 426 } |
410 for (const auto& underline : underlines) { | 427 for (const auto& underline : underlines) { |
411 unsigned underlineStart = baseOffset + underline.startOffset; | 428 unsigned underlineStart = baseOffset + underline.startOffset; |
412 unsigned underlineEnd = baseOffset + underline.endOffset; | 429 unsigned underlineEnd = baseOffset + underline.endOffset; |
413 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un
derlineStart), Position(baseNode, underlineEnd)); | 430 EphemeralRange ephemeralLineRange = EphemeralRange(Position(baseNode, un
derlineStart), Position(baseNode, underlineEnd)); |
414 if (ephemeralLineRange.isNull()) | 431 if (ephemeralLineRange.isNull()) |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
503 return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, Sele
ctionDirectionalMode::NonDirectional, FrameSelection::CloseTyping); | 520 return frame().selection().setSelectedRange(range, VP_DEFAULT_AFFINITY, Sele
ctionDirectionalMode::NonDirectional, FrameSelection::CloseTyping); |
504 } | 521 } |
505 | 522 |
506 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se
lectionOffsets) | 523 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se
lectionOffsets) |
507 { | 524 { |
508 if (!editor().canEdit()) | 525 if (!editor().canEdit()) |
509 return false; | 526 return false; |
510 return setSelectionOffsets(selectionOffsets); | 527 return setSelectionOffsets(selectionOffsets); |
511 } | 528 } |
512 | 529 |
513 PlainTextRange InputMethodController::createRangeForSelection(int start, int end
, size_t textLength) const | |
514 { | |
515 // In case of exceeding the left boundary. | |
516 start = std::max(start, 0); | |
517 end = std::max(end, start); | |
518 | |
519 // In case of exceeding the right boundary. | |
520 Element* rootEditableElement = frame().selection().rootEditableElement(); | |
521 if (!rootEditableElement) | |
522 return PlainTextRange(); | |
523 const EphemeralRange& range = EphemeralRange::rangeOfContents(*rootEditableE
lement); | |
524 if (range.isNull()) | |
525 return PlainTextRange(); | |
526 | |
527 const TextIteratorBehaviorFlags behaviorFlags = TextIteratorEmitsObjectRepla
cementCharacter | TextIteratorEmitsCharactersBetweenAllVisiblePositions; | |
528 TextIterator it(range.startPosition(), range.endPosition(), behaviorFlags); | |
529 | |
530 int rightBoundary = 0; | |
531 for (; !it.atEnd(); it.advance()) | |
532 rightBoundary += it.length(); | |
533 | |
534 if (hasComposition()) | |
535 rightBoundary -= compositionRange()->text().length(); | |
536 | |
537 rightBoundary += textLength; | |
538 | |
539 start = std::min(start, rightBoundary); | |
540 end = std::min(end, rightBoundary); | |
541 | |
542 return PlainTextRange(start, end); | |
543 } | |
544 | |
545 void InputMethodController::extendSelectionAndDelete(int before, int after) | 530 void InputMethodController::extendSelectionAndDelete(int before, int after) |
546 { | 531 { |
547 if (!editor().canEdit()) | 532 if (!editor().canEdit()) |
548 return; | 533 return; |
549 PlainTextRange selectionOffsets(getSelectionOffsets()); | 534 PlainTextRange selectionOffsets(getSelectionOffsets()); |
550 if (selectionOffsets.isNull()) | 535 if (selectionOffsets.isNull()) |
551 return; | 536 return; |
552 | 537 |
553 // A common call of before=1 and after=0 will fail if the last character | 538 // A common call of before=1 and after=0 will fail if the last character |
554 // is multi-code-word UTF-16, including both multi-16bit code-points and | 539 // is multi-code-word UTF-16, including both multi-16bit code-points and |
(...skipping 19 matching lines...) Expand all Loading... |
574 TypingCommand::deleteSelection(*frame().document()); | 559 TypingCommand::deleteSelection(*frame().document()); |
575 } | 560 } |
576 | 561 |
577 DEFINE_TRACE(InputMethodController) | 562 DEFINE_TRACE(InputMethodController) |
578 { | 563 { |
579 visitor->trace(m_frame); | 564 visitor->trace(m_frame); |
580 visitor->trace(m_compositionRange); | 565 visitor->trace(m_compositionRange); |
581 } | 566 } |
582 | 567 |
583 } // namespace blink | 568 } // namespace blink |
OLD | NEW |