WebKit/mac/WebView/WebFrameView.mm
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2005, 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  *
       
     8  * 1.  Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer. 
       
    10  * 2.  Redistributions in binary form must reproduce the above copyright
       
    11  *     notice, this list of conditions and the following disclaimer in the
       
    12  *     documentation and/or other materials provided with the distribution. 
       
    13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
       
    14  *     its contributors may be used to endorse or promote products derived
       
    15  *     from this software without specific prior written permission. 
       
    16  *
       
    17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
       
    18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
       
    19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
       
    20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
       
    21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
       
    22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
       
    23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
       
    24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
       
    26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    27  */
       
    28 
       
    29 #import "WebFrameView.h"
       
    30 
       
    31 #import "WebClipView.h"
       
    32 #import "WebDataSourcePrivate.h"
       
    33 #import "WebDocument.h"
       
    34 #import "WebDynamicScrollBarsViewInternal.h"
       
    35 #import "WebFrame.h"
       
    36 #import "WebFrameInternal.h"
       
    37 #import "WebFrameViewInternal.h"
       
    38 #import "WebFrameViewPrivate.h"
       
    39 #import "WebHistoryItemInternal.h"
       
    40 #import "WebHTMLViewPrivate.h"
       
    41 #import "WebKeyGenerator.h"
       
    42 #import "WebKitErrorsPrivate.h"
       
    43 #import "WebKitStatisticsPrivate.h"
       
    44 #import "WebKitVersionChecks.h"
       
    45 #import "WebNSDictionaryExtras.h"
       
    46 #import "WebNSObjectExtras.h"
       
    47 #import "WebNSPasteboardExtras.h"
       
    48 #import "WebNSViewExtras.h"
       
    49 #import "WebNSWindowExtras.h"
       
    50 #import "WebPDFView.h"
       
    51 #import "WebPreferenceKeysPrivate.h"
       
    52 #import "WebResourceInternal.h"
       
    53 #import "WebSystemInterface.h"
       
    54 #import "WebViewFactory.h"
       
    55 #import "WebViewInternal.h"
       
    56 #import "WebViewPrivate.h"
       
    57 #import <Foundation/NSURLRequest.h>
       
    58 #import <WebCore/BackForwardList.h>
       
    59 #import <WebCore/DragController.h>
       
    60 #import <WebCore/EventHandler.h>
       
    61 #import <WebCore/Frame.h>
       
    62 #import <WebCore/FrameView.h>
       
    63 #import <WebCore/HistoryItem.h>
       
    64 #import <WebCore/Page.h>
       
    65 #import <WebCore/RenderPart.h>
       
    66 #import <WebCore/ThreadCheck.h>
       
    67 #import <WebCore/WebCoreFrameView.h>
       
    68 #import <WebCore/WebCoreView.h>
       
    69 #import <WebKitSystemInterface.h>
       
    70 #import <wtf/Assertions.h>
       
    71 
       
    72 using namespace WebCore;
       
    73 
       
    74 @interface NSWindow (WindowPrivate)
       
    75 - (BOOL)_needsToResetDragMargins;
       
    76 - (void)_setNeedsToResetDragMargins:(BOOL)s;
       
    77 @end
       
    78 
       
    79 @interface NSClipView (AppKitSecretsIKnow)
       
    80 - (BOOL)_scrollTo:(const NSPoint *)newOrigin animate:(BOOL)animate; // need the boolean result from this method
       
    81 @end
       
    82 
       
    83 enum {
       
    84     SpaceKey = 0x0020
       
    85 };
       
    86 
       
    87 @interface WebFrameView (WebFrameViewFileInternal) <WebCoreFrameView>
       
    88 - (float)_verticalKeyboardScrollDistance;
       
    89 @end
       
    90 
       
    91 @interface WebFrameViewPrivate : NSObject {
       
    92 @public
       
    93     WebFrame *webFrame;
       
    94     WebDynamicScrollBarsView *frameScrollView;
       
    95     BOOL includedInWebKitStatistics;
       
    96 }
       
    97 @end
       
    98 
       
    99 @implementation WebFrameViewPrivate
       
   100 
       
   101 - (void)dealloc
       
   102 {
       
   103     [frameScrollView release];
       
   104     [super dealloc];
       
   105 }
       
   106 
       
   107 @end
       
   108 
       
   109 @implementation WebFrameView (WebFrameViewFileInternal)
       
   110 
       
   111 - (float)_verticalKeyboardScrollDistance
       
   112 {
       
   113     // Arrow keys scroll the same distance that clicking the scroll arrow does.
       
   114     return [[self _scrollView] verticalLineScroll];
       
   115 }
       
   116 
       
   117 - (Frame*)_web_frame
       
   118 {
       
   119     return core(_private->webFrame);
       
   120 }
       
   121 
       
   122 @end
       
   123 
       
   124 @implementation WebFrameView (WebInternal)
       
   125 
       
   126 // Note that the WebVew is not retained.
       
   127 - (WebView *)_webView
       
   128 {
       
   129     return [_private->webFrame webView];
       
   130 }
       
   131 
       
   132 - (void)_setDocumentView:(NSView <WebDocumentView> *)view
       
   133 {
       
   134     WebDynamicScrollBarsView *sv = [self _scrollView];
       
   135     core([self _webView])->dragController()->setDidInitiateDrag(false);
       
   136     
       
   137     [sv setSuppressLayout:YES];
       
   138     
       
   139     // If the old view is the first responder, transfer first responder status to the new view as 
       
   140     // a convenience and so that we don't leave the window pointing to a view that's no longer in it.
       
   141     NSWindow *window = [sv window];
       
   142     NSResponder *firstResponder = [window firstResponder];
       
   143     bool makeNewViewFirstResponder = [firstResponder isKindOfClass:[NSView class]] && [(NSView *)firstResponder isDescendantOf:[sv documentView]];
       
   144 
       
   145     // Suppress the resetting of drag margins since we know we can't affect them.
       
   146     BOOL resetDragMargins = [window _needsToResetDragMargins];
       
   147     [window _setNeedsToResetDragMargins:NO];
       
   148     [sv setDocumentView:view];
       
   149     [window _setNeedsToResetDragMargins:resetDragMargins];
       
   150 
       
   151     if (makeNewViewFirstResponder)
       
   152         [window makeFirstResponder:view];
       
   153     [sv setSuppressLayout:NO];
       
   154 }
       
   155 
       
   156 -(NSView <WebDocumentView> *)_makeDocumentViewForDataSource:(WebDataSource *)dataSource
       
   157 {
       
   158     NSString* MIMEType = [dataSource _responseMIMEType];
       
   159     if (!MIMEType)
       
   160         MIMEType = @"text/html";
       
   161     Class viewClass = [self _viewClassForMIMEType:MIMEType];
       
   162     NSView <WebDocumentView> *documentView;
       
   163     if (viewClass) {
       
   164         // If the dataSource's representation has already been created, and it is also the
       
   165         // same class as the desired documentView, then use it as the documentView instead
       
   166         // of creating another one (Radar 4340787).
       
   167         id <WebDocumentRepresentation> dataSourceRepresentation = [dataSource representation];
       
   168         if (dataSourceRepresentation && [dataSourceRepresentation class] == viewClass)
       
   169             documentView = (NSView <WebDocumentView> *)[dataSourceRepresentation retain];
       
   170         else
       
   171             documentView = [[viewClass alloc] initWithFrame:[self bounds]];
       
   172     } else
       
   173         documentView = nil;
       
   174     
       
   175     [self _setDocumentView:documentView];
       
   176     [documentView release];
       
   177     
       
   178     return documentView;
       
   179 }
       
   180 
       
   181 - (void)_setWebFrame:(WebFrame *)webFrame
       
   182 {
       
   183     if (!webFrame) {
       
   184         NSView *docV = [self documentView];
       
   185         if ([docV respondsToSelector:@selector(close)])
       
   186             [docV performSelector:@selector(close)];
       
   187     }
       
   188 
       
   189     // Not retained because the WebView owns the WebFrame, which owns the WebFrameView.
       
   190     _private->webFrame = webFrame;    
       
   191 
       
   192     if (!_private->includedInWebKitStatistics && [webFrame _isIncludedInWebKitStatistics]) {
       
   193         _private->includedInWebKitStatistics = YES;
       
   194         ++WebFrameViewCount;
       
   195     }
       
   196 }
       
   197 
       
   198 - (WebDynamicScrollBarsView *)_scrollView
       
   199 {
       
   200     // This can be called by [super dealloc] when cleaning up the key view loop,
       
   201     // after _private has been nilled out.
       
   202     if (_private == nil)
       
   203         return nil;
       
   204     return _private->frameScrollView;
       
   205 }
       
   206 
       
   207 - (float)_verticalPageScrollDistance
       
   208 {
       
   209     float height = [[self _contentView] bounds].size.height;
       
   210     return max<float>(height * Scrollbar::minFractionToStepWhenPaging(), height - Scrollbar::maxOverlapBetweenPages());
       
   211 }
       
   212 
       
   213 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes)
       
   214 {
       
   215     NSEnumerator *enumerator = [supportTypes objectEnumerator];
       
   216     ASSERT(enumerator != nil);
       
   217     NSString *mime = nil;
       
   218     while ((mime = [enumerator nextObject]) != nil) {
       
   219         // Don't clobber previously-registered classes.
       
   220         if ([allTypes objectForKey:mime] == nil)
       
   221             [allTypes setObject:objCClass forKey:mime];
       
   222     }
       
   223 }
       
   224 
       
   225 + (NSMutableDictionary *)_viewTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
       
   226 {
       
   227     static NSMutableDictionary *viewTypes = nil;
       
   228     static BOOL addedImageTypes = NO;
       
   229     
       
   230     if (!viewTypes) {
       
   231         viewTypes = [[NSMutableDictionary alloc] init];
       
   232         addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedNonImageMIMETypes]);
       
   233 
       
   234         // Since this is a "secret default" we don't bother registering it.
       
   235         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
       
   236         if (!omitPDFSupport)
       
   237             addTypesFromClass(viewTypes, [WebPDFView class], [WebPDFView supportedMIMETypes]);
       
   238     }
       
   239     
       
   240     if (!addedImageTypes && !allowImageTypeOmission) {
       
   241         addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedImageMIMETypes]);
       
   242         addedImageTypes = YES;
       
   243     }
       
   244     
       
   245     return viewTypes;
       
   246 }
       
   247 
       
   248 + (BOOL)_canShowMIMETypeAsHTML:(NSString *)MIMEType
       
   249 {
       
   250     return [[[self _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType] isSubclassOfClass:[WebHTMLView class]];
       
   251 }
       
   252 
       
   253 + (Class)_viewClassForMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
       
   254 {
       
   255     Class viewClass;
       
   256     return [WebView _viewClass:&viewClass andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins] ? viewClass : nil;
       
   257 }
       
   258 
       
   259 - (Class)_viewClassForMIMEType:(NSString *)MIMEType
       
   260 {
       
   261     return [[self class] _viewClassForMIMEType:MIMEType allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]];
       
   262 }
       
   263 
       
   264 - (void)_install
       
   265 {
       
   266     ASSERT(_private->webFrame);
       
   267     ASSERT(_private->frameScrollView);
       
   268 
       
   269     Frame* frame = core(_private->webFrame);
       
   270 
       
   271     ASSERT(frame);
       
   272     ASSERT(frame->page());
       
   273 
       
   274     // If this isn't the main frame, it must have an owner element set, or it
       
   275     // won't ever get installed in the view hierarchy.
       
   276     ASSERT(frame == frame->page()->mainFrame() || frame->ownerElement());
       
   277 
       
   278     FrameView* view = frame->view();
       
   279 
       
   280     view->setPlatformWidget(_private->frameScrollView);
       
   281 
       
   282     // FIXME: Frame tries to do this too. Is this code needed?
       
   283     if (RenderPart* owner = frame->ownerRenderer()) {
       
   284         owner->setWidget(view);
       
   285         // Now the render part owns the view, so we don't any more.
       
   286     }
       
   287 
       
   288     view->updateCanHaveScrollbars();
       
   289 }
       
   290 
       
   291 @end
       
   292 
       
   293 @implementation WebFrameView
       
   294 
       
   295 - (id)initWithFrame:(NSRect)frame
       
   296 {
       
   297     self = [super initWithFrame:frame];
       
   298     if (!self)
       
   299         return nil;
       
   300  
       
   301     static bool didFirstTimeInitialization;
       
   302     if (!didFirstTimeInitialization) {
       
   303         didFirstTimeInitialization = true;
       
   304         InitWebCoreSystemInterface();
       
   305         
       
   306         // Need to tell WebCore what function to call for the "History Item has Changed" notification.
       
   307         // Note: We also do this in WebHistoryItem's init method.
       
   308         WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
       
   309 
       
   310         [WebViewFactory createSharedFactory];
       
   311         [WebKeyGenerator createSharedGenerator];
       
   312 
       
   313 // FIXME: Remove the NSAppKitVersionNumberWithDeferredWindowDisplaySupport check once
       
   314 // once AppKit's Deferred Window Display support is available.
       
   315 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || !defined(NSAppKitVersionNumberWithDeferredWindowDisplaySupport)
       
   316         // CoreGraphics deferred updates are disabled if WebKitEnableCoalescedUpdatesPreferenceKey is NO
       
   317         // or has no value. For compatibility with Mac OS X 10.5 and lower, deferred updates are off by default.
       
   318         if (![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableDeferredUpdatesPreferenceKey])
       
   319             WKDisableCGDeferredUpdates();
       
   320 #endif
       
   321         if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MAIN_THREAD_EXCEPTIONS))
       
   322             setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundOne);
       
   323 
       
   324         bool throwExceptionsForRoundTwo = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_ROUND_TWO_MAIN_THREAD_EXCEPTIONS);
       
   325 #ifdef MAIL_THREAD_WORKAROUND
       
   326         // Even if old Mail is linked with new WebKit, don't throw exceptions.
       
   327         if ([WebResource _needMailThreadWorkaroundIfCalledOffMainThread])
       
   328             throwExceptionsForRoundTwo = false;
       
   329 #endif
       
   330         if (!throwExceptionsForRoundTwo)
       
   331             setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundTwo);
       
   332     }
       
   333 
       
   334     _private = [[WebFrameViewPrivate alloc] init];
       
   335 
       
   336     WebDynamicScrollBarsView *scrollView = [[WebDynamicScrollBarsView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, frame.size.width, frame.size.height)];
       
   337     _private->frameScrollView = scrollView;
       
   338     [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
       
   339     [scrollView setDrawsBackground:NO];
       
   340     [scrollView setHasVerticalScroller:NO];
       
   341     [scrollView setHasHorizontalScroller:NO];
       
   342     [scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
       
   343     [scrollView setLineScroll:Scrollbar::pixelsPerLineStep()];
       
   344     [self addSubview:scrollView];
       
   345 
       
   346     // Don't call our overridden version of setNextKeyView here; we need to make the standard NSView
       
   347     // link between us and our subview so that previousKeyView and previousValidKeyView work as expected.
       
   348     // This works together with our becomeFirstResponder and setNextKeyView overrides.
       
   349     [super setNextKeyView:scrollView];
       
   350     
       
   351     return self;
       
   352 }
       
   353 
       
   354 - (void)dealloc 
       
   355 {
       
   356     if (_private && _private->includedInWebKitStatistics)
       
   357         --WebFrameViewCount;
       
   358     
       
   359     [_private release];
       
   360     _private = nil;
       
   361     
       
   362     [super dealloc];
       
   363 }
       
   364 
       
   365 - (void)finalize 
       
   366 {
       
   367     if (_private && _private->includedInWebKitStatistics)
       
   368         --WebFrameViewCount;
       
   369 
       
   370     [super finalize];
       
   371 }
       
   372 
       
   373 - (WebFrame *)webFrame
       
   374 {
       
   375     // This method can be called beneath -[NSView dealloc] after _private has been cleared.
       
   376     return _private ? _private->webFrame : nil;
       
   377 }
       
   378 
       
   379 - (void)setAllowsScrolling:(BOOL)flag
       
   380 {
       
   381     WebCore::Frame *frame = core([self webFrame]);
       
   382     if (WebCore::FrameView *view = frame? frame->view() : 0)
       
   383         view->setCanHaveScrollbars(flag);
       
   384 }
       
   385 
       
   386 - (BOOL)allowsScrolling
       
   387 {
       
   388     WebCore::Frame *frame = core([self webFrame]);
       
   389     if (WebCore::FrameView *view = frame? frame->view() : 0)
       
   390         return view->canHaveScrollbars();
       
   391     return YES;
       
   392 }
       
   393 
       
   394 - (NSView <WebDocumentView> *)documentView
       
   395 {
       
   396     return [[self _scrollView] documentView];
       
   397 }
       
   398 
       
   399 - (BOOL)acceptsFirstResponder
       
   400 {
       
   401     // We always accept first responder; this matches OS X 10.2 WebKit
       
   402     // behavior (see 3469791).
       
   403     return YES;
       
   404 }
       
   405 
       
   406 - (BOOL)becomeFirstResponder
       
   407 {
       
   408     // This works together with setNextKeyView to splice the WebFrameView into
       
   409     // the key loop similar to the way NSScrollView does this. Note that
       
   410     // WebView has similar code.
       
   411     
       
   412     NSWindow *window = [self window];
       
   413     if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
       
   414         NSView *previousValidKeyView = [self previousValidKeyView];
       
   415         // If we couldn't find a previous valid key view, ask the WebView. This handles frameset
       
   416         // cases (one is mentioned in Radar bug 3748628). Note that previousValidKeyView should
       
   417         // never be self but can be due to AppKit oddness (mentioned in Radar bug 3748628).
       
   418         if (previousValidKeyView == nil || previousValidKeyView == self)
       
   419             previousValidKeyView = [[[self webFrame] webView] previousValidKeyView];
       
   420         [window makeFirstResponder:previousValidKeyView];
       
   421     } else {
       
   422         // If the scroll view won't accept first-responderness now, then just become
       
   423         // the first responder ourself like a normal view. This lets us be the first 
       
   424         // responder in cases where no page has yet been loaded.
       
   425         if ([[self _scrollView] acceptsFirstResponder])
       
   426             [window makeFirstResponder:[self _scrollView]];
       
   427     }
       
   428     
       
   429     return YES;
       
   430 }
       
   431 
       
   432 - (void)setNextKeyView:(NSView *)aView
       
   433 {
       
   434     // This works together with becomeFirstResponder to splice the WebFrameView into
       
   435     // the key loop similar to the way NSScrollView does this. Note that
       
   436     // WebView has very similar code.
       
   437     if ([self _scrollView] != nil) {
       
   438         [[self _scrollView] setNextKeyView:aView];
       
   439     } else {
       
   440         [super setNextKeyView:aView];
       
   441     }
       
   442 }
       
   443 
       
   444 - (BOOL)isOpaque
       
   445 {
       
   446     return [[self _webView] drawsBackground];
       
   447 }
       
   448 
       
   449 - (void)drawRect:(NSRect)rect
       
   450 {
       
   451     if ([self documentView] == nil) {
       
   452         // Need to paint ourselves if there's no documentView to do it instead.
       
   453         if ([[self _webView] drawsBackground]) {
       
   454             [[[self _webView] backgroundColor] set];
       
   455             NSRectFill(rect);
       
   456         }
       
   457     } else {
       
   458 #ifndef NDEBUG
       
   459         if ([[self _scrollView] drawsBackground]) {
       
   460             [[NSColor cyanColor] set];
       
   461             NSRectFill(rect);
       
   462         }
       
   463 #endif
       
   464     }
       
   465 }
       
   466 
       
   467 - (NSRect)visibleRect
       
   468 {
       
   469     // This method can be called beneath -[NSView dealloc] after we have cleared _private.
       
   470     if (!_private)
       
   471         return [super visibleRect];
       
   472 
       
   473     // FIXME: <rdar://problem/6213380> This method does not work correctly with transforms, for two reasons:
       
   474     // 1) [super visibleRect] does not account for the transform, since it is not represented
       
   475     //    in the NSView hierarchy.
       
   476     // 2) -_getVisibleRect: does not correct for transforms.
       
   477 
       
   478     NSRect rendererVisibleRect;
       
   479     if (![[self webFrame] _getVisibleRect:&rendererVisibleRect])
       
   480         return [super visibleRect];
       
   481 
       
   482     if (NSIsEmptyRect(rendererVisibleRect))
       
   483         return NSZeroRect;
       
   484 
       
   485     NSRect viewVisibleRect = [super visibleRect];
       
   486     if (NSIsEmptyRect(viewVisibleRect))
       
   487         return NSZeroRect;
       
   488 
       
   489     NSRect frame = [self frame];
       
   490     // rendererVisibleRect is in the parent's coordinate space, and frame is in the superview's coordinate space.
       
   491     // The return value from this method needs to be in this view's coordinate space. We get that right by subtracting
       
   492     // the origins (and correcting for flipping), but when we support transforms, we will need to do better than this.
       
   493     rendererVisibleRect.origin.x -= frame.origin.x;
       
   494     rendererVisibleRect.origin.y = NSMaxY(frame) - NSMaxY(rendererVisibleRect);
       
   495     return NSIntersectionRect(rendererVisibleRect, viewVisibleRect);
       
   496 }
       
   497 
       
   498 - (void)setFrameSize:(NSSize)size
       
   499 {
       
   500     if (!NSEqualSizes(size, [self frame].size)) {
       
   501         // See WebFrameLoaderClient::provisionalLoadStarted.
       
   502         if ([[[self webFrame] webView] drawsBackground])
       
   503             [[self _scrollView] setDrawsBackground:YES];
       
   504         if (Frame* coreFrame = [self _web_frame]) {
       
   505             if (FrameView* coreFrameView = coreFrame->view())
       
   506                 coreFrameView->setNeedsLayout();
       
   507         }
       
   508     }
       
   509     [super setFrameSize:size];
       
   510 }
       
   511 
       
   512 - (void)viewDidMoveToWindow
       
   513 {
       
   514     // See WebFrameLoaderClient::provisionalLoadStarted.
       
   515     // Need to check _private for nil because this can be called inside -[WebView initWithCoder:].
       
   516     if (_private && [[[self webFrame] webView] drawsBackground])
       
   517         [[self _scrollView] setDrawsBackground:YES];
       
   518     [super viewDidMoveToWindow];
       
   519 }
       
   520 
       
   521 - (BOOL)_scrollOverflowInDirection:(ScrollDirection)direction granularity:(ScrollGranularity)granularity
       
   522 {
       
   523     // scrolling overflows is only applicable if we're dealing with an WebHTMLView
       
   524     if (![[self documentView] isKindOfClass:[WebHTMLView class]])
       
   525         return NO;
       
   526     Frame* frame = core([self webFrame]);
       
   527     if (!frame)
       
   528         return NO;
       
   529     return frame->eventHandler()->scrollOverflow(direction, granularity);
       
   530 }
       
   531 
       
   532 - (BOOL)_scrollToBeginningOfDocument
       
   533 {
       
   534     if ([self _scrollOverflowInDirection:ScrollUp granularity:ScrollByDocument])
       
   535         return YES;
       
   536     if (![self _isScrollable])
       
   537         return NO;
       
   538     NSPoint point = [[[self _scrollView] documentView] frame].origin;
       
   539     return [[self _contentView] _scrollTo:&point animate:YES];
       
   540 }
       
   541 
       
   542 - (BOOL)_scrollToEndOfDocument
       
   543 {
       
   544     if ([self _scrollOverflowInDirection:ScrollDown granularity:ScrollByDocument])
       
   545         return YES;
       
   546     if (![self _isScrollable])
       
   547         return NO;
       
   548     NSRect frame = [[[self _scrollView] documentView] frame];
       
   549     NSPoint point = NSMakePoint(frame.origin.x, NSMaxY(frame));
       
   550     return [[self _contentView] _scrollTo:&point animate:YES];
       
   551 }
       
   552 
       
   553 - (void)scrollToBeginningOfDocument:(id)sender
       
   554 {
       
   555     if ([self _scrollToBeginningOfDocument])
       
   556         return;
       
   557     
       
   558     if (WebFrameView *child = [self _largestScrollableChild]) {
       
   559         if ([child _scrollToBeginningOfDocument])
       
   560             return;
       
   561     }
       
   562     [[self nextResponder] tryToPerform:@selector(scrollToBeginningOfDocument:) with:sender];
       
   563 }
       
   564 
       
   565 - (void)scrollToEndOfDocument:(id)sender
       
   566 {
       
   567     if ([self _scrollToEndOfDocument])
       
   568         return;
       
   569 
       
   570     if (WebFrameView *child = [self _largestScrollableChild]) {
       
   571         if ([child _scrollToEndOfDocument])
       
   572             return;
       
   573     }
       
   574     [[self nextResponder] tryToPerform:@selector(scrollToEndOfDocument:) with:sender];
       
   575 }
       
   576 
       
   577 - (void)_goBack
       
   578 {
       
   579     [[self _webView] goBack];
       
   580 }
       
   581 
       
   582 - (void)_goForward
       
   583 {
       
   584     [[self _webView] goForward];
       
   585 }
       
   586 
       
   587 - (BOOL)_scrollVerticallyBy:(float)delta
       
   588 {
       
   589     // This method uses the secret method _scrollTo on NSClipView.
       
   590     // It does that because it needs to know definitively whether scrolling was
       
   591     // done or not to help implement the "scroll parent if we are at the limit" feature.
       
   592     // In the presence of smooth scrolling, there's no easy way to tell if the method
       
   593     // did any scrolling or not with the public API.
       
   594     NSPoint point = [[self _contentView] bounds].origin;
       
   595     point.y += delta;
       
   596     return [[self _contentView] _scrollTo:&point animate:YES];
       
   597 }
       
   598 
       
   599 - (BOOL)_scrollHorizontallyBy:(float)delta
       
   600 {
       
   601     NSPoint point = [[self _contentView] bounds].origin;
       
   602     point.x += delta;
       
   603     return [[self _contentView] _scrollTo:&point animate:YES];
       
   604 }
       
   605 
       
   606 - (float)_horizontalKeyboardScrollDistance
       
   607 {
       
   608     // Arrow keys scroll the same distance that clicking the scroll arrow does.
       
   609     return [[self _scrollView] horizontalLineScroll];
       
   610 }
       
   611 
       
   612 - (float)_horizontalPageScrollDistance
       
   613 {
       
   614     float width = [[self _contentView] bounds].size.width;
       
   615     return max<float>(width * Scrollbar::minFractionToStepWhenPaging(), width - Scrollbar::maxOverlapBetweenPages());
       
   616 }
       
   617 
       
   618 - (BOOL)_pageVertically:(BOOL)up
       
   619 {
       
   620     if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByPage])
       
   621         return YES;
       
   622     
       
   623     if (![self _isScrollable])
       
   624         return [[self _largestScrollableChild] _pageVertically:up];
       
   625 
       
   626     float delta = [self _verticalPageScrollDistance];
       
   627     return [self _scrollVerticallyBy:up ? -delta : delta];
       
   628 }
       
   629 
       
   630 - (BOOL)_pageHorizontally:(BOOL)left
       
   631 {
       
   632     if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByPage])
       
   633         return YES;
       
   634 
       
   635     if (![self _isScrollable])
       
   636         return [[self _largestScrollableChild] _pageHorizontally:left];
       
   637     
       
   638     float delta = [self _horizontalPageScrollDistance];
       
   639     return [self _scrollHorizontallyBy:left ? -delta : delta];
       
   640 }
       
   641 
       
   642 - (BOOL)_scrollLineVertically:(BOOL)up
       
   643 {
       
   644     if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByLine])
       
   645         return YES;
       
   646 
       
   647     if (![self _isScrollable])
       
   648         return [[self _largestScrollableChild] _scrollLineVertically:up];
       
   649     
       
   650     float delta = [self _verticalKeyboardScrollDistance];
       
   651     return [self _scrollVerticallyBy:up ? -delta : delta];
       
   652 }
       
   653 
       
   654 - (BOOL)_scrollLineHorizontally:(BOOL)left
       
   655 {
       
   656     if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByLine])
       
   657         return YES;
       
   658 
       
   659     if (![self _isScrollable])
       
   660         return [[self _largestScrollableChild] _scrollLineHorizontally:left];
       
   661 
       
   662     float delta = [self _horizontalKeyboardScrollDistance];
       
   663     return [self _scrollHorizontallyBy:left ? -delta : delta];
       
   664 }
       
   665 
       
   666 - (void)scrollPageUp:(id)sender
       
   667 {
       
   668     if (![self _pageVertically:YES]) {
       
   669         // If we were already at the top, tell the next responder to scroll if it can.
       
   670         [[self nextResponder] tryToPerform:@selector(scrollPageUp:) with:sender];
       
   671     }
       
   672 }
       
   673 
       
   674 - (void)scrollPageDown:(id)sender
       
   675 {
       
   676     if (![self _pageVertically:NO]) {
       
   677         // If we were already at the bottom, tell the next responder to scroll if it can.
       
   678         [[self nextResponder] tryToPerform:@selector(scrollPageDown:) with:sender];
       
   679     }
       
   680 }
       
   681 
       
   682 - (void)scrollLineUp:(id)sender
       
   683 {
       
   684     if (![self _scrollLineVertically:YES])
       
   685         [[self nextResponder] tryToPerform:@selector(scrollLineUp:) with:sender];
       
   686 }
       
   687 
       
   688 - (void)scrollLineDown:(id)sender
       
   689 {
       
   690     if (![self _scrollLineVertically:NO])
       
   691         [[self nextResponder] tryToPerform:@selector(scrollLineDown:) with:sender];
       
   692 }
       
   693 
       
   694 - (BOOL)_firstResponderIsFormControl
       
   695 {
       
   696     NSResponder *firstResponder = [[self window] firstResponder];
       
   697     
       
   698     // WebHTMLView is an NSControl subclass these days, but it's not a form control
       
   699     if ([firstResponder isKindOfClass:[WebHTMLView class]]) {
       
   700         return NO;
       
   701     }
       
   702     return [firstResponder isKindOfClass:[NSControl class]];
       
   703 }
       
   704 
       
   705 - (void)keyDown:(NSEvent *)event
       
   706 {
       
   707     NSString *characters = [event characters];
       
   708     int index, count;
       
   709     BOOL callSuper = YES;
       
   710     Frame* coreFrame = [self _web_frame];
       
   711     BOOL maintainsBackForwardList = coreFrame && coreFrame->page()->backForwardList()->enabled() ? YES : NO;
       
   712     
       
   713     count = [characters length];
       
   714     for (index = 0; index < count; ++index) {
       
   715         switch ([characters characterAtIndex:index]) {
       
   716             case NSDeleteCharacter:
       
   717                 if (!maintainsBackForwardList) {
       
   718                     callSuper = YES;
       
   719                     break;
       
   720                 }
       
   721                 // This odd behavior matches some existing browsers,
       
   722                 // including Windows IE
       
   723                 if ([event modifierFlags] & NSShiftKeyMask) {
       
   724                     [self _goForward];
       
   725                 } else {
       
   726                     [self _goBack];
       
   727                 }
       
   728                 callSuper = NO;
       
   729                 break;
       
   730             case SpaceKey:
       
   731                 // Checking for a control will allow events to percolate 
       
   732                 // correctly when the focus is on a form control and we
       
   733                 // are in full keyboard access mode.
       
   734                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) || [self _firstResponderIsFormControl]) {
       
   735                     callSuper = YES;
       
   736                     break;
       
   737                 }
       
   738                 if ([event modifierFlags] & NSShiftKeyMask) {
       
   739                     [self scrollPageUp:nil];
       
   740                 } else {
       
   741                     [self scrollPageDown:nil];
       
   742                 }
       
   743                 callSuper = NO;
       
   744                 break;
       
   745             case NSPageUpFunctionKey:
       
   746                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
       
   747                     callSuper = YES;
       
   748                     break;
       
   749                 }
       
   750                 [self scrollPageUp:nil];
       
   751                 callSuper = NO;
       
   752                 break;
       
   753             case NSPageDownFunctionKey:
       
   754                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
       
   755                     callSuper = YES;
       
   756                     break;
       
   757                 }
       
   758                 [self scrollPageDown:nil];
       
   759                 callSuper = NO;
       
   760                 break;
       
   761             case NSHomeFunctionKey:
       
   762                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
       
   763                     callSuper = YES;
       
   764                     break;
       
   765                 }
       
   766                 [self scrollToBeginningOfDocument:nil];
       
   767                 callSuper = NO;
       
   768                 break;
       
   769             case NSEndFunctionKey:
       
   770                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
       
   771                     callSuper = YES;
       
   772                     break;
       
   773                 }
       
   774                 [self scrollToEndOfDocument:nil];
       
   775                 callSuper = NO;
       
   776                 break;
       
   777             case NSUpArrowFunctionKey:
       
   778                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
       
   779                 if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
       
   780                     callSuper = YES;
       
   781                     break;
       
   782                 }
       
   783                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
       
   784                     [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
       
   785                     // Let arrow keys go through to pop up buttons
       
   786                     // <rdar://problem/3455910>: hitting up or down arrows when focus is on a 
       
   787                     // pop-up menu should pop the menu
       
   788                     callSuper = YES;
       
   789                     break;
       
   790                 }
       
   791                 if ([event modifierFlags] & NSCommandKeyMask) {
       
   792                     [self scrollToBeginningOfDocument:nil];
       
   793                 } else if ([event modifierFlags] & NSAlternateKeyMask) {
       
   794                     [self scrollPageUp:nil];
       
   795                 } else {
       
   796                     [self scrollLineUp:nil];
       
   797                 }
       
   798                 callSuper = NO;
       
   799                 break;
       
   800             case NSDownArrowFunctionKey:
       
   801                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
       
   802                 if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
       
   803                     callSuper = YES;
       
   804                     break;
       
   805                 }
       
   806                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
       
   807                     [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
       
   808                     // Let arrow keys go through to pop up buttons
       
   809                     // <rdar://problem/3455910>: hitting up or down arrows when focus is on a 
       
   810                     // pop-up menu should pop the menu
       
   811                     callSuper = YES;
       
   812                     break;
       
   813                 }
       
   814                 if ([event modifierFlags] & NSCommandKeyMask) {
       
   815                     [self scrollToEndOfDocument:nil];
       
   816                 } else if ([event modifierFlags] & NSAlternateKeyMask) {
       
   817                     [self scrollPageDown:nil];
       
   818                 } else {
       
   819                     [self scrollLineDown:nil];
       
   820                 }
       
   821                 callSuper = NO;
       
   822                 break;
       
   823             case NSLeftArrowFunctionKey:
       
   824                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
       
   825                 if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
       
   826                     callSuper = YES;
       
   827                     break;
       
   828                 }
       
   829                 // Check back/forward related keys.
       
   830                 if ([event modifierFlags] & NSCommandKeyMask) {
       
   831                     if (!maintainsBackForwardList) {
       
   832                         callSuper = YES;
       
   833                         break;
       
   834                     }
       
   835                     [self _goBack];
       
   836                 } else {
       
   837                     // Now check scrolling related keys.
       
   838                     if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
       
   839                         callSuper = YES;
       
   840                         break;
       
   841                     }
       
   842 
       
   843                     if ([event modifierFlags] & NSAlternateKeyMask) {
       
   844                         [self _pageHorizontally:YES];
       
   845                     } else {
       
   846                         [self _scrollLineHorizontally:YES];
       
   847                     }
       
   848                 }
       
   849                 callSuper = NO;
       
   850                 break;
       
   851             case NSRightArrowFunctionKey:
       
   852                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
       
   853                 if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
       
   854                     callSuper = YES;
       
   855                     break;
       
   856                 }
       
   857                 // Check back/forward related keys.
       
   858                 if ([event modifierFlags] & NSCommandKeyMask) {
       
   859                     if (!maintainsBackForwardList) {
       
   860                         callSuper = YES;
       
   861                         break;
       
   862                     }
       
   863                     [self _goForward];
       
   864                 } else {
       
   865                     // Now check scrolling related keys.
       
   866                     if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
       
   867                         callSuper = YES;
       
   868                         break;
       
   869                     }
       
   870 
       
   871                     if ([event modifierFlags] & NSAlternateKeyMask) {
       
   872                         [self _pageHorizontally:NO];
       
   873                     } else {
       
   874                         [self _scrollLineHorizontally:NO];
       
   875                     }
       
   876                 }
       
   877                 callSuper = NO;
       
   878                 break;
       
   879         }
       
   880     }
       
   881     
       
   882     if (callSuper) {
       
   883         [super keyDown:event];
       
   884     } else {
       
   885         // if we did something useful, get the cursor out of the way
       
   886         [NSCursor setHiddenUntilMouseMoves:YES];
       
   887     }
       
   888 }
       
   889 
       
   890 - (NSView *)_webcore_effectiveFirstResponder
       
   891 {
       
   892     NSView *view = [self documentView];
       
   893     return view ? [view _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
       
   894 }
       
   895 
       
   896 - (BOOL)canPrintHeadersAndFooters
       
   897 {
       
   898     NSView *documentView = [[self _scrollView] documentView];
       
   899     if ([documentView respondsToSelector:@selector(canPrintHeadersAndFooters)]) {
       
   900         return [(id)documentView canPrintHeadersAndFooters];
       
   901     }
       
   902     return NO;
       
   903 }
       
   904 
       
   905 - (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo
       
   906 {
       
   907     NSView *documentView = [[self _scrollView] documentView];
       
   908     if (!documentView) {
       
   909         return nil;
       
   910     }
       
   911     if ([documentView respondsToSelector:@selector(printOperationWithPrintInfo:)]) {
       
   912         return [(id)documentView printOperationWithPrintInfo:printInfo];
       
   913     }
       
   914     return [NSPrintOperation printOperationWithView:documentView printInfo:printInfo];
       
   915 }
       
   916 
       
   917 - (BOOL)documentViewShouldHandlePrint
       
   918 {
       
   919     NSView *documentView = [[self _scrollView] documentView];
       
   920     if (documentView && [documentView respondsToSelector:@selector(documentViewShouldHandlePrint)])
       
   921         return [(id)documentView documentViewShouldHandlePrint];
       
   922     
       
   923     return NO;
       
   924 }
       
   925 
       
   926 - (void)printDocumentView
       
   927 {
       
   928     NSView *documentView = [[self _scrollView] documentView];
       
   929     if (documentView && [documentView respondsToSelector:@selector(printDocumentView)])
       
   930         [(id)documentView printDocumentView];
       
   931 }
       
   932 
       
   933 @end
       
   934 
       
   935 @implementation WebFrameView (WebPrivate)
       
   936 
       
   937 - (float)_area
       
   938 {
       
   939     NSRect frame = [self frame];
       
   940     return frame.size.height * frame.size.width;
       
   941 }
       
   942 
       
   943 - (BOOL)_isScrollable
       
   944 {
       
   945     WebDynamicScrollBarsView *scrollView = [self _scrollView];
       
   946     return [scrollView horizontalScrollingAllowed] || [scrollView verticalScrollingAllowed];
       
   947 }
       
   948 
       
   949 - (WebFrameView *)_largestScrollableChild
       
   950 {
       
   951     WebFrameView *largest = nil;
       
   952     NSArray *frameChildren = [[self webFrame] childFrames];
       
   953     
       
   954     unsigned i;
       
   955     for (i=0; i < [frameChildren count]; i++) {
       
   956         WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
       
   957         WebFrameView *scrollableFrameView = [childFrameView _isScrollable] ? childFrameView : [childFrameView _largestScrollableChild];
       
   958         if (!scrollableFrameView)
       
   959             continue;
       
   960         
       
   961         // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
       
   962         // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
       
   963         float area = [scrollableFrameView _area];
       
   964         if (area < 1.0)
       
   965             continue;
       
   966         
       
   967         if (!largest || (area > [largest _area])) {
       
   968             largest = scrollableFrameView;
       
   969         }
       
   970     }
       
   971     
       
   972     return largest;
       
   973 }
       
   974 
       
   975 - (BOOL)_hasScrollBars
       
   976 {
       
   977     // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
       
   978     // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed 
       
   979     // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
       
   980     NSScrollView *scrollView = [self _scrollView];
       
   981     return [scrollView hasHorizontalScroller] || [scrollView hasVerticalScroller];
       
   982 }
       
   983 
       
   984 - (WebFrameView *)_largestChildWithScrollBars
       
   985 {
       
   986     // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
       
   987     // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed 
       
   988     // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
       
   989     WebFrameView *largest = nil;
       
   990     NSArray *frameChildren = [[self webFrame] childFrames];
       
   991     
       
   992     unsigned i;
       
   993     for (i=0; i < [frameChildren count]; i++) {
       
   994         WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
       
   995         WebFrameView *scrollableFrameView = [childFrameView _hasScrollBars] ? childFrameView : [childFrameView _largestChildWithScrollBars];
       
   996         if (!scrollableFrameView)
       
   997             continue;
       
   998         
       
   999         // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
       
  1000         // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
       
  1001         float area = [scrollableFrameView _area];
       
  1002         if (area < 1.0)
       
  1003             continue;
       
  1004         
       
  1005         if (!largest || (area > [largest _area])) {
       
  1006             largest = scrollableFrameView;
       
  1007         }
       
  1008     }
       
  1009     
       
  1010     return largest;
       
  1011 }
       
  1012 
       
  1013 - (NSClipView *)_contentView
       
  1014 {
       
  1015     return [[self _scrollView] contentView];
       
  1016 }
       
  1017 
       
  1018 - (Class)_customScrollViewClass
       
  1019 {
       
  1020     if ([_private->frameScrollView class] == [WebDynamicScrollBarsView class])
       
  1021         return nil;
       
  1022     return [_private->frameScrollView class];
       
  1023 }
       
  1024 
       
  1025 - (void)_setCustomScrollViewClass:(Class)customClass
       
  1026 {
       
  1027     if (!customClass)
       
  1028         customClass = [WebDynamicScrollBarsView class];
       
  1029     ASSERT([customClass isSubclassOfClass:[WebDynamicScrollBarsView class]]);
       
  1030     if (customClass == [_private->frameScrollView class])
       
  1031         return;
       
  1032     if (![customClass isSubclassOfClass:[WebDynamicScrollBarsView class]])
       
  1033         return;
       
  1034 
       
  1035     WebDynamicScrollBarsView *oldScrollView = _private->frameScrollView; // already retained
       
  1036     NSView <WebDocumentView> *documentView = [[self documentView] retain];
       
  1037 
       
  1038     WebDynamicScrollBarsView *scrollView  = [[customClass alloc] initWithFrame:[oldScrollView frame]];
       
  1039     [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
       
  1040     [scrollView setDrawsBackground:[oldScrollView drawsBackground]];
       
  1041     [scrollView setHasVerticalScroller:[oldScrollView hasVerticalScroller]];
       
  1042     [scrollView setHasHorizontalScroller:[oldScrollView hasHorizontalScroller]];
       
  1043     [scrollView setAutoresizingMask:[oldScrollView autoresizingMask]];
       
  1044     [scrollView setLineScroll:[oldScrollView lineScroll]];
       
  1045     [self addSubview:scrollView];
       
  1046 
       
  1047     // don't call our overridden version here; we need to make the standard NSView link between us
       
  1048     // and our subview so that previousKeyView and previousValidKeyView work as expected. This works
       
  1049     // together with our becomeFirstResponder and setNextKeyView overrides.
       
  1050     [super setNextKeyView:scrollView];
       
  1051 
       
  1052     _private->frameScrollView = scrollView;
       
  1053 
       
  1054     [self _setDocumentView:documentView];
       
  1055     [self _install];
       
  1056 
       
  1057     [oldScrollView removeFromSuperview];
       
  1058     [oldScrollView release];
       
  1059     [documentView release];
       
  1060 }
       
  1061 
       
  1062 @end