a1436419dce32ea1307ca25037f131dab5a3fd50
[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 #endif
36
37 InputMethodContextEfl::InputMethodContextEfl(EwkViewImpl* viewImpl, PassOwnPtr<Ecore_IMF_Context> context)
38     : m_viewImpl(viewImpl)
39     , m_context(context)
40     , m_focused(false)
41 #if ENABLE(TIZEN_ISF_PORT)
42     , m_contextID(0)
43     , m_state(ECORE_IMF_INPUT_PANEL_STATE_HIDE)
44     , m_inputPickerType(-1)
45     , m_doNotHandleFakeKeyEvent(false)
46     , m_fakeKeyEventTimer(this, &InputMethodContextEfl::fakeKeyEventTimerFired)
47 #endif
48 {
49 #if !ENABLE(TIZEN_ISF_PORT)
50     ASSERT(context);
51     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
52     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
53 #endif
54 }
55
56 InputMethodContextEfl::~InputMethodContextEfl()
57 {
58 }
59
60 #if ENABLE(TIZEN_ISF_PORT)
61 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
62 {
63     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
64
65     inputMethodContext->setState(state);
66
67     if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
68 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
69         if (inputMethodContext->m_viewImpl->pageClient->isClipboardWindowOpened())
70             inputMethodContext->m_viewImpl->pageClient->closeClipboardWindow();
71 #endif
72         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
73     } else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
74         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
75 }
76
77 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
78 {
79     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
80     if (!inputMethodContext->m_context)
81         return;
82
83     Eina_Rectangle rect;
84     ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
85     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
86
87     inputMethodContext->setIMERect(IntRect(rect.x, rect.y, rect.w, rect.h));
88 }
89
90 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
91 {
92     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
93
94     if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
95         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
96     else
97         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
98 }
99
100 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
101 {
102     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
103     if (!inputMethodContext->m_context)
104         return;
105
106     Eina_Rectangle rect;
107     ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
108     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
109 }
110
111 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
112 {
113     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
114     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
115         return false;
116
117     String surroundingText;
118     int cursorOffset;
119     inputMethodContext->m_viewImpl->page()->getSurroundingTextAndCursorOffset(surroundingText, cursorOffset);
120
121     if (text) {
122         CString utf8Text(surroundingText.utf8());
123         size_t length = utf8Text.length();
124
125         *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
126         if (!(*text))
127             return false;
128
129         if (length)
130             strncpy(*text, utf8Text.data(), length);
131         (*text)[length] = 0;
132     }
133
134     if (offset)
135         *offset = cursorOffset;
136
137     return true;
138 }
139
140 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
141 {
142     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
143     if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
144         return;
145
146     inputMethodContext->requestFakeKeyEvent();
147
148     Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
149     inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
150 }
151
152 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
153 {
154     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
155     if (!eventInfo || !inputMethodContext->m_focused)
156         return;
157
158     inputMethodContext->requestFakeKeyEvent();
159
160     inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
161 }
162
163 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
164 unsigned getUTF8CharacterIndex(const char* string, unsigned byteIndex)
165 {
166     unsigned index = 0;
167     const char* end = string + byteIndex;
168
169     while (*string && string < end) {
170         unsigned offset;
171
172         if ((*string & 0x80) == 0x00)
173             offset = 1;
174         else if ((*string & 0xe0) == 0xc0)
175             offset = 2;
176         else if ((*string & 0xf0) == 0xe0)
177             offset = 3;
178         else if ((*string & 0xf8) == 0xf0)
179             offset = 4;
180         else if ((*string & 0xfc) == 0xf8)
181             offset = 5;
182         else if ((*string & 0xfe) == 0xfc)
183             offset = 6;
184         else
185             offset = 1;
186
187         ++index;
188         while (*string && offset--)
189             ++string;
190     }
191
192     return index;
193 }
194 #endif
195
196 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
197 {
198     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
199
200     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
201         return;
202
203     WebPageProxy* page = inputMethodContext->m_viewImpl->page();
204     if (!page->focusedFrame())
205         return;
206
207     inputMethodContext->requestFakeKeyEvent();
208
209     PageClientImpl* pageClient = inputMethodContext->m_viewImpl->pageClient.get();
210     IntRect caretRect;
211     page->getCaretPosition(caretRect);
212     caretRect.scale(pageClient->scaleFactor());
213
214     int viewX, viewY;
215     evas_object_geometry_get(inputMethodContext->m_viewImpl->view(), &viewX, &viewY, 0, 0);
216
217     int x = caretRect.x() - pageClient->scrollPosition().x() + viewX;
218     int y = caretRect.y() - pageClient->scrollPosition().y() + viewY;
219     int w = caretRect.width();
220     int h = caretRect.height();
221     ecore_imf_context_cursor_location_set(context, x, y, w, h);
222
223     char* buffer = 0;
224     Eina_List* preeditAttrs = 0;
225     int cursorPosition = 0;
226
227     ecore_imf_context_preedit_string_with_attributes_get(context, &buffer, &preeditAttrs, &cursorPosition);
228
229     String preeditString = String::fromUTF8(buffer);
230     Vector<CompositionUnderline> underlines;
231
232     if (preeditAttrs) {
233         void* item = 0;
234 #if ENABLE(TIZEN_WEBKIT2_SUPPORT_JAPANESE_IME)
235         Eina_List* listIterator = 0;
236         EINA_LIST_FOREACH(preeditAttrs, listIterator, item) {
237             Ecore_IMF_Preedit_Attr* preeditAttr = static_cast<Ecore_IMF_Preedit_Attr*>(item);
238
239             unsigned startIndex = getUTF8CharacterIndex(buffer, preeditAttr->start_index);
240             unsigned endIndex = getUTF8CharacterIndex(buffer, preeditAttr->end_index);
241             switch (preeditAttr->preedit_type) {
242             case ECORE_IMF_PREEDIT_TYPE_SUB1:
243                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), false));
244                 break;
245             case ECORE_IMF_PREEDIT_TYPE_SUB2:
246             case ECORE_IMF_PREEDIT_TYPE_SUB3:
247                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(255, 255, 255), false));
248                 break;
249             case ECORE_IMF_PREEDIT_TYPE_SUB4:
250                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(46, 168, 255), false));
251                 break;
252             case ECORE_IMF_PREEDIT_TYPE_SUB5:
253                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 98, 195), false));
254                 break;
255             case ECORE_IMF_PREEDIT_TYPE_SUB6:
256                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(118, 222, 55), false));
257                 break;
258             case ECORE_IMF_PREEDIT_TYPE_SUB7:
259                 underlines.append(CompositionUnderline(startIndex, endIndex, Color(0, 0, 0), Color(153, 153, 153), false));
260                 break;
261             default:
262                 break;
263             }
264         }
265 #endif
266         EINA_LIST_FREE(preeditAttrs, item)
267             free(item);
268     }
269
270     if (underlines.isEmpty())
271         underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
272
273     page->setComposition(preeditString, underlines, cursorPosition);
274
275     if (buffer)
276         free(buffer);
277 }
278 #else
279 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
280 {
281     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
282     if (!eventInfo || !inputMethodContext->m_focused)
283         return;
284
285     inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
286 }
287
288 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
289 {
290     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
291
292     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
293         return;
294
295     char* buffer = 0;
296     ecore_imf_context_preedit_string_get(context, &buffer, 0);
297     if (!buffer)
298         return;
299
300     String preeditString = String::fromUTF8(buffer);
301     free(buffer);
302     Vector<CompositionUnderline> underlines;
303     underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
304     inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
305 }
306 #endif
307
308 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
309 {
310     const char* defaultContextID = ecore_imf_context_default_id_get();
311     if (!defaultContextID)
312         return nullptr;
313
314     OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
315     if (!imfContext)
316         return nullptr;
317
318     Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
319     ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
320     ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
321
322     return imfContext.release();
323 }
324
325 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
326 {
327 #if ENABLE(TIZEN_ISF_PORT)
328     if (!m_context)
329         return;
330
331     resetIMFContext();
332 #else
333     ecore_imf_context_reset(m_context.get());
334 #endif
335 }
336
337 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
338 {
339 #if ENABLE(TIZEN_ISF_PORT)
340     if (!m_context)
341         return;
342
343     if (m_fakeKeyEventTimer.isActive())
344         m_fakeKeyEventTimer.stop();
345     else
346         m_viewImpl->page()->prepareKeyDownEvent();
347
348     m_doNotHandleFakeKeyEvent = true;
349 #endif
350
351     Ecore_IMF_Event inputMethodEvent;
352     ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
353
354     *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
355
356 #if ENABLE(TIZEN_ISF_PORT)
357     m_doNotHandleFakeKeyEvent = false;
358 #endif
359 }
360
361 #if ENABLE(TIZEN_ISF_PORT)
362 void InputMethodContextEfl::updateTextInputState()
363 {
364     const EditorState& editor = m_viewImpl->page()->editorState();
365     if (editor.shouldIgnoreCompositionSelectionChange || editor.updateEditorRectOnly)
366         return;
367
368     if (editor.isContentEditable)
369         showIMFContext(editor);
370     else
371         hideIMFContext();
372
373     if (m_context)
374         ecore_imf_context_cursor_position_set(m_context.get(), editor.cursorPosition);
375 }
376 #else
377 void InputMethodContextEfl::updateTextInputState()
378 {
379     if (!m_context)
380         return;
381
382     const EditorState& editor = m_viewImpl->page()->editorState();
383
384     if (editor.isContentEditable) {
385         if (m_focused)
386             return;
387
388         ecore_imf_context_reset(m_context.get());
389         ecore_imf_context_focus_in(m_context.get());
390         m_focused = true;
391     } else {
392         if (!m_focused)
393             return;
394
395         if (editor.hasComposition)
396             m_viewImpl->page()->cancelComposition();
397
398         m_focused = false;
399         ecore_imf_context_reset(m_context.get());
400         ecore_imf_context_focus_out(m_context.get());
401     }
402 }
403 #endif
404
405 #if ENABLE(TIZEN_ISF_PORT)
406 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout, int layoutVariation, Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType)
407 {
408     ecore_imf_context_input_panel_enabled_set(context, false);
409     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
410     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
411     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
412     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
413     ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
414     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
415     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
416     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
417
418     ecore_imf_context_input_panel_layout_set(context, layout);
419     if (layoutVariation >= 0)
420         ecore_imf_context_input_panel_layout_variation_set(context, layoutVariation);
421     ecore_imf_context_input_panel_return_key_type_set(context, returnKeyType);
422 }
423
424 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::takeContext(uintptr_t contextID)
425 {
426     size_t i = m_contextList.size();
427     while (i > 0) {
428         --i;
429         if (m_contextList[i].first == contextID) {
430             PassOwnPtr<Ecore_IMF_Context> context = m_contextList[i].second.release();
431             m_contextList.remove(i);
432             return context;
433         }
434     }
435
436     return PassOwnPtr<Ecore_IMF_Context>();
437 }
438
439 void InputMethodContextEfl::setIMFContext(const EditorState& editor)
440 {
441     const String& type = editor.inputMethodHints;
442     Ecore_IMF_Input_Panel_Layout layout;
443     int layoutVariation = -1;
444     Ecore_IMF_Input_Panel_Return_Key_Type returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
445
446     if (type == "number") {
447         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
448         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_NORMAL;
449     } else if (type == "signedNumber") {
450         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
451         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED;
452     } else if (type == "decimalNumber") {
453         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
454         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_DECIMAL;
455     } else if (type == "signedDecimalNumber") {
456         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY;
457         layoutVariation = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY_VARIATION_SIGNED_AND_DECIMAL;
458     } else if (type == "email")
459         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
460     else if (type == "url")
461         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
462     else if (type == "tel")
463         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
464     else if (type == "password")
465         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
466     else {
467         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
468         if (type == "search")
469             returnKeyType = ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
470     }
471
472     OwnPtr<Ecore_IMF_Context> context;
473     if (m_contextID == editor.inputMethodContextID)
474         context = m_context.release();
475     else
476         context = takeContext(editor.inputMethodContextID);
477
478     revertIMFContext();
479
480     if (!context) {
481         context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
482         if (!context)
483             return;
484         initializeIMFContext(context.get(), layout, layoutVariation, returnKeyType);
485     }
486
487     m_context = context.release();
488     m_contextID = editor.inputMethodContextID;
489
490     if (type == "password" || type == "plugin")
491         ecore_imf_context_prediction_allow_set(m_context.get(), false);
492     else
493         ecore_imf_context_prediction_allow_set(m_context.get(), true);
494
495     if (type.isEmpty() || type == "textarea")
496         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
497     else
498         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
499 }
500
501 bool InputMethodContextEfl::isShow()
502 {
503     return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
504 }
505
506 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
507 {
508     return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
509 }
510
511 void InputMethodContextEfl::onFocusIn()
512 {
513     if (m_inputPickerType >= 0) {
514         showInputPicker(m_viewImpl->page()->editorState());
515         return;
516     }
517
518     if (!m_context || !m_focused)
519         return;
520
521     ecore_imf_context_focus_in(m_context.get());
522     ecore_imf_context_input_panel_show(m_context.get());
523
524     setKeyboardMode(true);
525 }
526
527 void InputMethodContextEfl::onFocusOut()
528 {
529 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
530     if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
531         if (m_viewImpl->pageClient->isClipboardWindowOpened())
532             m_viewImpl->pageClient->closeClipboardWindow();
533     }
534 #endif
535
536     if (!m_context || !m_focused)
537         return;
538
539     ecore_imf_context_input_panel_hide(m_context.get());
540     ecore_imf_context_focus_out(m_context.get());
541
542     setKeyboardMode(false);
543 }
544
545 void InputMethodContextEfl::revertIMFContext()
546 {
547     if (!m_context)
548         return;
549
550     if (m_contextList.size() >= maxContextSize)
551         m_contextList.remove(0);
552
553     PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
554     m_contextList.append(std::make_pair(m_contextID, imfContext));
555     m_contextID = 0;
556 }
557
558 void InputMethodContextEfl::resetIMFContext()
559 {
560     if (!m_context)
561         return;
562
563     m_doNotHandleFakeKeyEvent = true;
564     ecore_imf_context_reset(m_context.get());
565     m_doNotHandleFakeKeyEvent = false;
566 }
567
568 void InputMethodContextEfl::showIMFContext(const EditorState& editor)
569 {
570     Ewk_Settings* settings = ewk_view_settings_get(m_viewImpl->view());
571     if (!editor.isTapEventHandling) {
572         if (!ewk_settings_uses_keypad_without_user_action_get(settings) || (m_focused && m_contextID == editor.inputMethodContextID))
573             return;
574     }
575
576     m_focused = true;
577
578 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
579     if (editor.inputMethodHints == "date")
580         m_inputPickerType = EWK_INPUT_TYPE_DATE;
581     else if (editor.inputMethodHints == "datetime")
582         m_inputPickerType = EWK_INPUT_TYPE_DATETIME;
583     else if (editor.inputMethodHints == "datetime-local")
584         m_inputPickerType = EWK_INPUT_TYPE_DATETIMELOCAL;
585     else if (editor.inputMethodHints == "month")
586         m_inputPickerType = EWK_INPUT_TYPE_MONTH;
587     else if (editor.inputMethodHints == "time")
588         m_inputPickerType = EWK_INPUT_TYPE_TIME;
589     else if (editor.inputMethodHints == "week")
590         m_inputPickerType = EWK_INPUT_TYPE_WEEK;
591     else
592         m_inputPickerType = -1;
593
594     if (m_inputPickerType >= 0) {
595         showInputPicker(editor);
596         revertIMFContext();
597         m_contextID = editor.inputMethodContextID;
598
599         return;
600     }
601
602 #if ENABLE(TIZEN_DATALIST_ELEMENT)
603     Vector<String> optionList = m_viewImpl->page()->getFocusedInputElementDataList();
604     if (optionList.size() > 0) {
605         if (editor.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
606             return;
607
608         if (editor.inputMethodHints == "tel")
609             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TELEPHONE, optionList);
610         else if (editor.inputMethodHints == "number")
611             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_NUMBER, optionList);
612         else if (editor.inputMethodHints == "email")
613             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_EMAIL, optionList);
614         else if (editor.inputMethodHints == "url")
615             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_URL, optionList);
616         else
617             ewkViewDataListShowRequest(m_viewImpl->view(), EWK_INPUT_TYPE_TEXT, optionList);
618
619         revertIMFContext();
620         m_contextID = editor.inputMethodContextID;
621
622         return;
623     }
624 #endif
625 #endif // ENABLE(TIZEN_INPUT_TAG_EXTENSION)
626
627     bool hasFocus = evas_object_focus_get(m_viewImpl->view());
628
629     if (!ewk_settings_default_keypad_enabled_get(settings)) {
630         if (hasFocus) {
631             Eina_Rectangle dummyRectForCustomKeypadCallback;
632             memset(&dummyRectForCustomKeypadCallback, 0, sizeof(Eina_Rectangle));
633             evas_object_smart_callback_call(m_viewImpl->view(), "inputmethod,changed", &dummyRectForCustomKeypadCallback);
634         }
635         return;
636     }
637
638     setIMFContext(editor);
639     if (!m_context)
640         return;
641
642     if (!hasFocus)
643         return;
644
645 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
646     if (m_viewImpl->pageClient->isClipboardWindowOpened())
647         m_viewImpl->pageClient->closeClipboardWindow();
648 #endif
649
650     resetIMFContext();
651     ecore_imf_context_focus_in(m_context.get());
652     ecore_imf_context_input_panel_show(m_context.get());
653
654     // input field zoom for external keyboard
655     ewk_view_focused_node_adjust(m_viewImpl->view(), EINA_TRUE);
656
657     setKeyboardMode(true);
658 }
659
660 void InputMethodContextEfl::hideIMFContext()
661 {
662 #if ENABLE(TIZEN_WEBKIT2_CONTEXT_MENU_CLIPBOARD)
663     if (m_state != ECORE_IMF_INPUT_PANEL_STATE_SHOW) {
664         if (m_viewImpl->pageClient->isClipboardWindowOpened())
665             m_viewImpl->pageClient->closeClipboardWindow();
666     }
667 #endif
668
669     m_inputPickerType = -1;
670
671     if (!m_context || !m_focused)
672         return;
673
674     if (ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE
675         && evas_object_focus_get(m_viewImpl->view())) {
676         resetIMFContext();
677         ecore_imf_context_input_panel_hide(m_context.get());
678         ecore_imf_context_focus_out(m_context.get());
679     }
680
681     setKeyboardMode(false);
682
683     m_focused = false;
684     revertIMFContext();
685 }
686
687 void InputMethodContextEfl::destroyIMFContextList()
688 {
689     m_contextList.clear();
690 }
691
692 #if ENABLE(TIZEN_INPUT_TAG_EXTENSION)
693 void InputMethodContextEfl::showInputPicker(const EditorState& editorState)
694 {
695     if (editorState.selectionIsRange || !evas_object_focus_get(m_viewImpl->view()))
696         return;
697
698     ewkViewInputPickerRequest(m_viewImpl->view(), static_cast<Ewk_Input_Type>(m_inputPickerType), editorState.surroundingText);
699     m_inputPickerType = -1;
700 }
701 #endif
702
703 bool InputMethodContextEfl::isIMEPostion(int x, int y)
704 {
705     if (m_state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
706         return m_imeRect.contains(x, y);
707
708     return false;
709 }
710
711 void InputMethodContextEfl::removeIMFContext(uintptr_t contextID)
712 {
713     if (m_contextID == contextID)
714         hideIMFContext();
715
716     takeContext(contextID);
717 }
718
719 void InputMethodContextEfl::setKeyboardMode(bool isOn)
720 {
721     Evas_Object* parent = elm_object_parent_widget_get(m_viewImpl->view());
722     while (parent) {
723         const char* type = elm_object_widget_type_get(parent);
724         if (type && !strcmp(type, "elm_win")) {
725             elm_win_keyboard_mode_set(parent, isOn ? ELM_WIN_KEYBOARD_ON : ELM_WIN_KEYBOARD_OFF);
726             return;
727         }
728
729         parent = elm_object_parent_widget_get(parent);
730     }
731 }
732
733 void InputMethodContextEfl::requestFakeKeyEvent()
734 {
735     if (m_doNotHandleFakeKeyEvent || m_fakeKeyEventTimer.isActive())
736         return;
737
738     m_fakeKeyEventTimer.startOneShot(0);
739     m_viewImpl->page()->prepareKeyDownEvent();
740 }
741
742 void InputMethodContextEfl::fakeKeyEventTimerFired(WebCore::Timer<InputMethodContextEfl>*)
743 {
744     const char* text = " ";
745
746     Evas_Event_Key_Down downEvent;
747     memset(&downEvent, 0, sizeof(Evas_Event_Key_Down));
748     downEvent.key = text;
749     downEvent.string = text;
750     m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&downEvent, true));
751
752     Evas_Event_Key_Up upEvent;
753     memset(&upEvent, 0, sizeof(Evas_Event_Key_Up));
754     upEvent.key = text;
755     upEvent.string = text;
756     m_viewImpl->page()->handleKeyboardEvent(NativeWebKeyboardEvent(&upEvent));
757 }
758 #endif // #if ENABLE(TIZEN_ISF_PORT)
759
760 }