[BlackBerry] Null check calls associated with retrieving the caret rect.
[WebKit-https.git] / Source / WebKit / blackberry / WebKitSupport / InputHandler.cpp
1 /*
2  * Copyright (C) 2009, 2010, 2011, 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20 #include "InputHandler.h"
21
22 #include "BackingStore.h"
23 #include "BackingStoreClient.h"
24 #include "CSSStyleDeclaration.h"
25 #include "Chrome.h"
26 #include "ColorPickerClient.h"
27 #include "DOMSupport.h"
28 #include "DatePickerClient.h"
29 #include "Document.h"
30 #include "DocumentLoader.h"
31 #include "DocumentMarkerController.h"
32 #include "FocusController.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "HTMLFormElement.h"
36 #include "HTMLInputElement.h"
37 #include "HTMLNames.h"
38 #include "HTMLOptGroupElement.h"
39 #include "HTMLOptionElement.h"
40 #include "HTMLSelectElement.h"
41 #include "HTMLTextAreaElement.h"
42 #include "NotImplemented.h"
43 #include "Page.h"
44 #include "PlatformKeyboardEvent.h"
45 #include "PluginView.h"
46 #include "Range.h"
47 #include "RenderLayer.h"
48 #include "RenderMenuList.h"
49 #include "RenderPart.h"
50 #include "RenderText.h"
51 #include "RenderTextControl.h"
52 #include "RenderWidget.h"
53 #include "RenderedDocumentMarker.h"
54 #include "ScopePointer.h"
55 #include "SelectPopupClient.h"
56 #include "SelectionHandler.h"
57 #include "SpellChecker.h"
58 #include "TextCheckerClient.h"
59 #include "TextIterator.h"
60 #include "VisiblePosition.h"
61 #include "WebPageClient.h"
62 #include "WebPage_p.h"
63 #include "WebSettings.h"
64 #include "htmlediting.h"
65 #include "visible_units.h"
66
67 #include <BlackBerryPlatformIMF.h>
68 #include <BlackBerryPlatformKeyboardEvent.h>
69 #include <BlackBerryPlatformLog.h>
70 #include <BlackBerryPlatformMisc.h>
71 #include <BlackBerryPlatformScreen.h>
72 #include <BlackBerryPlatformSettings.h>
73 #include <sys/keycodes.h>
74 #include <wtf/text/CString.h>
75
76 #define ENABLE_INPUT_LOG 0
77 #define ENABLE_FOCUS_LOG 0
78 #define ENABLE_SPELLING_LOG 0
79
80 static const unsigned MaxLearnTextDataSize = 500;
81
82 using namespace BlackBerry::Platform;
83 using namespace WebCore;
84
85 #if ENABLE_INPUT_LOG
86 #define InputLog(severity, format, ...) logAlways(severity, format, ## __VA_ARGS__)
87 #else
88 #define InputLog(severity, format, ...)
89 #endif // ENABLE_INPUT_LOG
90
91 #if ENABLE_FOCUS_LOG
92 #define FocusLog(severity, format, ...) logAlways(severity, format, ## __VA_ARGS__)
93 #else
94 #define FocusLog(severity, format, ...)
95 #endif // ENABLE_FOCUS_LOG
96
97 #if ENABLE_SPELLING_LOG
98 #define SpellingLog(severity, format, ...) logAlways(severity, format, ## __VA_ARGS__)
99 #else
100 #define SpellingLog(severity, format, ...)
101 #endif // ENABLE_SPELLING_LOG
102
103 namespace BlackBerry {
104 namespace WebKit {
105
106 class ProcessingChangeGuard {
107 public:
108     ProcessingChangeGuard(InputHandler* inputHandler)
109         : m_inputHandler(inputHandler)
110         , m_savedProcessingChange(false)
111     {
112         ASSERT(m_inputHandler);
113
114         m_savedProcessingChange = m_inputHandler->processingChange();
115         m_inputHandler->setProcessingChange(true);
116     }
117
118     ~ProcessingChangeGuard()
119     {
120         m_inputHandler->setProcessingChange(m_savedProcessingChange);
121     }
122
123 private:
124     InputHandler* m_inputHandler;
125     bool m_savedProcessingChange;
126 };
127
128 InputHandler::InputHandler(WebPagePrivate* page)
129     : m_webPage(page)
130     , m_currentFocusElement(0)
131     , m_inputModeEnabled(false)
132     , m_processingChange(false)
133     , m_changingFocus(false)
134     , m_currentFocusElementType(TextEdit)
135     , m_currentFocusElementTextEditMask(DEFAULT_STYLE)
136     , m_composingTextStart(0)
137     , m_composingTextEnd(0)
138     , m_pendingKeyboardVisibilityChange(NoChange)
139     , m_delayKeyboardVisibilityChange(false)
140     , m_request(0)
141     , m_processingTransactionId(-1)
142     , m_receivedBackspaceKeyDown(false)
143     , m_expectedKeyUpChar(0)
144 {
145 }
146
147 InputHandler::~InputHandler()
148 {
149 }
150
151 static BlackBerryInputType convertInputType(const HTMLInputElement* inputElement)
152 {
153     if (inputElement->isPasswordField())
154         return InputTypePassword;
155     if (inputElement->isSearchField())
156         return InputTypeSearch;
157     if (inputElement->isEmailField())
158         return InputTypeEmail;
159     if (inputElement->isMonthControl())
160         return InputTypeMonth;
161     if (inputElement->isNumberField())
162         return InputTypeNumber;
163     if (inputElement->isTelephoneField())
164         return InputTypeTelephone;
165     if (inputElement->isURLField())
166         return InputTypeURL;
167 #if ENABLE(INPUT_TYPE_COLOR)
168     if (inputElement->isColorControl())
169         return InputTypeColor;
170 #endif
171     if (inputElement->isDateControl())
172         return InputTypeDate;
173     if (inputElement->isDateTimeControl())
174         return InputTypeDateTime;
175     if (inputElement->isDateTimeLocalControl())
176         return InputTypeDateTimeLocal;
177     if (inputElement->isTimeControl())
178         return InputTypeTime;
179     // FIXME: missing WEEK popup selector
180     if (DOMSupport::elementIdOrNameIndicatesEmail(inputElement))
181         return InputTypeEmail;
182     if (DOMSupport::elementIdOrNameIndicatesUrl(inputElement))
183         return InputTypeURL;
184     if (DOMSupport::elementPatternIndicatesNumber(inputElement))
185         return InputTypeNumber;
186     if (DOMSupport::elementPatternIndicatesHexadecimal(inputElement))
187         return InputTypeHexadecimal;
188
189     return InputTypeText;
190 }
191
192 static int64_t inputStyle(BlackBerryInputType type, const Element* element)
193 {
194     switch (type) {
195     case InputTypeEmail:
196     case InputTypeURL:
197     case InputTypeSearch:
198     case InputTypeText:
199     case InputTypeTextArea:
200         {
201             DOMSupport::AttributeState autoCompleteState = DOMSupport::elementSupportsAutocomplete(element);
202             DOMSupport::AttributeState autoCorrectState = DOMSupport::elementSupportsAutocorrect(element);
203
204             // Autocomplete disabled explicitly.
205             if (autoCompleteState == DOMSupport::Off) {
206                 if (autoCorrectState == DOMSupport::On)
207                     return NO_PREDICTION;
208                 return NO_AUTO_TEXT | NO_PREDICTION | NO_AUTO_CORRECTION;
209             }
210
211             // Autocomplete enabled explicitly.
212             if (autoCompleteState == DOMSupport::On) {
213                 if (autoCorrectState == DOMSupport::Off)
214                     return NO_AUTO_TEXT | NO_AUTO_CORRECTION;
215                 return DEFAULT_STYLE;
216             }
217
218             // Check for reserved strings and known types.
219             if (type == InputTypeEmail || type == InputTypeURL || DOMSupport::elementIdOrNameIndicatesNoAutocomplete(element)) {
220                 if (autoCorrectState == DOMSupport::On)
221                     return NO_PREDICTION;
222                 return NO_AUTO_TEXT | NO_PREDICTION | NO_AUTO_CORRECTION;
223             }
224
225             // Autocomplete state wasn't provided if it is a text area or autocorrect is on, apply support.
226             if (autoCorrectState == DOMSupport::On || (type == InputTypeTextArea && autoCorrectState != DOMSupport::Off))
227                 return DEFAULT_STYLE;
228
229             // Single line text input, without special features explicitly turned on or a textarea
230             // with autocorrect disabled explicitly. Only enable predictions.
231             return NO_AUTO_TEXT | NO_AUTO_CORRECTION;
232         }
233     case InputTypePassword:
234     case InputTypeNumber:
235     case InputTypeTelephone:
236     case InputTypeHexadecimal:
237         // Disable special handling.
238         return NO_AUTO_TEXT | NO_PREDICTION | NO_AUTO_CORRECTION;
239     default:
240         break;
241     }
242     return DEFAULT_STYLE;
243 }
244
245 static VirtualKeyboardType convertInputTypeToVKBType(BlackBerryInputType inputType)
246 {
247     switch (inputType) {
248     case InputTypeURL:
249         return VKBTypeUrl;
250     case InputTypeEmail:
251         return VKBTypeEmail;
252     case InputTypeTelephone:
253         return VKBTypePhone;
254     case InputTypePassword:
255         return VKBTypePassword;
256     case InputTypeNumber:
257     case InputTypeHexadecimal:
258         return VKBTypePin;
259     default:
260         // All other types are text based use default keyboard.
261         return VKBTypeDefault;
262     }
263 }
264
265 static VirtualKeyboardType convertStringToKeyboardType(const AtomicString& string)
266 {
267     DEFINE_STATIC_LOCAL(AtomicString, Default, ("default"));
268     DEFINE_STATIC_LOCAL(AtomicString, Url, ("url"));
269     DEFINE_STATIC_LOCAL(AtomicString, Email, ("email"));
270     DEFINE_STATIC_LOCAL(AtomicString, Password, ("password"));
271     DEFINE_STATIC_LOCAL(AtomicString, Web, ("web"));
272     DEFINE_STATIC_LOCAL(AtomicString, Number, ("number"));
273     DEFINE_STATIC_LOCAL(AtomicString, Symbol, ("symbol"));
274     DEFINE_STATIC_LOCAL(AtomicString, Phone, ("phone"));
275     DEFINE_STATIC_LOCAL(AtomicString, Pin, ("pin"));
276     DEFINE_STATIC_LOCAL(AtomicString, Hex, ("hexadecimal"));
277
278     if (string.isEmpty())
279         return VKBTypeNotSet;
280     if (equalIgnoringCase(string, Default))
281         return VKBTypeDefault;
282     if (equalIgnoringCase(string, Url))
283         return VKBTypeUrl;
284     if (equalIgnoringCase(string, Email))
285         return VKBTypeEmail;
286     if (equalIgnoringCase(string, Password))
287         return VKBTypePassword;
288     if (equalIgnoringCase(string, Web))
289         return VKBTypeWeb;
290     if (equalIgnoringCase(string, Number))
291         return VKBTypeNumPunc;
292     if (equalIgnoringCase(string, Symbol))
293         return VKBTypeSymbol;
294     if (equalIgnoringCase(string, Phone))
295         return VKBTypePhone;
296     if (equalIgnoringCase(string, Pin) || equalIgnoringCase(string, Hex))
297         return VKBTypePin;
298     return VKBTypeNotSet;
299 }
300
301 static VirtualKeyboardType keyboardTypeAttribute(const WebCore::Element* element)
302 {
303     DEFINE_STATIC_LOCAL(QualifiedName, keyboardTypeAttr, (nullAtom, "data-blackberry-virtual-keyboard-type", nullAtom));
304
305     if (element->fastHasAttribute(keyboardTypeAttr)) {
306         AtomicString attributeString = element->fastGetAttribute(keyboardTypeAttr);
307         return convertStringToKeyboardType(attributeString);
308     }
309
310     if (element->isFormControlElement()) {
311         const HTMLFormControlElement* formElement = static_cast<const HTMLFormControlElement*>(element);
312         if (formElement->form() && formElement->form()->fastHasAttribute(keyboardTypeAttr)) {
313             AtomicString attributeString = formElement->form()->fastGetAttribute(keyboardTypeAttr);
314             return convertStringToKeyboardType(attributeString);
315         }
316     }
317
318     return VKBTypeNotSet;
319 }
320
321 static VirtualKeyboardEnterKeyType convertStringToKeyboardEnterKeyType(const AtomicString& string)
322 {
323     DEFINE_STATIC_LOCAL(AtomicString, Default, ("default"));
324     DEFINE_STATIC_LOCAL(AtomicString, Connect, ("connect"));
325     DEFINE_STATIC_LOCAL(AtomicString, Done, ("done"));
326     DEFINE_STATIC_LOCAL(AtomicString, Go, ("go"));
327     DEFINE_STATIC_LOCAL(AtomicString, Join, ("join"));
328     DEFINE_STATIC_LOCAL(AtomicString, Next, ("next"));
329     DEFINE_STATIC_LOCAL(AtomicString, Search, ("search"));
330     DEFINE_STATIC_LOCAL(AtomicString, Send, ("send"));
331     DEFINE_STATIC_LOCAL(AtomicString, Submit, ("submit"));
332
333     if (string.isEmpty())
334         return VKBEnterKeyNotSet;
335     if (equalIgnoringCase(string, Default))
336         return VKBEnterKeyDefault;
337     if (equalIgnoringCase(string, Connect))
338         return VKBEnterKeyConnect;
339     if (equalIgnoringCase(string, Done))
340         return VKBEnterKeyDone;
341     if (equalIgnoringCase(string, Go))
342         return VKBEnterKeyGo;
343     if (equalIgnoringCase(string, Join))
344         return VKBEnterKeyJoin;
345     if (equalIgnoringCase(string, Next))
346         return VKBEnterKeyNext;
347     if (equalIgnoringCase(string, Search))
348         return VKBEnterKeySearch;
349     if (equalIgnoringCase(string, Send))
350         return VKBEnterKeySend;
351     if (equalIgnoringCase(string, Submit))
352         return VKBEnterKeySubmit;
353     return VKBEnterKeyNotSet;
354 }
355
356 static VirtualKeyboardEnterKeyType keyboardEnterKeyTypeAttribute(const WebCore::Element* element)
357 {
358     DEFINE_STATIC_LOCAL(QualifiedName, keyboardEnterKeyTypeAttr, (nullAtom, "data-blackberry-virtual-keyboard-enter-key", nullAtom));
359
360     if (element->fastHasAttribute(keyboardEnterKeyTypeAttr)) {
361         AtomicString attributeString = element->fastGetAttribute(keyboardEnterKeyTypeAttr);
362         return convertStringToKeyboardEnterKeyType(attributeString);
363     }
364
365     if (element->isFormControlElement()) {
366         const HTMLFormControlElement* formElement = static_cast<const HTMLFormControlElement*>(element);
367         if (formElement->form() && formElement->form()->fastHasAttribute(keyboardEnterKeyTypeAttr)) {
368             AtomicString attributeString = formElement->form()->fastGetAttribute(keyboardEnterKeyTypeAttr);
369             return convertStringToKeyboardEnterKeyType(attributeString);
370         }
371     }
372
373     return VKBEnterKeyNotSet;
374 }
375
376 void InputHandler::setProcessingChange(bool processingChange)
377 {
378     if (processingChange == m_processingChange)
379         return;
380
381     m_processingChange = processingChange;
382
383     if (!m_processingChange)
384         m_webPage->m_selectionHandler->inputHandlerDidFinishProcessingChange();
385 }
386
387 WTF::String InputHandler::elementText()
388 {
389     if (!isActiveTextEdit())
390         return WTF::String();
391
392     return DOMSupport::inputElementText(m_currentFocusElement.get());
393 }
394
395 BlackBerryInputType InputHandler::elementType(Element* element) const
396 {
397     if (const HTMLInputElement* inputElement = static_cast<const HTMLInputElement*>(element->toInputElement()))
398         return convertInputType(inputElement);
399
400     if (element->hasTagName(HTMLNames::textareaTag))
401         return InputTypeTextArea;
402
403     // Default to InputTypeTextArea for content editable fields.
404     return InputTypeTextArea;
405 }
406
407 void InputHandler::focusedNodeChanged()
408 {
409     ASSERT(m_webPage->m_page->focusController());
410     Frame* frame = m_webPage->m_page->focusController()->focusedOrMainFrame();
411     if (!frame || !frame->document())
412         return;
413
414     Node* node = frame->document()->focusedNode();
415
416     if (isActiveTextEdit() && m_currentFocusElement == node) {
417         notifyClientOfKeyboardVisibilityChange(true);
418         return;
419     }
420
421     if (node && node->isElementNode()) {
422         Element* element = static_cast<Element*>(node);
423         if (DOMSupport::isElementTypePlugin(element)) {
424             setPluginFocused(element);
425             return;
426         }
427
428         if (DOMSupport::isTextBasedContentEditableElement(element)) {
429             // Focused node is a text based input field, textarea or content editable field.
430             setElementFocused(element);
431             return;
432         }
433     }
434
435     if (isActiveTextEdit() && m_currentFocusElement->isContentEditable()) {
436         // This is a special handler for content editable fields. The focus node is the top most
437         // field that is content editable, however, by enabling / disabling designmode and
438         // content editable, it is possible through javascript or selection to trigger the focus node to
439         // change even while maintaining editing on the same selection point. If the focus element
440         // isn't contentEditable, but the current selection is, don't send a change notification.
441
442         // When processing changes selection changes occur that may reset the focus element
443         // and could potentially cause a crash as m_currentFocusElement should not be
444         // changed during processing of an EditorCommand.
445         if (processingChange())
446             return;
447
448         Frame* frame = m_currentFocusElement->document()->frame();
449         ASSERT(frame);
450
451         // Test the current selection to make sure that the content in focus is still content
452         // editable. This may mean Javascript triggered a focus change by modifying the
453         // top level parent of this object's content editable state without actually modifying
454         // this particular object.
455         // Example site: html5demos.com/contentEditable - blur event triggers focus change.
456         if (frame == m_webPage->focusedOrMainFrame() && frame->selection()->start().anchorNode()
457             && frame->selection()->start().anchorNode()->isContentEditable())
458                 return;
459     }
460
461     // No valid focus element found for handling.
462     setElementUnfocused();
463 }
464
465 void InputHandler::setPluginFocused(Element* element)
466 {
467     ASSERT(DOMSupport::isElementTypePlugin(element));
468
469     if (isActiveTextEdit())
470         setElementUnfocused();
471
472     m_currentFocusElementType = Plugin;
473     m_currentFocusElement = element;
474 }
475
476 static bool convertStringToWchar(const WTF::String& string, wchar_t* dest, int destCapacity, int* destLength)
477 {
478     ASSERT(dest);
479
480     if (!string.length()) {
481         destLength = 0;
482         return true;
483     }
484
485     UErrorCode ec = U_ZERO_ERROR;
486     // wchar_t strings sent to IMF are 32 bit so casting to UChar32 is safe.
487     u_strToUTF32(reinterpret_cast<UChar32*>(dest), destCapacity, destLength, string.characters(), string.length(), &ec);
488     if (ec) {
489         logAlways(LogLevelCritical, "InputHandler::convertStringToWchar Error converting string ec (%d).", ec);
490         destLength = 0;
491         return false;
492     }
493     return true;
494 }
495
496 static bool convertStringToWcharVector(const WTF::String& string, WTF::Vector<wchar_t>& wcharString)
497 {
498     ASSERT(wcharString.isEmpty());
499
500     int length = string.length();
501     if (!length)
502         return true;
503
504     if (!wcharString.tryReserveCapacity(length + 1)) {
505         logAlways(LogLevelCritical, "InputHandler::convertStringToWcharVector Cannot allocate memory for string.");
506         return false;
507     }
508
509     int destLength = 0;
510     if (!convertStringToWchar(string, wcharString.data(), length + 1, &destLength))
511         return false;
512
513     wcharString.resize(destLength);
514     return true;
515 }
516
517 static WTF::String convertSpannableStringToString(spannable_string_t* src)
518 {
519     if (!src || !src->str || !src->length)
520         return WTF::String();
521
522     WTF::Vector<UChar> dest;
523     int destCapacity = (src->length * 2) + 1;
524     if (!dest.tryReserveCapacity(destCapacity)) {
525         logAlways(LogLevelCritical, "InputHandler::convertSpannableStringToString Cannot allocate memory for string.");
526         return WTF::String();
527     }
528
529     int destLength = 0;
530     UErrorCode ec = U_ZERO_ERROR;
531     // wchar_t strings sent from IMF are 32 bit so casting to UChar32 is safe.
532     u_strFromUTF32(dest.data(), destCapacity, &destLength, reinterpret_cast<UChar32*>(src->str), src->length, &ec);
533     if (ec) {
534         logAlways(LogLevelCritical, "InputHandler::convertSpannableStringToString Error converting string ec (%d).", ec);
535         return WTF::String();
536     }
537     dest.resize(destLength);
538     return WTF::String(dest.data(), destLength);
539 }
540
541 void InputHandler::sendLearnTextDetails(const WTF::String& string)
542 {
543     Vector<wchar_t> wcharString;
544     if (!convertStringToWcharVector(string, wcharString) || wcharString.isEmpty())
545         return;
546
547     m_webPage->m_client->inputLearnText(wcharString.data(), wcharString.size());
548 }
549
550 void InputHandler::learnText()
551 {
552     if (!isActiveTextEdit())
553         return;
554
555     // Do not send (or calculate) the text when the field is NO_PREDICTION or NO_AUTO_TEXT.
556     if (m_currentFocusElementTextEditMask & NO_PREDICTION || m_currentFocusElementTextEditMask & NO_AUTO_TEXT)
557         return;
558
559     WTF::String textInField(elementText());
560     textInField = textInField.substring(std::max(0, static_cast<int>(textInField.length() - MaxLearnTextDataSize)), textInField.length());
561     textInField.remove(0, textInField.find(" "));
562
563     // Build up the 500 character strings in word chunks.
564     // Spec says 1000, but memory corruption has been observed.
565     ASSERT(textInField.length() <= MaxLearnTextDataSize);
566
567     if (textInField.isEmpty())
568         return;
569
570     InputLog(LogLevelInfo, "InputHandler::learnText '%s'", textInField.latin1().data());
571     sendLearnTextDetails(textInField);
572 }
573
574 void InputHandler::requestCheckingOfString(PassRefPtr<WebCore::TextCheckingRequest> textCheckingRequest)
575 {
576     m_request = textCheckingRequest;
577
578     if (!m_request) {
579         SpellingLog(LogLevelWarn, "InputHandler::requestCheckingOfString did not receive a valid request.");
580         return;
581     }
582
583     unsigned requestLength = m_request->text().length();
584
585     // Check if the field should be spellchecked.
586     if (!isActiveTextEdit() || !shouldSpellCheckElement(m_currentFocusElement.get()) || requestLength < 2) {
587         m_request->didCancel();
588         return;
589     }
590
591     if (requestLength > MaxSpellCheckingStringLength) {
592         // Cancel this request and send it off in newly created chunks.
593         m_request->didCancel();
594         if (m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->selection()) {
595             // Convert from position back to selection so we can expand the range to include the previous line. This should handle cases when the user hits
596             // enter to finish composing a word and create a new line.
597             VisiblePosition caretPosition = m_currentFocusElement->document()->frame()->selection()->start();
598             VisibleSelection visibleSelection = VisibleSelection(previousLinePosition(caretPosition, caretPosition.lineDirectionPointForBlockDirectionNavigation()), caretPosition);
599             spellCheckBlock(visibleSelection, TextCheckingProcessIncremental);
600         }
601         return;
602     }
603
604     wchar_t* checkingString = (wchar_t*)malloc(sizeof(wchar_t) * (requestLength + 1));
605     if (!checkingString) {
606         logAlways(LogLevelCritical, "InputHandler::requestCheckingOfString Cannot allocate memory for string.");
607         m_request->didCancel();
608         return;
609     }
610
611     int paragraphLength = 0;
612     if (!convertStringToWchar(m_request->text(), checkingString, requestLength + 1, &paragraphLength)) {
613         logAlways(LogLevelCritical, "InputHandler::requestCheckingOfString Failed to convert String to wchar type.");
614         free(checkingString);
615         m_request->didCancel();
616         return;
617     }
618
619     m_processingTransactionId = m_webPage->m_client->checkSpellingOfStringAsync(checkingString, static_cast<unsigned>(paragraphLength));
620     free(checkingString);
621
622     // If the call to the input service did not go through, then cancel the request so we don't block endlessly.
623     // This should still take transactionId as a parameter to maintain the same behavior as if InputMethodSupport
624     // were to cancel a request during processing.
625     if (m_processingTransactionId == -1) { // Error before sending request to input service.
626         m_request->didCancel();
627         return;
628     }
629 }
630
631 void InputHandler::spellCheckingRequestCancelled(int32_t transactionId)
632 {
633     SpellingLog(LogLevelWarn, "InputHandler::spellCheckingRequestCancelled Expected transaction id %d, received %d. %s"
634                 , transactionId
635                 , m_processingTransactionId
636                 , transactionId == m_processingTransactionId ? "" : "We are out of sync with input service.");
637
638     m_request->didCancel();
639     m_processingTransactionId = -1;
640 }
641
642 void InputHandler::spellCheckingRequestProcessed(int32_t transactionId, spannable_string_t* spannableString)
643 {
644     SpellingLog(LogLevelWarn, "InputHandler::spellCheckingRequestProcessed Expected transaction id %d, received %d. %s"
645                 , transactionId
646                 , m_processingTransactionId
647                 , transactionId == m_processingTransactionId ? "" : "We are out of sync with input service.");
648
649     if (!spannableString || !isActiveTextEdit()) {
650         SpellingLog(LogLevelWarn, "InputHandler::spellCheckingRequestProcessed Cancelling request with transactionId %d.", transactionId);
651         m_request->didCancel();
652         m_processingTransactionId = -1;
653         return;
654     }
655
656     Vector<TextCheckingResult> results;
657
658     // Convert the spannableString to TextCheckingResult then append to results vector.
659     WTF::String replacement;
660     TextCheckingResult textCheckingResult;
661     textCheckingResult.type = TextCheckingTypeSpelling;
662     textCheckingResult.replacement = replacement;
663     textCheckingResult.location = 0;
664     textCheckingResult.length = 0;
665
666     span_t* span = spannableString->spans;
667     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
668         if (!span)
669             break;
670         if (span->end < span->start) {
671             m_request->didCancel();
672             return;
673         }
674         if (span->attributes_mask & MISSPELLED_WORD_ATTRIB) {
675             textCheckingResult.location = span->start;
676             // The end point includes the character that it is before. Ie, 0, 0
677             // applies to the first character as the end point includes the character
678             // at the position. This means the endPosition is always +1.
679             textCheckingResult.length = span->end - span->start + 1;
680             results.append(textCheckingResult);
681         }
682         span++;
683     }
684
685     m_request->didSucceed(results);
686 }
687
688 SpellChecker* InputHandler::getSpellChecker()
689 {
690     if (!m_currentFocusElement || !m_currentFocusElement->document())
691         return 0;
692
693     if (Frame* frame = m_currentFocusElement->document()->frame())
694         if (Editor* editor = frame->editor())
695             return editor->spellChecker();
696
697     return 0;
698 }
699
700 bool InputHandler::shouldRequestSpellCheckingOptionsForPoint(Platform::IntPoint& point, const Element* touchedElement, imf_sp_text_t& spellCheckingOptionRequest)
701 {
702     if (!isActiveTextEdit())
703         return false;
704
705     Element* currentFocusElement = m_currentFocusElement.get();
706     if (!currentFocusElement || !currentFocusElement->isElementNode())
707         return false;
708
709     while (!currentFocusElement->isRootEditableElement()) {
710         Element* parentElement = currentFocusElement->parentElement();
711         if (!parentElement)
712             break;
713         currentFocusElement = parentElement;
714     }
715
716     if (touchedElement != currentFocusElement)
717         return false;
718
719     LayoutPoint contentPos(m_webPage->mapFromViewportToContents(point));
720     contentPos = DOMSupport::convertPointToFrame(m_webPage->mainFrame(), m_webPage->focusedOrMainFrame(), roundedIntPoint(contentPos));
721
722     Document* document = currentFocusElement->document();
723     ASSERT(document);
724
725     RenderedDocumentMarker* marker = document->markers()->renderedMarkerContainingPoint(contentPos, DocumentMarker::Spelling);
726     if (!marker)
727         return false;
728
729     // Populate the marker details in preparation for the request as the marker is
730     // not guaranteed to be valid after the cursor is placed.
731     spellCheckingOptionRequest.startTextPosition = marker->startOffset();
732     spellCheckingOptionRequest.endTextPosition = marker->endOffset();
733
734     SpellingLog(LogLevelInfo, "InputHandler::shouldRequestSpellCheckingOptionsForPoint Found spelling marker at point %d, %d\nMarker start %d end %d",
735         point.x(), point.y(), spellCheckingOptionRequest.startTextPosition, spellCheckingOptionRequest.endTextPosition);
736
737     return true;
738 }
739
740 void InputHandler::requestSpellingCheckingOptions(imf_sp_text_t& spellCheckingOptionRequest, const WebCore::IntSize& screenOffset)
741 {
742     // If the caret is no longer active, no message should be sent.
743     if (m_webPage->focusedOrMainFrame()->selection()->selectionType() != VisibleSelection::CaretSelection)
744         return;
745
746     if (!m_currentFocusElement || !m_currentFocusElement->document() || !m_currentFocusElement->document()->frame())
747         return;
748
749     // imf_sp_text_t should be generated in pixel viewport coordinates.
750     WebCore::IntRect caretRect = m_webPage->focusedOrMainFrame()->selection()->selection().visibleStart().absoluteCaretBounds();
751     caretRect = m_webPage->focusedOrMainFrame()->view()->contentsToRootView(caretRect);
752     const WebCore::IntPoint scrollPosition = m_webPage->mainFrame()->view()->scrollPosition();
753     caretRect.move(scrollPosition.x(), scrollPosition.y());
754
755     // Calculate the offset for contentEditable since the marker offsets are relative to the node.
756     // Get caret position. Though the spelling markers might no longer exist, if this method is called we can assume the caret was placed on top of a marker earlier.
757     VisiblePosition caretPosition = m_currentFocusElement->document()->frame()->selection()->selection().visibleStart();
758
759     // Create a range from the start to end of word.
760     RefPtr<Range> rangeSelection = VisibleSelection(startOfWord(caretPosition), endOfWord(caretPosition)).toNormalizedRange();
761     if (!rangeSelection)
762         return;
763
764     unsigned location = 0;
765     unsigned length = 0;
766     TextIterator::getLocationAndLengthFromRange(m_currentFocusElement.get(), rangeSelection.get(), location, length);
767
768     if (location != notFound && length) {
769         spellCheckingOptionRequest.startTextPosition = location;
770         spellCheckingOptionRequest.endTextPosition = location + length;
771     }
772
773     InputLog(LogLevelInfo, "InputHandler::requestSpellingCheckingOptions caretRect topLeft=(%d,%d), bottomRight=(%d,%d), startTextPosition=%d, endTextPosition=%d"
774                             , caretRect.minXMinYCorner().x(), caretRect.minXMinYCorner().y(), caretRect.maxXMaxYCorner().x(), caretRect.maxXMaxYCorner().y()
775                             , spellCheckingOptionRequest.startTextPosition, spellCheckingOptionRequest.endTextPosition);
776
777     m_webPage->m_client->requestSpellingCheckingOptions(spellCheckingOptionRequest, caretRect, screenOffset);
778 }
779
780 void InputHandler::setElementUnfocused(bool refocusOccuring)
781 {
782     if (isActiveTextEdit()) {
783         FocusLog(LogLevelInfo, "InputHandler::setElementUnfocused");
784
785         // Pass any text into the field to IMF to learn.
786         learnText();
787
788         // End any composition that is in progress.
789         finishComposition();
790
791         // Only hide the keyboard if we aren't refocusing on a new input field.
792         if (!refocusOccuring)
793             notifyClientOfKeyboardVisibilityChange(false, true /* triggeredByFocusChange */);
794
795         m_webPage->m_client->inputFocusLost();
796
797         // If the frame selection isn't focused, focus it.
798         if (!m_currentFocusElement->document()->frame()->selection()->isFocused())
799             m_currentFocusElement->document()->frame()->selection()->setFocused(true);
800     }
801
802     // Clear the node details.
803     m_currentFocusElement = 0;
804     m_currentFocusElementType = TextEdit;
805 }
806
807 bool InputHandler::isInputModeEnabled() const
808 {
809     // Input mode is enabled when set, or when dump render tree or always show keyboard setting is enabled.
810     return m_inputModeEnabled || m_webPage->m_dumpRenderTree || Platform::Settings::instance()->alwaysShowKeyboardOnFocus();
811 }
812
813 void InputHandler::setInputModeEnabled(bool active)
814 {
815     FocusLog(LogLevelInfo, "InputHandler::setInputModeEnabled '%s', override is '%s'"
816              , active ? "true" : "false"
817              , m_webPage->m_dumpRenderTree || Platform::Settings::instance()->alwaysShowKeyboardOnFocus() ? "true" : "false");
818
819     m_inputModeEnabled = active;
820
821     // If the frame selection isn't focused, focus it.
822     if (isInputModeEnabled() && isActiveTextEdit() && !m_currentFocusElement->document()->frame()->selection()->isFocused())
823         m_currentFocusElement->document()->frame()->selection()->setFocused(true);
824 }
825
826 void InputHandler::setElementFocused(Element* element)
827 {
828     ASSERT(DOMSupport::isTextBasedContentEditableElement(element));
829     ASSERT(element && element->document() && element->document()->frame());
830
831 #ifdef ENABLE_SPELLING_LOG
832     BlackBerry::Platform::StopWatch timer;
833     timer.start();
834 #endif
835
836     if (!element || !(element->document()))
837         return;
838
839     Frame* frame = element->document()->frame();
840     if (!frame)
841         return;
842
843     if (frame->selection()->isFocused() != isInputModeEnabled())
844         frame->selection()->setFocused(isInputModeEnabled());
845
846     // Clear the existing focus node details.
847     setElementUnfocused(true /*refocusOccuring*/);
848
849     // Mark this element as active and add to frame set.
850     m_currentFocusElement = element;
851     m_currentFocusElementType = TextEdit;
852
853     // Send details to the client about this element.
854     BlackBerryInputType type = elementType(element);
855     m_currentFocusElementTextEditMask = inputStyle(type, element);
856
857     VirtualKeyboardType keyboardType = keyboardTypeAttribute(element);
858     if (keyboardType == VKBTypeNotSet)
859         keyboardType = convertInputTypeToVKBType(type);
860
861     VirtualKeyboardEnterKeyType enterKeyType = keyboardEnterKeyTypeAttribute(element);
862
863     if (enterKeyType == VKBEnterKeyNotSet && type != InputTypeTextArea) {
864         if (element->isFormControlElement()) {
865             const HTMLFormControlElement* formElement = static_cast<const HTMLFormControlElement*>(element);
866             if (formElement->form() && formElement->form()->defaultButton())
867                 enterKeyType = VKBEnterKeySubmit;
868         }
869     }
870
871     FocusLog(LogLevelInfo, "InputHandler::setElementFocused, Type=%d, Style=%d, Keyboard Type=%d, Enter Key=%d", type, m_currentFocusElementTextEditMask, keyboardType, enterKeyType);
872     m_webPage->m_client->inputFocusGained(m_currentFocusElementTextEditMask, keyboardType, enterKeyType);
873
874     handleInputLocaleChanged(m_webPage->m_webSettings->isWritingDirectionRTL());
875
876     if (!m_delayKeyboardVisibilityChange)
877         notifyClientOfKeyboardVisibilityChange(true, true /* triggeredByFocusChange */);
878
879 #ifdef ENABLE_SPELLING_LOG
880     SpellingLog(LogLevelInfo, "InputHandler::setElementFocused Focusing the field took %f seconds.", timer.elapsed());
881 #endif
882
883     // Check if the field should be spellchecked.
884     if (!shouldSpellCheckElement(element))
885         return;
886
887     // Spellcheck the field in its entirety.
888     VisibleSelection focusedBlock = DOMSupport::visibleSelectionForInputElement(element);
889     spellCheckBlock(focusedBlock, TextCheckingProcessBatch);
890
891 #ifdef ENABLE_SPELLING_LOG
892     SpellingLog(LogLevelInfo, "InputHandler::setElementFocused Spellchecking the field increased the total time to focus to %f seconds.", timer.elapsed());
893 #endif
894 }
895
896 bool InputHandler::shouldSpellCheckElement(const Element* element) const
897 {
898     DOMSupport::AttributeState spellCheckAttr = DOMSupport::elementSupportsSpellCheck(element);
899
900     // Explicitly set to off.
901     if (spellCheckAttr == DOMSupport::Off)
902         return false;
903
904     // Undefined and part of a set of cases which we do not wish to check. This includes user names and email addresses, so we are piggybacking on NoAutocomplete cases.
905     if (spellCheckAttr == DOMSupport::Default && (m_currentFocusElementTextEditMask & NO_AUTO_TEXT))
906         return false;
907
908     return true;
909 }
910
911 void InputHandler::spellCheckBlock(VisibleSelection& visibleSelection, TextCheckingProcessType textCheckingProcessType)
912 {
913     if (!isActiveTextEdit())
914         return;
915
916     RefPtr<Range> rangeForSpellChecking = visibleSelection.toNormalizedRange();
917     if (!rangeForSpellChecking || !rangeForSpellChecking->text() || !rangeForSpellChecking->text().length())
918         return;
919
920     SpellChecker* spellChecker = getSpellChecker();
921     if (!spellChecker) {
922         SpellingLog(LogLevelInfo, "InputHandler::spellCheckBlock Failed to spellcheck the current focused element.");
923         return;
924     }
925
926     // If we have a batch request, try to send off the entire block.
927     if (textCheckingProcessType == TextCheckingProcessBatch) {
928         // If total block text is under the limited amount, send the entire chunk.
929         if (rangeForSpellChecking->text().length() < MaxSpellCheckingStringLength) {
930             spellChecker->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling, TextCheckingProcessBatch, rangeForSpellChecking, rangeForSpellChecking));
931             return;
932         }
933     }
934
935     // Since we couldn't check the entire block at once, set up starting and ending markers to fire incrementally.
936     VisiblePosition startPos = visibleSelection.visibleStart();
937     VisiblePosition startOfCurrentLine = startOfLine(startPos);
938     VisiblePosition endOfCurrentLine = endOfLine(startOfCurrentLine);
939
940     while (!isEndOfBlock(startOfCurrentLine)) {
941         // Create a selection with the start and end points of the line, and convert to Range to create a SpellCheckRequest.
942         rangeForSpellChecking = VisibleSelection(startOfCurrentLine, endOfCurrentLine).toNormalizedRange();
943
944         if (rangeForSpellChecking->text().length() < MaxSpellCheckingStringLength) {
945             startOfCurrentLine = nextLinePosition(startOfCurrentLine, startOfCurrentLine.lineDirectionPointForBlockDirectionNavigation());
946             endOfCurrentLine = endOfLine(startOfCurrentLine);
947         } else {
948             // Iterate through words from the start of the line to the end.
949             rangeForSpellChecking = getRangeForSpellCheckWithFineGranularity(startOfCurrentLine, endOfCurrentLine);
950             if (!rangeForSpellChecking) {
951                 SpellingLog(LogLevelWarn, "InputHandler::spellCheckBlock Failed to set text range for spellchecking");
952                 return;
953             }
954             startOfCurrentLine = VisiblePosition(rangeForSpellChecking->endPosition());
955             endOfCurrentLine = endOfLine(startOfCurrentLine);
956             rangeForSpellChecking = DOMSupport::trimWhitespaceFromRange(VisiblePosition(rangeForSpellChecking->startPosition()), VisiblePosition(rangeForSpellChecking->endPosition()));
957         }
958
959         SpellingLog(LogLevelInfo, "InputHandler::spellCheckBlock Substring text is '%s', of size %d", rangeForSpellChecking->text().latin1().data(), rangeForSpellChecking->text().length());
960
961         // Call spellcheck with substring.
962         spellChecker->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling, TextCheckingProcessBatch, rangeForSpellChecking, rangeForSpellChecking));
963     }
964 }
965
966 PassRefPtr<Range> InputHandler::getRangeForSpellCheckWithFineGranularity(VisiblePosition startPosition, VisiblePosition endPosition)
967 {
968     VisiblePosition endOfCurrentWord = endOfWord(startPosition);
969
970     // Keep iterating until one of our cases is hit, or we've incremented the starting position right to the end.
971     while (startPosition != endPosition) {
972         // Check the text length within this range.
973         if (VisibleSelection(startPosition, endOfCurrentWord).toNormalizedRange()->text().length() >= MaxSpellCheckingStringLength) {
974             // If this is not the first word, return a Range with end boundary set to the previous word.
975             if (startOfWord(endOfCurrentWord, LeftWordIfOnBoundary) != startPosition && !DOMSupport::isEmptyRangeOrAllSpaces(startPosition, endOfCurrentWord))
976                 return VisibleSelection(startPosition, endOfWord(previousWordPosition(endOfCurrentWord), LeftWordIfOnBoundary)).toNormalizedRange();
977
978             // Our first word has gone over the character limit. Increment the starting position past an uncheckable word.
979             startPosition = endOfCurrentWord;
980             endOfCurrentWord = endOfWord(nextWordPosition(endOfCurrentWord));
981         } else if (endOfCurrentWord == endPosition) {
982             // Return the last segment if the end of our word lies at the end of the range.
983             return VisibleSelection(startPosition, endPosition).toNormalizedRange();
984         } else {
985             // Increment the current word.
986             endOfCurrentWord = endOfWord(nextWordPosition(endOfCurrentWord));
987         }
988     }
989     return 0;
990 }
991
992 bool InputHandler::openDatePopup(HTMLInputElement* element, BlackBerryInputType type)
993 {
994     if (!element || element->disabled() || element->readOnly() || !DOMSupport::isDateTimeInputField(element))
995         return false;
996
997     if (isActiveTextEdit())
998         clearCurrentFocusElement();
999
1000     switch (type) {
1001     case BlackBerry::Platform::InputTypeDate:
1002     case BlackBerry::Platform::InputTypeTime:
1003     case BlackBerry::Platform::InputTypeDateTime:
1004     case BlackBerry::Platform::InputTypeDateTimeLocal:
1005     case BlackBerry::Platform::InputTypeMonth: {
1006         // Date input have button appearance, we hide caret when they get clicked.
1007         element->document()->frame()->selection()->setCaretVisible(false);
1008
1009         // Check if popup already exists, close it if does.
1010         m_webPage->m_page->chrome()->client()->closePagePopup(0);
1011         WTF::String value = element->value();
1012         WTF::String min = element->getAttribute(HTMLNames::minAttr).string();
1013         WTF::String max = element->getAttribute(HTMLNames::maxAttr).string();
1014         double step = element->getAttribute(HTMLNames::stepAttr).toDouble();
1015
1016         DatePickerClient* client = new DatePickerClient(type, value, min, max, step,  m_webPage, element);
1017         return m_webPage->m_page->chrome()->client()->openPagePopup(client,  WebCore::IntRect());
1018         }
1019     default: // Other types not supported
1020         return false;
1021     }
1022 }
1023
1024 bool InputHandler::openColorPopup(HTMLInputElement* element)
1025 {
1026     if (!element || element->disabled() || element->readOnly() || !DOMSupport::isColorInputField(element))
1027         return false;
1028
1029     if (isActiveTextEdit())
1030         clearCurrentFocusElement();
1031
1032     m_currentFocusElement = element;
1033     m_currentFocusElementType = TextPopup;
1034
1035     // Check if popup already exists, close it if does.
1036     m_webPage->m_page->chrome()->client()->closePagePopup(0);
1037
1038     ColorPickerClient* client = new ColorPickerClient(element->value(), m_webPage, element);
1039     return m_webPage->m_page->chrome()->client()->openPagePopup(client,  WebCore::IntRect());
1040 }
1041
1042 void InputHandler::setInputValue(const WTF::String& value)
1043 {
1044     if (!isActiveTextPopup())
1045         return;
1046
1047     HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(m_currentFocusElement.get());
1048     inputElement->setValue(value);
1049     clearCurrentFocusElement();
1050 }
1051
1052 void InputHandler::nodeTextChanged(const Node* node)
1053 {
1054     if (processingChange() || !node || node != m_currentFocusElement || m_receivedBackspaceKeyDown)
1055         return;
1056
1057     InputLog(LogLevelInfo, "InputHandler::nodeTextChanged");
1058
1059     m_webPage->m_client->inputTextChanged();
1060
1061     // Remove the attributed text markers as the previous call triggered an end to
1062     // the composition.
1063     removeAttributedTextMarker();
1064 }
1065
1066 WebCore::IntRect InputHandler::boundingBoxForInputField()
1067 {
1068     if (!isActiveTextEdit())
1069         return WebCore::IntRect();
1070
1071     if (!m_currentFocusElement->renderer())
1072         return WebCore::IntRect();
1073
1074     // type="search" can have a 'X', so take the inner block bounding box to not include it.
1075     if (HTMLInputElement* element = m_currentFocusElement->toInputElement())
1076         if (element->isSearchField())
1077             return element->innerBlockElement()->renderer()->absoluteBoundingBoxRect();
1078
1079     return m_currentFocusElement->renderer()->absoluteBoundingBoxRect();
1080 }
1081
1082 void InputHandler::ensureFocusTextElementVisible(CaretScrollType scrollType)
1083 {
1084     if (!isActiveTextEdit() || !isInputModeEnabled() || !m_currentFocusElement->document())
1085         return;
1086
1087     if (!(Platform::Settings::instance()->allowedScrollAdjustmentForInputFields() & scrollType))
1088         return;
1089
1090     // Fixed position elements cannot be scrolled into view.
1091     if (DOMSupport::isFixedPositionOrHasFixedPositionAncestor(m_currentFocusElement->renderer()))
1092         return;
1093
1094     Frame* elementFrame = m_currentFocusElement->document()->frame();
1095     if (!elementFrame)
1096         return;
1097
1098     Frame* mainFrame = m_webPage->mainFrame();
1099     if (!mainFrame)
1100         return;
1101
1102     FrameView* mainFrameView = mainFrame->view();
1103     if (!mainFrameView)
1104         return;
1105
1106     WebCore::IntRect selectionFocusRect;
1107     switch (elementFrame->selection()->selectionType()) {
1108     case VisibleSelection::CaretSelection:
1109         selectionFocusRect = elementFrame->selection()->absoluteCaretBounds();
1110         break;
1111     case VisibleSelection::RangeSelection: {
1112         Position selectionPosition;
1113         if (m_webPage->m_selectionHandler->lastUpdatedEndPointIsValid())
1114             selectionPosition = elementFrame->selection()->end();
1115         else
1116             selectionPosition = elementFrame->selection()->start();
1117         selectionFocusRect = VisiblePosition(selectionPosition).absoluteCaretBounds();
1118         break;
1119     }
1120     case VisibleSelection::NoSelection:
1121         return;
1122     }
1123
1124     int fontHeight = selectionFocusRect.height();
1125
1126     m_webPage->suspendBackingStore();
1127
1128     // If the text is too small, zoom in to make it a minimum size.
1129     // The minimum size being defined as 3 mm is a good value based on my observations.
1130     static const int s_minimumTextHeightInPixels = Graphics::Screen::primaryScreen()->heightInMMToPixels(3);
1131
1132     double zoomScaleRequired;
1133     if (m_webPage->isUserScalable() && fontHeight && fontHeight * m_webPage->currentScale() < s_minimumTextHeightInPixels && !isRunningDrt())
1134         zoomScaleRequired = static_cast<double>(s_minimumTextHeightInPixels) / fontHeight;
1135     else
1136         zoomScaleRequired = m_webPage->currentScale(); // Don't scale.
1137
1138     // The scroll location we should go to given the zoom required, could be adjusted later.
1139     WebCore::FloatPoint offset(selectionFocusRect.location().x() - m_webPage->scrollPosition().x(), selectionFocusRect.location().y() - m_webPage->scrollPosition().y());
1140     double inverseScale = zoomScaleRequired / m_webPage->currentScale();
1141     WebCore::IntPoint destinationScrollLocation = WebCore::IntPoint(max(0, static_cast<int>(roundf(selectionFocusRect.location().x() - offset.x() / inverseScale))),
1142                                                                     max(0, static_cast<int>(roundf(selectionFocusRect.location().y() - offset.y() / inverseScale))));
1143
1144     if (elementFrame != mainFrame) { // Element is in a subframe.
1145         // Remove any scroll offset within the subframe to get the point relative to the main frame.
1146         selectionFocusRect.move(-elementFrame->view()->scrollPosition().x(), -elementFrame->view()->scrollPosition().y());
1147
1148         // Adjust the selection rect based on the frame offset in relation to the main frame if it's a subframe.
1149         if (elementFrame->ownerRenderer()) {
1150             WebCore::IntPoint frameOffset = elementFrame->ownerRenderer()->absoluteContentBox().location();
1151             selectionFocusRect.move(frameOffset.x(), frameOffset.y());
1152         }
1153     }
1154
1155     Position start = elementFrame->selection()->start();
1156     if (start.anchorNode() && start.anchorNode()->renderer()) {
1157         if (RenderLayer* layer = start.anchorNode()->renderer()->enclosingLayer()) {
1158             // Screen rect after the required zoom.
1159             WebCore::IntRect actualScreenRect = WebCore::IntRect(destinationScrollLocation.x(), destinationScrollLocation.y(), m_webPage->actualVisibleSize().width() / inverseScale, m_webPage->actualVisibleSize().height() / inverseScale);
1160
1161             ScrollAlignment horizontalScrollAlignment = ScrollAlignment::alignToEdgeIfNeeded;
1162             ScrollAlignment verticalScrollAlignment = ScrollAlignment::alignToEdgeIfNeeded;
1163
1164             if (scrollType != EdgeIfNeeded) {
1165                 // Align the selection rect if possible so that we show the field's
1166                 // outline if the caret is at the edge of the field.
1167                 if (RenderObject* focusedRenderer = m_currentFocusElement->renderer()) {
1168                     WebCore::IntRect nodeOutlineBounds = focusedRenderer->absoluteOutlineBounds();
1169                     WebCore::IntRect caretAtEdgeRect = rectForCaret(0);
1170                     int paddingX = abs(caretAtEdgeRect.x() - nodeOutlineBounds.x());
1171                     int paddingY = abs(caretAtEdgeRect.y() - nodeOutlineBounds.y());
1172
1173                     if (selectionFocusRect.x() - paddingX == nodeOutlineBounds.x())
1174                         selectionFocusRect.setX(nodeOutlineBounds.x());
1175                     else if (selectionFocusRect.maxX() + paddingX == nodeOutlineBounds.maxX())
1176                         selectionFocusRect.setX(nodeOutlineBounds.maxX() - selectionFocusRect.width());
1177                     if (selectionFocusRect.y() - paddingY == nodeOutlineBounds.y())
1178                         selectionFocusRect.setY(nodeOutlineBounds.y() - selectionFocusRect.height());
1179                     else if (selectionFocusRect.maxY() + paddingY == nodeOutlineBounds.maxY())
1180                         selectionFocusRect.setY(nodeOutlineBounds.maxY() - selectionFocusRect.height());
1181
1182                     // If the editing point is on the left hand side of the screen when the node's
1183                     // rect is edge aligned, edge align the node rect.
1184                     if (selectionFocusRect.x() - caretAtEdgeRect.x() < actualScreenRect.width() / 2)
1185                         selectionFocusRect.setX(nodeOutlineBounds.x());
1186                     else
1187                         horizontalScrollAlignment = ScrollAlignment::alignCenterIfNeeded;
1188
1189                 }
1190                 verticalScrollAlignment = (scrollType == CenterAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
1191             }
1192
1193             // Pad the rect to improve the visual appearance.
1194             // Convert the padding back from transformed to ensure a consistent padding regardless of
1195             // zoom level as controls do not zoom.
1196             static const int s_focusRectPaddingSize = Graphics::Screen::primaryScreen()->heightInMMToPixels(3);
1197             selectionFocusRect.inflate(m_webPage->mapFromTransformed(WebCore::IntSize(0, s_focusRectPaddingSize)).height());
1198
1199             WebCore::IntRect revealRect(layer->getRectToExpose(actualScreenRect, selectionFocusRect,
1200                                                                  horizontalScrollAlignment,
1201                                                                  verticalScrollAlignment));
1202
1203             mainFrameView->setConstrainsScrollingToContentEdge(false);
1204             // In order to adjust the scroll position to ensure the focused input field is visible,
1205             // we allow overscrolling. However this overscroll has to be strictly allowed towards the
1206             // bottom of the page on the y axis only, where the virtual keyboard pops up from.
1207             destinationScrollLocation = revealRect.location();
1208             destinationScrollLocation.clampNegativeToZero();
1209             WebCore::IntPoint maximumScrollPosition = WebCore::IntPoint(mainFrameView->contentsWidth() - actualScreenRect.width(), mainFrameView->contentsHeight() - actualScreenRect.height());
1210             destinationScrollLocation = destinationScrollLocation.shrunkTo(maximumScrollPosition);
1211         }
1212     }
1213
1214     if (destinationScrollLocation != mainFrameView->scrollPosition() || zoomScaleRequired != m_webPage->currentScale()) {
1215         mainFrameView->setConstrainsScrollingToContentEdge(true);
1216
1217         InputLog(LogLevelInfo, "InputHandler::ensureFocusTextElementVisible zooming in to %f and scrolling to point %d, %d", zoomScaleRequired, destinationScrollLocation.x(), destinationScrollLocation.y());
1218
1219         // Animate to given scroll position & zoom level
1220         m_webPage->m_finalBlockPoint = WebCore::FloatPoint(destinationScrollLocation);
1221         m_webPage->m_blockZoomFinalScale = zoomScaleRequired;
1222         m_webPage->m_shouldReflowBlock = false;
1223         m_webPage->m_userPerformedManualZoom = true;
1224         m_webPage->m_userPerformedManualScroll = true;
1225         m_webPage->client()->animateBlockZoom(zoomScaleRequired, m_webPage->m_finalBlockPoint);
1226     }
1227     m_webPage->resumeBackingStore();
1228 }
1229
1230 void InputHandler::ensureFocusPluginElementVisible()
1231 {
1232     if (!isActivePlugin() || !m_currentFocusElement->document())
1233         return;
1234
1235     Frame* elementFrame = m_currentFocusElement->document()->frame();
1236     if (!elementFrame)
1237         return;
1238
1239     Frame* mainFrame = m_webPage->mainFrame();
1240     if (!mainFrame)
1241         return;
1242
1243     FrameView* mainFrameView = mainFrame->view();
1244     if (!mainFrameView)
1245         return;
1246
1247     WebCore::IntRect selectionFocusRect;
1248
1249     RenderWidget* renderWidget = static_cast<RenderWidget*>(m_currentFocusElement->renderer());
1250     if (renderWidget) {
1251         PluginView* pluginView = static_cast<PluginView*>(renderWidget->widget());
1252
1253         if (pluginView)
1254             selectionFocusRect = pluginView->ensureVisibleRect();
1255     }
1256
1257     if (selectionFocusRect.isEmpty())
1258         return;
1259
1260     // FIXME: We may need to scroll the subframe (recursively) in the future. Revisit this...
1261     if (elementFrame != mainFrame) { // Element is in a subframe.
1262         // Remove any scroll offset within the subframe to get the point relative to the main frame.
1263         selectionFocusRect.move(-elementFrame->view()->scrollPosition().x(), -elementFrame->view()->scrollPosition().y());
1264
1265         // Adjust the selection rect based on the frame offset in relation to the main frame if it's a subframe.
1266         if (elementFrame->ownerRenderer()) {
1267             WebCore::IntPoint frameOffset = elementFrame->ownerRenderer()->absoluteContentBox().location();
1268             selectionFocusRect.move(frameOffset.x(), frameOffset.y());
1269         }
1270     }
1271
1272     WebCore::IntRect actualScreenRect = WebCore::IntRect(mainFrameView->scrollPosition(), m_webPage->actualVisibleSize());
1273     if (actualScreenRect.contains(selectionFocusRect))
1274         return;
1275
1276     // Calculate a point such that the center of the requested rectangle
1277     // is at the center of the screen. FIXME: If the element was partially on screen
1278     // we might want to just bring the offscreen portion into view, someone needs
1279     // to decide if that's the behavior we want or not.
1280     WebCore::IntPoint pos(selectionFocusRect.center().x() - actualScreenRect.width() / 2,
1281                  selectionFocusRect.center().y() - actualScreenRect.height() / 2);
1282
1283     mainFrameView->setScrollPosition(pos);
1284 }
1285
1286 void InputHandler::ensureFocusElementVisible(bool centerInView)
1287 {
1288     if (isActivePlugin())
1289         ensureFocusPluginElementVisible();
1290     else
1291         ensureFocusTextElementVisible(centerInView ? CenterAlways : CenterIfNeeded);
1292 }
1293
1294 void InputHandler::frameUnloaded(const Frame* frame)
1295 {
1296     if (!isActiveTextEdit())
1297         return;
1298
1299     if (m_currentFocusElement->document()->frame() != frame)
1300         return;
1301
1302     FocusLog(LogLevelInfo, "InputHandler::frameUnloaded");
1303
1304     setElementUnfocused(false /*refocusOccuring*/);
1305 }
1306
1307 void InputHandler::setDelayKeyboardVisibilityChange(bool value)
1308 {
1309     m_delayKeyboardVisibilityChange = value;
1310     m_pendingKeyboardVisibilityChange = NoChange;
1311 }
1312
1313 void InputHandler::processPendingKeyboardVisibilityChange()
1314 {
1315     if (!m_delayKeyboardVisibilityChange) {
1316         ASSERT(m_pendingKeyboardVisibilityChange == NoChange);
1317         return;
1318     }
1319
1320     m_delayKeyboardVisibilityChange = false;
1321
1322     if (m_pendingKeyboardVisibilityChange == NoChange)
1323         return;
1324
1325     notifyClientOfKeyboardVisibilityChange(m_pendingKeyboardVisibilityChange == Visible);
1326     m_pendingKeyboardVisibilityChange = NoChange;
1327 }
1328
1329 void InputHandler::notifyClientOfKeyboardVisibilityChange(bool visible, bool triggeredByFocusChange)
1330 {
1331     // If we aren't ready for input, keyboard changes should be ignored.
1332     if (!isInputModeEnabled() && visible)
1333         return;
1334
1335     // If we are processing a change assume the keyboard is visbile to avoid
1336     // flooding the VKB with show requests.
1337     if (!triggeredByFocusChange && processingChange() && visible)
1338         return;
1339
1340     if (!m_delayKeyboardVisibilityChange) {
1341         m_webPage->showVirtualKeyboard(visible);
1342         return;
1343     }
1344
1345     m_pendingKeyboardVisibilityChange = visible ? Visible : NotVisible;
1346 }
1347
1348 bool InputHandler::selectionAtStartOfElement()
1349 {
1350     if (!isActiveTextEdit())
1351         return false;
1352
1353     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1354
1355     if (!selectionStart())
1356         return true;
1357
1358     return false;
1359 }
1360
1361 bool InputHandler::selectionAtEndOfElement()
1362 {
1363     if (!isActiveTextEdit())
1364         return false;
1365
1366     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1367
1368     return selectionStart() == static_cast<int>(elementText().length());
1369 }
1370
1371 int InputHandler::selectionStart() const
1372 {
1373     return selectionPosition(true);
1374 }
1375
1376 int InputHandler::selectionEnd() const
1377 {
1378     return selectionPosition(false);
1379 }
1380
1381 int InputHandler::selectionPosition(bool start) const
1382 {
1383     if (!m_currentFocusElement->document() || !m_currentFocusElement->document()->frame())
1384         return 0;
1385
1386     if (HTMLTextFormControlElement* controlElement = DOMSupport::toTextControlElement(m_currentFocusElement.get()))
1387         return start ? controlElement->selectionStart() : controlElement->selectionEnd();
1388
1389     FrameSelection caretSelection;
1390     caretSelection.setSelection(m_currentFocusElement->document()->frame()->selection()->selection());
1391     RefPtr<Range> rangeSelection = caretSelection.selection().toNormalizedRange();
1392     if (!rangeSelection)
1393         return 0;
1394
1395     int selectionPointInNode = start ? rangeSelection->startOffset() : rangeSelection->endOffset();
1396     Node* containerNode = start ? rangeSelection->startContainer() : rangeSelection->endContainer();
1397
1398     ExceptionCode ec;
1399     RefPtr<Range> rangeForNode = rangeOfContents(m_currentFocusElement.get());
1400     rangeForNode->setEnd(containerNode, selectionPointInNode, ec);
1401     ASSERT(!ec);
1402
1403     return TextIterator::rangeLength(rangeForNode.get());
1404 }
1405
1406 void InputHandler::selectionChanged()
1407 {
1408     // This method can get called during WebPage shutdown process.
1409     // If that is the case, just bail out since the client is not
1410     // in a safe state of trust to request anything else from it.
1411     if (!m_webPage->m_mainFrame)
1412         return;
1413
1414     if (!isActiveTextEdit())
1415         return;
1416
1417     if (processingChange())
1418         return;
1419
1420     // Scroll the field if necessary. This must be done even if we are processing
1421     // a change as the text change may have moved the caret. IMF doesn't require
1422     // the update, but the user needs to see the caret.
1423     ensureFocusTextElementVisible(EdgeIfNeeded);
1424
1425     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1426
1427     if (m_receivedBackspaceKeyDown)
1428         return;
1429
1430     int newSelectionStart = selectionStart();
1431     int newSelectionEnd = selectionEnd();
1432
1433     InputLog(LogLevelInfo, "InputHandler::selectionChanged selectionStart=%u, selectionEnd=%u", newSelectionStart, newSelectionEnd);
1434
1435     m_webPage->m_client->inputSelectionChanged(newSelectionStart, newSelectionEnd);
1436
1437     // Remove the attributed text markers as the previous call triggered an end to
1438     // the composition.
1439     removeAttributedTextMarker();
1440 }
1441
1442 bool InputHandler::setCursorPosition(int location)
1443 {
1444     return setSelection(location, location);
1445 }
1446
1447 bool InputHandler::setSelection(int start, int end, bool changeIsPartOfComposition)
1448 {
1449     if (!isActiveTextEdit())
1450         return false;
1451
1452     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1453
1454     ProcessingChangeGuard guard(this);
1455
1456     VisibleSelection newSelection = DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), start, end);
1457     m_currentFocusElement->document()->frame()->selection()->setSelection(newSelection, changeIsPartOfComposition ? 0 : FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
1458
1459     InputLog(LogLevelInfo, "InputHandler::setSelection selectionStart=%u, selectionEnd=%u", start, end);
1460
1461     return start == selectionStart() && end == selectionEnd();
1462 }
1463
1464 WebCore::IntRect InputHandler::rectForCaret(int index)
1465 {
1466     if (!isActiveTextEdit())
1467         return WebCore::IntRect();
1468
1469     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1470
1471     if (index < 0 || index > static_cast<int>(elementText().length())) {
1472         // Invalid request.
1473         return WebCore::IntRect();
1474     }
1475
1476     FrameSelection caretSelection;
1477     caretSelection.setSelection(DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), index, index).visibleStart());
1478     caretSelection.modify(FrameSelection::AlterationExtend, DirectionForward, CharacterGranularity);
1479     return caretSelection.selection().visibleStart().absoluteCaretBounds();
1480 }
1481
1482 void InputHandler::cancelSelection()
1483 {
1484     if (!isActiveTextEdit())
1485         return;
1486
1487     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1488
1489     int selectionStartPosition = selectionStart();
1490     ProcessingChangeGuard guard(this);
1491     setCursorPosition(selectionStartPosition);
1492 }
1493
1494 bool InputHandler::handleKeyboardInput(const Platform::KeyboardEvent& keyboardEvent, bool changeIsPartOfComposition)
1495 {
1496     InputLog(LogLevelInfo, "InputHandler::handleKeyboardInput received character=%lc, type=%d", keyboardEvent.character(), keyboardEvent.type());
1497
1498     // Clearing the m_receivedBackspaceKeyDown state on any KeyboardEvent.
1499     m_receivedBackspaceKeyDown = false;
1500
1501     // Enable input mode if we are processing a key event.
1502     setInputModeEnabled();
1503
1504     Platform::KeyboardEvent::Type type = keyboardEvent.type();
1505     /*
1506      * IMF sends us an unadultered KeyUp for all key presses. This key event should be allowed to be processed at all times.
1507      * We bypass the check because the state of composition has no implication on this key event.
1508      * In order to ensure we allow the correct key event through, we keep track of key down events with m_expectedKeyUpChar.
1509     */
1510     if (type == Platform::KeyboardEvent::KeyUp) {
1511         // When IMF auto-capitalizes a KeyDown, say the first letter of a new sentence, our KeyUp will still be in lowercase.
1512         if (m_expectedKeyUpChar == keyboardEvent.character() || (isASCIIUpper(m_expectedKeyUpChar) && m_expectedKeyUpChar == toASCIIUpper(keyboardEvent.character()))) {
1513             m_expectedKeyUpChar = 0;
1514             changeIsPartOfComposition = true;
1515         }
1516     }
1517
1518     // If we aren't specifically part of a composition, fail, IMF should never send key input
1519     // while composing text. If IMF has failed, we should have already finished the
1520     // composition manually. There is a caveat for KeyUp which is explained above.
1521     if (!changeIsPartOfComposition && compositionActive())
1522         return false;
1523
1524     ProcessingChangeGuard guard(this);
1525
1526     unsigned adjustedModifiers = keyboardEvent.modifiers();
1527     if (WTF::isASCIIUpper(keyboardEvent.character()))
1528         adjustedModifiers |= KEYMOD_SHIFT;
1529
1530     ASSERT(m_webPage->m_page->focusController());
1531     bool keyboardEventHandled = false;
1532     if (Frame* focusedFrame = m_webPage->m_page->focusController()->focusedFrame()) {
1533         bool isKeyChar = type == Platform::KeyboardEvent::KeyChar;
1534
1535         // If this is a KeyChar type then we handle it as a keydown followed by a key up.
1536         if (isKeyChar)
1537             type = Platform::KeyboardEvent::KeyDown;
1538         else if (type == Platform::KeyboardEvent::KeyDown) {
1539             m_expectedKeyUpChar = keyboardEvent.character();
1540
1541             // If we receive the KeyDown of a Backspace, set this flag to prevent sending unnecessary selection and caret changes to IMF.
1542             if (keyboardEvent.character() == KEYCODE_BACKSPACE)
1543                 m_receivedBackspaceKeyDown = true;
1544         }
1545
1546         Platform::KeyboardEvent adjustedKeyboardEvent(keyboardEvent.character(), type, adjustedModifiers);
1547         keyboardEventHandled = focusedFrame->eventHandler()->keyEvent(PlatformKeyboardEvent(adjustedKeyboardEvent));
1548
1549         m_receivedBackspaceKeyDown = false;
1550
1551         if (isKeyChar) {
1552             type = Platform::KeyboardEvent::KeyUp;
1553             adjustedKeyboardEvent = Platform::KeyboardEvent(keyboardEvent.character(), type, adjustedModifiers);
1554             keyboardEventHandled = focusedFrame->eventHandler()->keyEvent(PlatformKeyboardEvent(adjustedKeyboardEvent)) || keyboardEventHandled;
1555         }
1556
1557         if (!changeIsPartOfComposition && type == Platform::KeyboardEvent::KeyUp)
1558             ensureFocusTextElementVisible(EdgeIfNeeded);
1559     }
1560     return keyboardEventHandled;
1561 }
1562
1563 bool InputHandler::deleteSelection()
1564 {
1565     if (!isActiveTextEdit())
1566         return false;
1567
1568     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1569     Frame* frame = m_currentFocusElement->document()->frame();
1570
1571     if (frame->selection()->selectionType() != VisibleSelection::RangeSelection)
1572         return false;
1573
1574     ASSERT(frame->editor());
1575     return handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_BACKSPACE, Platform::KeyboardEvent::KeyDown, 0), false /* changeIsPartOfComposition */);
1576 }
1577
1578 void InputHandler::insertText(const WTF::String& string)
1579 {
1580     if (!isActiveTextEdit())
1581         return;
1582
1583     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->editor());
1584     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1585     editor->command("InsertText").execute(string);
1586 }
1587
1588 void InputHandler::clearField()
1589 {
1590     if (!isActiveTextEdit())
1591         return;
1592
1593     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->editor());
1594     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1595
1596     editor->command("SelectAll").execute();
1597     editor->command("DeleteBackward").execute();
1598 }
1599
1600 bool InputHandler::executeTextEditCommand(const WTF::String& commandName)
1601 {
1602     ASSERT(m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->editor());
1603     Editor* editor = m_webPage->focusedOrMainFrame()->editor();
1604
1605     return editor->command(commandName).execute();
1606 }
1607
1608 void InputHandler::cut()
1609 {
1610     executeTextEditCommand("Cut");
1611 }
1612
1613 void InputHandler::copy()
1614 {
1615     executeTextEditCommand("Copy");
1616 }
1617
1618 void InputHandler::paste()
1619 {
1620     executeTextEditCommand("Paste");
1621 }
1622
1623 void InputHandler::selectAll()
1624 {
1625     executeTextEditCommand("SelectAll");
1626 }
1627
1628 void InputHandler::addAttributedTextMarker(int start, int end, const AttributeTextStyle& style)
1629 {
1630     if ((end - start) < 1 || end > static_cast<int>(elementText().length()))
1631         return;
1632
1633     RefPtr<Range> markerRange = DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), start, end).toNormalizedRange();
1634     m_currentFocusElement->document()->markers()->addMarker(markerRange.get(), DocumentMarker::AttributeText, WTF::String("Input Marker"), style);
1635 }
1636
1637 void InputHandler::removeAttributedTextMarker()
1638 {
1639     // Remove all attribute text markers.
1640     if (m_currentFocusElement && m_currentFocusElement->document())
1641         m_currentFocusElement->document()->markers()->removeMarkers(DocumentMarker::AttributeText);
1642
1643     m_composingTextStart = 0;
1644     m_composingTextEnd = 0;
1645 }
1646
1647 void InputHandler::handleInputLocaleChanged(bool isRTL)
1648 {
1649     if (!isActiveTextEdit())
1650         return;
1651
1652     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1653     RenderObject* renderer = m_currentFocusElement->renderer();
1654     if (!renderer)
1655         return;
1656
1657     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1658     ASSERT(editor);
1659     if ((renderer->style()->direction() == RTL) != isRTL)
1660         editor->setBaseWritingDirection(isRTL ? RightToLeftWritingDirection : LeftToRightWritingDirection);
1661 }
1662
1663 void InputHandler::clearCurrentFocusElement()
1664 {
1665     if (m_currentFocusElement)
1666         m_currentFocusElement->blur();
1667 }
1668
1669 bool InputHandler::willOpenPopupForNode(Node* node)
1670 {
1671     // This method must be kept synchronized with InputHandler::didNodeOpenPopup.
1672     if (!node)
1673         return false;
1674
1675     ASSERT(!node->isInShadowTree());
1676
1677     if (node->hasTagName(HTMLNames::selectTag) || node->hasTagName(HTMLNames::optionTag)) {
1678         // We open list popups for options and selects.
1679         return true;
1680     }
1681
1682     if (node->isElementNode()) {
1683         Element* element = static_cast<Element*>(node);
1684         if (DOMSupport::isPopupInputField(element))
1685             return true;
1686     }
1687
1688     return false;
1689 }
1690
1691 bool InputHandler::didNodeOpenPopup(Node* node)
1692 {
1693     // This method must be kept synchronized with InputHandler::willOpenPopupForNode.
1694     if (!node)
1695         return false;
1696
1697     ASSERT(!node->isInShadowTree());
1698
1699     if (node->hasTagName(HTMLNames::selectTag))
1700         return openSelectPopup(static_cast<HTMLSelectElement*>(node));
1701
1702     if (node->hasTagName(HTMLNames::optionTag)) {
1703         HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(node);
1704         return openSelectPopup(optionElement->ownerSelectElement());
1705     }
1706
1707     if (HTMLInputElement* element = node->toInputElement()) {
1708         if (DOMSupport::isDateTimeInputField(element))
1709             return openDatePopup(element, elementType(element));
1710
1711         if (DOMSupport::isColorInputField(element))
1712             return openColorPopup(element);
1713     }
1714     return false;
1715 }
1716
1717 bool InputHandler::openSelectPopup(HTMLSelectElement* select)
1718 {
1719     if (!select || select->disabled())
1720         return false;
1721
1722     // If there's no view, do nothing and return.
1723     if (!select->document()->view())
1724         return false;
1725
1726     if (isActiveTextEdit())
1727         clearCurrentFocusElement();
1728
1729     m_currentFocusElement = select;
1730     m_currentFocusElementType = SelectPopup;
1731
1732     const WTF::Vector<HTMLElement*>& listItems = select->listItems();
1733     int size = listItems.size();
1734
1735     bool multiple = select->multiple();
1736     ScopeArray<BlackBerry::Platform::String> labels;
1737     labels.reset(new BlackBerry::Platform::String[size]);
1738
1739     // Check if popup already exists, close it if does.
1740     m_webPage->m_page->chrome()->client()->closePagePopup(0);
1741
1742     bool* enableds = 0;
1743     int* itemTypes = 0;
1744     bool* selecteds = 0;
1745
1746     if (size) {
1747         enableds = new bool[size];
1748         itemTypes = new int[size];
1749         selecteds = new bool[size];
1750         for (int i = 0; i < size; i++) {
1751             if (listItems[i]->hasTagName(HTMLNames::optionTag)) {
1752                 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(listItems[i]);
1753                 labels[i] = option->textIndentedToRespectGroupLabel();
1754                 enableds[i] = option->disabled() ? 0 : 1;
1755                 selecteds[i] = option->selected();
1756                 itemTypes[i] = option->parentNode() && option->parentNode()->hasTagName(HTMLNames::optgroupTag) ? TypeOptionInGroup : TypeOption;
1757             } else if (listItems[i]->hasTagName(HTMLNames::optgroupTag)) {
1758                 HTMLOptGroupElement* optGroup = static_cast<HTMLOptGroupElement*>(listItems[i]);
1759                 labels[i] = optGroup->groupLabelText();
1760                 enableds[i] = optGroup->disabled() ? 0 : 1;
1761                 selecteds[i] = false;
1762                 itemTypes[i] = TypeGroup;
1763             } else if (listItems[i]->hasTagName(HTMLNames::hrTag)) {
1764                 enableds[i] = false;
1765                 selecteds[i] = false;
1766                 itemTypes[i] = TypeSeparator;
1767             }
1768         }
1769     }
1770
1771     SelectPopupClient* selectClient = new SelectPopupClient(multiple, size, labels, enableds, itemTypes, selecteds, m_webPage, select);
1772     WebCore::IntRect elementRectInRootView = select->document()->view()->contentsToRootView(enclosingIntRect(select->getRect()));
1773     // Fail to create HTML popup, use the old path
1774     if (!m_webPage->m_page->chrome()->client()->openPagePopup(selectClient, elementRectInRootView))
1775         m_webPage->m_client->openPopupList(multiple, size, labels, enableds, itemTypes, selecteds);
1776     delete[] enableds;
1777     delete[] itemTypes;
1778     delete[] selecteds;
1779     return true;
1780 }
1781
1782 void InputHandler::setPopupListIndex(int index)
1783 {
1784     if (index == -2) // Abandon
1785         return clearCurrentFocusElement();
1786
1787     if (!isActiveSelectPopup())
1788         return clearCurrentFocusElement();
1789
1790     RenderObject* renderer = m_currentFocusElement->renderer();
1791     if (renderer && renderer->isMenuList()) {
1792         RenderMenuList* renderMenu = toRenderMenuList(renderer);
1793         renderMenu->hidePopup();
1794     }
1795
1796     HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>(m_currentFocusElement.get());
1797     int optionIndex = selectElement->listToOptionIndex(index);
1798     selectElement->optionSelectedByUser(optionIndex, true /* deselect = true */, true /* fireOnChangeNow = false */);
1799     clearCurrentFocusElement();
1800 }
1801
1802 void InputHandler::setPopupListIndexes(int size, const bool* selecteds)
1803 {
1804     if (!isActiveSelectPopup())
1805         return clearCurrentFocusElement();
1806
1807     if (size < 0)
1808         return;
1809
1810     HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>(m_currentFocusElement.get());
1811     const WTF::Vector<HTMLElement*>& items = selectElement->listItems();
1812     if (items.size() != static_cast<unsigned int>(size))
1813         return;
1814
1815     HTMLOptionElement* option;
1816     for (int i = 0; i < size; i++) {
1817         if (items[i]->hasTagName(HTMLNames::optionTag)) {
1818             option = static_cast<HTMLOptionElement*>(items[i]);
1819             option->setSelectedState(selecteds[i]);
1820         }
1821     }
1822
1823     // Force repaint because we do not send mouse events to the select element
1824     // and the element doesn't automatically repaint itself.
1825     selectElement->dispatchFormControlChangeEvent();
1826     selectElement->renderer()->repaint();
1827     clearCurrentFocusElement();
1828 }
1829
1830 bool InputHandler::setBatchEditingActive(bool active)
1831 {
1832     if (!isActiveTextEdit())
1833         return false;
1834
1835     ASSERT(m_currentFocusElement->document());
1836     ASSERT(m_currentFocusElement->document()->frame());
1837
1838     // FIXME switch this to m_currentFocusElement->document()->frame() when we have separate
1839     // backingstore for each frame.
1840     BackingStoreClient* backingStoreClient = m_webPage->backingStoreClient();
1841     ASSERT(backingStoreClient);
1842
1843     // Enable / Disable the backingstore to prevent visual updates.
1844     // FIXME: Do we really need to suspend/resume both backingstore and screen here?
1845     if (!active) {
1846         backingStoreClient->backingStore()->resumeBackingStoreUpdates();
1847         backingStoreClient->backingStore()->resumeScreenUpdates(BackingStore::RenderAndBlit);
1848     } else {
1849         backingStoreClient->backingStore()->suspendBackingStoreUpdates();
1850         backingStoreClient->backingStore()->suspendScreenUpdates();
1851     }
1852
1853     return true;
1854 }
1855
1856 int InputHandler::caretPosition() const
1857 {
1858     if (!isActiveTextEdit())
1859         return -1;
1860
1861     // NOTE: This function is expected to return the start of the selection if
1862     // a selection is applied.
1863     return selectionStart();
1864 }
1865
1866 int relativeLeftOffset(int caretPosition, int leftOffset)
1867 {
1868     ASSERT(caretPosition >= 0);
1869
1870     return std::max(0, caretPosition - leftOffset);
1871 }
1872
1873 int relativeRightOffset(int caretPosition, unsigned totalLengthOfText, int rightOffset)
1874 {
1875     ASSERT(caretPosition >= 0);
1876     ASSERT(totalLengthOfText < INT_MAX);
1877
1878     return std::min(caretPosition + rightOffset, static_cast<int>(totalLengthOfText));
1879 }
1880
1881 bool InputHandler::deleteTextRelativeToCursor(int leftOffset, int rightOffset)
1882 {
1883     if (!isActiveTextEdit() || compositionActive())
1884         return false;
1885
1886     ProcessingChangeGuard guard(this);
1887
1888     InputLog(LogLevelInfo, "InputHandler::deleteTextRelativeToCursor left %d right %d", leftOffset, rightOffset);
1889
1890     int caretOffset = caretPosition();
1891     int start = relativeLeftOffset(caretOffset, leftOffset);
1892     int end = relativeRightOffset(caretOffset, elementText().length(), rightOffset);
1893
1894     // If we have backspace in a single character, send this to webkit as a KeyboardEvent. Otherwise, call deleteText.
1895     if (leftOffset == 1 && !rightOffset) {
1896         if (!handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_BACKSPACE, Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */))
1897             return false;
1898     } else if (!deleteText(start, end))
1899         return false;
1900
1901     // Scroll the field if necessary. The automatic update is suppressed
1902     // by the processing change guard.
1903     ensureFocusTextElementVisible(EdgeIfNeeded);
1904
1905     return true;
1906 }
1907
1908 bool InputHandler::deleteText(int start, int end)
1909 {
1910     if (!isActiveTextEdit())
1911         return false;
1912
1913     ProcessingChangeGuard guard(this);
1914
1915     if (end - start == 1)
1916         return handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_BACKSPACE, Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */);
1917
1918     if (!setSelection(start, end, true /*changeIsPartOfComposition*/))
1919         return false;
1920
1921     InputLog(LogLevelInfo, "InputHandler::deleteText start %d end %d", start, end);
1922
1923     return deleteSelection();
1924 }
1925
1926 spannable_string_t* InputHandler::spannableTextInRange(int start, int end, int32_t flags)
1927 {
1928     if (!isActiveTextEdit())
1929         return 0;
1930
1931     if (start == end)
1932         return 0;
1933
1934     ASSERT(end > start);
1935     int length = end - start;
1936
1937     WTF::String textString = elementText().substring(start, length);
1938
1939     spannable_string_t* pst = (spannable_string_t*)fastMalloc(sizeof(spannable_string_t));
1940
1941     // Don't use fastMalloc in case the string is unreasonably long. fastMalloc will
1942     // crash immediately on failure.
1943     pst->str = (wchar_t*)malloc(sizeof(wchar_t) * (length + 1));
1944     if (!pst->str) {
1945         logAlways(LogLevelCritical, "InputHandler::spannableTextInRange Cannot allocate memory for string.");
1946         free(pst);
1947         return 0;
1948     }
1949
1950     int stringLength = 0;
1951     if (!convertStringToWchar(textString, pst->str, length + 1, &stringLength)) {
1952         logAlways(LogLevelCritical, "InputHandler::spannableTextInRange failed to convert string.");
1953         free(pst->str);
1954         free(pst);
1955         return 0;
1956     }
1957
1958     pst->length = stringLength;
1959     pst->spans_count = 0;
1960     pst->spans = 0;
1961
1962     return pst;
1963 }
1964
1965 spannable_string_t* InputHandler::selectedText(int32_t flags)
1966 {
1967     if (!isActiveTextEdit())
1968         return 0;
1969
1970     return spannableTextInRange(selectionStart(), selectionEnd(), flags);
1971 }
1972
1973 spannable_string_t* InputHandler::textBeforeCursor(int32_t length, int32_t flags)
1974 {
1975     if (!isActiveTextEdit())
1976         return 0;
1977
1978     int caretOffset = caretPosition();
1979     int start = relativeLeftOffset(caretOffset, length);
1980     int end = caretOffset;
1981
1982     return spannableTextInRange(start, end, flags);
1983 }
1984
1985 spannable_string_t* InputHandler::textAfterCursor(int32_t length, int32_t flags)
1986 {
1987     if (!isActiveTextEdit())
1988         return 0;
1989
1990     int caretOffset = caretPosition();
1991     int start = caretOffset;
1992     int end = relativeRightOffset(caretOffset, elementText().length(), length);
1993
1994     return spannableTextInRange(start, end, flags);
1995 }
1996
1997 extracted_text_t* InputHandler::extractedTextRequest(extracted_text_request_t* request, int32_t flags)
1998 {
1999     if (!isActiveTextEdit())
2000         return 0;
2001
2002     extracted_text_t* extractedText = (extracted_text_t *)fastMalloc(sizeof(extracted_text_t));
2003
2004     // 'flags' indicates whether the text is being monitored. This is not currently used.
2005
2006     // FIXME add smart limiting based on the hint sizes. Currently return all text.
2007
2008     extractedText->text = spannableTextInRange(0, elementText().length(), flags);
2009
2010     // FIXME confirm these should be 0 on this requested. Text changes will likely require
2011     // the end be the length.
2012     extractedText->partial_start_offset = 0;
2013     extractedText->partial_end_offset = 0;
2014     extractedText->start_offset = 0;
2015
2016     // Adjust selection values relative to the start offset, which may be a subset
2017     // of the text in the field.
2018     extractedText->selection_start = selectionStart() - extractedText->start_offset;
2019     extractedText->selection_end = selectionEnd() - extractedText->start_offset;
2020
2021     // selectionActive is not limited to inside the extracted text.
2022     bool selectionActive = extractedText->selection_start != extractedText->selection_end;
2023     bool singleLine = m_currentFocusElement->hasTagName(HTMLNames::inputTag);
2024
2025     // FIXME flags has two values in doc, enum not in header yet.
2026     extractedText->flags = selectionActive & singleLine;
2027
2028     return extractedText;
2029 }
2030
2031 static void addCompositionTextStyleToAttributeTextStyle(AttributeTextStyle& style)
2032 {
2033     style.setUnderline(AttributeTextStyle::StandardUnderline);
2034 }
2035
2036 static void addActiveTextStyleToAttributeTextStyle(AttributeTextStyle& style)
2037 {
2038     style.setBackgroundColor(Color("blue"));
2039     style.setTextColor(Color("white"));
2040 }
2041
2042 static AttributeTextStyle compositionTextStyle()
2043 {
2044     AttributeTextStyle style;
2045     addCompositionTextStyleToAttributeTextStyle(style);
2046     return style;
2047 }
2048
2049 static AttributeTextStyle textStyleFromMask(int64_t mask)
2050 {
2051     AttributeTextStyle style;
2052     if (mask & COMPOSED_TEXT_ATTRIB)
2053         addCompositionTextStyleToAttributeTextStyle(style);
2054
2055     if (mask & ACTIVE_REGION_ATTRIB)
2056         addActiveTextStyleToAttributeTextStyle(style);
2057
2058     return style;
2059 }
2060
2061 bool InputHandler::removeComposedText()
2062 {
2063     if (compositionActive()) {
2064         if (!deleteText(m_composingTextStart, m_composingTextEnd)) {
2065             // Could not remove the existing composition region.
2066             return false;
2067         }
2068         removeAttributedTextMarker();
2069     }
2070
2071     return true;
2072 }
2073
2074 int32_t InputHandler::setComposingRegion(int32_t start, int32_t end)
2075 {
2076     if (!isActiveTextEdit())
2077         return -1;
2078
2079     if (!removeComposedText()) {
2080         // Could not remove the existing composition region.
2081         return -1;
2082     }
2083
2084     m_composingTextStart = start;
2085     m_composingTextEnd = end;
2086
2087     if (compositionActive())
2088         addAttributedTextMarker(start, end, compositionTextStyle());
2089
2090     InputLog(LogLevelInfo, "InputHandler::setComposingRegion start %d end %d", start, end);
2091
2092     return 0;
2093 }
2094
2095 int32_t InputHandler::finishComposition()
2096 {
2097     if (!isActiveTextEdit())
2098         return -1;
2099
2100     // FIXME if no composition is active, should we return failure -1?
2101     if (!compositionActive())
2102         return 0;
2103
2104     // Remove all markers.
2105     removeAttributedTextMarker();
2106
2107     InputLog(LogLevelInfo, "InputHandler::finishComposition completed");
2108
2109     return 0;
2110 }
2111
2112 span_t* InputHandler::firstSpanInString(spannable_string_t* spannableString, SpannableStringAttribute attrib)
2113 {
2114     span_t* span = spannableString->spans;
2115     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
2116         if (span->attributes_mask & attrib)
2117             return span;
2118         span++;
2119     }
2120
2121     return 0;
2122 }
2123
2124 bool InputHandler::isTrailingSingleCharacter(span_t* span, unsigned stringLength, unsigned composingTextLength)
2125 {
2126     // Make sure the new string is one character larger than the old.
2127     if (composingTextLength != stringLength - 1)
2128         return false;
2129
2130     if (!span)
2131         return false;
2132
2133     // Has only 1 character changed?
2134     if (span->start == span->end) {
2135         // Is this character the last character in the string?
2136         if (span->start == stringLength - 1)
2137             return true;
2138     }
2139     // Return after the first changed_attrib is found.
2140     return false;
2141 }
2142
2143 bool InputHandler::setText(spannable_string_t* spannableString)
2144 {
2145     if (!isActiveTextEdit() || !spannableString)
2146         return false;
2147
2148     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
2149     Frame* frame = m_currentFocusElement->document()->frame();
2150
2151     Editor* editor = frame->editor();
2152     ASSERT(editor);
2153
2154     // Disable selectionHandler's active selection as we will be resetting and these
2155     // changes should not be handled as notification event.
2156     m_webPage->m_selectionHandler->setSelectionActive(false);
2157
2158     WTF::String textToInsert = convertSpannableStringToString(spannableString);
2159     int textLength = textToInsert.length();
2160
2161     InputLog(LogLevelInfo, "InputHandler::setText spannableString is '%s', of length %d", textToInsert.latin1().data(), textLength);
2162
2163     span_t* changedSpan = firstSpanInString(spannableString, CHANGED_ATTRIB);
2164     int composingTextStart = m_composingTextStart;
2165     int composingTextEnd = m_composingTextEnd;
2166     int composingTextLength = compositionLength();
2167     removeAttributedTextMarker();
2168
2169     if (isTrailingSingleCharacter(changedSpan, textLength, composingTextLength)) {
2170         // If the text is unconverted, do not allow JS processing as it is not a "real"
2171         // character in the field.
2172         if (firstSpanInString(spannableString, UNCONVERTED_TEXT_ATTRIB)) {
2173             InputLog(LogLevelInfo, "InputHandler::setText Single trailing character detected.  Text is unconverted.");
2174             return editor->command("InsertText").execute(textToInsert.right(1));
2175         }
2176         InputLog(LogLevelInfo, "InputHandler::setText Single trailing character detected.");
2177         return handleKeyboardInput(Platform::KeyboardEvent(textToInsert[textLength - 1], Platform::KeyboardEvent::KeyDown, 0), false /* changeIsPartOfComposition */);
2178     }
2179
2180     // If no spans have changed, treat it as a delete operation.
2181     if (!changedSpan) {
2182         // If the composition length is the same as our string length, then we don't need to do anything.
2183         if (composingTextLength == textLength) {
2184             InputLog(LogLevelInfo, "InputHandler::setText No spans have changed. New text is the same length as the old. Nothing to do.");
2185             return true;
2186         }
2187
2188         if (composingTextLength - textLength == 1) {
2189             InputLog(LogLevelInfo, "InputHandler::setText No spans have changed. New text is one character shorter than the old. Treating as 'delete'.");
2190             return handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_BACKSPACE, Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */);
2191         }
2192     }
2193
2194     if (composingTextLength && !setSelection(composingTextStart, composingTextEnd, true /* changeIsPartOfComposition */))
2195         return false;
2196
2197     // If there is no text to add just delete.
2198     if (!textLength) {
2199         if (selectionActive())
2200             return handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_BACKSPACE, Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */);
2201
2202         // Nothing to do.
2203         return true;
2204     }
2205
2206     // Triggering an insert of the text with a space character trailing
2207     // causes new text to adopt the previous text style.
2208     // Remove it and apply it as a keypress later.
2209     // Upstream Webkit bug created https://bugs.webkit.org/show_bug.cgi?id=70823
2210     bool requiresSpaceKeyPress = false;
2211     if (textLength > 0 && textToInsert[textLength - 1] == KEYCODE_SPACE) {
2212         requiresSpaceKeyPress = true;
2213         textLength--;
2214         textToInsert.remove(textLength, 1);
2215     }
2216
2217     InputLog(LogLevelInfo, "InputHandler::setText Request being processed. Text before processing: '%s'", elementText().latin1().data());
2218
2219     if (textLength == 1 && !spannableString->spans_count) {
2220         // Handle single key non-attributed entry as key press rather than insert to allow
2221         // triggering of javascript events.
2222         InputLog(LogLevelInfo, "InputHandler::setText Single character entry treated as key-press in the absense of spans.");
2223         return handleKeyboardInput(Platform::KeyboardEvent(textToInsert[0], Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */);
2224     }
2225
2226     // Perform the text change as a single command if there is one.
2227     if (!textToInsert.isEmpty() && !editor->command("InsertText").execute(textToInsert)) {
2228         InputLog(LogLevelWarn, "InputHandler::setText Failed to insert text '%s'", textToInsert.latin1().data());
2229         return false;
2230     }
2231
2232     if (requiresSpaceKeyPress)
2233         handleKeyboardInput(Platform::KeyboardEvent(KEYCODE_SPACE, Platform::KeyboardEvent::KeyDown, 0), true /* changeIsPartOfComposition */);
2234
2235     InputLog(LogLevelInfo, "InputHandler::setText Request being processed. Text after processing '%s'", elementText().latin1().data());
2236
2237     return true;
2238 }
2239
2240 bool InputHandler::setTextAttributes(int insertionPoint, spannable_string_t* spannableString)
2241 {
2242     // Apply the attributes to the field.
2243     span_t* span = spannableString->spans;
2244     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
2245         unsigned int startPosition = insertionPoint + span->start;
2246         // The end point includes the character that it is before. Ie, 0, 0
2247         // applies to the first character as the end point includes the character
2248         // at the position. This means the endPosition is always +1.
2249         unsigned int endPosition = insertionPoint + span->end + 1;
2250         if (endPosition < startPosition || endPosition > elementText().length())
2251             return false;
2252
2253         if (!span->attributes_mask)
2254             continue; // Nothing to do.
2255
2256         // MISSPELLED_WORD_ATTRIB is present as an option, but it is not currently
2257         // used by IMF. When they add support for on the fly spell checking we can
2258         // use it to apply spelling markers and disable continuous spell checking.
2259
2260         InputLog(LogLevelInfo, "InputHandler::setTextAttributes adding marker %d to %d - %llu", startPosition, endPosition, span->attributes_mask);
2261         addAttributedTextMarker(startPosition, endPosition, textStyleFromMask(span->attributes_mask));
2262
2263         span++;
2264     }
2265
2266     InputLog(LogLevelInfo, "InputHandler::setTextAttributes attribute count %d", spannableString->spans_count);
2267
2268     return true;
2269 }
2270
2271 bool InputHandler::setRelativeCursorPosition(int insertionPoint, int relativeCursorPosition)
2272 {
2273     if (!isActiveTextEdit())
2274         return false;
2275
2276     // 1 place cursor at end of insertion text.
2277     if (relativeCursorPosition == 1) {
2278         m_currentFocusElement->document()->frame()->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
2279         return true;
2280     }
2281
2282     int cursorPosition = 0;
2283     if (relativeCursorPosition <= 0) {
2284         // Zero = insertionPoint
2285         // Negative value, move the cursor the requested number of characters before
2286         // the start of the inserted text.
2287         cursorPosition = insertionPoint + relativeCursorPosition;
2288     } else {
2289         // Positive value, move the cursor the requested number of characters after
2290         // the end of the inserted text minus 1.
2291         cursorPosition = caretPosition() + relativeCursorPosition - 1;
2292     }
2293
2294     if (cursorPosition < 0 || cursorPosition > (int)elementText().length())
2295         return false;
2296
2297     InputLog(LogLevelInfo, "InputHandler::setRelativeCursorPosition cursor position %d", cursorPosition);
2298
2299     return setCursorPosition(cursorPosition);
2300 }
2301
2302 bool InputHandler::setSpannableTextAndRelativeCursor(spannable_string_t* spannableString, int relativeCursorPosition, bool markTextAsComposing)
2303 {
2304     InputLog(LogLevelInfo, "InputHandler::setSpannableTextAndRelativeCursor(%d, %d, %d)", spannableString->length, relativeCursorPosition, markTextAsComposing);
2305     int insertionPoint = compositionActive() ? m_composingTextStart : selectionStart();
2306
2307     ProcessingChangeGuard guard(this);
2308
2309     if (!setText(spannableString))
2310         return false;
2311
2312     if (!setTextAttributes(insertionPoint, spannableString))
2313         return false;
2314
2315     if (!setRelativeCursorPosition(insertionPoint, relativeCursorPosition))
2316         return false;
2317
2318     if (markTextAsComposing) {
2319         m_composingTextStart = insertionPoint;
2320         m_composingTextEnd = insertionPoint + spannableString->length;
2321     }
2322
2323     // Scroll the field if necessary. The automatic update is suppressed
2324     // by the processing change guard.
2325     ensureFocusTextElementVisible(EdgeIfNeeded);
2326
2327     return true;
2328 }
2329
2330 int32_t InputHandler::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
2331 {
2332     if (!isActiveTextEdit())
2333         return -1;
2334
2335     if (!spannableString)
2336         return -1;
2337
2338     InputLog(LogLevelInfo, "InputHandler::setComposingText at relativeCursorPosition: %d", relativeCursorPosition);
2339
2340     // Enable input mode if we are processing a key event.
2341     setInputModeEnabled();
2342
2343     return setSpannableTextAndRelativeCursor(spannableString, relativeCursorPosition, true /* markTextAsComposing */) ? 0 : -1;
2344 }
2345
2346 int32_t InputHandler::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
2347 {
2348     if (!isActiveTextEdit())
2349         return -1;
2350
2351     if (!spannableString)
2352         return -1;
2353
2354     InputLog(LogLevelInfo, "InputHandler::commitText");
2355
2356     return setSpannableTextAndRelativeCursor(spannableString, relativeCursorPosition, false /* markTextAsComposing */) ? 0 : -1;
2357 }
2358
2359 }
2360 }