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