Eliminate viewportToContents and contentsToViewport
[WebKit-https.git] / WebCore / platform / mac / ScrollViewMac.mm
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, 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 #import "config.h"
27 #import "ScrollView.h"
28
29 #import "FloatRect.h"
30 #import "IntRect.h"
31 #import "BlockExceptions.h"
32 #import "Logging.h"
33 #import "WebCoreFrameView.h"
34
35 /*
36     This class implementation does NOT actually emulate the Qt ScrollView.
37     It does provide an implementation that khtml will use to interact with
38     WebKit's WebFrameView documentView and our NSScrollView subclass.
39
40     ScrollView's view is a NSScrollView (or subclass of NSScrollView)
41     in most cases. That scrollview is a subview of an
42     WebCoreFrameView. The WebCoreFrameView's documentView will also be
43     the scroll view's documentView.
44     
45     The WebCoreFrameView's size is the frame size.  The WebCoreFrameView's documentView
46     corresponds to the frame content size.  The scrollview itself is autosized to the
47     WebCoreFrameView's size (see Widget::resize).
48 */
49
50 namespace WebCore {
51
52 int ScrollView::visibleWidth() const
53 {
54     NSScrollView *view = (NSScrollView *)getView();
55
56     BEGIN_BLOCK_OBJC_EXCEPTIONS;
57     if ([view isKindOfClass:[NSScrollView class]])
58         return (int)[view documentVisibleRect].size.width;
59     else
60         return (int)[view bounds].size.width;
61     END_BLOCK_OBJC_EXCEPTIONS;
62
63     return 0;
64 }
65
66 int ScrollView::visibleHeight() const
67 {
68     NSScrollView *view = (NSScrollView *)getView();
69     
70     BEGIN_BLOCK_OBJC_EXCEPTIONS;
71     if ([view isKindOfClass:[NSScrollView class]])
72         return (int)[view documentVisibleRect].size.height;
73     else
74         return (int)[view bounds].size.height;
75     END_BLOCK_OBJC_EXCEPTIONS;
76     
77     return 0;
78 }
79
80 FloatRect ScrollView::visibleContentRect() const
81 {
82     BEGIN_BLOCK_OBJC_EXCEPTIONS;
83     if (NSView *docView = getDocumentView())
84         return [docView visibleRect];
85     END_BLOCK_OBJC_EXCEPTIONS;
86     return FloatRect();
87 }
88
89 int ScrollView::contentsWidth() const
90 {
91     NSView *docView, *view = getView();
92     docView = getDocumentView();
93
94     BEGIN_BLOCK_OBJC_EXCEPTIONS;
95     if (docView)
96         return (int)[docView bounds].size.width;
97     else
98         return (int)[view bounds].size.width;
99     END_BLOCK_OBJC_EXCEPTIONS;
100
101     return 0;
102 }
103
104 int ScrollView::contentsHeight() const
105 {
106     NSView *docView, *view = getView();
107     docView = getDocumentView();
108
109     BEGIN_BLOCK_OBJC_EXCEPTIONS;
110     if (docView)
111         return (int)[docView bounds].size.height;
112     else
113         return (int)[view bounds].size.height;
114     END_BLOCK_OBJC_EXCEPTIONS;
115
116     return 0;
117 }
118
119 int ScrollView::contentsX() const
120 {
121     NSView *view = getView();
122
123     BEGIN_BLOCK_OBJC_EXCEPTIONS;
124     if ([view isKindOfClass:[NSScrollView class]])
125         return (int)[(NSScrollView *)view documentVisibleRect].origin.x;
126     else
127         return (int)[view visibleRect].origin.x;
128     END_BLOCK_OBJC_EXCEPTIONS;
129
130     return 0;
131 }
132
133 int ScrollView::contentsY() const
134 {
135     NSView *view = getView();
136
137     BEGIN_BLOCK_OBJC_EXCEPTIONS;
138     if ([view isKindOfClass:[NSScrollView class]])
139         return (int)[(NSScrollView *)view documentVisibleRect].origin.y;
140     else
141         return (int)[view visibleRect].origin.y;
142     END_BLOCK_OBJC_EXCEPTIONS;
143
144     return 0;
145 }
146
147 IntSize ScrollView::scrollOffset() const
148 {
149     NSView *view = getView();
150     
151     BEGIN_BLOCK_OBJC_EXCEPTIONS;
152     if ([view isKindOfClass:[NSScrollView class]])
153         return IntPoint([[(NSScrollView *)view contentView] visibleRect].origin) - IntPoint();
154     END_BLOCK_OBJC_EXCEPTIONS;
155     return IntSize();
156 }
157
158 void ScrollView::scrollBy(int dx, int dy)
159 {
160     setContentsPos(contentsX() + dx, contentsY() + dy);
161 }
162
163 void ScrollView::scrollPointRecursively(int x, int y)
164
165     x = (x < 0) ? 0 : x;
166     y = (y < 0) ? 0 : y;
167     NSPoint p = NSMakePoint(x,y);
168     
169     BEGIN_BLOCK_OBJC_EXCEPTIONS;
170     NSView *docView;
171     NSView *view = getView();    
172     docView = getDocumentView();
173     if (docView)
174         view = docView;
175     
176     NSView *originalView = view;
177     while (view) {
178         if ([view isKindOfClass:[NSClipView class]]) {
179             NSPoint viewPoint = [view convertPoint:p fromView:originalView];
180             [view scrollPoint:viewPoint];
181         }
182         view = [view superview];
183     }
184     END_BLOCK_OBJC_EXCEPTIONS;
185 }
186
187 void ScrollView::setContentsPos(int x, int y)
188 {
189     x = (x < 0) ? 0 : x;
190     y = (y < 0) ? 0 : y;
191     NSPoint p =  NSMakePoint(x,y);
192
193     BEGIN_BLOCK_OBJC_EXCEPTIONS;
194     NSView *docView;
195     NSView *view = getView();    
196     docView = getDocumentView();
197     if (docView)
198         view = docView;
199     [view scrollPoint:p];
200     END_BLOCK_OBJC_EXCEPTIONS;
201 }
202
203 void ScrollView::setVScrollBarMode(ScrollBarMode vMode)
204 {
205     NSView* view = getView();
206
207     BEGIN_BLOCK_OBJC_EXCEPTIONS;
208     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
209         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
210         [frameView setVerticalScrollingMode: (WebCoreScrollBarMode)vMode];
211     }
212     END_BLOCK_OBJC_EXCEPTIONS;
213 }
214
215 void ScrollView::setHScrollBarMode(ScrollBarMode hMode)
216 {
217     NSView* view = getView();
218
219     BEGIN_BLOCK_OBJC_EXCEPTIONS;
220     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
221         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
222         [frameView setHorizontalScrollingMode: (WebCoreScrollBarMode)hMode];
223     }
224     END_BLOCK_OBJC_EXCEPTIONS;
225 }
226
227 void ScrollView::setScrollBarsMode(ScrollBarMode mode)
228 {
229     NSView* view = getView();
230
231     BEGIN_BLOCK_OBJC_EXCEPTIONS;
232     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
233         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
234         [frameView setScrollingMode: (WebCoreScrollBarMode)mode];
235     }
236     END_BLOCK_OBJC_EXCEPTIONS;
237 }
238
239 ScrollBarMode ScrollView::vScrollBarMode() const
240 {
241     NSView* view = getView();
242
243     BEGIN_BLOCK_OBJC_EXCEPTIONS;
244     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
245         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
246         return (ScrollBarMode)[frameView verticalScrollingMode];
247     }
248     END_BLOCK_OBJC_EXCEPTIONS;
249
250     return ScrollBarAuto;
251 }
252
253 ScrollBarMode ScrollView::hScrollBarMode() const
254 {
255     NSView* view = getView();
256
257     BEGIN_BLOCK_OBJC_EXCEPTIONS;
258     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
259         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
260         return (ScrollBarMode)[frameView horizontalScrollingMode];
261     }
262     END_BLOCK_OBJC_EXCEPTIONS;
263
264     return ScrollBarAuto;
265 }
266
267 void ScrollView::suppressScrollBars(bool suppressed,  bool repaintOnUnsuppress)
268 {
269     NSView* view = getView();
270
271     BEGIN_BLOCK_OBJC_EXCEPTIONS;
272     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
273         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
274         [frameView setScrollBarsSuppressed: suppressed
275                        repaintOnUnsuppress: repaintOnUnsuppress];
276     }
277     END_BLOCK_OBJC_EXCEPTIONS;
278 }
279
280 void ScrollView::addChild(Widget* child, int x, int y)
281 {
282     ASSERT(child != this);
283     
284     // we don't need to do the offscreen position initialization that KDE needs
285     if (x != -500000)
286         child->move(x, y);
287
288     NSView *thisView = getView();
289     NSView *thisDocView = getDocumentView();
290     if (thisDocView)
291         thisView = thisDocView;
292
293 #ifndef NDEBUG
294     NSView *subview = child->getOuterView();
295     
296     LOG(Frames, "Adding %p %@ at (%d,%d) w %d h %d\n", subview,
297         [(id)[subview class] className], x, y, (int)[subview frame].size.width, (int)[subview frame].size.height);
298 #endif
299     child->addToSuperview(thisView);
300 }
301
302 void ScrollView::removeChild(Widget* child)
303 {
304     child->removeFromSuperview();
305 }
306
307 void ScrollView::resizeContents(int w, int h)
308 {
309     BEGIN_BLOCK_OBJC_EXCEPTIONS;
310     int _w = w;
311     int _h = h;
312
313     LOG(Frames, "%p %@ at w %d h %d\n", getView(), [(id)[getView() class] className], w, h);
314     NSView *view = getView();
315     if ([view isKindOfClass:[NSScrollView class]]){
316         view = getDocumentView();
317         
318         LOG(Frames, "%p %@ at w %d h %d\n", view, [(id)[view class] className], w, h);
319         if (_w < 0)
320             _w = 0;
321         if (_h < 0)
322             _h = 0;
323             
324         NSSize tempSize = { _w, _h }; // workaround for 4213314
325         [view setFrameSize:tempSize];
326     } else {
327         resize (_w, _h);
328     }
329     END_BLOCK_OBJC_EXCEPTIONS;
330 }
331
332 void ScrollView::updateContents(const IntRect &rect, bool now)
333 {
334     BEGIN_BLOCK_OBJC_EXCEPTIONS;
335
336     NSView *view = getView();
337
338     if ([view isKindOfClass:[NSScrollView class]])
339         view = getDocumentView();
340
341     // Checking for rect visibility is an important optimization for the case of
342     // Select All of a large document. AppKit does not do this check, and so ends
343     // up building a large complicated NSRegion if we don't perform the check.
344     NSRect dirtyRect = NSIntersectionRect(rect, [view visibleRect]);
345     if (!NSIsEmptyRect(dirtyRect)) {
346         [view setNeedsDisplayInRect:dirtyRect];
347         if (now) {
348             [[view window] displayIfNeeded];
349             [[view window] flushWindowIfNeeded];
350         }
351     }
352
353     END_BLOCK_OBJC_EXCEPTIONS;
354 }
355
356 // "Containing Window" means the NSWindow's coord system, which is origin lower left
357
358 IntPoint ScrollView::convertToContainingWindow(const IntPoint& contentsPoint) const
359 {
360     BEGIN_BLOCK_OBJC_EXCEPTIONS;
361
362     NSView *docView;
363     NSView *view = getView();    
364      
365     docView = getDocumentView();
366     if (docView)
367         view = docView;
368     
369     NSPoint tempPoint = { contentsPoint.x(), contentsPoint.y() }; // workaround for 4213314
370     NSPoint np = [view convertPoint:tempPoint toView: nil];
371     return IntPoint(np);
372
373     END_BLOCK_OBJC_EXCEPTIONS;
374     
375     return IntPoint();
376 }
377
378 IntPoint ScrollView::convertFromContainingWindow(const IntPoint& point) const
379 {
380     BEGIN_BLOCK_OBJC_EXCEPTIONS;
381
382     NSView *docView;
383     NSView *view = getView();    
384
385     docView = getDocumentView();
386     if (docView)
387         view = docView;
388     
389     NSPoint tempPoint = { point.x(), point.y() }; // workaround for 4213314
390     NSPoint np = [view convertPoint:tempPoint fromView: nil];
391
392     return IntPoint(np);
393
394     END_BLOCK_OBJC_EXCEPTIONS;
395
396     return IntPoint();
397 }
398
399 void ScrollView::setStaticBackground(bool b)
400 {
401     NSScrollView *view = (NSScrollView *)getView();
402     BEGIN_BLOCK_OBJC_EXCEPTIONS;
403     if ([view isKindOfClass:[NSScrollView class]])
404         [[view contentView] setCopiesOnScroll: !b];
405     END_BLOCK_OBJC_EXCEPTIONS;
406 }
407
408 NSView *ScrollView::getDocumentView() const
409 {
410     id view = getView();
411
412     BEGIN_BLOCK_OBJC_EXCEPTIONS;
413     if ([view respondsToSelector:@selector(documentView)]) 
414         return [view documentView];
415     END_BLOCK_OBJC_EXCEPTIONS;
416     
417     return nil;
418 }
419
420 bool ScrollView::inWindow() const
421 {
422     return [getView() window];
423 }
424
425 void ScrollView::wheelEvent(PlatformWheelEvent&)
426 {
427     // Do nothing.  NSScrollView handles doing the scroll for us.
428 }
429
430 }