1 | /* |
2 | * Copyright (C) 2011, 2012 Nokia Corporation and/or its subsidiary(-ies) |
3 | * Copyright (C) 2011 Benjamin Poulain <[email protected]> |
4 | * Copyright (C) 2014 Igalia S.L. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Library General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Library General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Library General Public License |
17 | * along with this program; see the file COPYING.LIB. If not, write to |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include "config.h" |
23 | #include "SimpleViewportController.h" |
24 | |
25 | #if USE(COORDINATED_GRAPHICS) |
26 | |
27 | namespace WebKit { |
28 | using namespace WebCore; |
29 | |
30 | SimpleViewportController::SimpleViewportController(const IntSize& size) |
31 | : m_viewportSize(size) |
32 | { |
33 | resetViewportToDefaultState(); |
34 | } |
35 | |
36 | void SimpleViewportController::didChangeViewportSize(const IntSize& newSize) |
37 | { |
38 | if (newSize.isEmpty()) |
39 | return; |
40 | |
41 | m_viewportSize = newSize; |
42 | updateMinimumScaleToFit(); |
43 | } |
44 | |
45 | void SimpleViewportController::didChangeContentsSize(const IntSize& newSize) |
46 | { |
47 | m_contentsSize = newSize; |
48 | |
49 | updateMinimumScaleToFit(); |
50 | |
51 | if (m_initiallyFitToViewport) { |
52 | // Restrict scale factors to m_minimumScaleToFit. |
53 | ASSERT(m_minimumScaleToFit > 0); |
54 | m_rawAttributes.initialScale = m_minimumScaleToFit; |
55 | restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes); |
56 | } |
57 | } |
58 | |
59 | void SimpleViewportController::didChangeViewportAttributes(ViewportAttributes&& newAttributes) |
60 | { |
61 | if (newAttributes.layoutSize.isEmpty()) { |
62 | resetViewportToDefaultState(); |
63 | return; |
64 | } |
65 | |
66 | m_hasViewportAttribute = true; |
67 | |
68 | m_rawAttributes = WTFMove(newAttributes); |
69 | m_allowsUserScaling = m_rawAttributes.userScalable; |
70 | m_initiallyFitToViewport = m_rawAttributes.initialScale < 0; |
71 | |
72 | if (!m_initiallyFitToViewport) |
73 | restrictScaleFactorToInitialScaleIfNotUserScalable(m_rawAttributes); |
74 | |
75 | updateMinimumScaleToFit(); |
76 | } |
77 | |
78 | void SimpleViewportController::didScroll(const IntPoint& position) |
79 | { |
80 | m_contentsPosition = position; |
81 | } |
82 | |
83 | FloatRect SimpleViewportController::visibleContentsRect() const |
84 | { |
85 | if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty()) |
86 | return { }; |
87 | |
88 | FloatRect visibleContentsRect(boundContentsPosition(m_contentsPosition), visibleContentsSize()); |
89 | visibleContentsRect.intersect(FloatRect(FloatPoint::zero(), m_contentsSize)); |
90 | return visibleContentsRect; |
91 | } |
92 | |
93 | FloatSize SimpleViewportController::visibleContentsSize() const |
94 | { |
95 | return FloatSize(m_viewportSize.width() / m_pageScaleFactor, m_viewportSize.height() / m_pageScaleFactor); |
96 | } |
97 | |
98 | FloatPoint SimpleViewportController::boundContentsPositionAtScale(const FloatPoint& framePosition, float scale) const |
99 | { |
100 | // We need to floor the viewport here as to allow aligning the content in device units. If not, |
101 | // it might not be possible to scroll the last pixel and that affects fixed position elements. |
102 | return FloatPoint( |
103 | clampTo(framePosition.x(), .0f, std::max(.0f, m_contentsSize.width() - floorf(m_viewportSize.width() / scale))), |
104 | clampTo(framePosition.y(), .0f, std::max(.0f, m_contentsSize.height() - floorf(m_viewportSize.height() / scale)))); |
105 | } |
106 | |
107 | FloatPoint SimpleViewportController::boundContentsPosition(const FloatPoint& framePosition) const |
108 | { |
109 | return boundContentsPositionAtScale(framePosition, m_pageScaleFactor); |
110 | } |
111 | |
112 | bool fuzzyCompare(float a, float b, float epsilon) |
113 | { |
114 | return std::abs(a - b) < epsilon; |
115 | } |
116 | |
117 | bool SimpleViewportController::updateMinimumScaleToFit() |
118 | { |
119 | if (m_viewportSize.isEmpty() || m_contentsSize.isEmpty() || !m_hasViewportAttribute) |
120 | return false; |
121 | |
122 | bool currentlyScaledToFit = fuzzyCompare(m_pageScaleFactor, m_minimumScaleToFit, 0.0001); |
123 | |
124 | float minimumScale = computeMinimumScaleFactorForContentContained(m_rawAttributes, roundedIntSize(m_viewportSize), roundedIntSize(m_contentsSize)); |
125 | |
126 | if (minimumScale <= 0) |
127 | return false; |
128 | |
129 | if (!fuzzyCompare(minimumScale, m_minimumScaleToFit, 0.0001)) { |
130 | m_minimumScaleToFit = minimumScale; |
131 | |
132 | if (currentlyScaledToFit) |
133 | m_pageScaleFactor = m_minimumScaleToFit; |
134 | else { |
135 | // Ensure the effective scale stays within bounds. |
136 | float boundedScale = innerBoundedViewportScale(m_pageScaleFactor); |
137 | if (!fuzzyCompare(boundedScale, m_pageScaleFactor, 0.0001)) |
138 | m_pageScaleFactor = boundedScale; |
139 | } |
140 | |
141 | return true; |
142 | } |
143 | return false; |
144 | } |
145 | |
146 | float SimpleViewportController::innerBoundedViewportScale(float viewportScale) const |
147 | { |
148 | return clampTo(viewportScale, m_minimumScaleToFit, m_rawAttributes.maximumScale); |
149 | } |
150 | |
151 | void SimpleViewportController::resetViewportToDefaultState() |
152 | { |
153 | m_hasViewportAttribute = false; |
154 | m_pageScaleFactor = 1; |
155 | m_minimumScaleToFit = 1; |
156 | |
157 | // Initializing Viewport Raw Attributes to avoid random negative or infinity scale factors |
158 | // if there is a race condition between the first layout and setting the viewport attributes for the first time. |
159 | m_rawAttributes.minimumScale = 1; |
160 | m_rawAttributes.maximumScale = 1; |
161 | m_rawAttributes.userScalable = m_allowsUserScaling; |
162 | |
163 | // The initial scale might be implicit and set to -1, in this case we have to infer it |
164 | // using the viewport size and the final layout size. |
165 | // To be able to assert for valid scale we initialize it to -1. |
166 | m_rawAttributes.initialScale = -1; |
167 | } |
168 | |
169 | } // namespace WebCore |
170 | |
171 | #endif // USE(COORDINATED_GRAPHICS) |
172 | |