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