| /* |
| * Copyright (C) 2013 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "core/frame/PageScaleConstraintsSet.h" |
| |
| #include "platform/Length.h" |
| #include "wtf/Assertions.h" |
| |
| namespace blink { |
| |
| PageScaleConstraintsSet::PageScaleConstraintsSet() |
| : m_defaultConstraints(-1, 1, 1), |
| m_finalConstraints(computeConstraintsStack()), |
| m_lastContentsWidth(0), |
| m_needsReset(false), |
| m_constraintsDirty(false) {} |
| |
| void PageScaleConstraintsSet::setDefaultConstraints( |
| const PageScaleConstraints& defaultConstraints) { |
| m_defaultConstraints = defaultConstraints; |
| m_constraintsDirty = true; |
| } |
| |
| const PageScaleConstraints& PageScaleConstraintsSet::defaultConstraints() |
| const { |
| return m_defaultConstraints; |
| } |
| |
| void PageScaleConstraintsSet::updatePageDefinedConstraints( |
| const ViewportDescription& description, |
| Length legacyFallbackWidth) { |
| m_pageDefinedConstraints = |
| description.resolve(FloatSize(m_icbSize), legacyFallbackWidth); |
| |
| m_constraintsDirty = true; |
| } |
| |
| void PageScaleConstraintsSet::clearPageDefinedConstraints() { |
| m_pageDefinedConstraints = PageScaleConstraints(); |
| m_constraintsDirty = true; |
| } |
| |
| void PageScaleConstraintsSet::setUserAgentConstraints( |
| const PageScaleConstraints& userAgentConstraints) { |
| m_userAgentConstraints = userAgentConstraints; |
| m_constraintsDirty = true; |
| } |
| |
| void PageScaleConstraintsSet::setFullscreenConstraints( |
| const PageScaleConstraints& fullscreenConstraints) { |
| m_fullscreenConstraints = fullscreenConstraints; |
| m_constraintsDirty = true; |
| } |
| |
| PageScaleConstraints PageScaleConstraintsSet::computeConstraintsStack() const { |
| PageScaleConstraints constraints = defaultConstraints(); |
| constraints.overrideWith(m_pageDefinedConstraints); |
| constraints.overrideWith(m_userAgentConstraints); |
| constraints.overrideWith(m_fullscreenConstraints); |
| return constraints; |
| } |
| |
| void PageScaleConstraintsSet::computeFinalConstraints() { |
| m_finalConstraints = computeConstraintsStack(); |
| |
| m_constraintsDirty = false; |
| } |
| |
| void PageScaleConstraintsSet::adjustFinalConstraintsToContentsSize( |
| IntSize contentsSize, |
| int nonOverlayScrollbarWidth, |
| bool shrinksViewportContentToFit) { |
| if (shrinksViewportContentToFit) |
| m_finalConstraints.fitToContentsWidth( |
| contentsSize.width(), m_icbSize.width() - nonOverlayScrollbarWidth); |
| |
| m_finalConstraints.resolveAutoInitialScale(); |
| } |
| |
| void PageScaleConstraintsSet::setNeedsReset(bool needsReset) { |
| m_needsReset = needsReset; |
| if (needsReset) |
| m_constraintsDirty = true; |
| } |
| |
| void PageScaleConstraintsSet::didChangeContentsSize(IntSize contentsSize, |
| float pageScaleFactor) { |
| // If a large fixed-width element expanded the size of the document late in |
| // loading and our initial scale is not set (or set to be less than the last |
| // minimum scale), reset the page scale factor to the new initial scale. |
| if (contentsSize.width() > m_lastContentsWidth && |
| pageScaleFactor == finalConstraints().minimumScale && |
| computeConstraintsStack().initialScale < finalConstraints().minimumScale) |
| setNeedsReset(true); |
| |
| m_constraintsDirty = true; |
| m_lastContentsWidth = contentsSize.width(); |
| } |
| |
| static float computeDeprecatedTargetDensityDPIFactor( |
| const ViewportDescription& description, |
| float deviceScaleFactor) { |
| if (description.deprecatedTargetDensityDPI == |
| ViewportDescription::ValueDeviceDPI) |
| return 1.0f / deviceScaleFactor; |
| |
| float targetDPI = -1.0f; |
| if (description.deprecatedTargetDensityDPI == |
| ViewportDescription::ValueLowDPI) |
| targetDPI = 120.0f; |
| else if (description.deprecatedTargetDensityDPI == |
| ViewportDescription::ValueMediumDPI) |
| targetDPI = 160.0f; |
| else if (description.deprecatedTargetDensityDPI == |
| ViewportDescription::ValueHighDPI) |
| targetDPI = 240.0f; |
| else if (description.deprecatedTargetDensityDPI != |
| ViewportDescription::ValueAuto) |
| targetDPI = description.deprecatedTargetDensityDPI; |
| return targetDPI > 0 ? 160.0f / targetDPI : 1.0f; |
| } |
| |
| static float getLayoutWidthForNonWideViewport(const FloatSize& deviceSize, |
| float initialScale) { |
| return initialScale == -1 ? deviceSize.width() |
| : deviceSize.width() / initialScale; |
| } |
| |
| static float computeHeightByAspectRatio(float width, |
| const FloatSize& deviceSize) { |
| return width * (deviceSize.height() / deviceSize.width()); |
| } |
| |
| void PageScaleConstraintsSet::didChangeInitialContainingBlockSize( |
| const IntSize& size) { |
| if (m_icbSize == size) |
| return; |
| |
| m_icbSize = size; |
| m_constraintsDirty = true; |
| } |
| |
| IntSize PageScaleConstraintsSet::layoutSize() const { |
| return flooredIntSize(computeConstraintsStack().layoutSize); |
| } |
| |
| void PageScaleConstraintsSet::adjustForAndroidWebViewQuirks( |
| const ViewportDescription& description, |
| int layoutFallbackWidth, |
| float deviceScaleFactor, |
| bool supportTargetDensityDPI, |
| bool wideViewportQuirkEnabled, |
| bool useWideViewport, |
| bool loadWithOverviewMode, |
| bool nonUserScalableQuirkEnabled) { |
| if (!supportTargetDensityDPI && !wideViewportQuirkEnabled && |
| loadWithOverviewMode && !nonUserScalableQuirkEnabled) |
| return; |
| |
| const float oldInitialScale = m_pageDefinedConstraints.initialScale; |
| if (!loadWithOverviewMode) { |
| bool resetInitialScale = false; |
| if (description.zoom == -1) { |
| if (description.maxWidth.isAuto() || |
| description.maxWidth.type() == ExtendToZoom) |
| resetInitialScale = true; |
| if (useWideViewport || description.maxWidth.type() == DeviceWidth) |
| resetInitialScale = true; |
| } |
| if (resetInitialScale) |
| m_pageDefinedConstraints.initialScale = 1.0f; |
| } |
| |
| float adjustedLayoutSizeWidth = m_pageDefinedConstraints.layoutSize.width(); |
| float adjustedLayoutSizeHeight = m_pageDefinedConstraints.layoutSize.height(); |
| float targetDensityDPIFactor = 1.0f; |
| |
| if (supportTargetDensityDPI) { |
| targetDensityDPIFactor = |
| computeDeprecatedTargetDensityDPIFactor(description, deviceScaleFactor); |
| if (m_pageDefinedConstraints.initialScale != -1) |
| m_pageDefinedConstraints.initialScale *= targetDensityDPIFactor; |
| if (m_pageDefinedConstraints.minimumScale != -1) |
| m_pageDefinedConstraints.minimumScale *= targetDensityDPIFactor; |
| if (m_pageDefinedConstraints.maximumScale != -1) |
| m_pageDefinedConstraints.maximumScale *= targetDensityDPIFactor; |
| if (wideViewportQuirkEnabled && |
| (!useWideViewport || description.maxWidth.type() == DeviceWidth)) { |
| adjustedLayoutSizeWidth /= targetDensityDPIFactor; |
| adjustedLayoutSizeHeight /= targetDensityDPIFactor; |
| } |
| } |
| |
| if (wideViewportQuirkEnabled) { |
| if (useWideViewport && (description.maxWidth.isAuto() || |
| description.maxWidth.type() == ExtendToZoom) && |
| description.zoom != 1.0f) { |
| if (layoutFallbackWidth) |
| adjustedLayoutSizeWidth = layoutFallbackWidth; |
| adjustedLayoutSizeHeight = computeHeightByAspectRatio( |
| adjustedLayoutSizeWidth, FloatSize(m_icbSize)); |
| } else if (!useWideViewport) { |
| const float nonWideScale = |
| description.zoom < 1 && description.maxWidth.type() != DeviceWidth && |
| description.maxWidth.type() != DeviceHeight |
| ? -1 |
| : oldInitialScale; |
| adjustedLayoutSizeWidth = |
| getLayoutWidthForNonWideViewport(FloatSize(m_icbSize), nonWideScale) / |
| targetDensityDPIFactor; |
| float newInitialScale = targetDensityDPIFactor; |
| if (m_userAgentConstraints.initialScale != -1 && |
| (description.maxWidth.type() == DeviceWidth || |
| ((description.maxWidth.isAuto() || |
| description.maxWidth.type() == ExtendToZoom) && |
| description.zoom == -1))) { |
| adjustedLayoutSizeWidth /= m_userAgentConstraints.initialScale; |
| newInitialScale = m_userAgentConstraints.initialScale; |
| } |
| adjustedLayoutSizeHeight = computeHeightByAspectRatio( |
| adjustedLayoutSizeWidth, FloatSize(m_icbSize)); |
| if (description.zoom < 1) { |
| m_pageDefinedConstraints.initialScale = newInitialScale; |
| if (m_pageDefinedConstraints.minimumScale != -1) |
| m_pageDefinedConstraints.minimumScale = |
| std::min<float>(m_pageDefinedConstraints.minimumScale, |
| m_pageDefinedConstraints.initialScale); |
| if (m_pageDefinedConstraints.maximumScale != -1) |
| m_pageDefinedConstraints.maximumScale = |
| std::max<float>(m_pageDefinedConstraints.maximumScale, |
| m_pageDefinedConstraints.initialScale); |
| } |
| } |
| } |
| |
| if (nonUserScalableQuirkEnabled && !description.userZoom) { |
| m_pageDefinedConstraints.initialScale = targetDensityDPIFactor; |
| m_pageDefinedConstraints.minimumScale = |
| m_pageDefinedConstraints.initialScale; |
| m_pageDefinedConstraints.maximumScale = |
| m_pageDefinedConstraints.initialScale; |
| if (description.maxWidth.isAuto() || |
| description.maxWidth.type() == ExtendToZoom || |
| description.maxWidth.type() == DeviceWidth) { |
| adjustedLayoutSizeWidth = m_icbSize.width() / targetDensityDPIFactor; |
| adjustedLayoutSizeHeight = computeHeightByAspectRatio( |
| adjustedLayoutSizeWidth, FloatSize(m_icbSize)); |
| } |
| } |
| |
| m_pageDefinedConstraints.layoutSize.setWidth(adjustedLayoutSizeWidth); |
| m_pageDefinedConstraints.layoutSize.setHeight(adjustedLayoutSizeHeight); |
| } |
| |
| } // namespace blink |