950c4cd06058e0827ddf802fa10aec50b0ef63eb
[WebKit-https.git] / Source / WebCore / platform / mac / ScrollViewMac.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 "FloatSize.h"
32 #import "IntRect.h"
33 #import "Logging.h"
34 #import "NotImplemented.h"
35 #import "WebCoreFrameView.h"
36
37 @interface NSScrollView (Details)
38 - (NSEdgeInsets)contentInsets;
39 @end
40
41 @interface NSWindow (WebWindowDetails)
42 - (BOOL)_needsToResetDragMargins;
43 - (void)_setNeedsToResetDragMargins:(BOOL)needs;
44 @end
45
46 namespace WebCore {
47
48 inline NSScrollView<WebCoreFrameScrollView> *ScrollView::scrollView() const
49 {
50     ASSERT(!platformWidget() || [platformWidget() isKindOfClass:[NSScrollView class]]);
51     ASSERT(!platformWidget() || [platformWidget() conformsToProtocol:@protocol(WebCoreFrameScrollView)]);
52     return static_cast<NSScrollView<WebCoreFrameScrollView> *>(platformWidget());
53 }
54
55 NSView *ScrollView::documentView() const
56 {
57     BEGIN_BLOCK_OBJC_EXCEPTIONS;
58     return [scrollView() documentView];
59     END_BLOCK_OBJC_EXCEPTIONS;
60     return nil;
61 }
62
63 void ScrollView::platformAddChild(Widget* child)
64 {
65     BEGIN_BLOCK_OBJC_EXCEPTIONS;
66     NSView *parentView = documentView();
67     NSView *childView = child->getOuterView();
68     ASSERT(![parentView isDescendantOf:childView]);
69     
70     // Suppress the resetting of drag margins since we know we can't affect them.
71     NSWindow *window = [parentView window];
72     BOOL resetDragMargins = [window _needsToResetDragMargins];
73     [window _setNeedsToResetDragMargins:NO];
74     if ([childView superview] != parentView)
75         [parentView addSubview:childView];
76     [window _setNeedsToResetDragMargins:resetDragMargins];
77     END_BLOCK_OBJC_EXCEPTIONS;
78 }
79
80 void ScrollView::platformRemoveChild(Widget* child)
81 {
82     child->removeFromSuperview();
83 }
84
85 void ScrollView::platformSetScrollbarModes()
86 {
87     BEGIN_BLOCK_OBJC_EXCEPTIONS;
88     [scrollView() setScrollingModes:m_horizontalScrollbarMode vertical:m_verticalScrollbarMode andLock:NO];
89     END_BLOCK_OBJC_EXCEPTIONS;
90 }
91
92 void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
93 {
94     BEGIN_BLOCK_OBJC_EXCEPTIONS;
95     [scrollView() scrollingModes:&horizontal vertical:&vertical];
96     END_BLOCK_OBJC_EXCEPTIONS;
97 }
98
99 void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll)
100 {
101     BEGIN_BLOCK_OBJC_EXCEPTIONS;
102     [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll];
103     END_BLOCK_OBJC_EXCEPTIONS;
104 }
105
106 bool ScrollView::platformCanBlitOnScroll() const
107 {
108     return [[scrollView() contentView] copiesOnScroll];
109 }
110
111 float ScrollView::platformTopContentInset() const
112 {
113     BEGIN_BLOCK_OBJC_EXCEPTIONS;
114 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
115     return scrollView().contentInsets.top;
116 #endif
117     END_BLOCK_OBJC_EXCEPTIONS;
118
119     return 0;
120 }
121
122 void ScrollView::platformSetTopContentInset(float topContentInset)
123 {
124     BEGIN_BLOCK_OBJC_EXCEPTIONS;
125 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
126     if (topContentInset)
127         scrollView().automaticallyAdjustsContentInsets = NO;
128     else
129         scrollView().automaticallyAdjustsContentInsets = YES;
130
131     NSEdgeInsets contentInsets = scrollView().contentInsets;
132     contentInsets.top = topContentInset;
133     scrollView().contentInsets = contentInsets;
134 #else
135     UNUSED_PARAM(topContentInset);
136 #endif
137     END_BLOCK_OBJC_EXCEPTIONS;
138 }
139
140 IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const
141 {
142     BEGIN_BLOCK_OBJC_EXCEPTIONS;
143
144     IntRect visibleContentRect = enclosingIntRect([scrollView() documentVisibleRect]);
145 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
146     visibleContentRect.move(scrollView().contentInsets.left, scrollView().contentInsets.top);
147     visibleContentRect.contract(scrollView().contentInsets.left + scrollView().contentInsets.right, scrollView().contentInsets.top + scrollView().contentInsets.bottom);
148 #endif
149
150     if (includeScrollbars) {
151         IntSize frameSize = IntSize([scrollView() frame].size);
152 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
153         frameSize.contract(scrollView().contentInsets.left + scrollView().contentInsets.right, scrollView().contentInsets.top + scrollView().contentInsets.bottom);
154 #endif
155         visibleContentRect.setSize(frameSize);
156     }
157
158     return visibleContentRect;
159     END_BLOCK_OBJC_EXCEPTIONS;
160
161     return IntRect();
162 }
163
164 IntSize ScrollView::platformVisibleContentSize(bool includeScrollbars) const
165 {
166     return platformVisibleContentRect(includeScrollbars).size();
167 }
168
169 void ScrollView::platformSetContentsSize()
170 {
171     BEGIN_BLOCK_OBJC_EXCEPTIONS;
172     int w = m_contentsSize.width();
173     int h = m_contentsSize.height();
174     LOG(Frames, "%p %@ at w %d h %d\n", documentView(), [(id)[documentView() class] className], w, h);            
175     [documentView() setFrameSize:NSMakeSize(std::max(0, w), std::max(0, h))];
176     END_BLOCK_OBJC_EXCEPTIONS;
177 }
178
179 void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress)
180 {
181     BEGIN_BLOCK_OBJC_EXCEPTIONS;
182     [scrollView() setScrollBarsSuppressed:m_scrollbarsSuppressed
183                       repaintOnUnsuppress:repaintOnUnsuppress];
184     END_BLOCK_OBJC_EXCEPTIONS;
185 }
186
187 void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint)
188 {
189     BEGIN_BLOCK_OBJC_EXCEPTIONS;
190     NSPoint floatPoint = scrollPoint;
191     NSPoint tempPoint = { std::max(-[scrollView() scrollOrigin].x, floatPoint.x), std::max(-[scrollView() scrollOrigin].y, floatPoint.y) };  // Don't use NSMakePoint to work around 4213314.
192
193 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
194     // AppKit has the inset factored into all of its scroll positions. In WebCore, we use positions that ignore
195     // the insets so that they are equivalent whether or not there is an inset.
196     tempPoint.x = tempPoint.x - scrollView().contentInsets.left;
197     tempPoint.y = tempPoint.y - scrollView().contentInsets.top;
198 #endif
199
200     [documentView() scrollPoint:tempPoint];
201     END_BLOCK_OBJC_EXCEPTIONS;
202 }
203
204 bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
205 {
206     // FIXME: It would be nice to implement this so that all of the code in WebFrameView could go away.
207     notImplemented();
208     return false;
209 }
210
211 void ScrollView::platformRepaintContentRectangle(const IntRect& rect)
212 {
213     BEGIN_BLOCK_OBJC_EXCEPTIONS;
214     NSView *view = documentView();
215     [view setNeedsDisplayInRect:rect];
216
217     END_BLOCK_OBJC_EXCEPTIONS;
218 }
219
220 // "Containing Window" means the NSWindow's coord system, which is origin lower left
221
222 IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
223 {
224     BEGIN_BLOCK_OBJC_EXCEPTIONS;
225     if (NSView* documentView = this->documentView()) {
226         NSRect tempRect = rect;
227         tempRect = [documentView convertRect:tempRect toView:nil];
228 #pragma clang diagnostic push
229 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
230         tempRect.origin = [[documentView window] convertBaseToScreen:tempRect.origin];
231 #pragma clang diagnostic pop
232         return enclosingIntRect(tempRect);
233     }
234     END_BLOCK_OBJC_EXCEPTIONS;
235     return IntRect();
236 }
237
238 IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
239 {
240     BEGIN_BLOCK_OBJC_EXCEPTIONS;
241     if (NSView* documentView = this->documentView()) {
242 #pragma clang diagnostic push
243 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
244         NSPoint windowCoord = [[documentView window] convertScreenToBase: point];
245 #pragma clang diagnostic pop
246         return IntPoint([documentView convertPoint:windowCoord fromView:nil]);
247     }
248     END_BLOCK_OBJC_EXCEPTIONS;
249     return IntPoint();
250 }
251
252 bool ScrollView::platformIsOffscreen() const
253 {
254     return ![platformWidget() window] || ![[platformWidget() window] isVisible];
255 }
256
257 static inline NSScrollerKnobStyle toNSScrollerKnobStyle(ScrollbarOverlayStyle style)
258 {
259     switch (style) {
260     case ScrollbarOverlayStyleDark:
261         return NSScrollerKnobStyleDark;
262     case ScrollbarOverlayStyleLight:
263         return NSScrollerKnobStyleLight;
264     default:
265         return NSScrollerKnobStyleDefault;
266     }
267 }
268
269 void ScrollView::platformSetScrollbarOverlayStyle(ScrollbarOverlayStyle overlayStyle)
270 {
271     [scrollView() setScrollerKnobStyle:toNSScrollerKnobStyle(overlayStyle)];
272 }
273
274 void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
275 {
276     BEGIN_BLOCK_OBJC_EXCEPTIONS;
277     [scrollView() setScrollOrigin:origin updatePositionAtAll:updatePositionAtAll immediately:updatePositionSynchronously];
278     END_BLOCK_OBJC_EXCEPTIONS;
279 }
280
281 } // namespace WebCore