summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/BitmapImage.cpp24
-rw-r--r--WebCore/platform/graphics/FloatRect.h2
-rw-r--r--WebCore/platform/graphics/Gradient.h4
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.cpp130
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.h65
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h2
-rw-r--r--WebCore/platform/graphics/Icon.h2
-rw-r--r--WebCore/platform/graphics/MediaPlayer.cpp10
-rw-r--r--WebCore/platform/graphics/MediaPlayer.h16
-rw-r--r--WebCore/platform/graphics/MediaPlayerPrivate.h3
-rw-r--r--WebCore/platform/graphics/cg/GradientCG.cpp6
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp101
-rw-r--r--WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp3
-rw-r--r--WebCore/platform/graphics/gtk/IconGtk.cpp1
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp295
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h12
-rw-r--r--WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp51
-rw-r--r--WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h2
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp57
-rw-r--r--WebCore/platform/graphics/mac/IconMac.mm1
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h3
-rw-r--r--WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm25
-rw-r--r--WebCore/platform/graphics/mac/SimpleFontDataMac.mm69
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp31
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp92
-rw-r--r--WebCore/platform/graphics/qt/IconQt.cpp1
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp10
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp74
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp16
-rw-r--r--WebCore/platform/graphics/win/IconWin.cpp1
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp23
-rw-r--r--WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h3
32 files changed, 905 insertions, 230 deletions
diff --git a/WebCore/platform/graphics/BitmapImage.cpp b/WebCore/platform/graphics/BitmapImage.cpp
index 0b94efb..0cd3907 100644
--- a/WebCore/platform/graphics/BitmapImage.cpp
+++ b/WebCore/platform/graphics/BitmapImage.cpp
@@ -270,6 +270,18 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary)
if (m_frameTimer || !shouldAnimate() || frameCount() <= 1)
return;
+ // Don't advance the animation to an incomplete frame.
+ size_t nextFrame = (m_currentFrame + 1) % frameCount();
+ if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
+ return;
+
+ // Don't advance past the last frame if we haven't decoded the whole image
+ // yet and our repetition count is potentially unset. The repetition count
+ // in a GIF can potentially come after all the rest of the image data, so
+ // wait on it.
+ if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
+ return;
+
// Determine time for next frame to start. By ignoring paint and timer lag
// in this calculation, we make the animation appear to run at its desired
// rate regardless of how fast it's being repainted.
@@ -288,18 +300,6 @@ void BitmapImage::startAnimation(bool catchUpIfNecessary)
m_desiredFrameStartTime = time + currentDuration;
}
- // Don't advance the animation to an incomplete frame.
- size_t nextFrame = (m_currentFrame + 1) % frameCount();
- if (!m_allDataReceived && !frameIsCompleteAtIndex(nextFrame))
- return;
-
- // Don't advance past the last frame if we haven't decoded the whole image
- // yet and our repetition count is potentially unset. The repetition count
- // in a GIF can potentially come after all the rest of the image data, so
- // wait on it.
- if (!m_allDataReceived && repetitionCount(false) == cAnimationLoopOnce && m_currentFrame >= (frameCount() - 1))
- return;
-
// The image may load more slowly than it's supposed to animate, so that by
// the time we reach the end of the first repetition, we're well behind.
// Clamp the desired frame start time in this case, so that we don't skip
diff --git a/WebCore/platform/graphics/FloatRect.h b/WebCore/platform/graphics/FloatRect.h
index 74a6293..b265121 100644
--- a/WebCore/platform/graphics/FloatRect.h
+++ b/WebCore/platform/graphics/FloatRect.h
@@ -99,6 +99,8 @@ public:
float right() const { return x() + width(); }
float bottom() const { return y() + height(); }
+ FloatPoint center() const { return FloatPoint(x() + width() / 2, y() + height() / 2); }
+
void move(const FloatSize& delta) { m_location += delta; }
void move(float dx, float dy) { m_location.move(dx, dy); }
diff --git a/WebCore/platform/graphics/Gradient.h b/WebCore/platform/graphics/Gradient.h
index e1be1fe..0efd3bf 100644
--- a/WebCore/platform/graphics/Gradient.h
+++ b/WebCore/platform/graphics/Gradient.h
@@ -37,7 +37,9 @@
#if PLATFORM(CG)
-#ifdef BUILDING_ON_TIGER
+#define USE_CG_SHADING defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD)
+
+#if USE_CG_SHADING
typedef struct CGShading* CGShadingRef;
typedef CGShadingRef PlatformGradient;
#else
diff --git a/WebCore/platform/graphics/GraphicsContext3D.cpp b/WebCore/platform/graphics/GraphicsContext3D.cpp
new file mode 100644
index 0000000..3eb9818
--- /dev/null
+++ b/WebCore/platform/graphics/GraphicsContext3D.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+
+namespace WebCore {
+
+bool GraphicsContext3D::extractImageData(Image* image,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& imageData,
+ unsigned int* format,
+ unsigned int* internalFormat)
+{
+ if (!image)
+ return false;
+ AlphaOp alphaOp = kAlphaDoNothing;
+ bool hasAlphaChannel = true;
+ if (!getImageData(image, imageData, premultiplyAlpha,
+ &hasAlphaChannel, &alphaOp, format))
+ return false;
+ processImageData(imageData.data(),
+ image->width(),
+ image->height(),
+ flipY,
+ alphaOp);
+ *internalFormat = (hasAlphaChannel ? RGBA : RGB);
+ return true;
+}
+
+void GraphicsContext3D::processImageData(uint8_t* imageData,
+ unsigned width,
+ unsigned height,
+ bool flipVertically,
+ AlphaOp alphaOp)
+{
+ switch (alphaOp) {
+ case kAlphaDoPremultiply:
+ premultiplyAlpha(imageData, width * height);
+ break;
+ case kAlphaDoUnmultiply:
+ unmultiplyAlpha(imageData, width * height);
+ break;
+ default:
+ break;
+ }
+
+ if (flipVertically && width && height) {
+ int rowBytes = width * 4;
+ uint8_t* tempRow = new uint8_t[rowBytes];
+ for (unsigned i = 0; i < height / 2; i++) {
+ uint8_t* lowRow = imageData + (rowBytes * i);
+ uint8_t* highRow = imageData + (rowBytes * (height - i - 1));
+ memcpy(tempRow, lowRow, rowBytes);
+ memcpy(lowRow, highRow, rowBytes);
+ memcpy(highRow, tempRow, rowBytes);
+ }
+ delete[] tempRow;
+ }
+}
+
+// Premultiply alpha into color channels.
+void GraphicsContext3D::premultiplyAlpha(unsigned char* rgbaData, int numPixels)
+{
+ for (int j = 0; j < numPixels; j++) {
+ float r = rgbaData[4*j+0] / 255.0f;
+ float g = rgbaData[4*j+1] / 255.0f;
+ float b = rgbaData[4*j+2] / 255.0f;
+ float a = rgbaData[4*j+3] / 255.0f;
+ rgbaData[4*j+0] = (unsigned char) (r * a * 255.0f);
+ rgbaData[4*j+1] = (unsigned char) (g * a * 255.0f);
+ rgbaData[4*j+2] = (unsigned char) (b * a * 255.0f);
+ }
+}
+
+// Remove premultiplied alpha from color channels.
+// FIXME: this is lossy. Must retrieve original values from HTMLImageElement.
+void GraphicsContext3D::unmultiplyAlpha(unsigned char* rgbaData, int numPixels)
+{
+ for (int j = 0; j < numPixels; j++) {
+ float r = rgbaData[4*j+0] / 255.0f;
+ float g = rgbaData[4*j+1] / 255.0f;
+ float b = rgbaData[4*j+2] / 255.0f;
+ float a = rgbaData[4*j+3] / 255.0f;
+ if (a > 0.0f) {
+ r /= a;
+ g /= a;
+ b /= a;
+ r = (r > 1.0f) ? 1.0f : r;
+ g = (g > 1.0f) ? 1.0f : g;
+ b = (b > 1.0f) ? 1.0f : b;
+ rgbaData[4*j+0] = (unsigned char) (r * 255.0f);
+ rgbaData[4*j+1] = (unsigned char) (g * 255.0f);
+ rgbaData[4*j+2] = (unsigned char) (b * 255.0f);
+ }
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h
index b7be8fc..0a41dc6 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.h
+++ b/WebCore/platform/graphics/GraphicsContext3D.h
@@ -419,6 +419,43 @@ namespace WebCore {
// like GL_FLOAT, GL_INT, etc.
int sizeInBytes(int type);
+ //----------------------------------------------------------------------
+ // Helpers for texture uploading.
+ //
+
+ // Extracts the contents of the given Image into the passed
+ // Vector, obeying the flipY and premultiplyAlpha flags.
+ // Returns the applicable OpenGL format and internalFormat for
+ // the subsequent glTexImage2D or glTexSubImage2D call.
+ // Returns true upon success.
+ bool extractImageData(Image* image,
+ bool flipY,
+ bool premultiplyAlpha,
+ Vector<uint8_t>& imageData,
+ unsigned int* format,
+ unsigned int* internalFormat);
+
+ // Processes the given image data in preparation for uploading
+ // via texImage2D or texSubImage2D. The input data must be in
+ // 4-component format with the alpha channel last (i.e., RGBA
+ // or BGRA), tightly packed, with no space between rows.
+
+ enum AlphaOp {
+ kAlphaDoNothing = 0,
+ kAlphaDoPremultiply = 1,
+ kAlphaDoUnmultiply = 2
+ };
+
+ void processImageData(uint8_t* imageData,
+ unsigned width,
+ unsigned height,
+ bool flipVertically,
+ AlphaOp alphaOp);
+
+ //----------------------------------------------------------------------
+ // Entry points for WebGL.
+ //
+
void activeTexture(unsigned long texture);
void attachShader(WebGLProgram* program, WebGLShader* shader);
void bindAttribLocation(WebGLProgram*, unsigned long index, const String& name);
@@ -624,6 +661,34 @@ namespace WebCore {
private:
GraphicsContext3D(Attributes attrs);
+ // Helpers for texture uploading.
+ void premultiplyAlpha(unsigned char* rgbaData, int numPixels);
+ void unmultiplyAlpha(uint8_t* imageData, int numPixels);
+
+ // Each platform must provide an implementation of this method.
+ //
+ // Gets the data for the given Image into outputVector,
+ // without doing any processing of the data (vertical flip or
+ // otherwise).
+ //
+ // premultiplyAlpha indicates whether the user will eventually
+ // want the alpha channel multiplied into the color channels.
+ //
+ // The out parameter hasAlphaChannel indicates whether the
+ // image actually had an alpha channel.
+ //
+ // The out parameter neededAlphaOp should be passed to a
+ // subsequent call of processImageData.
+ //
+ // The out parameter format should be passed to subsequent
+ // invocations of texImage2D and texSubImage2D.
+ bool getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format);
+
int m_currentWidth, m_currentHeight;
#if PLATFORM(MAC)
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index 844301e..a097620 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -74,7 +74,7 @@ class FloatPoint3D;
class GraphicsContext;
class Image;
class TextStream;
-class TimingFunction;
+struct TimingFunction;
// Base class for animation values (also used for transitions). Here to
// represent values for properties being animated via the GraphicsLayer,
diff --git a/WebCore/platform/graphics/Icon.h b/WebCore/platform/graphics/Icon.h
index d7d694a..e9f2dc7 100644
--- a/WebCore/platform/graphics/Icon.h
+++ b/WebCore/platform/graphics/Icon.h
@@ -51,6 +51,8 @@ class String;
class Icon : public RefCounted<Icon> {
public:
+ // Deprecated. This function will be removed.
+ // FIXME: Remove it when all implementations are moved to ChromeClient::iconForFiles().
static PassRefPtr<Icon> createIconForFiles(const Vector<String>& filenames);
~Icon();
diff --git a/WebCore/platform/graphics/MediaPlayer.cpp b/WebCore/platform/graphics/MediaPlayer.cpp
index 2b09885..8a9a264 100644
--- a/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/WebCore/platform/graphics/MediaPlayer.cpp
@@ -69,6 +69,9 @@ public:
virtual void pause() { }
virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
virtual IntSize naturalSize() const { return IntSize(0, 0); }
@@ -364,6 +367,13 @@ PlatformMedia MediaPlayer::platformMedia() const
return m_private->platformMedia();
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayer::platformLayer() const
+{
+ return m_private->platformLayer();
+}
+#endif
+
MediaPlayer::NetworkState MediaPlayer::networkState()
{
return m_private->networkState();
diff --git a/WebCore/platform/graphics/MediaPlayer.h b/WebCore/platform/graphics/MediaPlayer.h
index 40ed8ae..1ca4576 100644
--- a/WebCore/platform/graphics/MediaPlayer.h
+++ b/WebCore/platform/graphics/MediaPlayer.h
@@ -39,6 +39,10 @@
#include <wtf/Noncopyable.h>
#include <wtf/PassOwnPtr.h>
+#if USE(ACCELERATED_COMPOSITING)
+#include "GraphicsLayer.h"
+#endif
+
#ifdef __OBJC__
@class QTMovie;
#else
@@ -67,10 +71,6 @@ class MediaPlayerPrivateInterface;
class String;
class TimeRanges;
-#if USE(ACCELERATED_COMPOSITING)
-class GraphicsLayer;
-#endif
-
class MediaPlayerClient {
public:
virtual ~MediaPlayerClient() { }
@@ -112,8 +112,9 @@ public:
// whether the rendering system can accelerate the display of this MediaPlayer.
virtual bool mediaPlayerRenderingCanBeAccelerated(MediaPlayer*) { return false; }
- // return the GraphicsLayer that will host the presentation for this MediaPlayer.
- virtual GraphicsLayer* mediaPlayerGraphicsLayer(MediaPlayer*) { return 0; }
+ // called when the media player's rendering mode changed, which indicates a change in the
+ // availability of the platformLayer().
+ virtual void mediaPlayerRenderingModeChanged(MediaPlayer*) { }
#endif
};
@@ -135,6 +136,9 @@ public:
bool supportsFullscreen() const;
bool supportsSave() const;
PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize();
bool hasVideo() const;
diff --git a/WebCore/platform/graphics/MediaPlayerPrivate.h b/WebCore/platform/graphics/MediaPlayerPrivate.h
index 3b7c4d4..3bb8475 100644
--- a/WebCore/platform/graphics/MediaPlayerPrivate.h
+++ b/WebCore/platform/graphics/MediaPlayerPrivate.h
@@ -45,6 +45,9 @@ public:
virtual void prepareToPlay() { }
virtual PlatformMedia platformMedia() const { return NoPlatformMedia; }
+#if USE(ACCELERATED_COMPOSITING)
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
virtual void play() = 0;
virtual void pause() = 0;
diff --git a/WebCore/platform/graphics/cg/GradientCG.cpp b/WebCore/platform/graphics/cg/GradientCG.cpp
index e9b5de7..9c91700 100644
--- a/WebCore/platform/graphics/cg/GradientCG.cpp
+++ b/WebCore/platform/graphics/cg/GradientCG.cpp
@@ -36,7 +36,7 @@ namespace WebCore {
void Gradient::platformDestroy()
{
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
CGShadingRelease(m_gradient);
#else
CGGradientRelease(m_gradient);
@@ -44,7 +44,7 @@ void Gradient::platformDestroy()
m_gradient = 0;
}
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
static void gradientCallback(void* info, const CGFloat* in, CGFloat* out)
{
float r, g, b, a;
@@ -114,7 +114,7 @@ void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
void Gradient::paint(GraphicsContext* context)
{
-#ifdef BUILDING_ON_TIGER
+#if USE_CG_SHADING
CGContextDrawShading(context->platformContext(), platformGradient());
#else
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
diff --git a/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
new file mode 100644
index 0000000..c6a8f83
--- /dev/null
+++ b/WebCore/platform/graphics/cg/GraphicsContext3DCG.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+
+#include <CoreGraphics/CGBitmapContext.h>
+#include <CoreGraphics/CGContext.h>
+#include <CoreGraphics/CGImage.h>
+
+namespace WebCore {
+
+bool GraphicsContext3D::getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format)
+{
+ if (!image)
+ return false;
+ CGImageRef cgImage = image->nativeImageForCurrentFrame();
+ if (!cgImage)
+ return false;
+ int width = CGImageGetWidth(cgImage);
+ int height = CGImageGetHeight(cgImage);
+ int rowBytes = width * 4;
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage);
+ *hasAlphaChannel = (info != kCGImageAlphaNone
+ && info != kCGImageAlphaNoneSkipLast
+ && info != kCGImageAlphaNoneSkipFirst);
+ if (!premultiplyAlpha && *hasAlphaChannel)
+ // FIXME: must fetch the image data before the premultiplication step
+ *neededAlphaOp = kAlphaDoUnmultiply;
+ *format = RGBA;
+ outputVector.resize(height * rowBytes);
+ // Try to reuse the color space from the image to preserve its colors.
+ // Some images use a color space (such as indexed) unsupported by the bitmap context.
+ CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
+ bool releaseColorSpace = false;
+ CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace);
+ switch (colorSpaceModel) {
+ case kCGColorSpaceModelMonochrome:
+ case kCGColorSpaceModelRGB:
+ case kCGColorSpaceModelCMYK:
+ case kCGColorSpaceModelLab:
+ case kCGColorSpaceModelDeviceN:
+ break;
+ default:
+ colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGBLinear);
+ releaseColorSpace = true;
+ break;
+ }
+ CGContextRef tmpContext = CGBitmapContextCreate(outputVector.data(),
+ width, height, 8, rowBytes,
+ colorSpace,
+ kCGImageAlphaPremultipliedLast);
+ if (releaseColorSpace)
+ CGColorSpaceRelease(colorSpace);
+ if (!tmpContext)
+ return false;
+ CGContextSetBlendMode(tmpContext, kCGBlendModeCopy);
+ CGContextDrawImage(tmpContext,
+ CGRectMake(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height)),
+ cgImage);
+ CGContextRelease(tmpContext);
+ return true;
+}
+
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
index e2c47c1..e71f66a 100644
--- a/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
+++ b/WebCore/platform/graphics/chromium/GlyphPageTreeNodeChromiumWin.cpp
@@ -134,7 +134,8 @@ static bool fillBMPGlyphs(unsigned offset,
// Copy the output to the GlyphPage
bool haveGlyphs = false;
int invalidGlyph = 0xFFFF;
- if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE))
+ const DWORD cffTableTag = 0x20464643; // 4-byte identifier for OpenType CFF table ('CFF ').
+ if (!isVistaOrNewer() && !(tm.tmPitchAndFamily & TMPF_TRUETYPE) && (GetFontData(dc, cffTableTag, 0, 0, 0) == GDI_ERROR))
invalidGlyph = 0x1F;
Glyph spaceGlyph = 0; // Glyph for a space. Lazily filled.
diff --git a/WebCore/platform/graphics/gtk/IconGtk.cpp b/WebCore/platform/graphics/gtk/IconGtk.cpp
index 3563a59..71b897e 100644
--- a/WebCore/platform/graphics/gtk/IconGtk.cpp
+++ b/WebCore/platform/graphics/gtk/IconGtk.cpp
@@ -87,6 +87,7 @@ static String lookupIconName(String MIMEType)
return GTK_STOCK_FILE;
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 1866c36..e1c9fd2 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -3,6 +3,7 @@
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
* Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+ * Copyright (C) 2009, 2010 Igalia S.L
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -52,20 +53,44 @@
#include <gst/video/video.h>
#include <limits>
#include <math.h>
-#include <webkit/webkitwebview.h>
#include <wtf/gtk/GOwnPtr.h>
+// GstPlayFlags flags from playbin2. It is the policy of GStreamer to
+// not publicly expose element-specific enums. That's why this
+// GstPlayFlags enum has been copied here.
+typedef enum {
+ GST_PLAY_FLAG_VIDEO = 0x00000001,
+ GST_PLAY_FLAG_AUDIO = 0x00000002,
+ GST_PLAY_FLAG_TEXT = 0x00000004,
+ GST_PLAY_FLAG_VIS = 0x00000008,
+ GST_PLAY_FLAG_SOFT_VOLUME = 0x00000010,
+ GST_PLAY_FLAG_NATIVE_AUDIO = 0x00000020,
+ GST_PLAY_FLAG_NATIVE_VIDEO = 0x00000040,
+ GST_PLAY_FLAG_DOWNLOAD = 0x00000080,
+ GST_PLAY_FLAG_BUFFERING = 0x000000100
+} GstPlayFlags;
+
using namespace std;
namespace WebCore {
+static int greatestCommonDivisor(int a, int b)
+{
+ while (b) {
+ int temp = a;
+ a = b;
+ b = temp % b;
+ }
+
+ return ABS(a);
+}
+
gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
{
GOwnPtr<GError> err;
GOwnPtr<gchar> debug;
MediaPlayer::NetworkState error;
MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
- gint percent = 0;
bool issueError = true;
bool attemptNextLocation = false;
@@ -115,8 +140,7 @@ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpo
mp->updateStates();
break;
case GST_MESSAGE_BUFFERING:
- gst_message_parse_buffering(message, &percent);
- LOG_VERBOSE(Media, "Buffering %d", percent);
+ mp->processBufferingStats(message);
break;
case GST_MESSAGE_DURATION:
LOG_VERBOSE(Media, "Duration changed");
@@ -174,6 +198,12 @@ gboolean notifyMuteIdleCallback(gpointer data)
return FALSE;
}
+gboolean bufferingTimeoutCallback(gpointer data)
+{
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ return mp->queryBufferingStats();
+}
+
static float playbackPosition(GstElement* playbin)
{
@@ -278,14 +308,24 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_playbackRate(1)
, m_errorOccured(false)
, m_volumeIdleId(0)
- , m_mediaDuration(0.0)
+ , m_mediaDuration(0)
, m_muteIdleId(0)
+ , m_startedBuffering(false)
+ , m_fillTimeoutId(0)
+ , m_maxTimeLoaded(0)
+ , m_fillStatus(0)
{
- doGstInit();
+ if (doGstInit())
+ createGSTPlayBin();
}
MediaPlayerPrivate::~MediaPlayerPrivate()
{
+ if (m_fillTimeoutId) {
+ g_source_remove(m_fillTimeoutId);
+ m_fillTimeoutId = 0;
+ }
+
if (m_volumeIdleId) {
g_source_remove(m_volumeIdleId);
m_volumeIdleId = 0;
@@ -338,7 +378,7 @@ void MediaPlayerPrivate::load(const String& url)
m_player->readyStateChanged();
}
- createGSTPlayBin(url);
+ g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
pause();
}
@@ -422,9 +462,6 @@ void MediaPlayerPrivate::seek(float time)
if (!m_playBin)
return;
- if (m_isStreaming)
- return;
-
if (m_errorOccured)
return;
@@ -473,30 +510,60 @@ IntSize MediaPlayerPrivate::naturalSize() const
if (!hasVideo())
return IntSize();
+ GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink");
+ if (!pad)
+ return IntSize();
+
+ int width = 0, height = 0;
+ GstCaps* caps = GST_PAD_CAPS(pad);
+ int pixelAspectRatioNumerator, pixelAspectRatioDenominator;
+ int displayWidth, displayHeight, displayAspectRatioGCD;
+ int originalWidth = 0, originalHeight = 0;
+
// TODO: handle possible clean aperture data. See
// https://bugzilla.gnome.org/show_bug.cgi?id=596571
// TODO: handle possible transformation matrix. See
// https://bugzilla.gnome.org/show_bug.cgi?id=596326
- int width = 0, height = 0;
- if (GstPad* pad = gst_element_get_static_pad(m_videoSink, "sink")) {
- GstCaps* caps = GST_PAD_CAPS(pad);
- gfloat pixelAspectRatio;
- gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
-
- if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
- || !gst_video_format_parse_caps(caps, 0, &width, &height)
- || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
- &pixelAspectRatioDenominator)) {
- gst_object_unref(GST_OBJECT(pad));
- return IntSize();
- }
- pixelAspectRatio = (gfloat) pixelAspectRatioNumerator / (gfloat) pixelAspectRatioDenominator;
- width *= pixelAspectRatio;
- height /= pixelAspectRatio;
+ // Get the video PAR and original size.
+ if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps)
+ || !gst_video_format_parse_caps(caps, 0, &originalWidth, &originalHeight)
+ || !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
+ &pixelAspectRatioDenominator)) {
gst_object_unref(GST_OBJECT(pad));
+ return IntSize();
}
+ gst_object_unref(GST_OBJECT(pad));
+
+ LOG_VERBOSE(Media, "Original video size: %dx%d", originalWidth, originalHeight);
+ LOG_VERBOSE(Media, "Pixel aspect ratio: %d/%d", pixelAspectRatioNumerator, pixelAspectRatioDenominator);
+
+ // Calculate DAR based on PAR and video size.
+ displayWidth = originalWidth * pixelAspectRatioNumerator;
+ displayHeight = originalHeight * pixelAspectRatioDenominator;
+
+ // Divide display width and height by their GCD to avoid possible overflows.
+ displayAspectRatioGCD = greatestCommonDivisor(displayWidth, displayHeight);
+ displayWidth /= displayAspectRatioGCD;
+ displayHeight /= displayAspectRatioGCD;
+
+ // Apply DAR to original video size. This is the same behavior as in xvimagesink's setcaps function.
+ if (!(originalHeight % displayHeight)) {
+ LOG_VERBOSE(Media, "Keeping video original height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = originalHeight;
+ } else if (!(originalWidth % displayWidth)) {
+ LOG_VERBOSE(Media, "Keeping video original width");
+ height = gst_util_uint64_scale_int(originalWidth, displayHeight, displayWidth);
+ width = originalWidth;
+ } else {
+ LOG_VERBOSE(Media, "Approximating while keeping original video height");
+ width = gst_util_uint64_scale_int(originalHeight, displayWidth, displayHeight);
+ height = originalHeight;
+ }
+
+ LOG_VERBOSE(Media, "Natural size: %dx%d", width, height);
return IntSize(width, height);
}
@@ -610,16 +677,79 @@ PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
return timeRanges.release();
}
+void MediaPlayerPrivate::processBufferingStats(GstMessage* message)
+{
+ GstBufferingMode mode;
+
+ gst_message_parse_buffering_stats(message, &mode, 0, 0, 0);
+ if (mode != GST_BUFFERING_DOWNLOAD)
+ return;
+
+ if (!m_startedBuffering) {
+ m_startedBuffering = true;
+
+ if (m_fillTimeoutId > 0)
+ g_source_remove(m_fillTimeoutId);
+
+ m_fillTimeoutId = g_timeout_add(200, (GSourceFunc) bufferingTimeoutCallback, this);
+ }
+}
+
+bool MediaPlayerPrivate::queryBufferingStats()
+{
+ GstQuery* query = gst_query_new_buffering(GST_FORMAT_PERCENT);
+
+ if (!gst_element_query(m_playBin, query)) {
+ gst_query_unref(query);
+ return TRUE;
+ }
+
+ gint64 start, stop;
+
+ gst_query_parse_buffering_range(query, 0, &start, &stop, 0);
+ gst_query_unref(query);
+
+ if (stop != -1)
+ m_fillStatus = 100.0 * stop / GST_FORMAT_PERCENT_MAX;
+ else
+ m_fillStatus = 100.0;
+
+ LOG_VERBOSE(Media, "Download buffer filled up to %f%%", m_fillStatus);
+
+ if (!m_mediaDuration)
+ durationChanged();
+
+ // Update maxTimeLoaded only if the media duration is
+ // available. Otherwise we can't compute it.
+ if (m_mediaDuration) {
+ m_maxTimeLoaded = static_cast<float>((m_fillStatus * m_mediaDuration) / 100.0);
+ LOG_VERBOSE(Media, "Updated maxTimeLoaded: %f", m_maxTimeLoaded);
+ }
+
+ if (m_fillStatus != 100.0) {
+ updateStates();
+ return TRUE;
+ }
+
+ // Media is now fully loaded. It will play even if network
+ // connection is cut. Buffering is done, remove the fill source
+ // from the main loop.
+ m_fillTimeoutId = 0;
+ m_startedBuffering = false;
+ updateStates();
+ return FALSE;
+}
+
float MediaPlayerPrivate::maxTimeSeekable() const
{
if (m_errorOccured)
return 0.0;
- // TODO
LOG_VERBOSE(Media, "maxTimeSeekable");
- if (m_isStreaming)
- return numeric_limits<float>::infinity();
// infinite duration means live stream
+ if (isinf(duration()))
+ return 0.0;
+
return maxTimeLoaded();
}
@@ -628,29 +758,28 @@ float MediaPlayerPrivate::maxTimeLoaded() const
if (m_errorOccured)
return 0.0;
- // TODO
- LOG_VERBOSE(Media, "maxTimeLoaded");
- notImplemented();
- return duration();
+ float loaded = m_maxTimeLoaded;
+ if (!loaded && !m_fillTimeoutId)
+ loaded = duration();
+ LOG_VERBOSE(Media, "maxTimeLoaded: %f", loaded);
+ return loaded;
}
unsigned MediaPlayerPrivate::bytesLoaded() const
{
- notImplemented();
- LOG_VERBOSE(Media, "bytesLoaded");
- /*if (!m_playBin)
+ if (!m_playBin)
return 0;
- float dur = duration();
- float maxTime = maxTimeLoaded();
- if (!dur)
- return 0;*/
- return 1; // totalBytes() * maxTime / dur;
+ if (!m_mediaDuration)
+ return 0;
+
+ unsigned loaded = totalBytes() * maxTimeLoaded() / m_mediaDuration;
+ LOG_VERBOSE(Media, "bytesLoaded: %d", loaded);
+ return loaded;
}
unsigned MediaPlayerPrivate::totalBytes() const
{
- LOG_VERBOSE(Media, "totalBytes");
if (!m_source)
return 0;
@@ -660,6 +789,7 @@ unsigned MediaPlayerPrivate::totalBytes() const
GstFormat fmt = GST_FORMAT_BYTES;
gint64 length = 0;
gst_element_query_duration(m_source, &fmt, &length);
+ LOG_VERBOSE(Media, "totalBytes %" G_GINT64_FORMAT, length);
return length;
}
@@ -710,6 +840,7 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_PLAYING) {
m_readyState = MediaPlayer::HaveEnoughData;
m_paused = false;
+ m_startedPlaying = true;
if (!m_mediaDuration) {
float newDuration = duration();
if (!isinf(newDuration))
@@ -718,6 +849,28 @@ void MediaPlayerPrivate::updateStates()
} else
m_paused = true;
+ // Is on-disk buffering in progress?
+ if (m_fillTimeoutId) {
+ m_networkState = MediaPlayer::Loading;
+ // Buffering has just started, we should now have enough
+ // data to restart playback if it was internally paused by
+ // GStreamer.
+ if (m_paused && !m_startedPlaying)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+
+ if (maxTimeLoaded() == duration()) {
+ m_networkState = MediaPlayer::Loaded;
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (state == GST_STATE_PAUSED)
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (m_paused)
+ m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
+
if (m_changingRate) {
m_player->rateChanged();
m_changingRate = false;
@@ -728,14 +881,24 @@ void MediaPlayerPrivate::updateStates()
m_seeking = false;
}
- m_networkState = MediaPlayer::Loaded;
break;
case GST_STATE_CHANGE_ASYNC:
LOG_VERBOSE(Media, "Async: State: %s, pending: %s",
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
// Change in progress
- return;
+
+ if (!m_isStreaming)
+ return;
+
+ // Resume playback if a seek was performed in a live pipeline.
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
+ break;
case GST_STATE_CHANGE_FAILURE:
LOG_VERBOSE(Media, "Failure: State: %s, pending: %s",
gst_element_state_get_name(state),
@@ -749,8 +912,25 @@ void MediaPlayerPrivate::updateStates()
if (state == GST_STATE_READY)
m_readyState = MediaPlayer::HaveNothing;
- else if (state == GST_STATE_PAUSED)
- m_readyState = MediaPlayer::HaveCurrentData;
+ else if (state == GST_STATE_PAUSED) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_paused = true;
+ // Live pipelines go in PAUSED without prerolling.
+ m_isStreaming = true;
+ } else if (state == GST_STATE_PLAYING) {
+ m_startedPlaying = true;
+ m_paused = false;
+ }
+
+ if (m_paused && !m_startedPlaying)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+
+ if (m_seeking) {
+ shouldUpdateAfterSeek = true;
+ m_seeking = false;
+ if (m_paused)
+ gst_element_set_state(m_playBin, GST_STATE_PLAYING);
+ }
m_networkState = MediaPlayer::Loading;
break;
@@ -898,8 +1078,11 @@ void MediaPlayerPrivate::didEnd()
// not always 0. So to not confuse the HTMLMediaElement we
// synchronize position and duration values.
float now = currentTime();
- if (now > 0)
+ if (now > 0) {
m_mediaDuration = now;
+ m_player->durationChanged();
+ }
+
gst_element_set_state(m_playBin, GST_STATE_PAUSED);
timeChanged();
@@ -1150,7 +1333,19 @@ bool MediaPlayerPrivate::supportsFullscreen() const
return true;
}
-void MediaPlayerPrivate::createGSTPlayBin(String url)
+void MediaPlayerPrivate::setAutobuffer(bool autoBuffer)
+{
+ ASSERT(m_playBin);
+
+ GstPlayFlags flags;
+ g_object_get(m_playBin, "flags", &flags, NULL);
+ if (autoBuffer)
+ g_object_set(m_playBin, "flags", flags | GST_PLAY_FLAG_DOWNLOAD, NULL);
+ else
+ g_object_set(m_playBin, "flags", flags & ~GST_PLAY_FLAG_DOWNLOAD, NULL);
+}
+
+void MediaPlayerPrivate::createGSTPlayBin()
{
ASSERT(!m_playBin);
m_playBin = gst_element_factory_make("playbin2", "play");
@@ -1160,8 +1355,6 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
gst_object_unref(bus);
- g_object_set(m_playBin, "uri", url.utf8().data(), NULL);
-
g_signal_connect(m_playBin, "notify::volume", G_CALLBACK(mediaPlayerPrivateVolumeChangedCallback), this);
g_signal_connect(m_playBin, "notify::source", G_CALLBACK(mediaPlayerPrivateSourceChangedCallback), this);
g_signal_connect(m_playBin, "notify::mute", G_CALLBACK(mediaPlayerPrivateMuteChangedCallback), this);
@@ -1180,7 +1373,7 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
} else {
m_fpsSink = 0;
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
- LOG(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
+ LOG_VERBOSE(Media, "Can't display FPS statistics, you need gst-plugins-bad >= 0.10.18");
}
} else
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index 34257ca..e19b686 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -2,6 +2,7 @@
* Copyright (C) 2007, 2009 Apple Inc. All rights reserved.
* Copyright (C) 2007 Collabora Ltd. All rights reserved.
* Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ * Copyright (C) 2009, 2010 Igalia S.L
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -86,6 +87,9 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
void muteChanged();
void muteChangedCallback();
+ void setAutobuffer(bool);
+ bool queryBufferingStats();
+
MediaPlayer::NetworkState networkState() const;
MediaPlayer::ReadyState readyState() const;
@@ -128,9 +132,11 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
float maxTimeLoaded() const;
void startEndPointTimerIfNeeded();
- void createGSTPlayBin(String url);
+ void createGSTPlayBin();
bool changePipelineState(GstState state);
+ void processBufferingStats(GstMessage* message);
+
private:
MediaPlayer* m_player;
GstElement* m_playBin;
@@ -157,6 +163,10 @@ class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
guint m_volumeIdleId;
gfloat m_mediaDuration;
guint m_muteIdleId;
+ bool m_startedBuffering;
+ guint m_fillTimeoutId;
+ float m_maxTimeLoaded;
+ gdouble m_fillStatus;
};
}
diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
index 390c0ec..74a7852 100644
--- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2009, 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -79,6 +79,10 @@ struct _WebKitWebSrcPrivate {
gchar* iradioGenre;
gchar* iradioUrl;
gchar* iradioTitle;
+
+ // TRUE if appsrc's version is >= 0.10.27, see
+ // https://bugzilla.gnome.org/show_bug.cgi?id=609423
+ gboolean haveAppSrc27;
};
enum {
@@ -109,7 +113,7 @@ static void webKitWebSrcNeedDataCb(GstAppSrc* appsrc, guint length, gpointer use
static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData);
static gboolean webKitWebSrcSeekDataCb(GstAppSrc* appsrc, guint64 offset, gpointer userData);
-static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset);
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking);
static GstAppSrcCallbacks appsrcCallbacks = {
webKitWebSrcNeedDataCb,
@@ -222,6 +226,9 @@ static void webkit_web_src_init(WebKitWebSrc* src,
return;
}
+ GstElementFactory* factory = GST_ELEMENT_FACTORY(GST_ELEMENT_GET_CLASS(priv->appsrc)->elementfactory);
+ priv->haveAppSrc27 = gst_plugin_feature_check_version(GST_PLUGIN_FEATURE(factory), 0, 10, 27);
+
gst_bin_add(GST_BIN(src), GST_ELEMENT(priv->appsrc));
targetpad = gst_element_get_static_pad(GST_ELEMENT(priv->appsrc), "src");
@@ -238,7 +245,20 @@ static void webkit_web_src_init(WebKitWebSrc* src,
// GStreamer to handle.
gst_app_src_set_max_bytes(priv->appsrc, 512 * 1024);
- webKitWebSrcStop(src, true);
+ // Emit the need-data signal if the queue contains less
+ // than 20% of data. Without this the need-data signal
+ // is emitted when the queue is empty, we then dispatch
+ // the soup message unpausing to the main loop and from
+ // there unpause the soup message. This already takes
+ // quite some time and libsoup even needs some more time
+ // to actually provide data again. If we do all this
+ // already if the queue is 20% empty, it's much more
+ // likely that libsoup already provides new data before
+ // the queue is really empty.
+ if (priv->haveAppSrc27)
+ g_object_set(priv->appsrc, "min-percent", 20, NULL);
+
+ webKitWebSrcStop(src, false);
}
static void webKitWebSrcFinalize(GObject* object)
@@ -296,7 +316,7 @@ static void webKitWebSrcGetProperty(GObject* object, guint propID, GValue* value
}
-static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset)
+static void webKitWebSrcStop(WebKitWebSrc* src, bool seeking)
{
WebKitWebSrcPrivate* priv = src->priv;
@@ -335,15 +355,19 @@ static void webKitWebSrcStop(WebKitWebSrc* src, bool resetRequestedOffset)
g_free(priv->iradioTitle);
priv->iradioTitle = 0;
- if (priv->appsrc)
+ if (priv->appsrc) {
gst_app_src_set_caps(priv->appsrc, 0);
+ if (!seeking)
+ gst_app_src_set_size(priv->appsrc, -1);
+ }
priv->offset = 0;
- priv->size = 0;
priv->seekable = FALSE;
- if (resetRequestedOffset)
+ if (!seeking) {
+ priv->size = 0;
priv->requestedOffset = 0;
+ }
GST_DEBUG_OBJECT(src, "Stopped request");
}
@@ -434,7 +458,7 @@ static GstStateChangeReturn webKitWebSrcChangeState(GstElement* element, GstStat
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
GST_DEBUG_OBJECT(src, "PAUSED->READY");
- webKitWebSrcStop(src, true);
+ webKitWebSrcStop(src, false);
break;
default:
break;
@@ -558,7 +582,7 @@ static void webKitWebSrcEnoughDataCb(GstAppSrc* appsrc, gpointer userData)
static gboolean webKitWebSrcSeekMainCb(WebKitWebSrc* src)
{
- webKitWebSrcStop(src, false);
+ webKitWebSrcStop(src, true);
webKitWebSrcStart(src);
return FALSE;
@@ -617,7 +641,8 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse
// If we seeked we need 206 == PARTIAL_CONTENT
if (priv->requestedOffset && response.httpStatusCode() != 206) {
GST_ELEMENT_ERROR(m_src, RESOURCE, READ, (0), (0));
- webKitWebSrcStop(m_src, true);
+ gst_app_src_end_of_stream(priv->appsrc);
+ webKitWebSrcStop(m_src, false);
return;
}
@@ -625,6 +650,12 @@ void StreamingClient::didReceiveResponse(ResourceHandle*, const ResourceResponse
if (length > 0) {
length += priv->requestedOffset;
gst_app_src_set_size(priv->appsrc, length);
+ if (!priv->haveAppSrc27) {
+ gst_segment_set_duration(&GST_BASE_SRC(priv->appsrc)->segment, GST_FORMAT_BYTES, length);
+ gst_element_post_message(GST_ELEMENT(priv->appsrc),
+ gst_message_new_duration(GST_OBJECT(priv->appsrc),
+ GST_FORMAT_BYTES, length));
+ }
}
priv->size = length >= 0 ? length : 0;
diff --git a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
index 045e7d7..ae19640 100644
--- a/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
+++ b/WebCore/platform/graphics/gtk/WebKitWebSourceGStreamer.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ * Copyright (C) 2009,2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
index 99ad130..096cdbd 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
@@ -1126,31 +1126,6 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long
return reinterpret_cast<long>(pointer);
}
-// Returned pointer must be freed by fastFree()
-static bool imageToTexture(Image* image, GLubyte*& buffer, size_t& width, size_t& height)
-{
- if (!image)
- return false;
-
- CGImageRef textureImage = image->getCGImageRef();
- if (!textureImage)
- return false;
-
- width = CGImageGetWidth(textureImage);
- height = CGImageGetHeight(textureImage);
-
- buffer = (GLubyte*) fastMalloc(width * height * 4);
- if (!buffer)
- return false;
-
- CGContextRef textureContext = CGBitmapContextCreate(buffer, width, height, 8, width * 4,
- CGImageGetColorSpace(textureImage), kCGImageAlphaPremultipliedLast);
- CGContextSetBlendMode(textureContext, kCGBlendModeCopy);
- CGContextDrawImage(textureContext, CGRectMake(0, 0, (CGFloat)width, (CGFloat)height), textureImage);
- CGContextRelease(textureContext);
- return true;
-}
-
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels)
{
// FIXME: Need to do bounds checking on the buffer here.
@@ -1160,20 +1135,12 @@ int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned inte
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
{
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- ASSERT(image);
-
ensureContext(m_contextObj);
- GLubyte* buffer;
- size_t width;
- size_t height;
- if (!imageToTexture(image, buffer, width, height))
+ Vector<uint8_t> imageData;
+ unsigned int format, internalFormat;
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat))
return -1;
-
- ::glTexImage2D(target, level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
- fastFree(buffer);
+ ::glTexImage2D(target, level, internalFormat, image->width(), image->height(), 0, format, GL_UNSIGNED_BYTE, imageData.data());
return 0;
}
@@ -1188,20 +1155,12 @@ int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned x
int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha)
{
// FIXME: we will need to deal with PixelStore params when dealing with image buffers that differ from the subimage size
- // FIXME: need to support flipY and premultiplyAlpha
- UNUSED_PARAM(flipY);
- UNUSED_PARAM(premultiplyAlpha);
- ASSERT(image);
-
ensureContext(m_contextObj);
- GLubyte* buffer;
- size_t width;
- size_t height;
- if (!imageToTexture(image, buffer, width, height))
+ Vector<uint8_t> imageData;
+ unsigned int format, internalFormat;
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat))
return -1;
-
- ::glTexSubImage2D(target, level, xoff, yoff, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
- fastFree(buffer);
+ ::glTexSubImage2D(target, level, xoff, yoff, image->width(), image->height(), format, GL_UNSIGNED_BYTE, imageData.data());
return 0;
}
diff --git a/WebCore/platform/graphics/mac/IconMac.mm b/WebCore/platform/graphics/mac/IconMac.mm
index aee7234..bc8c312 100644
--- a/WebCore/platform/graphics/mac/IconMac.mm
+++ b/WebCore/platform/graphics/mac/IconMac.mm
@@ -39,6 +39,7 @@ Icon::~Icon()
{
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
index e9f64be..355aa68 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.h
@@ -78,6 +78,9 @@ private:
static bool isAvailable();
PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize() const;
bool hasVideo() const;
diff --git a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
index dd87bb5..2b90f7a 100644
--- a/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
+++ b/WebCore/platform/graphics/mac/MediaPlayerPrivateQTKit.mm
@@ -445,12 +445,7 @@ void MediaPlayerPrivate::createQTMovieLayer()
#ifndef NDEBUG
[(CALayer *)m_qtVideoLayer.get() setName:@"Video layer"];
#endif
-
- // Hang the video layer from the render layer, if we have one yet. If not, we'll do this
- // later via acceleratedRenderingStateChanged().
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
}
#endif
}
@@ -522,6 +517,11 @@ void MediaPlayerPrivate::setUpVideoRendering()
createQTMovieLayer();
break;
}
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
}
void MediaPlayerPrivate::tearDownVideoRendering()
@@ -576,6 +576,13 @@ PlatformMedia MediaPlayerPrivate::platformMedia() const
return plaftformMedia;
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer.get();
+}
+#endif
+
void MediaPlayerPrivate::play()
{
if (!metaDataAvailable())
@@ -1406,12 +1413,6 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged()
{
// Set up or change the rendering path if necessary.
setUpVideoRendering();
-
- if (currentRenderingMode() == MediaRenderingMovieLayer) {
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (videoGraphicsLayer)
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer.get());
- }
}
#endif
diff --git a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
index ef7c58f..09947d8 100644
--- a/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
+++ b/WebCore/platform/graphics/mac/SimpleFontDataMac.mm
@@ -273,37 +273,54 @@ void SimpleFontData::platformInit()
} else
m_xHeight = [m_platformData.font() xHeight];
}
+
+static CFDataRef copyFontTableForTag(FontPlatformData platformData, FourCharCode tableName)
+{
+#ifdef BUILDING_ON_TIGER
+ ATSFontRef atsFont = FMGetATSFontRefFromFont(platformData.m_atsuFontID);
+
+ ByteCount tableSize;
+ if (ATSFontGetTable(atsFont, tableName, 0, 0, NULL, &tableSize) != noErr)
+ return 0;
+
+ CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, tableSize);
+ if (!data)
+ return 0;
+
+ CFDataIncreaseLength(data, tableSize);
+ if (ATSFontGetTable(atsFont, tableName, 0, tableSize, CFDataGetMutableBytePtr(data), &tableSize) != noErr) {
+ CFRelease(data);
+ return 0;
+ }
+
+ return data;
+#else
+ return CGFontCopyTableForTag(platformData.cgFont(), tableName);
+#endif
+}
void SimpleFontData::platformCharWidthInit()
{
- m_avgCharWidth = 0.f;
-
- // Calculate avgCharWidth according to http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6OS2.html
- // We can try grabbing it out of the OS/2 table or via ATSFontGetHorizontalMetrics, but
- // ATSFontGetHorizontalMetrics never seems to return a non-zero value and the OS/2 table
- // contains zero for a large number of fonts.
- GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
- if (glyphPageZero) {
- static int weights[] = { 64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2, 166 };
- int numGlyphs = 27;
- ASSERT(numGlyphs == sizeof(weights) / sizeof(int));
- // Compute the weighted sum of the space character and the lowercase letters in the Latin alphabet.
- float sum = 0.f;
- int totalWeight = 0;
- for (int i = 0; i < numGlyphs; i++) {
- Glyph glyph = glyphPageZero->glyphDataForCharacter((i < 26 ? i + 'a' : ' ')).glyph;
- if (glyph) {
- totalWeight += weights[i];
- sum += widthForGlyph(glyph) * weights[i];
- }
- }
- if (sum > 0.f && totalWeight > 0)
- m_avgCharWidth = sum / totalWeight;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+
+ RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, 'OS/2'));
+ if (os2Table && CFDataGetLength(os2Table.get()) >= 4) {
+ const UInt8* os2 = CFDataGetBytePtr(os2Table.get());
+ SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3];
+ m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_unitsPerEm) * m_platformData.m_size;
}
- m_maxCharWidth = 0.f;
- if (m_platformData.font())
- m_maxCharWidth = [m_platformData.font() maximumAdvancement].width;
+ RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData, 'head'));
+ if (headTable && CFDataGetLength(headTable.get()) >= 42) {
+ const UInt8* head = CFDataGetBytePtr(headTable.get());
+ ushort uxMin = head[36] * 256 + head[37];
+ ushort uxMax = head[40] * 256 + head[41];
+ SInt16 xMin = static_cast<SInt16>(uxMin);
+ SInt16 xMax = static_cast<SInt16>(uxMax);
+ float diff = static_cast<float>(xMax - xMin);
+ m_maxCharWidth = scaleEmToUnits(diff, m_unitsPerEm) * m_platformData.m_size;
+ }
// Fallback to a cross-platform estimate, which will populate these values if they are non-positive.
initCharWidths();
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 105d866..8bcda2e 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -219,6 +219,7 @@ public:
QStack<TransparencyLayer*> layers;
QPainter* redirect;
+ // reuse this brush for solid color (to prevent expensive QBrush construction)
QBrush solidColor;
InterpolationQuality imageInterpolationQuality;
@@ -760,11 +761,30 @@ void GraphicsContext::drawLineForMisspellingOrBadGrammar(const IntPoint&, int, b
FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
{
- QRectF rect(frect);
- rect = m_data->p()->deviceMatrix().mapRect(rect);
+ // It is not enough just to round to pixels in device space. The rotation part of the
+ // affine transform matrix to device space can mess with this conversion if we have a
+ // rotating image like the hands of the world clock widget. We just need the scale, so
+ // we get the affine transform matrix and extract the scale.
+ QPainter* painter = platformContext();
+ QTransform deviceTransform = painter->deviceTransform();
+ if (deviceTransform.isIdentity())
+ return frect;
- QRect result = rect.toRect(); //round it
- return FloatRect(QRectF(result));
+ qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
+ qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
+
+ QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
+ QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY);
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
+ deviceLowerRight.setY(deviceLowerRight.y() + 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
+ deviceLowerRight.setX(deviceLowerRight.x() + 1);
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
}
void GraphicsContext::setPlatformShadow(const IntSize& size, int, const Color&, ColorSpace)
@@ -1112,7 +1132,8 @@ void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colo
return;
QPainter* p = m_data->p();
QPen newPen(p->pen());
- newPen.setColor(color);
+ m_data->solidColor.setColor(color);
+ newPen.setBrush(m_data->solidColor);
p->setPen(newPen);
}
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
index 11f7384..0fd0f1a 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -136,7 +136,9 @@ public:
virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
// we manage transforms ourselves because transform-origin acts differently in webkit and in Qt
- void setBaseTransform(const QTransform&);
+ void setBaseTransform(const TransformationMatrix&);
+ QTransform computeTransform(const TransformationMatrix& baseTransform) const;
+ void updateTransform();
// let the compositor-API tell us which properties were changed
void notifyChange(ChangeMask);
@@ -145,7 +147,7 @@ public:
// this is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
// (meaning the sync would happen together with the next draw)
// or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
- void flushChanges(bool recursive = true);
+ void flushChanges(bool recursive = true, bool forceTransformUpdate = false);
// optimization: when we have an animation running on an element with no contents, that has child-elements with contents,
// ALL of them have to have ItemCoordinateCache and not DeviceCoordinateCache
@@ -166,7 +168,7 @@ signals:
public:
GraphicsLayerQt* m_layer;
- QTransform m_baseTransform;
+ TransformationMatrix m_baseTransform;
bool m_transformAnimationRunning;
bool m_opacityAnimationRunning;
QWeakPointer<MaskEffectQt> m_maskEffect;
@@ -237,7 +239,10 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
{
// we use graphics-view for compositing, not for interactivity
setAcceptedMouseButtons(Qt::NoButton);
- setEnabled(false);
+ // we need to have the item enabled, or else wheel events are not
+ // passed to the parent class implementation of wheelEvent, where
+ // they are ignored and passed to the item below.
+ setEnabled(true);
// we'll set the cache when we know what's going on
setCacheMode(NoCache);
@@ -280,18 +285,54 @@ void GraphicsLayerQtImpl::adjustCachingRecursively(bool animationIsRunning)
}
}
-void GraphicsLayerQtImpl::setBaseTransform(const QTransform& transform)
+void GraphicsLayerQtImpl::updateTransform()
+{
+ setBaseTransform(isTransformAnimationRunning() ? m_baseTransform : m_layer->transform());
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
+{
+ m_baseTransform = baseTransform;
+ setTransform(computeTransform(baseTransform));
+}
+
+QTransform GraphicsLayerQtImpl::computeTransform(const TransformationMatrix& baseTransform) const
{
if (!m_layer)
- return;
+ return baseTransform;
+
+ TransformationMatrix computedTransform;
+
+ // The origin for childrenTransform is always the center of the ancestor which contains the childrenTransform.
+ // this has to do with how WebCore implements -webkit-perspective and -webkit-perspective-origin, which are the CSS
+ // attribute that call setChildrenTransform
+ QPointF offset = -pos() - boundingRect().bottomRight() / 2;
+ const GraphicsLayerQtImpl* ancestor = this;
+ while ((ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject()))) {
+ if (!ancestor->m_state.childrenTransform.isIdentity()) {
+ offset += ancestor->boundingRect().bottomRight() / 2;
+ computedTransform
+ .translate(offset.x(), offset.y())
+ .multLeft(ancestor->m_state.childrenTransform)
+ .translate(-offset.x(), -offset.y());
+ break;
+ }
+ offset -= ancestor->pos();
+ }
+
+ computedTransform.multLeft(baseTransform);
+
// webkit has relative-to-size originPoint, graphics-view has a pixel originPoint, here we convert
// we have to manage this ourselves because QGraphicsView's transformOrigin is incompatible
- const qreal x = m_layer->anchorPoint().x() * m_layer->size().width();
- const qreal y = m_layer->anchorPoint().y() * m_layer->size().height();
- setTransform(QTransform::fromTranslate(x, y));
- setTransform(transform, true);
- translate(-x, -y);
- m_baseTransform = transform;
+ const qreal originX = m_state.anchorPoint.x() * m_size.width();
+ const qreal originY = m_state.anchorPoint.y() * m_size.height();
+ computedTransform = TransformationMatrix()
+ .translate(originX, originY)
+ .multiply(computedTransform)
+ .translate(-originX, -originY);
+
+ // now we project to 2D
+ return QTransform(computedTransform);
}
bool GraphicsLayerQtImpl::isTransformAnimationRunning() const
@@ -357,7 +398,7 @@ void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
m_layer->client()->notifySyncRequired(m_layer);
}
-void GraphicsLayerQtImpl::flushChanges(bool recursive)
+void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
{
// this is the bulk of the work. understanding what the compositor is trying to achieve,
// what graphics-view can do, and trying to find a sane common-grounds
@@ -425,12 +466,15 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
}
}
- if (m_changeMask & (TransformChange | AnchorPointChange | SizeChange)) {
- // since we convert a percentage-based origin-point to a pixel-based one,
- // the anchor-point, transform and size from WebCore all affect the one
- // that we give Qt
- if (m_state.transform != m_layer->transform() || m_state.anchorPoint != m_layer->anchorPoint() || m_state.size != m_layer->size())
- setBaseTransform(m_layer->transform());
+ // FIXME: this is a hack, due to a probable QGraphicsScene bug when rapidly modifying the perspective
+ // but without this line we get graphic artifacts
+ if ((m_changeMask & ChildrenTransformChange) && m_state.childrenTransform != m_layer->childrenTransform())
+ scene()->update();
+
+ if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange)) {
+ // due to the differences between the way WebCore handles transforms and the way Qt handles transforms,
+ // all these elements affect the transforms of all the descendants.
+ forceUpdateTransform = true;
}
if (m_changeMask & (ContentChange | DrawsContentChange | MaskLayerChange)) {
@@ -439,8 +483,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
update();
setFlag(ItemHasNoContents, false);
- // we only use ItemUsesExtendedStyleOption for HTML content - pixmap can be handled better with regular clipping
- setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
break;
case ColorContentType:
@@ -524,6 +566,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
m_state.drawsContent = m_layer->drawsContent();
m_state.contentsOpaque = m_layer->contentsOpaque();
m_state.backfaceVisibility = m_layer->backfaceVisibility();
+ m_state.childrenTransform = m_layer->childrenTransform();
m_currentContent.pixmap = m_pendingContent.pixmap;
m_currentContent.contentType = m_pendingContent.contentType;
m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
@@ -534,6 +577,9 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive)
afterLayerChanges:
+ if (forceUpdateTransform)
+ updateTransform();
+
if (!recursive)
return;
@@ -544,7 +590,7 @@ afterLayerChanges:
for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
if (QGraphicsItem* item = *it)
if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject()))
- layer->flushChanges(true);
+ layer->flushChanges(true, forceUpdateTransform);
}
}
@@ -1013,7 +1059,7 @@ public:
// this came up during the compositing/animation LayoutTests
// when the animation dies, the transform has to go back to default
if (m_layer)
- m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
+ m_layer.data()->updateTransform();
}
// the idea is that we let WebCore manage the transform-operations
diff --git a/WebCore/platform/graphics/qt/IconQt.cpp b/WebCore/platform/graphics/qt/IconQt.cpp
index a9870fc..eb09eda 100644
--- a/WebCore/platform/graphics/qt/IconQt.cpp
+++ b/WebCore/platform/graphics/qt/IconQt.cpp
@@ -40,6 +40,7 @@ Icon::~Icon()
{
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index 234f78b..18e7f08 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -102,7 +102,7 @@ size_t ImageDecoderQt::frameCount()
// Fixup for Qt decoders... imageCount() is wrong
// and jumpToNextImage does not work either... so
// we will have to parse everything...
- if (imageCount == 0)
+ if (!imageCount)
forceLoadEverything();
else
m_frameBufferCache.resize(imageCount);
@@ -132,13 +132,13 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
// In case the ImageDecoderQt got recreated we don't know
// yet how many images we are going to have and need to
// find that out now.
- int count = m_frameBufferCache.size();
- if (!m_failed && count == 0) {
+ size_t count = m_frameBufferCache.size();
+ if (!m_failed && !count) {
internalDecodeSize();
count = frameCount();
}
- if (index >= static_cast<size_t>(count))
+ if (index >= count)
return 0;
RGBA32Buffer& frame = m_frameBufferCache[index];
@@ -215,7 +215,7 @@ void ImageDecoderQt::forceLoadEverything()
do {
m_frameBufferCache.resize(++imageCount);
internalHandleCurrentImage(imageCount - 1);
- } while(!m_failed);
+ } while (!m_failed);
// If we failed decoding the first image we actually
// have no images and need to keep m_failed set to
diff --git a/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
new file mode 100644
index 0000000..cd86e6d
--- /dev/null
+++ b/WebCore/platform/graphics/skia/GraphicsContext3DSkia.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Google 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.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "GraphicsContext3D.h"
+
+#include "Image.h"
+#include "NativeImageSkia.h"
+
+namespace WebCore {
+
+bool GraphicsContext3D::getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format)
+{
+ if (!image)
+ return false;
+ NativeImageSkia* skiaImage = image->nativeImageForCurrentFrame();
+ if (!skiaImage)
+ return false;
+ SkBitmap::Config skiaConfig = skiaImage->config();
+ // FIXME: must support more image configurations.
+ if (skiaConfig != SkBitmap::kARGB_8888_Config)
+ return false;
+ SkBitmap& skiaImageRef = *skiaImage;
+ SkAutoLockPixels lock(skiaImageRef);
+ int width = skiaImage->width();
+ int height = skiaImage->height();
+ int rowBytes = skiaImage->rowBytes();
+ ASSERT(rowBytes == width * 4);
+ uint8_t* pixels = reinterpret_cast<uint8_t*>(skiaImage->getPixels());
+ outputVector.resize(rowBytes * height);
+ memcpy(outputVector.data(), pixels, rowBytes * height);
+ *hasAlphaChannel = true;
+ if (!premultiplyAlpha)
+ // FIXME: must fetch the image data before the premultiplication step
+ *neededAlphaOp = kAlphaDoUnmultiply;
+ // FIXME: remove this dependency on desktop OpenGL
+ *format = 0x80E1; // GL_BGRA
+ return true;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 92a1870..e0f6f5d 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -344,15 +344,6 @@ void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
paint->setShader(m_state->m_fillShader);
}
-static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max)
-{
- if (v < min)
- return min;
- if (v > max)
- return max;
- return v;
-}
-
float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
{
setupPaintCommon(paint);
@@ -361,13 +352,10 @@ float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, i
paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
paint->setShader(m_state->m_strokeShader);
paint->setStyle(SkPaint::kStroke_Style);
- // The limits here (512 and 256) were made up but are hopefully large
- // enough to be reasonable. They are, empirically, small enough not to
- // cause overflows in Skia.
- paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512));
+ paint->setStrokeWidth(SkFloatToScalar(width));
paint->setStrokeCap(m_state->m_lineCap);
paint->setStrokeJoin(m_state->m_lineJoin);
- paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256));
+ paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
if (m_state->m_dash)
paint->setPathEffect(m_state->m_dash);
diff --git a/WebCore/platform/graphics/win/IconWin.cpp b/WebCore/platform/graphics/win/IconWin.cpp
index 56b46de..cc9343a 100644
--- a/WebCore/platform/graphics/win/IconWin.cpp
+++ b/WebCore/platform/graphics/win/IconWin.cpp
@@ -47,6 +47,7 @@ Icon::~Icon()
DestroyIcon(m_hIcon);
}
+// FIXME: Move the code to ChromeClient::iconForFiles().
PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
{
if (filenames.isEmpty())
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
index b2fe069..1df73a7 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.cpp
@@ -108,6 +108,13 @@ PlatformMedia MediaPlayerPrivate::platformMedia() const
return p;
}
+#if USE(ACCELERATED_COMPOSITING)
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_qtVideoLayer->platformLayer();
+}
+#endif
+
class TaskTimer : TimerBase {
public:
static void initialize();
@@ -745,6 +752,11 @@ void MediaPlayerPrivate::setUpVideoRendering()
if (preferredMode == MediaRenderingMovieLayer)
createLayerForMovie();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
+ m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
+#endif
}
void MediaPlayerPrivate::tearDownVideoRendering()
@@ -810,11 +822,6 @@ void MediaPlayerPrivate::createLayerForMovie()
if (!m_qtMovie || m_qtVideoLayer)
return;
- // Do nothing if the parent layer hasn't been set up yet.
- GraphicsLayer* videoGraphicsLayer = m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player);
- if (!videoGraphicsLayer)
- return;
-
// Create a GraphicsLayer that won't be inserted directly into the render tree, but will used
// as a wrapper for a WKCACFLayer which gets inserted as the content layer of the video
// renderer's GraphicsLayer.
@@ -829,9 +836,7 @@ void MediaPlayerPrivate::createLayerForMovie()
#ifndef NDEBUG
m_qtVideoLayer->setName("Video layer");
#endif
-
- // Hang the video layer from the render layer.
- videoGraphicsLayer->setContentsToMedia(m_qtVideoLayer->platformLayer());
+ // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
#endif
}
@@ -858,7 +863,7 @@ void MediaPlayerPrivate::acceleratedRenderingStateChanged()
void MediaPlayerPrivate::notifySyncRequired(const GraphicsLayer*)
{
- GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_player->mediaPlayerClient()->mediaPlayerGraphicsLayer(m_player));
+ GraphicsLayerCACF* videoGraphicsLayer = static_cast<GraphicsLayerCACF*>(m_qtVideoLayer.get());
if (videoGraphicsLayer)
videoGraphicsLayer->notifySyncRequired();
}
diff --git a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
index d58f44f..029a520 100644
--- a/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
+++ b/WebCore/platform/graphics/win/MediaPlayerPrivateQuickTimeWin.h
@@ -76,6 +76,9 @@ private:
virtual bool supportsFullscreen() const;
virtual PlatformMedia platformMedia() const;
+#if USE(ACCELERATED_COMPOSITING)
+ PlatformLayer* platformLayer() const;
+#endif
IntSize naturalSize() const;
bool hasVideo() const;