e231ac0a6af945332d65d22058f675fe20ec8d1b
[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     child->move(x, y);
300
301     KWQ_BLOCK_EXCEPTIONS;
302
303     NSView * thisView;
304     NSView *thisDocView, *subview;
305     
306     thisView = getView();
307     thisDocView = getDocumentView();
308     if (thisDocView)
309         thisView = thisDocView;
310
311     subview = child->getOuterView();
312     ASSERT(subview != thisView);
313
314     if ([subview superview] != thisView) {
315         [subview removeFromSuperview];
316         
317         LOG(Frames, "Adding %p %@ at (%d,%d) w %d h %d\n", subview,
318             [(id)[subview class] className], x, y, (int)[subview frame].size.width, (int)[subview frame].size.height);
319         
320         [thisView addSubview:subview];
321     }
322     KWQ_UNBLOCK_EXCEPTIONS;
323 }
324
325 void QScrollView::removeChild(QWidget* child)
326 {
327     KWQ_BLOCK_EXCEPTIONS;
328     [child->getOuterView() removeFromSuperview];
329     KWQ_UNBLOCK_EXCEPTIONS;
330 }
331
332 void QScrollView::resizeContents(int w, int h)
333 {
334     KWQ_BLOCK_EXCEPTIONS;
335     int _w = w;
336     int _h = h;
337
338     LOG(Frames, "%p %@ at w %d h %d\n", getView(), [(id)[getView() class] className], w, h);
339     NSView *view = getView();
340     if ([view _KWQ_isScrollView]){
341         view = getDocumentView();
342         
343         LOG(Frames, "%p %@ at w %d h %d\n", view, [(id)[view class] className], w, h);
344         if (_w < 0)
345             _w = 0;
346         if (_h < 0)
347             _h = 0;
348
349         [view setFrameSize: NSMakeSize (_w,_h)];
350     } else {
351         resize (_w, _h);
352     }
353     KWQ_UNBLOCK_EXCEPTIONS;
354 }
355
356 void QScrollView::updateContents(int x, int y, int w, int h, bool now)
357 {
358     updateContents(QRect(x, y, w, h), now);
359 }
360
361 void QScrollView::updateContents(const QRect &rect, bool now)
362 {
363     KWQ_BLOCK_EXCEPTIONS;
364     NSView * view = getView();
365
366     if ([view _KWQ_isScrollView])
367         view = getDocumentView();
368
369     if (now)
370         [view displayRect: rect];
371     else
372         [view setNeedsDisplayInRect:rect];
373     KWQ_UNBLOCK_EXCEPTIONS;
374 }
375
376 void QScrollView::repaintContents(int x, int y, int w, int h, bool erase)
377 {
378     LOG(Frames, "%p %@ at (%d,%d) w %d h %d\n", getView(), [(id)[getView() class] className], x, y, w, h);
379 }
380
381 QPoint QScrollView::contentsToViewport(const QPoint &p)
382 {
383     int vx, vy;
384     contentsToViewport(p.x(), p.y(), vx, vy);
385     return QPoint(vx, vy);
386 }
387
388 void QScrollView::contentsToViewport(int x, int y, int& vx, int& vy)
389 {
390     KWQ_BLOCK_EXCEPTIONS;
391
392     NSView *docView;
393     NSView *view = getView();    
394      
395     docView = getDocumentView();
396     if (docView)
397         view = docView;
398     
399     NSPoint np = [view convertPoint: NSMakePoint (x, y) toView: nil];
400     vx = (int)np.x;
401     vy = (int)np.y;
402     
403     return;
404
405     KWQ_UNBLOCK_EXCEPTIONS;
406     
407     vx = 0;
408     vy = 0;
409 }
410
411 void QScrollView::viewportToContents(int vx, int vy, int& x, int& y)
412 {
413     KWQ_BLOCK_EXCEPTIONS;
414
415     NSView *docView;
416     NSView *view = getView();    
417
418     docView = getDocumentView();
419     if (docView)
420         view = docView;
421         
422     NSPoint np = [view convertPoint: NSMakePoint (vx, vy) fromView: nil];
423     x = (int)np.x;
424     y = (int)np.y;
425
426     return;
427
428     KWQ_UNBLOCK_EXCEPTIONS;
429
430     x = 0;
431     y = 0;
432 }
433
434 void QScrollView::setStaticBackground(bool b)
435 {
436     NSScrollView *view = (NSScrollView *)getView();
437     KWQ_BLOCK_EXCEPTIONS;
438     if ([view _KWQ_isScrollView])
439         [[view contentView] setCopiesOnScroll: !b];
440     KWQ_UNBLOCK_EXCEPTIONS;
441 }
442
443 void QScrollView::resizeEvent(QResizeEvent *)
444 {
445 }
446
447 void QScrollView::setContentsPosRecursive(int x, int y)
448 {
449     KWQ_BLOCK_EXCEPTIONS;
450     [getDocumentView() _KWQ_scrollPointRecursive:NSMakePoint(x, y)];
451     KWQ_UNBLOCK_EXCEPTIONS;
452 }
453
454 void QScrollView::ensureVisible(int x, int y)
455 {
456     // Note that the definition of ensureVisible in trolltech documentation says:
457     // "Scrolls the content so that the point (x, y) is visible with at least 
458     // 50-pixel margins (if possible, otherwise centered).", which is
459     // not what we're doing here.
460     KWQ_BLOCK_EXCEPTIONS;
461     [getDocumentView() scrollRectToVisible:NSMakeRect(x, y, 0, 0)];
462     KWQ_UNBLOCK_EXCEPTIONS;
463 }
464
465 void QScrollView::ensureVisible(int x, int y, int xmargin, int ymargin)
466 {
467     // Note that the definition of ensureVisible in trolltech documentation says:
468     // "Scrolls the content so that the point (x, y) is visible with at least the 
469     // xmargin and ymargin margins (if possible, otherwise centered).", which is
470     // not what we're doing here.
471     KWQ_BLOCK_EXCEPTIONS;
472     [getDocumentView() scrollRectToVisible:NSMakeRect(x, y, xmargin, ymargin)];
473     KWQ_UNBLOCK_EXCEPTIONS;
474 }
475
476 void QScrollView::ensureRectVisibleCentered(const QRect &rect)
477 {
478     KWQ_BLOCK_EXCEPTIONS;
479     [getDocumentView() _KWQ_scrollRectToVisible:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height())];
480     KWQ_UNBLOCK_EXCEPTIONS;
481 }
482
483 NSView *QScrollView::getDocumentView() const
484 {
485     id view = getView();
486
487     KWQ_BLOCK_EXCEPTIONS;
488     if ([view respondsToSelector:@selector(documentView)]) 
489         return [view documentView];
490     KWQ_UNBLOCK_EXCEPTIONS;
491     
492     return nil;
493 }