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