diff options
author | Steve Block <steveblock@google.com> | 2010-04-27 16:31:00 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-05-11 14:42:12 +0100 |
commit | dcc8cf2e65d1aa555cce12431a16547e66b469ee (patch) | |
tree | 92a8d65cd5383bca9749f5327fb5e440563926e6 /WebKit/efl/ewk | |
parent | ccac38a6b48843126402088a309597e682f40fe6 (diff) | |
download | external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2 |
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebKit/efl/ewk')
-rw-r--r-- | WebKit/efl/ewk/EWebKit.h | 34 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_eapi.h | 50 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_frame.cpp | 1844 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_frame.h | 184 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_history.cpp | 704 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_history.h | 96 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_logging.h | 31 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_main.cpp | 152 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_main.h | 36 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_private.h | 115 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_settings.cpp | 190 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_settings.h | 53 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_util.cpp | 98 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_util.h | 29 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_view.cpp | 3644 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_view.h | 455 | ||||
-rw-r--r-- | WebKit/efl/ewk/ewk_view_single.c | 585 |
17 files changed, 8300 insertions, 0 deletions
diff --git a/WebKit/efl/ewk/EWebKit.h b/WebKit/efl/ewk/EWebKit.h new file mode 100644 index 0000000..d87d204 --- /dev/null +++ b/WebKit/efl/ewk/EWebKit.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2008-2009 INdT - Instituto Nokia de Tecnologia + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef EWebKit_h +#define EWebKit_h + +#include "ewk_eapi.h" +#include "ewk_frame.h" +#include "ewk_history.h" +#include "ewk_main.h" +#include "ewk_settings.h" +#include "ewk_view.h" + +#include <Evas.h> + +#endif // EWebKit_h diff --git a/WebKit/efl/ewk/ewk_eapi.h b/WebKit/efl/ewk/ewk_eapi.h new file mode 100644 index 0000000..adb8d7b --- /dev/null +++ b/WebKit/efl/ewk/ewk_eapi.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_eapi_h +#define ewk_eapi_h + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef BUILDING_WEBKIT +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EINA_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#endif // ewk_eapi_h diff --git a/WebKit/efl/ewk/ewk_frame.cpp b/WebKit/efl/ewk/ewk_frame.cpp new file mode 100644 index 0000000..73d1d29 --- /dev/null +++ b/WebKit/efl/ewk/ewk_frame.cpp @@ -0,0 +1,1844 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +// Uncomment to view frame regions and debug messages +// #define EWK_FRAME_DEBUG + +#include "config.h" +#include "ewk_frame.h" + +#include "EWebKit.h" +#include "EventHandler.h" +#include "FocusController.h" +#include "FrameLoaderClientEfl.h" +#include "FrameTree.h" +#include "FrameView.h" +#include "HTMLPlugInElement.h" +#include "HitTestResult.h" +#include "KURL.h" +#include "PlatformKeyboardEvent.h" +#include "PlatformMouseEvent.h" +#include "PlatformWheelEvent.h" +#include "ProgressTracker.h" +#include "RefPtr.h" +#include "RenderTheme.h" +#include "ResourceRequest.h" +#include "ScriptValue.h" +#include "SharedBuffer.h" +#include "SubstituteData.h" +#include "WindowsKeyboardCodes.h" +#include "ewk_private.h" +#include <wtf/text/CString.h> + +#include <Eina.h> +#include <Evas.h> +#include <eina_safety_checks.h> + +static const char EWK_FRAME_TYPE_STR[] = "EWK_Frame"; + +struct Ewk_Frame_Smart_Data { + Evas_Object_Smart_Clipped_Data base; + Evas_Object* self; + Evas_Object* view; +#ifdef EWK_FRAME_DEBUG + Evas_Object* region; +#endif + WebCore::Frame* frame; + const char* theme; + const char* title; + const char* uri; + const char* name; + struct { + Evas_Coord w, h; + } contents_size; + Eina_Bool zoom_text_only:1; + Eina_Bool editable:1; +}; + +struct Eina_Iterator_Ewk_Frame { + Eina_Iterator base; + Evas_Object* obj; + WebCore::Frame* last; +}; + +#ifndef EWK_TYPE_CHECK +#define EWK_FRAME_TYPE_CHECK(o, ...) do { } while (0) +#else +#define EWK_FRAME_TYPE_CHECK(o, ...) \ + do { \ + const char* _tmp_otype = evas_object_type_get(o); \ + if (EINA_UNLIKELY(_tmp_otype != EWK_FRAME_TYPE_STR)) { \ + EINA_LOG_CRIT \ + ("%p (%s) is not of an ewk_frame!", o, \ + _tmp_otype ? _tmp_otype : "(null)"); \ + return __VA_ARGS__; \ + } \ + } while (0) +#endif + +#define EWK_FRAME_SD_GET(o, ptr) \ + Ewk_Frame_Smart_Data* ptr = (Ewk_Frame_Smart_Data*)evas_object_smart_data_get(o) + +#define EWK_FRAME_SD_GET_OR_RETURN(o, ptr, ...) \ + EWK_FRAME_TYPE_CHECK(o, __VA_ARGS__); \ + EWK_FRAME_SD_GET(o, ptr); \ + if (!ptr) { \ + CRITICAL("no smart data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return __VA_ARGS__; \ + } + +static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL; + +#ifdef EWK_FRAME_DEBUG +static inline void _ewk_frame_debug(Evas_Object* o) +{ + Evas_Object* clip, *parent; + Evas_Coord x, y, w, h, cx, cy, cw, ch; + int r, g, b, a, cr, cg, cb, ca; + + evas_object_color_get(o, &r, &g, &b, &a); + evas_object_geometry_get(o, &x, &y, &w, &h); + + clip = evas_object_clip_get(o); + evas_object_color_get(clip, &cr, &cg, &cb, &ca); + evas_object_geometry_get(clip, &cx, &cy, &cw, &ch); + + fprintf(stderr, "%p: type=%s name=%s, visible=%d, color=%02x%02x%02x%02x, %d,%d+%dx%d, clipper=%p (%d, %02x%02x%02x%02x, %d,%d+%dx%d)\n", + o, evas_object_type_get(o), evas_object_name_get(o), evas_object_visible_get(o), + r, g, b, a, x, y, w, h, + clip, evas_object_visible_get(clip), cr, cg, cb, ca, cx, cy, cw, ch); + parent = evas_object_smart_parent_get(o); + if (!parent) + fprintf(stderr, "\n"); + else + _ewk_frame_debug(parent); +} +#endif + +static WebCore::FrameLoaderClientEfl* _ewk_frame_loader_efl_get(WebCore::Frame* frame) +{ + return static_cast<WebCore::FrameLoaderClientEfl*>(frame->loader()->client()); +} + +static inline Evas_Object* kit(WebCore::Frame* frame) +{ + if (!frame) + return 0; + WebCore::FrameLoaderClientEfl* fl = _ewk_frame_loader_efl_get(frame); + if (!fl) + return 0; + return fl->webFrame(); +} + +static Eina_Bool _ewk_frame_children_iterator_next(Eina_Iterator_Ewk_Frame* it, Evas_Object** data) +{ + EWK_FRAME_SD_GET_OR_RETURN(it->obj, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + + WebCore::FrameTree* tree = sd->frame->tree(); // check if it's still valid + EINA_SAFETY_ON_NULL_RETURN_VAL(tree, EINA_FALSE); + + WebCore::Frame* frame; + if (it->last) + frame = it->last->tree()->nextSibling(); + else + frame = tree->firstChild(); + + if (!frame) + return EINA_FALSE; + + *data = kit(frame); + return EINA_TRUE; +} + +static Evas_Object* _ewk_frame_children_iterator_get_container(Eina_Iterator_Ewk_Frame* it) +{ + return it->obj; +} + +static void _ewk_frame_smart_add(Evas_Object* o) +{ + EWK_FRAME_SD_GET(o, sd); + + if (!sd) { + sd = (Ewk_Frame_Smart_Data*)calloc(1, sizeof(Ewk_Frame_Smart_Data)); + if (!sd) + CRITICAL("could not allocate Ewk_Frame_Smart_Data"); + else + evas_object_smart_data_set(o, sd); + } + + sd->self = o; + + _parent_sc.add(o); + evas_object_move(sd->base.clipper, 0, 0); + evas_object_resize(sd->base.clipper, 0, 0); + +#ifdef EWK_FRAME_DEBUG + sd->region = evas_object_rectangle_add(sd->base.evas); + static int i = 0; + switch (i) { + case 0: + evas_object_color_set(sd->region, 128, 0, 0, 128); + break; + case 1: + evas_object_color_set(sd->region, 0, 128, 0, 128); + break; + case 2: + evas_object_color_set(sd->region, 0, 0, 128, 128); + break; + case 3: + evas_object_color_set(sd->region, 128, 0, 0, 128); + break; + case 4: + evas_object_color_set(sd->region, 128, 128, 0, 128); + break; + case 5: + evas_object_color_set(sd->region, 128, 0, 128, 128); + break; + case 6: + evas_object_color_set(sd->region, 0, 128, 128, 128); + break; + default: + break; + } + i++; + if (i > 6) + i = 0; + + evas_object_smart_member_add(sd->region, o); + evas_object_hide(sd->region); +#endif +} + +static void _ewk_frame_smart_del(Evas_Object* o) +{ + WRN("o=%p", o); // XXX REMOVE ME LATER + EWK_FRAME_SD_GET(o, sd); + + if (sd) { + if (sd->frame) { + WebCore::FrameLoaderClientEfl* flc = _ewk_frame_loader_efl_get(sd->frame); + flc->setWebFrame(0); + sd->frame->loader()->cancelAndClear(); + sd->frame = 0; + } + + eina_stringshare_del(sd->title); + eina_stringshare_del(sd->uri); + eina_stringshare_del(sd->name); + } + + _parent_sc.del(o); +} + +static void _ewk_frame_smart_resize(Evas_Object* o, Evas_Coord w, Evas_Coord h) +{ + EWK_FRAME_SD_GET(o, sd); + evas_object_resize(sd->base.clipper, w, h); + +#ifdef EWK_FRAME_DEBUG + evas_object_resize(sd->region, w, h); + Evas_Coord x, y; + evas_object_geometry_get(sd->region, &x, &y, &w, &h); + INF("region=%p, visible=%d, geo=%d,%d + %dx%d", + sd->region, evas_object_visible_get(sd->region), x, y, w, h); + _ewk_frame_debug(o); +#endif +} + +static void _ewk_frame_smart_set(Evas_Smart_Class* api) +{ + evas_object_smart_clipped_smart_set(api); + api->add = _ewk_frame_smart_add; + api->del = _ewk_frame_smart_del; + api->resize = _ewk_frame_smart_resize; +} + +static inline Evas_Smart* _ewk_frame_smart_class_new(void) +{ + static Evas_Smart_Class sc = EVAS_SMART_CLASS_INIT_NAME_VERSION(EWK_FRAME_TYPE_STR); + static Evas_Smart* smart = 0; + + if (EINA_UNLIKELY(!smart)) { + evas_object_smart_clipped_smart_set(&_parent_sc); + _ewk_frame_smart_set(&sc); + smart = evas_smart_class_new(&sc); + } + + return smart; +} + +/** + * @internal + * + * Creates a new EFL WebKit Frame object. + * + * Frames are low level entries contained in a page that is contained + * by a view. Usually one operates on the view and not directly on the + * frame. + * + * @param e canvas where to create the frame object. + * + * @return frame object or @c NULL if errors. + */ +Evas_Object* ewk_frame_add(Evas* e) +{ + return evas_object_smart_add(e, _ewk_frame_smart_class_new()); +} + +/** + * Retrieves the ewk_view object that owns this frame. + * + * @param o frame object to get view from. + * + * @return view object or @c NULL if errors. + */ +Evas_Object* ewk_frame_view_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + return sd->view; +} + +/** + * Set the theme path to be used by this frame. + * + * Frames inherit theme from their parent, this will have all frames + * with unset theme to use this one. + * + * @param o frame object to change theme. + * @param path theme path, may be @c NULL to reset to default or inherit parent. + */ +void ewk_frame_theme_set(Evas_Object* o, const char* path) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + if (!eina_stringshare_replace(&sd->theme, path)) + return; + if (sd->frame && sd->frame->view()) { + sd->frame->view()->setEdjeTheme(WebCore::String(path)); + sd->frame->page()->theme()->themeChanged(); + } +} + +/** + * Gets the immediate theme set on this frame. + * + * This returns the value set by ewk_frame_theme_set(). Note that if + * it is @c NULL, the frame will inherit parent's theme. + * + * @param o frame object to get theme path. + * + * @return theme path, may be @c NULL if not set. + */ +const char* ewk_frame_theme_get(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + return sd->theme; +} + +/** + * Returns a new iterator over all direct children frames. + * + * Keep frame object intact while iteration happens otherwise frame + * may be destroyed while iterated. + * + * Iteration results are Evas_Object*, so give eina_iterator_next() a + * pointer to it. + * + * @return a newly allocated iterator, free using + * eina_iterator_free(). If not possible to create the + * iterator, @c NULL is returned. + */ +Eina_Iterator* ewk_frame_children_iterator_new(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + Eina_Iterator_Ewk_Frame* it = (Eina_Iterator_Ewk_Frame*) + calloc(1, sizeof(Eina_Iterator_Ewk_Frame)); + if (!it) + return 0; + + EINA_MAGIC_SET(&it->base, EINA_MAGIC_ITERATOR); + it->base.next = FUNC_ITERATOR_NEXT(_ewk_frame_children_iterator_next); + it->base.get_container = FUNC_ITERATOR_GET_CONTAINER(_ewk_frame_children_iterator_get_container); + it->base.free = FUNC_ITERATOR_FREE(free); + it->obj = o; + return &it->base; +} + +/** + * Finds a child frame by its name, recursively. + * + * For pre-defined names, returns @a o if @a name is "_self" or + * "_current", returns @a o's parent frame if @a name is "_parent", + * and returns the main frame if @a name is "_top". Also returns @a o + * if it is the main frame and @a name is either "_parent" or + * "_top". For other names, this function returns the first frame that + * matches @a name. This function searches @a o and its descendents + * first, then @a o's parent and its children moving up the hierarchy + * until a match is found. If no match is found in @a o's hierarchy, + * this function will search for a matching frame in other main frame + * hierarchies. + * + * @return object if found, @c NULL if nothing with that name. + */ +Evas_Object* ewk_frame_child_find(Evas_Object* o, const char* name) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, 0); + WebCore::String s = WebCore::String::fromUTF8(name); + return kit(sd->frame->tree()->find(WebCore::AtomicString(s))); +} + +/** + * Ask main frame to load the given URI. + * + * @param o frame object to load uri. + * @param uri uniform resource identifier to load. + */ +Eina_Bool ewk_frame_uri_set(Evas_Object* o, const char* uri) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + WebCore::KURL kurl(WebCore::KURL(), WebCore::String::fromUTF8(uri)); + WebCore::ResourceRequest req(kurl); + WebCore::FrameLoader* loader = sd->frame->loader(); + loader->load(req, false); + return EINA_TRUE; +} + +/** + * Gets the uri of this frame. + * + * @param o frame object to get uri. + * + * @return frame uri or @c NULL. It's a internal string and should + * not be modified. The string is guaranteed to be stringshared. + */ +const char* ewk_frame_uri_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + return sd->uri; +} + +/** + * Gets the title of this frame. + * + * @param o frame object to get title. + * + * @return frame title or @c NULL. It's a internal string and should + * not be modified. The string is guaranteed to be stringshared. + */ +const char* ewk_frame_title_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + return sd->title; +} + +/** + * Gets the name of this frame. + * + * @param o frame object to get name. + * + * @return frame name or @c NULL. It's a internal string and should + * not be modified. The string is guaranteed to be stringshared. + */ +const char* ewk_frame_name_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + + if (sd->name) + return sd->name; + + if (!sd->frame) { + ERR("could not get name of uninitialized frame."); + return 0; + } + + WebCore::String s = sd->frame->tree()->name(); + WTF::CString cs = s.utf8(); + sd->name = eina_stringshare_add_length(cs.data(), cs.length()); + return sd->name; +} + +/** + * Get last known contents size. + * + * @param o frame object to get contents size. + * @param w where to store contents size width. May be @c NULL. + * @param h where to store contents size height. May be @c NULL. + * + * @return @c EINA_TRUE on success or @c EINA_FALSE on failure and + * @a w and @a h will be zeroed. + */ +Eina_Bool ewk_frame_contents_size_get(const Evas_Object* o, Evas_Coord* w, Evas_Coord* h) +{ + if (w) + *w = 0; + if (h) + *h = 0; + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + if (w) + *w = sd->contents_size.w; + if (h) + *h = sd->contents_size.h; + return EINA_TRUE; +} + +static Eina_Bool _ewk_frame_contents_set_internal(Ewk_Frame_Smart_Data *sd, const char* contents, size_t contents_size, const char* mime_type, const char* encoding, const char* base_uri, const char* unreachable_uri) +{ + if (contents_size < 1) + contents_size = strlen(contents); + if (!mime_type) + mime_type = "text/html"; + if (!encoding) + encoding = "UTF-8"; + if (!base_uri) + base_uri = "about:blank"; + + WebCore::KURL baseKURL(WebCore::KURL(), WebCore::String::fromUTF8(base_uri)); + WebCore::KURL unreachableKURL; + if (unreachable_uri) + unreachableKURL = WebCore::KURL(WebCore::KURL(), WebCore::String::fromUTF8(unreachable_uri)); + else + unreachableKURL = WebCore::KURL(); + + WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(contents, contents_size); + WebCore::SubstituteData substituteData + (buffer.release(), + WebCore::String::fromUTF8(mime_type), + WebCore::String::fromUTF8(encoding), + baseKURL, unreachableKURL); + WebCore::ResourceRequest request(baseKURL); + + sd->frame->loader()->load(request, substituteData, false); + return EINA_TRUE; +} + +/** + * Requests loading the given contents in this frame. + * + * @param o frame object to load document. + * @param contents what to load into frame. Must not be @c NULL. + * @param contents_size byte size of data in @a contents. + * If zero, strlen() is used. + * @param mime_type type of @a contents data. If @c NULL "text/html" is assumed. + * @param encoding used for @a contents data. If @c NULL "UTF-8" is assumed. + * @param base_uri base uri to use for relative resources. May be @c NULL. + * If provided must be an absolute uri. + * + * @return @c EINA_TRUE on successful request, @c EINA_FALSE on errors. + */ +Eina_Bool ewk_frame_contents_set(Evas_Object* o, const char* contents, size_t contents_size, const char* mime_type, const char* encoding, const char* base_uri) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(contents, EINA_FALSE); + return _ewk_frame_contents_set_internal + (sd, contents, contents_size, mime_type, encoding, base_uri, 0); +} + +/** + * Requests loading alternative contents for unreachable URI in this frame. + * + * This is similar to ewk_frame_contents_set(), but is used when some + * URI failed to load, using the provided content instead. The main + * difference is that back-forward navigation list is not changed. + * + * @param o frame object to load document. + * @param contents what to load into frame. Must not be @c NULL. + * @param contents_size byte size of data in @a contents. + * If zero, strlen() is used. + * @param mime_type type of @a contents data. If @c NULL "text/html" is assumed. + * @param encoding used for @a contents data. If @c NULL "UTF-8" is assumed. + * @param base_uri base uri to use for relative resources. May be @c NULL. + * If provided must be an absolute uri. + * @param unreachable_uri the URI that failed to load and is getting the + * alternative representation. + * + * @return @c EINA_TRUE on successful request, @c EINA_FALSE on errors. + */ +Eina_Bool ewk_frame_contents_alternate_set(Evas_Object* o, const char* contents, size_t contents_size, const char* mime_type, const char* encoding, const char* base_uri, const char* unreachable_uri) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(contents, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(unreachable_uri, EINA_FALSE); + return _ewk_frame_contents_set_internal + (sd, contents, contents_size, mime_type, encoding, base_uri, + unreachable_uri); +} + +/** + * Requests execution of given script. + * + * @param o frame object to execute script. + * @param script java script to execute. + * + * @return @c EINA_TRUE if request was done, @c EINA_FALSE on errors. + */ +Eina_Bool ewk_frame_script_execute(Evas_Object* o, const char* script) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_FALSE_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(script, EINA_FALSE); + sd->frame->script()->executeScript(WebCore::String::fromUTF8(script), true); + return EINA_TRUE; +} + +/** + * Gets if frame is editable. + * + * @param o frame object to get editable state. + * + * @return @c EINA_TRUE if editable, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_editable_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return sd->editable; +} + +/** + * Sets if frame is editable. + * + * @param o frame object to set editable state. + * @param editable new state. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_editable_set(Evas_Object* o, Eina_Bool editable) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + editable = !!editable; + if (sd->editable == editable) + return EINA_TRUE; + if (editable) + sd->frame->applyEditingStyleToBodyElement(); + else + sd->frame->removeEditingStyleFromBodyElement(); + return EINA_TRUE; +} + +/** + * Get the copy of the selection text. + * + * @param o frame object to get selection text. + * + * @return newly allocated string or @c NULL if nothing is selected or failure. + */ +char* ewk_frame_selection_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, 0); + WTF::CString s = sd->frame->selectedText().utf8(); + if (s.isNull()) + return 0; + return strdup(s.data()); +} + +static inline Eina_Bool _ewk_frame_editor_command(Ewk_Frame_Smart_Data* sd, const char* command) +{ + return sd->frame->editor()->command(WebCore::String::fromUTF8(command)).execute(); +} + +/** + * Unselects whatever was selected. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_none(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "Unselect"); +} + +/** + * Selects everything. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_all(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "SelectAll"); +} + +/** + * Selects the current paragrah. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_paragraph(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "SelectParagraph"); +} + +/** + * Selects the current sentence. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_sentence(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "SelectSentence"); +} + +/** + * Selects the current line. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_line(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "SelectLine"); +} + +/** + * Selects the current word. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_select_word(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return _ewk_frame_editor_command(sd, "SelectWord"); +} + +/** + * Search the given text string in document. + * + * @param o frame object where to search text. + * @param string reference string to search. + * @param case_sensitive if search should be case sensitive or not. + * @param forward if search is from cursor and on or backwards. + * @param wrap if search should wrap at end. + * + * @return @c EINA_TRUE if found, @c EINA_FALSE if not or failure. + */ +Eina_Bool ewk_frame_text_search(const Evas_Object* o, const char* string, Eina_Bool case_sensitive, Eina_Bool forward, Eina_Bool wrap) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE); + + return sd->frame->findString(WebCore::String::fromUTF8(string), forward, case_sensitive, wrap, true); +} + +/** + * Mark matches the given text string in document. + * + * @param o frame object where to search text. + * @param string reference string to match. + * @param case_sensitive if match should be case sensitive or not. + * @param highlight if matches should be highlighted. + * @param limit maximum amount of matches, or zero to unlimited. + * + * @return number of matches. + */ +unsigned int ewk_frame_text_matches_mark(Evas_Object* o, const char* string, Eina_Bool case_sensitive, Eina_Bool highlight, unsigned int limit) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(string, 0); + + sd->frame->setMarkedTextMatchesAreHighlighted(highlight); + return sd->frame->markAllMatchesForText(WebCore::String::fromUTF8(string), case_sensitive, limit); +} + +/** + * Reverses the effect of ewk_frame_text_matches_mark() + * + * @param o frame object where to search text. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE for failure. + */ +Eina_Bool ewk_frame_text_matches_unmark_all(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + + sd->frame->document()->removeMarkers(WebCore::DocumentMarker::TextMatch); + return EINA_TRUE; +} + +/** + * Set if should highlight matches marked with ewk_frame_text_matches_mark(). + * + * @param o frame object where to set if matches are highlighted or not. + * @param highlight if @c EINA_TRUE, matches will be highlighted. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE for failure. + */ +Eina_Bool ewk_frame_text_matches_highlight_set(Evas_Object* o, Eina_Bool highlight) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + sd->frame->setMarkedTextMatchesAreHighlighted(highlight); + return EINA_TRUE; +} + +/** + * Get if should highlight matches marked with ewk_frame_text_matches_mark(). + * + * @param o frame object to query if matches are highlighted or not. + * + * @return @c EINA_TRUE if they are highlighted, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_text_matches_highlight_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + return sd->frame->markedTextMatchesAreHighlighted(); +} + +/** + * Ask frame to stop loading. + * + * @param o frame object to stop loading. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_stop(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + sd->frame->loader()->stopAllLoaders(); + return EINA_TRUE; +} + +/** + * Ask frame to reload current document. + * + * @param o frame object to reload. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_reload_full() + */ +Eina_Bool ewk_frame_reload(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + sd->frame->loader()->reload(); + return EINA_TRUE; +} + +/** + * Ask frame to fully reload current document, using no previous caches. + * + * @param o frame object to reload. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_reload_full(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + sd->frame->loader()->reload(true); + return EINA_TRUE; +} + +/** + * Ask frame to navigate back in history. + * + * @param o frame object to navigate back. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_navigate() + */ +Eina_Bool ewk_frame_back(Evas_Object* o) +{ + return ewk_frame_navigate(o, -1); +} + +/** + * Ask frame to navigate forward in history. + * + * @param o frame object to navigate forward. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_navigate() + */ +Eina_Bool ewk_frame_forward(Evas_Object* o) +{ + return ewk_frame_navigate(o, 1); +} + +/** + * Navigate back or forward in history. + * + * @param o frame object to navigate. + * @param steps if positive navigates that amount forwards, if negative + * does backwards. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_navigate(Evas_Object* o, int steps) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + WebCore::Page* page = sd->frame->page(); + if (!page->canGoBackOrForward(steps)) + return EINA_FALSE; + page->goBackOrForward(steps); + return EINA_TRUE; +} + +/** + * Check if it is possible to navigate backwards one item in history. + * + * @param o frame object to check if backward navigation is possible. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + * + * @see ewk_frame_navigate_possible() + */ +Eina_Bool ewk_frame_back_possible(Evas_Object* o) +{ + return ewk_frame_navigate_possible(o, -1); +} + +/** + * Check if it is possible to navigate forwards one item in history. + * + * @param o frame object to check if forward navigation is possible. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + * + * @see ewk_frame_navigate_possible() + */ +Eina_Bool ewk_frame_forward_possible(Evas_Object* o) +{ + return ewk_frame_navigate_possible(o, 1); +} + +/** + * Check if it is possible to navigate given @a steps in history. + * + * @param o frame object to navigate. + * @param steps if positive navigates that amount forwards, if negative + * does backwards. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_navigate_possible(Evas_Object* o, int steps) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + WebCore::Page* page = sd->frame->page(); + return page->canGoBackOrForward(steps); +} + +/** + * Get current zoom level used by this frame. + * + * @param o frame object to query zoom level. + * + * @return zoom level or -1.0 on failure. + */ +float ewk_frame_zoom_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, -1.0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, -1.0); + return sd->frame->zoomFactor(); +} + +/** + * Set current zoom level used by this frame. + * + * @param o frame object to change zoom level. + * @param zoom new level. + * + * @return @c EINA_TRUE on success or @c EINA_FALSE on failure. + * + * @see ewk_frame_zoom_text_only_set() + */ +Eina_Bool ewk_frame_zoom_set(Evas_Object* o, float zoom) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + sd->frame->setZoomFactor(zoom, sd->zoom_text_only); + return EINA_TRUE; +} + +/** + * Query if zoom level just applies to text and not other elements. + * + * @param o frame to query setting. + * + * @return @c EINA_TRUE if just text are scaled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_zoom_text_only_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return sd->zoom_text_only; +} + +/** + * Set if zoom level just applies to text and not other elements. + * + * @param o frame to change setting. + * @param setting @c EINA_TRUE if zoom should just be applied to text. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_zoom_text_only_set(Evas_Object* o, Eina_Bool setting) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + setting = !!setting; + if (sd->zoom_text_only == setting) + return EINA_TRUE; + + sd->zoom_text_only = setting; + sd->frame->setZoomFactor(sd->frame->zoomFactor(), setting); + return EINA_TRUE; +} + +/** + * Free hit test created with ewk_frame_hit_test_new(). + * + * @param hit_test instance. Must @b not be @c NULL. + */ +void ewk_frame_hit_test_free(Ewk_Hit_Test* hit_test) +{ + EINA_SAFETY_ON_NULL_RETURN(hit_test); + eina_stringshare_del(hit_test->title); + eina_stringshare_del(hit_test->alternate_text); + eina_stringshare_del(hit_test->link.text); + eina_stringshare_del(hit_test->link.url); + eina_stringshare_del(hit_test->link.title); + free(hit_test); +} + +/** + * Creates a new hit test for given frame and point. + * + * @param o frame to do hit test on. + * @param x horizontal position to query. + * @param y vertical position to query. + * + * @return a newly allocated hit test on success, @c NULL otherwise. + * Free memory with ewk_frame_hit_test_free() + */ +Ewk_Hit_Test* ewk_frame_hit_test_new(const Evas_Object* o, int x, int y) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, 0); + + WebCore::FrameView* view = sd->frame->view(); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->contentRenderer(), 0); + + WebCore::HitTestResult result = sd->frame->eventHandler()->hitTestResultAtPoint + (view->windowToContents(WebCore::IntPoint(x, y)), + /*allowShadowContent*/ false, /*ignoreClipping*/ true); + + if (result.scrollbar()) + return 0; + if (!result.innerNode()) + return 0; + + Ewk_Hit_Test* hit_test = (Ewk_Hit_Test*)calloc(1, sizeof(Ewk_Hit_Test)); + if (!hit_test) { + CRITICAL("Could not allocate memory for hit test."); + return 0; + } + + hit_test->x = result.point().x(); + hit_test->y = result.point().y(); +#if 0 + // FIXME + hit_test->bounding_box.x = result.boundingBox().x(); + hit_test->bounding_box.y = result.boundingBox().y(); + hit_test->bounding_box.w = result.boundingBox().width(); + hit_test->bounding_box.h = result.boundingBox().height(); +#else + hit_test->bounding_box.x = 0; + hit_test->bounding_box.y = 0; + hit_test->bounding_box.w = 0; + hit_test->bounding_box.h = 0; +#endif + + WebCore::TextDirection dir; + hit_test->title = eina_stringshare_add(result.title(dir).utf8().data()); + hit_test->alternate_text = eina_stringshare_add(result.altDisplayString().utf8().data()); + if (result.innerNonSharedNode() && result.innerNonSharedNode()->document() + && result.innerNonSharedNode()->document()->frame()) + hit_test->frame = kit(result.innerNonSharedNode()->document()->frame()); + + hit_test->link.text = eina_stringshare_add(result.textContent().utf8().data()); + hit_test->link.url = eina_stringshare_add(result.absoluteLinkURL().prettyURL().utf8().data()); + hit_test->link.title = eina_stringshare_add(result.titleDisplayString().utf8().data()); + hit_test->link.target_frame = kit(result.targetFrame()); + + hit_test->flags.editable = result.isContentEditable(); + hit_test->flags.selected = result.isSelected(); + + return hit_test; +} + +/** + * Relative scroll of given frame. + * + * @param o frame object to scroll. + * @param dx horizontal offset to scroll. + * @param dy vertical offset to scroll. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + */ +Eina_Bool +ewk_frame_scroll_add(Evas_Object* o, int dx, int dy) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + sd->frame->view()->scrollBy(IntSize(dx, dy)); + return EINA_TRUE; +} + +/** + * Set absolute scroll of given frame. + * + * Both values are from zero to the contents size minus the viewport + * size. See ewk_frame_scroll_size_get(). + * + * @param o frame object to scroll. + * @param x horizontal position to scroll. + * @param y vertical position to scroll. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + */ +Eina_Bool +ewk_frame_scroll_set(Evas_Object* o, int x, int y) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + sd->frame->view()->setScrollPosition(WebCore::IntPoint(x, y)); + return EINA_TRUE; +} + +/** + * Get the possible scroll size of given frame. + * + * Possible scroll size is contents size minus the viewport + * size. It's the last allowed value for ewk_frame_scroll_set() + * + * @param o frame object to scroll. + * @param w where to return horizontal size that is possible to + * scroll. May be @c NULL. + * @param h where to return vertical size that is possible to scroll. + * May be @c NULL. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise and + * values are zeroed. + */ +Eina_Bool +ewk_frame_scroll_size_get(const Evas_Object* o, int* w, int* h) +{ + if (w) + *w = 0; + if (h) + *h = 0; + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + WebCore::IntPoint point = sd->frame->view()->maximumScrollPosition(); + if (w) + *w = point.x(); + if (h) + *h = point.y(); + return EINA_TRUE; +} + +/** + * Get the current scroll position of given frame. + * + * @param o frame object to scroll. + * @param x where to return horizontal position. May be @c NULL. + * @param y where to return vertical position. May be @c NULL. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise and + * values are zeroed. + */ +Eina_Bool +ewk_frame_scroll_pos_get(const Evas_Object* o, int* x, int* y) +{ + if (x) + *x = 0; + if (y) + *y = 0; + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + WebCore::IntPoint pos = sd->frame->view()->scrollPosition(); + if (x) + *x = pos.x(); + if (y) + *y = pos.y(); + return EINA_TRUE; +} + +/** + * Get the current frame visible content geometry. + * + * @param o frame object to query visible content geometry. + * @param include_scrollbars whenever to include scrollbars size. + * @param x horizontal position. May be @c NULL. + * @param y vertical position. May be @c NULL. + * @param w width. May be @c NULL. + * @param h height. May be @c NULL. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise and + * values are zeroed. + */ +Eina_Bool ewk_frame_visible_content_geometry_get(const Evas_Object* o, Eina_Bool include_scrollbars, int* x, int* y, int* w, int* h) +{ + if (x) + *x = 0; + if (y) + *y = 0; + if (w) + *w = 0; + if (h) + *h = 0; + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + WebCore::IntRect rect = sd->frame->view()->visibleContentRect(include_scrollbars); + if (x) + *x = rect.x(); + if (y) + *y = rect.y(); + if (w) + *w = rect.width(); + if (h) + *h = rect.height(); + return EINA_TRUE; +} + +/** + * Get the current paintsEntireContents flag. + * + * This flag tells if dirty areas should be repainted even if they are + * out of the screen. + * + * @param o frame object to query paintsEntireContents flag. + * + * @return @c EINA_TRUE if repainting any dirty area, @c EINA_FALSE + * otherwise. + */ +Eina_Bool ewk_frame_paint_full_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame->view(), EINA_FALSE); + return sd->frame->view()->paintsEntireContents(); +} + +/** + * Set the current paintsEntireContents flag. + * + * This flag tells if dirty areas should be repainted even if they are + * out of the screen. + * + * @param o frame object to set paintsEntireContents flag. + * @param flag @c EINA_TRUE if want to always repaint any dirty area, + * @c EINA_FALSE otherwise. + */ +void ewk_frame_paint_full_set(Evas_Object* o, Eina_Bool flag) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->frame); + EINA_SAFETY_ON_NULL_RETURN(sd->frame->view()); + sd->frame->view()->setPaintsEntireContents(flag); +} + +/** + * Feed the focus in signal to this frame. + * + * @param o frame object to focus. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_focus_in(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + WebCore::FocusController* c = sd->frame->page()->focusController(); + c->setFocusedFrame(sd->frame); + return EINA_TRUE; +} + +/** + * Feed the focus out signal to this frame. + * + * @param o frame object to remove focus. + */ +Eina_Bool ewk_frame_feed_focus_out(Evas_Object* o) +{ + // TODO: what to do on focus out? + ERR("what to do?"); + return EINA_FALSE; +} + +/** + * Feed the mouse wheel event to the frame. + * + * @param o frame object to feed event. + * @param ev mouse wheel event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_mouse_wheel(Evas_Object* o, const Evas_Event_Mouse_Wheel* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + WebCore::FrameView* view = sd->frame->view(); + DBG("o=%p, view=%p, direction=%d, z=%d, pos=%d,%d", + o, view, ev->direction, ev->z, ev->canvas.x, ev->canvas.y); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + WebCore::PlatformWheelEvent event(ev); + return sd->frame->eventHandler()->handleWheelEvent(event); +} + +/** + * Feed the mouse down event to the frame. + * + * @param o frame object to feed event. + * @param ev mouse down event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_mouse_down(Evas_Object* o, const Evas_Event_Mouse_Down* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + WebCore::FrameView* view = sd->frame->view(); + DBG("o=%p, view=%p, button=%d, pos=%d,%d", + o, view, ev->button, ev->canvas.x, ev->canvas.y); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + Evas_Coord x, y; + evas_object_geometry_get(sd->view, &x, &y, 0, 0); + + WebCore::PlatformMouseEvent event(ev, WebCore::IntPoint(x, y)); + return sd->frame->eventHandler()->handleMousePressEvent(event); +} + +/** + * Feed the mouse up event to the frame. + * + * @param o frame object to feed event. + * @param ev mouse up event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_mouse_up(Evas_Object* o, const Evas_Event_Mouse_Up* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + WebCore::FrameView* view = sd->frame->view(); + DBG("o=%p, view=%p, button=%d, pos=%d,%d", + o, view, ev->button, ev->canvas.x, ev->canvas.y); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + Evas_Coord x, y; + evas_object_geometry_get(sd->view, &x, &y, 0, 0); + + WebCore::PlatformMouseEvent event(ev, WebCore::IntPoint(x, y)); + return sd->frame->eventHandler()->handleMouseReleaseEvent(event); +} + +/** + * Feed the mouse move event to the frame. + * + * @param o frame object to feed event. + * @param ev mouse move event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_mouse_move(Evas_Object* o, const Evas_Event_Mouse_Move* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + WebCore::FrameView* view = sd->frame->view(); + DBG("o=%p, view=%p, pos: old=%d,%d, new=%d,%d, buttons=%d", + o, view, ev->cur.canvas.x, ev->cur.canvas.y, + ev->prev.canvas.x, ev->prev.canvas.y, ev->buttons); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + Evas_Coord x, y; + evas_object_geometry_get(sd->view, &x, &y, 0, 0); + + WebCore::PlatformMouseEvent event(ev, WebCore::IntPoint(x, y)); + return sd->frame->eventHandler()->mouseMoved(event); +} + +static inline Eina_Bool _ewk_frame_handle_key_scrolling(WebCore::Frame* frame, const WebCore::PlatformKeyboardEvent &event) +{ + WebCore::ScrollDirection direction; + WebCore::ScrollGranularity granularity; + + int keyCode = event.windowsVirtualKeyCode(); + + switch (keyCode) { + case WebCore::VK_SPACE: + granularity = WebCore::ScrollByPage; + if (event.shiftKey()) + direction = WebCore::ScrollUp; + else + direction = WebCore::ScrollDown; + break; + case WebCore::VK_NEXT: + granularity = WebCore::ScrollByPage; + direction = WebCore::ScrollDown; + break; + case WebCore::VK_PRIOR: + granularity = WebCore::ScrollByPage; + direction = WebCore::ScrollUp; + break; + case WebCore::VK_HOME: + granularity = WebCore::ScrollByDocument; + direction = WebCore::ScrollUp; + break; + case WebCore::VK_END: + granularity = WebCore::ScrollByDocument; + direction = WebCore::ScrollDown; + break; + case WebCore::VK_LEFT: + granularity = WebCore::ScrollByLine; + direction = WebCore::ScrollLeft; + break; + case WebCore::VK_RIGHT: + granularity = WebCore::ScrollByLine; + direction = WebCore::ScrollRight; + break; + case WebCore::VK_UP: + direction = WebCore::ScrollUp; + if (event.ctrlKey()) + granularity = WebCore::ScrollByDocument; + else + granularity = WebCore::ScrollByLine; + break; + case WebCore::VK_DOWN: + direction = WebCore::ScrollDown; + if (event.ctrlKey()) + granularity = WebCore::ScrollByDocument; + else + granularity = WebCore::ScrollByLine; + break; + default: + return EINA_FALSE; + } + + if (frame->eventHandler()->scrollOverflow(direction, granularity)) + return EINA_FALSE; + + frame->view()->scroll(direction, granularity); + return EINA_TRUE; +} + +/** + * Feed the keyboard key down event to the frame. + * + * @param o frame object to feed event. + * @param ev keyboard key down event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_key_down(Evas_Object* o, const Evas_Event_Key_Down* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + DBG("o=%p keyname=%s (key=%s, string=%s)", + o, ev->keyname, ev->key ? ev->key : "", ev->string ? ev->string : ""); + + WebCore::PlatformKeyboardEvent event(ev); + if (sd->frame->eventHandler()->keyEvent(event)) + return EINA_TRUE; + + return _ewk_frame_handle_key_scrolling(sd->frame, event); +} + +/** + * Feed the keyboard key up event to the frame. + * + * @param o frame object to feed event. + * @param ev keyboard key up event. + * + * @return @c EINA_TRUE if it was handled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_frame_feed_key_up(Evas_Object* o, const Evas_Event_Key_Up* ev) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(ev, EINA_FALSE); + + DBG("o=%p keyname=%s (key=%s, string=%s)", + o, ev->keyname, ev->key ? ev->key : "", ev->string ? ev->string : ""); + + WebCore::PlatformKeyboardEvent event(ev); + return sd->frame->eventHandler()->keyEvent(event); +} + +/* internal methods ****************************************************/ + +/** + * @internal + * + * Initialize frame based on actual WebKit frame. + * + * This is internal and should never be called by external users. + */ +Eina_Bool ewk_frame_init(Evas_Object* o, Evas_Object* view, WebCore::Frame* frame) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + if (!sd->frame) { + WebCore::FrameLoaderClientEfl* flc = _ewk_frame_loader_efl_get(frame); + flc->setWebFrame(o); + sd->frame = frame; + sd->view = view; + frame->init(); + return EINA_TRUE; + } + + ERR("frame %p already set for %p, ignored new %p", + sd->frame, o, frame); + return EINA_FALSE; +} + +Evas_Object* ewk_frame_child_add(Evas_Object* o, WTF::PassRefPtr<WebCore::Frame> child, const WebCore::String& name, const WebCore::KURL& url, const WebCore::String& referrer) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + char buf[256]; + Evas_Object* frame; + WebCore::Frame* cf; + + frame = ewk_frame_add(sd->base.evas); + if (!frame) { + ERR("Could not create ewk_frame object."); + return 0; + } + + cf = child.get(); + sd->frame->tree()->appendChild(child); + if (cf->tree()) + cf->tree()->setName(name); + else + ERR("no tree for child object"); + + if (!ewk_frame_init(frame, sd->view, cf)) { + evas_object_del(frame); + return 0; + } + snprintf(buf, sizeof(buf), "EWK_Frame:child/%s", name.utf8().data()); + evas_object_name_set(frame, buf); + evas_object_smart_member_add(frame, o); + evas_object_show(frame); + + if (!cf->page()) + goto died; + + cf->loader()->loadURLIntoChildFrame(url, referrer, cf); + if (!cf->tree()->parent()) + goto died; + + // TODO: announce frame was created? + return frame; + +died: + CRITICAL("does this work: BEGIN"); + ewk_frame_core_gone(frame); // CONFIRM + evas_object_del(frame); // CONFIRM + CRITICAL("does this work: END"); + return 0; +} + +/** + * @internal + * Frame was destroyed by loader, remove internal reference. + */ +void ewk_frame_core_gone(Evas_Object* o) +{ + DBG("o=%p", o); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + sd->frame = 0; +} + +/** + * @internal + * Retrieve WebCore::Frame associated with this object. + * + * Avoid using this call from outside, add specific ewk_frame_* + * actions instead. + */ +WebCore::Frame* ewk_frame_core_get(const Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + return sd->frame; +} + + +/** + * @internal + * Reports the frame started loading something. + * + * Emits signal: "load,started" with no parameters. + */ +void ewk_frame_load_started(Evas_Object* o) +{ + Evas_Object* main_frame; + DBG("o=%p", o); + evas_object_smart_callback_call(o, "load,started", 0); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + ewk_view_load_started(sd->view); + + main_frame = ewk_view_frame_main_get(sd->view); + if (main_frame == o) + ewk_view_frame_main_load_started(sd->view); +} + +/** + * @internal + * Reports load finished, optionally with error information. + * + * Emits signal: "load,finished" with pointer to Ewk_Frame_Load_Error + * if any error, or @c NULL if successful load. + * + * @note there should notbe any error stuff here, but trying to be + * compatible with previous WebKit. + */ +void ewk_frame_load_finished(Evas_Object* o, const char* error_domain, int error_code, Eina_Bool is_cancellation, const char* error_description, const char* failing_url) +{ + Ewk_Frame_Load_Error buf, *error; + if (!error_domain) { + DBG("o=%p, success.", o); + error = 0; + } else { + DBG("o=%p, error=%s (%d, cancellation=%hhu) \"%s\", url=%s", + o, error_domain, error_code, is_cancellation, + error_description, failing_url); + + buf.domain = error_domain; + buf.code = error_code; + buf.is_cancellation = is_cancellation; + buf.description = error_description; + buf.failing_url = failing_url; + buf.frame = o; + error = &buf; + } + evas_object_smart_callback_call(o, "load,finished", error); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + ewk_view_load_finished(sd->view, error); +} + +/** + * @internal + * Reports load failed with error information. + * + * Emits signal: "load,error" with pointer to Ewk_Frame_Load_Error. + */ +void ewk_frame_load_error(Evas_Object* o, const char* error_domain, int error_code, Eina_Bool is_cancellation, const char* error_description, const char* failing_url) +{ + Ewk_Frame_Load_Error error; + + DBG("o=%p, error=%s (%d, cancellation=%hhu) \"%s\", url=%s", + o, error_domain, error_code, is_cancellation, + error_description, failing_url); + + EINA_SAFETY_ON_NULL_RETURN(error_domain); + + error.code = error_code; + error.is_cancellation = is_cancellation; + error.domain = error_domain; + error.description = error_description; + error.failing_url = failing_url; + error.frame = o; + evas_object_smart_callback_call(o, "load,error", &error); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + ewk_view_load_error(sd->view, &error); +} + +/** + * @internal + * Reports load progress changed. + * + * Emits signal: "load,progress" with pointer to a double from 0.0 to 1.0. + */ +void ewk_frame_load_progress_changed(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->frame); + + // TODO: this is per page, there should be a way to have per-frame. + double progress = sd->frame->page()->progress()->estimatedProgress(); + + DBG("o=%p (p=%0.3f)", o, progress); + + evas_object_smart_callback_call(o, "load,progress", &progress); + ewk_view_load_progress_changed(sd->view); +} + + +/** + * @internal + * + * Reports contents size changed. + */ +void ewk_frame_contents_size_changed(Evas_Object* o, Evas_Coord w, Evas_Coord h) +{ + DBG("o=%p: %dx%d", o, w, h); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + if (sd->contents_size.w == w && sd->contents_size.h == h) + return; + sd->contents_size.w = w; + sd->contents_size.h = h; + // TODO: update something else internally? + + Evas_Coord size[2] = {w, h}; + evas_object_smart_callback_call(o, "contents,size,changed", size); +} + +/** + * @internal + * + * Reports title changed. + */ +void ewk_frame_title_set(Evas_Object* o, const char* title) +{ + DBG("o=%p, title=%s", o, title ? title : "(null)"); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + if (!eina_stringshare_replace(&sd->title, title)) + return; + evas_object_smart_callback_call(o, "title,changed", (void*)sd->title); +} + +void ewk_frame_view_create_for_view(Evas_Object* o, Evas_Object* view) +{ + DBG("o=%p, view=%p", o, view); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->frame); + Evas_Coord w, h; + + if (sd->frame->view()) + return; + + evas_object_geometry_get(view, 0, 0, &w, &h); + + WebCore::IntSize size(w, h); + int r, g, b, a; + WebCore::Color bg; + + ewk_view_bg_color_get(view, &r, &g, &b, &a); + if (!a) + bg = WebCore::Color(0, 0, 0, 0); + else if (a == 255) + bg = WebCore::Color(r, g, b, a); + else + bg = WebCore::Color(r * 255 / a, g * 255 / a, b * 255 / a, a); + + sd->frame->createView(size, bg, !a, WebCore::IntSize(), false); + if (!sd->frame->view()) + return; + sd->frame->view()->setEdjeTheme(sd->theme); + sd->frame->view()->setEvasObject(o); +} + +/** + * @internal + * Reports uri changed and swap internal string reference. + * + * Emits signal: "uri,changed" with new uri as parameter. + */ +Eina_Bool ewk_frame_uri_changed(Evas_Object* o) +{ + EWK_FRAME_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE); + WTF::CString uri(sd->frame->loader()->url().prettyURL().utf8()); + + INF("uri=%s", uri.data()); + if (!uri.data()) { + ERR("no uri"); + return EINA_FALSE; + } + + eina_stringshare_replace(&sd->uri, uri.data()); + evas_object_smart_callback_call(o, "uri,changed", (void*)sd->uri); + return EINA_TRUE; +} + +void ewk_frame_force_layout(Evas_Object* o) +{ + DBG("o=%p", o); + EWK_FRAME_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->frame); + WebCore::FrameView* view = sd->frame->view(); + if (view) + view->forceLayout(true); +} + +WTF::PassRefPtr<WebCore::Widget> ewk_frame_plugin_create(Evas_Object* o, const WebCore::IntSize& pluginSize, WebCore::HTMLPlugInElement* element, const WebCore::KURL& url, const WTF::Vector<WebCore::String>& paramNames, const WTF::Vector<WebCore::String>& paramValues, const WebCore::String& mimeType, bool loadManually) +{ + DBG("o=%p, size=%dx%d, element=%p, url=%s, mimeType=%s", + o, pluginSize.width(), pluginSize.height(), element, + url.prettyURL().utf8().data(), mimeType.utf8().data()); + + EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0); + + // TODO: emit signal and ask webkit users if something else should be done. + // like creating another x window (see gtk, it allows users to create + // GtkPluginWidget. + + WTF::RefPtr<WebCore::PluginView> pluginView = WebCore::PluginView::create + (sd->frame, pluginSize, element, url, paramNames, paramValues, + mimeType, loadManually); + + if (pluginView->status() == WebCore::PluginStatusLoadedSuccessfully) + return pluginView; + + return 0; +} diff --git a/WebKit/efl/ewk/ewk_frame.h b/WebKit/efl/ewk/ewk_frame.h new file mode 100644 index 0000000..c71269b --- /dev/null +++ b/WebKit/efl/ewk/ewk_frame.h @@ -0,0 +1,184 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_frame_h +#define ewk_frame_h + +#include "ewk_eapi.h" +#include <Evas.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * + * WebKit frame smart object. + * + * This object is the low level access to WebKit-EFL browser + * component. It represents both the main and internal frames that + * HTML pages contain. + * + * Every ewk_view has at least one frame, called "main frame" and + * retrieved with ewk_view_frame_main_get(). One can retrieve frame's + * owner view with ewk_frame_view_get(). Parent frame can be retrieved + * with standard smart object's evas_object_smart_parent_get(). + * Children can be accessed with ewk_frame_children_iterator_new() or + * ewk_frame_child_find(). + * + * The following signals (see evas_object_smart_callback_add()) are emitted: + * + * - "title,changed", const char*: title of the main frame changed. + * - "uri,changed", const char*: uri of the main frame changed. + * - "load,started", void: frame started loading. + * - "load,progress", double*: load progress changed (overall value + * from 0.0 to 1.0, connect to individual frames for fine grained). + * - "load,finished", const Ewk_Frame_Load_Error*: reports load + * finished and as argument @c NULL if successfully or pointer to + * structure defining the error. + * - "load,error", const Ewk_Frame_Load_Error*: reports load failed + * and as argument a pointer to structure defining the error. + * - "contents,size,changed", Evas_Coord[2]: reports contents size + * changed due new layout, script actions or any other events. + */ + + +/** + * Structure used to report load errors. + * + * Load errors are reported as signal by ewk_view. All the strings are + * temporary references and should @b not be used after the signal + * callback returns. If required, make copies with strdup() or + * eina_stringshare_add() (they are not even guaranteed to be + * stringshared, so must use eina_stringshare_add() and not + * eina_stringshare_ref()). + */ +typedef struct _Ewk_Frame_Load_Error Ewk_Frame_Load_Error; +struct _Ewk_Frame_Load_Error { + int code; /**< numeric error code */ + Eina_Bool is_cancellation; /**< if load failed because it was canceled */ + const char *domain; /**< error domain name */ + const char *description; /**< error description already localized */ + const char *failing_url; /**< the url that failed to load */ + Evas_Object *frame; /**< frame where the failure happened */ +}; + +/** + * Structure used to report hit test results. + */ +typedef struct _Ewk_Hit_Test Ewk_Hit_Test; +struct _Ewk_Hit_Test { + int x, y; + struct { + int x, y, w, h; + } bounding_box; + const char *title; + const char *alternate_text; /**< for image, area, input and applet */ + Evas_Object *frame; + struct { + const char *text; + const char *url; + const char *title; + Evas_Object *target_frame; + } link; + struct { + Eina_Bool editable:1; + Eina_Bool selected:1; + } flags; +}; + + +EAPI Evas_Object *ewk_frame_view_get(const Evas_Object *o); +EAPI void ewk_frame_theme_set(Evas_Object *o, const char *path); +EAPI const char *ewk_frame_theme_get(Evas_Object *o); + +EAPI Eina_Iterator *ewk_frame_children_iterator_new(Evas_Object *o); +EAPI Evas_Object *ewk_frame_child_find(Evas_Object *o, const char *name); + +EAPI Eina_Bool ewk_frame_uri_set(Evas_Object *o, const char *uri); +EAPI const char *ewk_frame_uri_get(const Evas_Object *o); +EAPI const char *ewk_frame_title_get(const Evas_Object *o); +EAPI const char *ewk_frame_name_get(const Evas_Object *o); +EAPI Eina_Bool ewk_frame_contents_size_get(const Evas_Object *o, Evas_Coord *w, Evas_Coord *h); + +EAPI Eina_Bool ewk_frame_contents_set(Evas_Object *o, const char *contents, size_t contents_size, const char *mime_type, const char *encoding, const char *base_uri); +EAPI Eina_Bool ewk_frame_contents_alternate_set(Evas_Object *o, const char *contents, size_t contents_size, const char *mime_type, const char *encoding, const char *base_uri, const char *unreachable_uri); + +EAPI Eina_Bool ewk_frame_script_execute(Evas_Object *o, const char *script); + +EAPI Eina_Bool ewk_frame_editable_get(const Evas_Object *o); +EAPI Eina_Bool ewk_frame_editable_set(Evas_Object *o, Eina_Bool editable); + +EAPI char *ewk_frame_selection_get(const Evas_Object *o); + +EAPI Eina_Bool ewk_frame_text_search(const Evas_Object *o, const char *string, Eina_Bool case_sensitive, Eina_Bool forward, Eina_Bool wrap); + +EAPI unsigned int ewk_frame_text_matches_mark(Evas_Object *o, const char *string, Eina_Bool case_sensitive, Eina_Bool highlight, unsigned int limit); +EAPI Eina_Bool ewk_frame_text_matches_unmark_all(Evas_Object *o); +EAPI Eina_Bool ewk_frame_text_matches_highlight_set(Evas_Object *o, Eina_Bool highlight); +EAPI Eina_Bool ewk_frame_text_matches_highlight_get(const Evas_Object *o); + +EAPI Eina_Bool ewk_frame_stop(Evas_Object *o); +EAPI Eina_Bool ewk_frame_reload(Evas_Object *o); +EAPI Eina_Bool ewk_frame_reload_full(Evas_Object *o); + +EAPI Eina_Bool ewk_frame_back(Evas_Object *o); +EAPI Eina_Bool ewk_frame_forward(Evas_Object *o); +EAPI Eina_Bool ewk_frame_navigate(Evas_Object *o, int steps); + +EAPI Eina_Bool ewk_frame_back_possible(Evas_Object *o); +EAPI Eina_Bool ewk_frame_forward_possible(Evas_Object *o); +EAPI Eina_Bool ewk_frame_navigate_possible(Evas_Object *o, int steps); + +EAPI float ewk_frame_zoom_get(const Evas_Object *o); +EAPI Eina_Bool ewk_frame_zoom_set(Evas_Object *o, float zoom); +EAPI Eina_Bool ewk_frame_zoom_text_only_get(const Evas_Object *o); +EAPI Eina_Bool ewk_frame_zoom_text_only_set(Evas_Object *o, Eina_Bool setting); + +EAPI void ewk_frame_hit_test_free(Ewk_Hit_Test *hit_test); +EAPI Ewk_Hit_Test *ewk_frame_hit_test_new(const Evas_Object *o, int x, int y); + +EAPI Eina_Bool ewk_frame_scroll_add(Evas_Object *o, int dx, int dy); +EAPI Eina_Bool ewk_frame_scroll_set(Evas_Object *o, int x, int y); + +EAPI Eina_Bool ewk_frame_scroll_size_get(const Evas_Object *o, int *w, int *h); +EAPI Eina_Bool ewk_frame_scroll_pos_get(const Evas_Object *o, int *x, int *y); + +EAPI Eina_Bool ewk_frame_visible_content_geometry_get(const Evas_Object *o, Eina_Bool include_scrollbars, int *x, int *y, int *w, int *h); + +EAPI Eina_Bool ewk_frame_paint_full_get(const Evas_Object *o); +EAPI void ewk_frame_paint_full_set(Evas_Object *o, Eina_Bool flag); + +EAPI Eina_Bool ewk_frame_feed_focus_in(Evas_Object *o); +EAPI Eina_Bool ewk_frame_feed_focus_out(Evas_Object *o); + +EAPI Eina_Bool ewk_frame_feed_mouse_wheel(Evas_Object *o, const Evas_Event_Mouse_Wheel *ev); +EAPI Eina_Bool ewk_frame_feed_mouse_down(Evas_Object *o, const Evas_Event_Mouse_Down *ev); +EAPI Eina_Bool ewk_frame_feed_mouse_up(Evas_Object *o, const Evas_Event_Mouse_Up *ev); +EAPI Eina_Bool ewk_frame_feed_mouse_move(Evas_Object *o, const Evas_Event_Mouse_Move *ev); +EAPI Eina_Bool ewk_frame_feed_key_down(Evas_Object *o, const Evas_Event_Key_Down *ev); +EAPI Eina_Bool ewk_frame_feed_key_up(Evas_Object *o, const Evas_Event_Key_Up *ev); + + +#ifdef __cplusplus +} +#endif +#endif // ewk_frame_h diff --git a/WebKit/efl/ewk/ewk_history.cpp b/WebKit/efl/ewk/ewk_history.cpp new file mode 100644 index 0000000..da48c33 --- /dev/null +++ b/WebKit/efl/ewk/ewk_history.cpp @@ -0,0 +1,704 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_history.h" + +#include "BackForwardList.h" +#include "EWebKit.h" +#include "HistoryItem.h" +#include "Image.h" +#include "ewk_private.h" +#include <wtf/text/CString.h> + +#include <Eina.h> +#include <eina_safety_checks.h> + +struct _Ewk_History { + WebCore::BackForwardList *core; +}; + +#define EWK_HISTORY_CORE_GET_OR_RETURN(history, core_, ...) \ + if (!(history)) { \ + CRITICAL("history is NULL."); \ + return __VA_ARGS__; \ + } \ + if (!(history)->core) { \ + CRITICAL("history->core is NULL."); \ + return __VA_ARGS__; \ + } \ + if (!(history)->core->enabled()) { \ + ERR("history->core is disabled!."); \ + return __VA_ARGS__; \ + } \ + WebCore::BackForwardList *core_ = (history)->core + + +struct _Ewk_History_Item { + WebCore::HistoryItem *core; + + const char *title; + const char *alternate_title; + const char *uri; + const char *original_uri; +}; + +#define EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core_, ...) \ + if (!(item)) { \ + CRITICAL("item is NULL."); \ + return __VA_ARGS__; \ + } \ + if (!(item)->core) { \ + CRITICAL("item->core is NULL."); \ + return __VA_ARGS__; \ + } \ + WebCore::HistoryItem *core_ = (item)->core + + +static inline Ewk_History_Item *_ewk_history_item_new(WebCore::HistoryItem *core) +{ + Ewk_History_Item* item; + + if (!core) { + ERR("WebCore::HistoryItem is NULL."); + return 0; + } + + item = (Ewk_History_Item *)calloc(1, sizeof(Ewk_History_Item)); + if (!item) { + CRITICAL("Could not allocate item memory."); + return 0; + } + + core->ref(); + item->core = core; + + return item; +} + +static inline Eina_List *_ewk_history_item_list_get(const WebCore::HistoryItemVector &core_items) +{ + Eina_List* ret = 0; + unsigned int i, size; + + size = core_items.size(); + for (i = 0; i < size; i++) { + Ewk_History_Item* item = _ewk_history_item_new(core_items[i].get()); + if (item) + ret = eina_list_append(ret, item); + } + + return ret; +} + +/** + * Go forward in history one item, if possible. + * + * @param history which history instance to modify. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + */ +Eina_Bool ewk_history_forward(Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE); + if (core->forwardListCount() < 1) + return EINA_FALSE; + core->goForward(); + return EINA_TRUE; +} + +/** + * Go back in history one item, if possible. + * + * @param history which history instance to modify. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + */ +Eina_Bool ewk_history_back(Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE); + if (core->backListCount() < 1) + return EINA_FALSE; + core->goBack(); + return EINA_TRUE; +} + +/** + * Adds the given item to history. + * + * Memory handling: This will not modify or even take references to + * given item (Ewk_History_Item), so you should still handle it with + * ewk_history_item_free(). + * + * @param history which history instance to modify. + * @param item reference to add to history. Unmodified. Must @b not be @c NULL. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + */ +Eina_Bool ewk_history_history_item_add(Ewk_History* history, const Ewk_History_Item* item) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE); + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE); + history_core->addItem(item_core); + return EINA_TRUE; +} + +/** + * Sets the given item as current in history (go to item). + * + * Memory handling: This will not modify or even take references to + * given item (Ewk_History_Item), so you should still handle it with + * ewk_history_item_free(). + * + * @param history which history instance to modify. + * @param item reference to go to history. Unmodified. Must @b not be @c NULL. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure. + */ +Eina_Bool ewk_history_history_item_set(Ewk_History* history, const Ewk_History_Item* item) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE); + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE); + history_core->goToItem(item_core); + return EINA_TRUE; +} + +/** + * Get the first item from back list, if any. + * + * @param history which history instance to query. + * + * @return the @b newly allocated item instance. This memory must be + * released with ewk_history_item_free() after use. + */ +Ewk_History_Item* ewk_history_history_item_back_get(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return _ewk_history_item_new(core->backItem()); +} + +/** + * Get the current item in history, if any. + * + * @param history which history instance to query. + * + * @return the @b newly allocated item instance. This memory must be + * released with ewk_history_item_free() after use. + */ +Ewk_History_Item* ewk_history_history_item_current_get(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return _ewk_history_item_new(core->currentItem()); +} + +/** + * Get the first item from forward list, if any. + * + * @param history which history instance to query. + * + * @return the @b newly allocated item instance. This memory must be + * released with ewk_history_item_free() after use. + */ +Ewk_History_Item* ewk_history_history_item_forward_get(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return _ewk_history_item_new(core->forwardItem()); +} + +/** + * Get item at given position, if any at that index. + * + * @param history which history instance to query. + * @param index position of item to get. + * + * @return the @b newly allocated item instance. This memory must be + * released with ewk_history_item_free() after use. + */ +Ewk_History_Item* ewk_history_history_item_nth_get(const Ewk_History* history, int index) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return _ewk_history_item_new(core->itemAtIndex(index)); +} + +/** + * Queries if given item is in history. + * + * Memory handling: This will not modify or even take references to + * given item (Ewk_History_Item), so you should still handle it with + * ewk_history_item_free(). + * + * @param history which history instance to modify. + * @param item reference to check in history. Must @b not be @c NULL. + * + * @return @c EINA_TRUE if in history, @c EINA_FALSE if not or failure. + */ +Eina_Bool ewk_history_history_item_contains(const Ewk_History* history, const Ewk_History_Item* item) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE); + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE); + return history_core->containsItem(item_core); +} + +/** + * Get the whole forward list. + * + * @param history which history instance to query. + * + * @return a newly allocated list of @b newly allocated item + * instance. This memory of each item must be released with + * ewk_history_item_free() after use. use + * ewk_history_item_list_free() for convenience. + * + * @see ewk_history_item_list_free() + * @see ewk_history_forward_list_get_with_limit() + */ +Eina_List* ewk_history_forward_list_get(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + WebCore::HistoryItemVector items; + int limit = core->forwardListCount(); + core->forwardListWithLimit(limit, items); + return _ewk_history_item_list_get(items); +} + +/** + * Get the forward list within the given limit. + * + * @param history which history instance to query. + * @param limit the maximum number of items to return. + * + * @return a newly allocated list of @b newly allocated item + * instance. This memory of each item must be released with + * ewk_history_item_free() after use. use + * ewk_history_item_list_free() for convenience. + * + * @see ewk_history_item_list_free() + * @see ewk_history_forward_list_length() + * @see ewk_history_forward_list_get() + */ +Eina_List* ewk_history_forward_list_get_with_limit(const Ewk_History* history, int limit) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + WebCore::HistoryItemVector items; + core->forwardListWithLimit(limit, items); + return _ewk_history_item_list_get(items); +} + +/** + * Get the whole size of forward list. + * + * @param history which history instance to query. + * + * @return number of elements in whole list. + * + * @see ewk_history_forward_list_get_with_limit() + */ +int ewk_history_forward_list_length(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return core->forwardListCount(); +} + +/** + * Get the whole back list. + * + * @param history which history instance to query. + * + * @return a newly allocated list of @b newly allocated item + * instance. This memory of each item must be released with + * ewk_history_item_free() after use. use + * ewk_history_item_list_free() for convenience. + * + * @see ewk_history_item_list_free() + * @see ewk_history_back_list_get_with_limit() + */ +Eina_List* ewk_history_back_list_get(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + WebCore::HistoryItemVector items; + int limit = core->backListCount(); + core->backListWithLimit(limit, items); + return _ewk_history_item_list_get(items); +} + +/** + * Get the back list within the given limit. + * + * @param history which history instance to query. + * @param limit the maximum number of items to return. + * + * @return a newly allocated list of @b newly allocated item + * instance. This memory of each item must be released with + * ewk_history_item_free() after use. use + * ewk_history_item_list_free() for convenience. + * + * @see ewk_history_item_list_free() + * @see ewk_history_back_list_length() + * @see ewk_history_back_list_get() + */ +Eina_List* ewk_history_back_list_get_with_limit(const Ewk_History* history, int limit) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + WebCore::HistoryItemVector items; + core->backListWithLimit(limit, items); + return _ewk_history_item_list_get(items); +} + +/** + * Get the whole size of back list. + * + * @param history which history instance to query. + * + * @return number of elements in whole list. + * + * @see ewk_history_back_list_get_with_limit() + */ +int ewk_history_back_list_length(const Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return core->backListCount(); +} + +/** + * Get maximum capacity of given history. + * + * @param history which history instance to query. + * + * @return maximum number of entries this history will hold. + */ +int ewk_history_limit_get(Ewk_History* history) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0); + return core->capacity(); +} + +/** + * Set maximum capacity of given history. + * + * @param history which history instance to modify. + * @param limit maximum size to allow. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_history_limit_set(const Ewk_History* history, int limit) +{ + EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE); + core->setCapacity(limit); + return EINA_TRUE; +} + +/** + * Create a new history item with given URI and title. + * + * @param uri where this resource is located. + * @param title resource title. + * + * @return newly allocated history item or @c NULL on errors. You must + * free this item with ewk_history_item_free(). + */ +Ewk_History_Item* ewk_history_item_new(const char* uri, const char* title) +{ + WebCore::String u = WebCore::String::fromUTF8(uri); + WebCore::String t = WebCore::String::fromUTF8(title); + WTF::RefPtr<WebCore::HistoryItem> core = WebCore::HistoryItem::create(u, t, 0); + Ewk_History_Item* item = _ewk_history_item_new(core.release().releaseRef()); + return item; +} + +static inline void _ewk_history_item_free(Ewk_History_Item* item, WebCore::HistoryItem* core) +{ + core->deref(); + free(item); +} + +/** + * Free given history item instance. + * + * @param item what to free. + */ +void ewk_history_item_free(Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core); + _ewk_history_item_free(item, core); +} + +/** + * Free given list and associated history items instances. + * + * @param history_items list of items to free (both list nodes and + * item instances). + */ +void ewk_history_item_list_free(Eina_List* history_items) +{ + void* d; + EINA_LIST_FREE(history_items, d) { + Ewk_History_Item* item = (Ewk_History_Item*)d; + _ewk_history_item_free(item, item->core); + } +} + +/** + * Query title for given history item. + * + * @param item history item to query. + * + * @return the title pointer, that may be @c NULL. This pointer is + * guaranteed to be eina_stringshare, so whenever possible + * save yourself some cpu cycles and use + * eina_stringshare_ref() instead of eina_stringshare_add() or + * strdup(). + */ +const char* ewk_history_item_title_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + // hide the following optimzation from outside + Ewk_History_Item* i = (Ewk_History_Item*)item; + eina_stringshare_replace(&i->title, core->title().utf8().data()); + return i->title; +} + +/** + * Query alternate title for given history item. + * + * @param item history item to query. + * + * @return the alternate title pointer, that may be @c NULL. This + * pointer is guaranteed to be eina_stringshare, so whenever + * possible save yourself some cpu cycles and use + * eina_stringshare_ref() instead of eina_stringshare_add() or + * strdup(). + */ +const char* ewk_history_item_title_alternate_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + // hide the following optimzation from outside + Ewk_History_Item* i = (Ewk_History_Item*)item; + eina_stringshare_replace(&i->alternate_title, + core->alternateTitle().utf8().data()); + return i->alternate_title; +} + +/** + * Set alternate title for given history item. + * + * @param item history item to query. + * @param title new alternate title to use for given item. No + * references are kept after this function returns. + */ +void ewk_history_item_title_alternate_set(Ewk_History_Item* item, const char* title) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core); + if (!eina_stringshare_replace(&item->alternate_title, title)) + return; + core->setAlternateTitle(WebCore::String::fromUTF8(title)); +} + +/** + * Query URI for given history item. + * + * @param item history item to query. + * + * @return the URI pointer, that may be @c NULL. This pointer is + * guaranteed to be eina_stringshare, so whenever possible + * save yourself some cpu cycles and use + * eina_stringshare_ref() instead of eina_stringshare_add() or + * strdup(). + */ +const char* ewk_history_item_uri_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + // hide the following optimzation from outside + Ewk_History_Item* i = (Ewk_History_Item*)item; + eina_stringshare_replace(&i->uri, core->urlString().utf8().data()); + return i->uri; +} + +/** + * Query original URI for given history item. + * + * @param item history item to query. + * + * @return the original URI pointer, that may be @c NULL. This pointer + * is guaranteed to be eina_stringshare, so whenever possible + * save yourself some cpu cycles and use + * eina_stringshare_ref() instead of eina_stringshare_add() or + * strdup(). + */ +const char* ewk_history_item_uri_original_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + // hide the following optimzation from outside + Ewk_History_Item* i = (Ewk_History_Item*)item; + eina_stringshare_replace(&i->original_uri, + core->originalURLString().utf8().data()); + return i->original_uri; +} + +/** + * Query last visited time for given history item. + * + * @param item history item to query. + * + * @return the time in seconds this item was visited. + */ +double ewk_history_item_time_last_visited_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0.0); + return core->lastVisitedTime(); +} + +/** + * Get the icon (aka favicon) associated with this history item. + * + * @note in order to have this working, one must open icon database + * with ewk_settings_icon_database_path_set(). + * + * @param item history item to query. + * + * @return the surface reference or @c NULL on errors. Note that the + * reference may be to a standard fallback icon. + */ +cairo_surface_t* ewk_history_item_icon_surface_get(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + WebCore::Image* icon = core->icon(); + if (!icon) { + ERR("icon is NULL."); + return 0; + } + return icon->nativeImageForCurrentFrame(); +} + +/** + * Add an Evas_Object of type 'image' to given canvas with history item icon. + * + * This is an utility function that creates an Evas_Object of type + * image set to have fill always match object size + * (evas_object_image_filled_add()), saving some code to use it from Evas. + * + * @note in order to have this working, one must open icon database + * with ewk_settings_icon_database_path_set(). + * + * @param item history item to query. + * @param canvas evas instance where to add resulting object. + * + * @return newly allocated Evas_Object instance or @c NULL on + * errors. Delete the object with evas_object_del(). + */ +Evas_Object* ewk_history_item_icon_object_add(const Ewk_History_Item* item, Evas* canvas) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0); + WebCore::Image* icon = core->icon(); + cairo_surface_t* surface; + + if (!icon) { + ERR("icon is NULL."); + return 0; + } + + surface = icon->nativeImageForCurrentFrame(); + return ewk_util_image_from_cairo_surface_add(canvas, surface); +} + +/** + * Query if given item is still in page cache. + * + * @param item history item to query. + * + * @return @c EINA_TRUE if in cache, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_history_item_page_cache_exists(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_FALSE); + return core->isInPageCache(); +} + +/** + * Query number of times item was visited. + * + * @param item history item to query. + * + * @return number of visits. + */ +int ewk_history_item_visit_count(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0); + return core->visitCount(); +} + +/** + * Query if last visit to item was failure or not. + * + * @param item history item to query. + * + * @return @c EINA_TRUE if last visit was failure, @c EINA_FALSE if it + * was fine. + */ +Eina_Bool ewk_history_item_visit_last_failed(const Ewk_History_Item* item) +{ + EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_TRUE); + return core->lastVisitWasFailure(); +} + + +/* internal methods ****************************************************/ +/** + * @internal + * + * Creates history for given view. Called internally by ewk_view and + * should never be called from outside. + * + * @param core WebCore::BackForwardList instance to use internally. + * + * @return newly allocated history instance or @c NULL on errors. + */ +Ewk_History* ewk_history_new(WebCore::BackForwardList* core) +{ + Ewk_History* history; + EINA_SAFETY_ON_NULL_RETURN_VAL(core, 0); + DBG("core=%p", core); + + history = (Ewk_History*)malloc(sizeof(Ewk_History)); + if (!history) { + CRITICAL("Could not allocate history memory."); + return 0; + } + + core->ref(); + history->core = core; + + return history; +} + +/** + * @internal + * + * Destroys previously allocated history instance. This is called + * automatically by ewk_view and should never be called from outside. + * + * @param history instance to free + */ +void ewk_history_free(Ewk_History* history) +{ + DBG("history=%p", history); + history->core->deref(); + free(history); +} diff --git a/WebKit/efl/ewk/ewk_history.h b/WebKit/efl/ewk/ewk_history.h new file mode 100644 index 0000000..3943d7e --- /dev/null +++ b/WebKit/efl/ewk/ewk_history.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_history_h +#define ewk_history_h + +#include "ewk_eapi.h" + +#include <Eina.h> +#include <Evas.h> +#include <cairo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The history (back-forward list) associated with a given ewk_view. + * + * Changing the history affects immediately the view, changing the + * current uri, for example. + * + * When ewk_view is navigated or uris are set, history automatically + * updates. That's why no direct access to history structure is + * allowed. + */ +typedef struct _Ewk_History Ewk_History; + +/** + * Represents one item from Ewk_History. + */ +typedef struct _Ewk_History_Item Ewk_History_Item; + + + +EAPI Eina_Bool ewk_history_forward(Ewk_History *history); +EAPI Eina_Bool ewk_history_back(Ewk_History *history); + +EAPI Eina_Bool ewk_history_history_item_add(Ewk_History *history, const Ewk_History_Item *item); +EAPI Eina_Bool ewk_history_history_item_set(Ewk_History *history, const Ewk_History_Item *item); +EAPI Ewk_History_Item *ewk_history_history_item_back_get(const Ewk_History *history); +EAPI Ewk_History_Item *ewk_history_history_item_current_get(const Ewk_History *history); +EAPI Ewk_History_Item *ewk_history_history_item_forward_get(const Ewk_History *history); +EAPI Ewk_History_Item *ewk_history_history_item_nth_get(const Ewk_History *history, int index); +EAPI Eina_Bool ewk_history_history_item_contains(const Ewk_History *history, const Ewk_History_Item *item); + +EAPI Eina_List *ewk_history_forward_list_get(const Ewk_History *history); +EAPI Eina_List *ewk_history_forward_list_get_with_limit(const Ewk_History *history, int limit); +EAPI int ewk_history_forward_list_length(const Ewk_History *history); + +EAPI Eina_List *ewk_history_back_list_get(const Ewk_History *history); +EAPI Eina_List *ewk_history_back_list_get_with_limit(const Ewk_History *history, int limit); +EAPI int ewk_history_back_list_length(const Ewk_History *history); + +EAPI int ewk_history_limit_get(Ewk_History *history); +EAPI Eina_Bool ewk_history_limit_set(const Ewk_History *history, int limit); + +EAPI Ewk_History_Item *ewk_history_item_new(const char *uri, const char *title); +EAPI void ewk_history_item_free(Ewk_History_Item *item); +EAPI void ewk_history_item_list_free(Eina_List *history_items); + +EAPI const char *ewk_history_item_title_get(const Ewk_History_Item *item); +EAPI const char *ewk_history_item_title_alternate_get(const Ewk_History_Item *item); +EAPI void ewk_history_item_title_alternate_set(Ewk_History_Item *item, const char *title); +EAPI const char *ewk_history_item_uri_get(const Ewk_History_Item *item); +EAPI const char *ewk_history_item_uri_original_get(const Ewk_History_Item *item); +EAPI double ewk_history_item_time_last_visited_get(const Ewk_History_Item *item); + +EAPI cairo_surface_t *ewk_history_item_icon_surface_get(const Ewk_History_Item *item); +EAPI Evas_Object *ewk_history_item_icon_object_add(const Ewk_History_Item *item, Evas *canvas); + +EAPI Eina_Bool ewk_history_item_page_cache_exists(const Ewk_History_Item *item); +EAPI int ewk_history_item_visit_count(const Ewk_History_Item *item); +EAPI Eina_Bool ewk_history_item_visit_last_failed(const Ewk_History_Item *item); + +#ifdef __cplusplus +} +#endif +#endif // ewk_history_h diff --git a/WebKit/efl/ewk/ewk_logging.h b/WebKit/efl/ewk/ewk_logging.h new file mode 100644 index 0000000..045bd9c --- /dev/null +++ b/WebKit/efl/ewk/ewk_logging.h @@ -0,0 +1,31 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_logging_h +#define ewk_logging_h + +extern int _ewk_log_dom; +#define CRITICAL(...) EINA_LOG_DOM_CRIT(_ewk_log_dom, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_ewk_log_dom, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_ewk_log_dom, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_ewk_log_dom, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_ewk_log_dom, __VA_ARGS__) + +#endif // ewk_logging_h diff --git a/WebKit/efl/ewk/ewk_main.cpp b/WebKit/efl/ewk/ewk_main.cpp new file mode 100644 index 0000000..2c69b36 --- /dev/null +++ b/WebKit/efl/ewk/ewk_main.cpp @@ -0,0 +1,152 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_main.h" + +#include "EWebKit.h" +#include "Logging.h" +#include "PageCache.h" +#include "PageGroup.h" +#include "ewk_private.h" +#include "runtime/InitializeThreading.h" + +#include <Ecore.h> +#include <Ecore_Evas.h> +#include <Edje.h> +#include <Eina.h> +#include <Evas.h> + +#ifdef ENABLE_GLIB_SUPPORT +#include <glib-object.h> +#include <glib.h> + +#ifdef ENABLE_GTK_PLUGINS_SUPPORT +#include <gtk/gtk.h> +#endif + +#endif + +// REMOVE-ME: see todo below +#include "ResourceHandle.h" +#include <libsoup/soup.h> + +static int _ewk_init_count = 0; +int _ewk_log_dom = -1; + +int ewk_init(void) +{ + if (_ewk_init_count) + return ++_ewk_init_count; + + if (!eina_init()) + goto error_eina; + + _ewk_log_dom = eina_log_domain_register("ewebkit", EINA_COLOR_ORANGE); + if (_ewk_log_dom < 0) { + EINA_LOG_CRIT("could not register log domain 'ewebkit'"); + goto error_log_domain; + } + + if (!evas_init()) { + CRITICAL("could not init evas."); + goto error_evas; + } + + if (!ecore_init()) { + CRITICAL("could not init ecore."); + goto error_ecore; + } + + if (!ecore_evas_init()) { + CRITICAL("could not init ecore_evas."); + goto error_ecore_evas; + } + + if (!edje_init()) { + CRITICAL("could not init edje."); + goto error_edje; + } + +#ifdef ENABLE_GLIB_SUPPORT + g_type_init(); + + if (!g_thread_supported()) + g_thread_init(0); + +#ifdef ENABLE_GTK_PLUGINS_SUPPORT + gdk_threads_init(); + if (!gtk_init_check(0, 0)) + WRN("Could not initialize GTK support."); +#endif + + if (!ecore_main_loop_glib_integrate()) + WRN("Ecore was not compiled with GLib support, some plugins will not " + "work (ie: Adobe Flash)"); +#endif + + JSC::initializeThreading(); + WebCore::InitializeLoggingChannelsIfNecessary(); + + // Page cache capacity (in pages). Comment from Mac port: + // (Research indicates that value / page drops substantially after 3 pages.) + // FIXME: Expose this with an API and/or calculate based on available resources + WebCore::pageCache()->setCapacity(3); + WebCore::PageGroup::setShouldTrackVisitedLinks(true); + + // TODO: this should move to WebCore, already reported to webkit-gtk folks: + if (1) { + SoupSession* session = WebCore::ResourceHandle::defaultSession(); + soup_session_add_feature_by_type(session, SOUP_TYPE_CONTENT_SNIFFER); + } + + return ++_ewk_init_count; + +error_edje: + ecore_evas_shutdown(); +error_ecore_evas: + ecore_shutdown(); +error_ecore: + evas_shutdown(); +error_evas: + eina_log_domain_unregister(_ewk_log_dom); + _ewk_log_dom = -1; +error_log_domain: + eina_shutdown(); +error_eina: + return 0; +} + +int ewk_shutdown(void) +{ + _ewk_init_count--; + if (_ewk_init_count) + return _ewk_init_count; + + ecore_evas_shutdown(); + ecore_shutdown(); + evas_shutdown(); + eina_log_domain_unregister(_ewk_log_dom); + _ewk_log_dom = -1; + eina_shutdown(); + + return 0; +} + diff --git a/WebKit/efl/ewk/ewk_main.h b/WebKit/efl/ewk/ewk_main.h new file mode 100644 index 0000000..3730e88 --- /dev/null +++ b/WebKit/efl/ewk/ewk_main.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_main_h +#define ewk_main_h + +#include "ewk_eapi.h" + +#ifdef __cplusplus +extern "C" { +#endif + +EAPI int ewk_init(void); +EAPI int ewk_shutdown(void); + +#ifdef __cplusplus +} +#endif +#endif // ewk_main_h diff --git a/WebKit/efl/ewk/ewk_private.h b/WebKit/efl/ewk/ewk_private.h new file mode 100644 index 0000000..947bd79 --- /dev/null +++ b/WebKit/efl/ewk/ewk_private.h @@ -0,0 +1,115 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_private_h +#define ewk_private_h + +#include "BackForwardList.h" +#include "EWebKit.h" +#include "Frame.h" +#include "Page.h" +#include "Settings.h" +#include "Widget.h" +#include "ewk_logging.h" +#include "ewk_util.h" + +#include <cairo.h> +#include <wtf/PassRefPtr.h> +#include <wtf/Vector.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// If defined, ewk will do type checking to ensure objects are of correct type +#define EWK_TYPE_CHECK 1 + +void ewk_view_ready(Evas_Object *o); +void ewk_view_title_set(Evas_Object *o, const char *title); +void ewk_view_uri_changed(Evas_Object *o); +void ewk_view_load_started(Evas_Object *o); +void ewk_view_frame_main_load_started(Evas_Object *o); +void ewk_view_load_finished(Evas_Object *o, const Ewk_Frame_Load_Error *error); +void ewk_view_load_error(Evas_Object *o, const Ewk_Frame_Load_Error *error); +void ewk_view_load_progress_changed(Evas_Object *o); + +void ewk_view_mouse_link_hover_in(Evas_Object *o, void *data); +void ewk_view_mouse_link_hover_out(Evas_Object *o); + +void ewk_view_toolbars_visible_set(Evas_Object *o, Eina_Bool visible); +void ewk_view_toolbars_visible_get(Evas_Object *o, Eina_Bool *visible); + +void ewk_view_statusbar_visible_set(Evas_Object *o, Eina_Bool visible); +void ewk_view_statusbar_visible_get(Evas_Object *o, Eina_Bool *visible); +void ewk_view_statusbar_text_set(Evas_Object *o, const char *text); + +void ewk_view_scrollbars_visible_set(Evas_Object *o, Eina_Bool visible); +void ewk_view_scrollbars_visible_get(Evas_Object *o, Eina_Bool *visible); + +void ewk_view_menubar_visible_set(Evas_Object *o, Eina_Bool visible); +void ewk_view_menubar_visible_get(Evas_Object *o, Eina_Bool *visible); + +void ewk_view_tooltip_text_set(Evas_Object *o, const char *text); + +void ewk_view_add_console_message(Evas_Object *o, const char *message, unsigned int lineNumber, const char *sourceID); + +void ewk_view_run_javascript_alert(Evas_Object *o, Evas_Object *frame, const char *message); +Eina_Bool ewk_view_run_javascript_confirm(Evas_Object *o, Evas_Object *frame, const char *message); +Eina_Bool ewk_view_run_javascript_prompt(Evas_Object *o, Evas_Object *frame, const char *message, const char *defaultValue, char **value); +Eina_Bool ewk_view_should_interrupt_javascript(Evas_Object *o); +void ewk_view_exceeded_database_quota(Evas_Object *o, Evas_Object *frame, const char *databaseName); + +void ewk_view_repaint(Evas_Object *o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h); +void ewk_view_scroll(Evas_Object *o, Evas_Coord dx, Evas_Coord dy, Evas_Coord sx, Evas_Coord sy, Evas_Coord sw, Evas_Coord sh, Evas_Coord cx, Evas_Coord cy, Evas_Coord cw, Evas_Coord ch, Eina_Bool main_frame); +WebCore::Page *ewk_view_core_page_get(const Evas_Object *o); + +WTF::PassRefPtr<WebCore::Frame> ewk_view_frame_create(Evas_Object *o, Evas_Object *frame, const WebCore::String& name, WebCore::HTMLFrameOwnerElement* ownerElement, const WebCore::KURL& url, const WebCore::String& referrer); + +WTF::PassRefPtr<WebCore::Widget> ewk_view_plugin_create(Evas_Object* o, Evas_Object* frame, const WebCore::IntSize& pluginSize, WebCore::HTMLPlugInElement* element, const WebCore::KURL& url, const WTF::Vector<WebCore::String>& paramNames, const WTF::Vector<WebCore::String>& paramValues, const WebCore::String& mimeType, bool loadManually); + +Ewk_History *ewk_history_new(WebCore::BackForwardList *history); +void ewk_history_free(Ewk_History *history); + +Evas_Object *ewk_frame_add(Evas *e); +Eina_Bool ewk_frame_init(Evas_Object *o, Evas_Object *view, WebCore::Frame *frame); +Evas_Object *ewk_frame_child_add(Evas_Object *o, WTF::PassRefPtr<WebCore::Frame> child, const WebCore::String& name, const WebCore::KURL& url, const WebCore::String& referrer); + +WebCore::Frame *ewk_frame_core_get(const Evas_Object *o); +void ewk_frame_core_gone(Evas_Object *o); + +void ewk_frame_load_started(Evas_Object *o); +void ewk_frame_load_finished(Evas_Object *o, const char *error_domain, int error_code, Eina_Bool is_cancellation, const char *error_description, const char *failing_url); +void ewk_frame_load_error(Evas_Object *o, const char *error_domain, int error_code, Eina_Bool is_cancellation, const char *error_description, const char *failing_url); +void ewk_frame_load_progress_changed(Evas_Object *o); + +void ewk_frame_contents_size_changed(Evas_Object *o, Evas_Coord w, Evas_Coord h); +void ewk_frame_title_set(Evas_Object *o, const char *title); + +void ewk_frame_view_create_for_view(Evas_Object *o, Evas_Object *view); +Eina_Bool ewk_frame_uri_changed(Evas_Object *o); +void ewk_frame_force_layout(Evas_Object *o); + +WTF::PassRefPtr<WebCore::Widget> ewk_frame_plugin_create(Evas_Object* o, const WebCore::IntSize& pluginSize, WebCore::HTMLPlugInElement* element, const WebCore::KURL& url, const WTF::Vector<WebCore::String>& paramNames, const WTF::Vector<WebCore::String>& paramValues, const WebCore::String& mimeType, bool loadManually); + +#ifdef __cplusplus + +} +#endif +#endif // ewk_private_h diff --git a/WebKit/efl/ewk/ewk_settings.cpp b/WebKit/efl/ewk/ewk_settings.cpp new file mode 100644 index 0000000..0822dc2 --- /dev/null +++ b/WebKit/efl/ewk/ewk_settings.cpp @@ -0,0 +1,190 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_settings.h" + +#include "EWebKit.h" +#include "IconDatabase.h" +#include "Image.h" +#include "IntSize.h" +#include "KURL.h" +#include "ewk_private.h" +#include <wtf/text/CString.h> + +#include <eina_safety_checks.h> +#include <errno.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +static uint64_t _ewk_default_web_database_quota = 1 * 1024; + +/** + * Returns the default quota for Web Database databases. By default + * this value is 1MB. + * + * @return the current default database quota in bytes + **/ +uint64_t ewk_settings_web_database_default_quota_get() +{ + return _ewk_default_web_database_quota; +} + +/** + * Sets directory where to store icon database, opening database. + * + * @param directory where to store icon database, must be + * write-able. If @c NULL is given, then database is closed. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on errors. + */ +Eina_Bool ewk_settings_icon_database_path_set(const char *directory) +{ + WebCore::iconDatabase()->delayDatabaseCleanup(); + + if (directory) { + struct stat st; + + if (stat(directory, &st)) { + ERR("could not stat(%s): %s", directory, strerror(errno)); + return EINA_FALSE; + } + + if (!S_ISDIR(st.st_mode)) { + ERR("not a directory: %s", directory); + return EINA_FALSE; + } + + if (access(directory, R_OK | W_OK)) { + ERR("could not access directory '%s' for read and write: %s", + directory, strerror(errno)); + return EINA_FALSE; + } + + WebCore::iconDatabase()->setEnabled(true); + WebCore::iconDatabase()->open(WebCore::String::fromUTF8(directory)); + } else { + WebCore::iconDatabase()->setEnabled(false); + WebCore::iconDatabase()->close(); + } + return EINA_TRUE; +} + +/** + * Return directory path where icon database is stored. + * + * @return newly allocated string with database path or @c NULL if + * none is set or database is closed. Note that return must be + * freed with free() as it's a strdup()ed copy of the string + * due reference counting. + */ +char* ewk_settings_icon_database_path_get(void) +{ + if (!WebCore::iconDatabase()->isEnabled()) + return 0; + if (!WebCore::iconDatabase()->isOpen()) + return 0; + + WebCore::String path = WebCore::iconDatabase()->databasePath(); + if (path.isEmpty()) + return 0; + return strdup(path.utf8().data()); +} + +/** + * Remove all known icons from database. + * + * Database must be opened with ewk_settings_icon_database_path_set() + * in order to work. + * + * @return @c EINA_TRUE on success or @c EINA_FALSE otherwise, like + * closed database. + */ +Eina_Bool ewk_settings_icon_database_clear(void) +{ + if (!WebCore::iconDatabase()->isEnabled()) + return EINA_FALSE; + if (!WebCore::iconDatabase()->isOpen()) + return EINA_FALSE; + + WebCore::iconDatabase()->removeAllIcons(); + return EINA_TRUE; +} + +/** + * Query icon for given URL, returning associated cairo surface. + * + * @note in order to have this working, one must open icon database + * with ewk_settings_icon_database_path_set(). + * + * @param url which url to query icon. + * + * @return cairo surface if any, or NULL on failure. + */ +cairo_surface_t* ewk_settings_icon_database_icon_surface_get(const char *url) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(url, 0); + + WebCore::KURL kurl(WebCore::KURL(), WebCore::String::fromUTF8(url)); + WebCore::Image *icon = WebCore::iconDatabase()->iconForPageURL(kurl.string(), WebCore::IntSize(16, 16)); + + if (!icon) { + ERR("no icon for url %s", url); + return 0; + } + + return icon->nativeImageForCurrentFrame(); +} + +/** + * Create Evas_Object of type image representing the given URL. + * + * This is an utility function that creates an Evas_Object of type + * image set to have fill always match object size + * (evas_object_image_filled_add()), saving some code to use it from Evas. + * + * @note in order to have this working, one must open icon database + * with ewk_settings_icon_database_path_set(). + * + * @param url which url to query icon. + * @param canvas evas instance where to add resulting object. + * + * @return newly allocated Evas_Object instance or @c NULL on + * errors. Delete the object with evas_object_del(). + */ +Evas_Object* ewk_settings_icon_database_icon_object_add(const char* url, Evas* canvas) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(url, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0); + + WebCore::KURL kurl(WebCore::KURL(), WebCore::String::fromUTF8(url)); + WebCore::Image* icon = WebCore::iconDatabase()->iconForPageURL(kurl.string(), WebCore::IntSize(16, 16)); + cairo_surface_t* surface; + + if (!icon) { + ERR("no icon for url %s", url); + return 0; + } + + surface = icon->nativeImageForCurrentFrame(); + return ewk_util_image_from_cairo_surface_add(canvas, surface); +} diff --git a/WebKit/efl/ewk/ewk_settings.h b/WebKit/efl/ewk/ewk_settings.h new file mode 100644 index 0000000..e843fd1 --- /dev/null +++ b/WebKit/efl/ewk/ewk_settings.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_settings_h +#define ewk_settings_h + +#include "ewk_eapi.h" + +#include <Eina.h> +#include <Evas.h> +#include <cairo.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file + * + * General purpose settings, not tied to any view object. + */ + +EAPI uint64_t ewk_settings_web_database_default_quota_get(); + +EAPI Eina_Bool ewk_settings_icon_database_path_set(const char *path); +EAPI char *ewk_settings_icon_database_path_get(void); +EAPI Eina_Bool ewk_settings_icon_database_clear(void); + +EAPI cairo_surface_t *ewk_settings_icon_database_icon_surface_get(const char *url); +EAPI Evas_Object *ewk_settings_icon_database_icon_object_add(const char *url, Evas *canvas); + + +#ifdef __cplusplus +} +#endif +#endif // ewk_settings_h diff --git a/WebKit/efl/ewk/ewk_util.cpp b/WebKit/efl/ewk/ewk_util.cpp new file mode 100644 index 0000000..bf82695 --- /dev/null +++ b/WebKit/efl/ewk/ewk_util.cpp @@ -0,0 +1,98 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_util.h" + +#include "ewk_private.h" +#include <eina_safety_checks.h> + +Evas_Object* ewk_util_image_from_cairo_surface_add(Evas* canvas, cairo_surface_t* surface) +{ + cairo_status_t status; + cairo_surface_type_t type; + cairo_format_t format; + int w, h, stride; + Evas_Object* image; + const void* src; + void* dst; + + EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(surface, 0); + + status = cairo_surface_status(surface); + if (status != CAIRO_STATUS_SUCCESS) { + ERR("cairo surface is invalid: %s", cairo_status_to_string(status)); + return 0; + } + + type = cairo_surface_get_type(surface); + if (type != CAIRO_SURFACE_TYPE_IMAGE) { + ERR("unknown surface type %d, required %d (CAIRO_SURFACE_TYPE_IMAGE).", + type, CAIRO_SURFACE_TYPE_IMAGE); + return 0; + } + + format = cairo_image_surface_get_format(surface); + if (format != CAIRO_FORMAT_ARGB32 && format != CAIRO_FORMAT_RGB24) { + ERR("unknown surface format %d, expected %d or %d.", + format, CAIRO_FORMAT_ARGB32, CAIRO_FORMAT_RGB24); + return 0; + } + + w = cairo_image_surface_get_width(surface); + h = cairo_image_surface_get_height(surface); + stride = cairo_image_surface_get_stride(surface); + if (w <= 0 || h <= 0 || stride <= 0) { + ERR("invalid image size %dx%d, stride=%d", w, h, stride); + return 0; + } + + src = cairo_image_surface_get_data(surface); + if (!src) { + ERR("could not get source data."); + return 0; + } + + image = evas_object_image_filled_add(canvas); + if (!image) { + ERR("could not add image to canvas."); + return 0; + } + + evas_object_image_colorspace_set(image, EVAS_COLORSPACE_ARGB8888); + evas_object_image_size_set(image, w, h); + evas_object_image_alpha_set(image, format == CAIRO_FORMAT_ARGB32); + + if (evas_object_image_stride_get(image) * 4 != stride) { + ERR("evas' stride %d diverges from cairo's %d.", + evas_object_image_stride_get(image) * 4, stride); + evas_object_del(image); + return 0; + } + + dst = evas_object_image_data_get(image, EINA_TRUE); + memcpy(dst, src, h * stride); + evas_object_image_data_set(image, dst); + + evas_object_resize(image, w, h); // helpful but not really required + + return image; +} diff --git a/WebKit/efl/ewk/ewk_util.h b/WebKit/efl/ewk/ewk_util.h new file mode 100644 index 0000000..d9c8f9c --- /dev/null +++ b/WebKit/efl/ewk/ewk_util.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_util_h +#define ewk_util_h + +#include <Evas.h> +#include <cairo.h> + +Evas_Object* ewk_util_image_from_cairo_surface_add(Evas* canvas, cairo_surface_t* surface); + +#endif // ewk_util_h diff --git a/WebKit/efl/ewk/ewk_view.cpp b/WebKit/efl/ewk/ewk_view.cpp new file mode 100644 index 0000000..eeb6535 --- /dev/null +++ b/WebKit/efl/ewk/ewk_view.cpp @@ -0,0 +1,3644 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_view.h" + +#include "ChromeClientEfl.h" +#include "ContextMenuClientEfl.h" +#include "DocumentLoader.h" +#include "DragClientEfl.h" +#include "EWebKit.h" +#include "EditorClientEfl.h" +#include "FocusController.h" +#include "FrameLoaderClientEfl.h" +#include "FrameView.h" +#include "GraphicsContext.h" +#include "InspectorClientEfl.h" +#include "PopupMenuClient.h" +#include "ProgressTracker.h" +#include "ewk_private.h" + +#include <Ecore.h> +#include <Eina.h> +#include <Evas.h> +#include <eina_safety_checks.h> +#include <sys/time.h> + +#define ZOOM_MIN (0.05) +#define ZOOM_MAX (4.0) + +static const char EWK_VIEW_TYPE_STR[] = "EWK_View"; + +static const size_t EWK_VIEW_REPAINTS_SIZE_INITIAL = 32; +static const size_t EWK_VIEW_REPAINTS_SIZE_STEP = 8; +static const size_t EWK_VIEW_REPAINTS_SIZE_MAX_FREE = 64; + +static const size_t EWK_VIEW_SCROLLS_SIZE_INITIAL = 8; +static const size_t EWK_VIEW_SCROLLS_SIZE_STEP = 2; +static const size_t EWK_VIEW_SCROLLS_SIZE_MAX_FREE = 32; + +struct _Ewk_View_Private_Data { + WebCore::Page* page; + WebCore::Settings* page_settings; + WebCore::Frame* main_frame; + Ewk_History* history; + struct { + Ewk_Menu menu; + WebCore::PopupMenuClient* menu_client; + } popup; + struct { + Eina_Rectangle* array; + size_t count; + size_t allocated; + } repaints; + struct { + Ewk_Scroll_Request* array; + size_t count; + size_t allocated; + } scrolls; + struct { + const char* user_agent; + const char* user_stylesheet; + const char* encoding_default; + const char* encoding_custom; + int font_minimum_size; + int font_minimum_logical_size; + int font_default_size; + int font_monospace_size; + const char* font_standard; + const char* font_cursive; + const char* font_monospace; + const char* font_fantasy; + const char* font_serif; + const char* font_sans_serif; + Eina_Bool auto_load_images:1; + Eina_Bool auto_shrink_images:1; + Eina_Bool enable_scripts:1; + Eina_Bool enable_plugins:1; + Eina_Bool scripts_window_open:1; + Eina_Bool resizable_textareas:1; + Eina_Bool private_browsing:1; + Eina_Bool caret_browsing:1; + } settings; + struct { + struct { + double start; + double end; + double duration; + } time; + struct { + float start; + float end; + float range; + } zoom; + struct { + Evas_Coord x, y; + } center; + Ecore_Animator* animator; + } animated_zoom; + struct { + Evas_Coord w, h; + Eina_Bool use:1; + } fixed_layout; +}; + +#ifndef EWK_TYPE_CHECK +#define EWK_VIEW_TYPE_CHECK(o, ...) do { } while (0) +#else +#define EWK_VIEW_TYPE_CHECK(o, ...) \ + do { \ + const char* _tmp_otype = evas_object_type_get(o); \ + const Evas_Smart* _tmp_s = evas_object_smart_smart_get(o); \ + if (EINA_UNLIKELY(!_tmp_s)) { \ + EINA_LOG_CRIT \ + ("%p (%s) is not a smart object!", o, \ + _tmp_otype ? _tmp_otype : "(null)"); \ + return __VA_ARGS__; \ + } \ + const Evas_Smart_Class* _tmp_sc = evas_smart_class_get(_tmp_s); \ + if (EINA_UNLIKELY(!_tmp_sc)) { \ + EINA_LOG_CRIT \ + ("%p (%s) is not a smart object!", o, \ + _tmp_otype ? _tmp_otype : "(null)"); \ + return __VA_ARGS__; \ + } \ + if (EINA_UNLIKELY(_tmp_sc->data != EWK_VIEW_TYPE_STR)) { \ + EINA_LOG_CRIT \ + ("%p (%s) is not of an ewk_view (need %p, got %p)!", \ + o, _tmp_otype ? _tmp_otype : "(null)", \ + EWK_VIEW_TYPE_STR, _tmp_sc->data); \ + return __VA_ARGS__; \ + } \ + } while (0) +#endif + +#define EWK_VIEW_SD_GET(o, ptr) \ + Ewk_View_Smart_Data* ptr = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o) + +#define EWK_VIEW_SD_GET_OR_RETURN(o, ptr, ...) \ + EWK_VIEW_TYPE_CHECK(o, __VA_ARGS__); \ + EWK_VIEW_SD_GET(o, ptr); \ + if (!ptr) { \ + CRITICAL("no smart data for object %p (%s)", \ + o, evas_object_type_get(o)); \ + return __VA_ARGS__; \ + } + +#define EWK_VIEW_PRIV_GET(sd, ptr) \ + Ewk_View_Private_Data* ptr = sd->_priv + +#define EWK_VIEW_PRIV_GET_OR_RETURN(sd, ptr, ...) \ + EWK_VIEW_PRIV_GET(sd, ptr); \ + if (!ptr) { \ + CRITICAL("no private data for object %p (%s)", \ + sd->self, evas_object_type_get(sd->self)); \ + return __VA_ARGS__; \ + } + +static void _ewk_view_smart_changed(Ewk_View_Smart_Data* sd) +{ + if (sd->changed.any) + return; + sd->changed.any = EINA_TRUE; + evas_object_smart_changed(sd->self); +} + +static Eina_Bool _ewk_view_repaints_resize(Ewk_View_Private_Data* priv, size_t size) +{ + void* tmp = realloc(priv->repaints.array, size * sizeof(Eina_Rectangle)); + if (!tmp) { + CRITICAL("could not realloc repaints array to %zu elements.", size); + return EINA_FALSE; + } + priv->repaints.allocated = size; + priv->repaints.array = (Eina_Rectangle*)tmp; + return EINA_TRUE; +} + +static void _ewk_view_repaint_add(Ewk_View_Private_Data* priv, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) +{ + Eina_Rectangle* r; + + // fprintf(stderr, ">>> repaint requested: %d,%d+%dx%d\n", x, y, w, h); + if (priv->repaints.allocated == priv->repaints.count) { + size_t size; + if (!priv->repaints.allocated) + size = EWK_VIEW_REPAINTS_SIZE_INITIAL; + else + size = priv->repaints.allocated + EWK_VIEW_REPAINTS_SIZE_STEP; + if (!_ewk_view_repaints_resize(priv, size)) + return; + } + + r = priv->repaints.array + priv->repaints.count; + priv->repaints.count++; + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + + DBG("add repaint %d,%d+%dx%d", x, y, w, h); +} + +static void _ewk_view_repaints_flush(Ewk_View_Private_Data* priv) +{ + priv->repaints.count = 0; + if (priv->repaints.allocated <= EWK_VIEW_REPAINTS_SIZE_MAX_FREE) + return; + _ewk_view_repaints_resize(priv, EWK_VIEW_REPAINTS_SIZE_MAX_FREE); +} + +static Eina_Bool _ewk_view_scrolls_resize(Ewk_View_Private_Data* priv, size_t size) +{ + void* tmp = realloc(priv->scrolls.array, size * sizeof(Ewk_Scroll_Request)); + if (!tmp) { + CRITICAL("could not realloc scrolls array to %zu elements.", size); + return EINA_FALSE; + } + priv->scrolls.allocated = size; + priv->scrolls.array = (Ewk_Scroll_Request*)tmp; + return EINA_TRUE; +} + +static void _ewk_view_scroll_add(Ewk_View_Private_Data* priv, Evas_Coord dx, Evas_Coord dy, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, Eina_Bool main_scroll) +{ + Ewk_Scroll_Request* r; + Ewk_Scroll_Request* r_end; + Evas_Coord x2 = x + w, y2 = y + h; + + r = priv->scrolls.array; + r_end = r + priv->scrolls.count; + for (; r < r_end; r++) { + if (r->x == x && r->y == y && r->w == w && r->h == h) { + DBG("region already scrolled %d,%d+%dx%d %+03d,%+03d add " + "%+03d,%+03d", + r->x, r->y, r->w, r->h, r->dx, r->dy, dx, dy); + r->dx += dx; + r->dy += dy; + return; + } + if ((x <= r->x && x2 >= r->x2) && (y <= r->y && y2 >= r->y2)) { + DBG("old viewport (%d,%d+%dx%d %+03d,%+03d) was scrolled itself, " + "add %+03d,%+03d", + r->x, r->y, r->w, r->h, r->dx, r->dy, dx, dy); + r->x += dx; + r->y += dy; + } + } + + if (priv->scrolls.allocated == priv->scrolls.count) { + size_t size; + if (!priv->scrolls.allocated) + size = EWK_VIEW_SCROLLS_SIZE_INITIAL; + else + size = priv->scrolls.allocated + EWK_VIEW_SCROLLS_SIZE_STEP; + if (!_ewk_view_scrolls_resize(priv, size)) + return; + } + + r = priv->scrolls.array + priv->scrolls.count; + priv->scrolls.count++; + + r->x = x; + r->y = y; + r->w = w; + r->h = h; + r->x2 = x2; + r->y2 = y2; + r->dx = dx; + r->dy = dy; + r->main_scroll = main_scroll; + DBG("add scroll in region: %d,%d+%dx%d %+03d,%+03d", x, y, w, h, dx, dy); + + Eina_Rectangle* pr; + Eina_Rectangle* pr_end; + size_t count; + pr = priv->repaints.array; + count = priv->repaints.count; + pr_end = pr + count; + for (; pr < pr_end; pr++) { + pr->x += dx; + pr->y += dy; + } +} + +static void _ewk_view_scrolls_flush(Ewk_View_Private_Data* priv) +{ + priv->scrolls.count = 0; + if (priv->scrolls.allocated <= EWK_VIEW_SCROLLS_SIZE_MAX_FREE) + return; + _ewk_view_scrolls_resize(priv, EWK_VIEW_SCROLLS_SIZE_MAX_FREE); +} + +// Default Event Handling ////////////////////////////////////////////// +static Eina_Bool _ewk_view_smart_focus_in(Ewk_View_Smart_Data* sd) +{ + EWK_VIEW_PRIV_GET(sd, priv); + WebCore::FocusController* fc = priv->page->focusController(); + DBG("o=%p, fc=%p", sd->self, fc); + EINA_SAFETY_ON_NULL_RETURN_VAL(fc, EINA_FALSE); + + fc->setActive(true); + fc->setFocused(true); + return EINA_TRUE; +} + +static Eina_Bool _ewk_view_smart_focus_out(Ewk_View_Smart_Data* sd) +{ + EWK_VIEW_PRIV_GET(sd, priv); + WebCore::FocusController* fc = priv->page->focusController(); + DBG("o=%p, fc=%p", sd->self, fc); + EINA_SAFETY_ON_NULL_RETURN_VAL(fc, EINA_FALSE); + + fc->setActive(false); + fc->setFocused(false); + return EINA_TRUE; +} + +static Eina_Bool _ewk_view_smart_mouse_wheel(Ewk_View_Smart_Data* sd, const Evas_Event_Mouse_Wheel* ev) +{ + return ewk_frame_feed_mouse_wheel(sd->main_frame, ev); +} + +static Eina_Bool _ewk_view_smart_mouse_down(Ewk_View_Smart_Data* sd, const Evas_Event_Mouse_Down* ev) +{ + return ewk_frame_feed_mouse_down(sd->main_frame, ev); +} + +static Eina_Bool _ewk_view_smart_mouse_up(Ewk_View_Smart_Data* sd, const Evas_Event_Mouse_Up* ev) +{ + return ewk_frame_feed_mouse_up(sd->main_frame, ev); +} + +static Eina_Bool _ewk_view_smart_mouse_move(Ewk_View_Smart_Data* sd, const Evas_Event_Mouse_Move* ev) +{ + return ewk_frame_feed_mouse_move(sd->main_frame, ev); +} + +static Eina_Bool _ewk_view_smart_key_down(Ewk_View_Smart_Data* sd, const Evas_Event_Key_Down* ev) +{ + Evas_Object* frame = ewk_view_frame_focused_get(sd->self); + + if (!frame) + frame = sd->main_frame; + + return ewk_frame_feed_key_down(frame, ev); +} + +static Eina_Bool _ewk_view_smart_key_up(Ewk_View_Smart_Data* sd, const Evas_Event_Key_Up* ev) +{ + Evas_Object* frame = ewk_view_frame_focused_get(sd->self); + + if (!frame) + frame = sd->main_frame; + + return ewk_frame_feed_key_up(frame, ev); +} + +static void _ewk_view_smart_add_console_message(Ewk_View_Smart_Data* sd, const char* message, unsigned int lineNumber, const char* sourceID) +{ + INF("console message: %s @%d: %s\n", sourceID, lineNumber, message); +} + +static void _ewk_view_smart_run_javascript_alert(Ewk_View_Smart_Data* sd, Evas_Object* frame, const char* message) +{ + INF("javascript alert: %s\n", message); +} + +static Eina_Bool _ewk_view_smart_run_javascript_confirm(Ewk_View_Smart_Data* sd, Evas_Object* frame, const char* message) +{ + INF("javascript confirm: %s", message); + INF("javascript confirm (HARD CODED)? YES"); + return EINA_TRUE; +} + +static Eina_Bool _ewk_view_smart_should_interrupt_javascript(Ewk_View_Smart_Data* sd) +{ + INF("should interrupt javascript?\n" + "\t(HARD CODED) NO"); + return EINA_FALSE; +} + +static Eina_Bool _ewk_view_smart_run_javascript_prompt(Ewk_View_Smart_Data* sd, Evas_Object* frame, const char* message, const char* defaultValue, char** value) +{ + *value = strdup("test"); + Eina_Bool ret = EINA_TRUE; + INF("javascript prompt:\n" + "\t message: %s\n" + "\tdefault value: %s\n" + "\tgiving answer: %s\n" + "\t button: %s", message, defaultValue, *value, ret?"ok":"cancel"); + + return ret; +} + +// Event Handling ////////////////////////////////////////////////////// +static void _ewk_view_on_focus_in(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->focus_in); + sd->api->focus_in(sd); +} + +static void _ewk_view_on_focus_out(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->focus_out); + sd->api->focus_out(sd); +} + +static void _ewk_view_on_mouse_wheel(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Mouse_Wheel* ev = (Evas_Event_Mouse_Wheel*)event_info; + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->mouse_wheel); + sd->api->mouse_wheel(sd, ev); +} + +static void _ewk_view_on_mouse_down(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Mouse_Down* ev = (Evas_Event_Mouse_Down*)event_info; + Ewk_View_Smart_Data* sd = (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, ev); +} + +static void _ewk_view_on_mouse_up(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Mouse_Up* ev = (Evas_Event_Mouse_Up*)event_info; + Ewk_View_Smart_Data* sd = (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, ev); +} + +static void _ewk_view_on_mouse_move(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Mouse_Move* ev = (Evas_Event_Mouse_Move*)event_info; + Ewk_View_Smart_Data* sd = (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, ev); +} + +static void _ewk_view_on_key_down(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Key_Down* ev = (Evas_Event_Key_Down*)event_info; + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->key_down); + sd->api->key_down(sd, ev); +} + +static void _ewk_view_on_key_up(void* data, Evas* e, Evas_Object* o, void* event_info) +{ + Evas_Event_Key_Up* ev = (Evas_Event_Key_Up*)event_info; + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->key_up); + sd->api->key_up(sd, ev); +} + +static WTF::PassRefPtr<WebCore::Frame> _ewk_view_core_frame_new(Ewk_View_Smart_Data* sd, Ewk_View_Private_Data* priv, WebCore::HTMLFrameOwnerElement* owner) +{ + WebCore::FrameLoaderClientEfl* flc = new WebCore::FrameLoaderClientEfl(sd->self); + if (!flc) { + CRITICAL("Could not create frame loader client."); + return 0; + } + flc->setCustomUserAgent(WebCore::String::fromUTF8(priv->settings.user_agent)); + + return WebCore::Frame::create(priv->page, owner, flc); +} + +static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_0; + +static Ewk_View_Private_Data* _ewk_view_priv_new(Ewk_View_Smart_Data* sd) +{ + Ewk_View_Private_Data* priv = + (Ewk_View_Private_Data*)calloc(1, sizeof(Ewk_View_Private_Data)); + WebCore::AtomicString s; + WebCore::KURL url; + + if (!priv) { + CRITICAL("could not allocate Ewk_View_Private_Data"); + return 0; + } + priv->page = new WebCore::Page( + static_cast<WebCore::ChromeClient*>(new WebCore::ChromeClientEfl(sd->self)), + static_cast<WebCore::ContextMenuClient*>(new WebCore::ContextMenuClientEfl(sd->self)), + static_cast<WebCore::EditorClient*>(new WebCore::EditorClientEfl(sd->self)), + static_cast<WebCore::DragClient*>(new WebCore::DragClientEfl), + static_cast<WebCore::InspectorClient*>(new WebCore::InspectorClientEfl), + 0, + 0); + if (!priv->page) { + CRITICAL("Could not create WebKit Page"); + goto error_page; + } + + priv->page_settings = priv->page->settings(); + if (!priv->page_settings) { + CRITICAL("Could not get page settings."); + goto error_settings; + } + + priv->page_settings->setLoadsImagesAutomatically(true); + priv->page_settings->setDefaultFixedFontSize(12); + priv->page_settings->setDefaultFontSize(16); + priv->page_settings->setSerifFontFamily("serif"); + priv->page_settings->setFixedFontFamily("monotype"); + priv->page_settings->setSansSerifFontFamily("sans"); + priv->page_settings->setStandardFontFamily("sans"); + priv->page_settings->setJavaScriptEnabled(true); + priv->page_settings->setPluginsEnabled(true); + + url = priv->page_settings->userStyleSheetLocation(); + priv->settings.user_stylesheet = eina_stringshare_add(url.prettyURL().utf8().data()); + + priv->settings.encoding_default = eina_stringshare_add + (priv->page_settings->defaultTextEncodingName().utf8().data()); + priv->settings.encoding_custom = 0; + + priv->settings.font_minimum_size = priv->page_settings->minimumFontSize(); + priv->settings.font_minimum_logical_size = priv->page_settings->minimumLogicalFontSize(); + priv->settings.font_default_size = priv->page_settings->defaultFontSize(); + priv->settings.font_monospace_size = priv->page_settings->defaultFixedFontSize(); + + s = priv->page_settings->standardFontFamily(); + priv->settings.font_standard = eina_stringshare_add(s.string().utf8().data()); + s = priv->page_settings->cursiveFontFamily(); + priv->settings.font_cursive = eina_stringshare_add(s.string().utf8().data()); + s = priv->page_settings->fixedFontFamily(); + priv->settings.font_monospace = eina_stringshare_add(s.string().utf8().data()); + s = priv->page_settings->fantasyFontFamily(); + priv->settings.font_fantasy = eina_stringshare_add(s.string().utf8().data()); + s = priv->page_settings->serifFontFamily(); + priv->settings.font_serif = eina_stringshare_add(s.string().utf8().data()); + s = priv->page_settings->sansSerifFontFamily(); + priv->settings.font_sans_serif = eina_stringshare_add(s.string().utf8().data()); + + priv->settings.auto_load_images = priv->page_settings->loadsImagesAutomatically(); + priv->settings.auto_shrink_images = priv->page_settings->shrinksStandaloneImagesToFit(); + priv->settings.enable_scripts = priv->page_settings->isJavaScriptEnabled(); + priv->settings.enable_plugins = priv->page_settings->arePluginsEnabled(); + priv->settings.scripts_window_open = priv->page_settings->allowScriptsToCloseWindows(); + priv->settings.resizable_textareas = priv->page_settings->textAreasAreResizable(); + priv->settings.private_browsing = priv->page_settings->privateBrowsingEnabled(); + priv->settings.caret_browsing = priv->page_settings->caretBrowsingEnabled(); + + priv->main_frame = _ewk_view_core_frame_new(sd, priv, 0).get(); + if (!priv->main_frame) { + CRITICAL("Could not create main frame."); + goto error_main_frame; + } + + priv->history = ewk_history_new(priv->page->backForwardList()); + if (!priv->history) { + CRITICAL("Could not create history instance for view."); + goto error_history; + } + + return priv; + +error_history: + // delete priv->main_frame; /* do not delete priv->main_frame */ +error_main_frame: +error_settings: + delete priv->page; +error_page: + free(priv); + return 0; +} + +static void _ewk_view_priv_del(Ewk_View_Private_Data* priv) +{ + if (!priv) + return; + + /* do not delete priv->main_frame */ + + free(priv->repaints.array); + free(priv->scrolls.array); + + eina_stringshare_del(priv->settings.user_agent); + eina_stringshare_del(priv->settings.user_stylesheet); + eina_stringshare_del(priv->settings.encoding_default); + eina_stringshare_del(priv->settings.encoding_custom); + eina_stringshare_del(priv->settings.font_standard); + eina_stringshare_del(priv->settings.font_cursive); + eina_stringshare_del(priv->settings.font_monospace); + eina_stringshare_del(priv->settings.font_fantasy); + eina_stringshare_del(priv->settings.font_serif); + eina_stringshare_del(priv->settings.font_sans_serif); + + if (priv->animated_zoom.animator) + ecore_animator_del(priv->animated_zoom.animator); + + ewk_history_free(priv->history); + + delete priv->page; + free(priv); +} + +static void _ewk_view_smart_add(Evas_Object* o) +{ + const Evas_Smart* smart = evas_object_smart_smart_get(o); + const Evas_Smart_Class* sc = evas_smart_class_get(smart); + const Ewk_View_Smart_Class* api = (const Ewk_View_Smart_Class*)sc; + EINA_SAFETY_ON_NULL_RETURN(api->backing_store_add); + EWK_VIEW_SD_GET(o, sd); + + if (!sd) { + sd = (Ewk_View_Smart_Data*)calloc(1, sizeof(Ewk_View_Smart_Data)); + if (!sd) + CRITICAL("could not allocate Ewk_View_Smart_Data"); + else + evas_object_smart_data_set(o, sd); + } + + sd->bg_color.r = 255; + sd->bg_color.g = 255; + sd->bg_color.b = 255; + sd->bg_color.a = 255; + + sd->self = o; + sd->_priv = _ewk_view_priv_new(sd); + sd->api = api; + + _parent_sc.add(o); + + if (!sd->_priv) + return; + + EWK_VIEW_PRIV_GET(sd, priv); + + sd->backing_store = api->backing_store_add(sd); + if (!sd->backing_store) { + ERR("Could not create backing store object."); + return; + } + + evas_object_smart_member_add(sd->backing_store, o); + evas_object_show(sd->backing_store); + + sd->main_frame = ewk_frame_add(sd->base.evas); + if (!sd->main_frame) { + ERR("Could not create main frame object."); + return; + } + + if (!ewk_frame_init(sd->main_frame, o, priv->main_frame)) { + ERR("Could not initialize main frme object."); + evas_object_del(sd->main_frame); + sd->main_frame = 0; + + delete priv->main_frame; + priv->main_frame = 0; + return; + } + + evas_object_name_set(sd->main_frame, "EWK_Frame:main"); + evas_object_smart_member_add(sd->main_frame, o); + evas_object_show(sd->main_frame); + +#define CONNECT(s, c) evas_object_event_callback_add(o, s, c, sd) + CONNECT(EVAS_CALLBACK_FOCUS_IN, _ewk_view_on_focus_in); + CONNECT(EVAS_CALLBACK_FOCUS_OUT, _ewk_view_on_focus_out); + CONNECT(EVAS_CALLBACK_MOUSE_WHEEL, _ewk_view_on_mouse_wheel); + CONNECT(EVAS_CALLBACK_MOUSE_DOWN, _ewk_view_on_mouse_down); + CONNECT(EVAS_CALLBACK_MOUSE_UP, _ewk_view_on_mouse_up); + CONNECT(EVAS_CALLBACK_MOUSE_MOVE, _ewk_view_on_mouse_move); + CONNECT(EVAS_CALLBACK_KEY_DOWN, _ewk_view_on_key_down); + CONNECT(EVAS_CALLBACK_KEY_UP, _ewk_view_on_key_up); +#undef CONNECT +} + +static void _ewk_view_smart_del(Evas_Object* o) +{ + EWK_VIEW_SD_GET(o, sd); + Ewk_View_Private_Data* priv = sd ? sd->_priv : 0; + + _parent_sc.del(o); + _ewk_view_priv_del(priv); +} + +static void _ewk_view_smart_resize(Evas_Object* o, Evas_Coord w, Evas_Coord h) +{ + EWK_VIEW_SD_GET(o, sd); + + // these should be queued and processed in calculate as well! + evas_object_resize(sd->backing_store, w, h); + + sd->changed.size = EINA_TRUE; + _ewk_view_smart_changed(sd); +} + +static void _ewk_view_smart_move(Evas_Object* o, Evas_Coord x, Evas_Coord y) +{ + EWK_VIEW_SD_GET(o, sd); + sd->changed.position = EINA_TRUE; + _ewk_view_smart_changed(sd); +} + +static void _ewk_view_smart_calculate(Evas_Object* o) +{ + EWK_VIEW_SD_GET(o, sd); + EWK_VIEW_PRIV_GET(sd, priv); + EINA_SAFETY_ON_NULL_RETURN(sd->api->contents_resize); + EINA_SAFETY_ON_NULL_RETURN(sd->api->scrolls_process); + EINA_SAFETY_ON_NULL_RETURN(sd->api->repaints_process); + Evas_Coord x, y, w, h; + + sd->changed.any = EINA_FALSE; + + if (!sd->main_frame || !priv->main_frame) + return; + + evas_object_geometry_get(o, &x, &y, &w, &h); + + DBG("o=%p geo=[%d, %d + %dx%d], changed: size=%hhu, " + "scrolls=%zu, repaints=%zu", + o, x, y, w, h, sd->changed.size, + priv->scrolls.count, priv->repaints.count); + + if (sd->changed.size && ((w != sd->view.w) || (h != sd->view.h))) { + WebCore::FrameView* view = priv->main_frame->view(); + if (view) { + view->resize(w, h); + view->forceLayout(); + view->adjustViewSize(); + IntSize size = view->contentsSize(); + if (!sd->api->contents_resize(sd, size.width(), size.height())) + ERR("failed to resize contents to %dx%d", + size.width(), size.height()); + } + evas_object_resize(sd->main_frame, w, h); + sd->changed.frame_rect = EINA_TRUE; + sd->view.w = w; + sd->view.h = h; + } + sd->changed.size = EINA_FALSE; + + if (sd->changed.position && ((x != sd->view.x) || (y != sd->view.y))) { + evas_object_move(sd->main_frame, x, y); + evas_object_move(sd->backing_store, x, y); + sd->changed.frame_rect = EINA_TRUE; + sd->view.x = x; + sd->view.y = y; + } + sd->changed.position = EINA_FALSE; + + ewk_view_layout_if_needed_recursive(sd->_priv); + + if (!sd->api->scrolls_process(sd)) + ERR("failed to process scrolls."); + _ewk_view_scrolls_flush(priv); + + if (!sd->api->repaints_process(sd)) + ERR("failed to process repaints."); + _ewk_view_repaints_flush(priv); + + if (sd->changed.frame_rect) { + WebCore::FrameView* view = priv->main_frame->view(); + view->frameRectsChanged(); /* force tree to get position from root */ + sd->changed.frame_rect = EINA_FALSE; + } +} + +static Eina_Bool _ewk_view_smart_contents_resize(Ewk_View_Smart_Data* sd, int w, int h) +{ + return EINA_TRUE; +} + +static Eina_Bool _ewk_view_smart_zoom_set(Ewk_View_Smart_Data* sd, float zoom, Evas_Coord cx, Evas_Coord cy) +{ + double px, py; + Evas_Coord x, y, w, h; + Eina_Bool ret; + + ewk_frame_scroll_size_get(sd->main_frame, &w, &h); + ewk_frame_scroll_pos_get(sd->main_frame, &x, &y); + + if (w + sd->view.w > 0) + px = (double)(x + cx) / (w + sd->view.w); + else + px = 0.0; + + if (h + sd->view.h > 0) + py = (double)(y + cy) / (h + sd->view.h); + else + py = 0.0; + + ret = ewk_frame_zoom_set(sd->main_frame, zoom); + + ewk_frame_scroll_size_get(sd->main_frame, &w, &h); + x = (w + sd->view.w) * px - cx; + y = (h + sd->view.h) * py - cy; + ewk_frame_scroll_set(sd->main_frame, x, y); + return ret; +} + +static void _ewk_view_smart_flush(Ewk_View_Smart_Data* sd) +{ + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + _ewk_view_repaints_flush(priv); + _ewk_view_scrolls_flush(priv); +} + +static Eina_Bool _ewk_view_smart_pre_render_region(Ewk_View_Smart_Data* sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float zoom) +{ + WRN("not supported by engine. sd=%p area=%d,%d+%dx%d, zoom=%f", + sd, x, y, w, h, zoom); + return EINA_FALSE; +} + +static void _ewk_view_smart_pre_render_cancel(Ewk_View_Smart_Data* sd) +{ + WRN("not supported by engine. sd=%p", sd); +} + +static void _ewk_view_zoom_animated_mark_stop(Ewk_View_Smart_Data* sd) +{ + sd->animated_zoom.zoom.start = 0.0; + sd->animated_zoom.zoom.end = 0.0; + sd->animated_zoom.zoom.current = 0.0; +} + +static void _ewk_view_zoom_animated_finish(Ewk_View_Smart_Data* sd) +{ + EWK_VIEW_PRIV_GET(sd, priv); + ecore_animator_del(priv->animated_zoom.animator); + priv->animated_zoom.animator = 0; + _ewk_view_zoom_animated_mark_stop(sd); + evas_object_smart_callback_call(sd->self, "zoom,animated,end", 0); +} + +static float _ewk_view_zoom_animated_current(Ewk_View_Private_Data* priv) +{ + double now = ecore_loop_time_get(); + double delta = now - priv->animated_zoom.time.start; + + if (delta > priv->animated_zoom.time.duration) + delta = priv->animated_zoom.time.duration; + if (delta < 0.0) // time went back, clock adjusted? + delta = 0.0; + + delta /= priv->animated_zoom.time.duration; + + return ((priv->animated_zoom.zoom.range * delta) + + priv->animated_zoom.zoom.start); +} + +static int _ewk_view_zoom_animator_cb(void* data) +{ + Ewk_View_Smart_Data* sd = (Ewk_View_Smart_Data*)data; + Evas_Coord cx, cy; + EWK_VIEW_PRIV_GET(sd, priv); + double now = ecore_loop_time_get(); + + cx = priv->animated_zoom.center.x; + cy = priv->animated_zoom.center.y; + + // TODO: progressively center (cx, cy) -> (view.x + view.h/2, view.y + view.h/2) + if (cx >= sd->view.w) + cx = sd->view.w - 1; + if (cy >= sd->view.h) + cy = sd->view.h - 1; + + if ((now >= priv->animated_zoom.time.end) + || (now < priv->animated_zoom.time.start)) { + _ewk_view_zoom_animated_finish(sd); + ewk_view_zoom_set(sd->self, priv->animated_zoom.zoom.end, cx, cy); + return 0; + } + + sd->animated_zoom.zoom.current = _ewk_view_zoom_animated_current(priv); + sd->api->zoom_weak_set(sd, sd->animated_zoom.zoom.current, cx, cy); + return 1; +} + +static void _ewk_view_zoom_animation_start(Ewk_View_Smart_Data* sd) +{ + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + if (priv->animated_zoom.animator) + return; + priv->animated_zoom.animator = ecore_animator_add + (_ewk_view_zoom_animator_cb, sd); +} + +/** + * Sets the smart class api without any backing store, enabling view + * to be inherited. + * + * @param api class definition to be set, all members with the + * exception of Evas_Smart_Class->data may be overridden. Must + * @b not be @c 0. + * + * @note Evas_Smart_Class->data is used to implement type checking and + * is not supposed to be changed/overridden. If you need extra + * data for your smart class to work, just extend + * Ewk_View_Smart_Class instead. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (probably + * version mismatch). + * + * @see ewk_view_single_smart_set() + * @see ewk_view_tiled_smart_set() + */ +Eina_Bool ewk_view_base_smart_set(Ewk_View_Smart_Class* api) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(api, EINA_FALSE); + + if (api->version != EWK_VIEW_SMART_CLASS_VERSION) { + EINA_LOG_CRIT + ("Ewk_View_Smart_Class %p is version %lu while %lu was expected.", + api, api->version, EWK_VIEW_SMART_CLASS_VERSION); + return EINA_FALSE; + } + + if (EINA_UNLIKELY(!_parent_sc.add)) + evas_object_smart_clipped_smart_set(&_parent_sc); + + evas_object_smart_clipped_smart_set(&api->sc); + api->sc.add = _ewk_view_smart_add; + api->sc.del = _ewk_view_smart_del; + api->sc.resize = _ewk_view_smart_resize; + api->sc.move = _ewk_view_smart_move; + api->sc.calculate = _ewk_view_smart_calculate; + api->sc.data = EWK_VIEW_TYPE_STR; /* used by type checking */ + + api->contents_resize = _ewk_view_smart_contents_resize; + api->zoom_set = _ewk_view_smart_zoom_set; + api->flush = _ewk_view_smart_flush; + api->pre_render_region = _ewk_view_smart_pre_render_region; + api->pre_render_cancel = _ewk_view_smart_pre_render_cancel; + + api->focus_in = _ewk_view_smart_focus_in; + api->focus_out = _ewk_view_smart_focus_out; + api->mouse_wheel = _ewk_view_smart_mouse_wheel; + api->mouse_down = _ewk_view_smart_mouse_down; + api->mouse_up = _ewk_view_smart_mouse_up; + api->mouse_move = _ewk_view_smart_mouse_move; + api->key_down = _ewk_view_smart_key_down; + api->key_up = _ewk_view_smart_key_up; + + api->add_console_message = _ewk_view_smart_add_console_message; + api->run_javascript_alert = _ewk_view_smart_run_javascript_alert; + api->run_javascript_confirm = _ewk_view_smart_run_javascript_confirm; + api->run_javascript_prompt = _ewk_view_smart_run_javascript_prompt; + api->should_interrupt_javascript = _ewk_view_smart_should_interrupt_javascript; + + return EINA_TRUE; +} + +/** + * Set a fixed layout size to be used, dissociating it from viewport size. + * + * Setting a width different than zero enables fixed layout on that + * size. It's automatically scaled based on zoom, but will not change + * if viewport changes. + * + * Setting both @a w and @a h to zero will disable fixed layout. + * + * @param o view object to change fixed layout. + * @param w fixed width to use. This size will be automatically scaled + * based on zoom level. + * @param h fixed height to use. This size will be automatically scaled + * based on zoom level. + */ +void ewk_view_fixed_layout_size_set(Evas_Object* o, Evas_Coord w, Evas_Coord h) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + WebCore::FrameView* view = sd->_priv->main_frame->view(); + if (w <= 0 && h <= 0) { + if (!priv->fixed_layout.use) + return; + priv->fixed_layout.w = 0; + priv->fixed_layout.h = 0; + priv->fixed_layout.use = EINA_FALSE; + } else { + if (priv->fixed_layout.use + && priv->fixed_layout.w == w && priv->fixed_layout.h == h) + return; + priv->fixed_layout.w = w; + priv->fixed_layout.h = h; + priv->fixed_layout.use = EINA_TRUE; + + if (view) + view->setFixedLayoutSize(WebCore::IntSize(w, h)); + } + + if (!view) + return; + view->setUseFixedLayout(priv->fixed_layout.use); + view->forceLayout(); +} + +/** + * Get fixed layout size in use. + * + * @param o view object to query fixed layout size. + * @param w where to return width. Returns 0 on error or if no fixed + * layout in use. + * @param h where to return height. Returns 0 on error or if no fixed + * layout in use. + */ +void ewk_view_fixed_layout_size_get(Evas_Object* o, Evas_Coord* w, Evas_Coord* h) +{ + if (w) + *w = 0; + if (h) + *h = 0; + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + if (priv->fixed_layout.use) { + if (w) + *w = priv->fixed_layout.w; + if (h) + *h = priv->fixed_layout.h; + } +} + +/** + * Set the theme path to be used by this view. + * + * This also sets the theme on the main frame. As frames inherit theme + * from their parent, this will have all frames with unset theme to + * use this one. + * + * @param o view object to change theme. + * @param path theme path, may be @c 0 to reset to default. + */ +void ewk_view_theme_set(Evas_Object* o, const char* path) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + ewk_frame_theme_set(sd->main_frame, path); +} + +/** + * Gets the theme set on this frame. + * + * This returns the value set by ewk_view_theme_set(). + * + * @param o view object to get theme path. + * + * @return theme path, may be @c 0 if not set. + */ +const char* ewk_view_theme_get(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + return ewk_frame_theme_get(sd->main_frame); +} + +/** + * Get the object that represents the main frame. + * + * @param o view object to get main frame. + * + * @return ewk_frame object or @c 0 if none yet. + */ +Evas_Object* ewk_view_frame_main_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + return sd->main_frame; +} + +/** + * Get the currently focused frame object. + * + * @param o view object to get focused frame. + * + * @return ewk_frame object or @c 0 if none yet. + */ +Evas_Object* ewk_view_frame_focused_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + + WebCore::Frame* core = priv->page->focusController()->focusedFrame(); + if (!core) + return 0; + + WebCore::FrameLoaderClientEfl* client = static_cast<WebCore::FrameLoaderClientEfl*>(core->loader()->client()); + if (!client) + return 0; + return client->webFrame(); +} + +/** + * Ask main frame to load the given URI. + * + * @param o view object to load uri. + * @param uri uniform resource identifier to load. + * + * @return @c EINA_TRUE on successful request, @c EINA_FALSE on failure. + * Note that it means the request was done, not that it was + * satisfied. + */ +Eina_Bool ewk_view_uri_set(Evas_Object* o, const char* uri) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_uri_set(sd->main_frame, uri); +} + +/** + * Get the current uri loaded by main frame. + * + * @param o view object to get current uri. + * + * @return current uri reference or @c 0. It's internal, don't change. + */ +const char* ewk_view_uri_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + return ewk_frame_uri_get(sd->main_frame); +} + +/** + * Get the current title of main frame. + * + * @param o view object to get current title. + * + * @return current title reference or @c 0. It's internal, don't change. + */ +const char* ewk_view_title_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + return ewk_frame_title_get(sd->main_frame); +} + +/** + * Gets if main frame is editable. + * + * @param o view object to get editable state. + * + * @return @c EINA_TRUE if editable, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_editable_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_editable_get(sd->main_frame); +} + +/** + * Set background color and transparency + * + * Just as in Evas, colors are pre-multiplied, so 50% red is + * (128, 0, 0, 128) and not (255, 0, 0, 128)! + * + * @warning Watch out performance issues with transparency! Object + * will be handled as transparent image by evas even if the + * webpage specifies a background color. That mean you'll pay + * a price even if it's not really transparent, thus + * scrolling/panning and zooming will be likely slower than + * if transparency is off. + * + * @param o view object to change. + * @param r red component. + * @param g green component. + * @param b blue component. + * @param a transparency. + */ +void ewk_view_bg_color_set(Evas_Object* o, int r, int g, int b, int a) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->bg_color_set); + + if (a < 0) { + WRN("Alpha less than zero (%d).", a); + a = 0; + } else if (a > 255) { + WRN("Alpha is larger than 255 (%d).", a); + a = 255; + } + +#define CHECK_PREMUL_COLOR(c, a) \ + if (c < 0) { \ + WRN("Color component "#c" is less than zero (%d).", c); \ + c = 0; \ + } else if (c > a) { \ + WRN("Color component "#c" is greater than alpha (%d, alpha=%d).", \ + c, a); \ + c = a; \ + } + CHECK_PREMUL_COLOR(r, a); + CHECK_PREMUL_COLOR(g, a); + CHECK_PREMUL_COLOR(b, a); +#undef CHECK_PREMUL_COLOR + + sd->bg_color.r = r; + sd->bg_color.g = g; + sd->bg_color.b = b; + sd->bg_color.a = a; + + sd->api->bg_color_set(sd, r, g, b, a); + + WebCore::FrameView* view = sd->_priv->main_frame->view(); + if (view) { + WebCore::Color color; + + if (!a) + color = WebCore::Color(0, 0, 0, 0); + else if (a == 255) + color = WebCore::Color(r, g, b, a); + else + color = WebCore::Color(r * 255 / a, g * 255 / a, b * 255 / a, a); + + view->updateBackgroundRecursively(color, !a); + } +} + +/** + * Query if view object background color. + * + * Just as in Evas, colors are pre-multiplied, so 50% red is + * (128, 0, 0, 128) and not (255, 0, 0, 128)! + * + * @param o view object to query. + * @param r where to return red color component. + * @param g where to return green color component. + * @param b where to return blue color component. + * @param a where to return alpha value. + */ +void ewk_view_bg_color_get(const Evas_Object* o, int* r, int* g, int* b, int* a) +{ + if (r) + *r = 0; + if (g) + *g = 0; + if (b) + *b = 0; + if (a) + *a = 0; + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + if (r) + *r = sd->bg_color.r; + if (g) + *g = sd->bg_color.g; + if (b) + *b = sd->bg_color.b; + if (a) + *a = sd->bg_color.a; +} + +/** + * Search the given text string in document. + * + * @param o view object where to search text. + * @param string reference string to search. + * @param case_sensitive if search should be case sensitive or not. + * @param forward if search is from cursor and on or backwards. + * @param wrap if search should wrap at end. + * + * @return @c EINA_TRUE if found, @c EINA_FALSE if not or failure. + */ +Eina_Bool ewk_view_text_search(const Evas_Object* o, const char* string, Eina_Bool case_sensitive, Eina_Bool forward, Eina_Bool wrap) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(string, EINA_FALSE); + WebCore::TextCaseSensitivity sensitive; + WebCore::FindDirection direction; + + if (case_sensitive) + sensitive = WebCore::TextCaseSensitive; + else + sensitive = WebCore::TextCaseInsensitive; + + if (forward) + direction = WebCore::FindDirectionForward; + else + direction = WebCore::FindDirectionBackward; + + return priv->page->findString(WebCore::String::fromUTF8(string), sensitive, direction, wrap); +} + +/** + * Mark matches the given text string in document. + * + * @param o view object where to search text. + * @param string reference string to match. + * @param case_sensitive if match should be case sensitive or not. + * @param highlight if matches should be highlighted. + * @param limit maximum amount of matches, or zero to unlimited. + * + * @return number of matches. + */ +unsigned int ewk_view_text_matches_mark(Evas_Object* o, const char* string, Eina_Bool case_sensitive, Eina_Bool highlight, unsigned int limit) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(string, 0); + WebCore::TextCaseSensitivity sensitive; + + if (case_sensitive) + sensitive = WebCore::TextCaseSensitive; + else + sensitive = WebCore::TextCaseInsensitive; + + return priv->page->markAllMatchesForText(WebCore::String::fromUTF8(string), sensitive, highlight, limit); +} + +/** + * Reverses the effect of ewk_view_text_matches_mark() + * + * @param o view object where to search text. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE for failure. + */ +Eina_Bool ewk_view_text_matches_unmark_all(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + priv->page->unmarkAllTextMatches(); + return EINA_TRUE; +} + +/** + * Set if should highlight matches marked with ewk_view_text_matches_mark(). + * + * @param o view object where to set if matches are highlighted or not. + * @param highlight if @c EINA_TRUE, matches will be highlighted. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE for failure. + */ +Eina_Bool ewk_view_text_matches_highlight_set(Evas_Object* o, Eina_Bool highlight) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_text_matches_highlight_set(sd->main_frame, highlight); +} + +/** + * Get if should highlight matches marked with ewk_view_text_matches_mark(). + * + * @param o view object to query if matches are highlighted or not. + * + * @return @c EINA_TRUE if they are highlighted, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_text_matches_highlight_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_text_matches_highlight_get(sd->main_frame); +} + +/** + * Sets if main frame is editable. + * + * @param o view object to set editable state. + * @param editable new state. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_editable_set(Evas_Object* o, Eina_Bool editable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_editable_set(sd->main_frame, editable); +} + +/** + * Get the copy of the selection text. + * + * @param o view object to get selection text. + * + * @return newly allocated string or @c 0 if nothing is selected or failure. + */ +char* ewk_view_selection_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + WebCore::CString s = priv->page->focusController()->focusedOrMainFrame()->selectedText().utf8(); + if (s.isNull()) + return 0; + return strdup(s.data()); +} + +static Eina_Bool _ewk_view_editor_command(Ewk_View_Private_Data* priv, const char* command) +{ + return priv->page->focusController()->focusedOrMainFrame()->editor()->command(WebCore::String::fromUTF8(command)).execute(); +} + +/** + * Unselects whatever was selected. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_none(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "Unselect"); +} + +/** + * Selects everything. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_all(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "SelectAll"); +} + +/** + * Selects the current paragrah. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_paragraph(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "SelectParagraph"); +} + +/** + * Selects the current sentence. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_sentence(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "SelectSentence"); +} + +/** + * Selects the current line. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_line(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "SelectLine"); +} + +/** + * Selects the current word. + * + * @return @c EINA_TRUE if operation was executed, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_select_word(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return _ewk_view_editor_command(priv, "SelectWord"); +} + +/** + * Get current load progress estimate from 0.0 to 1.0. + * + * @param o view object to get current progress. + * + * @return progres value from 0.0 to 1.0 or -1.0 on error. + */ +double ewk_view_load_progress_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, -1.0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, -1.0); + return priv->page->progress()->estimatedProgress(); +} + +/** + * Ask main frame to stop loading. + * + * @param o view object to stop loading. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_stop() + */ +Eina_Bool ewk_view_stop(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_stop(sd->main_frame); +} + +/** + * Ask main frame to reload current document. + * + * @param o view object to reload. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_reload() + */ +Eina_Bool ewk_view_reload(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_reload(sd->main_frame); +} + +/** + * Ask main frame to fully reload current document, using no caches. + * + * @param o view object to reload. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_reload_full() + */ +Eina_Bool ewk_view_reload_full(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_reload_full(sd->main_frame); +} + +/** + * Ask main frame to navigate back in history. + * + * @param o view object to navigate back. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_back() + */ +Eina_Bool ewk_view_back(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_back(sd->main_frame); +} + +/** + * Ask main frame to navigate forward in history. + * + * @param o view object to navigate forward. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_forward() + */ +Eina_Bool ewk_view_forward(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_forward(sd->main_frame); +} + +/** + * Navigate back or forward in history. + * + * @param o view object to navigate. + * @param steps if positive navigates that amount forwards, if negative + * does backwards. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_frame_navigate() + */ +Eina_Bool ewk_view_navigate(Evas_Object* o, int steps) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_navigate(sd->main_frame, steps); +} + +/** + * Check if it is possible to navigate backwards one item in history. + * + * @param o view object to check if backward navigation is possible. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + * + * @see ewk_view_navigate_possible() + */ +Eina_Bool ewk_view_back_possible(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_back_possible(sd->main_frame); +} + +/** + * Check if it is possible to navigate forwards one item in history. + * + * @param o view object to check if forward navigation is possible. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + * + * @see ewk_view_navigate_possible() + */ +Eina_Bool ewk_view_forward_possible(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_forward_possible(sd->main_frame); +} + +/** + * Check if it is possible to navigate given @a steps in history. + * + * @param o view object to navigate. + * @param steps if positive navigates that amount forwards, if negative + * does backwards. + * + * @return @c EINA_TRUE if possible, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_navigate_possible(Evas_Object* o, int steps) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_navigate_possible(sd->main_frame, steps); +} + +/** + * Check if navigation history (back-forward lists) is enabled. + * + * @param o view object to check if navigation history is enabled. + * + * @return @c EINA_TRUE if view keeps history, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_history_enable_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->page->backForwardList()->enabled(); +} + +/** + * Sets if navigation history (back-forward lists) is enabled. + * + * @param o view object to set if navigation history is enabled. + * @param enable @c EINA_TRUE if we want to enable navigation history; + * @c EINA_FALSE otherwise. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_history_enable_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + priv->page->backForwardList()->setEnabled(enable); + return EINA_TRUE; +} + +/** + * Gets the history (back-forward list) associated with this view. + * + * @param o view object to get navigation history from. + * + * @return returns the history instance handle associated with this + * view or @c 0 on errors (including when history is not + * enabled with ewk_view_history_enable_set()). This instance + * is unique for this view and thus multiple calls to this + * function with the same view as parameter returns the same + * handle. This handle is alive while view is alive, thus one + * might want to listen for EVAS_CALLBACK_DEL on given view + * (@a o) to know when to stop using returned handle. + * + * @see ewk_view_history_enable_set() + */ +Ewk_History* ewk_view_history_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + if (!priv->page->backForwardList()->enabled()) { + ERR("asked history, but it's disabled! Returning 0!"); + return 0; + } + return priv->history; +} + +/** + * Get the current zoom level of main frame. + * + * @param o view object to query zoom level. + * + * @return current zoom level in use or -1.0 on error. + */ +float ewk_view_zoom_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, -1.0); + return ewk_frame_zoom_get(sd->main_frame); +} + +/** + * Set the current zoom level of main frame. + * + * @param o view object to set zoom level. + * @param zoom new level to use. + * @param cx x of center coordinate + * @param cy y of center coordinate + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_zoom_set(Evas_Object* o, float zoom, Evas_Coord cx, Evas_Coord cy) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api->zoom_set, EINA_FALSE); + if (zoom < ZOOM_MIN) { + WRN("zoom level is < %f : %f", (double)ZOOM_MIN, (double)zoom); + return EINA_FALSE; + } + if (zoom > ZOOM_MAX) { + WRN("zoom level is > %f : %f", (double)ZOOM_MAX, (double)zoom); + return EINA_FALSE; + } + + if (cx >= sd->view.w) + cx = sd->view.w - 1; + if (cy >= sd->view.h) + cy = sd->view.h - 1; + if (cx < 0) + cx = 0; + if (cy < 0) + cy = 0; + _ewk_view_zoom_animated_mark_stop(sd); + return sd->api->zoom_set(sd, zoom, cx, cy); +} + +Eina_Bool ewk_view_zoom_weak_smooth_scale_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return sd->zoom_weak_smooth_scale; +} + +void ewk_view_zoom_weak_smooth_scale_set(Evas_Object* o, Eina_Bool smooth_scale) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + smooth_scale = !!smooth_scale; + if (sd->zoom_weak_smooth_scale == smooth_scale) + return; + sd->zoom_weak_smooth_scale = smooth_scale; + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->zoom_weak_smooth_scale_set); + sd->api->zoom_weak_smooth_scale_set(sd, smooth_scale); +} + +/** + * Set the current zoom level of backing store, centered at given point. + * + * Unlike ewk_view_zoom_set(), this call do not ask WebKit to render + * at new size, but scale what is already rendered, being much faster + * but worse quality. + * + * Often one should use ewk_view_zoom_animated_set(), it will call the + * same machinery internally. + * + * @note this will set variables used by ewk_view_zoom_animated_set() + * so sub-classes will not reset internal state on their + * "calculate" phase. To unset those and enable sub-classes to + * reset their internal state, call + * ewk_view_zoom_animated_mark_stop(). Namely, this call will + * set ewk_view_zoom_animated_mark_start() to actual webkit zoom + * level, ewk_view_zoom_animated_mark_end() and + * ewk_view_zoom_animated_mark_current() to given zoom level. + * + * @param o view object to set weak zoom level. + * @param zoom level to scale backing store. + * @param cx horizontal center offset, relative to object (w/2 is middle). + * @param cy vertical center offset, relative to object (h/2 is middle). + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_zoom_weak_set(Evas_Object* o, float zoom, Evas_Coord cx, Evas_Coord cy) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api->zoom_weak_set, EINA_FALSE); + if (zoom < ZOOM_MIN) { + WRN("zoom level is < %f : %f", (double)ZOOM_MIN, (double)zoom); + return EINA_FALSE; + } + if (zoom > ZOOM_MAX) { + WRN("zoom level is > %f : %f", (double)ZOOM_MAX, (double)zoom); + return EINA_FALSE; + } + + if (cx >= sd->view.w) + cx = sd->view.w - 1; + if (cy >= sd->view.h) + cy = sd->view.h - 1; + if (cx < 0) + cx = 0; + if (cy < 0) + cy = 0; + + sd->animated_zoom.zoom.start = ewk_frame_zoom_get(sd->main_frame); + sd->animated_zoom.zoom.end = zoom; + sd->animated_zoom.zoom.current = zoom; + return sd->api->zoom_weak_set(sd, zoom, cx, cy); +} + +/** + * Mark internal zoom animation state to given zoom. + * + * This does not modify any actual zoom in WebKit or backing store, + * just set the Ewk_View_Smart_Data->animated_zoom.zoom.start so + * sub-classes will know they should not reset their internal state. + * + * @param o view object to change value. + * @param zoom new start value. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_view_zoom_animated_set() + * @see ewk_view_zoom_weak_set() + * @see ewk_view_zoom_animated_mark_stop() + * @see ewk_view_zoom_animated_mark_end() + * @see ewk_view_zoom_animated_mark_current() + */ +Eina_Bool ewk_view_zoom_animated_mark_start(Evas_Object* o, float zoom) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + sd->animated_zoom.zoom.start = zoom; + return EINA_TRUE; +} + +/** + * Mark internal zoom animation state to given zoom. + * + * This does not modify any actual zoom in WebKit or backing store, + * just set the Ewk_View_Smart_Data->animated_zoom.zoom.end so + * sub-classes will know they should not reset their internal state. + * + * @param o view object to change value. + * @param zoom new end value. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_view_zoom_animated_set() + * @see ewk_view_zoom_weak_set() + * @see ewk_view_zoom_animated_mark_stop() + * @see ewk_view_zoom_animated_mark_start() + * @see ewk_view_zoom_animated_mark_current() + */ +Eina_Bool ewk_view_zoom_animated_mark_end(Evas_Object* o, float zoom) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + sd->animated_zoom.zoom.end = zoom; + return EINA_TRUE; +} + +/** + * Mark internal zoom animation state to given zoom. + * + * This does not modify any actual zoom in WebKit or backing store, + * just set the Ewk_View_Smart_Data->animated_zoom.zoom.current so + * sub-classes will know they should not reset their internal state. + * + * @param o view object to change value. + * @param zoom new current value. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + * + * @see ewk_view_zoom_animated_set() + * @see ewk_view_zoom_weak_set() + * @see ewk_view_zoom_animated_mark_stop() + * @see ewk_view_zoom_animated_mark_start() + * @see ewk_view_zoom_animated_mark_end() + */ +Eina_Bool ewk_view_zoom_animated_mark_current(Evas_Object* o, float zoom) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + sd->animated_zoom.zoom.current = zoom; + return EINA_TRUE; +} + +/** + * Unmark internal zoom animation state. + * + * This zero all start, end and current values. + * + * @param o view object to mark as animated is stopped. + * + * @see ewk_view_zoom_animated_mark_start() + * @see ewk_view_zoom_animated_mark_end() + * @see ewk_view_zoom_animated_mark_current() + * @see ewk_view_zoom_weak_set() + */ +Eina_Bool ewk_view_zoom_animated_mark_stop(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + _ewk_view_zoom_animated_mark_stop(sd); + return EINA_TRUE; +} + +/** + * Set the current zoom level while animating. + * + * If the view was already animating to another zoom, it will start + * from current point to the next provided zoom (@a zoom parameter) + * and duration (@a duration parameter). + * + * This is the recommended way to do transitions from one level to + * another. However, one may wish to do those from outside, in that + * case use ewk_view_zoom_weak_set() and later control intermediate + * states with ewk_view_zoom_animated_mark_current(), + * ewk_view_zoom_animated_mark_end() and + * ewk_view_zoom_animated_mark_stop(). + * + * @param o view object to animate. + * @param zoom final zoom level to use. + * @param duration time in seconds the animation should take. + * @param cx offset inside object that defines zoom center. 0 is left side. + * @param cy offset inside object that defines zoom center. 0 is top side. + * @return @c EINA_TRUE if animation will be started, @c EINA_FALSE if not + * because zoom is too small/big. + */ +Eina_Bool ewk_view_zoom_animated_set(Evas_Object* o, float zoom, float duration, Evas_Coord cx, Evas_Coord cy) +{ + double now; + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api->zoom_weak_set, EINA_FALSE); + + if (zoom < ZOOM_MIN) { + WRN("zoom level is < %f : %f", (double)ZOOM_MIN, (double)zoom); + return EINA_FALSE; + } + if (zoom > ZOOM_MAX) { + WRN("zoom level is > %f : %f", (double)ZOOM_MAX, (double)zoom); + return EINA_FALSE; + } + + if (priv->animated_zoom.animator) + priv->animated_zoom.zoom.start = _ewk_view_zoom_animated_current(priv); + else { + priv->animated_zoom.zoom.start = ewk_frame_zoom_get(sd->main_frame); + _ewk_view_zoom_animation_start(sd); + } + + if (cx < 0) + cx = 0; + if (cy < 0) + cy = 0; + + now = ecore_loop_time_get(); + priv->animated_zoom.time.start = now; + priv->animated_zoom.time.end = now + duration; + priv->animated_zoom.time.duration = duration; + priv->animated_zoom.zoom.end = zoom; + priv->animated_zoom.zoom.range = (priv->animated_zoom.zoom.end - priv->animated_zoom.zoom.start); + priv->animated_zoom.center.x = cx; + priv->animated_zoom.center.y = cy; + sd->animated_zoom.zoom.current = priv->animated_zoom.zoom.start; + sd->animated_zoom.zoom.start = priv->animated_zoom.zoom.start; + sd->animated_zoom.zoom.end = priv->animated_zoom.zoom.end; + + return EINA_TRUE; +} + +/** + * Query if zoom level just applies to text and not other elements. + * + * @param o view to query setting. + * + * @return @c EINA_TRUE if just text are scaled, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_zoom_text_only_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_zoom_text_only_get(sd->main_frame); +} + +/** + * Set if zoom level just applies to text and not other elements. + * + * @param o view to change setting. + * @param setting @c EINA_TRUE if zoom should just be applied to text. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_zoom_text_only_set(Evas_Object* o, Eina_Bool setting) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + return ewk_frame_zoom_text_only_set(sd->main_frame, setting); +} + +/** + * Hint engine to pre-render region. + * + * Engines and backing store might be able to pre-render regions in + * order to speed up zooming or scrolling to that region. Not all + * engines might implement that and they will return @c EINA_FALSE + * in that case. + * + * The given region is a hint. Engines might do bigger or smaller area + * that covers that region. Pre-render might not be immediate, it may + * be postponed to a thread, operated cooperatively in the main loop + * and may be even ignored or cancelled afterwards. + * + * Multiple requests might be queued by engines. One can clear/forget + * about them with ewk_view_pre_render_cancel(). + * + * @param o view to ask pre-render of given region. + * @param x absolute coordinate (0=left) to pre-render at zoom. + * @param y absolute coordinate (0=top) to pre-render at zoom. + * @param w width to pre-render starting from @a x at zoom. + * @param h height to pre-render starting from @a y at zoom. + * @param zoom desired zoom. + * + * @return @c EINA_TRUE if request was accepted, @c EINA_FALSE + * otherwise (errors, pre-render not supported, etc). + * + * @see ewk_view_pre_render_cancel() + */ +Eina_Bool ewk_view_pre_render_region(Evas_Object* o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float zoom) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api->pre_render_region, EINA_FALSE); + float cur_zoom = ewk_frame_zoom_get(sd->main_frame); + Evas_Coord cw, ch; + + if (cur_zoom < 0.00001) + return EINA_FALSE; + if (!ewk_frame_contents_size_get(sd->main_frame, &cw, &ch)) + return EINA_FALSE; + + cw *= zoom / cur_zoom; + ch *= zoom / cur_zoom; + DBG("region %d,%d+%dx%d @ %f contents=%dx%d", x, y, w, h, zoom, cw, ch); + + if (x + w > cw) + w = cw - x; + + if (y + h > ch) + h = ch - y; + + if (x < 0) { + w += x; + x = 0; + } + if (y < 0) { + h += y; + y = 0; + } + + return sd->api->pre_render_region(sd, x, y, w, h, zoom); +} + +/** + * Cancel (clear) previous pre-render requests. + * + * @param o view to clear pre-render requests. + */ +void ewk_view_pre_render_cancel(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api->pre_render_cancel); + sd->api->pre_render_cancel(sd); +} + +const char* ewk_view_setting_user_agent_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.user_agent; +} + +Eina_Bool ewk_view_setting_user_agent_set(Evas_Object* o, const char* user_agent) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.user_agent, user_agent)) { + WebCore::FrameLoaderClientEfl* client = static_cast<WebCore::FrameLoaderClientEfl*>(priv->main_frame->loader()->client()); + client->setCustomUserAgent(WebCore::String::fromUTF8(user_agent)); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_user_stylesheet_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.user_stylesheet; +} + +Eina_Bool ewk_view_setting_user_stylesheet_set(Evas_Object* o, const char* uri) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.user_stylesheet, uri)) { + WebCore::KURL kurl(WebCore::KURL(), WebCore::String::fromUTF8(uri)); + priv->page_settings->setUserStyleSheetLocation(kurl); + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_auto_load_images_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.auto_load_images; +} + +Eina_Bool ewk_view_setting_auto_load_images_set(Evas_Object* o, Eina_Bool automatic) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + automatic = !!automatic; + if (priv->settings.auto_load_images != automatic) { + priv->page_settings->setLoadsImagesAutomatically(automatic); + priv->settings.auto_load_images = automatic; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_auto_shrink_images_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.auto_shrink_images; +} + +Eina_Bool ewk_view_setting_auto_shrink_images_set(Evas_Object* o, Eina_Bool automatic) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + automatic = !!automatic; + if (priv->settings.auto_shrink_images != automatic) { + priv->page_settings->setShrinksStandaloneImagesToFit(automatic); + priv->settings.auto_shrink_images = automatic; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_enable_scripts_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.enable_scripts; +} + +Eina_Bool ewk_view_setting_enable_scripts_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + enable = !!enable; + if (priv->settings.enable_scripts != enable) { + priv->page_settings->setJavaScriptEnabled(enable); + priv->settings.enable_scripts = enable; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_enable_plugins_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.enable_plugins; +} + +Eina_Bool ewk_view_setting_enable_plugins_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + enable = !!enable; + if (priv->settings.enable_plugins != enable) { + priv->page_settings->setPluginsEnabled(enable); + priv->settings.enable_plugins = enable; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_scripts_window_open_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.scripts_window_open; +} + +Eina_Bool ewk_view_setting_scripts_window_open_set(Evas_Object* o, Eina_Bool allow) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + allow = !!allow; + if (priv->settings.scripts_window_open != allow) { + priv->page_settings->setJavaScriptCanOpenWindowsAutomatically(allow); + priv->settings.scripts_window_open = allow; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_resizable_textareas_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.resizable_textareas; +} + +Eina_Bool ewk_view_setting_resizable_textareas_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + enable = !!enable; + if (priv->settings.resizable_textareas != enable) { + priv->page_settings->setTextAreasAreResizable(enable); + priv->settings.resizable_textareas = enable; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_private_browsing_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.private_browsing; +} + +Eina_Bool ewk_view_setting_private_browsing_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + enable = !!enable; + if (priv->settings.private_browsing != enable) { + priv->page_settings->setPrivateBrowsingEnabled(enable); + priv->settings.private_browsing = enable; + } + return EINA_TRUE; +} + +Eina_Bool ewk_view_setting_caret_browsing_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + return priv->settings.caret_browsing; +} + +Eina_Bool ewk_view_setting_caret_browsing_set(Evas_Object* o, Eina_Bool enable) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + enable = !!enable; + if (priv->settings.caret_browsing != enable) { + priv->page_settings->setCaretBrowsingEnabled(enable); + priv->settings.caret_browsing = enable; + } + return EINA_TRUE; +} + +/** + * Get current encoding of this View. + * + * @param o View. + * + * @return A pointer to an eina_strinshare containing the current custom + * encoding for View object @param o, or @c 0 if it's not set. + */ +const char* ewk_view_setting_encoding_custom_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + Evas_Object* main_frame = ewk_view_frame_main_get(o); + WebCore::Frame* core_frame = ewk_frame_core_get(main_frame); + + WebCore::String overrideEncoding = core_frame->loader()->documentLoader()->overrideEncoding(); + + if (overrideEncoding.isEmpty()) + return 0; + + eina_stringshare_replace(&priv->settings.encoding_custom, overrideEncoding.utf8().data()); + return priv->settings.encoding_custom; +} + +/** + * Set encoding of this View and reload page. + * + * @param o View. + * @param encoding The new encoding or @c 0 to restore the default encoding. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE otherwise. + */ +Eina_Bool ewk_view_setting_encoding_custom_set(Evas_Object* o, const char *encoding) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + Evas_Object* main_frame = ewk_view_frame_main_get(o); + WebCore::Frame* core_frame = ewk_frame_core_get(main_frame); +DBG("%s", encoding); + eina_stringshare_replace(&priv->settings.encoding_custom, encoding); + core_frame->loader()->reloadWithOverrideEncoding(WebCore::String::fromUTF8(encoding)); + + return EINA_TRUE; +} + +const char* ewk_view_setting_encoding_default_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.encoding_default; +} + +Eina_Bool ewk_view_setting_encoding_default_set(Evas_Object* o, const char* encoding) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.encoding_default, encoding)) + priv->page_settings->setDefaultTextEncodingName(WebCore::String::fromUTF8(encoding)); + return EINA_TRUE; +} + +int ewk_view_setting_font_minimum_size_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_minimum_size; +} + +Eina_Bool ewk_view_setting_font_minimum_size_set(Evas_Object* o, int size) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (priv->settings.font_minimum_size != size) { + priv->page_settings->setMinimumFontSize(size); + priv->settings.font_minimum_size = size; + } + return EINA_TRUE; +} + +int ewk_view_setting_font_minimum_logical_size_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_minimum_logical_size; +} + +Eina_Bool ewk_view_setting_font_minimum_logical_size_set(Evas_Object* o, int size) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (priv->settings.font_minimum_logical_size != size) { + priv->page_settings->setMinimumLogicalFontSize(size); + priv->settings.font_minimum_logical_size = size; + } + return EINA_TRUE; +} + +int ewk_view_setting_font_default_size_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_default_size; +} + +Eina_Bool ewk_view_setting_font_default_size_set(Evas_Object* o, int size) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (priv->settings.font_default_size != size) { + priv->page_settings->setDefaultFontSize(size); + priv->settings.font_default_size = size; + } + return EINA_TRUE; +} + +int ewk_view_setting_font_monospace_size_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_monospace_size; +} + +Eina_Bool ewk_view_setting_font_monospace_size_set(Evas_Object* o, int size) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (priv->settings.font_monospace_size != size) { + priv->page_settings->setDefaultFixedFontSize(size); + priv->settings.font_monospace_size = size; + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_standard_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_standard; +} + +Eina_Bool ewk_view_setting_font_standard_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_standard, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setStandardFontFamily(s); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_cursive_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_cursive; +} + +Eina_Bool ewk_view_setting_font_cursive_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_cursive, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setCursiveFontFamily(s); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_fantasy_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_fantasy; +} + +Eina_Bool ewk_view_setting_font_fantasy_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_fantasy, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setFantasyFontFamily(s); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_monospace_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_monospace; +} + +Eina_Bool ewk_view_setting_font_monospace_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_monospace, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setFixedFontFamily(s); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_serif_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_serif; +} + +Eina_Bool ewk_view_setting_font_serif_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_serif, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setSerifFontFamily(s); + } + return EINA_TRUE; +} + +const char* ewk_view_setting_font_sans_serif_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->settings.font_sans_serif; +} + +Eina_Bool ewk_view_setting_font_sans_serif_set(Evas_Object* o, const char* family) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + if (eina_stringshare_replace(&priv->settings.font_sans_serif, family)) { + WebCore::AtomicString s = WebCore::String::fromUTF8(family); + priv->page_settings->setSansSerifFontFamily(s); + } + return EINA_TRUE; +} + +/** + * Similar to evas_object_smart_data_get(), but does type checking. + * + * @param o view object to query internal data. + * @return internal data or @c 0 on errors (ie: incorrect type of @a o). + */ +Ewk_View_Smart_Data* ewk_view_smart_data_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + return sd; +} + +/** + * Gets the internal array of repaint requests. + * + * This array should not be modified anyhow. It should be processed + * immediately as any further ewk_view call might change it, like + * those that add repaints or flush them, so be sure that your code + * does not call any of those while you process the repaints, + * otherwise copy the array. + * + * @param priv private handle pointer of the view to get repaints. + * @param count where to return the number of elements of returned array. + * + * @return reference to array of requested repaints. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +const Eina_Rectangle* ewk_view_repaints_get(const Ewk_View_Private_Data* priv, size_t* count) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(count, 0); + if (count) + *count = 0; + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, 0); + if (count) + *count = priv->repaints.count; + return priv->repaints.array; +} + +/** + * Gets the internal array of scroll requests. + * + * This array should not be modified anyhow. It should be processed + * immediately as any further ewk_view call might change it, like + * those that add scrolls or flush them, so be sure that your code + * does not call any of those while you process the scrolls, + * otherwise copy the array. + * + * @param priv private handle pointer of the view to get scrolls. + * @param count where to return the number of elements of returned array. + * + * @return reference to array of requested scrolls. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +const Ewk_Scroll_Request* ewk_view_scroll_requests_get(const Ewk_View_Private_Data* priv, size_t* count) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(count, 0); + if (count) + *count = 0; + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, 0); + if (count) + *count = priv->scrolls.count; + return priv->scrolls.array; +} + +/** + * Add a new repaint request to queue. + * + * The repaints are assumed to be relative to current viewport. + * + * @param priv private handle pointer of the view to add repaint request. + * @param x horizontal position relative to current view port (scrolled). + * @param y vertical position relative to current view port (scrolled). + * @param w width of area to be repainted + * @param h height of area to be repainted + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_repaint_add(Ewk_View_Private_Data* priv, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) +{ + EINA_SAFETY_ON_NULL_RETURN(priv); + _ewk_view_repaint_add(priv, x, y, w, h); +} + +/** + * Do layout if required, applied recursively. + * + * @param priv private handle pointer of the view to layout. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_layout_if_needed_recursive(Ewk_View_Private_Data* priv) +{ + EINA_SAFETY_ON_NULL_RETURN(priv); + + WebCore::FrameView* v = priv->main_frame->view(); + if (!v) { + ERR("no main frame view"); + return; + } + v->layoutIfNeededRecursive(); +} + +void ewk_view_scrolls_process(Ewk_View_Smart_Data* sd) +{ + EINA_SAFETY_ON_NULL_RETURN(sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + if (!sd->api->scrolls_process(sd)) + ERR("failed to process scrolls."); + _ewk_view_scrolls_flush(priv); +} + +struct _Ewk_View_Paint_Context { + WebCore::GraphicsContext* gc; + WebCore::FrameView* view; + cairo_t* cr; +}; + +/** + * Create a new paint context using the view as source and cairo as output. + * + * @param priv private handle pointer of the view to use as paint source. + * @param cr cairo context to use as paint destination. A new + * reference is taken, so it's safe to call cairo_destroy() + * after this function returns. + * + * @return newly allocated instance or @c 0 on errors. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +Ewk_View_Paint_Context* ewk_view_paint_context_new(Ewk_View_Private_Data* priv, cairo_t* cr) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(cr, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(priv->main_frame, 0); + WebCore::FrameView* view = priv->main_frame->view(); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, 0); + Ewk_View_Paint_Context* ctxt = (Ewk_View_Paint_Context*)malloc(sizeof(*ctxt)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ctxt, 0); + + ctxt->gc = new WebCore::GraphicsContext(cr); + if (!ctxt->gc) { + free(ctxt); + return 0; + } + ctxt->view = view; + ctxt->cr = cairo_reference(cr); + return ctxt; +} + +/** + * Destroy previously created paint context. + * + * @param ctxt paint context to destroy. Must @b not be @c 0. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_free(Ewk_View_Paint_Context* ctxt) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + delete ctxt->gc; + cairo_destroy(ctxt->cr); + free(ctxt); +} + +/** + * Save (push to stack) paint context status. + * + * @param ctxt paint context to save. Must @b not be @c 0. + * + * @see ewk_view_paint_context_restore() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_save(Ewk_View_Paint_Context* ctxt) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + cairo_save(ctxt->cr); + ctxt->gc->save(); +} + +/** + * Restore (pop from stack) paint context status. + * + * @param ctxt paint context to restore. Must @b not be @c 0. + * + * @see ewk_view_paint_context_save() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_restore(Ewk_View_Paint_Context* ctxt) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + ctxt->gc->restore(); + cairo_restore(ctxt->cr); +} + +/** + * Clip paint context drawings to given area. + * + * @param ctxt paint context to clip. Must @b not be @c 0. + * @param area clip area to use. + * + * @see ewk_view_paint_context_save() + * @see ewk_view_paint_context_restore() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_clip(Ewk_View_Paint_Context* ctxt, const Eina_Rectangle* area) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + EINA_SAFETY_ON_NULL_RETURN(area); + ctxt->gc->clip(WebCore::IntRect(area->x, area->y, area->w, area->h)); +} + +/** + * Paint using context using given area. + * + * @param ctxt paint context to paint. Must @b not be @c 0. + * @param area paint area to use. Coordinates are relative to current viewport, + * thus "scrolled". + * + * @note one may use cairo functions on the cairo context to + * translate, scale or any modification that may fit his desires. + * + * @see ewk_view_paint_context_clip() + * @see ewk_view_paint_context_paint_contents() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_paint(Ewk_View_Paint_Context* ctxt, const Eina_Rectangle* area) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + EINA_SAFETY_ON_NULL_RETURN(area); + + WebCore::IntRect rect(area->x, area->y, area->w, area->h); + + if (ctxt->view->isTransparent()) + ctxt->gc->clearRect(rect); + ctxt->view->paint(ctxt->gc, rect); +} + +/** + * Paint just contents using context using given area. + * + * Unlike ewk_view_paint_context_paint(), this function paint just + * bare contents and ignores any scrolling, scrollbars and extras. It + * will walk the rendering tree and paint contents inside the given + * area to the cairo context specified in @a ctxt. + * + * @param ctxt paint context to paint. Must @b not be @c 0. + * @param area paint area to use. Coordinates are absolute to page. + * + * @note one may use cairo functions on the cairo context to + * translate, scale or any modification that may fit his desires. + * + * @see ewk_view_paint_context_clip() + * @see ewk_view_paint_context_paint() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +void ewk_view_paint_context_paint_contents(Ewk_View_Paint_Context* ctxt, const Eina_Rectangle* area) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + EINA_SAFETY_ON_NULL_RETURN(area); + + WebCore::IntRect rect(area->x, area->y, area->w, area->h); + + if (ctxt->view->isTransparent()) + ctxt->gc->clearRect(rect); + + ctxt->view->paintContents(ctxt->gc, rect); +} + +/** + * Scale the contents by the given factors. + * + * This function applies a scaling transformation using Cairo. + * + * @param ctxt paint context to paint. Must @b not be @c 0. + * @param scale_x scale factor for the X dimension. + * @param scale_y scale factor for the Y dimension. + */ +void ewk_view_paint_context_scale(Ewk_View_Paint_Context* ctxt, float scale_x, float scale_y) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + + ctxt->gc->scale(WebCore::FloatSize(scale_x, scale_y)); +} + +/** + * Performs a translation of the origin coordinates. + * + * This function moves the origin coordinates by @p x and @p y pixels. + * + * @param ctxt paint context to paint. Must @b not be @c 0. + * @param x amount of pixels to translate in the X dimension. + * @param y amount of pixels to translate in the Y dimension. + */ +void ewk_view_paint_context_translate(Ewk_View_Paint_Context* ctxt, float x, float y) +{ + EINA_SAFETY_ON_NULL_RETURN(ctxt); + + ctxt->gc->translate(x, y); +} + +/** + * Paint using given graphics context the given area. + * + * This uses viewport relative area and will also handle scrollbars + * and other extra elements. See ewk_view_paint_contents() for the + * alternative function. + * + * @param priv private handle pointer of view to use as paint source. + * @param cr cairo context to use as paint destination. Its state will + * be saved before operation and restored afterwards. + * @param area viewport relative geometry to paint. + * + * @return @c EINA_TRUE on success and @c EINA_FALSE on failure, like + * incorrect parameters. + * + * @note this is an easy to use version, but internal structures are + * always created, then graphics context is clipped, then + * painted, restored and destroyed. This might not be optimum, + * so using #Ewk_View_Paint_Context may be a better solutions + * for large number of operations. + * + * @see ewk_view_paint_contents() + * @see ewk_view_paint_context_paint() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +Eina_Bool ewk_view_paint(Ewk_View_Private_Data* priv, cairo_t* cr, const Eina_Rectangle* area) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(cr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(area, EINA_FALSE); + WebCore::FrameView* view = priv->main_frame->view(); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + if (view->needsLayout()) + view->forceLayout(); + WebCore::GraphicsContext gc(cr); + WebCore::IntRect rect(area->x, area->y, area->w, area->h); + + cairo_save(cr); + gc.save(); + gc.clip(rect); + if (view->isTransparent()) + gc.clearRect(rect); + view->paint(&gc, rect); + gc.restore(); + cairo_restore(cr); + + return EINA_TRUE; +} + +/** + * Paint just contents using given graphics context the given area. + * + * This uses absolute coordinates for area and will just handle + * contents, no scrollbars or extras. See ewk_view_paint() for the + * alternative solution. + * + * @param priv private handle pointer of view to use as paint source. + * @param cr cairo context to use as paint destination. Its state will + * be saved before operation and restored afterwards. + * @param area absolute geometry to paint. + * + * @return @c EINA_TRUE on success and @c EINA_FALSE on failure, like + * incorrect parameters. + * + * @note this is an easy to use version, but internal structures are + * always created, then graphics context is clipped, then + * painted, restored and destroyed. This might not be optimum, + * so using #Ewk_View_Paint_Context may be a better solutions + * for large number of operations. + * + * @see ewk_view_paint() + * @see ewk_view_paint_context_paint_contents() + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +Eina_Bool ewk_view_paint_contents(Ewk_View_Private_Data* priv, cairo_t* cr, const Eina_Rectangle* area) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(priv, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(cr, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(area, EINA_FALSE); + WebCore::FrameView* view = priv->main_frame->view(); + EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE); + + WebCore::GraphicsContext gc(cr); + WebCore::IntRect rect(area->x, area->y, area->w, area->h); + + cairo_save(cr); + gc.save(); + gc.clip(rect); + if (view->isTransparent()) + gc.clearRect(rect); + view->paintContents(&gc, rect); + gc.restore(); + cairo_restore(cr); + + return EINA_TRUE; +} + + +/* internal methods ****************************************************/ +/** + * @internal + * Reports the view is ready to be displayed as all elements are aready. + * + * Emits signal: "ready" with no parameters. + */ +void ewk_view_ready(Evas_Object* o) +{ + DBG("o=%p", o); + evas_object_smart_callback_call(o, "ready", 0); +} + +/** + * @internal + * The view title was changed by the frame loader. + * + * Emits signal: "title,changed" with pointer to new title string. + */ +void ewk_view_title_set(Evas_Object* o, const char* title) +{ + DBG("o=%p, title=%s", o, title ? title : "(null)"); + evas_object_smart_callback_call(o, "title,changed", (void*)title); +} + +/** + * @internal + * Reports that main frame's uri changed. + * + * Emits signal: "uri,changed" with pointer to the new uri string. + */ +void ewk_view_uri_changed(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + const char* uri = ewk_frame_uri_get(sd->main_frame); + DBG("o=%p, uri=%s", o, uri ? uri : "(null)"); + evas_object_smart_callback_call(o, "uri,changed", (void*)uri); +} + +/** + * @internal + * Reports the view started loading something. + * + * @param o View. + * + * Emits signal: "load,started" with no parameters. + */ +void ewk_view_load_started(Evas_Object* o) +{ + DBG("o=%p", o); + evas_object_smart_callback_call(o, "load,started", 0); +} + +/** + * Reports the frame started loading something. + * + * @param o View. + * + * Emits signal: "load,started" on main frame with no parameters. + */ +void ewk_view_frame_main_load_started(Evas_Object* o) +{ + DBG("o=%p", o); + Evas_Object* frame = ewk_view_frame_main_get(o); + evas_object_smart_callback_call(frame, "load,started", 0); +} + +/** + * @internal + * Reports the main frame started provisional load. + * + * @param o View. + * + * Emits signal: "load,provisional" on View with no parameters. + */ +void ewk_view_load_provisional(Evas_Object* o) +{ + DBG("o=%p", o); + evas_object_smart_callback_call(o, "load,provisional", 0); +} + +/** + * @internal + * Reports view can be shown after a new window is created. + * + * @param o Frame. + * + * Emits signal: "load,newwindow,show" on view with no parameters. + */ +void ewk_view_load_show(Evas_Object* o) +{ + DBG("o=%p", o); + evas_object_smart_callback_call(o, "load,newwindow,show", 0); +} + + +/** + * @internal + * Reports the main frame was cleared. + * + * @param o View. + */ +void ewk_view_frame_main_cleared(Evas_Object* o) +{ + DBG("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api->flush); + sd->api->flush(sd); +} + +/** + * @internal + * Reports the main frame received an icon. + * + * @param o View. + * + * Emits signal: "icon,received" with no parameters. + */ +void ewk_view_frame_main_icon_received(Evas_Object* o) +{ + DBG("o=%p", o); + Evas_Object* frame = ewk_view_frame_main_get(o); + evas_object_smart_callback_call(frame, "icon,received", 0); +} + +/** + * @internal + * Reports load finished, optionally with error information. + * + * Emits signal: "load,finished" with pointer to #Ewk_Frame_Load_Error + * if any error, or @c 0 if successful load. + * + * @note there should not be any error stuff here, but trying to be + * compatible with previous WebKit. + */ +void ewk_view_load_finished(Evas_Object* o, const Ewk_Frame_Load_Error* error) +{ + DBG("o=%p, error=%p", o, error); + evas_object_smart_callback_call(o, "load,finished", (void*)error); +} + +/** + * @internal + * Reports load failed with error information. + * + * Emits signal: "load,error" with pointer to Ewk_Frame_Load_Error. + */ +void ewk_view_load_error(Evas_Object* o, const Ewk_Frame_Load_Error* error) +{ + DBG("o=%p, error=%p", o, error); + evas_object_smart_callback_call(o, "load,error", (void*)error); +} + +/** + * @internal + * Reports load progress changed. + * + * Emits signal: "load,progress" with pointer to a double from 0.0 to 1.0. + */ +void ewk_view_load_progress_changed(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + + // Evas_Coord w, h; + double progress = priv->page->progress()->estimatedProgress(); + + DBG("o=%p (p=%0.3f)", o, progress); + + evas_object_smart_callback_call(o, "load,progress", &progress); +} + +/** + * @internal + * Reports view @param o should be restored to default conditions + * + * @param o View. + * @param frame Frame that originated restore. + * + * Emits signal: "restore" with frame. + */ +void ewk_view_restore_state(Evas_Object* o, Evas_Object* frame) +{ + evas_object_smart_callback_call(o, "restore", frame); +} + +/** + * @internal + * Delegates to browser the creation of a new window. If it is not implemented, + * current view is returned, so navigation might continue in same window. + * + * @param o Current view. + * + * @return New view, in case smart class implements the creation of new windows; + * else, current view @param o. + */ +Evas_Object* ewk_view_window_create(Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + + if (!sd->api->window_create) + return o; + + return sd->api->window_create(sd); +} + +/** + * @internal + * Reports mouse has moved over a link. + * + * Emits signal: "link,hover,in" + */ +void ewk_view_mouse_link_hover_in(Evas_Object* o, void* data) +{ + evas_object_smart_callback_call(o, "link,hover,in", data); +} + +/** + * @internal + * Reports mouse is not over a link anymore. + * + * Emits signal: "link,hover,out" + */ +void ewk_view_mouse_link_hover_out(Evas_Object* o) +{ + evas_object_smart_callback_call(o, "link,hover,out", 0); +} + +/** + * @internal + * Set toolbar visible. + * + * Emits signal: "toolbars,visible,set" with a pointer to a boolean. + */ +void ewk_view_toolbars_visible_set(Evas_Object* o, Eina_Bool visible) +{ + DBG("o=%p (visible=%d)", o, !!visible); + evas_object_smart_callback_call(o, "toolbars,visible,set", &visible); +} + +/** + * @internal + * Get toolbar visibility. + * + * @param o View. + * @param visible boolean pointer in which to save the result. It defaults + * to @c FALSE, i.e. if browser does no listen to emitted signal, it means + * there are no toolbars and therefore they are not visible. + * + * Emits signal: "toolbars,visible,get" with a pointer to a boolean. + */ +void ewk_view_toolbars_visible_get(Evas_Object* o, Eina_Bool* visible) +{ + DBG("%s, o=%p", __func__, o); + *visible = EINA_FALSE; + evas_object_smart_callback_call(o, "toolbars,visible,get", visible); +} + +/** + * @internal + * Set statusbar visible. + * + * @param o View. + * @param visible @c TRUE if statusbar are visible, @c FALSE otherwise. + * + * Emits signal: "statusbar,visible,set" with a pointer to a boolean. + */ +void ewk_view_statusbar_visible_set(Evas_Object* o, Eina_Bool visible) +{ + DBG("o=%p (visible=%d)", o, !!visible); + evas_object_smart_callback_call(o, "statusbar,visible,set", &visible); +} + +/** + * @internal + * Get statusbar visibility. + * + * @param o View. + * @param visible boolean pointer in which to save the result. It defaults + * to @c FALSE, i.e. if browser does no listen to emitted signal, it means + * there is no statusbar and therefore it is not visible. + * + * Emits signal: "statusbar,visible,get" with a pointer to a boolean. + */ +void ewk_view_statusbar_visible_get(Evas_Object* o, Eina_Bool* visible) +{ + DBG("%s, o=%p", __func__, o); + *visible = EINA_FALSE; + evas_object_smart_callback_call(o, "statusbar,visible,get", visible); +} + +/** + * @internal + * Set text of statusbar + * + * @param o View. + * @param text New text to put on statusbar. + * + * Emits signal: "statusbar,text,set" with a string. + */ +void ewk_view_statusbar_text_set(Evas_Object* o, const char* text) +{ + DBG("o=%p (text=%s)", o, text); + INF("status bar text set: %s", text); + evas_object_smart_callback_call(o, "statusbar,text,set", (void *)text); +} + +/** + * @internal + * Set scrollbars visible. + * + * @param o View. + * @param visible @c TRUE if scrollbars are visible, @c FALSE otherwise. + * + * Emits signal: "scrollbars,visible,set" with a pointer to a boolean. + */ +void ewk_view_scrollbars_visible_set(Evas_Object* o, Eina_Bool visible) +{ + DBG("o=%p (visible=%d)", o, !!visible); + evas_object_smart_callback_call(o, "scrollbars,visible,set", &visible); +} + +/** + * @internal + * Get scrollbars visibility. + * + * @param o View. + * @param visible boolean pointer in which to save the result. It defaults + * to @c FALSE, i.e. if browser does no listen to emitted signal, it means + * there are no scrollbars and therefore they are not visible. + * + * Emits signal: "scrollbars,visible,get" with a pointer to a boolean. + */ +void ewk_view_scrollbars_visible_get(Evas_Object* o, Eina_Bool* visible) +{ + DBG("%s, o=%p", __func__, o); + *visible = EINA_FALSE; + evas_object_smart_callback_call(o, "scrollbars,visible,get", visible); +} + +/** + * @internal + * Set menubar visible. + * + * @param o View. + * @param visible @c TRUE if menubar is visible, @c FALSE otherwise. + * + * Emits signal: "menubar,visible,set" with a pointer to a boolean. + */ +void ewk_view_menubar_visible_set(Evas_Object* o, Eina_Bool visible) +{ + DBG("o=%p (visible=%d)", o, !!visible); + evas_object_smart_callback_call(o, "menubar,visible,set", &visible); +} + +/** + * @internal + * Get menubar visibility. + * + * @param o View. + * @param visible boolean pointer in which to save the result. It defaults + * to @c FALSE, i.e. if browser does no listen to emitted signal, it means + * there is no menubar and therefore it is not visible. + * + * Emits signal: "menubar,visible,get" with a pointer to a boolean. + */ +void ewk_view_menubar_visible_get(Evas_Object* o, Eina_Bool* visible) +{ + DBG("%s, o=%p", __func__, o); + *visible = EINA_FALSE; + evas_object_smart_callback_call(o, "menubar,visible,get", visible); +} + +/** + * @internal + * Set tooltip text and display if it is currently hidden. + * + * @param o View. + * @param text Text to set tooltip to. + * + * Emits signal: "tooltip,text,set" with a string. If tooltip must be actually + * removed, text will be 0 or '\0' + */ +void ewk_view_tooltip_text_set(Evas_Object* o, const char* text) +{ + DBG("o=%p text=%s", o, text); + evas_object_smart_callback_call(o, "tooltip,text,set", (void *)text); +} + +/** + * @internal + * + * @param o View. + * @param message String to show on console. + * @param lineNumber Line number. + * @sourceID Source id. + * + */ +void ewk_view_add_console_message(Evas_Object* o, const char* message, unsigned int lineNumber, const char* sourceID) +{ + DBG("o=%p message=%s lineNumber=%u sourceID=%s", o, message, lineNumber, sourceID); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->add_console_message); + sd->api->add_console_message(sd, message, lineNumber, sourceID); +} + +void ewk_view_run_javascript_alert(Evas_Object* o, Evas_Object* frame, const char* message) +{ + DBG("o=%p frame=%p message=%s", o, frame, message); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api); + + if (!sd->api->run_javascript_alert) + return; + + sd->api->run_javascript_alert(sd, frame, message); +} + +Eina_Bool ewk_view_run_javascript_confirm(Evas_Object* o, Evas_Object* frame, const char* message) +{ + DBG("o=%p frame=%p message=%s", o, frame, message); + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + + if (!sd->api->run_javascript_confirm) + return EINA_FALSE; + + return sd->api->run_javascript_confirm(sd, frame, message); +} + +Eina_Bool ewk_view_run_javascript_prompt(Evas_Object* o, Evas_Object* frame, const char* message, const char* defaultValue, char** value) +{ + DBG("o=%p frame=%p message=%s", o, frame, message); + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + + if (!sd->api->run_javascript_prompt) + return EINA_FALSE; + + return sd->api->run_javascript_prompt(sd, frame, message, defaultValue, value); +} + +/** + * @internal + * Delegates to client to decide whether a script must be stopped because it's + * running for too long. If client does not implement it, it goes to default + * implementation, which logs and returns EINA_FALSE. Client may remove log by + * setting this function 0, which will just return EINA_FALSE. + * + * @param o View. + * + * @return @c EINA_TRUE if script should be stopped; @c EINA_FALSE otherwise + */ +Eina_Bool ewk_view_should_interrupt_javascript(Evas_Object* o) +{ + DBG("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + + if (!sd->api->should_interrupt_javascript) + return EINA_FALSE; + + return sd->api->should_interrupt_javascript(sd); +} + +/** + * @internal + * This is called whenever the web site shown in @param frame is asking to store data + * to the database @param databaseName and the quota allocated to that web site + * is exceeded. Browser may use this to increase the size of quota before the + * originating operationa fails. + * + * @param o View. + * @param frame The frame whose web page exceeded its database quota. + * @param databaseName Database name. + */ +void ewk_view_exceeded_database_quota(Evas_Object* o, Evas_Object* frame, const char* databaseName) +{ + DBG("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EINA_SAFETY_ON_NULL_RETURN(sd->api); + EINA_SAFETY_ON_NULL_RETURN(sd->api->exceeded_database_quota); + sd->api->exceeded_database_quota(sd, frame, databaseName); +} + +/** + * @internal + * Open panel to choose a file. + * + * @param o View. + * @param frame Frame in which operation is required. + * @param allows_multiple_files @c EINA_TRUE when more than one file may be + * selected, @c EINA_FALSE otherwise + * @suggested_filenames List of suggested files to select. It's advisable to + * just ignore this value, since it's a source of security flaw. + * @selected_filenames List of files selected. + * + * @return @EINA_FALSE if user canceled file selection; @EINA_TRUE if confirmed. + */ +Eina_Bool ewk_view_run_open_panel(Evas_Object* o, Evas_Object* frame, Eina_Bool allows_multiple_files, const Eina_List* suggested_filenames, Eina_List** selected_filenames) +{ + DBG("o=%p frame=%p allows_multiple_files=%d", o, frame, allows_multiple_files); + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(sd->api, EINA_FALSE); + Eina_Bool confirm; + + if (!sd->api->run_open_panel) + return EINA_FALSE; + + *selected_filenames = 0; + + confirm = sd->api->run_open_panel(sd, frame, allows_multiple_files, suggested_filenames, selected_filenames); + if (!confirm && *selected_filenames) + ERR("Canceled file selection, but selected filenames != 0. Free names before return."); + return confirm; +} + +void ewk_view_repaint(Evas_Object* o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h) +{ + DBG("o=%p, region=%d,%d + %dx%d", o, x, y, w, h); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + + if (!priv->main_frame->contentRenderer()) { + ERR("no main frame content renderer."); + return; + } + + _ewk_view_repaint_add(priv, x, y, w, h); + _ewk_view_smart_changed(sd); +} + +void ewk_view_scroll(Evas_Object* o, Evas_Coord dx, Evas_Coord dy, Evas_Coord sx, Evas_Coord sy, Evas_Coord sw, Evas_Coord sh, Evas_Coord cx, Evas_Coord cy, Evas_Coord cw, Evas_Coord ch, Eina_Bool main_frame) +{ + DBG("o=%p, delta: %d,%d, scroll: %d,%d+%dx%d, clip: %d,%d+%dx%d", + o, dx, dy, sx, sy, sw, sh, cx, cy, cw, ch); + + if ((sx != cx) || (sy != cy) || (sw != cw) || (sh != ch)) + WRN("scroll region and clip are different! %d,%d+%dx%d and %d,%d+%dx%d", + sx, sy, sw, sh, cx, cy, cw, ch); + + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + EINA_SAFETY_ON_TRUE_RETURN(!dx && !dy); + + _ewk_view_scroll_add(priv, dx, dy, sx, sy, sw, sh, main_frame); + _ewk_view_smart_changed(sd); +} + +WebCore::Page* ewk_view_core_page_get(const Evas_Object* o) +{ + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + return priv->page; +} + +/** + * Creates a new frame for given url and owner element. + * + * Emits "frame,created" with the new frame object on success. + */ +WTF::PassRefPtr<WebCore::Frame> ewk_view_frame_create(Evas_Object* o, Evas_Object* frame, const WebCore::String& name, WebCore::HTMLFrameOwnerElement* ownerElement, const WebCore::KURL& url, const WebCore::String& referrer) +{ + DBG("o=%p, frame=%p, name=%s, ownerElement=%p, url=%s, referrer=%s", + o, frame, name.utf8().data(), ownerElement, + url.prettyURL().utf8().data(), referrer.utf8().data()); + + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, 0); + + WTF::RefPtr<WebCore::Frame> cf = _ewk_view_core_frame_new + (sd, priv, ownerElement); + if (!cf) { + ERR("Could not create child core frame '%s'", name.utf8().data()); + return 0; + } + + if (!ewk_frame_child_add(frame, cf, name, url, referrer)) { + ERR("Could not create child frame object '%s'", name.utf8().data()); + return 0; + } + + // The creation of the frame may have removed itself already. + if (!cf->page() || !cf->tree() || !cf->tree()->parent()) + return 0; + + sd->changed.frame_rect = EINA_TRUE; + _ewk_view_smart_changed(sd); + + evas_object_smart_callback_call(o, "frame,created", frame); + return cf.release(); +} + +WTF::PassRefPtr<WebCore::Widget> ewk_view_plugin_create(Evas_Object* o, Evas_Object* frame, const WebCore::IntSize& pluginSize, WebCore::HTMLPlugInElement* element, const WebCore::KURL& url, const WTF::Vector<WebCore::String>& paramNames, const WTF::Vector<WebCore::String>& paramValues, const WebCore::String& mimeType, bool loadManually) +{ + DBG("o=%p, frame=%p, size=%dx%d, element=%p, url=%s, mimeType=%s", + o, frame, pluginSize.width(), pluginSize.height(), element, + url.prettyURL().utf8().data(), mimeType.utf8().data()); + + EWK_VIEW_SD_GET_OR_RETURN(o, sd, 0); + sd->changed.frame_rect = EINA_TRUE; + _ewk_view_smart_changed(sd); + + return ewk_frame_plugin_create + (frame, pluginSize, element, url, paramNames, paramValues, + mimeType, loadManually); +} + + +/** + * @internal + * + * Creates a new popup with options when a select widget was clicked. + * + * @param client PopupMenuClient instance that allows communication with webkit. + * @param selected Selected item. + * @param rect Menu's position. + * + * Emits: "popup,create" with a list of Ewk_Menu containing each item's data + */ +void ewk_view_popup_new(Evas_Object* o, WebCore::PopupMenuClient* client, int selected, const WebCore::IntRect& rect) +{ + INF("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + + if (priv->popup.menu_client) + ewk_view_popup_destroy(o); + + priv->popup.menu_client = client; + + // populate items + const int size = client->listSize(); + for (int i = 0; i < size; ++i) { + Ewk_Menu_Item* item = (Ewk_Menu_Item*) malloc(sizeof(*item)); + if (client->itemIsSeparator(i)) + item->type = EWK_MENU_SEPARATOR; + else if (client->itemIsLabel(i)) + item->type = EWK_MENU_GROUP; + else + item->type = EWK_MENU_OPTION; + item->text = eina_stringshare_add(client->itemText(i).utf8().data()); + + priv->popup.menu.items = eina_list_append(priv->popup.menu.items, item); + } + + priv->popup.menu.x = rect.x(); + priv->popup.menu.y = rect.y(); + priv->popup.menu.width = rect.width(); + priv->popup.menu.height = rect.height(); + evas_object_smart_callback_call(o, "popup,create", &priv->popup.menu); +} + +/** + * Destroy a previously created menu. + * + * Before destroying, it informs client that menu's data is ready to be + * destroyed by sending a "popup,willdelete" with a list of menu items. Then it + * removes any reference to menu inside webkit. It's safe to call this + * function either from inside webkit or from browser. + * + * @param o View. + * + * @returns EINA_TRUE in case menu was successfully destroyed or EINA_TRUE in + * case there wasn't any menu to be destroyed. + */ +Eina_Bool ewk_view_popup_destroy(Evas_Object* o) +{ + INF("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd, EINA_FALSE); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv, EINA_FALSE); + + if (!priv->popup.menu_client) + return EINA_FALSE; + + evas_object_smart_callback_call(o, "popup,willdelete", &priv->popup.menu); + + void* itemv; + EINA_LIST_FREE(priv->popup.menu.items, itemv) { + Ewk_Menu_Item* item = (Ewk_Menu_Item*)itemv; + eina_stringshare_del(item->text); + free(item); + } + priv->popup.menu_client->popupDidHide(); + priv->popup.menu_client = 0; + + return EINA_TRUE; +} + +/** + * Changes currently selected item. + * + * Changes the option selected in select widget. This is called by browser + * whenever user has chosen a different item. Most likely after calling this, a + * call to ewk_view_popup_destroy might be made in order to close the popup. + * + * @param o View. + * @index Index of selected item. + * + */ +void ewk_view_popup_selected_set(Evas_Object* o, int index) +{ + INF("o=%p", o); + EWK_VIEW_SD_GET_OR_RETURN(o, sd); + EWK_VIEW_PRIV_GET_OR_RETURN(sd, priv); + + priv->popup.menu_client->valueChanged(index); +} + +/** + * @internal + * Request a download to user. + * + * @param o View. + * @oaram download Ewk_Download struct to be sent. + * + * Emits: "download,request" with an Ewk_Download containing the details of the + * requested download. The download per se must be handled outside of webkit. + */ +void ewk_view_download_request(Evas_Object* o, Ewk_Download* download) +{ + DBG("view=%p", o); + evas_object_smart_callback_call(o, "download,request", download); +} diff --git a/WebKit/efl/ewk/ewk_view.h b/WebKit/efl/ewk/ewk_view.h new file mode 100644 index 0000000..20df601 --- /dev/null +++ b/WebKit/efl/ewk/ewk_view.h @@ -0,0 +1,455 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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. +*/ + +#ifndef ewk_view_h +#define ewk_view_h + +#include <Evas.h> +#include <cairo.h> +#include <ewk_history.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief WebKit main smart object. + * + * This object is the high level access to WebKit-EFL browser + * component. It is responsible for managing the main frame and other + * critical resources. + * + * Every ewk_view has at least one frame, called "main frame" and + * retrieved with ewk_view_frame_main_get(). Direct frame access is + * often discouraged, it is recommended to use ewk_view functions + * instead. + * + * The following signals (see evas_object_smart_callback_add()) are emitted: + * + * - "ready", void: page is fully loaded. + * - "title,changed", const char*: title of the main frame changed. + * - "uri,changed", const char*: uri of the main frame changed. + * - "load,started", void: frame started loading. + * - "load,progress", double*: load progress changed (overall value + * from 0.0 to 1.0, connect to individual frames for fine grained). + * - "load,finished", const Ewk_Frame_Load_Error*: reports load + * finished and as argument @c NULL if successfully or pointer to + * structure defining the error. + * - "load,provisional", void: view started provisional load. + * - "load,error", const Ewk_Frame_Load_Error*: reports load failed + * and as argument a pointer to structure defining the error. + * - "frame,created", Evas_Object*: when frames are created, they are + * emitted in this signal. + * - "zoom,animated,end", void: requested animated zoom is finished. + * - "menubar,visible,set", Eina_Bool: set menubar visibility. + * - "menubar,visible,get", Eina_Bool *: expects a @c EINA_TRUE if menubar is + * visible; otherwise, @c EINA_FALSE. + * - "menubar,visible,set", Eina_Bool: set menubar visibility. + * - "menubar,visible,get", Eina_Bool *: expects a @c EINA_TRUE if menubar is + * visible; @c EINA_FALSE, otherwise. + * - "scrollbars,visible,set", Eina_Bool: set scrollbars visibility. + * - "scrollbars,visible,get", Eina_Bool *: expects a @c EINA_TRUE if scrollbars + * are visible; @c EINA_FALSE, otherwise. + * - "statusbar,visible,set", Eina_Bool: set statusbar visibility. + * - "statusbar,visible,get", Eina_Bool *: expects a @c EINA_TRUE if statusbar is + * visible; @c EINA_FALSE, otherwise. + * - "toolbar,visible,set", Eina_Bool: set toolbar visibility. + * - "toolbar,visible,get", Eina_Bool *: expects a @c EINA_TRUE if toolbar + * is visible; @c EINA_FALSE, otherwise. + * - "link,hover,in", const char *link[2]: reports mouse is over a link and as + * argument gives the url in link[0] and link's title in link[1]. + * - "link,hover,out", const char *link[2]: reports mouse moved out from a link + * and as argument gives the url in link[0] and link's title in link[1]. + * - "popup,create", Ewk_Menu: reports that a new menu was created. + * - "popup,willdeleted", Ewk_Menu: reports that a previously created menu is + * about to be deleted. + * - "download,request", Ewk_Download: reports a download is being requested + * and as arguments gives its details. + * - "icon,received", void: main frame received an icon. + */ + +typedef struct _Ewk_View_Smart_Data Ewk_View_Smart_Data; + +/** + * Ewk view's class, to be overridden by sub-classes. + */ +typedef struct _Ewk_View_Smart_Class Ewk_View_Smart_Class; +struct _Ewk_View_Smart_Class { + Evas_Smart_Class sc; /**< all but 'data' is free to be changed. */ + unsigned long version; + + Evas_Object *(*window_create)(Ewk_View_Smart_Data *sd); /**< creates a new window, requested by webkit */ + // hooks to allow different backing stores + Evas_Object *(*backing_store_add)(Ewk_View_Smart_Data *sd); /**< must be defined */ + Eina_Bool (*scrolls_process)(Ewk_View_Smart_Data *sd); /**< must be defined */ + Eina_Bool (*repaints_process)(Ewk_View_Smart_Data *sd); /**< must be defined */ + Eina_Bool (*contents_resize)(Ewk_View_Smart_Data *sd, int w, int h); + Eina_Bool (*zoom_set)(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy); + Eina_Bool (*zoom_weak_set)(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy); + void (*zoom_weak_smooth_scale_set)(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale); + void (*bg_color_set)(Ewk_View_Smart_Data *sd, unsigned char r, unsigned char g, unsigned char b, unsigned char a); + void (*flush)(Ewk_View_Smart_Data *sd); + Eina_Bool (*pre_render_region)(Ewk_View_Smart_Data *sd, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float zoom); + void (*pre_render_cancel)(Ewk_View_Smart_Data *sd); + // event handling: + // - returns true if handled + // - if overridden, have to call parent method if desired + Eina_Bool (*focus_in)(Ewk_View_Smart_Data *sd); + Eina_Bool (*focus_out)(Ewk_View_Smart_Data *sd); + Eina_Bool (*mouse_wheel)(Ewk_View_Smart_Data *sd, const Evas_Event_Mouse_Wheel *ev); + Eina_Bool (*mouse_down)(Ewk_View_Smart_Data *sd, const Evas_Event_Mouse_Down *ev); + Eina_Bool (*mouse_up)(Ewk_View_Smart_Data *sd, const Evas_Event_Mouse_Up *ev); + Eina_Bool (*mouse_move)(Ewk_View_Smart_Data *sd, const Evas_Event_Mouse_Move *ev); + Eina_Bool (*key_down)(Ewk_View_Smart_Data *sd, const Evas_Event_Key_Down *ev); + Eina_Bool (*key_up)(Ewk_View_Smart_Data *sd, const Evas_Event_Key_Up *ev); + + void (*add_console_message)(Ewk_View_Smart_Data *sd, const char *message, unsigned int lineNumber, const char *sourceID); + void (*run_javascript_alert)(Ewk_View_Smart_Data *sd, Evas_Object *frame, const char *message); + Eina_Bool (*run_javascript_confirm)(Ewk_View_Smart_Data *sd, Evas_Object *frame, const char *message); + Eina_Bool (*run_javascript_prompt)(Ewk_View_Smart_Data *sd, Evas_Object *frame, const char *message, const char *defaultValue, char **value); + Eina_Bool (*should_interrupt_javascript)(Ewk_View_Smart_Data *sd); + void (*exceeded_database_quota)(Ewk_View_Smart_Data *sd, Evas_Object *frame, const char *databaseName); + + Eina_Bool (*run_open_panel)(Ewk_View_Smart_Data *sd, Evas_Object *frame, Eina_Bool allows_multiple_files, const Eina_List *suggested_filenames, Eina_List **selected_filenames); +}; + +#define EWK_VIEW_SMART_CLASS_VERSION 1UL /** the version you have to put into the version field in the Ewk_View_Smart_Class structure */ + +/** + * Initializer for whole Ewk_View_Smart_Class structure. + * + * @param smart_class_init initializer to use for the "base" field + * (Evas_Smart_Class). + * + * @see EWK_VIEW_SMART_CLASS_INIT_NULL + * @see EWK_VIEW_SMART_CLASS_INIT_VERSION + * @see EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION + */ +#define EWK_VIEW_SMART_CLASS_INIT(smart_class_init) {smart_class_init, EWK_VIEW_SMART_CLASS_VERSION, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + +/** + * Initializer to zero a whole Ewk_View_Smart_Class structure. + * + * @see EWK_VIEW_SMART_CLASS_INIT_VERSION + * @see EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION + * @see EWK_VIEW_SMART_CLASS_INIT + */ +#define EWK_VIEW_SMART_CLASS_INIT_NULL EWK_VIEW_SMART_CLASS_INIT(EVAS_SMART_CLASS_INIT_NULL) + +/** + * Initializer to zero a whole Ewk_View_Smart_Class structure and set version. + * + * Similar to EWK_VIEW_SMART_CLASS_INIT_NULL, but will set version field of + * Evas_Smart_Class (base field) to latest EVAS_SMART_CLASS_VERSION + * + * @see EWK_VIEW_SMART_CLASS_INIT_NULL + * @see EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION + * @see EWK_VIEW_SMART_CLASS_INIT + */ +#define EWK_VIEW_SMART_CLASS_INIT_VERSION EWK_VIEW_SMART_CLASS_INIT(EVAS_SMART_CLASS_INIT_VERSION) + +/** + * Initializer to zero a whole Ewk_View_Smart_Class structure and set + * name and version. + * + * Similar to EWK_VIEW_SMART_CLASS_INIT_NULL, but will set version field of + * Evas_Smart_Class (base field) to latest EVAS_SMART_CLASS_VERSION and name + * to the specific value. + * + * It will keep a reference to name field as a "const char *", that is, + * name must be available while the structure is used (hint: static or global!) + * and will not be modified. + * + * @see EWK_VIEW_SMART_CLASS_INIT_NULL + * @see EWK_VIEW_SMART_CLASS_INIT_VERSION + * @see EWK_VIEW_SMART_CLASS_INIT + */ +#define EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION(name) EWK_VIEW_SMART_CLASS_INIT(EVAS_SMART_CLASS_INIT_NAME_VERSION(name)) + +/** + * @internal + * + * private data that is used internally by EFL WebKit and should never + * be modified from outside. + */ +typedef struct _Ewk_View_Private_Data Ewk_View_Private_Data; + +enum _Ewk_Menu_Item_Type { + EWK_MENU_SEPARATOR, + EWK_MENU_GROUP, + EWK_MENU_OPTION +}; +typedef enum _Ewk_Menu_Item_Type Ewk_Menu_Item_Type; + + +/** + * Structure do contain data of each menu item + */ +typedef struct _Ewk_Menu_Item Ewk_Menu_Item; +struct _Ewk_Menu_Item { + const char *text; /**< Item's text */ + Ewk_Menu_Item_Type type; /** Item's type */ +}; + +/** + * Structure to contain Popup menu data. + */ +typedef struct _Ewk_Menu Ewk_Menu; +struct _Ewk_Menu { + Eina_List* items; + int x; + int y; + int width; + int height; +}; + +/** + * Structure to contain Download data + */ +typedef struct _Ewk_Download Ewk_Download; +struct _Ewk_Download { + const char* url; + /* to be extended */ +}; + +/** + * Scroll request that should be processed by subclass implementations. + */ +typedef struct _Ewk_Scroll_Request Ewk_Scroll_Request; +struct _Ewk_Scroll_Request { + Evas_Coord dx, dy; + Evas_Coord x, y, w, h, x2, y2; + Eina_Bool main_scroll; +}; + +/** + * Structure to contain internal View data, it is to be considered + * private by users, but may be extended or changed by sub-classes + * (that's why it's in public header file). + */ +struct _Ewk_View_Smart_Data { + Evas_Object_Smart_Clipped_Data base; + const Ewk_View_Smart_Class *api; /**< reference to casted class instance */ + Evas_Object *self; /**< reference to owner object */ + Evas_Object *main_frame; /**< reference to main frame object */ + Evas_Object *backing_store; /**< reference to backing store */ + Ewk_View_Private_Data *_priv; /**< should never be accessed, c++ stuff */ + struct { + Evas_Coord x, y, w, h; /**< last used viewport */ + } view; + struct { + struct { + float start; + float end; + float current; /**< if > 0.0, then doing animated zoom. */ + } zoom; + } animated_zoom; + struct { + unsigned char r, g, b, a; + } bg_color; + Eina_Bool zoom_weak_smooth_scale:1; + struct { /**< what changed since last smart_calculate */ + Eina_Bool any:1; + Eina_Bool size:1; + Eina_Bool position:1; + Eina_Bool frame_rect:1; + } changed; +}; + +EAPI Eina_Bool ewk_view_base_smart_set(Ewk_View_Smart_Class *api); +EAPI Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api); + +EAPI Evas_Object *ewk_view_single_add(Evas *e); + +EAPI void ewk_view_fixed_layout_size_set(Evas_Object *o, Evas_Coord w, Evas_Coord h); +EAPI void ewk_view_fixed_layout_size_get(Evas_Object *o, Evas_Coord *w, Evas_Coord *h); + +EAPI void ewk_view_theme_set(Evas_Object *o, const char *path); +EAPI const char *ewk_view_theme_get(Evas_Object *o); + +EAPI Evas_Object *ewk_view_frame_main_get(const Evas_Object *o); +EAPI Evas_Object *ewk_view_frame_focused_get(const Evas_Object *o); + +EAPI Eina_Bool ewk_view_uri_set(Evas_Object *o, const char *uri); +EAPI const char *ewk_view_uri_get(const Evas_Object *o); +EAPI const char *ewk_view_title_get(const Evas_Object *o); + +EAPI Eina_Bool ewk_view_editable_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_editable_set(Evas_Object *o, Eina_Bool editable); + +EAPI void ewk_view_bg_color_set(Evas_Object *o, int r, int g, int b, int a); +EAPI void ewk_view_bg_color_get(const Evas_Object *o, int *r, int *g, int *b, int *a); + +EAPI char *ewk_view_selection_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_select_none(Evas_Object *o); +EAPI Eina_Bool ewk_view_select_all(Evas_Object *o); +EAPI Eina_Bool ewk_view_select_paragraph(Evas_Object *o); +EAPI Eina_Bool ewk_view_select_sentence(Evas_Object *o); +EAPI Eina_Bool ewk_view_select_line(Evas_Object *o); +EAPI Eina_Bool ewk_view_select_word(Evas_Object *o); + +EAPI void ewk_view_popup_selected_set(Evas_Object *o, int index); +EAPI Eina_Bool ewk_view_popup_destroy(Evas_Object *o); + +EAPI Eina_Bool ewk_view_text_search(const Evas_Object *o, const char *string, Eina_Bool case_sensitive, Eina_Bool forward, Eina_Bool wrap); + +EAPI unsigned int ewk_view_text_matches_mark(Evas_Object *o, const char *string, Eina_Bool case_sensitive, Eina_Bool highlight, unsigned int limit); +EAPI Eina_Bool ewk_view_text_matches_unmark_all(Evas_Object *o); +EAPI Eina_Bool ewk_view_text_matches_highlight_set(Evas_Object *o, Eina_Bool highlight); +EAPI Eina_Bool ewk_view_text_matches_highlight_get(const Evas_Object *o); + +EAPI double ewk_view_load_progress_get(const Evas_Object *o); + +EAPI Eina_Bool ewk_view_stop(Evas_Object *o); +EAPI Eina_Bool ewk_view_reload(Evas_Object *o); +EAPI Eina_Bool ewk_view_reload_full(Evas_Object *o); + +EAPI Eina_Bool ewk_view_back(Evas_Object *o); +EAPI Eina_Bool ewk_view_forward(Evas_Object *o); +EAPI Eina_Bool ewk_view_navigate(Evas_Object *o, int steps); + +EAPI Eina_Bool ewk_view_back_possible(Evas_Object *o); +EAPI Eina_Bool ewk_view_forward_possible(Evas_Object *o); +EAPI Eina_Bool ewk_view_navigate_possible(Evas_Object *o, int steps); + +EAPI Eina_Bool ewk_view_history_enable_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_history_enable_set(Evas_Object *o, Eina_Bool enable); +EAPI Ewk_History *ewk_view_history_get(const Evas_Object *o); + +EAPI float ewk_view_zoom_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_zoom_set(Evas_Object *o, float zoom, Evas_Coord cx, Evas_Coord cy); + +EAPI Eina_Bool ewk_view_zoom_weak_smooth_scale_get(const Evas_Object *o); +EAPI void ewk_view_zoom_weak_smooth_scale_set(Evas_Object *o, Eina_Bool smooth_scale); + +EAPI Eina_Bool ewk_view_zoom_weak_set(Evas_Object *o, float zoom, Evas_Coord cx, Evas_Coord cy); +EAPI Eina_Bool ewk_view_zoom_animated_mark_start(Evas_Object *o, float zoom); +EAPI Eina_Bool ewk_view_zoom_animated_mark_end(Evas_Object *o, float zoom); +EAPI Eina_Bool ewk_view_zoom_animated_mark_current(Evas_Object *o, float zoom); +EAPI Eina_Bool ewk_view_zoom_animated_mark_stop(Evas_Object *o); + +EAPI Eina_Bool ewk_view_zoom_animated_set(Evas_Object *o, float zoom, float duration, Evas_Coord cx, Evas_Coord cy); +EAPI Eina_Bool ewk_view_zoom_text_only_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_zoom_text_only_set(Evas_Object *o, Eina_Bool setting); + +EAPI Eina_Bool ewk_view_pre_render_region(Evas_Object *o, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h, float zoom); +EAPI void ewk_view_pre_render_cancel(Evas_Object *o); + +/* settings */ +EAPI const char *ewk_view_setting_user_agent_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_user_agent_set(Evas_Object *o, const char *user_agent); + +EAPI Eina_Bool ewk_view_setting_auto_load_images_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_auto_load_images_set(Evas_Object *o, Eina_Bool automatic); + +EAPI Eina_Bool ewk_view_setting_auto_shrink_images_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_auto_shrink_images_set(Evas_Object *o, Eina_Bool automatic); + +EAPI Eina_Bool ewk_view_setting_enable_scripts_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_enable_scripts_set(Evas_Object *o, Eina_Bool enable); + +EAPI Eina_Bool ewk_view_setting_enable_plugins_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_enable_plugins_set(Evas_Object *o, Eina_Bool enable); + +EAPI Eina_Bool ewk_view_setting_scripts_window_open_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_scripts_window_open_set(Evas_Object *o, Eina_Bool allow); + +EAPI Eina_Bool ewk_view_setting_resizable_textareas_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_resizable_textareas_set(Evas_Object *o, Eina_Bool enable); + +EAPI const char *ewk_view_setting_user_stylesheet_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_user_stylesheet_set(Evas_Object *o, const char *uri); + +EAPI Eina_Bool ewk_view_setting_private_browsing_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_private_browsing_set(Evas_Object *o, Eina_Bool enable); + +EAPI Eina_Bool ewk_view_setting_caret_browsing_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_caret_browsing_set(Evas_Object *o, Eina_Bool enable); + +EAPI const char *ewk_view_setting_encoding_custom_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_encoding_custom_set(Evas_Object *o, const char *encoding); +EAPI const char *ewk_view_setting_encoding_default_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_encoding_default_set(Evas_Object *o, const char *encoding); + +EAPI int ewk_view_setting_font_minimum_size_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_minimum_size_set(Evas_Object *o, int size); +EAPI int ewk_view_setting_font_minimum_logical_size_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_minimum_logical_size_set(Evas_Object *o, int size); +EAPI int ewk_view_setting_font_default_size_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_default_size_set(Evas_Object *o, int size); +EAPI int ewk_view_setting_font_monospace_size_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_monospace_size_set(Evas_Object *o, int size); + +EAPI const char *ewk_view_setting_font_standard_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_standard_set(Evas_Object *o, const char *family); + +EAPI const char *ewk_view_setting_font_cursive_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_cursive_set(Evas_Object *o, const char *family); + +EAPI const char *ewk_view_setting_font_monospace_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_monospace_set(Evas_Object *o, const char *family); + +EAPI const char *ewk_view_setting_font_fantasy_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_fantasy_set(Evas_Object *o, const char *family); + +EAPI const char *ewk_view_setting_font_serif_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_serif_set(Evas_Object *o, const char *family); + +EAPI const char *ewk_view_setting_font_sans_serif_get(const Evas_Object *o); +EAPI Eina_Bool ewk_view_setting_font_sans_serif_set(Evas_Object *o, const char *family); + +/* to be used by subclass implementations */ +EAPI Ewk_View_Smart_Data *ewk_view_smart_data_get(const Evas_Object *o); + +EAPI const Eina_Rectangle *ewk_view_repaints_get(const Ewk_View_Private_Data *priv, size_t *count); +EAPI const Ewk_Scroll_Request *ewk_view_scroll_requests_get(const Ewk_View_Private_Data *priv, size_t *count); + +EAPI void ewk_view_repaint_add(Ewk_View_Private_Data *priv, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h); + +EAPI void ewk_view_layout_if_needed_recursive(Ewk_View_Private_Data *priv); + +EAPI void ewk_view_scrolls_process(Ewk_View_Smart_Data *sd); + +/** + * Structure that keeps paint context. + * + * @note this is not for general use but just for subclasses that want + * to define their own backing store. + */ +typedef struct _Ewk_View_Paint_Context Ewk_View_Paint_Context; + +EAPI Ewk_View_Paint_Context *ewk_view_paint_context_new(Ewk_View_Private_Data *priv, cairo_t *cr); +EAPI void ewk_view_paint_context_free(Ewk_View_Paint_Context *ctxt); + +EAPI void ewk_view_paint_context_save(Ewk_View_Paint_Context *ctxt); +EAPI void ewk_view_paint_context_restore(Ewk_View_Paint_Context *ctxt); +EAPI void ewk_view_paint_context_clip(Ewk_View_Paint_Context *ctxt, const Eina_Rectangle *area); +EAPI void ewk_view_paint_context_paint(Ewk_View_Paint_Context *ctxt, const Eina_Rectangle *area); +EAPI void ewk_view_paint_context_paint_contents(Ewk_View_Paint_Context *ctxt, const Eina_Rectangle *area); +EAPI void ewk_view_paint_context_scale(Ewk_View_Paint_Context *ctxt, float scale_x, float scale_y); +EAPI void ewk_view_paint_context_translate(Ewk_View_Paint_Context *ctxt, float x, float y); + +EAPI Eina_Bool ewk_view_paint(Ewk_View_Private_Data *priv, cairo_t *cr, const Eina_Rectangle *area); +EAPI Eina_Bool ewk_view_paint_contents(Ewk_View_Private_Data *priv, cairo_t *cr, const Eina_Rectangle *area); + +#ifdef __cplusplus +} +#endif +#endif // ewk_view_h diff --git a/WebKit/efl/ewk/ewk_view_single.c b/WebKit/efl/ewk/ewk_view_single.c new file mode 100644 index 0000000..4111370 --- /dev/null +++ b/WebKit/efl/ewk/ewk_view_single.c @@ -0,0 +1,585 @@ +/* + Copyright (C) 2009-2010 ProFUSION embedded systems + Copyright (C) 2009-2010 Samsung Electronics + + 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 "ewk_view.h" + +#include "ewk_frame.h" +#include "ewk_logging.h" + +#include <Evas.h> +#include <eina_safety_checks.h> +#include <string.h> + +static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL; + +static void _ewk_view_single_on_del(void *data, Evas *e, Evas_Object *o, void *event_info) +{ + Evas_Object *clip = (Evas_Object*)data; + evas_object_del(clip); +} + +static Evas_Object *_ewk_view_single_smart_backing_store_add(Ewk_View_Smart_Data *sd) +{ + Evas_Object *bs = evas_object_image_add(sd->base.evas); + Evas_Object *clip = evas_object_rectangle_add(sd->base.evas); + evas_object_image_alpha_set(bs, EINA_FALSE); + evas_object_image_smooth_scale_set(bs, sd->zoom_weak_smooth_scale); + evas_object_clip_set(bs, clip); + evas_object_show(clip); + + evas_object_event_callback_add + (bs, EVAS_CALLBACK_DEL, _ewk_view_single_on_del, clip); + + return bs; +} + +static void _ewk_view_single_smart_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h) +{ + Ewk_View_Smart_Data *sd = (Ewk_View_Smart_Data*)evas_object_smart_data_get(o); + _parent_sc.sc.resize(o, w, h); + + // these should be queued and processed in calculate as well! + evas_object_image_size_set(sd->backing_store, w, h); + if (sd->animated_zoom.zoom.current < 0.00001) { + Evas_Object *clip = evas_object_clip_get(sd->backing_store); + Evas_Coord x, y, cw, ch; + evas_object_image_fill_set(sd->backing_store, 0, 0, w, h); + evas_object_geometry_get(sd->backing_store, &x, &y, 0, 0); + evas_object_move(clip, x, y); + ewk_frame_contents_size_get(sd->main_frame, &cw, &ch); + if (w > cw) + w = cw; + if (h > ch) + h = ch; + evas_object_resize(clip, w, h); + } +} + +static inline void _ewk_view_4b_move_region_up(uint32_t *image, size_t rows, size_t x, size_t y, size_t w, size_t h, size_t rowsize) +{ + uint32_t *src; + uint32_t *dst; + + dst = image + x + y * rowsize; + src = dst + rows * rowsize; + h -= rows; + + for (; h > 0; h--, dst += rowsize, src += rowsize) + memcpy(dst, src, w * 4); +} + +static inline void _ewk_view_4b_move_region_down(uint32_t *image, size_t rows, size_t x, size_t y, size_t w, size_t h, size_t rowsize) +{ + uint32_t *src; + uint32_t *dst; + + h -= rows; + src = image + x + (y + h - 1) * rowsize; + dst = src + rows * rowsize; + + for (; h > 0; h--, dst -= rowsize, src -= rowsize) + memcpy(dst, src, w * 4); +} + +static inline void _ewk_view_4b_move_line_left(uint32_t *dst, const uint32_t *src, size_t count) +{ + uint32_t *dst_end = dst + count; + /* no memcpy() as it does not allow overlapping regions */ + /* no memmove() as it will copy to a temporary buffer */ + /* TODO: loop unrolling, copying up to quad-words would help */ + for (; dst < dst_end; dst++, src++) + *dst = *src; +} + +static inline void _ewk_view_4b_move_line_right(uint32_t *dst, uint32_t *src, size_t count) +{ + uint32_t *dst_end = dst - count; + /* no memcpy() as it does not allow overlapping regions */ + /* no memmove() as it will copy to a temporary buffer */ + /* TODO: loop unrolling, copying up to quad-words would help */ + for (; dst > dst_end; dst--, src--) + *dst = *src; +} + +static inline void _ewk_view_4b_move_region_left(uint32_t *image, size_t cols, size_t x, size_t y, size_t w, size_t h, size_t rowsize) +{ + uint32_t *src; + uint32_t *dst; + + dst = image + x + y * rowsize; + src = dst + cols; + w -= cols; + + for (; h > 0; h--, dst += rowsize, src += rowsize) + _ewk_view_4b_move_line_left(dst, src, w); +} + +static inline void _ewk_view_4b_move_region_right(uint32_t *image, size_t cols, size_t x, size_t y, size_t w, size_t h, size_t rowsize) +{ + uint32_t *src; + uint32_t *dst; + + w -= cols; + src = image + (x + w - 1) + y * rowsize; + dst = src + cols; + + for (; h > 0; h--, dst += rowsize, src += rowsize) + _ewk_view_4b_move_line_right(dst, src, w); +} + +/* catch-all function, not as optimized as the others, but does the work. */ +static inline void _ewk_view_4b_move_region(uint32_t *image, int dx, int dy, size_t x, size_t y, size_t w, size_t h, size_t rowsize) +{ + uint32_t *src; + uint32_t *dst; + + if (dy < 0) { + h += dy; + dst = image + x + y * rowsize; + src = dst - dy * rowsize; + if (dx <= 0) { + w += dx; + src -= dx; + for (; h > 0; h--, dst += rowsize, src += rowsize) + _ewk_view_4b_move_line_left(dst, src, w); + } else { + w -= dx; + src += w - 1; + dst += w + dx -1; + for (; h > 0; h--, dst += rowsize, src += rowsize) + _ewk_view_4b_move_line_right(dst, src, w); + } + } else { + h -= dy; + src = image + x + (y + h - 1) * rowsize; + dst = src + dy * rowsize; + if (dx <= 0) { + w += dx; + src -= dx; + for (; h > 0; h--, dst -= rowsize, src -= rowsize) + _ewk_view_4b_move_line_left(dst, src, w); + } else { + w -= dx; + src += w - 1; + dst += w + dx - 1; + for (; h > 0; h--, dst -= rowsize, src -= rowsize) + _ewk_view_4b_move_line_right(dst, src, w); + } + } +} + +static inline void _ewk_view_single_scroll_process_single(Ewk_View_Smart_Data *sd, void *pixels, Evas_Coord ow, Evas_Coord oh, const Ewk_Scroll_Request *sr) +{ + Evas_Coord sx, sy, sw, sh; + + DBG("%d,%d + %d,%d %+03d,%+03d, store: %p %dx%d", + sr->x, sr->y, sr->w, sr->h, sr->dx, sr->dy, pixels, ow, oh); + + sx = sr->x; + sy = sr->y; + sw = sr->w; + sh = sr->h; + + if (abs(sr->dx) >= sw || abs(sr->dy) >= sh) { + /* doubt webkit would be so stupid... */ + DBG("full page scroll %+03d,%+03d. convert to repaint %d,%d + %dx%d", + sr->dx, sr->dy, sx, sy, sw, sh); + ewk_view_repaint_add(sd->_priv, sx, sy, sw, sh); + return; + } + + if (sx < 0) { + sw += sx; + sx = 0; + } + if (sy < 0) { + sh += sy; + sy = 0; + } + + if (sx + sw > ow) + sw = ow - sx; + if (sy + sh > oh) + sh = oh - sy; + + if (sw < 0) + sw = 0; + if (sh < 0) + sh = 0; + + EINA_SAFETY_ON_TRUE_RETURN(!sw || !sh); + if (!sr->dx) { + if (sr->dy < 0) { + DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, " + "repaint=%d,%d+%dx%d", + sr->dx, sr->dy, sx, sy, sw, sh + sr->dy, + sx, sy + sh + sr->dy, sw, -sr->dy); + + _ewk_view_4b_move_region_up + ((uint32_t*)pixels, -sr->dy, sx, sy, sw, sh, ow); + evas_object_image_data_update_add + (sd->backing_store, sx, sy, sw, sh + sr->dy); + + ewk_view_repaint_add(sd->_priv, sx, sy + sh + sr->dy, sw, -sr->dy); + } else if (sr->dy > 0) { + DBG("scroll down: %+03d,%+03d update=%d,%d+%dx%d, " + "repaint=%d,%d+%dx%d", + sr->dx, sr->dy, sx, sy + sr->dy, sw, sh - sr->dy, + sx, sy, sw, sr->dy); + + _ewk_view_4b_move_region_down + ((uint32_t*)pixels, sr->dy, sx, sy, sw, sh, ow); + evas_object_image_data_update_add + (sd->backing_store, sx, sy + sr->dy, sw, sh - sr->dy); + + ewk_view_repaint_add(sd->_priv, sx, sy, sw, sr->dy); + } + } else if (!sr->dy) { + if (sr->dx < 0) { + DBG("scroll left: %+03d,%+03d update=%d,%d+%dx%d, " + "repaint=%d,%d+%dx%d", + sr->dx, sr->dy, sx, sy, sw + sr->dx, sh, + sx + sw + sr->dx, sy, -sr->dx, sh); + + _ewk_view_4b_move_region_left + ((uint32_t*)pixels, -sr->dx, sx, sy, sw, sh, ow); + evas_object_image_data_update_add + (sd->backing_store, sx, sy, sw + sr->dx, sh); + + ewk_view_repaint_add(sd->_priv, sx + sw + sr->dx, sy, -sr->dx, sh); + } else if (sr->dx > 0) { + DBG("scroll up: %+03d,%+03d update=%d,%d+%dx%d, " + "repaint=%d,%d+%dx%d", + sr->dx, sr->dy, sx + sr->dx, sy, sw - sr->dx, sh, + sx, sy, sr->dx, sh); + + _ewk_view_4b_move_region_right + ((uint32_t*)pixels, sr->dx, sx, sy, sw, sh, ow); + evas_object_image_data_update_add + (sd->backing_store, sx + sr->dx, sy, sw - sr->dx, sh); + + ewk_view_repaint_add(sd->_priv, sx, sy, sr->dx, sh); + } + } else { + Evas_Coord mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh; + + if (sr->dx < 0) { + mx = sx; + mw = sw + sr->dx; + ax = mx + mw; + aw = -sr->dx; + } else { + ax = sx; + aw = sr->dx; + mx = ax + aw; + mw = sw - sr->dx; + } + + if (sr->dy < 0) { + my = sy; + mh = sh + sr->dy; + by = my + mh; + bh = -sr->dy; + } else { + by = sy; + bh = sr->dy; + my = by + bh; + mh = sh - sr->dy; + } + + ay = my; + ah = mh; + bx = sx; + bw = sw; + + DBG("scroll diagonal: %+03d,%+03d update=%d,%d+%dx%d, " + "repaints: h=%d,%d+%dx%d v=%d,%d+%dx%d", + sr->dx, sr->dy, mx, my, mw, mh, ax, ay, aw, ah, bx, by, bw, bh); + + _ewk_view_4b_move_region + ((uint32_t*)pixels, sr->dx, sr->dy, sx, sy, sw, sh, ow); + + evas_object_image_data_update_add(sd->backing_store, mx, my, mw, mh); + ewk_view_repaint_add(sd->_priv, ax, ay, aw, ah); + ewk_view_repaint_add(sd->_priv, bx, by, bw, bh); + } +} + +static Eina_Bool _ewk_view_single_smart_scrolls_process(Ewk_View_Smart_Data *sd) +{ + const Ewk_Scroll_Request *sr; + const Ewk_Scroll_Request *sr_end; + Evas_Coord ow, oh; + size_t count; + void *pixels = evas_object_image_data_get(sd->backing_store, 1); + evas_object_image_size_get(sd->backing_store, &ow, &oh); + + sr = ewk_view_scroll_requests_get(sd->_priv, &count); + sr_end = sr + count; + for (; sr < sr_end; sr++) + _ewk_view_single_scroll_process_single(sd, pixels, ow, oh, sr); + + return EINA_TRUE; +} + +static Eina_Bool _ewk_view_single_smart_repaints_process(Ewk_View_Smart_Data *sd) +{ + Ewk_View_Paint_Context *ctxt; + Evas_Coord ow, oh; + void *pixels; + Eina_Rectangle r = {0, 0, 0, 0}; + const Eina_Rectangle *pr; + const Eina_Rectangle *pr_end; + Eina_Tiler *tiler; + Eina_Iterator *itr; + cairo_status_t status; + cairo_surface_t *surface; + cairo_format_t format; + cairo_t *cairo; + size_t count; + Eina_Bool ret = EINA_TRUE; + + if (sd->animated_zoom.zoom.current < 0.00001) { + Evas_Object *clip = evas_object_clip_get(sd->backing_store); + Evas_Coord w, h, cw, ch; + // reset effects of zoom_weak_set() + evas_object_image_fill_set + (sd->backing_store, 0, 0, sd->view.w, sd->view.h); + evas_object_move(clip, sd->view.x, sd->view.y); + + w = sd->view.w; + h = sd->view.h; + + ewk_frame_contents_size_get(sd->main_frame, &cw, &ch); + if (w > cw) + w = cw; + if (h > ch) + h = ch; + evas_object_resize(clip, w, h); + } + + pixels = evas_object_image_data_get(sd->backing_store, 1); + evas_object_image_size_get(sd->backing_store, &ow, &oh); + + if (sd->bg_color.a < 255) + format = CAIRO_FORMAT_ARGB32; + else + format = CAIRO_FORMAT_RGB24; + + surface = cairo_image_surface_create_for_data + ((unsigned char*)pixels, format, ow, oh, ow * 4); + status = cairo_surface_status(surface); + if (status != CAIRO_STATUS_SUCCESS) { + ERR("could not create surface from data %dx%d: %s", + ow, oh, cairo_status_to_string(status)); + ret = EINA_FALSE; + goto error_cairo_surface; + } + cairo = cairo_create(surface); + status = cairo_status(cairo); + if (status != CAIRO_STATUS_SUCCESS) { + ERR("could not create cairo from surface %dx%d: %s", + ow, oh, cairo_status_to_string(status)); + ret = EINA_FALSE; + goto error_cairo; + } + + ctxt = ewk_view_paint_context_new(sd->_priv, cairo); + if (!ctxt) { + ERR("could not create paint context"); + ret = EINA_FALSE; + goto error_paint_context; + } + + tiler = eina_tiler_new(ow, oh); + if (!tiler) { + ERR("could not create tiler %dx%d", ow, oh); + ret = EINA_FALSE; + goto error_tiler; + } + + pr = ewk_view_repaints_get(sd->_priv, &count); + pr_end = pr + count; + for (; pr < pr_end; pr++) + eina_tiler_rect_add(tiler, pr); + + itr = eina_tiler_iterator_new(tiler); + if (!itr) { + ERR("could not get iterator for tiler"); + ret = EINA_FALSE; + goto error_iterator; + } + + int sx, sy; + ewk_frame_scroll_pos_get(sd->main_frame, &sx, &sy); + + EINA_ITERATOR_FOREACH(itr, r) { + Eina_Rectangle scrolled_rect = { + r.x + sx, r.y + sy, + r.w, r.h + }; + + ewk_view_paint_context_save(ctxt); + + if ((sx) || (sy)) + ewk_view_paint_context_translate(ctxt, -sx, -sy); + + ewk_view_paint_context_clip(ctxt, &scrolled_rect); + ewk_view_paint_context_paint_contents(ctxt, &scrolled_rect); + + ewk_view_paint_context_restore(ctxt); + evas_object_image_data_update_add + (sd->backing_store, r.x, r.y, r.w, r.h); + } + eina_iterator_free(itr); + +error_iterator: + eina_tiler_free(tiler); +error_tiler: + ewk_view_paint_context_free(ctxt); +error_paint_context: + cairo_destroy(cairo); +error_cairo: + cairo_surface_destroy(surface); +error_cairo_surface: + evas_object_image_data_set(sd->backing_store, pixels); /* dec refcount */ + + return ret; +} + +static Eina_Bool _ewk_view_single_smart_zoom_weak_set(Ewk_View_Smart_Data *sd, float zoom, Evas_Coord cx, Evas_Coord cy) +{ + // TODO: review + float scale = zoom / sd->animated_zoom.zoom.start; + Evas_Coord w = sd->view.w * scale; + Evas_Coord h = sd->view.h * scale; + Evas_Coord dx, dy, cw, ch; + Evas_Object *clip = evas_object_clip_get(sd->backing_store); + + ewk_frame_contents_size_get(sd->main_frame, &cw, &ch); + if (sd->view.w > 0 && sd->view.h > 0) { + dx = (w * (sd->view.w - cx)) / sd->view.w; + dy = (h * (sd->view.h - cy)) / sd->view.h; + } else { + dx = 0; + dy = 0; + } + + evas_object_image_fill_set(sd->backing_store, cx + dx, cy + dy, w, h); + + if (sd->view.w > 0 && sd->view.h > 0) { + dx = ((sd->view.w - w) * cx) / sd->view.w; + dy = ((sd->view.h - h) * cy) / sd->view.h; + } else { + dx = 0; + dy = 0; + } + evas_object_move(clip, sd->view.x + dx, sd->view.y + dy); + + if (cw < sd->view.w) + w = cw * scale; + if (ch < sd->view.h) + h = ch * scale; + evas_object_resize(clip, w, h); + return EINA_TRUE; +} + +static void _ewk_view_single_smart_zoom_weak_smooth_scale_set(Ewk_View_Smart_Data *sd, Eina_Bool smooth_scale) +{ + evas_object_image_smooth_scale_set(sd->backing_store, smooth_scale); +} + +static void _ewk_view_single_smart_bg_color_set(Ewk_View_Smart_Data *sd, unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + evas_object_image_alpha_set(sd->backing_store, a < 255); +} + +/** + * Sets the smart class api using single backing store, enabling view + * to be inherited. + * + * @param api class definition to be set, all members with the + * exception of Evas_Smart_Class->data may be overridden. Must + * @b not be @c NULL. + * + * @note Evas_Smart_Class->data is used to implement type checking and + * is not supposed to be changed/overridden. If you need extra + * data for your smart class to work, just extend + * Ewk_View_Smart_Class instead. + * + * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (probably + * version mismatch). + * + * @see ewk_view_base_smart_set() + */ +Eina_Bool ewk_view_single_smart_set(Ewk_View_Smart_Class *api) +{ + if (!ewk_view_base_smart_set(api)) + return EINA_FALSE; + + if (EINA_UNLIKELY(!_parent_sc.sc.add)) + ewk_view_base_smart_set(&_parent_sc); + + api->sc.resize = _ewk_view_single_smart_resize; + + api->backing_store_add = _ewk_view_single_smart_backing_store_add; + api->scrolls_process = _ewk_view_single_smart_scrolls_process; + api->repaints_process = _ewk_view_single_smart_repaints_process; + api->zoom_weak_set = _ewk_view_single_smart_zoom_weak_set; + api->zoom_weak_smooth_scale_set = _ewk_view_single_smart_zoom_weak_smooth_scale_set; + api->bg_color_set = _ewk_view_single_smart_bg_color_set; + + return EINA_TRUE; +} + +static inline Evas_Smart *_ewk_view_single_smart_class_new(void) +{ + static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("Ewk_View_Single"); + static Evas_Smart *smart = 0; + + if (EINA_UNLIKELY(!smart)) { + ewk_view_single_smart_set(&api); + smart = evas_smart_class_new(&api.sc); + } + + return smart; +} + +/** + * Creates a new EFL WebKit View object. + * + * View objects are the recommended way to deal with EFL WebKit as it + * abstracts the complex pieces of the process. + * + * Each view is composed by a set of frames. The set has at least one + * frame, called 'main_frame'. See ewk_view_frame_main_get() and + * ewk_view_frame_focused_get(). + * + * @param e canvas where to create the view object. + * + * @return view object or @c NULL if errors. + * + * @see ewk_view_uri_set() + */ +Evas_Object *ewk_view_single_add(Evas *e) +{ + return evas_object_smart_add(e, _ewk_view_single_smart_class_new()); +} |