WebKit2: provide new bundle APIs to allow bundle clients to be notified of pasteboard...
[WebKit-https.git] / Source / WebKit / blackberry / WebCoreSupport / EditorClientBlackBerry.cpp
1 /*
2  * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
3  * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19
20 #include "config.h"
21 #include "EditorClientBlackBerry.h"
22
23 #include "AutofillManager.h"
24 #include "DOMSupport.h"
25 #include "DumpRenderTreeClient.h"
26 #include "EditCommand.h"
27 #include "Frame.h"
28 #include "HTMLInputElement.h"
29 #include "HTMLNames.h"
30 #include "InputHandler.h"
31 #include "KeyboardEvent.h"
32 #include "NotImplemented.h"
33 #include "Page.h"
34 #include "PlatformKeyboardEvent.h"
35 #include "SelectionHandler.h"
36 #include "WebPage_p.h"
37 #include "WindowsKeyboardCodes.h"
38
39 using namespace BlackBerry::WebKit;
40
41 namespace WebCore {
42
43 // Arbitrary depth limit for the undo stack, to keep it from using
44 // unbounded memory. This is the maximum number of distinct undoable
45 // actions -- unbroken stretches of typed characters are coalesced
46 // into a single action only when not interrupted by string replacements
47 // triggered by replaceText calls.
48 static const size_t maximumUndoStackDepth = 1000;
49
50 EditorClientBlackBerry::EditorClientBlackBerry(WebPagePrivate* webPagePrivate)
51     : m_webPagePrivate(webPagePrivate)
52     , m_waitingForCursorFocus(false)
53     , m_spellCheckState(SpellCheckDefault)
54     , m_inRedo(false)
55 {
56 }
57
58 void EditorClientBlackBerry::pageDestroyed()
59 {
60     delete this;
61 }
62
63 bool EditorClientBlackBerry::shouldDeleteRange(Range* range)
64 {
65     if (m_webPagePrivate->m_dumpRenderTree)
66         return m_webPagePrivate->m_dumpRenderTree->shouldDeleteDOMRange(range);
67     return true;
68 }
69
70 bool EditorClientBlackBerry::shouldShowDeleteInterface(HTMLElement*)
71 {
72     notImplemented();
73     return false;
74 }
75
76 bool EditorClientBlackBerry::smartInsertDeleteEnabled()
77 {
78     notImplemented();
79     return false;
80 }
81
82 bool EditorClientBlackBerry::isSelectTrailingWhitespaceEnabled()
83 {
84     if (m_webPagePrivate->m_dumpRenderTree)
85         return m_webPagePrivate->m_dumpRenderTree->isSelectTrailingWhitespaceEnabled();
86     return false;
87 }
88
89 void EditorClientBlackBerry::enableSpellChecking(bool enable)
90 {
91     m_spellCheckState = enable ? SpellCheckDefault : SpellCheckOff;
92 }
93
94 bool EditorClientBlackBerry::shouldSpellCheckFocusedField()
95 {
96     const Frame* frame = m_webPagePrivate->focusedOrMainFrame();
97     if (!frame || !frame->document() || !frame->editor())
98         return false;
99
100     const Node* node = frame->document()->focusedNode();
101     // NOTE: This logic is taken from EditorClientImpl::shouldSpellcheckByDefault
102     // If |node| is null, we default to allowing spellchecking. This is done in
103     // order to mitigate the issue when the user clicks outside the textbox, as a
104     // result of which |node| becomes null, resulting in all the spell check
105     // markers being deleted. Also, the Frame will decide not to do spellchecking
106     // if the user can't edit - so returning true here will not cause any problems
107     // to the Frame's behavior.
108     if (!node)
109         return true;
110
111     // If the field does not support autocomplete, do not do spellchecking.
112     if (node->isElementNode()) {
113         const Element* element = static_cast<const Element*>(node);
114         if (element->hasTagName(HTMLNames::inputTag) && !DOMSupport::elementSupportsAutocomplete(element))
115             return false;
116     }
117
118     // Check if the node disables spell checking directly.
119     return frame->editor()->isSpellCheckingEnabledInFocusedNode();
120 }
121
122 bool EditorClientBlackBerry::isContinuousSpellCheckingEnabled()
123 {
124     if (m_spellCheckState == SpellCheckOff)
125         return false;
126     if (m_spellCheckState == SpellCheckOn)
127         return true;
128     return shouldSpellCheckFocusedField();
129 }
130
131 void EditorClientBlackBerry::toggleContinuousSpellChecking()
132 {
133     // Use the current state to determine how to toggle, if it hasn't
134     // been explicitly set, it will toggle based on the field type.
135     if (isContinuousSpellCheckingEnabled())
136         m_spellCheckState = SpellCheckOff;
137     else
138         m_spellCheckState = SpellCheckOn;
139 }
140
141 bool EditorClientBlackBerry::isGrammarCheckingEnabled()
142 {
143     notImplemented();
144     return false;
145 }
146
147 void EditorClientBlackBerry::toggleGrammarChecking()
148 {
149     notImplemented();
150 }
151
152 int EditorClientBlackBerry::spellCheckerDocumentTag()
153 {
154     notImplemented();
155     return 0;
156 }
157
158 bool EditorClientBlackBerry::shouldBeginEditing(Range* range)
159 {
160     if (m_webPagePrivate->m_dumpRenderTree)
161         return m_webPagePrivate->m_dumpRenderTree->shouldBeginEditingInDOMRange(range);
162
163     return true;
164 }
165
166 bool EditorClientBlackBerry::shouldEndEditing(Range* range)
167 {
168     if (m_webPagePrivate->m_dumpRenderTree)
169         return m_webPagePrivate->m_dumpRenderTree->shouldEndEditingInDOMRange(range);
170     return true;
171 }
172
173 bool EditorClientBlackBerry::shouldInsertNode(Node* node, Range* range, EditorInsertAction insertAction)
174 {
175     if (m_webPagePrivate->m_dumpRenderTree)
176         return m_webPagePrivate->m_dumpRenderTree->shouldInsertNode(node, range, static_cast<int>(insertAction));
177     return true;
178 }
179
180 bool EditorClientBlackBerry::shouldInsertText(const WTF::String& text, Range* range, EditorInsertAction insertAction)
181 {
182     if (m_webPagePrivate->m_dumpRenderTree)
183         return m_webPagePrivate->m_dumpRenderTree->shouldInsertText(text, range, static_cast<int>(insertAction));
184     return true;
185 }
186
187 bool EditorClientBlackBerry::shouldChangeSelectedRange(Range* fromRange, Range* toRange, EAffinity affinity, bool stillSelecting)
188 {
189     if (m_webPagePrivate->m_dumpRenderTree)
190         return m_webPagePrivate->m_dumpRenderTree->shouldChangeSelectedDOMRangeToDOMRangeAffinityStillSelecting(fromRange, toRange, static_cast<int>(affinity), stillSelecting);
191
192     Frame* frame = m_webPagePrivate->focusedOrMainFrame();
193     if (frame && frame->document()) {
194         if (frame->document()->focusedNode() && frame->document()->focusedNode()->hasTagName(HTMLNames::selectTag))
195             return false;
196
197         // Check if this change does not represent a focus change and input is active and if so ensure the keyboard is visible.
198         if (m_webPagePrivate->m_inputHandler->isInputMode() && fromRange && toRange && (fromRange->startContainer() == toRange->startContainer()))
199             m_webPagePrivate->m_inputHandler->notifyClientOfKeyboardVisibilityChange(true);
200     }
201
202     return true;
203 }
204
205 bool EditorClientBlackBerry::shouldApplyStyle(StylePropertySet*, Range*)
206 {
207     notImplemented();
208     return true;
209 }
210
211 bool EditorClientBlackBerry::shouldMoveRangeAfterDelete(Range*, Range*)
212 {
213     notImplemented();
214     return true;
215 }
216
217 void EditorClientBlackBerry::didBeginEditing()
218 {
219     if (m_webPagePrivate->m_dumpRenderTree)
220         m_webPagePrivate->m_dumpRenderTree->didBeginEditing();
221 }
222
223 void EditorClientBlackBerry::respondToChangedContents()
224 {
225     if (m_webPagePrivate->m_dumpRenderTree)
226         m_webPagePrivate->m_dumpRenderTree->didChange();
227 }
228
229 void EditorClientBlackBerry::respondToChangedSelection(Frame* frame)
230 {
231     if (m_waitingForCursorFocus)
232         m_waitingForCursorFocus = false;
233     else
234         m_webPagePrivate->selectionChanged(frame);
235
236     if (m_webPagePrivate->m_dumpRenderTree)
237         m_webPagePrivate->m_dumpRenderTree->didChangeSelection();
238 }
239
240 void EditorClientBlackBerry::didEndEditing()
241 {
242     if (m_webPagePrivate->m_dumpRenderTree)
243         m_webPagePrivate->m_dumpRenderTree->didEndEditing();
244 }
245
246 void EditorClientBlackBerry::respondToSelectionAppearanceChange()
247 {
248     m_webPagePrivate->m_selectionHandler->selectionPositionChanged();
249 }
250
251 void EditorClientBlackBerry::didWriteSelectionToPasteboard()
252 {
253     notImplemented();
254 }
255
256 void EditorClientBlackBerry::willWriteSelectionToPasteboard(WebCore::Range*)
257 {
258     notImplemented();
259 }
260
261 void EditorClientBlackBerry::getClientPasteboardDataForRange(WebCore::Range*, Vector<String>& pasteboardTypes, Vector<RefPtr<WebCore::SharedBuffer> >& pasteboardData)
262 {
263     notImplemented();
264 }
265
266 void EditorClientBlackBerry::didSetSelectionTypesForPasteboard()
267 {
268     notImplemented();
269 }
270
271 void EditorClientBlackBerry::registerUndoStep(PassRefPtr<UndoStep> step)
272 {
273     // Remove the oldest item if we've reached the maximum capacity for the stack.
274     if (m_undoStack.size() == maximumUndoStackDepth)
275         m_undoStack.removeFirst();
276
277     if (!m_inRedo)
278         m_redoStack.clear();
279
280     m_undoStack.append(step);
281 }
282
283 void EditorClientBlackBerry::registerRedoStep(PassRefPtr<UndoStep> step)
284 {
285     m_redoStack.append(step);
286 }
287
288 void EditorClientBlackBerry::clearUndoRedoOperations()
289 {
290     m_undoStack.clear();
291     m_redoStack.clear();
292 }
293
294 bool EditorClientBlackBerry::canUndo() const
295 {
296     return !m_undoStack.isEmpty();
297 }
298
299 bool EditorClientBlackBerry::canRedo() const
300 {
301     return !m_redoStack.isEmpty();
302 }
303
304 bool EditorClientBlackBerry::canCopyCut(Frame*, bool defaultValue) const
305 {
306     return defaultValue;
307 }
308
309 bool EditorClientBlackBerry::canPaste(Frame*, bool defaultValue) const
310 {
311     return defaultValue;
312 }
313
314 void EditorClientBlackBerry::undo()
315 {
316     if (canUndo()) {
317         EditCommandStack::iterator back = --m_undoStack.end();
318         RefPtr<UndoStep> command(*back);
319         m_undoStack.remove(back);
320
321         // Unapply will call us back to push this command onto the redo stack.
322         command->unapply();
323     }
324 }
325
326 void EditorClientBlackBerry::redo()
327 {
328     if (canRedo()) {
329         EditCommandStack::iterator back = --m_redoStack.end();
330         RefPtr<UndoStep> command(*back);
331         m_redoStack.remove(back);
332
333         ASSERT(!m_inRedo);
334         m_inRedo = true;
335
336         // Reapply will call us back to push this command onto the undo stack.
337         command->reapply();
338         m_inRedo = false;
339     }
340 }
341
342 static const unsigned CtrlKey = 1 << 0;
343 static const unsigned AltKey = 1 << 1;
344 static const unsigned ShiftKey = 1 << 2;
345
346 struct KeyDownEntry {
347     unsigned virtualKey;
348     unsigned modifiers;
349     const char* name;
350 };
351
352 struct KeyPressEntry {
353     unsigned charCode;
354     unsigned modifiers;
355     const char* name;
356 };
357
358 static const KeyDownEntry keyDownEntries[] = {
359     { VK_LEFT,   0,                  "MoveLeft"                                    },
360     { VK_LEFT,   ShiftKey,           "MoveLeftAndModifySelection"                  },
361     { VK_LEFT,   CtrlKey,            "MoveWordLeft"                                },
362     { VK_LEFT,   CtrlKey | ShiftKey, "MoveWordLeftAndModifySelection"              },
363     { VK_RIGHT,  0,                  "MoveRight"                                   },
364     { VK_RIGHT,  ShiftKey,           "MoveRightAndModifySelection"                 },
365     { VK_RIGHT,  CtrlKey,            "MoveWordRight"                               },
366     { VK_RIGHT,  CtrlKey | ShiftKey, "MoveWordRightAndModifySelection"             },
367     { VK_UP,     0,                  "MoveUp"                                      },
368     { VK_UP,     ShiftKey,           "MoveUpAndModifySelection"                    },
369     { VK_DOWN,   0,                  "MoveDown"                                    },
370     { VK_DOWN,   ShiftKey,           "MoveDownAndModifySelection"                  },
371     { VK_PRIOR,  0,                  "MovePageUp"                                  },
372     { VK_PRIOR,  ShiftKey,           "MovePageUpAndModifySelection"                },
373     { VK_NEXT,   0,                  "MovePageDown"                                },
374     { VK_NEXT,   ShiftKey,           "MovePageDownAndModifySelection"              },
375     { VK_HOME,   0,                  "MoveToBeginningOfLine"                       },
376     { VK_HOME,   ShiftKey,           "MoveToBeginningOfLineAndModifySelection"     },
377     { VK_HOME,   CtrlKey,            "MoveToBeginningOfDocument"                   },
378     { VK_HOME,   CtrlKey | ShiftKey, "MoveToBeginningOfDocumentAndModifySelection" },
379     { VK_END,    0,                  "MoveToEndOfLine"                             },
380     { VK_END,    ShiftKey,           "MoveToEndOfLineAndModifySelection"           },
381     { VK_END,    CtrlKey,            "MoveToEndOfDocument"                         },
382     { VK_END,    CtrlKey | ShiftKey, "MoveToEndOfDocumentAndModifySelection"       },
383
384     { 'B',       CtrlKey,            "ToggleBold"                                  },
385     { 'I',       CtrlKey,            "ToggleItalic"                                },
386     { 'U',       CtrlKey,            "ToggleUnderline"                             },
387
388     { VK_BACK,   0,                  "DeleteBackward"                              },
389     { VK_BACK,   ShiftKey,           "DeleteBackward"                              },
390     { VK_DELETE, 0,                  "DeleteForward"                               },
391     { VK_BACK,   CtrlKey,            "DeleteWordBackward"                          },
392     { VK_DELETE, CtrlKey,            "DeleteWordForward"                           },
393
394     { 'C',       CtrlKey,            "Copy"                                        },
395     { 'V',       CtrlKey,            "Paste"                                       },
396     { 'V',       CtrlKey | ShiftKey, "PasteAndMatchStyle"                          },
397     { 'X',       CtrlKey,            "Cut"                                         },
398     { VK_INSERT, CtrlKey,            "Copy"                                        },
399     { VK_DELETE, ShiftKey,           "Cut"                                         },
400     { VK_INSERT, ShiftKey,           "Paste"                                       },
401
402     { 'A',       CtrlKey,            "SelectAll"                                   },
403     { 'Z',       CtrlKey,            "Undo"                                        },
404     { 'Z',       CtrlKey | ShiftKey, "Redo"                                        },
405     { 'Y',       CtrlKey,            "Redo"                                        },
406 };
407
408 static const KeyPressEntry keyPressEntries[] = {
409     { '\t',   0,                  "InsertTab"                                   },
410     { '\t',   ShiftKey,           "InsertBacktab"                               },
411     { '\r',   0,                  "InsertNewline"                               },
412     { '\r',   CtrlKey,            "InsertNewline"                               },
413     { '\r',   AltKey,             "InsertNewline"                               },
414     { '\r',   ShiftKey,           "InsertLineBreak"                             },
415     { '\r',   AltKey | ShiftKey,  "InsertNewline"                               },
416 };
417
418
419 const char* EditorClientBlackBerry::interpretKeyEvent(const KeyboardEvent* event)
420 {
421     ASSERT(event->type() == eventNames().keydownEvent || event->type() == eventNames().keypressEvent);
422
423     static HashMap<int, const char*>* keyDownCommandsMap = 0;
424     static HashMap<int, const char*>* keyPressCommandsMap = 0;
425
426     if (!keyDownCommandsMap) {
427         keyDownCommandsMap = new HashMap<int, const char*>;
428         keyPressCommandsMap = new HashMap<int, const char*>;
429
430         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyDownEntries); ++i)
431             keyDownCommandsMap->set(keyDownEntries[i].modifiers << 16 | keyDownEntries[i].virtualKey, keyDownEntries[i].name);
432
433         for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyPressEntries); ++i)
434             keyPressCommandsMap->set(keyPressEntries[i].modifiers << 16 | keyPressEntries[i].charCode, keyPressEntries[i].name);
435     }
436
437     unsigned modifiers = 0;
438     if (event->shiftKey())
439         modifiers |= ShiftKey;
440     if (event->altKey())
441         modifiers |= AltKey;
442     if (event->ctrlKey())
443         modifiers |= CtrlKey;
444
445     if (event->type() == eventNames().keydownEvent) {
446         int mapKey = modifiers << 16 | event->keyCode();
447         return mapKey ? keyDownCommandsMap->get(mapKey) : 0;
448     }
449
450     int mapKey = modifiers << 16 | event->charCode();
451     return mapKey ? keyPressCommandsMap->get(mapKey) : 0;
452 }
453
454 void EditorClientBlackBerry::handleKeyboardEvent(KeyboardEvent* event)
455 {
456     ASSERT(event);
457
458     const PlatformKeyboardEvent* platformEvent = event->keyEvent();
459     if (!platformEvent)
460         return;
461
462     ASSERT(event->target()->toNode());
463     Frame* frame = event->target()->toNode()->document()->frame();
464     ASSERT(frame);
465
466     String commandName = interpretKeyEvent(event);
467
468     // Check to see we are not trying to insert text on key down.
469     ASSERT(!(event->type() == eventNames().keydownEvent && frame->editor()->command(commandName).isTextInsertion()));
470
471     if (!commandName.isEmpty()) {
472         // Hot key handling. Cancel processing mode.
473         if (commandName != "DeleteBackward")
474             m_webPagePrivate->m_inputHandler->setProcessingChange(false);
475
476         if (frame->editor()->command(commandName).execute())
477             event->setDefaultHandled();
478         return;
479     }
480
481     if (!frame->editor()->canEdit())
482         return;
483
484     // Text insertion commands should only be triggered from keypressEvent.
485     // There is an assert guaranteeing this in
486     // EventHandler::handleTextInputEvent. Note that windowsVirtualKeyCode
487     // is not set for keypressEvent: special keys should have been already
488     // handled in keydownEvent, which is called first.
489     if (event->type() != eventNames().keypressEvent)
490         return;
491
492     // Don't insert null or control characters as they can result in unexpected behaviour.
493     if (event->charCode() < ' ')
494         return;
495
496     // Don't insert anything if a modifier is pressed.
497     if (event->ctrlKey() || event->altKey())
498         return;
499
500     if (!platformEvent->text().isEmpty()) {
501         if (frame->editor()->insertText(platformEvent->text(), event))
502             event->setDefaultHandled();
503     }
504 }
505
506 void EditorClientBlackBerry::handleInputMethodKeydown(KeyboardEvent*)
507 {
508     notImplemented();
509 }
510
511 void EditorClientBlackBerry::textFieldDidBeginEditing(Element*)
512 {
513     notImplemented();
514 }
515
516 void EditorClientBlackBerry::textFieldDidEndEditing(Element* element)
517 {
518     if (m_webPagePrivate->m_webSettings->isFormAutofillEnabled()) {
519         if (HTMLInputElement* inputElement = element->toInputElement())
520             m_webPagePrivate->m_autofillManager->textFieldDidEndEditing(inputElement);
521     }
522 }
523
524 void EditorClientBlackBerry::textDidChangeInTextField(Element* element)
525 {
526     if (m_webPagePrivate->m_webSettings->isFormAutofillEnabled()) {
527         if (HTMLInputElement* inputElement = element->toInputElement())
528             m_webPagePrivate->m_autofillManager->didChangeInTextField(inputElement);
529     }
530 }
531
532 bool EditorClientBlackBerry::doTextFieldCommandFromEvent(Element*, KeyboardEvent*)
533 {
534     notImplemented();
535     return false;
536 }
537
538 void EditorClientBlackBerry::textWillBeDeletedInTextField(Element*)
539 {
540     notImplemented();
541 }
542
543 void EditorClientBlackBerry::textDidChangeInTextArea(Element*)
544 {
545     notImplemented();
546 }
547
548 bool EditorClientBlackBerry::shouldEraseMarkersAfterChangeSelection(TextCheckingType) const
549 {
550     return true;
551 }
552
553 void EditorClientBlackBerry::ignoreWordInSpellDocument(const WTF::String&)
554 {
555     notImplemented();
556 }
557
558 void EditorClientBlackBerry::learnWord(const WTF::String&)
559 {
560     notImplemented();
561 }
562
563 void EditorClientBlackBerry::checkSpellingOfString(const UChar* text, int textLength, int* misspellLocation, int* misspellLength)
564 {
565     notImplemented();
566 }
567
568 WTF::String EditorClientBlackBerry::getAutoCorrectSuggestionForMisspelledWord(const WTF::String& misspelledWord)
569 {
570     notImplemented();
571     return WTF::String();
572 }
573
574 void EditorClientBlackBerry::checkGrammarOfString(const UChar*, int, WTF::Vector<GrammarDetail, 0u>&, int*, int*)
575 {
576     notImplemented();
577 }
578
579 void EditorClientBlackBerry::requestCheckingOfString(PassRefPtr<TextCheckingRequest> testCheckingRequest)
580 {
581     m_webPagePrivate->m_inputHandler->requestCheckingOfString(textCheckingRequest);
582 }
583
584 void EditorClientBlackBerry::checkTextOfParagraph(const UChar*, int, TextCheckingTypeMask, Vector<TextCheckingResult>&)
585 {
586     notImplemented();
587 }
588
589 TextCheckerClient* EditorClientBlackBerry::textChecker()
590 {
591     return this;
592 }
593
594 void EditorClientBlackBerry::updateSpellingUIWithGrammarString(const WTF::String&, const GrammarDetail&)
595 {
596     notImplemented();
597 }
598
599 void EditorClientBlackBerry::updateSpellingUIWithMisspelledWord(const WTF::String&)
600 {
601     notImplemented();
602 }
603
604 void EditorClientBlackBerry::showSpellingUI(bool)
605 {
606     notImplemented();
607 }
608
609 bool EditorClientBlackBerry::spellingUIIsShowing()
610 {
611     notImplemented();
612     return false;
613 }
614
615 void EditorClientBlackBerry::getGuessesForWord(const WTF::String&, WTF::Vector<WTF::String, 0u>&)
616 {
617     notImplemented();
618 }
619
620 void EditorClientBlackBerry::getGuessesForWord(const String&, const String&, Vector<String>&)
621 {
622     notImplemented();
623 }
624
625 void EditorClientBlackBerry::willSetInputMethodState()
626 {
627     notImplemented();
628 }
629
630 void EditorClientBlackBerry::setInputMethodState(bool)
631 {
632     m_webPagePrivate->m_inputHandler->focusedNodeChanged();
633 }
634
635 } // namespace WebCore