1 /* 2 * Copyright (C) 2010 Joone Hur <joone (at) kldp.org> 3 * Copyright (C) 2010 Collabora Ltd. 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 "webkitviewportattributes.h" 23 24 #include "Chrome.h" 25 #include "Frame.h" 26 #include "Page.h" 27 #include "webkitglobalsprivate.h" 28 #include "webkitviewportattributesprivate.h" 29 #include "webkitwebviewprivate.h" 30 #include <glib/gi18n-lib.h> 31 32 /** 33 * SECTION:webkitviewportattributes 34 * @short_description: Represents the viewport properties of a web page 35 * @see_also: #WebKitWebView::viewport-attributes-recompute-requested 36 * @see_also: #WebKitWebView::viewport-attributes-changed 37 * 38 * #WebKitViewportAttributes offers the viewport properties to user agents to 39 * control the viewport layout. It contains the viewport size, initial scale with limits, 40 * and information about whether a user is able to scale the contents in the viewport. 41 * This makes a web page fit the device screen. 42 * 43 * The #WebKitWebView::viewport-attributes-changed signal will be emitted with #WebKitViewportAttributes 44 * when the viewport attributes are updated in the case of loading web pages contain 45 * the viewport properties and calling webkit_viewport_attributes_recompute. 46 * 47 * If the device size, available size, desktop width, or device DPI needs to be changed due to 48 * a consequence of an explicit browser request (caused by screen rotation, resizing, or similar reasons), 49 * You should call #webkit_viewport_attributes_recompute to recompute the viewport properties and 50 * override those values in the handler of #WebKitWebView::viewport-attributes-recompute-requested signal. 51 * 52 * For more information on the viewport properties, refer to the Safari reference library at 53 * http://developer.apple.com/safari/library/documentation/appleapplications/reference/safarihtmlref/articles/metatags.html 54 * 55 * <informalexample><programlisting> 56 * /<!-- -->* Connect to the viewport-attributes-changes signal *<!-- -->/ 57 * WebKitViewportAttributes* attributes = webkit_web_view_get_viewport_attributes (web_view); 58 * g_signal_connect (web_view, "viewport-attributes-recompute-requested", G_CALLBACK (viewport_recompute_cb), window); 59 * g_signal_connect (web_view, "viewport-attributes-changed", G_CALLBACK (viewport_changed_cb), window); 60 * g_signal_connect (attributes, "notify::valid", G_CALLBACK (viewport_valid_changed_cb), web_view); 61 * 62 * /<!-- -->* Handle the viewport-attributes-recompute-requested signal to override the device width *<!-- -->/ 63 * static void 64 * viewport_recompute_cb (WebKitWebView* web_view, WebKitViewportAttributes* attributes, GtkWidget* window) 65 * { 66 * int override_available_width = 480; 67 * g_object_set (G_OBJECT(attributes), "available-width", override_available_width, NULL); 68 * } 69 * 70 * /<!-- -->* Handle the viewport-attributes-changed signal to recompute the initial scale factor *<!-- -->/ 71 * static void 72 * viewport_changed_cb (WebKitWebView* web_view, WebKitViewportAttributes* attributes, gpointer data) 73 * { 74 * gfloat initialScale; 75 * g_object_get (G_OBJECT (atributes), "initial-scale-factor", &initialScale, NULL); 76 * webkit_web_view_set_zoom_level (web_view, initialScale); 77 * } 78 * 79 * /<!-- -->* Handle the notify::valid signal to initialize the zoom level *<!-- -->/ 80 * static void 81 * viewport_valid_changed_cb (WebKitViewportAttributes* attributes, GParamSpec* pspec, WebKitWebView* web_view) 82 * { 83 * gboolean is_valid; 84 * g_object_get (attributes, "valid", &is_valid, NULL); 85 * if (!is_valid) 86 * webkit_web_view_set_zoom_level (web_view, 1.0); 87 * } 88 * </programlisting></informalexample> 89 */ 90 91 using namespace WebKit; 92 using namespace WebCore; 93 94 enum { 95 PROP_0, 96 97 PROP_DEVICE_WIDTH, 98 PROP_DEVICE_HEIGHT, 99 PROP_AVAILABLE_WIDTH, 100 PROP_AVAILABLE_HEIGHT, 101 PROP_DESKTOP_WIDTH, 102 PROP_DEVICE_DPI, 103 PROP_WIDTH, 104 PROP_HEIGHT, 105 PROP_INITIAL_SCALE_FACTOR, 106 PROP_MINIMUM_SCALE_FACTOR, 107 PROP_MAXIMUM_SCALE_FACTOR, 108 PROP_DEVICE_PIXEL_RATIO, 109 PROP_USER_SCALABLE, 110 PROP_VALID 111 }; 112 113 G_DEFINE_TYPE(WebKitViewportAttributes, webkit_viewport_attributes, G_TYPE_OBJECT); 114 115 static void webkit_viewport_attributes_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* paramSpec); 116 static void webkit_viewport_attributes_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* paramSpec); 117 118 static void webkit_viewport_attributes_class_init(WebKitViewportAttributesClass* kclass) 119 { 120 GObjectClass* gobjectClass = G_OBJECT_CLASS(kclass); 121 gobjectClass->get_property = webkit_viewport_attributes_get_property; 122 gobjectClass->set_property = webkit_viewport_attributes_set_property; 123 124 /** 125 * WebKitViewportAttributs:device-width: 126 * 127 * The width of the screen. This value is always automatically 128 * pre-computed during a viewport attributes recomputation, and 129 * can be overridden by the handler of 130 * WebKitWebView::viewport-attributes-recompute-requested. You 131 * should not do that unless you have a very good reason. 132 * 133 * Since: 1.3.8 134 */ 135 g_object_class_install_property(gobjectClass, 136 PROP_DEVICE_WIDTH, 137 g_param_spec_int( 138 "device-width", 139 _("Device Width"), 140 _("The width of the screen."), 141 0, 142 G_MAXINT, 143 0, 144 WEBKIT_PARAM_READWRITE)); 145 146 /** 147 * WebKitViewportAttributs:device-height: 148 * 149 * The height of the screen. This value is always automatically 150 * pre-computed during a viewport attributes recomputation, and 151 * can be overriden by the handler of 152 * WebKitWebView::viewport-attributes-recompute-requested. You 153 * should not do that unless you have a very good reason. 154 * 155 * Since: 1.3.8 156 */ 157 g_object_class_install_property(gobjectClass, 158 PROP_DEVICE_HEIGHT, 159 g_param_spec_int( 160 "device-height", 161 _("Device Height"), 162 _("The height of the screen."), 163 0, 164 G_MAXINT, 165 0, 166 WEBKIT_PARAM_READWRITE)); 167 168 /** 169 * WebKitViewportAttributs:available-width: 170 * 171 * The width of the current visible area. This will usually be the 172 * same as the space allocated to the widget, but in some cases 173 * you may have decided to make the widget bigger than the visible 174 * area. This value is by default initialized to the size 175 * allocated by the widget, but you can override it in the handler 176 * of WebKitWebView::viewport-attributes-recompute-requested to 177 * let the engine know what the visible area is. 178 * 179 * Since: 1.3.8 180 */ 181 g_object_class_install_property(gobjectClass, 182 PROP_AVAILABLE_WIDTH, 183 g_param_spec_int( 184 "available-width", 185 _("Available Width"), 186 _("The width of the visible area."), 187 0, 188 G_MAXINT, 189 0, 190 WEBKIT_PARAM_READWRITE)); 191 192 /** 193 * WebKitViewportAttributs:available-height: 194 * 195 * The height of the current visible area. This will usually be the 196 * same as the space allocated to the widget, but in some cases 197 * you may have decided to make the widget bigger than the visible 198 * area. This value is by default initialized to the size 199 * allocated by the widget, but you can override it in the handler 200 * of WebKitWebView::viewport-attributes-recompute-requested to 201 * let the engine know what the visible area is. 202 * 203 * Since: 1.3.8 204 */ 205 g_object_class_install_property(gobjectClass, 206 PROP_AVAILABLE_HEIGHT, 207 g_param_spec_int( 208 "available-height", 209 _("Available Height"), 210 _("The height of the visible area."), 211 0, 212 G_MAXINT, 213 0, 214 WEBKIT_PARAM_READWRITE)); 215 216 /** 217 * WebKitViewportAttributs:desktop-width: 218 * 219 * The width of viewport that works well for most web pages designed for 220 * desktop. This value is initialized to 980 pixels by default and used 221 * during a viewport attributes recomputation. Also, it can be overriden by 222 * the handler of WebKitWebView::viewport-attributes-recompute-requested. 223 * You should not do that unless you have a very good reason. 224 * 225 * Since: 1.3.8 226 */ 227 g_object_class_install_property(gobjectClass, 228 PROP_DESKTOP_WIDTH, 229 g_param_spec_int( 230 "desktop-width", 231 _("Desktop Width"), 232 _("The width of viewport that works well for most web pages designed for desktop."), 233 0, 234 G_MAXINT, 235 980, 236 WEBKIT_PARAM_READWRITE)); 237 238 /** 239 * WebKitViewportAttributs:device-dpi: 240 * 241 * The number of dots per inch of the screen. This value is 242 * initialized to 160 dpi by default and used during a viewport 243 * attributes recomputation, because it is the dpi of the original 244 * iPhone and Android devices. Also, it can be overriden by the 245 * handler of WebKitWebView::viewport-attributes-recompute-requested. 246 * You should not do that unless you have a very good reason. 247 * 248 * Since: 1.3.8 249 */ 250 g_object_class_install_property(gobjectClass, 251 PROP_DEVICE_DPI, 252 g_param_spec_int( 253 "device-dpi", 254 _("Device DPI"), 255 _("The number of dots per inch of the screen."), 256 0, 257 G_MAXINT, 258 160, 259 WEBKIT_PARAM_READWRITE)); 260 261 /** 262 * WebKitViewportAttributs:width: 263 * 264 * The width of the viewport. Before getting this property, 265 * you need to make sure that #WebKitViewportAttributes is valid. 266 * 267 * Since: 1.3.8 268 */ 269 g_object_class_install_property(gobjectClass, 270 PROP_WIDTH, 271 g_param_spec_int( 272 "width", 273 _("Width"), 274 _("The width of the viewport."), 275 0, 276 G_MAXINT, 277 0, 278 WEBKIT_PARAM_READABLE)); 279 280 /** 281 * WebKitViewportAttributs:height: 282 * 283 * The height of the viewport. Before getting this property, 284 * you need to make sure that #WebKitViewportAttributes is valid. 285 * 286 * Since: 1.3.8 287 */ 288 g_object_class_install_property(gobjectClass, 289 PROP_HEIGHT, 290 g_param_spec_int( 291 "height", 292 _("Height"), 293 _("The height of the viewport."), 294 0, 295 G_MAXINT, 296 0, 297 WEBKIT_PARAM_READABLE)); 298 299 /** 300 * WebKitViewportAttributs:initial-scale-factor: 301 * 302 * The initial scale of the viewport. Before getting this property, 303 * you need to make sure that #WebKitViewportAttributes is valid. 304 * 305 * Since: 1.3.8 306 */ 307 g_object_class_install_property(gobjectClass, 308 PROP_INITIAL_SCALE_FACTOR, 309 g_param_spec_float( 310 "initial-scale-factor", 311 _("Initial Scale Factor"), 312 _("The initial scale of the viewport."), 313 -1, 314 G_MAXFLOAT, 315 -1, 316 WEBKIT_PARAM_READABLE)); 317 318 /** 319 * WebKitViewportAttributs:minimum-scale-factor: 320 * 321 * The minimum scale of the viewport. Before getting this property, 322 * you need to make sure that #WebKitViewportAttributes is valid. 323 * 324 * Since: 1.3.8 325 */ 326 g_object_class_install_property(gobjectClass, 327 PROP_MINIMUM_SCALE_FACTOR, 328 g_param_spec_float( 329 "minimum-scale-factor", 330 _("Minimum Scale Factor"), 331 _("The minimum scale of the viewport."), 332 -1, 333 G_MAXFLOAT, 334 -1, 335 WEBKIT_PARAM_READABLE)); 336 337 /** 338 * WebKitViewportAttributs:maximum-scale-factor: 339 * 340 * The maximum scale of the viewport. Before getting this property, 341 * you need to make sure that #WebKitViewportAttributes is valid. 342 * 343 * Since: 1.3.8 344 */ 345 g_object_class_install_property(gobjectClass, 346 PROP_MAXIMUM_SCALE_FACTOR, 347 g_param_spec_float( 348 "maximum-scale-factor", 349 _("Maximum Scale Factor"), 350 _("The maximum scale of the viewport."), 351 -1, 352 G_MAXFLOAT, 353 -1, 354 WEBKIT_PARAM_READABLE)); 355 356 /** 357 * WebKitViewportAttributs:device-pixel-ratio: 358 * 359 * The device pixel ratio of the viewport. Before getting this property, 360 * you need to make sure that #WebKitViewportAttributes is valid. 361 * 362 * Since: 1.3.8 363 */ 364 g_object_class_install_property(gobjectClass, 365 PROP_DEVICE_PIXEL_RATIO, 366 g_param_spec_float( 367 "device-pixel-ratio", 368 _("Device Pixel Ratio"), 369 _("The device pixel ratio of the viewport."), 370 -1, 371 G_MAXFLOAT, 372 -1, 373 WEBKIT_PARAM_READABLE)); 374 375 /** 376 * WebKitViewportAttributs:user-scalable: 377 * 378 * Determines whether or not the user can zoom in and out. 379 * Before getting this property, you need to make sure that 380 * #WebKitViewportAttributes is valid. 381 * 382 * Since: 1.3.8 383 */ 384 g_object_class_install_property(gobjectClass, 385 PROP_USER_SCALABLE, 386 g_param_spec_boolean( 387 _("user-scalable"), 388 _("User Scalable"), 389 _("Determines whether or not the user can zoom in and out."), 390 TRUE, 391 WEBKIT_PARAM_READABLE)); 392 393 /** 394 * WebKitViewportAttributs:valid: 395 * 396 * Determines whether or not the attributes are valid. 397 * #WebKitViewportAttributes are only valid on pages 398 * which have a viewport meta tag, and have already 399 * had the attributes calculated. 400 * 401 * Since: 1.3.8 402 */ 403 g_object_class_install_property(gobjectClass, 404 PROP_VALID, 405 g_param_spec_boolean( 406 _("valid"), 407 _("Valid"), 408 _("Determines whether or not the attributes are valid, and can be used."), 409 FALSE, 410 WEBKIT_PARAM_READABLE)); 411 412 g_type_class_add_private(kclass, sizeof(WebKitViewportAttributesPrivate)); 413 } 414 415 static void webkit_viewport_attributes_init(WebKitViewportAttributes* viewport) 416 { 417 viewport->priv = G_TYPE_INSTANCE_GET_PRIVATE(viewport, WEBKIT_TYPE_VIEWPORT_ATTRIBUTES, WebKitViewportAttributesPrivate); 418 419 viewport->priv->deviceWidth = 0; 420 viewport->priv->deviceHeight = 0; 421 viewport->priv->availableWidth = 0; 422 viewport->priv->availableHeight = 0; 423 viewport->priv->desktopWidth = 980; // This value works well for most web pages designed for desktop browsers. 424 viewport->priv->deviceDPI = 160; // It is the dpi of the original iPhone and Android devices. 425 viewport->priv->width = 0; 426 viewport->priv->height = 0; 427 viewport->priv->initialScaleFactor = -1; 428 viewport->priv->minimumScaleFactor = -1; 429 viewport->priv->maximumScaleFactor = -1; 430 viewport->priv->devicePixelRatio = -1; 431 viewport->priv->userScalable = TRUE; 432 viewport->priv->isValid = FALSE; 433 } 434 435 static void webkit_viewport_attributes_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* paramSpec) 436 { 437 WebKitViewportAttributes* viewportAttributes = WEBKIT_VIEWPORT_ATTRIBUTES(object); 438 WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; 439 440 switch (propertyID) { 441 case PROP_DEVICE_WIDTH: 442 g_value_set_int(value, priv->deviceWidth); 443 break; 444 case PROP_DEVICE_HEIGHT: 445 g_value_set_int(value, priv->deviceHeight); 446 break; 447 case PROP_AVAILABLE_WIDTH: 448 g_value_set_int(value, priv->availableWidth); 449 break; 450 case PROP_AVAILABLE_HEIGHT: 451 g_value_set_int(value, priv->availableHeight); 452 break; 453 case PROP_DESKTOP_WIDTH: 454 g_value_set_int(value, priv->desktopWidth); 455 break; 456 case PROP_DEVICE_DPI: 457 g_value_set_int(value, priv->deviceDPI); 458 break; 459 case PROP_WIDTH: 460 g_value_set_int(value, priv->width); 461 break; 462 case PROP_HEIGHT: 463 g_value_set_int(value, priv->height); 464 break; 465 case PROP_INITIAL_SCALE_FACTOR: 466 g_value_set_float(value, priv->initialScaleFactor); 467 break; 468 case PROP_MINIMUM_SCALE_FACTOR: 469 g_value_set_float(value, priv->minimumScaleFactor); 470 break; 471 case PROP_MAXIMUM_SCALE_FACTOR: 472 g_value_set_float(value, priv->maximumScaleFactor); 473 break; 474 case PROP_DEVICE_PIXEL_RATIO: 475 g_value_set_float(value, priv->devicePixelRatio); 476 break; 477 case PROP_USER_SCALABLE: 478 g_value_set_boolean(value, priv->userScalable); 479 break; 480 case PROP_VALID: 481 g_value_set_boolean(value, priv->isValid); 482 break; 483 default: 484 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, paramSpec); 485 break; 486 } 487 } 488 489 static void webkit_viewport_attributes_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* paramSpec) 490 { 491 WebKitViewportAttributes* viewportAttributes = WEBKIT_VIEWPORT_ATTRIBUTES(object); 492 WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; 493 494 switch (propertyID) { 495 case PROP_DEVICE_WIDTH: 496 priv->deviceWidth = g_value_get_int(value); 497 break; 498 case PROP_DEVICE_HEIGHT: 499 priv->deviceHeight = g_value_get_int(value); 500 break; 501 case PROP_AVAILABLE_WIDTH: 502 priv->availableWidth = g_value_get_int(value); 503 break; 504 case PROP_AVAILABLE_HEIGHT: 505 priv->availableHeight = g_value_get_int(value); 506 break; 507 case PROP_DESKTOP_WIDTH: 508 priv->desktopWidth = g_value_get_int(value); 509 break; 510 case PROP_DEVICE_DPI: 511 priv->deviceDPI = g_value_get_int(value); 512 break; 513 default: 514 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, paramSpec); 515 break; 516 } 517 } 518 519 void webkitViewportAttributesRecompute(WebKitViewportAttributes* viewportAttributes) 520 { 521 WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; 522 WebKitWebView* webView = priv->webView; 523 524 IntRect windowRect(webView->priv->corePage->chrome()->windowRect()); 525 priv->deviceWidth = windowRect.width(); 526 priv->deviceHeight = windowRect.height(); 527 528 IntRect rect(webView->priv->corePage->chrome()->pageRect()); 529 priv->availableWidth = rect.width(); 530 priv->availableHeight = rect.height(); 531 532 // First of all, we give the application an opportunity to override some of the values. 533 g_signal_emit_by_name(webView, "viewport-attributes-recompute-requested", viewportAttributes); 534 535 ViewportArguments arguments = webView->priv->corePage->mainFrame()->document()->viewportArguments(); 536 537 ViewportAttributes attributes = computeViewportAttributes(arguments, priv->desktopWidth, priv->deviceWidth, priv->deviceHeight, priv->deviceDPI, IntSize(priv->availableWidth, priv->availableHeight)); 538 539 priv->width = attributes.layoutSize.width(); 540 priv->height = attributes.layoutSize.height(); 541 priv->initialScaleFactor = attributes.initialScale; 542 priv->minimumScaleFactor = attributes.minimumScale; 543 priv->maximumScaleFactor = attributes.maximumScale; 544 priv->devicePixelRatio = attributes.devicePixelRatio; 545 priv->userScalable = static_cast<bool>(arguments.userScalable); 546 547 if (!priv->isValid) { 548 priv->isValid = TRUE; 549 g_object_notify(G_OBJECT(viewportAttributes), "valid"); 550 } 551 552 // Now let the application know it is safe to use the new values. 553 g_signal_emit_by_name(webView, "viewport-attributes-changed", viewportAttributes); 554 } 555 556 /** 557 * webkit_viewport_attributes_recompute: 558 * @viewportAttributes: a #WebKitViewportAttributes 559 * 560 * Recompute the optimal viewport attributes and emit the viewport-attribute-changed signal. 561 * The viewport-attributes-recompute-requested signal also will be handled to override 562 * the device size, available size, desktop width, or device DPI. 563 * 564 * Since: 1.3.8 565 */ 566 void webkit_viewport_attributes_recompute(WebKitViewportAttributes* viewportAttributes) 567 { 568 if (!viewportAttributes->priv->isValid) 569 return; 570 webkitViewportAttributesRecompute(viewportAttributes); 571 } 572