summaryrefslogtreecommitdiff
path: root/Source/WebKit/mac/WebView/WebFrameView.mm
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit/mac/WebView/WebFrameView.mm')
-rw-r--r--Source/WebKit/mac/WebView/WebFrameView.mm1169
1 files changed, 0 insertions, 1169 deletions
diff --git a/Source/WebKit/mac/WebView/WebFrameView.mm b/Source/WebKit/mac/WebView/WebFrameView.mm
deleted file mode 100644
index c82c056bd..000000000
--- a/Source/WebKit/mac/WebView/WebFrameView.mm
+++ /dev/null
@@ -1,1169 +0,0 @@
-/*
- * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#import "WebFrameView.h"
-
-#import "WebClipView.h"
-#import "WebDataSourcePrivate.h"
-#import "WebDocument.h"
-#import "WebDynamicScrollBarsViewInternal.h"
-#import "WebFrame.h"
-#import "WebFrameInternal.h"
-#import "WebFrameViewInternal.h"
-#import "WebFrameViewPrivate.h"
-#import "WebHistoryItemInternal.h"
-#import "WebHTMLViewPrivate.h"
-#import "WebKeyGenerator.h"
-#import "WebKitErrorsPrivate.h"
-#import "WebKitStatisticsPrivate.h"
-#import "WebKitVersionChecks.h"
-#import "WebNSDictionaryExtras.h"
-#import "WebNSObjectExtras.h"
-#import "WebNSPasteboardExtras.h"
-#import "WebNSViewExtras.h"
-#import "WebNSWindowExtras.h"
-#import "WebPDFView.h"
-#import "WebPreferenceKeysPrivate.h"
-#import "WebResourceInternal.h"
-#import "WebSystemInterface.h"
-#import "WebViewInternal.h"
-#import "WebViewPrivate.h"
-#import <Foundation/NSURLRequest.h>
-#import <WebCore/BackForwardListImpl.h>
-#import <WebCore/DragController.h>
-#import <WebCore/EventHandler.h>
-#import <WebCore/Frame.h>
-#import <WebCore/FrameView.h>
-#import <WebCore/HistoryItem.h>
-#import <WebCore/Page.h>
-#import <WebCore/RenderPart.h>
-#import <WebCore/ThreadCheck.h>
-#import <WebCore/WebCoreFrameView.h>
-#import <WebCore/WebCoreView.h>
-#import <WebKitSystemInterface.h>
-#import <wtf/Assertions.h>
-
-using namespace WebCore;
-
-@interface NSWindow (WindowPrivate)
-- (BOOL)_needsToResetDragMargins;
-- (void)_setNeedsToResetDragMargins:(BOOL)s;
-@end
-
-@interface NSClipView (AppKitSecretsIKnow)
-- (BOOL)_scrollTo:(const NSPoint *)newOrigin animate:(BOOL)animate; // need the boolean result from this method
-@end
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-@interface NSView (Details)
-- (void)setBackgroundColor:(NSColor *)color;
-@end
-#endif
-
-enum {
- SpaceKey = 0x0020
-};
-
-@interface WebFrameView (WebFrameViewFileInternal) <WebCoreFrameView>
-- (float)_verticalKeyboardScrollDistance;
-@end
-
-@interface WebFrameViewPrivate : NSObject {
-@public
- WebFrame *webFrame;
- WebDynamicScrollBarsView *frameScrollView;
- BOOL includedInWebKitStatistics;
-}
-@end
-
-@implementation WebFrameViewPrivate
-
-- (void)dealloc
-{
- [frameScrollView release];
- [super dealloc];
-}
-
-@end
-
-@implementation WebFrameView (WebFrameViewFileInternal)
-
-- (float)_verticalKeyboardScrollDistance
-{
- // Arrow keys scroll the same distance that clicking the scroll arrow does.
- return [[self _scrollView] verticalLineScroll];
-}
-
-- (Frame*)_web_frame
-{
- return core(_private->webFrame);
-}
-
-@end
-
-@implementation WebFrameView (WebInternal)
-
-// Note that the WebVew is not retained.
-- (WebView *)_webView
-{
- return [_private->webFrame webView];
-}
-
-- (void)_setDocumentView:(NSView <WebDocumentView> *)view
-{
- WebDynamicScrollBarsView *sv = [self _scrollView];
-
-#if ENABLE(DRAG_SUPPORT)
- core([self _webView])->dragController()->setDidInitiateDrag(false);
-#endif
-
- [sv setSuppressLayout:YES];
-
- // If the old view is the first responder, transfer first responder status to the new view as
- // a convenience and so that we don't leave the window pointing to a view that's no longer in it.
- NSWindow *window = [sv window];
- NSResponder *firstResponder = [window firstResponder];
- bool makeNewViewFirstResponder = [firstResponder isKindOfClass:[NSView class]] && [(NSView *)firstResponder isDescendantOf:[sv documentView]];
-
- // Suppress the resetting of drag margins since we know we can't affect them.
- BOOL resetDragMargins = [window _needsToResetDragMargins];
- [window _setNeedsToResetDragMargins:NO];
- [sv setDocumentView:view];
- [window _setNeedsToResetDragMargins:resetDragMargins];
-
- if (makeNewViewFirstResponder)
- [window makeFirstResponder:view];
- [sv setSuppressLayout:NO];
-}
-
--(NSView <WebDocumentView> *)_makeDocumentViewForDataSource:(WebDataSource *)dataSource
-{
- NSString* MIMEType = [dataSource _responseMIMEType];
- if (!MIMEType)
- MIMEType = @"text/html";
- Class viewClass = [self _viewClassForMIMEType:MIMEType];
- NSView <WebDocumentView> *documentView;
- if (viewClass) {
- // If the dataSource's representation has already been created, and it is also the
- // same class as the desired documentView, then use it as the documentView instead
- // of creating another one (Radar 4340787).
- id <WebDocumentRepresentation> dataSourceRepresentation = [dataSource representation];
- if (dataSourceRepresentation && [dataSourceRepresentation class] == viewClass)
- documentView = (NSView <WebDocumentView> *)[dataSourceRepresentation retain];
- else
- documentView = [[viewClass alloc] init];
- } else
- documentView = nil;
-
- [self _setDocumentView:documentView];
- [documentView release];
-
- return documentView;
-}
-
-- (void)_setWebFrame:(WebFrame *)webFrame
-{
- if (!webFrame) {
- NSView *docV = [self documentView];
- if ([docV respondsToSelector:@selector(close)])
- [docV performSelector:@selector(close)];
- }
-
- // Not retained because the WebView owns the WebFrame, which owns the WebFrameView.
- _private->webFrame = webFrame;
-
- if (!_private->includedInWebKitStatistics && [webFrame _isIncludedInWebKitStatistics]) {
- _private->includedInWebKitStatistics = YES;
- ++WebFrameViewCount;
- }
-}
-
-- (WebDynamicScrollBarsView *)_scrollView
-{
- // This can be called by [super dealloc] when cleaning up the key view loop,
- // after _private has been nilled out.
- if (_private == nil)
- return nil;
- return _private->frameScrollView;
-}
-
-- (float)_verticalPageScrollDistance
-{
- float height = [[self _contentView] bounds].size.height;
- return max<float>(height * Scrollbar::minFractionToStepWhenPaging(), height - Scrollbar::maxOverlapBetweenPages());
-}
-
-static inline void addTypesFromClass(NSMutableDictionary *allTypes, Class objCClass, NSArray *supportTypes)
-{
- NSEnumerator *enumerator = [supportTypes objectEnumerator];
- ASSERT(enumerator != nil);
- NSString *mime = nil;
- while ((mime = [enumerator nextObject]) != nil) {
- // Don't clobber previously-registered classes.
- if ([allTypes objectForKey:mime] == nil)
- [allTypes setObject:objCClass forKey:mime];
- }
-}
-
-+ (NSMutableDictionary *)_viewTypesAllowImageTypeOmission:(BOOL)allowImageTypeOmission
-{
- static NSMutableDictionary *viewTypes = nil;
- static BOOL addedImageTypes = NO;
-
- if (!viewTypes) {
- viewTypes = [[NSMutableDictionary alloc] init];
- addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedNonImageMIMETypes]);
-
- // Since this is a "secret default" we don't bother registering it.
- BOOL omitPDFSupport = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebKitOmitPDFSupport"];
- if (!omitPDFSupport)
- addTypesFromClass(viewTypes, [WebPDFView class], [WebPDFView supportedMIMETypes]);
- }
-
- if (!addedImageTypes && !allowImageTypeOmission) {
- addTypesFromClass(viewTypes, [WebHTMLView class], [WebHTMLView supportedImageMIMETypes]);
- addedImageTypes = YES;
- }
-
- return viewTypes;
-}
-
-+ (BOOL)_canShowMIMETypeAsHTML:(NSString *)MIMEType
-{
- return [[[self _viewTypesAllowImageTypeOmission:YES] _webkit_objectForMIMEType:MIMEType] isSubclassOfClass:[WebHTMLView class]];
-}
-
-+ (Class)_viewClassForMIMEType:(NSString *)MIMEType allowingPlugins:(BOOL)allowPlugins
-{
- Class viewClass;
- return [WebView _viewClass:&viewClass andRepresentationClass:nil forMIMEType:MIMEType allowingPlugins:allowPlugins] ? viewClass : nil;
-}
-
-- (Class)_viewClassForMIMEType:(NSString *)MIMEType
-{
- return [[self class] _viewClassForMIMEType:MIMEType allowingPlugins:[[[self _webView] preferences] arePlugInsEnabled]];
-}
-
-- (void)_install
-{
- ASSERT(_private->webFrame);
- ASSERT(_private->frameScrollView);
-
- Frame* frame = core(_private->webFrame);
-
- ASSERT(frame);
- ASSERT(frame->page());
-
- // If this isn't the main frame, it must have an owner element set, or it
- // won't ever get installed in the view hierarchy.
- ASSERT(frame == frame->page()->mainFrame() || frame->ownerElement());
-
- FrameView* view = frame->view();
-
- view->setPlatformWidget(_private->frameScrollView);
-
- // FIXME: Frame tries to do this too. Is this code needed?
- if (RenderPart* owner = frame->ownerRenderer()) {
- owner->setWidget(view);
- // Now the render part owns the view, so we don't any more.
- }
-
- view->updateCanHaveScrollbars();
-}
-
-- (void)_frameSizeChanged
-{
- // See WebFrameLoaderClient::provisionalLoadStarted.
- if ([[[self webFrame] webView] drawsBackground])
- [[self _scrollView] setDrawsBackground:YES];
- if (Frame* coreFrame = [self _web_frame]) {
- if (FrameView* coreFrameView = coreFrame->view())
- coreFrameView->setNeedsLayout();
- }
-}
-
-@end
-
-@implementation WebFrameView
-
-- (id)initWithFrame:(NSRect)frame
-{
- self = [super initWithFrame:frame];
- if (!self)
- return nil;
-
- static bool didFirstTimeInitialization;
- if (!didFirstTimeInitialization) {
- didFirstTimeInitialization = true;
- InitWebCoreSystemInterface();
-
- // Need to tell WebCore what function to call for the "History Item has Changed" notification.
- // Note: We also do this in WebHistoryItem's init method.
- WebCore::notifyHistoryItemChanged = WKNotifyHistoryItemChanged;
-
-// FIXME: Remove the NSAppKitVersionNumberWithDeferredWindowDisplaySupport check once
-// once AppKit's Deferred Window Display support is available.
-#if !defined(NSAppKitVersionNumberWithDeferredWindowDisplaySupport)
- // CoreGraphics deferred updates are disabled if WebKitEnableCoalescedUpdatesPreferenceKey is NO
- // or has no value. For compatibility with Mac OS X 10.5 and lower, deferred updates are off by default.
- if (![[NSUserDefaults standardUserDefaults] boolForKey:WebKitEnableDeferredUpdatesPreferenceKey])
- WKDisableCGDeferredUpdates();
-#endif
- if (!WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_MAIN_THREAD_EXCEPTIONS))
- setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundOne);
-
- bool throwExceptionsForRoundTwo = WebKitLinkedOnOrAfter(WEBKIT_FIRST_VERSION_WITH_ROUND_TWO_MAIN_THREAD_EXCEPTIONS);
-#ifdef MAIL_THREAD_WORKAROUND
- // Even if old Mail is linked with new WebKit, don't throw exceptions.
- if ([WebResource _needMailThreadWorkaroundIfCalledOffMainThread])
- throwExceptionsForRoundTwo = false;
-#endif
- if (!throwExceptionsForRoundTwo)
- setDefaultThreadViolationBehavior(LogOnFirstThreadViolation, ThreadViolationRoundTwo);
- }
-
- _private = [[WebFrameViewPrivate alloc] init];
-
- WebDynamicScrollBarsView *scrollView = [[WebDynamicScrollBarsView alloc] initWithFrame:NSMakeRect(0.0f, 0.0f, frame.size.width, frame.size.height)];
- _private->frameScrollView = scrollView;
- [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
- [scrollView setDrawsBackground:NO];
- [scrollView setHasVerticalScroller:NO];
- [scrollView setHasHorizontalScroller:NO];
- [scrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
- [scrollView setLineScroll:Scrollbar::pixelsPerLineStep()];
- [self addSubview:scrollView];
-
- // Don't call our overridden version of setNextKeyView here; we need to make the standard NSView
- // link between us and our subview so that previousKeyView and previousValidKeyView work as expected.
- // This works together with our becomeFirstResponder and setNextKeyView overrides.
- [super setNextKeyView:scrollView];
-
- return self;
-}
-
-- (void)dealloc
-{
- if (_private && _private->includedInWebKitStatistics)
- --WebFrameViewCount;
-
- [_private release];
- _private = nil;
-
- [super dealloc];
-}
-
-- (void)finalize
-{
- if (_private && _private->includedInWebKitStatistics)
- --WebFrameViewCount;
-
- [super finalize];
-}
-
-- (WebFrame *)webFrame
-{
- // This method can be called beneath -[NSView dealloc] after _private has been cleared.
- return _private ? _private->webFrame : nil;
-}
-
-- (void)setAllowsScrolling:(BOOL)flag
-{
- WebCore::Frame *frame = core([self webFrame]);
- if (WebCore::FrameView *view = frame? frame->view() : 0)
- view->setCanHaveScrollbars(flag);
-}
-
-- (BOOL)allowsScrolling
-{
- WebCore::Frame *frame = core([self webFrame]);
- if (WebCore::FrameView *view = frame? frame->view() : 0)
- return view->canHaveScrollbars();
- return YES;
-}
-
-- (NSView <WebDocumentView> *)documentView
-{
- return [[self _scrollView] documentView];
-}
-
-- (BOOL)acceptsFirstResponder
-{
- // We always accept first responder; this matches OS X 10.2 WebKit
- // behavior (see 3469791).
- return YES;
-}
-
-- (BOOL)becomeFirstResponder
-{
- // This works together with setNextKeyView to splice the WebFrameView into
- // the key loop similar to the way NSScrollView does this. Note that
- // WebView has similar code.
-
- NSWindow *window = [self window];
- if ([window keyViewSelectionDirection] == NSSelectingPrevious) {
- NSView *previousValidKeyView = [self previousValidKeyView];
- // If we couldn't find a previous valid key view, ask the WebView. This handles frameset
- // cases (one is mentioned in Radar bug 3748628). Note that previousValidKeyView should
- // never be self but can be due to AppKit oddness (mentioned in Radar bug 3748628).
- if (previousValidKeyView == nil || previousValidKeyView == self)
- previousValidKeyView = [[[self webFrame] webView] previousValidKeyView];
- [window makeFirstResponder:previousValidKeyView];
- } else {
- // If the scroll view won't accept first-responderness now, then just become
- // the first responder ourself like a normal view. This lets us be the first
- // responder in cases where no page has yet been loaded.
- if ([[self _scrollView] acceptsFirstResponder])
- [window makeFirstResponder:[self _scrollView]];
- }
-
- return YES;
-}
-
-- (void)setNextKeyView:(NSView *)aView
-{
- // This works together with becomeFirstResponder to splice the WebFrameView into
- // the key loop similar to the way NSScrollView does this. Note that
- // WebView has very similar code.
- if ([self _scrollView] != nil) {
- [[self _scrollView] setNextKeyView:aView];
- } else {
- [super setNextKeyView:aView];
- }
-}
-
-- (BOOL)isOpaque
-{
- return [[self _webView] drawsBackground];
-}
-
-- (void)drawRect:(NSRect)rect
-{
- if (![self documentView]) {
- // Need to paint ourselves if there's no documentView to do it instead.
- if ([[self _webView] drawsBackground]) {
- [[[self _webView] backgroundColor] set];
- NSRectFill(rect);
- }
- } else {
-#ifndef NDEBUG
- if ([[self _scrollView] drawsBackground]) {
- [[NSColor cyanColor] set];
- NSRectFill(rect);
- }
-#endif
- }
-}
-
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
-- (BOOL)wantsUpdateLayer
-{
- return YES;
-}
-
-- (void)updateLayer
-{
- // Do what -drawRect: does but by setting a backgroundColor on the view. This avoids
- // backing store for this view when the WebView is layer-backed.
- if (![self documentView]) {
- if ([[self _webView] drawsBackground]) {
- [self setBackgroundColor:[[self _webView] backgroundColor]];
- return;
- }
- } else {
-#ifndef NDEBUG
- if ([[self _scrollView] drawsBackground]) {
- [self setBackgroundColor:[NSColor cyanColor]];
- return;
- }
-#endif
- }
-
- [self setBackgroundColor:[NSColor clearColor]];
-}
-#endif
-
-- (NSRect)visibleRect
-{
- // This method can be called beneath -[NSView dealloc] after we have cleared _private.
- if (!_private)
- return [super visibleRect];
-
- // FIXME: <rdar://problem/6213380> This method does not work correctly with transforms, for two reasons:
- // 1) [super visibleRect] does not account for the transform, since it is not represented
- // in the NSView hierarchy.
- // 2) -_getVisibleRect: does not correct for transforms.
-
- NSRect rendererVisibleRect;
- if (![[self webFrame] _getVisibleRect:&rendererVisibleRect])
- return [super visibleRect];
-
- if (NSIsEmptyRect(rendererVisibleRect))
- return NSZeroRect;
-
- NSRect viewVisibleRect = [super visibleRect];
- if (NSIsEmptyRect(viewVisibleRect))
- return NSZeroRect;
-
- NSRect frame = [self frame];
- // rendererVisibleRect is in the parent's coordinate space, and frame is in the superview's coordinate space.
- // The return value from this method needs to be in this view's coordinate space. We get that right by subtracting
- // the origins (and correcting for flipping), but when we support transforms, we will need to do better than this.
- rendererVisibleRect.origin.x -= frame.origin.x;
- rendererVisibleRect.origin.y = NSMaxY(frame) - NSMaxY(rendererVisibleRect);
- return NSIntersectionRect(rendererVisibleRect, viewVisibleRect);
-}
-
-- (void)setFrameSize:(NSSize)size
-{
- if (!NSEqualSizes(size, [self frame].size))
- [self _frameSizeChanged];
-
- [super setFrameSize:size];
-}
-
-- (void)viewDidMoveToWindow
-{
- // See WebFrameLoaderClient::provisionalLoadStarted.
- // Need to check _private for nil because this can be called inside -[WebView initWithCoder:].
- if (_private && [[[self webFrame] webView] drawsBackground])
- [[self _scrollView] setDrawsBackground:YES];
- [super viewDidMoveToWindow];
-}
-
-- (BOOL)_scrollOverflowInDirection:(ScrollDirection)direction granularity:(ScrollGranularity)granularity
-{
- // scrolling overflows is only applicable if we're dealing with an WebHTMLView
- if (![[self documentView] isKindOfClass:[WebHTMLView class]])
- return NO;
- Frame* frame = core([self webFrame]);
- if (!frame)
- return NO;
- return frame->eventHandler()->scrollOverflow(direction, granularity);
-}
-
-
-- (BOOL)_isVerticalDocument
-{
- Frame* coreFrame = [self _web_frame];
- if (!coreFrame)
- return YES;
- Document* document = coreFrame->document();
- if (!document)
- return YES;
- RenderObject* renderView = document->renderer();
- if (!renderView)
- return YES;
- return renderView->style()->isHorizontalWritingMode();
-}
-
-- (BOOL)_isFlippedDocument
-{
- Frame* coreFrame = [self _web_frame];
- if (!coreFrame)
- return NO;
- Document* document = coreFrame->document();
- if (!document)
- return NO;
- RenderObject* renderView = document->renderer();
- if (!renderView)
- return NO;
- return renderView->style()->isFlippedBlocksWritingMode();
-}
-
-- (BOOL)_scrollToBeginningOfDocument
-{
- if ([self _scrollOverflowInDirection:ScrollUp granularity:ScrollByDocument])
- return YES;
- if (![self _isScrollable])
- return NO;
- NSPoint point = [(NSView *)[[self _scrollView] documentView] frame].origin;
- point.x += [[self _scrollView] scrollOrigin].x;
- point.y += [[self _scrollView] scrollOrigin].y;
- return [[self _contentView] _scrollTo:&point animate:YES];
-}
-
-- (BOOL)_scrollToEndOfDocument
-{
- if ([self _scrollOverflowInDirection:ScrollDown granularity:ScrollByDocument])
- return YES;
- if (![self _isScrollable])
- return NO;
- NSRect frame = [(NSView *)[[self _scrollView] documentView] frame];
-
- bool isVertical = [self _isVerticalDocument];
- bool isFlipped = [self _isFlippedDocument];
-
- NSPoint point;
- if (isVertical) {
- if (!isFlipped)
- point = NSMakePoint(frame.origin.x, NSMaxY(frame));
- else
- point = NSMakePoint(frame.origin.x, NSMinY(frame));
- } else {
- if (!isFlipped)
- point = NSMakePoint(NSMaxX(frame), frame.origin.y);
- else
- point = NSMakePoint(NSMinX(frame), frame.origin.y);
- }
-
- // Reset the position opposite to the block progression direction.
- if (isVertical)
- point.x += [[self _scrollView] scrollOrigin].x;
- else
- point.y += [[self _scrollView] scrollOrigin].y;
- return [[self _contentView] _scrollTo:&point animate:YES];
-}
-
-- (void)scrollToBeginningOfDocument:(id)sender
-{
- if ([self _scrollToBeginningOfDocument])
- return;
-
- if (WebFrameView *child = [self _largestScrollableChild]) {
- if ([child _scrollToBeginningOfDocument])
- return;
- }
- [[self nextResponder] tryToPerform:@selector(scrollToBeginningOfDocument:) with:sender];
-}
-
-- (void)scrollToEndOfDocument:(id)sender
-{
- if ([self _scrollToEndOfDocument])
- return;
-
- if (WebFrameView *child = [self _largestScrollableChild]) {
- if ([child _scrollToEndOfDocument])
- return;
- }
- [[self nextResponder] tryToPerform:@selector(scrollToEndOfDocument:) with:sender];
-}
-
-- (void)_goBack
-{
- [[self _webView] goBack];
-}
-
-- (void)_goForward
-{
- [[self _webView] goForward];
-}
-
-- (BOOL)_scrollVerticallyBy:(float)delta
-{
- // This method uses the secret method _scrollTo on NSClipView.
- // It does that because it needs to know definitively whether scrolling was
- // done or not to help implement the "scroll parent if we are at the limit" feature.
- // In the presence of smooth scrolling, there's no easy way to tell if the method
- // did any scrolling or not with the public API.
- NSPoint point = [[self _contentView] bounds].origin;
- point.y += delta;
- return [[self _contentView] _scrollTo:&point animate:YES];
-}
-
-- (BOOL)_scrollHorizontallyBy:(float)delta
-{
- NSPoint point = [[self _contentView] bounds].origin;
- point.x += delta;
- return [[self _contentView] _scrollTo:&point animate:YES];
-}
-
-- (float)_horizontalKeyboardScrollDistance
-{
- // Arrow keys scroll the same distance that clicking the scroll arrow does.
- return [[self _scrollView] horizontalLineScroll];
-}
-
-- (float)_horizontalPageScrollDistance
-{
- float width = [[self _contentView] bounds].size.width;
- return max<float>(width * Scrollbar::minFractionToStepWhenPaging(), width - Scrollbar::maxOverlapBetweenPages());
-}
-
-- (BOOL)_pageVertically:(BOOL)up
-{
- if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByPage])
- return YES;
-
- if (![self _isScrollable])
- return [[self _largestScrollableChild] _pageVertically:up];
-
- float delta = [self _verticalPageScrollDistance];
- return [self _scrollVerticallyBy:up ? -delta : delta];
-}
-
-- (BOOL)_pageHorizontally:(BOOL)left
-{
- if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByPage])
- return YES;
-
- if (![self _isScrollable])
- return [[self _largestScrollableChild] _pageHorizontally:left];
-
- float delta = [self _horizontalPageScrollDistance];
- return [self _scrollHorizontallyBy:left ? -delta : delta];
-}
-
-- (BOOL)_pageInBlockProgressionDirection:(BOOL)forward
-{
- // Determine whether we're calling _pageVertically or _pageHorizontally.
- BOOL isVerticalDocument = [self _isVerticalDocument];
- BOOL isFlippedBlock = [self _isFlippedDocument];
- if (isVerticalDocument)
- return [self _pageVertically:isFlippedBlock ? !forward : forward];
- return [self _pageHorizontally:isFlippedBlock ? !forward : forward];
-}
-
-- (BOOL)_scrollLineVertically:(BOOL)up
-{
- if ([self _scrollOverflowInDirection:up ? ScrollUp : ScrollDown granularity:ScrollByLine])
- return YES;
-
- if (![self _isScrollable])
- return [[self _largestScrollableChild] _scrollLineVertically:up];
-
- float delta = [self _verticalKeyboardScrollDistance];
- return [self _scrollVerticallyBy:up ? -delta : delta];
-}
-
-- (BOOL)_scrollLineHorizontally:(BOOL)left
-{
- if ([self _scrollOverflowInDirection:left ? ScrollLeft : ScrollRight granularity:ScrollByLine])
- return YES;
-
- if (![self _isScrollable])
- return [[self _largestScrollableChild] _scrollLineHorizontally:left];
-
- float delta = [self _horizontalKeyboardScrollDistance];
- return [self _scrollHorizontallyBy:left ? -delta : delta];
-}
-
-- (void)scrollPageUp:(id)sender
-{
- if (![self _pageInBlockProgressionDirection:YES]) {
- // If we were already at the top, tell the next responder to scroll if it can.
- [[self nextResponder] tryToPerform:@selector(scrollPageUp:) with:sender];
- }
-}
-
-- (void)scrollPageDown:(id)sender
-{
- if (![self _pageInBlockProgressionDirection:NO]) {
- // If we were already at the bottom, tell the next responder to scroll if it can.
- [[self nextResponder] tryToPerform:@selector(scrollPageDown:) with:sender];
- }
-}
-
-- (void)scrollLineUp:(id)sender
-{
- if (![self _scrollLineVertically:YES])
- [[self nextResponder] tryToPerform:@selector(scrollLineUp:) with:sender];
-}
-
-- (void)scrollLineDown:(id)sender
-{
- if (![self _scrollLineVertically:NO])
- [[self nextResponder] tryToPerform:@selector(scrollLineDown:) with:sender];
-}
-
-- (BOOL)_firstResponderIsFormControl
-{
- NSResponder *firstResponder = [[self window] firstResponder];
-
- // WebHTMLView is an NSControl subclass these days, but it's not a form control
- if ([firstResponder isKindOfClass:[WebHTMLView class]]) {
- return NO;
- }
- return [firstResponder isKindOfClass:[NSControl class]];
-}
-
-- (void)keyDown:(NSEvent *)event
-{
- // Implement common browser behaviors for all kinds of content.
-
- // FIXME: This is not a good time to execute commands for WebHTMLView. We should run these at the time commands sent by key bindings
- // are executed for consistency.
- // This doesn't work automatically because most of the keys handled here are translated into moveXXX commands, which are not handled
- // by Editor when focus is not in editable content.
-
- NSString *characters = [event characters];
- int index, count;
- BOOL callSuper = YES;
- Frame* coreFrame = [self _web_frame];
- BOOL maintainsBackForwardList = coreFrame && static_cast<BackForwardListImpl*>(coreFrame->page()->backForwardList())->enabled() ? YES : NO;
-
- count = [characters length];
- for (index = 0; index < count; ++index) {
- switch ([characters characterAtIndex:index]) {
- case NSDeleteCharacter:
- if (!maintainsBackForwardList || ![[[self _webView] preferences] backspaceKeyNavigationEnabled]) {
- callSuper = YES;
- break;
- }
- // This odd behavior matches some existing browsers,
- // including Windows IE
- if ([event modifierFlags] & NSShiftKeyMask) {
- [self _goForward];
- } else {
- [self _goBack];
- }
- callSuper = NO;
- break;
- case SpaceKey:
- // Checking for a control will allow events to percolate
- // correctly when the focus is on a form control and we
- // are in full keyboard access mode.
- if ((![self allowsScrolling] && ![self _largestScrollableChild]) || [self _firstResponderIsFormControl]) {
- callSuper = YES;
- break;
- }
- if ([event modifierFlags] & NSShiftKeyMask) {
- [self scrollPageUp:nil];
- } else {
- [self scrollPageDown:nil];
- }
- callSuper = NO;
- break;
- case NSPageUpFunctionKey:
- if (![self allowsScrolling] && ![self _largestScrollableChild]) {
- callSuper = YES;
- break;
- }
- [self scrollPageUp:nil];
- callSuper = NO;
- break;
- case NSPageDownFunctionKey:
- if (![self allowsScrolling] && ![self _largestScrollableChild]) {
- callSuper = YES;
- break;
- }
- [self scrollPageDown:nil];
- callSuper = NO;
- break;
- case NSHomeFunctionKey:
- if (![self allowsScrolling] && ![self _largestScrollableChild]) {
- callSuper = YES;
- break;
- }
- [self scrollToBeginningOfDocument:nil];
- callSuper = NO;
- break;
- case NSEndFunctionKey:
- if (![self allowsScrolling] && ![self _largestScrollableChild]) {
- callSuper = YES;
- break;
- }
- [self scrollToEndOfDocument:nil];
- callSuper = NO;
- break;
- case NSUpArrowFunctionKey:
- // We don't handle shifted or control-arrow keys here, so let super have a chance.
- if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
- callSuper = YES;
- break;
- }
- if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
- [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
- // Let arrow keys go through to pop up buttons
- // <rdar://problem/3455910>: hitting up or down arrows when focus is on a
- // pop-up menu should pop the menu
- callSuper = YES;
- break;
- }
- if ([event modifierFlags] & NSCommandKeyMask) {
- [self scrollToBeginningOfDocument:nil];
- } else if ([event modifierFlags] & NSAlternateKeyMask) {
- [self scrollPageUp:nil];
- } else {
- [self scrollLineUp:nil];
- }
- callSuper = NO;
- break;
- case NSDownArrowFunctionKey:
- // We don't handle shifted or control-arrow keys here, so let super have a chance.
- if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
- callSuper = YES;
- break;
- }
- if ((![self allowsScrolling] && ![self _largestScrollableChild]) ||
- [[[self window] firstResponder] isKindOfClass:[NSPopUpButton class]]) {
- // Let arrow keys go through to pop up buttons
- // <rdar://problem/3455910>: hitting up or down arrows when focus is on a
- // pop-up menu should pop the menu
- callSuper = YES;
- break;
- }
- if ([event modifierFlags] & NSCommandKeyMask) {
- [self scrollToEndOfDocument:nil];
- } else if ([event modifierFlags] & NSAlternateKeyMask) {
- [self scrollPageDown:nil];
- } else {
- [self scrollLineDown:nil];
- }
- callSuper = NO;
- break;
- case NSLeftArrowFunctionKey:
- // We don't handle shifted or control-arrow keys here, so let super have a chance.
- if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
- callSuper = YES;
- break;
- }
- // Check back/forward related keys.
- if ([event modifierFlags] & NSCommandKeyMask) {
- if (!maintainsBackForwardList) {
- callSuper = YES;
- break;
- }
- [self _goBack];
- } else {
- // Now check scrolling related keys.
- if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
- callSuper = YES;
- break;
- }
-
- if ([event modifierFlags] & NSAlternateKeyMask) {
- [self _pageHorizontally:YES];
- } else {
- [self _scrollLineHorizontally:YES];
- }
- }
- callSuper = NO;
- break;
- case NSRightArrowFunctionKey:
- // We don't handle shifted or control-arrow keys here, so let super have a chance.
- if ([event modifierFlags] & (NSShiftKeyMask | NSControlKeyMask)) {
- callSuper = YES;
- break;
- }
- // Check back/forward related keys.
- if ([event modifierFlags] & NSCommandKeyMask) {
- if (!maintainsBackForwardList) {
- callSuper = YES;
- break;
- }
- [self _goForward];
- } else {
- // Now check scrolling related keys.
- if ((![self allowsScrolling] && ![self _largestScrollableChild])) {
- callSuper = YES;
- break;
- }
-
- if ([event modifierFlags] & NSAlternateKeyMask) {
- [self _pageHorizontally:NO];
- } else {
- [self _scrollLineHorizontally:NO];
- }
- }
- callSuper = NO;
- break;
- }
- }
-
- if (callSuper) {
- [super keyDown:event];
- } else {
- // if we did something useful, get the cursor out of the way
- [NSCursor setHiddenUntilMouseMoves:YES];
- }
-}
-
-- (NSView *)_webcore_effectiveFirstResponder
-{
- NSView *view = [self documentView];
- return view ? [view _webcore_effectiveFirstResponder] : [super _webcore_effectiveFirstResponder];
-}
-
-- (BOOL)canPrintHeadersAndFooters
-{
- NSView *documentView = [[self _scrollView] documentView];
- if ([documentView respondsToSelector:@selector(canPrintHeadersAndFooters)]) {
- return [(id)documentView canPrintHeadersAndFooters];
- }
- return NO;
-}
-
-- (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo
-{
- NSView *documentView = [[self _scrollView] documentView];
- if (!documentView) {
- return nil;
- }
- if ([documentView respondsToSelector:@selector(printOperationWithPrintInfo:)]) {
- return [(id)documentView printOperationWithPrintInfo:printInfo];
- }
- return [NSPrintOperation printOperationWithView:documentView printInfo:printInfo];
-}
-
-- (BOOL)documentViewShouldHandlePrint
-{
- NSView *documentView = [[self _scrollView] documentView];
- if (documentView && [documentView respondsToSelector:@selector(documentViewShouldHandlePrint)])
- return [(id)documentView documentViewShouldHandlePrint];
-
- return NO;
-}
-
-- (void)printDocumentView
-{
- NSView *documentView = [[self _scrollView] documentView];
- if (documentView && [documentView respondsToSelector:@selector(printDocumentView)])
- [(id)documentView printDocumentView];
-}
-
-@end
-
-@implementation WebFrameView (WebPrivate)
-
-- (float)_area
-{
- NSRect frame = [self frame];
- return frame.size.height * frame.size.width;
-}
-
-- (BOOL)_isScrollable
-{
- WebDynamicScrollBarsView *scrollView = [self _scrollView];
- return [scrollView horizontalScrollingAllowed] || [scrollView verticalScrollingAllowed];
-}
-
-- (WebFrameView *)_largestScrollableChild
-{
- WebFrameView *largest = nil;
- NSArray *frameChildren = [[self webFrame] childFrames];
-
- unsigned i;
- for (i=0; i < [frameChildren count]; i++) {
- WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
- WebFrameView *scrollableFrameView = [childFrameView _isScrollable] ? childFrameView : [childFrameView _largestScrollableChild];
- if (!scrollableFrameView)
- continue;
-
- // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
- // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
- float area = [scrollableFrameView _area];
- if (area < 1.0)
- continue;
-
- if (!largest || (area > [largest _area])) {
- largest = scrollableFrameView;
- }
- }
-
- return largest;
-}
-
-- (BOOL)_hasScrollBars
-{
- // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
- // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed
- // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
- NSScrollView *scrollView = [self _scrollView];
- return [scrollView hasHorizontalScroller] || [scrollView hasVerticalScroller];
-}
-
-- (WebFrameView *)_largestChildWithScrollBars
-{
- // FIXME: This method was used by Safari 4.0.x and older versions, but has not been used by any other WebKit
- // clients to my knowledge, and will not be used by future versions of Safari. It can probably be removed
- // once we no longer need to keep nightly WebKit builds working with Safari 4.0.x and earlier.
- WebFrameView *largest = nil;
- NSArray *frameChildren = [[self webFrame] childFrames];
-
- unsigned i;
- for (i=0; i < [frameChildren count]; i++) {
- WebFrameView *childFrameView = [[frameChildren objectAtIndex:i] frameView];
- WebFrameView *scrollableFrameView = [childFrameView _hasScrollBars] ? childFrameView : [childFrameView _largestChildWithScrollBars];
- if (!scrollableFrameView)
- continue;
-
- // Some ads lurk in child frames of zero width and height, see radar 4406994. These don't count as scrollable.
- // Maybe someday we'll discover that this minimum area check should be larger, but this covers the known cases.
- float area = [scrollableFrameView _area];
- if (area < 1.0)
- continue;
-
- if (!largest || (area > [largest _area])) {
- largest = scrollableFrameView;
- }
- }
-
- return largest;
-}
-
-- (NSClipView *)_contentView
-{
- return [[self _scrollView] contentView];
-}
-
-- (Class)_customScrollViewClass
-{
- if ([_private->frameScrollView class] == [WebDynamicScrollBarsView class])
- return nil;
- return [_private->frameScrollView class];
-}
-
-- (void)_setCustomScrollViewClass:(Class)customClass
-{
- if (!customClass)
- customClass = [WebDynamicScrollBarsView class];
- ASSERT([customClass isSubclassOfClass:[WebDynamicScrollBarsView class]]);
- if (customClass == [_private->frameScrollView class])
- return;
- if (![customClass isSubclassOfClass:[WebDynamicScrollBarsView class]])
- return;
-
- WebDynamicScrollBarsView *oldScrollView = _private->frameScrollView; // already retained
- NSView <WebDocumentView> *documentView = [[self documentView] retain];
-
- WebDynamicScrollBarsView *scrollView = [[customClass alloc] initWithFrame:[oldScrollView frame]];
- [scrollView setContentView:[[[WebClipView alloc] initWithFrame:[scrollView bounds]] autorelease]];
- [scrollView setDrawsBackground:[oldScrollView drawsBackground]];
- [scrollView setHasVerticalScroller:[oldScrollView hasVerticalScroller]];
- [scrollView setHasHorizontalScroller:[oldScrollView hasHorizontalScroller]];
- [scrollView setAutoresizingMask:[oldScrollView autoresizingMask]];
- [scrollView setLineScroll:[oldScrollView lineScroll]];
- [self addSubview:scrollView];
-
- // don't call our overridden version here; we need to make the standard NSView link between us
- // and our subview so that previousKeyView and previousValidKeyView work as expected. This works
- // together with our becomeFirstResponder and setNextKeyView overrides.
- [super setNextKeyView:scrollView];
-
- _private->frameScrollView = scrollView;
-
- [self _setDocumentView:documentView];
- [self _install];
-
- [oldScrollView removeFromSuperview];
- [oldScrollView release];
- [documentView release];
-}
-
-@end