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 "ScrollView.h"
28
29 #include "AXObjectCache.h"
30 #include "GraphicsContext.h"
31 #include "GraphicsLayer.h"
32 #include "HostWindow.h"
33 #include "PlatformMouseEvent.h"
34 #include "PlatformWheelEvent.h"
35 #include "ScrollAnimator.h"
36 #include "Scrollbar.h"
37 #include "ScrollbarTheme.h"
38 #include <wtf/StdLibExtras.h>
39
40 using namespace std;
41
42 namespace WebCore {
43
ScrollView()44 ScrollView::ScrollView()
45 : m_horizontalScrollbarMode(ScrollbarAuto)
46 , m_verticalScrollbarMode(ScrollbarAuto)
47 , m_horizontalScrollbarLock(false)
48 , m_verticalScrollbarLock(false)
49 , m_prohibitsScrolling(false)
50 , m_canBlitOnScroll(true)
51 , m_scrollbarsAvoidingResizer(0)
52 , m_scrollbarsSuppressed(false)
53 , m_inUpdateScrollbars(false)
54 , m_updateScrollbarsPass(0)
55 , m_drawPanScrollIcon(false)
56 , m_useFixedLayout(false)
57 , m_paintsEntireContents(false)
58 , m_clipsRepaints(true)
59 , m_delegatesScrolling(false)
60 , m_containsScrollableAreaWithOverlayScrollbars(false)
61 {
62 platformInit();
63 }
64
~ScrollView()65 ScrollView::~ScrollView()
66 {
67 platformDestroy();
68 }
69
addChild(PassRefPtr<Widget> prpChild)70 void ScrollView::addChild(PassRefPtr<Widget> prpChild)
71 {
72 Widget* child = prpChild.get();
73 ASSERT(child != this && !child->parent());
74 child->setParent(this);
75 m_children.add(prpChild);
76 if (child->platformWidget())
77 platformAddChild(child);
78 }
79
removeChild(Widget * child)80 void ScrollView::removeChild(Widget* child)
81 {
82 ASSERT(child->parent() == this);
83 child->setParent(0);
84 m_children.remove(child);
85 if (child->platformWidget())
86 platformRemoveChild(child);
87 }
88
setHasHorizontalScrollbar(bool hasBar)89 void ScrollView::setHasHorizontalScrollbar(bool hasBar)
90 {
91 if (hasBar && avoidScrollbarCreation())
92 return;
93
94 if (hasBar && !m_horizontalScrollbar) {
95 m_horizontalScrollbar = createScrollbar(HorizontalScrollbar);
96 addChild(m_horizontalScrollbar.get());
97 didAddHorizontalScrollbar(m_horizontalScrollbar.get());
98 m_horizontalScrollbar->styleChanged();
99 } else if (!hasBar && m_horizontalScrollbar) {
100 willRemoveHorizontalScrollbar(m_horizontalScrollbar.get());
101 removeChild(m_horizontalScrollbar.get());
102 m_horizontalScrollbar = 0;
103 }
104
105 if (AXObjectCache::accessibilityEnabled() && axObjectCache())
106 axObjectCache()->handleScrollbarUpdate(this);
107 }
108
setHasVerticalScrollbar(bool hasBar)109 void ScrollView::setHasVerticalScrollbar(bool hasBar)
110 {
111 if (hasBar && avoidScrollbarCreation())
112 return;
113
114 if (hasBar && !m_verticalScrollbar) {
115 m_verticalScrollbar = createScrollbar(VerticalScrollbar);
116 addChild(m_verticalScrollbar.get());
117 didAddVerticalScrollbar(m_verticalScrollbar.get());
118 m_verticalScrollbar->styleChanged();
119 } else if (!hasBar && m_verticalScrollbar) {
120 willRemoveVerticalScrollbar(m_verticalScrollbar.get());
121 removeChild(m_verticalScrollbar.get());
122 m_verticalScrollbar = 0;
123 }
124
125 if (AXObjectCache::accessibilityEnabled() && axObjectCache())
126 axObjectCache()->handleScrollbarUpdate(this);
127 }
128
129 #if !PLATFORM(GTK)
createScrollbar(ScrollbarOrientation orientation)130 PassRefPtr<Scrollbar> ScrollView::createScrollbar(ScrollbarOrientation orientation)
131 {
132 return Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
133 }
134
setScrollbarModes(ScrollbarMode horizontalMode,ScrollbarMode verticalMode,bool horizontalLock,bool verticalLock)135 void ScrollView::setScrollbarModes(ScrollbarMode horizontalMode, ScrollbarMode verticalMode,
136 bool horizontalLock, bool verticalLock)
137 {
138 bool needsUpdate = false;
139
140 if (horizontalMode != horizontalScrollbarMode() && !m_horizontalScrollbarLock) {
141 m_horizontalScrollbarMode = horizontalMode;
142 needsUpdate = true;
143 }
144
145 if (verticalMode != verticalScrollbarMode() && !m_verticalScrollbarLock) {
146 m_verticalScrollbarMode = verticalMode;
147 needsUpdate = true;
148 }
149
150 if (horizontalLock)
151 setHorizontalScrollbarLock();
152
153 if (verticalLock)
154 setVerticalScrollbarLock();
155
156 if (!needsUpdate)
157 return;
158
159 if (platformWidget())
160 platformSetScrollbarModes();
161 else
162 updateScrollbars(scrollOffset());
163 }
164 #endif
165
scrollbarModes(ScrollbarMode & horizontalMode,ScrollbarMode & verticalMode) const166 void ScrollView::scrollbarModes(ScrollbarMode& horizontalMode, ScrollbarMode& verticalMode) const
167 {
168 if (platformWidget()) {
169 platformScrollbarModes(horizontalMode, verticalMode);
170 return;
171 }
172 horizontalMode = m_horizontalScrollbarMode;
173 verticalMode = m_verticalScrollbarMode;
174 }
175
setCanHaveScrollbars(bool canScroll)176 void ScrollView::setCanHaveScrollbars(bool canScroll)
177 {
178 ScrollbarMode newHorizontalMode;
179 ScrollbarMode newVerticalMode;
180
181 scrollbarModes(newHorizontalMode, newVerticalMode);
182
183 if (canScroll && newVerticalMode == ScrollbarAlwaysOff)
184 newVerticalMode = ScrollbarAuto;
185 else if (!canScroll)
186 newVerticalMode = ScrollbarAlwaysOff;
187
188 if (canScroll && newHorizontalMode == ScrollbarAlwaysOff)
189 newHorizontalMode = ScrollbarAuto;
190 else if (!canScroll)
191 newHorizontalMode = ScrollbarAlwaysOff;
192
193 setScrollbarModes(newHorizontalMode, newVerticalMode);
194 }
195
setCanBlitOnScroll(bool b)196 void ScrollView::setCanBlitOnScroll(bool b)
197 {
198 if (platformWidget()) {
199 platformSetCanBlitOnScroll(b);
200 return;
201 }
202
203 m_canBlitOnScroll = b;
204 }
205
canBlitOnScroll() const206 bool ScrollView::canBlitOnScroll() const
207 {
208 if (platformWidget())
209 return platformCanBlitOnScroll();
210
211 return m_canBlitOnScroll;
212 }
213
setPaintsEntireContents(bool paintsEntireContents)214 void ScrollView::setPaintsEntireContents(bool paintsEntireContents)
215 {
216 m_paintsEntireContents = paintsEntireContents;
217 }
218
setClipsRepaints(bool clipsRepaints)219 void ScrollView::setClipsRepaints(bool clipsRepaints)
220 {
221 m_clipsRepaints = clipsRepaints;
222 }
223
setDelegatesScrolling(bool delegatesScrolling)224 void ScrollView::setDelegatesScrolling(bool delegatesScrolling)
225 {
226 m_delegatesScrolling = delegatesScrolling;
227 }
228
229 #if !PLATFORM(GTK)
visibleContentRect(bool includeScrollbars) const230 IntRect ScrollView::visibleContentRect(bool includeScrollbars) const
231 {
232 if (platformWidget())
233 return platformVisibleContentRect(includeScrollbars);
234
235 #if !PLATFORM(EFL)
236 if (paintsEntireContents())
237 return IntRect(IntPoint(0, 0), contentsSize());
238 #endif
239
240 int verticalScrollbarWidth = verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar()
241 && !includeScrollbars ? verticalScrollbar()->width() : 0;
242 int horizontalScrollbarHeight = horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar()
243 && !includeScrollbars ? horizontalScrollbar()->height() : 0;
244
245 return IntRect(IntPoint(m_scrollOffset.width(), m_scrollOffset.height()),
246 IntSize(max(0, m_boundsSize.width() - verticalScrollbarWidth),
247 max(0, m_boundsSize.height() - horizontalScrollbarHeight)));
248 }
249 #endif
250
layoutWidth() const251 int ScrollView::layoutWidth() const
252 {
253 return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleWidth() : m_fixedLayoutSize.width();
254 }
255
layoutHeight() const256 int ScrollView::layoutHeight() const
257 {
258 return m_fixedLayoutSize.isEmpty() || !m_useFixedLayout ? visibleHeight() : m_fixedLayoutSize.height();
259 }
260
fixedLayoutSize() const261 IntSize ScrollView::fixedLayoutSize() const
262 {
263 return m_fixedLayoutSize;
264 }
265
setFixedLayoutSize(const IntSize & newSize)266 void ScrollView::setFixedLayoutSize(const IntSize& newSize)
267 {
268 if (fixedLayoutSize() == newSize)
269 return;
270 m_fixedLayoutSize = newSize;
271 updateScrollbars(scrollOffset());
272 }
273
useFixedLayout() const274 bool ScrollView::useFixedLayout() const
275 {
276 return m_useFixedLayout;
277 }
278
setUseFixedLayout(bool enable)279 void ScrollView::setUseFixedLayout(bool enable)
280 {
281 if (useFixedLayout() == enable)
282 return;
283 m_useFixedLayout = enable;
284 updateScrollbars(scrollOffset());
285 }
286
contentsSize() const287 IntSize ScrollView::contentsSize() const
288 {
289 if (platformWidget())
290 return platformContentsSize();
291 return m_contentsSize;
292 }
293
setContentsSize(const IntSize & newSize)294 void ScrollView::setContentsSize(const IntSize& newSize)
295 {
296 if (contentsSize() == newSize)
297 return;
298 m_contentsSize = newSize;
299 if (platformWidget())
300 platformSetContentsSize();
301 else
302 updateScrollbars(scrollOffset());
303 }
304
maximumScrollPosition() const305 IntPoint ScrollView::maximumScrollPosition() const
306 {
307 IntPoint maximumOffset(contentsWidth() - visibleWidth() - m_scrollOrigin.x(), contentsHeight() - visibleHeight() - m_scrollOrigin.y());
308 maximumOffset.clampNegativeToZero();
309 return maximumOffset;
310 }
311
minimumScrollPosition() const312 IntPoint ScrollView::minimumScrollPosition() const
313 {
314 return IntPoint(-m_scrollOrigin.x(), -m_scrollOrigin.y());
315 }
316
adjustScrollPositionWithinRange(const IntPoint & scrollPoint) const317 IntPoint ScrollView::adjustScrollPositionWithinRange(const IntPoint& scrollPoint) const
318 {
319 IntPoint newScrollPosition = scrollPoint.shrunkTo(maximumScrollPosition());
320 newScrollPosition = newScrollPosition.expandedTo(minimumScrollPosition());
321 return newScrollPosition;
322 }
323
scrollSize(ScrollbarOrientation orientation) const324 int ScrollView::scrollSize(ScrollbarOrientation orientation) const
325 {
326 Scrollbar* scrollbar = ((orientation == HorizontalScrollbar) ? m_horizontalScrollbar : m_verticalScrollbar).get();
327 return scrollbar ? (scrollbar->totalSize() - scrollbar->visibleSize()) : 0;
328 }
329
didCompleteRubberBand(const IntSize &) const330 void ScrollView::didCompleteRubberBand(const IntSize&) const
331 {
332 }
333
notifyPageThatContentAreaWillPaint() const334 void ScrollView::notifyPageThatContentAreaWillPaint() const
335 {
336 }
337
setScrollOffset(const IntPoint & offset)338 void ScrollView::setScrollOffset(const IntPoint& offset)
339 {
340 int horizontalOffset = offset.x();
341 int verticalOffset = offset.y();
342 if (constrainsScrollingToContentEdge()) {
343 horizontalOffset = max(min(horizontalOffset, contentsWidth() - visibleWidth()), 0);
344 verticalOffset = max(min(verticalOffset, contentsHeight() - visibleHeight()), 0);
345 }
346
347 IntSize newOffset = m_scrollOffset;
348 newOffset.setWidth(horizontalOffset - m_scrollOrigin.x());
349 newOffset.setHeight(verticalOffset - m_scrollOrigin.y());
350
351 scrollTo(newOffset);
352 }
353
scrollTo(const IntSize & newOffset)354 void ScrollView::scrollTo(const IntSize& newOffset)
355 {
356 IntSize scrollDelta = newOffset - m_scrollOffset;
357 if (scrollDelta == IntSize())
358 return;
359 m_scrollOffset = newOffset;
360
361 if (scrollbarsSuppressed())
362 return;
363
364 repaintFixedElementsAfterScrolling();
365 scrollContents(scrollDelta);
366 }
367
scrollPosition(Scrollbar * scrollbar) const368 int ScrollView::scrollPosition(Scrollbar* scrollbar) const
369 {
370 if (scrollbar->orientation() == HorizontalScrollbar)
371 return scrollPosition().x() + m_scrollOrigin.x();
372 if (scrollbar->orientation() == VerticalScrollbar)
373 return scrollPosition().y() + m_scrollOrigin.y();
374 return 0;
375 }
376
setScrollPosition(const IntPoint & scrollPoint)377 void ScrollView::setScrollPosition(const IntPoint& scrollPoint)
378 {
379 if (prohibitsScrolling())
380 return;
381
382 if (platformWidget()) {
383 platformSetScrollPosition(scrollPoint);
384 return;
385 }
386
387 #if ENABLE(TILED_BACKING_STORE)
388 if (delegatesScrolling()) {
389 hostWindow()->delegatedScrollRequested(scrollPoint);
390 if (!m_actualVisibleContentRect.isEmpty())
391 m_actualVisibleContentRect.setLocation(scrollPoint);
392 return;
393 }
394 #endif
395
396 IntPoint newScrollPosition = adjustScrollPositionWithinRange(scrollPoint);
397
398 if (newScrollPosition == scrollPosition())
399 return;
400
401 updateScrollbars(IntSize(newScrollPosition.x(), newScrollPosition.y()));
402 }
403
scroll(ScrollDirection direction,ScrollGranularity granularity)404 bool ScrollView::scroll(ScrollDirection direction, ScrollGranularity granularity)
405 {
406 if (platformWidget())
407 return platformScroll(direction, granularity);
408
409 return ScrollableArea::scroll(direction, granularity);
410 }
411
logicalScroll(ScrollLogicalDirection direction,ScrollGranularity granularity)412 bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
413 {
414 return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
415 }
416
overhangAmount() const417 IntSize ScrollView::overhangAmount() const
418 {
419 IntSize stretch;
420
421 int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y();
422 if (physicalScrollY < 0)
423 stretch.setHeight(physicalScrollY);
424 else if (physicalScrollY > contentsHeight() - visibleContentRect().height())
425 stretch.setHeight(physicalScrollY - (contentsHeight() - visibleContentRect().height()));
426
427 int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x();
428 if (physicalScrollX < 0)
429 stretch.setWidth(physicalScrollX);
430 else if (physicalScrollX > contentsWidth() - visibleContentRect().width())
431 stretch.setWidth(physicalScrollX - (contentsWidth() - visibleContentRect().width()));
432
433 return stretch;
434 }
435
windowResizerRectChanged()436 void ScrollView::windowResizerRectChanged()
437 {
438 if (platformWidget())
439 return;
440
441 updateScrollbars(scrollOffset());
442 }
443
444 static const unsigned cMaxUpdateScrollbarsPass = 2;
445
updateScrollbars(const IntSize & desiredOffset)446 void ScrollView::updateScrollbars(const IntSize& desiredOffset)
447 {
448 if (m_inUpdateScrollbars || prohibitsScrolling() || delegatesScrolling() || platformWidget())
449 return;
450
451 // If we came in here with the view already needing a layout, then go ahead and do that
452 // first. (This will be the common case, e.g., when the page changes due to window resizing for example).
453 // This layout will not re-enter updateScrollbars and does not count towards our max layout pass total.
454 if (!m_scrollbarsSuppressed) {
455 m_inUpdateScrollbars = true;
456 visibleContentsResized();
457 m_inUpdateScrollbars = false;
458 }
459
460 bool hasHorizontalScrollbar = m_horizontalScrollbar;
461 bool hasVerticalScrollbar = m_verticalScrollbar;
462
463 bool newHasHorizontalScrollbar = hasHorizontalScrollbar;
464 bool newHasVerticalScrollbar = hasVerticalScrollbar;
465
466 ScrollbarMode hScroll = m_horizontalScrollbarMode;
467 ScrollbarMode vScroll = m_verticalScrollbarMode;
468
469 if (hScroll != ScrollbarAuto)
470 newHasHorizontalScrollbar = (hScroll == ScrollbarAlwaysOn);
471 if (vScroll != ScrollbarAuto)
472 newHasVerticalScrollbar = (vScroll == ScrollbarAlwaysOn);
473
474 if (m_scrollbarsSuppressed || (hScroll != ScrollbarAuto && vScroll != ScrollbarAuto)) {
475 if (hasHorizontalScrollbar != newHasHorizontalScrollbar)
476 setHasHorizontalScrollbar(newHasHorizontalScrollbar);
477 if (hasVerticalScrollbar != newHasVerticalScrollbar)
478 setHasVerticalScrollbar(newHasVerticalScrollbar);
479 } else {
480 bool sendContentResizedNotification = false;
481
482 IntSize docSize = contentsSize();
483 IntSize frameSize = m_boundsSize;
484
485 if (hScroll == ScrollbarAuto) {
486 newHasHorizontalScrollbar = docSize.width() > visibleWidth();
487 if (newHasHorizontalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
488 newHasHorizontalScrollbar = false;
489 }
490 if (vScroll == ScrollbarAuto) {
491 newHasVerticalScrollbar = docSize.height() > visibleHeight();
492 if (newHasVerticalScrollbar && !m_updateScrollbarsPass && docSize.width() <= frameSize.width() && docSize.height() <= frameSize.height())
493 newHasVerticalScrollbar = false;
494 }
495
496 // If we ever turn one scrollbar off, always turn the other one off too. Never ever
497 // try to both gain/lose a scrollbar in the same pass.
498 if (!newHasHorizontalScrollbar && hasHorizontalScrollbar && vScroll != ScrollbarAlwaysOn)
499 newHasVerticalScrollbar = false;
500 if (!newHasVerticalScrollbar && hasVerticalScrollbar && hScroll != ScrollbarAlwaysOn)
501 newHasHorizontalScrollbar = false;
502
503 if (hasHorizontalScrollbar != newHasHorizontalScrollbar) {
504 if (m_scrollOrigin.y() && !newHasHorizontalScrollbar)
505 m_scrollOrigin.setY(m_scrollOrigin.y() - m_horizontalScrollbar->height());
506 setHasHorizontalScrollbar(newHasHorizontalScrollbar);
507 sendContentResizedNotification = true;
508 }
509
510 if (hasVerticalScrollbar != newHasVerticalScrollbar) {
511 if (m_scrollOrigin.x() && !newHasVerticalScrollbar)
512 m_scrollOrigin.setX(m_scrollOrigin.x() - m_verticalScrollbar->width());
513 setHasVerticalScrollbar(newHasVerticalScrollbar);
514 sendContentResizedNotification = true;
515 }
516
517 if (sendContentResizedNotification && m_updateScrollbarsPass < cMaxUpdateScrollbarsPass) {
518 m_updateScrollbarsPass++;
519 contentsResized();
520 visibleContentsResized();
521 IntSize newDocSize = contentsSize();
522 if (newDocSize == docSize) {
523 // The layout with the new scroll state had no impact on
524 // the document's overall size, so updateScrollbars didn't get called.
525 // Recur manually.
526 updateScrollbars(desiredOffset);
527 }
528 m_updateScrollbarsPass--;
529 }
530 }
531
532 // Set up the range (and page step/line step), but only do this if we're not in a nested call (to avoid
533 // doing it multiple times).
534 if (m_updateScrollbarsPass)
535 return;
536
537 m_inUpdateScrollbars = true;
538
539 IntPoint scrollPoint = adjustScrollPositionWithinRange(IntPoint(desiredOffset));
540 IntSize scroll(scrollPoint.x(), scrollPoint.y());
541
542 if (m_horizontalScrollbar) {
543 int clientWidth = visibleWidth();
544 m_horizontalScrollbar->setEnabled(contentsWidth() > clientWidth);
545 int pageStep = max(max<int>(clientWidth * Scrollbar::minFractionToStepWhenPaging(), clientWidth - Scrollbar::maxOverlapBetweenPages()), 1);
546 IntRect oldRect(m_horizontalScrollbar->frameRect());
547 IntRect hBarRect = IntRect(0,
548 m_boundsSize.height() - m_horizontalScrollbar->height(),
549 m_boundsSize.width() - (m_verticalScrollbar ? m_verticalScrollbar->width() : 0),
550 m_horizontalScrollbar->height());
551 m_horizontalScrollbar->setFrameRect(hBarRect);
552 if (!m_scrollbarsSuppressed && oldRect != m_horizontalScrollbar->frameRect())
553 m_horizontalScrollbar->invalidate();
554
555 if (m_scrollbarsSuppressed)
556 m_horizontalScrollbar->setSuppressInvalidation(true);
557 m_horizontalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
558 m_horizontalScrollbar->setProportion(clientWidth, contentsWidth());
559 if (m_scrollbarsSuppressed)
560 m_horizontalScrollbar->setSuppressInvalidation(false);
561 }
562
563 if (m_verticalScrollbar) {
564 int clientHeight = visibleHeight();
565 m_verticalScrollbar->setEnabled(contentsHeight() > clientHeight);
566 int pageStep = max(max<int>(clientHeight * Scrollbar::minFractionToStepWhenPaging(), clientHeight - Scrollbar::maxOverlapBetweenPages()), 1);
567 IntRect oldRect(m_verticalScrollbar->frameRect());
568 IntRect vBarRect = IntRect(m_boundsSize.width() - m_verticalScrollbar->width(),
569 0,
570 m_verticalScrollbar->width(),
571 m_boundsSize.height() - (m_horizontalScrollbar ? m_horizontalScrollbar->height() : 0));
572 m_verticalScrollbar->setFrameRect(vBarRect);
573 if (!m_scrollbarsSuppressed && oldRect != m_verticalScrollbar->frameRect())
574 m_verticalScrollbar->invalidate();
575
576 if (m_scrollbarsSuppressed)
577 m_verticalScrollbar->setSuppressInvalidation(true);
578 m_verticalScrollbar->setSteps(Scrollbar::pixelsPerLineStep(), pageStep);
579 m_verticalScrollbar->setProportion(clientHeight, contentsHeight());
580 if (m_scrollbarsSuppressed)
581 m_verticalScrollbar->setSuppressInvalidation(false);
582 }
583
584 if (hasHorizontalScrollbar != (m_horizontalScrollbar != 0) || hasVerticalScrollbar != (m_verticalScrollbar != 0)) {
585 // FIXME: Is frameRectsChanged really necessary here? Have any frame rects changed?
586 frameRectsChanged();
587 positionScrollbarLayers();
588 updateScrollCorner();
589 }
590
591 ScrollableArea::scrollToOffsetWithoutAnimation(FloatPoint(scroll.width() + m_scrollOrigin.x(), scroll.height() + m_scrollOrigin.y()));
592
593 // Make sure the scrollbar offsets are up to date.
594 if (m_horizontalScrollbar)
595 m_horizontalScrollbar->offsetDidChange();
596 if (m_verticalScrollbar)
597 m_verticalScrollbar->offsetDidChange();
598
599 m_inUpdateScrollbars = false;
600 }
601
602 const int panIconSizeLength = 16;
603
rectToCopyOnScroll() const604 IntRect ScrollView::rectToCopyOnScroll() const
605 {
606 IntRect scrollViewRect = convertToContainingWindow(IntRect(0, 0, visibleWidth(), visibleHeight()));
607 if (hasOverlayScrollbars()) {
608 int verticalScrollbarWidth = (verticalScrollbar() && !hasLayerForVerticalScrollbar()) ? verticalScrollbar()->width() : 0;
609 int horizontalScrollbarHeight = (horizontalScrollbar() && !hasLayerForHorizontalScrollbar()) ? horizontalScrollbar()->height() : 0;
610
611 scrollViewRect.setWidth(scrollViewRect.width() - verticalScrollbarWidth);
612 scrollViewRect.setHeight(scrollViewRect.height() - horizontalScrollbarHeight);
613 }
614 return scrollViewRect;
615 }
616
scrollContents(const IntSize & scrollDelta)617 void ScrollView::scrollContents(const IntSize& scrollDelta)
618 {
619 if (!hostWindow())
620 return;
621
622 // Since scrolling is double buffered, we will be blitting the scroll view's intersection
623 // with the clip rect every time to keep it smooth.
624 IntRect clipRect = windowClipRect();
625 IntRect scrollViewRect = rectToCopyOnScroll();
626 IntRect updateRect = clipRect;
627 updateRect.intersect(scrollViewRect);
628
629 // Invalidate the window (not the backing store).
630 hostWindow()->invalidateWindow(updateRect, false /*immediate*/);
631
632 if (m_drawPanScrollIcon) {
633 // FIXME: the pan icon is broken when accelerated compositing is on, since it will draw under the compositing layers.
634 // https://bugs.webkit.org/show_bug.cgi?id=47837
635 int panIconDirtySquareSizeLength = 2 * (panIconSizeLength + max(abs(scrollDelta.width()), abs(scrollDelta.height()))); // We only want to repaint what's necessary
636 IntPoint panIconDirtySquareLocation = IntPoint(m_panScrollIconPoint.x() - (panIconDirtySquareSizeLength / 2), m_panScrollIconPoint.y() - (panIconDirtySquareSizeLength / 2));
637 IntRect panScrollIconDirtyRect = IntRect(panIconDirtySquareLocation , IntSize(panIconDirtySquareSizeLength, panIconDirtySquareSizeLength));
638 panScrollIconDirtyRect.intersect(clipRect);
639 hostWindow()->invalidateContentsAndWindow(panScrollIconDirtyRect, false /*immediate*/);
640 }
641
642 if (canBlitOnScroll()) { // The main frame can just blit the WebView window
643 // FIXME: Find a way to scroll subframes with this faster path
644 if (!scrollContentsFastPath(-scrollDelta, scrollViewRect, clipRect))
645 scrollContentsSlowPath(updateRect);
646 } else {
647 // We need to go ahead and repaint the entire backing store. Do it now before moving the
648 // windowed plugins.
649 scrollContentsSlowPath(updateRect);
650 }
651
652 // Invalidate the overhang areas if they are visible.
653 IntRect horizontalOverhangRect;
654 IntRect verticalOverhangRect;
655 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
656 if (!horizontalOverhangRect.isEmpty())
657 hostWindow()->invalidateContentsAndWindow(horizontalOverhangRect, false /*immediate*/);
658 if (!verticalOverhangRect.isEmpty())
659 hostWindow()->invalidateContentsAndWindow(verticalOverhangRect, false /*immediate*/);
660
661 // This call will move children with native widgets (plugins) and invalidate them as well.
662 frameRectsChanged();
663
664 // Now blit the backingstore into the window which should be very fast.
665 hostWindow()->invalidateWindow(IntRect(), true);
666 }
667
scrollContentsFastPath(const IntSize & scrollDelta,const IntRect & rectToScroll,const IntRect & clipRect)668 bool ScrollView::scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
669 {
670 hostWindow()->scroll(scrollDelta, rectToScroll, clipRect);
671 return true;
672 }
673
scrollContentsSlowPath(const IntRect & updateRect)674 void ScrollView::scrollContentsSlowPath(const IntRect& updateRect)
675 {
676 hostWindow()->invalidateContentsForSlowScroll(updateRect, false);
677 }
678
windowToContents(const IntPoint & windowPoint) const679 IntPoint ScrollView::windowToContents(const IntPoint& windowPoint) const
680 {
681 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
682 return viewPoint + scrollOffset();
683 }
684
contentsToWindow(const IntPoint & contentsPoint) const685 IntPoint ScrollView::contentsToWindow(const IntPoint& contentsPoint) const
686 {
687 IntPoint viewPoint = contentsPoint - scrollOffset();
688 return convertToContainingWindow(viewPoint);
689 }
690
windowToContents(const IntRect & windowRect) const691 IntRect ScrollView::windowToContents(const IntRect& windowRect) const
692 {
693 IntRect viewRect = convertFromContainingWindow(windowRect);
694 viewRect.move(scrollOffset());
695 return viewRect;
696 }
697
contentsToWindow(const IntRect & contentsRect) const698 IntRect ScrollView::contentsToWindow(const IntRect& contentsRect) const
699 {
700 IntRect viewRect = contentsRect;
701 viewRect.move(-scrollOffset());
702 return convertToContainingWindow(viewRect);
703 }
704
contentsToScreen(const IntRect & rect) const705 IntRect ScrollView::contentsToScreen(const IntRect& rect) const
706 {
707 if (platformWidget())
708 return platformContentsToScreen(rect);
709 if (!hostWindow())
710 return IntRect();
711 return hostWindow()->windowToScreen(contentsToWindow(rect));
712 }
713
screenToContents(const IntPoint & point) const714 IntPoint ScrollView::screenToContents(const IntPoint& point) const
715 {
716 if (platformWidget())
717 return platformScreenToContents(point);
718 if (!hostWindow())
719 return IntPoint();
720 return windowToContents(hostWindow()->screenToWindow(point));
721 }
722
containsScrollbarsAvoidingResizer() const723 bool ScrollView::containsScrollbarsAvoidingResizer() const
724 {
725 return !m_scrollbarsAvoidingResizer;
726 }
727
adjustScrollbarsAvoidingResizerCount(int overlapDelta)728 void ScrollView::adjustScrollbarsAvoidingResizerCount(int overlapDelta)
729 {
730 int oldCount = m_scrollbarsAvoidingResizer;
731 m_scrollbarsAvoidingResizer += overlapDelta;
732 if (parent())
733 parent()->adjustScrollbarsAvoidingResizerCount(overlapDelta);
734 else if (!scrollbarsSuppressed()) {
735 // If we went from n to 0 or from 0 to n and we're the outermost view,
736 // we need to invalidate the windowResizerRect(), since it will now need to paint
737 // differently.
738 if ((oldCount > 0 && m_scrollbarsAvoidingResizer == 0) ||
739 (oldCount == 0 && m_scrollbarsAvoidingResizer > 0))
740 invalidateRect(windowResizerRect());
741 }
742 }
743
setParent(ScrollView * parentView)744 void ScrollView::setParent(ScrollView* parentView)
745 {
746 if (parentView == parent())
747 return;
748
749 if (m_scrollbarsAvoidingResizer && parent())
750 parent()->adjustScrollbarsAvoidingResizerCount(-m_scrollbarsAvoidingResizer);
751
752 Widget::setParent(parentView);
753
754 if (m_scrollbarsAvoidingResizer && parent())
755 parent()->adjustScrollbarsAvoidingResizerCount(m_scrollbarsAvoidingResizer);
756 }
757
setScrollbarsSuppressed(bool suppressed,bool repaintOnUnsuppress)758 void ScrollView::setScrollbarsSuppressed(bool suppressed, bool repaintOnUnsuppress)
759 {
760 if (suppressed == m_scrollbarsSuppressed)
761 return;
762
763 m_scrollbarsSuppressed = suppressed;
764
765 if (platformWidget())
766 platformSetScrollbarsSuppressed(repaintOnUnsuppress);
767 else if (repaintOnUnsuppress && !suppressed) {
768 if (m_horizontalScrollbar)
769 m_horizontalScrollbar->invalidate();
770 if (m_verticalScrollbar)
771 m_verticalScrollbar->invalidate();
772
773 // Invalidate the scroll corner too on unsuppress.
774 invalidateRect(scrollCornerRect());
775 }
776 }
777
scrollbarAtPoint(const IntPoint & windowPoint)778 Scrollbar* ScrollView::scrollbarAtPoint(const IntPoint& windowPoint)
779 {
780 if (platformWidget())
781 return 0;
782
783 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
784 if (m_horizontalScrollbar && m_horizontalScrollbar->frameRect().contains(viewPoint))
785 return m_horizontalScrollbar.get();
786 if (m_verticalScrollbar && m_verticalScrollbar->frameRect().contains(viewPoint))
787 return m_verticalScrollbar.get();
788 return 0;
789 }
790
wheelEvent(PlatformWheelEvent & e)791 void ScrollView::wheelEvent(PlatformWheelEvent& e)
792 {
793 // We don't allow mouse wheeling to happen in a ScrollView that has had its scrollbars explicitly disabled.
794 #if PLATFORM(WX)
795 if (!canHaveScrollbars()) {
796 #else
797 if (!canHaveScrollbars() || platformWidget()) {
798 #endif
799 return;
800 }
801
802 ScrollableArea::handleWheelEvent(e);
803 }
804
805 #if ENABLE(GESTURE_EVENTS)
806 void ScrollView::gestureEvent(const PlatformGestureEvent& gestureEvent)
807 {
808 if (platformWidget())
809 return;
810
811 ScrollableArea::handleGestureEvent(gestureEvent);
812 }
813 #endif
814
815 void ScrollView::setFrameRect(const IntRect& newRect)
816 {
817 IntRect oldRect = frameRect();
818
819 if (newRect == oldRect)
820 return;
821
822 Widget::setFrameRect(newRect);
823
824 frameRectsChanged();
825 }
826
827 void ScrollView::setBoundsSize(const IntSize& newSize)
828 {
829 if (newSize == m_boundsSize)
830 return;
831
832 Widget::setBoundsSize(newSize);
833 m_boundsSize = newSize;
834
835 if (platformWidget())
836 return;
837
838 updateScrollbars(m_scrollOffset);
839 if (!m_useFixedLayout)
840 contentsResized();
841
842 positionScrollbarLayers();
843 }
844
845 void ScrollView::setInitialBoundsSize(const IntSize& newSize)
846 {
847 ASSERT(m_boundsSize.isZero());
848 m_boundsSize = newSize;
849 }
850
851 void ScrollView::frameRectsChanged()
852 {
853 if (platformWidget())
854 return;
855
856 HashSet<RefPtr<Widget> >::const_iterator end = m_children.end();
857 for (HashSet<RefPtr<Widget> >::const_iterator current = m_children.begin(); current != end; ++current)
858 (*current)->frameRectsChanged();
859 }
860
861 #if USE(ACCELERATED_COMPOSITING)
862 static void positionScrollbarLayer(GraphicsLayer* graphicsLayer, Scrollbar* scrollbar)
863 {
864 if (!graphicsLayer || !scrollbar)
865 return;
866 graphicsLayer->setDrawsContent(true);
867 IntRect scrollbarRect = scrollbar->frameRect();
868 graphicsLayer->setPosition(scrollbarRect.location());
869 if (scrollbarRect.size() != graphicsLayer->size())
870 graphicsLayer->setNeedsDisplay();
871 graphicsLayer->setSize(scrollbarRect.size());
872 }
873
874 static void positionScrollCornerLayer(GraphicsLayer* graphicsLayer, const IntRect& cornerRect)
875 {
876 if (!graphicsLayer)
877 return;
878 graphicsLayer->setDrawsContent(!cornerRect.isEmpty());
879 graphicsLayer->setPosition(cornerRect.location());
880 if (cornerRect.size() != graphicsLayer->size())
881 graphicsLayer->setNeedsDisplay();
882 graphicsLayer->setSize(cornerRect.size());
883 }
884 #endif
885
886
887 void ScrollView::positionScrollbarLayers()
888 {
889 #if USE(ACCELERATED_COMPOSITING)
890 positionScrollbarLayer(layerForHorizontalScrollbar(), horizontalScrollbar());
891 positionScrollbarLayer(layerForVerticalScrollbar(), verticalScrollbar());
892 positionScrollCornerLayer(layerForScrollCorner(), scrollCornerRect());
893 #endif
894 }
895
896 void ScrollView::repaintContentRectangle(const IntRect& rect, bool now)
897 {
898 IntRect paintRect = rect;
899 if (clipsRepaints() && !paintsEntireContents())
900 paintRect.intersect(visibleContentRect());
901 if (paintRect.isEmpty())
902 return;
903
904 if (platformWidget()) {
905 platformRepaintContentRectangle(paintRect, now);
906 return;
907 }
908
909 if (hostWindow())
910 hostWindow()->invalidateContentsAndWindow(contentsToWindow(paintRect), now /*immediate*/);
911 }
912
913 IntRect ScrollView::scrollCornerRect() const
914 {
915 IntRect cornerRect;
916
917 if (hasOverlayScrollbars())
918 return cornerRect;
919
920 if (m_horizontalScrollbar && m_boundsSize.width() - m_horizontalScrollbar->width() > 0) {
921 cornerRect.unite(IntRect(m_horizontalScrollbar->width(),
922 m_boundsSize.height() - m_horizontalScrollbar->height(),
923 m_boundsSize.width() - m_horizontalScrollbar->width(),
924 m_horizontalScrollbar->height()));
925 }
926
927 if (m_verticalScrollbar && m_boundsSize.height() - m_verticalScrollbar->height() > 0) {
928 cornerRect.unite(IntRect(m_boundsSize.width() - m_verticalScrollbar->width(),
929 m_verticalScrollbar->height(),
930 m_verticalScrollbar->width(),
931 m_boundsSize.height() - m_verticalScrollbar->height()));
932 }
933
934 return cornerRect;
935 }
936
937 bool ScrollView::isScrollCornerVisible() const
938 {
939 return !scrollCornerRect().isEmpty();
940 }
941
942 void ScrollView::updateScrollCorner()
943 {
944 }
945
946 void ScrollView::paintScrollCorner(GraphicsContext* context, const IntRect& cornerRect)
947 {
948 ScrollbarTheme::nativeTheme()->paintScrollCorner(this, context, cornerRect);
949 }
950
951 void ScrollView::invalidateScrollCornerRect(const IntRect& rect)
952 {
953 invalidateRect(rect);
954 }
955
956 void ScrollView::paintScrollbars(GraphicsContext* context, const IntRect& rect)
957 {
958 if (m_horizontalScrollbar
959 #if USE(ACCELERATED_COMPOSITING)
960 && !layerForHorizontalScrollbar()
961 #endif
962 )
963 m_horizontalScrollbar->paint(context, rect);
964 if (m_verticalScrollbar
965 #if USE(ACCELERATED_COMPOSITING)
966 && !layerForVerticalScrollbar()
967 #endif
968 )
969 m_verticalScrollbar->paint(context, rect);
970
971 #if USE(ACCELERATED_COMPOSITING)
972 if (layerForScrollCorner())
973 return;
974 #endif
975 paintScrollCorner(context, scrollCornerRect());
976 }
977
978 void ScrollView::paintPanScrollIcon(GraphicsContext* context)
979 {
980 static Image* panScrollIcon = Image::loadPlatformResource("panIcon").releaseRef();
981 context->drawImage(panScrollIcon, ColorSpaceDeviceRGB, m_panScrollIconPoint);
982 }
983
984 void ScrollView::paint(GraphicsContext* context, const IntRect& rect)
985 {
986 if (platformWidget()) {
987 Widget::paint(context, rect);
988 return;
989 }
990
991 if (context->paintingDisabled() && !context->updatingControlTints())
992 return;
993
994 notifyPageThatContentAreaWillPaint();
995
996 // If we encounter any overlay scrollbars as we paint, this will be set to true.
997 m_containsScrollableAreaWithOverlayScrollbars = false;
998
999 IntRect clipRect = frameRect();
1000 if (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1001 clipRect.setWidth(clipRect.width() - verticalScrollbar()->width());
1002 if (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1003 clipRect.setHeight(clipRect.height() - horizontalScrollbar()->height());
1004
1005 IntRect documentDirtyRect = rect;
1006 documentDirtyRect.intersect(clipRect);
1007
1008 if (!documentDirtyRect.isEmpty()) {
1009 GraphicsContextStateSaver stateSaver(*context);
1010
1011 context->translate(x(), y());
1012 documentDirtyRect.move(-x(), -y());
1013
1014 if (!paintsEntireContents()) {
1015 context->translate(-scrollX(), -scrollY());
1016 documentDirtyRect.move(scrollX(), scrollY());
1017
1018 context->clip(visibleContentRect());
1019 }
1020
1021 paintContents(context, documentDirtyRect);
1022 }
1023
1024 IntRect horizontalOverhangRect;
1025 IntRect verticalOverhangRect;
1026 calculateOverhangAreasForPainting(horizontalOverhangRect, verticalOverhangRect);
1027
1028 if (rect.intersects(horizontalOverhangRect) || rect.intersects(verticalOverhangRect))
1029 paintOverhangAreas(context, horizontalOverhangRect, verticalOverhangRect, rect);
1030
1031 // Now paint the scrollbars.
1032 if (!m_scrollbarsSuppressed && (m_horizontalScrollbar || m_verticalScrollbar)) {
1033 GraphicsContextStateSaver stateSaver(*context);
1034 IntRect scrollViewDirtyRect = rect;
1035 scrollViewDirtyRect.intersect(frameRect());
1036 context->translate(x(), y());
1037 scrollViewDirtyRect.move(-x(), -y());
1038
1039 paintScrollbars(context, scrollViewDirtyRect);
1040 }
1041
1042 // Paint the panScroll Icon
1043 if (m_drawPanScrollIcon)
1044 paintPanScrollIcon(context);
1045 }
1046
1047 void ScrollView::calculateOverhangAreasForPainting(IntRect& horizontalOverhangRect, IntRect& verticalOverhangRect)
1048 {
1049 int verticalScrollbarWidth = (verticalScrollbar() && !verticalScrollbar()->isOverlayScrollbar())
1050 ? verticalScrollbar()->width() : 0;
1051 int horizontalScrollbarHeight = (horizontalScrollbar() && !horizontalScrollbar()->isOverlayScrollbar())
1052 ? horizontalScrollbar()->height() : 0;
1053
1054 int physicalScrollY = scrollPosition().y() + m_scrollOrigin.y();
1055 if (physicalScrollY < 0) {
1056 horizontalOverhangRect = frameRect();
1057 horizontalOverhangRect.setHeight(-physicalScrollY);
1058 } else if (physicalScrollY > contentsHeight() - visibleContentRect().height()) {
1059 int height = physicalScrollY - (contentsHeight() - visibleContentRect().height());
1060 horizontalOverhangRect = frameRect();
1061 horizontalOverhangRect.setY(frameRect().maxY() - height - horizontalScrollbarHeight);
1062 horizontalOverhangRect.setHeight(height);
1063 }
1064
1065 int physicalScrollX = scrollPosition().x() + m_scrollOrigin.x();
1066 if (physicalScrollX < 0) {
1067 verticalOverhangRect.setWidth(-physicalScrollX);
1068 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height());
1069 verticalOverhangRect.setX(frameRect().x());
1070 if (horizontalOverhangRect.y() == frameRect().y())
1071 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1072 else
1073 verticalOverhangRect.setY(frameRect().y());
1074 } else if (physicalScrollX > contentsWidth() - visibleContentRect().width()) {
1075 int width = physicalScrollX - (contentsWidth() - visibleContentRect().width());
1076 verticalOverhangRect.setWidth(width);
1077 verticalOverhangRect.setHeight(frameRect().height() - horizontalOverhangRect.height());
1078 verticalOverhangRect.setX(frameRect().maxX() - width - verticalScrollbarWidth);
1079 if (horizontalOverhangRect.y() == frameRect().y())
1080 verticalOverhangRect.setY(frameRect().y() + horizontalOverhangRect.height());
1081 else
1082 verticalOverhangRect.setY(frameRect().y());
1083 }
1084 }
1085
1086 void ScrollView::paintOverhangAreas(GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect&)
1087 {
1088 // FIXME: This should be checking the dirty rect.
1089
1090 context->setFillColor(Color::white, ColorSpaceDeviceRGB);
1091 if (!horizontalOverhangRect.isEmpty())
1092 context->fillRect(horizontalOverhangRect);
1093
1094 context->setFillColor(Color::white, ColorSpaceDeviceRGB);
1095 if (!verticalOverhangRect.isEmpty())
1096 context->fillRect(verticalOverhangRect);
1097 }
1098
1099 bool ScrollView::isPointInScrollbarCorner(const IntPoint& windowPoint)
1100 {
1101 if (!scrollbarCornerPresent())
1102 return false;
1103
1104 IntPoint viewPoint = convertFromContainingWindow(windowPoint);
1105
1106 if (m_horizontalScrollbar) {
1107 int horizontalScrollbarYMin = m_horizontalScrollbar->frameRect().y();
1108 int horizontalScrollbarYMax = m_horizontalScrollbar->frameRect().y() + m_horizontalScrollbar->frameRect().height();
1109 int horizontalScrollbarXMin = m_horizontalScrollbar->frameRect().x() + m_horizontalScrollbar->frameRect().width();
1110
1111 return viewPoint.y() > horizontalScrollbarYMin && viewPoint.y() < horizontalScrollbarYMax && viewPoint.x() > horizontalScrollbarXMin;
1112 }
1113
1114 int verticalScrollbarXMin = m_verticalScrollbar->frameRect().x();
1115 int verticalScrollbarXMax = m_verticalScrollbar->frameRect().x() + m_verticalScrollbar->frameRect().width();
1116 int verticalScrollbarYMin = m_verticalScrollbar->frameRect().y() + m_verticalScrollbar->frameRect().height();
1117
1118 return viewPoint.x() > verticalScrollbarXMin && viewPoint.x() < verticalScrollbarXMax && viewPoint.y() > verticalScrollbarYMin;
1119 }
1120
1121 bool ScrollView::scrollbarCornerPresent() const
1122 {
1123 return (m_horizontalScrollbar && m_boundsSize.width() - m_horizontalScrollbar->width() > 0) ||
1124 (m_verticalScrollbar && m_boundsSize.height() - m_verticalScrollbar->height() > 0);
1125 }
1126
1127 IntRect ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntRect& localRect) const
1128 {
1129 // Scrollbars won't be transformed within us
1130 IntRect newRect = localRect;
1131 newRect.move(scrollbar->x(), scrollbar->y());
1132 return newRect;
1133 }
1134
1135 IntRect ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntRect& parentRect) const
1136 {
1137 IntRect newRect = parentRect;
1138 // Scrollbars won't be transformed within us
1139 newRect.move(-scrollbar->x(), -scrollbar->y());
1140 return newRect;
1141 }
1142
1143 // FIXME: test these on windows
1144 IntPoint ScrollView::convertFromScrollbarToContainingView(const Scrollbar* scrollbar, const IntPoint& localPoint) const
1145 {
1146 // Scrollbars won't be transformed within us
1147 IntPoint newPoint = localPoint;
1148 newPoint.move(scrollbar->x(), scrollbar->y());
1149 return newPoint;
1150 }
1151
1152 IntPoint ScrollView::convertFromContainingViewToScrollbar(const Scrollbar* scrollbar, const IntPoint& parentPoint) const
1153 {
1154 IntPoint newPoint = parentPoint;
1155 // Scrollbars won't be transformed within us
1156 newPoint.move(-scrollbar->x(), -scrollbar->y());
1157 return newPoint;
1158 }
1159
1160 void ScrollView::setParentVisible(bool visible)
1161 {
1162 if (isParentVisible() == visible)
1163 return;
1164
1165 Widget::setParentVisible(visible);
1166
1167 if (!isSelfVisible())
1168 return;
1169
1170 HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1171 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1172 (*it)->setParentVisible(visible);
1173 }
1174
1175 void ScrollView::show()
1176 {
1177 if (!isSelfVisible()) {
1178 setSelfVisible(true);
1179 if (isParentVisible()) {
1180 HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1181 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1182 (*it)->setParentVisible(true);
1183 }
1184 }
1185
1186 Widget::show();
1187 }
1188
1189 void ScrollView::hide()
1190 {
1191 if (isSelfVisible()) {
1192 if (isParentVisible()) {
1193 HashSet<RefPtr<Widget> >::iterator end = m_children.end();
1194 for (HashSet<RefPtr<Widget> >::iterator it = m_children.begin(); it != end; ++it)
1195 (*it)->setParentVisible(false);
1196 }
1197 setSelfVisible(false);
1198 }
1199
1200 Widget::hide();
1201 }
1202
1203 bool ScrollView::isOffscreen() const
1204 {
1205 if (platformWidget())
1206 return platformIsOffscreen();
1207
1208 if (!isVisible())
1209 return true;
1210
1211 // FIXME: Add a HostWindow::isOffscreen method here. Since only Mac implements this method
1212 // currently, we can add the method when the other platforms decide to implement this concept.
1213 return false;
1214 }
1215
1216
1217 void ScrollView::addPanScrollIcon(const IntPoint& iconPosition)
1218 {
1219 if (!hostWindow())
1220 return;
1221 m_drawPanScrollIcon = true;
1222 m_panScrollIconPoint = IntPoint(iconPosition.x() - panIconSizeLength / 2 , iconPosition.y() - panIconSizeLength / 2) ;
1223 hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1224 }
1225
1226 void ScrollView::removePanScrollIcon()
1227 {
1228 if (!hostWindow())
1229 return;
1230 m_drawPanScrollIcon = false;
1231 hostWindow()->invalidateContentsAndWindow(IntRect(m_panScrollIconPoint, IntSize(panIconSizeLength, panIconSizeLength)), true /*immediate*/);
1232 }
1233
1234 void ScrollView::setScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
1235 {
1236 if (m_scrollOrigin == origin)
1237 return;
1238
1239 m_scrollOrigin = origin;
1240
1241 if (platformWidget()) {
1242 platformSetScrollOrigin(origin, updatePositionAtAll, updatePositionSynchronously);
1243 return;
1244 }
1245
1246 // Update if the scroll origin changes, since our position will be different if the content size did not change.
1247 if (updatePositionAtAll && updatePositionSynchronously)
1248 updateScrollbars(scrollOffset());
1249 }
1250
1251 #if !PLATFORM(WX) && !PLATFORM(GTK) && !PLATFORM(EFL)
1252
1253 void ScrollView::platformInit()
1254 {
1255 }
1256
1257 void ScrollView::platformDestroy()
1258 {
1259 }
1260
1261 #endif
1262
1263 #if !PLATFORM(WX) && !PLATFORM(QT) && !PLATFORM(MAC)
1264
1265 void ScrollView::platformAddChild(Widget*)
1266 {
1267 }
1268
1269 void ScrollView::platformRemoveChild(Widget*)
1270 {
1271 }
1272
1273 #endif
1274
1275 #if !PLATFORM(MAC)
1276
1277 void ScrollView::platformSetScrollbarsSuppressed(bool)
1278 {
1279 }
1280
1281 void ScrollView::platformSetScrollOrigin(const IntPoint&, bool updatePositionAtAll, bool updatePositionSynchronously)
1282 {
1283 }
1284
1285 #endif
1286
1287 #if !PLATFORM(MAC) && !PLATFORM(WX)
1288
1289 void ScrollView::platformSetScrollbarModes()
1290 {
1291 }
1292
1293 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
1294 {
1295 horizontal = ScrollbarAuto;
1296 vertical = ScrollbarAuto;
1297 }
1298
1299 void ScrollView::platformSetCanBlitOnScroll(bool)
1300 {
1301 }
1302
1303 bool ScrollView::platformCanBlitOnScroll() const
1304 {
1305 return false;
1306 }
1307
1308 IntRect ScrollView::platformVisibleContentRect(bool) const
1309 {
1310 return IntRect();
1311 }
1312
1313 IntSize ScrollView::platformContentsSize() const
1314 {
1315 return IntSize();
1316 }
1317
1318 void ScrollView::platformSetContentsSize()
1319 {
1320 }
1321
1322 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
1323 {
1324 return rect;
1325 }
1326
1327 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
1328 {
1329 return point;
1330 }
1331
1332 void ScrollView::platformSetScrollPosition(const IntPoint&)
1333 {
1334 }
1335
1336 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
1337 {
1338 return true;
1339 }
1340
1341 void ScrollView::platformRepaintContentRectangle(const IntRect&, bool /*now*/)
1342 {
1343 }
1344
1345 bool ScrollView::platformIsOffscreen() const
1346 {
1347 return false;
1348 }
1349
1350 #endif
1351
1352 }
1353