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 "Frame.h"
25#include "FrameView.h"
26#include "HitTestResult.h"
27#include "KURL.h"
28#include "WebKitDOMNodePrivate.h"
29#include "webkitenumtypes.h"
30#include "webkitglobals.h"
31#include "webkitglobalsprivate.h"
32#include <glib/gi18n-lib.h>
33#include <wtf/gobject/GOwnPtr.h>
34#include <wtf/gobject/GRefPtr.h>
35#include <wtf/text/CString.h>
36
37/**
38 * SECTION:webkithittestresult
39 * @short_description: The target of a mouse event
40 *
41 * This class holds context information about the coordinates
42 * specified by a GDK event.
43 */
44
45G_DEFINE_TYPE(WebKitHitTestResult, webkit_hit_test_result, G_TYPE_OBJECT)
46
47struct _WebKitHitTestResultPrivate {
48    guint context;
49    char* linkURI;
50    char* imageURI;
51    char* mediaURI;
52    GRefPtr<WebKitDOMNode> innerNode;
53    WebCore::IntPoint position;
54};
55
56enum {
57    PROP_0,
58
59    PROP_CONTEXT,
60    PROP_LINK_URI,
61    PROP_IMAGE_URI,
62    PROP_MEDIA_URI,
63    PROP_INNER_NODE,
64    PROP_X,
65    PROP_Y
66};
67
68static void webkit_hit_test_result_finalize(GObject* object)
69{
70    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
71    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
72
73    g_free(priv->linkURI);
74    g_free(priv->imageURI);
75    g_free(priv->mediaURI);
76
77    G_OBJECT_CLASS(webkit_hit_test_result_parent_class)->finalize(object);
78}
79
80static void webkit_hit_test_result_dispose(GObject* object)
81{
82    WEBKIT_HIT_TEST_RESULT(object)->priv->~WebKitHitTestResultPrivate();
83
84    G_OBJECT_CLASS(webkit_hit_test_result_parent_class)->dispose(object);
85}
86
87static void webkit_hit_test_result_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* pspec)
88{
89    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
90    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
91
92    switch(propertyID) {
93    case PROP_CONTEXT:
94        g_value_set_flags(value, priv->context);
95        break;
96    case PROP_LINK_URI:
97        g_value_set_string(value, priv->linkURI);
98        break;
99    case PROP_IMAGE_URI:
100        g_value_set_string(value, priv->imageURI);
101        break;
102    case PROP_MEDIA_URI:
103        g_value_set_string(value, priv->mediaURI);
104        break;
105    case PROP_INNER_NODE:
106        g_value_set_object(value, priv->innerNode.get());
107        break;
108    case PROP_X:
109        g_value_set_int(value, priv->position.x());
110        break;
111    case PROP_Y:
112        g_value_set_int(value, priv->position.y());
113        break;
114    default:
115        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, pspec);
116    }
117}
118
119static void webkit_hit_test_result_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* pspec)
120{
121    WebKitHitTestResult* web_hit_test_result = WEBKIT_HIT_TEST_RESULT(object);
122    WebKitHitTestResultPrivate* priv = web_hit_test_result->priv;
123
124    switch(propertyID) {
125    case PROP_CONTEXT:
126        priv->context = g_value_get_flags(value);
127        break;
128    case PROP_LINK_URI:
129        g_free (priv->linkURI);
130        priv->linkURI = g_value_dup_string(value);
131        break;
132    case PROP_IMAGE_URI:
133        g_free (priv->imageURI);
134        priv->imageURI = g_value_dup_string(value);
135        break;
136    case PROP_MEDIA_URI:
137        g_free (priv->mediaURI);
138        priv->mediaURI = g_value_dup_string(value);
139        break;
140    case PROP_INNER_NODE:
141        priv->innerNode = static_cast<WebKitDOMNode*>(g_value_get_object(value));
142        break;
143    case PROP_X:
144        priv->position.setX(g_value_get_int(value));
145        break;
146    case PROP_Y:
147        priv->position.setY(g_value_get_int(value));
148        break;
149    default:
150        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, pspec);
151    }
152}
153
154static void webkit_hit_test_result_class_init(WebKitHitTestResultClass* webHitTestResultClass)
155{
156    GObjectClass* objectClass = G_OBJECT_CLASS(webHitTestResultClass);
157
158    objectClass->finalize = webkit_hit_test_result_finalize;
159    objectClass->dispose = webkit_hit_test_result_dispose;
160    objectClass->get_property = webkit_hit_test_result_get_property;
161    objectClass->set_property = webkit_hit_test_result_set_property;
162
163    webkitInit();
164
165    /**
166     * WebKitHitTestResult:context:
167     *
168     * Flags indicating the kind of target that received the event.
169     *
170     * Since: 1.1.15
171     */
172    g_object_class_install_property(objectClass, PROP_CONTEXT,
173                                    g_param_spec_flags("context",
174                                                       _("Context"),
175                                                       _("Flags indicating the kind of target that received the event."),
176                                                       WEBKIT_TYPE_HIT_TEST_RESULT_CONTEXT,
177                                                       WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT,
178                                                       static_cast<GParamFlags>((WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY))));
179
180    /**
181     * WebKitHitTestResult:link-uri:
182     *
183     * The URI to which the target that received the event points, if any.
184     *
185     * Since: 1.1.15
186     */
187    g_object_class_install_property(objectClass, PROP_LINK_URI,
188                                    g_param_spec_string("link-uri",
189                                                        _("Link URI"),
190                                                        _("The URI to which the target that received the event points, if any."),
191                                                        NULL,
192                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
193
194    /**
195     * WebKitHitTestResult:image-uri:
196     *
197     * The URI of the image that is part of the target that received the event, if any.
198     *
199     * Since: 1.1.15
200     */
201    g_object_class_install_property(objectClass, PROP_IMAGE_URI,
202                                    g_param_spec_string("image-uri",
203                                                        _("Image URI"),
204                                                        _("The URI of the image that is part of the target that received the event, if any."),
205                                                        NULL,
206                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
207
208    /**
209     * WebKitHitTestResult:media-uri:
210     *
211     * The URI of the media that is part of the target that received the event, if any.
212     *
213     * Since: 1.1.15
214     */
215    g_object_class_install_property(objectClass, PROP_MEDIA_URI,
216                                    g_param_spec_string("media-uri",
217                                                        _("Media URI"),
218                                                        _("The URI of the media that is part of the target that received the event, if any."),
219                                                        NULL,
220                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY)));
221
222    /**
223     * WebKitHitTestResult:inner-node:
224     *
225     * The DOM node at the coordinates where the hit test
226     * happened. Keep in mind that the node might not be
227     * representative of the information given in the context
228     * property, since WebKit uses a series of heuristics to figure
229     * out that information. One common example is inner-node having
230     * the text node inside the anchor (&lt;a&gt;) tag; WebKit knows the
231     * whole context and will put WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK
232     * in the 'context' property, but the user might be confused by
233     * the lack of any link tag in 'inner-node'.
234     *
235     * Since: 1.3.2
236     */
237    g_object_class_install_property(objectClass, PROP_INNER_NODE,
238                                    g_param_spec_object("inner-node",
239                                                        _("Inner node"),
240                                                        _("The inner DOM node associated with the hit test result."),
241                                                        WEBKIT_TYPE_DOM_NODE,
242                                                        static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
243
244    /**
245     * WebKitHitTestResult:x:
246     *
247     * The x coordinate of the event relative to the view's window.
248     *
249     * Since: 1.10
250     */
251    g_object_class_install_property(objectClass, PROP_X,
252                                    g_param_spec_int("x",
253                                                     _("X coordinate"),
254                                                     _("The x coordinate of the event relative to the view's window."),
255                                                     G_MININT, G_MAXINT, 0,
256                                                     static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
257
258    /**
259     * WebKitHitTestResult:y:
260     *
261     * The x coordinate of the event relative to the view's window.
262     *
263     * Since: 1.10
264     */
265    g_object_class_install_property(objectClass, PROP_Y,
266                                    g_param_spec_int("y",
267                                                     _("Y coordinate"),
268                                                     _("The y coordinate of the event relative to the view's window."),
269                                                     G_MININT, G_MAXINT, 0,
270                                                     static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
271
272    g_type_class_add_private(webHitTestResultClass, sizeof(WebKitHitTestResultPrivate));
273}
274
275static void webkit_hit_test_result_init(WebKitHitTestResult* web_hit_test_result)
276{
277    web_hit_test_result->priv = G_TYPE_INSTANCE_GET_PRIVATE(web_hit_test_result, WEBKIT_TYPE_HIT_TEST_RESULT, WebKitHitTestResultPrivate);
278    new (web_hit_test_result->priv) WebKitHitTestResultPrivate();
279}
280
281namespace WebKit {
282
283WebKitHitTestResult* kit(const WebCore::HitTestResult& result)
284{
285    guint context = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT;
286    GOwnPtr<char> linkURI(0);
287    GOwnPtr<char> imageURI(0);
288    GOwnPtr<char> mediaURI(0);
289    WebKitDOMNode* node = 0;
290    WebCore::Frame* innerNodeFrame;
291    WebCore::IntPoint point;
292
293    if (!result.absoluteLinkURL().isEmpty()) {
294        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK;
295        linkURI.set(g_strdup(result.absoluteLinkURL().string().utf8().data()));
296    }
297
298    if (!result.absoluteImageURL().isEmpty()) {
299        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE;
300        imageURI.set(g_strdup(result.absoluteImageURL().string().utf8().data()));
301    }
302
303    if (!result.absoluteMediaURL().isEmpty()) {
304        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA;
305        mediaURI.set(g_strdup(result.absoluteMediaURL().string().utf8().data()));
306    }
307
308    if (result.isSelected())
309        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION;
310
311    if (result.isContentEditable())
312        context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE;
313
314    if (result.innerNonSharedNode())
315        node = kit(result.innerNonSharedNode());
316
317    innerNodeFrame = result.innerNodeFrame();
318    if (innerNodeFrame && innerNodeFrame->view()) {
319        // Convert document coords to widget coords.
320        point = innerNodeFrame->view()->contentsToWindow(result.roundedPointInInnerNodeFrame());
321    } else {
322        // FIXME: Main frame coords is not the same as window coords,
323        // but we do not have pointer to  mainframe view here.
324        point = result.roundedPointInMainFrame();
325    }
326
327    return WEBKIT_HIT_TEST_RESULT(g_object_new(WEBKIT_TYPE_HIT_TEST_RESULT,
328                                               "link-uri", linkURI.get(),
329                                               "image-uri", imageURI.get(),
330                                               "media-uri", mediaURI.get(),
331                                               "context", context,
332                                               "inner-node", node,
333                                               "x", point.x(),
334                                               "y", point.y(),
335                                               NULL));
336}
337
338}
339