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 "PageScaleConstraintsSet.h"
     33 
     34 #include "wtf/Assertions.h"
     35 
     36 using namespace WebCore;
     37 
     38 namespace blink {
     39 
     40 static const float defaultMinimumScale = 0.25f;
     41 static const float defaultMaximumScale = 5.0f;
     42 
     43 PageScaleConstraintsSet::PageScaleConstraintsSet()
     44     : m_lastContentsWidth(0)
     45     , m_needsReset(false)
     46     , m_constraintsDirty(false)
     47 {
     48     m_finalConstraints = defaultConstraints();
     49 }
     50 
     51 PageScaleConstraints PageScaleConstraintsSet::defaultConstraints() const
     52 {
     53     return PageScaleConstraints(-1, defaultMinimumScale, defaultMaximumScale);
     54 }
     55 
     56 void PageScaleConstraintsSet::updatePageDefinedConstraints(const ViewportDescription& description, IntSize viewSize)
     57 {
     58     m_pageDefinedConstraints = description.resolve(viewSize);
     59 
     60     m_constraintsDirty = true;
     61 }
     62 
     63 void PageScaleConstraintsSet::setUserAgentConstraints(const PageScaleConstraints& userAgentConstraints)
     64 {
     65     m_userAgentConstraints = userAgentConstraints;
     66     m_constraintsDirty = true;
     67 }
     68 
     69 PageScaleConstraints PageScaleConstraintsSet::computeConstraintsStack() const
     70 {
     71     PageScaleConstraints constraints = defaultConstraints();
     72     constraints.overrideWith(m_pageDefinedConstraints);
     73     constraints.overrideWith(m_userAgentConstraints);
     74     return constraints;
     75 }
     76 
     77 void PageScaleConstraintsSet::computeFinalConstraints()
     78 {
     79     m_finalConstraints = computeConstraintsStack();
     80 
     81     m_constraintsDirty = false;
     82 }
     83 
     84 void PageScaleConstraintsSet::adjustFinalConstraintsToContentsSize(IntSize viewSize, IntSize contentsSize, int nonOverlayScrollbarWidth)
     85 {
     86     m_finalConstraints.fitToContentsWidth(contentsSize.width(), viewSize.width() - nonOverlayScrollbarWidth);
     87 }
     88 
     89 void PageScaleConstraintsSet::setNeedsReset(bool needsReset)
     90 {
     91     m_needsReset = needsReset;
     92     if (needsReset)
     93         m_constraintsDirty = true;
     94 }
     95 
     96 void PageScaleConstraintsSet::didChangeContentsSize(IntSize contentsSize, float pageScaleFactor)
     97 {
     98     // If a large fixed-width element expanded the size of the document late in
     99     // loading and our initial scale is not set (or set to be less than the last
    100     // minimum scale), reset the page scale factor to the new initial scale.
    101     if (contentsSize.width() > m_lastContentsWidth
    102         && pageScaleFactor == finalConstraints().minimumScale
    103         && computeConstraintsStack().initialScale < finalConstraints().minimumScale)
    104         setNeedsReset(true);
    105 
    106     m_constraintsDirty = true;
    107     m_lastContentsWidth = contentsSize.width();
    108 }
    109 
    110 static float computeDeprecatedTargetDensityDPIFactor(const ViewportDescription& description, float deviceScaleFactor)
    111 {
    112     if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueDeviceDPI)
    113         return 1.0f / deviceScaleFactor;
    114 
    115     float targetDPI = -1.0f;
    116     if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueLowDPI)
    117         targetDPI = 120.0f;
    118     else if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueMediumDPI)
    119         targetDPI = 160.0f;
    120     else if (description.deprecatedTargetDensityDPI == ViewportDescription::ValueHighDPI)
    121         targetDPI = 240.0f;
    122     else if (description.deprecatedTargetDensityDPI != ViewportDescription::ValueAuto)
    123         targetDPI = description.deprecatedTargetDensityDPI;
    124     return targetDPI > 0 ? 160.0f / targetDPI : 1.0f;
    125 }
    126 
    127 static float getLayoutWidthForNonWideViewport(const FloatSize& deviceSize, float initialScale)
    128 {
    129     return initialScale == -1 ? deviceSize.width() : deviceSize.width() / initialScale;
    130 }
    131 
    132 static float computeHeightByAspectRatio(float width, const FloatSize& deviceSize)
    133 {
    134     return width * (deviceSize.height() / deviceSize.width());
    135 }
    136 
    137 void PageScaleConstraintsSet::adjustForAndroidWebViewQuirks(const ViewportDescription& description, IntSize viewSize, int layoutFallbackWidth, float deviceScaleFactor, bool supportTargetDensityDPI, bool wideViewportQuirkEnabled, bool useWideViewport, bool loadWithOverviewMode, bool nonUserScalableQuirkEnabled)
    138 {
    139     if (!supportTargetDensityDPI && !wideViewportQuirkEnabled && loadWithOverviewMode && !nonUserScalableQuirkEnabled)
    140         return;
    141 
    142     const float oldInitialScale = m_pageDefinedConstraints.initialScale;
    143     if (!loadWithOverviewMode) {
    144         bool resetInitialScale = false;
    145         if (description.zoom == -1) {
    146             if (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom)
    147                 resetInitialScale = true;
    148             if (useWideViewport || description.maxWidth == Length(100, ViewportPercentageWidth))
    149                 resetInitialScale = true;
    150         }
    151         if (resetInitialScale)
    152             m_pageDefinedConstraints.initialScale = 1.0f;
    153     }
    154 
    155     float adjustedLayoutSizeWidth = m_pageDefinedConstraints.layoutSize.width();
    156     float adjustedLayoutSizeHeight = m_pageDefinedConstraints.layoutSize.height();
    157     float targetDensityDPIFactor = 1.0f;
    158 
    159     if (supportTargetDensityDPI) {
    160         targetDensityDPIFactor = computeDeprecatedTargetDensityDPIFactor(description, deviceScaleFactor);
    161         if (m_pageDefinedConstraints.initialScale != -1)
    162             m_pageDefinedConstraints.initialScale *= targetDensityDPIFactor;
    163         if (m_pageDefinedConstraints.minimumScale != -1)
    164             m_pageDefinedConstraints.minimumScale *= targetDensityDPIFactor;
    165         if (m_pageDefinedConstraints.maximumScale != -1)
    166             m_pageDefinedConstraints.maximumScale *= targetDensityDPIFactor;
    167         if (wideViewportQuirkEnabled && (!useWideViewport || description.maxWidth == Length(100, ViewportPercentageWidth))) {
    168             adjustedLayoutSizeWidth /= targetDensityDPIFactor;
    169             adjustedLayoutSizeHeight /= targetDensityDPIFactor;
    170         }
    171     }
    172 
    173     if (wideViewportQuirkEnabled) {
    174         if (useWideViewport && (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom) && description.zoom != 1.0f) {
    175             adjustedLayoutSizeWidth = layoutFallbackWidth;
    176             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, viewSize);
    177         } else if (!useWideViewport) {
    178             const float nonWideScale = description.zoom < 1 && !description.maxWidth.isViewportPercentage() ? -1 : oldInitialScale;
    179             adjustedLayoutSizeWidth = getLayoutWidthForNonWideViewport(viewSize, nonWideScale) / targetDensityDPIFactor;
    180             float newInitialScale = targetDensityDPIFactor;
    181             if (m_userAgentConstraints.initialScale != -1 && (description.maxWidth == Length(100, ViewportPercentageWidth) || ((description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom) && description.zoom == -1))) {
    182                 adjustedLayoutSizeWidth /= m_userAgentConstraints.initialScale;
    183                 newInitialScale = m_userAgentConstraints.initialScale;
    184             }
    185             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, viewSize);
    186             if (description.zoom < 1) {
    187                 m_pageDefinedConstraints.initialScale = newInitialScale;
    188                 if (m_pageDefinedConstraints.minimumScale != -1)
    189                     m_pageDefinedConstraints.minimumScale = std::min<float>(m_pageDefinedConstraints.minimumScale, m_pageDefinedConstraints.initialScale);
    190                 if (m_pageDefinedConstraints.maximumScale != -1)
    191                     m_pageDefinedConstraints.maximumScale = std::max<float>(m_pageDefinedConstraints.maximumScale, m_pageDefinedConstraints.initialScale);
    192             }
    193         }
    194     }
    195 
    196     if (nonUserScalableQuirkEnabled && !description.userZoom) {
    197         m_pageDefinedConstraints.initialScale = targetDensityDPIFactor;
    198         m_pageDefinedConstraints.minimumScale = m_pageDefinedConstraints.initialScale;
    199         m_pageDefinedConstraints.maximumScale = m_pageDefinedConstraints.initialScale;
    200         if (description.maxWidth.isAuto() || description.maxWidth.type() == ExtendToZoom || description.maxWidth == Length(100, ViewportPercentageWidth)) {
    201             adjustedLayoutSizeWidth = viewSize.width() / targetDensityDPIFactor;
    202             adjustedLayoutSizeHeight = computeHeightByAspectRatio(adjustedLayoutSizeWidth, viewSize);
    203         }
    204     }
    205 
    206     m_pageDefinedConstraints.layoutSize.setWidth(adjustedLayoutSizeWidth);
    207     m_pageDefinedConstraints.layoutSize.setHeight(adjustedLayoutSizeHeight);
    208 }
    209 
    210 } // namespace WebCore
    211