1/*
2 * Copyright (C) 2009 Collabora Ltd.
3 * Copyright (C) 2009 Igalia S.L.
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 "webkithittestresult.h"
23
24#include "GOwnPtr.h"
25#include "HitTestResult.h"
26#include "KURL.h"
27#include "WebKitDOMBinding.h"
28#include "WebKitDOMNode.h"
29#include "webkitenumtypes.h"
30#include "webkitglobals.h"
31#include "webkitglobalsprivate.h"
32#include <glib/gi18n-lib.h>
33#include <wtf/text/CString.h>
34
35/**
36 * SECTION:webkithittestresult
37 * @short_description: The target of a mouse event
38 *
39 * This class holds context information about the coordinates
40 * specified by a GDK event.
41 */
42
43G_DEFINE_TYPE(WebKitHitTestResult, webkit_hit_test_result, G_TYPE_OBJECT)
44
45struct _WebKitHitTestResultPrivate {
46    guint context;
47    char* linkURI;
48    char* imageURI;
49    char* mediaURI;
50    WebKitDOMNode* innerNode;
51};
52
53enum {
54    PROP_0,
55
56    PROP_CONTEXT,
57    PROP_LINK_URI,
58    PROP_IMAGE_URI,
59    PROP_MEDIA_URI,
60    PROP_INNER_NODE
61};
62
63static void webkit_hit_test_result_finalize(GObject* object)
64{
65    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
66    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
67
68    g_free(priv->linkURI);
69    g_free(priv->imageURI);
70    g_free(priv->mediaURI);
71
72    G_OBJECT_CLASS(webkit_hit_test_result_parent_class)->finalize(object);
73}
74
75static void webkit_hit_test_result_dispose(GObject* object)
76{
77    g_object_unref(WEBKIT_HIT_TEST_RESULT(object)->priv->innerNode);
78
79    G_OBJECT_CLASS(webkit_hit_test_result_parent_class)->dispose(object);
80}
81
82static void webkit_hit_test_result_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* pspec)
83{
84    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
85    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
86
87    switch(propertyID) {
88    case PROP_CONTEXT:
89        g_value_set_flags(value, priv->context);
90        break;
91    case PROP_LINK_URI:
92        g_value_set_string(value, priv->linkURI);
93        break;
94    case PROP_IMAGE_URI:
95        g_value_set_string(value, priv->imageURI);
96        break;
97    case PROP_MEDIA_URI:
98        g_value_set_string(value, priv->mediaURI);
99        break;
100    case PROP_INNER_NODE:
101        g_value_set_object(value, priv->innerNode);
102        break;
103    default:
104        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, pspec);
105    }
106}
107
108static void webkit_hit_test_result_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* pspec)
109{
110    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
111    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
112
113    switch(propertyID) {
114    case PROP_CONTEXT:
115        priv->context = g_value_get_flags(value);
116        break;
117    case PROP_LINK_URI:
118        g_free (priv->linkURI);
119        priv->linkURI = g_value_dup_string(value);
120        break;
121    case PROP_IMAGE_URI:
122        g_free (priv->imageURI);
123        priv->imageURI = g_value_dup_string(value);
124        break;
125    case PROP_MEDIA_URI:
126        g_free (priv->mediaURI);
127        priv->mediaURI = g_value_dup_string(value);
128        break;
129    case PROP_INNER_NODE:
130        priv->innerNode = static_cast<WebKitDOMNode*>(g_value_get_object(value));
131        break;
132    default:
133        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, pspec);
134    }
135}
136
137static void webkit_hit_test_result_class_init(WebKitHitTestResultClass* webHitTestResultClass)
138{
139    GObjectClass* objectClass = G_OBJECT_CLASS(webHitTestResultClass);
140
141    objectClass->finalize = webkit_hit_test_result_finalize;
142    objectClass->dispose = webkit_hit_test_result_dispose;
143    objectClass->get_property = webkit_hit_test_result_get_property;
144    objectClass->set_property = webkit_hit_test_result_set_property;
145
146    webkitInit();
147
148    /**
149     * WebKitHitTestResult:context:
150     *
151     * Flags indicating the kind of target that received the event.
152     *
153     * Since: 1.1.15
154     */
155    g_object_class_install_property(objectClass, PROP_CONTEXT,
156                                    g_param_spec_flags("context",
157                                                       _("Context"),
158                                                       _("Flags indicating the kind of target that received the event."),
159                                                       WEBKIT_TYPE_HIT_TEST_RESULT_CONTEXT,
160                                                       WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT,
161                                                       static_cast<GParamFlags>((WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY))));
162
163    /**
164     * WebKitHitTestResult:link-uri:
165     *
166     * The URI to which the target that received the event points, if any.
167     *
168     * Since: 1.1.15
169     */
170    g_object_class_install_property(objectClass, PROP_LINK_URI,
171                                    g_param_spec_string("link-uri",
172                                                        _("Link URI"),
173                                                        _("The URI to which the target that received the event points, if any."),
174                                                        NULL,
175                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
176
177    /**
178     * WebKitHitTestResult:image-uri:
179     *
180     * The URI of the image that is part of the target that received the event, if any.
181     *
182     * Since: 1.1.15
183     */
184    g_object_class_install_property(objectClass, PROP_IMAGE_URI,
185                                    g_param_spec_string("image-uri",
186                                                        _("Image URI"),
187                                                        _("The URI of the image that is part of the target that received the event, if any."),
188                                                        NULL,
189                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
190
191    /**
192     * WebKitHitTestResult:media-uri:
193     *
194     * The URI of the media that is part of the target that received the event, if any.
195     *
196     * Since: 1.1.15
197     */
198    g_object_class_install_property(objectClass, PROP_MEDIA_URI,
199                                    g_param_spec_string("media-uri",
200                                                        _("Media URI"),
201                                                        _("The URI of the media that is part of the target that received the event, if any."),
202                                                        NULL,
203                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
204
205    /**
206     * WebKitHitTestResult:inner-node:
207     *
208     * The DOM node at the coordinates where the hit test
209     * happened. Keep in mind that the node might not be
210     * representative of the information given in the context
211     * property, since WebKit uses a series of heuristics to figure
212     * out that information. One common example is inner-node having
213     * the text node inside the anchor (<a>) tag; WebKit knows the
214     * whole context and will put WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK
215     * in the 'context' property, but the user might be confused by
216     * the lack of any link tag in 'inner-node'.
217     *
218     * Since: 1.3.2
219     */
220    g_object_class_install_property(objectClass, PROP_INNER_NODE,
221                                    g_param_spec_object("inner-node",
222                                                        _("Inner node"),
223                                                        _("The inner DOM node associated with the hit test result."),
224                                                        WEBKIT_TYPE_DOM_NODE,
225                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
226
227    g_type_class_add_private(webHitTestResultClass, sizeof(WebKitHitTestResultPrivate));
228}
229
230static void webkit_hit_test_result_init(WebKitHitTestResult* web_hit_test_result)
231{
232    web_hit_test_result->priv = G_TYPE_INSTANCE_GET_PRIVATE(web_hit_test_result, WEBKIT_TYPE_HIT_TEST_RESULT, WebKitHitTestResultPrivate);
233}
234
235namespace WebKit {
236
237WebKitHitTestResult* kit(const WebCore::HitTestResult& result)
238{
239    guint context = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
240    GOwnPtr<char> linkURI(0);
241    GOwnPtr<char> imageURI(0);
242    GOwnPtr<char> mediaURI(0);
243    WebKitDOMNode* node = 0;
244
245    if (!result.absoluteLinkURL().isEmpty()) {
246        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK;
247        linkURI.set(g_strdup(result.absoluteLinkURL().string().utf8().data()));
248    }
249
250    if (!result.absoluteImageURL().isEmpty()) {
251        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE;
252        imageURI.set(g_strdup(result.absoluteImageURL().string().utf8().data()));
253    }
254
255    if (!result.absoluteMediaURL().isEmpty()) {
256        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA;
257        mediaURI.set(g_strdup(result.absoluteMediaURL().string().utf8().data()));
258    }
259
260    if (result.isSelected())
261        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION;
262
263    if (result.isContentEditable())
264        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE;
265
266    if (result.innerNonSharedNode())
267        node = kit(result.innerNonSharedNode());
268
269    return WEBKIT_HIT_TEST_RESULT(g_object_new(WEBKIT_TYPE_HIT_TEST_RESULT,
270                                               "link-uri", linkURI.get(),
271                                               "image-uri", imageURI.get(),
272                                               "media-uri", mediaURI.get(),
273                                               "context", context,
274                                               "inner-node", node,
275                                               NULL));
276}
277
278}
279