From 6f8d2190f56ebe8471925184403aefd38012bc59 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 5 Mar 2011 19:38:32 -0300 Subject: [PATCH] Closes #1136. Fixed: for the most part, web view's setScrollMode: message did nothing. New: automatic or explicit scroll mode selection in web views. By default the automatic mode will try to use Cappuccino scrollbars whenever possible, and otherwise fall back on Native scrollbars. Explicit settings are also allowed. The explicit AppKit setting will degrade to Native with a warning if impossible due to implement due to SOP. --- AppKit/CPWebView.j | 89 ++++++++++++++++------ Tests/Manual/CPWebViewTest/AppController.j | 10 +-- 2 files changed, 71 insertions(+), 28 deletions(-) diff --git a/AppKit/CPWebView.j b/AppKit/CPWebView.j index 77dfb805b..00c5acf70 100644 --- a/AppKit/CPWebView.j +++ b/AppKit/CPWebView.j @@ -36,6 +36,7 @@ CPWebViewProgressEstimateChangedNotification = "CPWebViewProgressEstimateChan CPWebViewProgressStartedNotification = "CPWebViewProgressStartedNotification"; CPWebViewProgressFinishedNotification = "CPWebViewProgressFinishedNotification"; +CPWebViewScrollAuto = 0; CPWebViewScrollAppKit = 1; CPWebViewScrollNative = 2; @@ -82,6 +83,8 @@ CPWebViewScrollNative = 2; Function _loadCallback; int _scrollMode; + int _effectiveScrollMode; + BOOL _contentIsAccessible; CGSize _scrollSize; int _loadHTMLStringTimer; @@ -100,10 +103,12 @@ CPWebViewScrollNative = 2; { if (self = [super initWithFrame:aFrame]) { - _mainFrameURL = nil; - _backwardStack = []; - _forwardStack = []; - _scrollMode = CPWebViewScrollNative; + _mainFrameURL = nil; + _backwardStack = []; + _forwardStack = []; + _scrollMode = CPWebViewScrollAuto; + _effectiveScrollMode = nil; // Unknown. + _contentIsAccessible = YES; [self _initDOMWithFrame:aFrame]; } @@ -170,12 +175,11 @@ CPWebViewScrollNative = 2; _frameView._DOMElement.appendChild(_iframe); - [self _setScrollMode:_scrollMode]; + [self _updateEffectiveScrollMode]; [self addSubview:_scrollView]; } - - (void)setFrameSize:(CPSize)aSize { [super setFrameSize:aSize]; @@ -184,7 +188,7 @@ CPWebViewScrollNative = 2; - (void)_attachScrollEventIfNecessary { - if (_scrollMode !== CPWebViewScrollAppKit) + if (_effectiveScrollMode !== CPWebViewScrollAppKit) return; var win = null; @@ -209,7 +213,7 @@ CPWebViewScrollNative = 2; - (void)_resizeWebFrame { - if (_scrollMode === CPWebViewScrollAppKit) + if (_effectiveScrollMode === CPWebViewScrollAppKit) { if (_scrollSize) { @@ -236,6 +240,7 @@ CPWebViewScrollNative = 2; } else { + // TODO If we do have access to the content, it might be that the 'body' element simply hasn't loaded yet. CPLog.warn("using default size 800*1600"); [_frameView setFrameSize:CGSizeMake(800, 1600)]; @@ -247,23 +252,44 @@ CPWebViewScrollNative = 2; } /*! - Sets the scroll mode of the receiver. Valid options are - CPWebViewScrollAppKit and CPWebViewScrollNative. + Sets the scroll mode of the receiver. Valid options are: + CPWebViewScrollAuto - (Default) Try to use Cappuccino style scrollbars whenever possible. + CPWebViewScrollAppKit - Always use Cappuccino style scrollbars. + CPWebViewScrollNative - Always use Native style scrollbars. */ - (void)setScrollMode:(int)aScrollMode { if (_scrollMode == aScrollMode) return; - [self _setScrollMode:aScrollMode]; + _scrollMode = aScrollMode; + + [self _updateEffectiveScrollMode]; } -- (void)_setScrollMode:(int)aScrollMode +- (void)_updateEffectiveScrollMode { - if (CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) - _scrollMode = CPWebViewScrollNative; - else - _scrollMode = aScrollMode; + var _newScrollMode = CPWebViewScrollAppKit; + + if (_scrollMode == CPWebViewScrollNative + || (_scrollMode == CPWebViewScrollAuto && !_contentIsAccessible) + || CPBrowserIsEngine(CPInternetExplorerBrowserEngine)) + { + _newScrollMode = CPWebViewScrollNative; + } + else if (_scrollMode == CPWebViewScrollAppKit && !_contentIsAccessible) + { + CPLog.error(self + " unable to use CPWebViewScrollAppKit scroll mode due to same origin policy."); + _newScrollMode = CPWebViewScrollNative; + } + + if (_newScrollMode !== _effectiveScrollMode) + [self _setEffectiveScrollMode:_newScrollMode]; +} + +- (void)_setEffectiveScrollMode:(int)aScrollMode +{ + _effectiveScrollMode = aScrollMode; _ignoreLoadStart = YES; _ignoreLoadEnd = YES; @@ -271,7 +297,7 @@ CPWebViewScrollNative = 2; var parent = _iframe.parentNode; parent.removeChild(_iframe); - if (_scrollMode === CPWebViewScrollAppKit) + if (_effectiveScrollMode === CPWebViewScrollAppKit) { [_scrollView setHasHorizontalScroller:YES]; [_scrollView setHasVerticalScroller:YES]; @@ -289,6 +315,8 @@ CPWebViewScrollNative = 2; } parent.appendChild(_iframe); + + [self _resizeWebFrame]; } /*! @@ -310,9 +338,6 @@ CPWebViewScrollNative = 2; - (void)loadHTMLString:(CPString)aString baseURL:(CPURL)URL { // FIXME: do something with baseURL? - - [self _setScrollMode:CPWebViewScrollAppKit]; - [_frameView setFrameSize:[_scrollView contentSize]]; [self _startedLoading]; @@ -328,8 +353,6 @@ CPWebViewScrollNative = 2; - (void)_loadMainFrameURL { - [self _setScrollMode:CPWebViewScrollNative]; - [self _startedLoading]; _ignoreLoadStart = YES; @@ -345,6 +368,10 @@ CPWebViewScrollNative = 2; { if (_url) { + // Assume NO until proven otherwise. + _contentIsAccessible = NO; + [self _updateEffectiveScrollMode]; + _iframe.src = _url; } else if (_html) @@ -352,6 +379,9 @@ CPWebViewScrollNative = 2; // clear the iframe _iframe.src = ""; + _contentIsAccessible = YES; + [self _updateEffectiveScrollMode]; + if (_loadHTMLStringTimer !== nil) { window.clearTimeout(_loadHTMLStringTimer); @@ -381,6 +411,19 @@ CPWebViewScrollNative = 2; - (void)_finishedLoading { + CPLog.info(self + '(void)_finishedLoading'); + + // Check if we have access. + try + { + _contentIsAccessible = !![self DOMWindow].document; + } + catch (e) + { + _contentIsAccessible = NO; + } + [self _updateEffectiveScrollMode]; + [self _resizeWebFrame]; [self _attachScrollEventIfNecessary]; @@ -789,7 +832,7 @@ CPWebViewScrollNative = 2; _mainFrameURL = nil; _backwardStack = []; _forwardStack = []; - _scrollMode = CPWebViewScrollNative; + _scrollMode = CPWebViewScrollAuto; #if PLATFORM(DOM) [self _initDOMWithFrame:[self frame]]; diff --git a/Tests/Manual/CPWebViewTest/AppController.j b/Tests/Manual/CPWebViewTest/AppController.j index fbea49ead..125a88650 100644 --- a/Tests/Manual/CPWebViewTest/AppController.j +++ b/Tests/Manual/CPWebViewTest/AppController.j @@ -25,22 +25,22 @@ { // This is called when the application is done loading. - //[webView1 setScrollMode:CPWebViewScrollAuto]; + [webView1 setScrollMode:CPWebViewScrollAuto]; [webView1 loadHTMLString:""]; [webView2 setScrollMode:CPWebViewScrollNative]; [webView2 loadHTMLString:""]; - //[webView3 setScrollMode:CPWebViewScrollAuto]; + [webView3 setScrollMode:CPWebViewScrollAuto]; [webView3 setMainFrameURL:[[CPBundle mainBundle] pathForResource:"hello_world.html"]]; - [webView4 setScrollMode:CPWebViewScrollNative]; [webView4 setMainFrameURL:[[CPBundle mainBundle] pathForResource:"hello_world.html"]]; - //[webView5 setScrollMode:CPWebViewScrollAuto]; + // XXX If this program is run from file:// in Safari, it will actually have SOP access. + [webView5 setScrollMode:CPWebViewScrollAuto]; [webView5 setMainFrameURL:"http://www.cappuccino.org"]; - //[webView5 setScrollMode:CPWebViewScrollAuto]; + [webView6 setScrollMode:CPWebViewScrollAppKit]; [webView6 setMainFrameURL:"http://www.cappuccino.org"]; }