Merge "Add copySurfaceTye argument to copySurface function." into tizen_2.1
[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 InputMethodContextEfl::InputMethodContextEfl(EwkViewImpl* viewImpl, PassOwnPtr<Ecore_IMF_Context> context)
34     : m_viewImpl(viewImpl)
35     , m_context(context)
36     , m_focused(false)
37 {
38     ASSERT(context);
39 #if ENABLE(TIZEN_ISF_PORT)
40     initializeIMFContext(m_context.get(), ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL);
41 #else
42     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
43     ecore_imf_context_event_callback_add(m_context.get(), ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
44 #endif
45 }
46
47 InputMethodContextEfl::~InputMethodContextEfl()
48 {
49 }
50
51 #if ENABLE(TIZEN_ISF_PORT)
52 void InputMethodContextEfl::onIMFInputPanelStateChanged(void* data, Ecore_IMF_Context*, int state)
53 {
54     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
55     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
56         return;
57
58     if (state == ECORE_IMF_INPUT_PANEL_STATE_HIDE)
59         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,closed", 0);
60     else if (state == ECORE_IMF_INPUT_PANEL_STATE_SHOW)
61         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,ime,opened", 0);
62 }
63
64 void InputMethodContextEfl::onIMFInputPanelGeometryChanged(void* data, Ecore_IMF_Context*, int value)
65 {
66     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
67     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
68         return;
69
70     Eina_Rectangle rect;
71     ecore_imf_context_input_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
72     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "inputmethod,changed", &rect);
73 }
74
75 void InputMethodContextEfl::onIMFCandidatePanelStateChanged(void* data, Ecore_IMF_Context*, int state)
76 {
77     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
78     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
79         return;
80
81     if (state == ECORE_IMF_CANDIDATE_PANEL_SHOW)
82         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,opened", 0);
83     else
84         evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,closed", 0);
85 }
86
87 void InputMethodContextEfl::onIMFCandidatePanelGeometryChanged(void* data, Ecore_IMF_Context*, int)
88 {
89     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
90     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
91         return;
92
93     Eina_Rectangle rect;
94     ecore_imf_context_candidate_panel_geometry_get(inputMethodContext->m_context.get(), &rect.x, &rect.y, &rect.w, &rect.h);
95     evas_object_smart_callback_call(inputMethodContext->m_viewImpl->view(), "editorclient,candidate,changed", &rect);
96 }
97
98 Eina_Bool InputMethodContextEfl::onIMFRetrieveSurrounding(void* data, Ecore_IMF_Context*, char** text, int* offset)
99 {
100     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
101     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused || (!text && !offset))
102         return false;
103
104     String surroundingText;
105     int cursorOffset;
106     inputMethodContext->m_viewImpl->page()->getSurroundingTextAndCursorOffset(surroundingText, cursorOffset);
107
108     if (text) {
109         CString utf8Text(surroundingText.utf8());
110         size_t length = utf8Text.length();
111
112         *text = static_cast<char*>(malloc((length + 1) * sizeof(char)));
113         if (!(*text))
114             return false;
115
116         if (length)
117             strncpy(*text, utf8Text.data(), length);
118         (*text)[length] = 0;
119     }
120
121     if (offset)
122         *offset = cursorOffset;
123
124     return true;
125 }
126
127 void InputMethodContextEfl::onIMFDeleteSurrounding(void* data, Ecore_IMF_Context*, void* eventInfo)
128 {
129     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
130     if (!eventInfo || !inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
131         return;
132
133     Ecore_IMF_Event_Delete_Surrounding* event = static_cast<Ecore_IMF_Event_Delete_Surrounding*>(eventInfo);
134     inputMethodContext->m_viewImpl->page()->deleteSurroundingText(event->offset, event->n_chars);
135 }
136
137 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
138 {
139     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
140     if (!eventInfo || !inputMethodContext->m_focused)
141         return;
142
143     inputMethodContext->m_viewImpl->pageClient->imContextCommitted(inputMethodContext->m_context.get(), static_cast<char*>(eventInfo));
144 }
145
146 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context*, void*)
147 {
148     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
149     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
150         return;
151
152     inputMethodContext->m_viewImpl->pageClient->imContextPreeditChanged(inputMethodContext->m_context.get());
153 }
154 #else
155 void InputMethodContextEfl::onIMFInputSequenceComplete(void* data, Ecore_IMF_Context*, void* eventInfo)
156 {
157     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
158     if (!eventInfo || !inputMethodContext->m_focused)
159         return;
160
161     inputMethodContext->m_viewImpl->page()->confirmComposition(String::fromUTF8(static_cast<char*>(eventInfo)));
162 }
163
164 void InputMethodContextEfl::onIMFPreeditSequenceChanged(void* data, Ecore_IMF_Context* context, void*)
165 {
166     InputMethodContextEfl* inputMethodContext = static_cast<InputMethodContextEfl*>(data);
167
168     if (!inputMethodContext->m_viewImpl->page()->focusedFrame() || !inputMethodContext->m_focused)
169         return;
170
171     char* buffer = 0;
172     ecore_imf_context_preedit_string_get(context, &buffer, 0);
173     if (!buffer)
174         return;
175
176     String preeditString = String::fromUTF8(buffer);
177     free(buffer);
178     Vector<CompositionUnderline> underlines;
179     underlines.append(CompositionUnderline(0, preeditString.length(), Color(0, 0, 0), false));
180     inputMethodContext->m_viewImpl->page()->setComposition(preeditString, underlines, 0);
181 }
182 #endif
183
184 PassOwnPtr<Ecore_IMF_Context> InputMethodContextEfl::createIMFContext(Evas* canvas)
185 {
186     const char* defaultContextID = ecore_imf_context_default_id_get();
187     if (!defaultContextID)
188         return nullptr;
189
190     OwnPtr<Ecore_IMF_Context> imfContext = adoptPtr(ecore_imf_context_add(defaultContextID));
191     if (!imfContext)
192         return nullptr;
193
194     Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(canvas);
195     ecore_imf_context_client_window_set(imfContext.get(), reinterpret_cast<void*>(ecore_evas_window_get(ecoreEvas)));
196     ecore_imf_context_client_canvas_set(imfContext.get(), canvas);
197
198     return imfContext.release();
199 }
200
201 void InputMethodContextEfl::handleMouseUpEvent(const Evas_Event_Mouse_Up*)
202 {
203     ecore_imf_context_reset(m_context.get());
204 }
205
206 void InputMethodContextEfl::handleKeyDownEvent(const Evas_Event_Key_Down* downEvent, bool* isFiltered)
207 {
208     Ecore_IMF_Event inputMethodEvent;
209     ecore_imf_evas_event_key_down_wrap(const_cast<Evas_Event_Key_Down*>(downEvent), &inputMethodEvent.key_down);
210
211     *isFiltered = ecore_imf_context_filter_event(m_context.get(), ECORE_IMF_EVENT_KEY_DOWN, &inputMethodEvent);
212 }
213
214 void InputMethodContextEfl::updateTextInputState()
215 {
216     if (!m_context)
217         return;
218
219     const EditorState& editor = m_viewImpl->page()->editorState();
220
221     if (editor.isContentEditable) {
222         if (m_focused)
223             return;
224
225         ecore_imf_context_reset(m_context.get());
226         ecore_imf_context_focus_in(m_context.get());
227         m_focused = true;
228     } else {
229         if (!m_focused)
230             return;
231
232         if (editor.hasComposition)
233             m_viewImpl->page()->cancelComposition();
234
235         m_focused = false;
236         ecore_imf_context_reset(m_context.get());
237         ecore_imf_context_focus_out(m_context.get());
238     }
239 }
240
241 #if ENABLE(TIZEN_ISF_PORT)
242 void InputMethodContextEfl::initializeIMFContext(Ecore_IMF_Context* context, Ecore_IMF_Input_Panel_Layout layout)
243 {
244     ecore_imf_context_input_panel_enabled_set(context, false);
245     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_STATE_EVENT, onIMFInputPanelStateChanged, this);
246     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, onIMFInputPanelGeometryChanged, this);
247     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_STATE_EVENT, onIMFCandidatePanelStateChanged, this);
248     ecore_imf_context_input_panel_event_callback_add(context, ECORE_IMF_CANDIDATE_PANEL_GEOMETRY_EVENT, onIMFCandidatePanelGeometryChanged, this);
249     ecore_imf_context_retrieve_surrounding_callback_set(context, onIMFRetrieveSurrounding, this);
250     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, onIMFDeleteSurrounding, this);
251     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, onIMFPreeditSequenceChanged, this);
252     ecore_imf_context_event_callback_add(context, ECORE_IMF_CALLBACK_COMMIT, onIMFInputSequenceComplete, this);
253     ecore_imf_context_input_panel_layout_set(m_context.get(), layout);
254 }
255
256 void InputMethodContextEfl::setType(const String& type)
257 {
258     Ecore_IMF_Input_Panel_Layout layout;
259     if (type == "number")
260         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER;
261     else if (type == "email")
262         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL;
263     else if (type == "url")
264         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_URL;
265     else if (type == "tel")
266         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER;
267     else if (type == "password")
268         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD;
269     else
270         layout = ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL;
271
272     if (m_contextList.contains(layout)) {
273         revertIMFContext();
274         m_context = m_contextList.take(layout);
275     } else if (!m_context || ecore_imf_context_input_panel_layout_get(m_context.get()) != layout) {
276         OwnPtr<Ecore_IMF_Context> context = createIMFContext(evas_object_evas_get(m_viewImpl->view()));
277         if (!m_context)
278             return;
279         revertIMFContext();
280         m_context = context.release();
281         initializeIMFContext(m_context.get(), layout);
282     }
283
284     if (type == "password" || type == "plugin")
285         ecore_imf_context_prediction_allow_set(m_context.get(), false);
286     else
287         ecore_imf_context_prediction_allow_set(m_context.get(), true);
288
289     if (type.isEmpty() || type == "textarea")
290         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE);
291     else
292         ecore_imf_context_autocapital_type_set(m_context.get(), ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
293 }
294
295 void InputMethodContextEfl::showIMFContext()
296 {
297     if (!m_context)
298         return;
299
300     ecore_imf_context_focus_in(m_context.get());
301     ecore_imf_context_input_panel_show(m_context.get());
302     ecore_imf_context_cursor_position_set(m_context.get(), m_viewImpl->page()->getCursorOffset());
303 }
304
305 void InputMethodContextEfl::setIMFContextCursorPosition(int position)
306 {
307     if (!m_context)
308         return;
309
310     ecore_imf_context_cursor_position_set(m_context.get(), position);
311 }
312
313 void InputMethodContextEfl::setIMData(const String& data)
314 {
315     if (!m_context)
316         return;
317
318     CString utf8Data = data.utf8();
319     ecore_imf_context_input_panel_imdata_set(m_context.get(), utf8Data.data(), utf8Data.length());
320 }
321
322 bool InputMethodContextEfl::isShow()
323 {
324     return (m_context && m_focused && ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE);
325 }
326
327 Ecore_IMF_Autocapital_Type InputMethodContextEfl::autoCapitalType()
328 {
329     return (m_context ? ecore_imf_context_autocapital_type_get(m_context.get()) : ECORE_IMF_AUTOCAPITAL_TYPE_NONE);
330 }
331
332 void InputMethodContextEfl::onFocusIn()
333 {
334     if (!m_context || !m_focused)
335         return;
336
337     ecore_imf_context_focus_in(m_context.get());
338     ecore_imf_context_input_panel_show(m_context.get());
339 }
340
341 void InputMethodContextEfl::onFocusOut()
342 {
343     if (!m_context || !m_focused)
344         return;
345
346     ecore_imf_context_input_panel_hide(m_context.get());
347     ecore_imf_context_focus_out(m_context.get());
348 }
349
350 void InputMethodContextEfl::revertIMFContext()
351 {
352     if (!m_context)
353         return;
354
355     PassOwnPtr<Ecore_IMF_Context> imfContext = m_context.release();
356     m_contextList.add(ecore_imf_context_input_panel_layout_get(imfContext.get()), imfContext);
357 }
358
359 void InputMethodContextEfl::resetIMFContext()
360 {
361     if (!m_context)
362         return;
363
364     ecore_imf_context_reset(m_context.get());
365
366     if (ecore_imf_context_input_panel_state_get(m_context.get()) == ECORE_IMF_INPUT_PANEL_STATE_HIDE)
367         revertIMFContext();
368 }
369
370 void InputMethodContextEfl::hideIMFContext()
371 {
372     if (!m_context)
373         return;
374
375     if (ecore_imf_context_input_panel_state_get(m_context.get()) != ECORE_IMF_INPUT_PANEL_STATE_HIDE) {
376         ecore_imf_context_reset(m_context.get());
377         ecore_imf_context_input_panel_hide(m_context.get());
378         ecore_imf_context_focus_out(m_context.get());
379     }
380
381     revertIMFContext();
382 }
383
384 void InputMethodContextEfl::destroyIMFContextList()
385 {
386     m_contextList.clear();
387 }
388 #endif
389
390 }