OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2010, Google Inc. All rights reserved. | |
3 * Copyright (C) 2008, 2011 Apple Inc. All Rights Reserved. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are | |
7 * met: | |
8 * | |
9 * * Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * * Redistributions in binary form must reproduce the above | |
12 * copyright notice, this list of conditions and the following disclaimer | |
13 * in the documentation and/or other materials provided with the | |
14 * distribution. | |
15 * * Neither the name of Google Inc. nor the names of its | |
16 * contributors may be used to endorse or promote products derived from | |
17 * this software without specific prior written permission. | |
18 * | |
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 */ | |
31 | |
32 #include "config.h" | |
33 #include "core/platform/ScrollableArea.h" | |
34 | |
35 #include "core/platform/ScrollAnimator.h" | |
36 #include "core/platform/ScrollbarTheme.h" | |
37 #include "core/platform/graphics/GraphicsLayer.h" | |
38 #include "platform/geometry/FloatPoint.h" | |
39 #include "wtf/PassOwnPtr.h" | |
40 | |
41 #include "platform/TraceEvent.h" | |
42 | |
43 static const int kPixelsPerLineStep = 40; | |
44 static const float kMinFractionToStepWhenPaging = 0.875f; | |
45 | |
46 namespace WebCore { | |
47 | |
48 struct SameSizeAsScrollableArea { | |
49 virtual ~SameSizeAsScrollableArea(); | |
50 void* pointer; | |
51 unsigned bitfields : 16; | |
52 IntPoint origin; | |
53 }; | |
54 | |
55 COMPILE_ASSERT(sizeof(ScrollableArea) == sizeof(SameSizeAsScrollableArea), Scrol
lableArea_should_stay_small); | |
56 | |
57 int ScrollableArea::pixelsPerLineStep() | |
58 { | |
59 return kPixelsPerLineStep; | |
60 } | |
61 | |
62 float ScrollableArea::minFractionToStepWhenPaging() | |
63 { | |
64 return kMinFractionToStepWhenPaging; | |
65 } | |
66 | |
67 int ScrollableArea::maxOverlapBetweenPages() | |
68 { | |
69 static int maxOverlapBetweenPages = ScrollbarTheme::theme()->maxOverlapBetwe
enPages(); | |
70 return maxOverlapBetweenPages; | |
71 } | |
72 | |
73 ScrollableArea::ScrollableArea() | |
74 : m_constrainsScrollingToContentEdge(true) | |
75 , m_inLiveResize(false) | |
76 , m_verticalScrollElasticity(ScrollElasticityNone) | |
77 , m_horizontalScrollElasticity(ScrollElasticityNone) | |
78 , m_scrollbarOverlayStyle(ScrollbarOverlayStyleDefault) | |
79 , m_scrollOriginChanged(false) | |
80 { | |
81 } | |
82 | |
83 ScrollableArea::~ScrollableArea() | |
84 { | |
85 } | |
86 | |
87 ScrollAnimator* ScrollableArea::scrollAnimator() const | |
88 { | |
89 if (!m_scrollAnimator) | |
90 m_scrollAnimator = ScrollAnimator::create(const_cast<ScrollableArea*>(th
is)); | |
91 | |
92 return m_scrollAnimator.get(); | |
93 } | |
94 | |
95 void ScrollableArea::setScrollOrigin(const IntPoint& origin) | |
96 { | |
97 if (m_scrollOrigin != origin) { | |
98 m_scrollOrigin = origin; | |
99 m_scrollOriginChanged = true; | |
100 } | |
101 } | |
102 | |
103 bool ScrollableArea::scroll(ScrollDirection direction, ScrollGranularity granula
rity, float multiplier) | |
104 { | |
105 ScrollbarOrientation orientation; | |
106 | |
107 if (direction == ScrollUp || direction == ScrollDown) | |
108 orientation = VerticalScrollbar; | |
109 else | |
110 orientation = HorizontalScrollbar; | |
111 | |
112 if (!userInputScrollable(orientation)) | |
113 return false; | |
114 | |
115 float step = 0; | |
116 switch (granularity) { | |
117 case ScrollByLine: | |
118 step = lineStep(orientation); | |
119 break; | |
120 case ScrollByPage: | |
121 step = pageStep(orientation); | |
122 break; | |
123 case ScrollByDocument: | |
124 step = documentStep(orientation); | |
125 break; | |
126 case ScrollByPixel: | |
127 case ScrollByPrecisePixel: | |
128 step = pixelStep(orientation); | |
129 break; | |
130 } | |
131 | |
132 if (direction == ScrollUp || direction == ScrollLeft) | |
133 multiplier = -multiplier; | |
134 | |
135 return scrollAnimator()->scroll(orientation, granularity, step, multiplier); | |
136 } | |
137 | |
138 void ScrollableArea::scrollToOffsetWithoutAnimation(const FloatPoint& offset) | |
139 { | |
140 scrollAnimator()->scrollToOffsetWithoutAnimation(offset); | |
141 } | |
142 | |
143 void ScrollableArea::scrollToOffsetWithoutAnimation(ScrollbarOrientation orienta
tion, float offset) | |
144 { | |
145 if (orientation == HorizontalScrollbar) | |
146 scrollToOffsetWithoutAnimation(FloatPoint(offset, scrollAnimator()->curr
entPosition().y())); | |
147 else | |
148 scrollToOffsetWithoutAnimation(FloatPoint(scrollAnimator()->currentPosit
ion().x(), offset)); | |
149 } | |
150 | |
151 void ScrollableArea::notifyScrollPositionChanged(const IntPoint& position) | |
152 { | |
153 scrollPositionChanged(position); | |
154 scrollAnimator()->setCurrentPosition(position); | |
155 } | |
156 | |
157 void ScrollableArea::scrollPositionChanged(const IntPoint& position) | |
158 { | |
159 TRACE_EVENT0("webkit", "ScrollableArea::scrollPositionChanged"); | |
160 | |
161 IntPoint oldPosition = scrollPosition(); | |
162 // Tell the derived class to scroll its contents. | |
163 setScrollOffset(position); | |
164 | |
165 Scrollbar* verticalScrollbar = this->verticalScrollbar(); | |
166 | |
167 // Tell the scrollbars to update their thumb postions. | |
168 if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { | |
169 horizontalScrollbar->offsetDidChange(); | |
170 if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalS
crollbar()) { | |
171 if (!verticalScrollbar) | |
172 horizontalScrollbar->invalidate(); | |
173 else { | |
174 // If there is both a horizontalScrollbar and a verticalScrollba
r, | |
175 // then we must also invalidate the corner between them. | |
176 IntRect boundsAndCorner = horizontalScrollbar->boundsRect(); | |
177 boundsAndCorner.setWidth(boundsAndCorner.width() + verticalScrol
lbar->width()); | |
178 horizontalScrollbar->invalidateRect(boundsAndCorner); | |
179 } | |
180 } | |
181 } | |
182 if (verticalScrollbar) { | |
183 verticalScrollbar->offsetDidChange(); | |
184 if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrol
lbar()) | |
185 verticalScrollbar->invalidate(); | |
186 } | |
187 | |
188 if (scrollPosition() != oldPosition) | |
189 scrollAnimator()->notifyContentAreaScrolled(scrollPosition() - oldPositi
on); | |
190 } | |
191 | |
192 bool ScrollableArea::handleWheelEvent(const PlatformWheelEvent& wheelEvent) | |
193 { | |
194 return scrollAnimator()->handleWheelEvent(wheelEvent); | |
195 } | |
196 | |
197 // NOTE: Only called from Internals for testing. | |
198 void ScrollableArea::setScrollOffsetFromInternals(const IntPoint& offset) | |
199 { | |
200 setScrollOffsetFromAnimation(offset); | |
201 } | |
202 | |
203 void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset) | |
204 { | |
205 scrollPositionChanged(offset); | |
206 } | |
207 | |
208 void ScrollableArea::willStartLiveResize() | |
209 { | |
210 if (m_inLiveResize) | |
211 return; | |
212 m_inLiveResize = true; | |
213 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
214 scrollAnimator->willStartLiveResize(); | |
215 } | |
216 | |
217 void ScrollableArea::willEndLiveResize() | |
218 { | |
219 if (!m_inLiveResize) | |
220 return; | |
221 m_inLiveResize = false; | |
222 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
223 scrollAnimator->willEndLiveResize(); | |
224 } | |
225 | |
226 void ScrollableArea::contentAreaWillPaint() const | |
227 { | |
228 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
229 scrollAnimator->contentAreaWillPaint(); | |
230 } | |
231 | |
232 void ScrollableArea::mouseEnteredContentArea() const | |
233 { | |
234 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
235 scrollAnimator->mouseEnteredContentArea(); | |
236 } | |
237 | |
238 void ScrollableArea::mouseExitedContentArea() const | |
239 { | |
240 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
241 scrollAnimator->mouseEnteredContentArea(); | |
242 } | |
243 | |
244 void ScrollableArea::mouseMovedInContentArea() const | |
245 { | |
246 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
247 scrollAnimator->mouseMovedInContentArea(); | |
248 } | |
249 | |
250 void ScrollableArea::mouseEnteredScrollbar(Scrollbar* scrollbar) const | |
251 { | |
252 scrollAnimator()->mouseEnteredScrollbar(scrollbar); | |
253 } | |
254 | |
255 void ScrollableArea::mouseExitedScrollbar(Scrollbar* scrollbar) const | |
256 { | |
257 scrollAnimator()->mouseExitedScrollbar(scrollbar); | |
258 } | |
259 | |
260 void ScrollableArea::contentAreaDidShow() const | |
261 { | |
262 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
263 scrollAnimator->contentAreaDidShow(); | |
264 } | |
265 | |
266 void ScrollableArea::contentAreaDidHide() const | |
267 { | |
268 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
269 scrollAnimator->contentAreaDidHide(); | |
270 } | |
271 | |
272 void ScrollableArea::finishCurrentScrollAnimations() const | |
273 { | |
274 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
275 scrollAnimator->finishCurrentScrollAnimations(); | |
276 } | |
277 | |
278 void ScrollableArea::didAddScrollbar(Scrollbar* scrollbar, ScrollbarOrientation
orientation) | |
279 { | |
280 if (orientation == VerticalScrollbar) | |
281 scrollAnimator()->didAddVerticalScrollbar(scrollbar); | |
282 else | |
283 scrollAnimator()->didAddHorizontalScrollbar(scrollbar); | |
284 | |
285 // <rdar://problem/9797253> AppKit resets the scrollbar's style when you att
ach a scrollbar | |
286 setScrollbarOverlayStyle(scrollbarOverlayStyle()); | |
287 } | |
288 | |
289 void ScrollableArea::willRemoveScrollbar(Scrollbar* scrollbar, ScrollbarOrientat
ion orientation) | |
290 { | |
291 if (orientation == VerticalScrollbar) | |
292 scrollAnimator()->willRemoveVerticalScrollbar(scrollbar); | |
293 else | |
294 scrollAnimator()->willRemoveHorizontalScrollbar(scrollbar); | |
295 } | |
296 | |
297 void ScrollableArea::contentsResized() | |
298 { | |
299 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
300 scrollAnimator->contentsResized(); | |
301 } | |
302 | |
303 bool ScrollableArea::hasOverlayScrollbars() const | |
304 { | |
305 return (verticalScrollbar() && verticalScrollbar()->isOverlayScrollbar()) | |
306 || (horizontalScrollbar() && horizontalScrollbar()->isOverlayScrollbar()
); | |
307 } | |
308 | |
309 void ScrollableArea::setScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle
) | |
310 { | |
311 m_scrollbarOverlayStyle = overlayStyle; | |
312 | |
313 if (horizontalScrollbar()) { | |
314 ScrollbarTheme::theme()->updateScrollbarOverlayStyle(horizontalScrollbar
()); | |
315 horizontalScrollbar()->invalidate(); | |
316 } | |
317 | |
318 if (verticalScrollbar()) { | |
319 ScrollbarTheme::theme()->updateScrollbarOverlayStyle(verticalScrollbar()
); | |
320 verticalScrollbar()->invalidate(); | |
321 } | |
322 } | |
323 | |
324 void ScrollableArea::invalidateScrollbar(Scrollbar* scrollbar, const IntRect& re
ct) | |
325 { | |
326 if (scrollbar == horizontalScrollbar()) { | |
327 if (GraphicsLayer* graphicsLayer = layerForHorizontalScrollbar()) { | |
328 graphicsLayer->setNeedsDisplay(); | |
329 graphicsLayer->setContentsNeedsDisplay(); | |
330 return; | |
331 } | |
332 } else if (scrollbar == verticalScrollbar()) { | |
333 if (GraphicsLayer* graphicsLayer = layerForVerticalScrollbar()) { | |
334 graphicsLayer->setNeedsDisplay(); | |
335 graphicsLayer->setContentsNeedsDisplay(); | |
336 return; | |
337 } | |
338 } | |
339 invalidateScrollbarRect(scrollbar, rect); | |
340 } | |
341 | |
342 void ScrollableArea::invalidateScrollCorner(const IntRect& rect) | |
343 { | |
344 if (GraphicsLayer* graphicsLayer = layerForScrollCorner()) { | |
345 graphicsLayer->setNeedsDisplay(); | |
346 return; | |
347 } | |
348 invalidateScrollCornerRect(rect); | |
349 } | |
350 | |
351 bool ScrollableArea::hasLayerForHorizontalScrollbar() const | |
352 { | |
353 return layerForHorizontalScrollbar(); | |
354 } | |
355 | |
356 bool ScrollableArea::hasLayerForVerticalScrollbar() const | |
357 { | |
358 return layerForVerticalScrollbar(); | |
359 } | |
360 | |
361 bool ScrollableArea::hasLayerForScrollCorner() const | |
362 { | |
363 return layerForScrollCorner(); | |
364 } | |
365 | |
366 void ScrollableArea::serviceScrollAnimations() | |
367 { | |
368 if (ScrollAnimator* scrollAnimator = existingScrollAnimator()) | |
369 scrollAnimator->serviceScrollAnimations(); | |
370 } | |
371 | |
372 IntRect ScrollableArea::visibleContentRect(IncludeScrollbarsInRect scrollbarIncl
usion) const | |
373 { | |
374 int verticalScrollbarWidth = 0; | |
375 int horizontalScrollbarHeight = 0; | |
376 | |
377 if (scrollbarInclusion == IncludeScrollbars) { | |
378 if (Scrollbar* verticalBar = verticalScrollbar()) | |
379 verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? vertic
alBar->width() : 0; | |
380 if (Scrollbar* horizontalBar = horizontalScrollbar()) | |
381 horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? h
orizontalBar->height() : 0; | |
382 } | |
383 | |
384 return IntRect(scrollPosition().x(), | |
385 scrollPosition().y(), | |
386 std::max(0, visibleWidth() + verticalScrollbarWidth), | |
387 std::max(0, visibleHeight() + horizontalScrollbarHeight)); | |
388 } | |
389 | |
390 IntPoint ScrollableArea::clampScrollPosition(const IntPoint& scrollPosition) con
st | |
391 { | |
392 return scrollPosition.shrunkTo(maximumScrollPosition()).expandedTo(minimumSc
rollPosition()); | |
393 } | |
394 | |
395 int ScrollableArea::lineStep(ScrollbarOrientation) const | |
396 { | |
397 return pixelsPerLineStep(); | |
398 } | |
399 | |
400 int ScrollableArea::documentStep(ScrollbarOrientation orientation) const | |
401 { | |
402 return scrollSize(orientation); | |
403 } | |
404 | |
405 float ScrollableArea::pixelStep(ScrollbarOrientation) const | |
406 { | |
407 return 1; | |
408 } | |
409 | |
410 } // namespace WebCore | |
OLD | NEW |