Home | History | Annotate | Download | only in webkit
      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