f0950cc1043ef7b63045cf25aac1f5b17c1db479
[WebKit-https.git] / Source / WebKit / efl / ewk / ewk_frame.cpp
1 /*
2     Copyright (C) 2009-2010 ProFUSION embedded systems
3     Copyright (C) 2009-2010 Samsung Electronics
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public License
16     along with this library; see the file COPYING.LIB.  If not, write to
17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18     Boston, MA 02110-1301, USA.
19 */
20
21 // Uncomment to view frame regions and debug messages
22 // #define EWK_FRAME_DEBUG
23
24 #include "config.h"
25 #include "ewk_frame.h"
26
27 #include "DocumentMarkerController.h"
28 #include "EWebKit.h"
29 #include "EventHandler.h"
30 #include "FocusController.h"
31 #include "FrameLoaderClientEfl.h"
32 #include "FrameView.h"
33 #include "HTMLCollection.h"
34 #include "HTMLHeadElement.h"
35 #include "HTMLImageElement.h"
36 #include "HTMLNames.h"
37 #include "HTMLPlugInElement.h"
38 #include "HistoryItem.h"
39 #include "HitTestResult.h"
40 #include "IntSize.h"
41 #include "KURL.h"
42 #include "PlatformKeyboardEvent.h"
43 #include "PlatformMouseEvent.h"
44 #include "PlatformTouchEvent.h"
45 #include "PlatformWheelEvent.h"
46 #include "ProgressTracker.h"
47 #include "RefPtr.h"
48 #include "ResourceRequest.h"
49 #include "ScriptValue.h"
50 #include "SharedBuffer.h"
51 #include "SubstituteData.h"
52 #include "WindowsKeyboardCodes.h"
53 #include "ewk_private.h"
54
55 #include <Eina.h>
56 #include <Evas.h>
57 #include <algorithm>
58 #include <eina_safety_checks.h>
59 #include <wtf/text/CString.h>
60
61 static const char EWK_FRAME_TYPE_STR[] = "EWK_Frame";
62
63 struct Ewk_Frame_Smart_Data {
64     Evas_Object_Smart_Clipped_Data base;
65     Evas_Object* self;
66     Evas_Object* view;
67 #ifdef EWK_FRAME_DEBUG
68     Evas_Object* region;
69 #endif
70     WebCore::Frame* frame;
71     const char* title;
72     const char* uri;
73     const char* name;
74     Eina_Bool editable : 1;
75 };
76
77 struct Eina_Iterator_Ewk_Frame {
78     Eina_Iterator base;
79     Evas_Object* object;
80     unsigned currentIndex;
81 };
82
83 #ifndef EWK_TYPE_CHECK
84 #define EWK_FRAME_TYPE_CHECK(ewkFrame, ...) do { } while (0)
85 #else
86 #define EWK_FRAME_TYPE_CHECK(ewkFrame, ...)                                    \
87     do {                                                                \
88         const char* _tmp_otype = evas_object_type_get(ewkFrame);               \
89         if (EINA_UNLIKELY(_tmp_otype != EWK_FRAME_TYPE_STR)) {          \
90             EINA_LOG_CRIT                                               \
91                 ("%p (%s) is not of an ewk_frame!", ewkFrame,                  \
92                 _tmp_otype ? _tmp_otype : "(null)");                    \
93             return __VA_ARGS__;                                         \
94         }                                                               \
95     } while (0)
96 #endif
97
98 #define EWK_FRAME_SD_GET(ewkFrame, ptr)                                \
99     Ewk_Frame_Smart_Data* ptr = static_cast<Ewk_Frame_Smart_Data*>(evas_object_smart_data_get(ewkFrame))
100
101 #define EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, ptr, ...)         \
102     EWK_FRAME_TYPE_CHECK(ewkFrame, __VA_ARGS__);               \
103     EWK_FRAME_SD_GET(ewkFrame, ptr);                           \
104     if (!ptr) {                                         \
105         CRITICAL("no smart data for object %p (%s)",    \
106                  ewkFrame, evas_object_type_get(ewkFrame));           \
107         return __VA_ARGS__;                             \
108     }
109
110 static Evas_Smart_Class _parent_sc = EVAS_SMART_CLASS_INIT_NULL;
111
112 #ifdef EWK_FRAME_DEBUG
113 static inline void _ewk_frame_debug(Evas_Object* ewkFrame)
114 {
115     Evas_Object* clip, * parent;
116     Evas_Coord x, y, width, height, contentX, contentY, contentWidth, contentHeight;
117     int red, green, blue, alpha, contentRed, contentGreen, contentBlue, contentAlpha;
118
119     evas_object_color_get(ewkFrame, &red, &green, &blue, &alpha);
120     evas_object_geometry_get(ewkFrame, &x, &y, &width, &height);
121
122     clip = evas_object_clip_get(ewkFrame);
123     evas_object_color_get(clip, &contentRed, &contentGreen, &contentBlue, &contentAlpha);
124     evas_object_geometry_get(clip, &contentX, &contentY, &contentWidth, &contentHeight);
125
126     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",
127             ewkFrame, evas_object_type_get(ewkFrame), evas_object_name_get(ewkFrame), evas_object_visible_get(ewkFrame),
128             red, green, blue, alpha, x, y, width, height,
129             clip, evas_object_visible_get(clip), contentRed, contentGreen, contentBlue, contentAlpha, contentX, contentY, contentWidth, contentHeight);
130     parent = evas_object_smart_parent_get(ewkFrame);
131     if (!parent)
132         fprintf(stderr, "\n");
133     else
134         _ewk_frame_debug(parent);
135 }
136 #endif
137
138 static WebCore::FrameLoaderClientEfl* _ewk_frame_loader_efl_get(const WebCore::Frame* frame)
139 {
140     return static_cast<WebCore::FrameLoaderClientEfl*>(frame->loader()->client());
141 }
142
143 static Eina_Bool _ewk_frame_children_iterator_next(Eina_Iterator_Ewk_Frame* iterator, Evas_Object** data)
144 {
145     EWK_FRAME_SD_GET_OR_RETURN(iterator->object, smartData, EINA_FALSE);
146     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
147
148     WebCore::FrameTree* tree = smartData->frame->tree(); // check if it's still valid
149     EINA_SAFETY_ON_NULL_RETURN_VAL(tree, EINA_FALSE);
150
151     if (iterator->currentIndex < tree->childCount()) {
152         *data = EWKPrivate::kitFrame(tree->child(iterator->currentIndex++));
153         return EINA_TRUE;
154     }
155
156     return EINA_FALSE;
157 }
158
159 static Evas_Object* _ewk_frame_children_iterator_get_container(Eina_Iterator_Ewk_Frame* iterator)
160 {
161     return iterator->object;
162 }
163
164 static void _ewk_frame_smart_add(Evas_Object* ewkFrame)
165 {
166     EWK_FRAME_SD_GET(ewkFrame, smartData);
167
168     if (!smartData) {
169         smartData = static_cast<Ewk_Frame_Smart_Data*>(calloc(1, sizeof(Ewk_Frame_Smart_Data)));
170         if (!smartData) {
171             CRITICAL("could not allocate Ewk_Frame_Smart_Data");
172             return;
173         }
174         evas_object_smart_data_set(ewkFrame, smartData);
175     }
176
177     smartData->self = ewkFrame;
178
179     _parent_sc.add(ewkFrame);
180     evas_object_static_clip_set(smartData->base.clipper, EINA_FALSE);
181     evas_object_move(smartData->base.clipper, 0, 0);
182     evas_object_resize(smartData->base.clipper, 0, 0);
183
184 #ifdef EWK_FRAME_DEBUG
185     smartData->region = evas_object_rectangle_add(smartData->base.evas);
186     static int i = 0;
187     switch (i) {
188     case 0:
189         evas_object_color_set(smartData->region, 128, 0, 0, 128);
190         break;
191     case 1:
192         evas_object_color_set(smartData->region, 0, 128, 0, 128);
193         break;
194     case 2:
195         evas_object_color_set(smartData->region, 0, 0, 128, 128);
196         break;
197     case 3:
198         evas_object_color_set(smartData->region, 128, 0, 0, 128);
199         break;
200     case 4:
201         evas_object_color_set(smartData->region, 128, 128, 0, 128);
202         break;
203     case 5:
204         evas_object_color_set(smartData->region, 128, 0, 128, 128);
205         break;
206     case 6:
207         evas_object_color_set(smartData->region, 0, 128, 128, 128);
208         break;
209     default:
210         break;
211     }
212     i++;
213     if (i > 6)
214         i = 0;
215
216     evas_object_smart_member_add(smartData->region, ewkFrame);
217     evas_object_hide(smartData->region);
218 #endif
219 }
220
221 static void _ewk_frame_smart_del(Evas_Object* ewkFrame)
222 {
223     EWK_FRAME_SD_GET(ewkFrame, smartData);
224
225     if (smartData) {
226         if (smartData->frame) {
227             WebCore::FrameLoaderClientEfl* flc = _ewk_frame_loader_efl_get(smartData->frame);
228             flc->setWebFrame(0);
229             smartData->frame->loader()->detachFromParent();
230             smartData->frame->loader()->cancelAndClear();
231             smartData->frame = 0;
232         }
233
234         eina_stringshare_del(smartData->title);
235         eina_stringshare_del(smartData->uri);
236         eina_stringshare_del(smartData->name);
237     }
238
239     _parent_sc.del(ewkFrame);
240 }
241
242 static void _ewk_frame_smart_resize(Evas_Object* ewkFrame, Evas_Coord width, Evas_Coord height)
243 {
244     EWK_FRAME_SD_GET(ewkFrame, smartData);
245     evas_object_resize(smartData->base.clipper, width, height);
246
247 #ifdef EWK_FRAME_DEBUG
248     evas_object_resize(smartData->region, width, height);
249     Evas_Coord x, y;
250     evas_object_geometry_get(smartData->region, &x, &y, &width, &height);
251     INF("region=%p, visible=%d, geo=%d,%d + %dx%d",
252         smartData->region, evas_object_visible_get(smartData->region), x, y, width, height);
253     _ewk_frame_debug(ewkFrame);
254 #endif
255 }
256
257 static void _ewk_frame_smart_set(Evas_Smart_Class* api)
258 {
259     evas_object_smart_clipped_smart_set(api);
260     api->add = _ewk_frame_smart_add;
261     api->del = _ewk_frame_smart_del;
262     api->resize = _ewk_frame_smart_resize;
263 }
264
265 static inline Evas_Smart* _ewk_frame_smart_class_new(void)
266 {
267     static Evas_Smart_Class smartClass = EVAS_SMART_CLASS_INIT_NAME_VERSION(EWK_FRAME_TYPE_STR);
268     static Evas_Smart* smart = 0;
269
270     if (EINA_UNLIKELY(!smart)) {
271         evas_object_smart_clipped_smart_set(&_parent_sc);
272         _ewk_frame_smart_set(&smartClass);
273         smart = evas_smart_class_new(&smartClass);
274     }
275
276     return smart;
277 }
278
279 Evas_Object* ewk_frame_view_get(const Evas_Object* ewkFrame)
280 {
281     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, 0);
282     return sd->view;
283 }
284
285 Eina_Iterator* ewk_frame_children_iterator_new(Evas_Object* ewkFrame)
286 {
287     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
288     Eina_Iterator_Ewk_Frame* iterator = static_cast<Eina_Iterator_Ewk_Frame*>
289                                   (calloc(1, sizeof(Eina_Iterator_Ewk_Frame)));
290     if (!iterator)
291         return 0;
292
293     EINA_MAGIC_SET(&iterator->base, EINA_MAGIC_ITERATOR);
294     iterator->base.next = FUNC_ITERATOR_NEXT(_ewk_frame_children_iterator_next);
295     iterator->base.get_container = FUNC_ITERATOR_GET_CONTAINER(_ewk_frame_children_iterator_get_container);
296     iterator->base.free = FUNC_ITERATOR_FREE(free);
297     iterator->object = ewkFrame;
298     iterator->currentIndex = 0;
299     return &iterator->base;
300 }
301
302 Evas_Object* ewk_frame_child_find(Evas_Object* ewkFrame, const char* name)
303 {
304     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
305     EINA_SAFETY_ON_NULL_RETURN_VAL(name, 0);
306     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, 0);
307     WTF::String frameName = WTF::String::fromUTF8(name);
308     return EWKPrivate::kitFrame(smartData->frame->tree()->find(WTF::AtomicString(frameName)));
309 }
310
311 Eina_Bool ewk_frame_uri_set(Evas_Object* ewkFrame, const char* uri)
312 {
313     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, EINA_FALSE);
314     WebCore::KURL kurl(WebCore::KURL(), WTF::String::fromUTF8(uri));
315     WebCore::ResourceRequest req(kurl);
316     WebCore::FrameLoader* loader = sd->frame->loader();
317     loader->load(req, false);
318     return EINA_TRUE;
319 }
320
321 const char* ewk_frame_uri_get(const Evas_Object* ewkFrame)
322 {
323     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, 0);
324     return sd->uri;
325 }
326
327 const char* ewk_frame_title_get(const Evas_Object* ewkFrame)
328 {
329     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
330     return smartData->title;
331 }
332
333 const char* ewk_frame_name_get(const Evas_Object* ewkFrame)
334 {
335     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
336
337     if (!smartData->frame) {
338         ERR("could not get name of uninitialized frame.");
339         return 0;
340     }
341
342     const WTF::String frameName = smartData->frame->tree()->uniqueName();
343
344     if ((smartData->name) && (smartData->name == frameName))
345         return smartData->name;
346
347     eina_stringshare_replace_length(&(smartData->name), frameName.utf8().data(), frameName.length());
348
349     return smartData->name;
350 }
351
352 Eina_Bool ewk_frame_contents_size_get(const Evas_Object* ewkFrame, Evas_Coord* width, Evas_Coord* height)
353 {
354     if (width)
355         *width = 0;
356     if (height)
357         *height = 0;
358     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, EINA_FALSE);
359     if (!sd->frame || !sd->frame->view())
360         return EINA_FALSE;
361     if (width)
362         *width = sd->frame->view()->contentsWidth();
363     if (height)
364         *height = sd->frame->view()->contentsHeight();
365     return EINA_TRUE;
366 }
367
368 static Eina_Bool _ewk_frame_contents_set_internal(Ewk_Frame_Smart_Data* smartData, const char* contents, size_t contentsSize, const char* mimeType, const char* encoding, const char* baseUri, const char* unreachableUri)
369 {
370     size_t length = strlen(contents);
371     if (contentsSize < 1 || contentsSize > length)
372         contentsSize = length;
373     if (!mimeType)
374         mimeType = "text/html";
375     if (!encoding)
376         encoding = "UTF-8";
377     if (!baseUri)
378         baseUri = "about:blank";
379
380     WebCore::KURL baseKURL(WebCore::KURL(), WTF::String::fromUTF8(baseUri));
381     WebCore::KURL unreachableKURL;
382     if (unreachableUri)
383         unreachableKURL = WebCore::KURL(WebCore::KURL(), WTF::String::fromUTF8(unreachableUri));
384     else
385         unreachableKURL = WebCore::KURL();
386
387     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(contents, contentsSize);
388     WebCore::SubstituteData substituteData
389         (buffer.release(),
390         WTF::String::fromUTF8(mimeType),
391         WTF::String::fromUTF8(encoding),
392         baseKURL, unreachableKURL);
393     WebCore::ResourceRequest request(baseKURL);
394
395     smartData->frame->loader()->load(request, substituteData, false);
396     return EINA_TRUE;
397 }
398
399 Eina_Bool ewk_frame_contents_set(Evas_Object* ewkFrame, const char* contents, size_t contentsSize, const char* mimeType, const char* encoding, const char* baseUri)
400 {
401     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
402     EINA_SAFETY_ON_FALSE_RETURN_VAL(smartData->frame, EINA_FALSE);
403     EINA_SAFETY_ON_NULL_RETURN_VAL(contents, EINA_FALSE);
404     return _ewk_frame_contents_set_internal
405                (smartData, contents, contentsSize, mimeType, encoding, baseUri, 0);
406 }
407
408 Eina_Bool ewk_frame_contents_alternate_set(Evas_Object* ewkFrame, const char* contents, size_t contentsSize, const char* mimeType, const char* encoding, const char* baseUri, const char* unreachableUri)
409 {
410     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
411     EINA_SAFETY_ON_FALSE_RETURN_VAL(smartData->frame, EINA_FALSE);
412     EINA_SAFETY_ON_NULL_RETURN_VAL(contents, EINA_FALSE);
413     EINA_SAFETY_ON_NULL_RETURN_VAL(unreachableUri, EINA_FALSE);
414     return _ewk_frame_contents_set_internal
415                (smartData, contents, contentsSize, mimeType, encoding, baseUri,
416                unreachableUri);
417 }
418
419 Eina_Bool ewk_frame_script_execute(Evas_Object* ewkFrame, const char* script)
420 {
421     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
422     EINA_SAFETY_ON_FALSE_RETURN_VAL(smartData->frame, EINA_FALSE);
423     EINA_SAFETY_ON_NULL_RETURN_VAL(script, EINA_FALSE);
424     smartData->frame->script()->executeScript(WTF::String::fromUTF8(script), true);
425     return EINA_TRUE;
426 }
427
428 Eina_Bool ewk_frame_editable_get(const Evas_Object* ewkFrame)
429 {
430     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
431     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
432     return smartData->editable;
433 }
434
435 Eina_Bool ewk_frame_editable_set(Evas_Object* ewkFrame, Eina_Bool editable)
436 {
437     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
438     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
439     editable = !!editable;
440     if (smartData->editable == editable)
441         return EINA_TRUE;
442     if (editable)
443         smartData->frame->editor()->applyEditingStyleToBodyElement();
444     return EINA_TRUE;
445 }
446
447 char* ewk_frame_selection_get(const Evas_Object* ewkFrame)
448 {
449     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
450     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, 0);
451     WTF::CString s = smartData->frame->editor()->selectedText().utf8();
452     if (s.isNull())
453         return 0;
454     return strdup(s.data());
455 }
456
457 Eina_Bool ewk_frame_text_search(const Evas_Object* ewkFrame, const char* text, Eina_Bool caseSensitive, Eina_Bool forward, Eina_Bool wrap)
458 {
459     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
460     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
461     EINA_SAFETY_ON_NULL_RETURN_VAL(text, EINA_FALSE);
462
463     return smartData->frame->editor()->findString(WTF::String::fromUTF8(text), forward, caseSensitive, wrap, true);
464 }
465
466 unsigned int ewk_frame_text_matches_mark(Evas_Object* ewkFrame, const char* string, Eina_Bool caseSensitive, Eina_Bool highlight, unsigned int limit)
467 {
468     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
469     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
470     EINA_SAFETY_ON_NULL_RETURN_VAL(string, 0);
471
472     smartData->frame->editor()->setMarkedTextMatchesAreHighlighted(highlight);
473     return smartData->frame->editor()->countMatchesForText(WTF::String::fromUTF8(string), caseSensitive, limit, true);
474 }
475
476 Eina_Bool ewk_frame_text_matches_unmark_all(Evas_Object* ewkFrame)
477 {
478     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
479     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
480
481     smartData->frame->document()->markers()->removeMarkers(WebCore::DocumentMarker::TextMatch);
482     return EINA_TRUE;
483 }
484
485 Eina_Bool ewk_frame_text_matches_highlight_set(Evas_Object* ewkFrame, Eina_Bool highlight)
486 {
487     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
488     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
489     smartData->frame->editor()->setMarkedTextMatchesAreHighlighted(highlight);
490     return EINA_TRUE;
491 }
492
493 Eina_Bool ewk_frame_text_matches_highlight_get(const Evas_Object* ewkFrame)
494 {
495     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
496     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
497     return smartData->frame->editor()->markedTextMatchesAreHighlighted();
498 }
499
500 /**
501  * Comparison function used by ewk_frame_text_matches_nth_pos_get
502  */
503 static bool _ewk_frame_rect_cmp_less_than(const WebCore::IntRect& begin, const WebCore::IntRect& end)
504 {
505     return (begin.y() < end.y() || (begin.y() == end.y() && begin.x() < end.x()));
506 }
507
508 /**
509  * Predicate used by ewk_frame_text_matches_nth_pos_get
510  */
511 static bool _ewk_frame_rect_is_negative_value(const WebCore::IntRect& rect)
512 {
513     return (rect.x() < 0 || rect.y() < 0);
514 }
515
516 Eina_Bool ewk_frame_text_matches_nth_pos_get(const Evas_Object* ewkFrame, size_t number, int* x, int* y)
517 {
518     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
519     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
520
521     Vector<WebCore::IntRect> intRects = smartData->frame->document()->markers()->renderedRectsForMarkers(WebCore::DocumentMarker::TextMatch);
522
523     /* remove useless values */
524     std::remove_if(intRects.begin(), intRects.end(), _ewk_frame_rect_is_negative_value);
525
526     if (intRects.isEmpty() || number > intRects.size())
527         return EINA_FALSE;
528
529     std::sort(intRects.begin(), intRects.end(), _ewk_frame_rect_cmp_less_than);
530
531     if (x)
532         *x = intRects[number - 1].x();
533     if (y)
534         *y = intRects[number - 1].y();
535     return EINA_TRUE;
536 }
537
538 Eina_Bool ewk_frame_stop(Evas_Object* ewkFrame)
539 {
540     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
541     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
542     smartData->frame->loader()->stopAllLoaders();
543     return EINA_TRUE;
544 }
545
546 Eina_Bool ewk_frame_reload(Evas_Object* ewkFrame)
547 {
548     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
549     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
550     smartData->frame->loader()->reload();
551     return EINA_TRUE;
552 }
553
554 Eina_Bool ewk_frame_reload_full(Evas_Object* ewkFrame)
555 {
556     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
557     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
558     smartData->frame->loader()->reload(true);
559     return EINA_TRUE;
560 }
561
562 Eina_Bool ewk_frame_back(Evas_Object* ewkFrame)
563 {
564     return ewk_frame_navigate(ewkFrame, -1);
565 }
566
567 Eina_Bool ewk_frame_forward(Evas_Object* ewkFrame)
568 {
569     return ewk_frame_navigate(ewkFrame, 1);
570 }
571
572 Eina_Bool ewk_frame_navigate(Evas_Object* ewkFrame, int steps)
573 {
574     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
575     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
576     WebCore::Page* page = smartData->frame->page();
577     if (!page->canGoBackOrForward(steps))
578         return EINA_FALSE;
579     page->goBackOrForward(steps);
580     return EINA_TRUE;
581 }
582
583 Eina_Bool ewk_frame_back_possible(Evas_Object* ewkFrame)
584 {
585     return ewk_frame_navigate_possible(ewkFrame, -1);
586 }
587
588 Eina_Bool ewk_frame_forward_possible(Evas_Object* ewkFrame)
589 {
590     return ewk_frame_navigate_possible(ewkFrame, 1);
591 }
592
593 Eina_Bool ewk_frame_navigate_possible(Evas_Object* ewkFrame, int steps)
594 {
595     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
596     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
597     WebCore::Page* page = smartData->frame->page();
598     return page->canGoBackOrForward(steps);
599 }
600
601 float ewk_frame_page_zoom_get(const Evas_Object* ewkFrame)
602 {
603     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, -1.0);
604     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, -1.0);
605     return smartData->frame->pageZoomFactor();
606 }
607
608 Eina_Bool ewk_frame_page_zoom_set(Evas_Object* ewkFrame, float pageZoomFactor)
609 {
610     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
611     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
612     smartData->frame->setPageZoomFactor(pageZoomFactor);
613     return EINA_TRUE;
614 }
615
616 float ewk_frame_text_zoom_get(const Evas_Object* ewkFrame)
617 {
618     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, -1.0);
619     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, -1.0);
620     return smartData->frame->textZoomFactor();
621 }
622
623 Eina_Bool ewk_frame_text_zoom_set(Evas_Object* ewkFrame, float textZoomFactor)
624 {
625     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
626     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
627     smartData->frame->setTextZoomFactor(textZoomFactor);
628     return EINA_TRUE;
629 }
630
631 void ewk_frame_hit_test_free(Ewk_Hit_Test* hitTest)
632 {
633     EINA_SAFETY_ON_NULL_RETURN(hitTest);
634     eina_stringshare_del(hitTest->title);
635     eina_stringshare_del(hitTest->alternate_text);
636     eina_stringshare_del(hitTest->link.text);
637     eina_stringshare_del(hitTest->link.url);
638     eina_stringshare_del(hitTest->link.title);
639     eina_stringshare_del(hitTest->image_uri);
640     eina_stringshare_del(hitTest->media_uri);
641     free(hitTest);
642 }
643
644 Ewk_Hit_Test* ewk_frame_hit_test_new(const Evas_Object* ewkFrame, int x, int y)
645 {
646     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
647     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, 0);
648
649     WebCore::FrameView* view = smartData->frame->view();
650     EINA_SAFETY_ON_NULL_RETURN_VAL(view, 0);
651     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->contentRenderer(), 0);
652
653     WebCore::HitTestResult result = smartData->frame->eventHandler()->hitTestResultAtPoint
654                                         (view->windowToContents(WebCore::IntPoint(x, y)),
655                                         /*allowShadowContent*/ false, /*ignoreClipping*/ true);
656
657     if (result.scrollbar())
658         return 0;
659     if (!result.innerNode())
660         return 0;
661
662     Ewk_Hit_Test* hitTest = static_cast<Ewk_Hit_Test*>(calloc(1, sizeof(Ewk_Hit_Test)));
663     if (!hitTest) {
664         CRITICAL("Could not allocate memory for hit test.");
665         return 0;
666     }
667
668     hitTest->x = result.point().x();
669     hitTest->y = result.point().y();
670 #if 0
671     // FIXME
672     hitTest->bounding_box.x = result.boundingBox().x();
673     hitTest->bounding_box.y = result.boundingBox().y();
674     hitTest->bounding_box.width = result.boundingBox().width();
675     hitTest->bounding_box.height = result.boundingBox().height();
676 #else
677     hitTest->bounding_box.x = 0;
678     hitTest->bounding_box.y = 0;
679     hitTest->bounding_box.w = 0;
680     hitTest->bounding_box.h = 0;
681 #endif
682
683     WebCore::TextDirection direction;
684     hitTest->title = eina_stringshare_add(result.title(direction).utf8().data());
685     hitTest->alternate_text = eina_stringshare_add(result.altDisplayString().utf8().data());
686     if (result.innerNonSharedNode() && result.innerNonSharedNode()->document()
687         && result.innerNonSharedNode()->document()->frame())
688         hitTest->frame = EWKPrivate::kitFrame(result.innerNonSharedNode()->document()->frame());
689
690     hitTest->link.text = eina_stringshare_add(result.textContent().utf8().data());
691     hitTest->link.url = eina_stringshare_add(result.absoluteLinkURL().string().utf8().data());
692     hitTest->link.title = eina_stringshare_add(result.titleDisplayString().utf8().data());
693     hitTest->link.target_frame = EWKPrivate::kitFrame(result.targetFrame());
694
695     hitTest->image_uri = eina_stringshare_add(result.absoluteImageURL().string().utf8().data());
696     hitTest->media_uri = eina_stringshare_add(result.absoluteMediaURL().string().utf8().data());
697
698     int context = EWK_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
699
700     if (!result.absoluteLinkURL().isEmpty())
701         context |= EWK_HIT_TEST_RESULT_CONTEXT_LINK;
702     if (!result.absoluteImageURL().isEmpty())
703         context |= EWK_HIT_TEST_RESULT_CONTEXT_IMAGE;
704     if (!result.absoluteMediaURL().isEmpty())
705         context |= EWK_HIT_TEST_RESULT_CONTEXT_MEDIA;
706     if (result.isSelected())
707         context |= EWK_HIT_TEST_RESULT_CONTEXT_SELECTION;
708     if (result.isContentEditable())
709         context |= EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE;
710
711     hitTest->context = static_cast<Ewk_Hit_Test_Result_Context>(context);
712
713     return hitTest;
714 }
715
716 Eina_Bool
717 ewk_frame_scroll_add(Evas_Object* ewkFrame, int deltaX, int deltaY)
718 {
719     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
720     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
721     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
722     smartData->frame->view()->scrollBy(WebCore::IntSize(deltaX, deltaY));
723     return EINA_TRUE;
724 }
725
726 Eina_Bool
727 ewk_frame_scroll_set(Evas_Object* ewkFrame, int x, int y)
728 {
729     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
730     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
731     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
732     smartData->frame->view()->setScrollPosition(WebCore::IntPoint(x, y));
733     return EINA_TRUE;
734 }
735
736 Eina_Bool
737 ewk_frame_scroll_size_get(const Evas_Object* ewkFrame, int* width, int* height)
738 {
739     if (width)
740         *width = 0;
741     if (height)
742         *height = 0;
743     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
744     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
745     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
746     WebCore::IntPoint point = smartData->frame->view()->maximumScrollPosition();
747     if (width)
748         *width = point.x();
749     if (height)
750         *height = point.y();
751     return EINA_TRUE;
752 }
753
754 Eina_Bool
755 ewk_frame_scroll_pos_get(const Evas_Object* ewkFrame, int* x, int* y)
756 {
757     if (x)
758         *x = 0;
759     if (y)
760         *y = 0;
761     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
762     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
763     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
764     WebCore::IntPoint pos = smartData->frame->view()->scrollPosition();
765     if (x)
766         *x = pos.x();
767     if (y)
768         *y = pos.y();
769     return EINA_TRUE;
770 }
771
772 Eina_Bool ewk_frame_visible_content_geometry_get(const Evas_Object* ewkFrame, Eina_Bool includeScrollbars, int* x, int* y, int* width, int* height)
773 {
774     if (x)
775         *x = 0;
776     if (y)
777         *y = 0;
778     if (width)
779         *width = 0;
780     if (height)
781         *height = 0;
782     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
783     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
784     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
785     WebCore::IntRect rect = smartData->frame->view()->visibleContentRect(includeScrollbars);
786     if (x)
787         *x = rect.x();
788     if (y)
789         *y = rect.y();
790     if (width)
791         *width = rect.width();
792     if (height)
793         *height = rect.height();
794     return EINA_TRUE;
795 }
796
797 Eina_Bool ewk_frame_paint_full_get(const Evas_Object* ewkFrame)
798 {
799     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
800     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
801     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->view(), EINA_FALSE);
802     return smartData->frame->view()->paintsEntireContents();
803 }
804
805 void ewk_frame_paint_full_set(Evas_Object* ewkFrame, Eina_Bool flag)
806 {
807     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
808     EINA_SAFETY_ON_NULL_RETURN(smartData->frame);
809     EINA_SAFETY_ON_NULL_RETURN(smartData->frame->view());
810     smartData->frame->view()->setPaintsEntireContents(flag);
811 }
812
813 Eina_Bool ewk_frame_feed_focus_in(Evas_Object* ewkFrame)
814 {
815     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
816     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
817     WebCore::FocusController* c = smartData->frame->page()->focusController();
818     c->setFocusedFrame(smartData->frame);
819     return EINA_TRUE;
820 }
821
822 Eina_Bool ewk_frame_feed_focus_out(Evas_Object* ewkFrame)
823 {
824     // TODO: what to do on focus out?
825     ERR("what to do?");
826     return EINA_FALSE;
827 }
828
829 Eina_Bool ewk_frame_feed_mouse_wheel(Evas_Object* ewkFrame, const Evas_Event_Mouse_Wheel* wheelEvent)
830 {
831     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
832     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
833     EINA_SAFETY_ON_NULL_RETURN_VAL(wheelEvent, EINA_FALSE);
834
835     WebCore::FrameView* view = smartData->frame->view();
836     DBG("ewkFrame=%p, view=%p, direction=%d, z=%d, pos=%d,%d",
837         ewkFrame, view, wheelEvent->direction, wheelEvent->z, wheelEvent->canvas.x, wheelEvent->canvas.y);
838     EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE);
839
840     WebCore::PlatformWheelEvent event(wheelEvent);
841     return smartData->frame->eventHandler()->handleWheelEvent(event);
842 }
843
844 Eina_Bool ewk_frame_feed_mouse_down(Evas_Object* ewkFrame, const Evas_Event_Mouse_Down* downEvent)
845 {
846     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
847     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
848     EINA_SAFETY_ON_NULL_RETURN_VAL(downEvent, EINA_FALSE);
849
850     WebCore::FrameView* view = smartData->frame->view();
851     DBG("ewkFrame=%p, view=%p, button=%d, pos=%d,%d",
852         ewkFrame, view, downEvent->button, downEvent->canvas.x, downEvent->canvas.y);
853     EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE);
854
855     Evas_Coord x, y;
856     evas_object_geometry_get(smartData->view, &x, &y, 0, 0);
857
858     WebCore::PlatformMouseEvent event(downEvent, WebCore::IntPoint(x, y));
859     return smartData->frame->eventHandler()->handleMousePressEvent(event);
860 }
861
862 Eina_Bool ewk_frame_feed_mouse_up(Evas_Object* ewkFrame, const Evas_Event_Mouse_Up* upEvent)
863 {
864     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
865     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
866     EINA_SAFETY_ON_NULL_RETURN_VAL(upEvent, EINA_FALSE);
867
868     WebCore::FrameView* view = smartData->frame->view();
869     DBG("ewkFrame=%p, view=%p, button=%d, pos=%d,%d",
870         ewkFrame, view, upEvent->button, upEvent->canvas.x, upEvent->canvas.y);
871     EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE);
872
873     Evas_Coord x, y;
874     evas_object_geometry_get(smartData->view, &x, &y, 0, 0);
875
876     WebCore::PlatformMouseEvent event(upEvent, WebCore::IntPoint(x, y));
877     return smartData->frame->eventHandler()->handleMouseReleaseEvent(event);
878 }
879
880 Eina_Bool ewk_frame_feed_mouse_move(Evas_Object* ewkFrame, const Evas_Event_Mouse_Move* moveEvent)
881 {
882     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
883     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
884     EINA_SAFETY_ON_NULL_RETURN_VAL(moveEvent, EINA_FALSE);
885
886     WebCore::FrameView* view = smartData->frame->view();
887     DBG("ewkFrame=%p, view=%p, pos: old=%d,%d, new=%d,%d, buttons=%d",
888         ewkFrame, view, moveEvent->cur.canvas.x, moveEvent->cur.canvas.y,
889         moveEvent->prev.canvas.x, moveEvent->prev.canvas.y, moveEvent->buttons);
890     EINA_SAFETY_ON_NULL_RETURN_VAL(view, EINA_FALSE);
891
892     Evas_Coord x, y;
893     evas_object_geometry_get(smartData->view, &x, &y, 0, 0);
894
895     WebCore::PlatformMouseEvent event(moveEvent, WebCore::IntPoint(x, y));
896     return smartData->frame->eventHandler()->mouseMoved(event);
897 }
898
899 Eina_Bool ewk_frame_feed_touch_event(Evas_Object* ewkFrame, Ewk_Touch_Event_Type action, Eina_List* points, int metaState)
900 {
901     Eina_Bool result = EINA_FALSE;
902
903 #if ENABLE(TOUCH_EVENTS)
904     EINA_SAFETY_ON_NULL_RETURN_VAL(points, EINA_FALSE);
905     EWK_FRAME_SD_GET(ewkFrame, smartData);
906
907     if (!smartData || !smartData->frame || !ewk_view_need_touch_events_get(smartData->view))
908         return EINA_FALSE;
909
910     Evas_Coord x, y;
911     evas_object_geometry_get(smartData->view, &x, &y, 0, 0);
912
913     WebCore::TouchEventType type = WebCore::TouchStart;
914     switch (action) {
915     case EWK_TOUCH_START:
916         type = WebCore::TouchStart;
917         break;
918     case EWK_TOUCH_END:
919         type = WebCore::TouchEnd;
920         break;
921     case EWK_TOUCH_MOVE:
922         type = WebCore::TouchMove;
923         break;
924     case EWK_TOUCH_CANCEL:
925         type = WebCore::TouchCancel;
926         break;
927     default:
928         return EINA_FALSE;
929     }
930
931     WebCore::PlatformTouchEvent touchEvent(points, WebCore::IntPoint(x, y), type, metaState);
932     result = smartData->frame->eventHandler()->handleTouchEvent(touchEvent);
933 #endif
934     return result;
935 }
936
937 static inline Eina_Bool _ewk_frame_handle_key_scrolling(WebCore::Frame* frame, const WebCore::PlatformKeyboardEvent& keyEvent)
938 {
939     WebCore::ScrollDirection direction;
940     WebCore::ScrollGranularity granularity;
941
942     int keyCode = keyEvent.windowsVirtualKeyCode();
943
944     switch (keyCode) {
945     case VK_SPACE:
946         granularity = WebCore::ScrollByPage;
947         if (keyEvent.shiftKey())
948             direction = WebCore::ScrollUp;
949         else
950             direction = WebCore::ScrollDown;
951         break;
952     case VK_NEXT:
953         granularity = WebCore::ScrollByPage;
954         direction = WebCore::ScrollDown;
955         break;
956     case VK_PRIOR:
957         granularity = WebCore::ScrollByPage;
958         direction = WebCore::ScrollUp;
959         break;
960     case VK_HOME:
961         granularity = WebCore::ScrollByDocument;
962         direction = WebCore::ScrollUp;
963         break;
964     case VK_END:
965         granularity = WebCore::ScrollByDocument;
966         direction = WebCore::ScrollDown;
967         break;
968     case VK_LEFT:
969         granularity = WebCore::ScrollByLine;
970         direction = WebCore::ScrollLeft;
971         break;
972     case VK_RIGHT:
973         granularity = WebCore::ScrollByLine;
974         direction = WebCore::ScrollRight;
975         break;
976     case VK_UP:
977         direction = WebCore::ScrollUp;
978         if (keyEvent.ctrlKey())
979             granularity = WebCore::ScrollByDocument;
980         else
981             granularity = WebCore::ScrollByLine;
982         break;
983     case VK_DOWN:
984         direction = WebCore::ScrollDown;
985         if (keyEvent.ctrlKey())
986             granularity = WebCore::ScrollByDocument;
987         else
988             granularity = WebCore::ScrollByLine;
989         break;
990     default:
991         return EINA_FALSE;
992     }
993
994     if (frame->eventHandler()->scrollOverflow(direction, granularity))
995         return EINA_FALSE;
996
997     frame->view()->scroll(direction, granularity);
998     return EINA_TRUE;
999 }
1000
1001 Eina_Bool ewk_frame_feed_key_down(Evas_Object* ewkFrame, const Evas_Event_Key_Down* downEvent)
1002 {
1003     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
1004     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
1005     EINA_SAFETY_ON_NULL_RETURN_VAL(downEvent, EINA_FALSE);
1006
1007     DBG("ewkFrame=%p keyname=%s (key=%s, string=%s)",
1008         ewkFrame, downEvent->keyname, downEvent->key ? downEvent->key : "", downEvent->string ? downEvent->string : "");
1009
1010     WebCore::PlatformKeyboardEvent event(downEvent);
1011     if (smartData->frame->eventHandler()->keyEvent(event))
1012         return EINA_TRUE;
1013
1014     return _ewk_frame_handle_key_scrolling(smartData->frame, event);
1015 }
1016
1017 Eina_Bool ewk_frame_feed_key_up(Evas_Object* ewkFrame, const Evas_Event_Key_Up* upEvent)
1018 {
1019     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
1020     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EINA_FALSE);
1021     EINA_SAFETY_ON_NULL_RETURN_VAL(upEvent, EINA_FALSE);
1022
1023     DBG("ewkFrame=%p keyname=%s (key=%s, string=%s)",
1024         ewkFrame, upEvent->keyname, upEvent->key ? upEvent->key : "", upEvent->string ? upEvent->string : "");
1025
1026     WebCore::PlatformKeyboardEvent event(upEvent);
1027     return smartData->frame->eventHandler()->keyEvent(event);
1028 }
1029
1030 Ewk_Text_Selection_Type ewk_frame_text_selection_type_get(const Evas_Object* ewkFrame)
1031 {
1032     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EWK_TEXT_SELECTION_NONE);
1033     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, EWK_TEXT_SELECTION_NONE);
1034
1035     WebCore::FrameSelection* controller = smartData->frame->selection();
1036     if (!controller)
1037         return EWK_TEXT_SELECTION_NONE;
1038
1039     switch (controller->selectionType()) {
1040     case WebCore::VisibleSelection::CaretSelection:
1041         return EWK_TEXT_SELECTION_CARET;
1042     case WebCore::VisibleSelection::RangeSelection:
1043         return EWK_TEXT_SELECTION_RANGE;
1044     default:
1045         return EWK_TEXT_SELECTION_NONE;
1046     }
1047 }
1048
1049 /* internal methods ****************************************************/
1050
1051 /**
1052  * @internal
1053  *
1054  * Creates a new EFL WebKit Frame object.
1055  *
1056  * Frames are low level entries contained in a page that is contained
1057  * by a view. Usually one operates on the view and not directly on the
1058  * frame.
1059  *
1060  * @param canvas canvas where to create the frame object
1061  *
1062  * @return a new frame object or @c 0 on failure
1063  */
1064 Evas_Object* ewk_frame_add(Evas* canvas)
1065 {
1066     return evas_object_smart_add(canvas, _ewk_frame_smart_class_new());
1067 }
1068
1069 /**
1070  * @internal
1071  *
1072  * Initialize frame based on actual WebKit frame.
1073  *
1074  * This is internal and should never be called by external users.
1075  */
1076 Eina_Bool ewk_frame_init(Evas_Object* ewkFrame, Evas_Object* view, WebCore::Frame* frame)
1077 {
1078     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, EINA_FALSE);
1079     if (!smartData->frame) {
1080         WebCore::FrameLoaderClientEfl* frameLoaderClient = _ewk_frame_loader_efl_get(frame);
1081         frameLoaderClient->setWebFrame(ewkFrame);
1082         smartData->frame = frame;
1083         smartData->view = view;
1084         frame->init();
1085         return EINA_TRUE;
1086     }
1087
1088     ERR("frame %p already set for %p, ignored new %p",
1089         smartData->frame, ewkFrame, frame);
1090     return EINA_FALSE;
1091 }
1092
1093 /**
1094  * @internal
1095  *
1096  * Adds child to the frame.
1097  */
1098 Eina_Bool ewk_frame_child_add(Evas_Object* ewkFrame, WTF::PassRefPtr<WebCore::Frame> child, const WTF::String& name, const WebCore::KURL& url, const WTF::String& referrer)
1099 {
1100     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
1101     char buffer[256];
1102     Evas_Object* frame;
1103     WebCore::Frame* coreFrame;
1104
1105     frame = ewk_frame_add(smartData->base.evas);
1106     if (!frame) {
1107         ERR("Could not create ewk_frame object.");
1108         return EINA_FALSE;
1109     }
1110
1111     coreFrame = child.get();
1112     if (coreFrame->tree())
1113         coreFrame->tree()->setName(name);
1114     else
1115         ERR("no tree for child object");
1116     smartData->frame->tree()->appendChild(child);
1117
1118     if (!ewk_frame_init(frame, smartData->view, coreFrame)) {
1119         evas_object_del(frame);
1120         return EINA_FALSE;
1121     }
1122     snprintf(buffer, sizeof(buffer), "EWK_Frame:child/%s", name.utf8().data());
1123     evas_object_name_set(frame, buffer);
1124     evas_object_smart_member_add(frame, ewkFrame);
1125     evas_object_show(frame);
1126
1127     // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
1128     if (!coreFrame->page()) {
1129         evas_object_del(frame);
1130         return EINA_TRUE;
1131     }
1132
1133     smartData->frame->loader()->loadURLIntoChildFrame(url, referrer, coreFrame);
1134
1135     // The frame's onload handler may have removed it from the document.
1136     // See fast/dom/null-page-show-modal-dialog-crash.html for an example.
1137     if (!coreFrame->tree()->parent()) {
1138         evas_object_del(frame);
1139         return EINA_TRUE;
1140     }
1141
1142     // TODO: announce frame was created?
1143     return EINA_TRUE;
1144 }
1145
1146 /**
1147  * @internal
1148  * Change the ewk view this frame is associated with.
1149  *
1150  * @param ewkFrame The ewk frame to act upon.
1151  * @param newParent The new view that will be set as the parent of the frame.
1152  */
1153 void ewk_frame_view_set(Evas_Object* ewkFrame, Evas_Object* newParent)
1154 {
1155     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1156
1157     evas_object_smart_member_del(ewkFrame);
1158     evas_object_smart_member_add(ewkFrame, newParent);
1159
1160     smartData->view = newParent;
1161 }
1162
1163 /**
1164  * @internal
1165  * Frame was destroyed by loader, remove internal reference.
1166  */
1167 void ewk_frame_core_gone(Evas_Object* ewkFrame)
1168 {
1169     DBG("ewkFrame=%p", ewkFrame);
1170     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1171     smartData->frame = 0;
1172 }
1173
1174 /**
1175  * @internal
1176  * Reports a resource will be requested. User may override behavior of webkit by
1177  * changing values in @param request.
1178  *
1179  * @param ewkFrame Frame.
1180  * @param request Request details that user may override. Whenever values on
1181  * this struct changes, it must be properly malloc'd as it will be freed
1182  * afterwards.
1183  *
1184  * Emits signal: "resource,request,willsend"
1185  */
1186 void ewk_frame_request_will_send(Evas_Object* ewkFrame, Ewk_Frame_Resource_Request* request)
1187 {
1188     evas_object_smart_callback_call(ewkFrame, "resource,request,willsend", request);
1189 }
1190
1191 /**
1192  * @internal
1193  * Reports that there's a new resource.
1194  *
1195  * @param ewkFrame Frame.
1196  * @param request New request details. No changes are allowed to fields.
1197  *
1198  * Emits signal: "resource,request,new"
1199  */
1200 void ewk_frame_request_assign_identifier(Evas_Object* ewkFrame, const Ewk_Frame_Resource_Request* request)
1201 {
1202     evas_object_smart_callback_call(ewkFrame, "resource,request,new", (void*)request);
1203 }
1204
1205 /**
1206  * @internal
1207  * Reports that first navigation occurred
1208  *
1209  * @param ewkFrame Frame.
1210  *
1211  * Emits signal: "navigation,first"
1212  */
1213 void ewk_frame_did_perform_first_navigation(Evas_Object* ewkFrame)
1214 {
1215     evas_object_smart_callback_call(ewkFrame, "navigation,first", 0);
1216 }
1217
1218 /**
1219  * @internal
1220  * Reports frame will be saved to current state
1221  *
1222  * @param ewkFrame Frame.
1223  * @param item History item to save details to.
1224  *
1225  * Emits signal: "state,save"
1226  */
1227 void ewk_frame_view_state_save(Evas_Object* ewkFrame, WebCore::HistoryItem* item)
1228 {
1229     evas_object_smart_callback_call(ewkFrame, "state,save", 0);
1230 }
1231
1232 /**
1233  * @internal
1234  * Reports the frame started loading something.
1235  *
1236  * Emits signal: "load,started" with no parameters.
1237  */
1238 void ewk_frame_load_started(Evas_Object* ewkFrame)
1239 {
1240     Evas_Object* mainFrame;
1241     DBG("ewkFrame=%p", ewkFrame);
1242     evas_object_smart_callback_call(ewkFrame, "load,started", 0);
1243     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1244     ewk_view_load_started(smartData->view);
1245
1246     mainFrame = ewk_view_frame_main_get(smartData->view);
1247     if (mainFrame == ewkFrame)
1248         ewk_view_frame_main_load_started(smartData->view);
1249 }
1250
1251 /**
1252  * @internal
1253  * Reports the frame started provisional load.
1254  *
1255  * @param ewkFrame Frame.
1256  *
1257  * Emits signal: "load,provisional" with no parameters.
1258  */
1259 void ewk_frame_load_provisional(Evas_Object* ewkFrame)
1260 {
1261     evas_object_smart_callback_call(ewkFrame, "load,provisional", 0);
1262 }
1263
1264 /**
1265  * @internal
1266  * Reports the frame finished first layout.
1267  *
1268  * @param ewkFrame Frame.
1269  *
1270  * Emits signal: "load,firstlayout,finished" with no parameters.
1271  */
1272 void ewk_frame_load_firstlayout_finished(Evas_Object* ewkFrame)
1273 {
1274     evas_object_smart_callback_call(ewkFrame, "load,firstlayout,finished", 0);
1275 }
1276
1277 /**
1278  * @internal
1279  * Reports the frame finished first non empty layout.
1280  *
1281  * @param ewkFrame Frame.
1282  *
1283  * Emits signal: "load,nonemptylayout,finished" with no parameters.
1284  */
1285 void ewk_frame_load_firstlayout_nonempty_finished(Evas_Object* ewkFrame)
1286 {
1287     evas_object_smart_callback_call(ewkFrame, "load,nonemptylayout,finished", 0);
1288 }
1289
1290 /**
1291  * @internal
1292  * Reports the loading of a document has finished on frame.
1293  *
1294  * @param ewkFrame Frame.
1295  *
1296  * Emits signal: "load,document,finished" with no parameters.
1297  */
1298 void ewk_frame_load_document_finished(Evas_Object* ewkFrame)
1299 {
1300     evas_object_smart_callback_call(ewkFrame, "load,document,finished", 0);
1301     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd);
1302     ewk_view_load_document_finished(sd->view, ewkFrame);
1303 }
1304
1305 /**
1306  * @internal
1307  * Reports load finished, optionally with error information.
1308  *
1309  * Emits signal: "load,finished" with pointer to Ewk_Frame_Load_Error
1310  * if any error, or @c NULL if successful load.
1311  *
1312  * @note there should notbe any error stuff here, but trying to be
1313  *       compatible with previous WebKit.
1314  */
1315 void ewk_frame_load_finished(Evas_Object* ewkFrame, const char* errorDomain, int errorCode, Eina_Bool isCancellation, const char* errorDescription, const char* failingUrl)
1316 {
1317     Ewk_Frame_Load_Error buffer, *error;
1318     if (!errorDomain) {
1319         DBG("ewkFrame=%p, success.", ewkFrame);
1320         error = 0;
1321     } else {
1322         DBG("ewkFrame=%p, error=%s (%d, cancellation=%hhu) \"%s\", url=%s",
1323             ewkFrame, errorDomain, errorCode, isCancellation,
1324             errorDescription, failingUrl);
1325
1326         buffer.domain = errorDomain;
1327         buffer.code = errorCode;
1328         buffer.is_cancellation = isCancellation;
1329         buffer.description = errorDescription;
1330         buffer.failing_url = failingUrl;
1331         buffer.frame = ewkFrame;
1332         error = &buffer;
1333     }
1334     evas_object_smart_callback_call(ewkFrame, "load,finished", error);
1335     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1336     ewk_view_load_finished(smartData->view, error);
1337 }
1338
1339 /**
1340  * @internal
1341  * Reports load failed with error information.
1342  *
1343  * Emits signal: "load,error" with pointer to Ewk_Frame_Load_Error.
1344  */
1345 void ewk_frame_load_error(Evas_Object* ewkFrame, const char* errorDomain, int errorCode, Eina_Bool isCancellation, const char* errorDescription, const char* failingUrl)
1346 {
1347     Ewk_Frame_Load_Error error;
1348
1349     DBG("ewkFrame=%p, error=%s (%d, cancellation=%hhu) \"%s\", url=%s",
1350         ewkFrame, errorDomain, errorCode, isCancellation,
1351         errorDescription, failingUrl);
1352
1353     EINA_SAFETY_ON_NULL_RETURN(errorDomain);
1354
1355     error.code = errorCode;
1356     error.is_cancellation = isCancellation;
1357     error.domain = errorDomain;
1358     error.description = errorDescription;
1359     error.failing_url = failingUrl;
1360     error.frame = ewkFrame;
1361     evas_object_smart_callback_call(ewkFrame, "load,error", &error);
1362     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd);
1363     ewk_view_load_error(sd->view, &error);
1364 }
1365
1366 /**
1367  * @internal
1368  * Reports load progress changed.
1369  *
1370  * Emits signal: "load,progress" with pointer to a double from 0.0 to 1.0.
1371  */
1372 void ewk_frame_load_progress_changed(Evas_Object* ewkFrame)
1373 {
1374     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1375     EINA_SAFETY_ON_NULL_RETURN(smartData->frame);
1376
1377     // TODO: this is per page, there should be a way to have per-frame.
1378     double progress = smartData->frame->page()->progress()->estimatedProgress();
1379
1380     DBG("ewkFrame=%p (p=%0.3f)", ewkFrame, progress);
1381
1382     evas_object_smart_callback_call(ewkFrame, "load,progress", &progress);
1383     ewk_view_load_progress_changed(smartData->view);
1384 }
1385
1386
1387 /**
1388  * @internal
1389  *
1390  * Reports contents size changed.
1391  */
1392 void ewk_frame_contents_size_changed(Evas_Object* ewkFrame, Evas_Coord width, Evas_Coord height)
1393 {
1394     Evas_Coord size[2] = {width, height};
1395     evas_object_smart_callback_call(ewkFrame, "contents,size,changed", size);
1396 }
1397
1398 /**
1399  * @internal
1400  *
1401  * Reports title changed.
1402  */
1403 void ewk_frame_title_set(Evas_Object* ewkFrame, const char* title)
1404 {
1405     DBG("ewkFrame=%p, title=%s", ewkFrame, title ? title : "(null)");
1406     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd);
1407     if (!eina_stringshare_replace(&sd->title, title))
1408         return;
1409     evas_object_smart_callback_call(ewkFrame, "title,changed", (void*)sd->title);
1410 }
1411
1412 /**
1413  * @internal
1414  *
1415  * Creates a view.
1416  */
1417 void ewk_frame_view_create_for_view(Evas_Object* ewkFrame, Evas_Object* view)
1418 {
1419     DBG("ewkFrame=%p, view=%p", ewkFrame, view);
1420     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1421     EINA_SAFETY_ON_NULL_RETURN(smartData->frame);
1422     Evas_Coord width, height;
1423
1424     evas_object_geometry_get(view, 0, 0, &width, &height);
1425
1426     WebCore::IntSize size(width, height);
1427     int red, green, blue, alpha;
1428     WebCore::Color background;
1429
1430     ewk_view_bg_color_get(view, &red, &green, &blue, &alpha);
1431     if (!alpha)
1432         background = WebCore::Color(0, 0, 0, 0);
1433     else if (alpha == 255)
1434         background = WebCore::Color(red, green, blue, alpha);
1435     else
1436         background = WebCore::Color(red * 255 / alpha, green * 255 / alpha, blue * 255 / alpha, alpha);
1437
1438     smartData->frame->createView(size, background, !alpha, WebCore::IntSize(), false);
1439     if (!smartData->frame->view())
1440         return;
1441
1442     const char* theme = ewk_view_theme_get(view);
1443     smartData->frame->view()->setEdjeTheme(theme);
1444     smartData->frame->view()->setEvasObject(ewkFrame);
1445 }
1446
1447 ssize_t ewk_frame_source_get(const Evas_Object* ewkFrame, char** frameSource)
1448 {
1449     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, -1);
1450     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, -1);
1451     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->document(), -1);
1452     EINA_SAFETY_ON_NULL_RETURN_VAL(frameSource, -1);
1453
1454     WTF::String source;
1455     *frameSource = 0; // Saves 0 to pointer until it's not allocated.
1456
1457     if (!smartData->frame->document()->isHTMLDocument()) {
1458         // FIXME: Support others documents.
1459         WRN("Only HTML documents are supported");
1460         return -1;
1461     }
1462
1463     // Look for <html> tag. If it exists, the node contatins all document's source.
1464     WebCore::Node* documentNode = smartData->frame->document()->documentElement();
1465     if (documentNode)
1466         for (WebCore::Node* node = documentNode->firstChild(); node; node = node->parentElement()) {
1467             if (node->hasTagName(WebCore::HTMLNames::htmlTag)) {
1468                 WebCore::HTMLElement* element = static_cast<WebCore::HTMLElement*>(node);
1469                 if (element)
1470                     source = element->outerHTML();
1471                 break;
1472             }
1473         }
1474
1475     // Try to get <head> and <body> tags if <html> tag was not found.
1476     if (source.isEmpty()) {
1477         if (smartData->frame->document()->head())
1478             source = smartData->frame->document()->head()->outerHTML();
1479
1480         if (smartData->frame->document()->body())
1481             source += smartData->frame->document()->body()->outerHTML();
1482     }
1483
1484     size_t sourceLength = strlen(source.utf8().data());
1485     *frameSource = static_cast<char*>(malloc(sourceLength + 1));
1486     if (!*frameSource) {
1487         CRITICAL("Could not allocate memory.");
1488         return -1;
1489     }
1490
1491     strncpy(*frameSource, source.utf8().data(), sourceLength);
1492     (*frameSource)[sourceLength] = '\0';
1493
1494     return sourceLength;
1495 }
1496
1497 Eina_List* ewk_frame_resources_location_get(const Evas_Object* ewkFrame)
1498 {
1499     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
1500     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, 0);
1501     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame->document(), 0);
1502
1503     Eina_List* listOfImagesLocation = 0;
1504
1505     // Get src attibute of images and saves them to the Eina_List.
1506     RefPtr<WebCore::HTMLCollection> images = smartData->frame->document()->images();
1507     for (size_t index = 0; index < images->length(); ++index) {
1508         WebCore::HTMLImageElement* imageElement = static_cast<WebCore::HTMLImageElement*>(images->item(index));
1509         if (!imageElement || imageElement->src().isNull() || imageElement->src().isEmpty())
1510             continue;
1511
1512         WTF::String imageLocation = WebCore::decodeURLEscapeSequences(imageElement->src().string());
1513         // Look for duplicated location.
1514         Eina_List* listIterator = 0;
1515         void* data = 0;
1516         Eina_Bool found = EINA_FALSE;
1517         EINA_LIST_FOREACH(listOfImagesLocation, listIterator, data)
1518             if (found = !strcmp(static_cast<char*>(data), imageLocation.utf8().data()))
1519                 break;
1520         if (found)
1521             continue;
1522
1523         char* imageLocationCopy = strdup(imageLocation.utf8().data());
1524         if (!imageLocationCopy)
1525             goto out_of_memory_handler;
1526         listOfImagesLocation = eina_list_append(listOfImagesLocation, imageLocationCopy);
1527         if (eina_error_get())
1528             goto out_of_memory_handler;
1529     }
1530     // FIXME: Get URL others resources (plugins, css, media files).
1531     return listOfImagesLocation;
1532
1533 out_of_memory_handler:
1534     CRITICAL("Could not allocate memory.");
1535     void* data;
1536     EINA_LIST_FREE(listOfImagesLocation, data)
1537         free(data);
1538     return 0;
1539 }
1540
1541 char* ewk_frame_plain_text_get(const Evas_Object* ewkFrame)
1542 {
1543     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData, 0);
1544     EINA_SAFETY_ON_NULL_RETURN_VAL(smartData->frame, 0);
1545
1546     if (!smartData->frame->document())
1547         return 0;
1548
1549     WebCore::Element* documentElement = smartData->frame->document()->documentElement();
1550
1551     if (!documentElement)
1552         return 0;
1553
1554     return strdup(documentElement->innerText().utf8().data());
1555 }
1556
1557 /**
1558  * @internal
1559  * Reports uri changed and swap internal string reference.
1560  *
1561  * Emits signal: "uri,changed" with new uri as parameter.
1562  */
1563 Eina_Bool ewk_frame_uri_changed(Evas_Object* ewkFrame)
1564 {
1565     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, EINA_FALSE);
1566     EINA_SAFETY_ON_NULL_RETURN_VAL(sd->frame, EINA_FALSE);
1567     WTF::CString uri(sd->frame->document()->url().string().utf8());
1568
1569     INF("uri=%s", uri.data());
1570     if (!uri.data()) {
1571         ERR("no uri");
1572         return EINA_FALSE;
1573     }
1574
1575     eina_stringshare_replace(&sd->uri, uri.data());
1576     evas_object_smart_callback_call(ewkFrame, "uri,changed", (void*)sd->uri);
1577     return EINA_TRUE;
1578 }
1579
1580 /**
1581  * @internal
1582  *
1583  * Forces layout for frame.
1584  */
1585 void ewk_frame_force_layout(Evas_Object* ewkFrame)
1586 {
1587     DBG("ewkFrame=%p", ewkFrame);
1588     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, smartData);
1589     EINA_SAFETY_ON_NULL_RETURN(smartData->frame);
1590     WebCore::FrameView* view = smartData->frame->view();
1591     if (view)
1592         view->forceLayout(true);
1593 }
1594
1595 /**
1596  * @internal
1597  *
1598  * Creates plugin.
1599  */
1600 WTF::PassRefPtr<WebCore::Widget> ewk_frame_plugin_create(Evas_Object* ewkFrame, const WebCore::IntSize& pluginSize, WebCore::HTMLPlugInElement* element, const WebCore::KURL& url, const WTF::Vector<WTF::String>& paramNames, const WTF::Vector<WTF::String>& paramValues, const WTF::String& mimeType, bool loadManually)
1601 {
1602     return 0;
1603 }
1604
1605 /**
1606  * @internal
1607  * Reports that editor client selection was changed.
1608  *
1609  * @param ewkFrame Frame
1610  *
1611  * Emits signal: "editorclientselection,changed" with no parameters.
1612  */
1613 void ewk_frame_editor_client_selection_changed(Evas_Object* ewkFrame)
1614 {
1615     evas_object_smart_callback_call(ewkFrame, "editorclient,selection,changed", 0);
1616     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd);
1617     ewk_view_editor_client_selection_changed(sd->view);
1618 }
1619
1620 /**
1621  * @internal
1622  * Reports that editor client's contents were changed.
1623  *
1624  * @param o Frame
1625  *
1626  * Emits signal: "editorclient,contents,changed" with no parameters.
1627  */
1628 void ewk_frame_editor_client_contents_changed(Evas_Object* ewkFrame)
1629 {
1630     evas_object_smart_callback_call(ewkFrame, "editorclient,contents,changed", 0);
1631     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd);
1632     ewk_view_editor_client_contents_changed(sd->view);
1633 }
1634
1635 namespace EWKPrivate {
1636
1637 WebCore::Frame *coreFrame(const Evas_Object *ewkFrame)
1638 {
1639     EWK_FRAME_SD_GET_OR_RETURN(ewkFrame, sd, 0);
1640     return sd->frame;
1641 }
1642
1643 Evas_Object* kitFrame(const WebCore::Frame* coreFrame)
1644 {
1645     if (!coreFrame)
1646         return 0;
1647
1648     WebCore::FrameLoaderClientEfl* frameLoaderClient = _ewk_frame_loader_efl_get(coreFrame);
1649     if (!frameLoaderClient)
1650         return 0;
1651
1652     return frameLoaderClient->webFrame();
1653 }
1654
1655 } // namespace EWKPrivate