blob: 2a5d9a210418b1042fcf1b647c9a2cc75dff1628 [file] [log] [blame]
/*
Copyright (C) 2011 Samsung Electronics
Copyright (C) 2012 Intel Corporation. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "EwkViewImpl.h"
#include "EflScreenUtilities.h"
#include "FindClientEfl.h"
#include "FormClientEfl.h"
#include "InputMethodContextEfl.h"
#include "LayerTreeCoordinatorProxy.h"
#include "LayerTreeRenderer.h"
#include "PageClientBase.h"
#include "PageClientDefaultImpl.h"
#include "PageClientLegacyImpl.h"
#include "PageLoadClientEfl.h"
#include "PagePolicyClientEfl.h"
#include "PageUIClientEfl.h"
#include "ResourceLoadClientEfl.h"
#include "WKDictionary.h"
#include "WKGeometry.h"
#include "WKNumber.h"
#include "WKString.h"
#include "WebContext.h"
#include "WebPageGroup.h"
#include "WebPageProxy.h"
#include "WebPopupMenuProxyEfl.h"
#include "WebPreferences.h"
#include "ewk_back_forward_list_private.h"
#include "ewk_color_picker_private.h"
#include "ewk_context_private.h"
#include "ewk_favicon_database_private.h"
#include "ewk_popup_menu_item_private.h"
#include "ewk_popup_menu_private.h"
#include "ewk_private.h"
#include "ewk_security_origin_private.h"
#include "ewk_settings_private.h"
#include "ewk_view.h"
#include "ewk_view_private.h"
#include <Ecore_Evas.h>
#include <Ecore_X.h>
#include <Edje.h>
#include <WebCore/CairoUtilitiesEfl.h>
#include <WebCore/Cursor.h>
#if ENABLE(VIBRATION)
#include "VibrationClientEfl.h"
#endif
#if ENABLE(FULLSCREEN_API)
#include "WebFullScreenManagerProxy.h"
#endif
#if USE(ACCELERATED_COMPOSITING)
#include <Evas_GL.h>
#endif
using namespace EwkViewCallbacks;
using namespace WebCore;
using namespace WebKit;
static const int defaultCursorSize = 16;
typedef HashMap<WKPageRef, Evas_Object*> PageViewMap;
static inline PageViewMap& pageViewMap()
{
DEFINE_STATIC_LOCAL(PageViewMap, map, ());
return map;
}
void EwkViewImpl::addToPageViewMap(EwkViewImpl* viewImpl)
{
PageViewMap::AddResult result = pageViewMap().add(viewImpl->wkPage(), viewImpl->view());
ASSERT_UNUSED(result, result.isNewEntry);
}
void EwkViewImpl::removeFromPageViewMap(EwkViewImpl* viewImpl)
{
ASSERT(pageViewMap().contains(viewImpl->wkPage()));
pageViewMap().remove(viewImpl->wkPage());
}
const Evas_Object* EwkViewImpl::viewFromPageViewMap(const WKPageRef page)
{
ASSERT(page);
return pageViewMap().get(page);
}
EwkViewImpl::EwkViewImpl(Evas_Object* view, PassRefPtr<EwkContext> context, PassRefPtr<WebPageGroup> pageGroup, ViewBehavior behavior)
: m_view(view)
, m_context(context)
, m_pageClient(behavior == DefaultBehavior ? PageClientDefaultImpl::create(this) : PageClientLegacyImpl::create(this))
, m_pageProxy(m_context->webContext()->createWebPage(m_pageClient.get(), pageGroup.get()))
, m_pageLoadClient(PageLoadClientEfl::create(this))
, m_pagePolicyClient(PagePolicyClientEfl::create(this))
, m_pageUIClient(PageUIClientEfl::create(this))
, m_resourceLoadClient(ResourceLoadClientEfl::create(this))
, m_findClient(FindClientEfl::create(this))
, m_formClient(FormClientEfl::create(this))
#if ENABLE(VIBRATION)
, m_vibrationClient(VibrationClientEfl::create(this))
#endif
, m_backForwardList(Ewk_Back_Forward_List::create(toAPI(m_pageProxy->backForwardList())))
#if USE(TILED_BACKING_STORE)
, m_scaleFactor(1)
#endif
, m_settings(Ewk_Settings::create(this))
, m_cursorIdentifier(0)
, m_mouseEventsEnabled(false)
#if ENABLE(TOUCH_EVENTS)
, m_touchEventsEnabled(false)
#endif
, m_displayTimer(this, &EwkViewImpl::displayTimerFired)
, m_inputMethodContext(InputMethodContextEfl::create(this, smartData()->base.evas))
, m_isHardwareAccelerated(true)
{
ASSERT(m_view);
ASSERT(m_context);
ASSERT(m_pageProxy);
#if USE(COORDINATED_GRAPHICS)
m_pageProxy->pageGroup()->preferences()->setAcceleratedCompositingEnabled(true);
m_pageProxy->pageGroup()->preferences()->setForceCompositingMode(true);
#if ENABLE(WEBGL)
m_pageProxy->pageGroup()->preferences()->setWebGLEnabled(true);
#endif
if (behavior == DefaultBehavior)
m_pageProxy->setUseFixedLayout(true);
#endif
m_pageProxy->initializeWebPage();
#if ENABLE(FULLSCREEN_API)
m_pageProxy->fullScreenManager()->setWebView(m_view);
m_pageProxy->pageGroup()->preferences()->setFullScreenEnabled(true);
#endif
m_pageProxy->pageGroup()->preferences()->setOfflineWebApplicationCacheEnabled(true);
// Enable mouse events by default
setMouseEventsEnabled(true);
// Listen for favicon changes.
Ewk_Favicon_Database* iconDatabase = m_context->faviconDatabase();
ASSERT(iconDatabase);
iconDatabase->watchChanges(IconChangeCallbackData(EwkViewImpl::onFaviconChanged, this));
EwkViewImpl::addToPageViewMap(this);
}
EwkViewImpl::~EwkViewImpl()
{
m_pageProxy->close();
// Unregister icon change callback.
Ewk_Favicon_Database* iconDatabase = m_context->faviconDatabase();
ASSERT(iconDatabase);
iconDatabase->unwatchChanges(EwkViewImpl::onFaviconChanged);
EwkViewImpl::removeFromPageViewMap(this);
}
Ewk_View_Smart_Data* EwkViewImpl::smartData() const
{
return static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(m_view));
}
EwkViewImpl* EwkViewImpl::fromEvasObject(const Evas_Object* view)
{
ASSERT(view);
Ewk_View_Smart_Data* sd = static_cast<Ewk_View_Smart_Data*>(evas_object_smart_data_get(view));
ASSERT(sd);
ASSERT(sd->priv);
return sd->priv;
}
/**
* @internal
* Retrieves the internal WKPage for this view.
*/
WKPageRef EwkViewImpl::wkPage()
{
return toAPI(m_pageProxy.get());
}
void EwkViewImpl::setCursor(const Cursor& cursor)
{
if (cursor.image()) {
// Custom cursor.
if (cursor.image() == m_cursorIdentifier)
return;
m_cursorIdentifier = cursor.image();
Ewk_View_Smart_Data* sd = smartData();
RefPtr<Evas_Object> cursorObject = adoptRef(cursor.image()->getEvasObject(sd->base.evas));
if (!cursorObject)
return;
// Resize cursor.
evas_object_resize(cursorObject.get(), cursor.image()->size().width(), cursor.image()->size().height());
// Get cursor hot spot.
IntPoint hotSpot;
cursor.image()->getHotSpot(hotSpot);
Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
// ecore_evas takes care of freeing the cursor object.
ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotSpot.x(), hotSpot.y());
return;
}
// Standard cursor.
const char* group = cursor.platformCursor();
if (!group || group == m_cursorIdentifier)
return;
m_cursorIdentifier = group;
Ewk_View_Smart_Data* sd = smartData();
RefPtr<Evas_Object> cursorObject = adoptRef(edje_object_add(sd->base.evas));
Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
if (!m_theme || !edje_object_file_set(cursorObject.get(), m_theme, group)) {
ecore_evas_object_cursor_set(ecoreEvas, 0, 0, 0, 0);
#ifdef HAVE_ECORE_X
if (WebCore::isUsingEcoreX(sd->base.evas))
WebCore::applyFallbackCursor(ecoreEvas, group);
#endif
return;
}
// Set cursor size.
Evas_Coord width, height;
edje_object_size_min_get(cursorObject.get(), &width, &height);
if (width <= 0 || height <= 0)
edje_object_size_min_calc(cursorObject.get(), &width, &height);
if (width <= 0 || height <= 0) {
width = defaultCursorSize;
height = defaultCursorSize;
}
evas_object_resize(cursorObject.get(), width, height);
// Get cursor hot spot.
const char* data;
int hotspotX = 0;
data = edje_object_data_get(cursorObject.get(), "hot.x");
if (data)
hotspotX = atoi(data);
int hotspotY = 0;
data = edje_object_data_get(cursorObject.get(), "hot.y");
if (data)
hotspotY = atoi(data);
// ecore_evas takes care of freeing the cursor object.
ecore_evas_object_cursor_set(ecoreEvas, cursorObject.release().leakRef(), EVAS_LAYER_MAX, hotspotX, hotspotY);
}
AffineTransform EwkViewImpl::transformFromScene() const
{
AffineTransform transform;
#if USE(TILED_BACKING_STORE)
transform.translate(m_scrollPosition.x(), m_scrollPosition.y());
transform.scale(1 / m_scaleFactor);
#endif
Ewk_View_Smart_Data* sd = smartData();
transform.translate(-sd->view.x, -sd->view.y);
return transform;
}
AffineTransform EwkViewImpl::transformToScene() const
{
return transformFromScene().inverse();
}
AffineTransform EwkViewImpl::transformToScreen() const
{
AffineTransform transform;
int windowGlobalX = 0;
int windowGlobalY = 0;
Ewk_View_Smart_Data* sd = smartData();
#ifdef HAVE_ECORE_X
Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
Ecore_X_Window window = ecore_evas_software_x11_window_get(ecoreEvas); // Returns 0 if none.
int x, y; // x, y are relative to parent (in a reparenting window manager).
while (window) {
ecore_x_window_geometry_get(window, &x, &y, 0, 0);
windowGlobalX += x;
windowGlobalY += y;
window = ecore_x_window_parent_get(window);
}
#endif
transform.translate(-sd->view.x, -sd->view.y);
transform.translate(windowGlobalX, windowGlobalY);
return transform;
}
void EwkViewImpl::displayTimerFired(Timer<EwkViewImpl>*)
{
#if USE(COORDINATED_GRAPHICS)
Ewk_View_Smart_Data* sd = smartData();
evas_gl_make_current(evasGL(), evasGLSurface(), evasGLContext());
// We are supposed to clip to the actual viewport, nothing less.
IntRect viewport(sd->view.x, sd->view.y, sd->view.w, sd->view.h);
LayerTreeRenderer* renderer = page()->drawingArea()->layerTreeCoordinatorProxy()->layerTreeRenderer();
renderer->setActive(true);
renderer->syncRemoteContent();
if (m_isHardwareAccelerated) {
renderer->paintToCurrentGLContext(transformToScene().toTransformationMatrix(), /* opacity */ 1, viewport);
// sd->image is tied to a native surface. The native surface is in the parent's coordinates,
// so we need to account for the viewport position when calling evas_object_image_data_update_add.
evas_object_image_data_update_add(sd->image, viewport.x(), viewport.y(), viewport.width(), viewport.height());
} else {
RefPtr<cairo_surface_t> surface = createSurfaceForImage(sd->image);
if (!surface)
return;
RefPtr<cairo_t> graphicsContext = adoptRef(cairo_create(surface.get()));
cairo_translate(graphicsContext.get(), -m_scrollPosition.x(), -m_scrollPosition.y());
cairo_scale(graphicsContext.get(), m_scaleFactor, m_scaleFactor);
renderer->paintToGraphicsContext(graphicsContext.get());
evas_object_image_data_update_add(sd->image, 0, 0, viewport.width(), viewport.height());
}
#endif
}
void EwkViewImpl::update(const IntRect& rect)
{
Ewk_View_Smart_Data* sd = smartData();
#if USE(COORDINATED_GRAPHICS)
// Coordinated graphices needs to schedule an full update, not
// repainting of a region. Update in the event loop.
UNUSED_PARAM(rect);
// Guard for zero sized viewport.
if (!(sd->view.w && sd->view.h))
return;
if (!m_displayTimer.isActive())
m_displayTimer.startOneShot(0);
#else
if (!sd->image)
return;
evas_object_image_data_update_add(sd->image, rect.x(), rect.y(), rect.width(), rect.height());
#endif
}
#if ENABLE(FULLSCREEN_API)
/**
* @internal
* Calls fullscreen_enter callback or falls back to default behavior and enables fullscreen mode.
*/
void EwkViewImpl::enterFullScreen()
{
Ewk_View_Smart_Data* sd = smartData();
RefPtr<EwkSecurityOrigin> origin = EwkSecurityOrigin::create(KURL(ParsedURLString, String::fromUTF8(m_url)));
if (!sd->api->fullscreen_enter || !sd->api->fullscreen_enter(sd, origin.get())) {
Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
ecore_evas_fullscreen_set(ecoreEvas, true);
}
}
/**
* @internal
* Calls fullscreen_exit callback or falls back to default behavior and disables fullscreen mode.
*/
void EwkViewImpl::exitFullScreen()
{
Ewk_View_Smart_Data* sd = smartData();
if (!sd->api->fullscreen_exit || !sd->api->fullscreen_exit(sd)) {
Ecore_Evas* ecoreEvas = ecore_evas_ecore_evas_get(sd->base.evas);
ecore_evas_fullscreen_set(ecoreEvas, false);
}
}
#endif
WKRect EwkViewImpl::windowGeometry() const
{
Evas_Coord x, y, width, height;
Ewk_View_Smart_Data* sd = smartData();
if (!sd->api->window_geometry_get || !sd->api->window_geometry_get(sd, &x, &y, &width, &height)) {
Ecore_Evas* ee = ecore_evas_ecore_evas_get(sd->base.evas);
ecore_evas_request_geometry_get(ee, &x, &y, &width, &height);
}
return WKRectMake(x, y, width, height);
}
void EwkViewImpl::setWindowGeometry(const WKRect& rect)
{
Ewk_View_Smart_Data* sd = smartData();
if (!sd->api->window_geometry_set || !sd->api->window_geometry_set(sd, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height)) {
Ecore_Evas* ee = ecore_evas_ecore_evas_get(sd->base.evas);
ecore_evas_move_resize(ee, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
}
}
void EwkViewImpl::setImageData(void* imageData, const IntSize& size)
{
Ewk_View_Smart_Data* sd = smartData();
if (!imageData || !sd->image)
return;
evas_object_resize(sd->image, size.width(), size.height());
evas_object_image_size_set(sd->image, size.width(), size.height());
evas_object_image_data_copy_set(sd->image, imageData);
}
#if USE(TILED_BACKING_STORE)
void EwkViewImpl::informLoadCommitted()
{
m_pageClient->didCommitLoad();
}
#endif
IntSize EwkViewImpl::size() const
{
int width, height;
evas_object_geometry_get(m_view, 0, 0, &width, &height);
return IntSize(width, height);
}
bool EwkViewImpl::isFocused() const
{
return evas_object_focus_get(m_view);
}
bool EwkViewImpl::isVisible() const
{
return evas_object_visible_get(m_view);
}
const char* EwkViewImpl::title() const
{
m_title = m_pageProxy->pageTitle().utf8().data();
return m_title;
}
/**
* @internal
* This function may return @c NULL.
*/
InputMethodContextEfl* EwkViewImpl::inputMethodContext()
{
return m_inputMethodContext.get();
}
const char* EwkViewImpl::themePath() const
{
return m_theme;
}
void EwkViewImpl::setThemePath(const char* theme)
{
if (m_theme != theme) {
m_theme = theme;
m_pageProxy->setThemePath(theme);
}
}
const char* EwkViewImpl::customTextEncodingName() const
{
String customEncoding = m_pageProxy->customTextEncodingName();
if (customEncoding.isEmpty())
return 0;
m_customEncoding = customEncoding.utf8().data();
return m_customEncoding;
}
void EwkViewImpl::setCustomTextEncodingName(const String& encoding)
{
m_pageProxy->setCustomTextEncodingName(encoding);
}
void EwkViewImpl::setMouseEventsEnabled(bool enabled)
{
if (m_mouseEventsEnabled == enabled)
return;
m_mouseEventsEnabled = enabled;
if (enabled) {
Ewk_View_Smart_Data* sd = smartData();
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_DOWN, onMouseDown, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_UP, onMouseUp, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_MOVE, onMouseMove, sd);
} else {
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_DOWN, onMouseDown);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_UP, onMouseUp);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_MOVE, onMouseMove);
}
}
#if ENABLE(TOUCH_EVENTS)
void EwkViewImpl::setTouchEventsEnabled(bool enabled)
{
if (m_touchEventsEnabled == enabled)
return;
m_touchEventsEnabled = enabled;
if (enabled) {
// FIXME: We have to connect touch callbacks with mouse and multi events
// because the Evas creates mouse events for first touch and multi events
// for second and third touches. Below codes should be fixed when the Evas
// supports the touch events.
// See https://bugs.webkit.org/show_bug.cgi?id=97785 for details.
Ewk_View_Smart_Data* sd = smartData();
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_DOWN, onTouchDown, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_UP, onTouchUp, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MOUSE_MOVE, onTouchMove, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MULTI_DOWN, onTouchDown, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MULTI_UP, onTouchUp, sd);
evas_object_event_callback_add(m_view, EVAS_CALLBACK_MULTI_MOVE, onTouchMove, sd);
} else {
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_DOWN, onTouchDown);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_UP, onTouchUp);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MOUSE_MOVE, onTouchMove);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MULTI_DOWN, onTouchDown);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MULTI_UP, onTouchUp);
evas_object_event_callback_del(m_view, EVAS_CALLBACK_MULTI_MOVE, onTouchMove);
}
}
#endif
/**
* @internal
* Update the view's favicon and emits a "icon,changed" signal if it has
* changed.
*
* This function is called whenever the URL has changed or when the icon for
* the current page URL has changed.
*/
void EwkViewImpl::informIconChange()
{
Ewk_Favicon_Database* iconDatabase = m_context->faviconDatabase();
ASSERT(iconDatabase);
m_faviconURL = ewk_favicon_database_icon_url_get(iconDatabase, m_url);
smartCallback<IconChanged>().call();
}
#if USE(ACCELERATED_COMPOSITING)
bool EwkViewImpl::createGLSurface(const IntSize& viewSize)
{
if (!m_isHardwareAccelerated)
return true;
if (!m_evasGL) {
Evas* evas = evas_object_evas_get(m_view);
m_evasGL = adoptPtr(evas_gl_new(evas));
if (!m_evasGL) {
m_isHardwareAccelerated = false;
page()->drawingArea()->layerTreeCoordinatorProxy()->layerTreeRenderer()->setAccelerationMode(TextureMapper::SoftwareMode);
#if ENABLE(WEBGL)
m_pageProxy->pageGroup()->preferences()->setWebGLEnabled(false);
#endif
return false;
}
}
if (!m_evasGLContext) {
m_evasGLContext = EvasGLContext::create(evasGL());
if (!m_evasGLContext) {
WARN("Failed to create GLContext.");
return false;
}
}
Ewk_View_Smart_Data* sd = smartData();
Evas_GL_Config evasGLConfig = {
EVAS_GL_RGBA_8888,
EVAS_GL_DEPTH_BIT_8,
EVAS_GL_STENCIL_NONE,
EVAS_GL_OPTIONS_NONE,
EVAS_GL_MULTISAMPLE_NONE
};
ASSERT(!m_evasGLSurface);
m_evasGLSurface = EvasGLSurface::create(evasGL(), &evasGLConfig, viewSize);
if (!m_evasGLSurface)
return false;
Evas_Native_Surface nativeSurface;
evas_gl_native_surface_get(evasGL(), evasGLSurface(), &nativeSurface);
evas_object_image_native_surface_set(sd->image, &nativeSurface);
evas_gl_make_current(evasGL(), evasGLSurface(), evasGLContext());
Evas_GL_API* gl = evas_gl_api_get(evasGL());
gl->glViewport(0, 0, viewSize.width() + sd->view.x, viewSize.height() + sd->view.y);
return true;
}
bool EwkViewImpl::enterAcceleratedCompositingMode()
{
page()->drawingArea()->layerTreeCoordinatorProxy()->layerTreeRenderer()->setActive(true);
if (!m_isHardwareAccelerated)
return true;
if (!m_evasGLSurface) {
if (!createGLSurface(size())) {
WARN("Failed to create GLSurface.");
return false;
}
}
return true;
}
bool EwkViewImpl::exitAcceleratedCompositingMode()
{
return true;
}
#endif
#if ENABLE(INPUT_TYPE_COLOR)
/**
* @internal
* Requests to show external color picker.
*/
void EwkViewImpl::requestColorPicker(WKColorPickerResultListenerRef listener, const WebCore::Color& color)
{
Ewk_View_Smart_Data* sd = smartData();
EINA_SAFETY_ON_NULL_RETURN(sd->api->input_picker_color_request);
if (!sd->api->input_picker_color_request)
return;
if (m_colorPicker)
dismissColorPicker();
m_colorPicker = Ewk_Color_Picker::create(listener, color);
sd->api->input_picker_color_request(sd, m_colorPicker.get());
}
/**
* @internal
* Requests to hide external color picker.
*/
void EwkViewImpl::dismissColorPicker()
{
if (!m_colorPicker)
return;
Ewk_View_Smart_Data* sd = smartData();
EINA_SAFETY_ON_NULL_RETURN(sd->api->input_picker_color_dismiss);
if (sd->api->input_picker_color_dismiss)
sd->api->input_picker_color_dismiss(sd);
m_colorPicker.clear();
}
#endif
void EwkViewImpl::informContentsSizeChange(const IntSize& size)
{
#if USE(COORDINATED_GRAPHICS)
m_pageClient->didChangeContentsSize(size);
#else
UNUSED_PARAM(size);
#endif
}
COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_RIGHT_TO_LEFT, RTL);
COMPILE_ASSERT_MATCHING_ENUM(EWK_TEXT_DIRECTION_LEFT_TO_RIGHT, LTR);
void EwkViewImpl::requestPopupMenu(WebPopupMenuProxyEfl* popupMenuProxy, const IntRect& rect, TextDirection textDirection, double pageScaleFactor, const Vector<WebPopupItem>& items, int32_t selectedIndex)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
ASSERT(popupMenuProxy);
if (!sd->api->popup_menu_show)
return;
if (m_popupMenu)
closePopupMenu();
m_popupMenu = Ewk_Popup_Menu::create(this, popupMenuProxy, items, selectedIndex);
sd->api->popup_menu_show(sd, rect, static_cast<Ewk_Text_Direction>(textDirection), pageScaleFactor, m_popupMenu.get());
}
void EwkViewImpl::closePopupMenu()
{
if (!m_popupMenu)
return;
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
if (sd->api->popup_menu_hide)
sd->api->popup_menu_hide(sd);
m_popupMenu.clear();
}
/**
* @internal
* Calls a smart member function for javascript alert().
*/
void EwkViewImpl::requestJSAlertPopup(const WKEinaSharedString& message)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
if (!sd->api->run_javascript_alert)
return;
sd->api->run_javascript_alert(sd, message);
}
/**
* @internal
* Calls a smart member function for javascript confirm() and returns a value from the function. Returns false by default.
*/
bool EwkViewImpl::requestJSConfirmPopup(const WKEinaSharedString& message)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
if (!sd->api->run_javascript_confirm)
return false;
return sd->api->run_javascript_confirm(sd, message);
}
/**
* @internal
* Calls a smart member function for javascript prompt() and returns a value from the function. Returns null string by default.
*/
WKEinaSharedString EwkViewImpl::requestJSPromptPopup(const WKEinaSharedString& message, const WKEinaSharedString& defaultValue)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
if (!sd->api->run_javascript_prompt)
return WKEinaSharedString();
return WKEinaSharedString::adopt(sd->api->run_javascript_prompt(sd, message, defaultValue));
}
#if ENABLE(SQL_DATABASE)
/**
* @internal
* Calls exceeded_database_quota callback or falls back to default behavior returns default database quota.
*/
unsigned long long EwkViewImpl::informDatabaseQuotaReached(const String& databaseName, const String& displayName, unsigned long long currentQuota, unsigned long long currentOriginUsage, unsigned long long currentDatabaseUsage, unsigned long long expectedUsage)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
static const unsigned long long defaultQuota = 5 * 1024 * 1204; // 5 MB
if (sd->api->exceeded_database_quota)
return sd->api->exceeded_database_quota(sd, databaseName.utf8().data(), displayName.utf8().data(), currentQuota, currentOriginUsage, currentDatabaseUsage, expectedUsage);
return defaultQuota;
}
#endif
/**
* @internal
* The url of view was changed by the frame loader.
*
* Emits signal: "url,changed" with pointer to new url string.
*/
void EwkViewImpl::informURLChange()
{
String activeURL = m_pageProxy->activeURL();
if (activeURL.isEmpty())
return;
CString rawActiveURL = activeURL.utf8();
if (m_url == rawActiveURL.data())
return;
m_url = rawActiveURL.data();
smartCallback<URLChanged>().call(m_url);
// Update the view's favicon.
informIconChange();
}
WKPageRef EwkViewImpl::createNewPage(WKDictionaryRef windowFeatures)
{
Ewk_View_Smart_Data* sd = smartData();
ASSERT(sd->api);
Evas_Object* newEwkView = 0;
// Extract the width and height from the window attributes and pass them along to the embedder.
WKRetainPtr<WKStringRef> widthStr(AdoptWK, WKStringCreateWithUTF8CString("width"));
WKRetainPtr<WKStringRef> heightStr(AdoptWK, WKStringCreateWithUTF8CString("height"));
WKTypeRef ref = WKDictionaryGetItemForKey(windowFeatures, widthStr.get());
unsigned width = ref ? WKDoubleGetValue(static_cast<WKDoubleRef>(ref)) : 0;
ref = WKDictionaryGetItemForKey(windowFeatures, heightStr.get());
unsigned height = ref ? WKDoubleGetValue(static_cast<WKDoubleRef>(ref)) : 0;
if (!sd->api->window_create_new)
return 0;
if (!(newEwkView = sd->api->window_create_new(sd, width, height)))
return 0;
EwkViewImpl* newViewImpl = EwkViewImpl::fromEvasObject(newEwkView);
ASSERT(newViewImpl);
return static_cast<WKPageRef>(WKRetain(newViewImpl->page()));
}
void EwkViewImpl::closePage()
{
smartCallback<CloseWindow>().call();
}
void EwkViewImpl::onMouseDown(void* data, Evas*, Evas_Object*, void* eventInfo)
{
Evas_Event_Mouse_Down* downEvent = static_cast<Evas_Event_Mouse_Down*>(eventInfo);
Ewk_View_Smart_Data* sd = static_cast<Ewk_View_Smart_Data*>(data);
EINA_SAFETY_ON_NULL_RETURN(sd->api);
EINA_SAFETY_ON_NULL_RETURN(sd->api->mouse_down);
sd->api->mouse_down(sd, downEvent);
}
void EwkViewImpl::onMouseUp(void* data, Evas*, Evas_Object*, void* eventInfo)
{
Evas_Event_Mouse_Up* upEvent = static_cast<Evas_Event_Mouse_Up*>(eventInfo);
Ewk_View_Smart_Data* sd = static_cast<Ewk_View_Smart_Data*>(data);
EINA_SAFETY_ON_NULL_RETURN(sd->api);
EINA_SAFETY_ON_NULL_RETURN(sd->api->mouse_up);
sd->api->mouse_up(sd, upEvent);
}
void EwkViewImpl::onMouseMove(void* data, Evas*, Evas_Object*, void* eventInfo)
{
Evas_Event_Mouse_Move* moveEvent = static_cast<Evas_Event_Mouse_Move*>(eventInfo);
Ewk_View_Smart_Data* sd = static_cast<Ewk_View_Smart_Data*>(data);
EINA_SAFETY_ON_NULL_RETURN(sd->api);
EINA_SAFETY_ON_NULL_RETURN(sd->api->mouse_move);
sd->api->mouse_move(sd, moveEvent);
}
#if ENABLE(TOUCH_EVENTS)
void EwkViewImpl::feedTouchEvents(Ewk_Touch_Event_Type type)
{
Ewk_View_Smart_Data* sd = smartData();
unsigned count = evas_touch_point_list_count(sd->base.evas);
if (!count)
return;
Eina_List* points = 0;
for (unsigned i = 0; i < count; ++i) {
Ewk_Touch_Point* point = new Ewk_Touch_Point;
point->id = evas_touch_point_list_nth_id_get(sd->base.evas, i);
evas_touch_point_list_nth_xy_get(sd->base.evas, i, &point->x, &point->y);
point->state = evas_touch_point_list_nth_state_get(sd->base.evas, i);
points = eina_list_append(points, point);
}
ewk_view_feed_touch_event(m_view, type, points, evas_key_modifier_get(sd->base.evas));
void* data;
EINA_LIST_FREE(points, data)
delete static_cast<Ewk_Touch_Point*>(data);
}
void EwkViewImpl::onTouchDown(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
{
EwkViewImpl* viewImpl = EwkViewImpl::fromEvasObject(ewkView);
viewImpl->feedTouchEvents(EWK_TOUCH_START);
}
void EwkViewImpl::onTouchUp(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
{
EwkViewImpl* viewImpl = EwkViewImpl::fromEvasObject(ewkView);
viewImpl->feedTouchEvents(EWK_TOUCH_END);
}
void EwkViewImpl::onTouchMove(void* /* data */, Evas* /* canvas */, Evas_Object* ewkView, void* /* eventInfo */)
{
EwkViewImpl* viewImpl = EwkViewImpl::fromEvasObject(ewkView);
viewImpl->feedTouchEvents(EWK_TOUCH_MOVE);
}
#endif
void EwkViewImpl::onFaviconChanged(const char* pageURL, void* eventInfo)
{
EwkViewImpl* viewImpl = static_cast<EwkViewImpl*>(eventInfo);
if (!viewImpl->url() || strcasecmp(viewImpl->url(), pageURL))
return;
viewImpl->informIconChange();
}