up spin button is now shown
[framework/web/webkit-efl.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 "CString.h"
26 #include "Chrome.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 "ScopePointer.h"
54 #include "SelectPopupClient.h"
55 #include "SelectionHandler.h"
56 #include "SpellChecker.h"
57 #include "TextCheckerClient.h"
58 #include "TextIterator.h"
59 #include "WebPageClient.h"
60 #include "WebPage_p.h"
61 #include "WebSettings.h"
62
63 #include <BlackBerryPlatformKeyboardEvent.h>
64 #include <BlackBerryPlatformLog.h>
65 #include <BlackBerryPlatformMisc.h>
66 #include <BlackBerryPlatformSettings.h>
67 #include <imf/events.h>
68 #include <sys/keycodes.h>
69
70 #define ENABLE_INPUT_LOG 0
71 #define ENABLE_FOCUS_LOG 0
72
73 static const unsigned MaxLearnTextDataSize = 500;
74
75 using namespace BlackBerry::Platform;
76 using namespace WebCore;
77
78 #if ENABLE_INPUT_LOG
79 #define InputLog(severity, format, ...) logAlways(severity, format, ## __VA_ARGS__)
80 #else
81 #define InputLog(severity, format, ...)
82 #endif // ENABLE_INPUT_LOG
83
84 #if ENABLE_FOCUS_LOG
85 #define FocusLog(severity, format, ...) logAlways(severity, format, ## __VA_ARGS__)
86 #else
87 #define FocusLog(severity, format, ...)
88 #endif // ENABLE_FOCUS_LOG
89
90 namespace BlackBerry {
91 namespace WebKit {
92
93 class ProcessingChangeGuard {
94 public:
95     ProcessingChangeGuard(InputHandler* inputHandler)
96         : m_inputHandler(inputHandler)
97         , m_savedProcessingChange(false)
98     {
99         ASSERT(m_inputHandler);
100
101         m_savedProcessingChange = m_inputHandler->processingChange();
102         m_inputHandler->setProcessingChange(true);
103     }
104
105     ~ProcessingChangeGuard()
106     {
107         m_inputHandler->setProcessingChange(m_savedProcessingChange);
108     }
109
110 private:
111     InputHandler* m_inputHandler;
112     bool m_savedProcessingChange;
113 };
114
115 InputHandler::InputHandler(WebPagePrivate* page)
116     : m_webPage(page)
117     , m_currentFocusElement(0)
118     , m_inputModeEnabled(false)
119     , m_processingChange(false)
120     , m_changingFocus(false)
121     , m_currentFocusElementType(TextEdit)
122     , m_currentFocusElementTextEditMask(DEFAULT_STYLE)
123     , m_composingTextStart(0)
124     , m_composingTextEnd(0)
125     , m_pendingKeyboardVisibilityChange(NoChange)
126     , m_delayKeyboardVisibilityChange(false)
127 {
128 }
129
130 InputHandler::~InputHandler()
131 {
132 }
133
134 static BlackBerryInputType convertInputType(const HTMLInputElement* inputElement)
135 {
136     if (inputElement->isPasswordField())
137         return InputTypePassword;
138     if (inputElement->isSearchField())
139         return InputTypeSearch;
140     if (inputElement->isEmailField())
141         return InputTypeEmail;
142     if (inputElement->isMonthControl())
143         return InputTypeMonth;
144     if (inputElement->isNumberField())
145         return InputTypeNumber;
146     if (inputElement->isTelephoneField())
147         return InputTypeTelephone;
148     if (inputElement->isURLField())
149         return InputTypeURL;
150 #if ENABLE(INPUT_TYPE_COLOR)
151     if (inputElement->isColorControl())
152         return InputTypeColor;
153 #endif
154     if (inputElement->isDateControl())
155         return InputTypeDate;
156     if (inputElement->isDateTimeControl())
157         return InputTypeDateTime;
158     if (inputElement->isDateTimeLocalControl())
159         return InputTypeDateTimeLocal;
160     if (inputElement->isTimeControl())
161         return InputTypeTime;
162     // FIXME: missing WEEK popup selector
163     if (DOMSupport::elementIdOrNameIndicatesEmail(inputElement))
164         return InputTypeEmail;
165     if (DOMSupport::elementIdOrNameIndicatesUrl(inputElement))
166         return InputTypeURL;
167     if (DOMSupport::elementPatternIndicatesNumber(inputElement))
168         return InputTypeNumber;
169     if (DOMSupport::elementPatternIndicatesHexadecimal(inputElement))
170         return InputTypeHexadecimal;
171
172     return InputTypeText;
173 }
174
175 static int inputStyle(BlackBerryInputType type, const Element* element)
176 {
177     switch (type) {
178     case InputTypeEmail:
179     case InputTypeURL:
180     case InputTypeSearch:
181     case InputTypeText:
182     case InputTypeTextArea:
183         {
184             // Regular input mode, disable help if autocomplete is off.
185             int imfMask = 0;
186             DOMSupport::AttributeState autoCompleteState = DOMSupport::elementSupportsAutocomplete(element);
187             if (autoCompleteState == DOMSupport::Off)
188                 imfMask = NO_AUTO_TEXT | NO_PREDICTION;
189             else if (autoCompleteState != DOMSupport::On
190                      && DOMSupport::elementIdOrNameIndicatesNoAutocomplete(element))
191                 imfMask = NO_AUTO_TEXT | NO_PREDICTION;
192
193             // Disable autocorrection if it's specifically off, of if it is in default mode
194             // and we have disabled auto text and prediction.
195             if (DOMSupport::elementSupportsAutocorrect(element) == DOMSupport::Off
196                 || (imfMask && DOMSupport::elementSupportsAutocorrect(element) == DOMSupport::Default))
197                 imfMask |= NO_AUTO_CORRECTION;
198
199             if (imfMask)
200                 return imfMask;
201             if ((type == InputTypeEmail || type == InputTypeURL) && autoCompleteState != DOMSupport::On)
202                 return NO_AUTO_TEXT | NO_PREDICTION | NO_AUTO_CORRECTION;
203             break;
204         }
205     case InputTypeIsIndex:
206     case InputTypePassword:
207     case InputTypeNumber:
208     case InputTypeTelephone:
209     case InputTypeHexadecimal:
210         // Disable special handling.
211         return NO_AUTO_TEXT | NO_PREDICTION | NO_AUTO_CORRECTION;
212     default:
213         break;
214     }
215     return DEFAULT_STYLE;
216 }
217
218 static VirtualKeyboardType convertStringToKeyboardType(const AtomicString& string)
219 {
220     DEFINE_STATIC_LOCAL(AtomicString, Default, ("default"));
221     DEFINE_STATIC_LOCAL(AtomicString, Url, ("url"));
222     DEFINE_STATIC_LOCAL(AtomicString, Email, ("email"));
223     DEFINE_STATIC_LOCAL(AtomicString, Password, ("password"));
224     DEFINE_STATIC_LOCAL(AtomicString, Web, ("web"));
225     DEFINE_STATIC_LOCAL(AtomicString, Number, ("number"));
226     DEFINE_STATIC_LOCAL(AtomicString, Symbol, ("symbol"));
227     DEFINE_STATIC_LOCAL(AtomicString, Phone, ("phone"));
228     DEFINE_STATIC_LOCAL(AtomicString, Pin, ("pin"));
229     DEFINE_STATIC_LOCAL(AtomicString, Hex, ("hexadecimal"));
230
231     if (string.isEmpty())
232         return VKBTypeNotSet;
233     if (equalIgnoringCase(string, Default))
234         return VKBTypeDefault;
235     if (equalIgnoringCase(string, Url))
236         return VKBTypeUrl;
237     if (equalIgnoringCase(string, Email))
238         return VKBTypeEmail;
239     if (equalIgnoringCase(string, Password))
240         return VKBTypePassword;
241     if (equalIgnoringCase(string, Web))
242         return VKBTypeWeb;
243     if (equalIgnoringCase(string, Number))
244         return VKBTypeNumPunc;
245     if (equalIgnoringCase(string, Symbol))
246         return VKBTypeSymbol;
247     if (equalIgnoringCase(string, Phone))
248         return VKBTypePhone;
249     if (equalIgnoringCase(string, Pin) || equalIgnoringCase(string, Hex))
250         return VKBTypePin;
251     return VKBTypeNotSet;
252 }
253
254 static VirtualKeyboardType keyboardTypeAttribute(const WebCore::Element* element)
255 {
256     DEFINE_STATIC_LOCAL(QualifiedName, keyboardTypeAttr, (nullAtom, "data-blackberry-virtual-keyboard-type", nullAtom));
257
258     if (element->fastHasAttribute(keyboardTypeAttr)) {
259         AtomicString attributeString = element->fastGetAttribute(keyboardTypeAttr);
260         return convertStringToKeyboardType(attributeString);
261     }
262
263     if (element->isFormControlElement()) {
264         const HTMLFormControlElement* formElement = static_cast<const HTMLFormControlElement*>(element);
265         if (formElement->form() && formElement->form()->fastHasAttribute(keyboardTypeAttr)) {
266             AtomicString attributeString = formElement->form()->fastGetAttribute(keyboardTypeAttr);
267             return convertStringToKeyboardType(attributeString);
268         }
269     }
270
271     return VKBTypeNotSet;
272 }
273
274 static VirtualKeyboardEnterKeyType convertStringToKeyboardEnterKeyType(const AtomicString& string)
275 {
276     DEFINE_STATIC_LOCAL(AtomicString, Default, ("default"));
277     DEFINE_STATIC_LOCAL(AtomicString, Connect, ("connect"));
278     DEFINE_STATIC_LOCAL(AtomicString, Done, ("done"));
279     DEFINE_STATIC_LOCAL(AtomicString, Go, ("go"));
280     DEFINE_STATIC_LOCAL(AtomicString, Join, ("join"));
281     DEFINE_STATIC_LOCAL(AtomicString, Next, ("next"));
282     DEFINE_STATIC_LOCAL(AtomicString, Search, ("search"));
283     DEFINE_STATIC_LOCAL(AtomicString, Send, ("send"));
284     DEFINE_STATIC_LOCAL(AtomicString, Submit, ("submit"));
285
286     if (string.isEmpty())
287         return VKBEnterKeyNotSet;
288     if (equalIgnoringCase(string, Default))
289         return VKBEnterKeyDefault;
290     if (equalIgnoringCase(string, Connect))
291         return VKBEnterKeyConnect;
292     if (equalIgnoringCase(string, Done))
293         return VKBEnterKeyDone;
294     if (equalIgnoringCase(string, Go))
295         return VKBEnterKeyGo;
296     if (equalIgnoringCase(string, Join))
297         return VKBEnterKeyJoin;
298     if (equalIgnoringCase(string, Next))
299         return VKBEnterKeyNext;
300     if (equalIgnoringCase(string, Search))
301         return VKBEnterKeySearch;
302     if (equalIgnoringCase(string, Send))
303         return VKBEnterKeySend;
304     if (equalIgnoringCase(string, Submit))
305         return VKBEnterKeySubmit;
306     return VKBEnterKeyNotSet;
307 }
308
309 static VirtualKeyboardEnterKeyType keyboardEnterKeyTypeAttribute(const WebCore::Element* element)
310 {
311     DEFINE_STATIC_LOCAL(QualifiedName, keyboardEnterKeyTypeAttr, (nullAtom, "data-blackberry-virtual-keyboard-enter-key", nullAtom));
312
313     if (element->fastHasAttribute(keyboardEnterKeyTypeAttr)) {
314         AtomicString attributeString = element->fastGetAttribute(keyboardEnterKeyTypeAttr);
315         return convertStringToKeyboardEnterKeyType(attributeString);
316     }
317
318     if (element->isFormControlElement()) {
319         const HTMLFormControlElement* formElement = static_cast<const HTMLFormControlElement*>(element);
320         if (formElement->form() && formElement->form()->fastHasAttribute(keyboardEnterKeyTypeAttr)) {
321             AtomicString attributeString = formElement->form()->fastGetAttribute(keyboardEnterKeyTypeAttr);
322             return convertStringToKeyboardEnterKeyType(attributeString);
323         }
324     }
325
326     return VKBEnterKeyNotSet;
327 }
328
329 WTF::String InputHandler::elementText()
330 {
331     if (!isActiveTextEdit())
332         return WTF::String();
333
334     return DOMSupport::inputElementText(m_currentFocusElement.get());
335 }
336
337 BlackBerryInputType InputHandler::elementType(Element* element) const
338 {
339     // <isIndex> is bundled with input so we need to check the formControlName
340     // first to differentiate it from input which is essentially the same as
341     // isIndex has been deprecated.
342     if (element->formControlName() == HTMLNames::isindexTag)
343         return InputTypeIsIndex;
344
345     if (const HTMLInputElement* inputElement = static_cast<const HTMLInputElement*>(element->toInputElement()))
346         return convertInputType(inputElement);
347
348     if (element->hasTagName(HTMLNames::textareaTag))
349         return InputTypeTextArea;
350
351     // Default to InputTypeTextArea for content editable fields.
352     return InputTypeTextArea;
353 }
354
355 void InputHandler::focusedNodeChanged()
356 {
357     ASSERT(m_webPage->m_page->focusController());
358     Frame* frame = m_webPage->m_page->focusController()->focusedOrMainFrame();
359     if (!frame || !frame->document())
360         return;
361
362     Node* node = frame->document()->focusedNode();
363
364     if (isActiveTextEdit() && m_currentFocusElement == node) {
365         if (!processingChange())
366             notifyClientOfKeyboardVisibilityChange(true);
367         return;
368     }
369
370     if (node && node->isElementNode()) {
371         Element* element = static_cast<Element*>(node);
372         if (DOMSupport::isElementTypePlugin(element)) {
373             setPluginFocused(element);
374             return;
375         }
376
377         if (DOMSupport::isTextBasedContentEditableElement(element)) {
378             // Focused node is a text based input field, textarea or content editable field.
379             setElementFocused(element);
380             return;
381         }
382     }
383
384     if (isActiveTextEdit() && m_currentFocusElement->isContentEditable()) {
385         // This is a special handler for content editable fields. The focus node is the top most
386         // field that is content editable, however, by enabling / disabling designmode and
387         // content editable, it is possible through javascript or selection to trigger the focus node to
388         // change even while maintaining editing on the same selection point. If the focus element
389         // isn't contentEditable, but the current selection is, don't send a change notification.
390
391         // When processing changes selection changes occur that may reset the focus element
392         // and could potentially cause a crash as m_currentFocusElement should not be
393         // changed during processing of an EditorCommand.
394         if (processingChange())
395             return;
396
397         Frame* frame = m_currentFocusElement->document()->frame();
398         ASSERT(frame);
399
400         // Test the current selection to make sure that the content in focus is still content
401         // editable. This may mean Javascript triggered a focus change by modifying the
402         // top level parent of this object's content editable state without actually modifying
403         // this particular object.
404         // Example site: html5demos.com/contentEditable - blur event triggers focus change.
405         if (frame == m_webPage->focusedOrMainFrame() && frame->selection()->start().anchorNode()
406             && frame->selection()->start().anchorNode()->isContentEditable())
407                 return;
408     }
409
410     // No valid focus element found for handling.
411     setElementUnfocused();
412 }
413
414 void InputHandler::setPluginFocused(Element* element)
415 {
416     ASSERT(DOMSupport::isElementTypePlugin(element));
417
418     if (isActiveTextEdit())
419         setElementUnfocused();
420
421     m_currentFocusElementType = Plugin;
422     m_currentFocusElement = element;
423 }
424
425 static bool convertStringToWchar(const String& string, wchar_t* dest, int destCapacity, int* destLength)
426 {
427     ASSERT(dest);
428
429     if (!string.length()) {
430         destLength = 0;
431         return true;
432     }
433
434     UErrorCode ec = U_ZERO_ERROR;
435     // wchar_t strings sent to IMF are 32 bit so casting to UChar32 is safe.
436     u_strToUTF32(reinterpret_cast<UChar32*>(dest), destCapacity, destLength, string.characters(), string.length(), &ec);
437     if (ec) {
438         logAlways(LogLevelCritical, "InputHandler::convertStringToWchar Error converting string ec (%d).", ec);
439         destLength = 0;
440         return false;
441     }
442     return true;
443 }
444
445 static bool convertStringToWcharVector(const String& string, WTF::Vector<wchar_t>& wcharString)
446 {
447     ASSERT(wcharString.isEmpty());
448
449     int length = string.length();
450     if (!length)
451         return true;
452
453     if (!wcharString.tryReserveCapacity(length + 1)) {
454         logAlways(LogLevelCritical, "InputHandler::convertStringToWcharVector Cannot allocate memory for string.\n");
455         return false;
456     }
457
458     int destLength = 0;
459     if (!convertStringToWchar(string, wcharString.data(), length + 1, &destLength))
460         return false;
461
462     wcharString.resize(destLength);
463     return true;
464 }
465
466 static String convertSpannableStringToString(spannable_string_t* src)
467 {
468     if (!src || !src->str || !src->length)
469         return String();
470
471     WTF::Vector<UChar> dest;
472     int destCapacity = (src->length * 2) + 1;
473     if (!dest.tryReserveCapacity(destCapacity)) {
474         logAlways(LogLevelCritical, "InputHandler::convertSpannableStringToString Cannot allocate memory for string.\n");
475         return String();
476     }
477
478     int destLength = 0;
479     UErrorCode ec = U_ZERO_ERROR;
480     // wchar_t strings sent from IMF are 32 bit so casting to UChar32 is safe.
481     u_strFromUTF32(dest.data(), destCapacity, &destLength, reinterpret_cast<UChar32*>(src->str), src->length, &ec);
482     if (ec) {
483         logAlways(LogLevelCritical, "InputHandler::convertSpannableStringToString Error converting string ec (%d).", ec);
484         return String();
485     }
486     dest.resize(destLength);
487     return String(dest.data(), destLength);
488 }
489
490 void InputHandler::sendLearnTextDetails(const WTF::String& string)
491 {
492     Vector<wchar_t> wcharString;
493     if (!convertStringToWcharVector(string, wcharString) || wcharString.isEmpty())
494         return;
495
496     m_webPage->m_client->inputLearnText(wcharString.data(), wcharString.size());
497 }
498
499 void InputHandler::learnText()
500 {
501     if (!isActiveTextEdit())
502         return;
503
504     // Do not send (or calculate) the text when the field is NO_PREDICTION or NO_AUTO_TEXT.
505     if (m_currentFocusElementTextEditMask & NO_PREDICTION || m_currentFocusElementTextEditMask & NO_AUTO_TEXT)
506         return;
507
508     String textInField(elementText());
509     textInField = textInField.substring(std::max(0, static_cast<int>(textInField.length() - MaxLearnTextDataSize)), textInField.length());
510     textInField.remove(0, textInField.find(" "));
511
512     // Build up the 500 character strings in word chunks.
513     // Spec says 1000, but memory corruption has been observed.
514     ASSERT(textInField.length() <= MaxLearnTextDataSize);
515
516     if (textInField.isEmpty())
517         return;
518
519     InputLog(LogLevelInfo, "InputHandler::learnText '%s'", textInField.latin1().data());
520     sendLearnTextDetails(textInField);
521 }
522
523 void InputHandler::requestCheckingOfString(PassRefPtr<WebCore::TextCheckingRequest> textCheckingRequest)
524 {
525     RefPtr<WebCore::TextCheckingRequest> request = textCheckingRequest;
526
527     int32_t sequenceId = request->sequence();
528     int requestLength = request->text().length();
529     if (!requestLength /* || requestLength > maxSpellCheckStringLength */) {
530         spellCheckingRequestCancelled(sequenceId, true /* isSequenceId */);
531         return;
532     }
533
534     wchar_t* checkingString = (wchar_t*)malloc(sizeof(wchar_t) * (requestLength + 1));
535     if (!checkingString) {
536         BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "InputHandler::requestCheckingOfString Cannot allocate memory for string.");
537         spellCheckingRequestCancelled(sequenceId, true /* isSequenceId */);
538         return;
539     }
540
541     int stringLength = 0;
542     if (!convertStringToWchar(request->text(), checkingString, requestLength + 1, &stringLength)) {
543         BlackBerry::Platform::logAlways(BlackBerry::Platform::LogLevelCritical, "InputHandler::requestCheckingOfString Failed to convert String to wchar type.");
544         free(checkingString);
545         spellCheckingRequestCancelled(sequenceId, true /* isSequenceId */);
546         return;
547     }
548
549     int32_t transactionId = m_webPage->m_client->checkSpellingOfStringAsync(checkingString, stringLength);
550     free(checkingString);
551
552     // If the call to the input service did not go through, then cancel the request so we don't block endlessly.
553     // This should still take transactionId as a parameter to maintain the same behavior as if InputMethodSupport
554     // were to cancel a request during processing.
555     if (transactionId == -1) { // Error before sending request to input service.
556         spellCheckingRequestCancelled(sequenceId, true /* isSequenceId */);
557         return;
558     }
559
560     // map sequenceId to transactionId.
561     m_sequenceMap[transactionId] = sequenceId;
562 }
563
564 int32_t InputHandler::convertTransactionIdToSequenceId(int32_t transactionId)
565 {
566     std::map<int32_t, int32_t>::iterator it = m_sequenceMap.find(transactionId);
567
568     if (it == m_sequenceMap.end())
569         return 0;
570
571     int32_t sequenceId = it->second;
572     // We only convert this value when we have received its response, so its safe to remove it from the map.
573     m_sequenceMap.erase(it);
574
575     return sequenceId;
576 }
577
578 void InputHandler::spellCheckingRequestProcessed(int32_t transactionId, spannable_string_t* spannableString)
579 {
580     if (!spannableString) {
581         spellCheckingRequestCancelled(transactionId, false /* isSequenceId */);
582         return;
583     }
584
585     Vector<TextCheckingResult> results;
586
587     // Convert the spannableString to TextCheckingResult then append to results vector.
588     String replacement;
589     TextCheckingResult textCheckingResult;
590     textCheckingResult.type = TextCheckingTypeSpelling;
591     textCheckingResult.replacement = replacement;
592     textCheckingResult.location = 0;
593     textCheckingResult.length = 0;
594
595     span_t* span = spannableString->spans;
596     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
597         if (!span)
598             break;
599         if (span->end < span->start) {
600             spellCheckingRequestCancelled(transactionId, false /* isSequenceId */);
601             return;
602         }
603         if (span->attributes_mask & MISSPELLED_WORD_ATTRIB) {
604             textCheckingResult.location = span->start;
605             // The end point includes the character that it is before. Ie, 0, 0
606             // applies to the first character as the end point includes the character
607             // at the position. This means the endPosition is always +1.
608             textCheckingResult.length = span->end - span->start + 1;
609             results.append(textCheckingResult);
610         }
611         span++;
612     }
613
614     // transactionId here is for use with the input service. We need to translate this to sequenceId used with SpellChecker.
615     int32_t sequenceId = convertTransactionIdToSequenceId(transactionId);
616
617     SpellChecker* sp = getSpellChecker();
618     if (!sp || !sequenceId) {
619         InputLog(LogLevelWarn, "InputHandler::spellCheckingRequestProcessed failed to process the request with sequenceId %d", sequenceId);
620         spellCheckingRequestCancelled(sequenceId, true /* isSequenceId */);
621         return;
622     }
623     sp->didCheckSucceeded(sequenceId, results);
624 }
625
626 void InputHandler::spellCheckingRequestCancelled(int32_t id, bool isSequenceId)
627 {
628     int32_t sequenceId = isSequenceId ? id : convertTransactionIdToSequenceId(id);
629     SpellChecker* sp = getSpellChecker();
630     if (!sp) {
631         InputLog(LogLevelWarn, "InputHandler::spellCheckingRequestCancelled failed to cancel the request with sequenceId %d", sequenceId);
632         return;
633     }
634     sp->didCheckCanceled(sequenceId);
635 }
636
637 SpellChecker* InputHandler::getSpellChecker()
638 {
639     if (Frame* frame = m_currentFocusElement->document()->frame())
640         if (Editor* editor = frame->editor())
641             return editor->spellChecker();
642
643     return 0;
644 }
645
646 void InputHandler::setElementUnfocused(bool refocusOccuring)
647 {
648     if (isActiveTextEdit()) {
649         FocusLog(LogLevelInfo, "InputHandler::setElementUnfocused");
650
651         // Pass any text into the field to IMF to learn.
652         learnText();
653
654         // End any composition that is in progress.
655         finishComposition();
656
657         // Only hide the keyboard if we aren't refocusing on a new input field.
658         if (!refocusOccuring)
659             notifyClientOfKeyboardVisibilityChange(false);
660
661         m_webPage->m_client->inputFocusLost();
662         m_webPage->m_selectionHandler->selectionPositionChanged();
663
664         // If the frame selection isn't focused, focus it.
665         if (!m_currentFocusElement->document()->frame()->selection()->isFocused())
666             m_currentFocusElement->document()->frame()->selection()->setFocused(true);
667     }
668
669     // Clear the node details.
670     m_currentFocusElement = 0;
671     m_currentFocusElementType = TextEdit;
672 }
673
674 bool InputHandler::isInputModeEnabled() const
675 {
676     // Input mode is enabled when set, or when dump render tree or always show keyboard setting is enabled.
677     return m_inputModeEnabled || m_webPage->m_dumpRenderTree || Platform::Settings::instance()->alwaysShowKeyboardOnFocus();
678 }
679
680 void InputHandler::setInputModeEnabled(bool active)
681 {
682     FocusLog(LogLevelInfo, "InputHandler::setInputModeEnabled '%s', override is '%s'"
683              , active ? "true" : "false"
684              , m_webPage->m_dumpRenderTree || Platform::Settings::instance()->alwaysShowKeyboardOnFocus() ? "true" : "false");
685
686     m_inputModeEnabled = active;
687
688     // If the frame selection isn't focused, focus it.
689     if (isInputModeEnabled() && isActiveTextEdit() && !m_currentFocusElement->document()->frame()->selection()->isFocused())
690         m_currentFocusElement->document()->frame()->selection()->setFocused(true);
691 }
692
693 void InputHandler::setElementFocused(Element* element)
694 {
695     ASSERT(DOMSupport::isTextBasedContentEditableElement(element));
696     ASSERT(element->document() && element->document()->frame());
697
698     if (element->document()->frame()->selection()->isFocused() != isInputModeEnabled())
699         element->document()->frame()->selection()->setFocused(isInputModeEnabled());
700
701     // Clear the existing focus node details.
702     setElementUnfocused(true /*refocusOccuring*/);
703
704     // Mark this element as active and add to frame set.
705     m_currentFocusElement = element;
706     m_currentFocusElementType = TextEdit;
707
708     // Send details to the client about this element.
709     BlackBerryInputType type = elementType(element);
710     m_currentFocusElementTextEditMask = inputStyle(type, element);
711
712     VirtualKeyboardType keyboardType = keyboardTypeAttribute(element);
713     VirtualKeyboardEnterKeyType enterKeyType = keyboardEnterKeyTypeAttribute(element);
714
715     FocusLog(LogLevelInfo, "InputHandler::setElementFocused, Type=%d, Style=%d, Keyboard Type=%d, Enter Key=%d", type, m_currentFocusElementTextEditMask, keyboardType, enterKeyType);
716     m_webPage->m_client->inputFocusGained(type, m_currentFocusElementTextEditMask, keyboardType, enterKeyType);
717
718     handleInputLocaleChanged(m_webPage->m_webSettings->isWritingDirectionRTL());
719
720     if (!m_delayKeyboardVisibilityChange)
721         notifyClientOfKeyboardVisibilityChange(true);
722 }
723
724 bool InputHandler::openDatePopup(HTMLInputElement* element, BlackBerryInputType type)
725 {
726     if (!element || element->disabled() || !DOMSupport::isDateTimeInputField(element))
727         return false;
728
729     if (isActiveTextEdit())
730         clearCurrentFocusElement();
731
732     switch (type) {
733     case BlackBerry::Platform::InputTypeDate:
734     case BlackBerry::Platform::InputTypeTime:
735     case BlackBerry::Platform::InputTypeDateTime:
736     case BlackBerry::Platform::InputTypeDateTimeLocal: {
737         // Check if popup already exists, close it if does.
738         m_webPage->m_page->chrome()->client()->closePagePopup(0);
739         String value = element->value();
740         String min = element->getAttribute(HTMLNames::minAttr).string();
741         String max = element->getAttribute(HTMLNames::maxAttr).string();
742         double step = element->getAttribute(HTMLNames::stepAttr).toDouble();
743
744         DatePickerClient* client = new DatePickerClient(type, value, min, max, step,  m_webPage, element);
745         // Fail to create HTML popup, use the old path
746         if (!m_webPage->m_page->chrome()->client()->openPagePopup(client,  WebCore::IntRect()))
747             m_webPage->m_client->openDateTimePopup(type, value, min, max, step);
748
749         return true;
750         }
751     default: // Other types not supported
752         return false;
753     }
754 }
755
756 bool InputHandler::openColorPopup(HTMLInputElement* element)
757 {
758     if (!element || element->disabled() || !DOMSupport::isColorInputField(element))
759         return false;
760
761     if (isActiveTextEdit())
762         clearCurrentFocusElement();
763
764     m_currentFocusElement = element;
765     m_currentFocusElementType = TextPopup;
766
767     m_webPage->m_client->openColorPopup(element->value());
768     return true;
769 }
770
771 void InputHandler::setInputValue(const WTF::String& value)
772 {
773     if (!isActiveTextPopup())
774         return;
775
776     HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(m_currentFocusElement.get());
777     inputElement->setValue(value);
778     clearCurrentFocusElement();
779 }
780
781 void InputHandler::nodeTextChanged(const Node* node)
782 {
783     if (processingChange() || !node)
784         return;
785
786     if (node != m_currentFocusElement)
787         return;
788
789     InputLog(LogLevelInfo, "InputHandler::nodeTextChanged");
790
791     m_webPage->m_client->inputTextChanged();
792
793     // Remove the attributed text markers as the previous call triggered an end to
794     // the composition.
795     removeAttributedTextMarker();
796 }
797
798 WebCore::IntRect InputHandler::boundingBoxForInputField()
799 {
800     if (!isActiveTextEdit())
801         return WebCore::IntRect();
802
803     if (!m_currentFocusElement->renderer())
804         return WebCore::IntRect();
805
806     return m_currentFocusElement->renderer()->absoluteBoundingBoxRect();
807 }
808
809 void InputHandler::ensureFocusTextElementVisible(CaretScrollType scrollType)
810 {
811     if (!isActiveTextEdit() || !isInputModeEnabled() || !m_currentFocusElement->document())
812         return;
813
814     if (!Platform::Settings::instance()->allowCenterScrollAdjustmentForInputFields() && scrollType != EdgeIfNeeded)
815         return;
816
817     Frame* elementFrame = m_currentFocusElement->document()->frame();
818     if (!elementFrame)
819         return;
820
821     Frame* mainFrame = m_webPage->mainFrame();
822     if (!mainFrame)
823         return;
824
825     FrameView* mainFrameView = mainFrame->view();
826     if (!mainFrameView)
827         return;
828
829     WebCore::IntRect selectionFocusRect;
830     switch (elementFrame->selection()->selectionType()) {
831     case VisibleSelection::CaretSelection:
832         selectionFocusRect = elementFrame->selection()->absoluteCaretBounds();
833         break;
834     case VisibleSelection::RangeSelection: {
835         Position selectionPosition;
836         if (m_webPage->m_selectionHandler->lastUpdatedEndPointIsValid())
837             selectionPosition = elementFrame->selection()->end();
838         else
839             selectionPosition = elementFrame->selection()->start();
840         selectionFocusRect = VisiblePosition(selectionPosition).absoluteCaretBounds();
841         break;
842     }
843     case VisibleSelection::NoSelection:
844         return;
845     }
846
847     int fontHeight = selectionFocusRect.height();
848
849     if (elementFrame != mainFrame) { // Element is in a subframe.
850         // Remove any scroll offset within the subframe to get the point relative to the main frame.
851         selectionFocusRect.move(-elementFrame->view()->scrollPosition().x(), -elementFrame->view()->scrollPosition().y());
852
853         // Adjust the selection rect based on the frame offset in relation to the main frame if it's a subframe.
854         if (elementFrame->ownerRenderer()) {
855             WebCore::IntPoint frameOffset = elementFrame->ownerRenderer()->absoluteContentBox().location();
856             selectionFocusRect.move(frameOffset.x(), frameOffset.y());
857         }
858     }
859
860     Position start = elementFrame->selection()->start();
861     if (start.anchorNode() && start.anchorNode()->renderer()) {
862         if (RenderLayer* layer = start.anchorNode()->renderer()->enclosingLayer()) {
863             WebCore::IntRect actualScreenRect = WebCore::IntRect(mainFrameView->scrollPosition(), m_webPage->actualVisibleSize());
864             ScrollAlignment horizontalScrollAlignment = ScrollAlignment::alignToEdgeIfNeeded;
865             ScrollAlignment verticalScrollAlignment = ScrollAlignment::alignToEdgeIfNeeded;
866
867             if (scrollType != EdgeIfNeeded) {
868                 // Align the selection rect if possible so that we show the field's
869                 // outline if the caret is at the edge of the field.
870                 if (RenderObject* focusedRenderer = m_currentFocusElement->renderer()) {
871                     WebCore::IntRect nodeOutlineBounds = focusedRenderer->absoluteOutlineBounds();
872                     WebCore::IntRect caretAtEdgeRect = rectForCaret(0);
873                     int paddingX = abs(caretAtEdgeRect.x() - nodeOutlineBounds.x());
874                     int paddingY = abs(caretAtEdgeRect.y() - nodeOutlineBounds.y());
875
876                     if (selectionFocusRect.x() - paddingX == nodeOutlineBounds.x())
877                         selectionFocusRect.setX(nodeOutlineBounds.x());
878                     else if (selectionFocusRect.maxX() + paddingX == nodeOutlineBounds.maxX())
879                         selectionFocusRect.setX(nodeOutlineBounds.maxX() - selectionFocusRect.width());
880                     if (selectionFocusRect.y() - paddingY == nodeOutlineBounds.y())
881                         selectionFocusRect.setY(nodeOutlineBounds.y() - selectionFocusRect.height());
882                     else if (selectionFocusRect.maxY() + paddingY == nodeOutlineBounds.maxY())
883                         selectionFocusRect.setY(nodeOutlineBounds.maxY() - selectionFocusRect.height());
884
885                     // If the editing point is on the left hand side of the screen when the node's
886                     // rect is edge aligned, edge align the node rect.
887                     if (selectionFocusRect.x() - caretAtEdgeRect.x() < actualScreenRect.width() / 2)
888                         selectionFocusRect.setX(nodeOutlineBounds.x());
889                     else
890                         horizontalScrollAlignment = ScrollAlignment::alignCenterIfNeeded;
891
892                 }
893                 verticalScrollAlignment = (scrollType == CenterAlways) ? ScrollAlignment::alignCenterAlways : ScrollAlignment::alignCenterIfNeeded;
894             }
895
896             // Pad the rect to improve the visual appearance.
897             // Padding must be large enough to expose the selection / FCC should they exist. Dragging the handle offscreen and releasing
898             // will not trigger an automatic scroll. Using a padding of 40 will fully exposing the width of the current handle and half of
899             // the height making it usable.
900             // FIXME: This will need to be updated when the graphics change.
901             // FIXME: The value of 40 should be calculated as a unit of measure using Graphics::Screen::primaryScreen()->heightInMMToPixels
902             // using a relative value to the size of the handle. We should also consider expanding different amounts horizontally vs vertically.
903             selectionFocusRect.inflate(40 /* padding in pixels */);
904             WebCore::IntRect revealRect = layer->getRectToExpose(actualScreenRect, selectionFocusRect,
905                                                                  horizontalScrollAlignment,
906                                                                  verticalScrollAlignment);
907
908             mainFrameView->setConstrainsScrollingToContentEdge(false);
909             // In order to adjust the scroll position to ensure the focused input field is visible,
910             // we allow overscrolling. However this overscroll has to be strictly allowed towards the
911             // bottom of the page on the y axis only, where the virtual keyboard pops up from.
912             WebCore::IntPoint scrollLocation = revealRect.location();
913             scrollLocation.clampNegativeToZero();
914             WebCore::IntPoint maximumScrollPosition = WebCore::IntPoint(mainFrameView->contentsWidth() - actualScreenRect.width(), mainFrameView->contentsHeight() - actualScreenRect.height());
915             scrollLocation = scrollLocation.shrunkTo(maximumScrollPosition);
916             mainFrameView->setScrollPosition(scrollLocation);
917             mainFrameView->setConstrainsScrollingToContentEdge(true);
918         }
919     }
920
921     // If the text is too small, zoom in to make it a minimum size.
922     static const int s_minimumTextHeightInPixels = 6;
923     if (fontHeight && fontHeight < s_minimumTextHeightInPixels)
924         m_webPage->zoomAboutPoint(s_minimumTextHeightInPixels / fontHeight, m_webPage->centerOfVisibleContentsRect());
925 }
926
927 void InputHandler::ensureFocusPluginElementVisible()
928 {
929     if (!isActivePlugin() || !m_currentFocusElement->document())
930         return;
931
932     Frame* elementFrame = m_currentFocusElement->document()->frame();
933     if (!elementFrame)
934         return;
935
936     Frame* mainFrame = m_webPage->mainFrame();
937     if (!mainFrame)
938         return;
939
940     FrameView* mainFrameView = mainFrame->view();
941     if (!mainFrameView)
942         return;
943
944     WebCore::IntRect selectionFocusRect;
945
946     RenderWidget* renderWidget = static_cast<RenderWidget*>(m_currentFocusElement->renderer());
947     if (renderWidget) {
948         PluginView* pluginView = static_cast<PluginView*>(renderWidget->widget());
949
950         if (pluginView)
951             selectionFocusRect = pluginView->ensureVisibleRect();
952     }
953
954     if (selectionFocusRect.isEmpty())
955         return;
956
957     // FIXME: We may need to scroll the subframe (recursively) in the future. Revisit this...
958     if (elementFrame != mainFrame) { // Element is in a subframe.
959         // Remove any scroll offset within the subframe to get the point relative to the main frame.
960         selectionFocusRect.move(-elementFrame->view()->scrollPosition().x(), -elementFrame->view()->scrollPosition().y());
961
962         // Adjust the selection rect based on the frame offset in relation to the main frame if it's a subframe.
963         if (elementFrame->ownerRenderer()) {
964             WebCore::IntPoint frameOffset = elementFrame->ownerRenderer()->absoluteContentBox().location();
965             selectionFocusRect.move(frameOffset.x(), frameOffset.y());
966         }
967     }
968
969     WebCore::IntRect actualScreenRect = WebCore::IntRect(mainFrameView->scrollPosition(), m_webPage->actualVisibleSize());
970     if (actualScreenRect.contains(selectionFocusRect))
971         return;
972
973     // Calculate a point such that the center of the requested rectangle
974     // is at the center of the screen. FIXME: If the element was partially on screen
975     // we might want to just bring the offscreen portion into view, someone needs
976     // to decide if that's the behavior we want or not.
977     WebCore::IntPoint pos(selectionFocusRect.center().x() - actualScreenRect.width() / 2,
978                  selectionFocusRect.center().y() - actualScreenRect.height() / 2);
979
980     mainFrameView->setScrollPosition(pos);
981 }
982
983 void InputHandler::ensureFocusElementVisible(bool centerInView)
984 {
985     if (isActivePlugin())
986         ensureFocusPluginElementVisible();
987     else
988         ensureFocusTextElementVisible(centerInView ? CenterAlways : CenterIfNeeded);
989 }
990
991 void InputHandler::frameUnloaded(const Frame* frame)
992 {
993     if (!isActiveTextEdit())
994         return;
995
996     if (m_currentFocusElement->document()->frame() != frame)
997         return;
998
999     FocusLog(LogLevelInfo, "InputHandler::frameUnloaded");
1000
1001     setElementUnfocused(false /*refocusOccuring*/);
1002 }
1003
1004 void InputHandler::setDelayKeyboardVisibilityChange(bool value)
1005 {
1006     m_delayKeyboardVisibilityChange = value;
1007     m_pendingKeyboardVisibilityChange = NoChange;
1008 }
1009
1010 void InputHandler::processPendingKeyboardVisibilityChange()
1011 {
1012     if (!m_delayKeyboardVisibilityChange) {
1013         ASSERT(m_pendingKeyboardVisibilityChange == NoChange);
1014         return;
1015     }
1016
1017     m_delayKeyboardVisibilityChange = false;
1018
1019     if (m_pendingKeyboardVisibilityChange == NoChange)
1020         return;
1021
1022     notifyClientOfKeyboardVisibilityChange(m_pendingKeyboardVisibilityChange == Visible);
1023     m_pendingKeyboardVisibilityChange = NoChange;
1024 }
1025
1026 void InputHandler::notifyClientOfKeyboardVisibilityChange(bool visible)
1027 {
1028     // If we aren't ready for input, keyboard changes should be ignored.
1029     if (!isInputModeEnabled() && visible)
1030         return;
1031
1032     if (!m_delayKeyboardVisibilityChange) {
1033         m_webPage->showVirtualKeyboard(visible);
1034         return;
1035     }
1036
1037     m_pendingKeyboardVisibilityChange = visible ? Visible : NotVisible;
1038 }
1039
1040 bool InputHandler::selectionAtStartOfElement()
1041 {
1042     if (!isActiveTextEdit())
1043         return false;
1044
1045     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1046
1047     if (!selectionStart())
1048         return true;
1049
1050     return false;
1051 }
1052
1053 bool InputHandler::selectionAtEndOfElement()
1054 {
1055     if (!isActiveTextEdit())
1056         return false;
1057
1058     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1059
1060     return selectionStart() == static_cast<int>(elementText().length());
1061 }
1062
1063 int InputHandler::selectionStart() const
1064 {
1065     return selectionPosition(true);
1066 }
1067
1068 int InputHandler::selectionEnd() const
1069 {
1070     return selectionPosition(false);
1071 }
1072
1073 int InputHandler::selectionPosition(bool start) const
1074 {
1075     if (!m_currentFocusElement->document() || !m_currentFocusElement->document()->frame())
1076         return 0;
1077
1078     if (HTMLTextFormControlElement* controlElement = DOMSupport::toTextControlElement(m_currentFocusElement.get()))
1079         return start ? controlElement->selectionStart() : controlElement->selectionEnd();
1080
1081     FrameSelection caretSelection;
1082     caretSelection.setSelection(m_currentFocusElement->document()->frame()->selection()->selection());
1083     RefPtr<Range> rangeSelection = caretSelection.selection().toNormalizedRange();
1084     if (!rangeSelection)
1085         return 0;
1086
1087     int selectionPointInNode = start ? rangeSelection->startOffset() : rangeSelection->endOffset();
1088     Node* containerNode = start ? rangeSelection->startContainer() : rangeSelection->endContainer();
1089
1090     ExceptionCode ec;
1091     RefPtr<Range> rangeForNode = rangeOfContents(m_currentFocusElement.get());
1092     rangeForNode->setEnd(containerNode, selectionPointInNode, ec);
1093     ASSERT(!ec);
1094
1095     return TextIterator::rangeLength(rangeForNode.get());
1096 }
1097
1098 void InputHandler::selectionChanged()
1099 {
1100     // This method can get called during WebPage shutdown process.
1101     // If that is the case, just bail out since the client is not
1102     // in a safe state of trust to request anything else from it.
1103     if (!m_webPage->m_mainFrame)
1104         return;
1105
1106     if (!isActiveTextEdit())
1107         return;
1108
1109     if (processingChange())
1110         return;
1111
1112     // Scroll the field if necessary. This must be done even if we are processing
1113     // a change as the text change may have moved the caret. IMF doesn't require
1114     // the update, but the user needs to see the caret.
1115     ensureFocusTextElementVisible(EdgeIfNeeded);
1116
1117     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1118
1119     int newSelectionStart = selectionStart();
1120     int newSelectionEnd = selectionEnd();
1121
1122     InputLog(LogLevelInfo, "InputHandler::selectionChanged selectionStart=%u, selectionEnd=%u", newSelectionStart, newSelectionEnd);
1123
1124     m_webPage->m_client->inputSelectionChanged(newSelectionStart, newSelectionEnd);
1125
1126     // Remove the attributed text markers as the previous call triggered an end to
1127     // the composition.
1128     removeAttributedTextMarker();
1129 }
1130
1131 bool InputHandler::setCursorPosition(int location)
1132 {
1133     return setSelection(location, location);
1134 }
1135
1136 bool InputHandler::setSelection(int start, int end, bool changeIsPartOfComposition)
1137 {
1138     if (!isActiveTextEdit())
1139         return false;
1140
1141     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1142
1143     ProcessingChangeGuard guard(this);
1144
1145     VisibleSelection newSelection = DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), start, end);
1146     m_currentFocusElement->document()->frame()->selection()->setSelection(newSelection, changeIsPartOfComposition ? 0 : FrameSelection::CloseTyping | FrameSelection::ClearTypingStyle);
1147
1148     InputLog(LogLevelInfo, "InputHandler::setSelection selectionStart=%u, selectionEnd=%u", start, end);
1149
1150     return start == selectionStart() && end == selectionEnd();
1151 }
1152
1153 WebCore::IntRect InputHandler::rectForCaret(int index)
1154 {
1155     if (!isActiveTextEdit())
1156         return WebCore::IntRect();
1157
1158     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1159
1160     if (index < 0 || index > static_cast<int>(elementText().length())) {
1161         // Invalid request.
1162         return WebCore::IntRect();
1163     }
1164
1165     FrameSelection caretSelection;
1166     caretSelection.setSelection(DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), index, index).visibleStart());
1167     caretSelection.modify(FrameSelection::AlterationExtend, DirectionForward, CharacterGranularity);
1168     return caretSelection.selection().visibleStart().absoluteCaretBounds();
1169 }
1170
1171 void InputHandler::cancelSelection()
1172 {
1173     if (!isActiveTextEdit())
1174         return;
1175
1176     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1177
1178     int selectionStartPosition = selectionStart();
1179     ProcessingChangeGuard guard(this);
1180     setCursorPosition(selectionStartPosition);
1181 }
1182
1183 bool InputHandler::handleKeyboardInput(const Platform::KeyboardEvent& keyboardEvent, bool changeIsPartOfComposition)
1184 {
1185     InputLog(LogLevelInfo, "InputHandler::handleKeyboardInput received character=%lc, type=%d", keyboardEvent.character(), keyboardEvent.type());
1186
1187     // Enable input mode if we are processing a key event.
1188     setInputModeEnabled();
1189
1190     // If we aren't specifically part of a composition, fail, IMF should never send key input
1191     // while composing text. If IMF has failed, we should have already finished the
1192     // composition manually.
1193     if (!changeIsPartOfComposition && compositionActive())
1194         return false;
1195
1196     ProcessingChangeGuard guard(this);
1197
1198     unsigned adjustedModifiers = keyboardEvent.modifiers();
1199     if (WTF::isASCIIUpper(keyboardEvent.character()))
1200         adjustedModifiers |= KEYMOD_SHIFT;
1201
1202     ASSERT(m_webPage->m_page->focusController());
1203     bool keyboardEventHandled = false;
1204     if (Frame* focusedFrame = m_webPage->m_page->focusController()->focusedFrame()) {
1205         bool isKeyChar = keyboardEvent.type() == Platform::KeyboardEvent::KeyChar;
1206         Platform::KeyboardEvent::Type type = keyboardEvent.type();
1207
1208         // If this is a KeyChar type then we handle it as a keydown followed by a key up.
1209         if (isKeyChar)
1210             type = Platform::KeyboardEvent::KeyDown;
1211
1212         Platform::KeyboardEvent adjustedKeyboardEvent(keyboardEvent.character(), type, adjustedModifiers);
1213         keyboardEventHandled = focusedFrame->eventHandler()->keyEvent(PlatformKeyboardEvent(adjustedKeyboardEvent));
1214
1215         if (isKeyChar) {
1216             type = Platform::KeyboardEvent::KeyUp;
1217             adjustedKeyboardEvent = Platform::KeyboardEvent(keyboardEvent.character(), type, adjustedModifiers);
1218             keyboardEventHandled = focusedFrame->eventHandler()->keyEvent(PlatformKeyboardEvent(adjustedKeyboardEvent)) || keyboardEventHandled;
1219         }
1220
1221         if (!changeIsPartOfComposition && type == Platform::KeyboardEvent::KeyUp)
1222             ensureFocusTextElementVisible(EdgeIfNeeded);
1223     }
1224     return keyboardEventHandled;
1225 }
1226
1227 bool InputHandler::deleteSelection()
1228 {
1229     if (!isActiveTextEdit())
1230         return false;
1231
1232     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1233     Frame* frame = m_currentFocusElement->document()->frame();
1234
1235     if (frame->selection()->selectionType() != VisibleSelection::RangeSelection)
1236         return false;
1237
1238     ASSERT(frame->editor());
1239     return frame->editor()->command("DeleteBackward").execute();
1240 }
1241
1242 void InputHandler::insertText(const WTF::String& string)
1243 {
1244     if (!isActiveTextEdit())
1245         return;
1246
1247     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->editor());
1248     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1249
1250     editor->command("InsertText").execute(string);
1251 }
1252
1253 void InputHandler::clearField()
1254 {
1255     if (!isActiveTextEdit())
1256         return;
1257
1258     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame() && m_currentFocusElement->document()->frame()->editor());
1259     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1260
1261     editor->command("SelectAll").execute();
1262     editor->command("DeleteBackward").execute();
1263 }
1264
1265 bool InputHandler::executeTextEditCommand(const WTF::String& commandName)
1266 {
1267     ASSERT(m_webPage->focusedOrMainFrame() && m_webPage->focusedOrMainFrame()->editor());
1268     Editor* editor = m_webPage->focusedOrMainFrame()->editor();
1269
1270     return editor->command(commandName).execute();
1271 }
1272
1273 void InputHandler::cut()
1274 {
1275     executeTextEditCommand("Cut");
1276 }
1277
1278 void InputHandler::copy()
1279 {
1280     executeTextEditCommand("Copy");
1281 }
1282
1283 void InputHandler::paste()
1284 {
1285     executeTextEditCommand("Paste");
1286 }
1287
1288 void InputHandler::selectAll()
1289 {
1290     executeTextEditCommand("SelectAll");
1291 }
1292
1293 void InputHandler::addAttributedTextMarker(int start, int end, const AttributeTextStyle& style)
1294 {
1295     if ((end - start) < 1 || end > static_cast<int>(elementText().length()))
1296         return;
1297
1298     RefPtr<Range> markerRange = DOMSupport::visibleSelectionForRangeInputElement(m_currentFocusElement.get(), start, end).toNormalizedRange();
1299     m_currentFocusElement->document()->markers()->addMarker(markerRange.get(), DocumentMarker::AttributeText, WTF::String("Input Marker"), style);
1300 }
1301
1302 void InputHandler::removeAttributedTextMarker()
1303 {
1304     // Remove all attribute text markers.
1305     if (m_currentFocusElement && m_currentFocusElement->document())
1306         m_currentFocusElement->document()->markers()->removeMarkers(DocumentMarker::AttributeText);
1307
1308     m_composingTextStart = 0;
1309     m_composingTextEnd = 0;
1310 }
1311
1312 void InputHandler::handleInputLocaleChanged(bool isRTL)
1313 {
1314     if (!isActiveTextEdit())
1315         return;
1316
1317     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1318     RenderObject* renderer = m_currentFocusElement->renderer();
1319     if (!renderer)
1320         return;
1321
1322     Editor* editor = m_currentFocusElement->document()->frame()->editor();
1323     ASSERT(editor);
1324     if ((renderer->style()->direction() == RTL) != isRTL)
1325         editor->setBaseWritingDirection(isRTL ? RightToLeftWritingDirection : LeftToRightWritingDirection);
1326 }
1327
1328 void InputHandler::clearCurrentFocusElement()
1329 {
1330     if (m_currentFocusElement)
1331         m_currentFocusElement->blur();
1332 }
1333
1334 bool InputHandler::willOpenPopupForNode(Node* node)
1335 {
1336     // This method must be kept synchronized with InputHandler::didNodeOpenPopup.
1337     if (!node)
1338         return false;
1339
1340     ASSERT(!node->isInShadowTree());
1341
1342     if (node->hasTagName(HTMLNames::selectTag) || node->hasTagName(HTMLNames::optionTag)) {
1343         // We open list popups for options and selects.
1344         return true;
1345     }
1346
1347     if (node->isElementNode()) {
1348         Element* element = static_cast<Element*>(node);
1349         if (DOMSupport::isPopupInputField(element))
1350             return true;
1351     }
1352
1353     return false;
1354 }
1355
1356 bool InputHandler::didNodeOpenPopup(Node* node)
1357 {
1358     // This method must be kept synchronized with InputHandler::willOpenPopupForNode.
1359     if (!node)
1360         return false;
1361
1362     ASSERT(!node->isInShadowTree());
1363
1364     if (node->hasTagName(HTMLNames::selectTag))
1365         return openSelectPopup(static_cast<HTMLSelectElement*>(node));
1366
1367     if (node->hasTagName(HTMLNames::optionTag)) {
1368         HTMLOptionElement* optionElement = static_cast<HTMLOptionElement*>(node);
1369         return openSelectPopup(optionElement->ownerSelectElement());
1370     }
1371
1372     if (HTMLInputElement* element = node->toInputElement()) {
1373         if (DOMSupport::isDateTimeInputField(element))
1374             return openDatePopup(element, elementType(element));
1375
1376         if (DOMSupport::isColorInputField(element))
1377             return openColorPopup(element);
1378     }
1379     return false;
1380 }
1381
1382 bool InputHandler::openSelectPopup(HTMLSelectElement* select)
1383 {
1384     if (!select || select->disabled())
1385         return false;
1386
1387     // If there's no view, do nothing and return.
1388     if (!select->document()->view())
1389         return false;
1390
1391     if (isActiveTextEdit())
1392         clearCurrentFocusElement();
1393
1394     m_currentFocusElement = select;
1395     m_currentFocusElementType = SelectPopup;
1396
1397     const WTF::Vector<HTMLElement*>& listItems = select->listItems();
1398     int size = listItems.size();
1399
1400     bool multiple = select->multiple();
1401     ScopeArray<WebString> labels;
1402     labels.reset(new WebString[size]);
1403
1404     // Check if popup already exists, close it if does.
1405     m_webPage->m_page->chrome()->client()->closePagePopup(0);
1406
1407     bool* enableds = 0;
1408     int* itemTypes = 0;
1409     bool* selecteds = 0;
1410
1411     if (size) {
1412         enableds = new bool[size];
1413         itemTypes = new int[size];
1414         selecteds = new bool[size];
1415         for (int i = 0; i < size; i++) {
1416             if (listItems[i]->hasTagName(HTMLNames::optionTag)) {
1417                 HTMLOptionElement* option = static_cast<HTMLOptionElement*>(listItems[i]);
1418                 labels[i] = option->textIndentedToRespectGroupLabel();
1419                 enableds[i] = option->disabled() ? 0 : 1;
1420                 selecteds[i] = option->selected();
1421                 itemTypes[i] = option->parentNode() && option->parentNode()->hasTagName(HTMLNames::optgroupTag) ? TypeOptionInGroup : TypeOption;
1422             } else if (listItems[i]->hasTagName(HTMLNames::optgroupTag)) {
1423                 HTMLOptGroupElement* optGroup = static_cast<HTMLOptGroupElement*>(listItems[i]);
1424                 labels[i] = optGroup->groupLabelText();
1425                 enableds[i] = optGroup->disabled() ? 0 : 1;
1426                 selecteds[i] = false;
1427                 itemTypes[i] = TypeGroup;
1428             } else if (listItems[i]->hasTagName(HTMLNames::hrTag)) {
1429                 enableds[i] = false;
1430                 selecteds[i] = false;
1431                 itemTypes[i] = TypeSeparator;
1432             }
1433         }
1434     }
1435
1436     SelectPopupClient* selectClient = new SelectPopupClient(multiple, size, labels, enableds, itemTypes, selecteds, m_webPage, select);
1437     WebCore::IntRect elementRectInRootView = select->document()->view()->contentsToRootView(enclosingIntRect(select->getRect()));
1438     // Fail to create HTML popup, use the old path
1439     if (!m_webPage->m_page->chrome()->client()->openPagePopup(selectClient, elementRectInRootView))
1440         m_webPage->m_client->openPopupList(multiple, size, labels, enableds, itemTypes, selecteds);
1441     return true;
1442 }
1443
1444 void InputHandler::setPopupListIndex(int index)
1445 {
1446     if (index == -2) // Abandon
1447         return clearCurrentFocusElement();
1448
1449     if (!isActiveSelectPopup())
1450         return clearCurrentFocusElement();
1451
1452     RenderObject* renderer = m_currentFocusElement->renderer();
1453     if (renderer && renderer->isMenuList()) {
1454         RenderMenuList* renderMenu = toRenderMenuList(renderer);
1455         renderMenu->hidePopup();
1456     }
1457
1458     HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>(m_currentFocusElement.get());
1459     int optionIndex = selectElement->listToOptionIndex(index);
1460     selectElement->optionSelectedByUser(optionIndex, true /* deselect = true */, true /* fireOnChangeNow = false */);
1461     clearCurrentFocusElement();
1462 }
1463
1464 void InputHandler::setPopupListIndexes(int size, const bool* selecteds)
1465 {
1466     if (!isActiveSelectPopup())
1467         return clearCurrentFocusElement();
1468
1469     if (size < 0)
1470         return;
1471
1472     HTMLSelectElement* selectElement = static_cast<HTMLSelectElement*>(m_currentFocusElement.get());
1473     const WTF::Vector<HTMLElement*>& items = selectElement->listItems();
1474     if (items.size() != static_cast<unsigned int>(size))
1475         return;
1476
1477     HTMLOptionElement* option;
1478     for (int i = 0; i < size; i++) {
1479         if (items[i]->hasTagName(HTMLNames::optionTag)) {
1480             option = static_cast<HTMLOptionElement*>(items[i]);
1481             option->setSelectedState(selecteds[i]);
1482         }
1483     }
1484
1485     // Force repaint because we do not send mouse events to the select element
1486     // and the element doesn't automatically repaint itself.
1487     selectElement->dispatchFormControlChangeEvent();
1488     selectElement->renderer()->repaint();
1489     clearCurrentFocusElement();
1490 }
1491
1492 bool InputHandler::setBatchEditingActive(bool active)
1493 {
1494     if (!isActiveTextEdit())
1495         return false;
1496
1497     ASSERT(m_currentFocusElement->document());
1498     ASSERT(m_currentFocusElement->document()->frame());
1499
1500     // FIXME switch this to m_currentFocusElement->document()->frame() when we have separate
1501     // backingstore for each frame.
1502     BackingStoreClient* backingStoreClientForFrame = m_webPage->backingStoreClientForFrame(m_webPage->mainFrame());
1503     ASSERT(backingStoreClientForFrame);
1504
1505     // Enable / Disable the backingstore to prevent visual updates.
1506     if (!active)
1507         backingStoreClientForFrame->backingStore()->resumeScreenAndBackingStoreUpdates(BackingStore::RenderAndBlit);
1508     else
1509         backingStoreClientForFrame->backingStore()->suspendScreenAndBackingStoreUpdates();
1510
1511     return true;
1512 }
1513
1514 int InputHandler::caretPosition() const
1515 {
1516     if (!isActiveTextEdit())
1517         return -1;
1518
1519     // NOTE: This function is expected to return the start of the selection if
1520     // a selection is applied.
1521     return selectionStart();
1522 }
1523
1524 int relativeLeftOffset(int caretPosition, int leftOffset)
1525 {
1526     ASSERT(caretPosition >= 0);
1527
1528     return std::max(0, caretPosition - leftOffset);
1529 }
1530
1531 int relativeRightOffset(int caretPosition, unsigned totalLengthOfText, int rightOffset)
1532 {
1533     ASSERT(caretPosition >= 0);
1534     ASSERT(totalLengthOfText < INT_MAX);
1535
1536     return std::min(caretPosition + rightOffset, static_cast<int>(totalLengthOfText));
1537 }
1538
1539 bool InputHandler::deleteTextRelativeToCursor(int leftOffset, int rightOffset)
1540 {
1541     if (!isActiveTextEdit() || compositionActive())
1542         return false;
1543
1544     ProcessingChangeGuard guard(this);
1545
1546     InputLog(LogLevelInfo, "InputHandler::deleteTextRelativeToCursor left %d right %d", leftOffset, rightOffset);
1547
1548     int caretOffset = caretPosition();
1549     int start = relativeLeftOffset(caretOffset, leftOffset);
1550     int end = relativeRightOffset(caretOffset, elementText().length(), rightOffset);
1551     if (!deleteText(start, end))
1552         return false;
1553
1554     // Scroll the field if necessary. The automatic update is suppressed
1555     // by the processing change guard.
1556     ensureFocusTextElementVisible(EdgeIfNeeded);
1557
1558     return true;
1559 }
1560
1561 bool InputHandler::deleteText(int start, int end)
1562 {
1563     if (!isActiveTextEdit())
1564         return false;
1565
1566     ProcessingChangeGuard guard(this);
1567
1568     if (!setSelection(start, end, true /*changeIsPartOfComposition*/))
1569         return false;
1570
1571     InputLog(LogLevelInfo, "InputHandler::deleteText start %d end %d", start, end);
1572
1573     return deleteSelection();
1574 }
1575
1576 spannable_string_t* InputHandler::spannableTextInRange(int start, int end, int32_t flags)
1577 {
1578     if (!isActiveTextEdit())
1579         return 0;
1580
1581     if (start == end)
1582         return 0;
1583
1584     ASSERT(end > start);
1585     int length = end - start;
1586
1587     WTF::String textString = elementText().substring(start, length);
1588
1589     spannable_string_t* pst = (spannable_string_t*)fastMalloc(sizeof(spannable_string_t));
1590
1591     // Don't use fastMalloc in case the string is unreasonably long. fastMalloc will
1592     // crash immediately on failure.
1593     pst->str = (wchar_t*)malloc(sizeof(wchar_t) * (length + 1));
1594     if (!pst->str) {
1595         logAlways(LogLevelCritical, "InputHandler::spannableTextInRange Cannot allocate memory for string.\n");
1596         free(pst);
1597         return 0;
1598     }
1599
1600     int stringLength = 0;
1601     if (!convertStringToWchar(textString, pst->str, length + 1, &stringLength)) {
1602         logAlways(LogLevelCritical, "InputHandler::spannableTextInRange failed to convert string.\n");
1603         free(pst->str);
1604         free(pst);
1605         return 0;
1606     }
1607
1608     pst->length = stringLength;
1609     pst->spans_count = 0;
1610     pst->spans = 0;
1611
1612     return pst;
1613 }
1614
1615 spannable_string_t* InputHandler::selectedText(int32_t flags)
1616 {
1617     if (!isActiveTextEdit())
1618         return 0;
1619
1620     return spannableTextInRange(selectionStart(), selectionEnd(), flags);
1621 }
1622
1623 spannable_string_t* InputHandler::textBeforeCursor(int32_t length, int32_t flags)
1624 {
1625     if (!isActiveTextEdit())
1626         return 0;
1627
1628     int caretOffset = caretPosition();
1629     int start = relativeLeftOffset(caretOffset, length);
1630     int end = caretOffset;
1631
1632     return spannableTextInRange(start, end, flags);
1633 }
1634
1635 spannable_string_t* InputHandler::textAfterCursor(int32_t length, int32_t flags)
1636 {
1637     if (!isActiveTextEdit())
1638         return 0;
1639
1640     int caretOffset = caretPosition();
1641     int start = caretOffset;
1642     int end = relativeRightOffset(caretOffset, elementText().length(), length);
1643
1644     return spannableTextInRange(start, end, flags);
1645 }
1646
1647 extracted_text_t* InputHandler::extractedTextRequest(extracted_text_request_t* request, int32_t flags)
1648 {
1649     if (!isActiveTextEdit())
1650         return 0;
1651
1652     extracted_text_t* extractedText = (extracted_text_t *)fastMalloc(sizeof(extracted_text_t));
1653
1654     // 'flags' indicates whether the text is being monitored. This is not currently used.
1655
1656     // FIXME add smart limiting based on the hint sizes. Currently return all text.
1657
1658     extractedText->text = spannableTextInRange(0, elementText().length(), flags);
1659
1660     // FIXME confirm these should be 0 on this requested. Text changes will likely require
1661     // the end be the length.
1662     extractedText->partial_start_offset = 0;
1663     extractedText->partial_end_offset = 0;
1664     extractedText->start_offset = 0;
1665
1666     // Adjust selection values relative to the start offset, which may be a subset
1667     // of the text in the field.
1668     extractedText->selection_start = selectionStart() - extractedText->start_offset;
1669     extractedText->selection_end = selectionEnd() - extractedText->start_offset;
1670
1671     // selectionActive is not limited to inside the extracted text.
1672     bool selectionActive = extractedText->selection_start != extractedText->selection_end;
1673     bool singleLine = m_currentFocusElement->hasTagName(HTMLNames::inputTag);
1674
1675     // FIXME flags has two values in doc, enum not in header yet.
1676     extractedText->flags = selectionActive & singleLine;
1677
1678     return extractedText;
1679 }
1680
1681 static void addCompositionTextStyleToAttributeTextStyle(AttributeTextStyle& style)
1682 {
1683     style.setUnderline(AttributeTextStyle::StandardUnderline);
1684 }
1685
1686 static void addActiveTextStyleToAttributeTextStyle(AttributeTextStyle& style)
1687 {
1688     style.setBackgroundColor(Color("blue"));
1689     style.setTextColor(Color("white"));
1690 }
1691
1692 static AttributeTextStyle compositionTextStyle()
1693 {
1694     AttributeTextStyle style;
1695     addCompositionTextStyleToAttributeTextStyle(style);
1696     return style;
1697 }
1698
1699 static AttributeTextStyle textStyleFromMask(int64_t mask)
1700 {
1701     AttributeTextStyle style;
1702     if (mask & COMPOSED_TEXT_ATTRIB)
1703         addCompositionTextStyleToAttributeTextStyle(style);
1704
1705     if (mask & ACTIVE_REGION_ATTRIB)
1706         addActiveTextStyleToAttributeTextStyle(style);
1707
1708     return style;
1709 }
1710
1711 bool InputHandler::removeComposedText()
1712 {
1713     if (compositionActive()) {
1714         if (!deleteText(m_composingTextStart, m_composingTextEnd)) {
1715             // Could not remove the existing composition region.
1716             return false;
1717         }
1718         removeAttributedTextMarker();
1719     }
1720
1721     return true;
1722 }
1723
1724 int32_t InputHandler::setComposingRegion(int32_t start, int32_t end)
1725 {
1726     if (!isActiveTextEdit())
1727         return -1;
1728
1729     if (!removeComposedText()) {
1730         // Could not remove the existing composition region.
1731         return -1;
1732     }
1733
1734     m_composingTextStart = start;
1735     m_composingTextEnd = end;
1736
1737     if (compositionActive())
1738         addAttributedTextMarker(start, end, compositionTextStyle());
1739
1740     InputLog(LogLevelInfo, "InputHandler::setComposingRegion start %d end %d", start, end);
1741
1742     return 0;
1743 }
1744
1745 int32_t InputHandler::finishComposition()
1746 {
1747     if (!isActiveTextEdit())
1748         return -1;
1749
1750     // FIXME if no composition is active, should we return failure -1?
1751     if (!compositionActive())
1752         return 0;
1753
1754     // Remove all markers.
1755     removeAttributedTextMarker();
1756
1757     InputLog(LogLevelInfo, "InputHandler::finishComposition completed");
1758
1759     return 0;
1760 }
1761
1762 span_t* InputHandler::firstSpanInString(spannable_string_t* spannableString, SpannableStringAttribute attrib)
1763 {
1764     span_t* span = spannableString->spans;
1765     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
1766         if (span->attributes_mask & attrib)
1767             return span;
1768         span++;
1769     }
1770
1771     return 0;
1772 }
1773
1774 bool InputHandler::isTrailingSingleCharacter(span_t* span, unsigned stringLength, unsigned composingTextLength)
1775 {
1776     // Make sure the new string is one character larger than the old.
1777     if (composingTextLength != stringLength - 1)
1778         return false;
1779
1780     if (!span)
1781         return false;
1782
1783     // Has only 1 character changed?
1784     if (span->start == span->end) {
1785         // Is this character the last character in the string?
1786         if (span->start == stringLength - 1)
1787             return true;
1788     }
1789     // Return after the first changed_attrib is found.
1790     return false;
1791 }
1792
1793 bool InputHandler::setText(spannable_string_t* spannableString)
1794 {
1795     if (!isActiveTextEdit() || !spannableString)
1796         return false;
1797
1798     ASSERT(m_currentFocusElement->document() && m_currentFocusElement->document()->frame());
1799     Frame* frame = m_currentFocusElement->document()->frame();
1800
1801     Editor* editor = frame->editor();
1802     ASSERT(editor);
1803
1804     // Disable selectionHandler's active selection as we will be resetting and these
1805     // changes should not be handled as notification event.
1806     m_webPage->m_selectionHandler->setSelectionActive(false);
1807
1808     String textToInsert = convertSpannableStringToString(spannableString);
1809     int textLength = textToInsert.length();
1810
1811     InputLog(LogLevelInfo, "InputHandler::setText spannableString is '%s', of length %d \n", textToInsert.latin1().data(), textLength);
1812
1813     span_t* changedSpan = firstSpanInString(spannableString, CHANGED_ATTRIB);
1814     int composingTextStart = m_composingTextStart;
1815     int composingTextEnd = m_composingTextEnd;
1816     int composingTextLength = compositionLength();
1817     removeAttributedTextMarker();
1818
1819     if (isTrailingSingleCharacter(changedSpan, textLength, composingTextLength)) {
1820         // Handle the case where text is being composed.
1821         if (firstSpanInString(spannableString, COMPOSED_TEXT_ATTRIB)) {
1822             InputLog(LogLevelInfo, "InputHandler::setText Single trailing character detected.  Text is being composed. \n");
1823             return editor->command("InsertText").execute(textToInsert.right(1));
1824         }
1825         InputLog(LogLevelInfo, "InputHandler::setText Single trailing character detected. Text is not being composed. \n");
1826         return handleKeyboardInput(Platform::KeyboardEvent(textToInsert[textLength - 1], Platform::KeyboardEvent::KeyChar, 0), false /* changeIsPartOfComposition */);
1827     }
1828
1829     // If no spans have changed, treat it as a delete operation.
1830     if (!changedSpan) {
1831         // If the composition length is the same as our string length, then we don't need to do anything.
1832         if (composingTextLength == textLength) {
1833             InputLog(LogLevelInfo, "InputHandler::setText No spans have changed. New text is the same length as the old. Nothing to do. \n");
1834             return true;
1835         }
1836
1837         if (composingTextLength - textLength == 1) {
1838             InputLog(LogLevelInfo, "InputHandler::setText No spans have changed. New text is one character shorter than the old. Treating as 'delete'. \n");
1839             return editor->command("DeleteBackward").execute();
1840         }
1841     }
1842
1843     if (composingTextLength && !setSelection(composingTextStart, composingTextEnd, true /* changeIsPartOfComposition */))
1844         return false;
1845
1846     // If there is no text to add just delete.
1847     if (!textLength) {
1848         if (selectionActive())
1849             return editor->command("DeleteBackward").execute();
1850
1851         // Nothing to do.
1852         return true;
1853     }
1854
1855     // Triggering an insert of the text with a space character trailing
1856     // causes new text to adopt the previous text style.
1857     // Remove it and apply it as a keypress later.
1858     // Upstream Webkit bug created https://bugs.webkit.org/show_bug.cgi?id=70823
1859     bool requiresSpaceKeyPress = false;
1860     if (textLength > 0 && textToInsert[textLength - 1] == 32 /* space */) {
1861         requiresSpaceKeyPress = true;
1862         textLength--;
1863         textToInsert.remove(textLength, 1);
1864     }
1865
1866     InputLog(LogLevelInfo, "InputHandler::setText Request being processed. Text before processing: '%s'", elementText().latin1().data());
1867
1868     if (textLength == 1 && !spannableString->spans_count) {
1869         // Handle single key non-attributed entry as key press rather than insert to allow
1870         // triggering of javascript events.
1871         InputLog(LogLevelInfo, "InputHandler::setText Single character entry treated as key-press in the absense of spans. \n");
1872         return handleKeyboardInput(Platform::KeyboardEvent(textToInsert[0], Platform::KeyboardEvent::KeyChar, 0), true /* changeIsPartOfComposition */);
1873     }
1874
1875     // Perform the text change as a single command if there is one.
1876     if (!textToInsert.isEmpty() && !editor->command("InsertText").execute(textToInsert)) {
1877         InputLog(LogLevelWarn, "InputHandler::setText Failed to insert text '%s'", textToInsert.latin1().data());
1878         return false;
1879     }
1880
1881     if (requiresSpaceKeyPress)
1882         handleKeyboardInput(Platform::KeyboardEvent(32 /* space */, Platform::KeyboardEvent::KeyChar, 0), true /* changeIsPartOfComposition */);
1883
1884     InputLog(LogLevelInfo, "InputHandler::setText Request being processed. Text after processing '%s'", elementText().latin1().data());
1885
1886     return true;
1887 }
1888
1889 bool InputHandler::setTextAttributes(int insertionPoint, spannable_string_t* spannableString)
1890 {
1891     // Apply the attributes to the field.
1892     span_t* span = spannableString->spans;
1893     for (unsigned int i = 0; i < spannableString->spans_count; i++) {
1894         unsigned int startPosition = insertionPoint + span->start;
1895         // The end point includes the character that it is before. Ie, 0, 0
1896         // applies to the first character as the end point includes the character
1897         // at the position. This means the endPosition is always +1.
1898         unsigned int endPosition = insertionPoint + span->end + 1;
1899         if (endPosition < startPosition || endPosition > elementText().length())
1900             return false;
1901
1902         if (!span->attributes_mask)
1903             continue; // Nothing to do.
1904
1905         // MISSPELLED_WORD_ATTRIB is present as an option, but it is not currently
1906         // used by IMF. When they add support for on the fly spell checking we can
1907         // use it to apply spelling markers and disable continuous spell checking.
1908
1909         InputLog(LogLevelInfo, "InputHandler::setTextAttributes adding marker %d to %d - %llu", startPosition, endPosition, span->attributes_mask);
1910         addAttributedTextMarker(startPosition, endPosition, textStyleFromMask(span->attributes_mask));
1911
1912         span++;
1913     }
1914
1915     InputLog(LogLevelInfo, "InputHandler::setTextAttributes attribute count %d", spannableString->spans_count);
1916
1917     return true;
1918 }
1919
1920 bool InputHandler::setRelativeCursorPosition(int insertionPoint, int relativeCursorPosition)
1921 {
1922     if (!isActiveTextEdit())
1923         return false;
1924
1925     // 1 place cursor at end of insertion text.
1926     if (relativeCursorPosition == 1) {
1927         m_currentFocusElement->document()->frame()->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
1928         return true;
1929     }
1930
1931     int cursorPosition = 0;
1932     if (relativeCursorPosition <= 0) {
1933         // Zero = insertionPoint
1934         // Negative value, move the cursor the requested number of characters before
1935         // the start of the inserted text.
1936         cursorPosition = insertionPoint + relativeCursorPosition;
1937     } else {
1938         // Positive value, move the cursor the requested number of characters after
1939         // the end of the inserted text minus 1.
1940         cursorPosition = caretPosition() + relativeCursorPosition - 1;
1941     }
1942
1943     if (cursorPosition < 0 || cursorPosition > (int)elementText().length())
1944         return false;
1945
1946     InputLog(LogLevelInfo, "InputHandler::setRelativeCursorPosition cursor position %d", cursorPosition);
1947
1948     return setCursorPosition(cursorPosition);
1949 }
1950
1951 bool InputHandler::setSpannableTextAndRelativeCursor(spannable_string_t* spannableString, int relativeCursorPosition, bool markTextAsComposing)
1952 {
1953     InputLog(LogLevelInfo, "InputHandler::setSpannableTextAndRelativeCursor(%d, %d, %d)\n", spannableString->length, relativeCursorPosition, markTextAsComposing);
1954     int insertionPoint = compositionActive() ? m_composingTextStart : selectionStart();
1955
1956     ProcessingChangeGuard guard(this);
1957
1958     if (!setText(spannableString))
1959         return false;
1960
1961     if (!setTextAttributes(insertionPoint, spannableString))
1962         return false;
1963
1964     if (!setRelativeCursorPosition(insertionPoint, relativeCursorPosition))
1965         return false;
1966
1967     if (markTextAsComposing) {
1968         m_composingTextStart = insertionPoint;
1969         m_composingTextEnd = insertionPoint + spannableString->length;
1970     }
1971
1972     // Scroll the field if necessary. The automatic update is suppressed
1973     // by the processing change guard.
1974     ensureFocusTextElementVisible(EdgeIfNeeded);
1975
1976     return true;
1977 }
1978
1979 int32_t InputHandler::setComposingText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
1980 {
1981     if (!isActiveTextEdit())
1982         return -1;
1983
1984     if (!spannableString)
1985         return -1;
1986
1987     InputLog(LogLevelInfo, "InputHandler::setComposingText at relativeCursorPosition: %d", relativeCursorPosition);
1988
1989     // Enable input mode if we are processing a key event.
1990     setInputModeEnabled();
1991
1992     return setSpannableTextAndRelativeCursor(spannableString, relativeCursorPosition, true /* markTextAsComposing */) ? 0 : -1;
1993 }
1994
1995 int32_t InputHandler::commitText(spannable_string_t* spannableString, int32_t relativeCursorPosition)
1996 {
1997     if (!isActiveTextEdit())
1998         return -1;
1999
2000     if (!spannableString)
2001         return -1;
2002
2003     InputLog(LogLevelInfo, "InputHandler::commitText");
2004
2005     return setSpannableTextAndRelativeCursor(spannableString, relativeCursorPosition, false /* markTextAsComposing */) ? 0 : -1;
2006 }
2007
2008 }
2009 }