1/* 2 * Copyright (C) 2012 Igalia S.L. 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 "WebKitHitTestResult.h" 22 23#include "WebHitTestResult.h" 24#include "WebKitHitTestResultPrivate.h" 25#include <glib/gi18n-lib.h> 26#include <wtf/text/CString.h> 27 28using namespace WebKit; 29 30/** 31 * SECTION: WebKitHitTestResult 32 * @Short_description: Result of a Hit Test 33 * @Title: WebKitHitTestResult 34 * @See_also: #WebKitWebView 35 * 36 * A Hit Test is an operation to get context information about a given 37 * point in a #WebKitWebView. #WebKitHitTestResult represents the 38 * result of a Hit Test. It provides context information about what is 39 * at the coordinates of the Hit Test, such as if there's a link, 40 * an image or a media. 41 * 42 * You can get the context of the HitTestResult with 43 * webkit_hit_test_result_get_context() that returns a bitmask of 44 * #WebKitHitTestResultContext flags. You can also use 45 * webkit_hit_test_result_context_is_link(), webkit_hit_test_result_context_is_image() and 46 * webkit_hit_test_result_context_is_media() to determine whether there's 47 * a link, image or a media element at the coordinates of the Hit Test. 48 * Note that it's possible that several #WebKitHitTestResultContext flags 49 * are active at the same time, for example if there's a link containing an image. 50 * 51 * When the mouse is moved over a #WebKitWebView a Hit Test is performed 52 * for the mouse coordinates and #WebKitWebView::mouse-target-changed 53 * signal is emitted with a #WebKitHitTestResult. 54 * 55 */ 56 57enum { 58 PROP_0, 59 60 PROP_CONTEXT, 61 PROP_LINK_URI, 62 PROP_LINK_TITLE, 63 PROP_LINK_LABEL, 64 PROP_IMAGE_URI, 65 PROP_MEDIA_URI 66}; 67 68struct _WebKitHitTestResultPrivate { 69 unsigned int context; 70 CString linkURI; 71 CString linkTitle; 72 CString linkLabel; 73 CString imageURI; 74 CString mediaURI; 75}; 76 77WEBKIT_DEFINE_TYPE(WebKitHitTestResult, webkit_hit_test_result, G_TYPE_OBJECT) 78 79static void webkitHitTestResultGetProperty(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec) 80{ 81 WebKitHitTestResult* hitTestResult = WEBKIT_HIT_TEST_RESULT(object); 82 83 switch (propId) { 84 case PROP_CONTEXT: 85 g_value_set_uint(value, webkit_hit_test_result_get_context(hitTestResult)); 86 break; 87 case PROP_LINK_URI: 88 g_value_set_string(value, webkit_hit_test_result_get_link_uri(hitTestResult)); 89 break; 90 case PROP_LINK_TITLE: 91 g_value_set_string(value, webkit_hit_test_result_get_link_title(hitTestResult)); 92 break; 93 case PROP_LINK_LABEL: 94 g_value_set_string(value, webkit_hit_test_result_get_link_label(hitTestResult)); 95 break; 96 case PROP_IMAGE_URI: 97 g_value_set_string(value, webkit_hit_test_result_get_image_uri(hitTestResult)); 98 break; 99 case PROP_MEDIA_URI: 100 g_value_set_string(value, webkit_hit_test_result_get_media_uri(hitTestResult)); 101 break; 102 default: 103 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); 104 } 105} 106 107static void webkitHitTestResultSetProperty(GObject* object, guint propId, const GValue* value, GParamSpec* paramSpec) 108{ 109 WebKitHitTestResult* hitTestResult = WEBKIT_HIT_TEST_RESULT(object); 110 111 switch (propId) { 112 case PROP_CONTEXT: 113 hitTestResult->priv->context = g_value_get_uint(value); 114 break; 115 case PROP_LINK_URI: 116 hitTestResult->priv->linkURI = g_value_get_string(value); 117 break; 118 case PROP_LINK_TITLE: 119 hitTestResult->priv->linkTitle = g_value_get_string(value); 120 break; 121 case PROP_LINK_LABEL: 122 hitTestResult->priv->linkLabel = g_value_get_string(value); 123 break; 124 case PROP_IMAGE_URI: 125 hitTestResult->priv->imageURI = g_value_get_string(value); 126 break; 127 case PROP_MEDIA_URI: 128 hitTestResult->priv->mediaURI = g_value_get_string(value); 129 break; 130 default: 131 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); 132 } 133} 134 135static void webkit_hit_test_result_class_init(WebKitHitTestResultClass* hitTestResultClass) 136{ 137 GObjectClass* objectClass = G_OBJECT_CLASS(hitTestResultClass); 138 objectClass->get_property = webkitHitTestResultGetProperty; 139 objectClass->set_property = webkitHitTestResultSetProperty; 140 141 GParamFlags paramFlags = static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); 142 143 /** 144 * WebKitHitTestResult:context: 145 * 146 * Bitmask of #WebKitHitTestResultContext flags representing 147 * the context of the #WebKitHitTestResult. 148 */ 149 g_object_class_install_property(objectClass, 150 PROP_CONTEXT, 151 g_param_spec_uint("context", 152 _("Context"), 153 _("Flags with the context of the WebKitHitTestResult"), 154 0, G_MAXUINT, 0, 155 paramFlags)); 156 157 /** 158 * WebKitHitTestResult:link-uri: 159 * 160 * The URI of the link if flag %WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK 161 * is present in #WebKitHitTestResult:context 162 */ 163 g_object_class_install_property(objectClass, 164 PROP_LINK_URI, 165 g_param_spec_string("link-uri", 166 _("Link URI"), 167 _("The link URI"), 168 0, 169 paramFlags)); 170 /** 171 * WebKitHitTestResult:link-title: 172 * 173 * The title of the link if flag %WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK 174 * is present in #WebKitHitTestResult:context 175 */ 176 g_object_class_install_property(objectClass, 177 PROP_LINK_TITLE, 178 g_param_spec_string("link-title", 179 _("Link Title"), 180 _("The link title"), 181 0, 182 paramFlags)); 183 /** 184 * WebKitHitTestResult:link-label: 185 * 186 * The label of the link if flag %WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK 187 * is present in #WebKitHitTestResult:context 188 */ 189 g_object_class_install_property(objectClass, 190 PROP_LINK_LABEL, 191 g_param_spec_string("link-label", 192 _("Link Label"), 193 _("The link label"), 194 0, 195 paramFlags)); 196 /** 197 * WebKitHitTestResult:image-uri: 198 * 199 * The URI of the image if flag %WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE 200 * is present in #WebKitHitTestResult:context 201 */ 202 g_object_class_install_property(objectClass, 203 PROP_IMAGE_URI, 204 g_param_spec_string("image-uri", 205 _("Image URI"), 206 _("The image URI"), 207 0, 208 paramFlags)); 209 /** 210 * WebKitHitTestResult:media-uri: 211 * 212 * The URI of the media if flag %WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA 213 * is present in #WebKitHitTestResult:context 214 */ 215 g_object_class_install_property(objectClass, 216 PROP_MEDIA_URI, 217 g_param_spec_string("media-uri", 218 _("Media URI"), 219 _("The media URI"), 220 0, 221 paramFlags)); 222} 223 224WebKitHitTestResult* webkitHitTestResultCreate(WebHitTestResult* hitTestResult) 225{ 226 unsigned context = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT; 227 228 const String& linkURL = hitTestResult->absoluteLinkURL(); 229 if (!linkURL.isEmpty()) 230 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK; 231 232 const String& imageURL = hitTestResult->absoluteImageURL(); 233 if (!imageURL.isEmpty()) 234 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE; 235 236 const String& mediaURL = hitTestResult->absoluteMediaURL(); 237 if (!mediaURL.isEmpty()) 238 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA; 239 240 if (hitTestResult->isContentEditable()) 241 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE; 242 243 if (hitTestResult->isScrollbar()) 244 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR; 245 246 const String& linkTitle = hitTestResult->linkTitle(); 247 const String& linkLabel = hitTestResult->linkLabel(); 248 249 return WEBKIT_HIT_TEST_RESULT(g_object_new(WEBKIT_TYPE_HIT_TEST_RESULT, 250 "context", context, 251 "link-uri", !linkURL.isEmpty() ? linkURL.utf8().data() : 0, 252 "image-uri", !imageURL.isEmpty() ? imageURL.utf8().data() : 0, 253 "media-uri", !mediaURL.isEmpty() ? mediaURL.utf8().data() : 0, 254 "link-title", !linkTitle.isEmpty() ? linkTitle.utf8().data() : 0, 255 "link-label", !linkLabel.isEmpty() ? linkLabel.utf8().data() : 0, 256 NULL)); 257} 258 259static bool stringIsEqualToCString(const String& string, const CString& cString) 260{ 261 return ((string.isEmpty() && cString.isNull()) || (string.utf8() == cString)); 262} 263 264bool webkitHitTestResultCompare(WebKitHitTestResult* hitTestResult, WebHitTestResult* webHitTestResult) 265{ 266 WebKitHitTestResultPrivate* priv = hitTestResult->priv; 267 return webHitTestResult->isContentEditable() == webkit_hit_test_result_context_is_editable(hitTestResult) 268 && webHitTestResult->isScrollbar() == webkit_hit_test_result_context_is_scrollbar(hitTestResult) 269 && stringIsEqualToCString(webHitTestResult->absoluteLinkURL(), priv->linkURI) 270 && stringIsEqualToCString(webHitTestResult->linkTitle(), priv->linkTitle) 271 && stringIsEqualToCString(webHitTestResult->linkLabel(), priv->linkLabel) 272 && stringIsEqualToCString(webHitTestResult->absoluteImageURL(), priv->imageURI) 273 && stringIsEqualToCString(webHitTestResult->absoluteMediaURL(), priv->mediaURI); 274} 275 276/** 277 * webkit_hit_test_result_get_context: 278 * @hit_test_result: a #WebKitHitTestResult 279 * 280 * Gets the value of the #WebKitHitTestResult:context property. 281 * 282 * Returns: a bitmask of #WebKitHitTestResultContext flags 283 */ 284guint webkit_hit_test_result_get_context(WebKitHitTestResult* hitTestResult) 285{ 286 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 287 288 return hitTestResult->priv->context; 289} 290 291/** 292 * webkit_hit_test_result_context_is_link: 293 * @hit_test_result: a #WebKitHitTestResult 294 * 295 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK flag is present in 296 * #WebKitHitTestResult:context. 297 * 298 * Returns: %TRUE if there's a link element in the coordinates of the Hit Test, 299 * or %FALSE otherwise 300 */ 301gboolean webkit_hit_test_result_context_is_link(WebKitHitTestResult* hitTestResult) 302{ 303 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 304 305 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK; 306} 307 308/** 309 * webkit_hit_test_result_context_is_image: 310 * @hit_test_result: a #WebKitHitTestResult 311 * 312 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE flag is present in 313 * #WebKitHitTestResult:context. 314 * 315 * Returns: %TRUE if there's an image element in the coordinates of the Hit Test, 316 * or %FALSE otherwise 317 */ 318gboolean webkit_hit_test_result_context_is_image(WebKitHitTestResult* hitTestResult) 319{ 320 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 321 322 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE; 323} 324 325/** 326 * webkit_hit_test_result_context_is_media: 327 * @hit_test_result: a #WebKitHitTestResult 328 * 329 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA flag is present in 330 * #WebKitHitTestResult:context. 331 * 332 * Returns: %TRUE if there's a media element in the coordinates of the Hit Test, 333 * or %FALSE otherwise 334 */ 335gboolean webkit_hit_test_result_context_is_media(WebKitHitTestResult* hitTestResult) 336{ 337 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 338 339 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA; 340} 341 342/** 343 * webkit_hit_test_result_context_is_editable: 344 * @hit_test_result: a #WebKitHitTestResult 345 * 346 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE flag is present in 347 * #WebKitHitTestResult:context. 348 * 349 * Returns: %TRUE if there's an editable element at the coordinates of the @hit_test_result, 350 * or %FALSE otherwise 351 */ 352gboolean webkit_hit_test_result_context_is_editable(WebKitHitTestResult* hitTestResult) 353{ 354 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 355 356 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE; 357} 358 359/** 360 * webkit_hit_test_result_get_link_uri: 361 * @hit_test_result: a #WebKitHitTestResult 362 * 363 * Gets the value of the #WebKitHitTestResult:link-uri property. 364 * 365 * Returns: the URI of the link element in the coordinates of the Hit Test, 366 * or %NULL if there ins't a link element in @hit_test_result context 367 */ 368const gchar* webkit_hit_test_result_get_link_uri(WebKitHitTestResult* hitTestResult) 369{ 370 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 371 372 return hitTestResult->priv->linkURI.data(); 373} 374 375/** 376 * webkit_hit_test_result_get_link_title: 377 * @hit_test_result: a #WebKitHitTestResult 378 * 379 * Gets the value of the #WebKitHitTestResult:link-title property. 380 * 381 * Returns: the title of the link element in the coordinates of the Hit Test, 382 * or %NULL if there ins't a link element in @hit_test_result context or the 383 * link element doesn't have a title 384 */ 385const gchar* webkit_hit_test_result_get_link_title(WebKitHitTestResult* hitTestResult) 386{ 387 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 388 389 return hitTestResult->priv->linkTitle.data(); 390} 391 392/** 393 * webkit_hit_test_result_get_link_label: 394 * @hit_test_result: a #WebKitHitTestResult 395 * 396 * Gets the value of the #WebKitHitTestResult:link-label property. 397 * 398 * Returns: the label of the link element in the coordinates of the Hit Test, 399 * or %NULL if there ins't a link element in @hit_test_result context or the 400 * link element doesn't have a label 401 */ 402const gchar* webkit_hit_test_result_get_link_label(WebKitHitTestResult* hitTestResult) 403{ 404 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 405 406 return hitTestResult->priv->linkLabel.data(); 407} 408 409/** 410 * webkit_hit_test_result_get_image_uri: 411 * @hit_test_result: a #WebKitHitTestResult 412 * 413 * Gets the value of the #WebKitHitTestResult:image-uri property. 414 * 415 * Returns: the URI of the image element in the coordinates of the Hit Test, 416 * or %NULL if there ins't an image element in @hit_test_result context 417 */ 418const gchar* webkit_hit_test_result_get_image_uri(WebKitHitTestResult* hitTestResult) 419{ 420 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 421 422 return hitTestResult->priv->imageURI.data(); 423} 424 425/** 426 * webkit_hit_test_result_get_media_uri: 427 * @hit_test_result: a #WebKitHitTestResult 428 * 429 * Gets the value of the #WebKitHitTestResult:media-uri property. 430 * 431 * Returns: the URI of the media element in the coordinates of the Hit Test, 432 * or %NULL if there ins't a media element in @hit_test_result context 433 */ 434const gchar* webkit_hit_test_result_get_media_uri(WebKitHitTestResult* hitTestResult) 435{ 436 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 437 438 return hitTestResult->priv->mediaURI.data(); 439} 440 441/** 442 * webkit_hit_test_result_context_is_scrollbar: 443 * @hit_test_result: a #WebKitHitTestResult 444 * 445 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR flag is present in 446 * #WebKitHitTestResult:context. 447 * 448 * Returns: %TRUE if there's a scrollbar element at the coordinates of the @hit_test_result, 449 * or %FALSE otherwise 450 */ 451gboolean webkit_hit_test_result_context_is_scrollbar(WebKitHitTestResult* hitTestResult) 452{ 453 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 454 455 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR; 456} 457