OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006, 2007, 2008 Apple 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 | |
6 * are met: | |
7 * 1. Redistributions of source code must retain the above copyright | |
8 * notice, this list of conditions and the following disclaimer. | |
9 * 2. Redistributions in binary form must reproduce the above copyright | |
10 * notice, this list of conditions and the following disclaimer in the | |
11 * documentation and/or other materials provided with the distribution. | |
12 * | |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "platform/scroll/ScrollView.h" | |
28 | |
29 #include "platform/graphics/GraphicsContextStateSaver.h" | |
30 #include "platform/graphics/GraphicsLayer.h" | |
31 #include "platform/HostWindow.h" | |
32 #include "platform/scroll/Scrollbar.h" | |
33 #include "wtf/StdLibExtras.h" | |
34 | |
35 namespace blink { | |
36 | |
37 ScrollView::ScrollView() | |
38 : m_horizontalScrollbarMode(ScrollbarAuto) | |
39 , m_verticalScrollbarMode(ScrollbarAuto) | |
40 , m_horizontalScrollbarLock(false) | |
41 , m_verticalScrollbarLock(false) | |
42 , m_scrollbarsSuppressed(false) | |
43 , m_inUpdateScrollbars(false) | |
44 , m_paintsEntireContents(false) | |
45 , m_clipsRepaints(true) | |
46 { | |
47 } | |
48 | |
49 ScrollView::~ScrollView() | |
50 { | |
51 } | |
52 | |
53 void ScrollView::addChild(PassRefPtr<Widget> prpChild) | |
54 { | |
55 Widget* child = prpChild.get(); | |
56 ASSERT(child != this && !child->parent()); | |
57 child->setParent(this); | |
58 m_children.add(prpChild); | |
59 } | |
60 | |
61 void ScrollView::removeChild(Widget* child) | |
62 { | |
63 ASSERT(child->parent() == this); | |
64 child->setParent(0); | |
65 m_children.remove(child); | |
66 } | |
67 | |
68 void ScrollView::setHasHorizontalScrollbar(bool hasBar) | |
69 { | |
70 if (hasBar && !m_horizontalScrollbar) { | |
71 m_horizontalScrollbar = createScrollbar(HorizontalScrollbar); | |
72 addChild(m_horizontalScrollbar.get()); | |
73 didAddScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar); | |
74 m_horizontalScrollbar->styleChanged(); | |
75 } else if (!hasBar && m_horizontalScrollbar) { | |
76 willRemoveScrollbar(m_horizontalScrollbar.get(), HorizontalScrollbar); | |
77 removeChild(m_horizontalScrollbar.get()); | |
78 m_horizontalScrollbar = nullptr; | |
79 } | |
80 } | |
81 | |
82 void ScrollView::setHasVerticalScrollbar(bool hasBar) | |
83 { | |
84 if (hasBar && !m_verticalScrollbar) { | |
85 m_verticalScrollbar = createScrollbar(VerticalScrollbar); | |
86 addChild(m_verticalScrollbar.get()); | |
87 didAddScrollbar(m_verticalScrollbar.get(), VerticalScrollbar); | |
88 m_verticalScrollbar->styleChanged(); | |
89 } else if (!hasBar && m_verticalScrollbar) { | |
90 willRemoveScrollbar(m_verticalScrollbar.get(), VerticalScrollbar); | |
91 removeChild(m_verticalScrollbar.get()); | |
92 m_verticalScrollbar = nullptr; | |
93 } | |
94 } | |
95 | |
96 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientati
on) | |
97 { | |
98 return Scrollbar::create(this, orientation); | |
99 } | |
100 | |
101 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode v
erticalMode, | |
102 bool horizontalLock, bool verticalLock) | |
103 { | |
104 bool needsUpdate = false; | |
105 | |
106 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLoc
k) { | |
107 m_horizontalScrollbarMode = horizontalMode; | |
108 needsUpdate = true; | |
109 } | |
110 | |
111 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) { | |
112 m_verticalScrollbarMode = verticalMode; | |
113 needsUpdate = true; | |
114 } | |
115 | |
116 if (horizontalLock) | |
117 setHorizontalScrollbarLock(); | |
118 | |
119 if (verticalLock) | |
120 setVerticalScrollbarLock(); | |
121 | |
122 if (!needsUpdate) | |
123 return; | |
124 | |
125 updateScrollbars(scrollOffset()); | |
126 | |
127 if (!layerForScrolling()) | |
128 return; | |
129 blink::WebLayer* layer = layerForScrolling()->platformLayer(); | |
130 if (!layer) | |
131 return; | |
132 layer->setUserScrollable(userInputScrollable(HorizontalScrollbar), userInput
Scrollable(VerticalScrollbar)); | |
133 } | |
134 | |
135 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& ve
rticalMode) const | |
136 { | |
137 horizontalMode = m_horizontalScrollbarMode; | |
138 verticalMode = m_verticalScrollbarMode; | |
139 } | |
140 | |
141 void ScrollView::setCanHaveScrollbars(bool canScroll) | |
142 { | |
143 ScrollbarMode newHorizontalMode; | |
144 ScrollbarMode newVerticalMode; | |
145 | |
146 scrollbarModes(newHorizontalMode, newVerticalMode); | |
147 | |
148 if (canScroll && newVerticalMode == ScrollbarAlwaysOff) | |
149 newVerticalMode = ScrollbarAuto; | |
150 else if (!canScroll) | |
151 newVerticalMode = ScrollbarAlwaysOff; | |
152 | |
153 if (canScroll && newHorizontalMode == ScrollbarAlwaysOff) | |
154 newHorizontalMode = ScrollbarAuto; | |
155 else if (!canScroll) | |
156 newHorizontalMode = ScrollbarAlwaysOff; | |
157 | |
158 setScrollbarModes(newHorizontalMode, newVerticalMode); | |
159 } | |
160 | |
161 void ScrollView::setPaintsEntireContents(bool paintsEntireContents) | |
162 { | |
163 m_paintsEntireContents = paintsEntireContents; | |
164 } | |
165 | |
166 void ScrollView::setClipsRepaints(bool clipsRepaints) | |
167 { | |
168 m_clipsRepaints = clipsRepaints; | |
169 } | |
170 | |
171 IntSize ScrollView::unscaledVisibleContentSize(IncludeScrollbarsInRect scrollbar
Inclusion) const | |
172 { | |
173 return scrollbarInclusion == ExcludeScrollbars ? excludeScrollbars(frameRect
().size()) : frameRect().size(); | |
174 } | |
175 | |
176 IntSize ScrollView::excludeScrollbars(const IntSize& size) const | |
177 { | |
178 int verticalScrollbarWidth = 0; | |
179 int horizontalScrollbarHeight = 0; | |
180 | |
181 if (Scrollbar* verticalBar = verticalScrollbar()) | |
182 verticalScrollbarWidth = !verticalBar->isOverlayScrollbar() ? verticalBa
r->width() : 0; | |
183 if (Scrollbar* horizontalBar = horizontalScrollbar()) | |
184 horizontalScrollbarHeight = !horizontalBar->isOverlayScrollbar() ? horiz
ontalBar->height() : 0; | |
185 | |
186 return IntSize(std::max(0, size.width() - verticalScrollbarWidth), | |
187 std::max(0, size.height() - horizontalScrollbarHeight)); | |
188 | |
189 } | |
190 | |
191 IntRect ScrollView::visibleContentRect(IncludeScrollbarsInRect scollbarInclusion
) const | |
192 { | |
193 FloatSize visibleContentSize = unscaledVisibleContentSize(scollbarInclusion)
; | |
194 visibleContentSize.scale(1 / visibleContentScaleFactor()); | |
195 return IntRect(IntPoint(m_scrollOffset), expandedIntSize(visibleContentSize)
); | |
196 } | |
197 | |
198 IntSize ScrollView::contentsSize() const | |
199 { | |
200 return m_contentsSize; | |
201 } | |
202 | |
203 void ScrollView::setContentsSize(const IntSize& newSize) | |
204 { | |
205 if (contentsSize() == newSize) | |
206 return; | |
207 m_contentsSize = newSize; | |
208 updateScrollbars(scrollOffset()); | |
209 updateOverhangAreas(); | |
210 } | |
211 | |
212 IntPoint ScrollView::maximumScrollPosition() const | |
213 { | |
214 IntPoint maximumOffset(contentsWidth() - visibleWidth() - scrollOrigin().x()
, contentsHeight() - visibleHeight() - scrollOrigin().y()); | |
215 maximumOffset.clampNegativeToZero(); | |
216 return maximumOffset; | |
217 } | |
218 | |
219 IntPoint ScrollView::minimumScrollPosition() const | |
220 { | |
221 return IntPoint(-scrollOrigin().x(), -scrollOrigin().y()); | |
222 } | |
223 | |
224 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint
) const | |
225 { | |
226 if (!constrainsScrollingToContentEdge()) | |
227 return scrollPoint; | |
228 | |
229 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition()); | |
230 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition()); | |
231 return newScrollPosition; | |
232 } | |
233 | |
234 void ScrollView::adjustScrollbarOpacity() | |
235 { | |
236 if (m_horizontalScrollbar && layerForHorizontalScrollbar()) { | |
237 bool isOpaqueScrollbar = !m_horizontalScrollbar->isOverlayScrollbar(); | |
238 layerForHorizontalScrollbar()->setContentsOpaque(isOpaqueScrollbar); | |
239 } | |
240 if (m_verticalScrollbar && layerForVerticalScrollbar()) { | |
241 bool isOpaqueScrollbar = !m_verticalScrollbar->isOverlayScrollbar(); | |
242 layerForVerticalScrollbar()->setContentsOpaque(isOpaqueScrollbar); | |
243 } | |
244 } | |
245 | |
246 int ScrollView::scrollSize(ScrollbarOrientation orientation) const | |
247 { | |
248 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalS
crollbar : m_verticalScrollbar).get(); | |
249 | |
250 // If no scrollbars are present, the content may still be scrollable. | |
251 if (!scrollbar) { | |
252 IntSize scrollSize = m_contentsSize - visibleContentRect().size(); | |
253 scrollSize.clampNegativeToZero(); | |
254 return orientation == HorizontalScrollbar ? scrollSize.width() : scrollS
ize.height(); | |
255 } | |
256 | |
257 return scrollbar->totalSize() - scrollbar->visibleSize(); | |
258 } | |
259 | |
260 void ScrollView::notifyPageThatContentAreaWillPaint() const | |
261 { | |
262 } | |
263 | |
264 void ScrollView::setScrollOffset(const IntPoint& offset) | |
265 { | |
266 scrollTo(toIntSize(adjustScrollPositionWithinRange(offset))); | |
267 } | |
268 | |
269 void ScrollView::scrollTo(const IntSize& newOffset) | |
270 { | |
271 IntSize scrollDelta = newOffset - m_scrollOffset; | |
272 if (scrollDelta == IntSize()) | |
273 return; | |
274 m_scrollOffset = newOffset; | |
275 | |
276 if (scrollbarsSuppressed()) | |
277 return; | |
278 | |
279 if (isFrameView()) | |
280 m_pendingScrollDelta += scrollDelta; | |
281 else | |
282 scrollContents(scrollDelta); | |
283 } | |
284 | |
285 void ScrollView::setScrollPosition(const IntPoint& scrollPoint, ScrollBehavior s
crollBehavior) | |
286 { | |
287 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint); | |
288 | |
289 if (newScrollPosition == scrollPosition()) | |
290 return; | |
291 | |
292 if (scrollBehavior == ScrollBehaviorInstant) | |
293 updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y())); | |
294 else | |
295 programmaticallyScrollSmoothlyToOffset(newScrollPosition); | |
296 } | |
297 | |
298 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity
) | |
299 { | |
300 return ScrollableArea::scroll(direction, granularity); | |
301 } | |
302 | |
303 IntSize ScrollView::overhangAmount() const | |
304 { | |
305 IntSize stretch; | |
306 | |
307 IntPoint currentScrollPosition = scrollPosition(); | |
308 IntPoint minScrollPosition = minimumScrollPosition(); | |
309 IntPoint maxScrollPosition = maximumScrollPosition(); | |
310 | |
311 if (currentScrollPosition.x() < minScrollPosition.x()) | |
312 stretch.setWidth(currentScrollPosition.x() - minScrollPosition.x()); | |
313 if (currentScrollPosition.x() > maxScrollPosition.x()) | |
314 stretch.setWidth(currentScrollPosition.x() - maxScrollPosition.x()); | |
315 | |
316 if (currentScrollPosition.y() < minScrollPosition.y()) | |
317 stretch.setHeight(currentScrollPosition.y() - minScrollPosition.y()); | |
318 if (currentScrollPosition.y() > maxScrollPosition.y()) | |
319 stretch.setHeight(currentScrollPosition.y() - maxScrollPosition.y()); | |
320 | |
321 return stretch; | |
322 } | |
323 | |
324 void ScrollView::computeScrollbarExistence(bool& newHasHorizontalScrollbar, bool
& newHasVerticalScrollbar, const IntSize& docSize, ComputeScrollbarExistenceOpti
on option) const | |
325 { | |
326 bool hasHorizontalScrollbar = m_horizontalScrollbar; | |
327 bool hasVerticalScrollbar = m_verticalScrollbar; | |
328 | |
329 newHasHorizontalScrollbar = hasHorizontalScrollbar; | |
330 newHasVerticalScrollbar = hasVerticalScrollbar; | |
331 | |
332 ScrollbarMode hScroll = m_horizontalScrollbarMode; | |
333 ScrollbarMode vScroll = m_verticalScrollbarMode; | |
334 | |
335 if (hScroll != ScrollbarAuto) | |
336 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn); | |
337 if (vScroll != ScrollbarAuto) | |
338 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn); | |
339 | |
340 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != Scroll
barAuto)) | |
341 return; | |
342 | |
343 if (hScroll == ScrollbarAuto) | |
344 newHasHorizontalScrollbar = docSize.width() > visibleWidth(); | |
345 if (vScroll == ScrollbarAuto) | |
346 newHasVerticalScrollbar = docSize.height() > visibleHeight(); | |
347 } | |
348 | |
349 void ScrollView::updateScrollbarGeometry() | |
350 { | |
351 if (m_horizontalScrollbar) { | |
352 int clientWidth = visibleWidth(); | |
353 IntRect oldRect(m_horizontalScrollbar->frameRect()); | |
354 IntRect hBarRect((shouldPlaceVerticalScrollbarOnLeft() && m_verticalScro
llbar) ? m_verticalScrollbar->width() : 0, | |
355 height() - m_horizontalScrollbar->height(), | |
356 width() - (m_verticalScrollbar ? m_verticalScrollbar->wi
dth() : 0), | |
357 m_horizontalScrollbar->height()); | |
358 m_horizontalScrollbar->setFrameRect(hBarRect); | |
359 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRe
ct()) | |
360 m_horizontalScrollbar->invalidate(); | |
361 | |
362 if (m_scrollbarsSuppressed) | |
363 m_horizontalScrollbar->setSuppressInvalidation(true); | |
364 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth); | |
365 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth()); | |
366 m_horizontalScrollbar->offsetDidChange(); | |
367 if (m_scrollbarsSuppressed) | |
368 m_horizontalScrollbar->setSuppressInvalidation(false); | |
369 } | |
370 | |
371 if (m_verticalScrollbar) { | |
372 int clientHeight = visibleHeight(); | |
373 IntRect oldRect(m_verticalScrollbar->frameRect()); | |
374 IntRect vBarRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (width() - m
_verticalScrollbar->width()), | |
375 0, | |
376 m_verticalScrollbar->width(), | |
377 height() - (m_horizontalScrollbar ? m_horizontalScrollb
ar->height() : 0)); | |
378 m_verticalScrollbar->setFrameRect(vBarRect); | |
379 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect
()) | |
380 m_verticalScrollbar->invalidate(); | |
381 | |
382 if (m_scrollbarsSuppressed) | |
383 m_verticalScrollbar->setSuppressInvalidation(true); | |
384 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight); | |
385 m_verticalScrollbar->setProportion(clientHeight, contentsHeight()); | |
386 m_verticalScrollbar->offsetDidChange(); | |
387 if (m_scrollbarsSuppressed) | |
388 m_verticalScrollbar->setSuppressInvalidation(false); | |
389 } | |
390 } | |
391 | |
392 bool ScrollView::adjustScrollbarExistence(ComputeScrollbarExistenceOption option
) | |
393 { | |
394 ASSERT(m_inUpdateScrollbars); | |
395 | |
396 // If we came in here with the view already needing a layout, then go ahead
and do that | |
397 // first. (This will be the common case, e.g., when the page changes due to
window resizing for example). | |
398 // This layout will not re-enter updateScrollbars and does not count towards
our max layout pass total. | |
399 if (!m_scrollbarsSuppressed) | |
400 scrollbarExistenceDidChange(); | |
401 | |
402 bool hasHorizontalScrollbar = m_horizontalScrollbar; | |
403 bool hasVerticalScrollbar = m_verticalScrollbar; | |
404 | |
405 bool newHasHorizontalScrollbar = false; | |
406 bool newHasVerticalScrollbar = false; | |
407 computeScrollbarExistence(newHasHorizontalScrollbar, newHasVerticalScrollbar
, contentsSize(), option); | |
408 | |
409 bool scrollbarExistenceChanged = hasHorizontalScrollbar != newHasHorizontalS
crollbar || hasVerticalScrollbar != newHasVerticalScrollbar; | |
410 if (!scrollbarExistenceChanged) | |
411 return false; | |
412 | |
413 setHasHorizontalScrollbar(newHasHorizontalScrollbar); | |
414 setHasVerticalScrollbar(newHasVerticalScrollbar); | |
415 | |
416 if (m_scrollbarsSuppressed) | |
417 return true; | |
418 | |
419 scrollbarExistenceDidChange(); | |
420 return true; | |
421 } | |
422 | |
423 void ScrollView::updateScrollbars(const IntSize& desiredOffset) | |
424 { | |
425 if (m_inUpdateScrollbars) | |
426 return; | |
427 InUpdateScrollbarsScope inUpdateScrollbarsScope(this); | |
428 | |
429 IntSize oldVisibleSize = visibleSize(); | |
430 | |
431 bool scrollbarExistenceChanged = false; | |
432 int maxUpdateScrollbarsPass = 1; | |
433 for (int updateScrollbarsPass = 0; updateScrollbarsPass < maxUpdateScrollbar
sPass; updateScrollbarsPass++) { | |
434 if (!adjustScrollbarExistence(updateScrollbarsPass ? Incremental : First
Pass)) | |
435 break; | |
436 scrollbarExistenceChanged = true; | |
437 } | |
438 | |
439 updateScrollbarGeometry(); | |
440 | |
441 if (scrollbarExistenceChanged) { | |
442 // FIXME: Is frameRectsChanged really necessary here? Have any frame rec
ts changed? | |
443 frameRectsChanged(); | |
444 positionScrollbarLayers(); | |
445 updateScrollCorner(); | |
446 } | |
447 | |
448 // FIXME: We don't need to do this if we are composited. | |
449 IntSize newVisibleSize = visibleSize(); | |
450 if (newVisibleSize.width() > oldVisibleSize.width()) { | |
451 if (shouldPlaceVerticalScrollbarOnLeft()) | |
452 invalidateRect(IntRect(0, 0, newVisibleSize.width() - oldVisibleSize
.width(), newVisibleSize.height())); | |
453 else | |
454 invalidateRect(IntRect(oldVisibleSize.width(), 0, newVisibleSize.wid
th() - oldVisibleSize.width(), newVisibleSize.height())); | |
455 } | |
456 if (newVisibleSize.height() > oldVisibleSize.height()) | |
457 invalidateRect(IntRect(0, oldVisibleSize.height(), newVisibleSize.width(
), newVisibleSize.height() - oldVisibleSize.height())); | |
458 | |
459 IntPoint adjustedScrollPosition = IntPoint(desiredOffset); | |
460 if (!isRubberBandInProgress()) | |
461 adjustedScrollPosition = adjustScrollPositionWithinRange(adjustedScrollP
osition); | |
462 if (adjustedScrollPosition != scrollPosition() || scrollOriginChanged()) { | |
463 ScrollableArea::scrollToOffsetWithoutAnimation(adjustedScrollPosition); | |
464 resetScrollOriginChanged(); | |
465 } | |
466 } | |
467 | |
468 IntRect ScrollView::rectToCopyOnScroll() const | |
469 { | |
470 IntRect scrollViewRect = convertToRootView(IntRect((shouldPlaceVerticalScrol
lbarOnLeft() && verticalScrollbar()) ? verticalScrollbar()->width() : 0, 0, visi
bleWidth(), visibleHeight())); | |
471 if (hasOverlayScrollbars()) { | |
472 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVertica
lScrollbar()) ? verticalScrollbar()->width() : 0; | |
473 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHo
rizontalScrollbar()) ? horizontalScrollbar()->height() : 0; | |
474 | |
475 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth)
; | |
476 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHe
ight); | |
477 } | |
478 return scrollViewRect; | |
479 } | |
480 | |
481 void ScrollView::scrollContentsIfNeeded() | |
482 { | |
483 if (m_pendingScrollDelta.isZero()) | |
484 return; | |
485 IntSize scrollDelta = m_pendingScrollDelta; | |
486 m_pendingScrollDelta = IntSize(); | |
487 scrollContents(scrollDelta); | |
488 } | |
489 | |
490 void ScrollView::scrollContents(const IntSize& scrollDelta) | |
491 { | |
492 HostWindow* window = hostWindow(); | |
493 if (!window) | |
494 return; | |
495 | |
496 IntRect clipRect = windowClipRect(); | |
497 IntRect updateRect = clipRect; | |
498 updateRect.intersect(rectToCopyOnScroll()); | |
499 | |
500 if (!scrollContentsFastPath(-scrollDelta)) | |
501 scrollContentsSlowPath(updateRect); | |
502 | |
503 // Invalidate the overhang areas if they are visible. | |
504 updateOverhangAreas(); | |
505 | |
506 // This call will move children with native widgets (plugins) and invalidate
them as well. | |
507 frameRectsChanged(); | |
508 } | |
509 | |
510 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect) | |
511 { | |
512 hostWindow()->invalidateContentsForSlowScroll(updateRect); | |
513 } | |
514 | |
515 IntPoint ScrollView::rootViewToContents(const IntPoint& rootViewPoint) const | |
516 { | |
517 IntPoint viewPoint = convertFromRootView(rootViewPoint); | |
518 return viewPoint + scrollOffset(); | |
519 } | |
520 | |
521 IntPoint ScrollView::contentsToRootView(const IntPoint& contentsPoint) const | |
522 { | |
523 IntPoint viewPoint = contentsPoint - scrollOffset(); | |
524 return convertToRootView(viewPoint); | |
525 } | |
526 | |
527 IntRect ScrollView::rootViewToContents(const IntRect& rootViewRect) const | |
528 { | |
529 IntRect viewRect = convertFromRootView(rootViewRect); | |
530 viewRect.move(scrollOffset()); | |
531 return viewRect; | |
532 } | |
533 | |
534 IntRect ScrollView::contentsToRootView(const IntRect& contentsRect) const | |
535 { | |
536 IntRect viewRect = contentsRect; | |
537 viewRect.move(-scrollOffset()); | |
538 return convertToRootView(viewRect); | |
539 } | |
540 | |
541 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const | |
542 { | |
543 IntPoint viewPoint = convertFromContainingWindow(windowPoint); | |
544 return viewPoint + scrollOffset(); | |
545 } | |
546 | |
547 FloatPoint ScrollView::windowToContents(const FloatPoint& windowPoint) const | |
548 { | |
549 FloatPoint viewPoint = convertFromContainingWindow(windowPoint); | |
550 return viewPoint + scrollOffset(); | |
551 } | |
552 | |
553 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const | |
554 { | |
555 IntPoint viewPoint = contentsPoint - scrollOffset(); | |
556 return convertToContainingWindow(viewPoint); | |
557 } | |
558 | |
559 IntRect ScrollView::windowToContents(const IntRect& windowRect) const | |
560 { | |
561 IntRect viewRect = convertFromContainingWindow(windowRect); | |
562 viewRect.move(scrollOffset()); | |
563 return viewRect; | |
564 } | |
565 | |
566 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const | |
567 { | |
568 IntRect viewRect = contentsRect; | |
569 viewRect.move(-scrollOffset()); | |
570 return convertToContainingWindow(viewRect); | |
571 } | |
572 | |
573 IntRect ScrollView::contentsToScreen(const IntRect& rect) const | |
574 { | |
575 HostWindow* window = hostWindow(); | |
576 if (!window) | |
577 return IntRect(); | |
578 return window->rootViewToScreen(contentsToRootView(rect)); | |
579 } | |
580 | |
581 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppre
ss) | |
582 { | |
583 if (suppressed == m_scrollbarsSuppressed) | |
584 return; | |
585 | |
586 m_scrollbarsSuppressed = suppressed; | |
587 | |
588 if (repaintOnUnsuppress && !suppressed) { | |
589 if (m_horizontalScrollbar) | |
590 m_horizontalScrollbar->invalidate(); | |
591 if (m_verticalScrollbar) | |
592 m_verticalScrollbar->invalidate(); | |
593 | |
594 // Invalidate the scroll corner too on unsuppress. | |
595 invalidateRect(scrollCornerRect()); | |
596 } | |
597 } | |
598 | |
599 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint) | |
600 { | |
601 IntPoint viewPoint = convertFromContainingWindow(windowPoint); | |
602 if (m_horizontalScrollbar && m_horizontalScrollbar->shouldParticipateInHitTe
sting() && m_horizontalScrollbar->frameRect().contains(viewPoint)) | |
603 return m_horizontalScrollbar.get(); | |
604 if (m_verticalScrollbar && m_verticalScrollbar->shouldParticipateInHitTestin
g() && m_verticalScrollbar->frameRect().contains(viewPoint)) | |
605 return m_verticalScrollbar.get(); | |
606 return 0; | |
607 } | |
608 | |
609 void ScrollView::setFrameRect(const IntRect& newRect) | |
610 { | |
611 IntRect oldRect = frameRect(); | |
612 | |
613 if (newRect == oldRect) | |
614 return; | |
615 | |
616 Widget::setFrameRect(newRect); | |
617 | |
618 updateScrollbars(scrollOffset()); | |
619 | |
620 frameRectsChanged(); | |
621 } | |
622 | |
623 void ScrollView::frameRectsChanged() | |
624 { | |
625 HashSet<RefPtr<Widget> >::const_iterator end = m_children.end(); | |
626 for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin();
current != end; ++current) | |
627 (*current)->frameRectsChanged(); | |
628 } | |
629 | |
630 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scro
llbar) | |
631 { | |
632 if (!graphicsLayer || !scrollbar) | |
633 return; | |
634 | |
635 IntRect scrollbarRect = scrollbar->frameRect(); | |
636 graphicsLayer->setPosition(scrollbarRect.location()); | |
637 | |
638 if (scrollbarRect.size() == graphicsLayer->size()) | |
639 return; | |
640 | |
641 graphicsLayer->setSize(scrollbarRect.size()); | |
642 | |
643 if (graphicsLayer->hasContentsLayer()) { | |
644 graphicsLayer->setContentsRect(IntRect(0, 0, scrollbarRect.width(), scro
llbarRect.height())); | |
645 return; | |
646 } | |
647 | |
648 graphicsLayer->setDrawsContent(true); | |
649 graphicsLayer->setNeedsDisplay(); | |
650 } | |
651 | |
652 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRec
t& cornerRect) | |
653 { | |
654 if (!graphicsLayer) | |
655 return; | |
656 graphicsLayer->setDrawsContent(!cornerRect.isEmpty()); | |
657 graphicsLayer->setPosition(cornerRect.location()); | |
658 if (cornerRect.size() != graphicsLayer->size()) | |
659 graphicsLayer->setNeedsDisplay(); | |
660 graphicsLayer->setSize(cornerRect.size()); | |
661 } | |
662 | |
663 void ScrollView::positionScrollbarLayers() | |
664 { | |
665 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar())
; | |
666 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar()); | |
667 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect()); | |
668 } | |
669 | |
670 bool ScrollView::userInputScrollable(ScrollbarOrientation orientation) const | |
671 { | |
672 ScrollbarMode mode = (orientation == HorizontalScrollbar) ? | |
673 m_horizontalScrollbarMode : m_verticalScrollbarMode; | |
674 | |
675 return mode == ScrollbarAuto || mode == ScrollbarAlwaysOn; | |
676 } | |
677 | |
678 bool ScrollView::shouldPlaceVerticalScrollbarOnLeft() const | |
679 { | |
680 return false; | |
681 } | |
682 | |
683 void ScrollView::contentRectangleForPaintInvalidation(const IntRect& rect) | |
684 { | |
685 IntRect paintRect = rect; | |
686 if (clipsPaintInvalidations() && !paintsEntireContents()) | |
687 paintRect.intersect(visibleContentRect()); | |
688 if (paintRect.isEmpty()) | |
689 return; | |
690 | |
691 if (HostWindow* window = hostWindow()) | |
692 window->invalidateContentsAndRootView(contentsToWindow(paintRect)); | |
693 } | |
694 | |
695 IntRect ScrollView::scrollCornerRect() const | |
696 { | |
697 IntRect cornerRect; | |
698 | |
699 if (hasOverlayScrollbars()) | |
700 return cornerRect; | |
701 | |
702 if (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() > 0) { | |
703 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : m_ho
rizontalScrollbar->width(), | |
704 height() - m_horizontalScrollbar->height(), | |
705 width() - m_horizontalScrollbar->width(), | |
706 m_horizontalScrollbar->height())); | |
707 } | |
708 | |
709 if (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0) { | |
710 cornerRect.unite(IntRect(shouldPlaceVerticalScrollbarOnLeft() ? 0 : (wid
th() - m_verticalScrollbar->width()), | |
711 m_verticalScrollbar->height(), | |
712 m_verticalScrollbar->width(), | |
713 height() - m_verticalScrollbar->height())); | |
714 } | |
715 | |
716 return cornerRect; | |
717 } | |
718 | |
719 bool ScrollView::isScrollCornerVisible() const | |
720 { | |
721 return !scrollCornerRect().isEmpty(); | |
722 } | |
723 | |
724 void ScrollView::updateScrollCorner() | |
725 { | |
726 } | |
727 | |
728 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& corn
erRect) | |
729 { | |
730 Scrollbar::paintScrollCorner(context, cornerRect); | |
731 } | |
732 | |
733 void ScrollView::paintScrollbar(GraphicsContext* context, Scrollbar* bar, const
IntRect& rect) | |
734 { | |
735 bar->paint(context, rect); | |
736 } | |
737 | |
738 void ScrollView::invalidateScrollCornerRect(const IntRect& rect) | |
739 { | |
740 invalidateRect(rect); | |
741 } | |
742 | |
743 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect) | |
744 { | |
745 if (m_horizontalScrollbar && !layerForHorizontalScrollbar()) | |
746 paintScrollbar(context, m_horizontalScrollbar.get(), rect); | |
747 if (m_verticalScrollbar && !layerForVerticalScrollbar()) | |
748 paintScrollbar(context, m_verticalScrollbar.get(), rect); | |
749 | |
750 if (layerForScrollCorner()) | |
751 return; | |
752 paintScrollCorner(context, scrollCornerRect()); | |
753 } | |
754 | |
755 void ScrollView::paint(GraphicsContext* context, const IntRect& rect) | |
756 { | |
757 notifyPageThatContentAreaWillPaint(); | |
758 | |
759 IntRect documentDirtyRect = rect; | |
760 if (!paintsEntireContents()) { | |
761 IntRect visibleAreaWithoutScrollbars(location(), visibleContentRect().si
ze()); | |
762 documentDirtyRect.intersect(visibleAreaWithoutScrollbars); | |
763 } | |
764 | |
765 if (!documentDirtyRect.isEmpty()) { | |
766 GraphicsContextStateSaver stateSaver(*context); | |
767 | |
768 context->translate(x(), y()); | |
769 documentDirtyRect.moveBy(-location()); | |
770 | |
771 if (!paintsEntireContents()) { | |
772 context->translate(-scrollX(), -scrollY()); | |
773 documentDirtyRect.moveBy(scrollPosition()); | |
774 | |
775 context->clip(visibleContentRect()); | |
776 } | |
777 | |
778 paintContents(context, documentDirtyRect); | |
779 } | |
780 | |
781 calculateAndPaintOverhangAreas(context, rect); | |
782 | |
783 // Now paint the scrollbars. | |
784 if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar
)) { | |
785 GraphicsContextStateSaver stateSaver(*context); | |
786 IntRect scrollViewDirtyRect = rect; | |
787 IntRect visibleAreaWithScrollbars(location(), visibleContentRect(Include
Scrollbars).size()); | |
788 scrollViewDirtyRect.intersect(visibleAreaWithScrollbars); | |
789 context->translate(x(), y()); | |
790 scrollViewDirtyRect.moveBy(-location()); | |
791 context->clip(IntRect(IntPoint(), visibleAreaWithScrollbars.size())); | |
792 | |
793 paintScrollbars(context, scrollViewDirtyRect); | |
794 } | |
795 } | |
796 | |
797 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRe
ct, IntRect& verticalOverhangRect) | |
798 { | |
799 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->i
sOverlayScrollbar()) | |
800 ? verticalScrollbar()->width() : 0; | |
801 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollb
ar()->isOverlayScrollbar()) | |
802 ? horizontalScrollbar()->height() : 0; | |
803 | |
804 int physicalScrollY = scrollPosition().y() + scrollOrigin().y(); | |
805 if (physicalScrollY < 0) { | |
806 horizontalOverhangRect = frameRect(); | |
807 horizontalOverhangRect.setHeight(-physicalScrollY); | |
808 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - vertica
lScrollbarWidth); | |
809 } else if (contentsHeight() && physicalScrollY > contentsHeight() - visibleH
eight()) { | |
810 int height = physicalScrollY - (contentsHeight() - visibleHeight()); | |
811 horizontalOverhangRect = frameRect(); | |
812 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScro
llbarHeight); | |
813 horizontalOverhangRect.setHeight(height); | |
814 horizontalOverhangRect.setWidth(horizontalOverhangRect.width() - vertica
lScrollbarWidth); | |
815 } | |
816 | |
817 int physicalScrollX = scrollPosition().x() + scrollOrigin().x(); | |
818 if (physicalScrollX < 0) { | |
819 verticalOverhangRect.setWidth(-physicalScrollX); | |
820 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhang
Rect.height() - horizontalScrollbarHeight); | |
821 verticalOverhangRect.setX(frameRect().x()); | |
822 if (horizontalOverhangRect.y() == frameRect().y()) | |
823 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.h
eight()); | |
824 else | |
825 verticalOverhangRect.setY(frameRect().y()); | |
826 } else if (contentsWidth() && physicalScrollX > contentsWidth() - visibleWid
th()) { | |
827 int width = physicalScrollX - (contentsWidth() - visibleWidth()); | |
828 verticalOverhangRect.setWidth(width); | |
829 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhang
Rect.height() - horizontalScrollbarHeight); | |
830 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbar
Width); | |
831 if (horizontalOverhangRect.y() == frameRect().y()) | |
832 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.h
eight()); | |
833 else | |
834 verticalOverhangRect.setY(frameRect().y()); | |
835 } | |
836 } | |
837 | |
838 void ScrollView::updateOverhangAreas() | |
839 { | |
840 HostWindow* window = hostWindow(); | |
841 if (!window) | |
842 return; | |
843 | |
844 IntRect horizontalOverhangRect; | |
845 IntRect verticalOverhangRect; | |
846 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRe
ct); | |
847 if (!horizontalOverhangRect.isEmpty()) | |
848 window->invalidateContentsAndRootView(horizontalOverhangRect); | |
849 if (!verticalOverhangRect.isEmpty()) | |
850 window->invalidateContentsAndRootView(verticalOverhangRect); | |
851 } | |
852 | |
853 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& hor
izontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRe
ct) | |
854 { | |
855 Scrollbar::paintOverhangBackground(context, horizontalOverhangRect, vertical
OverhangRect, dirtyRect); | |
856 } | |
857 | |
858 void ScrollView::calculateAndPaintOverhangAreas(GraphicsContext* context, const
IntRect& dirtyRect) | |
859 { | |
860 IntRect horizontalOverhangRect; | |
861 IntRect verticalOverhangRect; | |
862 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRe
ct); | |
863 | |
864 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(ver
ticalOverhangRect)) | |
865 paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect
, dirtyRect); | |
866 } | |
867 | |
868 void ScrollView::calculateAndPaintOverhangBackground(GraphicsContext* context, c
onst IntRect& dirtyRect) | |
869 { | |
870 IntRect horizontalOverhangRect; | |
871 IntRect verticalOverhangRect; | |
872 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRe
ct); | |
873 | |
874 if (dirtyRect.intersects(horizontalOverhangRect) || dirtyRect.intersects(ver
ticalOverhangRect)) | |
875 Scrollbar::paintOverhangBackground(context, horizontalOverhangRect, vert
icalOverhangRect, dirtyRect); | |
876 } | |
877 | |
878 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint) | |
879 { | |
880 if (!scrollbarCornerPresent()) | |
881 return false; | |
882 | |
883 IntPoint viewPoint = convertFromContainingWindow(windowPoint); | |
884 | |
885 if (m_horizontalScrollbar) { | |
886 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y(); | |
887 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m
_horizontalScrollbar->frameRect().height(); | |
888 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m
_horizontalScrollbar->frameRect().width(); | |
889 | |
890 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizo
ntalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin; | |
891 } | |
892 | |
893 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x(); | |
894 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_vertica
lScrollbar->frameRect().width(); | |
895 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_vertica
lScrollbar->frameRect().height(); | |
896 | |
897 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScro
llbarXMax && viewPoint.y() > verticalScrollbarYMin; | |
898 } | |
899 | |
900 bool ScrollView::scrollbarCornerPresent() const | |
901 { | |
902 return (m_horizontalScrollbar && width() - m_horizontalScrollbar->width() >
0) | |
903 || (m_verticalScrollbar && height() - m_verticalScrollbar->height() > 0)
; | |
904 } | |
905 | |
906 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scroll
bar, const IntRect& localRect) const | |
907 { | |
908 // Scrollbars won't be transformed within us | |
909 IntRect newRect = localRect; | |
910 newRect.moveBy(scrollbar->location()); | |
911 return newRect; | |
912 } | |
913 | |
914 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scroll
bar, const IntRect& parentRect) const | |
915 { | |
916 IntRect newRect = parentRect; | |
917 // Scrollbars won't be transformed within us | |
918 newRect.moveBy(-scrollbar->location()); | |
919 return newRect; | |
920 } | |
921 | |
922 // FIXME: test these on windows | |
923 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrol
lbar, const IntPoint& localPoint) const | |
924 { | |
925 // Scrollbars won't be transformed within us | |
926 IntPoint newPoint = localPoint; | |
927 newPoint.moveBy(scrollbar->location()); | |
928 return newPoint; | |
929 } | |
930 | |
931 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrol
lbar, const IntPoint& parentPoint) const | |
932 { | |
933 IntPoint newPoint = parentPoint; | |
934 // Scrollbars won't be transformed within us | |
935 newPoint.moveBy(-scrollbar->location()); | |
936 return newPoint; | |
937 } | |
938 | |
939 void ScrollView::setParentVisible(bool visible) | |
940 { | |
941 if (isParentVisible() == visible) | |
942 return; | |
943 | |
944 Widget::setParentVisible(visible); | |
945 | |
946 if (!isSelfVisible()) | |
947 return; | |
948 | |
949 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); | |
950 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end;
++it) | |
951 (*it)->setParentVisible(visible); | |
952 } | |
953 | |
954 void ScrollView::show() | |
955 { | |
956 if (!isSelfVisible()) { | |
957 setSelfVisible(true); | |
958 if (isParentVisible()) { | |
959 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); | |
960 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it
!= end; ++it) | |
961 (*it)->setParentVisible(true); | |
962 } | |
963 } | |
964 | |
965 Widget::show(); | |
966 } | |
967 | |
968 void ScrollView::hide() | |
969 { | |
970 if (isSelfVisible()) { | |
971 if (isParentVisible()) { | |
972 HashSet<RefPtr<Widget> >::iterator end = m_children.end(); | |
973 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it
!= end; ++it) | |
974 (*it)->setParentVisible(false); | |
975 } | |
976 setSelfVisible(false); | |
977 } | |
978 | |
979 Widget::hide(); | |
980 } | |
981 | |
982 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAl
l, bool updatePositionSynchronously) | |
983 { | |
984 if (scrollOrigin() == origin) | |
985 return; | |
986 | |
987 ScrollableArea::setScrollOrigin(origin); | |
988 | |
989 // Update if the scroll origin changes, since our position will be different
if the content size did not change. | |
990 if (updatePositionAtAll && updatePositionSynchronously) | |
991 updateScrollbars(scrollOffset()); | |
992 } | |
993 | |
994 } // namespace blink | |
OLD | NEW |