f0769040f020461a65d56549cee8544e1b88c2cd
[WebKit-https.git] / WebCore / kwq / KWQScrollView.mm
1 /*
2  * Copyright (C) 2003 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 "KWQScrollView.h"
27
28 #import "KWQExceptions.h"
29 #import "KWQLogging.h"
30 #import "KWQNSViewExtras.h"
31 #import "WebCoreFrameView.h"
32
33 /*
34     This class implementation does NOT actually emulate the Qt QScrollView.
35     It does provide an implementation that khtml will use to interact with
36     WebKit's WebFrameView documentView and our NSScrollView subclass.
37
38     QScrollView's view is a NSScrollView (or subclass of NSScrollView)
39     in most cases. That scrollview is a subview of an
40     WebCoreFrameView. The WebCoreFrameView's documentView will also be
41     the scroll view's documentView.
42     
43     The WebCoreFrameView's size is the frame size.  The WebCoreFrameView's documentView
44     corresponds to the frame content size.  The scrollview itself is autosized to the
45     WebCoreFrameView's size (see QWidget::resize).
46 */
47
48 @interface NSView (KWQExtensions)
49 - (BOOL)_KWQ_isScrollView;
50 @end
51
52 @implementation NSView (KWQExtensions)
53
54 - (BOOL)_KWQ_isScrollView
55 {
56     return [self isKindOfClass:[NSScrollView class]];
57 }
58
59 @end
60
61 QWidget* QScrollView::viewport() const
62 {
63     return const_cast<QScrollView *>(this);
64 }
65
66 int QScrollView::visibleWidth() const
67 {
68     NSScrollView *view = (NSScrollView *)getView();
69
70     KWQ_BLOCK_EXCEPTIONS;
71     if ([view _KWQ_isScrollView]) {
72         return (int)[view documentVisibleRect].size.width;
73     } else {
74         return (int)[view bounds].size.width;
75     }
76     KWQ_UNBLOCK_EXCEPTIONS;
77
78     return 0;
79 }
80
81 int QScrollView::visibleHeight() const
82 {
83     NSScrollView *view = (NSScrollView *)getView();
84     
85     KWQ_BLOCK_EXCEPTIONS;
86     if ([view _KWQ_isScrollView]) {
87         return (int)[view documentVisibleRect].size.height;
88     } else {
89         return (int)[view bounds].size.height;
90     }
91     KWQ_UNBLOCK_EXCEPTIONS;
92     
93     return 0;
94 }
95
96 int QScrollView::contentsWidth() const
97 {
98     NSView *docView, *view = getView();
99     docView = getDocumentView();
100
101     KWQ_BLOCK_EXCEPTIONS;
102     if (docView) {
103         return (int)[docView bounds].size.width;
104     } else {
105         return (int)[view bounds].size.width;
106     }
107     KWQ_UNBLOCK_EXCEPTIONS;
108
109     return 0;
110 }
111
112 int QScrollView::contentsHeight() const
113 {
114     NSView *docView, *view = getView();
115     docView = getDocumentView();
116
117     KWQ_BLOCK_EXCEPTIONS;
118     if (docView) {
119         return (int)[docView bounds].size.height;
120     } else {
121         return (int)[view bounds].size.height;
122     }
123     KWQ_UNBLOCK_EXCEPTIONS;
124
125     return 0;
126 }
127
128 int QScrollView::contentsX() const
129 {
130     NSView *view = getView();
131
132     KWQ_BLOCK_EXCEPTIONS;
133     if ([view _KWQ_isScrollView]) {
134         NSScrollView *sview = view;
135         return (int)[sview documentVisibleRect].origin.x;
136     } else {
137         return (int)[view visibleRect].origin.x;
138     }
139     KWQ_UNBLOCK_EXCEPTIONS;
140
141     return 0;
142 }
143
144 int QScrollView::contentsY() const
145 {
146     NSView *view = getView();
147
148     KWQ_BLOCK_EXCEPTIONS;
149     if ([view _KWQ_isScrollView]) {
150         NSScrollView *sview = view;
151         return (int)[sview documentVisibleRect].origin.y;
152     } else {
153         return (int)[view visibleRect].origin.y;
154     }
155     KWQ_UNBLOCK_EXCEPTIONS;
156
157     return 0;
158 }
159
160 int QScrollView::childX(QWidget* w)
161 {
162     return w->x();
163 }
164
165 int QScrollView::childY(QWidget* w)
166 {
167     return w->y();
168 }
169
170 void QScrollView::scrollBy(int dx, int dy)
171 {
172     setContentsPos(contentsX() + dx, contentsY() + dy);
173 }
174
175 void QScrollView::setContentsPos(int x, int y)
176 {
177     x = (x < 0) ? 0 : x;
178     y = (y < 0) ? 0 : y;
179     NSPoint p =  NSMakePoint(x,y);
180
181     KWQ_BLOCK_EXCEPTIONS;
182     NSView *docView;
183     NSView *view = getView();    
184     docView = getDocumentView();
185     if (docView)
186         view = docView;
187         
188     [view scrollPoint:p];
189     KWQ_UNBLOCK_EXCEPTIONS;
190 }
191
192 void QScrollView::setVScrollBarMode(ScrollBarMode vMode)
193 {
194     NSView* view = getView();
195
196     KWQ_BLOCK_EXCEPTIONS;
197     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
198         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
199         [frameView setVerticalScrollingMode: (WebCoreScrollBarMode)vMode];
200     }
201     KWQ_UNBLOCK_EXCEPTIONS;
202 }
203
204 void QScrollView::setHScrollBarMode(ScrollBarMode hMode)
205 {
206     NSView* view = getView();
207
208     KWQ_BLOCK_EXCEPTIONS;
209     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
210         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
211         [frameView setHorizontalScrollingMode: (WebCoreScrollBarMode)hMode];
212     }
213     KWQ_UNBLOCK_EXCEPTIONS;
214 }
215
216 void QScrollView::setScrollBarsMode(ScrollBarMode mode)
217 {
218     NSView* view = getView();
219
220     KWQ_BLOCK_EXCEPTIONS;
221     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
222         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
223         [frameView setScrollingMode: (WebCoreScrollBarMode)mode];
224     }
225     KWQ_UNBLOCK_EXCEPTIONS;
226 }
227
228 QScrollView::ScrollBarMode
229 QScrollView::vScrollBarMode() const
230 {
231     NSView* view = getView();
232
233     KWQ_BLOCK_EXCEPTIONS;
234     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
235         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
236         return (ScrollBarMode)[frameView verticalScrollingMode];
237     }
238     KWQ_UNBLOCK_EXCEPTIONS;
239
240     return Auto;
241 }
242
243 QScrollView::ScrollBarMode
244 QScrollView::hScrollBarMode() const
245 {
246     NSView* view = getView();
247
248     KWQ_BLOCK_EXCEPTIONS;
249     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
250         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
251         return (ScrollBarMode)[frameView horizontalScrollingMode];
252     }
253     KWQ_UNBLOCK_EXCEPTIONS;
254
255     return Auto;
256 }
257
258 bool QScrollView::hasVerticalScrollBar() const
259 {
260     NSScrollView *view = (NSScrollView *)getView();
261     
262     KWQ_BLOCK_EXCEPTIONS;
263     if ([view _KWQ_isScrollView])
264         return  [view hasVerticalScroller];
265     KWQ_UNBLOCK_EXCEPTIONS;
266
267     return false;
268 }
269
270 bool QScrollView::hasHorizontalScrollBar() const
271 {
272     NSScrollView *view = (NSScrollView *)getView();
273     
274     KWQ_BLOCK_EXCEPTIONS;
275     if ([view _KWQ_isScrollView])
276         return [view hasHorizontalScroller];
277     KWQ_UNBLOCK_EXCEPTIONS;
278
279     return false;
280 }
281
282 void QScrollView::suppressScrollBars(bool suppressed,  bool repaintOnUnsuppress)
283 {
284     NSView* view = getView();
285
286     KWQ_BLOCK_EXCEPTIONS;
287     if ([view conformsToProtocol:@protocol(WebCoreFrameView)]) {
288         NSView<WebCoreFrameView>* frameView = (NSView<WebCoreFrameView>*)view;
289         [frameView setScrollBarsSuppressed: suppressed
290                        repaintOnUnsuppress: repaintOnUnsuppress];
291     }
292     KWQ_UNBLOCK_EXCEPTIONS;
293 }
294
295 void QScrollView::addChild(QWidget* child, int x, int y)
296 {
297     ASSERT(child != this);
298     
299     // we don't need to do the offscreen position initialization that KDE needs
300     if (x != -500000)
301         child->move(x, y);
302
303     KWQ_BLOCK_EXCEPTIONS;
304
305     NSView * thisView;
306     NSView *thisDocView, *subview;
307     
308     thisView = getView();
309     thisDocView = getDocumentView();
310     if (thisDocView)
311         thisView = thisDocView;
312
313     subview = child->getOuterView();
314     ASSERT(subview != thisView);
315
316     if ([subview superview] != thisView) {
317         [subview removeFromSuperview];
318         
319         LOG(Frames, "Adding %p %@ at (%d,%d) w %d h %d\n", subview,
320             [(id)[subview class] className], x, y, (int)[subview frame].size.width, (int)[subview frame].size.height);
321         
322         [thisView addSubview:subview];
323     }
324     KWQ_UNBLOCK_EXCEPTIONS;
325 }
326
327 void QScrollView::removeChild(QWidget* child)
328 {
329     KWQ_BLOCK_EXCEPTIONS;
330     [child->getOuterView() removeFromSuperview];
331     KWQ_UNBLOCK_EXCEPTIONS;
332 }
333
334 void QScrollView::resizeContents(int w, int h)
335 {
336     KWQ_BLOCK_EXCEPTIONS;
337     int _w = w;
338     int _h = h;
339
340     LOG(Frames, "%p %@ at w %d h %d\n", getView(), [(id)[getView() class] className], w, h);
341     NSView *view = getView();
342     if ([view _KWQ_isScrollView]){
343         view = getDocumentView();
344         
345         LOG(Frames, "%p %@ at w %d h %d\n", view, [(id)[view class] className], w, h);
346         if (_w < 0)
347             _w = 0;
348         if (_h < 0)
349             _h = 0;
350
351         [view setFrameSize: NSMakeSize (_w,_h)];
352     } else {
353         resize (_w, _h);
354     }
355     KWQ_UNBLOCK_EXCEPTIONS;
356 }
357
358 void QScrollView::updateContents(int x, int y, int w, int h, bool now)
359 {
360     updateContents(QRect(x, y, w, h), now);
361 }
362
363 void QScrollView::updateContents(const QRect &rect, bool now)
364 {
365     KWQ_BLOCK_EXCEPTIONS;
366     NSView * view = getView();
367
368     if ([view _KWQ_isScrollView])
369         view = getDocumentView();
370
371     if (now)
372         [view displayRect: rect];
373     else
374         [view setNeedsDisplayInRect:rect];
375     KWQ_UNBLOCK_EXCEPTIONS;
376 }
377
378 void QScrollView::repaintContents(int x, int y, int w, int h, bool erase)
379 {
380     LOG(Frames, "%p %@ at (%d,%d) w %d h %d\n", getView(), [(id)[getView() class] className], x, y, w, h);
381 }
382
383 QPoint QScrollView::contentsToViewport(const QPoint &p)
384 {
385     int vx, vy;
386     contentsToViewport(p.x(), p.y(), vx, vy);
387     return QPoint(vx, vy);
388 }
389
390 // NB, for us "viewport" means the NSWindow's coord system, which is origin lower left
391
392 void QScrollView::contentsToViewport(int x, int y, int& vx, int& vy)
393 {
394     KWQ_BLOCK_EXCEPTIONS;
395
396     NSView *docView;
397     NSView *view = getView();    
398      
399     docView = getDocumentView();
400     if (docView)
401         view = docView;
402     
403     NSPoint np = [view convertPoint: NSMakePoint (x, y) toView: nil];
404     vx = (int)np.x;
405     vy = (int)np.y;
406     
407     return;
408
409     KWQ_UNBLOCK_EXCEPTIONS;
410     
411     vx = 0;
412     vy = 0;
413 }
414
415 void QScrollView::viewportToContents(int vx, int vy, int& x, int& y)
416 {
417     KWQ_BLOCK_EXCEPTIONS;
418
419     NSView *docView;
420     NSView *view = getView();    
421
422     docView = getDocumentView();
423     if (docView)
424         view = docView;
425         
426     NSPoint np = [view convertPoint: NSMakePoint (vx, vy) fromView: nil];
427     x = (int)np.x;
428     y = (int)np.y;
429
430     return;
431
432     KWQ_UNBLOCK_EXCEPTIONS;
433
434     x = 0;
435     y = 0;
436 }
437
438 void QScrollView::setStaticBackground(bool b)
439 {
440     NSScrollView *view = (NSScrollView *)getView();
441     KWQ_BLOCK_EXCEPTIONS;
442     if ([view _KWQ_isScrollView])
443         [[view contentView] setCopiesOnScroll: !b];
444     KWQ_UNBLOCK_EXCEPTIONS;
445 }
446
447 void QScrollView::resizeEvent(QResizeEvent *)
448 {
449 }
450
451 void QScrollView::setContentsPosRecursive(int x, int y)
452 {
453     KWQ_BLOCK_EXCEPTIONS;
454     [getDocumentView() _KWQ_scrollPointRecursive:NSMakePoint(x, y)];
455     KWQ_UNBLOCK_EXCEPTIONS;
456 }
457
458 void QScrollView::ensureVisible(int x, int y)
459 {
460     // Note that the definition of ensureVisible in trolltech documentation says:
461     // "Scrolls the content so that the point (x, y) is visible with at least 
462     // 50-pixel margins (if possible, otherwise centered).", which is
463     // not what we're doing here.
464     KWQ_BLOCK_EXCEPTIONS;
465     [getDocumentView() scrollRectToVisible:NSMakeRect(x, y, 0, 0)];
466     KWQ_UNBLOCK_EXCEPTIONS;
467 }
468
469 void QScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
470 {
471     // Note that the definition of ensureVisible in trolltech documentation says:
472     // "Scrolls the content so that the point (x, y) is visible with at least the 
473     // xmargin and ymargin margins (if possible, otherwise centered).", which is
474     // not what we're doing here.
475     KWQ_BLOCK_EXCEPTIONS;
476     [getDocumentView() scrollRectToVisible:NSMakeRect(x, y, xmargin, ymargin)];
477     KWQ_UNBLOCK_EXCEPTIONS;
478 }
479
480 void QScrollView::ensureRectVisibleCentered(const QRect &rect)
481 {
482     KWQ_BLOCK_EXCEPTIONS;
483     [getDocumentView() _KWQ_scrollRectToVisible:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
484     KWQ_UNBLOCK_EXCEPTIONS;
485 }
486
487 NSView *QScrollView::getDocumentView() const
488 {
489     id view = getView();
490
491     KWQ_BLOCK_EXCEPTIONS;
492     if ([view respondsToSelector:@selector(documentView)]) 
493         return [view documentView];
494     KWQ_UNBLOCK_EXCEPTIONS;
495     
496     return nil;
497 }