summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/mac
diff options
context:
space:
mode:
authorFeng Qian <>2009-04-10 18:11:29 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-10 18:11:29 -0700
commit8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch)
tree181bf9a400c30a1bf34ea6d72560e8d00111d549 /WebCore/platform/graphics/mac
parent7ed56f225e0ade046e1c2178977f72b2d896f196 (diff)
downloadexternal_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')
-rw-r--r--WebCore/platform/graphics/mac/ColorMac.mm3
-rw-r--r--WebCore/platform/graphics/mac/FontCacheMac.mm13
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.cpp17
-rw-r--r--WebCore/platform/graphics/mac/FontCustomPlatformData.h1
-rw-r--r--WebCore/platform/graphics/mac/FontMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontMacATSUI.mm1
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformData.h18
-rw-r--r--WebCore/platform/graphics/mac/FontPlatformDataMac.mm23
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContextMac.mm5
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h138
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm1540
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h58
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm253
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerProxy.h118
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.h57
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm219
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.h45
-rw-r--r--WebCore/platform/graphics/mac/WebTiledLayer.mm111
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)