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