diff options
Diffstat (limited to 'WebCore/dom/ViewportArguments.cpp')
-rw-r--r-- | WebCore/dom/ViewportArguments.cpp | 318 |
1 files changed, 259 insertions, 59 deletions
diff --git a/WebCore/dom/ViewportArguments.cpp b/WebCore/dom/ViewportArguments.cpp index 9f831dd..356f9ed 100644 --- a/WebCore/dom/ViewportArguments.cpp +++ b/WebCore/dom/ViewportArguments.cpp @@ -5,6 +5,7 @@ * (C) 2006 Alexey Proskuryakov (ap@webkit.org) * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -31,76 +32,275 @@ #include "DOMWindow.h" #include "Document.h" #include "Frame.h" +#include "IntSize.h" #include "Page.h" #include "PlatformString.h" #include "ScriptableDocumentParser.h" +using namespace std; + namespace WebCore { +ViewportConfiguration findConfigurationForViewportData(ViewportArguments args, int desktopWidth, int deviceWidth, int deviceHeight, int deviceDPI, IntSize visibleViewport) +{ + ViewportConfiguration result; + + float availableWidth = visibleViewport.width(); + float availableHeight = visibleViewport.height(); + + ASSERT(availableWidth > 0 && availableHeight > 0); + + switch (int(args.width)) { + case ViewportArguments::ValueDesktopWidth: + args.width = desktopWidth; + break; + case ViewportArguments::ValueDeviceWidth: + args.width = deviceWidth; + break; + case ViewportArguments::ValueDeviceHeight: + args.width = deviceHeight; + break; + } + + switch (int(args.height)) { + case ViewportArguments::ValueDesktopWidth: + args.height = desktopWidth; + break; + case ViewportArguments::ValueDeviceWidth: + args.height = deviceWidth; + break; + case ViewportArguments::ValueDeviceHeight: + args.height = deviceHeight; + break; + } + + result.devicePixelRatio = float(deviceDPI / 160.0); + + // Resolve non-'auto' width and height to pixel values. + if (deviceDPI != 1.0) { + deviceWidth /= result.devicePixelRatio; + deviceHeight /= result.devicePixelRatio; + + if (args.width != ViewportArguments::ValueAuto) + args.width /= result.devicePixelRatio; + if (args.height != ViewportArguments::ValueAuto) + args.height /= result.devicePixelRatio; + } + + // Clamp values to range defined by spec and resolve minimum-scale and maximum-scale values + if (args.width != ViewportArguments::ValueAuto) + args.width = min(float(10000), max(args.width, float(1))); + if (args.height != ViewportArguments::ValueAuto) + args.height = min(float(10000), max(args.height, float(1))); + + if (args.initialScale != ViewportArguments::ValueAuto) + args.initialScale = min(float(10), max(args.initialScale, float(0.1))); + if (args.minimumScale != ViewportArguments::ValueAuto) + args.minimumScale = min(float(10), max(args.minimumScale, float(0.1))); + if (args.maximumScale != ViewportArguments::ValueAuto) + args.maximumScale = min(float(10), max(args.maximumScale, float(0.1))); + + // Resolve minimum-scale and maximum-scale values according to spec. + if (args.minimumScale == ViewportArguments::ValueAuto) + result.minimumScale = float(0.25); + else + result.minimumScale = args.minimumScale; + + if (args.maximumScale == ViewportArguments::ValueAuto) { + result.maximumScale = float(5.0); + result.minimumScale = min(float(5.0), result.minimumScale); + } else + result.maximumScale = args.maximumScale; + result.maximumScale = max(result.minimumScale, result.maximumScale); + + // Resolve initial-scale value. + result.initialScale = args.initialScale; + if (result.initialScale == ViewportArguments::ValueAuto) { + result.initialScale = availableWidth / desktopWidth; + if (args.width != ViewportArguments::ValueAuto) + result.initialScale = availableWidth / args.width; + if (args.height != ViewportArguments::ValueAuto) { + // if 'auto', the initial-scale will be negative here and thus ignored. + result.initialScale = max(result.initialScale, availableHeight / args.height); + } + } + + // Constrain initial-scale value to minimum-scale/maximum-scale range. + result.initialScale = min(result.maximumScale, max(result.minimumScale, result.initialScale)); + + // Resolve width value. + float width; + if (args.width != ViewportArguments::ValueAuto) + width = args.width; + else { + if (args.initialScale == ViewportArguments::ValueAuto) + width = desktopWidth; + else if (args.height != ViewportArguments::ValueAuto) + width = args.height * (availableWidth / availableHeight); + else + width = availableWidth / result.initialScale; + } + + // Resolve height value. + float height; + if (args.height != ViewportArguments::ValueAuto) + height = args.height; + else + height = width * availableHeight / availableWidth; + + // Extend width and height to fill the visual viewport for the resolved initial-scale. + width = max(width, availableWidth / result.initialScale); + height = max(height, availableHeight / result.initialScale); + result.layoutViewport.setWidth(width); + result.layoutViewport.setHeight(height); + + // Update minimum scale factor, to never allow zooming out more than viewport + result.minimumScale = max(result.minimumScale, max(availableWidth / width, availableHeight / height)); + + return result; +} + +static float findSizeValue(const String& keyString, const String& valueString, Document* document) +{ + // 1) Non-negative number values are translated to px lengths. + // 2) Negative number values are translated to auto. + // 3) device-width and device-height are used as keywords. + // 4) Other keywords and unknown values translate to 0.0. + + if (equalIgnoringCase(valueString, "desktop-width")) + return ViewportArguments::ValueDesktopWidth; + if (equalIgnoringCase(valueString, "device-width")) + return ViewportArguments::ValueDeviceWidth; + if (equalIgnoringCase(valueString, "device-height")) + return ViewportArguments::ValueDeviceHeight; + + bool ok; + float value = valueString.toFloat(&ok); + if (!ok) { + reportViewportWarning(document, UnrecognizedViewportArgumentError, keyString); + return float(0.0); + } + + if (value < 0) + return ViewportArguments::ValueAuto; + + if (keyString == "width") + reportViewportWarning(document, DeviceWidthShouldBeUsedWarning, keyString); + else if (keyString == "height") + reportViewportWarning(document, DeviceHeightShouldBeUsedWarning, keyString); + + return value; +} + +static float findScaleValue(const String& keyString, const String& valueString, Document* document) +{ + // 1) Non-negative number values are translated to <number> values. + // 2) Negative number values are translated to auto. + // 3) yes is translated to 1.0. + // 4) device-width and device-height are translated to 10.0. + // 5) no and unknown values are translated to 0.0 + + if (equalIgnoringCase(valueString, "yes")) + return float(1.0); + if (equalIgnoringCase(valueString, "no")) + return float(0.0); + if (equalIgnoringCase(valueString, "desktop-width")) + return float(10.0); + if (equalIgnoringCase(valueString, "device-width")) + return float(10.0); + if (equalIgnoringCase(valueString, "device-height")) + return float(10.0); + + bool ok; + float value = valueString.toFloat(&ok); + if (!ok) { + reportViewportWarning(document, UnrecognizedViewportArgumentError, keyString); + return float(0.0); + } + + if (value < 0) + return ViewportArguments::ValueAuto; + + if (value > 10.0) + reportViewportWarning(document, MaximumScaleTooLargeError, keyString); + + return value; +} + +static bool findUserScalableValue(const String& keyString, const String& valueString, Document* document) +{ + // yes and no are used as keywords. + // Numbers >= 1, numbers <= -1, device-width and device-height are mapped to yes. + // Numbers in the range <-1, 1>, and unknown values, are mapped to no. + + if (equalIgnoringCase(valueString, "yes")) + return true; + if (equalIgnoringCase(valueString, "no")) + return false; + if (equalIgnoringCase(valueString, "desktop-width")) + return true; + if (equalIgnoringCase(valueString, "device-width")) + return true; + if (equalIgnoringCase(valueString, "device-height")) + return true; + + bool ok; + float value = valueString.toFloat(&ok); + if (!ok) { + reportViewportWarning(document, UnrecognizedViewportArgumentError, keyString); + return false; + } + + if (fabs(value) < 1) + return false; + + return true; +} + +static float findTargetDensityDPIValue(const String& keyString, const String& valueString, Document* document) +{ + if (equalIgnoringCase(valueString, "device-dpi")) + return ViewportArguments::ValueDeviceDPI; + if (equalIgnoringCase(valueString, "low-dpi")) + return ViewportArguments::ValueLowDPI; + if (equalIgnoringCase(valueString, "medium-dpi")) + return ViewportArguments::ValueMediumDPI; + if (equalIgnoringCase(valueString, "high-dpi")) + return ViewportArguments::ValueHighDPI; + + bool ok; + float value = valueString.toFloat(&ok); + if (!ok) { + reportViewportWarning(document, UnrecognizedViewportArgumentError, keyString); + return ViewportArguments::ValueAuto; + } + + if (value < 70 || value > 400) { + reportViewportWarning(document, TargetDensityDpiTooSmallOrLargeError, keyString); + return ViewportArguments::ValueAuto; + } + + return value; +} + void setViewportFeature(const String& keyString, const String& valueString, Document* document, void* data) { ViewportArguments* arguments = static_cast<ViewportArguments*>(data); - float value = ViewportArguments::ValueUndefined; - bool didUseConstants = false; - if (equalIgnoringCase(valueString, "yes")) - value = 1; - else if (equalIgnoringCase(valueString, "device-width")) { - didUseConstants = true; - if (document->page()) - value = document->page()->chrome()->windowRect().width(); - } else if (equalIgnoringCase(valueString, "device-height")) { - didUseConstants = true; - if (document->page()) - value = document->page()->chrome()->windowRect().height(); - } else if (equalIgnoringCase(valueString, "device-dpi")) { - didUseConstants = true; - // Default of today is 160dpi, resulting in a scaleFactor of 1.0. - if (document->page()) - value = 160 * document->page()->chrome()->scaleFactor(); - } else if (equalIgnoringCase(valueString, "low-dpi")) { - didUseConstants = true; - value = 120; - } else if (equalIgnoringCase(valueString, "medium-dpi")) { - didUseConstants = true; - value = 160; - } else if (equalIgnoringCase(valueString, "high-dpi")) { - didUseConstants = true; - value = 240; - } else if (equalIgnoringCase(valueString, "default")) // This allows us to distinguish the omission of a key from asking for the default value. - value = -2; - else if (valueString.length()) // listing a key with no value is shorthand for key=default - value = valueString.toFloat(); - - if (keyString == "initial-scale") - arguments->initialScale = value; + if (keyString == "width") + arguments->width = findSizeValue(keyString, valueString, document); + else if (keyString == "height") + arguments->height = findSizeValue(keyString, valueString, document); + else if (keyString == "initial-scale") + arguments->initialScale = findScaleValue(keyString, valueString, document); else if (keyString == "minimum-scale") - arguments->minimumScale = value; - else if (keyString == "maximum-scale") { - arguments->maximumScale = value; - if (value > 10.0) - reportViewportWarning(document, MaximumScaleTooLargeError, keyString); - } else if (keyString == "user-scalable") - arguments->userScalable = value; - else if (keyString == "width") { - if (document->page() && value == document->page()->chrome()->windowRect().width() && !didUseConstants) - reportViewportWarning(document, DeviceWidthShouldBeUsedWarning, keyString); - else if (document->page() && value == document->page()->chrome()->windowRect().height() && !didUseConstants) - reportViewportWarning(document, DeviceHeightShouldBeUsedWarning, keyString); - - arguments->width = value; - } else if (keyString == "height") { - if (document->page() && value == document->page()->chrome()->windowRect().width() && !didUseConstants) - reportViewportWarning(document, DeviceWidthShouldBeUsedWarning, keyString); - else if (document->page() && value == document->page()->chrome()->windowRect().height() && !didUseConstants) - reportViewportWarning(document, DeviceHeightShouldBeUsedWarning, keyString); - arguments->height = value; - } else if (keyString == "target-densitydpi" || keyString == "target-densityDpi") { - if (!didUseConstants && (value < 70 || value > 400)) - reportViewportWarning(document, TargetDensityDpiTooSmallOrLargeError, keyString); - arguments->targetDensityDpi = value; - } else - reportViewportWarning(document, UnrecognizedViewportArgumentError, keyString); + arguments->minimumScale = findScaleValue(keyString, valueString, document); + else if (keyString == "maximum-scale") + arguments->maximumScale = findScaleValue(keyString, valueString, document); + else if (keyString == "user-scalable") + arguments->userScalable = findUserScalableValue(keyString, valueString, document); + else if (keyString == "target-densitydpi") + arguments->targetDensityDpi = findTargetDensityDPIValue(keyString, valueString, document); } static const char* viewportErrorMessageTemplate(ViewportErrorCode errorCode) |