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 "EwkView.h"
23
24#include "ContextMenuClientEfl.h"
25#include "EflScreenUtilities.h"
26#include "FindClientEfl.h"
27#include "FormClientEfl.h"
28#include "InputMethodContextEfl.h"
29#include "NativeWebKeyboardEvent.h"
30#include "NativeWebMouseEvent.h"
31#include "NativeWebWheelEvent.h"
32#include "PageLoadClientEfl.h"
33#include "PagePolicyClientEfl.h"
34#include "PageUIClientEfl.h"
35#include "PageViewportController.h"
36#include "PageViewportControllerClientEfl.h"
37#include "SnapshotImageGL.h"
38#include "ViewClientEfl.h"
39#include "WKDictionary.h"
40#include "WKGeometry.h"
41#include "WKNumber.h"
42#include "WKPageGroup.h"
43#include "WKPopupItem.h"
44#include "WKString.h"
45#include "WKView.h"
46#include "WKViewEfl.h"
47#include "WebContext.h"
48#include "WebImage.h"
49#include "WebPageGroup.h"
50#include "WebPageProxy.h"
51#include "WebPreferences.h"
52#include "ewk_back_forward_list_private.h"
53#include "ewk_color_picker_private.h"
54#include "ewk_context_menu_item_private.h"
55#include "ewk_context_menu_private.h"
56#include "ewk_context_private.h"
57#include "ewk_favicon_database_private.h"
58#include "ewk_page_group_private.h"
59#include "ewk_popup_menu_item_private.h"
60#include "ewk_popup_menu_private.h"
61#include "ewk_private.h"
62#include "ewk_security_origin_private.h"
63#include "ewk_settings_private.h"
64#include "ewk_view.h"
65#include "ewk_window_features_private.h"
66#include <Ecore_Evas.h>
67#include <Ecore_X.h>
68#include <Edje.h>
69#if USE(ACCELERATED_COMPOSITING)
70#include <Evas_GL.h>
71#endif
72#include <WebCore/CairoUtilitiesEfl.h>
73#include <WebCore/Cursor.h>
74#include <WebCore/PlatformContextCairo.h>
75#include <WebKit2/WKImageCairo.h>
76#include <wtf/MathExtras.h>
77
78#if ENABLE(VIBRATION)
79#include "VibrationClientEfl.h"
80#endif
81
82#if ENABLE(FULLSCREEN_API)
83#include "WebFullScreenManagerProxy.h"
84#endif
85
86using namespace EwkViewCallbacks;
87using namespace WebCore;
88using namespace WebKit;
89
90static const char smartClassName[] = "EWK2_View";
91static const int defaultCursorSize = 16;
92
93// Auxiliary functions.
94
95static inline void smartDataChanged(Ewk_View_Smart_Data* smartData)
96{
97    ASSERT(smartData);
98
99    if (smartData->changed.any)
100        return;
101
102    smartData->changed.any = true;
103    evas_object_smart_changed(smartData->self);
104}
105
106static Evas_Smart* defaultSmartClassInstance()
107{
108    static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION(smartClassName);
109    static Evas_Smart* smart = 0;
110
111    if (!smart) {
112        EwkView::initSmartClassInterface(api);
113        smart = evas_smart_class_new(&api.sc);
114    }
115
116    return smart;
117}
118
119static inline Ewk_View_Smart_Data* toSmartData(Evas_Object* evasObject)
120{
121    ASSERT(evasObject);
122    ASSERT(isEwkViewEvasObject(evasObject));
123
124    return static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(evasObject));
125}
126
127static inline EwkView* toEwkView(const Ewk_View_Smart_Data* smartData)
128{
129    ASSERT(smartData);
130    ASSERT(smartData->priv);
131
132    return smartData->priv;
133}
134
135static inline void showEvasObjectsIfNeeded(const Ewk_View_Smart_Data* smartData)
136{
137    ASSERT(smartData);
138
139    if (evas_object_clipees_get(smartData->base.clipper))
140        evas_object_show(smartData->base.clipper);
141    evas_object_show(smartData->image);
142}
143
144// EwkViewEventHandler implementation.
145
146template <Evas_Callback_Type EventType>
147class EwkViewEventHandler {
148public:
149    static void subscribe(Evas_Object* evasObject)
150    {
151        evas_object_event_callback_add(evasObject, EventType, handleEvent, toSmartData(evasObject));
152    }
153
154    static void unsubscribe(Evas_Object* evasObject)
155    {
156        evas_object_event_callback_del(evasObject, EventType, handleEvent);
157    }
158
159    static void handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo);
160};
161
162template <>
163void EwkViewEventHandler<EVAS_CALLBACK_MOUSE_DOWN>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
164{
165    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
166    if (smartData->api->mouse_down)
167        smartData->api->mouse_down(smartData, static_cast<Evas_Event_Mouse_Down*>(eventInfo));
168}
169
170template <>
171void EwkViewEventHandler<EVAS_CALLBACK_MOUSE_UP>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
172{
173    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
174    if (smartData->api->mouse_up)
175        smartData->api->mouse_up(smartData, static_cast<Evas_Event_Mouse_Up*>(eventInfo));
176}
177
178template <>
179void EwkViewEventHandler<EVAS_CALLBACK_MOUSE_MOVE>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
180{
181    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
182    if (smartData->api->mouse_move)
183        smartData->api->mouse_move(smartData, static_cast<Evas_Event_Mouse_Move*>(eventInfo));
184}
185
186template <>
187void EwkViewEventHandler<EVAS_CALLBACK_FOCUS_IN>::handleEvent(void* data, Evas*, Evas_Object*, void*)
188{
189    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
190    if (smartData->api->focus_in)
191        smartData->api->focus_in(smartData);
192}
193
194template <>
195void EwkViewEventHandler<EVAS_CALLBACK_FOCUS_OUT>::handleEvent(void* data, Evas*, Evas_Object*, void*)
196{
197    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
198    if (smartData->api->focus_out)
199        smartData->api->focus_out(smartData);
200}
201
202template <>
203void EwkViewEventHandler<EVAS_CALLBACK_MOUSE_WHEEL>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
204{
205    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
206    if (smartData->api->mouse_wheel)
207        smartData->api->mouse_wheel(smartData, static_cast<Evas_Event_Mouse_Wheel*>(eventInfo));
208}
209
210template <>
211void EwkViewEventHandler<EVAS_CALLBACK_KEY_DOWN>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
212{
213    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
214    if (smartData->api->key_down)
215        smartData->api->key_down(smartData, static_cast<Evas_Event_Key_Down*>(eventInfo));
216}
217
218template <>
219void EwkViewEventHandler<EVAS_CALLBACK_KEY_UP>::handleEvent(void* data, Evas*, Evas_Object*, void* eventInfo)
220{
221    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
222    if (smartData->api->key_up)
223        smartData->api->key_up(smartData, static_cast<Evas_Event_Key_Up*>(eventInfo));
224}
225
226template <>
227void EwkViewEventHandler<EVAS_CALLBACK_SHOW>::handleEvent(void* data, Evas*, Evas_Object*, void*)
228{
229    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
230    WKViewSetIsVisible(toEwkView(smartData)->wkView(), true);
231}
232
233template <>
234void EwkViewEventHandler<EVAS_CALLBACK_HIDE>::handleEvent(void* data, Evas*, Evas_Object*, void*)
235{
236    Ewk_View_Smart_Data* smartData = static_cast<Ewk_View_Smart_Data*>(data);
237    WKViewSetIsVisible(toEwkView(smartData)->wkView(), false);
238}
239
240typedef HashMap<WKPageRef, Evas_Object*> WKPageToEvasObjectMap;
241
242static inline WKPageToEvasObjectMap& wkPageToEvasObjectMap()
243{
244    DEFINE_STATIC_LOCAL(WKPageToEvasObjectMap, map, ());
245    return map;
246}
247
248// EwkView implementation.
249
250EwkView::EwkView(WKViewRef view, Evas_Object* evasObject)
251    : m_webView(view)
252    , m_evasObject(evasObject)
253    , m_context(EwkContext::findOrCreateWrapper(WKPageGetContext(wkPage())))
254    , m_pageGroup(EwkPageGroup::findOrCreateWrapper(WKPageGetPageGroup(wkPage())))
255#if USE(ACCELERATED_COMPOSITING)
256    , m_pendingSurfaceResize(false)
257#endif
258    , m_pageLoadClient(PageLoadClientEfl::create(this))
259    , m_pagePolicyClient(PagePolicyClientEfl::create(this))
260    , m_pageUIClient(PageUIClientEfl::create(this))
261    , m_contextMenuClient(ContextMenuClientEfl::create(this))
262    , m_findClient(FindClientEfl::create(this))
263    , m_formClient(FormClientEfl::create(this))
264    , m_viewClient(ViewClientEfl::create(this))
265#if ENABLE(VIBRATION)
266    , m_vibrationClient(VibrationClientEfl::create(this))
267#endif
268    , m_backForwardList(EwkBackForwardList::create(WKPageGetBackForwardList(wkPage())))
269    , m_settings(EwkSettings::create(this))
270    , m_cursorIdentifier(0)
271    , m_userAgent(WKEinaSharedString(AdoptWK, WKPageCopyUserAgent(wkPage())))
272    , m_mouseEventsEnabled(false)
273#if ENABLE(TOUCH_EVENTS)
274    , m_touchEventsEnabled(false)
275#endif
276    , m_displayTimer(this, &EwkView::displayTimerFired)
277    , m_inputMethodContext(InputMethodContextEfl::create(this, smartData()->base.evas))
278#if USE(ACCELERATED_COMPOSITING)
279    , m_pageViewportControllerClient(PageViewportControllerClientEfl::create(this))
280    , m_pageViewportController(adoptPtr(new PageViewportController(page(), m_pageViewportControllerClient.get())))
281#endif
282    , m_isAccelerated(true)
283{
284    ASSERT(m_evasObject);
285    ASSERT(m_context);
286
287    // FIXME: Remove when possible.
288    static_cast<WebViewEfl*>(webView())->setEwkView(this);
289#if USE(ACCELERATED_COMPOSITING)
290    m_evasGL = adoptPtr(evas_gl_new(evas_object_evas_get(m_evasObject)));
291    if (m_evasGL)
292        m_evasGLContext = EvasGLContext::create(m_evasGL.get());
293
294    if (!m_evasGLContext) {
295        WARN("Failed to create Evas_GL, falling back to software mode.");
296        m_isAccelerated = false;
297    }
298#endif
299    WKViewInitialize(wkView());
300
301    WKPageGroupRef wkPageGroup = WKPageGetPageGroup(wkPage());
302    WKPreferencesRef wkPreferences = WKPageGroupGetPreferences(wkPageGroup);
303#if USE(ACCELERATED_COMPOSITING)
304    WKPreferencesSetWebGLEnabled(wkPreferences, true);
305#endif
306    WKPreferencesSetFullScreenEnabled(wkPreferences, true);
307    WKPreferencesSetWebAudioEnabled(wkPreferences, true);
308    WKPreferencesSetOfflineWebApplicationCacheEnabled(wkPreferences, true);
309#if ENABLE(SPELLCHECK)
310    WKPreferencesSetAsynchronousSpellCheckingEnabled(wkPreferences, true);
311#endif
312    WKPreferencesSetInteractiveFormValidationEnabled(wkPreferences, true);
313
314    // Enable mouse events by default
315    setMouseEventsEnabled(true);
316
317    // Listen for favicon changes.
318    EwkFaviconDatabase* iconDatabase = m_context->faviconDatabase();
319    ASSERT(iconDatabase);
320
321    iconDatabase->watchChanges(IconChangeCallbackData(EwkView::handleFaviconChanged, this));
322
323    WKPageToEvasObjectMap::AddResult result = wkPageToEvasObjectMap().add(wkPage(), m_evasObject);
324    ASSERT_UNUSED(result, result.isNewEntry);
325}
326
327EwkView::~EwkView()
328{
329    // Unregister icon change callback.
330    EwkFaviconDatabase* iconDatabase = m_context->faviconDatabase();
331    ASSERT(iconDatabase);
332
333    iconDatabase->unwatchChanges(EwkView::handleFaviconChanged);
334
335    ASSERT(wkPageToEvasObjectMap().get(wkPage()) == m_evasObject);
336    wkPageToEvasObjectMap().remove(wkPage());
337}
338
339EwkView* EwkView::create(WKViewRef webView, Evas* canvas, Evas_Smart* smart)
340{
341    EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0);
342
343    Evas_Object* evasObject = evas_object_smart_add(canvas, smart ? smart : defaultSmartClassInstance());
344    EINA_SAFETY_ON_NULL_RETURN_VAL(evasObject, 0);
345
346    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
347    if (!smartData) {
348        evas_object_del(evasObject);
349        return 0;
350    }
351
352    ASSERT(!smartData->priv);
353
354    smartData->priv = new EwkView(webView, evasObject);
355
356    return smartData->priv;
357}
358
359bool EwkView::initSmartClassInterface(Ewk_View_Smart_Class& api)
360{
361    if (api.version != EWK_VIEW_SMART_CLASS_VERSION) {
362        EINA_LOG_CRIT("Ewk_View_Smart_Class %p is version %lu while %lu was expected.",
363            &api, api.version, EWK_VIEW_SMART_CLASS_VERSION);
364        return false;
365    }
366
367    if (!parentSmartClass.add)
368        evas_object_smart_clipped_smart_set(&parentSmartClass);
369
370    evas_object_smart_clipped_smart_set(&api.sc);
371
372    // Set Evas_Smart_Class callbacks.
373    api.sc.add = handleEvasObjectAdd;
374    api.sc.del = handleEvasObjectDelete;
375    api.sc.move = handleEvasObjectMove;
376    api.sc.resize = handleEvasObjectResize;
377    api.sc.show = handleEvasObjectShow;
378    api.sc.hide = handleEvasObjectHide;
379    api.sc.color_set = handleEvasObjectColorSet;
380    api.sc.calculate = handleEvasObjectCalculate;
381    api.sc.data = smartClassName; // It is used for type checking.
382
383    // Set Ewk_View_Smart_Class callbacks.
384    api.focus_in = handleEwkViewFocusIn;
385    api.focus_out = handleEwkViewFocusOut;
386    api.mouse_wheel = handleEwkViewMouseWheel;
387    api.mouse_down = handleEwkViewMouseDown;
388    api.mouse_up = handleEwkViewMouseUp;
389    api.mouse_move = handleEwkViewMouseMove;
390    api.key_down = handleEwkViewKeyDown;
391    api.key_up = handleEwkViewKeyUp;
392
393    return true;
394}
395
396Evas_Object* EwkView::toEvasObject(WKPageRef page)
397{
398    ASSERT(page);
399    return wkPageToEvasObjectMap().get(page);
400}
401
402WKPageRef EwkView::wkPage() const
403{
404    return WKViewGetPage(wkView());
405}
406
407void EwkView::setCursor(const Cursor& cursor)
408{
409    if (cursor.image()) {
410        // Custom cursor.
411        if (cursor.image() == m_cursorIdentifier)
412            return;
413
414        m_cursorIdentifier = cursor.image();
415
416        Ewk_View_Smart_Data* sd = smartData();
417        RefPtr<Evas_Object> cursorObject = adoptRef(cursor.image()->getEvasObject(sd->base.evas));
418        if (!cursorObject)
419            return;
420
421        // Resize cursor.
422        evas_object_resize(cursorObject.get(), cursor.image()->size().width(), cursor.image()->size().height());
423
424        // Get cursor hot spot.
425        IntPoint hotSpot;
426        cursor.image()->getHotSpot(hotSpot);
427
428        Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
429        // ecore_evas takes care of freeing the cursor object.
430        ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotSpot.x(), hotSpot.y());
431
432        return;
433    }
434
435    // Standard cursor.
436    const char* group = cursor.platformCursor();
437    if (!group || group == m_cursorIdentifier)
438        return;
439
440    m_cursorIdentifier = group;
441    Ewk_View_Smart_Data* sd = smartData();
442    RefPtr<Evas_Object> cursorObject = adoptRef(edje_object_add(sd->base.evas));
443
444    Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
445    if (!m_theme || !edje_object_file_set(cursorObject.get(), m_theme, group)) {
446        ecore_evas_object_cursor_set(ecoreEvas, 0, 0, 0, 0);
447#ifdef HAVE_ECORE_X
448        if (WebCore::isUsingEcoreX(sd->base.evas))
449            WebCore::applyFallbackCursor(ecoreEvas, group);
450#endif
451        return;
452    }
453
454    // Set cursor size.
455    Evas_Coord width, height;
456    edje_object_size_min_get(cursorObject.get(), &width, &height);
457    if (width <= 0 || height <= 0)
458        edje_object_size_min_calc(cursorObject.get(), &width, &height);
459    if (width <= 0 || height <= 0) {
460        width = defaultCursorSize;
461        height = defaultCursorSize;
462    }
463    evas_object_resize(cursorObject.get(), width, height);
464
465    // Get cursor hot spot.
466    const char* data;
467    int hotspotX = 0;
468    data = edje_object_data_get(cursorObject.get(), "hot.x");
469    if (data)
470        hotspotX = atoi(data);
471
472    int hotspotY = 0;
473    data = edje_object_data_get(cursorObject.get(), "hot.y");
474    if (data)
475        hotspotY = atoi(data);
476
477    // ecore_evas takes care of freeing the cursor object.
478    ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotspotX, hotspotY);
479}
480
481void EwkView::setDeviceScaleFactor(float scale)
482{
483    const WKSize& deviceSize = WKViewGetSize(wkView());
484    WKPageSetCustomBackingScaleFactor(wkPage(), scale);
485
486    // Update internal viewport size after device-scale change.
487    WKViewSetSize(wkView(), deviceSize);
488}
489
490float EwkView::deviceScaleFactor() const
491{
492    return WKPageGetBackingScaleFactor(wkPage());
493}
494
495AffineTransform EwkView::transformToScreen() const
496{
497    AffineTransform transform;
498
499    int windowGlobalX = 0;
500    int windowGlobalY = 0;
501
502    Ewk_View_Smart_Data* sd = smartData();
503
504#ifdef HAVE_ECORE_X
505    Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
506
507    Ecore_X_Window window;
508    window = ecore_evas_gl_x11_window_get(ecoreEvas);
509    // Fallback to software mode if necessary.
510    if (!window)
511        window = ecore_evas_software_x11_window_get(ecoreEvas); // Returns 0 if none.
512
513    int x, y; // x, y are relative to parent (in a reparenting window manager).
514    while (window) {
515        ecore_x_window_geometry_get(window, &x, &y, 0, 0);
516        windowGlobalX += x;
517        windowGlobalY += y;
518        window = ecore_x_window_parent_get(window);
519    }
520#endif
521
522    transform.translate(-sd->view.x, -sd->view.y);
523    transform.translate(windowGlobalX, windowGlobalY);
524
525    return transform;
526}
527
528inline Ewk_View_Smart_Data* EwkView::smartData() const
529{
530    return toSmartData(m_evasObject);
531}
532
533inline IntSize EwkView::size() const
534{
535    // WebPage expects a size in UI units, and not raw device units.
536    FloatSize uiSize = deviceSize();
537    uiSize.scale(1 / deviceScaleFactor());
538    return roundedIntSize(uiSize);
539}
540
541inline IntSize EwkView::deviceSize() const
542{
543    return toIntSize(WKViewGetSize(wkView()));
544}
545
546void EwkView::displayTimerFired(Timer<EwkView>*)
547{
548    Ewk_View_Smart_Data* sd = smartData();
549
550#if USE(ACCELERATED_COMPOSITING)
551    if (m_pendingSurfaceResize) {
552        // Create a GL surface here so that Evas has no chance of painting to an empty GL surface.
553        if (!createGLSurface())
554            return;
555        // Make Evas objects visible here in order not to paint empty Evas objects with black color.
556        showEvasObjectsIfNeeded(sd);
557
558        m_pendingSurfaceResize = false;
559    }
560#endif
561
562    if (!m_isAccelerated) {
563        RefPtr<cairo_surface_t> surface = createSurfaceForImage(sd->image);
564        if (!surface)
565            return;
566
567        WKViewPaintToCairoSurface(wkView(), surface.get());
568        evas_object_image_data_update_add(sd->image, 0, 0, sd->view.w, sd->view.h);
569        return;
570    }
571#if USE(ACCELERATED_COMPOSITING)
572    evas_gl_make_current(m_evasGL.get(), m_evasGLSurface->surface(), m_evasGLContext->context());
573
574    WKViewPaintToCurrentGLContext(wkView());
575#endif
576    // sd->image is tied to a native surface, which is in the parent's coordinates.
577    evas_object_image_data_update_add(sd->image, sd->view.x, sd->view.y, sd->view.w, sd->view.h);
578}
579
580void EwkView::scheduleUpdateDisplay()
581{
582    if (deviceSize().isEmpty())
583        return;
584
585    if (!m_displayTimer.isActive())
586        m_displayTimer.startOneShot(0);
587}
588
589#if ENABLE(FULLSCREEN_API)
590/**
591 * @internal
592 * Calls fullscreen_enter callback or falls back to default behavior and enables fullscreen mode.
593 */
594void EwkView::enterFullScreen()
595{
596    Ewk_View_Smart_Data* sd = smartData();
597
598    RefPtr<EwkSecurityOrigin> origin = EwkSecurityOrigin::create(m_url);
599
600    if (!sd->api->fullscreen_enter || !sd->api->fullscreen_enter(sd, origin.get())) {
601        Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
602        ecore_evas_fullscreen_set(ecoreEvas, true);
603    }
604}
605
606/**
607 * @internal
608 * Calls fullscreen_exit callback or falls back to default behavior and disables fullscreen mode.
609 */
610void EwkView::exitFullScreen()
611{
612    Ewk_View_Smart_Data* sd = smartData();
613
614    if (!sd->api->fullscreen_exit || !sd->api->fullscreen_exit(sd)) {
615        Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
616        ecore_evas_fullscreen_set(ecoreEvas, false);
617    }
618}
619#endif
620
621WKRect EwkView::windowGeometry() const
622{
623    Evas_Coord x, y, width, height;
624    Ewk_View_Smart_Data* sd = smartData();
625
626    if (!sd->api->window_geometry_get || !sd->api->window_geometry_get(sd, &x, &y, &width, &height)) {
627        Ecore_Evas* ee = ecore_evas_ecore_evas_get(sd->base.evas);
628        ecore_evas_request_geometry_get(ee, &x, &y, &width, &height);
629    }
630
631    return WKRectMake(x, y, width, height);
632}
633
634void EwkView::setWindowGeometry(const WKRect& rect)
635{
636    Ewk_View_Smart_Data* sd = smartData();
637
638    if (!sd->api->window_geometry_set || !sd->api->window_geometry_set(sd, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)) {
639        Ecore_Evas* ee = ecore_evas_ecore_evas_get(sd->base.evas);
640        ecore_evas_move_resize(ee, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
641    }
642}
643
644const char* EwkView::title() const
645{
646    m_title = WKEinaSharedString(AdoptWK, WKPageCopyTitle(wkPage()));
647
648    return m_title;
649}
650
651/**
652 * @internal
653 * This function may return @c NULL.
654 */
655InputMethodContextEfl* EwkView::inputMethodContext()
656{
657    return m_inputMethodContext.get();
658}
659
660const char* EwkView::themePath() const
661{
662    return m_theme;
663}
664
665void EwkView::setThemePath(const char* theme)
666{
667    if (m_theme != theme) {
668        m_theme = theme;
669        WKRetainPtr<WKStringRef> wkTheme = adoptWK(WKStringCreateWithUTF8CString(theme));
670        WKViewSetThemePath(wkView(), wkTheme.get());
671    }
672}
673
674void EwkView::setCustomTextEncodingName(const char* customEncoding)
675{
676    if (m_customEncoding == customEncoding)
677        return;
678
679    m_customEncoding = customEncoding;
680    WKRetainPtr<WKStringRef> wkCustomEncoding = adoptWK(WKStringCreateWithUTF8CString(customEncoding));
681    WKPageSetCustomTextEncodingName(wkPage(), wkCustomEncoding.get());
682}
683
684void EwkView::setUserAgent(const char* userAgent)
685{
686    if (m_userAgent == userAgent)
687        return;
688
689    WKRetainPtr<WKStringRef> wkUserAgent = adoptWK(WKStringCreateWithUTF8CString(userAgent));
690    WKPageSetCustomUserAgent(wkPage(), wkUserAgent.get());
691
692    // When 'userAgent' is 0, user agent is set as a standard user agent by WKPageSetCustomUserAgent()
693    // so m_userAgent needs to be updated using WKPageCopyUserAgent().
694    m_userAgent = WKEinaSharedString(AdoptWK, WKPageCopyUserAgent(wkPage()));
695}
696
697void EwkView::setMouseEventsEnabled(bool enabled)
698{
699    if (m_mouseEventsEnabled == enabled)
700        return;
701
702    m_mouseEventsEnabled = enabled;
703    if (enabled) {
704        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_DOWN>::subscribe(m_evasObject);
705        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_UP>::subscribe(m_evasObject);
706        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_MOVE>::subscribe(m_evasObject);
707    } else {
708        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_DOWN>::unsubscribe(m_evasObject);
709        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_UP>::unsubscribe(m_evasObject);
710        EwkViewEventHandler<EVAS_CALLBACK_MOUSE_MOVE>::unsubscribe(m_evasObject);
711    }
712}
713
714#if ENABLE(TOUCH_EVENTS)
715void EwkView::feedTouchEvent(Ewk_Touch_Event_Type type, const Eina_List* points, const Evas_Modifier* modifiers)
716{
717    page()->handleTouchEvent(NativeWebTouchEvent(type, points, modifiers, webView()->transformFromScene(), transformToScreen(), ecore_time_get()));
718}
719
720void EwkView::setTouchEventsEnabled(bool enabled)
721{
722    if (m_touchEventsEnabled == enabled)
723        return;
724
725    m_touchEventsEnabled = enabled;
726
727    if (enabled) {
728        // FIXME: We have to connect touch callbacks with mouse and multi events
729        // because the Evas creates mouse events for first touch and multi events
730        // for second and third touches. Below codes should be fixed when the Evas
731        // supports the touch events.
732        // See https://bugs.webkit.org/show_bug.cgi?id=97785 for details.
733        Ewk_View_Smart_Data* sd = smartData();
734        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MOUSE_DOWN, handleTouchDown, sd);
735        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MOUSE_UP, handleTouchUp, sd);
736        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MOUSE_MOVE, handleTouchMove, sd);
737        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MULTI_DOWN, handleTouchDown, sd);
738        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MULTI_UP, handleTouchUp, sd);
739        evas_object_event_callback_add(m_evasObject, EVAS_CALLBACK_MULTI_MOVE, handleTouchMove, sd);
740    } else {
741        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MOUSE_DOWN, handleTouchDown);
742        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MOUSE_UP, handleTouchUp);
743        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MOUSE_MOVE, handleTouchMove);
744        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MULTI_DOWN, handleTouchDown);
745        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MULTI_UP, handleTouchUp);
746        evas_object_event_callback_del(m_evasObject, EVAS_CALLBACK_MULTI_MOVE, handleTouchMove);
747    }
748}
749#endif
750
751#if USE(ACCELERATED_COMPOSITING)
752bool EwkView::createGLSurface()
753{
754    if (!m_isAccelerated)
755        return true;
756
757    static Evas_GL_Config evasGLConfig = {
758        EVAS_GL_RGBA_8888,
759        EVAS_GL_DEPTH_BIT_8,
760        EVAS_GL_STENCIL_NONE,
761        EVAS_GL_OPTIONS_NONE,
762        EVAS_GL_MULTISAMPLE_NONE
763    };
764
765    // Recreate to current size: Replaces if non-null, and frees existing surface after (OwnPtr).
766    m_evasGLSurface = EvasGLSurface::create(m_evasGL.get(), &evasGLConfig, deviceSize());
767    if (!m_evasGLSurface)
768        return false;
769
770    Evas_Native_Surface nativeSurface;
771    evas_gl_native_surface_get(m_evasGL.get(), m_evasGLSurface->surface(), &nativeSurface);
772    evas_object_image_native_surface_set(smartData()->image, &nativeSurface);
773
774    evas_gl_make_current(m_evasGL.get(), m_evasGLSurface->surface(), m_evasGLContext->context());
775
776    Evas_GL_API* gl = evas_gl_api_get(m_evasGL.get());
777
778    WKPoint boundsEnd = WKViewUserViewportToScene(wkView(), WKPointMake(deviceSize().width(), deviceSize().height()));
779    gl->glViewport(0, 0, boundsEnd.x, boundsEnd.y);
780    gl->glClearColor(1.0, 1.0, 1.0, 0);
781    gl->glClear(GL_COLOR_BUFFER_BIT);
782
783    return true;
784}
785#endif
786
787#if ENABLE(INPUT_TYPE_COLOR)
788/**
789 * @internal
790 * Requests to show external color picker.
791 */
792void EwkView::requestColorPicker(WKColorPickerResultListenerRef listener, const WebCore::Color& color)
793{
794    Ewk_View_Smart_Data* sd = smartData();
795    EINA_SAFETY_ON_NULL_RETURN(sd->api->input_picker_color_request);
796
797    if (!sd->api->input_picker_color_request)
798        return;
799
800    if (m_colorPicker)
801        dismissColorPicker();
802
803    m_colorPicker = EwkColorPicker::create(listener, color);
804
805    sd->api->input_picker_color_request(sd, m_colorPicker.get());
806}
807
808/**
809 * @internal
810 * Requests to hide external color picker.
811 */
812void EwkView::dismissColorPicker()
813{
814    if (!m_colorPicker)
815        return;
816
817    Ewk_View_Smart_Data* sd = smartData();
818    EINA_SAFETY_ON_NULL_RETURN(sd->api->input_picker_color_dismiss);
819
820    if (sd->api->input_picker_color_dismiss)
821        sd->api->input_picker_color_dismiss(sd);
822
823    m_colorPicker.clear();
824}
825#endif
826
827COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_RIGHT_TO_LEFT, RTL);
828COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_LEFT_TO_RIGHT, LTR);
829
830void EwkView::customContextMenuItemSelected(WKContextMenuItemRef contextMenuItem)
831{
832    Ewk_View_Smart_Data* sd = smartData();
833    ASSERT(sd->api);
834
835    if (!sd->api->custom_item_selected)
836        return;
837
838    OwnPtr<EwkContextMenuItem> item = EwkContextMenuItem::create(contextMenuItem, 0);
839
840    sd->api->custom_item_selected(sd, item.get());
841}
842
843void EwkView::showContextMenu(WKPoint position, WKArrayRef items)
844{
845    Ewk_View_Smart_Data* sd = smartData();
846    ASSERT(sd->api);
847
848    if (!sd->api->context_menu_show)
849        return;
850
851    if (m_contextMenu)
852        hideContextMenu();
853
854    m_contextMenu = EwkContextMenu::create(this, items);
855
856    position = WKViewContentsToUserViewport(wkView(), position);
857
858    sd->api->context_menu_show(sd, position.x, position.y, m_contextMenu.get());
859}
860
861void EwkView::hideContextMenu()
862{
863    if (!m_contextMenu)
864        return;
865
866    Ewk_View_Smart_Data* sd = smartData();
867    ASSERT(sd->api);
868
869    if (sd->api->context_menu_hide)
870        sd->api->context_menu_hide(sd);
871
872    m_contextMenu.clear();
873}
874
875COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_RIGHT_TO_LEFT, kWKPopupItemTextDirectionRTL);
876COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_LEFT_TO_RIGHT, kWKPopupItemTextDirectionLTR);
877
878void EwkView::requestPopupMenu(WKPopupMenuListenerRef popupMenuListener, const WKRect& rect, WKPopupItemTextDirection textDirection, double pageScaleFactor, WKArrayRef items, int32_t selectedIndex)
879{
880    Ewk_View_Smart_Data* sd = smartData();
881    ASSERT(sd->api);
882
883    ASSERT(popupMenuListener);
884
885    if (!sd->api->popup_menu_show)
886        return;
887
888    if (m_popupMenu)
889        closePopupMenu();
890
891    m_popupMenu = EwkPopupMenu::create(this, popupMenuListener, items, selectedIndex);
892
893    WKPoint popupMenuPosition = WKViewContentsToUserViewport(wkView(), rect.origin);
894
895    Eina_Rectangle einaRect;
896    EINA_RECTANGLE_SET(&einaRect, popupMenuPosition.x, popupMenuPosition.y, rect.size.width, rect.size.height);
897
898    sd->api->popup_menu_show(sd, einaRect, static_cast<Ewk_Text_Direction>(textDirection), pageScaleFactor, m_popupMenu.get());
899}
900
901void EwkView::closePopupMenu()
902{
903    if (!m_popupMenu)
904        return;
905
906    Ewk_View_Smart_Data* sd = smartData();
907    ASSERT(sd->api);
908
909    if (sd->api->popup_menu_hide)
910        sd->api->popup_menu_hide(sd);
911
912    m_popupMenu.clear();
913}
914
915/**
916 * @internal
917 * Calls a smart member function for javascript alert().
918 */
919void EwkView::requestJSAlertPopup(const WKEinaSharedString& message)
920{
921    Ewk_View_Smart_Data* sd = smartData();
922    ASSERT(sd->api);
923
924    if (!sd->api->run_javascript_alert)
925        return;
926
927    sd->api->run_javascript_alert(sd, message);
928}
929
930/**
931 * @internal
932 * Calls a smart member function for javascript confirm() and returns a value from the function. Returns false by default.
933 */
934bool EwkView::requestJSConfirmPopup(const WKEinaSharedString& message)
935{
936    Ewk_View_Smart_Data* sd = smartData();
937    ASSERT(sd->api);
938
939    if (!sd->api->run_javascript_confirm)
940        return false;
941
942    return sd->api->run_javascript_confirm(sd, message);
943}
944
945/**
946 * @internal
947 * Calls a smart member function for javascript prompt() and returns a value from the function. Returns null string by default.
948 */
949WKEinaSharedString EwkView::requestJSPromptPopup(const WKEinaSharedString& message, const WKEinaSharedString& defaultValue)
950{
951    Ewk_View_Smart_Data* sd = smartData();
952    ASSERT(sd->api);
953
954    if (!sd->api->run_javascript_prompt)
955        return WKEinaSharedString();
956
957    return WKEinaSharedString::adopt(sd->api->run_javascript_prompt(sd, message, defaultValue));
958}
959
960#if ENABLE(SQL_DATABASE)
961/**
962 * @internal
963 * Calls exceeded_database_quota callback or falls back to default behavior returns default database quota.
964 */
965unsigned long long EwkView::informDatabaseQuotaReached(const String& databaseName, const String& displayName, unsigned long long currentQuota, unsigned long long currentOriginUsage, unsigned long long currentDatabaseUsage, unsigned long long expectedUsage)
966{
967    Ewk_View_Smart_Data* sd = smartData();
968    ASSERT(sd->api);
969
970    static const unsigned long long defaultQuota = 5 * 1024 * 1204; // 5 MB
971    if (sd->api->exceeded_database_quota)
972        return sd->api->exceeded_database_quota(sd, databaseName.utf8().data(), displayName.utf8().data(), currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage);
973
974    return defaultQuota;
975}
976#endif
977
978WebView* EwkView::webView()
979{
980    return toImpl(m_webView.get());
981}
982
983/**
984 * @internal
985 * The url of view was changed by the frame loader.
986 *
987 * Emits signal: "url,changed" with pointer to new url string.
988 */
989void EwkView::informURLChange()
990{
991    WKRetainPtr<WKURLRef> wkActiveURL = adoptWK(WKPageCopyActiveURL(wkPage()));
992    WKRetainPtr<WKStringRef> wkURLString = wkActiveURL ? adoptWK(WKURLCopyString(wkActiveURL.get())) : adoptWK(WKStringCreateWithUTF8CString(""));
993
994    if (WKStringIsEqualToUTF8CString(wkURLString.get(), m_url))
995        return;
996
997    m_url = WKEinaSharedString(wkURLString.get());
998    smartCallback<URLChanged>().call(m_url);
999
1000    // Update the view's favicon.
1001    smartCallback<FaviconChanged>().call();
1002}
1003
1004Evas_Object* EwkView::createFavicon() const
1005{
1006    EwkFaviconDatabase* iconDatabase = m_context->faviconDatabase();
1007    ASSERT(iconDatabase);
1008
1009    return ewk_favicon_database_icon_get(iconDatabase, m_url, smartData()->base.evas);
1010}
1011
1012EwkWindowFeatures* EwkView::windowFeatures()
1013{
1014    if (!m_windowFeatures)
1015        m_windowFeatures = EwkWindowFeatures::create(0, this);
1016
1017    return m_windowFeatures.get();
1018}
1019
1020WKPageRef EwkView::createNewPage(PassRefPtr<EwkUrlRequest> request, WKDictionaryRef windowFeatures)
1021{
1022    Ewk_View_Smart_Data* sd = smartData();
1023    ASSERT(sd->api);
1024
1025    if (!sd->api->window_create)
1026        return 0;
1027
1028    RefPtr<EwkWindowFeatures> ewkWindowFeatures = EwkWindowFeatures::create(windowFeatures, this);
1029
1030    Evas_Object* newEwkView = sd->api->window_create(sd, request->url(), ewkWindowFeatures.get());
1031    if (!newEwkView)
1032        return 0;
1033
1034    EwkView* newViewImpl = toEwkView(newEwkView);
1035    ASSERT(newViewImpl);
1036
1037    newViewImpl->m_windowFeatures = ewkWindowFeatures;
1038
1039    return static_cast<WKPageRef>(WKRetain(newViewImpl->page()));
1040}
1041
1042void EwkView::close()
1043{
1044    Ewk_View_Smart_Data* sd = smartData();
1045    ASSERT(sd->api);
1046
1047    if (!sd->api->window_close)
1048        return;
1049
1050    sd->api->window_close(sd);
1051}
1052
1053void EwkView::handleEvasObjectAdd(Evas_Object* evasObject)
1054{
1055    const Evas_Smart* smart = evas_object_smart_smart_get(evasObject);
1056    const Evas_Smart_Class* smartClass = evas_smart_class_get(smart);
1057    const Ewk_View_Smart_Class* api = reinterpret_cast<const Ewk_View_Smart_Class*>(smartClass);
1058    ASSERT(api);
1059
1060    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1061
1062    if (!smartData) {
1063        // Allocating with 'calloc' as the API contract is that it should be deleted with 'free()'.
1064        smartData = static_cast<Ewk_View_Smart_Data*>(calloc(1, sizeof(Ewk_View_Smart_Data)));
1065        evas_object_smart_data_set(evasObject, smartData);
1066    }
1067
1068    smartData->self = evasObject;
1069    smartData->api = api;
1070
1071    parentSmartClass.add(evasObject);
1072
1073    smartData->priv = 0; // Will be initialized further.
1074
1075    // Create evas_object_image to draw web contents.
1076    smartData->image = evas_object_image_add(smartData->base.evas);
1077    evas_object_image_alpha_set(smartData->image, false);
1078    evas_object_image_filled_set(smartData->image, true);
1079    evas_object_smart_member_add(smartData->image, evasObject);
1080    evas_object_show(smartData->image);
1081
1082    EwkViewEventHandler<EVAS_CALLBACK_FOCUS_IN>::subscribe(evasObject);
1083    EwkViewEventHandler<EVAS_CALLBACK_FOCUS_OUT>::subscribe(evasObject);
1084    EwkViewEventHandler<EVAS_CALLBACK_MOUSE_WHEEL>::subscribe(evasObject);
1085    EwkViewEventHandler<EVAS_CALLBACK_KEY_DOWN>::subscribe(evasObject);
1086    EwkViewEventHandler<EVAS_CALLBACK_KEY_UP>::subscribe(evasObject);
1087    EwkViewEventHandler<EVAS_CALLBACK_SHOW>::subscribe(evasObject);
1088    EwkViewEventHandler<EVAS_CALLBACK_HIDE>::subscribe(evasObject);
1089}
1090
1091void EwkView::handleEvasObjectDelete(Evas_Object* evasObject)
1092{
1093    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1094    if (smartData) {
1095        ASSERT(smartData->priv); // smartData->priv is EwkView instance.
1096        delete smartData->priv;
1097    }
1098
1099    parentSmartClass.del(evasObject);
1100}
1101
1102void EwkView::handleEvasObjectResize(Evas_Object* evasObject, Evas_Coord width, Evas_Coord height)
1103{
1104    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1105    ASSERT(smartData);
1106
1107    evas_object_resize(smartData->image, width, height);
1108    evas_object_image_size_set(smartData->image, width, height);
1109    evas_object_image_fill_set(smartData->image, 0, 0, width, height);
1110
1111    smartData->changed.size = true;
1112    smartDataChanged(smartData);
1113}
1114
1115void EwkView::handleEvasObjectMove(Evas_Object* evasObject, Evas_Coord /*x*/, Evas_Coord /*y*/)
1116{
1117    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1118    ASSERT(smartData);
1119
1120    smartData->changed.position = true;
1121    smartDataChanged(smartData);
1122}
1123
1124void EwkView::handleEvasObjectCalculate(Evas_Object* evasObject)
1125{
1126    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1127    ASSERT(smartData);
1128
1129    EwkView* self = toEwkView(smartData);
1130
1131    smartData->changed.any = false;
1132
1133    Evas_Coord x, y, width, height;
1134    evas_object_geometry_get(evasObject, &x, &y, &width, &height);
1135
1136    if (smartData->changed.position) {
1137        smartData->changed.position = false;
1138        smartData->view.x = x;
1139        smartData->view.y = y;
1140        evas_object_move(smartData->image, x, y);
1141        WKViewSetUserViewportTranslation(self->wkView(), x, y);
1142    }
1143
1144    if (smartData->changed.size) {
1145        smartData->changed.size = false;
1146        smartData->view.w = width;
1147        smartData->view.h = height;
1148
1149        WKViewSetSize(self->wkView(), WKSizeMake(width, height));
1150#if USE(ACCELERATED_COMPOSITING)
1151        if (WKPageUseFixedLayout(self->wkPage()))
1152            self->pageViewportController()->didChangeViewportSize(self->size());
1153
1154        self->setNeedsSurfaceResize();
1155#endif
1156    }
1157}
1158
1159void EwkView::handleEvasObjectShow(Evas_Object* evasObject)
1160{
1161    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1162    ASSERT(smartData);
1163
1164    if (!toEwkView(smartData)->m_isAccelerated)
1165        showEvasObjectsIfNeeded(smartData);
1166}
1167
1168void EwkView::handleEvasObjectHide(Evas_Object* evasObject)
1169{
1170    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1171    ASSERT(smartData);
1172
1173    evas_object_hide(smartData->base.clipper);
1174    evas_object_hide(smartData->image);
1175}
1176
1177void EwkView::handleEvasObjectColorSet(Evas_Object* evasObject, int red, int green, int blue, int alpha)
1178{
1179    Ewk_View_Smart_Data* smartData = toSmartData(evasObject);
1180    ASSERT(smartData);
1181
1182    EwkView* view = toEwkView(smartData);
1183    ASSERT(view);
1184
1185    alpha = clampTo(alpha, 0, 255);
1186    red = clampTo(red, 0, alpha);
1187    green = clampTo(green, 0, alpha);
1188    blue = clampTo(blue, 0, alpha);
1189
1190    evas_object_image_alpha_set(smartData->image, alpha < 255);
1191    WKViewSetDrawsBackground(view->wkView(), red || green || blue);
1192    WKViewSetDrawsTransparentBackground(view->wkView(), alpha < 255);
1193
1194    parentSmartClass.color_set(evasObject, red, green, blue, alpha);
1195}
1196
1197Eina_Bool EwkView::handleEwkViewFocusIn(Ewk_View_Smart_Data* smartData)
1198{
1199    WKViewSetIsFocused(toEwkView(smartData)->wkView(), true);
1200    return true;
1201}
1202
1203Eina_Bool EwkView::handleEwkViewFocusOut(Ewk_View_Smart_Data* smartData)
1204{
1205    WKViewSetIsFocused(toEwkView(smartData)->wkView(), false);
1206    return true;
1207}
1208
1209Eina_Bool EwkView::handleEwkViewMouseWheel(Ewk_View_Smart_Data* smartData, const Evas_Event_Mouse_Wheel* wheelEvent)
1210{
1211    EwkView* self = toEwkView(smartData);
1212    self->page()->handleWheelEvent(NativeWebWheelEvent(wheelEvent, self->webView()->transformFromScene(), self->transformToScreen()));
1213    return true;
1214}
1215
1216Eina_Bool EwkView::handleEwkViewMouseDown(Ewk_View_Smart_Data* smartData, const Evas_Event_Mouse_Down* downEvent)
1217{
1218    EwkView* self = toEwkView(smartData);
1219    self->page()->handleMouseEvent(NativeWebMouseEvent(downEvent, self->webView()->transformFromScene(), self->transformToScreen()));
1220    return true;
1221}
1222
1223Eina_Bool EwkView::handleEwkViewMouseUp(Ewk_View_Smart_Data* smartData, const Evas_Event_Mouse_Up* upEvent)
1224{
1225    EwkView* self = toEwkView(smartData);
1226    self->page()->handleMouseEvent(NativeWebMouseEvent(upEvent, self->webView()->transformFromScene(), self->transformToScreen()));
1227
1228    if (InputMethodContextEfl* inputMethodContext = self->inputMethodContext())
1229        inputMethodContext->handleMouseUpEvent(upEvent);
1230
1231    return true;
1232}
1233
1234Eina_Bool EwkView::handleEwkViewMouseMove(Ewk_View_Smart_Data* smartData, const Evas_Event_Mouse_Move* moveEvent)
1235{
1236    EwkView* self = toEwkView(smartData);
1237    self->page()->handleMouseEvent(NativeWebMouseEvent(moveEvent, self->webView()->transformFromScene(), self->transformToScreen()));
1238    return true;
1239}
1240
1241Eina_Bool EwkView::handleEwkViewKeyDown(Ewk_View_Smart_Data* smartData, const Evas_Event_Key_Down* downEvent)
1242{
1243    bool isFiltered = false;
1244    EwkView* self = toEwkView(smartData);
1245    if (InputMethodContextEfl* inputMethodContext = self->inputMethodContext())
1246        inputMethodContext->handleKeyDownEvent(downEvent, &isFiltered);
1247
1248    self->page()->handleKeyboardEvent(NativeWebKeyboardEvent(downEvent, isFiltered));
1249    return true;
1250}
1251
1252Eina_Bool EwkView::handleEwkViewKeyUp(Ewk_View_Smart_Data* smartData, const Evas_Event_Key_Up* upEvent)
1253{
1254    toEwkView(smartData)->page()->handleKeyboardEvent(NativeWebKeyboardEvent(upEvent));
1255    return true;
1256}
1257
1258#if ENABLE(TOUCH_EVENTS)
1259void EwkView::feedTouchEvents(Ewk_Touch_Event_Type type)
1260{
1261    Ewk_View_Smart_Data* sd = smartData();
1262
1263    unsigned count = evas_touch_point_list_count(sd->base.evas);
1264    if (!count)
1265        return;
1266
1267    Eina_List* points = 0;
1268    for (unsigned i = 0; i < count; ++i) {
1269        Ewk_Touch_Point* point = new Ewk_Touch_Point;
1270        point->id = evas_touch_point_list_nth_id_get(sd->base.evas, i);
1271        evas_touch_point_list_nth_xy_get(sd->base.evas, i, &point->x, &point->y);
1272        point->state = evas_touch_point_list_nth_state_get(sd->base.evas, i);
1273        points = eina_list_append(points, point);
1274    }
1275
1276    feedTouchEvent(type, points, evas_key_modifier_get(sd->base.evas));
1277
1278    void* data;
1279    EINA_LIST_FREE(points, data)
1280        delete static_cast<Ewk_Touch_Point*>(data);
1281}
1282
1283void EwkView::handleTouchDown(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
1284{
1285    toEwkView(ewkView)->feedTouchEvents(EWK_TOUCH_START);
1286}
1287
1288void EwkView::handleTouchUp(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
1289{
1290    toEwkView(ewkView)->feedTouchEvents(EWK_TOUCH_END);
1291}
1292
1293void EwkView::handleTouchMove(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
1294{
1295    toEwkView(ewkView)->feedTouchEvents(EWK_TOUCH_MOVE);
1296}
1297#endif
1298
1299void EwkView::handleFaviconChanged(const char* pageURL, void* eventInfo)
1300{
1301    EwkView* view = static_cast<EwkView*>(eventInfo);
1302
1303    if (!view->url() || strcasecmp(view->url(), pageURL))
1304        return;
1305
1306    view->smartCallback<FaviconChanged>().call();
1307}
1308
1309PassRefPtr<cairo_surface_t> EwkView::takeSnapshot()
1310{
1311    // Suspend all animations before taking the snapshot.
1312    WKViewSuspendActiveDOMObjectsAndAnimations(wkView());
1313
1314    // Wait for the pending repaint events to be processed.
1315    while (m_displayTimer.isActive())
1316        ecore_main_loop_iterate();
1317
1318    Ewk_View_Smart_Data* sd = smartData();
1319#if USE(ACCELERATED_COMPOSITING)
1320    if (m_isAccelerated) {
1321        RefPtr<cairo_surface_t> snapshot = getImageSurfaceFromFrameBuffer(0, 0, sd->view.w, sd->view.h);
1322        // Resume all animations.
1323        WKViewResumeActiveDOMObjectsAndAnimations(wkView());
1324
1325        return snapshot.release();
1326    }
1327#endif
1328    RefPtr<cairo_surface_t> snapshot = createSurfaceForImage(sd->image);
1329    // Resume all animations.
1330    WKViewResumeActiveDOMObjectsAndAnimations(wkView());
1331
1332    return snapshot.release();
1333}
1334
1335Evas_Smart_Class EwkView::parentSmartClass = EVAS_SMART_CLASS_INIT_NULL;
1336
1337// Free Ewk View functions.
1338
1339EwkView* toEwkView(const Evas_Object* evasObject)
1340{
1341    ASSERT(evasObject);
1342    ASSERT(isEwkViewEvasObject(evasObject));
1343
1344    return toEwkView(static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(evasObject)));
1345}
1346
1347bool isEwkViewEvasObject(const Evas_Object* evasObject)
1348{
1349    ASSERT(evasObject);
1350
1351    const char* evasObjectType = evas_object_type_get(evasObject);
1352    const Evas_Smart* evasSmart = evas_object_smart_smart_get(evasObject);
1353    if (!evasSmart) {
1354        EINA_LOG_CRIT("%p (%s) is not a smart object!", evasObject, evasObjectType ? evasObjectType : "(null)");
1355        return false;
1356    }
1357
1358    const Evas_Smart_Class* smartClass = evas_smart_class_get(evasSmart);
1359    if (!smartClass) {
1360        EINA_LOG_CRIT("%p (%s) is not a smart class object!", evasObject, evasObjectType ? evasObjectType : "(null)");
1361        return false;
1362    }
1363
1364    if (smartClass->data != smartClassName) {
1365        EINA_LOG_CRIT("%p (%s) is not of an ewk_view (need %p, got %p)!", evasObject, evasObjectType ? evasObjectType : "(null)",
1366            smartClassName, smartClass->data);
1367        return false;
1368    }
1369
1370    return true;
1371}
1372