blob: fb70903b5d649d61781ecf932c79b42dba5622ac [file] [log] [blame]
/*
Copyright (C) 2009-2010 ProFUSION embedded systems
Copyright (C) 2009-2010 Samsung Electronics
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "ewk_history.h"
#include "BackForwardListImpl.h"
#include "EWebKit.h"
#include "HistoryItem.h"
#include "IconDatabaseBase.h"
#include "Image.h"
#include "IntSize.h"
#include "ewk_private.h"
#include <wtf/text/CString.h>
#include <Eina.h>
#include <eina_safety_checks.h>
struct _Ewk_History {
WebCore::BackForwardListImpl *core;
};
#define EWK_HISTORY_CORE_GET_OR_RETURN(history, core_, ...) \
if (!(history)) { \
CRITICAL("history is NULL."); \
return __VA_ARGS__; \
} \
if (!(history)->core) { \
CRITICAL("history->core is NULL."); \
return __VA_ARGS__; \
} \
if (!(history)->core->enabled()) { \
ERR("history->core is disabled!."); \
return __VA_ARGS__; \
} \
WebCore::BackForwardListImpl *core_ = (history)->core
struct _Ewk_History_Item {
WebCore::HistoryItem *core;
const char *title;
const char *alternate_title;
const char *uri;
const char *original_uri;
};
#define EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core_, ...) \
if (!(item)) { \
CRITICAL("item is NULL."); \
return __VA_ARGS__; \
} \
if (!(item)->core) { \
CRITICAL("item->core is NULL."); \
return __VA_ARGS__; \
} \
WebCore::HistoryItem *core_ = (item)->core
static inline Ewk_History_Item *_ewk_history_item_new(WebCore::HistoryItem *core)
{
Ewk_History_Item* item;
if (!core) {
ERR("WebCore::HistoryItem is NULL.");
return 0;
}
item = (Ewk_History_Item *)calloc(1, sizeof(Ewk_History_Item));
if (!item) {
CRITICAL("Could not allocate item memory.");
return 0;
}
core->ref();
item->core = core;
return item;
}
static inline Eina_List *_ewk_history_item_list_get(const WebCore::HistoryItemVector &core_items)
{
Eina_List* ret = 0;
unsigned int i, size;
size = core_items.size();
for (i = 0; i < size; i++) {
Ewk_History_Item* item = _ewk_history_item_new(core_items[i].get());
if (item)
ret = eina_list_append(ret, item);
}
return ret;
}
/**
* Go forward in history one item, if possible.
*
* @param history which history instance to modify.
*
* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
*/
Eina_Bool ewk_history_forward(Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
if (core->forwardListCount() < 1)
return EINA_FALSE;
core->goForward();
return EINA_TRUE;
}
/**
* Go back in history one item, if possible.
*
* @param history which history instance to modify.
*
* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
*/
Eina_Bool ewk_history_back(Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
if (core->backListCount() < 1)
return EINA_FALSE;
core->goBack();
return EINA_TRUE;
}
/**
* Adds the given item to history.
*
* Memory handling: This will not modify or even take references to
* given item (Ewk_History_Item), so you should still handle it with
* ewk_history_item_free().
*
* @param history which history instance to modify.
* @param item reference to add to history. Unmodified. Must @b not be @c NULL.
*
* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
*/
Eina_Bool ewk_history_history_item_add(Ewk_History* history, const Ewk_History_Item* item)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
history_core->addItem(item_core);
return EINA_TRUE;
}
/**
* Sets the given item as current in history (go to item).
*
* Memory handling: This will not modify or even take references to
* given item (Ewk_History_Item), so you should still handle it with
* ewk_history_item_free().
*
* @param history which history instance to modify.
* @param item reference to go to history. Unmodified. Must @b not be @c NULL.
*
* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
*/
Eina_Bool ewk_history_history_item_set(Ewk_History* history, const Ewk_History_Item* item)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
history_core->goToItem(item_core);
return EINA_TRUE;
}
/**
* Get the first item from back list, if any.
*
* @param history which history instance to query.
*
* @return the @b newly allocated item instance. This memory must be
* released with ewk_history_item_free() after use.
*/
Ewk_History_Item* ewk_history_history_item_back_get(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return _ewk_history_item_new(core->backItem());
}
/**
* Get the current item in history, if any.
*
* @param history which history instance to query.
*
* @return the @b newly allocated item instance. This memory must be
* released with ewk_history_item_free() after use.
*/
Ewk_History_Item* ewk_history_history_item_current_get(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return _ewk_history_item_new(core->currentItem());
}
/**
* Get the first item from forward list, if any.
*
* @param history which history instance to query.
*
* @return the @b newly allocated item instance. This memory must be
* released with ewk_history_item_free() after use.
*/
Ewk_History_Item* ewk_history_history_item_forward_get(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return _ewk_history_item_new(core->forwardItem());
}
/**
* Get item at given position, if any at that index.
*
* @param history which history instance to query.
* @param index position of item to get.
*
* @return the @b newly allocated item instance. This memory must be
* released with ewk_history_item_free() after use.
*/
Ewk_History_Item* ewk_history_history_item_nth_get(const Ewk_History* history, int index)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return _ewk_history_item_new(core->itemAtIndex(index));
}
/**
* Queries if given item is in history.
*
* Memory handling: This will not modify or even take references to
* given item (Ewk_History_Item), so you should still handle it with
* ewk_history_item_free().
*
* @param history which history instance to modify.
* @param item reference to check in history. Must @b not be @c NULL.
*
* @return @c EINA_TRUE if in history, @c EINA_FALSE if not or failure.
*/
Eina_Bool ewk_history_history_item_contains(const Ewk_History* history, const Ewk_History_Item* item)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, history_core, EINA_FALSE);
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, item_core, EINA_FALSE);
return history_core->containsItem(item_core);
}
/**
* Get the whole forward list.
*
* @param history which history instance to query.
*
* @return a newly allocated list of @b newly allocated item
* instance. This memory of each item must be released with
* ewk_history_item_free() after use. use
* ewk_history_item_list_free() for convenience.
*
* @see ewk_history_item_list_free()
* @see ewk_history_forward_list_get_with_limit()
*/
Eina_List* ewk_history_forward_list_get(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
WebCore::HistoryItemVector items;
int limit = core->forwardListCount();
core->forwardListWithLimit(limit, items);
return _ewk_history_item_list_get(items);
}
/**
* Get the forward list within the given limit.
*
* @param history which history instance to query.
* @param limit the maximum number of items to return.
*
* @return a newly allocated list of @b newly allocated item
* instance. This memory of each item must be released with
* ewk_history_item_free() after use. use
* ewk_history_item_list_free() for convenience.
*
* @see ewk_history_item_list_free()
* @see ewk_history_forward_list_length()
* @see ewk_history_forward_list_get()
*/
Eina_List* ewk_history_forward_list_get_with_limit(const Ewk_History* history, int limit)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
WebCore::HistoryItemVector items;
core->forwardListWithLimit(limit, items);
return _ewk_history_item_list_get(items);
}
/**
* Get the whole size of forward list.
*
* @param history which history instance to query.
*
* @return number of elements in whole list.
*
* @see ewk_history_forward_list_get_with_limit()
*/
int ewk_history_forward_list_length(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return core->forwardListCount();
}
/**
* Get the whole back list.
*
* @param history which history instance to query.
*
* @return a newly allocated list of @b newly allocated item
* instance. This memory of each item must be released with
* ewk_history_item_free() after use. use
* ewk_history_item_list_free() for convenience.
*
* @see ewk_history_item_list_free()
* @see ewk_history_back_list_get_with_limit()
*/
Eina_List* ewk_history_back_list_get(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
WebCore::HistoryItemVector items;
int limit = core->backListCount();
core->backListWithLimit(limit, items);
return _ewk_history_item_list_get(items);
}
/**
* Get the back list within the given limit.
*
* @param history which history instance to query.
* @param limit the maximum number of items to return.
*
* @return a newly allocated list of @b newly allocated item
* instance. This memory of each item must be released with
* ewk_history_item_free() after use. use
* ewk_history_item_list_free() for convenience.
*
* @see ewk_history_item_list_free()
* @see ewk_history_back_list_length()
* @see ewk_history_back_list_get()
*/
Eina_List* ewk_history_back_list_get_with_limit(const Ewk_History* history, int limit)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
WebCore::HistoryItemVector items;
core->backListWithLimit(limit, items);
return _ewk_history_item_list_get(items);
}
/**
* Get the whole size of back list.
*
* @param history which history instance to query.
*
* @return number of elements in whole list.
*
* @see ewk_history_back_list_get_with_limit()
*/
int ewk_history_back_list_length(const Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return core->backListCount();
}
/**
* Get maximum capacity of given history.
*
* @param history which history instance to query.
*
* @return maximum number of entries this history will hold.
*/
int ewk_history_limit_get(Ewk_History* history)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, 0);
return core->capacity();
}
/**
* Set maximum capacity of given history.
*
* @param history which history instance to modify.
* @param limit maximum size to allow.
*
* @return @c EINA_TRUE on success, @c EINA_FALSE otherwise.
*/
Eina_Bool ewk_history_limit_set(const Ewk_History* history, int limit)
{
EWK_HISTORY_CORE_GET_OR_RETURN(history, core, EINA_FALSE);
core->setCapacity(limit);
return EINA_TRUE;
}
/**
* Create a new history item with given URI and title.
*
* @param uri where this resource is located.
* @param title resource title.
*
* @return newly allocated history item or @c NULL on errors. You must
* free this item with ewk_history_item_free().
*/
Ewk_History_Item* ewk_history_item_new(const char* uri, const char* title)
{
WTF::String u = WTF::String::fromUTF8(uri);
WTF::String t = WTF::String::fromUTF8(title);
WTF::RefPtr<WebCore::HistoryItem> core = WebCore::HistoryItem::create(u, t, 0);
Ewk_History_Item* item = _ewk_history_item_new(core.release().releaseRef());
return item;
}
static inline void _ewk_history_item_free(Ewk_History_Item* item, WebCore::HistoryItem* core)
{
core->deref();
free(item);
}
/**
* Free given history item instance.
*
* @param item what to free.
*/
void ewk_history_item_free(Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core);
_ewk_history_item_free(item, core);
}
/**
* Free given list and associated history items instances.
*
* @param history_items list of items to free (both list nodes and
* item instances).
*/
void ewk_history_item_list_free(Eina_List* history_items)
{
void* d;
EINA_LIST_FREE(history_items, d) {
Ewk_History_Item* item = (Ewk_History_Item*)d;
_ewk_history_item_free(item, item->core);
}
}
/**
* Query title for given history item.
*
* @param item history item to query.
*
* @return the title pointer, that may be @c NULL. This pointer is
* guaranteed to be eina_stringshare, so whenever possible
* save yourself some cpu cycles and use
* eina_stringshare_ref() instead of eina_stringshare_add() or
* strdup().
*/
const char* ewk_history_item_title_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
// hide the following optimzation from outside
Ewk_History_Item* i = (Ewk_History_Item*)item;
eina_stringshare_replace(&i->title, core->title().utf8().data());
return i->title;
}
/**
* Query alternate title for given history item.
*
* @param item history item to query.
*
* @return the alternate title pointer, that may be @c NULL. This
* pointer is guaranteed to be eina_stringshare, so whenever
* possible save yourself some cpu cycles and use
* eina_stringshare_ref() instead of eina_stringshare_add() or
* strdup().
*/
const char* ewk_history_item_title_alternate_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
// hide the following optimzation from outside
Ewk_History_Item* i = (Ewk_History_Item*)item;
eina_stringshare_replace(&i->alternate_title,
core->alternateTitle().utf8().data());
return i->alternate_title;
}
/**
* Set alternate title for given history item.
*
* @param item history item to query.
* @param title new alternate title to use for given item. No
* references are kept after this function returns.
*/
void ewk_history_item_title_alternate_set(Ewk_History_Item* item, const char* title)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core);
if (!eina_stringshare_replace(&item->alternate_title, title))
return;
core->setAlternateTitle(WTF::String::fromUTF8(title));
}
/**
* Query URI for given history item.
*
* @param item history item to query.
*
* @return the URI pointer, that may be @c NULL. This pointer is
* guaranteed to be eina_stringshare, so whenever possible
* save yourself some cpu cycles and use
* eina_stringshare_ref() instead of eina_stringshare_add() or
* strdup().
*/
const char* ewk_history_item_uri_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
// hide the following optimzation from outside
Ewk_History_Item* i = (Ewk_History_Item*)item;
eina_stringshare_replace(&i->uri, core->urlString().utf8().data());
return i->uri;
}
/**
* Query original URI for given history item.
*
* @param item history item to query.
*
* @return the original URI pointer, that may be @c NULL. This pointer
* is guaranteed to be eina_stringshare, so whenever possible
* save yourself some cpu cycles and use
* eina_stringshare_ref() instead of eina_stringshare_add() or
* strdup().
*/
const char* ewk_history_item_uri_original_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
// hide the following optimzation from outside
Ewk_History_Item* i = (Ewk_History_Item*)item;
eina_stringshare_replace(&i->original_uri,
core->originalURLString().utf8().data());
return i->original_uri;
}
/**
* Query last visited time for given history item.
*
* @param item history item to query.
*
* @return the time in seconds this item was visited.
*/
double ewk_history_item_time_last_visited_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0.0);
return core->lastVisitedTime();
}
/**
* Get the icon (aka favicon) associated with this history item.
*
* @note in order to have this working, one must open icon database
* with ewk_settings_icon_database_path_set().
*
* @param item history item to query.
*
* @return the surface reference or @c NULL on errors. Note that the
* reference may be to a standard fallback icon.
*/
cairo_surface_t* ewk_history_item_icon_surface_get(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(core->url(), WebCore::IntSize(16, 16));
if (!icon) {
ERR("icon is NULL.");
return 0;
}
return icon->nativeImageForCurrentFrame();
}
/**
* Add an Evas_Object of type 'image' to given canvas with history item icon.
*
* This is an utility function that creates an Evas_Object of type
* image set to have fill always match object size
* (evas_object_image_filled_add()), saving some code to use it from Evas.
*
* @note in order to have this working, one must open icon database
* with ewk_settings_icon_database_path_set().
*
* @param item history item to query.
* @param canvas evas instance where to add resulting object.
*
* @return newly allocated Evas_Object instance or @c NULL on
* errors. Delete the object with evas_object_del().
*/
Evas_Object* ewk_history_item_icon_object_add(const Ewk_History_Item* item, Evas* canvas)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(canvas, 0);
WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(core->url(), WebCore::IntSize(16, 16));
cairo_surface_t* surface;
if (!icon) {
ERR("icon is NULL.");
return 0;
}
surface = icon->nativeImageForCurrentFrame();
return ewk_util_image_from_cairo_surface_add(canvas, surface);
}
/**
* Query if given item is still in page cache.
*
* @param item history item to query.
*
* @return @c EINA_TRUE if in cache, @c EINA_FALSE otherwise.
*/
Eina_Bool ewk_history_item_page_cache_exists(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_FALSE);
return core->isInPageCache();
}
/**
* Query number of times item was visited.
*
* @param item history item to query.
*
* @return number of visits.
*/
int ewk_history_item_visit_count(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, 0);
return core->visitCount();
}
/**
* Query if last visit to item was failure or not.
*
* @param item history item to query.
*
* @return @c EINA_TRUE if last visit was failure, @c EINA_FALSE if it
* was fine.
*/
Eina_Bool ewk_history_item_visit_last_failed(const Ewk_History_Item* item)
{
EWK_HISTORY_ITEM_CORE_GET_OR_RETURN(item, core, EINA_TRUE);
return core->lastVisitWasFailure();
}
/* internal methods ****************************************************/
/**
* @internal
*
* Creates history for given view. Called internally by ewk_view and
* should never be called from outside.
*
* @param core WebCore::BackForwardListImpl instance to use internally.
*
* @return newly allocated history instance or @c NULL on errors.
*/
Ewk_History* ewk_history_new(WebCore::BackForwardListImpl* core)
{
Ewk_History* history;
EINA_SAFETY_ON_NULL_RETURN_VAL(core, 0);
DBG("core=%p", core);
history = (Ewk_History*)malloc(sizeof(Ewk_History));
if (!history) {
CRITICAL("Could not allocate history memory.");
return 0;
}
core->ref();
history->core = core;
return history;
}
/**
* @internal
*
* Destroys previously allocated history instance. This is called
* automatically by ewk_view and should never be called from outside.
*
* @param history instance to free
*/
void ewk_history_free(Ewk_History* history)
{
DBG("history=%p", history);
history->core->deref();
free(history);
}