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 "FileSystem.h"
24#include "IconDatabase.h"
25#include "Image.h"
26#include "IntSize.h"
27#include "webkitglobalsprivate.h"
28#include "webkitmarshal.h"
29#include "webkitsecurityoriginprivate.h"
30#include "webkitwebframe.h"
31#include <glib/gi18n-lib.h>
32#include <wtf/gobject/GOwnPtr.h>
33#include <wtf/text/CString.h>
34
35/**
36 * SECTION:webkiticondatabase
37 * @short_description: A WebKit web application database
38 *
39 * #WebKitIconDatabase provides access to website icons, as shown
40 * in tab labels, window captions or bookmarks. All views share
41 * the same icon database.
42 *
43 * The icon database is enabled by default and stored in
44 * ~/.local/share/webkit/icondatabase, depending on XDG_DATA_HOME.
45 *
46 * WebKit will automatically look for available icons in link elements
47 * on opened pages as well as an existing favicon.ico and load the
48 * images found into the memory cache if possible. The signal "icon-loaded"
49 * will be emitted when any icon is found and loaded.
50 * Old Icons are automatically cleaned up after 4 days.
51 *
52 * webkit_icon_database_set_path() can be used to change the location
53 * of the database and also to disable it by passing %NULL.
54 *
55 * If WebKitWebSettings::enable-private-browsing is %TRUE new icons
56 * won't be added to the database on disk and no existing icons will
57 * be deleted from it.
58 *
59 * Since: 1.3.13
60 *
61 * Deprecated: 1.8: Use WebKitFaviconDatabase instead.
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      * Deprecated: 1.8: Use WebKitFaviconDatabase::path instead.
145      */
146     g_object_class_install_property(gobjectClass, PROP_PATH,
147                                     g_param_spec_string("path",
148                                                         _("Path"),
149                                                         _("The absolute path of the icon database folder"),
150                                                         NULL,
151                WEBKIT_PARAM_READWRITE));
152
153    /**
154     * WebKitIconDatabase::icon-loaded:
155     * @database: the object on which the signal is emitted
156     * @frame: the frame containing the icon
157     * @frame_uri: the URI of the frame containing the icon
158     *
159     * This signal is emitted when a favicon is available for a page,
160     * or a child frame.
161     * See WebKitWebView::icon-loaded if you only need the favicon for
162     * the main frame of a particular #WebKitWebView.
163     *
164     * Since: 1.3.13
165     *
166     * Deprecated: 1.8: Use WebKitFaviconDatabase::icon-loaded instead.
167     */
168    webkit_icon_database_signals[ICON_LOADED] = g_signal_new("icon-loaded",
169        G_TYPE_FROM_CLASS(klass),
170        (GSignalFlags)G_SIGNAL_RUN_LAST,
171        0,
172        NULL,
173        NULL,
174        webkit_marshal_VOID__OBJECT_STRING,
175        G_TYPE_NONE, 2,
176        WEBKIT_TYPE_WEB_FRAME,
177        G_TYPE_STRING);
178
179    g_type_class_add_private(klass, sizeof(WebKitIconDatabasePrivate));
180}
181
182static void webkit_icon_database_init(WebKitIconDatabase* database)
183{
184    database->priv = G_TYPE_INSTANCE_GET_PRIVATE(database, WEBKIT_TYPE_ICON_DATABASE, WebKitIconDatabasePrivate);
185    // 'placement new syntax', see webkitwebview.cpp
186    new (database->priv) WebKitIconDatabasePrivate();
187}
188
189/**
190 * webkit_icon_database_get_path:
191 * @database: a #WebKitIconDatabase
192 *
193 * Determines the absolute path to the database folder on disk.
194 *
195 * Returns: the absolute path of the database folder, or %NULL
196 *
197 * Since: 1.3.13
198 *
199 * Deprecated: 1.8: Use webkit_favicon_database_get_path() instead.
200 **/
201const gchar* webkit_icon_database_get_path(WebKitIconDatabase* database)
202{
203    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
204
205    return database->priv->path.get();
206}
207
208static void closeIconDatabaseOnExit()
209{
210    if (WebCore::iconDatabase().isEnabled()) {
211        WebCore::iconDatabase().setEnabled(false);
212        WebCore::iconDatabase().close();
213    }
214}
215
216/**
217 * webkit_icon_database_set_path:
218 * @database: a #WebKitIconDatabase
219 * @path: an absolute path to the icon database folder
220 *
221 * Specifies the absolute path to the database folder on disk.
222 *
223 * Passing %NULL or "" disables the icon database.
224 *
225 * Since: 1.3.13
226 *
227 * Deprecated: 1.8: Use webkit_favicon_database_set_path() instead.
228 **/
229void webkit_icon_database_set_path(WebKitIconDatabase* database, const gchar* path)
230{
231    g_return_if_fail(WEBKIT_IS_ICON_DATABASE(database));
232
233    if (database->priv->path.get())
234        WebCore::iconDatabase().close();
235
236    if (!(path && path[0])) {
237        database->priv->path.set(0);
238        WebCore::iconDatabase().setEnabled(false);
239        return;
240    }
241
242    database->priv->path.set(g_strdup(path));
243
244    WebCore::iconDatabase().setEnabled(true);
245    WebCore::iconDatabase().open(WebCore::filenameToString(database->priv->path.get()), WebCore::IconDatabase::defaultDatabaseFilename());
246
247    static bool initialized = false;
248    if (!initialized) {
249        atexit(closeIconDatabaseOnExit);
250        initialized = true;
251    }
252}
253
254/**
255 * webkit_icon_database_get_icon_uri:
256 * @database: a #WebKitIconDatabase
257 * @page_uri: URI of the page containing the icon
258 *
259 * Obtains the URI for the favicon for the given page URI.
260 * See also webkit_web_view_get_icon_uri().
261 *
262 * Returns: a newly allocated URI for the favicon, or %NULL
263 *
264 * Since: 1.3.13
265 *
266 * Deprecated: 1.8: Use webkit_favicon_database_get_favicon_uri() instead.
267 **/
268gchar* webkit_icon_database_get_icon_uri(WebKitIconDatabase* database, const gchar* pageURI)
269{
270    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
271    g_return_val_if_fail(pageURI, 0);
272
273    String pageURL = String::fromUTF8(pageURI);
274    return g_strdup(WebCore::iconDatabase().synchronousIconURLForPageURL(pageURL).utf8().data());
275}
276
277/**
278 * webkit_icon_database_get_icon_pixbuf:
279 * @database: a #WebKitIconDatabase
280 * @page_uri: URI of the page containing the icon
281 *
282 * Obtains a #GdkPixbuf of the favicon for the given page URI, or
283 * a default icon if there is no icon for the given page. Use
284 * webkit_icon_database_get_icon_uri() if you need to distinguish these cases.
285 * Usually you want to connect to WebKitIconDatabase::icon-loaded and call this
286 * method in the callback.
287 *
288 * The pixbuf will have the largest size provided by the server and should
289 * be resized before it is displayed.
290 * See also webkit_web_view_get_icon_pixbuf().
291 *
292 * Returns: (transfer full): a new reference to a #GdkPixbuf, or %NULL
293 *
294 * Since: 1.3.13
295 *
296 * Deprecated: 1.8: Use webkit_favicon_database_try_get_favicon_pixbuf() instead.
297 **/
298GdkPixbuf* webkit_icon_database_get_icon_pixbuf(WebKitIconDatabase* database, const gchar* pageURI)
299{
300    g_return_val_if_fail(WEBKIT_IS_ICON_DATABASE(database), 0);
301    g_return_val_if_fail(pageURI, 0);
302
303    String pageURL = String::fromUTF8(pageURI);
304    // The exact size we pass is irrelevant to the WebCore::iconDatabase code.
305    // We must pass something greater than 0, 0 to get a pixbuf.
306    WebCore::Image* icon = WebCore::iconDatabase().synchronousIconForPageURL(pageURL, WebCore::IntSize(16, 16));
307    if (!icon)
308        return 0;
309    GdkPixbuf* pixbuf = icon->getGdkPixbuf();
310    if (!pixbuf)
311        return 0;
312    return static_cast<GdkPixbuf*>(g_object_ref(pixbuf));
313}
314
315/**
316 * webkit_icon_database_clear:
317 * @database: a #WebKitIconDatabase
318 *
319 * Clears all icons from the database.
320 *
321 * Since: 1.3.13
322 *
323 * Deprecated: 1.8: Use webkit_favicon_database_clear() instead.
324 **/
325void webkit_icon_database_clear(WebKitIconDatabase* database)
326{
327    g_return_if_fail(WEBKIT_IS_ICON_DATABASE(database));
328
329    WebCore::iconDatabase().removeAllIcons();
330}
331
332