| /* |
| * Copyright (C) 2010 Joone Hur <joone@kldp.org> |
| * Copyright (C) 2010 Collabora Ltd. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "config.h" |
| #include "webkitviewportattributes.h" |
| |
| #include "Chrome.h" |
| #include "Frame.h" |
| #include "Page.h" |
| #include "webkitglobalsprivate.h" |
| #include "webkitviewportattributesprivate.h" |
| #include "webkitwebviewprivate.h" |
| #include <glib/gi18n-lib.h> |
| |
| /** |
| * SECTION:webkitviewportattributes |
| * @short_description: Represents the viewport properties of a web page |
| * @see_also: #WebKitWebView::viewport-attributes-recompute-requested |
| * @see_also: #WebKitWebView::viewport-attributes-changed |
| * |
| * #WebKitViewportAttributes offers the viewport properties to user agents to |
| * control the viewport layout. It contains the viewport size, initial scale with limits, |
| * and information about whether a user is able to scale the contents in the viewport. |
| * This makes a web page fit the device screen. |
| * |
| * The #WebKitWebView::viewport-attributes-changed signal will be emitted with #WebKitViewportAttributes |
| * when the viewport attributes are updated in the case of loading web pages contain |
| * the viewport properties and calling webkit_viewport_attributes_recompute. |
| * |
| * If the device size, available size, desktop width, or device DPI needs to be changed due to |
| * a consequence of an explicit browser request (caused by screen rotation, resizing, or similar reasons), |
| * You should call #webkit_viewport_attributes_recompute to recompute the viewport properties and |
| * override those values in the handler of #WebKitWebView::viewport-attributes-recompute-requested signal. |
| * |
| * For more information on the viewport properties, refer to the Safari reference library at |
| * http://developer.apple.com/safari/library/documentation/appleapplications/reference/safarihtmlref/articles/metatags.html |
| * |
| * <informalexample><programlisting> |
| * /<!-- -->* Connect to the viewport-attributes-changes signal *<!-- -->/ |
| * WebKitViewportAttributes* attributes = webkit_web_view_get_viewport_attributes (web_view); |
| * g_signal_connect (web_view, "viewport-attributes-recompute-requested", G_CALLBACK (viewport_recompute_cb), window); |
| * g_signal_connect (web_view, "viewport-attributes-changed", G_CALLBACK (viewport_changed_cb), window); |
| * g_signal_connect (attributes, "notify::valid", G_CALLBACK (viewport_valid_changed_cb), web_view); |
| * |
| * /<!-- -->* Handle the viewport-attributes-recompute-requested signal to override the device width *<!-- -->/ |
| * static void |
| * viewport_recompute_cb (WebKitWebView* web_view, WebKitViewportAttributes* attributes, GtkWidget* window) |
| * { |
| * int override_available_width = 480; |
| * g_object_set (G_OBJECT(attributes), "available-width", override_available_width, NULL); |
| * } |
| * |
| * /<!-- -->* Handle the viewport-attributes-changed signal to recompute the initial scale factor *<!-- -->/ |
| * static void |
| * viewport_changed_cb (WebKitWebView* web_view, WebKitViewportAttributes* attributes, gpointer data) |
| * { |
| * gfloat initialScale; |
| * g_object_get (G_OBJECT (atributes), "initial-scale-factor", &initialScale, NULL); |
| * webkit_web_view_set_zoom_level (web_view, initialScale); |
| * } |
| * |
| * /<!-- -->* Handle the notify::valid signal to initialize the zoom level *<!-- -->/ |
| * static void |
| * viewport_valid_changed_cb (WebKitViewportAttributes* attributes, GParamSpec* pspec, WebKitWebView* web_view) |
| * { |
| * gboolean is_valid; |
| * g_object_get (attributes, "valid", &is_valid, NULL); |
| * if (!is_valid) |
| * webkit_web_view_set_zoom_level (web_view, 1.0); |
| * } |
| * </programlisting></informalexample> |
| */ |
| |
| using namespace WebKit; |
| using namespace WebCore; |
| |
| enum { |
| PROP_0, |
| |
| PROP_DEVICE_WIDTH, |
| PROP_DEVICE_HEIGHT, |
| PROP_AVAILABLE_WIDTH, |
| PROP_AVAILABLE_HEIGHT, |
| PROP_DESKTOP_WIDTH, |
| PROP_DEVICE_DPI, |
| PROP_WIDTH, |
| PROP_HEIGHT, |
| PROP_INITIAL_SCALE_FACTOR, |
| PROP_MINIMUM_SCALE_FACTOR, |
| PROP_MAXIMUM_SCALE_FACTOR, |
| PROP_DEVICE_PIXEL_RATIO, |
| PROP_USER_SCALABLE, |
| PROP_VALID |
| }; |
| |
| G_DEFINE_TYPE(WebKitViewportAttributes, webkit_viewport_attributes, G_TYPE_OBJECT); |
| |
| static void webkit_viewport_attributes_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* paramSpec); |
| static void webkit_viewport_attributes_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* paramSpec); |
| |
| static void webkit_viewport_attributes_class_init(WebKitViewportAttributesClass* kclass) |
| { |
| GObjectClass* gobjectClass = G_OBJECT_CLASS(kclass); |
| gobjectClass->get_property = webkit_viewport_attributes_get_property; |
| gobjectClass->set_property = webkit_viewport_attributes_set_property; |
| |
| /** |
| * WebKitViewportAttributs:device-width: |
| * |
| * The width of the screen. This value is always automatically |
| * pre-computed during a viewport attributes recomputation, and |
| * can be overridden by the handler of |
| * WebKitWebView::viewport-attributes-recompute-requested. You |
| * should not do that unless you have a very good reason. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_DEVICE_WIDTH, |
| g_param_spec_int( |
| "device-width", |
| _("Device Width"), |
| _("The width of the screen."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:device-height: |
| * |
| * The height of the screen. This value is always automatically |
| * pre-computed during a viewport attributes recomputation, and |
| * can be overriden by the handler of |
| * WebKitWebView::viewport-attributes-recompute-requested. You |
| * should not do that unless you have a very good reason. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_DEVICE_HEIGHT, |
| g_param_spec_int( |
| "device-height", |
| _("Device Height"), |
| _("The height of the screen."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:available-width: |
| * |
| * The width of the current visible area. This will usually be the |
| * same as the space allocated to the widget, but in some cases |
| * you may have decided to make the widget bigger than the visible |
| * area. This value is by default initialized to the size |
| * allocated by the widget, but you can override it in the handler |
| * of WebKitWebView::viewport-attributes-recompute-requested to |
| * let the engine know what the visible area is. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_AVAILABLE_WIDTH, |
| g_param_spec_int( |
| "available-width", |
| _("Available Width"), |
| _("The width of the visible area."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:available-height: |
| * |
| * The height of the current visible area. This will usually be the |
| * same as the space allocated to the widget, but in some cases |
| * you may have decided to make the widget bigger than the visible |
| * area. This value is by default initialized to the size |
| * allocated by the widget, but you can override it in the handler |
| * of WebKitWebView::viewport-attributes-recompute-requested to |
| * let the engine know what the visible area is. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_AVAILABLE_HEIGHT, |
| g_param_spec_int( |
| "available-height", |
| _("Available Height"), |
| _("The height of the visible area."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:desktop-width: |
| * |
| * The width of viewport that works well for most web pages designed for |
| * desktop. This value is initialized to 980 pixels by default and used |
| * during a viewport attributes recomputation. Also, it can be overriden by |
| * the handler of WebKitWebView::viewport-attributes-recompute-requested. |
| * You should not do that unless you have a very good reason. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_DESKTOP_WIDTH, |
| g_param_spec_int( |
| "desktop-width", |
| _("Desktop Width"), |
| _("The width of viewport that works well for most web pages designed for desktop."), |
| 0, |
| G_MAXINT, |
| 980, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:device-dpi: |
| * |
| * The number of dots per inch of the screen. This value is |
| * initialized to 160 dpi by default and used during a viewport |
| * attributes recomputation, because it is the dpi of the original |
| * iPhone and Android devices. Also, it can be overriden by the |
| * handler of WebKitWebView::viewport-attributes-recompute-requested. |
| * You should not do that unless you have a very good reason. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_DEVICE_DPI, |
| g_param_spec_int( |
| "device-dpi", |
| _("Device DPI"), |
| _("The number of dots per inch of the screen."), |
| 0, |
| G_MAXINT, |
| 160, |
| WEBKIT_PARAM_READWRITE)); |
| |
| /** |
| * WebKitViewportAttributs:width: |
| * |
| * The width of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_WIDTH, |
| g_param_spec_int( |
| "width", |
| _("Width"), |
| _("The width of the viewport."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:height: |
| * |
| * The height of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_HEIGHT, |
| g_param_spec_int( |
| "height", |
| _("Height"), |
| _("The height of the viewport."), |
| 0, |
| G_MAXINT, |
| 0, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:initial-scale-factor: |
| * |
| * The initial scale of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_INITIAL_SCALE_FACTOR, |
| g_param_spec_float( |
| "initial-scale-factor", |
| _("Initial Scale Factor"), |
| _("The initial scale of the viewport."), |
| -1, |
| G_MAXFLOAT, |
| -1, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:minimum-scale-factor: |
| * |
| * The minimum scale of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_MINIMUM_SCALE_FACTOR, |
| g_param_spec_float( |
| "minimum-scale-factor", |
| _("Minimum Scale Factor"), |
| _("The minimum scale of the viewport."), |
| -1, |
| G_MAXFLOAT, |
| -1, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:maximum-scale-factor: |
| * |
| * The maximum scale of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_MAXIMUM_SCALE_FACTOR, |
| g_param_spec_float( |
| "maximum-scale-factor", |
| _("Maximum Scale Factor"), |
| _("The maximum scale of the viewport."), |
| -1, |
| G_MAXFLOAT, |
| -1, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:device-pixel-ratio: |
| * |
| * The device pixel ratio of the viewport. Before getting this property, |
| * you need to make sure that #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_DEVICE_PIXEL_RATIO, |
| g_param_spec_float( |
| "device-pixel-ratio", |
| _("Device Pixel Ratio"), |
| _("The device pixel ratio of the viewport."), |
| -1, |
| G_MAXFLOAT, |
| -1, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:user-scalable: |
| * |
| * Determines whether or not the user can zoom in and out. |
| * Before getting this property, you need to make sure that |
| * #WebKitViewportAttributes is valid. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_USER_SCALABLE, |
| g_param_spec_boolean( |
| _("user-scalable"), |
| _("User Scalable"), |
| _("Determines whether or not the user can zoom in and out."), |
| TRUE, |
| WEBKIT_PARAM_READABLE)); |
| |
| /** |
| * WebKitViewportAttributs:valid: |
| * |
| * Determines whether or not the attributes are valid. |
| * #WebKitViewportAttributes are only valid on pages |
| * which have a viewport meta tag, and have already |
| * had the attributes calculated. |
| * |
| * Since: 1.3.8 |
| */ |
| g_object_class_install_property(gobjectClass, |
| PROP_VALID, |
| g_param_spec_boolean( |
| _("valid"), |
| _("Valid"), |
| _("Determines whether or not the attributes are valid, and can be used."), |
| FALSE, |
| WEBKIT_PARAM_READABLE)); |
| |
| g_type_class_add_private(kclass, sizeof(WebKitViewportAttributesPrivate)); |
| } |
| |
| static void webkit_viewport_attributes_init(WebKitViewportAttributes* viewport) |
| { |
| viewport->priv = G_TYPE_INSTANCE_GET_PRIVATE(viewport, WEBKIT_TYPE_VIEWPORT_ATTRIBUTES, WebKitViewportAttributesPrivate); |
| |
| viewport->priv->deviceWidth = 0; |
| viewport->priv->deviceHeight = 0; |
| viewport->priv->availableWidth = 0; |
| viewport->priv->availableHeight = 0; |
| viewport->priv->desktopWidth = 980; // This value works well for most web pages designed for desktop browsers. |
| viewport->priv->deviceDPI = 160; // It is the dpi of the original iPhone and Android devices. |
| viewport->priv->width = 0; |
| viewport->priv->height = 0; |
| viewport->priv->initialScaleFactor = -1; |
| viewport->priv->minimumScaleFactor = -1; |
| viewport->priv->maximumScaleFactor = -1; |
| viewport->priv->devicePixelRatio = -1; |
| viewport->priv->userScalable = TRUE; |
| viewport->priv->isValid = FALSE; |
| } |
| |
| static void webkit_viewport_attributes_get_property(GObject* object, guint propertyID, GValue* value, GParamSpec* paramSpec) |
| { |
| WebKitViewportAttributes* viewportAttributes = WEBKIT_VIEWPORT_ATTRIBUTES(object); |
| WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; |
| |
| switch (propertyID) { |
| case PROP_DEVICE_WIDTH: |
| g_value_set_int(value, priv->deviceWidth); |
| break; |
| case PROP_DEVICE_HEIGHT: |
| g_value_set_int(value, priv->deviceHeight); |
| break; |
| case PROP_AVAILABLE_WIDTH: |
| g_value_set_int(value, priv->availableWidth); |
| break; |
| case PROP_AVAILABLE_HEIGHT: |
| g_value_set_int(value, priv->availableHeight); |
| break; |
| case PROP_DESKTOP_WIDTH: |
| g_value_set_int(value, priv->desktopWidth); |
| break; |
| case PROP_DEVICE_DPI: |
| g_value_set_int(value, priv->deviceDPI); |
| break; |
| case PROP_WIDTH: |
| g_value_set_int(value, priv->width); |
| break; |
| case PROP_HEIGHT: |
| g_value_set_int(value, priv->height); |
| break; |
| case PROP_INITIAL_SCALE_FACTOR: |
| g_value_set_float(value, priv->initialScaleFactor); |
| break; |
| case PROP_MINIMUM_SCALE_FACTOR: |
| g_value_set_float(value, priv->minimumScaleFactor); |
| break; |
| case PROP_MAXIMUM_SCALE_FACTOR: |
| g_value_set_float(value, priv->maximumScaleFactor); |
| break; |
| case PROP_DEVICE_PIXEL_RATIO: |
| g_value_set_float(value, priv->devicePixelRatio); |
| break; |
| case PROP_USER_SCALABLE: |
| g_value_set_boolean(value, priv->userScalable); |
| break; |
| case PROP_VALID: |
| g_value_set_boolean(value, priv->isValid); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, paramSpec); |
| break; |
| } |
| } |
| |
| static void webkit_viewport_attributes_set_property(GObject* object, guint propertyID, const GValue* value, GParamSpec* paramSpec) |
| { |
| WebKitViewportAttributes* viewportAttributes = WEBKIT_VIEWPORT_ATTRIBUTES(object); |
| WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; |
| |
| switch (propertyID) { |
| case PROP_DEVICE_WIDTH: |
| priv->deviceWidth = g_value_get_int(value); |
| break; |
| case PROP_DEVICE_HEIGHT: |
| priv->deviceHeight = g_value_get_int(value); |
| break; |
| case PROP_AVAILABLE_WIDTH: |
| priv->availableWidth = g_value_get_int(value); |
| break; |
| case PROP_AVAILABLE_HEIGHT: |
| priv->availableHeight = g_value_get_int(value); |
| break; |
| case PROP_DESKTOP_WIDTH: |
| priv->desktopWidth = g_value_get_int(value); |
| break; |
| case PROP_DEVICE_DPI: |
| priv->deviceDPI = g_value_get_int(value); |
| break; |
| default: |
| G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propertyID, paramSpec); |
| break; |
| } |
| } |
| |
| void webkitViewportAttributesRecompute(WebKitViewportAttributes* viewportAttributes) |
| { |
| WebKitViewportAttributesPrivate* priv = viewportAttributes->priv; |
| WebKitWebView* webView = priv->webView; |
| |
| IntRect windowRect(webView->priv->corePage->chrome()->windowRect()); |
| priv->deviceWidth = windowRect.width(); |
| priv->deviceHeight = windowRect.height(); |
| |
| IntRect rect(webView->priv->corePage->chrome()->pageRect()); |
| priv->availableWidth = rect.width(); |
| priv->availableHeight = rect.height(); |
| |
| // First of all, we give the application an opportunity to override some of the values. |
| g_signal_emit_by_name(webView, "viewport-attributes-recompute-requested", viewportAttributes); |
| |
| ViewportArguments arguments = webView->priv->corePage->mainFrame()->document()->viewportArguments(); |
| |
| float devicePixelRatio = priv->deviceDPI / ViewportArguments::deprecatedTargetDPI; |
| ViewportAttributes attributes = computeViewportAttributes(arguments, priv->desktopWidth, priv->deviceWidth, priv->deviceHeight, devicePixelRatio, IntSize(priv->availableWidth, priv->availableHeight)); |
| restrictMinimumScaleFactorToViewportSize(attributes, IntSize(priv->availableWidth, priv->availableHeight), devicePixelRatio); |
| restrictScaleFactorToInitialScaleIfNotUserScalable(attributes); |
| |
| priv->width = attributes.layoutSize.width(); |
| priv->height = attributes.layoutSize.height(); |
| priv->initialScaleFactor = attributes.initialScale; |
| priv->minimumScaleFactor = attributes.minimumScale; |
| priv->maximumScaleFactor = attributes.maximumScale; |
| priv->devicePixelRatio = devicePixelRatio; |
| priv->userScalable = static_cast<bool>(arguments.userScalable); |
| |
| if (!priv->isValid) { |
| priv->isValid = TRUE; |
| g_object_notify(G_OBJECT(viewportAttributes), "valid"); |
| } |
| |
| // Now let the application know it is safe to use the new values. |
| g_signal_emit_by_name(webView, "viewport-attributes-changed", viewportAttributes); |
| } |
| |
| /** |
| * webkit_viewport_attributes_recompute: |
| * @viewportAttributes: a #WebKitViewportAttributes |
| * |
| * Recompute the optimal viewport attributes and emit the viewport-attribute-changed signal. |
| * The viewport-attributes-recompute-requested signal also will be handled to override |
| * the device size, available size, desktop width, or device DPI. |
| * |
| * Since: 1.3.8 |
| */ |
| void webkit_viewport_attributes_recompute(WebKitViewportAttributes* viewportAttributes) |
| { |
| if (!viewportAttributes->priv->isValid) |
| return; |
| webkitViewportAttributesRecompute(viewportAttributes); |
| } |