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