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 m_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 m_frame->eventHandler().handleTextInputEvent(text, 0, TextEventInputC
omposition); |
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 m_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 m_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 = m_frame->selection().start(); |
163 Position end = m_frame.selection().end(); | 163 Position end = m_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 m_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 (m_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 = m_frame->document()->focusedElement()) { |
195 unsigned baseOffset = m_frame.selection().base().downstream().deprecated
EditingOffset(); | 195 unsigned baseOffset = m_frame->selection().base().downstream().deprecate
dEditingOffset(); |
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, m_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(m_frame->document()); |
211 TypingCommand::deleteSelection(*m_frame.document(), 0); | 211 TypingCommand::deleteSelection(*m_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 m_frame->document()->updateRenderTreeIfNeeded(); |
235 | 235 |
236 selectComposition(); | 236 selectComposition(); |
237 | 237 |
238 if (m_frame.selection().isNone()) | 238 if (m_frame->selection().isNone()) |
239 return; | 239 return; |
240 | 240 |
241 if (Element* target = m_frame.document()->focusedElement()) { | 241 if (Element* target = m_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, m_frame->domWindow(), m_frame->selectedText(), underlines)); |
263 event = CompositionEvent::create(EventTypeNames::compositionupda
te, m_frame.domWindow(), text, underlines); | 263 event = CompositionEvent::create(EventTypeNames::compositionupda
te, m_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, m_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,
m_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(m_frame->document()); |
279 TypingCommand::deleteSelection(*m_frame.document(), TypingCommand::Preve
ntSpellChecking); | 279 TypingCommand::deleteSelection(*m_frame->document(), TypingCommand::Prev
entSpellChecking); |
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(m_frame->document()); |
287 TypingCommand::insertText(*m_frame.document(), text, TypingCommand::Sele
ctInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextComposi
tionUpdate); | 287 TypingCommand::insertText(*m_frame->document(), text, TypingCommand::Sel
ectInsertedText | TypingCommand::PreventSpellChecking, TypingCommand::TextCompos
itionUpdate); |
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 = m_frame->selection().base().downstream(); |
291 Position extent = m_frame.selection().extent(); | 291 Position extent = m_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 m_frame->selection().setSelectedRange(selectedRange.get(), DOWNSTREA
M, 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 = m_frame->selection().rootEditableElement(); |
321 Position base = m_frame.selection().base().downstream(); | 321 Position base = m_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 != m_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(m_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 = m_frame->selection().selection().firstRang
e(); |
371 if (!range) | 371 if (!range) |
372 return PlainTextRange(); | 372 return PlainTextRange(); |
373 ContainerNode* editable = m_frame.selection().rootEditableElementOrTreeScope
RootNode(); | 373 ContainerNode* editable = m_frame->selection().rootEditableElementOrTreeScop
eRootNode(); |
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 = m_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 m_frame->selection().setSelectedRange(range.get(), VP_DEFAULT_AFFINIT
Y, 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 (m_frame->selection().start() == m_frame->selection().end() && befor
e <= static_cast<int>(selectionOffsets.start())); |
427 TypingCommand::deleteSelection(*m_frame.document()); | 427 TypingCommand::deleteSelection(*m_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 |