summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/qt
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2010-04-27 16:31:00 +0100
committerSteve Block <steveblock@google.com>2010-05-11 14:42:12 +0100
commitdcc8cf2e65d1aa555cce12431a16547e66b469ee (patch)
tree92a8d65cd5383bca9749f5327fb5e440563926e6 /WebCore/platform/graphics/qt
parentccac38a6b48843126402088a309597e682f40fe6 (diff)
downloadexternal_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.zip
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.gz
external_webkit-dcc8cf2e65d1aa555cce12431a16547e66b469ee.tar.bz2
Merge webkit.org at r58033 : Initial merge by git
Change-Id: If006c38561af287c50cd578d251629b51e4d8cd1
Diffstat (limited to 'WebCore/platform/graphics/qt')
-rw-r--r--WebCore/platform/graphics/qt/FontPlatformDataQt.cpp3
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp19
-rw-r--r--WebCore/platform/graphics/qt/GradientQt.cpp10
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp1651
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp41
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp392
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.h3
-rw-r--r--WebCore/platform/graphics/qt/ImageBufferQt.cpp2
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp75
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.h4
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp67
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h1
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp571
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h133
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp4
-rw-r--r--WebCore/platform/graphics/qt/StillImageQt.cpp37
-rw-r--r--WebCore/platform/graphics/qt/TileQt.cpp178
17 files changed, 2984 insertions, 207 deletions
diff --git a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
index 0a1075f..0565deb 100644
--- a/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
+++ b/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -58,6 +58,9 @@ FontPlatformData::FontPlatformData(const FontDescription& description, const Ato
font.setLetterSpacing(QFont::AbsoluteSpacing, letterSpacing);
const bool smallCaps = description.smallCaps();
font.setCapitalization(smallCaps ? QFont::SmallCaps : QFont::MixedCase);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ font.setStyleStrategy(QFont::ForceIntegerMetrics);
+#endif
m_data->bold = font.bold();
m_data->size = font.pointSizeF();
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 9ff7c1a..974c179 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -1,6 +1,6 @@
/*
Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
- Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2008, 2010 Holger Hans Peter Freyther
Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
This library is free software; you can redistribute it and/or
@@ -134,7 +134,7 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
clip.adjust(dx1, dx2, dy1, dy2);
}
p->save();
- p->setClipRect(clip.toRect());
+ p->setClipRect(clip.toRect(), Qt::IntersectClip);
QPointF pt(point.x(), point.y() - ascent);
if (hasShadow) {
p->save();
@@ -169,17 +169,24 @@ void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const Float
p->drawText(pt, string, flags, run.padding());
}
-float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*) const
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
{
if (!run.length())
return 0;
+ if (run.length() == 1 && treatAsSpace(run[0]))
+ return QFontMetrics(font()).width(run[0]) - m_wordSpacing + run.padding();
+
String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
QString string = fromRawDataWithoutRef(sanitized);
QTextLayout layout(string, font());
QTextLine line = setupLayout(&layout, run);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ int w = int(line.horizontalAdvance());
+#else
int w = int(line.naturalTextWidth());
+#endif
// WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
if (treatAsSpace(run[0]))
w -= m_wordSpacing;
@@ -216,8 +223,10 @@ FloatRect Font::selectionRectForComplexText(const TextRun& run, const IntPoint&
QFont Font::font() const
{
QFont f = primaryFont()->getQtFont();
- f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing);
- f.setWordSpacing(m_wordSpacing);
+ if (m_letterSpacing != 0)
+ f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing);
+ if (m_wordSpacing != 0)
+ f.setWordSpacing(m_wordSpacing);
return f;
}
diff --git a/WebCore/platform/graphics/qt/GradientQt.cpp b/WebCore/platform/graphics/qt/GradientQt.cpp
index 9b9acc2..8b9e2d7 100644
--- a/WebCore/platform/graphics/qt/GradientQt.cpp
+++ b/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -51,6 +51,8 @@ QGradient* Gradient::platformGradient()
else
m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+ sortStopsIfNecessary();
+
QColor stopColor;
Vector<ColorStop>::iterator stopIterator = m_stops.begin();
qreal lastStop(0.0);
@@ -64,9 +66,17 @@ QGradient* Gradient::platformGradient()
if (m_radial && m_r0)
lastStop = m_r0 / m_r1 + lastStop * (1.0f - m_r0 / m_r1);
m_gradient->setColorAt(lastStop, stopColor);
+ // Keep the lastStop as orginal value, since the following stopColor depend it
+ lastStop = stopIterator->stop;
++stopIterator;
}
+ if (m_stops.isEmpty()) {
+ // The behavior of QGradient with no stops is defined differently from HTML5 spec,
+ // where the latter requires the gradient to be transparent black.
+ m_gradient->setColorAt(0.0, QColor(0, 0, 0, 0));
+ }
+
switch (m_spreadMethod) {
case SpreadMethodPad:
m_gradient->setSpread(QGradient::PadSpread);
diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
new file mode 100644
index 0000000..b0dd289
--- /dev/null
+++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -0,0 +1,1651 @@
+/*
+ Copyright (C) 2010 Tieto Corporation.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#include "config.h"
+
+#include "GraphicsContext3D.h"
+
+#include "CanvasObject.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "HostWindow.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
+#include "QWebPageClient.h"
+#include "WebGLActiveInfo.h"
+#include "WebGLArray.h"
+#include "WebGLBuffer.h"
+#include "WebGLFloatArray.h"
+#include "WebGLFramebuffer.h"
+#include "WebGLIntArray.h"
+#include "WebGLProgram.h"
+#include "WebGLRenderbuffer.h"
+#include "WebGLRenderingContext.h"
+#include "WebGLShader.h"
+#include "WebGLTexture.h"
+#include "WebGLUnsignedByteArray.h"
+#include <QAbstractScrollArea>
+#include <wtf/UnusedParam.h>
+#include <wtf/text/CString.h>
+
+#if ENABLE(3D_CANVAS)
+
+namespace WebCore {
+
+#if !defined(GLchar)
+typedef char GLchar;
+#endif
+
+#if !defined(APIENTRY)
+#define APIENTRY
+#endif
+
+typedef ptrdiff_t GLsizeiptrType;
+typedef ptrdiff_t GLintptrType;
+
+typedef void (APIENTRY* glActiveTextureType) (GLenum);
+typedef void (APIENTRY* glAttachShaderType) (GLuint, GLuint);
+typedef void (APIENTRY* glBindAttribLocationType) (GLuint, GLuint, const char*);
+typedef void (APIENTRY* glBindBufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBindFramebufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBindRenderbufferType) (GLenum, GLuint);
+typedef void (APIENTRY* glBlendColorType) (GLclampf, GLclampf, GLclampf, GLclampf);
+typedef void (APIENTRY* glBlendEquationType) (GLenum);
+typedef void (APIENTRY* glBlendEquationSeparateType)(GLenum, GLenum);
+typedef void (APIENTRY* glBlendFuncSeparateType)(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (APIENTRY* glBufferDataType) (GLenum, GLsizeiptrType, const GLvoid*, GLenum);
+typedef void (APIENTRY* glBufferSubDataType) (GLenum, GLintptrType, GLsizeiptrType, const GLvoid*);
+typedef GLenum (APIENTRY* glCheckFramebufferStatusType) (GLenum);
+typedef void (APIENTRY* glCompileShaderType) (GLuint);
+typedef GLuint (APIENTRY* glCreateProgramType) ();
+typedef GLuint (APIENTRY* glCreateShaderType) (GLenum);
+typedef void (APIENTRY* glDeleteBuffersType) (GLsizei, const GLuint*);
+typedef void (APIENTRY* glDeleteFramebuffersType) (GLsizei n, const GLuint*);
+typedef void (APIENTRY* glDeleteProgramType) (GLuint);
+typedef void (APIENTRY* glDeleteRenderbuffersType) (GLsizei n, const GLuint*);
+typedef void (APIENTRY* glDeleteShaderType) (GLuint);
+typedef void (APIENTRY* glDetachShaderType) (GLuint, GLuint);
+typedef void (APIENTRY* glDisableVertexAttribArrayType) (GLuint);
+typedef void (APIENTRY* glEnableVertexAttribArrayType) (GLuint);
+typedef void (APIENTRY* glFramebufferRenderbufferType) (GLenum, GLenum, GLenum, GLuint);
+typedef void (APIENTRY* glFramebufferTexture2DType) (GLenum, GLenum, GLenum, GLuint, GLint);
+typedef void (APIENTRY* glGenBuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGenerateMipmapType) (GLenum target);
+typedef void (APIENTRY* glGenFramebuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGenRenderbuffersType) (GLsizei, GLuint*);
+typedef void (APIENTRY* glGetActiveAttribType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*);
+typedef void (APIENTRY* glGetActiveUniformType) (GLuint, GLuint, GLsizei, GLsizei*, GLint*, GLenum*, GLchar*);
+typedef GLint (APIENTRY* glGetAttribLocationType) (GLuint, const char*);
+typedef void (APIENTRY* glGetBufferParameterivType) (GLenum, GLenum, GLint*);
+typedef void (APIENTRY* glGetFramebufferAttachmentParameterivType) (GLenum, GLenum, GLenum, GLint* params);
+typedef void (APIENTRY* glGetProgramInfoLogType) (GLuint, GLsizei, GLsizei*, char*);
+typedef void (APIENTRY* glGetProgramivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetRenderbufferParameterivType) (GLenum, GLenum, GLint*);
+typedef void (APIENTRY* glGetShaderInfoLogType) (GLuint, GLsizei, GLsizei*, char*);
+typedef void (APIENTRY* glGetShaderivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetShaderSourceType) (GLuint, GLsizei, GLsizei*, char*);
+typedef GLint (APIENTRY* glGetUniformLocationType) (GLuint, const char*);
+typedef void (APIENTRY* glGetUniformfvType) (GLuint, GLint, GLfloat*);
+typedef void (APIENTRY* glGetUniformivType) (GLuint, GLint, GLint*);
+typedef void (APIENTRY* glGetVertexAttribfvType) (GLuint, GLenum, GLfloat*);
+typedef void (APIENTRY* glGetVertexAttribivType) (GLuint, GLenum, GLint*);
+typedef void (APIENTRY* glGetVertexAttribPointervType) (GLuint, GLenum, GLvoid**);
+typedef GLboolean (APIENTRY* glIsBufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsFramebufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsProgramType) (GLuint);
+typedef GLboolean (APIENTRY* glIsRenderbufferType) (GLuint);
+typedef GLboolean (APIENTRY* glIsShaderType) (GLuint);
+typedef void (APIENTRY* glLinkProgramType) (GLuint);
+typedef void (APIENTRY* glRenderbufferStorageType) (GLenum, GLenum, GLsizei, GLsizei);
+typedef void (APIENTRY* glSampleCoverageType) (GLclampf, GLboolean);
+typedef void (APIENTRY* glShaderSourceType) (GLuint, GLsizei, const char**, const GLint*);
+typedef void (APIENTRY* glStencilFuncSeparateType) (GLenum, GLenum, GLint, GLuint);
+typedef void (APIENTRY* glStencilMaskSeparateType) (GLenum, GLuint);
+typedef void (APIENTRY* glStencilOpSeparateType) (GLenum, GLenum, GLenum, GLenum);
+typedef void (APIENTRY* glUniform1fType) (GLint, GLfloat);
+typedef void (APIENTRY* glUniform1fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform1iType) (GLint, GLint);
+typedef void (APIENTRY* glUniform1ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform2fType) (GLint, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform2fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform2iType) (GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform2ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform3fType) (GLint, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform3fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform3iType) (GLint, GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform3ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniform4fType) (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY* glUniform4fvType) (GLint, GLsizei, const GLfloat*);
+typedef void (APIENTRY* glUniform4iType) (GLint, GLint, GLint, GLint, GLint);
+typedef void (APIENTRY* glUniform4ivType) (GLint, GLsizei, const GLint*);
+typedef void (APIENTRY* glUniformMatrix2fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUniformMatrix3fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUniformMatrix4fvType) (GLint, GLsizei, GLboolean, const GLfloat*);
+typedef void (APIENTRY* glUseProgramType) (GLuint);
+typedef void (APIENTRY* glValidateProgramType) (GLuint);
+typedef void (APIENTRY* glVertexAttrib1fType) (GLuint, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib1fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib2fType) (GLuint, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib2fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib3fType) (GLuint, const GLfloat, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib3fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttrib4fType) (GLuint, const GLfloat, const GLfloat, const GLfloat, const GLfloat);
+typedef void (APIENTRY* glVertexAttrib4fvType) (GLuint, const GLfloat*);
+typedef void (APIENTRY* glVertexAttribPointerType) (GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);
+
+class GraphicsContext3DInternal {
+public:
+ GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow);
+ ~GraphicsContext3DInternal();
+
+ bool isContextValid() { return m_contextValid; }
+
+
+
+ glActiveTextureType activeTexture;
+ glAttachShaderType attachShader;
+ glBindAttribLocationType bindAttribLocation;
+ glBindBufferType bindBuffer;
+ glBindFramebufferType bindFramebuffer;
+ glBindRenderbufferType bindRenderbuffer;
+ glBlendColorType blendColor;
+ glBlendEquationType blendEquation;
+ glBlendEquationSeparateType blendEquationSeparate;
+ glBlendFuncSeparateType blendFuncSeparate;
+ glBufferDataType bufferData;
+ glBufferSubDataType bufferSubData;
+ glCheckFramebufferStatusType checkFramebufferStatus;
+ glCompileShaderType compileShader;
+ glCreateProgramType createProgram;
+ glCreateShaderType createShader;
+ glDeleteBuffersType deleteBuffers;
+ glDeleteFramebuffersType deleteFramebuffers;
+ glDeleteProgramType deleteProgram;
+ glDeleteRenderbuffersType deleteRenderbuffers;
+ glDeleteShaderType deleteShader;
+ glDetachShaderType detachShader;
+ glDisableVertexAttribArrayType disableVertexAttribArray;
+ glEnableVertexAttribArrayType enableVertexAttribArray;
+ glFramebufferRenderbufferType framebufferRenderbuffer;
+ glFramebufferTexture2DType framebufferTexture2D;
+ glGenBuffersType genBuffers;
+ glGenerateMipmapType generateMipmap;
+ glGenFramebuffersType genFramebuffers;
+ glGenRenderbuffersType genRenderbuffers;
+ glGetActiveAttribType getActiveAttrib;
+ glGetActiveUniformType getActiveUniform;
+ glGetAttribLocationType getAttribLocation;
+ glGetBufferParameterivType getBufferParameteriv;
+ glGetFramebufferAttachmentParameterivType getFramebufferAttachmentParameteriv;
+ glGetProgramInfoLogType getProgramInfoLog;
+ glGetProgramivType getProgramiv;
+ glGetRenderbufferParameterivType getRenderbufferParameteriv;
+ glGetShaderInfoLogType getShaderInfoLog;
+ glGetShaderivType getShaderiv;
+ glGetShaderSourceType getShaderSource;
+ glGetUniformfvType getUniformfv;
+ glGetUniformivType getUniformiv;
+ glGetUniformLocationType getUniformLocation;
+ glGetVertexAttribfvType getVertexAttribfv;
+ glGetVertexAttribivType getVertexAttribiv;
+ glGetVertexAttribPointervType getVertexAttribPointerv;
+ glIsBufferType isBuffer;
+ glIsFramebufferType isFramebuffer;
+ glIsProgramType isProgram;
+ glIsRenderbufferType isRenderbuffer;
+ glIsShaderType isShader;
+ glLinkProgramType linkProgram;
+ glRenderbufferStorageType renderbufferStorage;
+ glSampleCoverageType sampleCoverage;
+ glShaderSourceType shaderSource;
+ glStencilFuncSeparateType stencilFuncSeparate;
+ glStencilMaskSeparateType stencilMaskSeparate;
+ glStencilOpSeparateType stencilOpSeparate;
+ glUniform1fType uniform1f;
+ glUniform1fvType uniform1fv;
+ glUniform1iType uniform1i;
+ glUniform1ivType uniform1iv;
+ glUniform2fType uniform2f;
+ glUniform2fvType uniform2fv;
+ glUniform2iType uniform2i;
+ glUniform2ivType uniform2iv;
+ glUniform3fType uniform3f;
+ glUniform3fvType uniform3fv;
+ glUniform3iType uniform3i;
+ glUniform3ivType uniform3iv;
+ glUniform4fType uniform4f;
+ glUniform4fvType uniform4fv;
+ glUniform4iType uniform4i;
+ glUniform4ivType uniform4iv;
+ glUniformMatrix2fvType uniformMatrix2fv;
+ glUniformMatrix3fvType uniformMatrix3fv;
+ glUniformMatrix4fvType uniformMatrix4fv;
+ glUseProgramType useProgram;
+ glValidateProgramType validateProgram;
+ glVertexAttrib1fType vertexAttrib1f;
+ glVertexAttrib1fvType vertexAttrib1fv;
+ glVertexAttrib2fType vertexAttrib2f;
+ glVertexAttrib2fvType vertexAttrib2fv;
+ glVertexAttrib3fType vertexAttrib3f;
+ glVertexAttrib3fvType vertexAttrib3fv;
+ glVertexAttrib4fType vertexAttrib4f;
+ glVertexAttrib4fvType vertexAttrib4fv;
+ glVertexAttribPointerType vertexAttribPointer;
+
+ GraphicsContext3D::Attributes m_attrs;
+ QGLWidget* m_glWidget;
+ GLuint m_texture;
+ GLuint m_mainFbo;
+ GLuint m_currentFbo;
+ GLuint m_depthBuffer;
+ QImage m_pixels;
+ ListHashSet<unsigned long> m_syntheticErrors;
+
+private:
+
+ QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient);
+ void* getProcAddress(const String& proc);
+ bool m_contextValid;
+};
+
+#if defined (QT_OPENGL_ES_2)
+#define GET_PROC_ADDRESS(Proc) Proc
+#else
+#define GET_PROC_ADDRESS(Proc) reinterpret_cast<Proc##Type>(getProcAddress(#Proc));
+#endif
+
+GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
+ : m_attrs(attrs)
+ , m_glWidget(0)
+ , m_texture(0)
+ , m_mainFbo(0)
+ , m_currentFbo(0)
+ , m_depthBuffer(0)
+ , m_contextValid(true)
+{
+ QWebPageClient* webPageClient = hostWindow->platformPageClient();
+ QGLWidget* ownerGLWidget = getOwnerGLWidget(webPageClient);
+
+ if (ownerGLWidget)
+ m_glWidget = new QGLWidget(0, ownerGLWidget);
+ else {
+ QGLFormat format;
+ format.setDepth(true);
+ format.setSampleBuffers(true);
+ format.setStencil(false);
+
+ m_glWidget = new QGLWidget(format);
+ }
+
+ if (!m_glWidget->isValid()) {
+ LOG_ERROR("GraphicsContext3D: QGLWidget does not have a valid context");
+ m_contextValid = false;
+ return;
+ }
+
+ QGLFormat format = m_glWidget->format();
+
+ m_attrs.alpha = format.alpha();
+ m_attrs.depth = format.depth();
+ m_attrs.stencil = format.stencil();
+ m_attrs.antialias = false;
+ m_attrs.premultipliedAlpha = true;
+
+ m_glWidget->makeCurrent();
+
+ activeTexture = GET_PROC_ADDRESS(glActiveTexture);
+ attachShader = GET_PROC_ADDRESS(glAttachShader);
+ bindAttribLocation = GET_PROC_ADDRESS(glBindAttribLocation);
+ bindBuffer = GET_PROC_ADDRESS(glBindBuffer);
+ bindFramebuffer = GET_PROC_ADDRESS(glBindFramebuffer);
+ bindRenderbuffer = GET_PROC_ADDRESS(glBindRenderbuffer);
+ blendColor = GET_PROC_ADDRESS(glBlendColor);
+ blendEquation = GET_PROC_ADDRESS(glBlendEquation);
+ blendEquationSeparate = GET_PROC_ADDRESS(glBlendEquationSeparate);
+ blendFuncSeparate = GET_PROC_ADDRESS(glBlendFuncSeparate);
+ bufferData = GET_PROC_ADDRESS(glBufferData);
+ bufferSubData = GET_PROC_ADDRESS(glBufferSubData);
+ checkFramebufferStatus = GET_PROC_ADDRESS(glCheckFramebufferStatus);
+ compileShader = GET_PROC_ADDRESS(glCompileShader);
+ createProgram = GET_PROC_ADDRESS(glCreateProgram);
+ createShader = GET_PROC_ADDRESS(glCreateShader);
+ deleteBuffers = GET_PROC_ADDRESS(glDeleteBuffers);
+ deleteFramebuffers = GET_PROC_ADDRESS(glDeleteFramebuffers);
+ deleteProgram = GET_PROC_ADDRESS(glDeleteProgram);
+ deleteRenderbuffers = GET_PROC_ADDRESS(glDeleteRenderbuffers);
+ deleteShader = GET_PROC_ADDRESS(glDeleteShader);
+ detachShader = GET_PROC_ADDRESS(glDetachShader);
+ disableVertexAttribArray = GET_PROC_ADDRESS(glDisableVertexAttribArray);
+ enableVertexAttribArray = GET_PROC_ADDRESS(glEnableVertexAttribArray);
+ framebufferRenderbuffer = GET_PROC_ADDRESS(glFramebufferRenderbuffer);
+ framebufferTexture2D = GET_PROC_ADDRESS(glFramebufferTexture2D);
+ genBuffers = GET_PROC_ADDRESS(glGenBuffers);
+ generateMipmap = GET_PROC_ADDRESS(glGenerateMipmap);
+ genFramebuffers = GET_PROC_ADDRESS(glGenFramebuffers);
+ genRenderbuffers = GET_PROC_ADDRESS(glGenRenderbuffers);
+ getActiveAttrib = GET_PROC_ADDRESS(glGetActiveAttrib);
+ getActiveUniform = GET_PROC_ADDRESS(glGetActiveUniform);
+ getAttribLocation = GET_PROC_ADDRESS(glGetAttribLocation);
+ getBufferParameteriv = GET_PROC_ADDRESS(glGetBufferParameteriv);
+ getFramebufferAttachmentParameteriv = GET_PROC_ADDRESS(glGetFramebufferAttachmentParameteriv);
+ getProgramInfoLog = GET_PROC_ADDRESS(glGetProgramInfoLog);
+ getProgramiv = GET_PROC_ADDRESS(glGetProgramiv);
+ getRenderbufferParameteriv = GET_PROC_ADDRESS(glGetRenderbufferParameteriv);
+ getShaderInfoLog = GET_PROC_ADDRESS(glGetShaderInfoLog);
+ getShaderiv = GET_PROC_ADDRESS(glGetShaderiv);
+ getShaderSource = GET_PROC_ADDRESS(glGetShaderSource);
+ getUniformfv = GET_PROC_ADDRESS(glGetUniformfv);
+ getUniformiv = GET_PROC_ADDRESS(glGetUniformiv);
+ getUniformLocation = GET_PROC_ADDRESS(glGetUniformLocation);
+ getVertexAttribfv = GET_PROC_ADDRESS(glGetVertexAttribfv);
+ getVertexAttribiv = GET_PROC_ADDRESS(glGetVertexAttribiv);
+ getVertexAttribPointerv = GET_PROC_ADDRESS(glGetVertexAttribPointerv);
+ isBuffer = GET_PROC_ADDRESS(glIsBuffer);
+ isFramebuffer = GET_PROC_ADDRESS(glIsFramebuffer);
+ isProgram = GET_PROC_ADDRESS(glIsProgram);
+ isRenderbuffer = GET_PROC_ADDRESS(glIsRenderbuffer);
+ isShader = GET_PROC_ADDRESS(glIsShader);
+ linkProgram = GET_PROC_ADDRESS(glLinkProgram);
+ renderbufferStorage = GET_PROC_ADDRESS(glRenderbufferStorage);
+ sampleCoverage = GET_PROC_ADDRESS(glSampleCoverage);
+ shaderSource = GET_PROC_ADDRESS(glShaderSource);
+ stencilFuncSeparate = GET_PROC_ADDRESS(glStencilFuncSeparate);
+ stencilMaskSeparate = GET_PROC_ADDRESS(glStencilMaskSeparate);
+ stencilOpSeparate = GET_PROC_ADDRESS(glStencilOpSeparate);
+ uniform1f = GET_PROC_ADDRESS(glUniform1f);
+ uniform1fv = GET_PROC_ADDRESS(glUniform1fv);
+ uniform1i = GET_PROC_ADDRESS(glUniform1i);
+ uniform1iv = GET_PROC_ADDRESS(glUniform1iv);
+ uniform2f = GET_PROC_ADDRESS(glUniform2f);
+ uniform2fv = GET_PROC_ADDRESS(glUniform2fv);
+ uniform2i = GET_PROC_ADDRESS(glUniform2i);
+ uniform2iv = GET_PROC_ADDRESS(glUniform2iv);
+ uniform3f = GET_PROC_ADDRESS(glUniform3f);
+ uniform3fv = GET_PROC_ADDRESS(glUniform3fv);
+ uniform3i = GET_PROC_ADDRESS(glUniform3i);
+ uniform3iv = GET_PROC_ADDRESS(glUniform3iv);
+ uniform4f = GET_PROC_ADDRESS(glUniform4f);
+ uniform4fv = GET_PROC_ADDRESS(glUniform4fv);
+ uniform4i = GET_PROC_ADDRESS(glUniform4i);
+ uniform4iv = GET_PROC_ADDRESS(glUniform4iv);
+ uniformMatrix2fv = GET_PROC_ADDRESS(glUniformMatrix2fv);
+ uniformMatrix3fv = GET_PROC_ADDRESS(glUniformMatrix3fv);
+ uniformMatrix4fv = GET_PROC_ADDRESS(glUniformMatrix4fv);
+ useProgram = GET_PROC_ADDRESS(glUseProgram);
+ validateProgram = GET_PROC_ADDRESS(glValidateProgram);
+ vertexAttrib1f = GET_PROC_ADDRESS(glVertexAttrib1f);
+ vertexAttrib1fv = GET_PROC_ADDRESS(glVertexAttrib1fv);
+ vertexAttrib2f = GET_PROC_ADDRESS(glVertexAttrib2f);
+ vertexAttrib2fv = GET_PROC_ADDRESS(glVertexAttrib2fv);
+ vertexAttrib3f = GET_PROC_ADDRESS(glVertexAttrib3f);
+ vertexAttrib3fv = GET_PROC_ADDRESS(glVertexAttrib3fv);
+ vertexAttrib4f = GET_PROC_ADDRESS(glVertexAttrib4f);
+ vertexAttrib4fv = GET_PROC_ADDRESS(glVertexAttrib4fv);
+ vertexAttribPointer = GET_PROC_ADDRESS(glVertexAttribPointer);
+
+ if (!m_contextValid) {
+ LOG_ERROR("GraphicsContext3D: All needed OpenGL extensions are not available");
+ m_contextValid = false;
+ return;
+ }
+
+ glGenTextures(1, &m_texture);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, m_texture);
+ glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MAG_FILTER, GraphicsContext3D::LINEAR);
+ glTexParameterf(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_MIN_FILTER, GraphicsContext3D::LINEAR);
+ glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_S, GraphicsContext3D::CLAMP_TO_EDGE);
+ glTexParameteri(GraphicsContext3D::TEXTURE_2D, GraphicsContext3D::TEXTURE_WRAP_T, GraphicsContext3D::CLAMP_TO_EDGE);
+ glTexImage2D(GraphicsContext3D::TEXTURE_2D, 0, GraphicsContext3D::RGBA, 1, 1, 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, 0);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+
+ genFramebuffers(/* count */ 1, &m_mainFbo);
+ m_currentFbo = m_mainFbo;
+
+ bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_mainFbo);
+
+ genRenderbuffers(/* count */ 1, &m_depthBuffer);
+ bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
+#if defined(QT_OPENGL_ES_2)
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, /* width */ 1, /* height */ 1);
+#else
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, /* width */ 1, /* height */ 1);
+#endif
+
+ bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+
+ framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_texture, 0);
+ framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
+ glClearColor(/* red */ 0, /* green */ 0, /* blue */ 0, /* alpha */ 0);
+
+ if (checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ LOG_ERROR("GraphicsContext3D: Wasn't able to create the main framebuffer");
+ m_contextValid = false;
+ }
+}
+
+GraphicsContext3DInternal::~GraphicsContext3DInternal()
+{
+ delete m_glWidget;
+ m_glWidget = 0;
+}
+
+QGLWidget* GraphicsContext3DInternal::getOwnerGLWidget(QWebPageClient* webPageClient)
+{
+ QAbstractScrollArea* scrollArea = qobject_cast<QAbstractScrollArea*>(webPageClient->ownerWidget());
+
+ if (scrollArea)
+ return qobject_cast<QGLWidget*>(scrollArea->viewport());
+
+ return 0;
+}
+
+void* GraphicsContext3DInternal::getProcAddress(const String& proc)
+{
+ String ext[3] = { "", "ARB", "EXT" };
+
+ for (int i = 0; i < 3; i++) {
+ String nameWithExt = proc + ext[i];
+
+ void* addr = m_glWidget->context()->getProcAddress(nameWithExt.utf8().data());
+ if (addr)
+ return addr;
+ }
+
+ LOG_ERROR("GraphicsContext3D: Did not find GL function %s", proc.utf8().data());
+ m_contextValid = false;
+ return 0;
+}
+
+PassOwnPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
+{
+ OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow));
+ return context->m_internal ? context.release() : 0;
+}
+
+GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
+ : m_internal(new GraphicsContext3DInternal(attrs, hostWindow))
+{
+ if (!m_internal->isContextValid())
+ m_internal = 0;
+}
+
+GraphicsContext3D::~GraphicsContext3D()
+{
+}
+
+PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D()
+{
+ return m_internal->m_glWidget;
+}
+
+Platform3DObject GraphicsContext3D::platformTexture() const
+{
+ return m_internal->m_texture;
+}
+
+void GraphicsContext3D::makeContextCurrent()
+{
+ m_internal->m_glWidget->makeCurrent();
+}
+
+void GraphicsContext3D::beginPaint(WebGLRenderingContext* context)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ HTMLCanvasElement* canvas = context->canvas();
+ ImageBuffer* imageBuffer = canvas->buffer();
+
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo);
+
+ glReadPixels(/* x */ 0, /* y */ 0, m_currentWidth, m_currentHeight, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_internal->m_pixels.bits());
+
+ QPainter* p = imageBuffer->context()->platformContext();
+ p->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.transformed(QMatrix().rotate(180)));
+
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo);
+}
+
+void GraphicsContext3D::endPaint()
+{
+}
+
+void GraphicsContext3D::reshape(int width, int height)
+{
+ if (((width == m_currentWidth) && (height == m_currentHeight)) || (!m_internal))
+ return;
+
+ m_currentWidth = width;
+ m_currentHeight = height;
+
+ m_internal->m_pixels = QImage(m_currentWidth, m_currentHeight, QImage::Format_ARGB32);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, m_internal->m_texture);
+ glTexImage2D(GraphicsContext3D::TEXTURE_2D, /* level */ 0, GraphicsContext3D::RGBA, width, height, /* border */ 0, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, /* data */ 0);
+ glBindTexture(GraphicsContext3D::TEXTURE_2D, 0);
+
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_mainFbo);
+ m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer);
+#if defined(QT_OPENGL_ES_2)
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, width, height);
+#else
+ renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT, width, height);
+#endif
+ m_internal->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
+
+ m_internal->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_internal->m_texture, 0);
+ m_internal->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_internal->m_depthBuffer);
+
+ GLenum status = m_internal->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER);
+ if (status != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
+ LOG_ERROR("GraphicsContext3D: Wasn't able to reshape the main framebuffer");
+ notImplemented();
+ }
+
+ glClear(GraphicsContext3D::COLOR_BUFFER_BIT);
+ glFlush();
+}
+
+void GraphicsContext3D::activeTexture(unsigned long texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->activeTexture(texture);
+}
+
+void GraphicsContext3D::attachShader(WebGLProgram* program, WebGLShader* shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->attachShader((GLuint) program->object(), (GLuint) shader->object());
+}
+
+void GraphicsContext3D::bindAttribLocation(WebGLProgram* program, unsigned long index, const String& name)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindAttribLocation((GLuint) program->object(), index, name.utf8().data());
+}
+
+void GraphicsContext3D::bindBuffer(unsigned long target, WebGLBuffer* buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindBuffer(target, buffer ? (GLuint) buffer->object() : 0);
+}
+
+void GraphicsContext3D::bindFramebuffer(unsigned long target, WebGLFramebuffer* buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->m_currentFbo = (buffer && buffer->object()) ? (GLuint) buffer->object() : m_internal->m_mainFbo;
+ m_internal->bindFramebuffer(target, m_internal->m_currentFbo);
+}
+
+void GraphicsContext3D::bindRenderbuffer(unsigned long target, WebGLRenderbuffer* renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindRenderbuffer(target, renderbuffer ? (GLuint) renderbuffer->object() : 0);
+}
+
+void GraphicsContext3D::bindTexture(unsigned long target, WebGLTexture* texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBindTexture(target, texture ? (GLuint) texture->object() : 0);
+}
+
+void GraphicsContext3D::blendColor(double red, double green, double blue, double alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendColor(static_cast<float>(red), static_cast<float>(green), static_cast<float>(blue), static_cast<float>(alpha));
+}
+
+void GraphicsContext3D::blendEquation(unsigned long mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquation(mode);
+}
+
+void GraphicsContext3D::blendEquationSeparate(unsigned long modeRGB, unsigned long modeAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquationSeparate(modeRGB, modeAlpha);
+}
+
+void GraphicsContext3D::blendFunc(unsigned long sfactor, unsigned long dfactor)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBlendFunc(sfactor, dfactor);
+}
+
+void GraphicsContext3D::blendFuncSeparate(unsigned long srcRGB, unsigned long dstRGB, unsigned long srcAlpha, unsigned long dstAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void GraphicsContext3D::bufferData(unsigned long target, int size, unsigned long usage)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, size, /* data */ 0, usage);
+}
+
+void GraphicsContext3D::bufferData(unsigned long target, WebGLArray* array, unsigned long usage)
+{
+ if (!array || !array->length())
+ return;
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, array->byteLength(), array->baseAddress(), usage);
+}
+
+void GraphicsContext3D::bufferSubData(unsigned long target, long offset, WebGLArray* array)
+{
+ if (!array || !array->length())
+ return;
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferSubData(target, offset, array->byteLength(), array->baseAddress());
+}
+
+unsigned long GraphicsContext3D::checkFramebufferStatus(unsigned long target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->checkFramebufferStatus(target);
+}
+
+void GraphicsContext3D::clearColor(double r, double g, double b, double a)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearColor(static_cast<float>(r), static_cast<float>(g), static_cast<float>(b), static_cast<float>(a));
+}
+
+void GraphicsContext3D::clear(unsigned long mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClear(mask);
+}
+
+void GraphicsContext3D::clearDepth(double depth)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glClearDepthf(depth);
+#else
+ glClearDepth(depth);
+#endif
+}
+
+void GraphicsContext3D::clearStencil(long s)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearStencil(s);
+}
+
+void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glColorMask(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::compileShader(WebGLShader* shader)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->compileShader((GLuint) shader->object());
+}
+
+void GraphicsContext3D::copyTexImage2D(unsigned long target, long level, unsigned long internalformat, long x, long y, unsigned long width, unsigned long height, long border)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+void GraphicsContext3D::copyTexSubImage2D(unsigned long target, long level, long xoffset, long yoffset, long x, long y, unsigned long width, unsigned long height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+void GraphicsContext3D::cullFace(unsigned long mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCullFace(mode);
+}
+
+void GraphicsContext3D::depthFunc(unsigned long func)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthFunc(func);
+}
+
+void GraphicsContext3D::depthMask(bool flag)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthMask(flag);
+}
+
+void GraphicsContext3D::depthRange(double zNear, double zFar)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glDepthRangef(zNear, zFar);
+#else
+ glDepthRange(zNear, zFar);
+#endif
+}
+
+void GraphicsContext3D::detachShader(WebGLProgram* program, WebGLShader* shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->detachShader((GLuint) program->object(), (GLuint) shader->object());
+}
+
+void GraphicsContext3D::disable(unsigned long cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDisable(cap);
+}
+
+void GraphicsContext3D::disableVertexAttribArray(unsigned long index)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->disableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::drawArrays(unsigned long mode, long first, long count)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawArrays(mode, first, count);
+}
+
+void GraphicsContext3D::drawElements(unsigned long mode, unsigned long count, unsigned long type, long offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawElements(mode, count, type, reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::enable(unsigned long cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glEnable(cap);
+}
+
+void GraphicsContext3D::enableVertexAttribArray(unsigned long index)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->enableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::finish()
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFinish();
+}
+
+void GraphicsContext3D::flush()
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFlush();
+}
+
+void GraphicsContext3D::framebufferRenderbuffer(unsigned long target, unsigned long attachment, unsigned long renderbuffertarget, WebGLRenderbuffer* buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer ? (GLuint) buffer->object() : 0);
+}
+
+void GraphicsContext3D::framebufferTexture2D(unsigned long target, unsigned long attachment, unsigned long textarget, WebGLTexture* texture, long level)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferTexture2D(target, attachment, textarget, texture ? (GLuint) texture->object() : 0, level);
+}
+
+void GraphicsContext3D::frontFace(unsigned long mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFrontFace(mode);
+}
+
+void GraphicsContext3D::generateMipmap(unsigned long target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->generateMipmap(target);
+}
+
+bool GraphicsContext3D::getActiveAttrib(WebGLProgram* program, unsigned long index, ActiveInfo& info)
+{
+ if (!program->object()) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength;
+ m_internal->getProgramiv(static_cast<GLuint>(program->object()), GraphicsContext3D::ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength;
+ GLint size;
+ GLenum type;
+
+ m_internal->getActiveAttrib(static_cast<GLuint>(program->object()), index, maxLength, &nameLength, &size, &type, name);
+
+ if (!nameLength) {
+ fastFree(name);
+ return false;
+ }
+
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+
+ fastFree(name);
+ return true;
+}
+
+bool GraphicsContext3D::getActiveUniform(WebGLProgram* program, unsigned long index, ActiveInfo& info)
+{
+ if (!program->object()) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength;
+ m_internal->getProgramiv(static_cast<GLuint>(program->object()), GraphicsContext3D::ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength;
+ GLint size;
+ GLenum type;
+
+ m_internal->getActiveUniform(static_cast<GLuint>(program->object()), index, maxLength, &nameLength, &size, &type, name);
+
+ if (!nameLength) {
+ fastFree(name);
+ return false;
+ }
+
+ info.name = String(name, nameLength);
+ info.type = type;
+ info.size = size;
+
+ fastFree(name);
+ return true;
+}
+
+int GraphicsContext3D::getAttribLocation(WebGLProgram* program, const String& name)
+{
+ if (!program)
+ return -1;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getAttribLocation((GLuint) program->object(), name.utf8().data());
+}
+
+GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
+{
+ return m_internal->m_attrs;
+}
+
+unsigned long GraphicsContext3D::getError()
+{
+ if (m_internal->m_syntheticErrors.size() > 0) {
+ ListHashSet<unsigned long>::iterator iter = m_internal->m_syntheticErrors.begin();
+ unsigned long err = *iter;
+ m_internal->m_syntheticErrors.remove(iter);
+ return err;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+ return glGetError();
+}
+
+String GraphicsContext3D::getString(unsigned long name)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return String((const char*) glGetString(name));
+}
+
+void GraphicsContext3D::hint(unsigned long target, unsigned long mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glHint(target, mode);
+}
+
+bool GraphicsContext3D::isBuffer(WebGLBuffer* buffer)
+{
+ if (!buffer)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isBuffer((GLuint) buffer->object());
+}
+
+bool GraphicsContext3D::isEnabled(unsigned long cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return glIsEnabled(cap);
+}
+
+bool GraphicsContext3D::isFramebuffer(WebGLFramebuffer* framebuffer)
+{
+ if (!framebuffer)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isFramebuffer((GLuint) framebuffer->object());
+}
+
+bool GraphicsContext3D::isProgram(WebGLProgram* program)
+{
+ if (!program)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isProgram((GLuint) program->object());
+}
+
+bool GraphicsContext3D::isRenderbuffer(WebGLRenderbuffer* renderbuffer)
+{
+ if (!renderbuffer)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isRenderbuffer((GLuint) renderbuffer->object());
+}
+
+bool GraphicsContext3D::isShader(WebGLShader* shader)
+{
+ if (!shader)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isShader((GLuint) shader->object());
+}
+
+bool GraphicsContext3D::isTexture(WebGLTexture* texture)
+{
+ if (!texture)
+ return false;
+
+ m_internal->m_glWidget->makeCurrent();
+ return glIsTexture((GLuint) texture->object());
+}
+
+void GraphicsContext3D::lineWidth(double width)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glLineWidth(static_cast<float>(width));
+}
+
+void GraphicsContext3D::linkProgram(WebGLProgram* program)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->linkProgram((GLuint) program->object());
+}
+
+void GraphicsContext3D::pixelStorei(unsigned long paramName, long param)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPixelStorei(paramName, param);
+}
+
+void GraphicsContext3D::polygonOffset(double factor, double units)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPolygonOffset(static_cast<float>(factor), static_cast<float>(units));
+}
+
+void GraphicsContext3D::readPixels(long x, long y, unsigned long width, unsigned long height, unsigned long format, unsigned long type, void* data)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ if (type != GraphicsContext3D::UNSIGNED_BYTE || format != GraphicsContext3D::RGBA)
+ return;
+
+ glReadPixels(x, y, width, height, format, type, (GLvoid*) data);
+}
+
+void GraphicsContext3D::releaseShaderCompiler()
+{
+ m_internal->m_glWidget->makeCurrent();
+ notImplemented();
+}
+
+void GraphicsContext3D::renderbufferStorage(unsigned long target, unsigned long internalformat, unsigned long width, unsigned long height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->renderbufferStorage(target, internalformat, width, height);
+}
+
+void GraphicsContext3D::sampleCoverage(double value, bool invert)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->sampleCoverage(static_cast<float>(value), invert);
+}
+
+void GraphicsContext3D::scissor(long x, long y, unsigned long width, unsigned long height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glScissor(x, y, width, height);
+}
+
+void GraphicsContext3D::shaderSource(WebGLShader* shader, const String& source)
+{
+ ASSERT(shader);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ CString sourceCS = source.utf8();
+ const char* data = sourceCS.data();
+ int length = source.length();
+ m_internal->shaderSource((GLuint) shader->object(), /* count */ 1, &data, &length);
+}
+
+void GraphicsContext3D::stencilFunc(unsigned long func, long ref, unsigned long mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilFunc(func, ref, mask);
+}
+
+void GraphicsContext3D::stencilFuncSeparate(unsigned long face, unsigned long func, long ref, unsigned long mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilFuncSeparate(face, func, ref, mask);
+}
+
+void GraphicsContext3D::stencilMask(unsigned long mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilMask(mask);
+}
+
+void GraphicsContext3D::stencilMaskSeparate(unsigned long face, unsigned long mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilMaskSeparate(face, mask);
+}
+
+void GraphicsContext3D::stencilOp(unsigned long fail, unsigned long zfail, unsigned long zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilOp(fail, zfail, zpass);
+}
+
+void GraphicsContext3D::stencilOpSeparate(unsigned long face, unsigned long fail, unsigned long zfail, unsigned long zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void GraphicsContext3D::texParameterf(unsigned target, unsigned paramName, float value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameterf(target, paramName, static_cast<float>(value));
+}
+
+void GraphicsContext3D::texParameteri(unsigned target, unsigned paramName, int value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameteri(target, paramName, static_cast<float>(value));
+}
+
+void GraphicsContext3D::uniform1f(long location, float v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1f(location, v0);
+}
+
+void GraphicsContext3D::uniform1fv(long location, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2f(long location, float v0, float v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2f(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2fv(long location, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3f(long location, float v0, float v1, float v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3f(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3fv(long location, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4f(long location, float v0, float v1, float v2, float v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4f(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4fv(long location, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform1i(long location, int v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1i(location, v0);
+}
+
+void GraphicsContext3D::uniform1iv(long location, int* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2i(long location, int v0, int v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2i(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2iv(long location, int* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3i(long location, int v0, int v1, int v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3i(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3iv(long location, int* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4i(long location, int v0, int v1, int v2, int v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4i(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4iv(long location, int* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4iv(location, size, array);
+}
+
+void GraphicsContext3D::uniformMatrix2fv(long location, bool transpose, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix2fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix3fv(long location, bool transpose, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix3fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix4fv(long location, bool transpose, float* array, int size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix4fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::useProgram(WebGLProgram* program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->useProgram((GLuint) program->object());
+}
+
+void GraphicsContext3D::validateProgram(WebGLProgram* program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->validateProgram((GLuint) program->object());
+}
+
+void GraphicsContext3D::vertexAttrib1f(unsigned long indx, float v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1f(indx, v0);
+}
+
+void GraphicsContext3D::vertexAttrib1fv(unsigned long indx, float* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1fv(indx, array);
+}
+
+void GraphicsContext3D::vertexAttrib2f(unsigned long indx, float v0, float v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2f(indx, v0, v1);
+}
+
+void GraphicsContext3D::vertexAttrib2fv(unsigned long indx, float* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2fv(indx, array);
+}
+
+void GraphicsContext3D::vertexAttrib3f(unsigned long indx, float v0, float v1, float v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3f(indx, v0, v1, v2);
+}
+
+void GraphicsContext3D::vertexAttrib3fv(unsigned long indx, float* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3fv(indx, array);
+}
+
+void GraphicsContext3D::vertexAttrib4f(unsigned long indx, float v0, float v1, float v2, float v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4f(indx, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::vertexAttrib4fv(unsigned long indx, float* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4fv(indx, array);
+}
+
+void GraphicsContext3D::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, unsigned long stride, unsigned long offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttribPointer(indx, size, type, normalized, stride, reinterpret_cast<void*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::viewport(long x, long y, unsigned long width, unsigned long height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glViewport(static_cast<GLint>(x), static_cast<GLint>(y), static_cast<GLsizei>(width), static_cast<GLsizei>(height));
+}
+
+void GraphicsContext3D::getBooleanv(unsigned long paramName, unsigned char* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetBooleanv(paramName, value);
+}
+
+void GraphicsContext3D::getBufferParameteriv(unsigned long target, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getBufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getFloatv(unsigned long paramName, float* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetFloatv(paramName, value);
+}
+
+void GraphicsContext3D::getFramebufferAttachmentParameteriv(unsigned long target, unsigned long attachment, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getFramebufferAttachmentParameteriv(target, attachment, paramName, value);
+}
+
+void GraphicsContext3D::getIntegerv(unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetIntegerv(paramName, value);
+}
+
+void GraphicsContext3D::getProgramiv(WebGLProgram* program, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getProgramiv((GLuint) program->object(), paramName, value);
+}
+
+String GraphicsContext3D::getProgramInfoLog(WebGLProgram* program)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length;
+ m_internal->getProgramiv((GLuint) program->object(), GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size;
+
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getProgramInfoLog((GLuint) program->object(), length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getRenderbufferParameteriv(unsigned long target, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getRenderbufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getShaderiv(WebGLShader* shader, unsigned long paramName, int* value)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getShaderiv((GLuint) shader->object(), paramName, value);
+}
+
+String GraphicsContext3D::getShaderInfoLog(WebGLShader* shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length;
+ m_internal->getShaderiv((GLuint) shader->object(), GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderInfoLog((GLuint) shader->object(), length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+String GraphicsContext3D::getShaderSource(WebGLShader* shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length;
+ m_internal->getShaderiv((GLuint) shader->object(), GraphicsContext3D::SHADER_SOURCE_LENGTH, &length);
+
+ GLsizei size;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderSource((GLuint) shader->object(), length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getTexParameterfv(unsigned long target, unsigned long paramName, float* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameterfv(target, paramName, value);
+}
+
+void GraphicsContext3D::getTexParameteriv(unsigned long target, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getUniformfv(WebGLProgram* program, long location, float* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformfv((GLuint) program->object(), location, value);
+}
+
+void GraphicsContext3D::getUniformiv(WebGLProgram* program, long location, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformiv((GLuint) program->object(), location, value);
+}
+
+long GraphicsContext3D::getUniformLocation(WebGLProgram* program, const String& name)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getUniformLocation((GLuint) program->object(), name.utf8().data());
+}
+
+void GraphicsContext3D::getVertexAttribfv(unsigned long index, unsigned long paramName, float* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribfv(index, paramName, value);
+}
+
+void GraphicsContext3D::getVertexAttribiv(unsigned long index, unsigned long paramName, int* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribiv(index, paramName, value);
+}
+
+long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long paramName)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ void* pointer;
+ m_internal->getVertexAttribPointerv(index, paramName, &pointer);
+ return reinterpret_cast<long>(pointer);
+}
+
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels)
+{
+ glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ return 0;
+}
+
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
+{
+ ASSERT(image);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ Vector<uint8_t> imageData;
+ GLuint format;
+ GLuint internalFormat;
+
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) {
+ LOG_ERROR("GraphicsContext3D::texImage2D: could not extract Image data");
+ return -1;
+ }
+
+ glTexImage2D(target, level, internalFormat, image->width(), image->height(),
+ /* border */ 0, format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data());
+
+ return 0;
+}
+
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels)
+{
+ glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
+ return 0;
+}
+
+int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha)
+{
+ ASSERT(image);
+
+ Vector<uint8_t> imageData;
+ GLuint format;
+ GLuint internalFormat;
+
+ if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) {
+ LOG_ERROR("GraphicsContext3D::texSubImage2D: could not extract Image data");
+ return -1;
+ }
+
+ glTexSubImage2D(target, level, xoff, yoff, image->width(), image->height(),
+ format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data());
+
+ return 0;
+}
+
+unsigned GraphicsContext3D::createBuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle;
+ m_internal->genBuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+unsigned GraphicsContext3D::createFramebuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle;
+ m_internal->genFramebuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+unsigned GraphicsContext3D::createProgram()
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createProgram();
+}
+
+unsigned GraphicsContext3D::createRenderbuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle;
+ m_internal->genRenderbuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+unsigned GraphicsContext3D::createShader(unsigned long type)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createShader((type == FRAGMENT_SHADER) ? GraphicsContext3D::FRAGMENT_SHADER : GraphicsContext3D::VERTEX_SHADER);
+}
+
+unsigned GraphicsContext3D::createTexture()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle;
+ glGenTextures(1, &handle);
+ return handle;
+}
+
+void GraphicsContext3D::deleteBuffer(unsigned buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteBuffers(1, &buffer);
+}
+
+void GraphicsContext3D::deleteFramebuffer(unsigned framebuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteFramebuffers(1, &framebuffer);
+}
+
+void GraphicsContext3D::deleteProgram(unsigned program)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteProgram(program);
+}
+
+void GraphicsContext3D::deleteRenderbuffer(unsigned renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteRenderbuffers(1, &renderbuffer);
+}
+
+void GraphicsContext3D::deleteShader(unsigned shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteShader(shader);
+}
+
+void GraphicsContext3D::deleteTexture(unsigned texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDeleteTextures(1, &texture);
+}
+
+int GraphicsContext3D::sizeInBytes(int type)
+{
+ switch (type) {
+ case GraphicsContext3D::BYTE:
+ return sizeof(GLbyte);
+ case GraphicsContext3D::UNSIGNED_BYTE:
+ return sizeof(GLubyte);
+ case GraphicsContext3D::SHORT:
+ return sizeof(GLshort);
+ case GraphicsContext3D::UNSIGNED_SHORT:
+ return sizeof(GLushort);
+ case GraphicsContext3D::INT:
+ return sizeof(GLint);
+ case GraphicsContext3D::UNSIGNED_INT:
+ return sizeof(GLuint);
+ case GraphicsContext3D::FLOAT:
+ return sizeof(GLfloat);
+ default:
+ return 0;
+ }
+}
+
+void GraphicsContext3D::synthesizeGLError(unsigned long error)
+{
+ m_internal->m_syntheticErrors.add(error);
+}
+
+bool GraphicsContext3D::getImageData(Image* image,
+ Vector<uint8_t>& outputVector,
+ bool premultiplyAlpha,
+ bool* hasAlphaChannel,
+ AlphaOp* neededAlphaOp,
+ unsigned int* format)
+{
+ QImage::Format imageFormat = (!premultiplyAlpha) ?
+ QImage::Format_ARGB32 :
+ QImage::Format_ARGB32_Premultiplied;
+
+ QPixmap* nativePixmap = image->nativeImageForCurrentFrame();
+
+ *hasAlphaChannel = true;
+ *neededAlphaOp = kAlphaDoNothing;
+ *format = GraphicsContext3D::RGBA;
+
+ QImage nativeImage = nativePixmap->toImage().convertToFormat(imageFormat);
+ outputVector.append(nativeImage.bits(), nativeImage.byteCount());
+
+ return true;
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index 8bcda2e..edac268 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -312,14 +312,16 @@ void GraphicsContext::drawRect(const IntRect& rect)
const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
- IntSize shadowSize;
- int shadowBlur;
- Color shadowColor;
- if (getShadow(shadowSize, shadowBlur, shadowColor)) {
- IntRect shadowRect = rect;
- shadowRect.move(shadowSize.width(), shadowSize.height());
- shadowRect.inflate(static_cast<int>(p->pen().widthF()));
- p->fillRect(shadowRect, QColor(shadowColor));
+ if (m_common->state.shadowColor.isValid()) {
+ IntSize shadowSize;
+ int shadowBlur;
+ Color shadowColor;
+ if (getShadow(shadowSize, shadowBlur, shadowColor)) {
+ IntRect shadowRect = rect;
+ shadowRect.move(shadowSize.width(), shadowSize.height());
+ shadowRect.inflate(static_cast<int>(p->pen().widthF()));
+ p->fillRect(shadowRect, QColor(shadowColor));
+ }
}
p->drawRect(rect);
@@ -410,7 +412,7 @@ void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
patternOffset = patWidth / 2;
} else {
if (remainder)
- patternOffset = (patWidth - remainder)/2;
+ patternOffset = (patWidth - remainder) / 2;
}
}
@@ -614,10 +616,20 @@ void GraphicsContext::fillRect(const FloatRect& rect)
QPainter* p = m_data->p();
if (m_common->state.fillPattern || m_common->state.fillGradient || fillColor().alpha()) {
- drawBorderlessRectShadow(this, p, rect);
+ if (m_common->state.shadowColor.isValid())
+ drawBorderlessRectShadow(this, p, rect);
if (m_common->state.fillPattern) {
AffineTransform affine;
- p->fillRect(rect, QBrush(m_common->state.fillPattern->createPlatformPattern(affine)));
+ FloatRect rectM(rect);
+ QBrush brush(m_common->state.fillPattern->createPlatformPattern(affine));
+ QPixmap* image = m_common->state.fillPattern->tileImage()->nativeImageForCurrentFrame();
+
+ if (!m_common->state.fillPattern->repeatX() && image)
+ rectM.setWidth(image->width());
+ if (!m_common->state.fillPattern->repeatY() && image)
+ rectM.setHeight(image->height());
+ p->fillRect(rectM, brush);
+
} else if (m_common->state.fillGradient) {
QBrush brush(*m_common->state.fillGradient->platformGradient());
brush.setTransform(m_common->state.fillGradient->gradientSpaceTransform());
@@ -636,7 +648,8 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace
m_data->solidColor.setColor(c);
QPainter* p = m_data->p();
- drawBorderlessRectShadow(this, p, rect);
+ if (m_common->state.shadowColor.isValid())
+ drawBorderlessRectShadow(this, p, rect);
p->fillRect(rect, m_data->solidColor);
}
@@ -1006,11 +1019,11 @@ void GraphicsContext::rotate(float radians)
if (paintingDisabled())
return;
- m_data->p()->rotate(180/M_PI*radians);
+ m_data->p()->rotate(180 / M_PI*radians);
if (!m_data->currentPath.isEmpty()) {
QTransform matrix;
- m_data->currentPath = m_data->currentPath * matrix.rotate(-180/M_PI*radians);
+ m_data->currentPath = m_data->currentPath * matrix.rotate(-180 / M_PI*radians);
m_common->state.pathTransform.rotate(radians);
}
}
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
index 0fd0f1a..834cd4f 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -29,6 +29,7 @@
#include "UnitBezier.h"
#include <QtCore/qabstractanimation.h>
#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
#include <QtCore/qset.h>
#include <QtCore/qtimer.h>
#include <QtGui/qbitmap.h>
@@ -101,31 +102,37 @@ public:
// modified by the compositor, so we can know what to look for in the next flush
enum ChangeMask {
NoChanges = 0,
+
+ ParentChange = (1L << 0),
ChildrenChange = (1L << 1),
MaskLayerChange = (1L << 2),
PositionChange = (1L << 3),
+
AnchorPointChange = (1L << 4),
SizeChange = (1L << 5),
TransformChange = (1L << 6),
ContentChange = (1L << 7),
+
GeometryOrientationChange = (1L << 8),
ContentsOrientationChange = (1L << 9),
OpacityChange = (1L << 10),
ContentsRectChange = (1L << 11),
+
Preserves3DChange = (1L << 12),
MasksToBoundsChange = (1L << 13),
DrawsContentChange = (1L << 14),
ContentsOpaqueChange = (1L << 15),
+
BackfaceVisibilityChange = (1L << 16),
ChildrenTransformChange = (1L << 17),
DisplayChange = (1L << 18),
BackgroundColorChange = (1L << 19),
- ParentChange = (1L << 20),
- DistributesOpacityChange = (1L << 21)
+
+ DistributesOpacityChange = (1L << 20)
};
// the compositor lets us special-case images and colors, so we try to do so
- enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType};
+ enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType};
GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
virtual ~GraphicsLayerQtImpl();
@@ -149,10 +156,6 @@ public:
// or ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
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
- void adjustCachingRecursively(bool animationIsRunning);
-
// optimization: returns true if this or an ancestor has a transform animation running.
// this enables us to use ItemCoordinatesCache while the animation is running, otherwise we have to recache for every frame
bool isTransformAnimationRunning() const;
@@ -161,6 +164,9 @@ public slots:
// we need to notify the client (aka the layer compositor) when the animation actually starts
void notifyAnimationStarted();
+ // we notify WebCore of a layer changed asynchronously; otherwise we end up calling flushChanges too often.
+ void notifySyncRequired();
+
signals:
// optimization: we don't want to use QTimer::singleShot
void notifyAnimationStartedAsync();
@@ -179,6 +185,7 @@ public:
bool updateAll;
QColor contentsBackgroundColor;
QColor backgroundColor;
+ QWeakPointer<QGraphicsObject> mediaLayer;
StaticContentType contentType;
float opacity;
ContentData()
@@ -196,7 +203,9 @@ public:
int m_changeMask;
QSizeF m_size;
+#ifndef QT_NO_ANIMATION
QList<QWeakPointer<QAbstractAnimation> > m_animations;
+#endif
QTimer m_suspendTimer;
struct State {
@@ -227,7 +236,9 @@ public:
}
} m_state;
+#ifndef QT_NO_ANIMATION
friend class AnimationQtBase;
+#endif
};
GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
@@ -245,7 +256,7 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
setEnabled(true);
// we'll set the cache when we know what's going on
- setCacheMode(NoCache);
+ setCacheMode(ItemCoordinateCache);
connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
}
@@ -263,26 +274,13 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
item->setParentItem(0);
}
}
-
+
+#ifndef QT_NO_ANIMATION
// we do, however, own the animations...
for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_animations.begin(); it != m_animations.end(); ++it)
if (QAbstractAnimation* anim = it->data())
delete anim;
-}
-
-void GraphicsLayerQtImpl::adjustCachingRecursively(bool animationIsRunning)
-{
- // optimization: we make sure all our children have ItemCoordinateCache -
- // otherwise we end up re-rendering them during the animation
- const QList<QGraphicsItem*> children = childItems();
-
- for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it) {
- if (QGraphicsItem* item = *it)
- if (GraphicsLayerQtImpl* layer = qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject())) {
- if (layer->m_layer->drawsContent() && layer->m_currentContent.contentType == HTMLContentType)
- layer->setCacheMode(animationIsRunning ? QGraphicsItem::ItemCoordinateCache : QGraphicsItem::DeviceCoordinateCache);
- }
- }
+#endif
}
void GraphicsLayerQtImpl::updateTransform()
@@ -307,29 +305,26 @@ QTransform GraphicsLayerQtImpl::computeTransform(const TransformationMatrix& bas
// 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()))) {
+
+ for (const GraphicsLayerQtImpl* ancestor = this; (ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject())); ) {
if (!ancestor->m_state.childrenTransform.isIdentity()) {
- offset += ancestor->boundingRect().bottomRight() / 2;
+ const QPointF offset = mapFromItem(ancestor, QPointF(ancestor->m_size.width() / 2, ancestor->m_size.height() / 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 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);
+ computedTransform
+ .translate3d(originX, originY, m_state.anchorPoint.z())
+ .multLeft(baseTransform)
+ .translate3d(-originX, -originY, -m_state.anchorPoint.z());
// now we project to 2D
return QTransform(computedTransform);
@@ -353,6 +348,7 @@ QPainterPath GraphicsLayerQtImpl::opaqueArea() const
else {
if (m_state.contentsOpaque
|| (m_currentContent.contentType == ColorContentType && m_currentContent.contentsBackgroundColor.alpha() == 0xff)
+ || (m_currentContent.contentType == MediaContentType)
|| (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlpha())) {
painterPath.addRect(m_state.contentsRect);
@@ -369,14 +365,14 @@ QRectF GraphicsLayerQtImpl::boundingRect() const
void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
if (m_currentContent.backgroundColor.isValid())
- painter->fillRect(option->exposedRect, QColor(m_currentContent.backgroundColor));
+ painter->fillRect(option->rect, QColor(m_currentContent.backgroundColor));
switch (m_currentContent.contentType) {
case HTMLContentType:
if (m_state.drawsContent) {
// this is the expensive bit. we try to minimize calls to this area by proper caching
GraphicsContext gc(painter);
- m_layer->paintGraphicsLayerContents(gc, option->exposedRect.toAlignedRect());
+ m_layer->paintGraphicsLayerContents(gc, option->rect);
}
break;
case PixmapContentType:
@@ -385,19 +381,25 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte
case ColorContentType:
painter->fillRect(m_state.contentsRect, m_currentContent.contentsBackgroundColor);
break;
+ case MediaContentType:
+ // we don't need to paint anything: we have a QGraphicsItem from the media element
+ break;
}
}
-void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+void GraphicsLayerQtImpl::notifySyncRequired()
{
- Q_ASSERT(this);
-
- m_changeMask |= changeMask;
-
if (m_layer->client())
m_layer->client()->notifySyncRequired(m_layer);
}
+void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+{
+ m_changeMask |= changeMask;
+ static QMetaMethod syncMethod = staticMetaObject.method(staticMetaObject.indexOfMethod("notifySyncRequired()"));
+ syncMethod.invoke(this, Qt::QueuedConnection);
+}
+
void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
{
// this is the bulk of the work. understanding what the compositor is trying to achieve,
@@ -433,7 +435,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
w->setParentItem(this);
for (QSet<QGraphicsItem*>::const_iterator it = childrenToRemove.begin(); it != childrenToRemove.end(); ++it)
- if (QGraphicsItem* w = *it)
+ if (GraphicsLayerQtImpl* w = qobject_cast<GraphicsLayerQtImpl*>((*it)->toGraphicsObject()))
w->setParentItem(0);
// children are ordered by z-value, let graphics-view know.
@@ -450,7 +452,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
if (m_layer->maskLayer()) {
if (GraphicsLayerQtImpl* mask = qobject_cast<GraphicsLayerQtImpl*>(m_layer->maskLayer()->platformLayer()->toGraphicsObject())) {
mask->m_maskEffect = new MaskEffectQt(this, mask);
- mask->setCacheMode(NoCache);
setGraphicsEffect(mask->m_maskEffect.data());
}
}
@@ -465,11 +466,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
m_size = QSizeF(m_layer->size().width(), m_layer->size().height());
}
}
-
// 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 (scene())
+ 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,
@@ -483,11 +484,19 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
update();
setFlag(ItemHasNoContents, false);
+ // no point in caching a directly composited pixmap into another pixmap
+ setCacheMode(NoCache);
+
+ break;
+ case MediaContentType:
+ setFlag(ItemHasNoContents, true);
+ setCacheMode(NoCache);
+ m_pendingContent.mediaLayer.data()->setParentItem(this);
break;
case ColorContentType:
// no point in caching a solid-color rectangle
- setCacheMode(m_layer->maskLayer() ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
+ setCacheMode(NoCache);
if (m_pendingContent.contentType != m_currentContent.contentType || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
update();
m_state.drawsContent = false;
@@ -500,19 +509,11 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
case HTMLContentType:
if (m_pendingContent.contentType != m_currentContent.contentType)
update();
- if (!m_state.drawsContent && m_layer->drawsContent())
+ if (!m_state.drawsContent && m_layer->drawsContent()) {
update();
- if (m_layer->drawsContent() && !m_maskEffect) {
- const QGraphicsItem::CacheMode mewCacheMode = isTransformAnimationRunning() ? ItemCoordinateCache : DeviceCoordinateCache;
-
- // optimization: QGraphicsItem doesn't always perform this test
- if (mewCacheMode != cacheMode())
- setCacheMode(mewCacheMode);
-
- // HTML content: we want to use exposedRect so we don't use WebCore rendering if we don't have to
- setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
- }
- else
+ if (m_layer->drawsContent() && !m_maskEffect)
+ setCacheMode(ItemCoordinateCache);
+ } else if (!m_layer->drawsContent())
setCacheMode(NoCache);
setFlag(ItemHasNoContents, !m_layer->drawsContent());
@@ -520,7 +521,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
}
}
- if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity())
+ if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity() && !m_opacityAnimationRunning)
setOpacity(m_layer->opacity());
if (m_changeMask & ContentsRectChange) {
@@ -569,6 +570,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
m_state.childrenTransform = m_layer->childrenTransform();
m_currentContent.pixmap = m_pendingContent.pixmap;
m_currentContent.contentType = m_pendingContent.contentType;
+ m_currentContent.mediaLayer = m_pendingContent.mediaLayer;
m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
m_currentContent.regionToUpdate |= m_pendingContent.regionToUpdate;
m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
@@ -707,116 +709,140 @@ void GraphicsLayerQt::removeFromParent()
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setMaskLayer(GraphicsLayer* layer)
+void GraphicsLayerQt::setMaskLayer(GraphicsLayer* value)
{
- GraphicsLayer::setMaskLayer(layer);
+ if (value == maskLayer())
+ return;
+ GraphicsLayer::setMaskLayer(value);
m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setPosition(const FloatPoint& p)
+void GraphicsLayerQt::setPosition(const FloatPoint& value)
{
- if (position() != p)
- m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
- GraphicsLayer::setPosition(p);
+ if (value == position())
+ return;
+ GraphicsLayer::setPosition(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& p)
+void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& value)
{
- if (anchorPoint() != p)
- m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
- GraphicsLayer::setAnchorPoint(p);
+ if (value == anchorPoint())
+ return;
+ GraphicsLayer::setAnchorPoint(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setSize(const FloatSize& size)
+void GraphicsLayerQt::setSize(const FloatSize& value)
{
- if (this->size() != size)
- m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
- GraphicsLayer::setSize(size);
+ if (value == size())
+ return;
+ GraphicsLayer::setSize(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setTransform(const TransformationMatrix& t)
+void GraphicsLayerQt::setTransform(const TransformationMatrix& value)
{
- if (!m_impl->m_transformAnimationRunning && transform() != t)
- m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
- GraphicsLayer::setTransform(t);
+ if (value == transform())
+ return;
+ GraphicsLayer::setTransform(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& t)
+void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& value)
{
- GraphicsLayer::setChildrenTransform(t);
+ if (value == childrenTransform())
+ return;
+ GraphicsLayer::setChildrenTransform(value);
m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setPreserves3D(bool b)
+void GraphicsLayerQt::setPreserves3D(bool value)
{
- if (b != preserves3D());
- m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
- GraphicsLayer::setPreserves3D(b);
+ if (value == preserves3D())
+ return;
+ GraphicsLayer::setPreserves3D(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setMasksToBounds(bool b)
+void GraphicsLayerQt::setMasksToBounds(bool value)
{
- GraphicsLayer::setMasksToBounds(b);
+ if (value == masksToBounds())
+ return;
+ GraphicsLayer::setMasksToBounds(value);
m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setDrawsContent(bool b)
+void GraphicsLayerQt::setDrawsContent(bool value)
{
+ if (value == drawsContent())
+ return;
m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
- GraphicsLayer::setDrawsContent(b);
+ GraphicsLayer::setDrawsContent(value);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setBackgroundColor(const Color& c)
+void GraphicsLayerQt::setBackgroundColor(const Color& value)
{
+ if (value == m_impl->m_pendingContent.backgroundColor)
+ return;
+ m_impl->m_pendingContent.backgroundColor = value;
+ GraphicsLayer::setBackgroundColor(value);
m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
- m_impl->m_pendingContent.backgroundColor = c;
- GraphicsLayer::setBackgroundColor(c);
}
// reimp from GraphicsLayer.h
void GraphicsLayerQt::clearBackgroundColor()
{
+ if (!m_impl->m_pendingContent.backgroundColor.isValid())
+ return;
m_impl->m_pendingContent.backgroundColor = QColor();
- m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
GraphicsLayer::clearBackgroundColor();
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setContentsOpaque(bool b)
+void GraphicsLayerQt::setContentsOpaque(bool value)
{
+ if (value == contentsOpaque())
+ return;
m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
- GraphicsLayer::setContentsOpaque(b);
+ GraphicsLayer::setContentsOpaque(value);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setBackfaceVisibility(bool b)
+void GraphicsLayerQt::setBackfaceVisibility(bool value)
{
+ if (value == backfaceVisibility())
+ return;
+ GraphicsLayer::setBackfaceVisibility(value);
m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
- GraphicsLayer::setBackfaceVisibility(b);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setOpacity(float o)
+void GraphicsLayerQt::setOpacity(float value)
{
- if (!m_impl->m_opacityAnimationRunning && opacity() != o)
- m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
- GraphicsLayer::setOpacity(o);
+ if (value == opacity())
+ return;
+ GraphicsLayer::setOpacity(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
}
// reimp from GraphicsLayer.h
-void GraphicsLayerQt::setContentsRect(const IntRect& r)
+void GraphicsLayerQt::setContentsRect(const IntRect& value)
{
+ if (value == contentsRect())
+ return;
+ GraphicsLayer::setContentsRect(value);
m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
- GraphicsLayer::setContentsRect(r);
}
// reimp from GraphicsLayer.h
@@ -845,6 +871,19 @@ void GraphicsLayerQt::setContentsBackgroundColor(const Color& color)
GraphicsLayer::setContentsBackgroundColor(color);
}
+void GraphicsLayerQt::setContentsToMedia(PlatformLayer* media)
+{
+ if (media) {
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::MediaContentType;
+ m_impl->m_pendingContent.mediaLayer = media->toGraphicsObject();
+ } else
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
+
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ GraphicsLayer::setContentsToMedia(media);
+}
+
+
// reimp from GraphicsLayer.h
void GraphicsLayerQt::setGeometryOrientation(CompositingCoordinatesOrientation orientation)
{
@@ -913,18 +952,18 @@ static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, q
// we want the timing function to be as close as possible to what the web-developer intended, so we're using the same function used by WebCore when compositing is disabled
// Using easing-curves would probably work for some of the cases, but wouldn't really buy us anything as we'd have to convert the bezier function back to an easing curve
-static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, int duration)
-{
- if (timingFunction.type() == LinearTimingFunction)
- return progress;
- if (timingFunction.type() == CubicBezierTimingFunction) {
- return solveCubicBezierFunction(timingFunction.x1(),
- timingFunction.y1(),
- timingFunction.x2(),
- timingFunction.y2(),
- double(progress), double(duration) / 1000);
- }
+static inline qreal applyTimingFunction(const TimingFunction& timingFunction, qreal progress, double duration)
+{
+ if (timingFunction.type() == LinearTimingFunction)
return progress;
+ if (timingFunction.type() == CubicBezierTimingFunction) {
+ return solveCubicBezierFunction(timingFunction.x1(),
+ timingFunction.y1(),
+ timingFunction.x2(),
+ timingFunction.y2(),
+ double(progress), double(duration) / 1000);
+ }
+ return progress;
}
// helper functions to safely get a value out of WebCore's AnimationValue*
@@ -943,6 +982,7 @@ static void webkitAnimationToQtAnimationValue(const AnimationValue* animationVal
realValue = animationValue ? static_cast<const FloatAnimationValue*>(animationValue)->value() : 0;
}
+#ifndef QT_NO_ANIMATION
// we put a bit of the functionality in a base class to allow casting and to save some code size
class AnimationQtBase : public QAbstractAnimation {
public:
@@ -953,7 +993,9 @@ public:
, m_duration(anim->duration() * 1000)
, m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate)
, m_webkitPropertyID(values.property())
+ , m_webkitAnimation(anim)
, m_keyframesName(name)
+ , m_fillsForwards(false)
{
}
@@ -973,7 +1015,11 @@ public:
int m_duration;
bool m_isAlternate;
AnimatedPropertyID m_webkitPropertyID;
+
+ // we might need this in case the same animation is added again (i.e. resumed by WebCore)
+ const Animation* m_webkitAnimation;
QString m_keyframesName;
+ bool m_fillsForwards;
};
// we'd rather have a templatized QAbstractAnimation than QPropertyAnimation / QVariantAnimation;
@@ -992,6 +1038,8 @@ public:
KeyframeValueQt<T> keyframeValue;
if (animationValue->timingFunction())
keyframeValue.timingFunction = *animationValue->timingFunction();
+ else
+ keyframeValue.timingFunction = anim->timingFunction();
webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
m_keyframeValues[animationValue->keyTime()] = keyframeValue;
}
@@ -1028,7 +1076,7 @@ protected:
typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it+1;
if (it2 == m_keyframeValues.end())
- it2 = m_keyframeValues.begin();
+ it2 = it;
const KeyframeValueQt<T>& fromKeyframe = it.value();
const KeyframeValueQt<T>& toKeyframe = it2.value();
@@ -1040,7 +1088,7 @@ protected:
// we can now process the progress and apply the frame
progress = (!progress || progress == 1 || it.key() == it2.key())
? progress
- : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration() / 1000);
+ : applyTimingFunction(timingFunc, (progress - it.key()) / (it2.key() - it.key()), duration());
applyFrame(fromValue, toValue, progress);
}
@@ -1056,10 +1104,10 @@ public:
~TransformAnimationQt()
{
- // 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()->updateTransform();
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ else if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
}
// the idea is that we let WebCore manage the transform-operations
@@ -1077,15 +1125,29 @@ public:
sourceOperations.apply(m_boxSize, sourceMatrix);
transformMatrix = m_sourceMatrix;
transformMatrix.blend(sourceMatrix, 1 - progress);
- } else if (targetOperations.size() != sourceOperations.size()) {
- transformMatrix = m_sourceMatrix;
- targetOperations.apply(m_boxSize, transformMatrix);
- transformMatrix.blend(m_sourceMatrix, progress);
} else {
- for (size_t i = 0; i < targetOperations.size(); ++i)
- targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
+ bool validTransformLists = true;
+ const int sourceOperationCount = sourceOperations.size();
+ if (sourceOperationCount) {
+ if (targetOperations.size() != sourceOperationCount)
+ validTransformLists = false;
+ else
+ for (size_t j = 0; j < sourceOperationCount && validTransformLists; ++j)
+ if (!sourceOperations.operations()[j]->isSameType(*targetOperations.operations()[j]))
+ validTransformLists = false;
+ }
+
+ if (validTransformLists) {
+ for (size_t i = 0; i < targetOperations.size(); ++i)
+ targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
+ } else {
+ targetOperations.apply(m_boxSize, transformMatrix);
+ transformMatrix.blend(m_sourceMatrix, progress);
+ }
}
m_layer.data()->setBaseTransform(transformMatrix);
+ if (m_fillsForwards)
+ m_layer.data()->m_layer->setTransform(m_layer.data()->m_baseTransform);
}
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
@@ -1100,10 +1162,8 @@ public:
if (newState == QAbstractAnimation::Running) {
m_sourceMatrix = m_layer.data()->m_layer->transform();
m_layer.data()->m_transformAnimationRunning = true;
- m_layer.data()->adjustCachingRecursively(true);
- } else {
+ } else if (newState == QAbstractAnimation::Stopped) {
m_layer.data()->m_transformAnimationRunning = false;
- m_layer.data()->adjustCachingRecursively(false);
}
}
@@ -1117,9 +1177,25 @@ public:
{
}
+ ~OpacityAnimationQt()
+ {
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ else if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity());
+ }
virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
{
- m_layer.data()->setOpacity(qMin<qreal>(qMax<qreal>(fromValue + (toValue-fromValue)*progress, 0), 1));
+ qreal opacity = qBound(qreal(0), fromValue + (toValue-fromValue)*progress, qreal(1));
+
+ // FIXME: this is a hack, due to a probable QGraphicsScene bug.
+ // Without this the opacity change doesn't always have immediate effect.
+ if (!m_layer.data()->opacity() && opacity)
+ m_layer.data()->scene()->update();
+
+ m_layer.data()->setOpacity(opacity);
+ if (m_fillsForwards)
+ m_layer.data()->m_layer->setOpacity(opacity);
}
virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
@@ -1136,33 +1212,51 @@ bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSiz
if (!anim->duration() || !anim->iterationCount())
return false;
- QAbstractAnimation* newAnim;
+ AnimationQtBase* newAnim = 0;
- switch (values.property()) {
- case AnimatedPropertyOpacity:
- newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
- break;
- case AnimatedPropertyWebkitTransform:
- newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
- break;
- default:
- return false;
+ // fixed: we might already have the Qt animation object associated with this WebCore::Animation object
+ for (QList<QWeakPointer<QAbstractAnimation> >::iterator it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (*it) {
+ AnimationQtBase* curAnimation = static_cast<AnimationQtBase*>(it->data());
+ if (curAnimation && curAnimation->m_webkitAnimation == anim)
+ newAnim = curAnimation;
+ }
}
- // we make sure WebCore::Animation and QAnimation are on the same terms
- newAnim->setLoopCount(anim->iterationCount());
- m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
- QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
- timeOffset += anim->delay();
+ if (!newAnim) {
+ switch (values.property()) {
+ case AnimatedPropertyOpacity:
+ newAnim = new OpacityAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ case AnimatedPropertyWebkitTransform:
+ newAnim = new TransformAnimationQt(m_impl.get(), values, boxSize, anim, keyframesName);
+ break;
+ default:
+ return false;
+ }
+
+ // we make sure WebCore::Animation and QAnimation are on the same terms
+ newAnim->setLoopCount(anim->iterationCount());
+ newAnim->m_fillsForwards = anim->fillsForwards();
+ m_impl->m_animations.append(QWeakPointer<QAbstractAnimation>(newAnim));
+ QObject::connect(&m_impl->m_suspendTimer, SIGNAL(timeout()), newAnim, SLOT(resume()));
+ }
// flush now or flicker...
m_impl->flushChanges(false);
- if (timeOffset)
- QTimer::singleShot(timeOffset * 1000, newAnim, SLOT(start()));
+ // when fill-mode is backwards/both, we set the value to 0 before the delay takes place
+ if (anim->fillsBackwards())
+ newAnim->setCurrentTime(0);
+
+ if (anim->delay())
+ QTimer::singleShot(anim->delay() * 1000, newAnim, SLOT(start()));
else
newAnim->start();
+ // we synchronize the animation's clock to WebCore's timeOffset
+ newAnim->setCurrentTime(timeOffset * 1000);
+
// we don't need to manage the animation object's lifecycle:
// WebCore would call removeAnimations when it's time to delete.
@@ -1204,8 +1298,11 @@ void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
continue;
AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
- if (anim && anim->m_keyframesName == QString(name))
- QTimer::singleShot(timeOffset * 1000, anim, SLOT(pause()));
+ if (anim && anim->m_keyframesName == QString(name)) {
+ // we synchronize the animation's clock to WebCore's timeOffset
+ anim->setCurrentTime(timeOffset * 1000);
+ anim->pause();
+ }
}
}
@@ -1235,6 +1332,7 @@ void GraphicsLayerQt::resumeAnimations()
}
}
+#endif // QT_NO_ANIMATION
}
#include <GraphicsLayerQt.moc>
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
index 3a53bd9..9e5832f 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -63,13 +63,16 @@ public:
virtual void setBackfaceVisibility(bool b);
virtual void setOpacity(float opacity);
virtual void setContentsRect(const IntRect& r);
+#ifndef QT_NO_ANIMATION
virtual bool addAnimation(const KeyframeValueList&, const IntSize& boxSize, const Animation*, const String& keyframesName, double timeOffset);
virtual void removeAnimationsForProperty(AnimatedPropertyID);
virtual void removeAnimationsForKeyframes(const String& keyframesName);
virtual void pauseAnimation(const String& keyframesName, double timeOffset);
virtual void suspendAnimations(double time);
virtual void resumeAnimations();
+#endif // QT_NO_ANIMATION
virtual void setContentsToImage(Image*);
+ virtual void setContentsToMedia(PlatformLayer*);
virtual void setContentsBackgroundColor(const Color&);
virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation);
virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
diff --git a/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
index d831566..4b85a18 100644
--- a/WebCore/platform/graphics/qt/ImageBufferQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -28,11 +28,11 @@
#include "config.h"
#include "ImageBuffer.h"
-#include "CString.h"
#include "GraphicsContext.h"
#include "ImageData.h"
#include "MIMETypeRegistry.h"
#include "StillImageQt.h"
+#include <wtf/text/CString.h>
#include <QBuffer>
#include <QColor>
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index 18e7f08..b48b278 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -57,7 +57,7 @@ ImageDecoderQt::~ImageDecoderQt()
void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
{
- if (m_failed)
+ if (failed())
return;
// No progressive loading possible
@@ -75,7 +75,7 @@ void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size());
m_buffer.set(new QBuffer);
m_buffer->setData(imageData);
- m_buffer->open(QBuffer::ReadOnly);
+ m_buffer->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
m_reader.set(new QImageReader(m_buffer.get(), m_format));
// This will force the JPEG decoder to use JDCT_IFAST
@@ -106,9 +106,8 @@ size_t ImageDecoderQt::frameCount()
forceLoadEverything();
else
m_frameBufferCache.resize(imageCount);
- } else {
+ } else
m_frameBufferCache.resize(1);
- }
}
return m_frameBufferCache.size();
@@ -116,8 +115,21 @@ size_t ImageDecoderQt::frameCount()
int ImageDecoderQt::repetitionCount() const
{
- if (m_reader && m_reader->supportsAnimation())
- m_repetitionCount = qMax(0, m_reader->loopCount());
+ if (m_reader && m_reader->supportsAnimation()) {
+ m_repetitionCount = m_reader->loopCount();
+
+ // Qt and WebCore have a incompatible understanding of
+ // the loop count and we can not completely map everything.
+ // Qt | WebCore | description
+ // -1 | 0 | infinite animation
+ // 0 | cAnimationLoopOnce | show every frame once
+ // n | n | no idea if that is supported
+ // n/a | cAnimationNone | show only the first frame
+ if (m_repetitionCount == -1)
+ m_repetitionCount = 0;
+ else if (m_repetitionCount == 0)
+ m_repetitionCount = cAnimationLoopOnce;
+ }
return m_repetitionCount;
}
@@ -133,7 +145,7 @@ RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
// yet how many images we are going to have and need to
// find that out now.
size_t count = m_frameBufferCache.size();
- if (!m_failed && !count) {
+ if (!failed() && !count) {
internalDecodeSize();
count = frameCount();
}
@@ -157,8 +169,10 @@ void ImageDecoderQt::internalDecodeSize()
// If we have a QSize() something failed
QSize size = m_reader->size();
- if (size.isEmpty())
- return failRead();
+ if (size.isEmpty()) {
+ setFailed();
+ return clearPointers();
+ }
setSize(size.width(), size.height());
}
@@ -169,26 +183,33 @@ void ImageDecoderQt::internalReadImage(size_t frameIndex)
if (m_reader->supportsAnimation())
m_reader->jumpToImage(frameIndex);
- else if (frameIndex != 0)
- return failRead();
+ else if (frameIndex) {
+ setFailed();
+ return clearPointers();
+ }
- internalHandleCurrentImage(frameIndex);
+ if (!internalHandleCurrentImage(frameIndex))
+ setFailed();
// Attempt to return some memory
- for (int i = 0; i < m_frameBufferCache.size(); ++i)
+ for (int i = 0; i < m_frameBufferCache.size(); ++i) {
if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete)
return;
+ }
- m_reader.clear();
- m_buffer.clear();
+ clearPointers();
}
-void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
+bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
{
// Now get the QImage from Qt and place it in the RGBA32Buffer
QImage img;
- if (!m_reader->read(&img))
- return failRead();
+ if (!m_reader->read(&img)) {
+ frameCount();
+ repetitionCount();
+ clearPointers();
+ return false;
+ }
// now into the RGBA32Buffer - even if the image is not
QSize imageSize = img.size();
@@ -197,6 +218,7 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
buffer->setStatus(RGBA32Buffer::FrameComplete);
buffer->setDuration(m_reader->nextImageDelay());
buffer->setDecodedImage(img);
+ return true;
}
// The QImageIOHandler is not able to tell us how many frames
@@ -204,8 +226,8 @@ void ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
// 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.
+// the failed bit. If we failed to decode the first image
+// then we truly failed to decode, otherwise we're OK.
// TODO: Do not increment the m_frameBufferCache.size() by one but more than one
void ImageDecoderQt::forceLoadEverything()
@@ -214,20 +236,19 @@ void ImageDecoderQt::forceLoadEverything()
do {
m_frameBufferCache.resize(++imageCount);
- internalHandleCurrentImage(imageCount - 1);
- } while (!m_failed);
+ } while (internalHandleCurrentImage(imageCount - 1));
// 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
+ // have no images and need to set the failed bit.
+ // Otherwise, we want to forget about
// the last attempt to decode a image.
m_frameBufferCache.resize(imageCount - 1);
- m_failed = imageCount == 1;
+ if (imageCount == 1)
+ setFailed();
}
-void ImageDecoderQt::failRead()
+void ImageDecoderQt::clearPointers()
{
- setFailed();
m_reader.clear();
m_buffer.clear();
}
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.h b/WebCore/platform/graphics/qt/ImageDecoderQt.h
index be9a9b0..ceef884 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.h
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -61,9 +61,9 @@ private:
private:
void internalDecodeSize();
void internalReadImage(size_t);
- void internalHandleCurrentImage(size_t);
+ bool internalHandleCurrentImage(size_t);
void forceLoadEverything();
- void failRead();
+ void clearPointers();
private:
QByteArray m_format;
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
index 3274db5..21e670c 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -23,23 +23,25 @@
#include <limits>
-#include "CString.h"
#include "FrameView.h"
#include "GraphicsContext.h"
+#include "MIMETypeRegistry.h"
#include "NotImplemented.h"
#include "TimeRanges.h"
#include "Widget.h"
#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
#include <QDebug>
+#include <QEvent>
+#include <QMetaEnum>
#include <QPainter>
#include <QWidget>
-#include <QMetaEnum>
#include <QUrl>
-#include <QEvent>
-#include <phonon/path.h>
#include <phonon/audiooutput.h>
+#include <phonon/backendcapabilities.h>
+#include <phonon/path.h>
#include <phonon/mediaobject.h>
#include <phonon/videowidget.h>
@@ -143,15 +145,62 @@ MediaPlayerPrivate::~MediaPlayerPrivate()
m_mediaObject = 0;
}
-void MediaPlayerPrivate::getSupportedTypes(HashSet<String>&)
+HashSet<String>& MediaPlayerPrivate::supportedTypesCache()
{
- notImplemented();
+ static HashSet<String> supportedTypes;
+ if (!supportedTypes.isEmpty())
+ return supportedTypes;
+
+ // FIXME: we should rebuild the MIME type cache every time the backend is changed,
+ // however, this would have no effect on MIMETypeRegistry anyway, because it
+ // pulls this data only once.
+
+ QStringList types = Phonon::BackendCapabilities::availableMimeTypes();
+ foreach (const QString& type, types) {
+ QString first = type.split(QLatin1Char('/')).at(0);
+
+ // We're only interested in types which are not supported by WebCore itself.
+ if (first != QLatin1String("video")
+ && first != QLatin1String("audio")
+ && first != QLatin1String("application"))
+ continue;
+ if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
+ continue;
+
+ supportedTypes.add(String(type));
+ }
+
+ // These formats are supported by GStreamer, but not correctly advertised.
+ if (supportedTypes.contains(String("video/x-h264"))
+ || supportedTypes.contains(String("audio/x-m4a"))) {
+ supportedTypes.add(String("video/mp4"));
+ supportedTypes.add(String("audio/aac"));
+ }
+
+ if (supportedTypes.contains(String("video/x-theora")))
+ supportedTypes.add(String("video/ogg"));
+
+ if (supportedTypes.contains(String("audio/x-vorbis")))
+ supportedTypes.add(String("audio/ogg"));
+
+ if (supportedTypes.contains(String("audio/x-wav")))
+ supportedTypes.add(String("audio/wav"));
+
+ return supportedTypes;
}
-MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String&, const String&)
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
{
- // FIXME: do the real thing
- notImplemented();
+ types = supportedTypesCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
+{
+ if (type.isEmpty())
+ return MediaPlayer::IsNotSupported;
+
+ if (supportedTypesCache().contains(type))
+ return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
return MediaPlayer::IsNotSupported;
}
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
index e7630a1..ff6a01c 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -132,6 +132,7 @@ namespace WebCore {
static void getSupportedTypes(HashSet<String>&);
static MediaPlayer::SupportsType supportsType(const String& type, const String& codecs);
+ static HashSet<String>& supportedTypesCache();
static bool isAvailable() { return true; }
void updateStates();
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
new file mode 100644
index 0000000..bdac2a4
--- /dev/null
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -0,0 +1,571 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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
+ along 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"
+#include "MediaPlayerPrivateQt.h"
+
+#include "FrameLoaderClientQt.h"
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "HTMLMediaElement.h"
+#include "HTMLVideoElement.h"
+#include "TimeRanges.h"
+#include "Widget.h"
+#include "qwebframe.h"
+#include "qwebpage.h"
+
+#include <QGraphicsScene>
+#include <QGraphicsVideoItem>
+#include <QMediaPlayerControl>
+#include <QMediaService>
+#include <QNetworkAccessManager>
+#include <QNetworkCookieJar>
+#include <QNetworkRequest>
+#include <QPainter>
+#include <QPoint>
+#include <QRect>
+#include <QTime>
+#include <QTimer>
+#include <QUrl>
+#include <limits>
+#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivateInterface* MediaPlayerPrivate::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivate(player);
+}
+
+void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+void MediaPlayerPrivate::getSupportedTypes(HashSet<String> &supported)
+{
+ QStringList types = QMediaPlayer::supportedMimeTypes();
+
+ for (int i = 0; i < types.size(); i++) {
+ QString mime = types.at(i);
+ if (mime.startsWith("audio/") || mime.startsWith("video/"))
+ supported.add(mime);
+ }
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, const String& codec)
+{
+ if (!mime.startsWith("audio/") && !mime.startsWith("video/"))
+ return MediaPlayer::IsNotSupported;
+
+ if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimedia::ProbablySupported)
+ return MediaPlayer::IsSupported;
+
+ return MediaPlayer::MayBeSupported;
+}
+
+MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
+ : m_player(player)
+ , m_mediaPlayer(new QMediaPlayer)
+ , m_mediaPlayerControl(0)
+ , m_videoItem(new QGraphicsVideoItem)
+ , m_videoScene(new QGraphicsScene)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_isVisible(false)
+ , m_isSeeking(false)
+ , m_composited(false)
+ , m_queuedSeek(-1)
+{
+ m_videoItem->setMediaObject(m_mediaPlayer);
+ m_videoScene->addItem(m_videoItem);
+
+ // Signal Handlers
+ connect(m_mediaPlayer, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)),
+ this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));
+ connect(m_mediaPlayer, SIGNAL(stateChanged(QMediaPlayer::State)),
+ this, SLOT(stateChanged(QMediaPlayer::State)));
+ connect(m_mediaPlayer, SIGNAL(error(QMediaPlayer::Error)),
+ this, SLOT(handleError(QMediaPlayer::Error)));
+ connect(m_mediaPlayer, SIGNAL(durationChanged(qint64)),
+ this, SLOT(durationChanged(qint64)));
+ connect(m_mediaPlayer, SIGNAL(positionChanged(qint64)),
+ this, SLOT(positionChanged(qint64)));
+ connect(m_mediaPlayer, SIGNAL(volumeChanged(int)),
+ this, SLOT(volumeChanged(int)));
+ connect(m_mediaPlayer, SIGNAL(mutedChanged(bool)),
+ this, SLOT(mutedChanged(bool)));
+ connect(m_videoScene, SIGNAL(changed(QList<QRectF>)),
+ this, SLOT(repaint()));
+ connect(m_videoItem, SIGNAL(nativeSizeChanged(QSizeF)),
+ this, SLOT(nativeSizeChanged(QSizeF)));
+
+ // Grab the player control
+ QMediaService* service = m_mediaPlayer->service();
+ if (service) {
+ m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>(
+ service->control(QMediaPlayerControl_iid));
+ }
+}
+
+MediaPlayerPrivate::~MediaPlayerPrivate()
+{
+ delete m_mediaPlayer;
+ delete m_videoScene;
+}
+
+bool MediaPlayerPrivate::hasVideo() const
+{
+ return m_mediaPlayer->isVideoAvailable();
+}
+
+bool MediaPlayerPrivate::hasAudio() const
+{
+ return true;
+}
+
+void MediaPlayerPrivate::load(const String& url)
+{
+ // We are now loading
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_player->networkStateChanged();
+ }
+
+ // And we don't have any data yet
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_player->readyStateChanged();
+ }
+
+ const QUrl rUrl = QUrl(QString(url));
+ const QString scheme = rUrl.scheme().toLower();
+
+ // Grab the client media element
+ HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_player->mediaPlayerClient());
+
+ // Construct the media content with a network request if the resource is http[s]
+ if (scheme == "http" || scheme == "https") {
+ QNetworkRequest request = QNetworkRequest(rUrl);
+
+ // Grab the current document
+ Document* document = element->document();
+ if (!document)
+ document = element->ownerDocument();
+
+ // Grab the frame and network manager
+ Frame* frame = document ? document->frame() : 0;
+ FrameLoaderClientQt* frameLoader = frame ? static_cast<FrameLoaderClientQt*>(frame->loader()->client()) : 0;
+ QNetworkAccessManager* manager = frameLoader ? frameLoader->webFrame()->page()->networkAccessManager() : 0;
+
+ if (document && manager) {
+ // Set the cookies
+ QNetworkCookieJar* jar = manager->cookieJar();
+ QList<QNetworkCookie> cookies = jar->cookiesForUrl(rUrl);
+
+ // Don't set the header if there are no cookies.
+ // This prevents a warning from being emitted.
+ if (!cookies.isEmpty())
+ request.setHeader(QNetworkRequest::CookieHeader, qVariantFromValue(cookies));
+
+ // Set the refferer, but not when requesting insecure content from a secure page
+ QUrl documentUrl = QUrl(QString(document->documentURI()));
+ if (documentUrl.scheme().toLower() == "http" || scheme == "https")
+ request.setRawHeader("Referer", documentUrl.toEncoded());
+
+ // Set the user agent
+ request.setRawHeader("User-Agent", frameLoader->userAgent(rUrl).utf8().data());
+ }
+
+ m_mediaPlayer->setMedia(QMediaContent(request));
+ } else {
+ // Otherwise, just use the URL
+ m_mediaPlayer->setMedia(QMediaContent(rUrl));
+ }
+
+ // Set the current volume and mute status
+ // We get these from the element, rather than the player, in case we have
+ // transitioned from a media engine which doesn't support muting, to a media
+ // engine which does.
+ m_mediaPlayer->setMuted(element->muted());
+ m_mediaPlayer->setVolume(static_cast<int>(element->volume() * 100.0));
+}
+
+void MediaPlayerPrivate::cancelLoad()
+{
+ m_mediaPlayer->setMedia(QMediaContent());
+ updateStates();
+}
+
+void MediaPlayerPrivate::play()
+{
+ if (m_mediaPlayer->state() != QMediaPlayer::PlayingState)
+ m_mediaPlayer->play();
+}
+
+void MediaPlayerPrivate::pause()
+{
+ if (m_mediaPlayer->state() == QMediaPlayer::PlayingState)
+ m_mediaPlayer->pause();
+}
+
+bool MediaPlayerPrivate::paused() const
+{
+ return (m_mediaPlayer->state() != QMediaPlayer::PlayingState);
+}
+
+void MediaPlayerPrivate::seek(float position)
+{
+ if (!m_mediaPlayer->isSeekable())
+ return;
+
+ if (m_mediaPlayerControl && !m_mediaPlayerControl->availablePlaybackRanges().contains(position * 1000))
+ return;
+
+ if (m_isSeeking)
+ return;
+
+ if (position > duration())
+ position = duration();
+
+ // Seeking is most reliable when we're paused.
+ // Webkit will try to pause before seeking, but due to the asynchronous nature
+ // of the backend, the player may not actually be paused yet.
+ // In this case, we should queue the seek and wait until pausing has completed
+ // before attempting to seek.
+ if (m_mediaPlayer->state() == QMediaPlayer::PlayingState) {
+ m_mediaPlayer->pause();
+ m_isSeeking = true;
+ m_queuedSeek = static_cast<qint64>(position * 1000);
+
+ // Set a timeout, so that in the event that we don't get a state changed
+ // signal, we still attempt the seek.
+ QTimer::singleShot(1000, this, SLOT(queuedSeekTimeout()));
+ } else {
+ m_isSeeking = true;
+ m_mediaPlayer->setPosition(static_cast<qint64>(position * 1000));
+
+ // Set a timeout, in case we don't get a position changed signal
+ QTimer::singleShot(10000, this, SLOT(seekTimeout()));
+ }
+}
+
+bool MediaPlayerPrivate::seeking() const
+{
+ return m_isSeeking;
+}
+
+float MediaPlayerPrivate::duration() const
+{
+ if (m_readyState < MediaPlayer::HaveMetadata)
+ return 0.0f;
+
+ float duration = m_mediaPlayer->duration() / 1000.0f;
+
+ // We are streaming
+ if (duration <= 0.0f)
+ duration = std::numeric_limits<float>::infinity();
+
+ return duration;
+}
+
+float MediaPlayerPrivate::currentTime() const
+{
+ float currentTime = m_mediaPlayer->position() / 1000.0f;
+ return currentTime;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
+{
+ RefPtr<TimeRanges> buffered = TimeRanges::create();
+
+ if (!m_mediaPlayerControl)
+ return buffered;
+
+ QMediaTimeRange playbackRanges = m_mediaPlayerControl->availablePlaybackRanges();
+
+ foreach (const QMediaTimeInterval interval, playbackRanges.intervals()) {
+ float rangeMin = static_cast<float>(interval.start()) / 1000.0f;
+ float rangeMax = static_cast<float>(interval.end()) / 1000.0f;
+ buffered->add(rangeMin, rangeMax);
+ }
+
+ return buffered.release();
+}
+
+float MediaPlayerPrivate::maxTimeSeekable() const
+{
+ if (!m_mediaPlayerControl)
+ return 0;
+
+ return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f;
+}
+
+unsigned MediaPlayerPrivate::bytesLoaded() const
+{
+ unsigned percentage = m_mediaPlayer->bufferStatus();
+
+ if (percentage == 100) {
+ if (m_networkState != MediaPlayer::Idle) {
+ m_networkState = MediaPlayer::Idle;
+ m_player->networkStateChanged();
+ }
+ if (m_readyState != MediaPlayer::HaveEnoughData) {
+ m_readyState = MediaPlayer::HaveEnoughData;
+ m_player->readyStateChanged();
+ }
+ }
+
+ QLatin1String bytesLoadedKey("bytes-loaded");
+ if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey))
+ return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt();
+
+ return percentage;
+}
+
+unsigned MediaPlayerPrivate::totalBytes() const
+{
+ if (m_mediaPlayer->availableMetaData().contains(QtMultimedia::Size))
+ return m_mediaPlayer->metaData(QtMultimedia::Size).toInt();
+
+ return 100;
+}
+
+void MediaPlayerPrivate::setRate(float rate)
+{
+ m_mediaPlayer->setPlaybackRate(rate);
+}
+
+void MediaPlayerPrivate::setVolume(float volume)
+{
+ m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0));
+}
+
+bool MediaPlayerPrivate::supportsMuting() const
+{
+ return true;
+}
+
+void MediaPlayerPrivate::setMuted(bool muted)
+{
+ m_mediaPlayer->setMuted(muted);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
+{
+ return m_readyState;
+}
+
+void MediaPlayerPrivate::setVisible(bool visible)
+{
+ m_isVisible = visible;
+}
+
+void MediaPlayerPrivate::mediaStatusChanged(QMediaPlayer::MediaStatus)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::handleError(QMediaPlayer::Error)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivate::stateChanged(QMediaPlayer::State state)
+{
+ if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) {
+ m_mediaPlayer->setPosition(m_queuedSeek);
+ m_queuedSeek = -1;
+ }
+}
+
+void MediaPlayerPrivate::nativeSizeChanged(const QSizeF&)
+{
+ m_player->sizeChanged();
+}
+
+void MediaPlayerPrivate::queuedSeekTimeout()
+{
+ // If we haven't heard anything, assume the player is now paused
+ // and we can attempt the seek
+ if (m_isSeeking && m_queuedSeek >= 0) {
+ m_mediaPlayer->setPosition(m_queuedSeek);
+ m_queuedSeek = -1;
+
+ // Set a timeout, in case we don't get a position changed signal
+ QTimer::singleShot(10000, this, SLOT(seekTimeout()));
+ }
+}
+
+void MediaPlayerPrivate::seekTimeout()
+{
+ // If we haven't heard anything, assume the seek succeeded
+ if (m_isSeeking) {
+ m_player->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivate::positionChanged(qint64)
+{
+ // Only propogate this event if we are seeking
+ if (m_isSeeking && m_queuedSeek == -1) {
+ m_player->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivate::durationChanged(qint64)
+{
+ m_player->durationChanged();
+}
+
+void MediaPlayerPrivate::volumeChanged(int volume)
+{
+ m_player->volumeChanged(static_cast<float>(volume) / 100.0);
+}
+
+void MediaPlayerPrivate::mutedChanged(bool muted)
+{
+ m_player->muteChanged(muted);
+}
+
+void MediaPlayerPrivate::updateStates()
+{
+ // Store the old states so that we can detect a change and raise change events
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ QMediaPlayer::MediaStatus currentStatus = m_mediaPlayer->mediaStatus();
+ QMediaPlayer::Error currentError = m_mediaPlayer->error();
+
+ if (currentError != QMediaPlayer::NoError) {
+ m_readyState = MediaPlayer::HaveNothing;
+ if (currentError == QMediaPlayer::FormatError)
+ m_networkState = MediaPlayer::FormatError;
+ else
+ m_networkState = MediaPlayer::NetworkError;
+ } else if (currentStatus == QMediaPlayer::UnknownMediaStatus
+ || currentStatus == QMediaPlayer::NoMedia) {
+ m_networkState = MediaPlayer::Idle;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else if (currentStatus == QMediaPlayer::LoadingMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveNothing;
+ } else if (currentStatus == QMediaPlayer::LoadedMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveMetadata;
+ } else if (currentStatus == QMediaPlayer::BufferingMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveFutureData;
+ } else if (currentStatus == QMediaPlayer::StalledMedia) {
+ m_networkState = MediaPlayer::Loading;
+ m_readyState = MediaPlayer::HaveCurrentData;
+ } else if (currentStatus == QMediaPlayer::BufferedMedia
+ || currentStatus == QMediaPlayer::EndOfMedia) {
+ m_networkState = MediaPlayer::Idle;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (currentStatus == QMediaPlayer::InvalidMedia) {
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
+ }
+
+ // Log the state changes and raise the state change events
+ // NB: The readyStateChanged event must come before the networkStateChanged event.
+ // Breaking this invariant will cause the resource selection algorithm for multiple
+ // sources to fail.
+ if (m_readyState != oldReadyState)
+ m_player->readyStateChanged();
+
+ if (m_networkState != oldNetworkState)
+ m_player->networkStateChanged();
+}
+
+void MediaPlayerPrivate::setSize(const IntSize& size)
+{
+ if (size == m_currentSize)
+ return;
+
+ m_currentSize = size;
+ m_videoItem->setSize(QSizeF(QSize(size)));
+}
+
+IntSize MediaPlayerPrivate::naturalSize() const
+{
+ if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata)
+ return IntSize();
+
+ return IntSize(m_videoItem->nativeSize().toSize());
+}
+
+void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_composited)
+ return;
+#endif
+ if (context->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ // Grab the painter and widget
+ QPainter* painter = context->platformContext();
+
+ // Render the video
+ m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect());
+}
+
+void MediaPlayerPrivate::repaint()
+{
+ m_player->repaint();
+}
+
+#if USE(ACCELERATED_COMPOSITING)
+void MediaPlayerPrivate::acceleratedRenderingStateChanged()
+{
+ bool composited = m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player);
+ if (composited == m_composited)
+ return;
+
+ m_composited = composited;
+ if (composited)
+ m_videoScene->removeItem(m_videoItem);
+ else
+ m_videoScene->addItem(m_videoItem);
+}
+
+PlatformLayer* MediaPlayerPrivate::platformLayer() const
+{
+ return m_composited ? m_videoItem : 0;
+}
+#endif
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivateQt.cpp"
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
new file mode 100644
index 0000000..d72404c
--- /dev/null
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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
+ along 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 MediaPlayerPrivateQt_h
+#define MediaPlayerPrivateQt_h
+
+#include "MediaPlayerPrivate.h"
+
+#include <QMediaPlayer>
+#include <QObject>
+
+QT_BEGIN_NAMESPACE
+class QMediaPlayerControl;
+class QGraphicsVideoItem;
+class QGraphicsScene;
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+class MediaPlayerPrivate : public QObject, public MediaPlayerPrivateInterface {
+
+ Q_OBJECT
+
+public:
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ ~MediaPlayerPrivate();
+
+ static void registerMediaEngine(MediaEngineRegistrar);
+ static void getSupportedTypes(HashSet<String>&);
+ static MediaPlayer::SupportsType supportsType(const String&, const String&);
+ static bool isAvailable() { return true; }
+
+ bool hasVideo() const;
+ bool hasAudio() const;
+
+ void load(const String &url);
+ void cancelLoad();
+
+ void play();
+ void pause();
+
+ bool paused() const;
+ bool seeking() const;
+
+ float duration() const;
+ float currentTime() const;
+ void seek(float);
+
+ void setRate(float);
+ void setVolume(float);
+
+ bool supportsMuting() const;
+ void setMuted(bool);
+
+ MediaPlayer::NetworkState networkState() const;
+ MediaPlayer::ReadyState readyState() const;
+
+ PassRefPtr<TimeRanges> buffered() const;
+ float maxTimeSeekable() const;
+ unsigned bytesLoaded() const;
+ unsigned totalBytes() const;
+
+ void setVisible(bool);
+
+ IntSize naturalSize() const;
+ void setSize(const IntSize&);
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ bool supportsFullscreen() const { return false; }
+
+#if USE(ACCELERATED_COMPOSITING)
+ // whether accelerated rendering is supported by the media engine for the current media.
+ virtual bool supportsAcceleratedRendering() const { return true; }
+ // called when the rendering system flips the into or out of accelerated rendering mode.
+ virtual void acceleratedRenderingStateChanged();
+ // returns an object that can be directly composited via GraphicsLayerQt (essentially a QGraphicsItem*)
+ virtual PlatformLayer* platformLayer() const;
+#endif
+
+private slots:
+ void mediaStatusChanged(QMediaPlayer::MediaStatus);
+ void handleError(QMediaPlayer::Error);
+ void stateChanged(QMediaPlayer::State);
+ void nativeSizeChanged(const QSizeF&);
+ void queuedSeekTimeout();
+ void seekTimeout();
+ void positionChanged(qint64);
+ void durationChanged(qint64);
+ void volumeChanged(int);
+ void mutedChanged(bool);
+ void repaint();
+
+private:
+ void updateStates();
+
+private:
+ MediaPlayerPrivate(MediaPlayer*);
+
+ MediaPlayer* m_player;
+ QMediaPlayer* m_mediaPlayer;
+ QMediaPlayerControl* m_mediaPlayerControl;
+ QGraphicsVideoItem* m_videoItem;
+ QGraphicsScene* m_videoScene;
+
+ mutable MediaPlayer::NetworkState m_networkState;
+ mutable MediaPlayer::ReadyState m_readyState;
+
+ IntSize m_currentSize;
+ bool m_isVisible;
+ bool m_isSeeking;
+ bool m_composited;
+ qint64 m_queuedSeek;
+};
+}
+
+#endif // MediaPlayerPrivateQt_h
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index 507f029..ee4af7f 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -269,10 +269,12 @@ void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool antic
span += ea - sa;
}
- m_path.moveTo(QPointF(xc + radius * cos(sar),
+ // connect to the previous point by a straight line
+ m_path.lineTo(QPointF(xc + radius * cos(sar),
yc - radius * sin(sar)));
m_path.arcTo(xs, ys, width, height, sa, span);
+
}
void Path::addRect(const FloatRect& r)
diff --git a/WebCore/platform/graphics/qt/StillImageQt.cpp b/WebCore/platform/graphics/qt/StillImageQt.cpp
index 1db04a7..4653c58 100644
--- a/WebCore/platform/graphics/qt/StillImageQt.cpp
+++ b/WebCore/platform/graphics/qt/StillImageQt.cpp
@@ -57,8 +57,43 @@ void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
ctxt->save();
ctxt->setCompositeOperation(op);
+
+ // To support width or height is negative
+ float sx = src.x();
+ float sy = src.y();
+ float sw = src.width();
+ float sh = src.height();
+
+ if (sw < 0) {
+ sx = sx + sw;
+ sw = -sw;
+ }
+
+ if (sh < 0) {
+ sy = sy + sh;
+ sh = -sh;
+ }
+
+ float dx = dst.x();
+ float dy = dst.y();
+ float dw = dst.width();
+ float dh = dst.height();
+
+ if (dw < 0) {
+ dx = dx + dw;
+ dw = -dw;
+ }
+
+ if (dh < 0) {
+ dy = dy + dh;
+ dh = -dh;
+ }
+
+ FloatRect srcM(sx, sy, sw, sh);
+ FloatRect dstM(dx, dy, dw, dh);
QPainter* painter(ctxt->platformContext());
- painter->drawPixmap(dst, m_pixmap, src);
+
+ painter->drawPixmap(dstM, m_pixmap, srcM);
ctxt->restore();
}
diff --git a/WebCore/platform/graphics/qt/TileQt.cpp b/WebCore/platform/graphics/qt/TileQt.cpp
new file mode 100644
index 0000000..9628448
--- /dev/null
+++ b/WebCore/platform/graphics/qt/TileQt.cpp
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+
+ 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
+ along 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"
+#include "Tile.h"
+
+#if ENABLE(TILED_BACKING_STORE)
+
+#include "GraphicsContext.h"
+#include "TiledBackingStore.h"
+#include "TiledBackingStoreClient.h"
+#include <QApplication>
+#include <QObject>
+#include <QPainter>
+#include <QRegion>
+
+namespace WebCore {
+
+static const unsigned checkerSize = 16;
+static const unsigned checkerColor1 = 0xff555555;
+static const unsigned checkerColor2 = 0xffaaaaaa;
+
+static QPixmap& checkeredPixmap()
+{
+ static QPixmap* pixmap;
+ if (!pixmap) {
+ pixmap = new QPixmap(checkerSize, checkerSize);
+ QPainter painter(pixmap);
+ QColor color1(checkerColor1);
+ QColor color2(checkerColor2);
+ for (unsigned y = 0; y < checkerSize; y += checkerSize / 2) {
+ bool alternate = y % checkerSize;
+ for (unsigned x = 0; x < checkerSize; x += checkerSize / 2) {
+ painter.fillRect(x, y, checkerSize / 2, checkerSize / 2, alternate ? color1 : color2);
+ alternate = !alternate;
+ }
+ }
+ }
+ return *pixmap;
+}
+
+Tile::Tile(TiledBackingStore* backingStore, const Coordinate& tileCoordinate)
+ : m_backingStore(backingStore)
+ , m_coordinate(tileCoordinate)
+ , m_rect(m_backingStore->tileRectForCoordinate(tileCoordinate))
+ , m_buffer(0)
+ , m_backBuffer(0)
+ , m_dirtyRegion(new QRegion(m_rect))
+{
+}
+
+Tile::~Tile()
+{
+ delete m_buffer;
+ delete m_backBuffer;
+ delete m_dirtyRegion;
+}
+
+bool Tile::isDirty() const
+{
+ return !m_dirtyRegion->isEmpty();
+}
+
+bool Tile::isReadyToPaint() const
+{
+ return m_buffer;
+}
+
+void Tile::invalidate(const IntRect& dirtyRect)
+{
+ IntRect tileDirtyRect = intersection(dirtyRect, m_rect);
+ if (tileDirtyRect.isEmpty())
+ return;
+
+ *m_dirtyRegion += tileDirtyRect;
+}
+
+void Tile::updateBackBuffer()
+{
+ if (m_buffer && !isDirty())
+ return;
+
+ if (!m_backBuffer) {
+ if (!m_buffer)
+ m_backBuffer = new QPixmap(m_backingStore->m_tileSize.width(), m_backingStore->m_tileSize.height());
+ else {
+ // Currently all buffers are updated synchronously at the same time so there is no real need
+ // to have separate back and front buffers. Just use the existing buffer.
+ m_backBuffer = m_buffer;
+ m_buffer = 0;
+ }
+ }
+
+ QVector<QRect> dirtyRects = m_dirtyRegion->rects();
+ *m_dirtyRegion = QRegion();
+
+ QPainter painter(m_backBuffer);
+ GraphicsContext context(&painter);
+ context.translate(-m_rect.x(), -m_rect.y());
+
+ int size = dirtyRects.size();
+ for (int n = 0; n < size; ++n) {
+ context.save();
+ IntRect rect = dirtyRects[n];
+ context.clip(FloatRect(rect));
+ context.scale(FloatSize(m_backingStore->m_contentsScale, m_backingStore->m_contentsScale));
+ m_backingStore->m_client->tiledBackingStorePaint(&context, m_backingStore->mapToContents(rect));
+ context.restore();
+ }
+}
+
+void Tile::swapBackBufferToFront()
+{
+ if (!m_backBuffer)
+ return;
+ delete m_buffer;
+ m_buffer = m_backBuffer;
+ m_backBuffer = 0;
+}
+
+void Tile::paint(GraphicsContext* context, const IntRect& rect)
+{
+ if (!m_buffer)
+ return;
+
+ IntRect target = intersection(rect, m_rect);
+ IntRect source((target.x() - m_rect.x()),
+ (target.y() - m_rect.y()),
+ target.width(),
+ target.height());
+
+ context->platformContext()->drawPixmap(target, *m_buffer, source);
+}
+
+void Tile::paintCheckerPattern(GraphicsContext* context, const FloatRect& target)
+{
+ QPainter* painter = context->platformContext();
+ QTransform worldTransform = painter->worldTransform();
+ qreal scaleX = worldTransform.m11();
+ qreal scaleY = worldTransform.m22();
+
+ QRect targetViewRect = QRectF(target.x() * scaleX,
+ target.y() * scaleY,
+ target.width() * scaleX,
+ target.height() * scaleY).toAlignedRect();
+
+ QTransform adjustedTransform(1., worldTransform.m12(), worldTransform.m13(),
+ worldTransform.m21(), 1., worldTransform.m23(),
+ worldTransform.m31(), worldTransform.m32(), worldTransform.m33());
+ painter->setWorldTransform(adjustedTransform);
+
+ painter->drawTiledPixmap(targetViewRect,
+ checkeredPixmap(),
+ QPoint(targetViewRect.left() % checkerSize,
+ targetViewRect.top() % checkerSize));
+
+ painter->setWorldTransform(worldTransform);
+}
+
+}
+
+#endif