ContextMenu is overlapping with IME.
[framework/web/webkit-efl.git] / Source / WebKit2 / UIProcess / efl / InputMethodContextEfl.cpp
1 /*
2    Copyright (C) 2011 Samsung Electronics
3    Copyright (C) 2012 Intel Corporation. All rights reserved.
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public License
16     along with this library; see the file COPYING.LIB.  If not, write to
17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19 */
20
21 #include "config.h"
22 #include "InputMethodContextEfl.h"
23
24 #include "EwkViewImpl.h"
25 #include "WebPageProxy.h"
26 #include <Ecore_Evas.h>
27 #include <Ecore_IMF_Evas.h>
28
29 using namespace WebCore;
30
31 namespace WebKit {
32
33 #if ENABLE(TIZEN_ISF_PORT)
34 const unsigned InputMethodContextEfl::maxContextSize = 10;
35 Ecore_X_Atom InputMethodContextEfl::s_externalKeyboardProperty = 0;
36 bool InputMethodContextEfl::s_shouldUseExternalKeyboard = false;
37 bool InputMethodContextEfl::s_isSystemKeypadShow = false;
38
39 void InputMethodContextEfl::initializeExternalKeyboard()
40 {
41     s_externalKeyboardProperty = ecore_x_atom_get("X External Keyboard Exist");
42     if (!s_externalKeyboardProperty)
43         return;
44
45     Ecore_X_Window rootWin = ecore_x_window_root_first_get();
46     ecore_x_event_mask_set(rootWin, ECORE_X_EVENT_MASK_WINDOW_PROPERTY);
47
48     ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, windowPropertyChanged, 0);
49
50     unsigned int value;
51     if (ecore_x_window_prop_card32_get(rootWin, s_externalKeyboardProperty, &value, 1) <= 0)
52         return;
53
54     s_shouldUseExternalKeyboard = value;
55 }
56
57 Eina_Bool InputMethodContextEfl::windowPropertyChanged(void*, int, void* event)
58 {
59     Ecore_X_Event_Window_Property* propertyEvent = static_cast<Ecore_X_Event_Window_Property*>(event);
60
61     if (propertyEvent->atom != s_externalKeyboardProperty)
62         return ECORE_CALLBACK_PASS_ON;
63
64     unsigned int value;
65     if (ecore_x_window_prop_card32_get(propertyEvent->win, s_externalKeyboardProperty, &value, 1) <= 0 || s_shouldUseExternalKeyboard == value)
66         return ECORE_CALLBACK_PASS_ON;
67
68     s_shouldUseExternalKeyboard = value;
69
70 #if ENABLE(TIZEN_FOCUS_UI)
71     if (!s_shouldUseExternalKeyboard) {
72         Vector<RefPtr<WebPageProxy> > pages;
73         EwkViewImpl::pages(pages);
74
75         for (size_t i = 0; i < pages.size(); ++i)
76             pages[i]->setSpatialNavigationEnabled(false);
77     }
78 #endif
79
80     return ECORE_CALLBACK_PASS_ON;
81 }
82 #endif
83
84 InputMethodContextEfl::InputMethodContextEfl(EwkViewImpl* viewImpl, PassOwnPtr<Ecore_IMF_Context> context)
85     : m_viewImpl(viewImpl)
86     , m_context(context)
87     , m_focused(false)
88 #if ENABLE(TIZEN_ISF_PORT)
89     , m_contextID(0)
90     , m_state(ECORE_IMF_INPUT_PANEL_STATE_HIDE)
91     , m_inputPickerType(-1)
92     , m_doNotHandleFakeKeyEvent(false)
93     , m_fakeKeyEventTimer(this, &InputMethodContextEfl::fakeKeyEventTimerFired)
94 #endif
95 {
96 #if ENABLE(TIZEN_ISF_PORT)
97     if (!s_externalKeyboardProperty)
98         initializeExternalKeyboard();
99
100     m_IMEStatusChangeHandler = ecore_event_handler_add(ECORE_X_EVENT_WINDOW_PROPERTY, IMEStatusChangeCallback, this);
101 #else
102     ASSERT(context);
103     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
104     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
105 #endif
106 }
107
108 InputMethodContextEfl::~InputMethodContextEfl()
109 {
110     ecore_event_handler_del(m_IMEStatusChangeHandler);
111     m_IMEStatusChangeHandler = 0;
112 }
113
114 #if ENABLE(TIZEN_ISF_PORT)
115 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
116 {
117     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
118
119     inputMethodContext->setState(state);
120
121     if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
122 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
123         if (inputMethodContext->m_viewImpl->pageClient->isClipboardWindowOpened())
124             inputMethodContext->m_viewImpl->pageClient->closeClipboardWindow();
125 #endif
126
127         if (inputMethodContext->m_viewImpl->page()->editorState().hasComposition)
128             inputMethodContext->resetIMFContext();
129
130         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
131     } else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
132         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
133 }
134
135 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
136 {
137     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
138     if (!inputMethodContext->m_context)
139         return;
140
141     Eina_Rectangle rect;
142     ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
143     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
144
145     inputMethodContext->setIMERect(IntRect(rect.x, rect.y, rect.w, rect.h));
146 }
147
148 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
149 {
150     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
151
152     if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
153         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
154     else
155         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
156 }
157
158 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
159 {
160     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
161     if (!inputMethodContext->m_context)
162         return;
163
164     Eina_Rectangle rect;
165     ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
166     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
167 }
168
169 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
170 {
171     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
172     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
173         return false;
174
175     const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
176
177     if (text) {
178         CString utf8Text(editor.surroundingText.utf8());
179         size_t length = utf8Text.length();
180
181         *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
182         if (!(*text))
183             return false;
184
185         if (length)
186             strncpy(*text, utf8Text.data(), length);
187         (*text)[length] = 0;
188     }
189
190     if (offset)
191         *offset = editor.cursorPosition;
192
193     return true;
194 }
195
196 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
197 {
198     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
199     if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
200         return;
201
202     inputMethodContext->requestFakeKeyEvent();
203
204     Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
205     inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
206 }
207
208 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
209 {
210     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
211     if (!eventInfo || !inputMethodContext->m_focused)
212         return;
213
214     inputMethodContext->requestFakeKeyEvent();
215
216     inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
217 }
218
219 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
220 unsigned getUTF8CharacterIndex(const char* string, unsigned byteIndex)
221 {
222     unsigned index = 0;
223     const char* end = string + byteIndex;
224
225     while (*string && string < end) {
226         unsigned offset;
227
228         if ((*string & 0x80) == 0x00)
229             offset = 1;
230         else if ((*string & 0xe0) == 0xc0)
231             offset = 2;
232         else if ((*string & 0xf0) == 0xe0)
233             offset = 3;
234         else if ((*string & 0xf8) == 0xf0)
235             offset = 4;
236         else if ((*string & 0xfc) == 0xf8)
237             offset = 5;
238         else if ((*string & 0xfe) == 0xfc)
239             offset = 6;
240         else
241             offset = 1;
242
243         ++index;
244         while (*string && offset--)
245             ++string;
246     }
247
248     return index;
249 }
250 #endif
251
252 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
253 {
254     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
255
256     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
257         return;
258
259     WebPageProxy* page = inputMethodContext->m_viewImpl->page();
260     if (!page->focusedFrame())
261         return;
262
263     inputMethodContext->requestFakeKeyEvent();
264
265     const EditorState& editor = inputMethodContext->m_viewImpl->page()->editorState();
266     PageClientImpl* pageClient = inputMethodContext->m_viewImpl->pageClient.get();
267     IntRect caretRect;
268     if (!editor.selectionIsNone && !editor.selectionIsRange) {
269         caretRect = editor.selectionRect;
270         caretRect.scale(pageClient->scaleFactor());
271     }
272
273     int viewX, viewY;
274     evas_object_geometry_get(inputMethodContext->m_viewImpl->view(), &viewX, &viewY, 0, 0);
275
276     int x = caretRect.x() - pageClient->scrollPosition().x() + viewX;
277     int y = caretRect.y() - pageClient->scrollPosition().y() + viewY;
278     int w = caretRect.width();
279     int h = caretRect.height();
280     ecore_imf_context_cursor_location_set(context, x, y, w, h);
281
282     char* buffer = 0;
283     Eina_List* preeditAttrs = 0;
284     int cursorPosition = 0;
285
286     ecore_imf_context_preedit_string_with_attributes_get(context, &buffer, &preeditAttrs, &cursorPosition);
287
288     String preeditString = String::fromUTF8(buffer);
289     Vector<CompositionUnderline> underlines;
290
291     if (preeditAttrs) {
292         void* item = 0;
293 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
294         Eina_List* listIterator = 0;
295         EINA_LIST_FOREACH(preeditAttrs, listIterator, item) {
296             Ecore_IMF_Preedit_Attr* preeditAttr = static_cast<Ecore_IMF_Preedit_Attr*>(item);
297
298             unsigned startIndex = getUTF8CharacterIndex(buffer, preeditAttr->start_index);
299             unsigned endIndex = getUTF8CharacterIndex(buffer, preeditAttr->end_index);
300             switch (preeditAttr->preedit_type) {
301             case ECORE_IMF_PREEDIT_TYPE_SUB1:
302                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), false));
303                 break;
304             case ECORE_IMF_PREEDIT_TYPE_SUB2:
305             case ECORE_IMF_PREEDIT_TYPE_SUB3:
306                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(255, 255, 255), false));
307                 break;
308             case ECORE_IMF_PREEDIT_TYPE_SUB4:
309                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(46, 168, 255), false));
310                 break;
311             case ECORE_IMF_PREEDIT_TYPE_SUB5:
312                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 98, 195), false));
313                 break;
314             case ECORE_IMF_PREEDIT_TYPE_SUB6:
315                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(118, 222, 55), false));
316                 break;
317             case ECORE_IMF_PREEDIT_TYPE_SUB7:
318                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 153, 153), false));
319                 break;
320             default:
321                 break;
322             }
323         }
324 #endif
325         EINA_LIST_FREE(preeditAttrs, item)
326             free(item);
327     }
328
329     if (underlines.isEmpty())
330         underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
331
332     page->setComposition(preeditString, underlines, cursorPosition);
333
334     if (buffer)
335         free(buffer);
336 }
337 #else
338 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
339 {
340     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
341     if (!eventInfo || !inputMethodContext->m_focused)
342         return;
343
344     inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
345 }
346
347 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
348 {
349     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
350
351     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
352         return;
353
354     char* buffer = 0;
355     ecore_imf_context_preedit_string_get(context, &buffer, 0);
356     if (!buffer)
357         return;
358
359     String preeditString = String::fromUTF8(buffer);
360     free(buffer);
361     Vector<CompositionUnderline> underlines;
362     underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
363     inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
364 }
365 #endif
366
367 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
368 {
369     const char* defaultContextID = ecore_imf_context_default_id_get();
370     if (!defaultContextID)
371         return nullptr;
372
373     OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
374     if (!imfContext)
375         return nullptr;
376
377     Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
378     ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
379     ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
380
381     return imfContext.release();
382 }
383
384 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
385 {
386 #if ENABLE(TIZEN_ISF_PORT)
387     if (!m_context)
388         return;
389
390     resetIMFContext();
391 #else
392     ecore_imf_context_reset(m_context.get());
393 #endif
394 }
395
396 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
397 {
398 #if ENABLE(TIZEN_FOCUS_UI)
399     if (s_shouldUseExternalKeyboard && strncmp(downEvent->keyname, "XF86", 4))
400         m_viewImpl->page()->setSpatialNavigationEnabled(true);
401 #endif
402
403 #if ENABLE(TIZEN_ISF_PORT)
404     if (!m_context)
405         return;
406
407     if (m_fakeKeyEventTimer.isActive())
408         m_fakeKeyEventTimer.stop();
409     else
410         m_viewImpl->page()->prepareKeyDownEvent();
411
412     m_doNotHandleFakeKeyEvent = true;
413 #endif
414
415     Ecore_IMF_Event inputMethodEvent;
416     ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
417
418     *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
419
420 #if ENABLE(TIZEN_ISF_PORT)
421     m_doNotHandleFakeKeyEvent = false;
422 #endif
423 }
424
425 #if ENABLE(TIZEN_ISF_PORT)
426 void InputMethodContextEfl::updateTextInputState()
427 {
428     const EditorState& editor = m_viewImpl->page()->editorState();
429     if (editor.shouldIgnoreCompositionSelectionChange || editor.updateEditorRectOnly)
430         return;
431
432     if (editor.isContentEditable)
433         showIMFContext(editor);
434     else
435         hideIMFContext();
436
437     if (m_context)
438         ecore_imf_context_cursor_position_set(m_context.get(), editor.cursorPosition);
439 }
440
441 void InputMethodContextEfl::updateTextInputStateByUserAction(bool setFocus)
442 {
443     const EditorState& editor = m_viewImpl->page()->editorState();
444
445     if (editor.isContentEditable) {
446         if (setFocus)
447             evas_object_focus_set(m_viewImpl->view(), true);
448
449         showIMFContext(editor, true);
450     } else
451         hideIMFContext();
452 }
453 #else
454 void InputMethodContextEfl::updateTextInputState()
455 {
456     if (!m_context)
457         return;
458
459     const EditorState& editor = m_viewImpl->page()->editorState();
460
461     if (editor.isContentEditable) {
462         if (m_focused)
463             return;
464
465         ecore_imf_context_reset(m_context.get());
466         ecore_imf_context_focus_in(m_context.get());
467         m_focused = true;
468     } else {
469         if (!m_focused)
470             return;
471
472         if (editor.hasComposition)
473             m_viewImpl->page()->cancelComposition();
474
475         m_focused = false;
476         ecore_imf_context_reset(m_context.get());
477         ecore_imf_context_focus_out(m_context.get());
478     }
479 }
480 #endif
481
482 #if ENABLE(TIZEN_ISF_PORT)
483 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout, int layoutVariation, Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType)
484 {
485     ecore_imf_context_input_panel_enabled_set(context, false);
486     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
487     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
488     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
489     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
490     ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
491     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
492     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
493     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
494
495     ecore_imf_context_input_panel_layout_set(context, layout);
496     if (layoutVariation >= 0)
497         ecore_imf_context_input_panel_layout_variation_set(context, layoutVariation);
498     ecore_imf_context_input_panel_return_key_type_set(context, returnKeyType);
499 }
500
501 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::takeContext(uintptr_t contextID)
502 {
503     size_t i = m_contextList.size();
504     while (i > 0) {
505         --i;
506         if (m_contextList[i].first == contextID) {
507             PassOwnPtr<Ecore_IMF_Context> context = m_contextList[i].second.release();
508             m_contextList.remove(i);
509             return context;
510         }
511     }
512
513     return PassOwnPtr<Ecore_IMF_Context>();
514 }
515
516 void InputMethodContextEfl::setIMFContext(const EditorState& editor)
517 {
518     const String& type = editor.inputMethodHints;
519     Ecore_IMF_Input_Panel_Layout layout;
520     int layoutVariation = -1;
521     Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
522
523     if (type == "number") {
524         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
525         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL;
526     } else if (type == "signedNumber") {
527         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
528         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED;
529     } else if (type == "decimalNumber") {
530         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
531         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL;
532     } else if (type == "signedDecimalNumber") {
533         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
534         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL;
535     } else if (type == "email")
536         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
537     else if (type == "url")
538         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
539     else if (type == "tel")
540         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
541     else if (type == "password")
542         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
543     else {
544         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
545         if (type == "search")
546             returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
547     }
548
549     OwnPtr<Ecore_IMF_Context> context;
550     if (m_contextID == editor.inputMethodContextID)
551         context = m_context.release();
552     else
553         context = takeContext(editor.inputMethodContextID);
554
555     revertIMFContext();
556
557     if (!context) {
558         context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
559         if (!context)
560             return;
561         initializeIMFContext(context.get(), layout, layoutVariation, returnKeyType);
562     }
563
564     m_context = context.release();
565     m_contextID = editor.inputMethodContextID;
566
567     if (type == "password" || type == "plugin")
568         ecore_imf_context_prediction_allow_set(m_context.get(), false);
569     else
570         ecore_imf_context_prediction_allow_set(m_context.get(), true);
571
572     if (type.isEmpty() || type == "textarea")
573         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
574     else
575         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
576 }
577
578 bool InputMethodContextEfl::isShow()
579 {
580     return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
581 }
582
583 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
584 {
585     return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
586 }
587
588 void InputMethodContextEfl::onFocusIn()
589 {
590     if (m_inputPickerType >= 0) {
591         showInputPicker(m_viewImpl->page()->editorState());
592         return;
593     }
594
595     if (!m_context || !m_focused)
596         return;
597
598     ecore_imf_context_focus_in(m_context.get());
599     ecore_imf_context_input_panel_show(m_context.get());
600
601     setKeyboardMode(true);
602 }
603
604 void InputMethodContextEfl::onFocusOut()
605 {
606 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
607     if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
608         if (m_viewImpl->pageClient->isClipboardWindowOpened())
609             m_viewImpl->pageClient->closeClipboardWindow();
610     }
611 #endif
612
613 #if ENABLE(TIZEN_FOCUS_UI)
614     m_viewImpl->page()->setSpatialNavigationEnabled(false);
615 #endif
616
617     if (!m_context || !m_focused)
618         return;
619
620     ecore_imf_context_input_panel_hide(m_context.get());
621     ecore_imf_context_focus_out(m_context.get());
622
623     setKeyboardMode(false);
624 }
625
626 void InputMethodContextEfl::revertIMFContext()
627 {
628     if (!m_context)
629         return;
630
631     if (m_contextList.size() >= maxContextSize)
632         m_contextList.remove(0);
633
634     PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
635     m_contextList.append(std::make_pair(m_contextID, imfContext));
636     m_contextID = 0;
637 }
638
639 void InputMethodContextEfl::resetIMFContext()
640 {
641     if (!m_context)
642         return;
643
644     m_doNotHandleFakeKeyEvent = true;
645     ecore_imf_context_reset(m_context.get());
646     m_doNotHandleFakeKeyEvent = false;
647 }
648
649 void InputMethodContextEfl::showIMFContext(const EditorState& editor, bool isUserAction)
650 {
651     Ewk_Settings* settings = ewk_view_settings_get(m_viewImpl->view());
652     bool isContextTransition = (m_context ? m_contextID != editor.inputMethodContextID : m_state != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
653
654     if (!isUserAction && !isContextTransition) {
655         if (!ewk_settings_uses_keypad_without_user_action_get(settings) || (m_focused && m_contextID == editor.inputMethodContextID))
656             return;
657     }
658
659     if (m_contextID != editor.inputMethodContextID)
660         hideIMFContext();
661
662     m_focused = true;
663
664 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
665     if (editor.inputMethodHints == "date")
666         m_inputPickerType = EWK_INPUT_TYPE_DATE;
667     else if (editor.inputMethodHints == "datetime")
668         m_inputPickerType = EWK_INPUT_TYPE_DATETIME;
669     else if (editor.inputMethodHints == "datetime-local")
670         m_inputPickerType = EWK_INPUT_TYPE_DATETIMELOCAL;
671     else if (editor.inputMethodHints == "month")
672         m_inputPickerType = EWK_INPUT_TYPE_MONTH;
673     else if (editor.inputMethodHints == "time")
674         m_inputPickerType = EWK_INPUT_TYPE_TIME;
675     else if (editor.inputMethodHints == "week")
676         m_inputPickerType = EWK_INPUT_TYPE_WEEK;
677     else
678         m_inputPickerType = -1;
679
680     if (m_inputPickerType >= 0) {
681         showInputPicker(editor);
682         m_contextID = editor.inputMethodContextID;
683
684         return;
685     }
686
687 #if !ENABLE(TIZEN_DATALIST_ELEMENT)
688     Vector<String> optionList = m_viewImpl->page()->getFocusedInputElementDataList();
689     if (optionList.size() > 0) {
690         if (editor.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
691             return;
692
693         if (editor.inputMethodHints == "tel")
694             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TELEPHONE, optionList);
695         else if (editor.inputMethodHints == "number")
696             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_NUMBER, optionList);
697         else if (editor.inputMethodHints == "email")
698             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_EMAIL, optionList);
699         else if (editor.inputMethodHints == "url")
700             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_URL, optionList);
701         else
702             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TEXT, optionList);
703
704         m_contextID = editor.inputMethodContextID;
705
706         return;
707     }
708 #endif
709 #endif // ENABLE(TIZEN_INPUT_TAG_EXTENSION)
710
711     bool hasFocus = evas_object_focus_get(m_viewImpl->view());
712
713     if (!ewk_settings_default_keypad_enabled_get(settings)) {
714         if (hasFocus) {
715             Eina_Rectangle dummyRectForCustomKeypadCallback;
716             memset(&dummyRectForCustomKeypadCallback, 0, sizeof(Eina_Rectangle));
717             evas_object_smart_callback_call(m_viewImpl->view(), "inputmethod,changed", &dummyRectForCustomKeypadCallback);
718         }
719         return;
720     }
721
722     setIMFContext(editor);
723     if (!m_context)
724         return;
725
726     if (!hasFocus)
727         return;
728
729 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
730     if (m_viewImpl->pageClient->isClipboardWindowOpened())
731         m_viewImpl->pageClient->closeClipboardWindow();
732 #endif
733
734      // input field zoom for external keyboard
735     if (s_shouldUseExternalKeyboard)
736         ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_TRUE);
737     else {
738         if (isShow())
739             ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_FALSE);
740     }
741
742     resetIMFContext();
743     ecore_imf_context_focus_in(m_context.get());
744     ecore_imf_context_input_panel_show(m_context.get());
745
746     setKeyboardMode(true);
747 }
748
749 void InputMethodContextEfl::hideIMFContext()
750 {
751 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
752     if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
753         if (m_viewImpl->pageClient->isClipboardWindowOpened())
754             m_viewImpl->pageClient->closeClipboardWindow();
755     }
756 #endif
757
758     m_inputPickerType = -1;
759
760     if (!m_context || !m_focused)
761         return;
762
763     if (ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE
764         && evas_object_focus_get(m_viewImpl->view())) {
765         resetIMFContext();
766         ecore_imf_context_input_panel_hide(m_context.get());
767         ecore_imf_context_focus_out(m_context.get());
768     }
769
770     setKeyboardMode(false);
771
772     m_focused = false;
773     revertIMFContext();
774 }
775
776 void InputMethodContextEfl::destroyIMFContextList()
777 {
778     m_contextList.clear();
779 }
780
781 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
782 void InputMethodContextEfl::showInputPicker(const EditorState& editorState)
783 {
784     if (editorState.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
785         return;
786
787     ewkViewInputPickerRequest(m_viewImpl->view(), static_cast<Ewk_Input_Type>(m_inputPickerType), editorState.surroundingText);
788     m_inputPickerType = -1;
789 }
790 #endif
791
792 bool InputMethodContextEfl::isIMEPostion(int x, int y)
793 {
794     if (m_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
795         return m_imeRect.contains(x, y);
796
797     return false;
798 }
799
800 void InputMethodContextEfl::removeIMFContext(uintptr_t contextID)
801 {
802     if (m_contextID == contextID)
803         hideIMFContext();
804
805     takeContext(contextID);
806 }
807
808 void InputMethodContextEfl::setKeyboardMode(bool isOn)
809 {
810     Evas_Object* parent = elm_object_parent_widget_get(m_viewImpl->view());
811     while (parent) {
812         const char* type = elm_object_widget_type_get(parent);
813         if (type && !strcmp(type, "elm_win")) {
814             elm_win_keyboard_mode_set(parent, isOn ? ELM_WIN_KEYBOARD_ON : ELM_WIN_KEYBOARD_OFF);
815             return;
816         }
817
818         parent = elm_object_parent_widget_get(parent);
819     }
820 }
821
822 void InputMethodContextEfl::requestFakeKeyEvent()
823 {
824     if (m_doNotHandleFakeKeyEvent || m_fakeKeyEventTimer.isActive())
825         return;
826
827     m_fakeKeyEventTimer.startOneShot(0);
828     m_viewImpl->page()->prepareKeyDownEvent();
829 }
830
831 void InputMethodContextEfl::fakeKeyEventTimerFired(WebCore::Timer<InputMethodContextEfl>*)
832 {
833     const char* text = " ";
834
835     Evas_Event_Key_Down downEvent;
836     memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
837     downEvent.key = text;
838     downEvent.string = text;
839     m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&downEvent, true));
840
841     Evas_Event_Key_Up upEvent;
842     memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
843     upEvent.key = text;
844     upEvent.string = text;
845     m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&upEvent));
846 }
847
848 Eina_Bool InputMethodContextEfl::IMEStatusChangeCallback(void* data, int type, void* event)
849 {
850     // Callback to get Virtual keyboard state from window manager.
851     // In case it is invoked from other than WebPage.
852     Ecore_X_Event_Window_Property* ev = static_cast<Ecore_X_Event_Window_Property*>(event);
853
854     Ecore_X_Virtual_Keyboard_State state = ecore_x_e_virtual_keyboard_state_get(ev->win);
855     if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_ON)
856         s_isSystemKeypadShow = true;
857     else if (state == ECORE_X_VIRTUAL_KEYBOARD_STATE_OFF)
858         s_isSystemKeypadShow = false;
859
860     return ECORE_CALLBACK_PASS_ON;
861 }
862 #endif // #if ENABLE(TIZEN_ISF_PORT)
863
864 }