/* * Copyright (C) 2004, 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #import "config.h" #import "ScrollView.h" #import "FloatRect.h" #import "IntRect.h" #import "Logging.h" #import "NotImplemented.h" #import "WAKAppKitStubs.h" #import "WAKClipView.h" #import "WAKScrollView.h" #import "WAKViewInternal.h" #import "WAKWindow.h" #import "WKViewPrivate.h" #import "WebCoreFrameView.h" #import <wtf/BlockObjCExceptions.h> #import <wtf/CurrentTime.h> using namespace std; namespace WebCore { inline NSScrollView<WebCoreFrameScrollView> *ScrollView::scrollView() const { ASSERT(!platformWidget() || [platformWidget() isKindOfClass:[NSScrollView class]]); ASSERT(!platformWidget() || [platformWidget() conformsToProtocol:@protocol(WebCoreFrameScrollView)]); return static_cast<NSScrollView<WebCoreFrameScrollView> *>(platformWidget()); } NSView *ScrollView::documentView() const { BEGIN_BLOCK_OBJC_EXCEPTIONS; return [scrollView() documentView]; END_BLOCK_OBJC_EXCEPTIONS; return nil; } void ScrollView::platformAddChild(Widget* child) { ASSERT(child != this); child->addToSuperview(documentView()); } void ScrollView::platformRemoveChild(Widget* child) { child->removeFromSuperview(); } void ScrollView::platformSetScrollbarModes() { BEGIN_BLOCK_OBJC_EXCEPTIONS; [scrollView() setScrollingModes:m_horizontalScrollbarMode vertical:m_verticalScrollbarMode andLock:NO]; END_BLOCK_OBJC_EXCEPTIONS; } void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; [scrollView() scrollingModes:&horizontal vertical:&vertical]; END_BLOCK_OBJC_EXCEPTIONS; } void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll) { BEGIN_BLOCK_OBJC_EXCEPTIONS; [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll]; END_BLOCK_OBJC_EXCEPTIONS; } bool ScrollView::platformCanBlitOnScroll() const { return [[scrollView() contentView] copiesOnScroll]; } IntRect ScrollView::unobscuredContentRect(VisibleContentRectIncludesScrollbars) const { if (WAKScrollView *view = static_cast<WAKScrollView *>(platformWidget())) { CGRect r = CGRectZero; BEGIN_BLOCK_OBJC_EXCEPTIONS; r = [view unobscuredContentRect]; END_BLOCK_OBJC_EXCEPTIONS; return enclosingIntRect(r); } if (!m_unobscuredContentSize.isEmpty()) return IntRect(m_scrollPosition, roundedIntSize(m_unobscuredContentSize)); return unobscuredContentRectInternal(); } void ScrollView::setUnobscuredContentSize(const FloatSize& size) { ASSERT(!platformWidget()); if (size == m_unobscuredContentSize) return; m_unobscuredContentSize = size; unobscuredContentSizeChanged(); } FloatRect ScrollView::exposedContentRect() const { if (NSScrollView *view = static_cast<NSScrollView *>(platformWidget())) { CGRect r = CGRectZero; BEGIN_BLOCK_OBJC_EXCEPTIONS; if ([view isKindOfClass:[NSScrollView class]]) r = [view exposedContentRect]; else { r.origin = [view visibleRect].origin; r.size = [view bounds].size; } END_BLOCK_OBJC_EXCEPTIONS; return r; } const ScrollView* parent = this->parent(); if (!parent) return m_exposedContentRect; IntRect parentViewExtentContentRect = enclosingIntRect(parent->exposedContentRect()); IntRect selfExtentContentRect = rootViewToContents(parentViewExtentContentRect); selfExtentContentRect.intersect(boundsRect()); return selfExtentContentRect; } void ScrollView::setExposedContentRect(const FloatRect& rect) { ASSERT(!platformWidget()); m_exposedContentRect = rect; } void ScrollView::setActualScrollPosition(const IntPoint& position) { NSScrollView *view = static_cast<NSScrollView *>(platformWidget()); BEGIN_BLOCK_OBJC_EXCEPTIONS; if ([view isKindOfClass:[NSScrollView class]]) [view setActualScrollPosition:position]; END_BLOCK_OBJC_EXCEPTIONS; } float ScrollView::platformTopContentInset() const { return 0; } void ScrollView::platformSetTopContentInset(float) { } IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; if (includeScrollbars) { if (NSView* documentView = this->documentView()) return enclosingIntRect([documentView visibleRect]); } return enclosingIntRect([scrollView() documentVisibleRect]); END_BLOCK_OBJC_EXCEPTIONS; return IntRect(); } IntSize ScrollView::platformVisibleContentSize(bool includeScrollbars) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; if (includeScrollbars) { if (NSView* documentView = this->documentView()) return IntSize([documentView visibleRect].size); } return expandedIntSize(FloatSize([scrollView() documentVisibleRect].size)); END_BLOCK_OBJC_EXCEPTIONS; return IntSize(); } IntRect ScrollView::platformVisibleContentRectIncludingObscuredArea(bool includeScrollbars) const { return platformVisibleContentRect(includeScrollbars); } IntSize ScrollView::platformVisibleContentSizeIncludingObscuredArea(bool includeScrollbars) const { return platformVisibleContentSize(includeScrollbars); } LegacyTileCache* ScrollView::legacyTileCache() { // Make tile cache pointer available via the main frame only. Tile cache interaction should be managed by // the main frame and this avoids having to add parent checks to all call sites. if (parent()) return 0; BEGIN_BLOCK_OBJC_EXCEPTIONS; WAKScrollView *view = static_cast<WAKScrollView *>(platformWidget()); return [[view window] tileCache]; END_BLOCK_OBJC_EXCEPTIONS; } void ScrollView::platformSetContentsSize() { BEGIN_BLOCK_OBJC_EXCEPTIONS; int w = m_contentsSize.width(); int h = m_contentsSize.height(); #if !PLATFORM(IOS) LOG(Frames, "%p %@ at w %d h %d\n", documentView(), [(id)[documentView() class] className], w, h); #else LOG(Frames, "%p %@ at w %d h %d\n", documentView(), NSStringFromClass([documentView() class]), w, h); #endif NSSize tempSize = { static_cast<CGFloat>(max(0, w)), static_cast<CGFloat>(max(0, h)) }; // workaround for 4213314 [documentView() setBoundsSize:tempSize]; END_BLOCK_OBJC_EXCEPTIONS; } void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress) { BEGIN_BLOCK_OBJC_EXCEPTIONS; [scrollView() setScrollBarsSuppressed:m_scrollbarsSuppressed repaintOnUnsuppress:repaintOnUnsuppress]; END_BLOCK_OBJC_EXCEPTIONS; } void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint) { BEGIN_BLOCK_OBJC_EXCEPTIONS; NSPoint floatPoint = scrollPoint; NSPoint tempPoint = { max(-[scrollView() scrollOrigin].x, floatPoint.x), max(-[scrollView() scrollOrigin].y, floatPoint.y) }; // Don't use NSMakePoint to work around 4213314. [documentView() scrollPoint:tempPoint]; END_BLOCK_OBJC_EXCEPTIONS; } bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity) { // FIXME: It would be nice to implement this so that all of the code in WebFrameView could go away. notImplemented(); return false; } void ScrollView::platformRepaintContentRectangle(const IntRect& rect) { BEGIN_BLOCK_OBJC_EXCEPTIONS; NSView *view = documentView(); [view setNeedsDisplayInRect:rect]; END_BLOCK_OBJC_EXCEPTIONS; } // "Containing Window" means the NSWindow's coord system, which is origin lower left IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; if (NSView* documentView = this->documentView()) { NSRect tempRect = rect; tempRect = [documentView convertRect:tempRect toView:nil]; tempRect.origin = [[documentView window] convertBaseToScreen:tempRect.origin]; return enclosingIntRect(tempRect); } END_BLOCK_OBJC_EXCEPTIONS; return IntRect(); } IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const { BEGIN_BLOCK_OBJC_EXCEPTIONS; if (NSView* documentView = this->documentView()) { NSPoint windowCoord = [[documentView window] convertScreenToBase: point]; return IntPoint([documentView convertPoint:windowCoord fromView:nil]); } END_BLOCK_OBJC_EXCEPTIONS; return IntPoint(); } bool ScrollView::platformIsOffscreen() const { // FIXME: DDK: ScrollViewMac.mm also checks: ![[platformWidget() window] isVisible] // but -[WAKWindow isVisible] doesn't exist. return ![platformWidget() window]; } void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle) { } void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePositionAll, bool updatePositionSynchronously) { BEGIN_BLOCK_OBJC_EXCEPTIONS; [scrollView() setScrollOrigin:static_cast<CGPoint>(origin) updatePositionAtAll:updatePositionAll immediately:updatePositionSynchronously]; END_BLOCK_OBJC_EXCEPTIONS; } }