webengine/osswebengine/WebKit/WebView/WebDynamicScrollBarsView.m
changeset 0 dd21522fd290
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebKit/WebView/WebDynamicScrollBarsView.m	Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,345 @@
+/*
+ * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer. 
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution. 
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <WebKit/WebDynamicScrollBarsView.h>
+
+#import <WebKit/WebDocument.h>
+#import <WebKitSystemInterface.h>
+
+@implementation WebDynamicScrollBarsView
+
+- (void)setSuppressLayout: (BOOL)flag;
+{
+    suppressLayout = flag;
+}
+
+- (void)setScrollBarsSuppressed:(BOOL)suppressed repaintOnUnsuppress:(BOOL)repaint
+{
+    suppressScrollers = suppressed;
+
+    // This code was originally changes for a Leopard performance imporvement. We decided to 
+    // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
+#ifndef BUILDING_ON_TIGER
+    if (suppressed) {
+        [[self verticalScroller] setNeedsDisplay:NO];
+        [[self horizontalScroller] setNeedsDisplay:NO];
+    }
+        
+    if (!suppressed && repaint)
+        [super reflectScrolledClipView:[self contentView]];
+#else
+    if (suppressed || repaint) { 
+        [[self verticalScroller] setNeedsDisplay: !suppressed]; 
+        [[self horizontalScroller] setNeedsDisplay: !suppressed]; 
+    }
+#endif
+}
+
+- (void)updateScrollers
+{
+    // We need to do the work below twice in the case where a scroll bar disappears,
+    // making the second layout have a wider width than the first. Doing it more than
+    // twice would indicate some kind of infinite loop, so we do it at most twice.
+    // It's quite efficient to do this work twice in the normal case, so we don't bother
+    // trying to figure out of the second pass is needed or not.
+    if (inUpdateScrollers)
+        return;
+    
+    inUpdateScrollers = true;
+
+    int pass;
+    BOOL hasVerticalScroller = [self hasVerticalScroller];
+    BOOL hasHorizontalScroller = [self hasHorizontalScroller];
+    BOOL oldHasVertical = hasVerticalScroller;
+    BOOL oldHasHorizontal = hasHorizontalScroller;
+
+    for (pass = 0; pass < 2; pass++) {
+        BOOL scrollsVertically;
+        BOOL scrollsHorizontally;
+
+        if (!suppressLayout && !suppressScrollers && (hScroll == WebCoreScrollbarAuto || vScroll == WebCoreScrollbarAuto)) {
+            // Do a layout if pending, before checking if scrollbars are needed.
+            // This fixes 2969367, although may introduce a slowdown in live resize performance.
+            NSView *documentView = [self documentView];
+            if ((hasVerticalScroller != oldHasVertical ||
+                hasHorizontalScroller != oldHasHorizontal || [documentView inLiveResize]) && [documentView conformsToProtocol:@protocol(WebDocumentView)]) {
+                [(id <WebDocumentView>)documentView setNeedsLayout: YES];
+                [(id <WebDocumentView>)documentView layout];
+            }
+
+            NSSize documentSize = [documentView frame].size;
+            NSSize frameSize = [self frame].size;
+
+            scrollsVertically = (vScroll == WebCoreScrollbarAlwaysOn) ||
+                (vScroll == WebCoreScrollbarAuto && documentSize.height > frameSize.height);
+            if (scrollsVertically)
+                scrollsHorizontally = (hScroll == WebCoreScrollbarAlwaysOn) ||
+                    (hScroll == WebCoreScrollbarAuto && documentSize.width + [NSScroller scrollerWidth] > frameSize.width);
+            else {
+                scrollsHorizontally = (hScroll == WebCoreScrollbarAlwaysOn) ||
+                    (hScroll == WebCoreScrollbarAuto && documentSize.width > frameSize.width);
+                if (scrollsHorizontally)
+                    scrollsVertically = (vScroll == WebCoreScrollbarAlwaysOn) ||
+                        (vScroll == WebCoreScrollbarAuto && documentSize.height + [NSScroller scrollerWidth] > frameSize.height);
+            }
+        } else {
+            scrollsHorizontally = (hScroll == WebCoreScrollbarAuto) ? hasHorizontalScroller : (hScroll == WebCoreScrollbarAlwaysOn);
+            scrollsVertically = (vScroll == WebCoreScrollbarAuto) ? hasVerticalScroller : (vScroll == WebCoreScrollbarAlwaysOn);
+        }
+
+        if (hasVerticalScroller != scrollsVertically) {
+            [self setHasVerticalScroller:scrollsVertically];
+            hasVerticalScroller = scrollsVertically;
+        }
+
+        if (hasHorizontalScroller != scrollsHorizontally) {
+            [self setHasHorizontalScroller:scrollsHorizontally];
+            hasHorizontalScroller = scrollsHorizontally;
+        }
+    }
+
+    if (suppressScrollers) {
+        [[self verticalScroller] setNeedsDisplay: NO];
+        [[self horizontalScroller] setNeedsDisplay: NO];
+    }
+
+    inUpdateScrollers = false;
+}
+
+// Make the horizontal and vertical scroll bars come and go as needed.
+- (void)reflectScrolledClipView:(NSClipView *)clipView
+{
+    if (clipView == [self contentView]) {
+        // FIXME: This hack here prevents infinite recursion that takes place when we
+        // gyrate between having a vertical scroller and not having one. A reproducible
+        // case is clicking on the "the Policy Routing text" link at
+        // http://www.linuxpowered.com/archive/howto/Net-HOWTO-8.html.
+        // The underlying cause is some problem in the NSText machinery, but I was not
+        // able to pin it down.
+        if (!inUpdateScrollers && [[NSGraphicsContext currentContext] isDrawingToScreen])
+            [self updateScrollers];
+    }
+
+    // This code was originally changed for a Leopard performance imporvement. We decided to 
+    // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
+#ifndef BUILDING_ON_TIGER
+    // Update the scrollers if they're not being suppressed.
+    if (!suppressScrollers)
+        [super reflectScrolledClipView:clipView];
+#else
+    [super reflectScrolledClipView:clipView]; 
+  
+    // Validate the scrollers if they're being suppressed. 
+    if (suppressScrollers) { 
+        [[self verticalScroller] setNeedsDisplay: NO]; 
+        [[self horizontalScroller] setNeedsDisplay: NO]; 
+    }
+#endif
+}
+
+- (void)setAllowsScrolling:(BOOL)flag
+{
+    if (hScrollModeLocked && vScrollModeLocked)
+        return;
+
+    if (flag && vScroll == WebCoreScrollbarAlwaysOff)
+        vScroll = WebCoreScrollbarAuto;
+    else if (!flag && vScroll != WebCoreScrollbarAlwaysOff)
+        vScroll = WebCoreScrollbarAlwaysOff;
+
+    if (flag && hScroll == WebCoreScrollbarAlwaysOff)
+        hScroll = WebCoreScrollbarAuto;
+    else if (!flag && hScroll != WebCoreScrollbarAlwaysOff)
+        hScroll = WebCoreScrollbarAlwaysOff;
+
+    [self updateScrollers];
+}
+
+- (BOOL)allowsScrolling
+{
+    // Returns YES if either horizontal or vertical scrolling is allowed.
+    return hScroll != WebCoreScrollbarAlwaysOff || vScroll != WebCoreScrollbarAlwaysOff;
+}
+
+- (void)setAllowsHorizontalScrolling:(BOOL)flag
+{
+    if (hScrollModeLocked)
+        return;
+    if (flag && hScroll == WebCoreScrollbarAlwaysOff)
+        hScroll = WebCoreScrollbarAuto;
+    else if (!flag && hScroll != WebCoreScrollbarAlwaysOff)
+        hScroll = WebCoreScrollbarAlwaysOff;
+    [self updateScrollers];
+}
+
+- (void)setAllowsVerticalScrolling:(BOOL)flag
+{
+    if (vScrollModeLocked)
+        return;
+    if (flag && vScroll == WebCoreScrollbarAlwaysOff)
+        vScroll = WebCoreScrollbarAuto;
+    else if (!flag && vScroll != WebCoreScrollbarAlwaysOff)
+        vScroll = WebCoreScrollbarAlwaysOff;
+    [self updateScrollers];
+}
+
+- (BOOL)allowsHorizontalScrolling
+{
+    return hScroll != WebCoreScrollbarAlwaysOff;
+}
+
+- (BOOL)allowsVerticalScrolling
+{
+    return vScroll != WebCoreScrollbarAlwaysOff;
+}
+
+-(WebCoreScrollbarMode)horizontalScrollingMode
+{
+    return hScroll;
+}
+
+-(WebCoreScrollbarMode)verticalScrollingMode
+{
+    return vScroll;
+}
+
+- (void)setHorizontalScrollingMode:(WebCoreScrollbarMode)mode
+{
+    [self setHorizontalScrollingMode:mode andLock:NO];
+}
+
+- (void)setHorizontalScrollingMode:(WebCoreScrollbarMode)mode andLock:(BOOL)lock
+{
+    if (mode == hScroll || hScrollModeLocked)
+        return;
+
+    hScroll = mode;
+
+    if (lock)
+        [self setHorizontalScrollingModeLocked:YES];
+
+    [self updateScrollers];
+}
+
+- (void)setVerticalScrollingMode:(WebCoreScrollbarMode)mode
+{
+    [self setVerticalScrollingMode:mode andLock:NO];
+}
+
+- (void)setVerticalScrollingMode:(WebCoreScrollbarMode)mode andLock:(BOOL)lock
+{
+    if (mode == vScroll || vScrollModeLocked)
+        return;
+
+    vScroll = mode;
+
+    if (lock)
+        [self setVerticalScrollingModeLocked:YES];
+
+    [self updateScrollers];
+}
+
+- (void)setScrollingMode:(WebCoreScrollbarMode)mode
+{
+    [self setScrollingMode:mode andLock:NO];
+}
+
+- (void)setScrollingMode:(WebCoreScrollbarMode)mode andLock:(BOOL)lock
+{
+    if ((mode == vScroll && mode == hScroll) || (vScrollModeLocked && hScrollModeLocked))
+        return;
+
+    BOOL update = NO;
+    if (mode != vScroll && !vScrollModeLocked) {
+        vScroll = mode;
+        update = YES;
+    }
+
+    if (mode != hScroll && !hScrollModeLocked) {
+        hScroll = mode;
+        update = YES;
+    }
+
+    if (lock)
+        [self setScrollingModesLocked:YES];
+
+    if (update)
+        [self updateScrollers];
+}
+
+- (void)setHorizontalScrollingModeLocked:(BOOL)locked
+{
+    hScrollModeLocked = locked;
+}
+
+- (void)setVerticalScrollingModeLocked:(BOOL)locked
+{
+    vScrollModeLocked = locked;
+}
+
+- (void)setScrollingModesLocked:(BOOL)locked
+{
+    hScrollModeLocked = vScrollModeLocked = locked;
+}
+
+- (BOOL)horizontalScrollingModeLocked
+{
+    return hScrollModeLocked;
+}
+
+- (BOOL)verticalScrollingModeLocked
+{
+    return vScrollModeLocked;
+}
+
+- (BOOL)autoforwardsScrollWheelEvents
+{
+    return YES;
+}
+
+- (void)scrollWheel:(NSEvent *)event
+{
+    float deltaX;
+    float deltaY;
+    BOOL isContinuous;
+    WKGetWheelEventDeltas(event, &deltaX, &deltaY, &isContinuous);
+
+    if (fabsf(deltaY) > fabsf(deltaX)) {
+        if (![self allowsVerticalScrolling]) {
+            [[self nextResponder] scrollWheel:event];
+            return;
+        }
+    } else if (![self allowsHorizontalScrolling]) {
+        [[self nextResponder] scrollWheel:event];
+        return;
+    }
+
+    [super scrollWheel:event];
+}
+
+@end