Home | History | Annotate | Download | only in web
      1 /*
      2  * Copyright (C) 2013 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "web/PageScaleConstraintsSet.h"
     33 
     34 #include "platform/Length.h"
     35 #include "wtf/Assertions.h"
     36 
     37 using namespace WebCore;
     38 
     39 namespace blink {
     40 
     41 static const float defaultMinimumScale = 0.25f;
     42 static const float defaultMaximumScale = 5.0f;
     43 
     44 PageScaleConstraintsSet::PageScaleConstraintsSet()
     45     : m_lastContentsWidth(0)
     46     , m_needsReset(false)
     47     , m_constraintsDirty(false)
     48 {
     49     m_finalConstraints = defaultConstraints();
     50 }
     51 
     52 PageScaleConstraints PageScaleConstraintsSet::defaultConstraints() const
     53 {
     54     return PageScaleConstraints(-1, defaultMinimumScale, defaultMaximumScale);
     55 }
     56 
     57 void PageScaleConstraintsSet::updatePageDefinedConstraints(const ViewportDescription& description, Length legacyFallbackWidth)
     58 {
     59     m_pageDefinedConstraints = description.resolve(m_viewSize, legacyFallbackWidth);
     60 
     61     m_constraintsDirty = true;
     62 }
     63 
     64 void PageScaleConstraintsSet::setUserAgentConstraints(const PageScaleConstraints& userAgentConstraints)
     65 {
     66     m_userAgentConstraints = userAgentConstraints;
     67     m_constraintsDirty = true;
     68 }
     69 
     70 PageScaleConstraints PageScaleConstraintsSet::computeConstraintsStack() const
     71 {
     72     PageScaleConstraints constraints = defaultConstraints();
     73     constraints.overrideWith(m_pageDefinedConstraints);
     74     constraints.overrideWith(m_userAgentConstraints);
     75     return constraints;
     76 }
     77 
     78 void PageScaleConstraintsSet::computeFinalConstraints()
     79 {
     80     m_finalConstraints = computeConstraintsStack();
     81 
     82     m_constraintsDirty = false;
     83 }
     84 
     85 void PageScaleConstraintsSet::adjustFinalConstraintsToContentsSize(IntSize contentsSize, int nonOverlayScrollbarWidth)
     86 {
     87     m_finalConstraints.fitToContentsWidth(contentsSize.width(), m_viewSize.width() - nonOverlayScrollbarWidth);
     88 }
     89 
     90 void PageScaleConstraintsSet::setNeedsReset(bool needsReset)
     91 {
     92     m_needsReset = needsReset;
     93     if (needsReset)
     94         m_constraintsDirty = true;
     95 }
     96 
     97 void PageScaleConstraintsSet::didChangeContentsSize(IntSize contentsSize, float pageScaleFactor)
     98 {
     99     // If a large fixed-width element expanded the size of the document late in
    100     // loading and our initial scale is not set (or set to be less than the last
    101     // minimum scale), reset the page scale factor to the new initial scale.
    102     if (contentsSize.width() > m_lastContentsWidth
    103         && pageScaleFactor == finalConstraints().minimumScale
    104         && computeConstraintsStack().initialScale < finalConstraints().minimumScale)
    105         setNeedsReset(true);
    106 
    107     m_constraintsDirty = true;
    108     m_lastContentsWidth = contentsSize.width();
    109 }
    110 
    111 static float computeDeprecatedTargetDensityDPIFactor(const ViewportDescription& description, float deviceScaleFactor)
    112 {
    113     if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueDeviceDPI)
    114         return 1.0f / deviceScaleFactor;
    115 
    116     float targetDPI = -1.0f;
    117     if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueLowDPI)
    118         targetDPI = 120.0f;
    119     else if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueMediumDPI)
    120         targetDPI = 160.0f;
    121     else if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueHighDPI)
    122         targetDPI = 240.0f;
    123     else if (description.deprecatedTargetDensityDPI != ViewportDescription::ValueAuto)
    124         targetDPI = description.deprecatedTargetDensityDPI;
    125     return targetDPI > 0 ? 160.0f / targetDPI : 1.0f;
    126 }
    127 
    128 static float getLayoutWidthForNonWideViewport(const FloatSize& deviceSize, float initialScale)
    129 {
    130     return initialScale == -1 ? deviceSize.width() : deviceSize.width() / initialScale;
    131 }
    132 
    133 static float computeHeightByAspectRatio(float width, const FloatSize& deviceSize)
    134 {
    135     return width * (deviceSize.height() / deviceSize.width());
    136 }
    137 
    138 void PageScaleConstraintsSet::didChangeViewSize(const IntSize& size)
    139 {
    140     if (m_viewSize == size)
    141         return;
    142 
    143     m_viewSize = size;
    144     m_constraintsDirty = true;
    145 }
    146 
    147 IntSize PageScaleConstraintsSet::mainFrameSize(const IntSize& contentsSize) const
    148 {
    149     // If there's no explicit minimum scale factor set, size the frame so that its width == content width
    150     // so there's no horizontal scrolling at the minimum scale.
    151     if (m_pageDefinedConstraints.minimumScale < finalConstraints().minimumScale
    152         && m_userAgentConstraints.minimumScale < finalConstraints().minimumScale
    153         && contentsSize.width()
    154         && m_viewSize.width())
    155         return IntSize(contentsSize.width(), computeHeightByAspectRatio(contentsSize.width(), m_viewSize));
    156 
    157     // If there is a minimum scale (or there's no content size yet), the frame size should match the viewport
    158     // size at minimum scale, since the viewport must always be contained by the frame.
    159     IntSize frameSize(m_viewSize);
    160     frameSize.scale(1 / finalConstraints().minimumScale);
    161     return frameSize;
    162 }
    163 
    164 void PageScaleConstraintsSet::adjustForAndroidWebViewQuirks(const ViewportDescription& description, int layoutFallbackWidth, float deviceScaleFactor, bool supportTargetDensityDPI, bool wideViewportQuirkEnabled, bool useWideViewport, bool loadWithOverviewMode, bool nonUserScalableQuirkEnabled)
    165 {
    166     if (!supportTargetDensityDPI && !wideViewportQuirkEnabled && loadWithOverviewMode && !nonUserScalableQuirkEnabled)
    167         return;
    168 
    169     const float oldInitialScale = m_pageDefinedConstraints.initialScale;
    170     if (!loadWithOverviewMode) {
    171         bool resetInitialScale = false;
    172         if (description.zoom == -1) {
    173             if (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom)
    174                 resetInitialScale = true;
    175             if (useWideViewport || description.maxWidth.type() == DeviceWidth)
    176                 resetInitialScale = true;
    177         }
    178         if (resetInitialScale)
    179             m_pageDefinedConstraints.initialScale = 1.0f;
    180     }
    181 
    182     float adjustedLayoutSizeWidth = m_pageDefinedConstraints.layoutSize.width();
    183     float adjustedLayoutSizeHeight = m_pageDefinedConstraints.layoutSize.height();
    184     float targetDensityDPIFactor = 1.0f;
    185 
    186     if (supportTargetDensityDPI) {
    187         targetDensityDPIFactor = computeDeprecatedTargetDensityDPIFactor(description, deviceScaleFactor);
    188         if (m_pageDefinedConstraints.initialScale != -1)
    189             m_pageDefinedConstraints.initialScale *= targetDensityDPIFactor;
    190         if (m_pageDefinedConstraints.minimumScale != -1)
    191             m_pageDefinedConstraints.minimumScale *= targetDensityDPIFactor;
    192         if (m_pageDefinedConstraints.maximumScale != -1)
    193             m_pageDefinedConstraints.maximumScale *= targetDensityDPIFactor;
    194         if (wideViewportQuirkEnabled && (!useWideViewport || description.maxWidth.type() == DeviceWidth)) {
    195             adjustedLayoutSizeWidth /= targetDensityDPIFactor;
    196             adjustedLayoutSizeHeight /= targetDensityDPIFactor;
    197         }
    198     }
    199 
    200     if (wideViewportQuirkEnabled) {
    201         if (useWideViewport && (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom) && description.zoom != 1.0f) {
    202             adjustedLayoutSizeWidth = layoutFallbackWidth;
    203             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, m_viewSize);
    204         } else if (!useWideViewport) {
    205             const float nonWideScale = description.zoom < 1 && description.maxWidth.type() != DeviceWidth && description.maxWidth.type() != DeviceHeight ? -1 : oldInitialScale;
    206             adjustedLayoutSizeWidth = getLayoutWidthForNonWideViewport(m_viewSize, nonWideScale) / targetDensityDPIFactor;
    207             float newInitialScale = targetDensityDPIFactor;
    208             if (m_userAgentConstraints.initialScale != -1 && (description.maxWidth.type() == DeviceWidth || ((description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom) && description.zoom == -1))) {
    209                 adjustedLayoutSizeWidth /= m_userAgentConstraints.initialScale;
    210                 newInitialScale = m_userAgentConstraints.initialScale;
    211             }
    212             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, m_viewSize);
    213             if (description.zoom < 1) {
    214                 m_pageDefinedConstraints.initialScale = newInitialScale;
    215                 if (m_pageDefinedConstraints.minimumScale != -1)
    216                     m_pageDefinedConstraints.minimumScale = std::min<float>(m_pageDefinedConstraints.minimumScale, m_pageDefinedConstraints.initialScale);
    217                 if (m_pageDefinedConstraints.maximumScale != -1)
    218                     m_pageDefinedConstraints.maximumScale = std::max<float>(m_pageDefinedConstraints.maximumScale, m_pageDefinedConstraints.initialScale);
    219             }
    220         }
    221     }
    222 
    223     if (nonUserScalableQuirkEnabled && !description.userZoom) {
    224         m_pageDefinedConstraints.initialScale = targetDensityDPIFactor;
    225         m_pageDefinedConstraints.minimumScale = m_pageDefinedConstraints.initialScale;
    226         m_pageDefinedConstraints.maximumScale = m_pageDefinedConstraints.initialScale;
    227         if (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom || description.maxWidth.type() == DeviceWidth) {
    228             adjustedLayoutSizeWidth = m_viewSize.width() / targetDensityDPIFactor;
    229             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, m_viewSize);
    230         }
    231     }
    232 
    233     m_pageDefinedConstraints.layoutSize.setWidth(adjustedLayoutSizeWidth);
    234     m_pageDefinedConstraints.layoutSize.setHeight(adjustedLayoutSizeHeight);
    235 }
    236 
    237 } // namespace WebCore
    238