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