Don't use (Details) when exposing SPI
[WebKit-https.git] / Source / WebKit / mac / WebView / WebFrameView.mm
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 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 "WebNSViewExtras.h"
48 #import "WebPDFView.h"
49 #import "WebPreferenceKeysPrivate.h"
50 #import "WebResourceInternal.h"
51 #import "WebSystemInterface.h"
52 #import "WebViewInternal.h"
53 #import "WebViewPrivate.h"
54 #import <Foundation/NSURLRequest.h>
55 #import <WebCore/BackForwardController.h>
56 #import <WebCore/BackForwardList.h>
57 #import <WebCore/DragController.h>
58 #import <WebCore/EventHandler.h>
59 #import <WebCore/Frame.h>
60 #import <WebCore/FrameView.h>
61 #import <WebCore/HistoryItem.h>
62 #import <WebCore/Page.h>
63 #import <WebCore/RenderView.h>
64 #import <WebCore/RenderWidget.h>
65 #import <WebCore/ThreadCheck.h>
66 #import <WebCore/WebCoreFrameView.h>
67 #import <WebCore/WebCoreView.h>
68 #import <WebKitSystemInterface.h>
69 #import <wtf/Assertions.h>
70
71 #if PLATFORM(IOS)
72 #import "WebFrameInternal.h"
73 #import "WebPDFViewIOS.h"
74 #import "WebUIKitDelegate.h"
75 #import <Foundation/NSURLRequest.h>
76 #import <WebCore/GraphicsContext.h>
77 #import <WebCore/KeyEventCodesIOS.h>
78 #import <WebCore/MainFrame.h>
79 #import <WebCore/WAKClipView.h>
80 #import <WebCore/WAKScrollView.h>
81 #import <WebCore/WAKWindow.h>
82 #import <WebCore/WKGraphics.h>
83 #import <WebCore/WebEvent.h>
84 #else
85 #import "WebNSPasteboardExtras.h"
86 #import "WebNSWindowExtras.h"
87 #endif
88
89 using namespace WebCore;
90
91 #if !PLATFORM(IOS)
92 @interface NSWindow (WindowPrivate)
93 - (BOOL)_needsToResetDragMargins;
94 - (void)_setNeedsToResetDragMargins:(BOOL)s;
95 @end
96 #endif
97
98 @interface NSClipView (AppKitSecretsIKnow)
99 - (BOOL)_scrollTo:(const NSPoint *)newOrigin animate:(BOOL)animate; // need the boolean result from this method
100 @end
101
102 #if PLATFORM(MAC)
103 @interface NSView ()
104 - (void)setBackgroundColor:(NSColor *)color;
105 @end
106 #endif
107
108 enum {
109     SpaceKey = 0x0020
110 };
111
112 @interface WebFrameView (WebFrameViewFileInternal) <WebCoreFrameView>
113 - (float)_verticalKeyboardScrollDistance;
114 @end
115
116 @interface WebFrameViewPrivate : NSObject {
117 @public
118     WebFrame *webFrame;
119     WebDynamicScrollBarsView *frameScrollView;
120     BOOL includedInWebKitStatistics;
121 }
122 @end
123
124 @implementation WebFrameViewPrivate
125
126 - (void)dealloc
127 {
128     [frameScrollView release];
129     [super dealloc];
130 }
131
132 @end
133
134 @implementation WebFrameView (WebFrameViewFileInternal)
135
136 - (float)_verticalKeyboardScrollDistance
137 {
138     // Arrow keys scroll the same distance that clicking the scroll arrow does.
139     return [[self _scrollView] verticalLineScroll];
140 }
141
142 - (Frame*)_web_frame
143 {
144     return core(_private->webFrame);
145 }
146
147 @end
148
149 @implementation WebFrameView (WebInternal)
150
151 // Note that the WebVew is not retained.
152 - (WebView *)_webView
153 {
154     return [_private->webFrame webView];
155 }
156
157 - (void)_setDocumentView:(NSView <WebDocumentView> *)view
158 {
159     WebDynamicScrollBarsView *sv = [self _scrollView];
160     
161 #if ENABLE(DRAG_SUPPORT)
162     core([self _webView])->dragController().setDidInitiateDrag(false);
163 #endif
164     
165 #if !PLATFORM(IOS)
166     [sv setSuppressLayout:YES];
167     
168     // If the old view is the first responder, transfer first responder status to the new view as 
169     // a convenience and so that we don't leave the window pointing to a view that's no longer in it.
170     NSWindow *window = [sv window];
171     NSResponder *firstResponder = [window firstResponder];
172     bool makeNewViewFirstResponder = [firstResponder isKindOfClass:[NSView class]] && [(NSView *)firstResponder isDescendantOf:[sv documentView]];
173
174     // Suppress the resetting of drag margins since we know we can't affect them.
175     BOOL resetDragMargins = [window _needsToResetDragMargins];
176     [window _setNeedsToResetDragMargins:NO];
177 #endif
178     [sv setDocumentView:view];
179 #if !PLATFORM(IOS)
180     [window _setNeedsToResetDragMargins:resetDragMargins];
181
182     if (makeNewViewFirstResponder)
183         [window makeFirstResponder:view];
184     [sv setSuppressLayout:NO];
185 #else
186     ASSERT(_private->webFrame);
187
188     Frame* frame = core(_private->webFrame);
189
190     ASSERT(frame);
191     ASSERT(frame->page());
192
193     if (frame == &frame->page()->mainFrame())
194         [[self window] makeFirstResponder:[self documentView]];
195 #endif
196 }
197
198 -(NSView <WebDocumentView> *)_makeDocumentViewForDataSource:(WebDataSource *)dataSource
199 {
200     NSString* MIMEType = [dataSource _responseMIMEType];
201     if (!MIMEType)
202         MIMEType = @"text/html";
203     Class viewClass = [self _viewClassForMIMEType:MIMEType];
204     NSView <WebDocumentView> *documentView;
205     if (viewClass) {
206         // If the dataSource's representation has already been created, and it is also the
207         // same class as the desired documentView, then use it as the documentView instead
208         // of creating another one (Radar 4340787).
209         id <WebDocumentRepresentation> dataSourceRepresentation = [dataSource representation];
210         if (dataSourceRepresentation && [dataSourceRepresentation class] == viewClass)
211             documentView = (NSView <WebDocumentView> *)[dataSourceRepresentation retain];
212         else
213             documentView = [(NSView <WebDocumentView> *)[viewClass alloc] init];
214     } else
215         documentView = nil;
216     
217     [self _setDocumentView:documentView];
218     [documentView release];
219     
220     return documentView;
221 }
222
223 - (void)_setWebFrame:(WebFrame *)webFrame
224 {
225     if (!webFrame) {
226         NSView *docV = [self documentView];
227         if ([docV respondsToSelector:@selector(close)])
228             [docV performSelector:@selector(close)];
229     }
230
231     // Not retained because the WebView owns the WebFrame, which owns the WebFrameView.
232     _private->webFrame = webFrame;    
233
234     if (!_private->includedInWebKitStatistics && [webFrame _isIncludedInWebKitStatistics]) {
235         _private->includedInWebKitStatistics = YES;
236         ++WebFrameViewCount;
237     }
238 }
239
240 - (WebDynamicScrollBarsView *)_scrollView
241 {
242     // This can be called by [super dealloc] when cleaning up the key view loop,
243     // after _private has been nilled out.
244     if (_private == nil)
245         return nil;
246     return _private->frameScrollView;
247 }
248
249 - (float)_verticalPageScrollDistance
250 {
251     float height = [[self _contentView] bounds].size.height;
252     return std::max<float>(height * Scrollbar::minFractionToStepWhenPaging(), height - Scrollbar::maxOverlapBetweenPages());
253 }
254
255 static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes)
256 {
257     NSEnumerator *enumerator = [supportTypes objectEnumerator];
258     ASSERT(enumerator != nil);
259     NSString *mime = nil;
260     while ((mime = [enumerator nextObject]) != nil) {
261         // Don't clobber previously-registered classes.
262         if ([allTypes objectForKey:mime] == nil)
263             [allTypes setObject:objCClass forKey:mime];
264     }
265 }
266
267 + (NSMutableDictionary *)_viewTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
268 {
269     static NSMutableDictionary *viewTypes = nil;
270     static BOOL addedImageTypes = NO;
271     
272     if (!viewTypes) {
273         viewTypes = [[NSMutableDictionary alloc] init];
274         addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedNonImageMIMETypes]);
275         addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedMediaMIMETypes]);
276
277         // Since this is a "secret default" we don't bother registering it.
278         BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
279         if (!omitPDFSupport)
280 #if PLATFORM(IOS)
281 #define WebPDFView ([WebView _getPDFViewClass])
282 #endif
283             addTypesFromClass(viewTypes, [WebPDFView class], [WebPDFView supportedMIMETypes]);
284 #if PLATFORM(IOS)
285 #undef WebPDFView
286 #endif
287     }
288     
289     if (!addedImageTypes && !allowImageTypeOmission) {
290         addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedImageMIMETypes]);
291         addedImageTypes = YES;
292     }
293     
294     return viewTypes;
295 }
296
297 + (BOOL)_canShowMIMETypeAsHTML:(NSString *)MIMEType
298 {
299     return [[[self _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType] isSubclassOfClass:[WebHTMLView class]];
300 }
301
302 + (Class)_viewClassForMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
303 {
304     Class viewClass;
305     return [WebView _viewClass:&viewClass andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins] ? viewClass : nil;
306 }
307
308 - (Class)_viewClassForMIMEType:(NSString *)MIMEType
309 {
310     Class retVal = [[self class] _viewClassForMIMEType:MIMEType allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]];
311
312 #if PLATFORM(IOS)   
313     if ([retVal respondsToSelector:@selector(_representationClassForWebFrame:)])
314         retVal = [retVal performSelector:@selector(_representationClassForWebFrame:) withObject:[self webFrame]];
315 #endif
316         
317     return retVal;
318 }
319
320 - (void)_install
321 {
322     ASSERT(_private->webFrame);
323     ASSERT(_private->frameScrollView);
324
325     Frame* frame = core(_private->webFrame);
326
327     ASSERT(frame);
328     ASSERT(frame->page());
329
330     // If this isn't the main frame, it must have an owner element set, or it
331     // won't ever get installed in the view hierarchy.
332     ASSERT(frame->isMainFrame() || frame->ownerElement());
333
334     FrameView* view = frame->view();
335
336     view->setPlatformWidget(_private->frameScrollView);
337
338     // FIXME: Frame tries to do this too. Is this code needed?
339     if (RenderWidget* owner = frame->ownerRenderer()) {
340         owner->setWidget(view);
341         // Now the RenderWidget owns the view, so we don't any more.
342     }
343
344     view->updateCanHaveScrollbars();
345 }
346
347 - (void)_frameSizeChanged
348 {
349     // See WebFrameLoaderClient::provisionalLoadStarted.
350     if ([[[self webFrame] webView] drawsBackground])
351         [[self _scrollView] setDrawsBackground:YES];
352     if (Frame* coreFrame = [self _web_frame]) {
353         if (FrameView* coreFrameView = coreFrame->view())
354             coreFrameView->availableContentSizeChanged(ScrollableArea::AvailableSizeChangeReason::AreaSizeChanged);
355     }
356 }
357
358 @end
359
360 @implementation WebFrameView
361
362 - (id)initWithFrame:(NSRect)frame
363 {
364     self = [super initWithFrame:frame];
365     if (!self)
366         return nil;
367  
368     static bool didFirstTimeInitialization;
369     if (!didFirstTimeInitialization) {
370         didFirstTimeInitialization = true;
371         InitWebCoreSystemInterface();
372         
373         // Need to tell WebCore what function to call for the "History Item has Changed" notification.
374         // Note: We also do this in WebHistoryItem's init method.
375         WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
376
377 #if !PLATFORM(IOS)
378         if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MAIN_THREAD_EXCEPTIONS))
379             setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundOne);
380
381         bool throwExceptionsForRoundTwo = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_ROUND_TWO_MAIN_THREAD_EXCEPTIONS);
382         if (!throwExceptionsForRoundTwo)
383             setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundTwo);
384 #endif
385     }
386
387     _private = [[WebFrameViewPrivate alloc] init];
388
389     WebDynamicScrollBarsView *scrollView = [[WebDynamicScrollBarsView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, frame.size.width, frame.size.height)];
390     _private->frameScrollView = scrollView;
391 #if PLATFORM(IOS)
392     [scrollView setDelegate:self];
393 #else
394     [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
395 #endif
396     [scrollView setDrawsBackground:NO];
397     [scrollView setHasVerticalScroller:NO];
398     [scrollView setHasHorizontalScroller:NO];
399     [scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
400     [scrollView setLineScroll:Scrollbar::pixelsPerLineStep()];
401     [self addSubview:scrollView];
402
403     // Don't call our overridden version of setNextKeyView here; we need to make the standard NSView
404     // link between us and our subview so that previousKeyView and previousValidKeyView work as expected.
405     // This works together with our becomeFirstResponder and setNextKeyView overrides.
406     [super setNextKeyView:scrollView];
407     
408     return self;
409 }
410
411 - (void)dealloc 
412 {
413     if (_private && _private->includedInWebKitStatistics)
414         --WebFrameViewCount;
415     
416     [_private release];
417     _private = nil;
418     
419     [super dealloc];
420 }
421
422 - (void)finalize 
423 {
424     if (_private && _private->includedInWebKitStatistics)
425         --WebFrameViewCount;
426
427     [super finalize];
428 }
429
430 #if PLATFORM(IOS)
431 - (BOOL)scrollView:(WAKScrollView *)scrollView shouldScrollToPoint:(CGPoint)point
432 {
433     WebView *webView = [self _webView];
434     return [[webView _UIKitDelegateForwarder] webView:webView shouldScrollToPoint:point forFrame:_private->webFrame];
435 }
436 #endif
437
438 - (WebFrame *)webFrame
439 {
440     // This method can be called beneath -[NSView dealloc] after _private has been cleared.
441     return _private ? _private->webFrame : nil;
442 }
443
444 - (void)setAllowsScrolling:(BOOL)flag
445 {
446     WebCore::Frame *frame = core([self webFrame]);
447     if (WebCore::FrameView *view = frame? frame->view() : 0)
448         view->setCanHaveScrollbars(flag);
449 }
450
451 - (BOOL)allowsScrolling
452 {
453     WebCore::Frame *frame = core([self webFrame]);
454     if (WebCore::FrameView *view = frame? frame->view() : 0)
455         return view->canHaveScrollbars();
456     return YES;
457 }
458
459 - (NSView <WebDocumentView> *)documentView
460 {
461     return [[self _scrollView] documentView];
462 }
463
464 - (BOOL)acceptsFirstResponder
465 {
466     // We always accept first responder; this matches OS X 10.2 WebKit
467     // behavior (see 3469791).
468     return YES;
469 }
470
471 - (BOOL)becomeFirstResponder
472 {
473     // This works together with setNextKeyView to splice the WebFrameView into
474     // the key loop similar to the way NSScrollView does this. Note that
475     // WebView has similar code.
476     
477     NSWindow *window = [self window];
478     if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
479         NSView *previousValidKeyView = [self previousValidKeyView];
480         // If we couldn't find a previous valid key view, ask the WebView. This handles frameset
481         // cases (one is mentioned in Radar bug 3748628). Note that previousValidKeyView should
482         // never be self but can be due to AppKit oddness (mentioned in Radar bug 3748628).
483         if (previousValidKeyView == nil || previousValidKeyView == self)
484             previousValidKeyView = [[[self webFrame] webView] previousValidKeyView];
485         [window makeFirstResponder:previousValidKeyView];
486     } else {
487         // If the scroll view won't accept first-responderness now, then just become
488         // the first responder ourself like a normal view. This lets us be the first 
489         // responder in cases where no page has yet been loaded.
490         if ([[self _scrollView] acceptsFirstResponder])
491             [window makeFirstResponder:[self _scrollView]];
492     }
493     
494     return YES;
495 }
496
497 - (void)setNextKeyView:(NSView *)aView
498 {
499     // This works together with becomeFirstResponder to splice the WebFrameView into
500     // the key loop similar to the way NSScrollView does this. Note that
501     // WebView has very similar code.
502     if ([self _scrollView] != nil) {
503         [[self _scrollView] setNextKeyView:aView];
504     } else {
505         [super setNextKeyView:aView];
506     }
507 }
508
509 - (BOOL)isOpaque
510 {
511     return [[self _webView] drawsBackground];
512 }
513
514 - (void)drawRect:(NSRect)rect
515 {
516 #if !PLATFORM(IOS)
517     if (![self documentView])
518 #else
519     if (![self documentView] || [[self documentView] frame].size.height == 0 || [[self webFrame] _isCommitting])
520 #endif
521     {
522         // Need to paint ourselves if there's no documentView to do it instead.
523         if ([[self _webView] drawsBackground]) {
524 #if !PLATFORM(IOS)
525             [[[self _webView] backgroundColor] set];
526             NSRectFill(rect);
527 #else
528             CGContextRef cgContext = WKGetCurrentGraphicsContext();
529             CGContextSetFillColorWithColor(cgContext, cachedCGColor(Color::white, ColorSpaceDeviceRGB));
530             WKRectFill(cgContext, rect);
531 #endif
532         }
533     } else {
534 #ifndef NDEBUG
535         if ([[self _scrollView] drawsBackground]) {
536 #if !PLATFORM(IOS)
537             [[NSColor cyanColor] set];
538             NSRectFill(rect);
539 #else
540             CGContextRef cgContext = WKGetCurrentGraphicsContext();
541             CGContextSetFillColorWithColor(cgContext, cachedCGColor(Color::cyan, ColorSpaceDeviceRGB));
542             WKRectFill(cgContext, rect);
543 #endif
544         }
545 #endif
546     }
547 }
548
549 #if PLATFORM(MAC)
550 - (BOOL)wantsUpdateLayer
551 {
552     return YES;
553 }
554
555 - (void)updateLayer
556 {
557     // Do what -drawRect: does but by setting a backgroundColor on the view. This avoids
558     // backing store for this view when the WebView is layer-backed.
559     if (![self documentView]) {
560         if ([[self _webView] drawsBackground]) {
561             [self setBackgroundColor:[[self _webView] backgroundColor]];
562             return;
563         }
564     } else {
565 #ifndef NDEBUG
566         if ([[self _scrollView] drawsBackground]) {
567             [self setBackgroundColor:[NSColor cyanColor]];
568             return;
569         }
570 #endif
571     }
572
573     [self setBackgroundColor:[NSColor clearColor]];
574 }
575 #endif
576
577 - (NSRect)visibleRect
578 {
579     // This method can be called beneath -[NSView dealloc] after we have cleared _private.
580     if (!_private)
581         return [super visibleRect];
582
583     // FIXME: <rdar://problem/6213380> This method does not work correctly with transforms, for two reasons:
584     // 1) [super visibleRect] does not account for the transform, since it is not represented
585     //    in the NSView hierarchy.
586     // 2) -_getVisibleRect: does not correct for transforms.
587
588     NSRect rendererVisibleRect;
589     if (![[self webFrame] _getVisibleRect:&rendererVisibleRect])
590         return [super visibleRect];
591
592     if (NSIsEmptyRect(rendererVisibleRect))
593         return NSZeroRect;
594
595     NSRect viewVisibleRect = [super visibleRect];
596     if (NSIsEmptyRect(viewVisibleRect))
597         return NSZeroRect;
598
599     NSRect frame = [self frame];
600     // rendererVisibleRect is in the parent's coordinate space, and frame is in the superview's coordinate space.
601     // The return value from this method needs to be in this view's coordinate space. We get that right by subtracting
602     // the origins (and correcting for flipping), but when we support transforms, we will need to do better than this.
603     rendererVisibleRect.origin.x -= frame.origin.x;
604     rendererVisibleRect.origin.y = NSMaxY(frame) - NSMaxY(rendererVisibleRect);
605     return NSIntersectionRect(rendererVisibleRect, viewVisibleRect);
606 }
607
608 - (void)setFrameSize:(NSSize)size
609 {
610     if (!NSEqualSizes(size, [self frame].size))
611         [self _frameSizeChanged];
612
613     [super setFrameSize:size];
614 }
615
616 - (void)viewDidMoveToWindow
617 {
618     // See WebFrameLoaderClient::provisionalLoadStarted.
619     // Need to check _private for nil because this can be called inside -[WebView initWithCoder:].
620     if (_private && [[[self webFrame] webView] drawsBackground])
621         [[self _scrollView] setDrawsBackground:YES];
622     [super viewDidMoveToWindow];
623 }
624
625 - (BOOL)_scrollOverflowInDirection:(ScrollDirection)direction granularity:(ScrollGranularity)granularity
626 {
627     // scrolling overflows is only applicable if we're dealing with an WebHTMLView
628     if (![[self documentView] isKindOfClass:[WebHTMLView class]])
629         return NO;
630     Frame* frame = core([self webFrame]);
631     if (!frame)
632         return NO;
633     return frame->eventHandler().scrollOverflow(direction, granularity);
634 }
635
636
637 - (BOOL)_isVerticalDocument
638 {
639     Frame* coreFrame = [self _web_frame];
640     if (!coreFrame)
641         return YES;
642     Document* document = coreFrame->document();
643     if (!document)
644         return YES;
645     RenderView* renderView = document->renderView();
646     if (!renderView)
647         return YES;
648     return renderView->style().isHorizontalWritingMode();
649 }
650
651 - (BOOL)_isFlippedDocument
652 {
653     Frame* coreFrame = [self _web_frame];
654     if (!coreFrame)
655         return NO;
656     Document* document = coreFrame->document();
657     if (!document)
658         return NO;
659     RenderView* renderView = document->renderView();
660     if (!renderView)
661         return NO;
662     return renderView->style().isFlippedBlocksWritingMode();
663 }
664
665 - (BOOL)_scrollToBeginningOfDocument
666 {
667     if ([self _scrollOverflowInDirection:ScrollUp granularity:ScrollByDocument])
668         return YES;
669     if (![self _isScrollable])
670         return NO;
671     NSPoint point = [(NSView *)[[self _scrollView] documentView] frame].origin;
672     point.x += [[self _scrollView] scrollOrigin].x;
673     point.y += [[self _scrollView] scrollOrigin].y;
674     return [[self _contentView] _scrollTo:&point animate:YES];
675 }
676
677 - (BOOL)_scrollToEndOfDocument
678 {
679     if ([self _scrollOverflowInDirection:ScrollDown granularity:ScrollByDocument])
680         return YES;
681     if (![self _isScrollable])
682         return NO;
683     NSRect frame = [(NSView *)[[self _scrollView] documentView] frame];
684     
685     bool isVertical = [self _isVerticalDocument];
686     bool isFlipped = [self _isFlippedDocument];
687
688     NSPoint point;
689     if (isVertical) {
690         if (!isFlipped)
691             point = NSMakePoint(frame.origin.x, NSMaxY(frame));
692         else
693             point = NSMakePoint(frame.origin.x, NSMinY(frame));
694     } else {
695         if (!isFlipped)
696             point = NSMakePoint(NSMaxX(frame), frame.origin.y);
697         else
698             point = NSMakePoint(NSMinX(frame), frame.origin.y);
699     }
700     
701     // Reset the position opposite to the block progression direction.
702     if (isVertical)
703         point.x += [[self _scrollView] scrollOrigin].x;
704     else
705         point.y += [[self _scrollView] scrollOrigin].y;
706     return [[self _contentView] _scrollTo:&point animate:YES];
707 }
708
709 - (void)scrollToBeginningOfDocument:(id)sender
710 {
711     if ([self _scrollToBeginningOfDocument])
712         return;
713     
714     if (WebFrameView *child = [self _largestScrollableChild]) {
715         if ([child _scrollToBeginningOfDocument])
716             return;
717     }
718     [[self nextResponder] tryToPerform:@selector(scrollToBeginningOfDocument:) with:sender];
719 }
720
721 - (void)scrollToEndOfDocument:(id)sender
722 {
723     if ([self _scrollToEndOfDocument])
724         return;
725
726     if (WebFrameView *child = [self _largestScrollableChild]) {
727         if ([child _scrollToEndOfDocument])
728             return;
729     }
730     [[self nextResponder] tryToPerform:@selector(scrollToEndOfDocument:) with:sender];
731 }
732
733 - (void)_goBack
734 {
735     [[self _webView] goBack];
736 }
737
738 - (void)_goForward
739 {
740     [[self _webView] goForward];
741 }
742
743 - (BOOL)_scrollVerticallyBy:(float)delta
744 {
745     // This method uses the secret method _scrollTo on NSClipView.
746     // It does that because it needs to know definitively whether scrolling was
747     // done or not to help implement the "scroll parent if we are at the limit" feature.
748     // In the presence of smooth scrolling, there's no easy way to tell if the method
749     // did any scrolling or not with the public API.
750     NSPoint point = [[self _contentView] bounds].origin;
751     point.y += delta;
752     return [[self _contentView] _scrollTo:&point animate:YES];
753 }
754
755 - (BOOL)_scrollHorizontallyBy:(float)delta
756 {
757     NSPoint point = [[self _contentView] bounds].origin;
758     point.x += delta;
759     return [[self _contentView] _scrollTo:&point animate:YES];
760 }
761
762 - (float)_horizontalKeyboardScrollDistance
763 {
764     // Arrow keys scroll the same distance that clicking the scroll arrow does.
765     return [[self _scrollView] horizontalLineScroll];
766 }
767
768 - (float)_horizontalPageScrollDistance
769 {
770     float width = [[self _contentView] bounds].size.width;
771     return std::max<float>(width * Scrollbar::minFractionToStepWhenPaging(), width - Scrollbar::maxOverlapBetweenPages());
772 }
773
774 - (BOOL)_pageVertically:(BOOL)up
775 {
776     if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByPage])
777         return YES;
778     
779     if (![self _isScrollable])
780         return [[self _largestScrollableChild] _pageVertically:up];
781
782     float delta = [self _verticalPageScrollDistance];
783     return [self _scrollVerticallyBy:up ? -delta : delta];
784 }
785
786 - (BOOL)_pageHorizontally:(BOOL)left
787 {
788     if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByPage])
789         return YES;
790
791     if (![self _isScrollable])
792         return [[self _largestScrollableChild] _pageHorizontally:left];
793     
794     float delta = [self _horizontalPageScrollDistance];
795     return [self _scrollHorizontallyBy:left ? -delta : delta];
796 }
797
798 - (BOOL)_pageInBlockProgressionDirection:(BOOL)forward
799 {
800     // Determine whether we're calling _pageVertically or _pageHorizontally.
801     BOOL isVerticalDocument = [self _isVerticalDocument];
802     BOOL isFlippedBlock = [self _isFlippedDocument];
803     if (isVerticalDocument)
804         return [self _pageVertically:isFlippedBlock ? !forward : forward];
805     return [self _pageHorizontally:isFlippedBlock ? !forward : forward];
806 }
807
808 - (BOOL)_scrollLineVertically:(BOOL)up
809 {
810     if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByLine])
811         return YES;
812
813     if (![self _isScrollable])
814         return [[self _largestScrollableChild] _scrollLineVertically:up];
815     
816     float delta = [self _verticalKeyboardScrollDistance];
817     return [self _scrollVerticallyBy:up ? -delta : delta];
818 }
819
820 - (BOOL)_scrollLineHorizontally:(BOOL)left
821 {
822     if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByLine])
823         return YES;
824
825     if (![self _isScrollable])
826         return [[self _largestScrollableChild] _scrollLineHorizontally:left];
827
828     float delta = [self _horizontalKeyboardScrollDistance];
829     return [self _scrollHorizontallyBy:left ? -delta : delta];
830 }
831
832 - (void)scrollPageUp:(id)sender
833 {
834     if (![self _pageInBlockProgressionDirection:YES]) {
835         // If we were already at the top, tell the next responder to scroll if it can.
836         [[self nextResponder] tryToPerform:@selector(scrollPageUp:) with:sender];
837     }
838 }
839
840 - (void)scrollPageDown:(id)sender
841 {
842     if (![self _pageInBlockProgressionDirection:NO]) {
843         // If we were already at the bottom, tell the next responder to scroll if it can.
844         [[self nextResponder] tryToPerform:@selector(scrollPageDown:) with:sender];
845     }
846 }
847
848 - (void)scrollLineUp:(id)sender
849 {
850     if (![self _scrollLineVertically:YES])
851         [[self nextResponder] tryToPerform:@selector(scrollLineUp:) with:sender];
852 }
853
854 - (void)scrollLineDown:(id)sender
855 {
856     if (![self _scrollLineVertically:NO])
857         [[self nextResponder] tryToPerform:@selector(scrollLineDown:) with:sender];
858 }
859
860 - (BOOL)_firstResponderIsFormControl
861 {
862 #if PLATFORM(IOS)
863     return NO;
864 #else
865     NSResponder *firstResponder = [[self window] firstResponder];
866     
867     // WebHTMLView is an NSControl subclass these days, but it's not a form control
868     if ([firstResponder isKindOfClass:[WebHTMLView class]]) {
869         return NO;
870     }
871     return [firstResponder isKindOfClass:[NSControl class]];
872 #endif
873 }
874
875 #if PLATFORM(IOS)
876 // Unlike OS X WebKit, on iOS, unhandled mouse events are forwarded to allow for scrolling.
877 // Since mouse events were forwarded to this WebFrameView, this means that the subviews didn't
878 // handle the event. Pass the events to the next scroll view.
879 - (void)_forwardMouseEvent:(WebEvent *)event
880 {
881     WAKView *superview = [self superview];
882     if ([superview conformsToProtocol:@protocol(WebDocumentView)])
883         [[[superview _web_parentWebFrameView] _scrollView] handleEvent:event];
884     else
885         [[self nextResponder] handleEvent:event];
886 }
887
888 - (void)mouseDown:(WebEvent *)event
889 {
890     [self _forwardMouseEvent:event];
891 }
892
893 - (void)mouseUp:(WebEvent *)event
894 {
895     [self _forwardMouseEvent:event];
896 }
897 #endif
898
899 #if !PLATFORM(IOS)
900 - (void)keyDown:(NSEvent *)event
901 #else
902 - (void)keyDown:(WebEvent *)event
903 #endif
904 {
905     // Implement common browser behaviors for all kinds of content.
906
907     // FIXME: This is not a good time to execute commands for WebHTMLView. We should run these at the time commands sent by key bindings
908     // are executed for consistency.
909     // This doesn't work automatically because most of the keys handled here are translated into moveXXX commands, which are not handled
910     // by Editor when focus is not in editable content.
911
912 #if !PLATFORM(IOS)
913     NSString *characters = [event characters];
914     int modifierFlags = [event modifierFlags];
915 #else
916     NSString *characters = event.characters;
917     int modifierFlags = event.modifierFlags;
918 #endif
919     int index, count;
920     BOOL callSuper = YES;
921     Frame* coreFrame = [self _web_frame];
922     BOOL maintainsBackForwardList = coreFrame && static_cast<BackForwardList*>(coreFrame->page()->backForward().client())->enabled() ? YES : NO;
923     
924     count = [characters length];
925     for (index = 0; index < count; ++index) {
926         switch ([characters characterAtIndex:index]) {
927             case NSDeleteCharacter:
928                 if (!maintainsBackForwardList || ![[[self _webView] preferences] backspaceKeyNavigationEnabled]) {
929                     callSuper = YES;
930                     break;
931                 }
932                 // This odd behavior matches some existing browsers,
933                 // including Windows IE
934                 if (modifierFlags & NSShiftKeyMask) {
935                     [self _goForward];
936                 } else {
937                     [self _goBack];
938                 }
939                 callSuper = NO;
940                 break;
941             case SpaceKey:
942                 // Checking for a control will allow events to percolate 
943                 // correctly when the focus is on a form control and we
944                 // are in full keyboard access mode.
945                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) || [self _firstResponderIsFormControl]) {
946                     callSuper = YES;
947                     break;
948                 }
949                 if (modifierFlags & NSShiftKeyMask) {
950                     [self scrollPageUp:nil];
951                 } else {
952                     [self scrollPageDown:nil];
953                 }
954                 callSuper = NO;
955                 break;
956             case NSPageUpFunctionKey:
957                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
958                     callSuper = YES;
959                     break;
960                 }
961                 [self scrollPageUp:nil];
962                 callSuper = NO;
963                 break;
964             case NSPageDownFunctionKey:
965                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
966                     callSuper = YES;
967                     break;
968                 }
969                 [self scrollPageDown:nil];
970                 callSuper = NO;
971                 break;
972             case NSHomeFunctionKey:
973                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
974                     callSuper = YES;
975                     break;
976                 }
977                 [self scrollToBeginningOfDocument:nil];
978                 callSuper = NO;
979                 break;
980             case NSEndFunctionKey:
981                 if (![self allowsScrolling] && ![self _largestScrollableChild]) {
982                     callSuper = YES;
983                     break;
984                 }
985                 [self scrollToEndOfDocument:nil];
986                 callSuper = NO;
987                 break;
988             case NSUpArrowFunctionKey:
989                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
990                 if (modifierFlags & (NSShiftKeyMask | NSControlKeyMask)) {
991                     callSuper = YES;
992                     break;
993                 }
994 #if !PLATFORM(IOS)
995                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
996                     [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
997                     // Let arrow keys go through to pop up buttons
998                     // <rdar://problem/3455910>: hitting up or down arrows when focus is on a 
999                     // pop-up menu should pop the menu
1000                     callSuper = YES;
1001                     break;
1002                 }
1003 #endif
1004                 if (modifierFlags & NSCommandKeyMask) {
1005                     [self scrollToBeginningOfDocument:nil];
1006                 } else if (modifierFlags & NSAlternateKeyMask) {
1007                     [self scrollPageUp:nil];
1008                 } else {
1009                     [self scrollLineUp:nil];
1010                 }
1011                 callSuper = NO;
1012                 break;
1013             case NSDownArrowFunctionKey:
1014                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
1015                 if (modifierFlags & (NSShiftKeyMask | NSControlKeyMask)) {
1016                     callSuper = YES;
1017                     break;
1018                 }
1019 #if !PLATFORM(IOS)
1020                 if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
1021                     [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
1022                     // Let arrow keys go through to pop up buttons
1023                     // <rdar://problem/3455910>: hitting up or down arrows when focus is on a 
1024                     // pop-up menu should pop the menu
1025                     callSuper = YES;
1026                     break;
1027                 }
1028 #endif
1029                 if (modifierFlags & NSCommandKeyMask) {
1030                     [self scrollToEndOfDocument:nil];
1031                 } else if (modifierFlags & NSAlternateKeyMask) {
1032                     [self scrollPageDown:nil];
1033                 } else {
1034                     [self scrollLineDown:nil];
1035                 }
1036                 callSuper = NO;
1037                 break;
1038             case NSLeftArrowFunctionKey:
1039                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
1040                 if (modifierFlags & (NSShiftKeyMask | NSControlKeyMask)) {
1041                     callSuper = YES;
1042                     break;
1043                 }
1044                 // Check back/forward related keys.
1045                 if (modifierFlags & NSCommandKeyMask) {
1046                     if (!maintainsBackForwardList) {
1047                         callSuper = YES;
1048                         break;
1049                     }
1050                     [self _goBack];
1051                 } else {
1052                     // Now check scrolling related keys.
1053                     if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
1054                         callSuper = YES;
1055                         break;
1056                     }
1057
1058                     if (modifierFlags & NSAlternateKeyMask) {
1059                         [self _pageHorizontally:YES];
1060                     } else {
1061                         [self _scrollLineHorizontally:YES];
1062                     }
1063                 }
1064                 callSuper = NO;
1065                 break;
1066             case NSRightArrowFunctionKey:
1067                 // We don't handle shifted or control-arrow keys here, so let super have a chance.
1068                 if (modifierFlags & (NSShiftKeyMask | NSControlKeyMask)) {
1069                     callSuper = YES;
1070                     break;
1071                 }
1072                 // Check back/forward related keys.
1073                 if (modifierFlags & NSCommandKeyMask) {
1074                     if (!maintainsBackForwardList) {
1075                         callSuper = YES;
1076                         break;
1077                     }
1078                     [self _goForward];
1079                 } else {
1080                     // Now check scrolling related keys.
1081                     if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
1082                         callSuper = YES;
1083                         break;
1084                     }
1085
1086                     if (modifierFlags & NSAlternateKeyMask) {
1087                         [self _pageHorizontally:NO];
1088                     } else {
1089                         [self _scrollLineHorizontally:NO];
1090                     }
1091                 }
1092                 callSuper = NO;
1093                 break;
1094         }
1095     }
1096     
1097     if (callSuper) {
1098         [super keyDown:event];
1099     } else {
1100         // if we did something useful, get the cursor out of the way
1101         [NSCursor setHiddenUntilMouseMoves:YES];
1102     }
1103 }
1104
1105 - (NSView *)_webcore_effectiveFirstResponder
1106 {
1107     NSView *view = [self documentView];
1108     return view ? [view _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
1109 }
1110
1111 #if !PLATFORM(IOS)
1112 - (BOOL)canPrintHeadersAndFooters
1113 {
1114     NSView *documentView = [[self _scrollView] documentView];
1115     if ([documentView respondsToSelector:@selector(canPrintHeadersAndFooters)]) {
1116         return [(id)documentView canPrintHeadersAndFooters];
1117     }
1118     return NO;
1119 }
1120
1121 - (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo
1122 {
1123     NSView *documentView = [[self _scrollView] documentView];
1124     if (!documentView) {
1125         return nil;
1126     }
1127     if ([documentView respondsToSelector:@selector(printOperationWithPrintInfo:)]) {
1128         return [(id)documentView printOperationWithPrintInfo:printInfo];
1129     }
1130     return [NSPrintOperation printOperationWithView:documentView printInfo:printInfo];
1131 }
1132 #endif
1133
1134 - (BOOL)documentViewShouldHandlePrint
1135 {
1136     NSView *documentView = [[self _scrollView] documentView];
1137     if (documentView && [documentView respondsToSelector:@selector(documentViewShouldHandlePrint)])
1138         return [(id)documentView documentViewShouldHandlePrint];
1139     
1140     return NO;
1141 }
1142
1143 - (void)printDocumentView
1144 {
1145     NSView *documentView = [[self _scrollView] documentView];
1146     if (documentView && [documentView respondsToSelector:@selector(printDocumentView)])
1147         [(id)documentView printDocumentView];
1148 }
1149
1150 @end
1151
1152 @implementation WebFrameView (WebPrivate)
1153
1154 - (float)_area
1155 {
1156     NSRect frame = [self frame];
1157     return frame.size.height * frame.size.width;
1158 }
1159
1160 - (BOOL)_isScrollable
1161 {
1162 #if !PLATFORM(IOS)
1163     WebDynamicScrollBarsView *scrollView = [self _scrollView];
1164     return [scrollView horizontalScrollingAllowed] || [scrollView verticalScrollingAllowed];
1165 #else
1166     return [self _hasScrollBars];
1167 #endif
1168 }
1169
1170 - (WebFrameView *)_largestScrollableChild
1171 {
1172     WebFrameView *largest = nil;
1173     NSArray *frameChildren = [[self webFrame] childFrames];
1174     
1175     unsigned i;
1176     for (i=0; i < [frameChildren count]; i++) {
1177         WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
1178         WebFrameView *scrollableFrameView = [childFrameView _isScrollable] ? childFrameView : [childFrameView _largestScrollableChild];
1179         if (!scrollableFrameView)
1180             continue;
1181         
1182         // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
1183         // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
1184         float area = [scrollableFrameView _area];
1185         if (area < 1.0)
1186             continue;
1187         
1188         if (!largest || (area > [largest _area])) {
1189             largest = scrollableFrameView;
1190         }
1191     }
1192     
1193     return largest;
1194 }
1195
1196 - (BOOL)_hasScrollBars
1197 {
1198     // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
1199     // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed 
1200     // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
1201     NSScrollView *scrollView = [self _scrollView];
1202     return [scrollView hasHorizontalScroller] || [scrollView hasVerticalScroller];
1203 }
1204
1205 - (WebFrameView *)_largestChildWithScrollBars
1206 {
1207     // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
1208     // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed 
1209     // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
1210     WebFrameView *largest = nil;
1211     NSArray *frameChildren = [[self webFrame] childFrames];
1212     
1213     unsigned i;
1214     for (i=0; i < [frameChildren count]; i++) {
1215         WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
1216         WebFrameView *scrollableFrameView = [childFrameView _hasScrollBars] ? childFrameView : [childFrameView _largestChildWithScrollBars];
1217         if (!scrollableFrameView)
1218             continue;
1219         
1220         // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
1221         // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
1222         float area = [scrollableFrameView _area];
1223         if (area < 1.0)
1224             continue;
1225         
1226         if (!largest || (area > [largest _area])) {
1227             largest = scrollableFrameView;
1228         }
1229     }
1230     
1231     return largest;
1232 }
1233
1234 - (NSClipView *)_contentView
1235 {
1236     return [[self _scrollView] contentView];
1237 }
1238
1239 - (Class)_customScrollViewClass
1240 {
1241     if ([_private->frameScrollView class] == [WebDynamicScrollBarsView class])
1242         return nil;
1243     return [_private->frameScrollView class];
1244 }
1245
1246 #if !PLATFORM(IOS)
1247 - (void)_setCustomScrollViewClass:(Class)customClass
1248 {
1249     if (!customClass)
1250         customClass = [WebDynamicScrollBarsView class];
1251     ASSERT([customClass isSubclassOfClass:[WebDynamicScrollBarsView class]]);
1252     if (customClass == [_private->frameScrollView class])
1253         return;
1254     if (![customClass isSubclassOfClass:[WebDynamicScrollBarsView class]])
1255         return;
1256
1257     WebDynamicScrollBarsView *oldScrollView = _private->frameScrollView; // already retained
1258     NSView <WebDocumentView> *documentView = [[self documentView] retain];
1259
1260     WebDynamicScrollBarsView *scrollView  = [[customClass alloc] initWithFrame:[oldScrollView frame]];
1261     [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
1262     [scrollView setDrawsBackground:[oldScrollView drawsBackground]];
1263     [scrollView setHasVerticalScroller:[oldScrollView hasVerticalScroller]];
1264     [scrollView setHasHorizontalScroller:[oldScrollView hasHorizontalScroller]];
1265     [scrollView setAutoresizingMask:[oldScrollView autoresizingMask]];
1266     [scrollView setLineScroll:[oldScrollView lineScroll]];
1267     [self addSubview:scrollView];
1268
1269     // don't call our overridden version here; we need to make the standard NSView link between us
1270     // and our subview so that previousKeyView and previousValidKeyView work as expected. This works
1271     // together with our becomeFirstResponder and setNextKeyView overrides.
1272     [super setNextKeyView:scrollView];
1273
1274     _private->frameScrollView = scrollView;
1275
1276     [self _setDocumentView:documentView];
1277     [self _install];
1278
1279     [oldScrollView removeFromSuperview];
1280     [oldScrollView release];
1281     [documentView release];
1282 }
1283 #endif // !PLATFORM(IOS)
1284
1285 @end