#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(); 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); 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;
}
Evas_Object* ewk_frame_add(Evas* e)
{
return evas_object_smart_add(e, _ewk_frame_smart_class_new());
}
Evas_Object* ewk_frame_view_get(const Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0);
return sd->view;
}
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();
}
}
const char* ewk_frame_theme_get(Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0);
return sd->theme;
}
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;
}
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)));
}
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;
}
const char* ewk_frame_uri_get(const Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0);
return sd->uri;
}
const char* ewk_frame_title_get(const Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0);
return sd->title;
}
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;
}
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;
}
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);
}
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);
}
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;
}
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;
}
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;
}
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();
}
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");
}
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");
}
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");
}
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");
}
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");
}
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");
}
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);
}
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);
}
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;
}
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;
}
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();
}
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;
}
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;
}
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;
}
Eina_Bool ewk_frame_back(Evas_Object* o)
{
return ewk_frame_navigate(o, -1);
}
Eina_Bool ewk_frame_forward(Evas_Object* o)
{
return ewk_frame_navigate(o, 1);
}
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;
}
Eina_Bool ewk_frame_back_possible(Evas_Object* o)
{
return ewk_frame_navigate_possible(o, -1);
}
Eina_Bool ewk_frame_forward_possible(Evas_Object* o)
{
return ewk_frame_navigate_possible(o, 1);
}
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);
}
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();
}
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);
WebCore::ZoomMode zoomMode;
if (sd->zoom_text_only)
zoomMode = WebCore::ZoomTextOnly;
else
zoomMode = WebCore::ZoomPage;
sd->frame->setZoomFactor(zoom, zoomMode);
return EINA_TRUE;
}
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;
}
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;
WebCore::ZoomMode zoomMode;
if (sd->zoom_text_only)
zoomMode = WebCore::ZoomTextOnly;
else
zoomMode = WebCore::ZoomPage;
sd->frame->setZoomFactor(sd->frame->zoomFactor(), zoomMode);
return EINA_TRUE;
}
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);
}
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)),
false, 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
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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();
}
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);
}
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;
}
Eina_Bool ewk_frame_feed_focus_out(Evas_Object* o)
{
ERR("what to do?");
return EINA_FALSE;
}
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);
}
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);
}
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);
}
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 VK_SPACE:
granularity = WebCore::ScrollByPage;
if (event.shiftKey())
direction = WebCore::ScrollUp;
else
direction = WebCore::ScrollDown;
break;
case VK_NEXT:
granularity = WebCore::ScrollByPage;
direction = WebCore::ScrollDown;
break;
case VK_PRIOR:
granularity = WebCore::ScrollByPage;
direction = WebCore::ScrollUp;
break;
case VK_HOME:
granularity = WebCore::ScrollByDocument;
direction = WebCore::ScrollUp;
break;
case VK_END:
granularity = WebCore::ScrollByDocument;
direction = WebCore::ScrollDown;
break;
case VK_LEFT:
granularity = WebCore::ScrollByLine;
direction = WebCore::ScrollLeft;
break;
case VK_RIGHT:
granularity = WebCore::ScrollByLine;
direction = WebCore::ScrollRight;
break;
case VK_UP:
direction = WebCore::ScrollUp;
if (event.ctrlKey())
granularity = WebCore::ScrollByDocument;
else
granularity = WebCore::ScrollByLine;
break;
case 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;
}
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);
}
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);
}
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;
return frame;
died:
CRITICAL("does this work: BEGIN");
ewk_frame_core_gone(frame); evas_object_del(frame); CRITICAL("does this work: END");
return 0;
}
void ewk_frame_core_gone(Evas_Object* o)
{
DBG("o=%p", o);
EWK_FRAME_SD_GET_OR_RETURN(o, sd);
sd->frame = 0;
}
WebCore::Frame* ewk_frame_core_get(const Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd, 0);
return sd->frame;
}
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);
}
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);
}
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);
}
void ewk_frame_load_progress_changed(Evas_Object* o)
{
EWK_FRAME_SD_GET_OR_RETURN(o, sd);
EINA_SAFETY_ON_NULL_RETURN(sd->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);
}
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;
Evas_Coord size[2] = {w, h};
evas_object_smart_callback_call(o, "contents,size,changed", size);
}
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);
}
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)
{
return 0;
}