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