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(const WebHitTestResult::Data& hitTestResult) 225{ 226 unsigned context = WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT; 227 228 if (!hitTestResult.absoluteLinkURL.isEmpty()) 229 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK; 230 231 if (!hitTestResult.absoluteImageURL.isEmpty()) 232 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE; 233 234 if (!hitTestResult.absoluteMediaURL.isEmpty()) 235 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA; 236 237 if (hitTestResult.isContentEditable) 238 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE; 239 240 if (hitTestResult.isScrollbar) 241 context |= WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR; 242 243 return WEBKIT_HIT_TEST_RESULT(g_object_new(WEBKIT_TYPE_HIT_TEST_RESULT, 244 "context", context, 245 "link-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK ? hitTestResult.absoluteLinkURL.utf8().data() : nullptr, 246 "image-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE ? hitTestResult.absoluteImageURL.utf8().data() : nullptr, 247 "media-uri", context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA ? hitTestResult.absoluteMediaURL.utf8().data() : nullptr, 248 "link-title", !hitTestResult.linkTitle.isEmpty() ? hitTestResult.linkTitle.utf8().data() : nullptr, 249 "link-label", !hitTestResult.linkLabel.isEmpty() ? hitTestResult.linkLabel.utf8().data() : nullptr, 250 nullptr)); 251} 252 253static bool stringIsEqualToCString(const String& string, const CString& cString) 254{ 255 return ((string.isEmpty() && cString.isNull()) || (string.utf8() == cString)); 256} 257 258bool webkitHitTestResultCompare(WebKitHitTestResult* hitTestResult, const WebHitTestResult::Data& webHitTestResult) 259{ 260 WebKitHitTestResultPrivate* priv = hitTestResult->priv; 261 return webHitTestResult.isContentEditable == webkit_hit_test_result_context_is_editable(hitTestResult) 262 && webHitTestResult.isScrollbar == webkit_hit_test_result_context_is_scrollbar(hitTestResult) 263 && stringIsEqualToCString(webHitTestResult.absoluteLinkURL, priv->linkURI) 264 && stringIsEqualToCString(webHitTestResult.linkTitle, priv->linkTitle) 265 && stringIsEqualToCString(webHitTestResult.linkLabel, priv->linkLabel) 266 && stringIsEqualToCString(webHitTestResult.absoluteImageURL, priv->imageURI) 267 && stringIsEqualToCString(webHitTestResult.absoluteMediaURL, priv->mediaURI); 268} 269 270/** 271 * webkit_hit_test_result_get_context: 272 * @hit_test_result: a #WebKitHitTestResult 273 * 274 * Gets the value of the #WebKitHitTestResult:context property. 275 * 276 * Returns: a bitmask of #WebKitHitTestResultContext flags 277 */ 278guint webkit_hit_test_result_get_context(WebKitHitTestResult* hitTestResult) 279{ 280 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 281 282 return hitTestResult->priv->context; 283} 284 285/** 286 * webkit_hit_test_result_context_is_link: 287 * @hit_test_result: a #WebKitHitTestResult 288 * 289 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK flag is present in 290 * #WebKitHitTestResult:context. 291 * 292 * Returns: %TRUE if there's a link element in the coordinates of the Hit Test, 293 * or %FALSE otherwise 294 */ 295gboolean webkit_hit_test_result_context_is_link(WebKitHitTestResult* hitTestResult) 296{ 297 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 298 299 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK; 300} 301 302/** 303 * webkit_hit_test_result_context_is_image: 304 * @hit_test_result: a #WebKitHitTestResult 305 * 306 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE flag is present in 307 * #WebKitHitTestResult:context. 308 * 309 * Returns: %TRUE if there's an image element in the coordinates of the Hit Test, 310 * or %FALSE otherwise 311 */ 312gboolean webkit_hit_test_result_context_is_image(WebKitHitTestResult* hitTestResult) 313{ 314 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 315 316 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_IMAGE; 317} 318 319/** 320 * webkit_hit_test_result_context_is_media: 321 * @hit_test_result: a #WebKitHitTestResult 322 * 323 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA flag is present in 324 * #WebKitHitTestResult:context. 325 * 326 * Returns: %TRUE if there's a media element in the coordinates of the Hit Test, 327 * or %FALSE otherwise 328 */ 329gboolean webkit_hit_test_result_context_is_media(WebKitHitTestResult* hitTestResult) 330{ 331 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 332 333 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_MEDIA; 334} 335 336/** 337 * webkit_hit_test_result_context_is_editable: 338 * @hit_test_result: a #WebKitHitTestResult 339 * 340 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE flag is present in 341 * #WebKitHitTestResult:context. 342 * 343 * Returns: %TRUE if there's an editable element at the coordinates of the @hit_test_result, 344 * or %FALSE otherwise 345 */ 346gboolean webkit_hit_test_result_context_is_editable(WebKitHitTestResult* hitTestResult) 347{ 348 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 349 350 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE; 351} 352 353/** 354 * webkit_hit_test_result_get_link_uri: 355 * @hit_test_result: a #WebKitHitTestResult 356 * 357 * Gets the value of the #WebKitHitTestResult:link-uri property. 358 * 359 * Returns: the URI of the link element in the coordinates of the Hit Test, 360 * or %NULL if there ins't a link element in @hit_test_result context 361 */ 362const gchar* webkit_hit_test_result_get_link_uri(WebKitHitTestResult* hitTestResult) 363{ 364 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 365 366 return hitTestResult->priv->linkURI.data(); 367} 368 369/** 370 * webkit_hit_test_result_get_link_title: 371 * @hit_test_result: a #WebKitHitTestResult 372 * 373 * Gets the value of the #WebKitHitTestResult:link-title property. 374 * 375 * Returns: the title of the link element in the coordinates of the Hit Test, 376 * or %NULL if there ins't a link element in @hit_test_result context or the 377 * link element doesn't have a title 378 */ 379const gchar* webkit_hit_test_result_get_link_title(WebKitHitTestResult* hitTestResult) 380{ 381 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 382 383 return hitTestResult->priv->linkTitle.data(); 384} 385 386/** 387 * webkit_hit_test_result_get_link_label: 388 * @hit_test_result: a #WebKitHitTestResult 389 * 390 * Gets the value of the #WebKitHitTestResult:link-label property. 391 * 392 * Returns: the label of the link element in the coordinates of the Hit Test, 393 * or %NULL if there ins't a link element in @hit_test_result context or the 394 * link element doesn't have a label 395 */ 396const gchar* webkit_hit_test_result_get_link_label(WebKitHitTestResult* hitTestResult) 397{ 398 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 399 400 return hitTestResult->priv->linkLabel.data(); 401} 402 403/** 404 * webkit_hit_test_result_get_image_uri: 405 * @hit_test_result: a #WebKitHitTestResult 406 * 407 * Gets the value of the #WebKitHitTestResult:image-uri property. 408 * 409 * Returns: the URI of the image element in the coordinates of the Hit Test, 410 * or %NULL if there ins't an image element in @hit_test_result context 411 */ 412const gchar* webkit_hit_test_result_get_image_uri(WebKitHitTestResult* hitTestResult) 413{ 414 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 415 416 return hitTestResult->priv->imageURI.data(); 417} 418 419/** 420 * webkit_hit_test_result_get_media_uri: 421 * @hit_test_result: a #WebKitHitTestResult 422 * 423 * Gets the value of the #WebKitHitTestResult:media-uri property. 424 * 425 * Returns: the URI of the media element in the coordinates of the Hit Test, 426 * or %NULL if there ins't a media element in @hit_test_result context 427 */ 428const gchar* webkit_hit_test_result_get_media_uri(WebKitHitTestResult* hitTestResult) 429{ 430 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), 0); 431 432 return hitTestResult->priv->mediaURI.data(); 433} 434 435/** 436 * webkit_hit_test_result_context_is_scrollbar: 437 * @hit_test_result: a #WebKitHitTestResult 438 * 439 * Gets whether %WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR flag is present in 440 * #WebKitHitTestResult:context. 441 * 442 * Returns: %TRUE if there's a scrollbar element at the coordinates of the @hit_test_result, 443 * or %FALSE otherwise 444 */ 445gboolean webkit_hit_test_result_context_is_scrollbar(WebKitHitTestResult* hitTestResult) 446{ 447 g_return_val_if_fail(WEBKIT_IS_HIT_TEST_RESULT(hitTestResult), FALSE); 448 449 return hitTestResult->priv->context & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR; 450} 451