| 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 { | 49 { |
| 50 } | 50 } |
| 51 | 51 |
| 52 InputMethodController::SelectionOffsetsScope::~SelectionOffsetsScope() | 52 InputMethodController::SelectionOffsetsScope::~SelectionOffsetsScope() |
| 53 { | 53 { |
| 54 m_inputMethodController->setSelectionOffsets(m_offsets); | 54 m_inputMethodController->setSelectionOffsets(m_offsets); |
| 55 } | 55 } |
| 56 | 56 |
| 57 // ---------------------------- | 57 // ---------------------------- |
| 58 | 58 |
| 59 PassOwnPtr<InputMethodController> InputMethodController::create(LocalFrame& fram
e) | 59 PassOwnPtrWillBeRawPtr<InputMethodController> InputMethodController::create(Loca
lFrame& frame) |
| 60 { | 60 { |
| 61 return adoptPtr(new InputMethodController(frame)); | 61 return adoptPtrWillBeNoop(new InputMethodController(frame)); |
| 62 } | 62 } |
| 63 | 63 |
| 64 InputMethodController::InputMethodController(LocalFrame& frame) | 64 InputMethodController::InputMethodController(LocalFrame& frame) |
| 65 : m_frame(frame) | 65 : m_frame(&frame) |
| 66 , m_compositionStart(0) | 66 , m_compositionStart(0) |
| 67 , m_compositionEnd(0) | 67 , m_compositionEnd(0) |
| 68 { | 68 { |
| 69 } | 69 } |
| 70 | 70 |
| 71 InputMethodController::~InputMethodController() | 71 InputMethodController::~InputMethodController() |
| 72 { | 72 { |
| 73 } | 73 } |
| 74 | 74 |
| 75 bool InputMethodController::hasComposition() const | 75 bool InputMethodController::hasComposition() const |
| 76 { | 76 { |
| 77 return m_compositionNode && m_compositionNode->isContentEditable(); | 77 return m_compositionNode && m_compositionNode->isContentEditable(); |
| 78 } | 78 } |
| 79 | 79 |
| 80 inline Editor& InputMethodController::editor() const | 80 inline Editor& InputMethodController::editor() const |
| 81 { | 81 { |
| 82 return m_frame.editor(); | 82 return frame().editor(); |
| 83 } | 83 } |
| 84 | 84 |
| 85 void InputMethodController::clear() | 85 void InputMethodController::clear() |
| 86 { | 86 { |
| 87 m_compositionNode = nullptr; | 87 m_compositionNode = nullptr; |
| 88 m_customCompositionUnderlines.clear(); | 88 m_customCompositionUnderlines.clear(); |
| 89 } | 89 } |
| 90 | 90 |
| 91 bool InputMethodController::insertTextForConfirmedComposition(const String& text
) | 91 bool InputMethodController::insertTextForConfirmedComposition(const String& text
) |
| 92 { | 92 { |
| 93 return m_frame.eventHandler().handleTextInputEvent(text, 0, TextEventInputCo
mposition); | 93 return frame().eventHandler().handleTextInputEvent(text, 0, TextEventInputCo
mposition); |
| 94 } | 94 } |
| 95 | 95 |
| 96 void InputMethodController::selectComposition() const | 96 void InputMethodController::selectComposition() const |
| 97 { | 97 { |
| 98 RefPtrWillBeRawPtr<Range> range = compositionRange(); | 98 RefPtrWillBeRawPtr<Range> range = compositionRange(); |
| 99 if (!range) | 99 if (!range) |
| 100 return; | 100 return; |
| 101 | 101 |
| 102 // The composition can start inside a composed character sequence, so we hav
e to override checks. | 102 // The composition can start inside a composed character sequence, so we hav
e to override checks. |
| 103 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> | 103 // See <http://bugs.webkit.org/show_bug.cgi?id=15781> |
| 104 VisibleSelection selection; | 104 VisibleSelection selection; |
| 105 selection.setWithoutValidation(range->startPosition(), range->endPosition())
; | 105 selection.setWithoutValidation(range->startPosition(), range->endPosition())
; |
| 106 m_frame.selection().setSelection(selection, 0); | 106 frame().selection().setSelection(selection, 0); |
| 107 } | 107 } |
| 108 | 108 |
| 109 bool InputMethodController::confirmComposition() | 109 bool InputMethodController::confirmComposition() |
| 110 { | 110 { |
| 111 if (!hasComposition()) | 111 if (!hasComposition()) |
| 112 return false; | 112 return false; |
| 113 return finishComposition(m_compositionNode->data().substring(m_compositionSt
art, m_compositionEnd - m_compositionStart), ConfirmComposition); | 113 return finishComposition(m_compositionNode->data().substring(m_compositionSt
art, m_compositionEnd - m_compositionStart), ConfirmComposition); |
| 114 } | 114 } |
| 115 | 115 |
| 116 bool InputMethodController::confirmComposition(const String& text) | 116 bool InputMethodController::confirmComposition(const String& text) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 138 SelectionOffsetsScope selectionOffsetsScope(this); | 138 SelectionOffsetsScope selectionOffsetsScope(this); |
| 139 return confirmComposition(); | 139 return confirmComposition(); |
| 140 } | 140 } |
| 141 | 141 |
| 142 void InputMethodController::confirmCompositionAndResetState() | 142 void InputMethodController::confirmCompositionAndResetState() |
| 143 { | 143 { |
| 144 if (!hasComposition()) | 144 if (!hasComposition()) |
| 145 return; | 145 return; |
| 146 | 146 |
| 147 // ChromeClient::willSetInputMethodState() resets input method and the compo
sition string is committed. | 147 // ChromeClient::willSetInputMethodState() resets input method and the compo
sition string is committed. |
| 148 m_frame.chromeClient().willSetInputMethodState(); | 148 frame().chromeClient().willSetInputMethodState(); |
| 149 } | 149 } |
| 150 | 150 |
| 151 void InputMethodController::cancelComposition() | 151 void InputMethodController::cancelComposition() |
| 152 { | 152 { |
| 153 finishComposition(emptyString(), CancelComposition); | 153 finishComposition(emptyString(), CancelComposition); |
| 154 } | 154 } |
| 155 | 155 |
| 156 void InputMethodController::cancelCompositionIfSelectionIsInvalid() | 156 void InputMethodController::cancelCompositionIfSelectionIsInvalid() |
| 157 { | 157 { |
| 158 if (!hasComposition() || editor().preventRevealSelection()) | 158 if (!hasComposition() || editor().preventRevealSelection()) |
| 159 return; | 159 return; |
| 160 | 160 |
| 161 // Check if selection start and selection end are valid. | 161 // Check if selection start and selection end are valid. |
| 162 Position start = m_frame.selection().start(); | 162 Position start = frame().selection().start(); |
| 163 Position end = m_frame.selection().end(); | 163 Position end = frame().selection().end(); |
| 164 if (start.containerNode() == m_compositionNode | 164 if (start.containerNode() == m_compositionNode |
| 165 && end.containerNode() == m_compositionNode | 165 && end.containerNode() == m_compositionNode |
| 166 && static_cast<unsigned>(start.computeOffsetInContainerNode()) >= m_comp
ositionStart | 166 && static_cast<unsigned>(start.computeOffsetInContainerNode()) >= m_comp
ositionStart |
| 167 && static_cast<unsigned>(end.computeOffsetInContainerNode()) <= m_compos
itionEnd) | 167 && static_cast<unsigned>(end.computeOffsetInContainerNode()) <= m_compos
itionEnd) |
| 168 return; | 168 return; |
| 169 | 169 |
| 170 cancelComposition(); | 170 cancelComposition(); |
| 171 m_frame.chromeClient().didCancelCompositionOnSelectionChange(); | 171 frame().chromeClient().didCancelCompositionOnSelectionChange(); |
| 172 } | 172 } |
| 173 | 173 |
| 174 bool InputMethodController::finishComposition(const String& text, FinishComposit
ionMode mode) | 174 bool InputMethodController::finishComposition(const String& text, FinishComposit
ionMode mode) |
| 175 { | 175 { |
| 176 if (!hasComposition()) | 176 if (!hasComposition()) |
| 177 return false; | 177 return false; |
| 178 | 178 |
| 179 ASSERT(mode == ConfirmComposition || mode == CancelComposition); | 179 ASSERT(mode == ConfirmComposition || mode == CancelComposition); |
| 180 | 180 |
| 181 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 181 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
| 182 | 182 |
| 183 if (mode == CancelComposition) | 183 if (mode == CancelComposition) |
| 184 ASSERT(text == emptyString()); | 184 ASSERT(text == emptyString()); |
| 185 else | 185 else |
| 186 selectComposition(); | 186 selectComposition(); |
| 187 | 187 |
| 188 if (m_frame.selection().isNone()) | 188 if (frame().selection().isNone()) |
| 189 return false; | 189 return false; |
| 190 | 190 |
| 191 // Dispatch a compositionend event to the focused node. | 191 // Dispatch a compositionend event to the focused node. |
| 192 // We should send this event before sending a TextEvent as written in Sectio
n 6.2.2 and 6.2.3 of | 192 // We should send this event before sending a TextEvent as written in Sectio
n 6.2.2 and 6.2.3 of |
| 193 // the DOM Event specification. | 193 // the DOM Event specification. |
| 194 if (Element* target = m_frame.document()->focusedElement()) { | 194 if (Element* target = frame().document()->focusedElement()) { |
| 195 unsigned baseOffset = m_frame.selection().base().downstream().deprecated
EditingOffset(); | 195 unsigned baseOffset = frame().selection().base().downstream().deprecated
EditingOffset(); |
| 196 Vector<CompositionUnderline> underlines; | 196 Vector<CompositionUnderline> underlines; |
| 197 for (size_t i = 0; i < m_customCompositionUnderlines.size(); ++i) { | 197 for (size_t i = 0; i < m_customCompositionUnderlines.size(); ++i) { |
| 198 CompositionUnderline underline = m_customCompositionUnderlines[i]; | 198 CompositionUnderline underline = m_customCompositionUnderlines[i]; |
| 199 underline.startOffset -= baseOffset; | 199 underline.startOffset -= baseOffset; |
| 200 underline.endOffset -= baseOffset; | 200 underline.endOffset -= baseOffset; |
| 201 underlines.append(underline); | 201 underlines.append(underline); |
| 202 } | 202 } |
| 203 RefPtrWillBeRawPtr<CompositionEvent> event = CompositionEvent::create(Ev
entTypeNames::compositionend, m_frame.domWindow(), text, underlines); | 203 RefPtrWillBeRawPtr<CompositionEvent> event = CompositionEvent::create(Ev
entTypeNames::compositionend, frame().domWindow(), text, underlines); |
| 204 target->dispatchEvent(event, IGNORE_EXCEPTION); | 204 target->dispatchEvent(event, IGNORE_EXCEPTION); |
| 205 } | 205 } |
| 206 | 206 |
| 207 // If text is empty, then delete the old composition here. If text is non-em
pty, InsertTextCommand::input | 207 // If text is empty, then delete the old composition here. If text is non-em
pty, InsertTextCommand::input |
| 208 // will delete the old composition with an optimized replace operation. | 208 // will delete the old composition with an optimized replace operation. |
| 209 if (text.isEmpty() && mode != CancelComposition) { | 209 if (text.isEmpty() && mode != CancelComposition) { |
| 210 ASSERT(m_frame.document()); | 210 ASSERT(frame().document()); |
| 211 TypingCommand::deleteSelection(*m_frame.document(), 0); | 211 TypingCommand::deleteSelection(*frame().document(), 0); |
| 212 } | 212 } |
| 213 | 213 |
| 214 m_compositionNode = nullptr; | 214 m_compositionNode = nullptr; |
| 215 m_customCompositionUnderlines.clear(); | 215 m_customCompositionUnderlines.clear(); |
| 216 | 216 |
| 217 insertTextForConfirmedComposition(text); | 217 insertTextForConfirmedComposition(text); |
| 218 | 218 |
| 219 if (mode == CancelComposition) { | 219 if (mode == CancelComposition) { |
| 220 // An open typing command that disagrees about current selection would c
ause issues with typing later on. | 220 // An open typing command that disagrees about current selection would c
ause issues with typing later on. |
| 221 TypingCommand::closeTyping(&m_frame); | 221 TypingCommand::closeTyping(m_frame); |
| 222 } | 222 } |
| 223 | 223 |
| 224 return true; | 224 return true; |
| 225 } | 225 } |
| 226 | 226 |
| 227 void InputMethodController::setComposition(const String& text, const Vector<Comp
ositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd) | 227 void InputMethodController::setComposition(const String& text, const Vector<Comp
ositionUnderline>& underlines, unsigned selectionStart, unsigned selectionEnd) |
| 228 { | 228 { |
| 229 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 229 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
| 230 | 230 |
| 231 // Updates styles before setting selection for composition to prevent | 231 // Updates styles before setting selection for composition to prevent |
| 232 // inserting the previous composition text into text nodes oddly. | 232 // inserting the previous composition text into text nodes oddly. |
| 233 // See https://bugs.webkit.org/show_bug.cgi?id=46868 | 233 // See https://bugs.webkit.org/show_bug.cgi?id=46868 |
| 234 m_frame.document()->updateRenderTreeIfNeeded(); | 234 frame().document()->updateRenderTreeIfNeeded(); |
| 235 | 235 |
| 236 selectComposition(); | 236 selectComposition(); |
| 237 | 237 |
| 238 if (m_frame.selection().isNone()) | 238 if (frame().selection().isNone()) |
| 239 return; | 239 return; |
| 240 | 240 |
| 241 if (Element* target = m_frame.document()->focusedElement()) { | 241 if (Element* target = frame().document()->focusedElement()) { |
| 242 // Dispatch an appropriate composition event to the focused node. | 242 // Dispatch an appropriate composition event to the focused node. |
| 243 // We check the composition status and choose an appropriate composition
event since this | 243 // We check the composition status and choose an appropriate composition
event since this |
| 244 // function is used for three purposes: | 244 // function is used for three purposes: |
| 245 // 1. Starting a new composition. | 245 // 1. Starting a new composition. |
| 246 // Send a compositionstart and a compositionupdate event when this fu
nction creates | 246 // Send a compositionstart and a compositionupdate event when this fu
nction creates |
| 247 // a new composition node, i.e. | 247 // a new composition node, i.e. |
| 248 // m_compositionNode == 0 && !text.isEmpty(). | 248 // m_compositionNode == 0 && !text.isEmpty(). |
| 249 // Sending a compositionupdate event at this time ensures that at lea
st one | 249 // Sending a compositionupdate event at this time ensures that at lea
st one |
| 250 // compositionupdate event is dispatched. | 250 // compositionupdate event is dispatched. |
| 251 // 2. Updating the existing composition node. | 251 // 2. Updating the existing composition node. |
| 252 // Send a compositionupdate event when this function updates the exis
ting composition | 252 // Send a compositionupdate event when this function updates the exis
ting composition |
| 253 // node, i.e. m_compositionNode != 0 && !text.isEmpty(). | 253 // node, i.e. m_compositionNode != 0 && !text.isEmpty(). |
| 254 // 3. Canceling the ongoing composition. | 254 // 3. Canceling the ongoing composition. |
| 255 // Send a compositionend event when function deletes the existing com
position node, i.e. | 255 // Send a compositionend event when function deletes the existing com
position node, i.e. |
| 256 // m_compositionNode != 0 && test.isEmpty(). | 256 // m_compositionNode != 0 && test.isEmpty(). |
| 257 RefPtrWillBeRawPtr<CompositionEvent> event = nullptr; | 257 RefPtrWillBeRawPtr<CompositionEvent> event = nullptr; |
| 258 if (!hasComposition()) { | 258 if (!hasComposition()) { |
| 259 // We should send a compositionstart event only when the given text
is not empty because this | 259 // We should send a compositionstart event only when the given text
is not empty because this |
| 260 // function doesn't create a composition node when the text is empty
. | 260 // function doesn't create a composition node when the text is empty
. |
| 261 if (!text.isEmpty()) { | 261 if (!text.isEmpty()) { |
| 262 target->dispatchEvent(CompositionEvent::create(EventTypeNames::c
ompositionstart, m_frame.domWindow(), m_frame.selectedText(), underlines)); | 262 target->dispatchEvent(CompositionEvent::create(EventTypeNames::c
ompositionstart, frame().domWindow(), frame().selectedText(), underlines)); |
| 263 event = CompositionEvent::create(EventTypeNames::compositionupda
te, m_frame.domWindow(), text, underlines); | 263 event = CompositionEvent::create(EventTypeNames::compositionupda
te, frame().domWindow(), text, underlines); |
| 264 } | 264 } |
| 265 } else { | 265 } else { |
| 266 if (!text.isEmpty()) | 266 if (!text.isEmpty()) |
| 267 event = CompositionEvent::create(EventTypeNames::compositionupda
te, m_frame.domWindow(), text, underlines); | 267 event = CompositionEvent::create(EventTypeNames::compositionupda
te, frame().domWindow(), text, underlines); |
| 268 else | 268 else |
| 269 event = CompositionEvent::create(EventTypeNames::compositionend,
m_frame.domWindow(), text, underlines); | 269 event = CompositionEvent::create(EventTypeNames::compositionend,
frame().domWindow(), text, underlines); |
| 270 } | 270 } |
| 271 if (event.get()) | 271 if (event.get()) |
| 272 target->dispatchEvent(event, IGNORE_EXCEPTION); | 272 target->dispatchEvent(event, IGNORE_EXCEPTION); |
| 273 } | 273 } |
| 274 | 274 |
| 275 // If text is empty, then delete the old composition here. If text is non-em
pty, InsertTextCommand::input | 275 // If text is empty, then delete the old composition here. If text is non-em
pty, InsertTextCommand::input |
| 276 // will delete the old composition with an optimized replace operation. | 276 // will delete the old composition with an optimized replace operation. |
| 277 if (text.isEmpty()) { | 277 if (text.isEmpty()) { |
| 278 ASSERT(m_frame.document()); | 278 ASSERT(frame().document()); |
| 279 TypingCommand::deleteSelection(*m_frame.document(), TypingCommand::Preve
ntSpellChecking); | 279 TypingCommand::deleteSelection(*frame().document(), TypingCommand::Preve
ntSpellChecking); |
| 280 } | 280 } |
| 281 | 281 |
| 282 m_compositionNode = nullptr; | 282 m_compositionNode = nullptr; |
| 283 m_customCompositionUnderlines.clear(); | 283 m_customCompositionUnderlines.clear(); |
| 284 | 284 |
| 285 if (!text.isEmpty()) { | 285 if (!text.isEmpty()) { |
| 286 ASSERT(m_frame.document()); | 286 ASSERT(frame().document()); |
| 287 TypingCommand::insertText(*m_frame.document(), text, TypingCommand::Sele
ctInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextComposi
tionUpdate); | 287 TypingCommand::insertText(*frame().document(), text, TypingCommand::Sele
ctInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextComposi
tionUpdate); |
| 288 | 288 |
| 289 // Find out what node has the composition now. | 289 // Find out what node has the composition now. |
| 290 Position base = m_frame.selection().base().downstream(); | 290 Position base = frame().selection().base().downstream(); |
| 291 Position extent = m_frame.selection().extent(); | 291 Position extent = frame().selection().extent(); |
| 292 Node* baseNode = base.deprecatedNode(); | 292 Node* baseNode = base.deprecatedNode(); |
| 293 unsigned baseOffset = base.deprecatedEditingOffset(); | 293 unsigned baseOffset = base.deprecatedEditingOffset(); |
| 294 Node* extentNode = extent.deprecatedNode(); | 294 Node* extentNode = extent.deprecatedNode(); |
| 295 unsigned extentOffset = extent.deprecatedEditingOffset(); | 295 unsigned extentOffset = extent.deprecatedEditingOffset(); |
| 296 | 296 |
| 297 if (baseNode && baseNode == extentNode && baseNode->isTextNode() && base
Offset + text.length() == extentOffset) { | 297 if (baseNode && baseNode == extentNode && baseNode->isTextNode() && base
Offset + text.length() == extentOffset) { |
| 298 m_compositionNode = toText(baseNode); | 298 m_compositionNode = toText(baseNode); |
| 299 m_compositionStart = baseOffset; | 299 m_compositionStart = baseOffset; |
| 300 m_compositionEnd = extentOffset; | 300 m_compositionEnd = extentOffset; |
| 301 m_customCompositionUnderlines = underlines; | 301 m_customCompositionUnderlines = underlines; |
| 302 size_t numUnderlines = m_customCompositionUnderlines.size(); | 302 size_t numUnderlines = m_customCompositionUnderlines.size(); |
| 303 for (size_t i = 0; i < numUnderlines; ++i) { | 303 for (size_t i = 0; i < numUnderlines; ++i) { |
| 304 m_customCompositionUnderlines[i].startOffset += baseOffset; | 304 m_customCompositionUnderlines[i].startOffset += baseOffset; |
| 305 m_customCompositionUnderlines[i].endOffset += baseOffset; | 305 m_customCompositionUnderlines[i].endOffset += baseOffset; |
| 306 } | 306 } |
| 307 if (baseNode->renderer()) | 307 if (baseNode->renderer()) |
| 308 baseNode->renderer()->setShouldDoFullPaintInvalidation(true); | 308 baseNode->renderer()->setShouldDoFullPaintInvalidation(true); |
| 309 | 309 |
| 310 unsigned start = std::min(baseOffset + selectionStart, extentOffset)
; | 310 unsigned start = std::min(baseOffset + selectionStart, extentOffset)
; |
| 311 unsigned end = std::min(std::max(start, baseOffset + selectionEnd),
extentOffset); | 311 unsigned end = std::min(std::max(start, baseOffset + selectionEnd),
extentOffset); |
| 312 RefPtrWillBeRawPtr<Range> selectedRange = Range::create(baseNode->do
cument(), baseNode, start, baseNode, end); | 312 RefPtrWillBeRawPtr<Range> selectedRange = Range::create(baseNode->do
cument(), baseNode, start, baseNode, end); |
| 313 m_frame.selection().setSelectedRange(selectedRange.get(), DOWNSTREAM
, FrameSelection::NonDirectional, NotUserTriggered); | 313 frame().selection().setSelectedRange(selectedRange.get(), DOWNSTREAM
, FrameSelection::NonDirectional, NotUserTriggered); |
| 314 } | 314 } |
| 315 } | 315 } |
| 316 } | 316 } |
| 317 | 317 |
| 318 void InputMethodController::setCompositionFromExistingText(const Vector<Composit
ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd) | 318 void InputMethodController::setCompositionFromExistingText(const Vector<Composit
ionUnderline>& underlines, unsigned compositionStart, unsigned compositionEnd) |
| 319 { | 319 { |
| 320 Element* editable = m_frame.selection().rootEditableElement(); | 320 Element* editable = frame().selection().rootEditableElement(); |
| 321 Position base = m_frame.selection().base().downstream(); | 321 Position base = frame().selection().base().downstream(); |
| 322 Node* baseNode = base.anchorNode(); | 322 Node* baseNode = base.anchorNode(); |
| 323 if (editable->firstChild() == baseNode && editable->lastChild() == baseNode
&& baseNode->isTextNode()) { | 323 if (editable->firstChild() == baseNode && editable->lastChild() == baseNode
&& baseNode->isTextNode()) { |
| 324 m_compositionNode = nullptr; | 324 m_compositionNode = nullptr; |
| 325 m_customCompositionUnderlines.clear(); | 325 m_customCompositionUnderlines.clear(); |
| 326 | 326 |
| 327 if (base.anchorType() != Position::PositionIsOffsetInAnchor) | 327 if (base.anchorType() != Position::PositionIsOffsetInAnchor) |
| 328 return; | 328 return; |
| 329 if (!baseNode || baseNode != m_frame.selection().extent().anchorNode()) | 329 if (!baseNode || baseNode != frame().selection().extent().anchorNode()) |
| 330 return; | 330 return; |
| 331 | 331 |
| 332 m_compositionNode = toText(baseNode); | 332 m_compositionNode = toText(baseNode); |
| 333 RefPtrWillBeRawPtr<Range> range = PlainTextRange(compositionStart, compo
sitionEnd).createRange(*editable); | 333 RefPtrWillBeRawPtr<Range> range = PlainTextRange(compositionStart, compo
sitionEnd).createRange(*editable); |
| 334 if (!range) | 334 if (!range) |
| 335 return; | 335 return; |
| 336 | 336 |
| 337 m_compositionStart = range->startOffset(); | 337 m_compositionStart = range->startOffset(); |
| 338 m_compositionEnd = range->endOffset(); | 338 m_compositionEnd = range->endOffset(); |
| 339 m_customCompositionUnderlines = underlines; | 339 m_customCompositionUnderlines = underlines; |
| 340 size_t numUnderlines = m_customCompositionUnderlines.size(); | 340 size_t numUnderlines = m_customCompositionUnderlines.size(); |
| 341 for (size_t i = 0; i < numUnderlines; ++i) { | 341 for (size_t i = 0; i < numUnderlines; ++i) { |
| 342 m_customCompositionUnderlines[i].startOffset += m_compositionStart; | 342 m_customCompositionUnderlines[i].startOffset += m_compositionStart; |
| 343 m_customCompositionUnderlines[i].endOffset += m_compositionStart; | 343 m_customCompositionUnderlines[i].endOffset += m_compositionStart; |
| 344 } | 344 } |
| 345 if (baseNode->renderer()) | 345 if (baseNode->renderer()) |
| 346 baseNode->renderer()->setShouldDoFullPaintInvalidation(true); | 346 baseNode->renderer()->setShouldDoFullPaintInvalidation(true); |
| 347 return; | 347 return; |
| 348 } | 348 } |
| 349 | 349 |
| 350 Editor::RevealSelectionScope revealSelectionScope(&editor()); | 350 Editor::RevealSelectionScope revealSelectionScope(&editor()); |
| 351 SelectionOffsetsScope selectionOffsetsScope(this); | 351 SelectionOffsetsScope selectionOffsetsScope(this); |
| 352 setSelectionOffsets(PlainTextRange(compositionStart, compositionEnd)); | 352 setSelectionOffsets(PlainTextRange(compositionStart, compositionEnd)); |
| 353 setComposition(m_frame.selectedText(), underlines, 0, 0); | 353 setComposition(frame().selectedText(), underlines, 0, 0); |
| 354 } | 354 } |
| 355 | 355 |
| 356 PassRefPtrWillBeRawPtr<Range> InputMethodController::compositionRange() const | 356 PassRefPtrWillBeRawPtr<Range> InputMethodController::compositionRange() const |
| 357 { | 357 { |
| 358 if (!hasComposition()) | 358 if (!hasComposition()) |
| 359 return nullptr; | 359 return nullptr; |
| 360 unsigned length = m_compositionNode->length(); | 360 unsigned length = m_compositionNode->length(); |
| 361 unsigned start = std::min(m_compositionStart, length); | 361 unsigned start = std::min(m_compositionStart, length); |
| 362 unsigned end = std::min(std::max(start, m_compositionEnd), length); | 362 unsigned end = std::min(std::max(start, m_compositionEnd), length); |
| 363 if (start >= end) | 363 if (start >= end) |
| 364 return nullptr; | 364 return nullptr; |
| 365 return Range::create(m_compositionNode->document(), m_compositionNode.get(),
start, m_compositionNode.get(), end); | 365 return Range::create(m_compositionNode->document(), m_compositionNode.get(),
start, m_compositionNode.get(), end); |
| 366 } | 366 } |
| 367 | 367 |
| 368 PlainTextRange InputMethodController::getSelectionOffsets() const | 368 PlainTextRange InputMethodController::getSelectionOffsets() const |
| 369 { | 369 { |
| 370 RefPtrWillBeRawPtr<Range> range = m_frame.selection().selection().firstRange
(); | 370 RefPtrWillBeRawPtr<Range> range = frame().selection().selection().firstRange
(); |
| 371 if (!range) | 371 if (!range) |
| 372 return PlainTextRange(); | 372 return PlainTextRange(); |
| 373 ContainerNode* editable = m_frame.selection().rootEditableElementOrTreeScope
RootNode(); | 373 ContainerNode* editable = frame().selection().rootEditableElementOrTreeScope
RootNode(); |
| 374 ASSERT(editable); | 374 ASSERT(editable); |
| 375 return PlainTextRange::create(*editable, *range.get()); | 375 return PlainTextRange::create(*editable, *range.get()); |
| 376 } | 376 } |
| 377 | 377 |
| 378 bool InputMethodController::setSelectionOffsets(const PlainTextRange& selectionO
ffsets) | 378 bool InputMethodController::setSelectionOffsets(const PlainTextRange& selectionO
ffsets) |
| 379 { | 379 { |
| 380 if (selectionOffsets.isNull()) | 380 if (selectionOffsets.isNull()) |
| 381 return false; | 381 return false; |
| 382 Element* rootEditableElement = m_frame.selection().rootEditableElement(); | 382 Element* rootEditableElement = frame().selection().rootEditableElement(); |
| 383 if (!rootEditableElement) | 383 if (!rootEditableElement) |
| 384 return false; | 384 return false; |
| 385 | 385 |
| 386 RefPtrWillBeRawPtr<Range> range = selectionOffsets.createRange(*rootEditable
Element); | 386 RefPtrWillBeRawPtr<Range> range = selectionOffsets.createRange(*rootEditable
Element); |
| 387 if (!range) | 387 if (!range) |
| 388 return false; | 388 return false; |
| 389 | 389 |
| 390 return m_frame.selection().setSelectedRange(range.get(), VP_DEFAULT_AFFINITY
, FrameSelection::NonDirectional, FrameSelection::CloseTyping); | 390 return frame().selection().setSelectedRange(range.get(), VP_DEFAULT_AFFINITY
, FrameSelection::NonDirectional, FrameSelection::CloseTyping); |
| 391 } | 391 } |
| 392 | 392 |
| 393 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se
lectionOffsets) | 393 bool InputMethodController::setEditableSelectionOffsets(const PlainTextRange& se
lectionOffsets) |
| 394 { | 394 { |
| 395 if (!editor().canEdit()) | 395 if (!editor().canEdit()) |
| 396 return false; | 396 return false; |
| 397 return setSelectionOffsets(selectionOffsets); | 397 return setSelectionOffsets(selectionOffsets); |
| 398 } | 398 } |
| 399 | 399 |
| 400 void InputMethodController::extendSelectionAndDelete(int before, int after) | 400 void InputMethodController::extendSelectionAndDelete(int before, int after) |
| (...skipping 15 matching lines...) Expand all Loading... |
| 416 // that will not delete a full multi-code-point composition but rather | 416 // that will not delete a full multi-code-point composition but rather |
| 417 // only the last code-point so that it's possible for a user to correct | 417 // only the last code-point so that it's possible for a user to correct |
| 418 // a composition without starting it from the beginning. | 418 // a composition without starting it from the beginning. |
| 419 // http://crbug.com/37993 | 419 // http://crbug.com/37993 |
| 420 do { | 420 do { |
| 421 if (!setSelectionOffsets(PlainTextRange(std::max(static_cast<int>(select
ionOffsets.start()) - before, 0), selectionOffsets.end() + after))) | 421 if (!setSelectionOffsets(PlainTextRange(std::max(static_cast<int>(select
ionOffsets.start()) - before, 0), selectionOffsets.end() + after))) |
| 422 return; | 422 return; |
| 423 if (before == 0) | 423 if (before == 0) |
| 424 break; | 424 break; |
| 425 ++before; | 425 ++before; |
| 426 } while (m_frame.selection().start() == m_frame.selection().end() && before
<= static_cast<int>(selectionOffsets.start())); | 426 } while (frame().selection().start() == frame().selection().end() && before
<= static_cast<int>(selectionOffsets.start())); |
| 427 TypingCommand::deleteSelection(*m_frame.document()); | 427 TypingCommand::deleteSelection(*frame().document()); |
| 428 } |
| 429 |
| 430 void InputMethodController::trace(Visitor* visitor) |
| 431 { |
| 432 visitor->trace(m_frame); |
| 433 visitor->trace(m_compositionNode); |
| 428 } | 434 } |
| 429 | 435 |
| 430 } // namespace blink | 436 } // namespace blink |
| OLD | NEW |