diff options
Diffstat (limited to 'Source/WebCore/platform/mac')
-rw-r--r-- | Source/WebCore/platform/mac/DragImageMac.mm | 210 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/EmptyProtocolDefinitions.h | 5 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/FileSystemMac.mm | 25 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/MIMETypeRegistryMac.mm | 3 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/PasteboardMac.mm | 3 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/PopupMenuMac.mm | 25 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/ScrollAnimatorMac.h | 79 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/ScrollAnimatorMac.mm | 923 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/ScrollViewMac.mm | 4 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/ScrollbarThemeMac.h | 7 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/ScrollbarThemeMac.mm | 126 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/WebCoreSystemInterface.h | 43 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/WebCoreSystemInterface.mm | 43 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/WheelEventMac.mm | 3 | ||||
-rw-r--r-- | Source/WebCore/platform/mac/WidgetMac.mm | 4 |
15 files changed, 1447 insertions, 56 deletions
diff --git a/Source/WebCore/platform/mac/DragImageMac.mm b/Source/WebCore/platform/mac/DragImageMac.mm index f444b6e..fc58173 100644 --- a/Source/WebCore/platform/mac/DragImageMac.mm +++ b/Source/WebCore/platform/mac/DragImageMac.mm @@ -28,9 +28,16 @@ #if ENABLE(DRAG_SUPPORT) #import "CachedImage.h" +#import "Font.h" +#import "FontDescription.h" +#import "FontSelector.h" +#import "GraphicsContext.h" #import "Image.h" #import "KURL.h" #import "ResourceResponse.h" +#import "Settings.h" +#import "StringTruncator.h" +#import "TextRun.h" namespace WebCore { @@ -98,7 +105,210 @@ RetainPtr<NSImage> createDragImageIconForCachedImage(CachedImage* image) return [[NSWorkspace sharedWorkspace] iconForFileType:extension]; } + + +const float DragLabelBorderX = 4; +//Keep border_y in synch with DragController::LinkDragBorderInset +const float DragLabelBorderY = 2; +const float DragLabelRadius = 5; +const float LabelBorderYOffset = 2; + +const float MinDragLabelWidthBeforeClip = 120; +const float MaxDragLabelWidth = 320; + +const float DragLinkLabelFontsize = 11; +const float DragLinkUrlFontSize = 10; + +// FIXME - we should move all the functionality of NSString extras to WebCore + +static Font& fontFromNSFont(NSFont *font) +{ + static NSFont *currentFont; + DEFINE_STATIC_LOCAL(Font, currentRenderer, ()); + + if ([font isEqual:currentFont]) + return currentRenderer; + if (currentFont) + CFRelease(currentFont); + currentFont = font; + CFRetain(currentFont); + FontPlatformData f(font, [font pointSize]); + currentRenderer = Font(f, ![[NSGraphicsContext currentContext] isDrawingToScreen]); + return currentRenderer; +} + +static bool canUseFastRenderer(const UniChar* buffer, unsigned length) +{ + unsigned i; + for (i = 0; i < length; i++) { + UCharDirection direction = u_charDirection(buffer[i]); + if (direction == U_RIGHT_TO_LEFT || direction > U_OTHER_NEUTRAL) + return false; + } + return true; +} + +static float widthWithFont(NSString *string, NSFont *font) +{ + unsigned length = [string length]; + Vector<UniChar, 2048> buffer(length); + [string getCharacters:buffer.data()]; + + if (canUseFastRenderer(buffer.data(), length)) { + Font webCoreFont(FontPlatformData(font, [font pointSize]), ![[NSGraphicsContext currentContext] isDrawingToScreen]); + TextRun run(buffer.data(), length); + run.disableRoundingHacks(); + return webCoreFont.floatWidth(run); + } + + return [string sizeWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]].width; +} + +static inline CGFloat webkit_CGCeiling(CGFloat value) +{ + if (sizeof(value) == sizeof(float)) + return ceilf(value); + return static_cast<CGFloat>(ceil(value)); +} + +static void drawAtPoint(NSString *string, NSPoint point, NSFont *font, NSColor *textColor) +{ + unsigned length = [string length]; + Vector<UniChar, 2048> buffer(length); + + [string getCharacters:buffer.data()]; + + if (canUseFastRenderer(buffer.data(), length)) { + // The following is a half-assed attempt to match AppKit's rounding rules for drawAtPoint. + // It's probably incorrect for high DPI. + // If you change this, be sure to test all the text drawn this way in Safari, including + // the status bar, bookmarks bar, tab bar, and activity window. + point.y = webkit_CGCeiling(point.y); + + NSGraphicsContext *nsContext = [NSGraphicsContext currentContext]; + CGContextRef cgContext = static_cast<CGContextRef>([nsContext graphicsPort]); + GraphicsContext graphicsContext(cgContext); + + // Safari doesn't flip the NSGraphicsContext before calling WebKit, yet WebCore requires a flipped graphics context. + BOOL flipped = [nsContext isFlipped]; + if (!flipped) + CGContextScaleCTM(cgContext, 1, -1); + + Font webCoreFont(FontPlatformData(font, [font pointSize]), ![nsContext isDrawingToScreen], Antialiased); + TextRun run(buffer.data(), length); + run.disableRoundingHacks(); + + CGFloat red; + CGFloat green; + CGFloat blue; + CGFloat alpha; + [[textColor colorUsingColorSpaceName:NSDeviceRGBColorSpace] getRed:&red green:&green blue:&blue alpha:&alpha]; + graphicsContext.setFillColor(makeRGBA(red * 255, green * 255, blue * 255, alpha * 255), ColorSpaceDeviceRGB); + + webCoreFont.drawText(&graphicsContext, run, FloatPoint(point.x, (flipped ? point.y : (-1 * point.y)))); + + if (!flipped) + CGContextScaleCTM(cgContext, 1, -1); + } else { + // The given point is on the baseline. + if ([[NSView focusView] isFlipped]) + point.y -= [font ascender]; + else + point.y += [font descender]; + + [string drawAtPoint:point withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, textColor, NSForegroundColorAttributeName, nil]]; + } +} + +static void drawDoubledAtPoint(NSString *string, NSPoint textPoint, NSColor *topColor, NSColor *bottomColor, NSFont *font) +{ + // turn off font smoothing so translucent text draws correctly (Radar 3118455) + drawAtPoint(string, textPoint, font, bottomColor); + + textPoint.y += 1; + drawAtPoint(string, textPoint, font, topColor); +} + +DragImageRef createDragImageForLink(KURL& url, const String& title, Frame* frame) +{ + if (!frame) + return nil; + NSString *label = 0; + if (!title.isEmpty()) + label = title; + NSURL *cocoaURL = url; + NSString *urlString = [cocoaURL absoluteString]; + + BOOL drawURLString = YES; + BOOL clipURLString = NO; + BOOL clipLabelString = NO; + + if (!label) { + drawURLString = NO; + label = urlString; + } + + NSFont *labelFont = [[NSFontManager sharedFontManager] convertFont:[NSFont systemFontOfSize:DragLinkLabelFontsize] + toHaveTrait:NSBoldFontMask]; + NSFont *urlFont = [NSFont systemFontOfSize:DragLinkUrlFontSize]; + NSSize labelSize; + labelSize.width = widthWithFont(label, labelFont); + labelSize.height = [labelFont ascender] - [labelFont descender]; + if (labelSize.width > MaxDragLabelWidth){ + labelSize.width = MaxDragLabelWidth; + clipLabelString = YES; + } + + NSSize imageSize; + imageSize.width = labelSize.width + DragLabelBorderX * 2; + imageSize.height = labelSize.height + DragLabelBorderY * 2; + if (drawURLString) { + NSSize urlStringSize; + urlStringSize.width = widthWithFont(urlString, urlFont); + urlStringSize.height = [urlFont ascender] - [urlFont descender]; + imageSize.height += urlStringSize.height; + if (urlStringSize.width > MaxDragLabelWidth) { + imageSize.width = std::max(MaxDragLabelWidth + DragLabelBorderY * 2, MinDragLabelWidthBeforeClip); + clipURLString = YES; + } else + imageSize.width = std::max(labelSize.width + DragLabelBorderX * 2, urlStringSize.width + DragLabelBorderX * 2); + } + NSImage *dragImage = [[[NSImage alloc] initWithSize: imageSize] autorelease]; + [dragImage lockFocus]; + + [[NSColor colorWithDeviceRed: 0.7f green: 0.7f blue: 0.7f alpha: 0.8f] set]; + + // Drag a rectangle with rounded corners + NSBezierPath *path = [NSBezierPath bezierPath]; + [path appendBezierPathWithOvalInRect: NSMakeRect(0, 0, DragLabelRadius * 2, DragLabelRadius * 2)]; + [path appendBezierPathWithOvalInRect: NSMakeRect(0, imageSize.height - DragLabelRadius * 2, DragLabelRadius * 2, DragLabelRadius * 2)]; + [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DragLabelRadius * 2, imageSize.height - DragLabelRadius * 2, DragLabelRadius * 2, DragLabelRadius * 2)]; + [path appendBezierPathWithOvalInRect: NSMakeRect(imageSize.width - DragLabelRadius * 2, 0, DragLabelRadius * 2, DragLabelRadius * 2)]; + + [path appendBezierPathWithRect: NSMakeRect(DragLabelRadius, 0, imageSize.width - DragLabelRadius * 2, imageSize.height)]; + [path appendBezierPathWithRect: NSMakeRect(0, DragLabelRadius, DragLabelRadius + 10, imageSize.height - 2 * DragLabelRadius)]; + [path appendBezierPathWithRect: NSMakeRect(imageSize.width - DragLabelRadius - 20, DragLabelRadius, DragLabelRadius + 20, imageSize.height - 2 * DragLabelRadius)]; + [path fill]; + + NSColor *topColor = [NSColor colorWithDeviceWhite:0.0f alpha:0.75f]; + NSColor *bottomColor = [NSColor colorWithDeviceWhite:1.0f alpha:0.5f]; + if (drawURLString) { + if (clipURLString) + urlString = StringTruncator::centerTruncate(urlString, imageSize.width - (DragLabelBorderX * 2), fontFromNSFont(urlFont)); + + drawDoubledAtPoint(urlString, NSMakePoint(DragLabelBorderX, DragLabelBorderY - [urlFont descender]), topColor, bottomColor, urlFont); + } + + if (clipLabelString) + label = StringTruncator::rightTruncate(label, imageSize.width - (DragLabelBorderX * 2), fontFromNSFont(labelFont)); + drawDoubledAtPoint(label, NSMakePoint(DragLabelBorderX, imageSize.height - LabelBorderYOffset - [labelFont pointSize]), topColor, bottomColor, labelFont); + + [dragImage unlockFocus]; + + return dragImage; +} + } // namespace WebCore #endif // ENABLE(DRAG_SUPPORT) diff --git a/Source/WebCore/platform/mac/EmptyProtocolDefinitions.h b/Source/WebCore/platform/mac/EmptyProtocolDefinitions.h index b73177b..04bf236 100644 --- a/Source/WebCore/platform/mac/EmptyProtocolDefinitions.h +++ b/Source/WebCore/platform/mac/EmptyProtocolDefinitions.h @@ -23,6 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef EmptyProtocolDefinitions_h +#define EmptyProtocolDefinitions_h + #if defined(__OBJC__) #define EMPTY_PROTOCOL(NAME) \ @@ -47,3 +50,5 @@ EMPTY_PROTOCOL(NSURLDownloadDelegate) #undef EMPTY_PROTOCOL #endif /* defined(__OBJC__) */ + +#endif /* EmptyProtocolDefinitions_h */ diff --git a/Source/WebCore/platform/mac/FileSystemMac.mm b/Source/WebCore/platform/mac/FileSystemMac.mm index 0df3c89..bbeb76a 100644 --- a/Source/WebCore/platform/mac/FileSystemMac.mm +++ b/Source/WebCore/platform/mac/FileSystemMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -25,10 +25,12 @@ * (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 "config.h" #import "FileSystem.h" #import "PlatformString.h" +#import <wtf/RetainPtr.h> #import <wtf/text/CString.h> namespace WebCore { @@ -62,4 +64,25 @@ CString openTemporaryFile(const char* prefix, PlatformFileHandle& platformFileHa return CString(temporaryFilePath.data()); } +bool canExcludeFromBackup() +{ +#ifdef BUILDING_ON_TIGER + return false; +#else + return true; +#endif +} + +bool excludeFromBackup(const String& path) +{ +#ifdef BUILDING_ON_TIGER + UNUSED_PARAM(path); + return false; +#else + // It is critical to pass FALSE for excludeByPath because excluding by path requires root privileges. + CSBackupSetItemExcluded(pathAsURL(path).get(), TRUE, FALSE); + return true; +#endif +} + } // namespace WebCore diff --git a/Source/WebCore/platform/mac/MIMETypeRegistryMac.mm b/Source/WebCore/platform/mac/MIMETypeRegistryMac.mm index 82348e0..3792b5a 100644 --- a/Source/WebCore/platform/mac/MIMETypeRegistryMac.mm +++ b/Source/WebCore/platform/mac/MIMETypeRegistryMac.mm @@ -28,12 +28,15 @@ #include "MIMETypeRegistry.h" #include "WebCoreSystemInterface.h" +#include <wtf/Assertions.h> +#include <wtf/MainThread.h> namespace WebCore { String MIMETypeRegistry::getMIMETypeForExtension(const String &ext) { + ASSERT(isMainThread()); return wkGetMIMETypeForExtension(ext); } diff --git a/Source/WebCore/platform/mac/PasteboardMac.mm b/Source/WebCore/platform/mac/PasteboardMac.mm index 71e4046..65180a0 100644 --- a/Source/WebCore/platform/mac/PasteboardMac.mm +++ b/Source/WebCore/platform/mac/PasteboardMac.mm @@ -27,7 +27,6 @@ #import "Pasteboard.h" #import "CachedResource.h" -#import "CharacterNames.h" #import "DOMRangeInternal.h" #import "Document.h" #import "DocumentFragment.h" @@ -49,10 +48,10 @@ #import "Text.h" #import "WebCoreNSStringExtras.h" #import "markup.h" - #import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> #import <wtf/UnusedParam.h> +#import <wtf/unicode/CharacterNames.h> @interface NSAttributedString (AppKitSecretsIKnowAbout) - (id)_initWithDOMRange:(DOMRange *)domRange; diff --git a/Source/WebCore/platform/mac/PopupMenuMac.mm b/Source/WebCore/platform/mac/PopupMenuMac.mm index 1bf500b..e69bcb2 100644 --- a/Source/WebCore/platform/mac/PopupMenuMac.mm +++ b/Source/WebCore/platform/mac/PopupMenuMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2008, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). * * This library is free software; you can redistribute it and/or @@ -75,6 +75,11 @@ void PopupMenuMac::populate() if (!client()->shouldPopOver()) [m_popup.get() addItemWithTitle:@""]; +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + TextDirection menuTextDirection = client()->menuStyle().textDirection(); + [m_popup.get() setUserInterfaceLayoutDirection:menuTextDirection == LTR ? NSUserInterfaceLayoutDirectionLeftToRight : NSUserInterfaceLayoutDirectionRightToLeft]; +#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + ASSERT(client()); int size = client()->listSize(); @@ -92,13 +97,27 @@ void PopupMenuMac::populate() } [attributes setObject:font forKey:NSFontAttributeName]; } + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + RetainPtr<NSMutableParagraphStyle> paragraphStyle(AdoptNS, [[NSParagraphStyle defaultParagraphStyle] mutableCopy]); + [paragraphStyle.get() setAlignment:menuTextDirection == LTR ? NSLeftTextAlignment : NSRightTextAlignment]; + NSWritingDirection writingDirection = style.textDirection() == LTR ? NSWritingDirectionLeftToRight : NSWritingDirectionRightToLeft; + [paragraphStyle.get() setBaseWritingDirection:writingDirection]; + if (style.hasTextDirectionOverride()) { + RetainPtr<NSNumber> writingDirectionValue(AdoptNS, [[NSNumber alloc] initWithInteger:writingDirection + NSTextWritingDirectionOverride]); + RetainPtr<NSArray> writingDirectionArray(AdoptNS, [[NSArray alloc] initWithObjects:writingDirectionValue.get(), nil]); + [attributes setObject:writingDirectionArray.get() forKey:NSWritingDirectionAttributeName]; + } + [attributes setObject:paragraphStyle.get() forKey:NSParagraphStyleAttributeName]; +#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + // FIXME: Add support for styling the foreground and background colors. // FIXME: Find a way to customize text color when an item is highlighted. - NSAttributedString* string = [[NSAttributedString alloc] initWithString:client()->itemText(i) attributes:attributes]; + NSAttributedString *string = [[NSAttributedString alloc] initWithString:client()->itemText(i) attributes:attributes]; [attributes release]; [m_popup.get() addItemWithTitle:@""]; - NSMenuItem* menuItem = [m_popup.get() lastItem]; + NSMenuItem *menuItem = [m_popup.get() lastItem]; [menuItem setAttributedTitle:string]; [menuItem setEnabled:client()->itemIsEnabled(i)]; [menuItem setToolTip:client()->itemToolTip(i)]; diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.h b/Source/WebCore/platform/mac/ScrollAnimatorMac.h index f05db40..3f7612a 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.h +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,17 +28,30 @@ #if ENABLE(SMOOTH_SCROLLING) +#include "FloatPoint.h" +#include "FloatSize.h" +#include "HeaderDetection.h" #include "ScrollAnimator.h" +#include "Timer.h" +#include "WebCoreSystemInterface.h" #include <wtf/RetainPtr.h> #ifdef __OBJC__ @class ScrollAnimationHelperDelegate; +@class ScrollbarPainterDelegate; +@class ScrollbarPainterControllerDelegate; +@class ScrollbarPainterDelegate; #else class ScrollAnimationHelperDelegate; +class ScrollbarPainterDelegate; +class ScrollbarPainterControllerDelegate; +class ScrollbarPainterDelegate; #endif namespace WebCore { +class Scrollbar; + class ScrollAnimatorMac : public ScrollAnimator { public: ScrollAnimatorMac(ScrollableArea*); @@ -47,12 +60,72 @@ public: virtual bool scroll(ScrollbarOrientation, ScrollGranularity, float step, float multiplier); virtual void scrollToOffsetWithoutAnimation(const FloatPoint&); - // Called by the ScrollAnimationHelperDelegate. - void immediateScrollToPoint(const FloatPoint& newPosition); +#if ENABLE(RUBBER_BANDING) + virtual void handleWheelEvent(PlatformWheelEvent&); +#if ENABLE(GESTURE_EVENTS) + virtual void handleGestureEvent(const PlatformGestureEvent&); +#endif +#endif + void immediateScrollToPoint(const FloatPoint& newPosition); + void immediateScrollByDeltaX(float deltaX); + void immediateScrollByDeltaY(float deltaY); + private: RetainPtr<id> m_scrollAnimationHelper; RetainPtr<ScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate; + +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + RetainPtr<WKScrollbarPainterControllerRef> m_scrollbarPainterController; + RetainPtr<ScrollbarPainterControllerDelegate> m_scrollbarPainterControllerDelegate; + RetainPtr<id> m_scrollbarPainterDelegate; +#endif + + virtual void notityPositionChanged(); + virtual void contentAreaWillPaint() const; + virtual void mouseEnteredContentArea() const; + virtual void mouseExitedContentArea() const; + virtual void mouseMovedInContentArea() const; + virtual void willStartLiveResize(); + virtual void contentsResized() const; + virtual void willEndLiveResize(); + virtual void contentAreaDidShow() const; + virtual void contentAreaDidHide() const; + + virtual void didAddVerticalScrollbar(Scrollbar*); + virtual void willRemoveVerticalScrollbar(Scrollbar*); + virtual void didAddHorizontalScrollbar(Scrollbar*); + virtual void willRemoveHorizontalScrollbar(Scrollbar*); + + float adjustScrollXPositionIfNecessary(float) const; + float adjustScrollYPositionIfNecessary(float) const; + FloatPoint adjustScrollPositionIfNecessary(const FloatPoint&) const; + +#if ENABLE(RUBBER_BANDING) + bool allowsVerticalStretching() const; + bool allowsHorizontalStretching() const; + bool pinnedInDirection(float deltaX, float deltaY); + void snapRubberBand(); + void snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*); + void smoothScrollWithEvent(PlatformWheelEvent&); + void beginScrollGesture(); + void endScrollGesture(); + + bool m_inScrollGesture; + bool m_momentumScrollInProgress; + bool m_ignoreMomentumScrolls; + CFTimeInterval m_lastMomemtumScrollTimestamp; + FloatSize m_overflowScrollDelta; + FloatSize m_stretchScrollForce; + FloatSize m_momentumVelocity; + + // Rubber band state. + CFTimeInterval m_startTime; + FloatSize m_startStretch; + FloatPoint m_origOrigin; + FloatSize m_origVelocity; + Timer<ScrollAnimatorMac> m_snapRubberBandTimer; +#endif }; } // namespace WebCore diff --git a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm index 59b333b..c1154d5 100644 --- a/Source/WebCore/platform/mac/ScrollAnimatorMac.mm +++ b/Source/WebCore/platform/mac/ScrollAnimatorMac.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010, 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,10 +30,20 @@ #include "ScrollAnimatorMac.h" #include "FloatPoint.h" +#include "IntRect.h" +#include "PlatformGestureEvent.h" +#include "PlatformWheelEvent.h" +#include "ScrollView.h" #include "ScrollableArea.h" +#include "ScrollbarTheme.h" +#include "ScrollbarThemeMac.h" #include <wtf/PassOwnPtr.h> +#include <wtf/UnusedParam.h> -@interface NSObject (NSScrollAnimationHelperDetails) +using namespace WebCore; +using namespace std; + +@interface NSObject (ScrollAnimationHelperDetails) - (id)initWithDelegate:(id)delegate; - (void)_stopRun; - (BOOL)_isAnimating; @@ -44,18 +54,7 @@ { WebCore::ScrollAnimatorMac* _animator; } - - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; - -- (NSRect)bounds; -- (void)_immediateScrollToPoint:(NSPoint)newPosition; -- (NSSize)convertSizeToBase:(NSSize)size; -- (NSSize)convertSizeFromBase:(NSSize)size; - -- (id)superview; // Return nil. -- (id)documentView; // Return nil. -- (id)window; // Return nil. -- (void)_recursiveRecomputeToolTips; // No-op. @end static NSSize abs(NSSize size) @@ -80,14 +79,24 @@ static NSSize abs(NSSize size) return self; } +- (void)scrollAnimatorDestroyed +{ + _animator = 0; +} + - (NSRect)bounds { + if (!_animator) + return NSZeroRect; + WebCore::FloatPoint currentPosition = _animator->currentPosition(); return NSMakeRect(currentPosition.x(), currentPosition.y(), 0, 0); } - (void)_immediateScrollToPoint:(NSPoint)newPosition { + if (!_animator) + return; _animator->immediateScrollToPoint(newPosition); } @@ -101,6 +110,16 @@ static NSSize abs(NSSize size) return abs(size); } +- (NSSize)convertSizeToBacking:(NSSize)size +{ + return abs(size); +} + +- (NSSize)convertSizeFromBacking:(NSSize)size +{ + return abs(size); +} + - (id)superview { return nil; @@ -122,6 +141,307 @@ static NSSize abs(NSSize size) @end +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + +@interface ScrollbarPainterControllerDelegate : NSObject +{ + WebCore::ScrollAnimatorMac* _animator; +} +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; +@end + +@implementation ScrollbarPainterControllerDelegate + +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator +{ + self = [super init]; + if (!self) + return nil; + + _animator = scrollAnimator; + return self; +} + +- (void)scrollAnimatorDestroyed +{ + _animator = 0; +} + +- (NSRect)contentAreaRectForScrollerImpPair:(id)scrollerImpPair +{ + UNUSED_PARAM(scrollerImpPair); + if (!_animator) + return NSZeroRect; + + WebCore::IntSize contentsSize = _animator->scrollableArea()->contentsSize(); + return NSMakeRect(0, 0, contentsSize.width(), contentsSize.height()); +} + +- (BOOL)inLiveResizeForScrollerImpPair:(id)scrollerImpPair +{ + UNUSED_PARAM(scrollerImpPair); + if (!_animator) + return NO; + + return _animator->scrollableArea()->inLiveResize(); +} + +- (NSPoint)mouseLocationInContentAreaForScrollerImpPair:(id)scrollerImpPair +{ + UNUSED_PARAM(scrollerImpPair); + if (!_animator) + return NSZeroPoint; + + return _animator->scrollableArea()->currentMousePosition(); +} + +- (NSPoint)scrollerImpPair:(id)scrollerImpPair convertContentPoint:(NSPoint)pointInContentArea toScrollerImp:(id)scrollerImp +{ + UNUSED_PARAM(scrollerImpPair); + if (!_animator) + return NSZeroPoint; + + WebCore::Scrollbar* scrollbar = 0; + if (wkScrollbarPainterIsHorizontal((WKScrollbarPainterRef)scrollerImp)) + scrollbar = _animator->scrollableArea()->horizontalScrollbar(); + else + scrollbar = _animator->scrollableArea()->verticalScrollbar(); + + // It is possible to have a null scrollbar here since it is possible for this delegate + // method to be called between the moment when a scrollbar has been set to 0 and the + // moment when its destructor has been called. We should probably de-couple some + // of the clean-up work in ScrollbarThemeMac::unregisterScrollbar() to avoid this + // issue. + if (!scrollbar) + return WebCore::IntPoint(); + + return scrollbar->convertFromContainingView(WebCore::IntPoint(pointInContentArea)); +} + +- (void)scrollerImpPair:(id)scrollerImpPair setContentAreaNeedsDisplayInRect:(NSRect)rect +{ + UNUSED_PARAM(scrollerImpPair); + UNUSED_PARAM(rect); +} + +- (void)scrollerImpPair:(id)scrollerImpPair updateScrollerStyleForNewRecommendedScrollerStyle:(NSScrollerStyle)newRecommendedScrollerStyle +{ + if (!_animator) + return; + + WKScrollbarPainterControllerRef painterController = (WKScrollbarPainterControllerRef)scrollerImpPair; + WebCore::ScrollbarThemeMac* macTheme = (WebCore::ScrollbarThemeMac*)WebCore::ScrollbarTheme::nativeTheme(); + + WKScrollbarPainterRef oldVerticalPainter = wkVerticalScrollbarPainterForController(painterController); + if (oldVerticalPainter) { + WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar(); + WKScrollbarPainterRef newVerticalPainter = wkMakeScrollbarReplacementPainter(oldVerticalPainter, + newRecommendedScrollerStyle, + verticalScrollbar->controlSize(), + false); + macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); + } + + WKScrollbarPainterRef oldHorizontalPainter = wkHorizontalScrollbarPainterForController(painterController); + if (oldHorizontalPainter) { + WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar(); + WKScrollbarPainterRef newHorizontalPainter = wkMakeScrollbarReplacementPainter(oldHorizontalPainter, + newRecommendedScrollerStyle, + horizontalScrollbar->controlSize(), + true); + macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); + } + + wkSetScrollbarPainterControllerStyle(painterController, newRecommendedScrollerStyle); +} + +@end + +@interface ScrollbarPartAnimation : NSAnimation +{ + RetainPtr<WKScrollbarPainterRef> _scrollerPainter; + WebCore::ScrollbarPart _part; + WebCore::ScrollAnimatorMac* _animator; + CGFloat _initialAlpha; + CGFloat _newAlpha; +} +- (id)initWithScrollbarPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part scrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration; +@end + +@implementation ScrollbarPartAnimation + +- (id)initWithScrollbarPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part scrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration +{ + self = [super initWithDuration:duration animationCurve:NSAnimationEaseInOut]; + if (!self) + return nil; + + _scrollerPainter = scrollerPainter; + _part = part; + _animator = scrollAnimator; + _initialAlpha = _part == WebCore::ThumbPart ? wkScrollbarPainterKnobAlpha(_scrollerPainter.get()) : wkScrollbarPainterTrackAlpha(_scrollerPainter.get()); + _newAlpha = newAlpha; + + return self; +} + +- (void)setCurrentProgress:(NSAnimationProgress)progress +{ + [super setCurrentProgress:progress]; + + if (!_animator) + return; + + CGFloat currentAlpha; + if (_initialAlpha > _newAlpha) + currentAlpha = 1 - progress; + else + currentAlpha = progress; + + if (_part == WebCore::ThumbPart) + wkSetScrollbarPainterKnobAlpha(_scrollerPainter.get(), currentAlpha); + else + wkSetScrollbarPainterTrackAlpha(_scrollerPainter.get(), currentAlpha); + + // Invalidate the scrollbars so that they paint the animation + if (WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar()) + _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); + if (WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar()) + _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); +} + +- (void)scrollAnimatorDestroyed +{ + [self stopAnimation]; + _animator = 0; +} + +@end + +@interface ScrollbarPainterDelegate : NSObject<NSAnimationDelegate> +{ + WebCore::ScrollAnimatorMac* _animator; + + RetainPtr<ScrollbarPartAnimation> _verticalKnobAnimation; + RetainPtr<ScrollbarPartAnimation> _horizontalKnobAnimation; + + RetainPtr<ScrollbarPartAnimation> _verticalTrackAnimation; + RetainPtr<ScrollbarPartAnimation> _horizontalTrackAnimation; +} +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; +@end + +@implementation ScrollbarPainterDelegate + +- (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator +{ + self = [super init]; + if (!self) + return nil; + + _animator = scrollAnimator; + return self; +} + +- (NSRect)convertRectToBacking:(NSRect)aRect +{ + return aRect; +} + +- (NSRect)convertRectFromBacking:(NSRect)aRect +{ + return aRect; +} + +- (CALayer *)layer +{ + if (!_animator) + return nil; + if (!_animator->scrollableArea()->scrollbarWillRenderIntoCompositingLayer()) + return nil; + + // FIXME: This should attempt to return an actual layer. + static CALayer *dummyLayer = [[CALayer alloc] init]; + return dummyLayer; +} + +- (void)setUpAnimation:(RetainPtr<ScrollbarPartAnimation>&)scrollbarPartAnimation scrollerPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration +{ + // If we are currently animating, stop + if (scrollbarPartAnimation) { + [scrollbarPartAnimation.get() stopAnimation]; + scrollbarPartAnimation = nil; + } + + scrollbarPartAnimation.adoptNS([[ScrollbarPartAnimation alloc] initWithScrollbarPainter:scrollerPainter + part:part + scrollAnimator:_animator + animateAlphaTo:newAlpha + duration:duration]); + [scrollbarPartAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking]; + [scrollbarPartAnimation.get() startAnimation]; +} + +- (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration +{ + if (!_animator) + return; + + WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; + if (newKnobAlpha == wkScrollbarPainterKnobAlpha(scrollerPainter)) + return; + + if (wkScrollbarPainterIsHorizontal(scrollerPainter)) + [self setUpAnimation:_horizontalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; + else + [self setUpAnimation:_verticalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; +} + +- (void)scrollerImp:(id)scrollerImp animateTrackAlphaTo:(CGFloat)newTrackAlpha duration:(NSTimeInterval)duration +{ + if (!_animator) + return; + + WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; + if (newTrackAlpha == wkScrollbarPainterTrackAlpha(scrollerPainter)) + return; + + if (wkScrollbarPainterIsHorizontal(scrollerPainter)) + [self setUpAnimation:_horizontalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; + else + [self setUpAnimation:_verticalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; +} + +- (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState +{ + if (!_animator) + return; + + WKScrollbarPainterRef scrollbarPainter = (WKScrollbarPainterRef)scrollerImp; + wkScrollbarPainterSetOverlayState(scrollbarPainter, newOverlayScrollerState); + + if (wkScrollbarPainterIsHorizontal(scrollbarPainter)) { + WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar(); + _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); + } else { + WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar(); + _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); + + } +} + +- (void)scrollAnimatorDestroyed +{ + _animator = 0; + [_verticalKnobAnimation.get() scrollAnimatorDestroyed]; + [_horizontalKnobAnimation.get() scrollAnimatorDestroyed]; + [_verticalTrackAnimation.get() scrollAnimatorDestroyed]; + [_horizontalTrackAnimation.get() scrollAnimatorDestroyed]; +} + +@end +#endif // #if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + namespace WebCore { PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea) @@ -131,13 +451,33 @@ PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) : ScrollAnimator(scrollableArea) +#if ENABLE(RUBBER_BANDING) + , m_inScrollGesture(false) + , m_momentumScrollInProgress(false) + , m_ignoreMomentumScrolls(false) + , m_lastMomemtumScrollTimestamp(0) + , m_startTime(0) + , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) +#endif { m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); + +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + m_scrollbarPainterControllerDelegate.adoptNS([[ScrollbarPainterControllerDelegate alloc] initWithScrollAnimator:this]); + m_scrollbarPainterController = wkMakeScrollbarPainterController(m_scrollbarPainterControllerDelegate.get()); + m_scrollbarPainterDelegate.adoptNS([[ScrollbarPainterDelegate alloc] initWithScrollAnimator:this]); +#endif } ScrollAnimatorMac::~ScrollAnimatorMac() { +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + [m_scrollbarPainterControllerDelegate.get() scrollAnimatorDestroyed]; + [(id)m_scrollbarPainterController.get() setDelegate:nil]; + [m_scrollbarPainterDelegate.get() scrollAnimatorDestroyed]; + [m_scrollAnimationHelperDelegate.get() scrollAnimatorDestroyed]; +#endif } bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) @@ -167,16 +507,567 @@ bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranulari void ScrollAnimatorMac::scrollToOffsetWithoutAnimation(const FloatPoint& offset) { [m_scrollAnimationHelper.get() _stopRun]; - ScrollAnimator::scrollToOffsetWithoutAnimation(offset); + immediateScrollToPoint(offset); +} + +float ScrollAnimatorMac::adjustScrollXPositionIfNecessary(float position) const +{ + if (!m_scrollableArea->constrainsScrollingToContentEdge()) + return position; + + return max<float>(min<float>(position, m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); +} + +float ScrollAnimatorMac::adjustScrollYPositionIfNecessary(float position) const +{ + if (!m_scrollableArea->constrainsScrollingToContentEdge()) + return position; + + return max<float>(min<float>(position, m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); +} + +FloatPoint ScrollAnimatorMac::adjustScrollPositionIfNecessary(const FloatPoint& position) const +{ + if (!m_scrollableArea->constrainsScrollingToContentEdge()) + return position; + + float newX = max<float>(min<float>(position.x(), m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); + float newY = max<float>(min<float>(position.y(), m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); + + return FloatPoint(newX, newY); } void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) { - m_currentPosX = newPosition.x(); - m_currentPosY = newPosition.y(); + FloatPoint adjustedPosition = adjustScrollPositionIfNecessary(newPosition); + + m_currentPosX = adjustedPosition.x(); + m_currentPosY = adjustedPosition.y(); notityPositionChanged(); } +void ScrollAnimatorMac::immediateScrollByDeltaX(float deltaX) +{ + m_currentPosX = adjustScrollXPositionIfNecessary(m_currentPosX + deltaX); + notityPositionChanged(); +} + +void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) +{ + m_currentPosY = adjustScrollYPositionIfNecessary(m_currentPosY + deltaY); + notityPositionChanged(); +} + +void ScrollAnimatorMac::notityPositionChanged() +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkContentAreaScrolled(m_scrollbarPainterController.get()); +#endif + ScrollAnimator::notityPositionChanged(); +} + +void ScrollAnimatorMac::contentAreaWillPaint() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkContentAreaWillPaint(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::mouseEnteredContentArea() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkMouseEnteredContentArea(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::mouseExitedContentArea() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkMouseExitedContentArea(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::mouseMovedInContentArea() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkMouseMovedInContentArea(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::willStartLiveResize() +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkWillStartLiveResize(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::contentsResized() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkContentAreaResized(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::willEndLiveResize() +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkWillEndLiveResize(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::contentAreaDidShow() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkContentAreaDidShow(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::contentAreaDidHide() const +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + wkContentAreaDidHide(m_scrollbarPainterController.get()); +#endif +} + +void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); + wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); + wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false); + if (scrollableArea()->inLiveResize()) + wkSetScrollbarPainterKnobAlpha(painter, 1); +#else + UNUSED_PARAM(scrollbar); +#endif +} + +void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); + wkScrollbarPainterSetDelegate(painter, nil); + wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false); +#else + UNUSED_PARAM(scrollbar); +#endif +} + +void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); + wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); + wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true); + if (scrollableArea()->inLiveResize()) + wkSetScrollbarPainterKnobAlpha(painter, 1); +#else + UNUSED_PARAM(scrollbar); +#endif +} + +void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) +{ +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); + wkScrollbarPainterSetDelegate(painter, nil); + wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true); +#else + UNUSED_PARAM(scrollbar); +#endif +} + +#if ENABLE(RUBBER_BANDING) + +static const float scrollVelocityZeroingTimeout = 0.10f; +static const float rubberbandStiffness = 20; +static const float rubberbandDirectionLockStretchRatio = 1; +static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10; +static const float rubberbandAmplitude = 0.31f; +static const float rubberbandPeriod = 1.6f; + +static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) +{ + float amplitude = rubberbandAmplitude; + float period = rubberbandPeriod; + float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period); + + return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor; +} + +static float elasticDeltaForReboundDelta(float delta) +{ + float stiffness = std::max(rubberbandStiffness, 1.0f); + return delta / stiffness; +} + +static float reboundDeltaForElasticDelta(float delta) +{ + return delta * rubberbandStiffness; +} + +static float scrollWheelMultiplier() +{ + static float multiplier = -1; + if (multiplier < 0) { + multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"]; + if (multiplier <= 0) + multiplier = 1; + } + return multiplier; +} + +void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) +{ + if (!wheelEvent.hasPreciseScrollingDeltas()) { + ScrollAnimator::handleWheelEvent(wheelEvent); + return; + } + + wheelEvent.accept(); + + bool isMometumScrollEvent = (wheelEvent.phase() != PlatformWheelEventPhaseNone); + if (m_ignoreMomentumScrolls && (isMometumScrollEvent || m_snapRubberBandTimer.isActive())) { + if (wheelEvent.phase() == PlatformWheelEventPhaseEnded) + m_ignoreMomentumScrolls = false; + return; + } + + smoothScrollWithEvent(wheelEvent); +} + +void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent) +{ + if (gestureEvent.type() == PlatformGestureEvent::ScrollBeginType) + beginScrollGesture(); + else + endScrollGesture(); +} + +bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) +{ + FloatSize limitDelta; + if (fabsf(deltaY) >= fabsf(deltaX)) { + if (deltaY < 0) { + // We are trying to scroll up. Make sure we are not pinned to the top + limitDelta.setHeight(m_scrollableArea->visibleContentRect().y()); + } else { + // We are trying to scroll down. Make sure we are not pinned to the bottom + limitDelta.setHeight(m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleContentRect().maxY()); + } + } else if (deltaX != 0) { + if (deltaX < 0) { + // We are trying to scroll left. Make sure we are not pinned to the left + limitDelta.setWidth(m_scrollableArea->visibleContentRect().x()); + } else { + // We are trying to scroll right. Make sure we are not pinned to the right + limitDelta.setWidth(m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleContentRect().maxX()); + } + } + + if ((deltaX != 0 || deltaY != 0) && (limitDelta.width() < 1 && limitDelta.height() < 1)) + return true; + return false; +} + +bool ScrollAnimatorMac::allowsVerticalStretching() const +{ + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + if (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))) + return true; + + return false; +} + +bool ScrollAnimatorMac::allowsHorizontalStretching() const +{ + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + if (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))) + return true; + + return false; +} + +void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) +{ + float deltaX = m_overflowScrollDelta.width(); + float deltaY = m_overflowScrollDelta.height(); + + // Reset overflow values because we may decide to remove delta at various points and put it into overflow. + m_overflowScrollDelta = FloatSize(); + + float eventCoallescedDeltaX = -wheelEvent.deltaX(); + float eventCoallescedDeltaY = -wheelEvent.deltaY(); + + deltaX += eventCoallescedDeltaX; + deltaY += eventCoallescedDeltaY; + + // Slightly prefer scrolling vertically by applying the = case to deltaY + if (fabsf(deltaY) >= fabsf(deltaX)) + deltaX = 0; + else + deltaY = 0; + + bool isVerticallyStretched = false; + bool isHorizontallyStretched = false; + bool shouldStretch = false; + + IntSize stretchAmount = m_scrollableArea->overhangAmount(); + + isHorizontallyStretched = stretchAmount.width(); + isVerticallyStretched = stretchAmount.height(); + + PlatformWheelEventPhase phase = wheelEvent.phase(); + + // If we are starting momentum scrolling then do some setup. + if (!m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged)) + m_momentumScrollInProgress = true; + + CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomemtumScrollTimestamp; + if (m_inScrollGesture || m_momentumScrollInProgress) { + if (m_lastMomemtumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) { + m_momentumVelocity.setWidth(eventCoallescedDeltaX / (float)timeDelta); + m_momentumVelocity.setHeight(eventCoallescedDeltaY / (float)timeDelta); + m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); + } else { + m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); + m_momentumVelocity = FloatSize(); + } + + if (isVerticallyStretched) { + if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) { + // Stretching only in the vertical. + if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio)) + deltaX = 0; + else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + deltaX = 0; + } else + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + } + } else if (isHorizontallyStretched) { + // Stretching only in the horizontal. + if (pinnedInDirection(0, deltaY)) { + if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio)) + deltaY = 0; + else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); + deltaY = 0; + } else + m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); + } + } else { + // Not stretching at all yet. + if (pinnedInDirection(deltaX, deltaY)) { + if (fabsf(deltaY) >= fabsf(deltaX)) { + if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + deltaX = 0; + } else + m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); + } + shouldStretch = true; + } + } + } + + if (deltaX != 0 || deltaY != 0) { + if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) { + if (deltaY != 0) { + deltaY *= scrollWheelMultiplier(); + immediateScrollByDeltaY(deltaY); + } + if (deltaX != 0) { + deltaX *= scrollWheelMultiplier(); + immediateScrollByDeltaX(deltaX); + } + } else { + if (!allowsHorizontalStretching()) { + deltaX = 0; + eventCoallescedDeltaX = 0; + } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) { + deltaX *= scrollWheelMultiplier(); + + m_scrollableArea->setConstrainsScrollingToContentEdge(false); + immediateScrollByDeltaX(deltaX); + m_scrollableArea->setConstrainsScrollingToContentEdge(true); + + deltaX = 0; + } + + if (!allowsVerticalStretching()) { + deltaY = 0; + eventCoallescedDeltaY = 0; + } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) { + deltaY *= scrollWheelMultiplier(); + + m_scrollableArea->setConstrainsScrollingToContentEdge(false); + immediateScrollByDeltaY(deltaY); + m_scrollableArea->setConstrainsScrollingToContentEdge(true); + + deltaY = 0; + } + + IntSize stretchAmount = m_scrollableArea->overhangAmount(); + + if (m_momentumScrollInProgress) { + if ((pinnedInDirection(eventCoallescedDeltaX, eventCoallescedDeltaY) || (fabsf(eventCoallescedDeltaX) + fabsf(eventCoallescedDeltaY) <= 0)) && m_lastMomemtumScrollTimestamp) { + m_ignoreMomentumScrolls = true; + m_momentumScrollInProgress = false; + snapRubberBand(); + } + } + + m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX); + m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); + + FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); + FloatPoint origOrigin = m_scrollableArea->visibleContentRect().location() - stretchAmount; + FloatPoint newOrigin = origOrigin + dampedDelta; + + if (origOrigin != newOrigin) { + m_scrollableArea->setConstrainsScrollingToContentEdge(false); + immediateScrollToPoint(newOrigin); + m_scrollableArea->setConstrainsScrollingToContentEdge(true); + } + } + } + + if (m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) { + m_momentumScrollInProgress = false; + m_ignoreMomentumScrolls = false; + m_lastMomemtumScrollTimestamp = 0; + } +} + +void ScrollAnimatorMac::beginScrollGesture() +{ + m_inScrollGesture = true; + m_momentumScrollInProgress = false; + m_ignoreMomentumScrolls = false; + m_lastMomemtumScrollTimestamp = 0; + m_momentumVelocity = FloatSize(); + + IntSize stretchAmount = m_scrollableArea->overhangAmount(); + m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width())); + m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height())); + + m_overflowScrollDelta = FloatSize(); + + if (m_snapRubberBandTimer.isActive()) + m_snapRubberBandTimer.stop(); +} + +void ScrollAnimatorMac::endScrollGesture() +{ + snapRubberBand(); +} + +void ScrollAnimatorMac::snapRubberBand() +{ + CFTimeInterval timeDelta = [[NSProcessInfo processInfo] systemUptime] - m_lastMomemtumScrollTimestamp; + if (m_lastMomemtumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout) + m_momentumVelocity = FloatSize(); + + m_inScrollGesture = false; + + if (m_snapRubberBandTimer.isActive()) + return; + + m_startTime = [NSDate timeIntervalSinceReferenceDate]; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + + m_snapRubberBandTimer.startRepeating(1.0/60.0); +} + +static inline float roundTowardZero(float num) +{ + return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f); +} + +static inline float roundToDevicePixelTowardZero(float num) +{ + float roundedNum = roundf(num); + if (fabs(num - roundedNum) < 0.125) + num = roundedNum; + + return roundTowardZero(num); +} + +void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) +{ + if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) { + CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime; + + if (m_startStretch == FloatSize()) { + m_startStretch = m_scrollableArea->overhangAmount(); + if (m_startStretch == FloatSize()) { + m_snapRubberBandTimer.stop(); + m_stretchScrollForce = FloatSize(); + m_startTime = 0; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + + return; + } + + m_origOrigin = m_scrollableArea->visibleContentRect().location() - m_startStretch; + m_origVelocity = m_momentumVelocity; + + // Just like normal scrolling, prefer vertical rubberbanding + if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width())) + m_origVelocity.setWidth(0); + + // Don't rubber-band horizontally if it's not possible to scroll horizontally + Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); + if (!hScroller || !hScroller->enabled()) + m_origVelocity.setWidth(0); + + // Don't rubber-band vertically if it's not possible to scroll horizontally + Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); + if (!vScroller || !vScroller->enabled()) + m_origVelocity.setHeight(0); + } + + FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), (float)timeDelta)), + roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), (float)timeDelta))); + + if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) { + FloatPoint newOrigin = m_origOrigin + delta; + + m_scrollableArea->setConstrainsScrollingToContentEdge(false); + immediateScrollToPoint(newOrigin); + m_scrollableArea->setConstrainsScrollingToContentEdge(true); + + FloatSize newStretch = m_scrollableArea->overhangAmount(); + + m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width())); + m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height())); + } else { + immediateScrollToPoint(m_origOrigin); + + m_scrollableArea->didCompleteRubberBand(roundedIntSize(m_startStretch)); + + m_snapRubberBandTimer.stop(); + m_stretchScrollForce = FloatSize(); + + m_startTime = 0; + m_startStretch = FloatSize(); + m_origOrigin = FloatPoint(); + m_origVelocity = FloatSize(); + } + } else { + m_startTime = [NSDate timeIntervalSinceReferenceDate]; + m_startStretch = FloatSize(); + } +} +#endif + } // namespace WebCore #endif // ENABLE(SMOOTH_SCROLLING) diff --git a/Source/WebCore/platform/mac/ScrollViewMac.mm b/Source/WebCore/platform/mac/ScrollViewMac.mm index 93ec971..ff2e14e 100644 --- a/Source/WebCore/platform/mac/ScrollViewMac.mm +++ b/Source/WebCore/platform/mac/ScrollViewMac.mm @@ -203,10 +203,10 @@ bool ScrollView::platformIsOffscreen() const return ![platformWidget() window] || ![[platformWidget() window] isVisible]; } -void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePosition) +void ScrollView::platformSetScrollOrigin(const IntPoint& origin, bool updatePositionAtAll, bool updatePositionSynchronously) { BEGIN_BLOCK_OBJC_EXCEPTIONS; - [scrollView() setScrollOrigin:origin updatePosition:updatePosition]; + [scrollView() setScrollOrigin:origin updatePositionAtAll:updatePositionAtAll immediately:updatePositionSynchronously]; END_BLOCK_OBJC_EXCEPTIONS; } diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.h b/Source/WebCore/platform/mac/ScrollbarThemeMac.h index 8b5412d..844a088 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.h +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.h @@ -26,7 +26,9 @@ #ifndef ScrollbarThemeMac_h #define ScrollbarThemeMac_h +#include "HeaderDetection.h" #include "ScrollbarThemeComposite.h" +#include "WebCoreSystemInterface.h" namespace WebCore { @@ -50,6 +52,11 @@ public: virtual void registerScrollbar(Scrollbar*); virtual void unregisterScrollbar(Scrollbar*); +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) + void setNewPainterForScrollbar(Scrollbar*, WKScrollbarPainterRef); + WKScrollbarPainterRef painterForScrollbar(Scrollbar*); +#endif + protected: virtual bool hasButtons(Scrollbar*); virtual bool hasThumb(Scrollbar*); diff --git a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm index 032d9f3..c35dfa0 100644 --- a/Source/WebCore/platform/mac/ScrollbarThemeMac.mm +++ b/Source/WebCore/platform/mac/ScrollbarThemeMac.mm @@ -29,17 +29,13 @@ #include "ImageBuffer.h" #include "LocalCurrentGraphicsContext.h" #include "PlatformMouseEvent.h" +#include "ScrollAnimatorMac.h" #include "ScrollView.h" -#include "WebCoreSystemInterface.h" #include <Carbon/Carbon.h> #include <wtf/HashMap.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD) -#define USE_WK_SCROLLBAR_PAINTER -#endif - // FIXME: There are repainting problems due to Aqua scroll bar buttons' visual overflow. using namespace std; @@ -47,7 +43,7 @@ using namespace WebCore; namespace WebCore { -#if defined(USE_WK_SCROLLBAR_PAINTER) +#if USE(WK_SCROLLBAR_PAINTER) typedef HashMap<Scrollbar*, RetainPtr<WKScrollbarPainterRef> > ScrollbarPainterMap; #else typedef HashSet<Scrollbar*> ScrollbarPainterMap; @@ -83,7 +79,7 @@ static ScrollbarPainterMap* scrollbarMap() return; ScrollbarPainterMap::iterator end = scrollbarMap()->end(); for (ScrollbarPainterMap::iterator it = scrollbarMap()->begin(); it != end; ++it) { -#if defined(USE_WK_SCROLLBAR_PAINTER) +#if USE(WK_SCROLLBAR_PAINTER) it->first->styleChanged(); it->first->invalidate(); #else @@ -117,13 +113,15 @@ ScrollbarTheme* ScrollbarTheme::nativeTheme() } // FIXME: Get these numbers from CoreUI. -static int cScrollbarThickness[] = { 15, 11 }; static int cRealButtonLength[] = { 28, 21 }; -static int cButtonInset[] = { 14, 11 }; static int cButtonHitInset[] = { 3, 2 }; // cRealButtonLength - cButtonInset static int cButtonLength[] = { 14, 10 }; +#if !USE(WK_SCROLLBAR_PAINTER) +static int cScrollbarThickness[] = { 15, 11 }; +static int cButtonInset[] = { 14, 11 }; static int cThumbMinLength[] = { 26, 20 }; +#endif static int cOuterButtonLength[] = { 16, 14 }; // The outer button in a double button pair is a bit bigger. static int cOuterButtonOverlap = 2; @@ -131,13 +129,15 @@ static int cOuterButtonOverlap = 2; static float gInitialButtonDelay = 0.5f; static float gAutoscrollButtonDelay = 0.05f; static bool gJumpOnTrackClick = false; + +#if USE(WK_SCROLLBAR_PAINTER) +static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsNone; +#else static ScrollbarButtonsPlacement gButtonPlacement = ScrollbarButtonsDoubleEnd; +#endif static void updateArrowPlacement() { -#if defined(USE_WK_SCROLLBAR_PAINTER) - gButtonPlacement = ScrollbarButtonsNone; -#else NSString *buttonPlacement = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleScrollBarVariant"]; if ([buttonPlacement isEqualToString:@"Single"]) gButtonPlacement = ScrollbarButtonsSingle; @@ -145,16 +145,20 @@ static void updateArrowPlacement() gButtonPlacement = ScrollbarButtonsDoubleStart; else if ([buttonPlacement isEqualToString:@"DoubleBoth"]) gButtonPlacement = ScrollbarButtonsDoubleBoth; - else - gButtonPlacement = ScrollbarButtonsDoubleEnd; // The default is ScrollbarButtonsDoubleEnd. + else { +#if USE(WK_SCROLLBAR_PAINTER) + gButtonPlacement = ScrollbarButtonsNone; +#else + gButtonPlacement = ScrollbarButtonsDoubleEnd; #endif + } } void ScrollbarThemeMac::registerScrollbar(Scrollbar* scrollbar) { -#if defined(USE_WK_SCROLLBAR_PAINTER) - WKScrollbarPainterRef scrollbarPainter = wkMakeScrollbarPainter(scrollbar->controlSize(), - scrollbar->orientation() == HorizontalScrollbar); +#if USE(WK_SCROLLBAR_PAINTER) + bool isHorizontal = scrollbar->orientation() == HorizontalScrollbar; + WKScrollbarPainterRef scrollbarPainter = wkMakeScrollbarPainter(scrollbar->controlSize(), isHorizontal); scrollbarMap()->add(scrollbar, scrollbarPainter); #else scrollbarMap()->add(scrollbar); @@ -163,9 +167,22 @@ void ScrollbarThemeMac::registerScrollbar(Scrollbar* scrollbar) void ScrollbarThemeMac::unregisterScrollbar(Scrollbar* scrollbar) { + scrollbarMap()->remove(scrollbar); } +#if defined(USE_WK_SCROLLBAR_PAINTER_AND_CONTROLLER) +void ScrollbarThemeMac::setNewPainterForScrollbar(Scrollbar* scrollbar, WKScrollbarPainterRef newPainter) +{ + scrollbarMap()->set(scrollbar, newPainter); +} + +WKScrollbarPainterRef ScrollbarThemeMac::painterForScrollbar(Scrollbar* scrollbar) +{ + return scrollbarMap()->get(scrollbar).get(); +} +#endif + ScrollbarThemeMac::ScrollbarThemeMac() { static bool initialized; @@ -192,13 +209,20 @@ void ScrollbarThemeMac::preferencesChanged() int ScrollbarThemeMac::scrollbarThickness(ScrollbarControlSize controlSize) { +#if USE(WK_SCROLLBAR_PAINTER) + return wkScrollbarThickness(controlSize); +#else return cScrollbarThickness[controlSize]; +#endif } bool ScrollbarThemeMac::usesOverlayScrollbars() const { - // FIXME: This should be enabled when <rdar://problem/8492788> is resolved. +#if USE(WK_SCROLLBAR_PAINTER) + return wkScrollbarPainterUsesOverlayScrollers(); +#else return false; +#endif } double ScrollbarThemeMac::initialAutoscrollTimerDelay() @@ -218,20 +242,29 @@ ScrollbarButtonsPlacement ScrollbarThemeMac::buttonsPlacement() const bool ScrollbarThemeMac::hasButtons(Scrollbar* scrollbar) { - return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? - scrollbar->width() : - scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]); + return scrollbar->enabled() && gButtonPlacement != ScrollbarButtonsNone + && (scrollbar->orientation() == HorizontalScrollbar + ? scrollbar->width() + : scrollbar->height()) >= 2 * (cRealButtonLength[scrollbar->controlSize()] - cButtonHitInset[scrollbar->controlSize()]); } bool ScrollbarThemeMac::hasThumb(Scrollbar* scrollbar) { + int minLengthForThumb; +#if USE(WK_SCROLLBAR_PAINTER) + minLengthForThumb = wkScrollbarMinimumTotalLengthNeededForThumb(scrollbarMap()->get(scrollbar).get()); +#else + minLengthForThumb = 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1; +#endif return scrollbar->enabled() && (scrollbar->orientation() == HorizontalScrollbar ? scrollbar->width() : - scrollbar->height()) >= 2 * cButtonInset[scrollbar->controlSize()] + cThumbMinLength[scrollbar->controlSize()] + 1; + scrollbar->height()) >= minLengthForThumb; } static IntRect buttonRepaintRect(const IntRect& buttonRect, ScrollbarOrientation orientation, ScrollbarControlSize controlSize, bool start) { + ASSERT(gButtonPlacement != ScrollbarButtonsNone); + IntRect paintRect(buttonRect); if (orientation == HorizontalScrollbar) { paintRect.setWidth(cRealButtonLength[controlSize]); @@ -359,7 +392,11 @@ IntRect ScrollbarThemeMac::trackRect(Scrollbar* scrollbar, bool painting) int ScrollbarThemeMac::minimumThumbLength(Scrollbar* scrollbar) { +#if USE(WK_SCROLLBAR_PAINTER) + return wkScrollbarMinimumThumbLength(scrollbarMap()->get(scrollbar).get()); +#else return cThumbMinLength[scrollbar->controlSize()]; +#endif } bool ScrollbarThemeMac::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt) @@ -391,15 +428,32 @@ static int scrollbarPartToHIPressedState(ScrollbarPart part) bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, const IntRect& damageRect) { -#if defined(USE_WK_SCROLLBAR_PAINTER) +#if USE(WK_SCROLLBAR_PAINTER) + float value = 0.0f; + float totalSize = 0.0f; + + if (scrollbar->currentPos() < 0) { + // Scrolled past the top. + value = 0.0f; + totalSize = scrollbar->totalSize() - scrollbar->currentPos(); + } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) { + // Scrolled past the bottom. + value = 1.0f; + totalSize = scrollbar->visibleSize() + scrollbar->currentPos(); + } else { + // Within the bounds of the scrollable area. + value = scrollbar->currentPos() / scrollbar->maximum(); + totalSize = scrollbar->totalSize(); + } + context->save(); context->clip(damageRect); context->translate(scrollbar->frameRect().x(), scrollbar->frameRect().y()); LocalCurrentGraphicsContext localContext(context); wkScrollbarPainterPaint(scrollbarMap()->get(scrollbar).get(), scrollbar->enabled(), - scrollbar->currentPos() / scrollbar->maximum(), - static_cast<CGFloat>(scrollbar->visibleSize()) / scrollbar->totalSize(), + value, + static_cast<CGFloat>(scrollbar->visibleSize()) / totalSize, scrollbar->frameRect()); context->restore(); return true; @@ -409,9 +463,27 @@ bool ScrollbarThemeMac::paint(Scrollbar* scrollbar, GraphicsContext* context, co trackInfo.version = 0; trackInfo.kind = scrollbar->controlSize() == RegularScrollbar ? kThemeMediumScrollBar : kThemeSmallScrollBar; trackInfo.bounds = scrollbar->frameRect(); + + float maximum = 0.0f; + float position = 0.0f; + if (scrollbar->currentPos() < 0) { + // Scrolled past the top. + maximum = (scrollbar->totalSize() - scrollbar->currentPos()) - scrollbar->visibleSize(); + position = 0; + } else if (scrollbar->visibleSize() + scrollbar->currentPos() > scrollbar->totalSize()) { + // Scrolled past the bottom. + maximum = scrollbar->currentPos(); + position = maximum; + } else { + // Within the bounds of the scrollable area. + maximum = scrollbar->maximum(); + position = scrollbar->currentPos(); + } + trackInfo.min = 0; - trackInfo.max = scrollbar->maximum(); - trackInfo.value = scrollbar->currentPos(); + trackInfo.max = static_cast<int>(maximum); + trackInfo.value = static_cast<int>(position); + trackInfo.trackInfo.scrollbar.viewsize = scrollbar->visibleSize(); trackInfo.attributes = 0; if (scrollbar->orientation() == HorizontalScrollbar) diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.h b/Source/WebCore/platform/mac/WebCoreSystemInterface.h index 045864a..e6d6cf6 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.h +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.h @@ -147,6 +147,8 @@ extern void (*wkSignalCFReadStreamEnd)(CFReadStreamRef stream); extern void (*wkSignalCFReadStreamError)(CFReadStreamRef stream, CFStreamError *error); extern void (*wkSignalCFReadStreamHasBytes)(CFReadStreamRef stream); extern unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); +extern int (*wkGetHTTPPipeliningPriority)(NSURLRequest *); +extern void (*wkSetHTTPPipeliningPriority)(NSMutableURLRequest *, int priority); extern void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); extern void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); extern CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); @@ -189,9 +191,50 @@ extern CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); typedef struct __WKScrollbarPainter *WKScrollbarPainterRef; extern WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizontal); +extern WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); +extern void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); extern void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +extern int (*wkScrollbarThickness)(int controlSize); +extern int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); +extern int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); +extern CGFloat (*wkScrollbarPainterKnobAlpha)(WKScrollbarPainterRef); +extern void (*wkSetScrollbarPainterKnobAlpha)(WKScrollbarPainterRef, CGFloat); +extern CGFloat (*wkScrollbarPainterTrackAlpha)(WKScrollbarPainterRef); +extern void (*wkSetScrollbarPainterTrackAlpha)(WKScrollbarPainterRef, CGFloat); +extern bool (*wkScrollbarPainterIsHorizontal)(WKScrollbarPainterRef); +extern void (*wkScrollbarPainterSetOverlayState)(WKScrollbarPainterRef, int overlayScrollerState); + +typedef struct __WKScrollbarPainterController *WKScrollbarPainterControllerRef; +extern WKScrollbarPainterControllerRef (*wkMakeScrollbarPainterController)(id painterControllerDelegate); +extern void (*wkSetPainterForPainterController)(WKScrollbarPainterControllerRef, WKScrollbarPainterRef, bool isHorizontal); +extern WKScrollbarPainterRef (*wkVerticalScrollbarPainterForController)(WKScrollbarPainterControllerRef); +extern WKScrollbarPainterRef (*wkHorizontalScrollbarPainterForController)(WKScrollbarPainterControllerRef); +extern void (*wkSetScrollbarPainterControllerStyle)(WKScrollbarPainterControllerRef, int newStyle); +extern void (*wkContentAreaScrolled)(WKScrollbarPainterControllerRef); +extern void (*wkContentAreaWillPaint)(WKScrollbarPainterControllerRef); +extern void (*wkMouseEnteredContentArea)(WKScrollbarPainterControllerRef); +extern void (*wkMouseExitedContentArea)(WKScrollbarPainterControllerRef); +extern void (*wkMouseMovedInContentArea)(WKScrollbarPainterControllerRef); +extern void (*wkWillStartLiveResize)(WKScrollbarPainterControllerRef); +extern void (*wkContentAreaResized)(WKScrollbarPainterControllerRef); +extern void (*wkWillEndLiveResize)(WKScrollbarPainterControllerRef); +extern void (*wkContentAreaDidShow)(WKScrollbarPainterControllerRef); +extern void (*wkContentAreaDidHide)(WKScrollbarPainterControllerRef); + +extern bool (*wkScrollbarPainterUsesOverlayScrollers)(void); #endif +extern void (*wkUnregisterUniqueIdForElement)(id element); +extern void (*wkAccessibilityHandleFocusChanged)(void); +extern CFTypeID (*wkGetAXTextMarkerTypeID)(void); +extern CFTypeID (*wkGetAXTextMarkerRangeTypeID)(void); +extern CFTypeRef (*wkCreateAXTextMarkerRange)(CFTypeRef start, CFTypeRef end); +extern CFTypeRef (*wkCopyAXTextMarkerRangeStart)(CFTypeRef range); +extern CFTypeRef (*wkCopyAXTextMarkerRangeEnd)(CFTypeRef range); +extern CFTypeRef (*wkCreateAXTextMarker)(const void *bytes, size_t len); +extern BOOL (*wkGetBytesFromAXTextMarker)(CFTypeRef textMarker, void *bytes, size_t length); +extern AXUIElementRef (*wkCreateAXUIElementRef)(id element); + } #endif diff --git a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm index 047827f..24bdcb1 100644 --- a/Source/WebCore/platform/mac/WebCoreSystemInterface.mm +++ b/Source/WebCore/platform/mac/WebCoreSystemInterface.mm @@ -89,6 +89,8 @@ void (*wkSetNSURLConnectionDefersCallbacks)(NSURLConnection *, BOOL); void (*wkSetNSURLRequestShouldContentSniff)(NSMutableURLRequest *, BOOL); id (*wkCreateNSURLConnectionDelegateProxy)(void); unsigned (*wkInitializeMaximumHTTPConnectionCountPerHost)(unsigned preferredConnectionCount); +int (*wkGetHTTPPipeliningPriority)(NSURLRequest *); +void (*wkSetHTTPPipeliningPriority)(NSMutableURLRequest *, int priority); void (*wkSetCONNECTProxyForStream)(CFReadStreamRef, CFStringRef proxyHost, CFNumberRef proxyPort); void (*wkSetCONNECTProxyAuthorizationForStream)(CFReadStreamRef, CFStringRef proxyAuthorizationString); CFHTTPMessageRef (*wkCopyCONNECTProxyResponse)(CFReadStreamRef, CFURLRef responseURL); @@ -127,5 +129,46 @@ CGContextRef (*wkIOSurfaceContextCreate)(IOSurfaceRef surface, unsigned width, u CGImageRef (*wkIOSurfaceContextCreateImage)(CGContextRef context); WKScrollbarPainterRef (*wkMakeScrollbarPainter)(int controlSize, bool isHorizontal); +WKScrollbarPainterRef (*wkMakeScrollbarReplacementPainter)(WKScrollbarPainterRef oldPainter, int newStyle, int controlSize, bool isHorizontal); +void (*wkScrollbarPainterSetDelegate)(WKScrollbarPainterRef, id scrollbarPainterDelegate); void (*wkScrollbarPainterPaint)(WKScrollbarPainterRef, bool enabled, double value, CGFloat proportion, CGRect frameRect); +int (*wkScrollbarThickness)(int controlSize); +int (*wkScrollbarMinimumThumbLength)(WKScrollbarPainterRef); +int (*wkScrollbarMinimumTotalLengthNeededForThumb)(WKScrollbarPainterRef); +CGFloat (*wkScrollbarPainterKnobAlpha)(WKScrollbarPainterRef); +void (*wkSetScrollbarPainterKnobAlpha)(WKScrollbarPainterRef, CGFloat); +CGFloat (*wkScrollbarPainterTrackAlpha)(WKScrollbarPainterRef); +void (*wkSetScrollbarPainterTrackAlpha)(WKScrollbarPainterRef, CGFloat); +bool (*wkScrollbarPainterIsHorizontal)(WKScrollbarPainterRef); +void (*wkScrollbarPainterSetOverlayState)(WKScrollbarPainterRef, int overlayScrollerState); + +WKScrollbarPainterControllerRef (*wkMakeScrollbarPainterController)(id painterControllerDelegate); +void (*wkSetPainterForPainterController)(WKScrollbarPainterControllerRef, WKScrollbarPainterRef, bool isHorizontal); +WKScrollbarPainterRef (*wkVerticalScrollbarPainterForController)(WKScrollbarPainterControllerRef); +WKScrollbarPainterRef (*wkHorizontalScrollbarPainterForController)(WKScrollbarPainterControllerRef); +void (*wkSetScrollbarPainterControllerStyle)(WKScrollbarPainterControllerRef, int newStyle); +void (*wkContentAreaScrolled)(WKScrollbarPainterControllerRef); +void (*wkContentAreaWillPaint)(WKScrollbarPainterControllerRef); +void (*wkMouseEnteredContentArea)(WKScrollbarPainterControllerRef); +void (*wkMouseExitedContentArea)(WKScrollbarPainterControllerRef); +void (*wkMouseMovedInContentArea)(WKScrollbarPainterControllerRef); +void (*wkWillStartLiveResize)(WKScrollbarPainterControllerRef); +void (*wkContentAreaResized)(WKScrollbarPainterControllerRef); +void (*wkWillEndLiveResize)(WKScrollbarPainterControllerRef); +void (*wkContentAreaDidShow)(WKScrollbarPainterControllerRef); +void (*wkContentAreaDidHide)(WKScrollbarPainterControllerRef); + +bool (*wkScrollbarPainterUsesOverlayScrollers)(void); #endif + +void (*wkUnregisterUniqueIdForElement)(id element); +void (*wkAccessibilityHandleFocusChanged)(void); +CFTypeID (*wkGetAXTextMarkerTypeID)(void); +CFTypeID (*wkGetAXTextMarkerRangeTypeID)(void); +CFTypeRef (*wkCreateAXTextMarkerRange)(CFTypeRef start, CFTypeRef end); +CFTypeRef (*wkCopyAXTextMarkerRangeStart)(CFTypeRef range); +CFTypeRef (*wkCopyAXTextMarkerRangeEnd)(CFTypeRef range); +CFTypeRef (*wkCreateAXTextMarker)(const void *bytes, size_t len); +BOOL (*wkGetBytesFromAXTextMarker)(CFTypeRef textMarker, void *bytes, size_t length); +AXUIElementRef (*wkCreateAXUIElementRef)(id element); + diff --git a/Source/WebCore/platform/mac/WheelEventMac.mm b/Source/WebCore/platform/mac/WheelEventMac.mm index d4fc698..74265d1 100644 --- a/Source/WebCore/platform/mac/WheelEventMac.mm +++ b/Source/WebCore/platform/mac/WheelEventMac.mm @@ -64,6 +64,7 @@ PlatformWheelEvent::PlatformWheelEvent(NSEvent* event, NSView *windowView) , m_altKey([event modifierFlags] & NSAlternateKeyMask) , m_metaKey([event modifierFlags] & NSCommandKeyMask) , m_phase(phaseForEvent(event)) + , m_timestamp([event timestamp]) { BOOL continuous; @@ -71,11 +72,13 @@ PlatformWheelEvent::PlatformWheelEvent(NSEvent* event, NSView *windowView) if (continuous) { m_wheelTicksX = m_deltaX / static_cast<float>(Scrollbar::pixelsPerLineStep()); m_wheelTicksY = m_deltaY / static_cast<float>(Scrollbar::pixelsPerLineStep()); + m_hasPreciseScrollingDeltas = true; } else { m_wheelTicksX = m_deltaX; m_wheelTicksY = m_deltaY; m_deltaX *= static_cast<float>(Scrollbar::pixelsPerLineStep()); m_deltaY *= static_cast<float>(Scrollbar::pixelsPerLineStep()); + m_hasPreciseScrollingDeltas = false; } } diff --git a/Source/WebCore/platform/mac/WidgetMac.mm b/Source/WebCore/platform/mac/WidgetMac.mm index f3c951a..96bcde2 100644 --- a/Source/WebCore/platform/mac/WidgetMac.mm +++ b/Source/WebCore/platform/mac/WidgetMac.mm @@ -252,7 +252,7 @@ void Widget::paint(GraphicsContext* p, const IntRect& r) IntRect dirtyRect = r; dirtyRect.move(-transformOrigin.x(), -transformOrigin.y()); if (![view isFlipped]) - dirtyRect.setY([view bounds].size.height - dirtyRect.bottom()); + dirtyRect.setY([view bounds].size.height - dirtyRect.maxY()); [view displayRectIgnoringOpacity:dirtyRect]; @@ -296,7 +296,7 @@ void Widget::paint(GraphicsContext* p, const IntRect& r) IntRect dirtyRect = r; dirtyRect.move(-transformOrigin.x(), -transformOrigin.y()); if (![view isFlipped]) - dirtyRect.setY([view bounds].size.height - dirtyRect.bottom()); + dirtyRect.setY([view bounds].size.height - dirtyRect.maxY()); BEGIN_BLOCK_OBJC_EXCEPTIONS; { |