summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'WebCore/platform/graphics')
-rw-r--r--WebCore/platform/graphics/GraphicsContext.h5
-rw-r--r--WebCore/platform/graphics/GraphicsContext3D.h23
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.cpp16
-rw-r--r--WebCore/platform/graphics/GraphicsLayer.h11
-rw-r--r--WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp5
-rw-r--r--WebCore/platform/graphics/cg/GraphicsContextCG.cpp5
-rw-r--r--WebCore/platform/graphics/chromium/FontLinux.cpp25
-rw-r--r--WebCore/platform/graphics/filters/FEColorMatrix.cpp5
-rw-r--r--WebCore/platform/graphics/filters/FEComponentTransfer.cpp10
-rw-r--r--WebCore/platform/graphics/filters/FEGaussianBlur.cpp140
-rw-r--r--WebCore/platform/graphics/filters/FEGaussianBlur.h57
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.cpp7
-rw-r--r--WebCore/platform/graphics/filters/FilterEffect.h18
-rw-r--r--WebCore/platform/graphics/filters/SourceAlpha.cpp2
-rw-r--r--WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp2
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp234
-rw-r--r--WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h19
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp289
-rw-r--r--WebCore/platform/graphics/gtk/VideoSinkGStreamer.h10
-rw-r--r--WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp5
-rw-r--r--WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp16
-rw-r--r--WebCore/platform/graphics/mac/Canvas3DLayer.h4
-rw-r--r--WebCore/platform/graphics/mac/Canvas3DLayer.mm63
-rw-r--r--WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp168
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.h2
-rw-r--r--WebCore/platform/graphics/mac/GraphicsLayerCA.mm34
-rw-r--r--WebCore/platform/graphics/mac/WebLayer.mm2
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp5
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp62
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h4
-rw-r--r--WebCore/platform/graphics/skia/GraphicsContextSkia.cpp16
-rw-r--r--WebCore/platform/graphics/skia/PathSkia.cpp21
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.cpp64
-rw-r--r--WebCore/platform/graphics/skia/PlatformContextSkia.h2
-rw-r--r--WebCore/platform/graphics/skia/SkiaUtils.cpp11
-rw-r--r--WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp2
-rw-r--r--WebCore/platform/graphics/wince/GraphicsContextWince.cpp5
-rw-r--r--WebCore/platform/graphics/wx/GraphicsContextWx.cpp5
38 files changed, 912 insertions, 462 deletions
diff --git a/WebCore/platform/graphics/GraphicsContext.h b/WebCore/platform/graphics/GraphicsContext.h
index b1d1ef9..5b62b2c 100644
--- a/WebCore/platform/graphics/GraphicsContext.h
+++ b/WebCore/platform/graphics/GraphicsContext.h
@@ -334,6 +334,11 @@ namespace WebCore {
void addPath(const Path&);
void clip(const Path&);
+
+ // This clip function is used only by <canvas> code. It allows
+ // implementations to handle clipping on the canvas differently since
+ // the disipline is different.
+ void canvasClip(const Path&);
void clipOut(const Path&);
void scale(const FloatSize&);
diff --git a/WebCore/platform/graphics/GraphicsContext3D.h b/WebCore/platform/graphics/GraphicsContext3D.h
index 5223e05..07ec04d 100644
--- a/WebCore/platform/graphics/GraphicsContext3D.h
+++ b/WebCore/platform/graphics/GraphicsContext3D.h
@@ -29,6 +29,7 @@
#include "PlatformString.h"
#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
#if PLATFORM(MAC)
#include <OpenGL/OpenGL.h>
@@ -45,6 +46,7 @@ const Platform3DObject NullPlatform3DObject = 0;
#endif
namespace WebCore {
+ class CanvasActiveInfo;
class CanvasArray;
class CanvasBuffer;
class CanvasUnsignedByteArray;
@@ -61,17 +63,23 @@ namespace WebCore {
class HTMLVideoElement;
class ImageData;
class WebKitCSSMatrix;
-
+
+ struct ActiveInfo {
+ String name;
+ unsigned type;
+ int size;
+ };
+
// FIXME: ideally this would be used on all platforms.
#if PLATFORM(CHROMIUM)
class GraphicsContext3DInternal;
#endif
- class GraphicsContext3D : Noncopyable {
+ class GraphicsContext3D : public Noncopyable {
public:
enum ShaderType { FRAGMENT_SHADER, VERTEX_SHADER };
- GraphicsContext3D();
+ static PassOwnPtr<GraphicsContext3D> create();
virtual ~GraphicsContext3D();
#if PLATFORM(MAC)
@@ -85,7 +93,6 @@ namespace WebCore {
Platform3DObject platformTexture() const { return NullPlatform3DObject; }
#endif
void checkError() const;
-
void makeContextCurrent();
// Helper to return the size in bytes of OpenGL data types
@@ -141,6 +148,9 @@ namespace WebCore {
void frontFace(unsigned long mode);
void generateMipmap(unsigned long target);
+ bool getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo&);
+ bool getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo&);
+
int getAttribLocation(CanvasProgram*, const String& name);
bool getBoolean(unsigned long pname);
@@ -204,8 +214,7 @@ namespace WebCore {
void pixelStorei(unsigned long pname, long param);
void polygonOffset(double factor, double units);
- // TBD
- //void readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* pixels);
+ PassRefPtr<CanvasArray> readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type);
void releaseShaderCompiler();
void renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height);
@@ -311,6 +320,8 @@ namespace WebCore {
void deleteTexture(unsigned);
private:
+ GraphicsContext3D();
+
int m_currentWidth, m_currentHeight;
#if PLATFORM(MAC)
diff --git a/WebCore/platform/graphics/GraphicsLayer.cpp b/WebCore/platform/graphics/GraphicsLayer.cpp
index b375bd3..c8582bb 100644
--- a/WebCore/platform/graphics/GraphicsLayer.cpp
+++ b/WebCore/platform/graphics/GraphicsLayer.cpp
@@ -59,9 +59,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
: m_client(client)
, m_anchorPoint(0.5f, 0.5f, 0)
, m_opacity(1)
-#ifndef NDEBUG
, m_zPosition(0)
-#endif
, m_backgroundColorSet(false)
, m_contentsOpaque(false)
, m_preserves3D(false)
@@ -74,9 +72,7 @@ GraphicsLayer::GraphicsLayer(GraphicsLayerClient* client)
, m_contentsOrientation(CompositingCoordinatesTopDown)
, m_parent(0)
, m_maskLayer(0)
-#ifndef NDEBUG
, m_repaintCount(0)
-#endif
{
}
@@ -86,6 +82,16 @@ GraphicsLayer::~GraphicsLayer()
removeFromParent();
}
+bool GraphicsLayer::hasAncestor(GraphicsLayer* ancestor) const
+{
+ for (GraphicsLayer* curr = parent(); curr; curr = curr->parent()) {
+ if (curr == ancestor)
+ return true;
+ }
+
+ return false;
+}
+
void GraphicsLayer::addChild(GraphicsLayer* childLayer)
{
ASSERT(childLayer != this);
@@ -219,7 +225,6 @@ void GraphicsLayer::resumeAnimations()
{
}
-#ifndef NDEBUG
void GraphicsLayer::updateDebugIndicators()
{
if (GraphicsLayer::showDebugBorders()) {
@@ -241,7 +246,6 @@ void GraphicsLayer::setZPosition(float position)
{
m_zPosition = position;
}
-#endif
float GraphicsLayer::accumulatedOpacity() const
{
diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h
index 2924073..85eace0 100644
--- a/WebCore/platform/graphics/GraphicsLayer.h
+++ b/WebCore/platform/graphics/GraphicsLayer.h
@@ -172,6 +172,9 @@ public:
GraphicsLayer* parent() const { return m_parent; };
void setParent(GraphicsLayer* layer) { m_parent = layer; } // Internal use only.
+ // Returns true if the layer has the given layer as an ancestor (excluding self).
+ bool hasAncestor(GraphicsLayer*) const;
+
const Vector<GraphicsLayer*>& children() const { return m_children; }
// Add child layers. If the child is already parented, it will be removed from its old parent.
@@ -273,10 +276,8 @@ public:
void dumpLayer(TextStream&, int indent = 0) const;
-#ifndef NDEBUG
int repaintCount() const { return m_repaintCount; }
int incrementRepaintCount() { return ++m_repaintCount; }
-#endif
// Report whether the underlying compositing system uses a top-down
// or a bottom-up coordinate system.
@@ -291,7 +292,6 @@ public:
virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation) { m_contentsOrientation = orientation; }
CompositingCoordinatesOrientation contentsOrientation() const { return m_contentsOrientation; }
-#ifndef NDEBUG
static bool showDebugBorders();
static bool showRepaintCounter();
@@ -302,7 +302,6 @@ public:
// z-position is the z-equivalent of position(). It's only used for debugging purposes.
virtual float zPosition() const { return m_zPosition; }
virtual void setZPosition(float);
-#endif
virtual void distributeOpacity(float);
virtual float accumulatedOpacity() const;
@@ -339,9 +338,7 @@ protected:
Color m_backgroundColor;
float m_opacity;
-#ifndef NDEBUG
float m_zPosition;
-#endif
bool m_backgroundColorSet : 1;
bool m_contentsOpaque : 1;
@@ -362,9 +359,7 @@ protected:
IntRect m_contentsRect;
-#ifndef NDEBUG
int m_repaintCount;
-#endif
};
diff --git a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
index de8afb3..8741c5e 100644
--- a/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
+++ b/WebCore/platform/graphics/cairo/GraphicsContextCairo.cpp
@@ -931,6 +931,11 @@ void GraphicsContext::clip(const Path& path)
m_data->clip(path);
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
diff --git a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
index 1b843e4..1350bd3 100644
--- a/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
+++ b/WebCore/platform/graphics/cg/GraphicsContextCG.cpp
@@ -849,6 +849,11 @@ void GraphicsContext::clip(const Path& path)
m_data->clip(path);
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
diff --git a/WebCore/platform/graphics/chromium/FontLinux.cpp b/WebCore/platform/graphics/chromium/FontLinux.cpp
index dca0efb..a4526a8 100644
--- a/WebCore/platform/graphics/chromium/FontLinux.cpp
+++ b/WebCore/platform/graphics/chromium/FontLinux.cpp
@@ -57,6 +57,23 @@ bool Font::canReturnFallbackFontsForComplexText()
return false;
}
+static bool isCanvasMultiLayered(SkCanvas* canvas)
+{
+ SkCanvas::LayerIter layerIterator(canvas, false);
+ layerIterator.next();
+ return !layerIterator.done();
+}
+
+static bool adjustTextRenderMode(SkPaint* paint, bool isCanvasMultiLayered)
+{
+ // Our layers only have a single alpha channel. This means that subpixel
+ // rendered text cannot be compositied correctly when the layer is
+ // collapsed. Therefore, subpixel text is disabled when we are drawing
+ // onto a layer.
+ if (isCanvasMultiLayered)
+ paint->setLCDRenderText(false);
+}
+
void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
const GlyphBuffer& glyphBuffer, int from, int numGlyphs,
const FloatPoint& point) const {
@@ -84,12 +101,14 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
SkCanvas* canvas = gc->platformContext()->canvas();
int textMode = gc->platformContext()->getTextDrawingMode();
+ bool haveMultipleLayers = isCanvasMultiLayered(canvas);
// We draw text up to two times (once for fill, once for stroke).
if (textMode & cTextFill) {
SkPaint paint;
gc->platformContext()->setupPaintForFilling(&paint);
font->platformData().setupPaint(&paint);
+ adjustTextRenderMode(&paint, haveMultipleLayers);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setColor(gc->fillColor().rgb());
canvas->drawPosText(glyphs, numGlyphs << 1, pos, paint);
@@ -102,6 +121,7 @@ void Font::drawGlyphs(GraphicsContext* gc, const SimpleFontData* font,
SkPaint paint;
gc->platformContext()->setupPaintForStroking(&paint, 0, 0);
font->platformData().setupPaint(&paint);
+ adjustTextRenderMode(&paint, haveMultipleLayers);
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setColor(gc->strokeColor().rgb());
@@ -472,15 +492,18 @@ void Font::drawComplexText(GraphicsContext* gc, const TextRun& run,
}
TextRunWalker walker(run, point.x(), this);
+ bool haveMultipleLayers = isCanvasMultiLayered(canvas);
while (walker.nextScriptRun()) {
if (fill) {
walker.fontPlatformDataForScriptRun()->setupPaint(&fillPaint);
+ adjustTextRenderMode(&fillPaint, haveMultipleLayers);
canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), fillPaint);
}
if (stroke) {
walker.fontPlatformDataForScriptRun()->setupPaint(&strokePaint);
+ adjustTextRenderMode(&strokePaint, haveMultipleLayers);
canvas->drawPosTextH(walker.glyphs(), walker.length() << 1, walker.xPositions(), point.y(), strokePaint);
}
}
@@ -645,8 +668,6 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run,
if (toX == -1 && !to)
toX = rightEdge;
- else if (!walker.rtl())
- toX += truncateFixedPointToInteger(toAdvance);
ASSERT(fromX != -1 && toX != -1);
diff --git a/WebCore/platform/graphics/filters/FEColorMatrix.cpp b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
index 1e2e552..a2ed9bd 100644
--- a/WebCore/platform/graphics/filters/FEColorMatrix.cpp
+++ b/WebCore/platform/graphics/filters/FEColorMatrix.cpp
@@ -30,6 +30,7 @@
#include "GraphicsContext.h"
#include "ImageData.h"
#include <math.h>
+#include <wtf/MathExtras.h>
namespace WebCore {
@@ -92,8 +93,8 @@ inline void saturate(double& red, double& green, double& blue, const float& s)
inline void huerotate(double& red, double& green, double& blue, const float& hue)
{
- double cosHue = cos(hue * M_PI / 180);
- double sinHue = sin(hue * M_PI / 180);
+ double cosHue = cos(hue * piDouble / 180);
+ double sinHue = sin(hue * piDouble / 180);
double r = red * (0.213 + cosHue * 0.787 - sinHue * 0.213) +
green * (0.715 - cosHue * 0.715 - sinHue * 0.715) +
blue * (0.072 - cosHue * 0.072 + sinHue * 0.928);
diff --git a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
index 43e5edd..0d76d8d 100644
--- a/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
+++ b/WebCore/platform/graphics/filters/FEComponentTransfer.cpp
@@ -92,11 +92,11 @@ void FEComponentTransfer::setAlphaFunction(const ComponentTransferFunction& func
m_alphaFunc = func;
}
-void identity(unsigned char*, const ComponentTransferFunction&)
+static void identity(unsigned char*, const ComponentTransferFunction&)
{
}
-void table(unsigned char* values, const ComponentTransferFunction& transferFunction)
+static void table(unsigned char* values, const ComponentTransferFunction& transferFunction)
{
const Vector<float>& tableValues = transferFunction.tableValues;
unsigned n = tableValues.size();
@@ -113,7 +113,7 @@ void table(unsigned char* values, const ComponentTransferFunction& transferFunct
}
}
-void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction)
+static void discrete(unsigned char* values, const ComponentTransferFunction& transferFunction)
{
const Vector<float>& tableValues = transferFunction.tableValues;
unsigned n = tableValues.size();
@@ -128,7 +128,7 @@ void discrete(unsigned char* values, const ComponentTransferFunction& transferFu
}
}
-void linear(unsigned char* values, const ComponentTransferFunction& transferFunction)
+static void linear(unsigned char* values, const ComponentTransferFunction& transferFunction)
{
for (unsigned i = 0; i < 256; ++i) {
double val = transferFunction.slope * i + 255 * transferFunction.intercept;
@@ -137,7 +137,7 @@ void linear(unsigned char* values, const ComponentTransferFunction& transferFunc
}
}
-void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
+static void gamma(unsigned char* values, const ComponentTransferFunction& transferFunction)
{
for (unsigned i = 0; i < 256; ++i) {
double val = 255.0 * (transferFunction.amplitude * pow((i / 255.0), transferFunction.exponent) + transferFunction.offset);
diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.cpp b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
new file mode 100644
index 0000000..f480f10
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEGaussianBlur.cpp
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@webkit.org>
+ 2009 Dirk Schulze <krit@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#if ENABLE(FILTERS)
+#include "FEGaussianBlur.h"
+
+#include "CanvasPixelArray.h"
+#include "Filter.h"
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+FEGaussianBlur::FEGaussianBlur(FilterEffect* in, const float& x, const float& y)
+ : FilterEffect()
+ , m_in(in)
+ , m_x(x)
+ , m_y(y)
+{
+}
+
+PassRefPtr<FEGaussianBlur> FEGaussianBlur::create(FilterEffect* in, const float& x, const float& y)
+{
+ return adoptRef(new FEGaussianBlur(in, x, y));
+}
+
+float FEGaussianBlur::stdDeviationX() const
+{
+ return m_x;
+}
+
+void FEGaussianBlur::setStdDeviationX(float x)
+{
+ m_x = x;
+}
+
+float FEGaussianBlur::stdDeviationY() const
+{
+ return m_y;
+}
+
+void FEGaussianBlur::setStdDeviationY(float y)
+{
+ m_y = y;
+}
+
+static void boxBlur(CanvasPixelArray*& srcPixelArray, CanvasPixelArray*& dstPixelArray,
+ unsigned dx, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage)
+{
+ int dxLeft = dx / 2;
+ int dxRight = dx - dxLeft;
+
+ for (int y = 0; y < effectHeight; ++y) {
+ int line = y * strideLine;
+ for (int channel = 3; channel >= 0; --channel) {
+ int sum = 0;
+ // Fill the kernel
+ int maxKernelSize = std::min(dxRight, effectWidth);
+ for (int i = 0; i < maxKernelSize; ++i)
+ sum += srcPixelArray->get(line + i * stride + channel);
+
+ // Blurring
+ for (int x = 0; x < effectWidth; ++x) {
+ int pixelByteOffset = line + x * stride + channel;
+ dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx));
+ if (x >= dxLeft)
+ sum -= srcPixelArray->get(pixelByteOffset - dxLeft * stride);
+ if (x + dxRight < effectWidth)
+ sum += srcPixelArray->get(pixelByteOffset + dxRight * stride);
+ }
+ if (alphaImage) // Source image is black, it just has different alpha values
+ break;
+ }
+ }
+}
+
+void FEGaussianBlur::apply(Filter* filter)
+{
+ m_in->apply(filter);
+ if (!m_in->resultImage())
+ return;
+
+ if (!getEffectContext())
+ return;
+
+ setIsAlphaImage(m_in->isAlphaImage());
+
+ if (m_x == 0 || m_y == 0)
+ return;
+
+ unsigned sdx = static_cast<unsigned>(floor(m_x * 3 * sqrt(2 * piDouble) / 4.f + 0.5f));
+ unsigned sdy = static_cast<unsigned>(floor(m_y * 3 * sqrt(2 * piDouble) / 4.f + 0.5f));
+
+ IntRect effectDrawingRect = calculateDrawingIntRect(m_in->subRegion());
+ RefPtr<ImageData> srcImageData(m_in->resultImage()->getPremultipliedImageData(effectDrawingRect));
+ CanvasPixelArray* srcPixelArray(srcImageData->data());
+
+ IntRect imageRect(IntPoint(), resultImage()->size());
+ RefPtr<ImageData> tmpImageData = ImageData::create(imageRect.width(), imageRect.height());
+ CanvasPixelArray* tmpPixelArray(tmpImageData->data());
+
+ int stride = 4 * imageRect.width();
+ for (int i = 0; i < 3; ++i) {
+ boxBlur(srcPixelArray, tmpPixelArray, sdx, 4, stride, imageRect.width(), imageRect.height(), isAlphaImage());
+ boxBlur(tmpPixelArray, srcPixelArray, sdy, stride, 4, imageRect.height(), imageRect.width(), isAlphaImage());
+ }
+
+ resultImage()->putPremultipliedImageData(srcImageData.get(), imageRect, IntPoint());
+}
+
+void FEGaussianBlur::dump()
+{
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
diff --git a/WebCore/platform/graphics/filters/FEGaussianBlur.h b/WebCore/platform/graphics/filters/FEGaussianBlur.h
new file mode 100644
index 0000000..ecdb9e3
--- /dev/null
+++ b/WebCore/platform/graphics/filters/FEGaussianBlur.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
+ 2004, 2005 Rob Buis <buis@kde.org>
+ 2005 Eric Seidel <eric@webkit.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FEGaussianBlur_h
+#define FEGaussianBlur_h
+
+#if ENABLE(FILTERS)
+#include "FilterEffect.h"
+#include "Filter.h"
+
+namespace WebCore {
+
+ class FEGaussianBlur : public FilterEffect {
+ public:
+ static PassRefPtr<FEGaussianBlur> create(FilterEffect*, const float&, const float&);
+
+ float stdDeviationX() const;
+ void setStdDeviationX(float);
+
+ float stdDeviationY() const;
+ void setStdDeviationY(float);
+
+ virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return calculateUnionOfChildEffectSubregions(filter, m_in.get()); }
+ void apply(Filter*);
+ void dump();
+
+ private:
+ FEGaussianBlur(FilterEffect*, const float&, const float&);
+
+ RefPtr<FilterEffect> m_in;
+ float m_x;
+ float m_y;
+ };
+
+} // namespace WebCore
+
+#endif // ENABLE(FILTERS)
+
+#endif // FEGaussianBlur_h
diff --git a/WebCore/platform/graphics/filters/FilterEffect.cpp b/WebCore/platform/graphics/filters/FilterEffect.cpp
index 5818e50..68900b5 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.cpp
+++ b/WebCore/platform/graphics/filters/FilterEffect.cpp
@@ -25,14 +25,11 @@
namespace WebCore {
FilterEffect::FilterEffect()
- : m_xBBoxMode(false)
- , m_yBBoxMode(false)
- , m_widthBBoxMode(false)
- , m_heightBBoxMode(false)
- , m_hasX(false)
+ : m_hasX(false)
, m_hasY(false)
, m_hasWidth(false)
, m_hasHeight(false)
+ , m_alphaImage(false)
{
}
diff --git a/WebCore/platform/graphics/filters/FilterEffect.h b/WebCore/platform/graphics/filters/FilterEffect.h
index e2b8a0e..b30e513 100644
--- a/WebCore/platform/graphics/filters/FilterEffect.h
+++ b/WebCore/platform/graphics/filters/FilterEffect.h
@@ -38,18 +38,6 @@ namespace WebCore {
public:
virtual ~FilterEffect();
- bool xBoundingBoxMode() const { return m_xBBoxMode; }
- void setXBoundingBoxMode(bool bboxMode) { m_xBBoxMode = bboxMode; }
-
- bool yBoundingBoxMode() const { return m_yBBoxMode; }
- void setYBoundingBoxMode(bool bboxMode) { m_yBBoxMode = bboxMode; }
-
- bool widthBoundingBoxMode() const { return m_widthBBoxMode; }
- void setWidthBoundingBoxMode(bool bboxMode) { m_widthBBoxMode = bboxMode; }
-
- bool heightBoundingBoxMode() const { return m_heightBBoxMode; }
- void setHeightBoundingBoxMode(bool bboxMode) { m_heightBBoxMode = bboxMode; }
-
void setUnionOfChildEffectSubregions(const FloatRect& uniteRect) { m_unionOfChildEffectSubregions = uniteRect; }
FloatRect unionOfChildEffectSubregions() const { return m_unionOfChildEffectSubregions; }
@@ -79,6 +67,10 @@ namespace WebCore {
FloatRect calculateDrawingRect(const FloatRect&);
IntRect calculateDrawingIntRect(const FloatRect&);
+ // black image with different alpha values
+ bool isAlphaImage() { return m_alphaImage; }
+ void setIsAlphaImage(bool alphaImage) { m_alphaImage = alphaImage; }
+
virtual FloatRect uniteChildEffectSubregions(Filter* filter) { return filter->filterRegion(); }
virtual FloatRect calculateEffectRect(Filter*);
virtual void apply(Filter*) = 0;
@@ -102,6 +94,8 @@ namespace WebCore {
bool m_hasWidth : 1;
bool m_hasHeight : 1;
+ bool m_alphaImage;
+
FloatRect m_subRegion;
FloatRect m_unionOfChildEffectSubregions;
diff --git a/WebCore/platform/graphics/filters/SourceAlpha.cpp b/WebCore/platform/graphics/filters/SourceAlpha.cpp
index 57436be..1b6309b 100644
--- a/WebCore/platform/graphics/filters/SourceAlpha.cpp
+++ b/WebCore/platform/graphics/filters/SourceAlpha.cpp
@@ -59,6 +59,8 @@ void SourceAlpha::apply(Filter* filter)
if (!filterContext)
return;
+ setIsAlphaImage(true);
+
FloatRect imageRect(FloatPoint(), filter->sourceImage()->image()->size());
filterContext->save();
filterContext->clipToImageBuffer(imageRect, filter->sourceImage());
diff --git a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp
index a6c2dfb..567da74 100644
--- a/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/DataSourceGStreamer.cpp
@@ -214,7 +214,7 @@ static gboolean webkit_data_src_uri_set_uri(GstURIHandler* handler, const gchar*
GInputStream* stream = g_memory_input_stream_new_from_data(decoded_data,
decoded_size,
g_free);
- g_object_set(src->kid, "stream", stream, 0);
+ g_object_set(src->kid, "stream", stream, NULL);
g_object_unref(stream);
if (src->uri) {
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
index 65c64b4..8d1d261 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.cpp
@@ -25,9 +25,10 @@
#if ENABLE(VIDEO)
#include "MediaPlayerPrivateGStreamer.h"
-#include "DataSourceGStreamer.h"
+
#include "CString.h"
+#include "DataSourceGStreamer.h"
#include "GraphicsContext.h"
#include "IntRect.h"
#include "KURL.h"
@@ -35,11 +36,10 @@
#include "MediaPlayer.h"
#include "NotImplemented.h"
#include "ScrollView.h"
+#include "TimeRanges.h"
#include "VideoSinkGStreamer.h"
#include "Widget.h"
-#include "TimeRanges.h"
-#include <gst/base/gstbasesrc.h>
#include <gst/gst.h>
#include <gst/interfaces/mixer.h>
#include <gst/interfaces/xoverlay.h>
@@ -52,16 +52,20 @@ using namespace std;
namespace WebCore {
-gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data)
+gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data)
{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) {
- GOwnPtr<GError> err;
- GOwnPtr<gchar> debug;
+ GOwnPtr<GError> err;
+ GOwnPtr<gchar> debug;
+ MediaPlayer::NetworkState error;
+ MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ gint percent = 0;
+ switch (GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_ERROR:
gst_message_parse_error(message, &err.outPtr(), &debug.outPtr());
LOG_VERBOSE(Media, "Error: %d, %s", err->code, err->message);
- MediaPlayer::NetworkState error = MediaPlayer::Empty;
+ error = MediaPlayer::Empty;
if (err->domain == GST_CORE_ERROR || err->domain == GST_LIBRARY_ERROR)
error = MediaPlayer::DecodeError;
else if (err->domain == GST_RESOURCE_ERROR)
@@ -69,44 +73,32 @@ gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpoin
else if (err->domain == GST_STREAM_ERROR)
error = MediaPlayer::NetworkError;
- MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
if (mp)
mp->loadingFailed(error);
- }
- return true;
-}
-
-gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data)
-{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_EOS) {
+ break;
+ case GST_MESSAGE_EOS:
LOG_VERBOSE(Media, "End of Stream");
- MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
mp->didEnd();
- }
- return true;
-}
-
-gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data)
-{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STATE_CHANGED) {
- MediaPlayerPrivate* mp = reinterpret_cast<MediaPlayerPrivate*>(data);
+ break;
+ case GST_MESSAGE_STATE_CHANGED:
mp->updateStates();
- }
- return true;
-}
-
-gboolean mediaPlayerPrivateBufferingCallback(GstBus* bus, GstMessage* message, gpointer data)
-{
- if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_BUFFERING) {
- gint percent = 0;
+ break;
+ case GST_MESSAGE_BUFFERING:
gst_message_parse_buffering(message, &percent);
LOG_VERBOSE(Media, "Buffering %d", percent);
+ break;
+ default:
+ LOG_VERBOSE(Media, "Unhandled GStreamer message type: %s",
+ GST_MESSAGE_TYPE_NAME(message));
+ break;
}
return true;
}
-static void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, MediaPlayerPrivate* playerPrivate)
+void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate)
{
+ g_return_if_fail(GST_IS_BUFFER(buffer));
+ gst_buffer_replace(&playerPrivate->m_buffer, buffer);
playerPrivate->repaint();
}
@@ -123,7 +115,8 @@ void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
static bool gstInitialized = false;
-static void do_gst_init() {
+static void do_gst_init()
+{
// FIXME: We should pass the arguments from the command line
if (!gstInitialized) {
gst_init(0, 0);
@@ -139,50 +132,33 @@ MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
, m_playBin(0)
, m_videoSink(0)
, m_source(0)
- , m_rate(1.0f)
, m_endTime(numeric_limits<float>::infinity())
- , m_volume(0.5f)
, m_networkState(MediaPlayer::Empty)
, m_readyState(MediaPlayer::HaveNothing)
, m_startedPlaying(false)
, m_isStreaming(false)
, m_size(IntSize())
- , m_visible(true)
+ , m_buffer(0)
, m_paused(true)
, m_seeking(false)
, m_errorOccured(false)
{
do_gst_init();
-
- // FIXME: The size shouldn't be fixed here, this is just a quick hack.
- m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 640, 480);
-}
-
-static gboolean idleUnref(gpointer data)
-{
- g_object_unref(reinterpret_cast<GObject*>(data));
- return FALSE;
}
MediaPlayerPrivate::~MediaPlayerPrivate()
{
- if (m_surface)
- cairo_surface_destroy(m_surface);
+ if (m_buffer)
+ gst_buffer_unref(m_buffer);
+ m_buffer = 0;
if (m_playBin) {
gst_element_set_state(m_playBin, GST_STATE_NULL);
gst_object_unref(GST_OBJECT(m_playBin));
}
- // FIXME: We should find a better way to handle the lifetime of this object; this is
- // needed because the object is sometimes being destroyed inbetween a call to
- // webkit_video_sink_render, and the idle it schedules. Adding a ref in
- // webkit_video_sink_render that would be balanced by the idle is not an option,
- // because in some cases the destruction of the sink may happen in time for the idle
- // to be removed from the queue, so it may not run. It would also cause lots of ref
- // counting churn (render/idle are called many times). This is an ugly race.
if (m_videoSink) {
- g_idle_add(idleUnref, m_videoSink);
+ g_object_unref(m_videoSink);
m_videoSink = 0;
}
}
@@ -226,24 +202,14 @@ float MediaPlayerPrivate::duration() const
GstFormat timeFormat = GST_FORMAT_TIME;
gint64 timeLength = 0;
-#if !GST_CHECK_VERSION(0, 10, 23)
- // We try to get the duration, but we do not trust the
- // return value of the query function only; the problem we are
- // trying to work-around here is that pipelines in stream mode may
- // not be able to figure out the duration, but still return true!
- // See https://bugs.webkit.org/show_bug.cgi?id=24639 which has been
- // fixed in gst-plugins-base 0.10.23
- if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeLength <= 0) {
-#else
- if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength)) {
-#endif
+ if (!gst_element_query_duration(m_playBin, &timeFormat, &timeLength) || timeFormat != GST_FORMAT_TIME || timeLength == GST_CLOCK_TIME_NONE) {
LOG_VERBOSE(Media, "Time duration query failed.");
return numeric_limits<float>::infinity();
}
LOG_VERBOSE(Media, "Duration: %" GST_TIME_FORMAT, GST_TIME_ARGS(timeLength));
- return (float) (timeLength / 1000000000.0);
+ return (float) ((guint64) timeLength / 1000000000.0);
// FIXME: handle 3.14.9.5 properly
}
@@ -288,7 +254,7 @@ void MediaPlayerPrivate::seek(float time)
return;
LOG_VERBOSE(Media, "Seek: %" GST_TIME_FORMAT, GST_TIME_ARGS(sec));
- if (!gst_element_seek( m_playBin, m_rate,
+ if (!gst_element_seek(m_playBin, m_player->rate(),
GST_FORMAT_TIME,
(GstSeekFlags)(GST_SEEK_FLAG_FLUSH),
GST_SEEK_TYPE_SET, sec,
@@ -340,14 +306,17 @@ IntSize MediaPlayerPrivate::naturalSize() const
// 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")) {
- gst_video_get_size(GST_PAD(pad), &width, &height);
GstCaps* caps = GST_PAD_CAPS(pad);
gfloat pixelAspectRatio;
gint pixelAspectRatioNumerator, pixelAspectRatioDenominator;
- if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator,
- &pixelAspectRatioDenominator))
- pixelAspectRatioNumerator = pixelAspectRatioDenominator = 1;
+ if (!GST_IS_CAPS(caps) || !gst_caps_is_fixed(caps) ||
+ !gst_video_format_parse_caps(caps, NULL, &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;
@@ -376,21 +345,10 @@ bool MediaPlayerPrivate::hasAudio() const
void MediaPlayerPrivate::setVolume(float volume)
{
- m_volume = volume;
- LOG_VERBOSE(Media, "Volume to %f", volume);
-
if (!m_playBin)
return;
- g_object_set(G_OBJECT(m_playBin), "volume", m_volume, NULL);
-}
-
-void MediaPlayerPrivate::setMuted(bool mute)
-{
- if (!m_playBin)
- return;
-
- g_object_set(G_OBJECT(m_playBin), "mute", mute, NULL);
+ g_object_set(G_OBJECT(m_playBin), "volume", static_cast<double>(volume), NULL);
}
void MediaPlayerPrivate::setRate(float rate)
@@ -403,7 +361,6 @@ void MediaPlayerPrivate::setRate(float rate)
if (m_isStreaming)
return;
- m_rate = rate;
LOG_VERBOSE(Media, "Set Rate to %f", rate);
seek(currentTime());
}
@@ -495,7 +452,11 @@ unsigned MediaPlayerPrivate::totalBytes() const
void MediaPlayerPrivate::cancelLoad()
{
- notImplemented();
+ if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
+ return;
+
+ if (m_playBin)
+ gst_element_set_state(m_playBin, GST_STATE_NULL);
}
void MediaPlayerPrivate::updateStates()
@@ -525,14 +486,15 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
- if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::HaveEnoughData;
- } else if (state == GST_STATE_PAUSED)
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (state == GST_STATE_PAUSED)
m_readyState = MediaPlayer::HaveEnoughData;
- if (state == GST_STATE_PLAYING)
+ if (state == GST_STATE_PLAYING) {
+ m_readyState = MediaPlayer::HaveEnoughData;
m_paused = false;
- else
+ } else
m_paused = true;
if (m_seeking) {
@@ -563,9 +525,9 @@ void MediaPlayerPrivate::updateStates()
gst_element_state_get_name(state),
gst_element_state_get_name(pending));
- if (state == GST_STATE_READY) {
- m_readyState = MediaPlayer::HaveFutureData;
- } else if (state == GST_STATE_PAUSED)
+ if (state == GST_STATE_READY)
+ m_readyState = MediaPlayer::HaveNothing;
+ else if (state == GST_STATE_PAUSED)
m_readyState = MediaPlayer::HaveCurrentData;
m_networkState = MediaPlayer::Loading;
@@ -639,23 +601,11 @@ void MediaPlayerPrivate::loadingFailed(MediaPlayer::NetworkState error)
void MediaPlayerPrivate::setSize(const IntSize& size)
{
- // Destroy and re-create the cairo surface only if the size
- // changed.
- if (size != m_size) {
- if (m_surface)
- cairo_surface_destroy(m_surface);
- m_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size.width(),
- size.height());
- g_object_set(m_videoSink, "surface", m_surface, 0);
- }
-
m_size = size;
-
}
void MediaPlayerPrivate::setVisible(bool visible)
{
- m_visible = visible;
}
void MediaPlayerPrivate::repaint()
@@ -668,20 +618,65 @@ void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
if (context->paintingDisabled())
return;
- if (!m_visible)
+ if (!m_player->visible())
return;
+ if (!m_buffer)
+ return;
+
+ int width = 0, height = 0;
+ int pixelAspectRatioNumerator = 0;
+ int pixelAspectRatioDenominator = 0;
+ double doublePixelAspectRatioNumerator = 0;
+ double doublePixelAspectRatioDenominator = 0;
+ double displayWidth;
+ double displayHeight;
+ double scale, gapHeight, gapWidth;
+
+ GstCaps *caps = gst_buffer_get_caps(m_buffer);
+
+ if (!gst_video_format_parse_caps(caps, NULL, &width, &height) ||
+ !gst_video_parse_caps_pixel_aspect_ratio(caps, &pixelAspectRatioNumerator, &pixelAspectRatioDenominator)) {
+ gst_caps_unref(caps);
+ return;
+ }
+
+ displayWidth = width;
+ displayHeight = height;
+ doublePixelAspectRatioNumerator = pixelAspectRatioNumerator;
+ doublePixelAspectRatioDenominator = pixelAspectRatioDenominator;
cairo_t* cr = context->platformContext();
+ cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(m_buffer),
+ CAIRO_FORMAT_RGB24,
+ width, height,
+ 4 * width);
cairo_save(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+ displayWidth *= doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator;
+ displayHeight *= doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator;
+
+ scale = MIN (rect.width () / displayWidth, rect.height () / displayHeight);
+ displayWidth *= scale;
+ displayHeight *= scale;
+
+ // Calculate gap between border an picture
+ gapWidth = (rect.width() - displayWidth) / 2.0;
+ gapHeight = (rect.height() - displayHeight) / 2.0;
+
// paint the rectangle on the context and draw the surface inside.
- cairo_translate(cr, rect.x(), rect.y());
+ cairo_translate(cr, rect.x() + gapWidth, rect.y() + gapHeight);
cairo_rectangle(cr, 0, 0, rect.width(), rect.height());
- cairo_set_source_surface(cr, m_surface, 0, 0);
+ cairo_scale(cr, doublePixelAspectRatioNumerator / doublePixelAspectRatioDenominator,
+ doublePixelAspectRatioDenominator / doublePixelAspectRatioNumerator);
+ cairo_scale(cr, scale, scale);
+ cairo_set_source_surface(cr, src, 0, 0);
cairo_fill(cr);
cairo_restore(cr);
+
+ cairo_surface_destroy(src);
+ gst_caps_unref(caps);
}
static HashSet<String> mimeTypeCache()
@@ -805,25 +800,18 @@ void MediaPlayerPrivate::createGSTPlayBin(String url)
GstBus* bus = gst_pipeline_get_bus(GST_PIPELINE(m_playBin));
gst_bus_add_signal_watch(bus);
- g_signal_connect(bus, "message::error", G_CALLBACK(mediaPlayerPrivateErrorCallback), this);
- g_signal_connect(bus, "message::eos", G_CALLBACK(mediaPlayerPrivateEOSCallback), this);
- g_signal_connect(bus, "message::state-changed", G_CALLBACK(mediaPlayerPrivateStateCallback), this);
- g_signal_connect(bus, "message::buffering", G_CALLBACK(mediaPlayerPrivateBufferingCallback), this);
+ g_signal_connect(bus, "message", G_CALLBACK(mediaPlayerPrivateMessageCallback), this);
gst_object_unref(bus);
- g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(), NULL);
-
- m_videoSink = webkit_video_sink_new(m_surface);
+ g_object_set(G_OBJECT(m_playBin), "uri", url.utf8().data(),
+ "volume", static_cast<double>(m_player->volume()), NULL);
- // This ref is to protect the sink from being destroyed before we stop the idle it
- // creates internally. See the comment in ~MediaPlayerPrivate.
- g_object_ref(m_videoSink);
+ m_videoSink = webkit_video_sink_new();
+ g_object_ref_sink(m_videoSink);
g_object_set(m_playBin, "video-sink", m_videoSink, NULL);
g_signal_connect(m_videoSink, "repaint-requested", G_CALLBACK(mediaPlayerPrivateRepaintCallback), this);
-
- setVolume(m_volume);
}
}
diff --git a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
index d305759..54da420 100644
--- a/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
+++ b/WebCore/platform/graphics/gtk/MediaPlayerPrivateGStreamer.h
@@ -30,8 +30,10 @@
#include <cairo.h>
#include <glib.h>
-typedef struct _GstElement GstElement;
+typedef struct _WebKitVideoSink WebKitVideoSink;
+typedef struct _GstBuffer GstBuffer;
typedef struct _GstMessage GstMessage;
+typedef struct _GstElement GstElement;
typedef struct _GstBus GstBus;
namespace WebCore {
@@ -41,14 +43,11 @@ namespace WebCore {
class IntRect;
class String;
- gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
- gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
- gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
+ gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
class MediaPlayerPrivate : public MediaPlayerPrivateInterface {
- friend gboolean mediaPlayerPrivateErrorCallback(GstBus* bus, GstMessage* message, gpointer data);
- friend gboolean mediaPlayerPrivateEOSCallback(GstBus* bus, GstMessage* message, gpointer data);
- friend gboolean mediaPlayerPrivateStateCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend gboolean mediaPlayerPrivateMessageCallback(GstBus* bus, GstMessage* message, gpointer data);
+ friend void mediaPlayerPrivateRepaintCallback(WebKitVideoSink*, GstBuffer *buffer, MediaPlayerPrivate* playerPrivate);
public:
static void registerMediaEngine(MediaEngineRegistrar);
@@ -74,7 +73,6 @@ namespace WebCore {
void setRate(float);
void setVolume(float);
- void setMuted(bool);
int dataRate() const;
@@ -126,17 +124,14 @@ namespace WebCore {
GstElement* m_playBin;
GstElement* m_videoSink;
GstElement* m_source;
- float m_rate;
float m_endTime;
bool m_isEndReached;
- double m_volume;
MediaPlayer::NetworkState m_networkState;
MediaPlayer::ReadyState m_readyState;
bool m_startedPlaying;
mutable bool m_isStreaming;
IntSize m_size;
- bool m_visible;
- cairo_surface_t* m_surface;
+ GstBuffer* m_buffer;
bool m_paused;
bool m_seeking;
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
index fb86fe9..b5e1a8b 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.cpp
@@ -21,8 +21,9 @@
* SECTION:webkit-video-sink
* @short_description: GStreamer video sink
*
- * #WebKitVideoSink is a GStreamer sink element that sends
- * data to a #cairo_surface_t.
+ * #WebKitVideoSink is a GStreamer sink element that triggers
+ * repaints in the WebKit GStreamer media player for the
+ * current video buffer.
*/
#include "config.h"
@@ -57,22 +58,26 @@ enum {
};
enum {
- PROP_0,
- PROP_SURFACE
+ PROP_0
};
static guint webkit_video_sink_signals[LAST_SIGNAL] = { 0, };
struct _WebKitVideoSinkPrivate {
- cairo_surface_t* surface;
- GAsyncQueue* async_queue;
- gboolean rgb_ordering;
- int width;
- int height;
- int fps_n;
- int fps_d;
- int par_n;
- int par_d;
+ GstBuffer* buffer;
+ guint timeout_id;
+ GMutex* buffer_mutex;
+ GCond* data_cond;
+
+ // If this is TRUE all processing should finish ASAP
+ // This is necessary because there could be a race between
+ // unlock() and render(), where unlock() wins, signals the
+ // GCond, then render() tries to render a frame although
+ // everything else isn't running anymore. This will lead
+ // to deadlocks because render() holds the stream lock.
+ //
+ // Protected by the buffer mutex
+ gboolean unlocked;
};
#define _do_init(bla) \
@@ -83,8 +88,8 @@ struct _WebKitVideoSinkPrivate {
GST_BOILERPLATE_FULL(WebKitVideoSink,
webkit_video_sink,
- GstBaseSink,
- GST_TYPE_BASE_SINK,
+ GstVideoSink,
+ GST_TYPE_VIDEO_SINK,
_do_init);
static void
@@ -102,59 +107,37 @@ webkit_video_sink_init(WebKitVideoSink* sink, WebKitVideoSinkClass* klass)
WebKitVideoSinkPrivate* priv;
sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
- priv->async_queue = g_async_queue_new();
+ priv->data_cond = g_cond_new();
+ priv->buffer_mutex = g_mutex_new();
}
static gboolean
-webkit_video_sink_idle_func(gpointer data)
+webkit_video_sink_timeout_func(gpointer data)
{
WebKitVideoSink* sink = reinterpret_cast<WebKitVideoSink*>(data);
WebKitVideoSinkPrivate* priv = sink->priv;
GstBuffer* buffer;
- GstCaps* caps;
- GstVideoFormat format;
- gint par_n, par_d;
- gfloat par;
- gint bwidth, bheight;
- if (!priv->async_queue)
- return FALSE;
+ g_mutex_lock(priv->buffer_mutex);
+ buffer = priv->buffer;
+ priv->buffer = 0;
+ priv->timeout_id = 0;
- buffer = (GstBuffer*)g_async_queue_try_pop(priv->async_queue);
- if (!buffer || G_UNLIKELY(!GST_IS_BUFFER(buffer)))
+ if (!buffer || priv->unlocked || G_UNLIKELY(!GST_IS_BUFFER(buffer))) {
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
return FALSE;
+ }
- caps = GST_BUFFER_CAPS(buffer);
- if (!gst_video_format_parse_caps(caps, &format, &bwidth, &bheight)) {
- GST_ERROR_OBJECT(sink, "Unknown video format in buffer caps '%s'",
- gst_caps_to_string(caps));
- return FALSE;
+ if (G_UNLIKELY(!GST_BUFFER_CAPS(buffer))) {
+ buffer = gst_buffer_make_metadata_writable(buffer);
+ gst_buffer_set_caps(buffer, GST_PAD_CAPS(GST_BASE_SINK_PAD(sink)));
}
- if (!gst_video_parse_caps_pixel_aspect_ratio(caps, &par_n, &par_d))
- par_n = par_d = 1;
-
- par = (gfloat) par_n / (gfloat) par_d;
-
- // TODO: consider priv->rgb_ordering?
- cairo_surface_t* src = cairo_image_surface_create_for_data(GST_BUFFER_DATA(buffer),
- CAIRO_FORMAT_RGB24,
- bwidth, bheight,
- 4 * bwidth);
-
- // TODO: We copy the data twice right now. This could be easily improved.
- cairo_t* cr = cairo_create(priv->surface);
- cairo_scale(cr, par, 1.0 / par);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_surface(cr, src, 0, 0);
- cairo_surface_destroy(src);
- cairo_rectangle(cr, 0, 0, priv->width, priv->height);
- cairo_fill(cr);
- cairo_destroy(cr);
+ g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0, buffer);
gst_buffer_unref(buffer);
- g_async_queue_unref(priv->async_queue);
-
- g_signal_emit(sink, webkit_video_sink_signals[REPAINT_REQUESTED], 0);
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
return FALSE;
}
@@ -165,53 +148,24 @@ webkit_video_sink_render(GstBaseSink* bsink, GstBuffer* buffer)
WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
WebKitVideoSinkPrivate* priv = sink->priv;
- g_async_queue_ref(priv->async_queue);
- g_async_queue_push(priv->async_queue, gst_buffer_ref(buffer));
- g_idle_add_full(G_PRIORITY_HIGH_IDLE, webkit_video_sink_idle_func, sink, 0);
-
- return GST_FLOW_OK;
-}
-
-static gboolean
-webkit_video_sink_set_caps(GstBaseSink* bsink, GstCaps* caps)
-{
- WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(bsink);
- WebKitVideoSinkPrivate* priv = sink->priv;
- GstStructure* structure;
- gboolean ret;
- gint width, height, fps_n, fps_d;
- int red_mask;
-
- GstCaps* intersection = gst_caps_intersect(gst_static_pad_template_get_caps(&sinktemplate), caps);
+ g_mutex_lock(priv->buffer_mutex);
- if (gst_caps_is_empty(intersection))
- return FALSE;
-
- gst_caps_unref(intersection);
-
- structure = gst_caps_get_structure(caps, 0);
-
- ret = gst_structure_get_int(structure, "width", &width);
- ret &= gst_structure_get_int(structure, "height", &height);
-
- /* We dont yet use fps but handy to have */
- ret &= gst_structure_get_fraction(structure, "framerate",
- &fps_n, &fps_d);
- g_return_val_if_fail(ret, FALSE);
-
- priv->width = width;
- priv->height = height;
- priv->fps_n = fps_n;
- priv->fps_d = fps_d;
+ if (priv->unlocked) {
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_OK;
+ }
- if (!gst_structure_get_fraction(structure, "pixel-aspect-ratio",
- &priv->par_n, &priv->par_d))
- priv->par_n = priv->par_d = 1;
+ priv->buffer = gst_buffer_ref(buffer);
- gst_structure_get_int(structure, "red_mask", &red_mask);
- priv->rgb_ordering = (red_mask == static_cast<int>(0xff000000));
+ // Use HIGH_IDLE+20 priority, like Gtk+ for redrawing operations.
+ priv->timeout_id = g_timeout_add_full(G_PRIORITY_HIGH_IDLE + 20, 0,
+ webkit_video_sink_timeout_func,
+ gst_object_ref(sink),
+ (GDestroyNotify)gst_object_unref);
- return TRUE;
+ g_cond_wait(priv->data_cond, priv->buffer_mutex);
+ g_mutex_unlock(priv->buffer_mutex);
+ return GST_FLOW_OK;
}
static void
@@ -220,56 +174,58 @@ webkit_video_sink_dispose(GObject* object)
WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
WebKitVideoSinkPrivate* priv = sink->priv;
- if (priv->surface) {
- cairo_surface_destroy(priv->surface);
- priv->surface = 0;
+ if (priv->data_cond) {
+ g_cond_free(priv->data_cond);
+ priv->data_cond = 0;
}
- if (priv->async_queue) {
- g_async_queue_unref(priv->async_queue);
- priv->async_queue = 0;
+ if (priv->buffer_mutex) {
+ g_mutex_free(priv->buffer_mutex);
+ priv->buffer_mutex = 0;
}
G_OBJECT_CLASS(parent_class)->dispose(object);
}
static void
-webkit_video_sink_finalize(GObject* object)
+unlock_buffer_mutex(WebKitVideoSinkPrivate* priv)
{
- G_OBJECT_CLASS(parent_class)->finalize(object);
+ g_mutex_lock(priv->buffer_mutex);
+
+ if (priv->buffer) {
+ gst_buffer_unref(priv->buffer);
+ priv->buffer = 0;
+ }
+
+ priv->unlocked = TRUE;
+
+ g_cond_signal(priv->data_cond);
+ g_mutex_unlock(priv->buffer_mutex);
}
-static void
-webkit_video_sink_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec* pspec)
+static gboolean
+webkit_video_sink_unlock(GstBaseSink* object)
{
WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
- WebKitVideoSinkPrivate* priv = sink->priv;
- switch (prop_id) {
- case PROP_SURFACE:
- if (priv->surface)
- cairo_surface_destroy(priv->surface);
- priv->surface = cairo_surface_reference((cairo_surface_t*)g_value_get_pointer(value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
+ unlock_buffer_mutex(sink->priv);
+
+ return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock,
+ (object), TRUE);
}
-static void
-webkit_video_sink_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
+static gboolean
+webkit_video_sink_unlock_stop(GstBaseSink* object)
{
WebKitVideoSink* sink = WEBKIT_VIDEO_SINK(object);
+ WebKitVideoSinkPrivate* priv = sink->priv;
- switch (prop_id) {
- case PROP_SURFACE:
- g_value_set_pointer(value, sink->priv->surface);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
- break;
- }
+ g_mutex_lock(priv->buffer_mutex);
+ priv->unlocked = FALSE;
+ g_mutex_unlock(priv->buffer_mutex);
+
+ return GST_CALL_PARENT_WITH_DEFAULT(GST_BASE_SINK_CLASS, unlock_stop,
+ (object), TRUE);
}
static gboolean
@@ -277,20 +233,46 @@ webkit_video_sink_stop(GstBaseSink* base_sink)
{
WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
- g_async_queue_lock(priv->async_queue);
-
- /* Remove all remaining objects from the queue */
- while (GstBuffer* buffer = (GstBuffer*)g_async_queue_try_pop_unlocked(priv->async_queue))
- gst_buffer_unref(buffer);
-
- g_async_queue_unlock(priv->async_queue);
+ unlock_buffer_mutex(priv);
+ return TRUE;
+}
- g_idle_remove_by_data(base_sink);
+static gboolean
+webkit_video_sink_start(GstBaseSink* base_sink)
+{
+ WebKitVideoSinkPrivate* priv = WEBKIT_VIDEO_SINK(base_sink)->priv;
+ g_mutex_lock(priv->buffer_mutex);
+ priv->unlocked = FALSE;
+ g_mutex_unlock(priv->buffer_mutex);
return TRUE;
}
static void
+marshal_VOID__MINIOBJECT(GClosure * closure, GValue * return_value,
+ guint n_param_values, const GValue * param_values,
+ gpointer invocation_hint, gpointer marshal_data)
+{
+ typedef void (*marshalfunc_VOID__MINIOBJECT) (gpointer obj, gpointer arg1, gpointer data2);
+ marshalfunc_VOID__MINIOBJECT callback;
+ GCClosure *cc = (GCClosure *) closure;
+ gpointer data1, data2;
+
+ g_return_if_fail(n_param_values == 2);
+
+ if (G_CCLOSURE_SWAP_DATA(closure)) {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer(param_values + 0);
+ } else {
+ data1 = g_value_peek_pointer(param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (marshalfunc_VOID__MINIOBJECT) (marshal_data ? marshal_data : cc->callback);
+
+ callback(data1, gst_value_get_mini_object(param_values + 1), data2);
+}
+
+static void
webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
{
GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
@@ -298,16 +280,14 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
g_type_class_add_private(klass, sizeof(WebKitVideoSinkPrivate));
- gobject_class->set_property = webkit_video_sink_set_property;
- gobject_class->get_property = webkit_video_sink_get_property;
-
gobject_class->dispose = webkit_video_sink_dispose;
- gobject_class->finalize = webkit_video_sink_finalize;
+ gstbase_sink_class->unlock = webkit_video_sink_unlock;
+ gstbase_sink_class->unlock_stop = webkit_video_sink_unlock_stop;
gstbase_sink_class->render = webkit_video_sink_render;
gstbase_sink_class->preroll = webkit_video_sink_render;
gstbase_sink_class->stop = webkit_video_sink_stop;
- gstbase_sink_class->set_caps = webkit_video_sink_set_caps;
+ gstbase_sink_class->start = webkit_video_sink_start;
webkit_video_sink_signals[REPAINT_REQUESTED] = g_signal_new("repaint-requested",
G_TYPE_FROM_CLASS(klass),
@@ -315,37 +295,20 @@ webkit_video_sink_class_init(WebKitVideoSinkClass* klass)
0,
0,
0,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
-
- g_object_class_install_property(
- gobject_class, PROP_SURFACE,
- g_param_spec_pointer("surface", "surface", "Target cairo_surface_t*",
- (GParamFlags)(G_PARAM_READWRITE)));
+ marshal_VOID__MINIOBJECT,
+ G_TYPE_NONE, 1, GST_TYPE_BUFFER);
}
/**
* webkit_video_sink_new:
- * @surface: a #cairo_surface_t
*
- * Creates a new GStreamer video sink which uses @surface as the target
- * for sinking a video stream from GStreamer.
+ * Creates a new GStreamer video sink.
*
* Return value: a #GstElement for the newly created video sink
*/
GstElement*
-webkit_video_sink_new(cairo_surface_t* surface)
+webkit_video_sink_new(void)
{
- return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, "surface", surface, 0);
+ return (GstElement*)g_object_new(WEBKIT_TYPE_VIDEO_SINK, 0);
}
-void
-webkit_video_sink_set_surface(WebKitVideoSink* sink, cairo_surface_t* surface)
-{
- WebKitVideoSinkPrivate* priv;
-
- sink->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE(sink, WEBKIT_TYPE_VIDEO_SINK, WebKitVideoSinkPrivate);
- if (priv->surface)
- cairo_surface_destroy(priv->surface);
- priv->surface = cairo_surface_reference(surface);
-}
diff --git a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
index be2c94c..7ea7d91 100644
--- a/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
+++ b/WebCore/platform/graphics/gtk/VideoSinkGStreamer.h
@@ -22,7 +22,7 @@
#include <cairo.h>
#include <glib-object.h>
-#include <gst/base/gstbasesink.h>
+#include <gst/video/gstvideosink.h>
G_BEGIN_DECLS
@@ -54,13 +54,13 @@ typedef struct _WebKitVideoSinkPrivate WebKitVideoSinkPrivate;
struct _WebKitVideoSink {
/*< private >*/
- GstBaseSink parent;
+ GstVideoSink parent;
WebKitVideoSinkPrivate *priv;
};
struct _WebKitVideoSinkClass {
/*< private >*/
- GstBaseSinkClass parent_class;
+ GstVideoSinkClass parent_class;
/* Future padding */
void (* _webkit_reserved1)(void);
@@ -72,9 +72,7 @@ struct _WebKitVideoSinkClass {
};
GType webkit_video_sink_get_type(void) G_GNUC_CONST;
-GstElement *webkit_video_sink_new(cairo_surface_t *surface);
-
-void webkit_video_sink_set_surface(WebKitVideoSink *sink, cairo_surface_t *surface);
+GstElement *webkit_video_sink_new(void);
G_END_DECLS
diff --git a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
index d785ef4..c23b8a9 100644
--- a/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/GraphicsContextHaiku.cpp
@@ -369,6 +369,11 @@ void GraphicsContext::clip(const Path& path)
m_data->m_view->ConstrainClippingRegion(path.platformPath());
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
diff --git a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp
index 34941c0..adb7573 100644
--- a/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp
+++ b/WebCore/platform/graphics/haiku/SimpleFontDataHaiku.cpp
@@ -39,6 +39,8 @@
#include <unicode/unorm.h>
+extern int charUnicodeToUTF8HACK(unsigned short, char*);
+
namespace WebCore {
void SimpleFontData::platformInit()
@@ -93,15 +95,15 @@ void SimpleFontData::determinePitch()
float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
{
- const char charArray[1] = { glyph };
- float escapements[1];
+ if (!m_platformData.font())
+ return 0;
- if (m_platformData.font()) {
- m_platformData.font()->GetEscapements(charArray, 1, escapements);
- return escapements[0] * m_platformData.font()->Size();
- }
+ char charArray[4];
+ float escapements[1];
- return 0;
+ charUnicodeToUTF8HACK(glyph, charArray);
+ m_platformData.font()->GetEscapements(charArray, 1, escapements);
+ return escapements[0] * m_platformData.font()->Size();
}
} // namespace WebCore
diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.h b/WebCore/platform/graphics/mac/Canvas3DLayer.h
index 6c65676..122ef39 100644
--- a/WebCore/platform/graphics/mac/Canvas3DLayer.h
+++ b/WebCore/platform/graphics/mac/Canvas3DLayer.h
@@ -41,7 +41,9 @@ namespace WebCore {
GLuint m_texture;
}
--(id)initWithContext:(CGLContextObj)context texture:(GLuint)texture;
+- (id)initWithContext:(CGLContextObj)context texture:(GLuint)texture;
+
+- (CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace;
@end
diff --git a/WebCore/platform/graphics/mac/Canvas3DLayer.mm b/WebCore/platform/graphics/mac/Canvas3DLayer.mm
index 545c58b..94819d4 100644
--- a/WebCore/platform/graphics/mac/Canvas3DLayer.mm
+++ b/WebCore/platform/graphics/mac/Canvas3DLayer.mm
@@ -33,6 +33,8 @@
#import "GraphicsLayer.h"
#import <QuartzCore/QuartzCore.h>
#import <OpenGL/OpenGL.h>
+#import <wtf/RetainPtr.h>
+#include <wtf/FastMalloc.h>
using namespace WebCore;
@@ -48,19 +50,14 @@ using namespace WebCore;
-(CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
{
- CGLPixelFormatAttribute attribs[] =
- {
- (CGLPixelFormatAttribute) kCGLPFAAccelerated,
- (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32,
- (CGLPixelFormatAttribute) kCGLPFADisplayMask, (CGLPixelFormatAttribute) mask,
- (CGLPixelFormatAttribute) 0
- };
-
- CGLPixelFormatObj pixelFormatObj;
- GLint numPixelFormats;
-
- CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);
- return pixelFormatObj;
+ // FIXME: The mask param tells you which display (on a multi-display system)
+ // is to be used. But since we are now getting the pixel format from the
+ // Canvas CGL context, we don't use it. This seems to do the right thing on
+ // one multi-display system. But there may be cases where this is not the case.
+ // If needed we will have to set the display mask in the Canvas CGLContext and
+ // make sure it matches.
+ UNUSED_PARAM(mask);
+ return CGLRetainPixelFormat(CGLGetPixelFormat(m_contextObj));
}
-(CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat
@@ -72,6 +69,10 @@ using namespace WebCore;
-(void)drawInCGLContext:(CGLContextObj)glContext pixelFormat:(CGLPixelFormatObj)pixelFormat forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp
{
+ CGLSetCurrentContext(m_contextObj);
+ glFinish();
+ CGLSetCurrentContext(glContext);
+
CGRect frame = [self frame];
// draw the FBO into the layer
@@ -103,6 +104,42 @@ using namespace WebCore;
[super drawInCGLContext:glContext pixelFormat:pixelFormat forLayerTime:timeInterval displayTime:timeStamp];
}
+static void freeData(void *, const void *data, size_t /* size */)
+{
+ fastFree(const_cast<void *>(data));
+}
+
+-(CGImageRef)copyImageSnapshotWithColorSpace:(CGColorSpaceRef)colorSpace
+{
+ CGLSetCurrentContext(m_contextObj);
+
+ RetainPtr<CGColorSpaceRef> imageColorSpace = colorSpace;
+ if (!imageColorSpace)
+ imageColorSpace.adoptCF(CGColorSpaceCreateDeviceRGB());
+
+ CGRect layerBounds = CGRectIntegral([self bounds]);
+
+ size_t width = layerBounds.size.width;
+ size_t height = layerBounds.size.height;
+
+ size_t rowBytes = (width * 4 + 15) & ~15;
+ size_t dataSize = rowBytes * height;
+ void* data = fastMalloc(dataSize);
+ if (!data)
+ return 0;
+
+ glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4);
+ glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
+
+ CGDataProviderRef provider = CGDataProviderCreateWithData(0, data, dataSize, freeData);
+ CGImageRef image = CGImageCreate(width, height, 8, 32, rowBytes, imageColorSpace.get(),
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,
+ provider, 0, true,
+ kCGRenderingIntentDefault);
+ CGDataProviderRelease(provider);
+ return image;
+}
+
@end
@implementation Canvas3DLayer(WebLayerAdditions)
diff --git a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
index cd66445..47617d8 100644
--- a/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
+++ b/WebCore/platform/graphics/mac/GraphicsContext3DMac.cpp
@@ -30,9 +30,10 @@
#include "GraphicsContext3D.h"
#include "CachedImage.h"
+#include "CanvasActiveInfo.h"
+#include "CanvasArray.h"
#include "CanvasBuffer.h"
#include "CanvasFramebuffer.h"
-#include "CanvasArray.h"
#include "CanvasFloatArray.h"
#include "CanvasIntArray.h"
#include "CanvasObject.h"
@@ -49,29 +50,91 @@
#include "WebKitCSSMatrix.h"
#include <CoreGraphics/CGBitmapContext.h>
+#include <OpenGL/CGLRenderers.h>
namespace WebCore {
-GraphicsContext3D::GraphicsContext3D()
+static void setPixelFormat(Vector<CGLPixelFormatAttribute>& attribs, int colorBits, int depthBits, bool accelerated, bool supersample, bool closest)
{
- CGLPixelFormatAttribute attribs[] =
- {
- (CGLPixelFormatAttribute) kCGLPFAAccelerated,
- (CGLPixelFormatAttribute) kCGLPFAColorSize, (CGLPixelFormatAttribute) 32,
- (CGLPixelFormatAttribute) kCGLPFADepthSize, (CGLPixelFormatAttribute) 32,
- (CGLPixelFormatAttribute) kCGLPFASupersample,
- (CGLPixelFormatAttribute) 0
- };
+ attribs.clear();
- CGLPixelFormatObj pixelFormatObj;
- GLint numPixelFormats;
+ attribs.append(kCGLPFAColorSize);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(colorBits));
+ attribs.append(kCGLPFADepthSize);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(depthBits));
- CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);
-
- CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
+ if (accelerated)
+ attribs.append(kCGLPFAAccelerated);
+ else {
+ attribs.append(kCGLPFARendererID);
+ attribs.append(static_cast<CGLPixelFormatAttribute>(kCGLRendererGenericFloatID));
+ }
+
+ if (supersample)
+ attribs.append(kCGLPFASupersample);
+
+ if (closest)
+ attribs.append(kCGLPFAClosestPolicy);
+
+ attribs.append(static_cast<CGLPixelFormatAttribute>(0));
+}
+
+PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create()
+{
+ OwnPtr<GraphicsContext3D> context(new GraphicsContext3D());
+ return context->m_contextObj ? context.release() : 0;
+}
+
+GraphicsContext3D::GraphicsContext3D()
+ : m_contextObj(0)
+ , m_texture(0)
+ , m_fbo(0)
+ , m_depthBuffer(0)
+{
+ Vector<CGLPixelFormatAttribute> attribs;
+ CGLPixelFormatObj pixelFormatObj = 0;
+ GLint numPixelFormats = 0;
+
+ // We will try:
+ //
+ // 1) 32 bit RGBA/32 bit depth/accelerated/supersampled
+ // 2) 32 bit RGBA/32 bit depth/accelerated
+ // 3) 32 bit RGBA/16 bit depth/accelerated
+ // 4) closest to 32 bit RGBA/16 bit depth/software renderer
+ //
+ // If none of that works, we simply fail and set m_contextObj to 0.
+
+ setPixelFormat(attribs, 32, 32, true, true, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 32, true, false, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 16, true, false, false);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ setPixelFormat(attribs, 32, 16, false, false, true);
+ CGLChoosePixelFormat(attribs.data(), &pixelFormatObj, &numPixelFormats);
+
+ if (numPixelFormats == 0) {
+ // Could not find an acceptable renderer - fail
+ return;
+ }
+ }
+ }
+ }
+ CGLError err = CGLCreateContext(pixelFormatObj, 0, &m_contextObj);
CGLDestroyPixelFormat(pixelFormatObj);
+ if (err != kCGLNoError || !m_contextObj) {
+ // Could not create the context - fail
+ m_contextObj = 0;
+ return;
+ }
+
// Set the current context to the one given to us.
CGLSetCurrentContext(m_contextObj);
@@ -102,12 +165,14 @@ GraphicsContext3D::GraphicsContext3D()
GraphicsContext3D::~GraphicsContext3D()
{
- CGLSetCurrentContext(m_contextObj);
- ::glDeleteRenderbuffersEXT(1, & m_depthBuffer);
- ::glDeleteTextures(1, &m_texture);
- ::glDeleteFramebuffersEXT(1, &m_fbo);
- CGLSetCurrentContext(0);
- CGLDestroyContext(m_contextObj);
+ if (m_contextObj) {
+ CGLSetCurrentContext(m_contextObj);
+ ::glDeleteRenderbuffersEXT(1, & m_depthBuffer);
+ ::glDeleteTextures(1, &m_texture);
+ ::glDeleteFramebuffersEXT(1, &m_fbo);
+ CGLSetCurrentContext(0);
+ CGLDestroyContext(m_contextObj);
+ }
}
void GraphicsContext3D::checkError() const
@@ -135,7 +200,7 @@ void GraphicsContext3D::endPaint()
void GraphicsContext3D::reshape(int width, int height)
{
- if (width == m_currentWidth && height == m_currentHeight)
+ if (width == m_currentWidth && height == m_currentHeight || !m_contextObj)
return;
m_currentWidth = width;
@@ -167,6 +232,9 @@ void GraphicsContext3D::reshape(int width, int height)
static inline void ensureContext(CGLContextObj context)
{
+ if (!context)
+ return;
+
CGLContextObj currentContext = CGLGetCurrentContext();
if (currentContext != context)
CGLSetCurrentContext(context);
@@ -442,6 +510,46 @@ void GraphicsContext3D::generateMipmap(unsigned long target)
::glGenerateMipmapEXT(target);
}
+bool GraphicsContext3D::getActiveAttrib(CanvasProgram* program, unsigned long index, ActiveInfo& info)
+{
+ if (!program->object())
+ return false;
+ ensureContext(m_contextObj);
+ GLint maxAttributeSize = 0;
+ ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttributeSize);
+ GLchar name[maxAttributeSize]; // GL_ACTIVE_ATTRIBUTE_MAX_LENGTH includes null termination
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+ ::glGetActiveAttrib(static_cast<GLuint>(program->object()), index, maxAttributeSize, &nameLength, &size, &type, name);
+ if (!nameLength)
+ return false;
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+ return true;
+}
+
+bool GraphicsContext3D::getActiveUniform(CanvasProgram* program, unsigned long index, ActiveInfo& info)
+{
+ if (!program->object())
+ return false;
+ ensureContext(m_contextObj);
+ GLint maxUniformSize = 0;
+ ::glGetProgramiv(static_cast<GLuint>(program->object()), GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformSize);
+ GLchar name[maxUniformSize]; // GL_ACTIVE_UNIFORM_MAX_LENGTH includes null termination
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+ ::glGetActiveUniform(static_cast<GLuint>(program->object()), index, maxUniformSize, &nameLength, &size, &type, name);
+ if (!nameLength)
+ return false;
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+ return true;
+}
+
int GraphicsContext3D::getAttribLocation(CanvasProgram* program, const String& name)
{
if (!program)
@@ -556,6 +664,22 @@ void GraphicsContext3D::polygonOffset(double factor, double units)
::glPolygonOffset(static_cast<float>(factor), static_cast<float>(units));
}
+PassRefPtr<CanvasArray> GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type)
+{
+ ensureContext(m_contextObj);
+
+ // FIXME: For now we only accept GL_UNSIGNED_BYTE/GL_RGBA. In reality OpenGL ES 2.0 accepts that pair and one other
+ // as specified by GL_IMPLEMENTATION_COLOR_READ_FORMAT and GL_IMPLEMENTATION_COLOR_READ_TYPE. But for now we will
+ // not accept those.
+ // FIXME: Also, we should throw when an unacceptable value is passed
+ if (type != GL_UNSIGNED_BYTE || format != GL_RGBA)
+ return 0;
+
+ RefPtr<CanvasUnsignedByteArray> array = CanvasUnsignedByteArray::create(width * height * 4);
+ ::glReadPixels(x, y, width, height, format, type, (GLvoid*) array->data());
+ return array;
+}
+
void GraphicsContext3D::releaseShaderCompiler()
{
// FIXME: This is not implemented on desktop OpenGL. We need to have ifdefs for the different GL variants
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.h b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
index d0e1108..8cf51b4 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.h
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.h
@@ -110,10 +110,8 @@ public:
virtual PlatformLayer* platformLayer() const;
-#ifndef NDEBUG
virtual void setDebugBackgroundColor(const Color&);
virtual void setDebugBorder(const Color&, float borderWidth);
-#endif
virtual void setGeometryOrientation(CompositingCoordinatesOrientation);
diff --git a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
index e9960f1..b351956 100644
--- a/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
+++ b/WebCore/platform/graphics/mac/GraphicsLayerCA.mm
@@ -274,7 +274,6 @@ static CAMediaTimingFunction* getCAMediaTimingFunction(const TimingFunction& tim
return 0;
}
-#ifndef NDEBUG
static void setLayerBorderColor(PlatformLayer* layer, const Color& color)
{
CGColorRef borderColor = createCGColor(color);
@@ -286,7 +285,6 @@ static void clearBorderColor(PlatformLayer* layer)
{
[layer setBorderColor:nil];
}
-#endif
static void setLayerBackgroundColor(PlatformLayer* layer, const Color& color)
{
@@ -317,7 +315,6 @@ GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayer::compositingCoord
return CompositingCoordinatesBottomUp;
}
-#ifndef NDEBUG
bool GraphicsLayer::showDebugBorders()
{
static bool showDebugBorders = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerBorders"];
@@ -329,7 +326,6 @@ bool GraphicsLayer::showRepaintCounter()
static bool showRepaintCounter = [[NSUserDefaults standardUserDefaults] boolForKey:@"WebCoreLayerRepaintCounter"];
return showRepaintCounter;
}
-#endif
static NSDictionary* nullActionsDictionary()
{
@@ -373,9 +369,7 @@ GraphicsLayerCA::GraphicsLayerCA(GraphicsLayerClient* client)
setContentsOrientation(defaultContentsOrientation());
#endif
-#ifndef NDEBUG
updateDebugIndicators();
-#endif
m_animationDelegate.adoptNS([[WebAnimationDelegate alloc] init]);
[m_animationDelegate.get() setLayer:this];
@@ -964,9 +958,7 @@ void GraphicsLayerCA::updateChildrenTransform()
void GraphicsLayerCA::updateMasksToBounds()
{
[m_layer.get() setMasksToBounds:m_masksToBounds];
-#ifndef NDEBUG
updateDebugIndicators();
-#endif
}
void GraphicsLayerCA::updateContentsOpaque()
@@ -1051,9 +1043,7 @@ void GraphicsLayerCA::updateLayerDrawsContent()
else
[m_layer.get() setContents:nil];
-#ifndef NDEBUG
updateDebugIndicators();
-#endif
}
void GraphicsLayerCA::updateLayerBackgroundColor()
@@ -1245,6 +1235,21 @@ void GraphicsLayerCA::setAnimationOnLayer(CAPropertyAnimation* caAnim, AnimatedP
[layer addAnimation:caAnim forKey:animationName];
}
+// Workaround for <rdar://problem/7311367>
+static void bug7311367Workaround(CALayer* transformLayer, const TransformationMatrix& transform)
+{
+ if (!transformLayer)
+ return;
+
+ CATransform3D caTransform;
+ copyTransform(caTransform, transform);
+ caTransform.m41 += 1;
+ [transformLayer setTransform:caTransform];
+
+ caTransform.m41 -= 1;
+ [transformLayer setTransform:caTransform];
+}
+
bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int index)
{
PlatformLayer* layer = animatedLayer(property);
@@ -1255,10 +1260,11 @@ bool GraphicsLayerCA::removeAnimationFromLayer(AnimatedPropertyID property, int
return false;
[layer removeAnimationForKey:animationName];
+
+ bug7311367Workaround(m_transformLayer.get(), m_transform);
return true;
}
-
static void copyAnimationProperties(CAPropertyAnimation* from, CAPropertyAnimation* to)
{
[to setBeginTime:[from beginTime]];
@@ -1679,7 +1685,6 @@ PlatformLayer* GraphicsLayerCA::platformLayer() const
return primaryLayer();
}
-#ifndef NDEBUG
void GraphicsLayerCA::setDebugBackgroundColor(const Color& color)
{
BEGIN_BLOCK_OBJC_EXCEPTIONS
@@ -1706,7 +1711,6 @@ void GraphicsLayerCA::setDebugBorder(const Color& color, float borderWidth)
END_BLOCK_OBJC_EXCEPTIONS
}
-#endif // NDEBUG
bool GraphicsLayerCA::requiresTiledLayer(const FloatSize& size) const
{
@@ -1784,9 +1788,7 @@ void GraphicsLayerCA::swapFromOrToTiledLayer(bool useTiledLayer)
// need to tell new layer to draw itself
setNeedsDisplay();
-#ifndef NDEBUG
updateDebugIndicators();
-#endif
}
GraphicsLayer::CompositingCoordinatesOrientation GraphicsLayerCA::defaultContentsOrientation() const
@@ -1830,12 +1832,10 @@ void GraphicsLayerCA::setupContentsLayer(CALayer* contentsLayer)
} else
[contentsLayer setAnchorPoint:CGPointZero];
-#ifndef NDEBUG
if (showDebugBorders()) {
setLayerBorderColor(contentsLayer, Color(0, 0, 128, 180));
[contentsLayer setBorderWidth:1.0f];
}
-#endif
}
void GraphicsLayerCA::setOpacityInternal(float accumulatedOpacity)
diff --git a/WebCore/platform/graphics/mac/WebLayer.mm b/WebCore/platform/graphics/mac/WebLayer.mm
index 2647466..56b28e6 100644
--- a/WebCore/platform/graphics/mac/WebLayer.mm
+++ b/WebCore/platform/graphics/mac/WebLayer.mm
@@ -80,7 +80,6 @@ using namespace WebCore;
}
#endif
-#ifndef NDEBUG
if (layerContents->showRepaintCounter()) {
bool isTiledLayer = [layer isKindOfClass:[CATiledLayer class]];
@@ -107,7 +106,6 @@ using namespace WebCore;
CGContextRestoreGState(context);
}
-#endif
CGContextRestoreGState(context);
}
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index fa7b070..57a481a 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -1053,6 +1053,11 @@ void GraphicsContext::clip(const Path& path)
m_data->p()->setClipPath(*path.platformPath(), Qt::IntersectClip);
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipOut(const Path& path)
{
if (paintingDisabled())
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index 3a27fe3..f8403b7 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -43,22 +43,13 @@ ImageDecoder* ImageDecoder::create(const SharedBuffer& data)
if (data.size() < 4)
return 0;
- QByteArray bytes = QByteArray::fromRawData(data.data(), data.size());
- QBuffer buffer(&bytes);
- if (!buffer.open(QBuffer::ReadOnly))
- return 0;
-
- QByteArray imageFormat = QImageReader::imageFormat(&buffer);
- if (imageFormat.isEmpty())
- return 0; // Image format not supported
-
- return new ImageDecoderQt(imageFormat);
+ return new ImageDecoderQt;
}
-ImageDecoderQt::ImageDecoderQt(const QByteArray& imageFormat)
- : m_buffer(0)
+ImageDecoderQt::ImageDecoderQt()
+ : m_buffer(0)
, m_reader(0)
- , m_repetitionCount(-1)
+ , m_repetitionCount(cAnimationNone)
{
}
@@ -73,13 +64,13 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
if (m_failed)
return;
- // Cache our own new data.
- ImageDecoder::setData(data, allDataReceived);
-
// No progressive loading possible
if (!allDataReceived)
return;
+ // Cache our own new data.
+ ImageDecoder::setData(data, allDataReceived);
+
// We expect to be only called once with allDataReceived
ASSERT(!m_buffer);
ASSERT(!m_reader);
@@ -89,15 +80,12 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
m_buffer = new QBuffer;
m_buffer->setData(imageData);
m_buffer->open(QBuffer::ReadOnly);
- m_reader = new QImageReader(m_buffer);
-
- if (!m_reader->canRead())
- failRead();
+ m_reader = new QImageReader(m_buffer, m_format);
}
bool ImageDecoderQt::isSizeAvailable()
{
- if (!m_failed && !ImageDecoder::isSizeAvailable() && m_reader)
+ if (!ImageDecoder::isSizeAvailable() && m_reader)
internalDecodeSize();
return ImageDecoder::isSizeAvailable();
@@ -134,14 +122,16 @@ int ImageDecoderQt::repetitionCount() const
String ImageDecoderQt::filenameExtension() const
{
- return m_format;
+ return String(m_format.constData(), m_format.length());
};
RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
{
- // this information might not have been set
+ // 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 (count == 0) {
+ if (!m_failed && count == 0) {
internalDecodeSize();
count = frameCount();
}
@@ -171,7 +161,12 @@ void ImageDecoderQt::internalDecodeSize()
{
ASSERT(m_reader);
+ // If we have a QSize() something failed
QSize size = m_reader->size();
+ if (size.isEmpty())
+ return failRead();
+
+ m_format = m_reader->format();
setSize(size.width(), size.height());
}
@@ -213,9 +208,15 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
buffer->setDecodedImage(img);
}
-// We will parse everything and we have no idea how
-// many images we have... We will have to find out the
-// hard way.
+// The QImageIOHandler is not able to tell us how many frames
+// we have and we need to parse every image. We do this by
+// increasing the m_frameBufferCache by one and try to parse
+// the image. We stop when QImage::read fails and then need
+// to resize the m_frameBufferCache to the final size and update
+// the m_failed. In case we failed to decode the first image
+// we want to keep m_failed set to true.
+
+// TODO: Do not increment the m_frameBufferCache.size() by one but more than one
void ImageDecoderQt::forceLoadEverything()
{
int imageCount = 0;
@@ -225,9 +226,12 @@ void ImageDecoderQt::forceLoadEverything()
internalHandleCurrentImage(imageCount - 1);
} while(!m_failed);
- // reset the failed state and resize the vector...
+ // If we failed decoding the first image we actually
+ // have no images and need to keep m_failed set to
+ // true otherwise we want to reset it and forget about
+ // the last attempt to decode a image.
m_frameBufferCache.resize(imageCount - 1);
- m_failed = false;
+ m_failed = imageCount == 1;
}
void ImageDecoderQt::failRead()
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index 7b3b686..d11b938 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -40,7 +40,7 @@ namespace WebCore {
class ImageDecoderQt : public ImageDecoder
{
public:
- ImageDecoderQt(const QByteArray& imageFormat);
+ ImageDecoderQt();
~ImageDecoderQt();
virtual void setData(SharedBuffer* data, bool allDataReceived);
@@ -65,7 +65,7 @@ private:
void failRead();
private:
- String m_format;
+ QByteArray m_format;
QBuffer* m_buffer;
QImageReader* m_reader;
mutable int m_repetitionCount;
diff --git a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
index c9f1349..889c41b 100644
--- a/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/GraphicsContextSkia.cpp
@@ -296,7 +296,7 @@ void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect, int thickness
r.inset(SkIntToScalar(thickness), SkIntToScalar(thickness));
path.addOval(r, SkPath::kCCW_Direction);
}
- platformContext()->canvas()->clipPath(path);
+ platformContext()->clipPathAntiAliased(path);
}
void GraphicsContext::addPath(const Path& path)
@@ -356,6 +356,18 @@ void GraphicsContext::clip(const Path& path)
if (!isPathSkiaSafe(getCTM(), p))
return;
+ platformContext()->clipPathAntiAliased(p);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ const SkPath& p = *path.platformPath();
+ if (!isPathSkiaSafe(getCTM(), p))
+ return;
+
platformContext()->canvas()->clipPath(p);
}
@@ -407,7 +419,7 @@ void GraphicsContext::clipPath(WindRule clipRule)
return;
path.setFillType(clipRule == RULE_EVENODD ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType);
- platformContext()->canvas()->clipPath(path);
+ platformContext()->clipPathAntiAliased(path);
}
void GraphicsContext::clipToImageBuffer(const FloatRect& rect,
diff --git a/WebCore/platform/graphics/skia/PathSkia.cpp b/WebCore/platform/graphics/skia/PathSkia.cpp
index 5ac14b9..2cbb759 100644
--- a/WebCore/platform/graphics/skia/PathSkia.cpp
+++ b/WebCore/platform/graphics/skia/PathSkia.cpp
@@ -123,26 +123,31 @@ void Path::addArc(const FloatPoint& p, float r, float sa, float ea, bool anticlo
SkScalar cx = WebCoreFloatToSkScalar(p.x());
SkScalar cy = WebCoreFloatToSkScalar(p.y());
SkScalar radius = WebCoreFloatToSkScalar(r);
+ SkScalar s360 = SkIntToScalar(360);
SkRect oval;
oval.set(cx - radius, cy - radius, cx + radius, cy + radius);
float sweep = ea - sa;
- // check for a circle
- if (sweep >= 2 * piFloat || sweep <= -2 * piFloat)
+ SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
+ SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
+ // Check for a circle.
+ if (sweepDegrees >= s360 || sweepDegrees <= -s360) {
+ // Move to the start position (0 sweep means we add a single point).
+ m_path->arcTo(oval, startDegrees, 0, false);
+ // Draw the circle.
m_path->addOval(oval);
- else {
- SkScalar startDegrees = WebCoreFloatToSkScalar(sa * 180 / piFloat);
- SkScalar sweepDegrees = WebCoreFloatToSkScalar(sweep * 180 / piFloat);
-
+ // Force a moveTo the end position.
+ m_path->arcTo(oval, startDegrees + sweepDegrees, 0, true);
+ } else {
// Counterclockwise arcs should be drawn with negative sweeps, while
// clockwise arcs should be drawn with positive sweeps. Check to see
// if the situation is reversed and correct it by adding or subtracting
// a full circle
if (anticlockwise && sweepDegrees > 0) {
- sweepDegrees -= SkIntToScalar(360);
+ sweepDegrees -= s360;
} else if (!anticlockwise && sweepDegrees < 0) {
- sweepDegrees += SkIntToScalar(360);
+ sweepDegrees += s360;
}
m_path->arcTo(oval, startDegrees, sweepDegrees, false);
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
index 1fb62fc..a079da0 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.cpp
@@ -45,6 +45,7 @@
#include "SkDashPathEffect.h"
#include <wtf/MathExtras.h>
+#include <wtf/Vector.h>
namespace WebCore
{
@@ -95,6 +96,10 @@ struct PlatformContextSkia::State {
WebCore::FloatRect m_clip;
#endif
+ // This is a list of clipping paths which are currently active, in the
+ // order in which they were pushed.
+ WTF::Vector<SkPath> m_antiAliasClipPaths;
+
private:
// Not supported.
void operator=(const State&);
@@ -110,8 +115,8 @@ PlatformContextSkia::State::State()
, m_fillShader(0)
, m_strokeStyle(WebCore::SolidStroke)
, m_strokeColor(WebCore::Color::black)
- , m_strokeThickness(0)
, m_strokeShader(0)
+ , m_strokeThickness(0)
, m_dashRatio(3)
, m_miterLimit(4)
, m_lineCap(SkPaint::kDefault_Cap)
@@ -130,8 +135,8 @@ PlatformContextSkia::State::State(const State& other)
, m_fillShader(other.m_fillShader)
, m_strokeStyle(other.m_strokeStyle)
, m_strokeColor(other.m_strokeColor)
- , m_strokeThickness(other.m_strokeThickness)
, m_strokeShader(other.m_strokeShader)
+ , m_strokeThickness(other.m_strokeThickness)
, m_dashRatio(other.m_dashRatio)
, m_miterLimit(other.m_miterLimit)
, m_lineCap(other.m_lineCap)
@@ -249,6 +254,21 @@ void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rec
}
#endif
+void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
+{
+ // If we are currently tracking any anti-alias clip paths, then we already
+ // have a layer in place and don't need to add another.
+ bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size();
+
+ // See comments in applyAntiAliasedClipPaths about how this works.
+ m_state->m_antiAliasClipPaths.append(clipPath);
+
+ if (!haveLayerOutstanding) {
+ SkRect bounds = clipPath.getBounds();
+ canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag));
+ }
+}
+
void PlatformContextSkia::restore()
{
#if defined(__linux__) || PLATFORM(WIN_OS)
@@ -258,6 +278,9 @@ void PlatformContextSkia::restore()
}
#endif
+ if (!m_state->m_antiAliasClipPaths.isEmpty())
+ applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths);
+
m_stateStack.removeLast();
m_state = &m_stateStack.last();
@@ -549,3 +572,40 @@ void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, con
m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
}
#endif
+
+void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths)
+{
+ // Anti-aliased clipping:
+ //
+ // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit:
+ // We have a square canvas, filled with white and we declare a circular
+ // clipping path. Then we fill twice with a black rectangle. The fractional
+ // pixels would first get the correct color (white * alpha + black * (1 -
+ // alpha)), but the second fill would apply the alpha to the already
+ // modified color and the result would be too dark.
+ //
+ // This, anti-aliased clipping needs to be performed after the drawing has
+ // been done. In order to do this, we create a new layer of the canvas in
+ // clipPathAntiAliased and store the clipping path. All drawing is done to
+ // the layer's bitmap while it's in effect. When WebKit calls restore() to
+ // undo the clipping, this function is called.
+ //
+ // Here, we walk the list of clipping paths backwards and, for each, we
+ // clear outside of the clipping path. We only need a single extra layer
+ // for any number of clipping paths.
+ //
+ // When we call restore on the SkCanvas, the layer's bitmap is composed
+ // into the layer below and we end up with correct, anti-aliased clipping.
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kClear_Mode);
+ paint.setAntiAlias(true);
+ paint.setStyle(SkPaint::kFill_Style);
+
+ for (size_t i = paths.size() - 1; i < paths.size(); --i) {
+ paths[i].setFillType(SkPath::kInverseWinding_FillType);
+ m_canvas->drawPath(paths[i], paint);
+ }
+
+ m_canvas->restore();
+}
diff --git a/WebCore/platform/graphics/skia/PlatformContextSkia.h b/WebCore/platform/graphics/skia/PlatformContextSkia.h
index 0c87fc2..53590bf 100644
--- a/WebCore/platform/graphics/skia/PlatformContextSkia.h
+++ b/WebCore/platform/graphics/skia/PlatformContextSkia.h
@@ -92,6 +92,7 @@ public:
void beginLayerClippedToImage(const WebCore::FloatRect&,
const WebCore::ImageBuffer*);
#endif
+ void clipPathAntiAliased(const SkPath&);
// Sets up the common flags on a paint for antialiasing, effects, etc.
// This is implicitly called by setupPaintFill and setupPaintStroke, but
@@ -172,6 +173,7 @@ private:
// m_canvas that are also in imageBuffer.
void applyClipFromImage(const WebCore::FloatRect&, const SkBitmap&);
#endif
+ void applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths);
// Defines drawing style.
struct State;
diff --git a/WebCore/platform/graphics/skia/SkiaUtils.cpp b/WebCore/platform/graphics/skia/SkiaUtils.cpp
index bb15aa2..377ca06 100644
--- a/WebCore/platform/graphics/skia/SkiaUtils.cpp
+++ b/WebCore/platform/graphics/skia/SkiaUtils.cpp
@@ -200,8 +200,13 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::
SkRect bounds = originalPath->getBounds();
- // We can immediately return false if the point is outside the bounding rect
- if (!bounds.contains(SkFloatToScalar(point.x()), SkFloatToScalar(point.y())))
+ // We can immediately return false if the point is outside the bounding
+ // rect. We don't use bounds.contains() here, since it would exclude
+ // points on the right and bottom edges of the bounding rect, and we want
+ // to include them.
+ SkScalar fX = SkFloatToScalar(point.x());
+ SkScalar fY = SkFloatToScalar(point.y());
+ if (fX < bounds.fLeft || fX > bounds.fRight || fY < bounds.fTop || fY > bounds.fBottom)
return false;
originalPath->setFillType(ft);
@@ -225,7 +230,7 @@ bool SkPathContainsPoint(SkPath* originalPath, const FloatPoint& point, SkPath::
int x = static_cast<int>(floorf(point.x() / scale));
int y = static_cast<int>(floorf(point.y() / scale));
- clip.setRect(x, y, x + 1, y + 1);
+ clip.setRect(x - 1, y - 1, x + 1, y + 1);
bool contains = rgn.setPath(*path, clip);
diff --git a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
index 26b22af..e845d85 100644
--- a/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
+++ b/WebCore/platform/graphics/win/SimpleFontDataCairoWin.cpp
@@ -34,11 +34,11 @@
#include "Font.h"
#include "FontCache.h"
#include "FontDescription.h"
-#include "MathExtras.h"
#include <cairo.h>
#include <cairo-win32.h>
#include <mlang.h>
#include <tchar.h>
+#include <wtf/MathExtras.h>
namespace WebCore {
diff --git a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
index c114c0e..f308840 100644
--- a/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
+++ b/WebCore/platform/graphics/wince/GraphicsContextWince.cpp
@@ -1219,6 +1219,11 @@ void GraphicsContext::clip(const Path& path)
notImplemented();
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipOut(const Path&)
{
notImplemented();
diff --git a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
index 686fb07..39f14f4 100644
--- a/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
+++ b/WebCore/platform/graphics/wx/GraphicsContextWx.cpp
@@ -344,6 +344,11 @@ void GraphicsContext::clip(const Path&)
notImplemented();
}
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
void GraphicsContext::clipToImageBuffer(const FloatRect&, const ImageBuffer*)
{
notImplemented();