diff options
author | Feng Qian <> | 2009-04-10 18:11:29 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-10 18:11:29 -0700 |
commit | 8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch) | |
tree | 181bf9a400c30a1bf34ea6d72560e8d00111d549 /WebCore/platform/graphics/mac | |
parent | 7ed56f225e0ade046e1c2178977f72b2d896f196 (diff) | |
download | external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2 |
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'WebCore/platform/graphics/mac')
19 files changed, 2462 insertions, 160 deletions
diff --git a/WebCore/platform/graphics/mac/ColorMac.mm b/WebCore/platform/graphics/mac/ColorMac.mm index 9b0f770..1c4350c 100644 --- a/WebCore/platform/graphics/mac/ColorMac.mm +++ b/WebCore/platform/graphics/mac/ColorMac.mm @@ -27,6 +27,7 @@ #import "Color.h" #import "ColorMac.h" +#import <AppKit/AppKit.h> #import <wtf/Assertions.h> #import <wtf/StdLibExtras.h> #import <wtf/RetainPtr.h> @@ -110,7 +111,7 @@ static CGColorRef CGColorFromNSColor(NSColor* color) return cgColor; } -CGColorRef cgColor(const Color& c) +CGColorRef createCGColor(const Color& c) { // We could directly create a CGColor here, but that would // skip any RGB caching the nsColor method does. A direct diff --git a/WebCore/platform/graphics/mac/FontCacheMac.mm b/WebCore/platform/graphics/mac/FontCacheMac.mm index 26d84cc..2202459 100644 --- a/WebCore/platform/graphics/mac/FontCacheMac.mm +++ b/WebCore/platform/graphics/mac/FontCacheMac.mm @@ -35,7 +35,8 @@ #import "FontPlatformData.h" #import "WebCoreSystemInterface.h" #import "WebFontCache.h" -#include <wtf/StdLibExtras.h> +#import <AppKit/AppKit.h> +#import <wtf/StdLibExtras.h> #ifdef BUILDING_ON_TIGER typedef int NSInteger; @@ -191,13 +192,11 @@ FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontD actualTraits = [fontManager traitsOfFont:nsFont]; NSInteger actualWeight = [fontManager weightOfFont:nsFont]; - FontPlatformData* result = new FontPlatformData; + NSFont *platformFont = fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]; + bool syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight); + bool syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait); - // Use the correct font for print vs. screen. - result->setFont(fontDescription.usePrinterFont() ? [nsFont printerFont] : [nsFont screenFont]); - result->m_syntheticBold = isAppKitFontWeightBold(weight) && !isAppKitFontWeightBold(actualWeight); - result->m_syntheticOblique = (traits & NSFontItalicTrait) && !(actualTraits & NSFontItalicTrait); - return result; + return new FontPlatformData(platformFont, syntheticBold, syntheticOblique); } } // namespace WebCore diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp index 9aa4997..e40bbab 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.cpp @@ -29,7 +29,8 @@ namespace WebCore { FontCustomPlatformData::~FontCustomPlatformData() { - ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault); + if (m_atsContainer) + ATSFontDeactivate(m_atsContainer, NULL, kATSOptionFlagsDefault); CGFontRelease(m_cgFont); } @@ -42,8 +43,18 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) { ASSERT_ARG(buffer, buffer); - // Use ATS to activate the font. ATSFontContainerRef containerRef = 0; + ATSFontRef fontRef = 0; + +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + RetainPtr<CFDataRef> bufferData(AdoptCF, buffer->createCFData()); + RetainPtr<CGDataProviderRef> dataProvider(AdoptCF, CGDataProviderCreateWithCFData(bufferData.get())); + + CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider.get()); + if (!cgFontRef) + return 0; +#else + // Use ATS to activate the font. // The value "3" means that the font is private and can't be seen by anyone else. ATSFontActivateFromMemory((void*)buffer->data(), buffer->size(), 3, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &containerRef); @@ -58,7 +69,6 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) return 0; } - ATSFontRef fontRef = 0; ATSFontFindFromContainer(containerRef, kATSOptionFlagsDefault, 1, &fontRef, NULL); if (!fontRef) { ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); @@ -77,6 +87,7 @@ FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer) ATSFontDeactivate(containerRef, NULL, kATSOptionFlagsDefault); return 0; } +#endif // !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) return new FontCustomPlatformData(containerRef, fontRef, cgFontRef); } diff --git a/WebCore/platform/graphics/mac/FontCustomPlatformData.h b/WebCore/platform/graphics/mac/FontCustomPlatformData.h index 1e73ae0..2c1222f 100644 --- a/WebCore/platform/graphics/mac/FontCustomPlatformData.h +++ b/WebCore/platform/graphics/mac/FontCustomPlatformData.h @@ -22,6 +22,7 @@ #define FontCustomPlatformData_h #include "FontRenderingMode.h" +#include <CoreFoundation/CFBase.h> #include <wtf/Noncopyable.h> typedef struct CGFont* CGFontRef; diff --git a/WebCore/platform/graphics/mac/FontMac.mm b/WebCore/platform/graphics/mac/FontMac.mm index bef18d0..dc86c4b 100644 --- a/WebCore/platform/graphics/mac/FontMac.mm +++ b/WebCore/platform/graphics/mac/FontMac.mm @@ -29,6 +29,7 @@ #import "SimpleFontData.h" #import "WebCoreSystemInterface.h" #import "WebCoreTextRenderer.h" +#import <AppKit/AppKit.h> #define SYNTHETIC_OBLIQUE_ANGLE 14 diff --git a/WebCore/platform/graphics/mac/FontMacATSUI.mm b/WebCore/platform/graphics/mac/FontMacATSUI.mm index 52493e7..3794149 100644 --- a/WebCore/platform/graphics/mac/FontMacATSUI.mm +++ b/WebCore/platform/graphics/mac/FontMacATSUI.mm @@ -30,6 +30,7 @@ #import "Logging.h" #import "ShapeArabic.h" #import "SimpleFontData.h" +#import <AppKit/NSGraphicsContext.h> #import <wtf/OwnArrayPtr.h> #define SYNTHETIC_OBLIQUE_ANGLE 14 diff --git a/WebCore/platform/graphics/mac/FontPlatformData.h b/WebCore/platform/graphics/mac/FontPlatformData.h index 40a2dbd..e911867 100644 --- a/WebCore/platform/graphics/mac/FontPlatformData.h +++ b/WebCore/platform/graphics/mac/FontPlatformData.h @@ -1,8 +1,8 @@ /* * This file is part of the internal font implementation. - * It should not be included by source files outside it. + * It should not be included by source files outside of it. * - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -33,7 +33,6 @@ class NSFont; #endif typedef struct CGFont* CGFontRef; -typedef UInt32 ATSUFontID; #ifndef BUILDING_ON_TIGER typedef const struct __CTFont* CTFontRef; #endif @@ -42,6 +41,8 @@ typedef const struct __CTFont* CTFontRef; #include <objc/objc-auto.h> #include <wtf/RetainPtr.h> +typedef UInt32 ATSUFontID; + namespace WebCore { #ifndef BUILDING_ON_TIGER @@ -61,10 +62,15 @@ struct FontPlatformData { { } - FontPlatformData(NSFont * = 0, bool syntheticBold = false, bool syntheticOblique = false); + FontPlatformData(NSFont *nsFont, bool syntheticBold = false, bool syntheticOblique = false); - FontPlatformData(CGFontRef f, ATSUFontID fontID, float s, bool b , bool o) - : m_syntheticBold(b), m_syntheticOblique(o), m_atsuFontID(fontID), m_size(s), m_font(0), m_cgFont(f) + FontPlatformData(CGFontRef cgFont, ATSUFontID fontID, float size, bool syntheticBold, bool syntheticOblique) + : m_syntheticBold(syntheticBold) + , m_syntheticOblique(syntheticOblique) + , m_atsuFontID(fontID) + , m_size(size) + , m_font(0) + , m_cgFont(cgFont) { } diff --git a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm index 7cd9ab6..83da4a9 100644 --- a/WebCore/platform/graphics/mac/FontPlatformDataMac.mm +++ b/WebCore/platform/graphics/mac/FontPlatformDataMac.mm @@ -1,7 +1,7 @@ /* * This file is part of the internal font implementation. * - * Copyright (C) 2006-7 Apple Computer, Inc. + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,21 +24,24 @@ #import "FontPlatformData.h" #import "WebCoreSystemInterface.h" +#import <AppKit/NSFont.h> namespace WebCore { -FontPlatformData::FontPlatformData(NSFont *f, bool b , bool o) -: m_syntheticBold(b), m_syntheticOblique(o), m_font(f) +FontPlatformData::FontPlatformData(NSFont *nsFont, bool syntheticBold, bool syntheticOblique) + : m_syntheticBold(syntheticBold) + , m_syntheticOblique(syntheticOblique) + , m_font(nsFont) { - if (f) - CFRetain(f); - m_size = f ? [f pointSize] : 0.0f; + if (nsFont) + CFRetain(nsFont); + m_size = nsFont ? [nsFont pointSize] : 0.0f; #ifndef BUILDING_ON_TIGER - m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(f), 0)); - m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(f), 0); + m_cgFont.adoptCF(CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0)); + m_atsuFontID = CTFontGetPlatformFont(toCTFontRef(nsFont), 0); #else - m_cgFont = wkGetCGFontFromNSFont(f); - m_atsuFontID = wkGetNSFontATSUFontId(f); + m_cgFont = wkGetCGFontFromNSFont(nsFont); + m_atsuFontID = wkGetNSFontATSUFontId(nsFont); #endif } diff --git a/WebCore/platform/graphics/mac/GraphicsContextMac.mm b/WebCore/platform/graphics/mac/GraphicsContextMac.mm index ae829e2..4e11602 100644 --- a/WebCore/platform/graphics/mac/GraphicsContextMac.mm +++ b/WebCore/platform/graphics/mac/GraphicsContextMac.mm @@ -27,10 +27,13 @@ #import "GraphicsContext.h" #import "../cg/GraphicsContextPlatformPrivateCG.h" +#import <AppKit/AppKit.h> #import <wtf/StdLibExtras.h> #import "WebCoreSystemInterface.h" +@class NSColor; + // FIXME: More of this should use CoreGraphics instead of AppKit. // FIXME: More of this should move into GraphicsContextCG.cpp. @@ -47,7 +50,7 @@ void GraphicsContext::drawFocusRing(const Color& color) int radius = (focusRingWidth() - 1) / 2; int offset = radius + focusRingOffset(); - CGColorRef colorRef = color.isValid() ? cgColor(color) : 0; + CGColorRef colorRef = color.isValid() ? createCGColor(color) : 0; CGMutablePathRef focusRingPath = CGPathCreateMutable(); const Vector<IntRect>& rects = focusRingRects(); diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h new file mode 100644 index 0000000..3a692d3 --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef GraphicsLayerCA_h +#define GraphicsLayerCA_h + +#if USE(ACCELERATED_COMPOSITING) + +#include "GraphicsLayer.h" +#include <wtf/RetainPtr.h> + +@class WebAnimationDelegate; +@class WebLayer; + +namespace WebCore { + +class GraphicsLayerCA : public GraphicsLayer { +public: + + GraphicsLayerCA(GraphicsLayerClient*); + virtual ~GraphicsLayerCA(); + + virtual void setName(const String&); + + // for hosting this GraphicsLayer in a native layer hierarchy + virtual NativeLayer nativeLayer() const; + + virtual void addChild(GraphicsLayer*); + virtual void addChildAtIndex(GraphicsLayer*, int index); + virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling); + virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling); + virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild); + + virtual void removeFromParent(); + + virtual void setPosition(const FloatPoint&); + virtual void setAnchorPoint(const FloatPoint3D&); + virtual void setSize(const FloatSize&); + + virtual void setTransform(const TransformationMatrix&); + + virtual void setChildrenTransform(const TransformationMatrix&); + + virtual void setPreserves3D(bool); + virtual void setMasksToBounds(bool); + virtual void setDrawsContent(bool); + + virtual void setBackgroundColor(const Color&, const Animation* anim = 0, double beginTime = 0); + virtual void clearBackgroundColor(); + + virtual void setContentsOpaque(bool); + virtual void setBackfaceVisibility(bool); + + // return true if we started an animation + virtual bool setOpacity(float, const Animation* anim = 0, double beginTime = 0); + + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + + virtual void suspendAnimations(); + virtual void resumeAnimations(); + + virtual bool animateTransform(const TransformValueList&, const IntSize&, const Animation*, double beginTime, bool isTransition); + virtual bool animateFloat(AnimatedPropertyID, const FloatValueList&, const Animation*, double beginTime); + + virtual void setContentsToImage(Image*); + virtual void setContentsToVideo(PlatformLayer*); + virtual void clearContents(); + + virtual void updateContentsRect(); + + virtual PlatformLayer* platformLayer() const; + +#ifndef NDEBUG + virtual void setDebugBackgroundColor(const Color&); + virtual void setDebugBorder(const Color&, float borderWidth); + virtual void setZPosition(float); +#endif + +private: + WebLayer* primaryLayer() const { return m_transformLayer.get() ? m_transformLayer.get() : m_layer.get(); } + WebLayer* hostLayerForSublayers() const; + WebLayer* layerForSuperlayer() const; + + WebLayer* animatedLayer(AnimatedPropertyID property) const + { + return (property == AnimatedPropertyBackgroundColor) ? m_contentsLayer.get() : primaryLayer(); + } + + void setBasicAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation*, double time); + void setKeyframeAnimation(AnimatedPropertyID, TransformOperation::OperationType, short index, void* keys, void* values, void* timingFunctions, bool isTransition, const Animation*, double time); + + virtual void removeAnimation(int index, bool reset); + + bool requiresTiledLayer(const FloatSize&) const; + void swapFromOrToTiledLayer(bool useTiledLayer); + + void setHasContentsLayer(bool); + void setContentsLayer(WebLayer*); + void setContentsLayerFlipped(bool); + + RetainPtr<WebLayer> m_layer; + RetainPtr<WebLayer> m_transformLayer; + RetainPtr<WebLayer> m_contentsLayer; + + RetainPtr<WebAnimationDelegate> m_animationDelegate; + + bool m_contentLayerForImageOrVideo; +}; + +} // namespace WebCore + + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // GraphicsLayerCA_h diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm new file mode 100644 index 0000000..f3f2d7f --- /dev/null +++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm @@ -0,0 +1,1540 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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 "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#import "GraphicsLayerCA.h" + +#import "Animation.h" +#import "BlockExceptions.h" +#import "CString.h" +#import "FloatConversion.h" +#import "FloatRect.h" +#import "Image.h" +#import "PlatformString.h" +#import <QuartzCore/QuartzCore.h> +#import "RotateTransformOperation.h" +#import "ScaleTransformOperation.h" +#import "SystemTime.h" +#import "TranslateTransformOperation.h" +#import "WebLayer.h" +#import "WebTiledLayer.h" +#import <wtf/CurrentTime.h> +#import <wtf/UnusedParam.h> + +using namespace std; + +#define HAVE_MODERN_QUARTZCORE (!defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)) + +namespace WebCore { + +// The threshold width or height above which a tiled layer will be used. This should be +// large enough to avoid tiled layers for most GraphicsLayers, but less than the OpenGL +// texture size limit on all supported hardware. +static const int cMaxPixelDimension = 2000; + +// The width and height of a single tile in a tiled layer. Should be large enough to +// avoid lots of small tiles (and therefore lots of drawing callbacks), but small enough +// to keep the overall tile cost low. +static const int cTiledLayerTileSize = 512; + +// If we send a duration of 0 to CA, then it will use the default duration +// of 250ms. So send a very small value instead. +static const float cAnimationAlmostZeroDuration = 1e-3f; + +// CACurrentMediaTime() is a time since boot. These methods convert between that and +// WebCore time, which is system time (UTC). +static CFTimeInterval currentTimeToMediaTime(double t) +{ + return CACurrentMediaTime() + t - WTF::currentTime(); +} + +static double mediaTimeToCurrentTime(CFTimeInterval t) +{ + return WTF::currentTime() + t - CACurrentMediaTime(); +} + +} // namespace WebCore + +static NSString* const WebAnimationCSSPropertyKey = @"GraphicsLayerCA_property"; + +@interface WebAnimationDelegate : NSObject { + WebCore::GraphicsLayerCA* m_graphicsLayer; +} + +- (void)animationDidStart:(CAAnimation *)anim; +- (WebCore::GraphicsLayerCA*)graphicsLayer; +- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer; + +@end + +@implementation WebAnimationDelegate + +- (void)animationDidStart:(CAAnimation *)animation +{ + if (!m_graphicsLayer) + return; + + double startTime = WebCore::mediaTimeToCurrentTime([animation beginTime]); + m_graphicsLayer->client()->notifyAnimationStarted(m_graphicsLayer, startTime); +} + +- (WebCore::GraphicsLayerCA*)graphicsLayer +{ + return m_graphicsLayer; +} + +- (void)setLayer:(WebCore::GraphicsLayerCA*)graphicsLayer +{ + m_graphicsLayer = graphicsLayer; +} + +@end + +namespace WebCore { + +static inline void copyTransform(CATransform3D& toT3D, const TransformationMatrix& t) +{ + toT3D.m11 = narrowPrecisionToFloat(t.m11()); + toT3D.m12 = narrowPrecisionToFloat(t.m12()); + toT3D.m13 = narrowPrecisionToFloat(t.m13()); + toT3D.m14 = narrowPrecisionToFloat(t.m14()); + toT3D.m21 = narrowPrecisionToFloat(t.m21()); + toT3D.m22 = narrowPrecisionToFloat(t.m22()); + toT3D.m23 = narrowPrecisionToFloat(t.m23()); + toT3D.m24 = narrowPrecisionToFloat(t.m24()); + toT3D.m31 = narrowPrecisionToFloat(t.m31()); + toT3D.m32 = narrowPrecisionToFloat(t.m32()); + toT3D.m33 = narrowPrecisionToFloat(t.m33()); + toT3D.m34 = narrowPrecisionToFloat(t.m34()); + toT3D.m41 = narrowPrecisionToFloat(t.m41()); + toT3D.m42 = narrowPrecisionToFloat(t.m42()); + toT3D.m43 = narrowPrecisionToFloat(t.m43()); + toT3D.m44 = narrowPrecisionToFloat(t.m44()); +} + +static NSValue* getTransformFunctionValue(const GraphicsLayer::TransformValue& transformValue, size_t index, const IntSize& size, TransformOperation::OperationType transformType) +{ + TransformOperation* op = (index >= transformValue.value()->operations().size()) ? 0 : transformValue.value()->operations()[index].get(); + + switch (transformType) { + case TransformOperation::ROTATE: + case TransformOperation::ROTATE_X: + case TransformOperation::ROTATE_Y: + return [NSNumber numberWithDouble:op ? deg2rad(static_cast<RotateTransformOperation*>(op)->angle()) : 0]; + case TransformOperation::SCALE_X: + return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->x() : 0]; + case TransformOperation::SCALE_Y: + return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->y() : 0]; + case TransformOperation::SCALE_Z: + return [NSNumber numberWithDouble:op ? static_cast<ScaleTransformOperation*>(op)->z() : 0]; + case TransformOperation::TRANSLATE_X: + return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->x(size) : 0]; + case TransformOperation::TRANSLATE_Y: + return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->y(size) : 0]; + case TransformOperation::TRANSLATE_Z: + return [NSNumber numberWithDouble:op ? static_cast<TranslateTransformOperation*>(op)->z(size) : 0]; + case TransformOperation::SCALE: + case TransformOperation::TRANSLATE: + case TransformOperation::SKEW_X: + case TransformOperation::SKEW_Y: + case TransformOperation::SKEW: + case TransformOperation::MATRIX: + case TransformOperation::SCALE_3D: + case TransformOperation::TRANSLATE_3D: + case TransformOperation::ROTATE_3D: + case TransformOperation::MATRIX_3D: + case TransformOperation::PERSPECTIVE: + case TransformOperation::IDENTITY: + case TransformOperation::NONE: { + TransformationMatrix t; + if (op) + op->apply(t, size); + CATransform3D cat; + copyTransform(cat, t); + return [NSValue valueWithCATransform3D:cat]; + } + } + + return 0; +} + +#if HAVE_MODERN_QUARTZCORE +static NSString* getValueFunctionNameForTransformOperation(TransformOperation::OperationType transformType) +{ + // Use literal strings to avoid link-time dependency on those symbols. + switch (transformType) { + case TransformOperation::ROTATE_X: + return @"rotateX"; // kCAValueFunctionRotateX; + case TransformOperation::ROTATE_Y: + return @"rotateY"; // kCAValueFunctionRotateY; + case TransformOperation::ROTATE: + return @"rotateZ"; // kCAValueFunctionRotateZ; + case TransformOperation::SCALE_X: + return @"scaleX"; // kCAValueFunctionScaleX; + case TransformOperation::SCALE_Y: + return @"scaleY"; // kCAValueFunctionScaleY; + case TransformOperation::SCALE_Z: + return @"scaleZ"; // kCAValueFunctionScaleZ; + case TransformOperation::TRANSLATE_X: + return @"translateX"; // kCAValueFunctionTranslateX; + case TransformOperation::TRANSLATE_Y: + return @"translateY"; // kCAValueFunctionTranslateY; + case TransformOperation::TRANSLATE_Z: + return @"translateZ"; // kCAValueFunctionTranslateZ; + default: + return nil; + } +} +#endif + +static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& timingFunction) +{ + switch (timingFunction.type()) { + case LinearTimingFunction: + return [CAMediaTimingFunction functionWithName:@"linear"]; + case CubicBezierTimingFunction: + return [CAMediaTimingFunction functionWithControlPoints:static_cast<float>(timingFunction.x1()) :static_cast<float>(timingFunction.y1()) + :static_cast<float>(timingFunction.x2()) :static_cast<float>(timingFunction.y2())]; + } + return 0; +} + +#ifndef NDEBUG +static void setLayerBorderColor(PlatformLayer* layer, const Color& color) +{ + CGColorRef borderColor = createCGColor(color); + [layer setBorderColor:borderColor]; + CGColorRelease(borderColor); +} + +static void clearBorderColor(PlatformLayer* layer) +{ + [layer setBorderColor:nil]; +} +#endif + +static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color) +{ + CGColorRef bgColor = createCGColor(color); + [layer setBackgroundColor:bgColor]; + CGColorRelease(bgColor); +} + +static void clearLayerBackgroundColor(PlatformLayer* layer) +{ + [layer setBackgroundColor:0]; +} + +static CALayer* getPresentationLayer(CALayer* layer) +{ + CALayer* presLayer = [layer presentationLayer]; + if (!presLayer) + presLayer = layer; + + return presLayer; +} + +static bool caValueFunctionSupported() +{ + static bool sHaveValueFunction = [CAPropertyAnimation instancesRespondToSelector:@selector(setValueFunction:)]; + return sHaveValueFunction; +} + +static bool forceSoftwareAnimation() +{ + static bool forceSoftwareAnimation = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreForceSoftwareAnimation"]; + return forceSoftwareAnimation; +} + +bool GraphicsLayer::graphicsContextsFlipped() +{ + return true; +} + +#ifndef NDEBUG +bool GraphicsLayer::showDebugBorders() +{ + static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"]; + return showDebugBorders; +} + +bool GraphicsLayer::showRepaintCounter() +{ + static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"]; + return showRepaintCounter; +} +#endif + +static NSDictionary* nullActionsDictionary() +{ + NSNull* nullValue = [NSNull null]; + NSDictionary* actions = [NSDictionary dictionaryWithObjectsAndKeys: + nullValue, @"anchorPoint", + nullValue, @"bounds", + nullValue, @"contents", + nullValue, @"contentsRect", + nullValue, @"opacity", + nullValue, @"position", + nullValue, @"shadowColor", + nullValue, @"sublayerTransform", + nullValue, @"sublayers", + nullValue, @"transform", +#ifndef NDEBUG + nullValue, @"zPosition", +#endif + nil]; + return actions; +} + +GraphicsLayer* GraphicsLayer::createGraphicsLayer(GraphicsLayerClient* client) +{ + return new GraphicsLayerCA(client); +} + +GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client) +: GraphicsLayer(client) +, m_contentLayerForImageOrVideo(false) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + m_layer.adoptNS([[WebLayer alloc] init]); + [m_layer.get() setLayerOwner:this]; + +#ifndef NDEBUG + updateDebugIndicators(); +#endif + + m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]); + [m_animationDelegate.get() setLayer:this]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +GraphicsLayerCA::~GraphicsLayerCA() +{ + // Remove a inner layer if there is one. + clearContents(); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // Clean up the WK layer. + if (m_layer) { + WebLayer* layer = m_layer.get(); + [layer setLayerOwner:nil]; + [layer removeFromSuperlayer]; + } + + if (m_transformLayer) + [m_transformLayer.get() removeFromSuperlayer]; + + // animationDidStart: can fire after this, so we need to clear out the layer on the delegate. + [m_animationDelegate.get() setLayer:0]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setName(const String& name) +{ + String longName = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + name; + GraphicsLayer::setName(longName); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setName:name]; + END_BLOCK_OBJC_EXCEPTIONS +} + +NativeLayer GraphicsLayerCA::nativeLayer() const +{ + return m_layer.get(); +} + +void GraphicsLayerCA::addChild(GraphicsLayer* childLayer) +{ + GraphicsLayer::addChild(childLayer); + + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer); + BEGIN_BLOCK_OBJC_EXCEPTIONS + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::addChildAtIndex(GraphicsLayer* childLayer, int index) +{ + GraphicsLayer::addChildAtIndex(childLayer, index); + + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer); + BEGIN_BLOCK_OBJC_EXCEPTIONS + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() atIndex:index]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::addChildBelow(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + // FIXME: share code with base class + ASSERT(childLayer != this); + childLayer->removeFromParent(); + + bool found = false; + for (unsigned i = 0; i < m_children.size(); i++) { + if (sibling == m_children[i]) { + m_children.insert(i, childLayer); + found = true; + break; + } + } + childLayer->setParent(this); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer); + GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling); + if (found) + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() below:siblingLayerCA->layerForSuperlayer()]; + else { + m_children.append(childLayer); + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()]; + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::addChildAbove(GraphicsLayer* childLayer, GraphicsLayer* sibling) +{ + // FIXME: share code with base class + ASSERT(childLayer != this); + childLayer->removeFromParent(); + + unsigned i; + bool found = false; + for (i = 0; i < m_children.size(); i++) { + if (sibling == m_children[i]) { + m_children.insert(i+1, childLayer); + found = true; + break; + } + } + childLayer->setParent(this); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + GraphicsLayerCA* childLayerCA = static_cast<GraphicsLayerCA*>(childLayer); + GraphicsLayerCA* siblingLayerCA = static_cast<GraphicsLayerCA*>(sibling); + if (found) { + [hostLayerForSublayers() insertSublayer:childLayerCA->layerForSuperlayer() above:siblingLayerCA->layerForSuperlayer()]; + } else { + m_children.append(childLayer); + [hostLayerForSublayers() addSublayer:childLayerCA->layerForSuperlayer()]; + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +bool GraphicsLayerCA::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + // FIXME: share code with base class + ASSERT(!newChild->parent()); + + bool found = false; + for (unsigned i = 0; i < m_children.size(); i++) { + if (oldChild == m_children[i]) { + m_children[i] = newChild; + found = true; + break; + } + } + + if (found) { + oldChild->setParent(0); + + newChild->removeFromParent(); + newChild->setParent(this); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + GraphicsLayerCA* oldChildCA = static_cast<GraphicsLayerCA*>(oldChild); + GraphicsLayerCA* newChildCA = static_cast<GraphicsLayerCA*>(newChild); + [hostLayerForSublayers() replaceSublayer:oldChildCA->layerForSuperlayer() with:newChildCA->layerForSuperlayer()]; + END_BLOCK_OBJC_EXCEPTIONS + return true; + } + return false; +} + +void GraphicsLayerCA::removeFromParent() +{ + GraphicsLayer::removeFromParent(); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [layerForSuperlayer() removeFromSuperlayer]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setPosition(const FloatPoint& point) +{ + // Don't short-circuit here, because position and anchor point are inter-dependent. + GraphicsLayer::setPosition(point); + + // Position is offset on the layer by the layer anchor point. + CGPoint posPoint = CGPointMake(m_position.x() + m_anchorPoint.x() * m_size.width(), + m_position.y() + m_anchorPoint.y() * m_size.height()); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [primaryLayer() setPosition:posPoint]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setAnchorPoint(const FloatPoint3D& point) +{ + // Don't short-circuit here, because position and anchor point are inter-dependent. + bool zChanged = (point.z() != m_anchorPoint.z()); + GraphicsLayer::setAnchorPoint(point); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + // set the value on the layer to the new transform. + [primaryLayer() setAnchorPoint:FloatPoint(point.x(), point.y())]; + + if (zChanged) { +#if HAVE_MODERN_QUARTZCORE + [primaryLayer() setAnchorPointZ:m_anchorPoint.z()]; +#endif + } + + // Position depends on anchor point, so update it now. + setPosition(m_position); + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setSize(const FloatSize& size) +{ + GraphicsLayer::setSize(size); + + CGRect rect = CGRectMake(0.0f, + 0.0f, + m_size.width(), + m_size.height()); + + CGPoint centerPoint = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (m_transformLayer) { + [m_transformLayer.get() setBounds:rect]; + + // the anchor of the contents layer is always at 0.5, 0.5, so the position + // is center-relative + [m_layer.get() setPosition:centerPoint]; + } + + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + + [m_layer.get() setBounds:rect]; + + // Note that we don't resize m_contentsLayer. It's up the caller to do that. + + END_BLOCK_OBJC_EXCEPTIONS + + // if we've changed the bounds, we need to recalculate the position + // of the layer, taking anchor point into account + setPosition(m_position); +} + +void GraphicsLayerCA::setTransform(const TransformationMatrix& t) +{ + GraphicsLayer::setTransform(t); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + CATransform3D transform; + copyTransform(transform, t); + [primaryLayer() setTransform:transform]; + END_BLOCK_OBJC_EXCEPTIONS + + // Remove any old transition entries for transform. + removeAllAnimationsForProperty(AnimatedPropertyWebkitTransform); + + // Even if we don't have a transition in the list, the layer may still have one. + // This happens when we are setting the final transform value after an animation or + // transition has ended. In removeAnimation we toss the entry from the list but don't + // remove it from the list. That way we aren't in danger of displaying a stale transform + // in the time between removing the animation and setting the new unanimated value. We + // can't do this in removeAnimation because we don't know the new transform value there. + String keyPath = propertyIdToString(AnimatedPropertyWebkitTransform); + CALayer* layer = animatedLayer(AnimatedPropertyWebkitTransform); + + for (int i = 0; ; ++i) { + String animName = keyPath + "_" + String::number(i); + if (![layer animationForKey: animName]) + break; + [layer removeAnimationForKey:animName]; + } +} + +void GraphicsLayerCA::setChildrenTransform(const TransformationMatrix& t) +{ + if (t == m_childrenTransform) + return; + + GraphicsLayer::setChildrenTransform(t); + + CATransform3D transform; + copyTransform(transform, t); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + // Set the value on the layer to the new transform. + [primaryLayer() setSublayerTransform:transform]; + END_BLOCK_OBJC_EXCEPTIONS +} + +static void moveAnimation(AnimatedPropertyID property, CALayer* fromLayer, CALayer* toLayer) +{ + String keyPath = GraphicsLayer::propertyIdToString(property); + for (short index = 0; ; ++index) { + String animName = keyPath + "_" + String::number(index); + CAAnimation* anim = [fromLayer animationForKey:animName]; + if (!anim) + break; + + [anim retain]; + [fromLayer removeAnimationForKey:animName]; + [toLayer addAnimation:anim forKey:animName]; + [anim release]; + } +} + +static void moveSublayers(CALayer* fromLayer, CALayer* toLayer) +{ + NSArray* sublayersCopy = [[fromLayer sublayers] copy]; // Avoid mutation while enumerating, and keep the sublayers alive. + NSEnumerator* childrenEnumerator = [sublayersCopy objectEnumerator]; + + CALayer* layer; + while ((layer = [childrenEnumerator nextObject]) != nil) { + [layer removeFromSuperlayer]; + [toLayer addSublayer:layer]; + } + [sublayersCopy release]; +} + +void GraphicsLayerCA::setPreserves3D(bool preserves3D) +{ + GraphicsLayer::setPreserves3D(preserves3D); + + CGPoint point = CGPointMake(m_size.width() / 2.0f, m_size.height() / 2.0f); + CGPoint centerPoint = CGPointMake(0.5f, 0.5f); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + Class transformLayerClass = NSClassFromString(@"CATransformLayer"); + if (preserves3D && !m_transformLayer && transformLayerClass) { + // Create the transform layer. + m_transformLayer.adoptNS([[transformLayerClass alloc] init]); + + // Turn off default animations. + [m_transformLayer.get() setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + +#ifndef NDEBUG + [m_transformLayer.get() setName:[NSString stringWithFormat:@"Transform Layer CATransformLayer(%p) GraphicsLayer(%p)", m_transformLayer.get(), this]]; +#endif + // Copy the position from this layer. + [m_transformLayer.get() setBounds:[m_layer.get() bounds]]; + [m_transformLayer.get() setPosition:[m_layer.get() position]]; + [m_transformLayer.get() setAnchorPoint:[m_layer.get() anchorPoint]]; +#if HAVE_MODERN_QUARTZCORE + [m_transformLayer.get() setAnchorPointZ:[m_layer.get() anchorPointZ]]; +#endif + [m_transformLayer.get() setContentsRect:[m_layer.get() contentsRect]]; +#ifndef NDEBUG + [m_transformLayer.get() setZPosition:[m_layer.get() zPosition]]; +#endif + + // The contents layer is positioned at (0,0) relative to the transformLayer. + [m_layer.get() setPosition:point]; + [m_layer.get() setAnchorPoint:centerPoint]; +#ifndef NDEBUG + [m_layer.get() setZPosition:0.0f]; +#endif + + // Transfer the transform over. + [m_transformLayer.get() setTransform:[m_layer.get() transform]]; + [m_layer.get() setTransform:CATransform3DIdentity]; + + // Transfer the opacity from the old layer to the transform layer. + [m_transformLayer.get() setOpacity:m_opacity]; + [m_layer.get() setOpacity:1]; + + // Move this layer to be a child of the transform layer. + [[m_layer.get() superlayer] replaceSublayer:m_layer.get() with:m_transformLayer.get()]; + [m_transformLayer.get() addSublayer:m_layer.get()]; + + moveAnimation(AnimatedPropertyWebkitTransform, m_layer.get(), m_transformLayer.get()); + moveSublayers(m_layer.get(), m_transformLayer.get()); + + } else if (!preserves3D && m_transformLayer) { + // Relace the transformLayer in the parent with this layer. + [m_layer.get() removeFromSuperlayer]; + [[m_transformLayer.get() superlayer] replaceSublayer:m_transformLayer.get() with:m_layer.get()]; + + moveAnimation(AnimatedPropertyWebkitTransform, m_transformLayer.get(), m_layer.get()); + moveSublayers(m_transformLayer.get(), m_layer.get()); + + // Reset the layer position and transform. + [m_layer.get() setPosition:[m_transformLayer.get() position]]; + [m_layer.get() setAnchorPoint:[m_transformLayer.get() anchorPoint]]; +#if HAVE_MODERN_QUARTZCORE + [m_layer.get() setAnchorPointZ:[m_transformLayer.get() anchorPointZ]]; +#endif + [m_layer.get() setContentsRect:[m_transformLayer.get() contentsRect]]; + [m_layer.get() setTransform:[m_transformLayer.get() transform]]; + [m_layer.get() setOpacity:[m_transformLayer.get() opacity]]; +#ifndef NDEBUG + [m_layer.get() setZPosition:[m_transformLayer.get() zPosition]]; +#endif + + // Release the transform layer. + m_transformLayer = 0; + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setMasksToBounds(bool masksToBounds) +{ + if (masksToBounds == m_masksToBounds) + return; + + GraphicsLayer::setMasksToBounds(masksToBounds); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setMasksToBounds:masksToBounds]; + END_BLOCK_OBJC_EXCEPTIONS + +#ifndef NDEBUG + updateDebugIndicators(); +#endif +} + +void GraphicsLayerCA::setDrawsContent(bool drawsContent) +{ + if (drawsContent != m_drawsContent) { + GraphicsLayer::setDrawsContent(drawsContent); + + bool needTiledLayer = requiresTiledLayer(m_size); + if (needTiledLayer != m_usingTiledLayer) + swapFromOrToTiledLayer(needTiledLayer); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + // Clobber any existing content. If necessary, CA will create backing store on the next display. + [m_layer.get() setContents:nil]; + +#ifndef NDEBUG + updateDebugIndicators(); +#endif + END_BLOCK_OBJC_EXCEPTIONS + } +} + +void GraphicsLayerCA::setBackgroundColor(const Color& color, const Animation* transition, double beginTime) +{ + GraphicsLayer::setBackgroundColor(color, transition, beginTime); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + setHasContentsLayer(true); + + if (transition && !transition->isEmptyOrZeroDuration()) { + CALayer* presLayer = [m_contentsLayer.get() presentationLayer]; + // If we don't have a presentationLayer, just use the CALayer + if (!presLayer) + presLayer = m_contentsLayer.get(); + + // Get the current value of the background color from the layer + CGColorRef fromBackgroundColor = [presLayer backgroundColor]; + + CGColorRef bgColor = createCGColor(color); + setBasicAnimation(AnimatedPropertyBackgroundColor, TransformOperation::NONE, 0, fromBackgroundColor, bgColor, true, transition, beginTime); + CGColorRelease(bgColor); + } else { + removeAllAnimationsForProperty(AnimatedPropertyBackgroundColor); + setHasContentsLayer(true); + setLayerBackgroundColor(m_contentsLayer.get(), m_backgroundColor); + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::clearBackgroundColor() +{ + if (!m_contentLayerForImageOrVideo) + setHasContentsLayer(false); + else + clearLayerBackgroundColor(m_contentsLayer.get()); +} + +void GraphicsLayerCA::setContentsOpaque(bool opaque) +{ + GraphicsLayer::setContentsOpaque(opaque); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setOpaque:m_contentsOpaque]; + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setBackfaceVisibility(bool visible) +{ + if (m_backfaceVisibility == visible) + return; + + GraphicsLayer::setBackfaceVisibility(visible); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_layer.get() setDoubleSided:visible]; + END_BLOCK_OBJC_EXCEPTIONS +} + +bool GraphicsLayerCA::setOpacity(float opacity, const Animation* transition, double beginTime) +{ + if (forceSoftwareAnimation()) + return false; + + float clampedOpacity = max(0.0f, min(opacity, 1.0f)); + + bool opacitiesDiffer = (m_opacity != clampedOpacity); + + GraphicsLayer::setOpacity(clampedOpacity, transition, beginTime); + + int animIndex = findAnimationEntry(AnimatedPropertyOpacity, 0); + + // If we don't have a transition just set the opacity + if (!transition || transition->isEmptyOrZeroDuration()) { + // Three cases: + // 1) no existing animation or transition: just set opacity + // 2) existing transition: clear it and set opacity + // 3) existing animation: just return + // + if (animIndex < 0 || m_animations[animIndex].isTransition()) { + BEGIN_BLOCK_OBJC_EXCEPTIONS + [primaryLayer() setOpacity:opacity]; + if (animIndex >= 0) { + removeAllAnimationsForProperty(AnimatedPropertyOpacity); + animIndex = -1; + } else { + String keyPath = propertyIdToString(AnimatedPropertyOpacity); + + // FIXME: using hardcoded '0' here. We should be clearing all animations. For now there is only 1. + String animName = keyPath + "_0"; + [animatedLayer(AnimatedPropertyOpacity) removeAnimationForKey:animName]; + } + END_BLOCK_OBJC_EXCEPTIONS + } else { + // We have an animation, so don't set the opacity directly. + return false; + } + } else { + // At this point, we know we have a transition. But if it is the same and + // the opacity value has not changed, don't do anything. + if (!opacitiesDiffer && + ((animIndex == -1) || + (m_animations[animIndex].isTransition() && *(m_animations[animIndex].animation()) == *transition))) { + return false; + } + } + + // If an animation is running, ignore this transition, but still save the value. + if (animIndex >= 0 && !m_animations[animIndex].isTransition()) + return false; + + bool didAnimate = false; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + NSNumber* fromOpacityValue = nil; + NSNumber* toOpacityValue = [NSNumber numberWithFloat:opacity]; + + if (transition && !transition->isEmptyOrZeroDuration()) { + CALayer* presLayer = getPresentationLayer(primaryLayer()); + float fromOpacity = [presLayer opacity]; + fromOpacityValue = [NSNumber numberWithFloat:fromOpacity]; + setBasicAnimation(AnimatedPropertyOpacity, TransformOperation::NONE, 0, fromOpacityValue, toOpacityValue, true, transition, beginTime); + didAnimate = true; + } + + END_BLOCK_OBJC_EXCEPTIONS + + return didAnimate; +} + +void GraphicsLayerCA::setNeedsDisplay() +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (drawsContent()) + [m_layer.get() setNeedsDisplay]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setNeedsDisplayInRect(const FloatRect& rect) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (drawsContent()) + [m_layer.get() setNeedsDisplayInRect:rect]; + + END_BLOCK_OBJC_EXCEPTIONS +} + + +bool GraphicsLayerCA::animateTransform(const TransformValueList& valueList, const IntSize& size, const Animation* anim, double beginTime, bool isTransition) +{ + if (forceSoftwareAnimation() || !anim || anim->isEmptyOrZeroDuration() || valueList.size() < 2) + return false; + + TransformValueList::FunctionList functionList; + bool isValid, hasBigRotation; + valueList.makeFunctionList(functionList, isValid, hasBigRotation); + + // We need to fall back to software animation if we don't have setValueFunction:, and + // we would need to animate each incoming transform function separately. This is the + // case if we have a rotation >= 180 or we have more than one transform function. + if ((hasBigRotation || functionList.size() > 1) && !caValueFunctionSupported()) + return false; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // Rules for animation: + // + // 1) If functionList is empty or we don't have a big rotation, we do a matrix animation. We could + // use component animation for lists without a big rotation, but there is no need to, and this + // is more efficient. + // + // 2) Otherwise we do a component hardware animation. + bool isMatrixAnimation = !isValid || !hasBigRotation; + + // Set transform to identity since we are animating components and we need the base + // to be the identity transform. + TransformationMatrix t; + CATransform3D toT3D; + copyTransform(toT3D, t); + [primaryLayer() setTransform:toT3D]; + + bool isKeyframe = valueList.size() > 2; + + // Iterate through the transform functions, sending an animation for each one. + for (int functionIndex = 0; ; ++functionIndex) { + if (functionIndex >= static_cast<int>(functionList.size()) && !isMatrixAnimation) + break; + + TransformOperation::OperationType opType = isMatrixAnimation ? TransformOperation::MATRIX_3D : functionList[functionIndex]; + + if (isKeyframe) { + NSMutableArray* timesArray = [[NSMutableArray alloc] init]; + NSMutableArray* valArray = [[NSMutableArray alloc] init]; + NSMutableArray* tfArray = [[NSMutableArray alloc] init]; + + // Iterate through the keyframes, building arrays for the animation. + for (Vector<TransformValue>::const_iterator it = valueList.values().begin(); it != valueList.values().end(); ++it) { + const TransformValue& curValue = (*it); + + // fill in the key time and timing function + [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]]; + + const TimingFunction* tf = 0; + if (curValue.timingFunction()) + tf = curValue.timingFunction(); + else if (anim->isTimingFunctionSet()) + tf = &anim->timingFunction(); + + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction(LinearTimingFunction)); + [tfArray addObject:timingFunction]; + + // fill in the function + if (isMatrixAnimation) { + TransformationMatrix t; + curValue.value()->apply(size, t); + CATransform3D cat; + copyTransform(cat, t); + [valArray addObject:[NSValue valueWithCATransform3D:cat]]; + } else + [valArray addObject:getTransformFunctionValue(curValue, functionIndex, size, opType)]; + } + + // We toss the last tfArray value because it has to one shorter than the others. + [tfArray removeLastObject]; + + setKeyframeAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, timesArray, valArray, tfArray, isTransition, anim, beginTime); + + [timesArray release]; + [valArray release]; + [tfArray release]; + } else { + // Is a transition + id fromValue, toValue; + + if (isMatrixAnimation) { + TransformationMatrix fromt, tot; + valueList.at(0).value()->apply(size, fromt); + valueList.at(1).value()->apply(size, tot); + + CATransform3D cat; + copyTransform(cat, fromt); + fromValue = [NSValue valueWithCATransform3D:cat]; + copyTransform(cat, tot); + toValue = [NSValue valueWithCATransform3D:cat]; + } else { + fromValue = getTransformFunctionValue(valueList.at(0), functionIndex, size, opType); + toValue = getTransformFunctionValue(valueList.at(1), functionIndex, size, opType); + } + + setBasicAnimation(AnimatedPropertyWebkitTransform, opType, functionIndex, fromValue, toValue, isTransition, anim, beginTime); + } + + if (isMatrixAnimation) + break; + } + + END_BLOCK_OBJC_EXCEPTIONS + return true; +} + +bool GraphicsLayerCA::animateFloat(AnimatedPropertyID property, const FloatValueList& valueList, const Animation* animation, double beginTime) +{ + if (forceSoftwareAnimation() || valueList.size() < 2) + return false; + + // if there is already is an animation for this property and it hasn't changed, ignore it. + int i = findAnimationEntry(property, 0); + if (i >= 0 && *m_animations[i].animation() == *animation) { + m_animations[i].setIsCurrent(); + return false; + } + + if (valueList.size() == 2) { + float fromVal = valueList.at(0).value(); + float toVal = valueList.at(1).value(); + if (isnan(toVal) && isnan(fromVal)) + return false; + + // initialize the property to 0 + [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)]; + setBasicAnimation(property, TransformOperation::NONE, 0, isnan(fromVal) ? nil : [NSNumber numberWithFloat:fromVal], isnan(toVal) ? nil : [NSNumber numberWithFloat:toVal], false, animation, beginTime); + return true; + } + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + NSMutableArray* timesArray = [[NSMutableArray alloc] init]; + NSMutableArray* valArray = [[NSMutableArray alloc] init]; + NSMutableArray* tfArray = [[NSMutableArray alloc] init]; + + for (unsigned i = 0; i < valueList.values().size(); ++i) { + const FloatValue& curValue = valueList.values()[i]; + [timesArray addObject:[NSNumber numberWithFloat:curValue.key()]]; + [valArray addObject:[NSNumber numberWithFloat:curValue.value()]]; + + const TimingFunction* tf = 0; + if (curValue.timingFunction()) + tf = curValue.timingFunction(); + else if (animation->isTimingFunctionSet()) + tf = &animation->timingFunction(); + + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction()); + [tfArray addObject:timingFunction]; + } + + // We toss the last tfArray value because it has to one shorter than the others. + [tfArray removeLastObject]; + + // Initialize the property to 0. + [animatedLayer(property) setValue:0 forKeyPath:propertyIdToString(property)]; + // Then set the animation. + setKeyframeAnimation(property, TransformOperation::NONE, 0, timesArray, valArray, tfArray, false, animation, beginTime); + + [timesArray release]; + [valArray release]; + [tfArray release]; + + END_BLOCK_OBJC_EXCEPTIONS + return true; +} + +void GraphicsLayerCA::setContentsToImage(Image* image) +{ + if (image) { + setHasContentsLayer(true); + + // FIXME: is image flipping really a property of the graphics context? + bool needToFlip = GraphicsLayer::graphicsContextsFlipped(); + CGPoint anchorPoint = needToFlip ? CGPointMake(0.0f, 1.0f) : CGPointZero; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + { + CGImageRef theImage = image->nativeImageForCurrentFrame(); + // FIXME: maybe only do trilinear if the image is being scaled down, + // but then what if the layer size changes? +#if HAVE_MODERN_QUARTZCORE + [m_contentsLayer.get() setMinificationFilter:kCAFilterTrilinear]; +#endif + if (needToFlip) { + CATransform3D flipper = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + [m_contentsLayer.get() setTransform:flipper]; + } + + [m_contentsLayer.get() setAnchorPoint:anchorPoint]; + [m_contentsLayer.get() setContents:(id)theImage]; + } + END_BLOCK_OBJC_EXCEPTIONS + } else + setHasContentsLayer(false); + + m_contentLayerForImageOrVideo = (image != 0); +} + +void GraphicsLayerCA::setContentsToVideo(PlatformLayer* videoLayer) +{ + setContentsLayer(videoLayer); + m_contentLayerForImageOrVideo = (videoLayer != 0); +} + +void GraphicsLayerCA::clearContents() +{ + if (m_contentLayerForImageOrVideo) { + setHasContentsLayer(false); + m_contentLayerForImageOrVideo = false; + } +} + +void GraphicsLayerCA::updateContentsRect() +{ + if (m_client && m_contentsLayer) { + IntRect contentRect = m_client->contentsBox(this); + + CGPoint point = CGPointMake(contentRect.x(), + contentRect.y()); + CGRect rect = CGRectMake(0.0f, + 0.0f, + contentRect.width(), + contentRect.height()); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [m_contentsLayer.get() setPosition:point]; + [m_contentsLayer.get() setBounds:rect]; + END_BLOCK_OBJC_EXCEPTIONS + } +} + +void GraphicsLayerCA::setBasicAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* fromVal, void* toVal, bool isTransition, const Animation* transition, double beginTime) +{ + ASSERT(fromVal || toVal); + + WebLayer* layer = animatedLayer(property); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // add an entry for this animation + addAnimationEntry(property, index, isTransition, transition); + + String keyPath = propertyIdToString(property); + String animName = keyPath + "_" + String::number(index); + + CABasicAnimation* basicAnim = [CABasicAnimation animationWithKeyPath:keyPath]; + + double duration = transition->duration(); + if (duration <= 0) + duration = cAnimationAlmostZeroDuration; + + float repeatCount = transition->iterationCount(); + if (repeatCount == Animation::IterationCountInfinite) + repeatCount = FLT_MAX; + else if (transition->direction() == Animation::AnimationDirectionAlternate) + repeatCount /= 2; + + [basicAnim setDuration:duration]; + [basicAnim setRepeatCount:repeatCount]; + [basicAnim setAutoreverses:transition->direction()]; + [basicAnim setRemovedOnCompletion:NO]; + + // Note that currently transform is the only property which has animations + // with an index > 0. + [basicAnim setAdditive:property == AnimatedPropertyWebkitTransform]; + [basicAnim setFillMode:@"extended"]; +#if HAVE_MODERN_QUARTZCORE + if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType)) + [basicAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; +#else + UNUSED_PARAM(operationType); +#endif + + // Set the delegate (and property value). + int prop = isTransition ? property : AnimatedPropertyInvalid; + [basicAnim setValue:[NSNumber numberWithInt:prop] forKey:WebAnimationCSSPropertyKey]; + [basicAnim setDelegate:m_animationDelegate.get()]; + + NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0; + [basicAnim setBeginTime:bt]; + + if (fromVal) + [basicAnim setFromValue:reinterpret_cast<id>(fromVal)]; + if (toVal) + [basicAnim setToValue:reinterpret_cast<id>(toVal)]; + + const TimingFunction* tf = 0; + if (transition->isTimingFunctionSet()) + tf = &transition->timingFunction(); + + CAMediaTimingFunction* timingFunction = getCAMediaTimingFunction(tf ? *tf : TimingFunction()); + [basicAnim setTimingFunction:timingFunction]; + + // Send over the animation. + [layer removeAnimationForKey:animName]; + [layer addAnimation:basicAnim forKey:animName]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setKeyframeAnimation(AnimatedPropertyID property, TransformOperation::OperationType operationType, short index, void* keys, void* values, void* timingFunctions, + bool isTransition, const Animation* anim, double beginTime) +{ + PlatformLayer* layer = animatedLayer(property); + + // Add an entry for this animation (which may change beginTime). + addAnimationEntry(property, index, isTransition, anim); + + String keyPath = propertyIdToString(property); + String animName = keyPath + "_" + String::number(index); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + CAKeyframeAnimation* keyframeAnim = [CAKeyframeAnimation animationWithKeyPath:keyPath]; + + double duration = anim->duration(); + if (duration <= 0) + duration = cAnimationAlmostZeroDuration; + + float repeatCount = anim->iterationCount(); + if (repeatCount == Animation::IterationCountInfinite) + repeatCount = FLT_MAX; + else if (anim->direction() == Animation::AnimationDirectionAlternate) + repeatCount /= 2; + + [keyframeAnim setDuration:duration]; + [keyframeAnim setRepeatCount:repeatCount]; + [keyframeAnim setAutoreverses:anim->direction()]; + [keyframeAnim setRemovedOnCompletion:NO]; + + // The first animation is non-additive, all the rest are additive. + // Note that currently transform is the only property which has animations + // with an index > 0. + [keyframeAnim setAdditive:(property == AnimatedPropertyWebkitTransform) ? YES : NO]; + [keyframeAnim setFillMode:@"extended"]; +#if HAVE_MODERN_QUARTZCORE + if (NSString* valueFunctionName = getValueFunctionNameForTransformOperation(operationType)) + [keyframeAnim setValueFunction:[CAValueFunction functionWithName:valueFunctionName]]; +#else + UNUSED_PARAM(operationType); +#endif + + [keyframeAnim setKeyTimes:reinterpret_cast<id>(keys)]; + [keyframeAnim setValues:reinterpret_cast<id>(values)]; + + // Set the delegate (and property value). + int prop = isTransition ? property : AnimatedPropertyInvalid; + [keyframeAnim setValue:[NSNumber numberWithInt: prop] forKey:WebAnimationCSSPropertyKey]; + [keyframeAnim setDelegate:m_animationDelegate.get()]; + + NSTimeInterval bt = beginTime ? [layer convertTime:currentTimeToMediaTime(beginTime) fromLayer:nil] : 0; + [keyframeAnim setBeginTime:bt]; + + // Set the timing functions, if any. + if (timingFunctions != nil) + [keyframeAnim setTimingFunctions:(id)timingFunctions]; + + // Send over the animation. + [layer removeAnimationForKey:animName]; + [layer addAnimation:keyframeAnim forKey:animName]; + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::suspendAnimations() +{ + double t = currentTimeToMediaTime(currentTime()); + [primaryLayer() setSpeed:0]; + [primaryLayer() setTimeOffset:t]; +} + +void GraphicsLayerCA::resumeAnimations() +{ + [primaryLayer() setSpeed:1]; + [primaryLayer() setTimeOffset:0]; +} + +void GraphicsLayerCA::removeAnimation(int index, bool reset) +{ + ASSERT(index >= 0); + + AnimatedPropertyID property = m_animations[index].property(); + + // Set the value of the property and remove the animation. + String keyPath = propertyIdToString(property); + String animName = keyPath + "_" + String::number(m_animations[index].index()); + CALayer* layer = animatedLayer(property); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + // If we are not resetting, it means we are pausing. So we need to get the current presentation + // value into the property before we remove the animation. + if (!reset) { + // Put the current value into the property. + CALayer* presLayer = [layer presentationLayer]; + if (presLayer) + [layer setValue:[presLayer valueForKeyPath:keyPath] forKeyPath:keyPath]; + + // Make sure the saved values accurately reflect the value in the layer. + id val = [layer valueForKeyPath:keyPath]; + switch (property) { + case AnimatedPropertyWebkitTransform: + // FIXME: needs comment explaining why the m_transform is not obtained from the layer + break; + case AnimatedPropertyBackgroundColor: + m_backgroundColor = Color(reinterpret_cast<CGColorRef>(val)); + break; + case AnimatedPropertyOpacity: + m_opacity = [val floatValue]; + break; + case AnimatedPropertyInvalid: + ASSERT_NOT_REACHED(); + break; + } + } + + // If we have reached the end of an animation, we don't want to actually remove the + // animation from the CALayer. At some point we will be setting the property to its + // unanimated value and at that point we will remove the animation. That will avoid + // any flashing between the time the animation is removed and the property is set. + if (!reset || m_animations[index].isTransition()) + [layer removeAnimationForKey:animName]; + + END_BLOCK_OBJC_EXCEPTIONS + + // Remove the animation entry. + m_animations.remove(index); +} + +PlatformLayer* GraphicsLayerCA::hostLayerForSublayers() const +{ + return m_transformLayer ? m_transformLayer.get() : m_layer.get(); +} + +PlatformLayer* GraphicsLayerCA::layerForSuperlayer() const +{ + if (m_transformLayer) + return m_transformLayer.get(); + + return m_layer.get(); +} + +PlatformLayer* GraphicsLayerCA::platformLayer() const +{ + return primaryLayer(); +} + +#ifndef NDEBUG +void GraphicsLayerCA::setDebugBackgroundColor(const Color& color) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (color.isValid()) + setLayerBackgroundColor(m_layer.get(), color); + else + clearLayerBackgroundColor(m_layer.get()); + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (color.isValid()) { + setLayerBorderColor(m_layer.get(), color); + [m_layer.get() setBorderWidth:borderWidth]; + } else { + clearBorderColor(m_layer.get()); + [m_layer.get() setBorderWidth:0]; + } + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setZPosition(float position) +{ + GraphicsLayer::setZPosition(position); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + [primaryLayer() setZPosition:position]; + END_BLOCK_OBJC_EXCEPTIONS +} +#endif + +bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const +{ + if (!m_drawsContent) + return false; + + // FIXME: catch zero-size height or width here (or earlier)? + return size.width() > cMaxPixelDimension || size.height() > cMaxPixelDimension; +} + +void GraphicsLayerCA::swapFromOrToTiledLayer(bool userTiledLayer) +{ + if (userTiledLayer == m_usingTiledLayer) + return; + + CGSize tileSize = CGSizeMake(cTiledLayerTileSize, cTiledLayerTileSize); + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + RetainPtr<CALayer> oldLayer = m_layer.get(); + + Class layerClass = userTiledLayer ? [WebTiledLayer self] : [WebLayer self]; + m_layer.adoptNS([[layerClass alloc] init]); + + if (userTiledLayer) { + WebTiledLayer* tiledLayer = (WebTiledLayer*)m_layer.get(); + [tiledLayer setTileSize:tileSize]; + [tiledLayer setLevelsOfDetail:1]; + [tiledLayer setLevelsOfDetailBias:0]; + + if (GraphicsLayer::graphicsContextsFlipped()) + [tiledLayer setContentsGravity:@"bottomLeft"]; + else + [tiledLayer setContentsGravity:@"topLeft"]; + } + + [m_layer.get() setLayerOwner:this]; + [m_layer.get() setSublayers:[oldLayer.get() sublayers]]; + + [[oldLayer.get() superlayer] replaceSublayer:oldLayer.get() with:m_layer.get()]; + + [m_layer.get() setBounds:[oldLayer.get() bounds]]; + [m_layer.get() setPosition:[oldLayer.get() position]]; + [m_layer.get() setAnchorPoint:[oldLayer.get() anchorPoint]]; + [m_layer.get() setOpaque:[oldLayer.get() isOpaque]]; + [m_layer.get() setOpacity:[oldLayer.get() opacity]]; + [m_layer.get() setTransform:[oldLayer.get() transform]]; + [m_layer.get() setSublayerTransform:[oldLayer.get() sublayerTransform]]; + [m_layer.get() setDoubleSided:[oldLayer.get() isDoubleSided]]; +#ifndef NDEBUG + [m_layer.get() setZPosition:[oldLayer.get() zPosition]]; +#endif + +#ifndef NDEBUG + String name = String::format("CALayer(%p) GraphicsLayer(%p) ", m_layer.get(), this) + m_name; + [m_layer.get() setName:name]; +#endif + + // move over animations + moveAnimation(AnimatedPropertyWebkitTransform, oldLayer.get(), m_layer.get()); + moveAnimation(AnimatedPropertyOpacity, oldLayer.get(), m_layer.get()); + moveAnimation(AnimatedPropertyBackgroundColor, oldLayer.get(), m_layer.get()); + + // need to tell new layer to draw itself + setNeedsDisplay(); + + END_BLOCK_OBJC_EXCEPTIONS + + m_usingTiledLayer = userTiledLayer; + +#ifndef NDEBUG + updateDebugIndicators(); +#endif +} + +void GraphicsLayerCA::setHasContentsLayer(bool hasLayer) +{ + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (hasLayer && !m_contentsLayer) { + // create the inner layer + WebLayer* contentsLayer = [WebLayer layer]; +#ifndef NDEBUG + [contentsLayer setName:@"Contents Layer"]; +#endif + setContentsLayer(contentsLayer); + + } else if (!hasLayer && m_contentsLayer) + setContentsLayer(0); + + END_BLOCK_OBJC_EXCEPTIONS +} + +void GraphicsLayerCA::setContentsLayer(WebLayer* contentsLayer) +{ + if (contentsLayer == m_contentsLayer) + return; + + BEGIN_BLOCK_OBJC_EXCEPTIONS + + if (m_contentsLayer) { + [m_contentsLayer.get() removeFromSuperlayer]; + m_contentsLayer = 0; + } + + if (contentsLayer) { + // Turn off implicit animations on the inner layer. + [contentsLayer setStyle:[NSDictionary dictionaryWithObject:nullActionsDictionary() forKey:@"actions"]]; + + m_contentsLayer.adoptNS([contentsLayer retain]); + [m_contentsLayer.get() setAnchorPoint:CGPointZero]; + [m_layer.get() addSublayer:m_contentsLayer.get()]; + + updateContentsRect(); + + // Set contents to nil if the layer does not draw its own content. + if (m_client && !drawsContent()) + [m_layer.get() setContents:nil]; + +#ifndef NDEBUG + if (showDebugBorders()) { + setLayerBorderColor(m_contentsLayer.get(), Color(0, 0, 128, 180)); + [m_contentsLayer.get() setBorderWidth:1.0f]; + } +#endif + } +#ifndef NDEBUG + updateDebugIndicators(); +#endif + + END_BLOCK_OBJC_EXCEPTIONS +} + +} // namespace WebCore + + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h index 3f18ab4..677c31a 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 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,7 +28,7 @@ #if ENABLE(VIDEO) -#include "MediaPlayer.h" +#include "MediaPlayerPrivate.h" #include "Timer.h" #include <wtf/RetainPtr.h> @@ -52,11 +52,28 @@ class WebCoreMovieObserver; namespace WebCore { -class MediaPlayerPrivate : Noncopyable { +class MediaPlayerPrivate : public MediaPlayerPrivateInterface { public: - MediaPlayerPrivate(MediaPlayer*); + static void registerMediaEngine(MediaEngineRegistrar); + ~MediaPlayerPrivate(); - + + void repaint(); + void loadStateChanged(); + void rateChanged(); + void sizeChanged(); + void timeChanged(); + void didEnd(); + +private: + MediaPlayerPrivate(MediaPlayer*); + + // engine support + static MediaPlayerPrivateInterface* create(MediaPlayer* player); + static void getSupportedTypes(HashSet<String>& types); + static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs); + static bool isAvailable(); + IntSize naturalSize() const; bool hasVideo() const; @@ -72,11 +89,12 @@ public: float duration() const; float currentTime() const; void seek(float time); - void setEndTime(float time); void setRate(float); void setVolume(float); - + + void setEndTime(float time); + int dataRate() const; MediaPlayer::NetworkState networkState() const { return m_networkState; } @@ -89,21 +107,10 @@ public: unsigned totalBytes() const; void setVisible(bool); - void setRect(const IntRect& r); - - void loadStateChanged(); - void rateChanged(); - void sizeChanged(); - void timeChanged(); - void didEnd(); + void setSize(const IntSize&); - void repaint(); void paint(GraphicsContext*, const IntRect&); - - static void getSupportedTypes(HashSet<String>& types); - static bool isAvailable(); - -private: + void createQTMovie(const String& url); void setUpVideoRendering(); void tearDownVideoRendering(); @@ -117,10 +124,10 @@ private: void doSeek(); void cancelSeek(); void seekTimerFired(Timer<MediaPlayerPrivate>*); - void endPointTimerFired(Timer<MediaPlayerPrivate>*); float maxTimeLoaded() const; - void startEndPointTimerIfNeeded(); - void disableUnsupportedTracks(unsigned& enabledTrackCount); + void disableUnsupportedTracks(); + + bool metaDataAvailable() const { return m_qtMovie && m_readyState >= MediaPlayer::HaveMetadata; } MediaPlayer* m_player; RetainPtr<QTMovie> m_qtMovie; @@ -128,14 +135,15 @@ private: RetainPtr<QTVideoRendererWebKitOnly> m_qtVideoRenderer; RetainPtr<WebCoreMovieObserver> m_objcObserver; float m_seekTo; - float m_endTime; Timer<MediaPlayerPrivate> m_seekTimer; - Timer<MediaPlayerPrivate> m_endPointTimer; MediaPlayer::NetworkState m_networkState; MediaPlayer::ReadyState m_readyState; bool m_startedPlaying; bool m_isStreaming; bool m_visible; + IntRect m_rect; + unsigned m_enabledTrackCount; + float m_duration; #if DRAW_FRAME_RATE int m_frameCountWhilePlaying; double m_timeStartedPlaying; diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm index a33c8d2..74a9ff9 100644 --- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm +++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -69,6 +69,7 @@ SOFT_LINK_CLASS(QTKit, QTMovieView) SOFT_LINK_POINTER(QTKit, QTMediaTypeAttribute, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeBase, NSString *) +SOFT_LINK_POINTER(QTKit, QTMediaTypeMPEG, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeSound, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeText, NSString *) SOFT_LINK_POINTER(QTKit, QTMediaTypeVideo, NSString *) @@ -95,6 +96,7 @@ SOFT_LINK_POINTER(QTKit, QTVideoRendererWebKitOnlyNewImageAvailableNotification, #define QTMediaTypeAttribute getQTMediaTypeAttribute() #define QTMediaTypeBase getQTMediaTypeBase() +#define QTMediaTypeMPEG getQTMediaTypeMPEG() #define QTMediaTypeSound getQTMediaTypeSound() #define QTMediaTypeText getQTMediaTypeText() #define QTMediaTypeVideo getQTMediaTypeVideo() @@ -155,24 +157,35 @@ using namespace std; namespace WebCore { -static const float endPointTimerInterval = 0.020f; - #ifdef BUILDING_ON_TIGER static const long minimumQuickTimeVersion = 0x07300000; // 7.3 #endif + +MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player) +{ + return new MediaPlayerPrivate(player); +} + +void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar) +{ + if (isAvailable()) + registrar(create, getSupportedTypes, supportsType); +} + MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player) : m_player(player) , m_objcObserver(AdoptNS, [[WebCoreMovieObserver alloc] initWithCallback:this]) , m_seekTo(-1) - , m_endTime(numeric_limits<float>::infinity()) , m_seekTimer(this, &MediaPlayerPrivate::seekTimerFired) - , m_endPointTimer(this, &MediaPlayerPrivate::endPointTimerFired) , m_networkState(MediaPlayer::Empty) - , m_readyState(MediaPlayer::DataUnavailable) + , m_readyState(MediaPlayer::HaveNothing) , m_startedPlaying(false) , m_isStreaming(false) , m_visible(false) + , m_rect() + , m_enabledTrackCount(0) + , m_duration(-1.0f) #if DRAW_FRAME_RATE , m_frameCountWhilePlaying(0) , m_timeStartedPlaying(0) @@ -270,7 +283,7 @@ void MediaPlayerPrivate::createQTMovieView() detachQTMovieView(); static bool addedCustomMethods = false; - if (!addedCustomMethods) { + if (!m_player->inMediaDocument() && !addedCustomMethods) { Class QTMovieContentViewClass = NSClassFromString(@"QTMovieContentView"); ASSERT(QTMovieContentViewClass); @@ -281,9 +294,12 @@ void MediaPlayerPrivate::createQTMovieView() addedCustomMethods = true; } + // delay callbacks as we *will* get notifications during setup + [m_objcObserver.get() setDelayCallbacks:YES]; + m_qtMovieView.adoptNS([[QTMovieView alloc] init]); - setRect(m_player->rect()); - NSView* parentView = m_player->m_frameView->documentView(); + setSize(m_player->size()); + NSView* parentView = m_player->frameView()->documentView(); [parentView addSubview:m_qtMovieView.get()]; #ifdef BUILDING_ON_TIGER // setDelegate: isn't a public call in Tiger, so use performSelector to keep the compiler happy @@ -303,6 +319,8 @@ void MediaPlayerPrivate::createQTMovieView() // Note that we expect mainThreadSetNeedsDisplay to be invoked only when synchronous drawing is requested. if (!m_player->inMediaDocument()) wkQTMovieViewSetDrawSynchronously(m_qtMovieView.get(), YES); + + [m_objcObserver.get() setDelayCallbacks:NO]; } void MediaPlayerPrivate::detachQTMovieView() @@ -356,7 +374,7 @@ void MediaPlayerPrivate::destroyQTVideoRenderer() void MediaPlayerPrivate::setUpVideoRendering() { - if (!m_player->m_frameView || !m_qtMovie) + if (!m_player->frameView() || !m_qtMovie) return; if (m_player->inMediaDocument() || !QTVideoRendererClass() ) @@ -375,7 +393,7 @@ void MediaPlayerPrivate::tearDownVideoRendering() QTTime MediaPlayerPrivate::createQTTime(float time) const { - if (!m_qtMovie) + if (!metaDataAvailable()) return QTMakeTime(0, 600); long timeScale = [[m_qtMovie.get() attributeForKey:QTMovieTimeScaleAttribute] longValue]; return QTMakeTime(time * timeScale, timeScale); @@ -387,12 +405,11 @@ void MediaPlayerPrivate::load(const String& url) m_networkState = MediaPlayer::Loading; m_player->networkStateChanged(); } - if (m_readyState != MediaPlayer::DataUnavailable) { - m_readyState = MediaPlayer::DataUnavailable; + if (m_readyState != MediaPlayer::HaveNothing) { + m_readyState = MediaPlayer::HaveNothing; m_player->readyStateChanged(); } cancelSeek(); - m_endPointTimer.stop(); [m_objcObserver.get() setDelayCallbacks:YES]; @@ -404,7 +421,7 @@ void MediaPlayerPrivate::load(const String& url) void MediaPlayerPrivate::play() { - if (!m_qtMovie) + if (!metaDataAvailable()) return; m_startedPlaying = true; #if DRAW_FRAME_RATE @@ -413,12 +430,11 @@ void MediaPlayerPrivate::play() [m_objcObserver.get() setDelayCallbacks:YES]; [m_qtMovie.get() setRate:m_player->rate()]; [m_objcObserver.get() setDelayCallbacks:NO]; - startEndPointTimerIfNeeded(); } void MediaPlayerPrivate::pause() { - if (!m_qtMovie) + if (!metaDataAvailable()) return; m_startedPlaying = false; #if DRAW_FRAME_RATE @@ -427,12 +443,11 @@ void MediaPlayerPrivate::pause() [m_objcObserver.get() setDelayCallbacks:YES]; [m_qtMovie.get() stop]; [m_objcObserver.get() setDelayCallbacks:NO]; - m_endPointTimer.stop(); } float MediaPlayerPrivate::duration() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return 0; QTTime time = [m_qtMovie.get() duration]; if (time.flags == kQTTimeIsIndefinite) @@ -442,22 +457,22 @@ float MediaPlayerPrivate::duration() const float MediaPlayerPrivate::currentTime() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return 0; QTTime time = [m_qtMovie.get() currentTime]; - return min(static_cast<float>(time.timeValue) / time.timeScale, m_endTime); + return static_cast<float>(time.timeValue) / time.timeScale; } void MediaPlayerPrivate::seek(float time) { cancelSeek(); - if (!m_qtMovie) + if (!metaDataAvailable()) return; if (time > duration()) time = duration(); - + m_seekTo = time; if (maxTimeLoaded() >= m_seekTo) doSeek(); @@ -475,7 +490,7 @@ void MediaPlayerPrivate::doSeek() [m_qtMovie.get() setCurrentTime:qttime]; float timeAfterSeek = currentTime(); // restore playback only if not at end, othewise QTMovie will loop - if (timeAfterSeek < duration() && timeAfterSeek < m_endTime) + if (oldRate && timeAfterSeek < duration()) [m_qtMovie.get() setRate:oldRate]; cancelSeek(); [m_objcObserver.get() setDelayCallbacks:NO]; @@ -489,7 +504,7 @@ void MediaPlayerPrivate::cancelSeek() void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) { - if (!m_qtMovie || !seeking() || currentTime() == m_seekTo) { + if (!metaDataAvailable()|| !seeking() || currentTime() == m_seekTo) { cancelSeek(); updateStates(); m_player->timeChanged(); @@ -508,67 +523,48 @@ void MediaPlayerPrivate::seekTimerFired(Timer<MediaPlayerPrivate>*) } } -void MediaPlayerPrivate::setEndTime(float time) +void MediaPlayerPrivate::setEndTime(float) { - m_endTime = time; - startEndPointTimerIfNeeded(); -} - -void MediaPlayerPrivate::startEndPointTimerIfNeeded() -{ - if (m_endTime < duration() && m_startedPlaying && !m_endPointTimer.isActive()) - m_endPointTimer.startRepeating(endPointTimerInterval); -} - -void MediaPlayerPrivate::endPointTimerFired(Timer<MediaPlayerPrivate>*) -{ - float time = currentTime(); - - // just do end for now - if (time >= m_endTime) { - pause(); - didEnd(); - } } bool MediaPlayerPrivate::paused() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return true; return [m_qtMovie.get() rate] == 0; } bool MediaPlayerPrivate::seeking() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return false; return m_seekTo >= 0; } IntSize MediaPlayerPrivate::naturalSize() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return IntSize(); return IntSize([[m_qtMovie.get() attributeForKey:QTMovieNaturalSizeAttribute] sizeValue]); } bool MediaPlayerPrivate::hasVideo() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return false; return [[m_qtMovie.get() attributeForKey:QTMovieHasVideoAttribute] boolValue]; } void MediaPlayerPrivate::setVolume(float volume) { - if (!m_qtMovie) + if (!metaDataAvailable()) return; [m_qtMovie.get() setVolume:volume]; } void MediaPlayerPrivate::setRate(float rate) { - if (!m_qtMovie) + if (!metaDataAvailable()) return; if (!paused()) [m_qtMovie.get() setRate:rate]; @@ -576,7 +572,7 @@ void MediaPlayerPrivate::setRate(float rate) int MediaPlayerPrivate::dataRate() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return 0; return wkQTMovieDataRate(m_qtMovie.get()); } @@ -596,7 +592,7 @@ float MediaPlayerPrivate::maxTimeSeekable() const float MediaPlayerPrivate::maxTimeLoaded() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return 0; return wkQTMovieMaxTimeLoaded(m_qtMovie.get()); } @@ -616,7 +612,7 @@ bool MediaPlayerPrivate::totalBytesKnown() const unsigned MediaPlayerPrivate::totalBytes() const { - if (!m_qtMovie) + if (!metaDataAvailable()) return 0; return [[m_qtMovie.get() attributeForKey:QTMovieDataSizeAttribute] intValue]; } @@ -639,52 +635,66 @@ void MediaPlayerPrivate::updateStates() MediaPlayer::ReadyState oldReadyState = m_readyState; long loadState = m_qtMovie ? [[m_qtMovie.get() attributeForKey:QTMovieLoadStateAttribute] longValue] : static_cast<long>(QTMovieLoadStateError); - - if (loadState >= QTMovieLoadStateLoaded && m_networkState < MediaPlayer::LoadedMetaData && !m_player->inMediaDocument()) { - unsigned enabledTrackCount; - disableUnsupportedTracks(enabledTrackCount); - // FIXME: We should differentiate between load errors and decode errors <rdar://problem/5605692> - if (!enabledTrackCount) + + if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata && !m_player->inMediaDocument()) { + disableUnsupportedTracks(); + if (!m_enabledTrackCount) loadState = QTMovieLoadStateError; } - // "Loaded" is reserved for fully buffered movies, never the case when streaming if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) { - if (m_networkState < MediaPlayer::Loaded) - m_networkState = MediaPlayer::Loaded; - m_readyState = MediaPlayer::CanPlayThrough; + // "Loaded" is reserved for fully buffered movies, never the case when streaming + m_networkState = MediaPlayer::Loaded; + m_readyState = MediaPlayer::HaveEnoughData; } else if (loadState >= QTMovieLoadStatePlaythroughOK) { - if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) - m_networkState = MediaPlayer::LoadedFirstFrame; - m_readyState = MediaPlayer::CanPlayThrough; + m_readyState = MediaPlayer::HaveFutureData; + m_networkState = MediaPlayer::Loading; } else if (loadState >= QTMovieLoadStatePlayable) { - if (m_networkState < MediaPlayer::LoadedFirstFrame && !seeking()) - m_networkState = MediaPlayer::LoadedFirstFrame; // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967> - m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::CanPlay : MediaPlayer::DataUnavailable; + m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData; + m_networkState = MediaPlayer::Loading; } else if (loadState >= QTMovieLoadStateLoaded) { - if (m_networkState < MediaPlayer::LoadedMetaData) - m_networkState = MediaPlayer::LoadedMetaData; - m_readyState = MediaPlayer::DataUnavailable; + m_readyState = MediaPlayer::HaveMetadata; + m_networkState = MediaPlayer::Loading; } else if (loadState > QTMovieLoadStateError) { - if (m_networkState < MediaPlayer::Loading) - m_networkState = MediaPlayer::Loading; - m_readyState = MediaPlayer::DataUnavailable; + m_readyState = MediaPlayer::HaveNothing; + m_networkState = MediaPlayer::Loading; } else { - m_networkState = MediaPlayer::LoadFailed; - m_readyState = MediaPlayer::DataUnavailable; + float loaded = maxTimeLoaded(); + + if (!loaded) + m_readyState = MediaPlayer::HaveNothing; + + if (!m_enabledTrackCount) + m_networkState = MediaPlayer::FormatError; + else { + // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692> + if (loaded > 0) + m_networkState = MediaPlayer::DecodeError; + else + m_readyState = MediaPlayer::HaveNothing; + } } if (seeking()) - m_readyState = MediaPlayer::DataUnavailable; - + m_readyState = MediaPlayer::HaveNothing; + if (m_networkState != oldNetworkState) m_player->networkStateChanged(); if (m_readyState != oldReadyState) m_player->readyStateChanged(); - if (loadState >= QTMovieLoadStateLoaded && oldNetworkState < MediaPlayer::LoadedMetaData && m_player->visible()) + if (loadState >= QTMovieLoadStateLoaded && oldReadyState < MediaPlayer::HaveMetadata && m_player->visible()) setUpVideoRendering(); + + if (loadState >= QTMovieLoadStateLoaded) { + float dur = duration(); + if (dur != m_duration) { + if (m_duration != -1.0f) + m_player->durationChanged(); + m_duration = dur; + } + } } void MediaPlayerPrivate::loadStateChanged() @@ -695,10 +705,12 @@ void MediaPlayerPrivate::loadStateChanged() void MediaPlayerPrivate::rateChanged() { updateStates(); + m_player->rateChanged(); } void MediaPlayerPrivate::sizeChanged() { + m_player->sizeChanged(); } void MediaPlayerPrivate::timeChanged() @@ -709,7 +721,6 @@ void MediaPlayerPrivate::timeChanged() void MediaPlayerPrivate::didEnd() { - m_endPointTimer.stop(); m_startedPlaying = false; #if DRAW_FRAME_RATE m_timeStoppedPlaying = [NSDate timeIntervalSinceReferenceDate]; @@ -718,18 +729,19 @@ void MediaPlayerPrivate::didEnd() m_player->timeChanged(); } -void MediaPlayerPrivate::setRect(const IntRect& r) +void MediaPlayerPrivate::setSize(const IntSize& size) { if (!m_qtMovieView) return; + m_rect.setSize(size); if (m_player->inMediaDocument()) // We need the QTMovieView to be placed in the proper location for document mode. - [m_qtMovieView.get() setFrame:r]; + [m_qtMovieView.get() setFrame:m_rect]; else { // We don't really need the QTMovieView in any specific location so let's just get it out of the way // where it won't intercept events or try to bring up the context menu. - IntRect farAwayButCorrectSize(r); + IntRect farAwayButCorrectSize(m_rect); farAwayButCorrectSize.move(-1000000, -1000000); [m_qtMovieView.get() setFrame:farAwayButCorrectSize]; } @@ -740,7 +752,7 @@ void MediaPlayerPrivate::setVisible(bool b) if (m_visible != b) { m_visible = b; if (b) { - if (m_networkState >= MediaPlayer::LoadedMetaData) + if (m_readyState >= MediaPlayer::HaveMetadata) setUpVideoRendering(); } else tearDownVideoRendering(); @@ -789,13 +801,19 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [NSGraphicsContext setCurrentContext:newContext]; [(id<WebKitVideoRenderingDetails>)qtVideoRenderer drawInRect:paintRect]; [NSGraphicsContext restoreGraphicsState]; - } else + } else { + if (m_player->inMediaDocument() && r != m_rect) { + // the QTMovieView needs to be placed in the proper location for document mode + m_rect = r; + [view setFrame:m_rect]; + } [view displayRectIgnoringOpacity:paintRect inContext:newContext]; + } #if DRAW_FRAME_RATE // Draw the frame rate only after having played more than 10 frames. if (m_frameCountWhilePlaying > 10) { - Frame* frame = m_player->m_frameView ? m_player->m_frameView->frame() : NULL; + Frame* frame = m_player->frameView() ? m_player->frameView()->frame() : NULL; Document* document = frame ? frame->document() : NULL; RenderObject* renderer = document ? document->renderer() : NULL; RenderStyle* styleToUse = renderer ? renderer->style() : NULL; @@ -821,22 +839,42 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& r) [m_objcObserver.get() setDelayCallbacks:NO]; } -void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +static HashSet<String> mimeTypeCache() { - NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes]; - int count = [fileTypes count]; - for (int n = 0; n < count; n++) { - CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); - RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); - if (!uti) - continue; - RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); - if (!mime) - continue; - types.add(mime.get()); + DEFINE_STATIC_LOCAL(HashSet<String>, cache, ()); + static bool typeListInitialized = false; + + if (!typeListInitialized) { + NSArray* fileTypes = [QTMovie movieFileTypes:QTIncludeCommonTypes]; + int count = [fileTypes count]; + for (int n = 0; n < count; n++) { + CFStringRef ext = reinterpret_cast<CFStringRef>([fileTypes objectAtIndex:n]); + RetainPtr<CFStringRef> uti(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, ext, NULL)); + if (!uti) + continue; + RetainPtr<CFStringRef> mime(AdoptCF, UTTypeCopyPreferredTagWithClass(uti.get(), kUTTagClassMIMEType)); + if (!mime) + continue; + cache.add(mime.get()); + } + typeListInitialized = true; } -} + return cache; +} + +void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types) +{ + types = mimeTypeCache(); +} + +MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs) +{ + // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an + // extended MIME type yet + return mimeTypeCache().contains(type) ? (codecs && !codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported; +} + bool MediaPlayerPrivate::isAvailable() { #ifdef BUILDING_ON_TIGER @@ -858,10 +896,10 @@ bool MediaPlayerPrivate::isAvailable() #endif } -void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) +void MediaPlayerPrivate::disableUnsupportedTracks() { if (!m_qtMovie) { - enabledTrackCount = 0; + m_enabledTrackCount = 0; return; } @@ -872,6 +910,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) allowedTrackTypes->add(QTMediaTypeSound); allowedTrackTypes->add(QTMediaTypeText); allowedTrackTypes->add(QTMediaTypeBase); + allowedTrackTypes->add(QTMediaTypeMPEG); allowedTrackTypes->add("clcp"); allowedTrackTypes->add("sbtl"); } @@ -879,7 +918,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) NSArray *tracks = [m_qtMovie.get() tracks]; unsigned trackCount = [tracks count]; - enabledTrackCount = trackCount; + m_enabledTrackCount = trackCount; for (unsigned trackIndex = 0; trackIndex < trackCount; trackIndex++) { // Grab the track at the current index. If there isn't one there, then // we can move onto the next one. @@ -907,7 +946,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) if (!allowedTrackTypes->contains(mediaType)) { // If this track type is not allowed, then we need to disable it. [track setEnabled:NO]; - --enabledTrackCount; + --m_enabledTrackCount; } // Disable chapter tracks. These are most likely to lead to trouble, as @@ -939,7 +978,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) // Disable the evil, evil track. [chapterTrack setEnabled:NO]; - --enabledTrackCount; + --m_enabledTrackCount; } } @@ -947,7 +986,7 @@ void MediaPlayerPrivate::disableUnsupportedTracks(unsigned& enabledTrackCount) @implementation WebCoreMovieObserver -- (id)initWithCallback:(MediaPlayerPrivate *)callback +- (id)initWithCallback:(MediaPlayerPrivate*)callback { m_callback = callback; return [super init]; diff --git a/WebCore/platform/graphics/mac/MediaPlayerProxy.h b/WebCore/platform/graphics/mac/MediaPlayerProxy.h new file mode 100644 index 0000000..6060484 --- /dev/null +++ b/WebCore/platform/graphics/mac/MediaPlayerProxy.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef MediaPlayerProxy_h +#define MediaPlayerProxy_h + +#ifdef __OBJC__ +@class WebMediaPlayerProxy; +#else +class WebMediaPlayerProxy; +#endif + +enum MediaPlayerProxyNotificationType { + + MediaPlayerNotificationMediaValidated = 1, + MediaPlayerNotificationMediaFailedToValidate, + + MediaPlayerNotificationStartUsingNetwork, + MediaPlayerNotificationStopUsingNetwork, + + MediaPlayerNotificationEnteredFullScreen, + MediaPlayerNotificationExitedFullScreen, + + MediaPlayerNotificationReadyForInspection, + MediaPlayerNotificationReadyForPlayback, + MediaPlayerNotificationDidPlayToTheEnd, + + MediaPlayerNotificationPlaybackFailed, + + MediaPlayerNotificationStreamLikelyToKeepUp, + MediaPlayerNotificationStreamUnlikelyToKeepUp, + MediaPlayerNotificationStreamBufferFull, + MediaPlayerNotificationStreamRanDry, + MediaPlayerNotificationFileLoaded, + + MediaPlayerNotificationSizeDidChange, + MediaPlayerNotificationVolumeDidChange, + MediaPlayerNotificationMutedDidChange, + MediaPlayerNotificationTimeJumped, + + MediaPlayerNotificationPlayPauseButtonPressed, +}; + +#ifdef __OBJC__ +@interface NSObject (WebMediaPlayerProxy) + +- (int)_interfaceVersion; + +- (void)_disconnect; + +- (void)_load:(NSURL *)url; +- (void)_cancelLoad; + +- (void)_setPoster:(NSURL *)url; + +- (void)_play; +- (void)_pause; + +- (NSSize)_naturalSize; + +- (BOOL)_hasVideo; +- (BOOL)_hasAudio; + +- (NSTimeInterval)_duration; + +- (double)_currentTime; +- (void)_setCurrentTime:(double)time; +- (BOOL)_seeking; + +- (void)_setEndTime:(double)time; + +- (float)_rate; +- (void)_setRate:(float)rate; + +- (float)_volume; +- (void)_setVolume:(float)newVolume; + +- (BOOL)_muted; +- (void)_setMuted:(BOOL)muted; + +- (float)_maxTimeBuffered; +- (float)_maxTimeSeekable; +- (NSArray *)_bufferedTimeRanges; + +- (int)_dataRate; + +- (BOOL)_totalBytesKnown; +- (unsigned)_totalBytes; +- (unsigned)_bytesLoaded; + +- (NSArray *)_mimeTypes; + +@end +#endif + +#endif diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm index 30dbf97..a3c10fa 100644 --- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm +++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm @@ -38,6 +38,7 @@ #import "FontDescription.h" #import "SharedBuffer.h" #import "WebCoreSystemInterface.h" +#import <AppKit/AppKit.h> #import <ApplicationServices/ApplicationServices.h> #import <float.h> #import <unicode/uchar.h> diff --git a/WebCore/platform/graphics/mac/WebLayer.h b/WebCore/platform/graphics/mac/WebLayer.h new file mode 100644 index 0000000..b8b46ed --- /dev/null +++ b/WebCore/platform/graphics/mac/WebLayer.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef WebLayer_h +#define WebLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#import <QuartzCore/QuartzCore.h> + +namespace WebCore { + class GraphicsLayer; +} + +// Category implemented by WebLayer and WebTiledLayer. +@interface CALayer(WebLayerAdditions) + +- (void)setLayerOwner:(WebCore::GraphicsLayer*)layer; +- (WebCore::GraphicsLayer*)layerOwner; + +@end + +@interface WebLayer : CALayer +{ + WebCore::GraphicsLayer* m_layerOwner; +} + +// Class method allows us to share implementation across TiledLayerMac and WebLayer ++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context; + +@end + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WebLayer_h diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm new file mode 100644 index 0000000..267b5bc --- /dev/null +++ b/WebCore/platform/graphics/mac/WebLayer.mm @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#import "WebLayer.h" + +#import "GraphicsContext.h" +#import "GraphicsLayer.h" +#import <QuartzCore/QuartzCore.h> +#import "WebCoreTextRenderer.h" +#import <wtf/UnusedParam.h> + +using namespace WebCore; + +@implementation WebLayer + ++ (void)drawContents:(WebCore::GraphicsLayer*)layerContents ofLayer:(CALayer*)layer intoContext:(CGContextRef)context +{ + UNUSED_PARAM(layer); + CGContextSaveGState(context); + + if (layerContents && layerContents->client()) { + [NSGraphicsContext saveGraphicsState]; + + // Set up an NSGraphicsContext for the context, so that parts of AppKit that rely on + // the current NSGraphicsContext (e.g. NSCell drawing) get the right one. + NSGraphicsContext* layerContext = [NSGraphicsContext graphicsContextWithGraphicsPort:context flipped:YES]; + [NSGraphicsContext setCurrentContext:layerContext]; + + GraphicsContext graphicsContext(context); + + // It's important to get the clip from the context, because it may be significantly + // smaller than the layer bounds (e.g. tiled layers) + CGRect clipBounds = CGContextGetClipBoundingBox(context); + IntRect clip(enclosingIntRect(clipBounds)); + layerContents->paintGraphicsLayerContents(graphicsContext, clip); + + [NSGraphicsContext restoreGraphicsState]; + } +#ifndef NDEBUG + else { + ASSERT_NOT_REACHED(); + + // FIXME: ideally we'd avoid calling -setNeedsDisplay on a layer that is a plain color, + // so CA never makes backing store for it (which is what -setNeedsDisplay will do above). + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 1.0f); + CGRect aBounds = [layer bounds]; + CGContextFillRect(context, aBounds); + } +#endif + + CGContextRestoreGState(context); + +#ifndef NDEBUG + if (layerContents && layerContents->showRepaintCounter()) { + bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]]; + + char text[16]; // that's a lot of repaints + snprintf(text, sizeof(text), "%d", layerContents->incrementRepaintCount()); + + CGAffineTransform a = CGContextGetCTM(context); + + CGContextSaveGState(context); + if (isTiledLayer) + CGContextSetRGBFillColor(context, 0.0f, 1.0f, 0.0f, 0.8f); + else + CGContextSetRGBFillColor(context, 1.0f, 0.0f, 0.0f, 0.8f); + + CGRect aBounds = [layer bounds]; + + aBounds.size.width = 10 + 12 * strlen(text); + aBounds.size.height = 25; + CGContextFillRect(context, aBounds); + + CGContextSetRGBFillColor(context, 0.0f, 0.0f, 0.0f, 1.0f); + + CGContextSetTextMatrix(context, CGAffineTransformMakeScale(1.0f, -1.0f)); + CGContextSelectFont(context, "Helvetica", 25, kCGEncodingMacRoman); + CGContextShowTextAtPoint(context, aBounds.origin.x + 3.0f, aBounds.origin.y + 20.0f, text, strlen(text)); + + CGContextRestoreGState(context); + } +#endif +} + +// Disable default animations +- (id<CAAction>)actionForKey:(NSString *)key +{ + UNUSED_PARAM(key); + return nil; +} + +// Implement this so presentationLayer can get our custom attributes +- (id)initWithLayer:(id)layer +{ + if ((self = [super initWithLayer:layer])) + m_layerOwner = [(WebLayer*)layer layerOwner]; + + return self; +} + +- (void)setNeedsDisplay +{ + if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) + [super setNeedsDisplay]; +} + +- (void)setNeedsDisplayInRect:(CGRect)dirtyRect +{ + if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) { + [super setNeedsDisplayInRect:dirtyRect]; + +#ifndef NDEBUG + if (m_layerOwner->showRepaintCounter()) { + CGRect bounds = [self bounds]; + [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)]; + } +#endif + } +} + +- (void)drawInContext:(CGContextRef)context +{ + [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:context]; +} + +@end // implementation WebLayer + +#pragma mark - + +@implementation WebLayer(WebLayerAdditions) + +- (void)setLayerOwner:(GraphicsLayer*)aLayer +{ + m_layerOwner = aLayer; +} + +- (GraphicsLayer*)layerOwner +{ + return m_layerOwner; +} + +@end + +#pragma mark - + +#ifndef NDEBUG + +@implementation CALayer(ExtendedDescription) + +- (NSString*)_descriptionWithPrefix:(NSString*)inPrefix +{ + CGRect aBounds = [self bounds]; + CGPoint aPos = [self position]; + CATransform3D t = [self transform]; + + NSString* selfString = [NSString stringWithFormat:@"%@<%@ 0x%08x> \"%@\" bounds(%.1f, %.1f, %.1f, %.1f) pos(%.1f, %.1f), sublayers=%d masking=%d", + inPrefix, + [self class], + self, + [self name], + aBounds.origin.x, aBounds.origin.y, aBounds.size.width, aBounds.size.height, + aPos.x, aPos.y, + [[self sublayers] count], + [self masksToBounds]]; + + NSMutableString* curDesc = [NSMutableString stringWithString:selfString]; + + if ([[self sublayers] count] > 0) + [curDesc appendString:@"\n"]; + + NSString* sublayerPrefix = [inPrefix stringByAppendingString:@"\t"]; + + NSEnumerator* sublayersEnum = [[self sublayers] objectEnumerator]; + CALayer* curLayer; + while ((curLayer = [sublayersEnum nextObject])) + [curDesc appendString:[curLayer _descriptionWithPrefix:sublayerPrefix]]; + + if ([[self sublayers] count] == 0) + [curDesc appendString:@"\n"]; + + return curDesc; +} + +- (NSString*)extendedDescription +{ + return [self _descriptionWithPrefix:@""]; +} + +@end // implementation WebLayer(ExtendedDescription) + +#endif // NDEBUG + +#endif // USE(ACCELERATED_COMPOSITING) diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.h b/WebCore/platform/graphics/mac/WebTiledLayer.h new file mode 100644 index 0000000..1c9144d --- /dev/null +++ b/WebCore/platform/graphics/mac/WebTiledLayer.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#ifndef WebTiledLayer_h +#define WebTiledLayer_h + +#if USE(ACCELERATED_COMPOSITING) + +#import "WebLayer.h" + +@interface WebTiledLayer : CATiledLayer +{ + WebCore::GraphicsLayer* m_layerOwner; +} + +// implements WebLayerAdditions + +@end + +#endif // USE(ACCELERATED_COMPOSITING) + +#endif // WebTiledLayer_h + diff --git a/WebCore/platform/graphics/mac/WebTiledLayer.mm b/WebCore/platform/graphics/mac/WebTiledLayer.mm new file mode 100644 index 0000000..1dd00ba --- /dev/null +++ b/WebCore/platform/graphics/mac/WebTiledLayer.mm @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2009 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 COMPUTER, INC. OR + * 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. + */ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) + +#import "WebTiledLayer.h" + +#import "GraphicsContext.h" +#import "GraphicsLayer.h" +#import <wtf/UnusedParam.h> + +using namespace WebCore; + +@implementation WebTiledLayer + +// Set a zero duration for the fade in of tiles ++ (CFTimeInterval)fadeDuration +{ + return 0; +} + +// Make sure that tiles are drawn on the main thread ++ (BOOL)shouldDrawOnMainThread +{ + return YES; +} + +// Disable default animations +- (id<CAAction>)actionForKey:(NSString *)key +{ + UNUSED_PARAM(key); + return nil; +} + +// Implement this so presentationLayer can get our custom attributes +- (id)initWithLayer:(id)layer +{ + if ((self = [super initWithLayer:layer])) + m_layerOwner = [(WebLayer*)layer layerOwner]; + + return self; +} + +- (void)setNeedsDisplay +{ + if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) + [super setNeedsDisplay]; +} + +- (void)setNeedsDisplayInRect:(CGRect)dirtyRect +{ + if (m_layerOwner && m_layerOwner->client() && m_layerOwner->drawsContent()) { + [super setNeedsDisplayInRect:dirtyRect]; + +#ifndef NDEBUG + if (m_layerOwner->showRepaintCounter()) { + CGRect bounds = [self bounds]; + [super setNeedsDisplayInRect:CGRectMake(bounds.origin.x, bounds.origin.y, 46, 25)]; + } +#endif + } +} + +- (void)drawInContext:(CGContextRef)ctx +{ + [WebLayer drawContents:m_layerOwner ofLayer:self intoContext:ctx]; +} + +@end // implementation WebTiledLayer + +#pragma mark - + +@implementation WebTiledLayer(LayerMacAdditions) + +- (void)setLayerOwner:(GraphicsLayer*)aLayer +{ + m_layerOwner = aLayer; +} + +- (GraphicsLayer*)layerOwner +{ + return m_layerOwner; +} + +@end + +#endif // USE(ACCELERATED_COMPOSITING) |