1 /*
2 * Copyright (C) 2010 Joone Hur <joone@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
webkit_viewport_attributes_class_init(WebKitViewportAttributesClass * kclass)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
webkit_viewport_attributes_init(WebKitViewportAttributes * viewport)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
webkit_viewport_attributes_get_property(GObject * object,guint propertyID,GValue * value,GParamSpec * paramSpec)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
webkit_viewport_attributes_set_property(GObject * object,guint propertyID,const GValue * value,GParamSpec * paramSpec)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
webkitViewportAttributesRecompute(WebKitViewportAttributes * viewportAttributes)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 */
webkit_viewport_attributes_recompute(WebKitViewportAttributes * viewportAttributes)566 void webkit_viewport_attributes_recompute(WebKitViewportAttributes* viewportAttributes)
567 {
568 if (!viewportAttributes->priv->isValid)
569 return;
570 webkitViewportAttributesRecompute(viewportAttributes);
571 }
572