initial import
[vuplus_webkit] / Source / WebKit / efl / ewk / ewk_history.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 #include "config.h"
22 #include "ewk_history.h"
23
24 #include "BackForwardListImpl.h"
25 #include "EWebKit.h"
26 #include "HistoryItem.h"
27 #include "IconDatabaseBase.h"
28 #include "Image.h"
29 #include "IntSize.h"
30 #include "ewk_private.h"
31
32 #include <Eina.h>
33 #include <eina_safety_checks.h>
34 #include <wtf/text/CString.h>
35
36 struct _Ewk_History {
37     WebCore::BackForwardListImpl *core;
38 };
39
40 #define EWK_HISTORY_CORE_GET_OR_RETURN(history, core_, ...)      \
41     if (!(history)) {                                            \
42         CRITICAL("history is NULL.");                            \
43         return __VA_ARGS__;                                      \
44     }                                                            \
45     if (!(history)->core) {                                      \
46         CRITICAL("history->core is NULL.");                      \
47         return __VA_ARGS__;                                      \
48     }                                                            \
49     if (!(history)->core->enabled()) {                           \
50         ERR("history->core is disabled!.");                      \
51         return __VA_ARGS__;                                      \
52     }                                                            \
53     WebCore::BackForwardListImpl *core_ = (history)->core
54
55
56 struct _Ewk_History_Item {
57     WebCore::HistoryItem *core;
58
59     const char *title;
60     const char *alternate_title;
61     const char *uri;
62     const char *original_uri;
63 };
64
65 #define EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core_, ...) \
66     if (!(item)) {                                            \
67         CRITICAL("item is NULL.");                            \
68         return __VA_ARGS__;                                   \
69     }                                                         \
70     if (!(item)->core) {                                      \
71         CRITICAL("item->core is NULL.");                      \
72         return __VA_ARGS__;                                   \
73     }                                                         \
74     WebCore::HistoryItem *core_ = (item)->core
75
76
77 static inline Ewk_History_Item *_ewk_history_item_new(WebCore::HistoryItem *core)
78 {
79     Ewk_History_Item* item;
80
81     if (!core) {
82         ERR("WebCore::HistoryItem is NULL.");
83         return 0;
84     }
85
86     item = (Ewk_History_Item *)calloc(1, sizeof(Ewk_History_Item));
87     if (!item) {
88         CRITICAL("Could not allocate item memory.");
89         return 0;
90     }
91
92     core->ref();
93     item->core = core;
94
95     return item;
96 }
97
98 static inline Eina_List *_ewk_history_item_list_get(const WebCore::HistoryItemVector &core_items)
99 {
100     Eina_List* ret = 0;
101     unsigned int i, size;
102
103     size = core_items.size();
104     for (i = 0; i < size; i++) {
105         Ewk_History_Item* item = _ewk_history_item_new(core_items[i].get());
106         if (item)
107             ret = eina_list_append(ret, item);
108     }
109
110     return ret;
111 }
112
113 Eina_Bool ewk_history_forward(Ewk_History* history)
114 {
115     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
116     if (core->forwardListCount() < 1)
117         return EINA_FALSE;
118     core->goForward();
119     return EINA_TRUE;
120 }
121
122 Eina_Bool ewk_history_back(Ewk_History* history)
123 {
124     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
125     if (core->backListCount() < 1)
126         return EINA_FALSE;
127     core->goBack();
128     return EINA_TRUE;
129 }
130
131 Eina_Bool ewk_history_history_item_add(Ewk_History* history, const Ewk_History_Item* item)
132 {
133     EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
134     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
135     history_core->addItem(item_core);
136     return EINA_TRUE;
137 }
138
139 Eina_Bool ewk_history_history_item_set(Ewk_History* history, const Ewk_History_Item* item)
140 {
141     EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
142     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
143     history_core->goToItem(item_core);
144     return EINA_TRUE;
145 }
146
147 Ewk_History_Item* ewk_history_history_item_back_get(const Ewk_History* history)
148 {
149     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
150     return _ewk_history_item_new(core->backItem());
151 }
152
153 Ewk_History_Item* ewk_history_history_item_current_get(const Ewk_History* history)
154 {
155     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
156     WebCore::HistoryItem *currentItem = core->currentItem();
157     if (currentItem)
158         return _ewk_history_item_new(currentItem);
159     return 0;
160 }
161
162 Ewk_History_Item* ewk_history_history_item_forward_get(const Ewk_History* history)
163 {
164     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
165     return _ewk_history_item_new(core->forwardItem());
166 }
167
168 Ewk_History_Item* ewk_history_history_item_nth_get(const Ewk_History* history, int index)
169 {
170     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
171     return _ewk_history_item_new(core->itemAtIndex(index));
172 }
173
174 Eina_Bool ewk_history_history_item_contains(const Ewk_History* history, const Ewk_History_Item* item)
175 {
176     EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
177     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
178     return history_core->containsItem(item_core);
179 }
180
181 Eina_List* ewk_history_forward_list_get(const Ewk_History* history)
182 {
183     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
184     WebCore::HistoryItemVector items;
185     int limit = core->forwardListCount();
186     core->forwardListWithLimit(limit, items);
187     return _ewk_history_item_list_get(items);
188 }
189
190 Eina_List* ewk_history_forward_list_get_with_limit(const Ewk_History* history, int limit)
191 {
192     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
193     WebCore::HistoryItemVector items;
194     core->forwardListWithLimit(limit, items);
195     return _ewk_history_item_list_get(items);
196 }
197
198 int ewk_history_forward_list_length(const Ewk_History* history)
199 {
200     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
201     return core->forwardListCount();
202 }
203
204 Eina_List* ewk_history_back_list_get(const Ewk_History* history)
205 {
206     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
207     WebCore::HistoryItemVector items;
208     int limit = core->backListCount();
209     core->backListWithLimit(limit, items);
210     return _ewk_history_item_list_get(items);
211 }
212
213 Eina_List* ewk_history_back_list_get_with_limit(const Ewk_History* history, int limit)
214 {
215     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
216     WebCore::HistoryItemVector items;
217     core->backListWithLimit(limit, items);
218     return _ewk_history_item_list_get(items);
219 }
220
221 int ewk_history_back_list_length(const Ewk_History* history)
222 {
223     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
224     return core->backListCount();
225 }
226
227 int ewk_history_limit_get(Ewk_History* history)
228 {
229     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
230     return core->capacity();
231 }
232
233 Eina_Bool ewk_history_limit_set(const Ewk_History* history, int limit)
234 {
235     EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
236     core->setCapacity(limit);
237     return EINA_TRUE;
238 }
239
240 Ewk_History_Item* ewk_history_item_new(const char* uri, const char* title)
241 {
242     WTF::String u = WTF::String::fromUTF8(uri);
243     WTF::String t = WTF::String::fromUTF8(title);
244     WTF::RefPtr<WebCore::HistoryItem> core = WebCore::HistoryItem::create(u, t, 0);
245     Ewk_History_Item* item = _ewk_history_item_new(core.release().releaseRef());
246     return item;
247 }
248
249 static inline void _ewk_history_item_free(Ewk_History_Item* item, WebCore::HistoryItem* core)
250 {
251     core->deref();
252     free(item);
253 }
254
255 void ewk_history_item_free(Ewk_History_Item* item)
256 {
257     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core);
258     _ewk_history_item_free(item, core);
259 }
260
261 void ewk_history_item_list_free(Eina_List* history_items)
262 {
263     void* d;
264     EINA_LIST_FREE(history_items, d) {
265         Ewk_History_Item* item = (Ewk_History_Item*)d;
266         _ewk_history_item_free(item, item->core);
267     }
268 }
269
270 const char* ewk_history_item_title_get(const Ewk_History_Item* item)
271 {
272     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
273     // hide the following optimzation from outside
274     Ewk_History_Item* i = (Ewk_History_Item*)item;
275     eina_stringshare_replace(&i->title, core->title().utf8().data());
276     return i->title;
277 }
278
279 const char* ewk_history_item_title_alternate_get(const Ewk_History_Item* item)
280 {
281     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
282     // hide the following optimzation from outside
283     Ewk_History_Item* i = (Ewk_History_Item*)item;
284     eina_stringshare_replace(&i->alternate_title,
285                              core->alternateTitle().utf8().data());
286     return i->alternate_title;
287 }
288
289 void ewk_history_item_title_alternate_set(Ewk_History_Item* item, const char* title)
290 {
291     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core);
292     if (!eina_stringshare_replace(&item->alternate_title, title))
293         return;
294     core->setAlternateTitle(WTF::String::fromUTF8(title));
295 }
296
297 const char* ewk_history_item_uri_get(const Ewk_History_Item* item)
298 {
299     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
300     // hide the following optimzation from outside
301     Ewk_History_Item* i = (Ewk_History_Item*)item;
302     eina_stringshare_replace(&i->uri, core->urlString().utf8().data());
303     return i->uri;
304 }
305
306 const char* ewk_history_item_uri_original_get(const Ewk_History_Item* item)
307 {
308     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
309     // hide the following optimzation from outside
310     Ewk_History_Item* i = (Ewk_History_Item*)item;
311     eina_stringshare_replace(&i->original_uri,
312                              core->originalURLString().utf8().data());
313     return i->original_uri;
314 }
315
316 double ewk_history_item_time_last_visited_get(const Ewk_History_Item* item)
317 {
318     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0.0);
319     return core->lastVisitedTime();
320 }
321
322 cairo_surface_t* ewk_history_item_icon_surface_get(const Ewk_History_Item* item)
323 {
324     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
325     
326     WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(core->url(), WebCore::IntSize(16, 16));
327     if (!icon) {
328         ERR("icon is NULL.");
329         return 0;
330     }
331     return icon->nativeImageForCurrentFrame();
332 }
333
334 Evas_Object* ewk_history_item_icon_object_add(const Ewk_History_Item* item, Evas* canvas)
335 {
336     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
337     EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0);
338     WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(core->url(), WebCore::IntSize(16, 16));
339     cairo_surface_t* surface;
340
341     if (!icon) {
342         ERR("icon is NULL.");
343         return 0;
344     }
345
346     surface = icon->nativeImageForCurrentFrame();
347     return ewk_util_image_from_cairo_surface_add(canvas, surface);
348 }
349
350 Eina_Bool ewk_history_item_page_cache_exists(const Ewk_History_Item* item)
351 {
352     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_FALSE);
353     return core->isInPageCache();
354 }
355
356 int ewk_history_item_visit_count(const Ewk_History_Item* item)
357 {
358     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
359     return core->visitCount();
360 }
361
362 Eina_Bool ewk_history_item_visit_last_failed(const Ewk_History_Item* item)
363 {
364     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_TRUE);
365     return core->lastVisitWasFailure();
366 }
367
368
369 /* internal methods ****************************************************/
370 /**
371  * @internal
372  *
373  * Creates history for given view. Called internally by ewk_view and
374  * should never be called from outside.
375  *
376  * @param core WebCore::BackForwardListImpl instance to use internally.
377  *
378  * @return newly allocated history instance or @c NULL on errors.
379  */
380 Ewk_History* ewk_history_new(WebCore::BackForwardListImpl* core)
381 {
382     Ewk_History* history;
383     EINA_SAFETY_ON_NULL_RETURN_VAL(core, 0);
384     DBG("core=%p", core);
385
386     history = (Ewk_History*)malloc(sizeof(Ewk_History));
387     if (!history) {
388         CRITICAL("Could not allocate history memory.");
389         return 0;
390     }
391
392     core->ref();
393     history->core = core;
394
395     return history;
396 }
397
398 /**
399  * @internal
400  *
401  * Destroys previously allocated history instance. This is called
402  * automatically by ewk_view and should never be called from outside.
403  *
404  * @param history instance to free
405  */
406 void ewk_history_free(Ewk_History* history)
407 {
408     DBG("history=%p", history);
409     history->core->deref();
410     free(history);
411 }
412
413 /**
414  * @internal
415  *
416  * Returns a newly-allocated string with the item's target name.
417  * Callers are responsible for freeing the allocated memory with free(3).
418  *
419  * @param item instance to operate upon.
420  */
421 char* ewk_history_item_target_get(const Ewk_History_Item* item)
422 {
423     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
424     return strdup(core->target().utf8().data());
425 }
426
427 /**
428  * @internal
429  *
430  * Returns whether the given item is currently a target.
431  *
432  * @param item instance to check.
433  */
434 Eina_Bool ewk_history_item_target_is(const Ewk_History_Item* item)
435 {
436     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
437     return core->isTargetItem();
438 }
439
440 /**
441  * @internal
442  *
443  * Returns a list of child history items relative to the given item,
444  * or @c NULL if there are none.
445  *
446  * @param item instance to operate upon.
447  */
448 Eina_List* ewk_history_item_children_get(const Ewk_History_Item* item)
449 {
450     EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
451     const WebCore::HistoryItemVector& children = core->children();
452     if (!children.size())
453         return 0;
454
455     Eina_List* kids = 0;
456     const unsigned size = children.size();
457     for (unsigned i = 0; i < size; ++i)
458         kids = eina_list_append(kids, _ewk_history_item_new(children[i].get()));
459     return kids;
460 }