• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PageScaleConstraintsSet()43 PageScaleConstraintsSet::PageScaleConstraintsSet()
44     : m_lastContentsWidth(0)
45     , m_needsReset(false)
46     , m_constraintsDirty(false)
47 {
48     m_finalConstraints = defaultConstraints();
49 }
50 
defaultConstraints() const51 PageScaleConstraints PageScaleConstraintsSet::defaultConstraints() const
52 {
53     return PageScaleConstraints(-1, defaultMinimumScale, defaultMaximumScale);
54 }
55 
updatePageDefinedConstraints(const ViewportDescription & description,IntSize viewSize)56 void PageScaleConstraintsSet::updatePageDefinedConstraints(const ViewportDescription& description, IntSize viewSize)
57 {
58     m_pageDefinedConstraints = description.resolve(viewSize);
59 
60     m_constraintsDirty = true;
61 }
62 
setUserAgentConstraints(const PageScaleConstraints & userAgentConstraints)63 void PageScaleConstraintsSet::setUserAgentConstraints(const PageScaleConstraints& userAgentConstraints)
64 {
65     m_userAgentConstraints = userAgentConstraints;
66     m_constraintsDirty = true;
67 }
68 
computeConstraintsStack() const69 PageScaleConstraints PageScaleConstraintsSet::computeConstraintsStack() const
70 {
71     PageScaleConstraints constraints = defaultConstraints();
72     constraints.overrideWith(m_pageDefinedConstraints);
73     constraints.overrideWith(m_userAgentConstraints);
74     return constraints;
75 }
76 
computeFinalConstraints()77 void PageScaleConstraintsSet::computeFinalConstraints()
78 {
79     m_finalConstraints = computeConstraintsStack();
80 
81     m_constraintsDirty = false;
82 }
83 
adjustFinalConstraintsToContentsSize(IntSize viewSize,IntSize contentsSize,int nonOverlayScrollbarWidth)84 void PageScaleConstraintsSet::adjustFinalConstraintsToContentsSize(IntSize viewSize, IntSize contentsSize, int nonOverlayScrollbarWidth)
85 {
86     m_finalConstraints.fitToContentsWidth(contentsSize.width(), viewSize.width() - nonOverlayScrollbarWidth);
87 }
88 
setNeedsReset(bool needsReset)89 void PageScaleConstraintsSet::setNeedsReset(bool needsReset)
90 {
91     m_needsReset = needsReset;
92     if (needsReset)
93         m_constraintsDirty = true;
94 }
95 
didChangeContentsSize(IntSize contentsSize,float pageScaleFactor)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 
computeDeprecatedTargetDensityDPIFactor(const ViewportDescription & description,float deviceScaleFactor)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 
getLayoutWidthForNonWideViewport(const FloatSize & deviceSize,float initialScale)127 static float getLayoutWidthForNonWideViewport(const FloatSize& deviceSize, float initialScale)
128 {
129     return initialScale == -1 ? deviceSize.width() : deviceSize.width() / initialScale;
130 }
131 
computeHeightByAspectRatio(float width,const FloatSize & deviceSize)132 static float computeHeightByAspectRatio(float width, const FloatSize& deviceSize)
133 {
134     return width * (deviceSize.height() / deviceSize.width());
135 }
136 
adjustForAndroidWebViewQuirks(const ViewportDescription & description,IntSize viewSize,int layoutFallbackWidth,float deviceScaleFactor,bool supportTargetDensityDPI,bool wideViewportQuirkEnabled,bool useWideViewport,bool loadWithOverviewMode,bool nonUserScalableQuirkEnabled)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