1/*
2 * Copyright (C) 2011 Christian Dywan <christian@lanedo.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB.  If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#include "config.h"
21#include "webkiticondatabase.h"
22
23#include "DatabaseDetails.h"
24#include "DatabaseTracker.h"
25#include "FileSystem.h"
26#include "IconDatabase.h"
27#include "Image.h"
28#include "IntSize.h"
29#include "webkitglobalsprivate.h"
30#include "webkitmarshal.h"
31#include "webkitsecurityoriginprivate.h"
32#include "webkitwebframe.h"
33#include <glib/gi18n-lib.h>
34#include <wtf/gobject/GOwnPtr.h>
35#include <wtf/text/CString.h>
36
37/**
38 * SECTION:webkitwebdatabase
39 * @short_description: A WebKit web application database
40 *
41 * #WebKitIconDatabase provides access to website icons, as shown
42 * in tab labels, window captions or bookmarks. All views share
43 * the same icon database.
44 *
45 * The icon database is enabled by default and stored in
46 * ~/.local/share/webkit/icondatabase, depending on XDG_DATA_HOME.
47 *
48 * WebKit will automatically look for available icons in link elements
49 * on opened pages as well as an existing favicon.ico and load the
50 * images found into the memory cache if possible. The signal "icon-loaded"
51 * will be emitted when any icon is found and loaded.
52 * Old Icons are automatically cleaned up after 4 days.
53 *
54 * webkit_icon_database_set_path() can be used to change the location
55 * of the database and also to disable it by passing %NULL.
56 *
57 * If WebKitWebSettings::enable-private-browsing is %TRUE new icons
58 * won't be added to the database on disk and no existing icons will
59 * be deleted from it.
60 *
61 * Since: 1.3.13
62 */
63
64using namespace WebKit;
65
66enum {
67    PROP_0,
68
69    PROP_PATH,
70};
71
72enum {
73    ICON_LOADED,
74
75    LAST_SIGNAL
76};
77
78static guint webkit_icon_database_signals[LAST_SIGNAL] = { 0, };
79
80G_DEFINE_TYPE(WebKitIconDatabase, webkit_icon_database, G_TYPE_OBJECT);
81
82struct _WebKitIconDatabasePrivate {
83    GOwnPtr<gchar> path;
84};
85
86static void webkit_icon_database_finalize(GObject* object)
87{
88    // Call C++ destructors, the reverse of 'placement new syntax'
89    WEBKIT_ICON_DATABASE(object)->priv->~WebKitIconDatabasePrivate();
90
91    G_OBJECT_CLASS(webkit_icon_database_parent_class)->finalize(object);
92}
93
94static void webkit_icon_database_dispose(GObject* object)
95{
96    G_OBJECT_CLASS(webkit_icon_database_parent_class)->dispose(object);
97}
98
99static void webkit_icon_database_set_property(GObject* object, guint propId, const GValue* value, GParamSpec* pspec)
100{
101    WebKitIconDatabase* database = WEBKIT_ICON_DATABASE(object);
102
103    switch (propId) {
104    case PROP_PATH:
105        webkit_icon_database_set_path(database, g_value_get_string(value));
106        break;
107    default:
108        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
109        break;
110    }
111}
112
113static void webkit_icon_database_get_property(GObject* object, guint propId, GValue* value, GParamSpec* pspec)
114{
115    WebKitIconDatabase* database = WEBKIT_ICON_DATABASE(object);
116
117    switch (propId) {
118    case PROP_PATH:
119        g_value_set_string(value, webkit_icon_database_get_path(database));
120        break;
121    default:
122        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, pspec);
123        break;
124    }
125}
126
127static void webkit_icon_database_class_init(WebKitIconDatabaseClass* klass)
128{
129    webkitInit();
130
131    GObjectClass* gobjectClass = G_OBJECT_CLASS(klass);
132    gobjectClass->dispose = webkit_icon_database_dispose;
133    gobjectClass->finalize = webkit_icon_database_finalize;
134    gobjectClass->set_property = webkit_icon_database_set_property;
135    gobjectClass->get_property = webkit_icon_database_get_property;
136
137     /**
138      * WebKitIconDatabase:path:
139      *
140      * The absolute path of the icon database folder.
141      *
142      * Since: 1.3.13
143      */
144     g_object_class_install_property(gobjectClass, PROP_PATH,
145                                     g_param_spec_string("path",
146                                                         _("Path"),
147                                                         _("The absolute path of the icon database folder"),
148                                                         NULL,
149                WEBKIT_PARAM_READWRITE));
150
151    /**
152     * WebKitIconDatabase::icon-loaded:
153     * @database: the object on which the signal is emitted
154     * @frame: the frame containing the icon
155     * @frame_uri: the URI of the frame containing the icon
156     *
157     * This signal is emitted when a favicon is available for a page,
158     * or a child frame.
159     * See WebKitWebView::icon-loaded if you only need the favicon for
160     * the main frame of a particular #WebKitWebView.
161     *
162     * Since: 1.3.13
163     */
164    webkit_icon_database_signals[ICON_LOADED] = g_signal_new("icon-loaded",
165            G_TYPE_FROM_CLASS(klass),
166            (GSignalFlags)G_SIGNAL_RUN_LAST,
167            0,
168            NULL,
169            NULL,
170            webkit_marshal_VOID__OBJECT_STRING,
171            G_TYPE_NONE, 2,
172            WEBKIT_TYPE_WEB_FRAME,
173            G_TYPE_STRING);
174
175    g_type_class_add_private(klass, sizeof(WebKitIconDatabasePrivate));
176}
177
178static void webkit_icon_database_init(WebKitIconDatabase* database)
179{
180    database->priv = G_TYPE_INSTANCE_GET_PRIVATE(database, WEBKIT_TYPE_ICON_DATABASE, WebKitIconDatabasePrivate);
181    // 'placement new syntax', see webkitwebview.cpp
182    new (database->priv) WebKitIconDatabasePrivate();
183}
184
185/**
186 * webkit_icon_database_get_path:
187 * @database: a #WebKitIconDatabase
188 *
189 * Determines the absolute path to the database folder on disk.
190 *
191 * Returns: the absolute path of the database folder, or %NULL
192 *
193 * Since: 1.3.13
194 **/
195G_CONST_RETURN gchar* webkit_icon_database_get_path(WebKitIconDatabase* database)
196{
197    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
198
199    return database->priv->path.get();
200}
201
202static void closeIconDatabaseOnExit()
203{
204    if (WebCore::iconDatabase().isEnabled()) {
205        WebCore::iconDatabase().setEnabled(false);
206        WebCore::iconDatabase().close();
207    }
208}
209
210/**
211 * webkit_icon_database_set_path:
212 * @database: a #WebKitIconDatabase
213 * @path: an absolute path to the icon database folder
214 *
215 * Specifies the absolute path to the database folder on disk.
216 *
217 * Passing %NULL or "" disables the icon database.
218 *
219 * Since: 1.3.13
220 **/
221void webkit_icon_database_set_path(WebKitIconDatabase* database, const gchar* path)
222{
223    g_return_if_fail(WEBKIT_IS_ICON_DATABASE(database));
224
225    if (database->priv->path.get())
226        WebCore::iconDatabase().close();
227
228    if (!(path && path[0])) {
229        database->priv->path.set(0);
230        WebCore::iconDatabase().setEnabled(false);
231        return;
232    }
233
234    database->priv->path.set(g_strdup(path));
235
236    WebCore::iconDatabase().setEnabled(true);
237    WebCore::iconDatabase().open(WebCore::filenameToString(database->priv->path.get()), WebCore::IconDatabase::defaultDatabaseFilename());
238
239    static bool initialized = false;
240    if (!initialized) {
241        atexit(closeIconDatabaseOnExit);
242        initialized = true;
243    }
244}
245
246/**
247 * webkit_icon_database_get_icon_uri:
248 * @database: a #WebKitIconDatabase
249 * @page_uri: URI of the page containing the icon
250 *
251 * Obtains the URI for the favicon for the given page URI.
252 * See also webkit_web_view_get_icon_uri().
253 *
254 * Returns: a newly allocated URI for the favicon, or %NULL
255 *
256 * Since: 1.3.13
257 **/
258gchar* webkit_icon_database_get_icon_uri(WebKitIconDatabase* database, const gchar* pageURI)
259{
260    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
261    g_return_val_if_fail(pageURI, 0);
262
263    String pageURL = String::fromUTF8(pageURI);
264    return g_strdup(WebCore::iconDatabase().synchronousIconURLForPageURL(pageURL).utf8().data());
265}
266
267/**
268 * webkit_icon_database_get_icon_pixbuf:
269 * @database: a #WebKitIconDatabase
270 * @page_uri: URI of the page containing the icon
271 *
272 * Obtains a #GdkPixbuf of the favicon for the given page URI, or
273 * a default icon if there is no icon for the given page. Use
274 * webkit_icon_database_get_icon_uri() if you need to distinguish these cases.
275 * Usually you want to connect to WebKitIconDatabase::icon-loaded and call this
276 * method in the callback.
277 *
278 * The pixbuf will have the largest size provided by the server and should
279 * be resized before it is displayed.
280 * See also webkit_web_view_get_icon_pixbuf().
281 *
282 * Returns: (transfer full): a new reference to a #GdkPixbuf, or %NULL
283 *
284 * Since: 1.3.13
285 **/
286GdkPixbuf* webkit_icon_database_get_icon_pixbuf(WebKitIconDatabase* database, const gchar* pageURI)
287{
288    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
289    g_return_val_if_fail(pageURI, 0);
290
291    String pageURL = String::fromUTF8(pageURI);
292    // The exact size we pass is irrelevant to the WebCore::iconDatabase code.
293    // We must pass something greater than 0, 0 to get a pixbuf.
294    WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(pageURL, WebCore::IntSize(16, 16));
295    if (!icon)
296        return 0;
297    GdkPixbuf* pixbuf = icon->getGdkPixbuf();
298    if (!pixbuf)
299        return 0;
300    return static_cast<GdkPixbuf*>(g_object_ref(pixbuf));
301}
302
303/**
304 * webkit_icon_database_clear():
305 * @database: a #WebKitIconDatabase
306 *
307 * Clears all icons from the database.
308 *
309 * Since: 1.3.13
310 **/
311void webkit_icon_database_clear(WebKitIconDatabase* database)
312{
313    g_return_if_fail(WEBKIT_IS_ICON_DATABASE(database));
314
315    WebCore::iconDatabase().removeAllIcons();
316}
317
318