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 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 "BlockExceptions.h"
30#import "FloatRect.h"
31#import "IntRect.h"
32#import "Logging.h"
33#import "NotImplemented.h"
34#import "WebCoreFrameView.h"
35
36using namespace std;
37
38@interface NSWindow (WebWindowDetails)
39- (BOOL)_needsToResetDragMargins;
40- (void)_setNeedsToResetDragMargins:(BOOL)needs;
41@end
42
43namespace WebCore {
44
45inline NSScrollView<WebCoreFrameScrollView> *ScrollView::scrollView() const
46{
47    ASSERT(!platformWidget() || [platformWidget() isKindOfClass:[NSScrollView class]]);
48    ASSERT(!platformWidget() || [platformWidget() conformsToProtocol:@protocol(WebCoreFrameScrollView)]);
49    return static_cast<NSScrollView<WebCoreFrameScrollView> *>(platformWidget());
50}
51
52NSView *ScrollView::documentView() const
53{
54    BEGIN_BLOCK_OBJC_EXCEPTIONS;
55    return [scrollView() documentView];
56    END_BLOCK_OBJC_EXCEPTIONS;
57    return nil;
58}
59
60void ScrollView::platformAddChild(Widget* child)
61{
62    BEGIN_BLOCK_OBJC_EXCEPTIONS;
63    NSView *parentView = documentView();
64    NSView *childView = child->getOuterView();
65    ASSERT(![parentView isDescendantOf:childView]);
66
67    // Suppress the resetting of drag margins since we know we can't affect them.
68    NSWindow *window = [parentView window];
69    BOOL resetDragMargins = [window _needsToResetDragMargins];
70    [window _setNeedsToResetDragMargins:NO];
71    if ([childView superview] != parentView)
72        [parentView addSubview:childView];
73    [window _setNeedsToResetDragMargins:resetDragMargins];
74    END_BLOCK_OBJC_EXCEPTIONS;
75}
76
77void ScrollView::platformRemoveChild(Widget* child)
78{
79    child->removeFromSuperview();
80}
81
82void ScrollView::platformSetScrollbarModes()
83{
84    BEGIN_BLOCK_OBJC_EXCEPTIONS;
85    [scrollView() setScrollingModes:m_horizontalScrollbarMode vertical:m_verticalScrollbarMode andLock:NO];
86    END_BLOCK_OBJC_EXCEPTIONS;
87}
88
89void ScrollView::platformScrollbarModes(ScrollbarMode& horizontal, ScrollbarMode& vertical) const
90{
91    BEGIN_BLOCK_OBJC_EXCEPTIONS;
92    [scrollView() scrollingModes:&horizontal vertical:&vertical];
93    END_BLOCK_OBJC_EXCEPTIONS;
94}
95
96void ScrollView::platformSetCanBlitOnScroll(bool canBlitOnScroll)
97{
98    BEGIN_BLOCK_OBJC_EXCEPTIONS;
99    [[scrollView() contentView] setCopiesOnScroll:canBlitOnScroll];
100    END_BLOCK_OBJC_EXCEPTIONS;
101}
102
103bool ScrollView::platformCanBlitOnScroll() const
104{
105    return [[scrollView() contentView] copiesOnScroll];
106}
107
108IntRect ScrollView::platformVisibleContentRect(bool includeScrollbars) const
109{
110    BEGIN_BLOCK_OBJC_EXCEPTIONS;
111    IntRect result = enclosingIntRect([scrollView() documentVisibleRect]);
112    if (includeScrollbars)
113        result.setSize(IntSize([scrollView() frame].size));
114    return result;
115    END_BLOCK_OBJC_EXCEPTIONS;
116    return IntRect();
117}
118
119IntSize ScrollView::platformContentsSize() const
120{
121    BEGIN_BLOCK_OBJC_EXCEPTIONS;
122    if (NSView* documentView = this->documentView())
123        return enclosingIntRect([documentView bounds]).size();
124    END_BLOCK_OBJC_EXCEPTIONS;
125    return IntSize();
126}
127
128void ScrollView::platformSetContentsSize()
129{
130    BEGIN_BLOCK_OBJC_EXCEPTIONS;
131    int w = m_contentsSize.width();
132    int h = m_contentsSize.height();
133    LOG(Frames, "%p %@ at w %d h %d\n", documentView(), [(id)[documentView() class] className], w, h);
134    NSSize tempSize = { max(0, w), max(0, h) }; // workaround for 4213314
135    [documentView() setFrameSize:tempSize];
136    END_BLOCK_OBJC_EXCEPTIONS;
137}
138
139void ScrollView::platformSetScrollbarsSuppressed(bool repaintOnUnsuppress)
140{
141    BEGIN_BLOCK_OBJC_EXCEPTIONS;
142    [scrollView() setScrollBarsSuppressed:m_scrollbarsSuppressed
143                      repaintOnUnsuppress:repaintOnUnsuppress];
144    END_BLOCK_OBJC_EXCEPTIONS;
145}
146
147void ScrollView::platformSetScrollPosition(const IntPoint& scrollPoint)
148{
149    BEGIN_BLOCK_OBJC_EXCEPTIONS;
150    NSPoint floatPoint = scrollPoint;
151    NSPoint tempPoint = { max(-[scrollView() scrollOrigin].x, floatPoint.x), max(-[scrollView() scrollOrigin].y, floatPoint.y) };  // Don't use NSMakePoint to work around 4213314.
152    [documentView() scrollPoint:tempPoint];
153    END_BLOCK_OBJC_EXCEPTIONS;
154}
155
156bool ScrollView::platformScroll(ScrollDirection, ScrollGranularity)
157{
158    // FIXME: It would be nice to implement this so that all of the code in WebFrameView could go away.
159    notImplemented();
160    return false;
161}
162
163void ScrollView::platformRepaintContentRectangle(const IntRect& rect, bool now)
164{
165    BEGIN_BLOCK_OBJC_EXCEPTIONS;
166    NSView *view = documentView();
167    [view setNeedsDisplayInRect:rect];
168    if (now) {
169        [[view window] displayIfNeeded];
170        [[view window] flushWindowIfNeeded];
171    }
172    END_BLOCK_OBJC_EXCEPTIONS;
173}
174
175// "Containing Window" means the NSWindow's coord system, which is origin lower left
176
177IntRect ScrollView::platformContentsToScreen(const IntRect& rect) const
178{
179    BEGIN_BLOCK_OBJC_EXCEPTIONS;
180    if (NSView* documentView = this->documentView()) {
181        NSRect tempRect = rect;
182        tempRect = [documentView convertRect:tempRect toView:nil];
183        tempRect.origin = [[documentView window] convertBaseToScreen:tempRect.origin];
184        return enclosingIntRect(tempRect);
185    }
186    END_BLOCK_OBJC_EXCEPTIONS;
187    return IntRect();
188}
189
190IntPoint ScrollView::platformScreenToContents(const IntPoint& point) const
191{
192    BEGIN_BLOCK_OBJC_EXCEPTIONS;
193    if (NSView* documentView = this->documentView()) {
194        NSPoint windowCoord = [[documentView window] convertScreenToBase: point];
195        return IntPoint([documentView convertPoint:windowCoord fromView:nil]);
196    }
197    END_BLOCK_OBJC_EXCEPTIONS;
198    return IntPoint();
199}
200
201bool ScrollView::platformIsOffscreen() const
202{
203    return ![platformWidget() window] || ![[platformWidget() window] isVisible];
204}
205
206void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously)
207{
208    BEGIN_BLOCK_OBJC_EXCEPTIONS;
209    [scrollView() setScrollOrigin:origin updatePositionAtAll:updatePositionAtAll immediately:updatePositionSynchronously];
210    END_BLOCK_OBJC_EXCEPTIONS;
211}
212
213} // namespace WebCore
214