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