[iOS WK2] Use larger tiles when possible to reduce per-tile painting overhead
[WebKit.git] / Source / WebCore / platform / ios / ScrollViewIOS.mm
1 /*
2  * Copyright (C) 2004, 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 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 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 #import "config.h"
27 #import "ScrollView.h"
28
29 #import "BlockExceptions.h"
30 #import "FloatRect.h"
31 #import "IntRect.h"
32 #import "Logging.h"
33 #import "NotImplemented.h"
34 #import "WAKAppKitStubs.h"
35 #import "WAKClipView.h"
36 #import "WAKScrollView.h"
37 #import "WAKViewInternal.h"
38 #import "WAKWindow.h"
39 #import "WKViewPrivate.h"
40 #import "WebCoreFrameView.h"
41 #import <wtf/CurrentTime.h>
42
43 using namespace std;
44
45 namespace WebCore {
46
47 inline NSScrollView<WebCoreFrameScrollView> *ScrollView::scrollView() const
48 {
49     ASSERT(!platformWidget() || [platformWidget() isKindOfClass:[NSScrollView class]]);
50     ASSERT(!platformWidget() || [platformWidget() conformsToProtocol:@protocol(WebCoreFrameScrollView)]);
51     return static_cast<NSScrollView<WebCoreFrameScrollView> *>(platformWidget());
52 }
53
54 NSView *ScrollView::documentView() const
55 {
56     BEGIN_BLOCK_OBJC_EXCEPTIONS;
57     return [scrollView() documentView];
58     END_BLOCK_OBJC_EXCEPTIONS;
59     return nil;
60 }
61
62 void ScrollView::platformAddChild(Widget* child)
63 {
64     ASSERT(child != this);
65
66     child->addToSuperview(documentView());
67 }
68
69 void ScrollView::platformRemoveChild(Widget* child)
70 {
71     child->removeFromSuperview();
72 }
73
74 void ScrollView::platformSetScrollbarModes()
75 {
76     BEGIN_BLOCK_OBJC_EXCEPTIONS;
77     [scrollView() setScrollingModes:m_horizontalScrollbarMode vertical:m_verticalScrollbarMode andLock:NO];
78     END_BLOCK_OBJC_EXCEPTIONS;
79 }
80
81 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
82 {
83     BEGIN_BLOCK_OBJC_EXCEPTIONS;
84     [scrollView() scrollingModes:&horizontal vertical:&vertical];
85     END_BLOCK_OBJC_EXCEPTIONS;
86 }
87
88 void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll)
89 {
90     BEGIN_BLOCK_OBJC_EXCEPTIONS;
91     [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll];
92     END_BLOCK_OBJC_EXCEPTIONS;
93 }
94
95 bool ScrollView::platformCanBlitOnScroll() const
96 {
97     return [[scrollView() contentView] copiesOnScroll];
98 }
99
100 IntRect ScrollView::unobscuredContentRect(VisibleContentRectIncludesScrollbars) const
101 {
102     if (WAKScrollView *view = static_cast<WAKScrollView *>(platformWidget())) {
103         CGRect r = CGRectZero;
104         BEGIN_BLOCK_OBJC_EXCEPTIONS;
105         r = [view unobscuredContentRect];
106         END_BLOCK_OBJC_EXCEPTIONS;
107         return enclosingIntRect(r);
108     }
109
110     if (!m_unobscuredContentSize.isEmpty())
111         return IntRect(m_scrollPosition, roundedIntSize(m_unobscuredContentSize));
112
113     return unobscuredContentRectInternal();
114 }
115
116 void ScrollView::setUnobscuredContentSize(const FloatSize& size)
117 {
118     ASSERT(!platformWidget());
119     if (size == m_unobscuredContentSize)
120         return;
121
122     m_unobscuredContentSize = size;
123     unobscuredContentSizeChanged();
124 }
125
126 FloatRect ScrollView::exposedContentRect() const
127 {
128     if (NSScrollView *view = static_cast<NSScrollView *>(platformWidget())) {
129         CGRect r = CGRectZero;
130         BEGIN_BLOCK_OBJC_EXCEPTIONS;
131         if ([view isKindOfClass:[NSScrollView class]])
132             r = [view exposedContentRect];
133         else {
134             r.origin = [view visibleRect].origin;
135             r.size = [view bounds].size;
136         }
137
138         END_BLOCK_OBJC_EXCEPTIONS;
139         return r;
140     }
141
142     const ScrollView* parent = this->parent();
143     if (!parent)
144         return m_exposedContentRect;
145
146     IntRect parentViewExtentContentRect = enclosingIntRect(parent->exposedContentRect());
147     IntRect selfExtentContentRect = rootViewToContents(parentViewExtentContentRect);
148     selfExtentContentRect.intersect(boundsRect());
149     return selfExtentContentRect;
150 }
151
152 void ScrollView::setExposedContentRect(const FloatRect& rect)
153 {
154     ASSERT(!platformWidget());
155     m_exposedContentRect = rect;
156 }
157
158 void ScrollView::setActualScrollPosition(const IntPoint& position)
159 {
160     NSScrollView *view = static_cast<NSScrollView *>(platformWidget());
161
162     BEGIN_BLOCK_OBJC_EXCEPTIONS;
163     if ([view isKindOfClass:[NSScrollView class]])
164         [view setActualScrollPosition:position];
165     END_BLOCK_OBJC_EXCEPTIONS;
166 }
167
168 float ScrollView::platformTopContentInset() const
169 {
170     return 0;
171 }
172
173 void ScrollView::platformSetTopContentInset(float)
174 {
175 }
176
177 IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const
178 {
179     BEGIN_BLOCK_OBJC_EXCEPTIONS;
180     if (includeScrollbars) {
181         if (NSView* documentView = this->documentView())
182             return enclosingIntRect([documentView visibleRect]);
183     }
184     return enclosingIntRect([scrollView() documentVisibleRect]);
185     END_BLOCK_OBJC_EXCEPTIONS;
186     return IntRect();
187 }
188
189 IntSize ScrollView::platformVisibleContentSize(bool includeScrollbars) const
190 {
191     BEGIN_BLOCK_OBJC_EXCEPTIONS;
192     if (includeScrollbars) {
193         if (NSView* documentView = this->documentView())
194             return IntSize([documentView visibleRect].size);
195     }
196
197     return expandedIntSize(FloatSize([scrollView() documentVisibleRect].size));
198     END_BLOCK_OBJC_EXCEPTIONS;
199     return IntSize();
200 }
201
202 IntRect ScrollView::platformVisibleContentRectIncludingObscuredArea(bool includeScrollbars) const
203 {
204     return platformVisibleContentRect(includeScrollbars);
205 }
206
207 IntSize ScrollView::platformVisibleContentSizeIncludingObscuredArea(bool includeScrollbars) const
208 {
209     return platformVisibleContentSize(includeScrollbars);
210 }
211
212 LegacyTileCache* ScrollView::legacyTileCache()
213 {
214     // Make tile cache pointer available via the main frame only. Tile cache interaction should be managed by
215     // the main frame and this avoids having to add parent checks to all call sites.
216     if (parent())
217         return 0;
218     BEGIN_BLOCK_OBJC_EXCEPTIONS;
219     WAKScrollView *view = static_cast<WAKScrollView *>(platformWidget());
220     return [[view window] tileCache];
221     END_BLOCK_OBJC_EXCEPTIONS;
222 }
223
224 void ScrollView::platformSetContentsSize()
225 {
226     BEGIN_BLOCK_OBJC_EXCEPTIONS;
227     int w = m_contentsSize.width();
228     int h = m_contentsSize.height();
229 #if !PLATFORM(IOS)
230     LOG(Frames, "%p %@ at w %d h %d\n", documentView(), [(id)[documentView() class] className], w, h);            
231 #else
232     LOG(Frames, "%p %@ at w %d h %d\n", documentView(), NSStringFromClass([documentView() class]), w, h);
233 #endif
234     NSSize tempSize = { static_cast<CGFloat>(max(0, w)), static_cast<CGFloat>(max(0, h)) }; // workaround for 4213314
235     [documentView() setBoundsSize:tempSize];
236     END_BLOCK_OBJC_EXCEPTIONS;
237 }
238
239 void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress)
240 {
241     BEGIN_BLOCK_OBJC_EXCEPTIONS;
242     [scrollView() setScrollBarsSuppressed:m_scrollbarsSuppressed
243                       repaintOnUnsuppress:repaintOnUnsuppress];
244     END_BLOCK_OBJC_EXCEPTIONS;
245 }
246
247 void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint)
248 {
249     BEGIN_BLOCK_OBJC_EXCEPTIONS;
250     NSPoint floatPoint = scrollPoint;
251     NSPoint tempPoint = { max(-[scrollView() scrollOrigin].x, floatPoint.x), max(-[scrollView() scrollOrigin].y, floatPoint.y) };  // Don't use NSMakePoint to work around 4213314.
252     [documentView() scrollPoint:tempPoint];
253     END_BLOCK_OBJC_EXCEPTIONS;
254 }
255
256 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
257 {
258     // FIXME: It would be nice to implement this so that all of the code in WebFrameView could go away.
259     notImplemented();
260     return false;
261 }
262
263 void ScrollView::platformRepaintContentRectangle(const IntRect& rect)
264 {
265     BEGIN_BLOCK_OBJC_EXCEPTIONS;
266
267     NSView *view = documentView();
268
269     [view setNeedsDisplayInRect:rect];    
270
271     END_BLOCK_OBJC_EXCEPTIONS;
272 }
273
274 // "Containing Window" means the NSWindow's coord system, which is origin lower left
275
276 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
277 {
278     BEGIN_BLOCK_OBJC_EXCEPTIONS;
279     if (NSView* documentView = this->documentView()) {
280         NSRect tempRect = rect;
281         tempRect = [documentView convertRect:tempRect toView:nil];
282         tempRect.origin = [[documentView window] convertBaseToScreen:tempRect.origin];
283         return enclosingIntRect(tempRect);
284     }
285     END_BLOCK_OBJC_EXCEPTIONS;
286     return IntRect();
287 }
288
289 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
290 {
291     BEGIN_BLOCK_OBJC_EXCEPTIONS;
292     if (NSView* documentView = this->documentView()) {
293         NSPoint windowCoord = [[documentView window] convertScreenToBase: point];
294         return IntPoint([documentView convertPoint:windowCoord fromView:nil]);
295     }
296     END_BLOCK_OBJC_EXCEPTIONS;
297     return IntPoint();
298 }
299
300 bool ScrollView::platformIsOffscreen() const
301 {
302     // FIXME: DDK: ScrollViewMac.mm also checks: ![[platformWidget() window] isVisible]
303     // but -[WAKWindow isVisible] doesn't exist.
304     return ![platformWidget() window];
305 }
306
307 void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle)
308 {
309 }
310
311 void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePositionAll, bool updatePositionSynchronously)
312 {
313     BEGIN_BLOCK_OBJC_EXCEPTIONS;
314     [scrollView() setScrollOrigin:static_cast<CGPoint>(origin) updatePositionAtAll:updatePositionAll immediately:updatePositionSynchronously];
315     END_BLOCK_OBJC_EXCEPTIONS;
316 }
317
318 }