summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/platform/graphics/qt
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-06 11:45:16 +0100
committerSteve Block <steveblock@google.com>2011-05-12 13:44:10 +0100
commitcad810f21b803229eb11403f9209855525a25d57 (patch)
tree29a6fd0279be608e0fe9ffe9841f722f0f4e4269 /Source/WebCore/platform/graphics/qt
parent121b0cf4517156d0ac5111caf9830c51b69bae8f (diff)
downloadexternal_webkit-cad810f21b803229eb11403f9209855525a25d57.zip
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.gz
external_webkit-cad810f21b803229eb11403f9209855525a25d57.tar.bz2
Merge WebKit at r75315: Initial merge by git.
Change-Id: I570314b346ce101c935ed22a626b48c2af266b84
Diffstat (limited to 'Source/WebCore/platform/graphics/qt')
-rw-r--r--Source/WebCore/platform/graphics/qt/ColorQt.cpp51
-rw-r--r--Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp167
-rw-r--r--Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp61
-rw-r--r--Source/WebCore/platform/graphics/qt/Extensions3DQt.h50
-rw-r--r--Source/WebCore/platform/graphics/qt/FloatPointQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/FloatRectQt.cpp64
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCacheQt.cpp72
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h50
-rw-r--r--Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp69
-rw-r--r--Source/WebCore/platform/graphics/qt/FontPlatformData.h175
-rw-r--r--Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp132
-rw-r--r--Source/WebCore/platform/graphics/qt/FontQt.cpp432
-rw-r--r--Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp36
-rw-r--r--Source/WebCore/platform/graphics/qt/GradientQt.cpp119
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp1674
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp1370
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp1779
-rw-r--r--Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h95
-rw-r--r--Source/WebCore/platform/graphics/qt/IconQt.cpp69
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageBufferData.h52
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp412
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp258
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageDecoderQt.h80
-rw-r--r--Source/WebCore/platform/graphics/qt/ImageQt.cpp256
-rw-r--r--Source/WebCore/platform/graphics/qt/IntPointQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/IntRectQt.cpp48
-rw-r--r--Source/WebCore/platform/graphics/qt/IntSizeQt.cpp49
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp547
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h153
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp674
-rw-r--r--Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h156
-rw-r--r--Source/WebCore/platform/graphics/qt/PathQt.cpp446
-rw-r--r--Source/WebCore/platform/graphics/qt/PatternQt.cpp47
-rw-r--r--Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp89
-rw-r--r--Source/WebCore/platform/graphics/qt/StillImageQt.cpp91
-rw-r--r--Source/WebCore/platform/graphics/qt/StillImageQt.h67
-rw-r--r--Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp214
-rw-r--r--Source/WebCore/platform/graphics/qt/TextureMapperQt.h76
-rw-r--r--Source/WebCore/platform/graphics/qt/TileQt.cpp179
-rw-r--r--Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp47
-rw-r--r--Source/WebCore/platform/graphics/qt/TransparencyLayer.h86
41 files changed, 10588 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/qt/ColorQt.cpp b/Source/WebCore/platform/graphics/qt/ColorQt.cpp
new file mode 100644
index 0000000..151766a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ColorQt.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Color.h"
+
+#include <QColor>
+
+namespace WebCore {
+
+Color::Color(const QColor& c)
+ : m_color(makeRGBA(c.red(), c.green(), c.blue(), c.alpha()))
+{
+ m_valid = c.isValid();
+}
+
+Color::operator QColor() const
+{
+ if (m_valid)
+ return QColor(red(), green(), blue(), alpha());
+ else
+ return QColor();
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp
new file mode 100644
index 0000000..834ca62
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ContextShadowQt.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2010 Sencha, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ContextShadow.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+#include <QPainter>
+#include <QTimerEvent>
+
+namespace WebCore {
+
+// ContextShadow needs a scratch image as the buffer for the blur filter.
+// Instead of creating and destroying the buffer for every operation,
+// we create a buffer which will be automatically purged via a timer.
+
+class ShadowBuffer: public QObject {
+public:
+ ShadowBuffer(QObject* parent = 0);
+
+ QImage* scratchImage(const QSize& size);
+
+ void schedulePurge();
+
+protected:
+ void timerEvent(QTimerEvent* event);
+
+private:
+ QImage image;
+ int timerId;
+};
+
+ShadowBuffer::ShadowBuffer(QObject* parent)
+ : QObject(parent)
+ , timerId(0)
+{
+}
+
+QImage* ShadowBuffer::scratchImage(const QSize& size)
+{
+ int width = size.width();
+ int height = size.height();
+
+ // We do not need to recreate the buffer if the buffer is reasonably
+ // larger than the requested size. However, if the requested size is
+ // much smaller than our buffer, reduce our buffer so that we will not
+ // keep too many allocated pixels for too long.
+ if (!image.isNull() && (image.width() > width) && (image.height() > height))
+ if (((2 * width) > image.width()) && ((2 * height) > image.height())) {
+ image.fill(Qt::transparent);
+ return &image;
+ }
+
+ // Round to the nearest 32 pixels so we do not grow the buffer everytime
+ // there is larger request by 1 pixel.
+ width = (1 + (width >> 5)) << 5;
+ height = (1 + (height >> 5)) << 5;
+
+ image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
+ image.fill(Qt::transparent);
+ return &image;
+}
+
+void ShadowBuffer::schedulePurge()
+{
+ static const double BufferPurgeDelay = 2; // seconds
+ killTimer(timerId);
+ timerId = startTimer(BufferPurgeDelay * 1000);
+}
+
+void ShadowBuffer::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() == timerId) {
+ killTimer(timerId);
+ image = QImage();
+ }
+ QObject::timerEvent(event);
+}
+
+Q_GLOBAL_STATIC(ShadowBuffer, scratchShadowBuffer)
+
+PlatformContext ContextShadow::beginShadowLayer(GraphicsContext* context, const FloatRect& layerArea)
+{
+ // Set m_blurDistance.
+ adjustBlurDistance(context);
+
+ PlatformContext p = context->platformContext();
+
+ QRect clipRect;
+ if (p->hasClipping())
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+ clipRect = p->clipBoundingRect().toAlignedRect();
+#else
+ clipRect = p->clipRegion().boundingRect();
+#endif
+ else
+ clipRect = p->transform().inverted().mapRect(p->window());
+
+ // Set m_layerOrigin, m_layerContextTranslation, m_sourceRect.
+ IntRect clip(clipRect.x(), clipRect.y(), clipRect.width(), clipRect.height());
+ IntRect layerRect = calculateLayerBoundingRect(context, layerArea, clip);
+
+ // Don't paint if we are totally outside the clip region.
+ if (layerRect.isEmpty())
+ return 0;
+
+ ShadowBuffer* shadowBuffer = scratchShadowBuffer();
+ QImage* shadowImage = shadowBuffer->scratchImage(layerRect.size());
+ m_layerImage = QImage(*shadowImage);
+
+ m_layerContext = new QPainter;
+ m_layerContext->begin(&m_layerImage);
+ m_layerContext->setFont(p->font());
+ m_layerContext->translate(m_layerContextTranslation);
+ return m_layerContext;
+}
+
+void ContextShadow::endShadowLayer(GraphicsContext* context)
+{
+ m_layerContext->end();
+ delete m_layerContext;
+ m_layerContext = 0;
+
+ if (m_type == BlurShadow) {
+ blurLayerImage(m_layerImage.bits(), IntSize(m_layerImage.width(), m_layerImage.height()),
+ m_layerImage.bytesPerLine());
+ }
+
+ if (m_type != NoShadow) {
+ // "Colorize" with the right shadow color.
+ QPainter p(&m_layerImage);
+ p.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ p.fillRect(m_layerImage.rect(), m_color.rgb());
+ p.end();
+ }
+
+ context->platformContext()->drawImage(m_layerOrigin, m_layerImage, m_sourceRect);
+
+ scratchShadowBuffer()->schedulePurge();
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp
new file mode 100644
index 0000000..cd28f0e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(3D_CANVAS)
+
+#include "Extensions3DQt.h"
+
+#include "GraphicsContext3D.h"
+
+namespace WebCore {
+
+Extensions3DQt::Extensions3DQt()
+{
+}
+
+Extensions3DQt::~Extensions3DQt()
+{
+}
+
+bool Extensions3DQt::supports(const String&)
+{
+ return false;
+}
+
+void Extensions3DQt::ensureEnabled(const String& name)
+{
+ ASSERT(supports(name));
+}
+
+int Extensions3DQt::getGraphicsResetStatusARB()
+{
+ return GraphicsContext3D::NO_ERROR;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/qt/Extensions3DQt.h b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h
new file mode 100644
index 0000000..ae4b375
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/Extensions3DQt.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Extensions3DQt_h
+#define Extensions3DQt_h
+
+#include "Extensions3D.h"
+
+namespace WebCore {
+
+class Extensions3DQt : public Extensions3D {
+public:
+ virtual ~Extensions3DQt();
+
+ // Extensions3D methods.
+ virtual bool supports(const String&);
+ virtual void ensureEnabled(const String&);
+ virtual int getGraphicsResetStatusARB();
+
+private:
+ // This class only needs to be instantiated by GraphicsContext3D implementations.
+ friend class GraphicsContext3D;
+ Extensions3DQt();
+};
+
+} // namespace WebCore
+
+#endif // Extensions3DQt_h
diff --git a/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp b/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp
new file mode 100644
index 0000000..82093d8
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FloatPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatPoint.h"
+
+#include <QPointF>
+
+namespace WebCore {
+
+FloatPoint::FloatPoint(const QPointF& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+FloatPoint::operator QPointF() const
+{
+ return QPointF(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp b/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp
new file mode 100644
index 0000000..063876b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FloatRectQt.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "FloatRect.h"
+
+#include <QRectF>
+
+namespace WebCore {
+
+FloatRect::FloatRect(const QRectF& r)
+ : m_location(r.topLeft())
+ , m_size(r.width()
+ , r.height())
+{
+}
+
+FloatRect::operator QRectF() const
+{
+ return QRectF(x(), y(), width(), height());
+}
+
+FloatRect FloatRect::normalized() const
+{
+ FloatRect normalizedRect = *this;
+
+ if (width() < 0) {
+ normalizedRect.setX(x() + width());
+ normalizedRect.setWidth(-width());
+ }
+ if (height() < 0) {
+ normalizedRect.setY(y() + height());
+ normalizedRect.setHeight(-height());
+ }
+ return normalizedRect;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp b/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp
new file mode 100644
index 0000000..c59c523
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCacheQt.cpp
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ Copyright (C) 2007 Nicholas Shanks <webkit@nickshanks.com>
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "FontCache.h"
+
+#include "FontDescription.h"
+#include "FontPlatformData.h"
+#include "Font.h"
+#include "PlatformString.h"
+#include <utility>
+#include <wtf/ListHashSet.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/text/StringHash.h>
+
+#include <QFont>
+
+using namespace WTF;
+
+namespace WebCore {
+
+void FontCache::platformInit()
+{
+}
+
+const SimpleFontData* FontCache::getFontDataForCharacters(const Font&, const UChar*, int)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getSimilarFontPlatformData(const Font& font)
+{
+ return 0;
+}
+
+SimpleFontData* FontCache::getLastResortFallbackFont(const FontDescription& fontDescription)
+{
+ const AtomicString fallbackFamily = QFont(fontDescription.family().family()).lastResortFamily();
+ return getCachedFontData(new FontPlatformData(fontDescription, fallbackFamily));
+}
+
+void FontCache::getTraitsInFamily(const AtomicString&, Vector<unsigned>&)
+{
+}
+
+FontPlatformData* FontCache::createFontPlatformData(const FontDescription& fontDescription, const AtomicString& familyName)
+{
+ return new FontPlatformData(fontDescription, familyName);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h
new file mode 100644
index 0000000..6c41d47
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformData.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#ifndef FontCustomPlatformData_h
+#define FontCustomPlatformData_h
+
+#include "FontOrientation.h"
+#include "FontRenderingMode.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebCore {
+
+class FontPlatformData;
+class SharedBuffer;
+
+struct FontCustomPlatformData : Noncopyable {
+ ~FontCustomPlatformData();
+
+ // for use with QFontDatabase::addApplicationFont/removeApplicationFont
+ int m_handle;
+
+ FontPlatformData fontPlatformData(int size, bool bold, bool italic, FontOrientation = Horizontal, FontRenderingMode = NormalRenderingMode);
+
+ static bool supportsFormat(const String&);
+};
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer);
+
+} // namespace WebCore
+
+#endif // FontCustomPlatformData_h
diff --git a/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp
new file mode 100644
index 0000000..e2f009b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontCustomPlatformDataQt.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2008 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "FontCustomPlatformData.h"
+
+#include "FontPlatformData.h"
+#include "SharedBuffer.h"
+#include <QFontDatabase>
+#include <QStringList>
+
+namespace WebCore {
+
+FontCustomPlatformData::~FontCustomPlatformData()
+{
+ QFontDatabase::removeApplicationFont(m_handle);
+}
+
+FontPlatformData FontCustomPlatformData::fontPlatformData(int size, bool bold, bool italic, FontOrientation, FontRenderingMode)
+{
+ QFont font;
+ font.setFamily(QFontDatabase::applicationFontFamilies(m_handle)[0]);
+ font.setPixelSize(size);
+ if (bold)
+ font.setWeight(QFont::Bold);
+ font.setItalic(italic);
+
+ return FontPlatformData(font);
+}
+
+FontCustomPlatformData* createFontCustomPlatformData(SharedBuffer* buffer)
+{
+ ASSERT_ARG(buffer, buffer);
+
+ int id = QFontDatabase::addApplicationFontFromData(QByteArray(buffer->data(), buffer->size()));
+ if (id == -1)
+ return 0;
+
+ Q_ASSERT(QFontDatabase::applicationFontFamilies(id).size() > 0);
+
+ FontCustomPlatformData *data = new FontCustomPlatformData;
+ data->m_handle = id;
+ return data;
+}
+
+bool FontCustomPlatformData::supportsFormat(const String& format)
+{
+ return equalIgnoringCase(format, "truetype") || equalIgnoringCase(format, "opentype");
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformData.h b/Source/WebCore/platform/graphics/qt/FontPlatformData.h
new file mode 100644
index 0000000..1c57e29
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontPlatformData.h
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#ifndef FontPlatformData_h
+#define FontPlatformData_h
+
+#include <wtf/Forward.h>
+#include "FontDescription.h"
+#include "FontOrientation.h"
+#include <QFont>
+#include <QHash>
+
+namespace WebCore {
+
+class FontPlatformDataPrivate : public Noncopyable {
+public:
+ FontPlatformDataPrivate()
+ : refCount(1)
+ , size(font.pixelSize())
+ , bold(font.bold())
+ , oblique(false)
+ {}
+ FontPlatformDataPrivate(const float size, const bool bold, const bool oblique)
+ : refCount(1)
+ , size(size)
+ , bold(bold)
+ , oblique(oblique)
+ {}
+ FontPlatformDataPrivate(const QFont& font)
+ : refCount(1)
+ , font(font)
+ , size(font.pixelSize())
+ , bold(font.bold())
+ , oblique(false)
+ {}
+ unsigned refCount;
+ QFont font;
+ float size;
+ bool bold : 1;
+ bool oblique : 1;
+};
+
+
+
+class FontPlatformData : public FastAllocBase {
+public:
+ FontPlatformData(float size, bool bold, bool oblique);
+ FontPlatformData(const FontPlatformData &);
+ FontPlatformData(const FontDescription&, const AtomicString& familyName, int wordSpacing = 0, int letterSpacing = 0);
+ FontPlatformData(const QFont& font)
+ : m_data(new FontPlatformDataPrivate(font))
+ {}
+ FontPlatformData(WTF::HashTableDeletedValueType)
+ : m_data(reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ {}
+
+ ~FontPlatformData();
+
+ FontPlatformData& operator=(const FontPlatformData&);
+ bool operator==(const FontPlatformData&) const;
+
+ bool isHashTableDeletedValue() const
+ {
+ return m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1);
+ }
+
+ static inline QFont::Weight toQFontWeight(FontWeight fontWeight)
+ {
+ switch (fontWeight) {
+ case FontWeight100:
+ case FontWeight200:
+ return QFont::Light; // QFont::Light == Weight of 25
+ case FontWeight600:
+ return QFont::DemiBold; // QFont::DemiBold == Weight of 63
+ case FontWeight700:
+ case FontWeight800:
+ return QFont::Bold; // QFont::Bold == Weight of 75
+ case FontWeight900:
+ return QFont::Black; // QFont::Black == Weight of 87
+ case FontWeight300:
+ case FontWeight400:
+ case FontWeight500:
+ default:
+ return QFont::Normal; // QFont::Normal == Weight of 50
+ }
+ }
+
+ QFont font() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font;
+ return QFont();
+ }
+ float size() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->size;
+ return 0.0f;
+ }
+ QString family() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.family();
+ return QString();
+ }
+ bool bold() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->bold;
+ return false;
+ }
+ bool italic() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.italic();
+ return false;
+ }
+ bool smallCaps() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data)
+ return m_data->font.capitalization() == QFont::SmallCaps;
+ return false;
+ }
+ int pixelSize() const
+ {
+ Q_ASSERT(m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1));
+ if (m_data) {
+ // WebKit allows font size zero but QFont does not.
+ if (!m_data->size)
+ return m_data->size;
+ return m_data->font.pixelSize();
+ }
+ return 0;
+ }
+
+ FontOrientation orientation() const { return Horizontal; } // FIXME: Implement.
+
+ unsigned hash() const;
+
+#ifndef NDEBUG
+ String description() const;
+#endif
+private:
+ FontPlatformDataPrivate* m_data;
+};
+
+} // namespace WebCore
+
+#endif // FontPlatformData_h
diff --git a/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
new file mode 100644
index 0000000..4c9eb32
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontPlatformDataQt.cpp
@@ -0,0 +1,132 @@
+/*
+ Copyright (C) 2008 Holger Hans Peter Freyther
+ Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+
+ 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 "FontPlatformData.h"
+
+#include "PlatformString.h"
+
+namespace WebCore {
+
+static inline bool isEmptyValue(const float size, const bool bold, const bool oblique)
+{
+ // this is the empty value by definition of the trait FontDataCacheKeyTraits
+ return !bold && !oblique && size == 0.f;
+}
+
+FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
+{
+ if (isEmptyValue(size, bold, oblique))
+ m_data = 0;
+ else
+ m_data = new FontPlatformDataPrivate(size, bold, oblique);
+}
+
+FontPlatformData::FontPlatformData(const FontPlatformData &other) : m_data(other.m_data)
+{
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ ++m_data->refCount;
+}
+
+FontPlatformData::FontPlatformData(const FontDescription& description, const AtomicString& familyName, int wordSpacing, int letterSpacing)
+ : m_data(new FontPlatformDataPrivate())
+{
+ QFont& font = m_data->font;
+ int requestedSize = qRound(description.computedPixelSize());
+ font.setFamily(familyName);
+ font.setPixelSize(qRound(requestedSize));
+ font.setItalic(description.italic());
+ font.setWeight(toQFontWeight(description.weight()));
+ font.setWordSpacing(wordSpacing);
+ 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();
+ // WebKit allows font size zero but QFont does not. We will return
+ // m_data->size if a font size of zero is requested and pixelSize()
+ // otherwise.
+ m_data->size = (!requestedSize) ? requestedSize : font.pixelSize();
+}
+
+FontPlatformData::~FontPlatformData()
+{
+ if (!m_data || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return;
+ --m_data->refCount;
+ if (!m_data->refCount)
+ delete m_data;
+}
+
+FontPlatformData& FontPlatformData::operator=(const FontPlatformData& other)
+{
+ if (m_data == other.m_data)
+ return *this;
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1)) {
+ --m_data->refCount;
+ if (!m_data->refCount)
+ delete m_data;
+ }
+ m_data = other.m_data;
+ if (m_data && m_data != reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ ++m_data->refCount;
+ return *this;
+}
+
+bool FontPlatformData::operator==(const FontPlatformData& other) const
+{
+ if (m_data == other.m_data)
+ return true;
+
+ if (!m_data || !other.m_data
+ || m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1) || other.m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return false;
+
+ const bool equals = (m_data->size == other.m_data->size
+ && m_data->bold == other.m_data->bold
+ && m_data->oblique == other.m_data->oblique
+ && m_data->font == other.m_data->font);
+ return equals;
+}
+
+unsigned FontPlatformData::hash() const
+{
+ if (!m_data)
+ return 0;
+ if (m_data == reinterpret_cast<FontPlatformDataPrivate*>(-1))
+ return 1;
+ return qHash(m_data->font.toString())
+ ^ qHash(*reinterpret_cast<quint32*>(&m_data->size))
+ ^ qHash(m_data->bold)
+ ^ qHash(m_data->oblique);
+}
+
+#ifndef NDEBUG
+String FontPlatformData::description() const
+{
+ return String();
+}
+#endif
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/FontQt.cpp b/Source/WebCore/platform/graphics/qt/FontQt.cpp
new file mode 100644
index 0000000..f1ced2b
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/FontQt.cpp
@@ -0,0 +1,432 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ 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
+ 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 "Font.h"
+
+#include "AffineTransform.h"
+#include "ContextShadow.h"
+#include "FontDescription.h"
+#include "FontFallbackList.h"
+#include "FontSelector.h"
+#include "Gradient.h"
+#include "GraphicsContext.h"
+#include "NotImplemented.h"
+#include "Pattern.h"
+
+#include <QBrush>
+#include <QFontInfo>
+#include <QFontMetrics>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPen>
+#include <QTextLayout>
+#include <qalgorithms.h>
+#include <qdebug.h>
+
+#include <limits.h>
+
+namespace WebCore {
+
+static const QString fromRawDataWithoutRef(const String& string, int start = 0, int len = -1)
+{
+ if (len < 0)
+ len = string.length() - start;
+ Q_ASSERT(start + len <= string.length());
+
+ // We don't detach. This assumes the WebCore string data will stay valid for the
+ // lifetime of the QString we pass back, since we don't ref the WebCore string.
+ return QString::fromRawData(reinterpret_cast<const QChar*>(string.characters() + start), len);
+}
+
+static QTextLine setupLayout(QTextLayout* layout, const TextRun& style)
+{
+ int flags = style.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+ if (style.padding())
+ flags |= Qt::TextJustificationForced;
+ layout->setFlags(flags);
+ layout->beginLayout();
+ QTextLine line = layout->createLine();
+ line.setLineWidth(INT_MAX/256);
+ if (style.padding())
+ line.setLineWidth(line.naturalTextWidth() + style.padding());
+ layout->endLayout();
+ return line;
+}
+
+static void drawTextCommon(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to, const QFont& font, bool isComplexText)
+{
+ if (to < 0)
+ to = run.length();
+
+ QPainter *p = ctx->platformContext();
+
+ QPen textFillPen;
+ if (ctx->textDrawingMode() & TextModeFill) {
+ if (ctx->fillGradient()) {
+ QBrush brush(*ctx->fillGradient()->platformGradient());
+ brush.setTransform(ctx->fillGradient()->gradientSpaceTransform());
+ textFillPen = QPen(brush, 0);
+ } else if (ctx->fillPattern()) {
+ AffineTransform affine;
+ textFillPen = QPen(QBrush(ctx->fillPattern()->createPlatformPattern(affine)), 0);
+ } else
+ textFillPen = QPen(QColor(ctx->fillColor()));
+ }
+
+ QPen textStrokePen;
+ if (ctx->textDrawingMode() & TextModeStroke) {
+ if (ctx->strokeGradient()) {
+ QBrush brush(*ctx->strokeGradient()->platformGradient());
+ brush.setTransform(ctx->strokeGradient()->gradientSpaceTransform());
+ textStrokePen = QPen(brush, ctx->strokeThickness());
+ } else if (ctx->strokePattern()) {
+ AffineTransform affine;
+ QBrush brush(ctx->strokePattern()->createPlatformPattern(affine));
+ textStrokePen = QPen(brush, ctx->strokeThickness());
+ } else
+ textStrokePen = QPen(QColor(ctx->strokeColor()), ctx->strokeThickness());
+ }
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+ QPointF pt(point.x(), point.y());
+
+ if (from > 0 || to < run.length()) {
+ if (isComplexText) {
+ QTextLayout layout(string, font);
+ QTextLine line = setupLayout(&layout, run);
+ float x1 = line.cursorToX(from);
+ float x2 = line.cursorToX(to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ QFontMetrics fm(font);
+ int ascent = fm.ascent();
+ QRectF boundingRect(point.x() + x1, point.y() - ascent, x2 - x1, fm.height());
+ QRectF clip = boundingRect;
+
+ ContextShadow* ctxShadow = ctx->contextShadow();
+
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ qreal dx1 = 0, dx2 = 0, dy1 = 0, dy2 = 0;
+ if (ctxShadow->offset().x() > 0)
+ dx2 = ctxShadow->offset().x();
+ else
+ dx1 = -ctxShadow->offset().x();
+ if (ctxShadow->offset().y() > 0)
+ dy2 = ctxShadow->offset().y();
+ else
+ dy1 = -ctxShadow->offset().y();
+ // expand the clip rect to include the text shadow as well
+ clip.adjust(dx1, dx2, dy1, dy2);
+ clip.adjust(-ctxShadow->m_blurDistance, -ctxShadow->m_blurDistance, ctxShadow->m_blurDistance, ctxShadow->m_blurDistance);
+ }
+ p->save();
+ p->setClipRect(clip.toRect(), Qt::IntersectClip);
+ pt.setY(pt.y() - ascent);
+
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ ContextShadow* ctxShadow = ctx->contextShadow();
+ if (!ctxShadow->mustUseContextShadow(ctx)) {
+ p->save();
+ p->setPen(ctxShadow->m_color);
+ p->translate(ctxShadow->offset());
+ line.draw(p, pt);
+ p->restore();
+ } else {
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->setPen(ctxShadow->m_color);
+ line.draw(shadowPainter, pt);
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ }
+ p->setPen(textFillPen);
+ line.draw(p, pt);
+ p->restore();
+ return;
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ int skipWidth = QFontMetrics(font).width(string, from, Qt::TextBypassShaping);
+ pt.setX(pt.x() + skipWidth);
+ string = fromRawDataWithoutRef(sanitized, from, to - from);
+#endif
+ }
+
+ p->setFont(font);
+
+ int flags = run.rtl() ? Qt::TextForceRightToLeft : Qt::TextForceLeftToRight;
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ // See QWebPagePrivate::QWebPagePrivate() where the default path is set to Complex for Qt 4.6 and earlier.
+ if (!isComplexText && !(ctx->textDrawingMode() & TextModeStroke))
+ flags |= Qt::TextBypassShaping;
+#endif
+
+ QPainterPath textStrokePath;
+ if (ctx->textDrawingMode() & TextModeStroke)
+ textStrokePath.addText(pt, font, string);
+
+ ContextShadow* ctxShadow = ctx->contextShadow();
+ if (ctxShadow->m_type != ContextShadow::NoShadow) {
+ if (ctx->textDrawingMode() & TextModeFill) {
+ if (ctxShadow->m_type != ContextShadow::BlurShadow) {
+ p->save();
+ p->setPen(ctxShadow->m_color);
+ p->translate(ctxShadow->offset());
+ p->drawText(pt, string, flags, run.padding());
+ p->restore();
+ } else {
+ QFontMetrics fm(font);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height());
+#else
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height());
+#endif
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->setPen(ctxShadow->m_color);
+ shadowPainter->drawText(pt, string, flags, run.padding());
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ } else if (ctx->textDrawingMode() & TextModeStroke) {
+ if (ctxShadow->m_type != ContextShadow::BlurShadow) {
+ p->translate(ctxShadow->offset());
+ p->strokePath(textStrokePath, QPen(ctxShadow->m_color));
+ p->translate(-ctxShadow->offset());
+ } else {
+ QFontMetrics fm(font);
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string, -1, flags), fm.height());
+#else
+ QRectF boundingRect(pt.x(), point.y() - fm.ascent(), fm.width(string), fm.height());
+#endif
+ QPainter* shadowPainter = ctxShadow->beginShadowLayer(ctx, boundingRect);
+ if (shadowPainter) {
+ // Since it will be blurred anyway, we don't care about render hints.
+ shadowPainter->setFont(p->font());
+ shadowPainter->strokePath(textStrokePath, QPen(ctxShadow->m_color));
+ ctxShadow->endShadowLayer(ctx);
+ }
+ }
+ }
+ }
+
+ if (ctx->textDrawingMode() & TextModeStroke)
+ p->strokePath(textStrokePath, textStrokePen);
+
+ if (ctx->textDrawingMode() & TextModeFill) {
+ QPen previousPen = p->pen();
+ p->setPen(textFillPen);
+ p->drawText(pt, string, flags, run.padding());
+ p->setPen(previousPen);
+ }
+}
+
+void Font::drawSimpleText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */false);
+#else
+ Q_ASSERT(false);
+#endif
+}
+
+void Font::drawComplexText(GraphicsContext* ctx, const TextRun& run, const FloatPoint& point, int from, int to) const
+{
+ drawTextCommon(ctx, run, point, from, to, font(), /* isComplexText = */true);
+}
+
+int Font::emphasisMarkAscent(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+int Font::emphasisMarkDescent(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+int Font::emphasisMarkHeight(const AtomicString&) const
+{
+ notImplemented();
+ return 0;
+}
+
+void Font::drawEmphasisMarksForSimpleText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+void Font::drawEmphasisMarksForComplexText(GraphicsContext* /* context */, const TextRun& /* run */, const AtomicString& /* mark */, const FloatPoint& /* point */, int /* from */, int /* to */) const
+{
+ notImplemented();
+}
+
+float Font::floatWidthForSimpleText(const TextRun& run, GlyphBuffer* glyphBuffer, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
+{
+ if (!primaryFont()->platformData().size())
+ return 0;
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ if (!run.length())
+ return 0;
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ int w = QFontMetrics(font()).width(string, -1, Qt::TextBypassShaping);
+
+ // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
+ if (treatAsSpace(run[0]))
+ w -= m_wordSpacing;
+
+ return w + run.padding();
+#else
+ Q_ASSERT(false);
+ return 0;
+#endif
+}
+
+float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFontData*>*, GlyphOverflow*) const
+{
+ if (!primaryFont()->platformData().size())
+ return 0;
+
+ if (!run.length())
+ return 0;
+
+ if (run.length() == 1 && treatAsSpace(run[0]))
+ return QFontMetrics(font()).width(space) + run.padding();
+
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ int w = QFontMetrics(font()).width(string);
+ // WebKit expects us to ignore word spacing on the first character (as opposed to what Qt does)
+ if (treatAsSpace(run[0]))
+ w -= m_wordSpacing;
+
+ return w + run.padding();
+}
+
+int Font::offsetForPositionForSimpleText(const TextRun& run, float position, bool includePartialGlyphs) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QFontMetrics fm(font());
+ float delta = position;
+ int curPos = 0;
+ do {
+ float charWidth = fm.width(string[curPos]);
+ delta -= charWidth;
+ if (includePartialGlyphs) {
+ if (delta + charWidth / 2 <= 0)
+ break;
+ } else {
+ if (delta + charWidth <= 0)
+ break;
+ }
+ } while (++curPos < string.size());
+
+ return curPos;
+#else
+ Q_ASSERT(false);
+ return 0;
+#endif
+}
+
+int Font::offsetForPositionForComplexText(const TextRun& run, float position, bool) const
+{
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QTextLayout layout(string, font());
+ QTextLine line = setupLayout(&layout, run);
+ return line.xToCursor(position);
+}
+
+FloatRect Font::selectionRectForSimpleText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString wholeText = fromRawDataWithoutRef(sanitized);
+ QString selectedText = fromRawDataWithoutRef(sanitized, from, qMin(to - from, wholeText.length() - from));
+
+ int startX = QFontMetrics(font()).width(wholeText, from, Qt::TextBypassShaping);
+ int width = QFontMetrics(font()).width(selectedText, -1, Qt::TextBypassShaping);
+
+ return FloatRect(pt.x() + startX, pt.y(), width, h);
+#else
+ Q_ASSERT(false);
+ return FloatRect();
+#endif
+}
+
+FloatRect Font::selectionRectForComplexText(const TextRun& run, const FloatPoint& pt, int h, int from, int to) const
+{
+ String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
+ QString string = fromRawDataWithoutRef(sanitized);
+
+ QTextLayout layout(string, font());
+ QTextLine line = setupLayout(&layout, run);
+
+ float x1 = line.cursorToX(from);
+ float x2 = line.cursorToX(to);
+ if (x2 < x1)
+ qSwap(x1, x2);
+
+ return FloatRect(pt.x() + x1, pt.y(), x2 - x1, h);
+}
+
+bool Font::canReturnFallbackFontsForComplexText()
+{
+ return false;
+}
+
+bool Font::primaryFontHasGlyphForCharacter(UChar32) const
+{
+ notImplemented();
+ return true;
+}
+
+QFont Font::font() const
+{
+ QFont f = primaryFont()->getQtFont();
+ if (m_letterSpacing != 0)
+ f.setLetterSpacing(QFont::AbsoluteSpacing, m_letterSpacing);
+ if (m_wordSpacing != 0)
+ f.setWordSpacing(m_wordSpacing);
+ return f;
+}
+
+}
+
diff --git a/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp b/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
new file mode 100644
index 0000000..2121206
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GlyphPageTreeNodeQt.cpp
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+#include "config.h"
+#include "GlyphPageTreeNode.h"
+
+namespace WebCore {
+
+void GlyphPageTreeNode::pruneTreeCustomFontData(const FontData*)
+{
+}
+
+void GlyphPageTreeNode::pruneTreeFontData(const WebCore::SimpleFontData*)
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/GradientQt.cpp b/Source/WebCore/platform/graphics/qt/GradientQt.cpp
new file mode 100644
index 0000000..72bb009
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GradientQt.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2006, 2007, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Gradient.h"
+
+#include "CSSParser.h"
+#include "GraphicsContext.h"
+
+#include <QGradient>
+#include <QPainter>
+
+namespace WebCore {
+
+void Gradient::platformDestroy()
+{
+ delete m_gradient;
+ m_gradient = 0;
+}
+
+QGradient* Gradient::platformGradient()
+{
+ if (m_gradient)
+ return m_gradient;
+
+ bool reversed = m_r0 > m_r1;
+
+ qreal innerRadius = reversed ? m_r1 : m_r0;
+ qreal outerRadius = reversed ? m_r0 : m_r1;
+ QPointF center = reversed ? m_p0 : m_p1;
+ QPointF focalPoint = reversed ? m_p1 : m_p0;
+
+ if (m_radial)
+ m_gradient = new QRadialGradient(center, outerRadius, focalPoint);
+ else
+ m_gradient = new QLinearGradient(m_p0.x(), m_p0.y(), m_p1.x(), m_p1.y());
+
+ m_gradient->setInterpolationMode(QGradient::ComponentInterpolation);
+
+ sortStopsIfNecessary();
+
+ QColor stopColor;
+ Vector<ColorStop>::iterator stopIterator = m_stops.begin();
+ qreal lastStop(0.0);
+ const qreal lastStopDiff = 0.0000001;
+ while (stopIterator != m_stops.end()) {
+ stopColor.setRgbF(stopIterator->red, stopIterator->green, stopIterator->blue, stopIterator->alpha);
+ if (qFuzzyCompare(lastStop, qreal(stopIterator->stop)))
+ lastStop = stopIterator->stop + lastStopDiff;
+ else
+ lastStop = stopIterator->stop;
+
+ if (m_radial && !qFuzzyCompare(1 + outerRadius, qreal(1))) {
+ lastStop = lastStop * (1.0f - innerRadius / outerRadius);
+ if (!reversed)
+ lastStop += innerRadius / outerRadius;
+ }
+
+ qreal stopPosition = qMin(lastStop, qreal(1.0f));
+
+ if (m_radial && reversed)
+ stopPosition = 1 - stopPosition;
+
+ m_gradient->setColorAt(stopPosition, 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);
+ break;
+ case SpreadMethodReflect:
+ m_gradient->setSpread(QGradient::ReflectSpread);
+ break;
+ case SpreadMethodRepeat:
+ m_gradient->setSpread(QGradient::RepeatSpread);
+ break;
+ }
+
+ return m_gradient;
+}
+
+void Gradient::fill(GraphicsContext* context, const FloatRect& rect)
+{
+ context->platformContext()->fillRect(rect, *platformGradient());
+}
+
+} //namespace
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
new file mode 100644
index 0000000..295212c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -0,0 +1,1674 @@
+/*
+ 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 "WebGLObject.h"
+#include "CanvasRenderingContext.h"
+#include "Extensions3DQt.h"
+#include "GraphicsContext.h"
+#include "HTMLCanvasElement.h"
+#include "HostWindow.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
+#include "QWebPageClient.h"
+#include <QAbstractScrollArea>
+#include <QGLContext>
+#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
+
+#ifdef QT_OPENGL_ES_2
+typedef GLsizeiptr GLsizeiptrType;
+typedef GLintptr GLintptrType;
+#else
+typedef ptrdiff_t GLsizeiptrType;
+typedef ptrdiff_t GLintptrType;
+#endif
+
+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 void (APIENTRY* glGetAttachedShadersType) (GLuint, GLsizei, GLsizei*, GLuint*);
+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; }
+ QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient);
+
+ 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;
+ glGetAttachedShadersType getAttachedShaders;
+ 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;
+ HostWindow* m_hostWindow;
+ QGLWidget* m_glWidget;
+ GLuint m_texture;
+ GLuint m_mainFbo;
+ GLuint m_currentFbo;
+ GLuint m_depthBuffer;
+ QImage m_pixels;
+ ListHashSet<unsigned long> m_syntheticErrors;
+
+ OwnPtr<Extensions3DQt> m_extensions;
+
+private:
+
+ 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
+
+bool GraphicsContext3D::isGLES2Compliant() const
+{
+#if defined (QT_OPENGL_ES_2)
+ return true;
+#else
+ return false;
+#endif
+}
+
+// Even with underlying GLES2 driver, the below flags should still be set to
+// false if extentions exist (and they almost always do).
+bool GraphicsContext3D::isGLES2NPOTStrict() const
+{
+ return false;
+}
+
+bool GraphicsContext3D::isErrorGeneratedOnOutOfBoundsAccesses() const
+{
+ return false;
+}
+
+int GraphicsContext3D::getGraphicsResetStatusARB()
+{
+ return NO_ERROR;
+}
+
+
+GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
+ : m_attrs(attrs)
+ , m_hostWindow(hostWindow)
+ , 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);
+ getAttachedShaders = GET_PROC_ADDRESS(glGetAttachedShaders);
+ 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, GraphicsContext3D::RenderStyle renderStyle)
+{
+ // This implementation doesn't currently support rendering directly to the HostWindow.
+ if (renderStyle == RenderDirectlyToHostWindow)
+ return 0;
+ OwnPtr<GraphicsContext3D> context(new GraphicsContext3D(attrs, hostWindow, false));
+ return context->m_internal ? context.release() : 0;
+}
+
+GraphicsContext3D::GraphicsContext3D(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow, bool)
+ : 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::paintRenderingResultsToCanvas(CanvasRenderingContext* context)
+{
+ m_internal->m_glWidget->makeCurrent();
+ HTMLCanvasElement* canvas = context->canvas();
+ ImageBuffer* imageBuffer = canvas->buffer();
+ QPainter* painter = imageBuffer->context()->platformContext();
+ paint(painter, QRect(QPoint(0, 0), QSize(m_currentWidth, m_currentHeight)));
+}
+
+void GraphicsContext3D::paint(QPainter* painter, const QRect& rect) const
+{
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ QWebPageClient* webPageClient = m_internal->m_hostWindow->platformPageClient();
+ QGLWidget* ownerGLWidget = m_internal->getOwnerGLWidget(webPageClient);
+ if (ownerGLWidget) {
+ ownerGLWidget->drawTexture(rect, m_internal->m_texture);
+ return;
+ }
+#endif
+ m_internal->m_glWidget->makeCurrent();
+ 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());
+ painter->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.rgbSwapped().transformed(QMatrix().rotate(180)));
+ m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo);
+}
+
+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();
+}
+
+IntSize GraphicsContext3D::getInternalFramebufferSize()
+{
+ return IntSize(m_currentWidth, m_currentHeight);
+}
+
+void GraphicsContext3D::activeTexture(GC3Denum texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->activeTexture(texture);
+}
+
+void GraphicsContext3D::attachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->attachShader(program, shader);
+}
+
+void GraphicsContext3D::getAttachedShaders(Platform3DObject program, GC3Dsizei maxCount, GC3Dsizei* count, Platform3DObject* shaders)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+ getAttachedShaders(program, maxCount, count, shaders);
+}
+
+void GraphicsContext3D::bindAttribLocation(Platform3DObject program, GC3Duint index, const String& name)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindAttribLocation(program, index, name.utf8().data());
+}
+
+void GraphicsContext3D::bindBuffer(GC3Denum target, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindBuffer(target, buffer);
+}
+
+void GraphicsContext3D::bindFramebuffer(GC3Denum target, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->m_currentFbo = buffer ? buffer : m_internal->m_mainFbo;
+ m_internal->bindFramebuffer(target, m_internal->m_currentFbo);
+}
+
+void GraphicsContext3D::bindRenderbuffer(GC3Denum target, Platform3DObject renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bindRenderbuffer(target, renderbuffer);
+}
+
+void GraphicsContext3D::bindTexture(GC3Denum target, Platform3DObject texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBindTexture(target, texture);
+}
+
+void GraphicsContext3D::blendColor(GC3Dclampf red, GC3Dclampf green, GC3Dclampf blue, GC3Dclampf alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendColor(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::blendEquation(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquation(mode);
+}
+
+void GraphicsContext3D::blendEquationSeparate(GC3Denum modeRGB, GC3Denum modeAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendEquationSeparate(modeRGB, modeAlpha);
+}
+
+void GraphicsContext3D::blendFunc(GC3Denum sfactor, GC3Denum dfactor)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glBlendFunc(sfactor, dfactor);
+}
+
+void GraphicsContext3D::blendFuncSeparate(GC3Denum srcRGB, GC3Denum dstRGB, GC3Denum srcAlpha, GC3Denum dstAlpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->blendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, GC3Denum usage)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, size, /* data */ 0, usage);
+}
+
+void GraphicsContext3D::bufferData(GC3Denum target, GC3Dsizeiptr size, const void* data, GC3Denum usage)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferData(target, size, data, usage);
+}
+
+void GraphicsContext3D::bufferSubData(GC3Denum target, GC3Dintptr offset, GC3Dsizeiptr size, const void* data)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->bufferSubData(target, offset, size, data);
+}
+
+GC3Denum GraphicsContext3D::checkFramebufferStatus(GC3Denum target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->checkFramebufferStatus(target);
+}
+
+void GraphicsContext3D::clearColor(GC3Dclampf r, GC3Dclampf g, GC3Dclampf b, GC3Dclampf a)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearColor(r, g, b, a);
+}
+
+void GraphicsContext3D::clear(GC3Dbitfield mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClear(mask);
+}
+
+void GraphicsContext3D::clearDepth(GC3Dclampf depth)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glClearDepthf(depth);
+#else
+ glClearDepth(depth);
+#endif
+}
+
+void GraphicsContext3D::clearStencil(GC3Dint s)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glClearStencil(s);
+}
+
+void GraphicsContext3D::colorMask(GC3Dboolean red, GC3Dboolean green, GC3Dboolean blue, GC3Dboolean alpha)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glColorMask(red, green, blue, alpha);
+}
+
+void GraphicsContext3D::compileShader(Platform3DObject shader)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->compileShader(shader);
+}
+
+void GraphicsContext3D::copyTexImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Dint border)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+}
+
+void GraphicsContext3D::copyTexSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoffset, GC3Dint yoffset, GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+void GraphicsContext3D::cullFace(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glCullFace(mode);
+}
+
+void GraphicsContext3D::depthFunc(GC3Denum func)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthFunc(func);
+}
+
+void GraphicsContext3D::depthMask(GC3Dboolean flag)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDepthMask(flag);
+}
+
+void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar)
+{
+ m_internal->m_glWidget->makeCurrent();
+#if defined(QT_OPENGL_ES_2)
+ glDepthRangef(zNear, zFar);
+#else
+ glDepthRange(zNear, zFar);
+#endif
+}
+
+void GraphicsContext3D::detachShader(Platform3DObject program, Platform3DObject shader)
+{
+ ASSERT(program);
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->detachShader(program, shader);
+}
+
+void GraphicsContext3D::disable(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDisable(cap);
+}
+
+void GraphicsContext3D::disableVertexAttribArray(GC3Duint index)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->disableVertexAttribArray(index);
+}
+
+void GraphicsContext3D::drawArrays(GC3Denum mode, GC3Dint first, GC3Dsizei count)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawArrays(mode, first, count);
+}
+
+void GraphicsContext3D::drawElements(GC3Denum mode, GC3Dsizei count, GC3Denum type, GC3Dintptr offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDrawElements(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::enable(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glEnable(cap);
+}
+
+void GraphicsContext3D::enableVertexAttribArray(GC3Duint 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(GC3Denum target, GC3Denum attachment, GC3Denum renderbuffertarget, Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferRenderbuffer(target, attachment, renderbuffertarget, buffer);
+}
+
+void GraphicsContext3D::framebufferTexture2D(GC3Denum target, GC3Denum attachment, GC3Denum textarget, Platform3DObject texture, GC3Dint level)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->framebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void GraphicsContext3D::frontFace(GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glFrontFace(mode);
+}
+
+void GraphicsContext3D::generateMipmap(GC3Denum target)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->generateMipmap(target);
+}
+
+bool GraphicsContext3D::getActiveAttrib(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength = 0;
+ m_internal->getProgramiv(program, GraphicsContext3D::ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+
+ m_internal->getActiveAttrib(program, 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(Platform3DObject program, GC3Duint index, ActiveInfo& info)
+{
+ if (!program) {
+ synthesizeGLError(INVALID_VALUE);
+ return false;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint maxLength = 0;
+ m_internal->getProgramiv(static_cast<GLuint>(program), GraphicsContext3D::ACTIVE_UNIFORM_MAX_LENGTH, &maxLength);
+
+ GLchar* name = (GLchar*) fastMalloc(maxLength);
+ GLsizei nameLength = 0;
+ GLint size = 0;
+ GLenum type = 0;
+
+ m_internal->getActiveUniform(static_cast<GLuint>(program), 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(Platform3DObject program, const String& name)
+{
+ if (!program)
+ return -1;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getAttribLocation(program, name.utf8().data());
+}
+
+GraphicsContext3D::Attributes GraphicsContext3D::getContextAttributes()
+{
+ return m_internal->m_attrs;
+}
+
+GC3Denum GraphicsContext3D::getError()
+{
+ if (m_internal->m_syntheticErrors.size() > 0) {
+ ListHashSet<GC3Denum>::iterator iter = m_internal->m_syntheticErrors.begin();
+ GC3Denum err = *iter;
+ m_internal->m_syntheticErrors.remove(iter);
+ return err;
+ }
+
+ m_internal->m_glWidget->makeCurrent();
+ return glGetError();
+}
+
+String GraphicsContext3D::getString(GC3Denum name)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return String((const char*) glGetString(name));
+}
+
+void GraphicsContext3D::hint(GC3Denum target, GC3Denum mode)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glHint(target, mode);
+}
+
+GC3Dboolean GraphicsContext3D::isBuffer(Platform3DObject buffer)
+{
+ if (!buffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isBuffer(buffer);
+}
+
+GC3Dboolean GraphicsContext3D::isEnabled(GC3Denum cap)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return glIsEnabled(cap);
+}
+
+GC3Dboolean GraphicsContext3D::isFramebuffer(Platform3DObject framebuffer)
+{
+ if (!framebuffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isFramebuffer(framebuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isProgram(Platform3DObject program)
+{
+ if (!program)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isProgram(program);
+}
+
+GC3Dboolean GraphicsContext3D::isRenderbuffer(Platform3DObject renderbuffer)
+{
+ if (!renderbuffer)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isRenderbuffer(renderbuffer);
+}
+
+GC3Dboolean GraphicsContext3D::isShader(Platform3DObject shader)
+{
+ if (!shader)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->isShader(shader);
+}
+
+GC3Dboolean GraphicsContext3D::isTexture(Platform3DObject texture)
+{
+ if (!texture)
+ return GL_FALSE;
+
+ m_internal->m_glWidget->makeCurrent();
+ return glIsTexture(texture);
+}
+
+void GraphicsContext3D::lineWidth(double width)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glLineWidth(static_cast<float>(width));
+}
+
+void GraphicsContext3D::linkProgram(Platform3DObject program)
+{
+ ASSERT(program);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->linkProgram(program);
+}
+
+void GraphicsContext3D::pixelStorei(GC3Denum paramName, GC3Dint param)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPixelStorei(paramName, param);
+}
+
+void GraphicsContext3D::polygonOffset(GC3Dfloat factor, GC3Dfloat units)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glPolygonOffset(factor, units);
+}
+
+void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ if (type != GraphicsContext3D::UNSIGNED_BYTE || format != GraphicsContext3D::RGBA)
+ return;
+
+ glReadPixels(x, y, width, height, format, type, data);
+}
+
+void GraphicsContext3D::releaseShaderCompiler()
+{
+ m_internal->m_glWidget->makeCurrent();
+ notImplemented();
+}
+
+void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->renderbufferStorage(target, internalformat, width, height);
+}
+
+void GraphicsContext3D::sampleCoverage(GC3Dclampf value, GC3Dboolean invert)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->sampleCoverage(value, invert);
+}
+
+void GraphicsContext3D::scissor(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glScissor(x, y, width, height);
+}
+
+void GraphicsContext3D::shaderSource(Platform3DObject shader, const String& source)
+{
+ ASSERT(shader);
+
+ m_internal->m_glWidget->makeCurrent();
+
+ String prefixedSource;
+
+#if defined (QT_OPENGL_ES_2)
+ prefixedSource.append("precision mediump float;\n");
+#endif
+
+ prefixedSource.append(source);
+
+ CString sourceCS = prefixedSource.utf8();
+ const char* data = sourceCS.data();
+ int length = prefixedSource.length();
+ m_internal->shaderSource((GLuint) shader, /* count */ 1, &data, &length);
+}
+
+void GraphicsContext3D::stencilFunc(GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilFunc(func, ref, mask);
+}
+
+void GraphicsContext3D::stencilFuncSeparate(GC3Denum face, GC3Denum func, GC3Dint ref, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilFuncSeparate(face, func, ref, mask);
+}
+
+void GraphicsContext3D::stencilMask(GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilMask(mask);
+}
+
+void GraphicsContext3D::stencilMaskSeparate(GC3Denum face, GC3Duint mask)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilMaskSeparate(face, mask);
+}
+
+void GraphicsContext3D::stencilOp(GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glStencilOp(fail, zfail, zpass);
+}
+
+void GraphicsContext3D::stencilOpSeparate(GC3Denum face, GC3Denum fail, GC3Denum zfail, GC3Denum zpass)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->stencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void GraphicsContext3D::texParameterf(GC3Denum target, GC3Denum paramName, GC3Dfloat value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameterf(target, paramName, value);
+}
+
+void GraphicsContext3D::texParameteri(GC3Denum target, GC3Denum paramName, GC3Dint value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexParameteri(target, paramName, value);
+}
+
+void GraphicsContext3D::uniform1f(GC3Dint location, GC3Dfloat v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1f(location, v0);
+}
+
+void GraphicsContext3D::uniform1fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2f(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3f(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4f(GC3Dint location, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4f(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4fv(GC3Dint location, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4fv(location, size, array);
+}
+
+void GraphicsContext3D::uniform1i(GC3Dint location, GC3Dint v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1i(location, v0);
+}
+
+void GraphicsContext3D::uniform1iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform1iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform2i(GC3Dint location, GC3Dint v0, GC3Dint v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2i(location, v0, v1);
+}
+
+void GraphicsContext3D::uniform2iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform2iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform3i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3i(location, v0, v1, v2);
+}
+
+void GraphicsContext3D::uniform3iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform3iv(location, size, array);
+}
+
+void GraphicsContext3D::uniform4i(GC3Dint location, GC3Dint v0, GC3Dint v1, GC3Dint v2, GC3Dint v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4i(location, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::uniform4iv(GC3Dint location, GC3Dint* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniform4iv(location, size, array);
+}
+
+void GraphicsContext3D::uniformMatrix2fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix2fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix3fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix3fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::uniformMatrix4fv(GC3Dint location, GC3Dboolean transpose, GC3Dfloat* array, GC3Dsizei size)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->uniformMatrix4fv(location, size, transpose, array);
+}
+
+void GraphicsContext3D::useProgram(Platform3DObject program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->useProgram(program);
+}
+
+void GraphicsContext3D::validateProgram(Platform3DObject program)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->validateProgram(program);
+}
+
+void GraphicsContext3D::vertexAttrib1f(GC3Duint index, GC3Dfloat v0)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1f(index, v0);
+}
+
+void GraphicsContext3D::vertexAttrib1fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib1fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib2f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2f(index, v0, v1);
+}
+
+void GraphicsContext3D::vertexAttrib2fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib2fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib3f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3f(index, v0, v1, v2);
+}
+
+void GraphicsContext3D::vertexAttrib3fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib3fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttrib4f(GC3Duint index, GC3Dfloat v0, GC3Dfloat v1, GC3Dfloat v2, GC3Dfloat v3)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4f(index, v0, v1, v2, v3);
+}
+
+void GraphicsContext3D::vertexAttrib4fv(GC3Duint index, GC3Dfloat* array)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttrib4fv(index, array);
+}
+
+void GraphicsContext3D::vertexAttribPointer(GC3Duint index, GC3Dint size, GC3Denum type, GC3Dboolean normalized, GC3Dsizei stride, GC3Dintptr offset)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->vertexAttribPointer(index, size, type, normalized, stride, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)));
+}
+
+void GraphicsContext3D::viewport(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glViewport(x, y, width, height);
+}
+
+void GraphicsContext3D::getBooleanv(GC3Denum paramName, GC3Dboolean* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetBooleanv(paramName, value);
+}
+
+void GraphicsContext3D::getBufferParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getBufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getFloatv(GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetFloatv(paramName, value);
+}
+
+void GraphicsContext3D::getFramebufferAttachmentParameteriv(GC3Denum target, GC3Denum attachment, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getFramebufferAttachmentParameteriv(target, attachment, paramName, value);
+}
+
+void GraphicsContext3D::getIntegerv(GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetIntegerv(paramName, value);
+}
+
+void GraphicsContext3D::getProgramiv(Platform3DObject program, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getProgramiv(program, paramName, value);
+}
+
+String GraphicsContext3D::getProgramInfoLog(Platform3DObject program)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getProgramiv(program, GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size = 0;
+
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getProgramInfoLog(program, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getRenderbufferParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getRenderbufferParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getShaderiv(Platform3DObject shader, GC3Denum paramName, GC3Dint* value)
+{
+ ASSERT(shader);
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getShaderiv(shader, paramName, value);
+}
+
+String GraphicsContext3D::getShaderInfoLog(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getShaderiv(shader, GraphicsContext3D::INFO_LOG_LENGTH, &length);
+
+ GLsizei size = 0;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderInfoLog(shader, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+String GraphicsContext3D::getShaderSource(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLint length = 0;
+ m_internal->getShaderiv(shader, GraphicsContext3D::SHADER_SOURCE_LENGTH, &length);
+
+ GLsizei size = 0;
+ GLchar* info = (GLchar*) fastMalloc(length);
+ if (!info)
+ return "";
+
+ m_internal->getShaderSource(shader, length, &size, info);
+
+ String result(info);
+ fastFree(info);
+
+ return result;
+}
+
+void GraphicsContext3D::getTexParameterfv(GC3Denum target, GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameterfv(target, paramName, value);
+}
+
+void GraphicsContext3D::getTexParameteriv(GC3Denum target, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glGetTexParameteriv(target, paramName, value);
+}
+
+void GraphicsContext3D::getUniformfv(Platform3DObject program, GC3Dint location, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformfv(program, location, value);
+}
+
+void GraphicsContext3D::getUniformiv(Platform3DObject program, GC3Dint location, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getUniformiv(program, location, value);
+}
+
+long GraphicsContext3D::getUniformLocation(Platform3DObject program, const String& name)
+{
+ ASSERT(program);
+
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->getUniformLocation(program, name.utf8().data());
+}
+
+void GraphicsContext3D::getVertexAttribfv(GC3Duint index, GC3Denum paramName, GC3Dfloat* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribfv(index, paramName, value);
+}
+
+void GraphicsContext3D::getVertexAttribiv(GC3Duint index, GC3Denum paramName, GC3Dint* value)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->getVertexAttribiv(index, paramName, value);
+}
+
+GC3Dsizeiptr GraphicsContext3D::getVertexAttribOffset(GC3Duint index, GC3Denum paramName)
+{
+ m_internal->m_glWidget->makeCurrent();
+
+ GLvoid* pointer = 0;
+ m_internal->getVertexAttribPointerv(index, paramName, &pointer);
+ return static_cast<GC3Dsizeiptr>(reinterpret_cast<intptr_t>(pointer));
+}
+
+bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+ return true;
+}
+
+void GraphicsContext3D::texSubImage2D(GC3Denum target, GC3Dint level, GC3Dint xoff, GC3Dint yoff, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, const void* pixels)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
+}
+
+Platform3DObject GraphicsContext3D::createBuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genBuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createFramebuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genFramebuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createProgram()
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createProgram();
+}
+
+Platform3DObject GraphicsContext3D::createRenderbuffer()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ m_internal->genRenderbuffers(/* count */ 1, &handle);
+ return handle;
+}
+
+Platform3DObject GraphicsContext3D::createShader(GC3Denum type)
+{
+ m_internal->m_glWidget->makeCurrent();
+ return m_internal->createShader(type);
+}
+
+Platform3DObject GraphicsContext3D::createTexture()
+{
+ m_internal->m_glWidget->makeCurrent();
+ GLuint handle = 0;
+ glGenTextures(1, &handle);
+ return handle;
+}
+
+void GraphicsContext3D::deleteBuffer(Platform3DObject buffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteBuffers(1, &buffer);
+}
+
+void GraphicsContext3D::deleteFramebuffer(Platform3DObject framebuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteFramebuffers(1, &framebuffer);
+}
+
+void GraphicsContext3D::deleteProgram(Platform3DObject program)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteProgram(program);
+}
+
+void GraphicsContext3D::deleteRenderbuffer(Platform3DObject renderbuffer)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteRenderbuffers(1, &renderbuffer);
+}
+
+void GraphicsContext3D::deleteShader(Platform3DObject shader)
+{
+ m_internal->m_glWidget->makeCurrent();
+ m_internal->deleteShader(shader);
+}
+
+void GraphicsContext3D::deleteTexture(Platform3DObject texture)
+{
+ m_internal->m_glWidget->makeCurrent();
+ glDeleteTextures(1, &texture);
+}
+
+unsigned int GraphicsContext3D::sizeInBytes(GC3Denum 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(GC3Denum error)
+{
+ m_internal->m_syntheticErrors.add(error);
+}
+
+Extensions3D* GraphicsContext3D::getExtensions()
+{
+ if (!m_internal->m_extensions)
+ m_internal->m_extensions = adoptPtr(new Extensions3DQt);
+ return m_internal->m_extensions;
+}
+
+bool GraphicsContext3D::getImageData(Image* image,
+ GC3Denum format,
+ GC3Denum type,
+ bool premultiplyAlpha,
+ bool ignoreGammaAndColorProfile,
+ Vector<uint8_t>& outputVector)
+{
+ UNUSED_PARAM(ignoreGammaAndColorProfile);
+ if (!image)
+ return false;
+ QPixmap* nativePixmap = image->nativeImageForCurrentFrame();
+ if (!nativePixmap)
+ return false;
+
+ AlphaOp neededAlphaOp = kAlphaDoNothing;
+ if (!premultiplyAlpha)
+ // FIXME: must fetch the image data before the premultiplication step
+ neededAlphaOp = kAlphaDoUnmultiply;
+ QImage nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32);
+ outputVector.resize(nativeImage.byteCount());
+ return packPixels(nativeImage.rgbSwapped().bits(), kSourceFormatRGBA8, image->width(), image->height(), 0,
+ format, type, neededAlphaOp, outputVector.data());
+}
+
+}
+
+#endif // ENABLE(3D_CANVAS)
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
new file mode 100644
index 0000000..e237fc0
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -0,0 +1,1370 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ * Copyright (C) 2010 Sencha, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GraphicsContext.h"
+
+#ifdef Q_WS_WIN
+#include <windows.h>
+#endif
+
+#include "AffineTransform.h"
+#include "Color.h"
+#include "ContextShadow.h"
+#include "FloatConversion.h"
+#include "Font.h"
+#include "ImageBuffer.h"
+#include "NotImplemented.h"
+#include "Path.h"
+#include "Pattern.h"
+#include "TransparencyLayer.h"
+
+#include <QBrush>
+#include <QGradient>
+#include <QPaintDevice>
+#include <QPaintEngine>
+#include <QPainter>
+#include <QPainterPath>
+#include <QPixmap>
+#include <QPolygonF>
+#include <QStack>
+#include <QVector>
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+QPainter::CompositionMode GraphicsContext::toQtCompositionMode(CompositeOperator op)
+{
+ switch (op) {
+ case CompositeClear:
+ return QPainter::CompositionMode_Clear;
+ case CompositeCopy:
+ return QPainter::CompositionMode_Source;
+ case CompositeSourceOver:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositeSourceIn:
+ return QPainter::CompositionMode_SourceIn;
+ case CompositeSourceOut:
+ return QPainter::CompositionMode_SourceOut;
+ case CompositeSourceAtop:
+ return QPainter::CompositionMode_SourceAtop;
+ case CompositeDestinationOver:
+ return QPainter::CompositionMode_DestinationOver;
+ case CompositeDestinationIn:
+ return QPainter::CompositionMode_DestinationIn;
+ case CompositeDestinationOut:
+ return QPainter::CompositionMode_DestinationOut;
+ case CompositeDestinationAtop:
+ return QPainter::CompositionMode_DestinationAtop;
+ case CompositeXOR:
+ return QPainter::CompositionMode_Xor;
+ case CompositePlusDarker:
+ // there is no exact match, but this is the closest
+ return QPainter::CompositionMode_Darken;
+ case CompositeHighlight:
+ return QPainter::CompositionMode_SourceOver;
+ case CompositePlusLighter:
+ return QPainter::CompositionMode_Plus;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return QPainter::CompositionMode_SourceOver;
+}
+
+static inline Qt::PenCapStyle toQtLineCap(LineCap lc)
+{
+ switch (lc) {
+ case ButtCap:
+ return Qt::FlatCap;
+ case RoundCap:
+ return Qt::RoundCap;
+ case SquareCap:
+ return Qt::SquareCap;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return Qt::FlatCap;
+}
+
+static inline Qt::PenJoinStyle toQtLineJoin(LineJoin lj)
+{
+ switch (lj) {
+ case MiterJoin:
+ return Qt::SvgMiterJoin;
+ case RoundJoin:
+ return Qt::RoundJoin;
+ case BevelJoin:
+ return Qt::BevelJoin;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+
+ return Qt::SvgMiterJoin;
+}
+
+static Qt::PenStyle toQPenStyle(StrokeStyle style)
+{
+ switch (style) {
+ case NoStroke:
+ return Qt::NoPen;
+ break;
+ case SolidStroke:
+ return Qt::SolidLine;
+ break;
+ case DottedStroke:
+ return Qt::DotLine;
+ break;
+ case DashedStroke:
+ return Qt::DashLine;
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return Qt::NoPen;
+}
+
+static inline Qt::FillRule toQtFillRule(WindRule rule)
+{
+ switch (rule) {
+ case RULE_EVENODD:
+ return Qt::OddEvenFill;
+ case RULE_NONZERO:
+ return Qt::WindingFill;
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ return Qt::OddEvenFill;
+}
+
+class GraphicsContextPlatformPrivate : public Noncopyable {
+public:
+ GraphicsContextPlatformPrivate(QPainter*, const QColor& initialSolidColor);
+ ~GraphicsContextPlatformPrivate();
+
+ inline QPainter* p() const
+ {
+ if (layers.isEmpty())
+ return painter;
+ return &layers.top()->painter;
+ }
+
+ bool antiAliasingForRectsAndLines;
+
+ QStack<TransparencyLayer*> layers;
+ // Counting real layers. Required by inTransparencyLayer() calls
+ // For example, layers with valid alphaMask are not real layers
+ int layerCount;
+
+ // reuse this brush for solid color (to prevent expensive QBrush construction)
+ QBrush solidColor;
+
+ InterpolationQuality imageInterpolationQuality;
+ bool initialSmoothPixmapTransformHint;
+
+ ContextShadow shadow;
+ QStack<ContextShadow> shadowStack;
+
+ QRectF clipBoundingRect() const
+ {
+#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
+ return p()->clipBoundingRect();
+#else
+ return p()->clipRegion().boundingRect();
+#endif
+ }
+
+ void takeOwnershipOfPlatformContext() { platformContextIsOwned = true; }
+
+private:
+ QPainter* painter;
+ bool platformContextIsOwned;
+};
+
+GraphicsContextPlatformPrivate::GraphicsContextPlatformPrivate(QPainter* p, const QColor& initialSolidColor)
+ : antiAliasingForRectsAndLines(false)
+ , layerCount(0)
+ , solidColor(initialSolidColor)
+ , imageInterpolationQuality(InterpolationDefault)
+ , initialSmoothPixmapTransformHint(false)
+ , painter(p)
+ , platformContextIsOwned(false)
+{
+ if (!painter)
+ return;
+
+ // Use the default the QPainter was constructed with.
+ antiAliasingForRectsAndLines = painter->testRenderHint(QPainter::Antialiasing);
+
+ // Used for default image interpolation quality.
+ initialSmoothPixmapTransformHint = painter->testRenderHint(QPainter::SmoothPixmapTransform);
+
+ painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+GraphicsContextPlatformPrivate::~GraphicsContextPlatformPrivate()
+{
+ if (!platformContextIsOwned)
+ return;
+
+ QPaintDevice* device = painter->device();
+ painter->end();
+ delete painter;
+ delete device;
+}
+
+void GraphicsContext::platformInit(PlatformGraphicsContext* painter)
+{
+ m_data = new GraphicsContextPlatformPrivate(painter, fillColor());
+
+ setPaintingDisabled(!painter);
+
+ if (!painter)
+ return;
+
+ // solidColor is initialized with the fillColor().
+ painter->setBrush(m_data->solidColor);
+
+ QPen pen(painter->pen());
+ pen.setColor(strokeColor());
+ pen.setJoinStyle(toQtLineJoin(MiterJoin));
+ painter->setPen(pen);
+}
+
+void GraphicsContext::platformDestroy()
+{
+ while (!m_data->layers.isEmpty())
+ endTransparencyLayer();
+
+ delete m_data;
+}
+
+PlatformGraphicsContext* GraphicsContext::platformContext() const
+{
+ return m_data->p();
+}
+
+AffineTransform GraphicsContext::getCTM() const
+{
+ const QTransform& matrix = platformContext()->combinedTransform();
+ return AffineTransform(matrix.m11(), matrix.m12(), matrix.m21(),
+ matrix.m22(), matrix.dx(), matrix.dy());
+}
+
+void GraphicsContext::savePlatformState()
+{
+ if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+ ++m_data->layers.top()->saveCounter;
+ m_data->p()->save();
+ m_data->shadowStack.push(m_data->shadow);
+}
+
+void GraphicsContext::restorePlatformState()
+{
+ if (!m_data->layers.isEmpty() && !m_data->layers.top()->alphaMask.isNull())
+ if (!--m_data->layers.top()->saveCounter)
+ endTransparencyLayer();
+
+ m_data->p()->restore();
+
+ if (m_data->shadowStack.isEmpty())
+ m_data->shadow = ContextShadow();
+ else
+ m_data->shadow = m_data->shadowStack.pop();
+}
+
+// Draws a filled rectangle with a stroked border.
+// This is only used to draw borders (real fill is done via fillRect), and
+// thus it must not cast any shadow.
+void GraphicsContext::drawRect(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+
+ p->drawRect(rect);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// This is only used to draw borders.
+// Must not cast any shadow.
+void GraphicsContext::drawLine(const IntPoint& point1, const IntPoint& point2)
+{
+ if (paintingDisabled())
+ return;
+
+ StrokeStyle style = strokeStyle();
+ Color color = strokeColor();
+ if (style == NoStroke)
+ return;
+
+ float width = strokeThickness();
+
+ FloatPoint p1 = point1;
+ FloatPoint p2 = point2;
+ bool isVerticalLine = (p1.x() == p2.x());
+
+ QPainter* p = m_data->p();
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
+ adjustLineToPixelBoundaries(p1, p2, width, style);
+
+ int patWidth = 0;
+ switch (style) {
+ case NoStroke:
+ case SolidStroke:
+ break;
+ case DottedStroke:
+ patWidth = static_cast<int>(width);
+ break;
+ case DashedStroke:
+ patWidth = 3 * static_cast<int>(width);
+ break;
+ }
+
+ if (patWidth) {
+ p->save();
+
+ // Do a rect fill of our endpoints. This ensures we always have the
+ // appearance of being a border. We then draw the actual dotted/dashed line.
+ if (isVerticalLine) {
+ p->fillRect(FloatRect(p1.x() - width / 2, p1.y() - width, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x() - width / 2, p2.y(), width, width), QColor(color));
+ } else {
+ p->fillRect(FloatRect(p1.x() - width, p1.y() - width / 2, width, width), QColor(color));
+ p->fillRect(FloatRect(p2.x(), p2.y() - width / 2, width, width), QColor(color));
+ }
+
+ // Example: 80 pixels with a width of 30 pixels.
+ // Remainder is 20. The maximum pixels of line we could paint
+ // will be 50 pixels.
+ int distance = (isVerticalLine ? (point2.y() - point1.y()) : (point2.x() - point1.x())) - 2*(int)width;
+ int remainder = distance % patWidth;
+ int coverage = distance - remainder;
+ int numSegments = coverage / patWidth;
+
+ float patternOffset = 0.0f;
+ // Special case 1px dotted borders for speed.
+ if (patWidth == 1)
+ patternOffset = 1.0f;
+ else {
+ bool evenNumberOfSegments = !(numSegments % 2);
+ if (remainder)
+ evenNumberOfSegments = !evenNumberOfSegments;
+ if (evenNumberOfSegments) {
+ if (remainder) {
+ patternOffset += patWidth - remainder;
+ patternOffset += remainder / 2;
+ } else
+ patternOffset = patWidth / 2;
+ } else {
+ if (remainder)
+ patternOffset = (patWidth - remainder) / 2;
+ }
+ }
+
+ QVector<qreal> dashes;
+ dashes << qreal(patWidth) / width << qreal(patWidth) / width;
+
+ QPen pen = p->pen();
+ pen.setWidthF(width);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setDashPattern(dashes);
+ pen.setDashOffset(patternOffset / width);
+ p->setPen(pen);
+ }
+
+ p->drawLine(p1, p2);
+
+ if (patWidth)
+ p->restore();
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+// This method is only used to draw the little circles used in lists.
+void GraphicsContext::drawEllipse(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->drawEllipse(rect);
+}
+
+void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias)
+{
+ if (paintingDisabled())
+ return;
+
+ if (npoints <= 1)
+ return;
+
+ QPolygonF polygon(npoints);
+
+ for (size_t i = 0; i < npoints; i++)
+ polygon[i] = points[i];
+
+ QPainter* p = m_data->p();
+
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, shouldAntialias);
+
+ p->drawConvexPolygon(polygon);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::clipConvexPolygon(size_t numPoints, const FloatPoint* points, bool antialiased)
+{
+ if (paintingDisabled())
+ return;
+
+ if (numPoints <= 1)
+ return;
+
+ QPainterPath path(points[0]);
+ for (size_t i = 1; i < numPoints; ++i)
+ path.lineTo(points[i]);
+ path.setFillRule(Qt::WindingFill);
+
+ QPainter* p = m_data->p();
+
+ bool painterWasAntialiased = p->testRenderHint(QPainter::Antialiasing);
+
+ if (painterWasAntialiased != antialiased)
+ p->setRenderHint(QPainter::Antialiasing, antialiased);
+
+ p->setClipPath(path, Qt::IntersectClip);
+
+ if (painterWasAntialiased != antialiased)
+ p->setRenderHint(QPainter::Antialiasing, painterWasAntialiased);
+}
+
+void GraphicsContext::fillPath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(toQtFillRule(fillRule()));
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this) || m_state.fillPattern || m_state.fillGradient)
+ {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, platformPath.controlPointRect());
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillPath(platformPath, QColor(m_data->shadow.m_color));
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ QPointF offset = shadow->offset();
+ p->translate(offset);
+ p->fillPath(platformPath, QColor(shadow->m_color));
+ p->translate(-offset);
+ }
+ }
+ if (m_state.fillPattern) {
+ AffineTransform affine;
+ p->fillPath(platformPath, QBrush(m_state.fillPattern->createPlatformPattern(affine)));
+ } else if (m_state.fillGradient) {
+ QBrush brush(*m_state.fillGradient->platformGradient());
+ brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
+ p->fillPath(platformPath, brush);
+ } else
+ p->fillPath(platformPath, p->brush());
+}
+
+void GraphicsContext::strokePath(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen pen(p->pen());
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(toQtFillRule(fillRule()));
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this) || m_state.strokePattern || m_state.strokeGradient)
+ {
+ FloatRect boundingRect = platformPath.controlPointRect();
+ boundingRect.inflate(pen.miterLimit() + pen.widthF());
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, boundingRect);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(m_data->shadow.m_color.alpha()) / 255);
+ shadowPainter->strokePath(platformPath, pen);
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ QPen shadowPen(pen);
+ shadowPen.setColor(m_data->shadow.m_color);
+ QPointF offset = shadow->offset();
+ p->translate(offset);
+ p->strokePath(platformPath, shadowPen);
+ p->translate(-offset);
+ }
+ }
+
+ if (m_state.strokePattern) {
+ AffineTransform affine;
+ pen.setBrush(QBrush(m_state.strokePattern->createPlatformPattern(affine)));
+ p->setPen(pen);
+ p->strokePath(platformPath, pen);
+ } else if (m_state.strokeGradient) {
+ QBrush brush(*m_state.strokeGradient->platformGradient());
+ brush.setTransform(m_state.strokeGradient->gradientSpaceTransform());
+ pen.setBrush(brush);
+ p->setPen(pen);
+ p->strokePath(platformPath, pen);
+ } else
+ p->strokePath(platformPath, pen);
+}
+
+static inline void drawRepeatPattern(QPainter* p, QPixmap* image, const FloatRect& rect, const bool repeatX, const bool repeatY)
+{
+ // Patterns must be painted so that the top left of the first image is anchored at
+ // the origin of the coordinate space
+ if (image) {
+ int w = image->width();
+ int h = image->height();
+ int startX, startY;
+ QRect r(static_cast<int>(rect.x()), static_cast<int>(rect.y()), static_cast<int>(rect.width()), static_cast<int>(rect.height()));
+
+ // startX, startY is the coordinate of the first image we need to put on the left-top of the rect
+ if (repeatX && repeatY) {
+ // repeat
+ // startX, startY is at the left top side of the left-top of the rect
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else {
+ if (!repeatX && !repeatY) {
+ // no-repeat
+ // only draw the image once at orgin once, check if need to draw
+ QRect imageRect(0, 0, w, h);
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = 0;
+ } else
+ return;
+ } else if (repeatX && !repeatY) {
+ // repeat-x
+ // startY is fixed, but startX change based on the left-top of the rect
+ QRect imageRect(r.x(), 0, r.width(), h);
+ if (imageRect.intersects(r)) {
+ startX = r.x() >=0 ? r.x() - (r.x() % w) : r.x() - (w - qAbs(r.x()) % w);
+ startY = 0;
+ } else
+ return;
+ } else {
+ // repeat-y
+ // startX is fixed, but startY change based on the left-top of the rect
+ QRect imageRect(0, r.y(), w, r.height());
+ if (imageRect.intersects(r)) {
+ startX = 0;
+ startY = r.y() >=0 ? r.y() - (r.y() % h) : r.y() - (h - qAbs(r.y()) % h);
+ } else
+ return;
+ }
+ }
+
+ int x = startX;
+ int y = startY;
+ do {
+ // repeat Y
+ do {
+ // repeat X
+ QRect imageRect(x, y, w, h);
+ QRect intersectRect = imageRect.intersected(r);
+ QPoint destStart(intersectRect.x(), intersectRect.y());
+ QRect sourceRect(intersectRect.x() - imageRect.x(), intersectRect.y() - imageRect.y(), intersectRect.width(), intersectRect.height());
+
+ p->drawPixmap(destStart, *image, sourceRect);
+ x += w;
+ } while (repeatX && x < r.x() + r.width());
+ x = startX;
+ y += h;
+ } while (repeatY && y < r.y() + r.height());
+ }
+}
+
+void GraphicsContext::fillRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QRectF normalizedRect = rect.normalized();
+ ContextShadow* shadow = contextShadow();
+
+ if (m_state.fillPattern) {
+ AffineTransform affine;
+ QBrush brush(m_state.fillPattern->createPlatformPattern(affine));
+ QPixmap* image = m_state.fillPattern->tileImage()->nativeImageForCurrentFrame();
+ QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
+ if (shadowPainter) {
+ drawRepeatPattern(shadowPainter, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ drawRepeatPattern(p, image, normalizedRect, m_state.fillPattern->repeatX(), m_state.fillPattern->repeatY());
+ } else if (m_state.fillGradient) {
+ QBrush brush(*m_state.fillGradient->platformGradient());
+ brush.setTransform(m_state.fillGradient->gradientSpaceTransform());
+ QPainter* shadowPainter = hasShadow() ? shadow->beginShadowLayer(this, normalizedRect) : 0;
+ if (shadowPainter) {
+ shadowPainter->fillRect(normalizedRect, brush);
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_SourceIn);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ p->fillRect(normalizedRect, brush);
+ } else {
+ if (hasShadow()) {
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->fillRect(normalizedRect, p->brush());
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ // Solid rectangle fill with no blur shadow or transformations applied can be done
+ // faster without using the shadow layer at all.
+ QColor shadowColor = shadow->m_color;
+ shadowColor.setAlphaF(shadowColor.alphaF() * p->brush().color().alphaF());
+ p->fillRect(normalizedRect.translated(shadow->offset()), shadowColor);
+ }
+ }
+
+ p->fillRect(normalizedRect, p->brush());
+ }
+}
+
+
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ m_data->solidColor.setColor(color);
+ QPainter* p = m_data->p();
+ QRectF normalizedRect = rect.normalized();
+
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, normalizedRect);
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillRect(normalizedRect, shadow->m_color);
+ shadow->endShadowLayer(this);
+ }
+ } else
+ p->fillRect(normalizedRect.translated(shadow->offset()), shadow->m_color);
+ }
+
+ p->fillRect(normalizedRect, m_data->solidColor);
+}
+
+void GraphicsContext::fillRoundedRect(const IntRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ Path path;
+ path.addRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
+ QPainter* p = m_data->p();
+ if (hasShadow()) {
+ ContextShadow* shadow = contextShadow();
+ if (shadow->mustUseContextShadow(this)) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(this, rect);
+ if (shadowPainter) {
+ shadowPainter->setCompositionMode(QPainter::CompositionMode_Source);
+ shadowPainter->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+ shadow->endShadowLayer(this);
+ }
+ } else {
+ p->translate(m_data->shadow.offset());
+ p->fillPath(path.platformPath(), QColor(m_data->shadow.m_color));
+ p->translate(-m_data->shadow.offset());
+ }
+ }
+ p->fillPath(path.platformPath(), QColor(color));
+}
+
+bool GraphicsContext::inTransparencyLayer() const
+{
+ return m_data->layerCount;
+}
+
+ContextShadow* GraphicsContext::contextShadow()
+{
+ return &m_data->shadow;
+}
+
+void GraphicsContext::clip(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setClipRect(rect, Qt::IntersectClip);
+}
+
+void GraphicsContext::clipPath(const Path& path, WindRule clipRule)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath platformPath = path.platformPath();
+ platformPath.setFillRule(clipRule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+ p->setClipPath(platformPath, Qt::IntersectClip);
+}
+
+void drawFocusRingForPath(QPainter* p, const QPainterPath& path, int width, const Color& color, bool antiAliasing)
+{
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, antiAliasing);
+
+ const QPen oldPen = p->pen();
+ const QBrush oldBrush = p->brush();
+
+ QPen nPen = p->pen();
+ nPen.setColor(color);
+ nPen.setWidth(width);
+ p->setBrush(Qt::NoBrush);
+ nPen.setStyle(Qt::SolidLine);
+
+ p->strokePath(path, nPen);
+ p->setBrush(oldBrush);
+ p->setPen(oldPen);
+
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::drawFocusRing(const Path& path, int width, int offset, const Color& color)
+{
+ // FIXME: Use 'offset' for something? http://webkit.org/b/49909
+
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ drawFocusRingForPath(m_data->p(), path.platformPath(), width, color, m_data->antiAliasingForRectsAndLines);
+}
+
+/**
+ * Focus ring handling for form controls is not handled here. Qt style in
+ * RenderTheme handles drawing focus on widgets which
+ * need it. It is still handled here for links.
+ */
+void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ unsigned rectCount = rects.size();
+
+ if (!rects.size())
+ return;
+
+ int radius = (width - 1) / 2;
+ QPainterPath path;
+ for (unsigned i = 0; i < rectCount; ++i) {
+ QRect rect = QRect((rects[i])).adjusted(-offset - radius, -offset - radius, offset + radius, offset + radius);
+ // This is not the most efficient way to add a rect to a path, but if we don't create the tmpPath,
+ // we will end up with ugly lines in between rows of text on anchors with multiple lines.
+ QPainterPath tmpPath;
+ tmpPath.addRoundedRect(rect, radius, radius);
+ path = path.united(tmpPath);
+ }
+
+ drawFocusRingForPath(m_data->p(), path, width, color, m_data->antiAliasingForRectsAndLines);
+}
+
+void GraphicsContext::drawLineForText(const IntPoint& origin, int width, bool)
+{
+ if (paintingDisabled())
+ return;
+
+ IntPoint startPoint = origin;
+ IntPoint endPoint = origin + IntSize(width, 0);
+
+ // If paintengine type is X11 to avoid artifacts
+ // like bug https://bugs.webkit.org/show_bug.cgi?id=42248
+#if defined(Q_WS_X11)
+ QPainter* p = m_data->p();
+ if (p->paintEngine()->type() == QPaintEngine::X11) {
+ // If stroke thickness is odd we need decrease Y coordinate by 1 pixel,
+ // because inside method adjustLineToPixelBoundaries(...), which
+ // called from drawLine(...), Y coordinate will be increased by 0.5f
+ // and then inside Qt painting engine will be rounded to next greater
+ // integer value.
+ float strokeWidth = strokeThickness();
+ if (static_cast<int>(strokeWidth) % 2) {
+ startPoint.setY(startPoint.y() - 1);
+ endPoint.setY(endPoint.y() - 1);
+ }
+ }
+#endif // defined(Q_WS_X11)
+
+ drawLine(startPoint, endPoint);
+}
+
+void GraphicsContext::drawLineForTextChecking(const IntPoint&, int, TextCheckingLineStyle)
+{
+ if (paintingDisabled())
+ return;
+
+ notImplemented();
+}
+
+FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect)
+{
+ // It is not enough just to round to pixels in device space. The rotation part of the
+ // affine transform matrix to device space can mess with this conversion if we have a
+ // rotating image like the hands of the world clock widget. We just need the scale, so
+ // we get the affine transform matrix and extract the scale.
+ QPainter* painter = platformContext();
+ QTransform deviceTransform = painter->deviceTransform();
+ if (deviceTransform.isIdentity())
+ return frect;
+
+ qreal deviceScaleX = sqrtf(deviceTransform.m11() * deviceTransform.m11() + deviceTransform.m12() * deviceTransform.m12());
+ qreal deviceScaleY = sqrtf(deviceTransform.m21() * deviceTransform.m21() + deviceTransform.m22() * deviceTransform.m22());
+
+ QPoint deviceOrigin(frect.x() * deviceScaleX, frect.y() * deviceScaleY);
+ QPoint deviceLowerRight(frect.right() * deviceScaleX, frect.bottom() * deviceScaleY);
+
+ // Don't let the height or width round to 0 unless either was originally 0
+ if (deviceOrigin.y() == deviceLowerRight.y() && frect.height())
+ deviceLowerRight.setY(deviceLowerRight.y() + 1);
+ if (deviceOrigin.x() == deviceLowerRight.x() && frect.width())
+ deviceLowerRight.setX(deviceLowerRight.x() + 1);
+
+ FloatPoint roundedOrigin = FloatPoint(deviceOrigin.x() / deviceScaleX, deviceOrigin.y() / deviceScaleY);
+ FloatPoint roundedLowerRight = FloatPoint(deviceLowerRight.x() / deviceScaleX, deviceLowerRight.y() / deviceScaleY);
+ return FloatRect(roundedOrigin, roundedLowerRight - roundedOrigin);
+}
+
+void GraphicsContext::setPlatformShadow(const FloatSize& size, float blur, const Color& color, ColorSpace)
+{
+ // Qt doesn't support shadows natively, they are drawn manually in the draw*
+ // functions
+
+ if (m_state.shadowsIgnoreTransforms) {
+ // Meaning that this graphics context is associated with a CanvasRenderingContext
+ // We flip the height since CG and HTML5 Canvas have opposite Y axis
+ m_state.shadowOffset = FloatSize(size.width(), -size.height());
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), -size.height()));
+ } else
+ m_data->shadow = ContextShadow(color, blur, FloatSize(size.width(), size.height()));
+
+ m_data->shadow.setShadowsIgnoreTransforms(m_state.shadowsIgnoreTransforms);
+}
+
+void GraphicsContext::clearPlatformShadow()
+{
+ m_data->shadow.clear();
+}
+
+void GraphicsContext::pushTransparencyLayerInternal(const QRect &rect, qreal opacity, QPixmap& alphaMask)
+{
+ QPainter* p = m_data->p();
+ m_data->layers.push(new TransparencyLayer(p, p->transform().mapRect(rect), 1.0, alphaMask));
+}
+
+void GraphicsContext::beginTransparencyLayer(float opacity)
+{
+ if (paintingDisabled())
+ return;
+
+ int x, y, w, h;
+ x = y = 0;
+ QPainter* p = m_data->p();
+ const QPaintDevice* device = p->device();
+ w = device->width();
+ h = device->height();
+
+ QRectF clip = m_data->clipBoundingRect();
+ QRectF deviceClip = p->transform().mapRect(clip);
+ x = int(qBound(qreal(0), deviceClip.x(), (qreal)w));
+ y = int(qBound(qreal(0), deviceClip.y(), (qreal)h));
+ w = int(qBound(qreal(0), deviceClip.width(), (qreal)w) + 2);
+ h = int(qBound(qreal(0), deviceClip.height(), (qreal)h) + 2);
+
+ QPixmap emptyAlphaMask;
+ m_data->layers.push(new TransparencyLayer(p, QRect(x, y, w, h), opacity, emptyAlphaMask));
+ ++m_data->layerCount;
+}
+
+void GraphicsContext::endTransparencyLayer()
+{
+ if (paintingDisabled())
+ return;
+
+ TransparencyLayer* layer = m_data->layers.pop();
+ if (!layer->alphaMask.isNull()) {
+ layer->painter.resetTransform();
+ layer->painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ layer->painter.drawPixmap(QPoint(), layer->alphaMask);
+ } else
+ --m_data->layerCount; // see the comment for layerCount
+ layer->painter.end();
+
+ QPainter* p = m_data->p();
+ p->save();
+ p->resetTransform();
+ p->setOpacity(layer->opacity);
+ p->drawPixmap(layer->offset, layer->pixmap);
+ p->restore();
+
+ delete layer;
+}
+
+void GraphicsContext::clearRect(const FloatRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainter::CompositionMode currentCompositionMode = p->compositionMode();
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+ p->fillRect(rect, Qt::transparent);
+ if (p->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ p->setCompositionMode(currentCompositionMode);
+}
+
+void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth)
+{
+ if (paintingDisabled())
+ return;
+
+ Path path;
+ path.addRect(rect);
+
+ float previousStrokeThickness = strokeThickness();
+
+ if (lineWidth != previousStrokeThickness)
+ setStrokeThickness(lineWidth);
+
+ strokePath(path);
+
+ if (lineWidth != previousStrokeThickness)
+ setStrokeThickness(previousStrokeThickness);
+}
+
+void GraphicsContext::setLineCap(LineCap lc)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setCapStyle(toQtLineCap(lc));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset)
+{
+ QPainter* p = m_data->p();
+ QPen pen = p->pen();
+ unsigned dashLength = dashes.size();
+ if (dashLength) {
+ QVector<qreal> pattern;
+ unsigned count = dashLength;
+ if (dashLength % 2)
+ count *= 2;
+
+ float penWidth = narrowPrecisionToFloat(double(pen.widthF()));
+ for (unsigned i = 0; i < count; i++)
+ pattern.append(dashes[i % dashLength] / penWidth);
+
+ pen.setDashPattern(pattern);
+ pen.setDashOffset(dashOffset / penWidth);
+ } else
+ pen.setStyle(Qt::SolidLine);
+ p->setPen(pen);
+}
+
+void GraphicsContext::setLineJoin(LineJoin lj)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setJoinStyle(toQtLineJoin(lj));
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setMiterLimit(float limit)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen nPen = p->pen();
+ nPen.setMiterLimit(limit);
+ p->setPen(nPen);
+}
+
+void GraphicsContext::setAlpha(float opacity)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ p->setOpacity(opacity);
+}
+
+void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* painter = m_data->p();
+
+ if (!painter->paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ return;
+
+ painter->setCompositionMode(toQtCompositionMode(op));
+}
+
+void GraphicsContext::clip(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainterPath clipPath = path.platformPath();
+ clipPath.setFillRule(Qt::WindingFill);
+ m_data->p()->setClipPath(clipPath, Qt::IntersectClip);
+}
+
+void GraphicsContext::canvasClip(const Path& path)
+{
+ clip(path);
+}
+
+void GraphicsContext::clipOut(const Path& path)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath clippedOut = path.platformPath();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ if (p->hasClipping()) {
+ newClip.addRect(m_data->clipBoundingRect());
+ newClip.addPath(clippedOut);
+ p->setClipPath(newClip, Qt::IntersectClip);
+ } else {
+ QRect windowRect = p->transform().inverted().mapRect(p->window());
+ newClip.addRect(windowRect);
+ newClip.addPath(clippedOut.intersected(newClip));
+ p->setClipPath(newClip);
+ }
+}
+
+void GraphicsContext::translate(float x, float y)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->translate(x, y);
+}
+
+void GraphicsContext::rotate(float radians)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->rotate(180 / M_PI*radians);
+}
+
+void GraphicsContext::scale(const FloatSize& s)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->scale(s.width(), s.height());
+}
+
+void GraphicsContext::clipOut(const IntRect& rect)
+{
+ if (paintingDisabled())
+ return;
+
+ QPainter* p = m_data->p();
+ QPainterPath newClip;
+ newClip.setFillRule(Qt::OddEvenFill);
+ if (p->hasClipping()) {
+ newClip.addRect(m_data->clipBoundingRect());
+ newClip.addRect(QRect(rect));
+ p->setClipPath(newClip, Qt::IntersectClip);
+ } else {
+ QRect clipOutRect(rect);
+ QRect window = p->transform().inverted().mapRect(p->window());
+ clipOutRect &= window;
+ newClip.addRect(window);
+ newClip.addRect(clipOutRect);
+ p->setClipPath(newClip);
+ }
+}
+
+void GraphicsContext::addInnerRoundedRectClip(const IntRect& rect,
+ int thickness)
+{
+ if (paintingDisabled())
+ return;
+
+ clip(rect);
+ QPainterPath path;
+
+ // Add outer ellipse
+ path.addEllipse(QRectF(rect.x(), rect.y(), rect.width(), rect.height()));
+
+ // Add inner ellipse.
+ path.addEllipse(QRectF(rect.x() + thickness, rect.y() + thickness,
+ rect.width() - (thickness * 2), rect.height() - (thickness * 2)));
+
+ path.setFillRule(Qt::OddEvenFill);
+
+ QPainter* p = m_data->p();
+
+ const bool antiAlias = p->testRenderHint(QPainter::Antialiasing);
+ p->setRenderHint(QPainter::Antialiasing, true);
+ p->setClipPath(path, Qt::IntersectClip);
+ p->setRenderHint(QPainter::Antialiasing, antiAlias);
+}
+
+void GraphicsContext::concatCTM(const AffineTransform& transform)
+{
+ if (paintingDisabled())
+ return;
+
+ m_data->p()->setWorldTransform(transform, true);
+}
+
+void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
+{
+ notImplemented();
+}
+
+void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ m_data->solidColor.setColor(color);
+ newPen.setBrush(m_data->solidColor);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeStyle(StrokeStyle strokeStyle)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setStyle(toQPenStyle(strokeStyle));
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformStrokeThickness(float thickness)
+{
+ if (paintingDisabled())
+ return;
+ QPainter* p = m_data->p();
+ QPen newPen(p->pen());
+ newPen.setWidthF(thickness);
+ p->setPen(newPen);
+}
+
+void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
+{
+ if (paintingDisabled() || !color.isValid())
+ return;
+
+ m_data->solidColor.setColor(color);
+ m_data->p()->setBrush(m_data->solidColor);
+}
+
+void GraphicsContext::setPlatformShouldAntialias(bool enable)
+{
+ if (paintingDisabled())
+ return;
+ m_data->p()->setRenderHint(QPainter::Antialiasing, enable);
+}
+
+#ifdef Q_WS_WIN
+
+HDC GraphicsContext::getWindowsContext(const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
+
+ if (dstRect.isEmpty())
+ return 0;
+
+ // Create a bitmap DC in which to draw.
+ BITMAPINFO bitmapInfo;
+ bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bitmapInfo.bmiHeader.biWidth = dstRect.width();
+ bitmapInfo.bmiHeader.biHeight = dstRect.height();
+ bitmapInfo.bmiHeader.biPlanes = 1;
+ bitmapInfo.bmiHeader.biBitCount = 32;
+ bitmapInfo.bmiHeader.biCompression = BI_RGB;
+ bitmapInfo.bmiHeader.biSizeImage = 0;
+ bitmapInfo.bmiHeader.biXPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biYPelsPerMeter = 0;
+ bitmapInfo.bmiHeader.biClrUsed = 0;
+ bitmapInfo.bmiHeader.biClrImportant = 0;
+
+ void* pixels = 0;
+ HBITMAP bitmap = ::CreateDIBSection(0, &bitmapInfo, DIB_RGB_COLORS, &pixels, 0, 0);
+ if (!bitmap)
+ return 0;
+
+ HDC displayDC = ::GetDC(0);
+ HDC bitmapDC = ::CreateCompatibleDC(displayDC);
+ ::ReleaseDC(0, displayDC);
+
+ ::SelectObject(bitmapDC, bitmap);
+
+ // Fill our buffer with clear if we're going to alpha blend.
+ if (supportAlphaBlend) {
+ BITMAP bmpInfo;
+ GetObject(bitmap, sizeof(bmpInfo), &bmpInfo);
+ int bufferSize = bmpInfo.bmWidthBytes * bmpInfo.bmHeight;
+ memset(bmpInfo.bmBits, 0, bufferSize);
+ }
+
+#if !OS(WINCE)
+ // Make sure we can do world transforms.
+ SetGraphicsMode(bitmapDC, GM_ADVANCED);
+
+ // Apply a translation to our context so that the drawing done will be at (0,0) of the bitmap.
+ XFORM xform;
+ xform.eM11 = 1.0f;
+ xform.eM12 = 0.0f;
+ xform.eM21 = 0.0f;
+ xform.eM22 = 1.0f;
+ xform.eDx = -dstRect.x();
+ xform.eDy = -dstRect.y();
+ ::SetWorldTransform(bitmapDC, &xform);
+#endif
+
+ return bitmapDC;
+}
+
+void GraphicsContext::releaseWindowsContext(HDC hdc, const IntRect& dstRect, bool supportAlphaBlend, bool mayCreateBitmap)
+{
+ // painting through native HDC is only supported for plugin, where mayCreateBitmap is always true
+ Q_ASSERT(mayCreateBitmap);
+
+ if (hdc) {
+
+ if (!dstRect.isEmpty()) {
+
+ HBITMAP bitmap = static_cast<HBITMAP>(GetCurrentObject(hdc, OBJ_BITMAP));
+ BITMAP info;
+ GetObject(bitmap, sizeof(info), &info);
+ ASSERT(info.bmBitsPixel == 32);
+
+ QPixmap pixmap = QPixmap::fromWinHBITMAP(bitmap, supportAlphaBlend ? QPixmap::PremultipliedAlpha : QPixmap::NoAlpha);
+ m_data->p()->drawPixmap(dstRect, pixmap);
+
+ ::DeleteObject(bitmap);
+ }
+
+ ::DeleteDC(hdc);
+ }
+}
+#endif
+
+void GraphicsContext::setImageInterpolationQuality(InterpolationQuality quality)
+{
+ m_data->imageInterpolationQuality = quality;
+
+ switch (quality) {
+ case InterpolationNone:
+ case InterpolationLow:
+ // use nearest-neigbor
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, false);
+ break;
+
+ case InterpolationMedium:
+ case InterpolationHigh:
+ // use the filter
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, true);
+ break;
+
+ case InterpolationDefault:
+ default:
+ m_data->p()->setRenderHint(QPainter::SmoothPixmapTransform, m_data->initialSmoothPixmapTransformHint);
+ break;
+ };
+}
+
+InterpolationQuality GraphicsContext::imageInterpolationQuality() const
+{
+ return m_data->imageInterpolationQuality;
+}
+
+void GraphicsContext::takeOwnershipOfPlatformContext()
+{
+ m_data->takeOwnershipOfPlatformContext();
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
new file mode 100644
index 0000000..f31844a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -0,0 +1,1779 @@
+/*
+ Copyright (C) 2009 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 "GraphicsLayerQt.h"
+
+#include "CurrentTime.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "Image.h"
+#include "RefCounted.h"
+#include "TranslateTransformOperation.h"
+#include "UnitBezier.h"
+#include <QtCore/qabstractanimation.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qmetaobject.h>
+#include <QtCore/qset.h>
+#include <QtCore/qtimer.h>
+#include <QtGui/qcolor.h>
+#include <QtGui/qgraphicseffect.h>
+#include <QtGui/qgraphicsitem.h>
+#include <QtGui/qgraphicsscene.h>
+#include <QtGui/qgraphicsview.h>
+#include <QtGui/qgraphicswidget.h>
+#include <QtGui/qpainter.h>
+#include <QtGui/qpixmap.h>
+#include <QtGui/qpixmapcache.h>
+#include <QtGui/qstyleoption.h>
+
+#if ENABLE(TILED_BACKING_STORE)
+#include "TiledBackingStore.h"
+#include "TiledBackingStoreClient.h"
+
+// The minimum width/height for tiling. We use the same value as the Windows implementation.
+#define GRAPHICS_LAYER_TILING_THRESHOLD 2000
+#endif
+
+
+#define QT_DEBUG_RECACHE 0
+#define QT_DEBUG_CACHEDUMP 0
+
+#define QT_DEBUG_FPS 0
+
+namespace WebCore {
+
+#ifndef QT_NO_GRAPHICSEFFECT
+class MaskEffectQt : public QGraphicsEffect {
+public:
+ MaskEffectQt(QObject* parent, QGraphicsItem* maskLayer)
+ : QGraphicsEffect(parent)
+ , m_maskLayer(maskLayer)
+ {
+ }
+
+ void draw(QPainter* painter)
+ {
+ // This is a modified clone of QGraphicsOpacityEffect.
+ // It's more efficient to do it this way because:
+ // (a) We don't need the QBrush abstraction - we always end up using QGraphicsItem::paint
+ // from the mask layer.
+ // (b) QGraphicsOpacityEffect detaches the pixmap, which is inefficient on OpenGL.
+ const QSize maskSize = sourceBoundingRect().toAlignedRect().size();
+ if (!maskSize.isValid() || maskSize.isEmpty()) {
+ drawSource(painter);
+ return;
+ }
+ QPixmap maskPixmap(maskSize);
+
+ // We need to do this so the pixmap would have hasAlpha().
+ maskPixmap.fill(Qt::transparent);
+ QPainter maskPainter(&maskPixmap);
+ QStyleOptionGraphicsItem option;
+ option.exposedRect = option.rect = maskPixmap.rect();
+ maskPainter.setRenderHints(painter->renderHints(), true);
+ m_maskLayer->paint(&maskPainter, &option, 0);
+ maskPainter.end();
+
+ QPoint offset;
+ QPixmap srcPixmap = sourcePixmap(Qt::LogicalCoordinates, &offset, QGraphicsEffect::NoPad);
+
+ // We have to use another intermediate pixmap, to make sure the mask applies only to this item
+ // and doesn't modify pixels already painted into this paint-device.
+ QPixmap pixmap(srcPixmap.size());
+ pixmap.fill(Qt::transparent);
+
+ if (pixmap.isNull())
+ return;
+
+ QPainter pixmapPainter(&pixmap);
+
+ pixmapPainter.setRenderHints(painter->renderHints());
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
+
+ // We use drawPixmap rather than detaching, because it's more efficient on OpenGL.
+ pixmapPainter.drawPixmap(0, 0, srcPixmap);
+ pixmapPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ pixmapPainter.drawPixmap(0, 0, maskPixmap);
+
+ pixmapPainter.end();
+ painter->drawPixmap(offset, pixmap);
+ }
+
+ QGraphicsItem* m_maskLayer;
+};
+#endif // QT_NO_GRAPHICSEFFECT
+
+class GraphicsLayerQtImpl : public QGraphicsObject
+#if ENABLE(TILED_BACKING_STORE)
+, public virtual TiledBackingStoreClient
+#endif
+{
+ Q_OBJECT
+
+public:
+ // This set of flags help us defer which properties of the layer have been
+ // 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),
+
+ ContentsOrientationChange = (1L << 8),
+ OpacityChange = (1L << 9),
+ ContentsRectChange = (1L << 10),
+
+ Preserves3DChange = (1L << 11),
+ MasksToBoundsChange = (1L << 12),
+ DrawsContentChange = (1L << 13),
+ ContentsOpaqueChange = (1L << 14),
+
+ BackfaceVisibilityChange = (1L << 15),
+ ChildrenTransformChange = (1L << 16),
+ DisplayChange = (1L << 17),
+ BackgroundColorChange = (1L << 18),
+
+ DistributesOpacityChange = (1L << 19)
+ };
+
+ // The compositor lets us special-case images and colors, so we try to do so.
+ enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType, Canvas3DContentType};
+
+ const GraphicsLayerQtImpl* rootLayer() const;
+
+ GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
+ virtual ~GraphicsLayerQtImpl();
+
+ // reimps from QGraphicsItem
+ virtual QPainterPath opaqueArea() const;
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*);
+
+ // We manage transforms ourselves because transform-origin acts differently in webkit and in Qt,
+ // and we need it as a fallback in case we encounter an un-invertible matrix.
+ void setBaseTransform(const TransformationMatrix&);
+ void updateTransform();
+
+ // let the compositor-API tell us which properties were changed
+ void notifyChange(ChangeMask);
+
+ // Actual rendering of the web-content into a QPixmap:
+ // We prefer to use our own caching because it gives us a higher level of granularity than
+ // QGraphicsItem cache modes - Sometimes we need to cache the contents even though the item
+ // needs to be updated, e.g. when the background-color is changed.
+ // TODO: investigate if QGraphicsItem caching can be improved to support that out of the box.
+ QPixmap recache(const QRegion&);
+
+ // Called when the compositor is ready for us to show the changes on screen.
+ // This is called indirectly from ChromeClientQt::setNeedsOneShotDrawingSynchronization
+ // (meaning the sync would happen together with the next draw) or
+ // ChromeClientQt::scheduleCompositingLayerSync (meaning the sync will happen ASAP)
+ void flushChanges(bool recursive = true, bool forceTransformUpdate = false);
+
+#if ENABLE(TILED_BACKING_STORE)
+ // reimplementations from TiledBackingStoreClient
+ virtual void tiledBackingStorePaintBegin();
+ virtual void tiledBackingStorePaint(GraphicsContext*, const IntRect&);
+ virtual void tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea);
+ virtual IntRect tiledBackingStoreContentsRect();
+ virtual IntRect tiledBackingStoreVisibleRect();
+ virtual Color tiledBackingStoreBackgroundColor() const;
+#endif
+
+public slots:
+ // We need to notify the client (ie. 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: Avoid using QTimer::singleShot().
+ void notifyAnimationStartedAsync();
+
+public:
+ GraphicsLayerQt* m_layer;
+
+ TransformationMatrix m_baseTransform;
+ TransformationMatrix m_transformRelativeToRootLayer;
+ bool m_transformAnimationRunning;
+ bool m_opacityAnimationRunning;
+ bool m_blockNotifySyncRequired;
+#ifndef QT_NO_GRAPHICSEFFECT
+ QWeakPointer<MaskEffectQt> m_maskEffect;
+#endif
+
+ struct ContentData {
+ QPixmap pixmap;
+ QRegion regionToUpdate;
+ bool updateAll;
+
+ QColor contentsBackgroundColor;
+ QColor backgroundColor;
+
+ QWeakPointer<QGraphicsObject> mediaLayer;
+ StaticContentType contentType;
+
+ float opacity;
+
+ ContentData()
+ : updateAll(false)
+ , contentType(HTMLContentType)
+ , opacity(1.f)
+ {
+ }
+
+ };
+
+ ContentData m_pendingContent;
+ ContentData m_currentContent;
+
+ int m_changeMask;
+
+#if ENABLE(TILED_BACKING_STORE)
+ TiledBackingStore* m_tiledBackingStore;
+#endif
+
+ QSizeF m_size;
+ struct {
+ QPixmapCache::Key key;
+ QSizeF size;
+ } m_backingStore;
+#ifndef QT_NO_ANIMATION
+ QList<QWeakPointer<QAbstractAnimation> > m_animations;
+#endif
+ QTimer m_suspendTimer;
+
+ struct State {
+ GraphicsLayer* maskLayer;
+ FloatPoint pos;
+ FloatPoint3D anchorPoint;
+ FloatSize size;
+ TransformationMatrix transform;
+ TransformationMatrix childrenTransform;
+ Color backgroundColor;
+ Color currentColor;
+ GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation;
+ float opacity;
+ QRect contentsRect;
+
+ bool preserves3D: 1;
+ bool masksToBounds: 1;
+ bool drawsContent: 1;
+ bool contentsOpaque: 1;
+ bool backfaceVisibility: 1;
+ bool distributeOpacity: 1;
+ bool align: 2;
+
+ State()
+ : maskLayer(0)
+ , opacity(1.f)
+ , preserves3D(false)
+ , masksToBounds(false)
+ , drawsContent(false)
+ , contentsOpaque(false)
+ , backfaceVisibility(false)
+ , distributeOpacity(false)
+ {
+ }
+ } m_state;
+
+#if ENABLE(3D_CANVAS)
+ const GraphicsContext3D* m_gc3D;
+#endif
+
+#ifndef QT_NO_ANIMATION
+ friend class AnimationQtBase;
+#endif
+};
+
+inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsItem* item)
+{
+ ASSERT(item);
+ return qobject_cast<GraphicsLayerQtImpl*>(item->toGraphicsObject());
+}
+
+inline GraphicsLayerQtImpl* toGraphicsLayerQtImpl(QGraphicsObject* item)
+{
+ return qobject_cast<GraphicsLayerQtImpl*>(item);
+}
+
+GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
+ : QGraphicsObject(0)
+ , m_layer(newLayer)
+ , m_transformAnimationRunning(false)
+ , m_opacityAnimationRunning(false)
+ , m_blockNotifySyncRequired(false)
+ , m_changeMask(NoChanges)
+#if ENABLE(TILED_BACKING_STORE)
+ , m_tiledBackingStore(0)
+#endif
+#if ENABLE(3D_CANVAS)
+ , m_gc3D(0)
+#endif
+{
+ // We use graphics-view for compositing-only, not for interactivity.
+ setAcceptedMouseButtons(Qt::NoButton);
+
+ // We need to have the item enabled, or else wheel events are not passed to the parent class
+ // implementation of wheelEvent, where they are ignored and passed to the item below.
+ setEnabled(true);
+
+ connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
+}
+
+GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
+{
+ // The compositor manages lifecycle of item, so we do not want the graphicsview system to delete
+ // our items automatically.
+ const QList<QGraphicsItem*> children = childItems();
+ QList<QGraphicsItem*>::const_iterator cit;
+ for (cit = children.constBegin(); cit != children.constEnd(); ++cit) {
+ if (QGraphicsItem* item = *cit) {
+ if (scene())
+ scene()->removeItem(item);
+ item->setParentItem(0);
+ }
+ }
+#if ENABLE(TILED_BACKING_STORE)
+ delete m_tiledBackingStore;
+#endif
+#ifndef QT_NO_ANIMATION
+ // We do, however, own the animations.
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_animations.begin(); it != m_animations.end(); ++it)
+ if (QAbstractAnimation* anim = it->data())
+ delete anim;
+#endif
+}
+
+const GraphicsLayerQtImpl* GraphicsLayerQtImpl::rootLayer() const
+{
+ if (const GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject()))
+ return parent->rootLayer();
+ return this;
+}
+
+QPixmap GraphicsLayerQtImpl::recache(const QRegion& regionToUpdate)
+{
+ if (!m_layer->drawsContent() || m_size.isEmpty() || !m_size.isValid())
+ return QPixmap();
+
+#if ENABLE(TILED_BACKING_STORE)
+ const bool requiresTiling = (m_state.drawsContent && m_currentContent.contentType == HTMLContentType) && (m_size.width() > GRAPHICS_LAYER_TILING_THRESHOLD || m_size.height() > GRAPHICS_LAYER_TILING_THRESHOLD);
+ if (requiresTiling && !m_tiledBackingStore) {
+ m_tiledBackingStore = new TiledBackingStore(this);
+ m_tiledBackingStore->setTileCreationDelay(0);
+ setFlag(ItemUsesExtendedStyleOption, true);
+ } else if (!requiresTiling && m_tiledBackingStore) {
+ delete m_tiledBackingStore;
+ m_tiledBackingStore = 0;
+ setFlag(ItemUsesExtendedStyleOption, false);
+ }
+
+ if (m_tiledBackingStore) {
+ m_tiledBackingStore->adjustVisibleRect();
+ const QVector<QRect> rects = regionToUpdate.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ m_tiledBackingStore->invalidate(rects[i]);
+ return QPixmap();
+ }
+#endif
+
+ QPixmap pixmap;
+ QRegion region = regionToUpdate;
+ if (QPixmapCache::find(m_backingStore.key, &pixmap)) {
+ if (region.isEmpty())
+ return pixmap;
+ QPixmapCache::remove(m_backingStore.key); // Remove the reference to the pixmap in the cache to avoid a detach.
+ }
+
+ {
+ bool erased = false;
+
+ // If the pixmap is not in the cache or the view has grown since last cached.
+ if (pixmap.isNull() || m_size != m_backingStore.size) {
+#if QT_DEBUG_RECACHE
+ if (pixmap.isNull())
+ qDebug() << "CacheMiss" << this << m_size;
+#endif
+ bool fill = true;
+ QRegion newRegion;
+ QPixmap oldPixmap = pixmap;
+
+ // If the pixmap is two small to hold the view contents we enlarge, otherwise just use the old (large) pixmap.
+ if (pixmap.width() < m_size.width() || pixmap.height() < m_size.height()) {
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheGrow" << this << m_size;
+#endif
+ pixmap = QPixmap(m_size.toSize());
+ pixmap.fill(Qt::transparent);
+ newRegion = QRegion(0, 0, m_size.width(), m_size.height());
+ }
+
+#if 1
+ // Blit the contents of oldPixmap back into the cached pixmap as we are just adding new pixels.
+ if (!oldPixmap.isNull()) {
+ const QRegion cleanRegion = (QRegion(0, 0, m_size.width(), m_size.height())
+ & QRegion(0, 0, m_backingStore.size.width(), m_backingStore.size.height())) - regionToUpdate;
+ if (!cleanRegion.isEmpty()) {
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheBlit" << this << cleanRegion;
+#endif
+ const QRect cleanBounds(cleanRegion.boundingRect());
+ QPainter painter(&pixmap);
+ painter.setCompositionMode(QPainter::CompositionMode_Source);
+ painter.drawPixmap(cleanBounds.topLeft(), oldPixmap, cleanBounds);
+ newRegion -= cleanRegion;
+ fill = false; // We cannot just fill the pixmap.
+ }
+ oldPixmap = QPixmap();
+ }
+#endif
+ region += newRegion;
+ if (fill && !region.isEmpty()) { // Clear the entire pixmap with the background.
+#if QT_DEBUG_RECACHE
+ qDebug() << "CacheErase" << this << m_size << background;
+#endif
+ erased = true;
+ pixmap.fill(Qt::transparent);
+ }
+ }
+ region &= QRegion(0, 0, m_size.width(), m_size.height());
+
+ // If we have something to draw its time to erase it and render the contents.
+ if (!region.isEmpty()) {
+#if QT_DEBUG_CACHEDUMP
+ static int recacheCount = 0;
+ ++recacheCount;
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_A.png", recacheCount), "PNG");
+#endif
+
+ QPainter painter(&pixmap);
+ GraphicsContext gc(&painter);
+
+ painter.setClipRegion(region);
+
+ if (!erased) { // Erase the area in cache that we're drawing into.
+ painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ painter.fillRect(region.boundingRect(), Qt::transparent);
+
+#if QT_DEBUG_CACHEDUMP
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_B.png", recacheCount), "PNG");
+#endif
+ }
+
+ // Render the actual contents into the cache.
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ m_layer->paintGraphicsLayerContents(gc, region.boundingRect());
+ painter.end();
+
+#if QT_DEBUG_CACHEDUMP
+ qDebug() << "**** CACHEDUMP" << recacheCount << this << m_layer << region << m_size;
+ pixmap.save(QString().sprintf("/tmp/%05d_C.png", recacheCount), "PNG");
+#endif
+ }
+ m_backingStore.size = m_size; // Store the used size of the pixmap.
+ }
+
+ // Finally insert into the cache and allow a reference there.
+ m_backingStore.key = QPixmapCache::insert(pixmap);
+ return pixmap;
+}
+
+void GraphicsLayerQtImpl::updateTransform()
+{
+ if (!m_transformAnimationRunning)
+ m_baseTransform = m_layer->transform();
+
+ TransformationMatrix localTransform;
+
+ GraphicsLayerQtImpl* parent = toGraphicsLayerQtImpl(parentObject());
+
+ // WebCore has relative-to-size originPoint, where as the QGraphicsView has a pixel originPoint.
+ // Thus, we need to convert here as we have to manage this outselves due to the fact that the
+ // transformOrigin of the graphicsview is imcompatible.
+ const qreal originX = m_state.anchorPoint.x() * m_size.width();
+ const qreal originY = m_state.anchorPoint.y() * m_size.height();
+
+ // We ignore QGraphicsItem::pos completely, and use transforms only, due to the fact that we
+ // have to maintain that ourselves for 3D.
+ localTransform
+ .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z())
+ .multLeft(m_baseTransform)
+ .translate3d(-originX, -originY, -m_state.anchorPoint.z());
+
+ // This is the actual 3D transform of this item, with the ancestors' transform baked in.
+ m_transformRelativeToRootLayer = TransformationMatrix(parent ? parent->m_transformRelativeToRootLayer : TransformationMatrix())
+ .multLeft(localTransform);
+
+ // Now we have enough information to determine if the layer is facing backwards.
+ if (!m_state.backfaceVisibility && m_transformRelativeToRootLayer.inverse().m33() < 0) {
+ setVisible(false);
+ // No point in making extra calculations for invisible elements.
+ return;
+ }
+
+ // The item is front-facing or backface-visibility is on.
+ setVisible(true);
+
+ // Flatten to 2D-space of this item if it doesn't preserve 3D.
+ if (!m_state.preserves3D) {
+ m_transformRelativeToRootLayer.setM13(0);
+ m_transformRelativeToRootLayer.setM23(0);
+ m_transformRelativeToRootLayer.setM31(0);
+ m_transformRelativeToRootLayer.setM32(0);
+ m_transformRelativeToRootLayer.setM33(1);
+ m_transformRelativeToRootLayer.setM34(0);
+ m_transformRelativeToRootLayer.setM43(0);
+ }
+
+ // Apply perspective for the use of this item's children. Perspective is always applied from the item's
+ // center.
+ if (!m_state.childrenTransform.isIdentity()) {
+ m_transformRelativeToRootLayer
+ .translate(m_size.width() / 2, m_size.height() /2)
+ .multLeft(m_state.childrenTransform)
+ .translate(-m_size.width() / 2, -m_size.height() /2);
+ }
+
+ bool inverseOk = true;
+ // Use QTransform::inverse to extrapolate the relative transform of this item, based on the parent's
+ // transform relative to the root layer and the desired transform for this item relative to the root layer.
+ const QTransform parentTransform = parent ? parent->itemTransform(rootLayer()) : QTransform();
+ const QTransform transform2D = QTransform(m_transformRelativeToRootLayer) * parentTransform.inverted(&inverseOk);
+
+ // In rare cases the transformation cannot be inversed - in that case we don't apply the transformation at
+ // all, otherwise we'd flicker. FIXME: This should be amended when Qt moves to a real 3D scene-graph.
+ if (!inverseOk)
+ return;
+
+ setTransform(transform2D);
+
+ const QList<QGraphicsItem*> children = childItems();
+ QList<QGraphicsItem*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it)
+ if (GraphicsLayerQtImpl* layer= toGraphicsLayerQtImpl(*it))
+ layer->updateTransform();
+}
+
+void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
+{
+ m_baseTransform = baseTransform;
+ updateTransform();
+}
+
+QPainterPath GraphicsLayerQtImpl::opaqueArea() const
+{
+ QPainterPath painterPath;
+
+ // We try out best to return the opaque area, maybe it will help graphics-view render less items.
+ if (m_currentContent.backgroundColor.isValid() && m_currentContent.backgroundColor.alpha() == 0xff)
+ painterPath.addRect(boundingRect());
+ 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);
+ }
+ }
+ return painterPath;
+}
+
+QRectF GraphicsLayerQtImpl::boundingRect() const
+{
+ return QRectF(QPointF(0, 0), QSizeF(m_size));
+}
+
+void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
+{
+#if ENABLE(TILED_BACKING_STORE)
+ // FIXME: There's currently no Qt API to know if a new region of an item is exposed outside of the paint event.
+ // Suggested for Qt: http://bugreports.qt.nokia.com/browse/QTBUG-14877.
+ if (m_tiledBackingStore)
+ m_tiledBackingStore->adjustVisibleRect();
+#endif
+
+ if (m_currentContent.backgroundColor.isValid())
+ painter->fillRect(option->exposedRect, QColor(m_currentContent.backgroundColor));
+
+ switch (m_currentContent.contentType) {
+ case HTMLContentType:
+ if (m_state.drawsContent) {
+ QPixmap backingStore;
+ // We might need to recache, in case we try to paint and the cache was purged (e.g. if it was full).
+ if (!QPixmapCache::find(m_backingStore.key, &backingStore) || backingStore.size() != m_size.toSize())
+ backingStore = recache(QRegion(m_state.contentsRect));
+ const QRectF bounds(0, 0, m_backingStore.size.width(), m_backingStore.size.height());
+ painter->drawPixmap(0, 0, backingStore);
+ }
+ break;
+ case PixmapContentType:
+ painter->drawPixmap(m_state.contentsRect, m_currentContent.pixmap);
+ break;
+ 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;
+#if ENABLE(3D_CANVAS)
+ case Canvas3DContentType:
+ m_gc3D->paint(painter, option->rect);
+ break;
+#endif
+ }
+}
+
+void GraphicsLayerQtImpl::notifySyncRequired()
+{
+ m_blockNotifySyncRequired = false;
+
+ if (m_layer->client())
+ m_layer->client()->notifySyncRequired(m_layer);
+}
+
+void GraphicsLayerQtImpl::notifyChange(ChangeMask changeMask)
+{
+ m_changeMask |= changeMask;
+
+ if (m_blockNotifySyncRequired)
+ return;
+
+ static QMetaMethod syncMethod = staticMetaObject.method(staticMetaObject.indexOfMethod("notifySyncRequired()"));
+ syncMethod.invoke(this, Qt::QueuedConnection);
+
+ m_blockNotifySyncRequired = true;
+}
+
+void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform)
+{
+ // This is the bulk of the work. understanding what the compositor is trying to achieve, what
+ // graphicsview can do, and trying to find a sane common-ground.
+ if (!m_layer || m_changeMask == NoChanges)
+ goto afterLayerChanges;
+
+ if (m_changeMask & ParentChange) {
+ // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't
+ // try to snatch that ownership.
+ if (!m_layer->parent() && !parentItem())
+ setParentItem(0);
+ else if (m_layer && m_layer->parent() && m_layer->parent()->platformLayer() != parentItem())
+ setParentItem(m_layer->parent()->platformLayer());
+ }
+
+ if (m_changeMask & ChildrenChange) {
+ // We basically do an XOR operation on the list of current children and the list of wanted
+ // children, and remove/add.
+ QSet<QGraphicsItem*> newChildren;
+ const Vector<GraphicsLayer*> newChildrenVector = (m_layer->children());
+ newChildren.reserve(newChildrenVector.size());
+
+ for (size_t i = 0; i < newChildrenVector.size(); ++i)
+ newChildren.insert(newChildrenVector[i]->platformLayer());
+
+ const QSet<QGraphicsItem*> currentChildren = childItems().toSet();
+ const QSet<QGraphicsItem*> childrenToAdd = newChildren - currentChildren;
+ const QSet<QGraphicsItem*> childrenToRemove = currentChildren - newChildren;
+
+ QSet<QGraphicsItem*>::const_iterator it;
+ for (it = childrenToAdd.constBegin(); it != childrenToAdd.constEnd(); ++it) {
+ if (QGraphicsItem* w = *it)
+ w->setParentItem(this);
+ }
+
+ QSet<QGraphicsItem*>::const_iterator rit;
+ for (rit = childrenToRemove.constBegin(); rit != childrenToRemove.constEnd(); ++rit) {
+ if (GraphicsLayerQtImpl* w = toGraphicsLayerQtImpl(*rit))
+ w->setParentItem(0);
+ }
+
+ // Children are ordered by z-value, let graphicsview know.
+ for (size_t i = 0; i < newChildrenVector.size(); ++i) {
+ if (newChildrenVector[i]->platformLayer())
+ newChildrenVector[i]->platformLayer()->setZValue(i);
+ }
+ }
+
+ if (m_changeMask & MaskLayerChange) {
+ // We can't paint here, because we don't know if the mask layer itself is ready... we'll have
+ // to wait till this layer tries to paint.
+ setFlag(ItemClipsChildrenToShape, m_layer->maskLayer() || m_layer->masksToBounds());
+#ifndef QT_NO_GRAPHICSEFFECT
+ setGraphicsEffect(0);
+ if (m_layer->maskLayer()) {
+ if (GraphicsLayerQtImpl* mask = toGraphicsLayerQtImpl(m_layer->maskLayer()->platformLayer())) {
+ mask->m_maskEffect = new MaskEffectQt(this, mask);
+ setGraphicsEffect(mask->m_maskEffect.data());
+ }
+ }
+#endif
+ }
+
+ if (m_changeMask & SizeChange) {
+ if (m_layer->size() != m_state.size) {
+ prepareGeometryChange();
+ 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())
+ if (scene())
+ scene()->update();
+
+ if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange | ParentChange)) {
+ // Due to the differences between the way WebCore handles transforms and the way Qt handles transforms,
+ // all these elements affect the transforms of all the descendants.
+ forceUpdateTransform = true;
+ }
+
+ if (m_changeMask & (ContentChange | DrawsContentChange | MaskLayerChange)) {
+ switch (m_pendingContent.contentType) {
+ case PixmapContentType:
+ update();
+ setFlag(ItemHasNoContents, false);
+ break;
+
+ case MediaContentType:
+ setFlag(ItemHasNoContents, true);
+ m_pendingContent.mediaLayer.data()->setParentItem(this);
+ break;
+
+ case ColorContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType
+ || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
+ update();
+ m_state.drawsContent = false;
+ setFlag(ItemHasNoContents, false);
+
+ // Only use ItemUsesExtendedStyleOption for HTML content as colors don't gain much from that.
+ setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, false);
+ break;
+
+ case HTMLContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType)
+ update();
+ if (!m_state.drawsContent && m_layer->drawsContent())
+ update();
+
+ setFlag(ItemHasNoContents, !m_layer->drawsContent());
+ break;
+
+#if ENABLE(3D_CANVAS)
+ case Canvas3DContentType:
+ if (m_pendingContent.contentType != m_currentContent.contentType)
+ update();
+
+ setCacheMode(NoCache);
+ setFlag(ItemHasNoContents, false);
+ break;
+#endif
+ }
+ }
+
+ if ((m_changeMask & OpacityChange) && m_state.opacity != m_layer->opacity() && !m_opacityAnimationRunning)
+ setOpacity(m_layer->opacity());
+
+ if (m_changeMask & ContentsRectChange) {
+ const QRect rect(m_layer->contentsRect());
+ if (m_state.contentsRect != rect) {
+ m_state.contentsRect = rect;
+ if (m_pendingContent.mediaLayer) {
+ QGraphicsWidget* widget = qobject_cast<QGraphicsWidget*>(m_pendingContent.mediaLayer.data());
+ if (widget)
+ widget->setGeometry(rect);
+ }
+ update();
+ }
+ }
+
+ if ((m_changeMask & MasksToBoundsChange) && m_state.masksToBounds != m_layer->masksToBounds()) {
+ setFlag(QGraphicsItem::ItemClipsToShape, m_layer->masksToBounds());
+ setFlag(QGraphicsItem::ItemClipsChildrenToShape, m_layer->masksToBounds());
+ }
+
+ if ((m_changeMask & ContentsOpaqueChange) && m_state.contentsOpaque != m_layer->contentsOpaque())
+ prepareGeometryChange();
+
+#ifndef QT_NO_GRAPHICSEFFECT
+ if (m_maskEffect)
+ m_maskEffect.data()->update();
+ else
+#endif
+ if (m_changeMask & DisplayChange) {
+#ifndef QT_GRAPHICS_LAYER_NO_RECACHE_ON_DISPLAY_CHANGE
+ // Recache now: all the content is ready and we don't want to wait until the paint event.
+ // We only need to do this for HTML content, there's no point in caching directly composited
+ // content like images or solid rectangles.
+ if (m_pendingContent.contentType == HTMLContentType)
+ recache(m_pendingContent.regionToUpdate);
+#endif
+ update(m_pendingContent.regionToUpdate.boundingRect());
+ m_pendingContent.regionToUpdate = QRegion();
+ }
+
+ if ((m_changeMask & BackgroundColorChange)
+ && (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
+ update();
+
+ m_state.maskLayer = m_layer->maskLayer();
+ m_state.pos = m_layer->position();
+ m_state.anchorPoint = m_layer->anchorPoint();
+ m_state.size = m_layer->size();
+ m_state.transform = m_layer->transform();
+ m_state.contentsOrientation =m_layer->contentsOrientation();
+ m_state.opacity = m_layer->opacity();
+ m_state.contentsRect = m_layer->contentsRect();
+ m_state.preserves3D = m_layer->preserves3D();
+ m_state.masksToBounds = m_layer->masksToBounds();
+ m_state.drawsContent = m_layer->drawsContent();
+ m_state.contentsOpaque = m_layer->contentsOpaque();
+ m_state.backfaceVisibility = m_layer->backfaceVisibility();
+ m_state.childrenTransform = m_layer->childrenTransform();
+ m_currentContent.pixmap = m_pendingContent.pixmap;
+ m_currentContent.contentType = m_pendingContent.contentType;
+ m_currentContent.mediaLayer = m_pendingContent.mediaLayer;
+ m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
+ m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
+ m_pendingContent.regionToUpdate = QRegion();
+ m_changeMask = NoChanges;
+
+afterLayerChanges:
+ if (forceUpdateTransform)
+ updateTransform();
+
+ if (!recursive)
+ return;
+
+ QList<QGraphicsItem*> children = childItems();
+ if (m_state.maskLayer)
+ children.append(m_state.maskLayer->platformLayer());
+
+ QList<QGraphicsItem*>::const_iterator it;
+ for (it = children.constBegin(); it != children.constEnd(); ++it) {
+ if (QGraphicsItem* item = *it) {
+ if (GraphicsLayerQtImpl* layer = toGraphicsLayerQtImpl(item))
+ layer->flushChanges(true, forceUpdateTransform);
+ }
+ }
+}
+
+#if ENABLE(TILED_BACKING_STORE)
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaintBegin()
+{
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaint(GraphicsContext* gc, const IntRect& rect)
+{
+ m_layer->paintGraphicsLayerContents(*gc, rect);
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+void GraphicsLayerQtImpl::tiledBackingStorePaintEnd(const Vector<IntRect>& paintedArea)
+{
+ for (int i = 0; i < paintedArea.size(); ++i)
+ update(QRectF(paintedArea[i]));
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+IntRect GraphicsLayerQtImpl::tiledBackingStoreContentsRect()
+{
+ return m_layer->contentsRect();
+}
+
+/* \reimp (TiledBackingStoreClient.h)
+*/
+Color GraphicsLayerQtImpl::tiledBackingStoreBackgroundColor() const
+{
+ if (m_currentContent.contentType == PixmapContentType && !m_currentContent.pixmap.hasAlphaChannel())
+ return Color(0, 0, 0);
+ // We return a transparent color so that the tiles initialize with alpha.
+ return Color(0, 0, 0, 0);
+}
+
+IntRect GraphicsLayerQtImpl::tiledBackingStoreVisibleRect()
+{
+ const QGraphicsView* view = scene()->views().isEmpty() ? 0 : scene()->views().first();
+ if (!view)
+ return mapFromScene(scene()->sceneRect()).boundingRect().toAlignedRect();
+
+ // All we get is the viewport's visible region. We have to map it to the scene and then to item coordinates.
+ return mapFromScene(view->mapToScene(view->viewport()->visibleRegion().boundingRect()).boundingRect()).boundingRect().toAlignedRect();
+}
+#endif
+
+void GraphicsLayerQtImpl::notifyAnimationStarted()
+{
+ // WebCore notifies javascript when the animation starts. Here we're letting it know.
+ m_layer->client()->notifyAnimationStarted(m_layer, /* DOM time */ WTF::currentTime());
+}
+
+GraphicsLayerQt::GraphicsLayerQt(GraphicsLayerClient* client)
+ : GraphicsLayer(client)
+ , m_impl(PassOwnPtr<GraphicsLayerQtImpl>(new GraphicsLayerQtImpl(this)))
+{
+}
+
+GraphicsLayerQt::~GraphicsLayerQt()
+{
+}
+
+// This is the hook for WebCore compositor to know that Qt implements compositing with GraphicsLayerQt.
+PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client)
+{
+ return new GraphicsLayerQt(client);
+}
+
+/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display.
+*/
+void GraphicsLayerQt::setNeedsDisplay()
+{
+ m_impl->m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), QSize(size().width(), size().height())));
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setNeedsDisplayInRect(const FloatRect& rect)
+{
+ m_impl->m_pendingContent.regionToUpdate |= QRectF(rect).toAlignedRect();
+ m_impl->notifyChange(GraphicsLayerQtImpl::DisplayChange);
+}
+
+void GraphicsLayerQt::setContentsNeedsDisplay()
+{
+ switch (m_impl->m_pendingContent.contentType) {
+ case GraphicsLayerQtImpl::MediaContentType:
+ if (!m_impl->m_pendingContent.mediaLayer)
+ return;
+ m_impl->m_pendingContent.mediaLayer.data()->update();
+ break;
+ default:
+ setNeedsDisplay();
+ break;
+ }
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setName(const String& name)
+{
+ m_impl->setObjectName(name);
+ GraphicsLayer::setName(name);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setParent(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::setParent(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerQt::setChildren(const Vector<GraphicsLayer*>& children)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return GraphicsLayer::setChildren(children);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChild(GraphicsLayer* layer)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ GraphicsLayer::addChild(layer);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildAtIndex(GraphicsLayer* layer, int index)
+{
+ GraphicsLayer::addChildAtIndex(layer, index);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+ GraphicsLayer::addChildAbove(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling)
+{
+
+ GraphicsLayer::addChildBelow(layer, sibling);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+bool GraphicsLayerQt::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild)
+{
+ if (GraphicsLayer::replaceChild(oldChild, newChild)) {
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenChange);
+ return true;
+ }
+
+ return false;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::removeFromParent()
+{
+ if (parent())
+ m_impl->notifyChange(GraphicsLayerQtImpl::ParentChange);
+ GraphicsLayer::removeFromParent();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setMaskLayer(GraphicsLayer* value)
+{
+ if (value == maskLayer())
+ return;
+ GraphicsLayer::setMaskLayer(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MaskLayerChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setPosition(const FloatPoint& value)
+{
+ if (value == position())
+ return;
+ GraphicsLayer::setPosition(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::PositionChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setAnchorPoint(const FloatPoint3D& value)
+{
+ if (value == anchorPoint())
+ return;
+ GraphicsLayer::setAnchorPoint(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::AnchorPointChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setSize(const FloatSize& value)
+{
+ if (value == size())
+ return;
+ GraphicsLayer::setSize(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::SizeChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setTransform(const TransformationMatrix& value)
+{
+ if (value == transform())
+ return;
+ GraphicsLayer::setTransform(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::TransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setChildrenTransform(const TransformationMatrix& value)
+{
+ if (value == childrenTransform())
+ return;
+ GraphicsLayer::setChildrenTransform(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ChildrenTransformChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setPreserves3D(bool value)
+{
+ if (value == preserves3D())
+ return;
+ GraphicsLayer::setPreserves3D(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::Preserves3DChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setMasksToBounds(bool value)
+{
+ if (value == masksToBounds())
+ return;
+ GraphicsLayer::setMasksToBounds(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::MasksToBoundsChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setDrawsContent(bool value)
+{
+ if (value == drawsContent())
+ return;
+ m_impl->notifyChange(GraphicsLayerQtImpl::DrawsContentChange);
+ GraphicsLayer::setDrawsContent(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+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);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::clearBackgroundColor()
+{
+ if (!m_impl->m_pendingContent.backgroundColor.isValid())
+ return;
+ m_impl->m_pendingContent.backgroundColor = QColor();
+ GraphicsLayer::clearBackgroundColor();
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackgroundColorChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsOpaque(bool value)
+{
+ if (value == contentsOpaque())
+ return;
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOpaqueChange);
+ GraphicsLayer::setContentsOpaque(value);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setBackfaceVisibility(bool value)
+{
+ if (value == backfaceVisibility())
+ return;
+ GraphicsLayer::setBackfaceVisibility(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::BackfaceVisibilityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setOpacity(float value)
+{
+ if (value == opacity())
+ return;
+ GraphicsLayer::setOpacity(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsRect(const IntRect& value)
+{
+ if (value == contentsRect())
+ return;
+ GraphicsLayer::setContentsRect(value);
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsRectChange);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsToImage(Image* image)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::HTMLContentType;
+ GraphicsLayer::setContentsToImage(image);
+ if (image) {
+ QPixmap* pxm = image->nativeImageForCurrentFrame();
+ if (pxm) {
+ m_impl->m_pendingContent.pixmap = *pxm;
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::PixmapContentType;
+ return;
+ }
+ }
+ m_impl->m_pendingContent.pixmap = QPixmap();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsBackgroundColor(const Color& color)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::ColorContentType;
+ m_impl->m_pendingContent.contentsBackgroundColor = QColor(color);
+ GraphicsLayer::setContentsBackgroundColor(color);
+}
+
+#if ENABLE(3D_CANVAS)
+void GraphicsLayerQt::setContentsToGraphicsContext3D(const GraphicsContext3D* ctx)
+{
+ if (ctx == m_impl->m_gc3D)
+ return;
+
+ m_impl->m_pendingContent.contentType = GraphicsLayerQtImpl::Canvas3DContentType;
+ m_impl->m_gc3D = ctx;
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentChange);
+}
+
+void GraphicsLayerQt::setGraphicsContext3DNeedsDisplay()
+{
+ setNeedsDisplay();
+}
+#endif
+
+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 (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::setContentsOrientation(CompositingCoordinatesOrientation orientation)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::ContentsOrientationChange);
+ GraphicsLayer::setContentsOrientation(orientation);
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::distributeOpacity(float o)
+{
+ m_impl->notifyChange(GraphicsLayerQtImpl::OpacityChange);
+ m_impl->m_state.distributeOpacity = true;
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+float GraphicsLayerQt::accumulatedOpacity() const
+{
+ return m_impl->effectiveOpacity();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::syncCompositingState()
+{
+ m_impl->flushChanges();
+ GraphicsLayer::syncCompositingState();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+void GraphicsLayerQt::syncCompositingStateForThisLayerOnly()
+{
+ // We can't call flushChanges recursively here
+ m_impl->flushChanges(false);
+ GraphicsLayer::syncCompositingStateForThisLayerOnly();
+}
+
+/* \reimp (GraphicsLayer.h)
+*/
+PlatformLayer* GraphicsLayerQt::platformLayer() const
+{
+ return m_impl.get();
+}
+
+// Now we start dealing with WebCore animations translated to Qt animations
+
+template <typename T>
+struct KeyframeValueQt {
+ const TimingFunction* timingFunction;
+ T value;
+};
+
+/* Copied from AnimationBase.cpp
+*/
+static inline double solveEpsilon(double duration)
+{
+ return 1.0 / (200.0 * duration);
+}
+
+static inline double solveCubicBezierFunction(qreal p1x, qreal p1y, qreal p2x, qreal p2y, double t, double duration)
+{
+ UnitBezier bezier(p1x, p1y, p2x, p2y);
+ return bezier.solve(t, solveEpsilon(duration));
+}
+
+static inline double solveStepsFunction(int numSteps, bool stepAtStart, double t)
+{
+ if (stepAtStart)
+ return qMin(1.0, (floor(numSteps * t) + 1) / numSteps);
+ return floor(numSteps * t) / numSteps;
+}
+
+static inline qreal applyTimingFunction(const TimingFunction* timingFunction, qreal progress, double duration)
+{
+ // 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.
+
+ if (timingFunction->isCubicBezierTimingFunction()) {
+ const CubicBezierTimingFunction* ctf = static_cast<const CubicBezierTimingFunction*>(timingFunction);
+ return solveCubicBezierFunction(ctf->x1(),
+ ctf->y1(),
+ ctf->x2(),
+ ctf->y2(),
+ double(progress), double(duration) / 1000);
+ } else if (timingFunction->isStepsTimingFunction()) {
+ const StepsTimingFunction* stf = static_cast<const StepsTimingFunction*>(timingFunction);
+ return solveStepsFunction(stf->numberOfSteps(), stf->stepAtStart(), double(progress));
+ } else
+ return progress;
+}
+
+// Helper functions to safely get a value out of WebCore's AnimationValue*.
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, TransformOperations& transformOperations)
+{
+ transformOperations = TransformOperations();
+ if (!animationValue)
+ return;
+
+ if (const TransformOperations* ops = static_cast<const TransformAnimationValue*>(animationValue)->value())
+ transformOperations = *ops;
+}
+
+static void webkitAnimationToQtAnimationValue(const AnimationValue* animationValue, qreal& realValue)
+{
+ 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:
+ AnimationQtBase(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : QAbstractAnimation(0)
+ , m_layer(layer)
+ , m_boxSize(boxSize)
+ , m_duration(anim->duration() * 1000)
+ , m_isAlternate(anim->direction() == Animation::AnimationDirectionAlternate)
+ , m_webkitPropertyID(values.property())
+ , m_webkitAnimation(anim)
+ , m_keyframesName(name)
+ , m_fillsForwards(false)
+ {
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ QAbstractAnimation::updateState(newState, oldState);
+
+ // For some reason we have do this asynchronously - or the animation won't work.
+ if (newState == Running && oldState == Stopped && m_layer.data())
+ m_layer.data()->notifyAnimationStartedAsync();
+ }
+
+ virtual int duration() const { return m_duration; }
+
+ QWeakPointer<GraphicsLayerQtImpl> m_layer;
+ IntSize m_boxSize;
+ 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;
+// Since we know the types that we're dealing with, the QObject/QProperty/QVariant abstraction
+// buys us very little in this case, for too much overhead.
+template <typename T>
+class AnimationQt : public AnimationQtBase {
+
+public:
+ AnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQtBase(layer, values, boxSize, anim, name)
+ {
+ // Copying those WebCore structures is not trivial, we have to do it like this.
+ for (size_t i = 0; i < values.size(); ++i) {
+ const AnimationValue* animationValue = values.at(i);
+ KeyframeValueQt<T> keyframeValue;
+ if (animationValue->timingFunction())
+ keyframeValue.timingFunction = animationValue->timingFunction();
+ else
+ keyframeValue.timingFunction = anim->timingFunction().get();
+ webkitAnimationToQtAnimationValue(animationValue, keyframeValue.value);
+ m_keyframeValues[animationValue->keyTime()] = keyframeValue;
+ }
+ }
+
+protected:
+
+ // This is the part that differs between animated properties.
+ virtual void applyFrame(const T& fromValue, const T& toValue, qreal progress) = 0;
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+#if QT_DEBUG_FPS
+ if (newState == Running && oldState == Stopped) {
+ qDebug("Animation Started!");
+ m_fps.frames = 0;
+ m_fps.duration.start();
+ } else if (newState == Stopped && oldState == Running) {
+ const int duration = m_fps.duration.elapsed();
+ qDebug("Animation Ended! %dms [%f FPS]", duration,
+ (1000 / (((float)duration) / m_fps.frames)));
+ }
+#endif
+ AnimationQtBase::updateState(newState, oldState);
+ }
+
+ virtual void updateCurrentTime(int currentTime)
+ {
+ if (!m_layer)
+ return;
+
+ qreal progress = qreal(currentLoopTime()) / duration();
+
+ if (m_isAlternate && currentLoop()%2)
+ progress = 1-progress;
+
+ if (m_keyframeValues.isEmpty())
+ return;
+
+ // Find the current from-to keyframes in our little map.
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it = m_keyframeValues.find(progress);
+
+ // We didn't find an exact match, we try the closest match (lower bound).
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.lowerBound(progress)-1;
+
+ // We didn't find any match; use the first keyframe.
+ if (it == m_keyframeValues.end())
+ it = m_keyframeValues.begin();
+
+ typename QMap<qreal, KeyframeValueQt<T> >::iterator it2 = it + 1;
+ if (it2 == m_keyframeValues.end())
+ it2 = it;
+ const KeyframeValueQt<T>& fromKeyframe = it.value();
+ const KeyframeValueQt<T>& toKeyframe = it2.value();
+
+ const TimingFunction* timingFunc = fromKeyframe.timingFunction;
+ const T& fromValue = fromKeyframe.value;
+ const T& toValue = toKeyframe.value;
+
+ // Now we have a source keyframe, origin keyframe and a timing function.
+ // 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());
+ applyFrame(fromValue, toValue, progress);
+#if QT_DEBUG_FPS
+ ++m_fps.frames;
+#endif
+ }
+
+ QMap<qreal, KeyframeValueQt<T> > m_keyframeValues;
+#if QT_DEBUG_FPS
+ struct {
+ QTime duration;
+ int frames;
+ } m_fps;
+#endif
+};
+
+class TransformAnimationQt : public AnimationQt<TransformOperations> {
+public:
+ TransformAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString & name)
+ : AnimationQt<TransformOperations>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ ~TransformAnimationQt()
+ {
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ }
+
+ // The idea is that we let WebCore manage the transform operations and Qt just manage the
+ // animation heartbeat and the bottom-line QTransform. We gain performance, not by using
+ // Transform instead of TransformationMatrix, but by proper caching of items that are
+ // expensive for WebCore to render. We want the rest to be as close to WebCore's idea as possible.
+ virtual void applyFrame(const TransformOperations& sourceOperations, const TransformOperations& targetOperations, qreal progress)
+ {
+ TransformationMatrix transformMatrix;
+
+ 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()->m_layer->setTransform(transformMatrix);
+ // We force the actual opacity change, otherwise it would be ignored because of the animation.
+ m_layer.data()->setBaseTransform(transformMatrix);
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ AnimationQt<TransformOperations>::updateState(newState, oldState);
+ if (!m_layer)
+ return;
+
+ m_layer.data()->flushChanges(true);
+
+ // To increase FPS, we use a less accurate caching mechanism while animation is going on
+ // this is a UX choice that should probably be customizable.
+ if (newState == QAbstractAnimation::Running) {
+ m_sourceMatrix = m_layer.data()->m_layer->transform();
+ m_layer.data()->m_transformAnimationRunning = true;
+ } else if (newState == QAbstractAnimation::Stopped) {
+ // We update the transform back to the default. This already takes fill-modes into account.
+ m_layer.data()->m_transformAnimationRunning = false;
+ if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
+ }
+ }
+
+ TransformationMatrix m_sourceMatrix;
+};
+
+class OpacityAnimationQt : public AnimationQt<qreal> {
+public:
+ OpacityAnimationQt(GraphicsLayerQtImpl* layer, const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const QString& name)
+ : AnimationQt<qreal>(layer, values, boxSize, anim, name)
+ {
+ }
+
+ ~OpacityAnimationQt()
+ {
+ if (m_fillsForwards)
+ setCurrentTime(1);
+ }
+
+ virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
+ {
+ 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()->scene() && !m_layer.data()->opacity() && opacity)
+ m_layer.data()->scene()->update();
+
+ m_layer.data()->m_layer->setOpacity(opacity);
+ // We force the actual opacity change, otherwise it would be ignored because of the animation.
+ m_layer.data()->setOpacity(opacity);
+ }
+
+ virtual void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
+ {
+ AnimationQt<qreal>::updateState(newState, oldState);
+
+ if (m_layer)
+ m_layer.data()->m_opacityAnimationRunning = (newState == QAbstractAnimation::Running);
+
+ // If stopped, we update the opacity back to the default. This already takes fill-modes into account.
+ if (newState == Stopped)
+ if (m_layer && m_layer.data()->m_layer)
+ m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity());
+
+ }
+};
+
+bool GraphicsLayerQt::addAnimation(const KeyframeValueList& values, const IntSize& boxSize, const Animation* anim, const String& keyframesName, double timeOffset)
+{
+ if (!anim->duration() || !anim->iterationCount())
+ return false;
+
+ AnimationQtBase* newAnim = 0;
+
+ // Fixed: we might already have the Qt animation object associated with this WebCore::Animation object.
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (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;
+ }
+ }
+
+ 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 to avoid flicker.
+ m_impl->flushChanges(false);
+
+ // Qhen fill-mode is backwards/both, we set the value to 0 before the delay takes place.
+ if (anim->fillsBackwards())
+ newAnim->setCurrentTime(0);
+
+ 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.
+
+ return true;
+}
+
+void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_webkitPropertyID == id) {
+ // We need to stop the animation right away, or it might flicker before it's deleted.
+ anim->stop();
+ anim->deleteLater();
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+}
+
+void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_keyframesName == QString(name)) {
+ // We need to stop the animation right away, or it might flicker before it's deleted.
+ anim->stop();
+ anim->deleteLater();
+ it = m_impl->m_animations.erase(it);
+ --it;
+ }
+ }
+}
+
+void GraphicsLayerQt::pauseAnimation(const String& name, double timeOffset)
+{
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (!(*it))
+ continue;
+
+ AnimationQtBase* anim = static_cast<AnimationQtBase*>(it->data());
+ if (anim && anim->m_keyframesName == QString(name)) {
+ // we synchronize the animation's clock to WebCore's timeOffset
+ anim->setCurrentTime(timeOffset * 1000);
+ anim->pause();
+ }
+ }
+}
+
+void GraphicsLayerQt::suspendAnimations(double time)
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ m_impl->m_suspendTimer.start(time * 1000);
+ } else {
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (QAbstractAnimation* anim = it->data())
+ anim->pause();
+ }
+ }
+}
+
+void GraphicsLayerQt::resumeAnimations()
+{
+ if (m_impl->m_suspendTimer.isActive()) {
+ m_impl->m_suspendTimer.stop();
+ QList<QWeakPointer<QAbstractAnimation> >::iterator it;
+ for (it = m_impl->m_animations.begin(); it != m_impl->m_animations.end(); ++it) {
+ if (QAbstractAnimation* anim = it->data())
+ anim->resume();
+ }
+ }
+}
+
+#endif // QT_NO_ANIMATION
+}
+
+#include <GraphicsLayerQt.moc>
diff --git a/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h
new file mode 100644
index 0000000..b1692d2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2009 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 GraphicsLayerQt_h
+#define GraphicsLayerQt_h
+
+#if ENABLE(3D_CANVAS)
+#include "GraphicsContext3D.h"
+#endif
+#include "GraphicsLayer.h"
+#include "GraphicsLayerClient.h"
+
+namespace WebCore {
+
+class GraphicsLayerQtImpl;
+
+class GraphicsLayerQt : public GraphicsLayer {
+ friend class GraphicsLayerQtImpl;
+
+public:
+ GraphicsLayerQt(GraphicsLayerClient*);
+ virtual ~GraphicsLayerQt();
+
+ // reimps from GraphicsLayer.h
+ virtual PlatformLayer* platformLayer() const;
+ virtual void setNeedsDisplay();
+ virtual void setNeedsDisplayInRect(const FloatRect&);
+ virtual void setParent(GraphicsLayer* layer);
+ virtual void setName(const String& name);
+ virtual bool setChildren(const Vector<GraphicsLayer*>&);
+ virtual void addChild(GraphicsLayer*);
+ virtual void addChildAtIndex(GraphicsLayer*, int index);
+ virtual void addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual void addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling);
+ virtual bool replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild);
+ virtual void removeFromParent();
+ virtual void setMaskLayer(GraphicsLayer* layer);
+ virtual void setPosition(const FloatPoint& p);
+ virtual void setAnchorPoint(const FloatPoint3D& p);
+ virtual void setSize(const FloatSize& size);
+ virtual void setTransform(const TransformationMatrix& t);
+ virtual void setChildrenTransform(const TransformationMatrix& t);
+ virtual void setPreserves3D(bool b);
+ virtual void setMasksToBounds(bool b);
+ virtual void setDrawsContent(bool b);
+ virtual void setBackgroundColor(const Color&);
+ virtual void clearBackgroundColor();
+ virtual void setContentsOpaque(bool b);
+ 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 setContentsNeedsDisplay();
+ virtual void setContentsToMedia(PlatformLayer*);
+ virtual void setContentsBackgroundColor(const Color&);
+#if ENABLE(3D_CANVAS)
+ virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*);
+ virtual void setGraphicsContext3DNeedsDisplay();
+#endif
+ virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
+ virtual void distributeOpacity(float);
+ virtual float accumulatedOpacity() const;
+ virtual void syncCompositingState();
+ virtual void syncCompositingStateForThisLayerOnly();
+
+private:
+ OwnPtr<GraphicsLayerQtImpl> m_impl;
+};
+
+}
+#endif // GraphicsLayerQt_h
diff --git a/Source/WebCore/platform/graphics/qt/IconQt.cpp b/Source/WebCore/platform/graphics/qt/IconQt.cpp
new file mode 100644
index 0000000..eb09eda
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IconQt.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * 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 "Icon.h"
+
+#include "GraphicsContext.h"
+#include "PlatformString.h"
+#include "IntRect.h"
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qrect.h>
+#include <qglobal.h>
+
+namespace WebCore {
+
+Icon::Icon()
+{
+}
+
+Icon::~Icon()
+{
+}
+
+// FIXME: Move the code to ChromeClient::iconForFiles().
+PassRefPtr<Icon> Icon::createIconForFiles(const Vector<String>& filenames)
+{
+ if (filenames.isEmpty())
+ return 0;
+
+ if (filenames.size() == 1) {
+ RefPtr<Icon> i = adoptRef(new Icon);
+ i->m_icon = QIcon(filenames[0]);
+ return i.release();
+ }
+
+ //FIXME: Implement this
+ return 0;
+}
+
+void Icon::paint(GraphicsContext* ctx, const IntRect& rect)
+{
+ QPixmap px = m_icon.pixmap(rect.size());
+ QPainter *p = static_cast<QPainter*>(ctx->platformContext());
+ if (p && !px.isNull())
+ p->drawPixmap(rect.x(), rect.y(), px);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferData.h b/Source/WebCore/platform/graphics/qt/ImageBufferData.h
new file mode 100644
index 0000000..aa32253
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageBufferData.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2008 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageBufferData_h
+#define ImageBufferData_h
+
+#include "Image.h"
+#include <wtf/RefPtr.h>
+
+#include <QPainter>
+#include <QPixmap>
+
+#include "OwnPtr.h"
+
+namespace WebCore {
+
+class IntSize;
+
+class ImageBufferData {
+public:
+ ImageBufferData(const IntSize&);
+
+ QPixmap m_pixmap;
+ OwnPtr<QPainter> m_painter;
+ RefPtr<Image> m_image;
+};
+
+} // namespace WebCore
+
+#endif // ImageBufferData_h
diff --git a/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp
new file mode 100644
index 0000000..f56603d
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageBufferQt.cpp
@@ -0,0 +1,412 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageBuffer.h"
+
+#include "GraphicsContext.h"
+#include "ImageData.h"
+#include "MIMETypeRegistry.h"
+#include "StillImageQt.h"
+#include "TransparencyLayer.h"
+#include <wtf/text/CString.h>
+#include <wtf/text/StringConcatenate.h>
+
+#include <QBuffer>
+#include <QColor>
+#include <QImage>
+#include <QImageWriter>
+#include <QPainter>
+#include <QPixmap>
+#include <math.h>
+
+namespace WebCore {
+
+ImageBufferData::ImageBufferData(const IntSize& size)
+ : m_pixmap(size)
+ , m_painter(0)
+{
+ if (m_pixmap.isNull())
+ return;
+
+ m_pixmap.fill(QColor(Qt::transparent));
+
+ QPainter* painter = new QPainter;
+ m_painter.set(painter);
+
+ if (!painter->begin(&m_pixmap))
+ return;
+
+ // Since ImageBuffer is used mainly for Canvas, explicitly initialize
+ // its painter's pen and brush with the corresponding canvas defaults
+ // NOTE: keep in sync with CanvasRenderingContext2D::State
+ QPen pen = painter->pen();
+ pen.setColor(Qt::black);
+ pen.setWidth(1);
+ pen.setCapStyle(Qt::FlatCap);
+ pen.setJoinStyle(Qt::SvgMiterJoin);
+ pen.setMiterLimit(10);
+ painter->setPen(pen);
+ QBrush brush = painter->brush();
+ brush.setColor(Qt::black);
+ painter->setBrush(brush);
+ painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
+
+ m_image = StillImage::createForRendering(&m_pixmap);
+}
+
+ImageBuffer::ImageBuffer(const IntSize& size, ColorSpace, RenderingMode, bool& success)
+ : m_data(size)
+ , m_size(size)
+{
+ success = m_data.m_painter && m_data.m_painter->isActive();
+ if (!success)
+ return;
+
+ m_context.set(new GraphicsContext(m_data.m_painter.get()));
+}
+
+ImageBuffer::~ImageBuffer()
+{
+}
+
+GraphicsContext* ImageBuffer::context() const
+{
+ ASSERT(m_data.m_painter->isActive());
+
+ return m_context.get();
+}
+
+bool ImageBuffer::drawsUsingCopy() const
+{
+ return false;
+}
+
+PassRefPtr<Image> ImageBuffer::copyImage() const
+{
+ return StillImage::create(m_data.m_pixmap);
+}
+
+void ImageBuffer::draw(GraphicsContext* destContext, ColorSpace styleColorSpace, const FloatRect& destRect, const FloatRect& srcRect,
+ CompositeOperator op, bool useLowQualityScale)
+{
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ destContext->drawImage(copy.get(), ColorSpaceDeviceRGB, destRect, srcRect, op, useLowQualityScale);
+ } else
+ destContext->drawImage(m_data.m_image.get(), styleColorSpace, destRect, srcRect, op, useLowQualityScale);
+}
+
+void ImageBuffer::drawPattern(GraphicsContext* destContext, const FloatRect& srcRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace styleColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ if (destContext == context()) {
+ // We're drawing into our own buffer. In order for this to work, we need to copy the source buffer first.
+ RefPtr<Image> copy = copyImage();
+ copy->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+ } else
+ m_data.m_image->drawPattern(destContext, srcRect, patternTransform, phase, styleColorSpace, op, destRect);
+}
+
+void ImageBuffer::clip(GraphicsContext* context, const FloatRect& floatRect) const
+{
+ QPixmap* nativeImage = m_data.m_image->nativeImageForCurrentFrame();
+ if (!nativeImage)
+ return;
+
+ IntRect rect = enclosingIntRect(floatRect);
+ QPixmap alphaMask = *nativeImage;
+ if (alphaMask.width() != rect.width() || alphaMask.height() != rect.height())
+ alphaMask = alphaMask.scaled(rect.width(), rect.height());
+
+ context->pushTransparencyLayerInternal(rect, 1.0, alphaMask);
+}
+
+void ImageBuffer::platformTransformColorSpace(const Vector<int>& lookUpTable)
+{
+ bool isPainting = m_data.m_painter->isActive();
+ if (isPainting)
+ m_data.m_painter->end();
+
+ QImage image = m_data.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+ ASSERT(!image.isNull());
+
+ uchar* bits = image.bits();
+ const int bytesPerLine = image.bytesPerLine();
+
+ for (int y = 0; y < m_size.height(); ++y) {
+ quint32* scanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < m_size.width(); ++x) {
+ QRgb& pixel = scanLine[x];
+ pixel = qRgba(lookUpTable[qRed(pixel)],
+ lookUpTable[qGreen(pixel)],
+ lookUpTable[qBlue(pixel)],
+ qAlpha(pixel));
+ }
+ }
+
+ m_data.m_pixmap = QPixmap::fromImage(image);
+
+ if (isPainting)
+ m_data.m_painter->begin(&m_data.m_pixmap);
+}
+
+template <Multiply multiplied>
+PassRefPtr<ByteArray> getImageData(const IntRect& rect, const ImageBufferData& imageData, const IntSize& size)
+{
+ RefPtr<ByteArray> result = ByteArray::create(rect.width() * rect.height() * 4);
+ unsigned char* data = result->data();
+
+ if (rect.x() < 0 || rect.y() < 0 || rect.right() > size.width() || rect.bottom() > size.height())
+ memset(data, 0, result->length());
+
+ int originx = rect.x();
+ int destx = 0;
+ if (originx < 0) {
+ destx = -originx;
+ originx = 0;
+ }
+ int endx = rect.right();
+ if (endx > size.width())
+ endx = size.width();
+ int numColumns = endx - originx;
+
+ int originy = rect.y();
+ int desty = 0;
+ if (originy < 0) {
+ desty = -originy;
+ originy = 0;
+ }
+ int endy = rect.bottom();
+ if (endy > size.height())
+ endy = size.height();
+ int numRows = endy - originy;
+
+ // NOTE: For unmultiplied data, we undo the premultiplication below.
+ QImage image = imageData.m_pixmap.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied);
+
+ ASSERT(!image.isNull());
+
+ const int bytesPerLine = image.bytesPerLine();
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ const uchar* bits = image.constBits();
+#else
+ const uchar* bits = image.bits();
+#endif
+
+ quint32* destRows = reinterpret_cast_ptr<quint32*>(&data[desty * rect.width() * 4 + destx * 4]);
+
+ if (multiplied == Unmultiplied) {
+ for (int y = 0; y < numRows; ++y) {
+ const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ QRgb pixel = scanLine[x + originx];
+ int alpha = qAlpha(pixel);
+ // Un-premultiply and convert RGB to BGR.
+ if (alpha == 255)
+ destRows[x] = (0xFF000000
+ | (qBlue(pixel) << 16)
+ | (qGreen(pixel) << 8)
+ | (qRed(pixel)));
+ else if (alpha > 0)
+ destRows[x] = ((alpha << 24)
+ | (((255 * qBlue(pixel)) / alpha)) << 16)
+ | (((255 * qGreen(pixel)) / alpha) << 8)
+ | ((255 * qRed(pixel)) / alpha);
+ else
+ destRows[x] = 0;
+ }
+ destRows += rect.width();
+ }
+ } else {
+ for (int y = 0; y < numRows; ++y) {
+ const quint32* scanLine = reinterpret_cast_ptr<const quint32*>(bits + (y + originy) * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ QRgb pixel = scanLine[x + originx];
+ // Convert RGB to BGR.
+ destRows[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
+
+ }
+ destRows += rect.width();
+ }
+ }
+
+ return result.release();
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Unmultiplied>(rect, m_data, m_size);
+}
+
+PassRefPtr<ByteArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect) const
+{
+ return getImageData<Premultiplied>(rect, m_data, m_size);
+}
+
+static inline unsigned int premultiplyABGRtoARGB(unsigned int x)
+{
+ unsigned int a = x >> 24;
+ if (a == 255)
+ return (x << 16) | ((x >> 16) & 0xff) | (x & 0xff00ff00);
+ unsigned int t = (x & 0xff00ff) * a;
+ t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
+ t = ((t << 16) | (t >> 16)) & 0xff00ff;
+
+ x = ((x >> 8) & 0xff) * a;
+ x = (x + ((x >> 8) & 0xff) + 0x80);
+ x &= 0xff00;
+ x |= t | (a << 24);
+ return x;
+}
+
+template <Multiply multiplied>
+void putImageData(ByteArray*& source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, ImageBufferData& data, const IntSize& size)
+{
+ ASSERT(sourceRect.width() > 0);
+ ASSERT(sourceRect.height() > 0);
+
+ int originx = sourceRect.x();
+ int destx = destPoint.x() + sourceRect.x();
+ ASSERT(destx >= 0);
+ ASSERT(destx < size.width());
+ ASSERT(originx >= 0);
+ ASSERT(originx <= sourceRect.right());
+
+ int endx = destPoint.x() + sourceRect.right();
+ ASSERT(endx <= size.width());
+
+ int numColumns = endx - destx;
+
+ int originy = sourceRect.y();
+ int desty = destPoint.y() + sourceRect.y();
+ ASSERT(desty >= 0);
+ ASSERT(desty < size.height());
+ ASSERT(originy >= 0);
+ ASSERT(originy <= sourceRect.bottom());
+
+ int endy = destPoint.y() + sourceRect.bottom();
+ ASSERT(endy <= size.height());
+ int numRows = endy - desty;
+
+ unsigned srcBytesPerRow = 4 * sourceSize.width();
+
+ // NOTE: For unmultiplied input data, we do the premultiplication below.
+ QImage image(numColumns, numRows, QImage::Format_ARGB32_Premultiplied);
+ uchar* bits = image.bits();
+ const int bytesPerLine = image.bytesPerLine();
+
+ const quint32* srcScanLine = reinterpret_cast_ptr<const quint32*>(source->data() + originy * srcBytesPerRow + originx * 4);
+
+ if (multiplied == Unmultiplied) {
+ for (int y = 0; y < numRows; ++y) {
+ quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ // Premultiply and convert BGR to RGB.
+ quint32 pixel = srcScanLine[x];
+ destScanLine[x] = premultiplyABGRtoARGB(pixel);
+ }
+ srcScanLine += sourceSize.width();
+ }
+ } else {
+ for (int y = 0; y < numRows; ++y) {
+ quint32* destScanLine = reinterpret_cast_ptr<quint32*>(bits + y * bytesPerLine);
+ for (int x = 0; x < numColumns; x++) {
+ // Convert BGR to RGB.
+ quint32 pixel = srcScanLine[x];
+ destScanLine[x] = ((pixel << 16) & 0xff0000) | ((pixel >> 16) & 0xff) | (pixel & 0xff00ff00);
+ }
+ srcScanLine += sourceSize.width();
+ }
+ }
+
+ bool isPainting = data.m_painter->isActive();
+ if (!isPainting)
+ data.m_painter->begin(&data.m_pixmap);
+ else {
+ data.m_painter->save();
+
+ // putImageData() should be unaffected by painter state
+ data.m_painter->resetTransform();
+ data.m_painter->setOpacity(1.0);
+ data.m_painter->setClipping(false);
+ }
+
+ data.m_painter->setCompositionMode(QPainter::CompositionMode_Source);
+ data.m_painter->drawImage(destx, desty, image);
+
+ if (!isPainting)
+ data.m_painter->end();
+ else
+ data.m_painter->restore();
+}
+
+void ImageBuffer::putUnmultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Unmultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+void ImageBuffer::putPremultipliedImageData(ByteArray* source, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint)
+{
+ putImageData<Premultiplied>(source, sourceSize, sourceRect, destPoint, m_data, m_size);
+}
+
+// We get a mimeType here but QImageWriter does not support mimetypes but
+// only formats (png, gif, jpeg..., xpm). So assume we get image/ as image
+// mimetypes and then remove the image/ to get the Qt format.
+String ImageBuffer::toDataURL(const String& mimeType, const double* quality) const
+{
+ ASSERT(MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType));
+
+ if (!mimeType.startsWith("image/"))
+ return "data:,";
+
+ // prepare our target
+ QByteArray data;
+ QBuffer buffer(&data);
+ buffer.open(QBuffer::WriteOnly);
+
+ if (quality && *quality >= 0.0 && *quality <= 1.0) {
+ if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), *quality * 100 + 0.5)) {
+ buffer.close();
+ return "data:,";
+ }
+ } else {
+ if (!m_data.m_pixmap.save(&buffer, mimeType.substring(sizeof "image").utf8().data(), 100)) {
+ buffer.close();
+ return "data:,";
+ }
+ }
+
+ buffer.close();
+
+ return makeString("data:", mimeType, ";base64,", data.toBase64().data());
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
new file mode 100644
index 0000000..2bbb9ce
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageDecoderQt.h"
+
+#include <QtCore/QByteArray>
+#include <QtCore/QBuffer>
+
+#include <QtGui/QImageReader>
+#include <qdebug.h>
+
+namespace WebCore {
+
+ImageDecoder* ImageDecoder::create(const SharedBuffer& data, ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+{
+ // We need at least 4 bytes to figure out what kind of image we're dealing with.
+ if (data.size() < 4)
+ return 0;
+
+ return new ImageDecoderQt(alphaOption, gammaAndColorProfileOption);
+}
+
+ImageDecoderQt::ImageDecoderQt(ImageSource::AlphaOption alphaOption, ImageSource::GammaAndColorProfileOption gammaAndColorProfileOption)
+ : ImageDecoder(alphaOption, gammaAndColorProfileOption)
+ , m_repetitionCount(cAnimationNone)
+{
+}
+
+ImageDecoderQt::~ImageDecoderQt()
+{
+}
+
+void ImageDecoderQt::setData(SharedBuffer* data, bool allDataReceived)
+{
+ if (failed())
+ return;
+
+ // No progressive loading possible
+ if (!allDataReceived)
+ return;
+
+ // Cache our own new data.
+ ImageDecoder::setData(data, allDataReceived);
+
+ // We expect to be only called once with allDataReceived
+ ASSERT(!m_buffer);
+ ASSERT(!m_reader);
+
+ // Attempt to load the data
+ QByteArray imageData = QByteArray::fromRawData(m_data->data(), m_data->size());
+ m_buffer.set(new QBuffer);
+ m_buffer->setData(imageData);
+ 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
+ m_reader->setQuality(49);
+
+ // QImageReader only allows retrieving the format before reading the image
+ m_format = m_reader->format();
+}
+
+bool ImageDecoderQt::isSizeAvailable()
+{
+ if (!ImageDecoder::isSizeAvailable() && m_reader)
+ internalDecodeSize();
+
+ return ImageDecoder::isSizeAvailable();
+}
+
+size_t ImageDecoderQt::frameCount()
+{
+ if (m_frameBufferCache.isEmpty() && m_reader) {
+ if (m_reader->supportsAnimation()) {
+ int imageCount = m_reader->imageCount();
+
+ // Fixup for Qt decoders... imageCount() is wrong
+ // and jumpToNextImage does not work either... so
+ // we will have to parse everything...
+ if (!imageCount)
+ forceLoadEverything();
+ else {
+ m_frameBufferCache.resize(imageCount);
+ for (size_t i = 0; i < m_frameBufferCache.size(); ++i)
+ m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
+ }
+ } else {
+ m_frameBufferCache.resize(1);
+ m_frameBufferCache[0].setPremultiplyAlpha(m_premultiplyAlpha);
+ }
+ }
+
+ return m_frameBufferCache.size();
+}
+
+int ImageDecoderQt::repetitionCount() const
+{
+ if (m_reader && m_reader->supportsAnimation())
+ m_repetitionCount = m_reader->loopCount();
+ return m_repetitionCount;
+}
+
+String ImageDecoderQt::filenameExtension() const
+{
+ return String(m_format.constData(), m_format.length());
+};
+
+RGBA32Buffer* ImageDecoderQt::frameBufferAtIndex(size_t index)
+{
+ // In case the ImageDecoderQt got recreated we don't know
+ // yet how many images we are going to have and need to
+ // find that out now.
+ size_t count = m_frameBufferCache.size();
+ if (!failed() && !count) {
+ internalDecodeSize();
+ count = frameCount();
+ }
+
+ if (index >= count)
+ return 0;
+
+ RGBA32Buffer& frame = m_frameBufferCache[index];
+ if (frame.status() != RGBA32Buffer::FrameComplete && m_reader)
+ internalReadImage(index);
+ return &frame;
+}
+
+void ImageDecoderQt::clearFrameBufferCache(size_t /*index*/)
+{
+}
+
+void ImageDecoderQt::internalDecodeSize()
+{
+ ASSERT(m_reader);
+
+ // If we have a QSize() something failed
+ QSize size = m_reader->size();
+ if (size.isEmpty()) {
+ setFailed();
+ return clearPointers();
+ }
+
+ setSize(size.width(), size.height());
+}
+
+void ImageDecoderQt::internalReadImage(size_t frameIndex)
+{
+ ASSERT(m_reader);
+
+ if (m_reader->supportsAnimation())
+ m_reader->jumpToImage(frameIndex);
+ else if (frameIndex) {
+ setFailed();
+ return clearPointers();
+ }
+
+ if (!internalHandleCurrentImage(frameIndex))
+ setFailed();
+
+ // Attempt to return some memory
+ for (int i = 0; i < m_frameBufferCache.size(); ++i) {
+ if (m_frameBufferCache[i].status() != RGBA32Buffer::FrameComplete)
+ return;
+ }
+
+ clearPointers();
+}
+
+bool ImageDecoderQt::internalHandleCurrentImage(size_t frameIndex)
+{
+ QPixmap pixmap;
+
+#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
+ pixmap = QPixmap::fromImageReader(m_reader.get());
+#else
+ QImage img;
+ if (m_reader->read(&img))
+ pixmap = QPixmap::fromImage(img);
+#endif
+
+ if (pixmap.isNull()) {
+ frameCount();
+ repetitionCount();
+ clearPointers();
+ return false;
+ }
+
+ // now into the RGBA32Buffer - even if the image is not
+ RGBA32Buffer* const buffer = &m_frameBufferCache[frameIndex];
+ buffer->setRect(m_reader->currentImageRect());
+ buffer->setStatus(RGBA32Buffer::FrameComplete);
+ buffer->setDuration(m_reader->nextImageDelay());
+ buffer->setPixmap(pixmap);
+ return true;
+}
+
+// The QImageIOHandler is not able to tell us how many frames
+// we have and we need to parse every image. We do this by
+// increasing the m_frameBufferCache by one and try to parse
+// the image. We stop when QImage::read fails and then need
+// to resize the m_frameBufferCache to the final size and update
+// the 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()
+{
+ int imageCount = 0;
+
+ do {
+ m_frameBufferCache.resize(++imageCount);
+ } while (internalHandleCurrentImage(imageCount - 1));
+
+ // If we failed decoding the first image we actually
+ // 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);
+ for (size_t i = 0; i < m_frameBufferCache.size(); ++i)
+ m_frameBufferCache[i].setPremultiplyAlpha(m_premultiplyAlpha);
+ if (imageCount == 1)
+ setFailed();
+}
+
+void ImageDecoderQt::clearPointers()
+{
+ m_reader.clear();
+ m_buffer.clear();
+}
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h
new file mode 100644
index 0000000..23fb79a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageDecoderQt.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 Friedemann Kleint <fkleint@trolltech.com>
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ImageDecoderQt_h
+#define ImageDecoderQt_h
+
+#include "ImageDecoder.h"
+#include <QtGui/QImageReader>
+#include <QtGui/QPixmap>
+#include <QtCore/QList>
+#include <QtCore/QHash>
+#include <QtCore/QBuffer>
+#include <wtf/OwnPtr.h>
+
+namespace WebCore {
+
+
+class ImageDecoderQt : public ImageDecoder
+{
+public:
+ ImageDecoderQt(ImageSource::AlphaOption, ImageSource::GammaAndColorProfileOption);
+ ~ImageDecoderQt();
+
+ virtual void setData(SharedBuffer* data, bool allDataReceived);
+ virtual bool isSizeAvailable();
+ virtual size_t frameCount();
+ virtual int repetitionCount() const;
+ virtual RGBA32Buffer* frameBufferAtIndex(size_t index);
+
+ virtual String filenameExtension() const;
+
+ virtual void clearFrameBufferCache(size_t clearBeforeFrame);
+
+private:
+ ImageDecoderQt(const ImageDecoderQt&);
+ ImageDecoderQt &operator=(const ImageDecoderQt&);
+
+private:
+ void internalDecodeSize();
+ void internalReadImage(size_t);
+ bool internalHandleCurrentImage(size_t);
+ void forceLoadEverything();
+ void clearPointers();
+
+private:
+ QByteArray m_format;
+ OwnPtr<QBuffer> m_buffer;
+ OwnPtr<QImageReader> m_reader;
+ mutable int m_repetitionCount;
+};
+
+
+
+}
+
+#endif
+
diff --git a/Source/WebCore/platform/graphics/qt/ImageQt.cpp b/Source/WebCore/platform/graphics/qt/ImageQt.cpp
new file mode 100644
index 0000000..49afd29
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/ImageQt.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2009 Torch Mobile Inc. http://www.torchmobile.com/
+ * Copyright (C) 2010 Sencha, Inc.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Image.h"
+
+#include "AffineTransform.h"
+#include "BitmapImage.h"
+#include "ContextShadow.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageObserver.h"
+#include "PlatformString.h"
+#include "StillImageQt.h"
+#include "qwebsettings.h"
+
+#include <QPixmap>
+#include <QPainter>
+#include <QImage>
+#include <QImageReader>
+#include <QTransform>
+
+#include <QDebug>
+
+#include <math.h>
+
+// This function loads resources into WebKit
+static QPixmap loadResourcePixmap(const char *name)
+{
+ QPixmap pixmap;
+ if (qstrcmp(name, "missingImage") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingImageGraphic);
+ else if (qstrcmp(name, "nullPlugin") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::MissingPluginGraphic);
+ else if (qstrcmp(name, "urlIcon") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DefaultFrameIconGraphic);
+ else if (qstrcmp(name, "textAreaResizeCorner") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::TextAreaSizeGripCornerGraphic);
+ else if (qstrcmp(name, "deleteButton") == 0)
+ pixmap = QWebSettings::webGraphic(QWebSettings::DeleteButtonGraphic);
+ else if (!qstrcmp(name, "inputSpeech"))
+ pixmap = QWebSettings::webGraphic(QWebSettings::InputSpeechButtonGraphic);
+
+ return pixmap;
+}
+
+namespace WebCore {
+
+bool FrameData::clear(bool clearMetadata)
+{
+ if (clearMetadata)
+ m_haveMetadata = false;
+
+ if (m_frame) {
+ delete m_frame;
+ m_frame = 0;
+ return true;
+ }
+ return false;
+}
+
+
+// ================================================
+// Image Class
+// ================================================
+
+PassRefPtr<Image> Image::loadPlatformResource(const char* name)
+{
+ return StillImage::create(loadResourcePixmap(name));
+}
+
+void Image::drawPattern(GraphicsContext* ctxt, const FloatRect& tileRect, const AffineTransform& patternTransform,
+ const FloatPoint& phase, ColorSpace, CompositeOperator op, const FloatRect& destRect)
+{
+ QPixmap* framePixmap = nativeImageForCurrentFrame();
+ if (!framePixmap) // If it's too early we won't have an image yet.
+ return;
+
+ // Qt interprets 0 width/height as full width/height so just short circuit.
+ QRectF dr = QRectF(destRect).normalized();
+ QRect tr = QRectF(tileRect).toRect().normalized();
+ if (!dr.width() || !dr.height() || !tr.width() || !tr.height())
+ return;
+
+ QPixmap pixmap = *framePixmap;
+ if (tr.x() || tr.y() || tr.width() != pixmap.width() || tr.height() != pixmap.height())
+ pixmap = pixmap.copy(tr);
+
+ CompositeOperator previousOperator = ctxt->compositeOperation();
+
+ ctxt->setCompositeOperation(op);
+ QPainter* p = ctxt->platformContext();
+ if (!pixmap.hasAlpha() && p->compositionMode() == QPainter::CompositionMode_SourceOver)
+ p->setCompositionMode(QPainter::CompositionMode_Source);
+
+ /* Translate the coordinates as phase is not in world matrix coordinate space but the tile rect origin is. */
+ QTransform transform(patternTransform);
+ transform *= QTransform().translate(phase.x(), phase.y());
+ transform.translate(tr.x(), tr.y());
+
+ QBrush b(pixmap);
+ b.setTransform(transform);
+ p->fillRect(dr, b);
+
+ ctxt->setCompositeOperation(previousOperator);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+BitmapImage::BitmapImage(QPixmap* pixmap, ImageObserver* observer)
+ : Image(observer)
+ , m_currentFrame(0)
+ , m_frames(0)
+ , m_frameTimer(0)
+ , m_repetitionCount(cAnimationNone)
+ , m_repetitionCountStatus(Unknown)
+ , m_repetitionsComplete(0)
+ , m_isSolidColor(false)
+ , m_checkedForSolidColor(false)
+ , m_animationFinished(true)
+ , m_allDataReceived(true)
+ , m_haveSize(true)
+ , m_sizeAvailable(true)
+ , m_decodedSize(0)
+ , m_haveFrameCount(true)
+ , m_frameCount(1)
+{
+ initPlatformData();
+
+ int width = pixmap->width();
+ int height = pixmap->height();
+ m_decodedSize = width * height * 4;
+ m_size = IntSize(width, height);
+
+ m_frames.grow(1);
+ m_frames[0].m_frame = pixmap;
+ m_frames[0].m_hasAlpha = pixmap->hasAlpha();
+ m_frames[0].m_haveMetadata = true;
+ checkForSolidColor();
+}
+
+void BitmapImage::initPlatformData()
+{
+}
+
+void BitmapImage::invalidatePlatformData()
+{
+}
+
+// Drawing Routines
+void BitmapImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, ColorSpace styleColorSpace, CompositeOperator op)
+{
+ QRectF normalizedDst = dst.normalized();
+ QRectF normalizedSrc = src.normalized();
+
+ startAnimation();
+
+ if (normalizedSrc.isEmpty() || normalizedDst.isEmpty())
+ return;
+
+ QPixmap* image = nativeImageForCurrentFrame();
+ if (!image)
+ return;
+
+ if (mayFillWithSolidColor()) {
+ fillWithSolidColor(ctxt, normalizedDst, solidColor(), styleColorSpace, op);
+ return;
+ }
+
+ QPainter* painter(ctxt->platformContext());
+
+ QPainter::CompositionMode compositionMode = GraphicsContext::toQtCompositionMode(op);
+
+ if (!image->hasAlpha() && painter->compositionMode() == QPainter::CompositionMode_SourceOver)
+ compositionMode = QPainter::CompositionMode_Source;
+
+ QPainter::CompositionMode lastCompositionMode = painter->compositionMode();
+ painter->setCompositionMode(compositionMode);
+
+ ContextShadow* shadow = ctxt->contextShadow();
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->drawPixmap(normalizedDst, *image, normalizedSrc);
+ shadow->endShadowLayer(ctxt);
+ }
+ }
+
+ // Test using example site at
+ // http://www.meyerweb.com/eric/css/edge/complexspiral/demo.html
+ painter->drawPixmap(normalizedDst, *image, normalizedSrc);
+
+ painter->setCompositionMode(lastCompositionMode);
+
+ if (imageObserver())
+ imageObserver()->didDraw(this);
+}
+
+void BitmapImage::checkForSolidColor()
+{
+ m_isSolidColor = false;
+ m_checkedForSolidColor = true;
+
+ if (frameCount() > 1)
+ return;
+
+ QPixmap* framePixmap = frameAtIndex(0);
+ if (!framePixmap || framePixmap->width() != 1 || framePixmap->height() != 1)
+ return;
+
+ m_isSolidColor = true;
+ m_solidColor = QColor::fromRgba(framePixmap->toImage().pixel(0, 0));
+}
+
+#if OS(WINDOWS)
+PassRefPtr<BitmapImage> BitmapImage::create(HBITMAP hBitmap)
+{
+ return BitmapImage::create(new QPixmap(QPixmap::fromWinHBITMAP(hBitmap)));
+}
+#endif
+
+}
+
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntPointQt.cpp b/Source/WebCore/platform/graphics/qt/IntPointQt.cpp
new file mode 100644
index 0000000..f9d336a
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntPointQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntPoint.h"
+
+#include <QPoint>
+
+namespace WebCore {
+
+IntPoint::IntPoint(const QPoint& p)
+ : m_x(p.x())
+ , m_y(p.y())
+{
+}
+
+IntPoint::operator QPoint() const
+{
+ return QPoint(m_x, m_y);
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntRectQt.cpp b/Source/WebCore/platform/graphics/qt/IntRectQt.cpp
new file mode 100644
index 0000000..ccc153e
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntRectQt.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IntRect.h"
+
+#include <QRect>
+
+namespace WebCore {
+
+IntRect::IntRect(const QRect& r)
+ : m_location(r.topLeft())
+ , m_size(r.width(), r.height())
+{
+}
+
+IntRect::operator QRect() const
+{
+ return QRect(x(), y(), width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp b/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp
new file mode 100644
index 0000000..4f2bf35
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/IntSizeQt.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <QSize>
+
+#include "IntSize.h"
+
+namespace WebCore {
+
+IntSize::IntSize(const QSize& r)
+ : m_width(r.width())
+ , m_height(r.height())
+{
+}
+
+IntSize::operator QSize() const
+{
+ return QSize(width(), height());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
new file mode 100644
index 0000000..b881036
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.cpp
@@ -0,0 +1,547 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ 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 "MediaPlayerPrivatePhonon.h"
+
+#include <limits>
+
+#include "FrameView.h"
+#include "GraphicsContext.h"
+#include "Logging.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 <QUrl>
+
+#include <phonon/audiooutput.h>
+#include <phonon/backendcapabilities.h>
+#include <phonon/path.h>
+#include <phonon/mediaobject.h>
+#include <phonon/videowidget.h>
+
+using namespace Phonon;
+
+#define LOG_MEDIAOBJECT() (LOG(Media, "%s", debugMediaObject(this, *m_mediaObject).constData()))
+
+#if !LOG_DISABLED
+static QByteArray debugMediaObject(WebCore::MediaPlayerPrivatePhonon* mediaPlayer, const MediaObject& mediaObject)
+{
+ QByteArray byteArray;
+ QTextStream stream(&byteArray);
+
+ const QMetaObject* metaObj = mediaPlayer->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+
+ stream << "debugMediaObject -> Phonon::MediaObject(";
+ stream << "State: " << phononStates.valueToKey(mediaObject.state());
+ stream << " | Current time: " << mediaObject.currentTime();
+ stream << " | Remaining time: " << mediaObject.remainingTime();
+ stream << " | Total time: " << mediaObject.totalTime();
+ stream << " | Meta-data: ";
+ QMultiMap<QString, QString> map = mediaObject.metaData();
+ for (QMap<QString, QString>::const_iterator it = map.constBegin();
+ it != map.constEnd(); ++it) {
+ stream << "(" << it.key() << ", " << it.value() << ")";
+ }
+ stream << " | Has video: " << mediaObject.hasVideo();
+ stream << " | Is seekable: " << mediaObject.isSeekable();
+ stream << ")";
+
+ stream.flush();
+
+ return byteArray;
+}
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivatePhonon::MediaPlayerPrivatePhonon(MediaPlayer* player)
+ : m_player(player)
+ , m_networkState(MediaPlayer::Empty)
+ , m_readyState(MediaPlayer::HaveNothing)
+ , m_mediaObject(new MediaObject())
+ , m_videoWidget(new VideoWidget(0))
+ , m_audioOutput(new AudioOutput())
+ , m_isVisible(false)
+{
+ // Hint to Phonon to disable overlay painting
+ m_videoWidget->setAttribute(Qt::WA_DontShowOnScreen);
+ m_videoWidget->setAttribute(Qt::WA_QuitOnClose, false);
+
+ createPath(m_mediaObject, m_videoWidget);
+ createPath(m_mediaObject, m_audioOutput);
+
+ // Make sure we get updates for each frame
+ m_videoWidget->installEventFilter(this);
+ foreach (QWidget* widget, qFindChildren<QWidget*>(m_videoWidget))
+ widget->installEventFilter(this);
+
+ connect(m_mediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),
+ this, SLOT(stateChanged(Phonon::State,Phonon::State)));
+ connect(m_mediaObject, SIGNAL(metaDataChanged()), this, SLOT(metaDataChanged()));
+ connect(m_mediaObject, SIGNAL(seekableChanged(bool)), this, SLOT(seekableChanged(bool)));
+ connect(m_mediaObject, SIGNAL(hasVideoChanged(bool)), this, SLOT(hasVideoChanged(bool)));
+ connect(m_mediaObject, SIGNAL(bufferStatus(int)), this, SLOT(bufferStatus(int)));
+ connect(m_mediaObject, SIGNAL(finished()), this, SLOT(finished()));
+ connect(m_mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)),
+ this, SLOT(currentSourceChanged(Phonon::MediaSource)));
+ connect(m_mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish()));
+ connect(m_mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
+}
+
+MediaPlayerPrivateInterface* MediaPlayerPrivatePhonon::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivatePhonon(player);
+}
+
+void MediaPlayerPrivatePhonon::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ if (isAvailable())
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+
+MediaPlayerPrivatePhonon::~MediaPlayerPrivatePhonon()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting videowidget");
+ m_videoWidget->close();
+ delete m_videoWidget;
+ m_videoWidget = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting audiooutput");
+ delete m_audioOutput;
+ m_audioOutput = 0;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::dtor deleting mediaobject");
+ delete m_mediaObject;
+ m_mediaObject = 0;
+}
+
+HashSet<String>& MediaPlayerPrivatePhonon::supportedTypesCache()
+{
+ 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;
+}
+
+void MediaPlayerPrivatePhonon::getSupportedTypes(HashSet<String>& types)
+{
+ types = supportedTypesCache();
+}
+
+MediaPlayer::SupportsType MediaPlayerPrivatePhonon::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;
+}
+
+bool MediaPlayerPrivatePhonon::hasVideo() const
+{
+ bool hasVideo = m_mediaObject->hasVideo();
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideo() -> %s", hasVideo ? "true" : "false");
+ return hasVideo;
+}
+
+bool MediaPlayerPrivatePhonon::hasAudio() const
+{
+ // FIXME: Phonon::MediaObject does not have such a hasAudio() function
+ bool hasAudio = true;
+ LOG(Media, "MediaPlayerPrivatePhonon::hasAudio() -> %s", hasAudio ? "true" : "false");
+ return hasAudio;
+}
+
+void MediaPlayerPrivatePhonon::load(const String& url)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::load(\"%s\")", url.utf8().data());
+
+ // 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();
+ }
+
+ m_mediaObject->setCurrentSource(QUrl(url));
+ m_audioOutput->setVolume(m_player->volume());
+ setVisible(m_player->visible());
+}
+
+void MediaPlayerPrivatePhonon::cancelLoad()
+{
+ notImplemented();
+}
+
+
+void MediaPlayerPrivatePhonon::play()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::play()");
+ m_mediaObject->play();
+}
+
+void MediaPlayerPrivatePhonon::pause()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::pause()");
+ m_mediaObject->pause();
+}
+
+
+bool MediaPlayerPrivatePhonon::paused() const
+{
+ bool paused = m_mediaObject->state() == Phonon::PausedState;
+ LOG(Media, "MediaPlayerPrivatePhonon::paused() --> %s", paused ? "true" : "false");
+ return paused;
+}
+
+void MediaPlayerPrivatePhonon::seek(float position)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::seek(%f)", position);
+
+ if (!m_mediaObject->isSeekable())
+ return;
+
+ if (position > duration())
+ position = duration();
+
+ m_mediaObject->seek(position * 1000.0f);
+}
+
+bool MediaPlayerPrivatePhonon::seeking() const
+{
+ return false;
+}
+
+float MediaPlayerPrivatePhonon::duration() const
+{
+ if (m_readyState < MediaPlayer::HaveMetadata)
+ return 0.0f;
+
+ float duration = m_mediaObject->totalTime() / 1000.0f;
+
+ if (duration == 0.0f) // We are streaming
+ duration = std::numeric_limits<float>::infinity();
+
+ LOG(Media, "MediaPlayerPrivatePhonon::duration() --> %f", duration);
+ return duration;
+}
+
+float MediaPlayerPrivatePhonon::currentTime() const
+{
+ float currentTime = m_mediaObject->currentTime() / 1000.0f;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::currentTime() --> %f", currentTime);
+ return currentTime;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivatePhonon::buffered() const
+{
+ notImplemented();
+ return TimeRanges::create();
+}
+
+float MediaPlayerPrivatePhonon::maxTimeSeekable() const
+{
+ notImplemented();
+ return 0.0f;
+}
+
+unsigned MediaPlayerPrivatePhonon::bytesLoaded() const
+{
+ notImplemented();
+ return 0;
+}
+
+unsigned MediaPlayerPrivatePhonon::totalBytes() const
+{
+ //notImplemented();
+ return 0;
+}
+
+void MediaPlayerPrivatePhonon::setRate(float)
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivatePhonon::setVolume(float volume)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setVolume()");
+ m_audioOutput->setVolume(volume);
+}
+
+void MediaPlayerPrivatePhonon::setMuted(bool muted)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::setMuted()");
+ m_audioOutput->setMuted(muted);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivatePhonon::networkState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::networkState() --> %s", networkStates.valueToKey(m_networkState));
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivatePhonon::readyState() const
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::readyState() --> %s", readyStates.valueToKey(m_readyState));
+ return m_readyState;
+}
+
+void MediaPlayerPrivatePhonon::updateStates()
+{
+ MediaPlayer::NetworkState oldNetworkState = m_networkState;
+ MediaPlayer::ReadyState oldReadyState = m_readyState;
+
+ Phonon::State phononState = m_mediaObject->state();
+
+ if (phononState == Phonon::StoppedState) {
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ m_networkState = MediaPlayer::Loading; // FIXME: should this be MediaPlayer::Idle?
+ m_readyState = MediaPlayer::HaveMetadata;
+ m_mediaObject->pause();
+ }
+ } else if (phononState == Phonon::PausedState) {
+ m_networkState = MediaPlayer::Loaded;
+ m_readyState = MediaPlayer::HaveEnoughData;
+ } else if (phononState == Phonon::ErrorState) {
+ if (!m_mediaObject || m_mediaObject->errorType() == Phonon::FatalError) {
+ // FIXME: is it possile to differentiate between different types of errors
+ m_networkState = MediaPlayer::NetworkError;
+ m_readyState = MediaPlayer::HaveNothing;
+ cancelLoad();
+ } else
+ m_mediaObject->pause();
+ }
+
+ if (seeking())
+ m_readyState = MediaPlayer::HaveNothing;
+
+ if (m_networkState != oldNetworkState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum networkStates = metaObj->enumerator(metaObj->indexOfEnumerator("NetworkState"));
+ LOG(Media, "Network state changed from '%s' to '%s'",
+ networkStates.valueToKey(oldNetworkState),
+ networkStates.valueToKey(m_networkState));
+ m_player->networkStateChanged();
+ }
+
+ if (m_readyState != oldReadyState) {
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum readyStates = metaObj->enumerator(metaObj->indexOfEnumerator("ReadyState"));
+ LOG(Media, "Ready state changed from '%s' to '%s'",
+ readyStates.valueToKey(oldReadyState),
+ readyStates.valueToKey(m_readyState));
+ m_player->readyStateChanged();
+ }
+}
+
+void MediaPlayerPrivatePhonon::setVisible(bool visible)
+{
+ m_isVisible = visible;
+ LOG(Media, "MediaPlayerPrivatePhonon::setVisible(%s)", visible ? "true" : "false");
+
+ m_videoWidget->setVisible(m_isVisible);
+}
+
+void MediaPlayerPrivatePhonon::setSize(const IntSize& newSize)
+{
+ if (!m_videoWidget)
+ return;
+
+ LOG(Media, "MediaPlayerPrivatePhonon::setSize(%d,%d)",
+ newSize.width(), newSize.height());
+
+ QRect currentRect = m_videoWidget->rect();
+
+ if (newSize.width() != currentRect.width() || newSize.height() != currentRect.height())
+ m_videoWidget->resize(newSize.width(), newSize.height());
+}
+
+IntSize MediaPlayerPrivatePhonon::naturalSize() const
+{
+ if (!hasVideo()) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ if (m_readyState < MediaPlayer::HaveMetadata) {
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ 0, 0);
+ return IntSize();
+ }
+
+ QSize videoSize = m_videoWidget->sizeHint();
+ IntSize naturalSize(videoSize.width(), videoSize.height());
+ LOG(Media, "MediaPlayerPrivatePhonon::naturalSize() -> %dx%d",
+ naturalSize.width(), naturalSize.height());
+ return naturalSize;
+}
+
+bool MediaPlayerPrivatePhonon::eventFilter(QObject* obj, QEvent* event)
+{
+ if (event->type() == QEvent::UpdateRequest)
+ m_player->repaint();
+
+ return QObject::eventFilter(obj, event);
+}
+
+void MediaPlayerPrivatePhonon::paint(GraphicsContext* graphicsContect, const IntRect& rect)
+{
+ if (graphicsContect->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ QPainter* painter = graphicsContect->platformContext();
+
+ painter->fillRect(rect, Qt::black);
+
+ m_videoWidget->render(painter, QPoint(rect.x(), rect.y()),
+ QRegion(0, 0, rect.width(), rect.height()));
+}
+
+// ====================== Phonon::MediaObject signals ======================
+
+void MediaPlayerPrivatePhonon::stateChanged(Phonon::State newState, Phonon::State oldState)
+{
+ const QMetaObject* metaObj = this->metaObject();
+ QMetaEnum phononStates = metaObj->enumerator(metaObj->indexOfEnumerator("PhononState"));
+ LOG(Media, "MediaPlayerPrivatePhonon::stateChanged(newState=%s, oldState=%s)",
+ phononStates.valueToKey(newState), phononStates.valueToKey(oldState));
+
+ updateStates();
+}
+
+void MediaPlayerPrivatePhonon::metaDataChanged()
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::metaDataChanged()");
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::seekableChanged(bool)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::hasVideoChanged(bool hasVideo)
+{
+ LOG(Media, "MediaPlayerPrivatePhonon::hasVideoChanged(%s)", hasVideo ? "true" : "false");
+}
+
+void MediaPlayerPrivatePhonon::bufferStatus(int)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::finished()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::currentSourceChanged(const Phonon::MediaSource&)
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::aboutToFinish()
+{
+ notImplemented();
+ LOG_MEDIAOBJECT();
+}
+
+void MediaPlayerPrivatePhonon::totalTimeChanged(qint64 totalTime)
+{
+#if OS(WINDOWS)
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%I64d)", totalTime);
+#else
+ LOG(Media, "MediaPlayerPrivatePhonon::totalTimeChanged(%lld)", totalTime);
+#endif
+ LOG_MEDIAOBJECT();
+}
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivatePhonon.cpp"
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
new file mode 100644
index 0000000..d793675
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivatePhonon.h
@@ -0,0 +1,153 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2009 Apple Inc. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ 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 MediaPlayerPrivatePhonon_h
+#define MediaPlayerPrivatePhonon_h
+
+#include "MediaPlayerPrivate.h"
+
+#include <QObject>
+#include <phononnamespace.h>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+class QUrl;
+
+namespace Phonon {
+ class MediaObject;
+ class VideoWidget;
+ class AudioOutput;
+ class MediaSource;
+}
+QT_END_NAMESPACE
+
+namespace WebCore {
+
+ class MediaPlayerPrivatePhonon : public QObject, public MediaPlayerPrivateInterface {
+
+ Q_OBJECT
+
+ public:
+ static void registerMediaEngine(MediaEngineRegistrar);
+ ~MediaPlayerPrivatePhonon();
+
+ // These enums are used for debugging
+ Q_ENUMS(ReadyState NetworkState PhononState)
+
+ enum ReadyState {
+ HaveNothing,
+ HaveMetadata,
+ HaveCurrentData,
+ HaveFutureData,
+ HaveEnoughData
+ };
+
+ enum NetworkState {
+ Empty,
+ Idle,
+ Loading,
+ Loaded,
+ FormatError,
+ NetworkError,
+ DecodeError
+ };
+
+ enum PhononState {
+ LoadingState,
+ StoppedState,
+ PlayingState,
+ BufferingState,
+ PausedState,
+ ErrorState
+ };
+
+ IntSize naturalSize() const;
+ 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);
+ 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);
+ void setSize(const IntSize&);
+
+ void paint(GraphicsContext*, const IntRect&);
+
+ protected:
+ bool eventFilter(QObject*, QEvent*);
+
+ private slots:
+ void stateChanged(Phonon::State, Phonon::State);
+ void metaDataChanged();
+ void seekableChanged(bool);
+ void hasVideoChanged(bool);
+ void bufferStatus(int);
+ void finished();
+ void currentSourceChanged(const Phonon::MediaSource&);
+ void aboutToFinish();
+ void totalTimeChanged(qint64);
+
+ private:
+ MediaPlayerPrivatePhonon(MediaPlayer*);
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+
+ 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();
+
+ MediaPlayer* m_player;
+
+ MediaPlayer::NetworkState m_networkState;
+ MediaPlayer::ReadyState m_readyState;
+
+ Phonon::MediaObject* m_mediaObject;
+ Phonon::VideoWidget* m_videoWidget;
+ Phonon::AudioOutput* m_audioOutput;
+
+ bool m_isVisible;
+ };
+}
+
+#endif // MediaPlayerPrivatePhonon_h
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
new file mode 100644
index 0000000..dd4b6e6
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -0,0 +1,674 @@
+/*
+ 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 "QtNAMThreadSafeProxy.h"
+#include "NetworkingContext.h"
+#include "NotImplemented.h"
+#include "RenderVideo.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 <QStyleOptionGraphicsItem>
+#include <QTime>
+#include <QTimer>
+#include <QUrl>
+#include <limits>
+#include <wtf/HashSet.h>
+#include <wtf/text/CString.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "texmap/TextureMapperPlatformLayer.h"
+#endif
+
+using namespace WTF;
+
+namespace WebCore {
+
+MediaPlayerPrivateInterface* MediaPlayerPrivateQt::create(MediaPlayer* player)
+{
+ return new MediaPlayerPrivateQt(player);
+}
+
+void MediaPlayerPrivateQt::registerMediaEngine(MediaEngineRegistrar registrar)
+{
+ registrar(create, getSupportedTypes, supportsType);
+}
+
+void MediaPlayerPrivateQt::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 MediaPlayerPrivateQt::supportsType(const String& mime, const String& codec)
+{
+ if (!mime.startsWith("audio/") && !mime.startsWith("video/"))
+ return MediaPlayer::IsNotSupported;
+
+ if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimediaKit::ProbablySupported)
+ return MediaPlayer::IsSupported;
+
+ return MediaPlayer::MayBeSupported;
+}
+
+MediaPlayerPrivateQt::MediaPlayerPrivateQt(MediaPlayer* player)
+ : m_webCorePlayer(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_currentSize(0, 0)
+ , m_naturalSize(RenderVideo::defaultSize())
+ , m_isVisible(false)
+ , m_isSeeking(false)
+ , m_composited(false)
+ , m_queuedSeek(-1)
+ , m_preload(MediaPlayer::Auto)
+{
+ m_mediaPlayer->bind(m_videoItem);
+ 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(bufferStatusChanged(int)),
+ this, SLOT(bufferStatusChanged(int)));
+ 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
+ if (QMediaService* service = m_mediaPlayer->service()) {
+ m_mediaPlayerControl = qobject_cast<QMediaPlayerControl *>(
+ service->requestControl(QMediaPlayerControl_iid));
+ }
+}
+
+MediaPlayerPrivateQt::~MediaPlayerPrivateQt()
+{
+ m_mediaPlayer->disconnect(this);
+ m_mediaPlayer->stop();
+ m_mediaPlayer->setMedia(QMediaContent());
+
+ delete m_mediaPlayer;
+ delete m_videoScene;
+}
+
+bool MediaPlayerPrivateQt::hasVideo() const
+{
+ return m_mediaPlayer->isVideoAvailable();
+}
+
+bool MediaPlayerPrivateQt::hasAudio() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateQt::load(const String& url)
+{
+ m_mediaUrl = url;
+
+ // QtMultimedia does not have an API to throttle loading
+ // so we handle this ourselves by delaying the load
+ if (m_preload == MediaPlayer::None) {
+ m_delayingLoad = true;
+ return;
+ }
+
+ commitLoad(url);
+}
+
+void MediaPlayerPrivateQt::commitLoad(const String& url)
+{
+ // We are now loading
+ if (m_networkState != MediaPlayer::Loading) {
+ m_networkState = MediaPlayer::Loading;
+ m_webCorePlayer->networkStateChanged();
+ }
+
+ // And we don't have any data yet
+ if (m_readyState != MediaPlayer::HaveNothing) {
+ m_readyState = MediaPlayer::HaveNothing;
+ m_webCorePlayer->readyStateChanged();
+ }
+
+ const QUrl rUrl = QUrl(QString(url));
+ const QString scheme = rUrl.scheme().toLower();
+
+ // Grab the client media element
+ HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->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;
+ QNetworkAccessManager* manager = frame ? frame->loader()->networkingContext()->networkAccessManager() : 0;
+ FrameLoaderClientQt* frameLoader = frame ? static_cast<FrameLoaderClientQt*>(frame->loader()->client()) : 0;
+
+ if (document && manager) {
+ // Set the cookies
+ QtNAMThreadSafeProxy managerProxy(manager);
+ QList<QNetworkCookie> cookies = managerProxy.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));
+
+ // Setting a media source will start loading the media, but we need
+ // to pre-roll as well to get video size-hints and buffer-status
+ if (element->paused())
+ m_mediaPlayer->pause();
+ else
+ m_mediaPlayer->play();
+}
+
+void MediaPlayerPrivateQt::resumeLoad()
+{
+ m_delayingLoad = false;
+
+ if (!m_mediaUrl.isNull())
+ commitLoad(m_mediaUrl);
+}
+
+void MediaPlayerPrivateQt::cancelLoad()
+{
+ m_mediaPlayer->setMedia(QMediaContent());
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::prepareToPlay()
+{
+ if (m_mediaPlayer->media().isNull() || m_delayingLoad)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQt::play()
+{
+ if (m_mediaPlayer->state() != QMediaPlayer::PlayingState)
+ m_mediaPlayer->play();
+}
+
+void MediaPlayerPrivateQt::pause()
+{
+ if (m_mediaPlayer->state() == QMediaPlayer::PlayingState)
+ m_mediaPlayer->pause();
+}
+
+bool MediaPlayerPrivateQt::paused() const
+{
+ return (m_mediaPlayer->state() != QMediaPlayer::PlayingState);
+}
+
+void MediaPlayerPrivateQt::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 MediaPlayerPrivateQt::seeking() const
+{
+ return m_isSeeking;
+}
+
+float MediaPlayerPrivateQt::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 MediaPlayerPrivateQt::currentTime() const
+{
+ return m_mediaPlayer->position() / 1000.0f;
+}
+
+PassRefPtr<TimeRanges> MediaPlayerPrivateQt::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 MediaPlayerPrivateQt::maxTimeSeekable() const
+{
+ if (!m_mediaPlayerControl)
+ return 0;
+
+ return static_cast<float>(m_mediaPlayerControl->availablePlaybackRanges().latestTime()) / 1000.0f;
+}
+
+unsigned MediaPlayerPrivateQt::bytesLoaded() const
+{
+ QLatin1String bytesLoadedKey("bytes-loaded");
+ if (m_mediaPlayer->availableExtendedMetaData().contains(bytesLoadedKey))
+ return m_mediaPlayer->extendedMetaData(bytesLoadedKey).toInt();
+
+ return m_mediaPlayer->bufferStatus();
+}
+
+unsigned MediaPlayerPrivateQt::totalBytes() const
+{
+ if (m_mediaPlayer->availableMetaData().contains(QtMultimediaKit::Size))
+ return m_mediaPlayer->metaData(QtMultimediaKit::Size).toInt();
+
+ return 100;
+}
+
+void MediaPlayerPrivateQt::setPreload(MediaPlayer::Preload preload)
+{
+ m_preload = preload;
+ if (m_delayingLoad && m_preload != MediaPlayer::None)
+ resumeLoad();
+}
+
+void MediaPlayerPrivateQt::setRate(float rate)
+{
+ m_mediaPlayer->setPlaybackRate(rate);
+}
+
+void MediaPlayerPrivateQt::setVolume(float volume)
+{
+ m_mediaPlayer->setVolume(static_cast<int>(volume * 100.0));
+}
+
+bool MediaPlayerPrivateQt::supportsMuting() const
+{
+ return true;
+}
+
+void MediaPlayerPrivateQt::setMuted(bool muted)
+{
+ m_mediaPlayer->setMuted(muted);
+}
+
+MediaPlayer::NetworkState MediaPlayerPrivateQt::networkState() const
+{
+ return m_networkState;
+}
+
+MediaPlayer::ReadyState MediaPlayerPrivateQt::readyState() const
+{
+ return m_readyState;
+}
+
+void MediaPlayerPrivateQt::setVisible(bool visible)
+{
+ m_isVisible = visible;
+}
+
+void MediaPlayerPrivateQt::mediaStatusChanged(QMediaPlayer::MediaStatus)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::handleError(QMediaPlayer::Error)
+{
+ updateStates();
+}
+
+void MediaPlayerPrivateQt::stateChanged(QMediaPlayer::State state)
+{
+ if (state != QMediaPlayer::PlayingState && m_isSeeking && m_queuedSeek >= 0) {
+ m_mediaPlayer->setPosition(m_queuedSeek);
+ m_queuedSeek = -1;
+ }
+}
+
+void MediaPlayerPrivateQt::nativeSizeChanged(const QSizeF& size)
+{
+ LOG(Media, "MediaPlayerPrivateQt::naturalSizeChanged(%dx%d)",
+ size.toSize().width(), size.toSize().height());
+
+ if (!size.isValid())
+ return;
+
+ m_naturalSize = size.toSize();
+ m_webCorePlayer->sizeChanged();
+}
+
+void MediaPlayerPrivateQt::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 MediaPlayerPrivateQt::seekTimeout()
+{
+ // If we haven't heard anything, assume the seek succeeded
+ if (m_isSeeking) {
+ m_webCorePlayer->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivateQt::positionChanged(qint64)
+{
+ // Only propagate this event if we are seeking
+ if (m_isSeeking && m_queuedSeek == -1) {
+ m_webCorePlayer->timeChanged();
+ m_isSeeking = false;
+ }
+}
+
+void MediaPlayerPrivateQt::bufferStatusChanged(int)
+{
+ notImplemented();
+}
+
+void MediaPlayerPrivateQt::durationChanged(qint64)
+{
+ m_webCorePlayer->durationChanged();
+}
+
+void MediaPlayerPrivateQt::volumeChanged(int volume)
+{
+ m_webCorePlayer->volumeChanged(static_cast<float>(volume) / 100.0);
+}
+
+void MediaPlayerPrivateQt::mutedChanged(bool muted)
+{
+ m_webCorePlayer->muteChanged(muted);
+}
+
+void MediaPlayerPrivateQt::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_webCorePlayer->readyStateChanged();
+
+ if (m_networkState != oldNetworkState)
+ m_webCorePlayer->networkStateChanged();
+}
+
+void MediaPlayerPrivateQt::setSize(const IntSize& size)
+{
+ LOG(Media, "MediaPlayerPrivateQt::setSize(%dx%d)",
+ size.width(), size.height());
+
+ if (size == m_currentSize)
+ return;
+
+ m_currentSize = size;
+ m_videoItem->setSize(QSizeF(QSize(size)));
+}
+
+IntSize MediaPlayerPrivateQt::naturalSize() const
+{
+ if (!hasVideo() || m_readyState < MediaPlayer::HaveMetadata) {
+ LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> 0x0 (!hasVideo || !haveMetaData)");
+ return IntSize();
+ }
+
+ LOG(Media, "MediaPlayerPrivateQt::naturalSize() -> %dx%d (m_naturalSize)",
+ m_naturalSize.width(), m_naturalSize.height());
+
+ return m_naturalSize;
+}
+
+void MediaPlayerPrivateQt::paint(GraphicsContext* context, const IntRect& rect)
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_composited)
+ return;
+#endif
+ if (context->paintingDisabled())
+ return;
+
+ if (!m_isVisible)
+ return;
+
+ QPainter* painter = context->platformContext();
+ m_videoScene->render(painter, QRectF(QRect(rect)), m_videoItem->sceneBoundingRect());
+}
+
+void MediaPlayerPrivateQt::repaint()
+{
+ m_webCorePlayer->repaint();
+}
+
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+
+class TextureMapperVideoLayerQt : public virtual TextureMapperVideoLayer {
+public:
+ TextureMapperVideoLayerQt(QGraphicsVideoItem* videoItem)
+ : m_videoItem(videoItem)
+ {
+ }
+
+ virtual void setPlatformLayerClient(TextureMapperLayerClient* client)
+ {
+ m_client = client;
+ }
+
+ virtual void paint(GraphicsContext* context)
+ {
+ if (!m_videoItem)
+ return;
+
+ QStyleOptionGraphicsItem opt;
+ opt.exposedRect = m_videoItem.data()->sceneBoundingRect();
+ opt.rect = opt.exposedRect.toRect();
+ m_videoItem.data()->paint(context->platformContext(), &opt);
+ }
+
+ virtual IntSize size() const
+ {
+ return m_videoItem ? IntSize(m_videoItem.data()->size().width(), m_videoItem.data()->size().height()) : IntSize();
+ }
+
+ QWeakPointer<QGraphicsVideoItem> m_videoItem;
+ TextureMapperLayerClient* m_client;
+};
+
+
+void MediaPlayerPrivateQt::acceleratedRenderingStateChanged()
+{
+ MediaPlayerClient* client = m_webCorePlayer->mediaPlayerClient();
+ bool composited = client->mediaPlayerRenderingCanBeAccelerated(m_webCorePlayer);
+ if (composited == m_composited)
+ return;
+
+ m_composited = composited;
+ if (composited)
+ m_platformLayer = new TextureMapperVideoLayerQt(m_videoItem);
+}
+
+PlatformLayer* MediaPlayerPrivateQt::platformLayer() const
+{
+ return m_composited ? m_platformLayer.get() : 0;
+}
+#endif
+
+PlatformMedia MediaPlayerPrivateQt::platformMedia() const
+{
+ PlatformMedia pm;
+ pm.type = PlatformMedia::QtMediaPlayerType;
+ pm.media.qtMediaPlayer = const_cast<MediaPlayerPrivateQt*>(this);
+ return pm;
+}
+
+} // namespace WebCore
+
+#include "moc_MediaPlayerPrivateQt.cpp"
diff --git a/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
new file mode 100644
index 0000000..93c9d1c
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.h
@@ -0,0 +1,156 @@
+/*
+ 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 TextureMapperVideoLayer;
+
+class MediaPlayerPrivateQt : public QObject, public MediaPlayerPrivateInterface {
+
+ Q_OBJECT
+
+public:
+ static MediaPlayerPrivateInterface* create(MediaPlayer* player);
+ ~MediaPlayerPrivateQt();
+
+ 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 commitLoad(const String& url);
+ void resumeLoad();
+ void cancelLoad();
+
+ void play();
+ void pause();
+ void prepareToPlay();
+
+ 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);
+
+ void setPreload(MediaPlayer::Preload);
+
+ 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)
+#if USE(TEXTURE_MAPPER)
+ // 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;
+#else
+ virtual bool supportsAcceleratedRendering() const { return false; }
+ virtual void acceleratedRenderingStateChanged() { }
+ virtual PlatformLayer* platformLayer() const { return 0; }
+#endif
+#endif
+
+ virtual PlatformMedia platformMedia() const;
+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 bufferStatusChanged(int);
+ void volumeChanged(int);
+ void mutedChanged(bool);
+ void repaint();
+
+private:
+ void updateStates();
+
+private:
+ MediaPlayerPrivateQt(MediaPlayer*);
+
+ MediaPlayer* m_webCorePlayer;
+ QMediaPlayer* m_mediaPlayer;
+ QMediaPlayerControl* m_mediaPlayerControl;
+ QGraphicsVideoItem* m_videoItem;
+ QGraphicsScene* m_videoScene;
+#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
+ OwnPtr<TextureMapperVideoLayer> m_platformLayer;
+#endif
+
+ mutable MediaPlayer::NetworkState m_networkState;
+ mutable MediaPlayer::ReadyState m_readyState;
+
+ IntSize m_currentSize;
+ IntSize m_naturalSize;
+ bool m_isVisible;
+ bool m_isSeeking;
+ bool m_composited;
+ qint64 m_queuedSeek;
+ MediaPlayer::Preload m_preload;
+ bool m_delayingLoad;
+ String m_mediaUrl;
+
+};
+}
+
+#endif // MediaPlayerPrivateQt_h
diff --git a/Source/WebCore/platform/graphics/qt/PathQt.cpp b/Source/WebCore/platform/graphics/qt/PathQt.cpp
new file mode 100644
index 0000000..571b405
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/PathQt.cpp
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * 2006 Rob Buis <buis@kde.org>
+ * 2009, 2010 Dirk Schulze <krit@webkit.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Path.h"
+
+#include "AffineTransform.h"
+#include "FloatRect.h"
+#include "GraphicsContext.h"
+#include "ImageBuffer.h"
+#include "PlatformString.h"
+#include "StrokeStyleApplier.h"
+#include <QPainterPath>
+#include <QTransform>
+#include <QString>
+#include <wtf/OwnPtr.h>
+
+#define _USE_MATH_DEFINES
+#include <math.h>
+
+#ifndef M_PI
+# define M_PI 3.14159265358979323846
+#endif
+
+namespace WebCore {
+
+Path::Path()
+{
+}
+
+Path::~Path()
+{
+}
+
+Path::Path(const Path& other)
+ : m_path(other.m_path)
+{
+}
+
+Path& Path::operator=(const Path& other)
+{
+ m_path = other.m_path;
+ return *this;
+}
+
+static inline bool areCollinear(const QPointF& a, const QPointF& b, const QPointF& c)
+{
+ // Solved from comparing the slopes of a to b and b to c: (ay-by)/(ax-bx) == (cy-by)/(cx-bx)
+ return qFuzzyCompare((c.y() - b.y()) * (a.x() - b.x()), (a.y() - b.y()) * (c.x() - b.x()));
+}
+
+static inline bool withinRange(qreal p, qreal a, qreal b)
+{
+ return (p >= a && p <= b) || (p >= b && p <= a);
+}
+
+// Check whether a point is on the border
+static bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p)
+{
+ // null border doesn't contain points
+ if (border.isEmpty())
+ return false;
+
+ QPointF p1 = border.at(0);
+ QPointF p2;
+
+ for (int i = 1; i < border.size(); ++i) {
+ p2 = border.at(i);
+ if (areCollinear(p, p1, p2)
+ // Once we know that the points are collinear we
+ // only need to check one of the coordinates
+ && (qAbs(p2.x() - p1.x()) > qAbs(p2.y() - p1.y()) ?
+ withinRange(p.x(), p1.x(), p2.x()) :
+ withinRange(p.y(), p1.y(), p2.y()))) {
+ return true;
+ }
+ p1 = p2;
+ }
+ return false;
+}
+
+bool Path::contains(const FloatPoint& point, WindRule rule) const
+{
+ Qt::FillRule savedRule = m_path.fillRule();
+ const_cast<QPainterPath*>(&m_path)->setFillRule(rule == RULE_EVENODD ? Qt::OddEvenFill : Qt::WindingFill);
+
+ bool contains = m_path.contains(point);
+
+ if (!contains) {
+ // check whether the point is on the border
+ contains = isPointOnPathBorder(m_path.toFillPolygon(), point);
+ }
+
+ const_cast<QPainterPath*>(&m_path)->setFillRule(savedRule);
+ return contains;
+}
+
+static GraphicsContext* scratchContext()
+{
+ static QImage image(1, 1, QImage::Format_ARGB32_Premultiplied);
+ static QPainter painter(&image);
+ static GraphicsContext* context = new GraphicsContext(&painter);
+ return context;
+}
+
+bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const
+{
+ ASSERT(applier);
+
+ QPainterPathStroker stroke;
+ GraphicsContext* context = scratchContext();
+ applier->strokeStyle(context);
+
+ QPen pen = context->platformContext()->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+
+ return stroke.createStroke(m_path).contains(point);
+}
+
+void Path::translate(const FloatSize& size)
+{
+ QTransform matrix;
+ matrix.translate(size.width(), size.height());
+ m_path = m_path * matrix;
+}
+
+FloatRect Path::boundingRect() const
+{
+ return m_path.boundingRect();
+}
+
+FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier)
+{
+ GraphicsContext* context = scratchContext();
+ QPainterPathStroker stroke;
+ if (applier) {
+ applier->strokeStyle(context);
+
+ QPen pen = context->platformContext()->pen();
+ stroke.setWidth(pen.widthF());
+ stroke.setCapStyle(pen.capStyle());
+ stroke.setJoinStyle(pen.joinStyle());
+ stroke.setMiterLimit(pen.miterLimit());
+ stroke.setDashPattern(pen.dashPattern());
+ stroke.setDashOffset(pen.dashOffset());
+ }
+ return stroke.createStroke(m_path).boundingRect();
+}
+
+void Path::moveTo(const FloatPoint& point)
+{
+ m_path.moveTo(point);
+}
+
+void Path::addLineTo(const FloatPoint& p)
+{
+ m_path.lineTo(p);
+}
+
+void Path::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p)
+{
+ m_path.quadTo(cp, p);
+}
+
+void Path::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p)
+{
+ m_path.cubicTo(cp1, cp2, p);
+}
+
+void Path::addArcTo(const FloatPoint& p1, const FloatPoint& p2, float radius)
+{
+ FloatPoint p0(m_path.currentPosition());
+
+ FloatPoint p1p0((p0.x() - p1.x()), (p0.y() - p1.y()));
+ FloatPoint p1p2((p2.x() - p1.x()), (p2.y() - p1.y()));
+ float p1p0_length = sqrtf(p1p0.x() * p1p0.x() + p1p0.y() * p1p0.y());
+ float p1p2_length = sqrtf(p1p2.x() * p1p2.x() + p1p2.y() * p1p2.y());
+
+ double cos_phi = (p1p0.x() * p1p2.x() + p1p0.y() * p1p2.y()) / (p1p0_length * p1p2_length);
+
+ // The points p0, p1, and p2 are on the same straight line (HTML5, 4.8.11.1.8)
+ // We could have used areCollinear() here, but since we're reusing
+ // the variables computed above later on we keep this logic.
+ if (qFuzzyCompare(qAbs(cos_phi), 1.0)) {
+ m_path.lineTo(p1);
+ return;
+ }
+
+ float tangent = radius / tan(acos(cos_phi) / 2);
+ float factor_p1p0 = tangent / p1p0_length;
+ FloatPoint t_p1p0((p1.x() + factor_p1p0 * p1p0.x()), (p1.y() + factor_p1p0 * p1p0.y()));
+
+ FloatPoint orth_p1p0(p1p0.y(), -p1p0.x());
+ float orth_p1p0_length = sqrt(orth_p1p0.x() * orth_p1p0.x() + orth_p1p0.y() * orth_p1p0.y());
+ float factor_ra = radius / orth_p1p0_length;
+
+ // angle between orth_p1p0 and p1p2 to get the right vector orthographic to p1p0
+ double cos_alpha = (orth_p1p0.x() * p1p2.x() + orth_p1p0.y() * p1p2.y()) / (orth_p1p0_length * p1p2_length);
+ if (cos_alpha < 0.f)
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+
+ FloatPoint p((t_p1p0.x() + factor_ra * orth_p1p0.x()), (t_p1p0.y() + factor_ra * orth_p1p0.y()));
+
+ // calculate angles for addArc
+ orth_p1p0 = FloatPoint(-orth_p1p0.x(), -orth_p1p0.y());
+ float sa = acos(orth_p1p0.x() / orth_p1p0_length);
+ if (orth_p1p0.y() < 0.f)
+ sa = 2 * piDouble - sa;
+
+ // anticlockwise logic
+ bool anticlockwise = false;
+
+ float factor_p1p2 = tangent / p1p2_length;
+ FloatPoint t_p1p2((p1.x() + factor_p1p2 * p1p2.x()), (p1.y() + factor_p1p2 * p1p2.y()));
+ FloatPoint orth_p1p2((t_p1p2.x() - p.x()), (t_p1p2.y() - p.y()));
+ float orth_p1p2_length = sqrtf(orth_p1p2.x() * orth_p1p2.x() + orth_p1p2.y() * orth_p1p2.y());
+ float ea = acos(orth_p1p2.x() / orth_p1p2_length);
+ if (orth_p1p2.y() < 0)
+ ea = 2 * piDouble - ea;
+ if ((sa > ea) && ((sa - ea) < piDouble))
+ anticlockwise = true;
+ if ((sa < ea) && ((ea - sa) > piDouble))
+ anticlockwise = true;
+
+ m_path.lineTo(t_p1p0);
+
+ addArc(p, radius, sa, ea, anticlockwise);
+}
+
+void Path::closeSubpath()
+{
+ m_path.closeSubpath();
+}
+
+#define DEGREES(t) ((t) * 180.0 / M_PI)
+void Path::addArc(const FloatPoint& p, float r, float sar, float ear, bool anticlockwise)
+{
+ qreal xc = p.x();
+ qreal yc = p.y();
+ qreal radius = r;
+
+
+ //### HACK
+ // In Qt we don't switch the coordinate system for degrees
+ // and still use the 0,0 as bottom left for degrees so we need
+ // to switch
+ sar = -sar;
+ ear = -ear;
+ anticlockwise = !anticlockwise;
+ //end hack
+
+ float sa = DEGREES(sar);
+ float ea = DEGREES(ear);
+
+ double span = 0;
+
+ double xs = xc - radius;
+ double ys = yc - radius;
+ double width = radius*2;
+ double height = radius*2;
+
+ if ((!anticlockwise && (ea - sa >= 360)) || (anticlockwise && (sa - ea >= 360))) {
+ // If the anticlockwise argument is false and endAngle-startAngle is equal to or greater than 2*PI, or, if the
+ // anticlockwise argument is true and startAngle-endAngle is equal to or greater than 2*PI, then the arc is the whole
+ // circumference of this circle.
+ span = 360;
+
+ if (anticlockwise)
+ span = -span;
+ } else {
+ if (!anticlockwise && (ea < sa))
+ span += 360;
+ else if (anticlockwise && (sa < ea))
+ span -= 360;
+
+ // this is also due to switched coordinate system
+ // we would end up with a 0 span instead of 360
+ if (!(qFuzzyCompare(span + (ea - sa) + 1, 1.0)
+ && qFuzzyCompare(qAbs(span), 360.0))) {
+ // mod 360
+ span += (ea - sa) - (static_cast<int>((ea - sa) / 360)) * 360;
+ }
+ }
+
+ // If the path is empty, move to where the arc will start to avoid painting a line from (0,0)
+ // NOTE: QPainterPath::isEmpty() won't work here since it ignores a lone MoveToElement
+ if (!m_path.elementCount())
+ m_path.arcMoveTo(xs, ys, width, height, sa);
+ else if (!radius) {
+ m_path.lineTo(xc, yc);
+ return;
+ }
+
+ m_path.arcTo(xs, ys, width, height, sa, span);
+
+}
+
+void Path::addRect(const FloatRect& r)
+{
+ m_path.addRect(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::addEllipse(const FloatRect& r)
+{
+ m_path.addEllipse(r.x(), r.y(), r.width(), r.height());
+}
+
+void Path::clear()
+{
+ if (!m_path.elementCount())
+ return;
+ m_path = QPainterPath();
+}
+
+bool Path::isEmpty() const
+{
+ // Don't use QPainterPath::isEmpty(), as that also returns true if there's only
+ // one initial MoveTo element in the path.
+ return !m_path.elementCount();
+}
+
+bool Path::hasCurrentPoint() const
+{
+ return !isEmpty();
+}
+
+FloatPoint Path::currentPoint() const
+{
+ return m_path.currentPosition();
+}
+
+void Path::apply(void* info, PathApplierFunction function) const
+{
+ PathElement pelement;
+ FloatPoint points[3];
+ pelement.points = points;
+ for (int i = 0; i < m_path.elementCount(); ++i) {
+ const QPainterPath::Element& cur = m_path.elementAt(i);
+
+ switch (cur.type) {
+ case QPainterPath::MoveToElement:
+ pelement.type = PathElementMoveToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::LineToElement:
+ pelement.type = PathElementAddLineToPoint;
+ pelement.points[0] = QPointF(cur);
+ function(info, &pelement);
+ break;
+ case QPainterPath::CurveToElement:
+ {
+ const QPainterPath::Element& c1 = m_path.elementAt(i + 1);
+ const QPainterPath::Element& c2 = m_path.elementAt(i + 2);
+
+ Q_ASSERT(c1.type == QPainterPath::CurveToDataElement);
+ Q_ASSERT(c2.type == QPainterPath::CurveToDataElement);
+
+ pelement.type = PathElementAddCurveToPoint;
+ pelement.points[0] = QPointF(cur);
+ pelement.points[1] = QPointF(c1);
+ pelement.points[2] = QPointF(c2);
+ function(info, &pelement);
+
+ i += 2;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(false);
+ }
+ }
+}
+
+void Path::transform(const AffineTransform& transform)
+{
+ QTransform qTransform(transform);
+#if QT_VERSION < QT_VERSION_CHECK(4, 7, 0)
+ // Workaround for http://bugreports.qt.nokia.com/browse/QTBUG-11264
+ // QTransform.map doesn't handle the MoveTo element because of the isEmpty issue
+ if (m_path.isEmpty() && m_path.elementCount()) {
+ QPointF point = qTransform.map(m_path.currentPosition());
+ moveTo(point);
+ } else
+#endif
+ m_path = qTransform.map(m_path);
+}
+
+float Path::length()
+{
+ return m_path.length();
+}
+
+FloatPoint Path::pointAtLength(float length, bool& ok)
+{
+ ok = (length >= 0 && length <= m_path.length());
+
+ qreal percent = m_path.percentAtLength(length);
+ QPointF point = m_path.pointAtPercent(percent);
+
+ return point;
+}
+
+float Path::normalAngleAtLength(float length, bool& ok)
+{
+ ok = (length >= 0 && length <= m_path.length());
+
+ qreal percent = m_path.percentAtLength(length);
+ qreal angle = m_path.angleAtPercent(percent);
+
+ return angle;
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/PatternQt.cpp b/Source/WebCore/platform/graphics/qt/PatternQt.cpp
new file mode 100644
index 0000000..af7b128
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/PatternQt.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Eric Seidel <eric@webkit.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Pattern.h"
+
+#include "AffineTransform.h"
+#include "GraphicsContext.h"
+
+namespace WebCore {
+
+QBrush Pattern::createPlatformPattern(const AffineTransform&) const
+{
+ QPixmap* pixmap = tileImage()->nativeImageForCurrentFrame();
+ if (!pixmap)
+ return QBrush();
+
+ // Qt merges patter space and user space itself
+ QBrush brush(*pixmap);
+ brush.setTransform(m_patternSpaceTransformation);
+
+ return brush;
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
new file mode 100644
index 0000000..47ddf02
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/SimpleFontDataQt.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
+ Copyright (C) 2008 Holger Hans Peter Freyther
+
+ 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.
+
+ This class provides all functionality needed for loading images, style sheets and html
+ pages from the web. It has a memory cache for these objects.
+*/
+
+#include "config.h"
+#include "SimpleFontData.h"
+
+#include <QFontMetrics>
+
+namespace WebCore {
+
+void SimpleFontData::determinePitch()
+{
+ m_treatAsFixedPitch = m_platformData.font().fixedPitch();
+}
+
+bool SimpleFontData::containsCharacters(const UChar*, int) const
+{
+ return true;
+}
+
+void SimpleFontData::platformInit()
+{
+ if (!m_platformData.size()) {
+ m_ascent = 0;
+ m_descent = 0;
+ m_lineGap = 0;
+ m_lineSpacing = 0;
+ m_avgCharWidth = 0;
+ m_maxCharWidth = 0;
+ m_xHeight = 0;
+ m_unitsPerEm = 0;
+ return;
+ }
+
+ QFontMetrics fm(m_platformData.font());
+
+ m_ascent = fm.ascent();
+ m_descent = fm.descent();
+ m_lineSpacing = fm.lineSpacing();
+ m_xHeight = fm.xHeight();
+ m_spaceWidth = fm.width(QLatin1Char(' '));
+ m_lineGap = fm.leading();
+}
+
+void SimpleFontData::platformGlyphInit()
+{
+ if (!m_platformData.size())
+ return;
+ m_spaceGlyph = 0;
+ m_adjustedSpaceWidth = m_spaceWidth;
+ determinePitch();
+ m_missingGlyphData.fontData = this;
+ m_missingGlyphData.glyph = 0;
+}
+
+void SimpleFontData::platformCharWidthInit()
+{
+ if (!m_platformData.size())
+ return;
+ QFontMetrics fm(m_platformData.font());
+ m_avgCharWidth = fm.averageCharWidth();
+ m_maxCharWidth = fm.maxWidth();
+}
+
+void SimpleFontData::platformDestroy()
+{
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/StillImageQt.cpp b/Source/WebCore/platform/graphics/qt/StillImageQt.cpp
new file mode 100644
index 0000000..3b08995
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/StillImageQt.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StillImageQt.h"
+
+#include "ContextShadow.h"
+#include "GraphicsContext.h"
+#include "IntSize.h"
+
+#include <QPainter>
+
+namespace WebCore {
+
+StillImage::StillImage(const QPixmap& pixmap)
+ : m_pixmap(new QPixmap(pixmap))
+ , m_ownsPixmap(true)
+{}
+
+StillImage::StillImage(const QPixmap* pixmap)
+ : m_pixmap(pixmap)
+ , m_ownsPixmap(false)
+{}
+
+StillImage::~StillImage()
+{
+ if (m_ownsPixmap)
+ delete m_pixmap;
+}
+
+IntSize StillImage::size() const
+{
+ return IntSize(m_pixmap->width(), m_pixmap->height());
+}
+
+NativeImagePtr StillImage::nativeImageForCurrentFrame()
+{
+ return const_cast<NativeImagePtr>(m_pixmap);
+}
+
+void StillImage::draw(GraphicsContext* ctxt, const FloatRect& dst,
+ const FloatRect& src, ColorSpace, CompositeOperator op)
+{
+ if (m_pixmap->isNull())
+ return;
+
+ FloatRect normalizedSrc = src.normalized();
+ FloatRect normalizedDst = dst.normalized();
+
+ CompositeOperator previousOperator = ctxt->compositeOperation();
+ ctxt->setCompositeOperation(op);
+
+ ContextShadow* shadow = ctxt->contextShadow();
+ if (shadow->m_type != ContextShadow::NoShadow) {
+ QPainter* shadowPainter = shadow->beginShadowLayer(ctxt, normalizedDst);
+ if (shadowPainter) {
+ shadowPainter->setOpacity(static_cast<qreal>(shadow->m_color.alpha()) / 255);
+ shadowPainter->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc);
+ shadow->endShadowLayer(ctxt);
+ }
+ }
+
+ ctxt->platformContext()->drawPixmap(normalizedDst, *m_pixmap, normalizedSrc);
+ ctxt->setCompositeOperation(previousOperator);
+}
+
+}
diff --git a/Source/WebCore/platform/graphics/qt/StillImageQt.h b/Source/WebCore/platform/graphics/qt/StillImageQt.h
new file mode 100644
index 0000000..58071d9
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/StillImageQt.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 Holger Hans Peter Freyther
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StillImageQt_h
+#define StillImageQt_h
+
+#include "Image.h"
+
+namespace WebCore {
+
+ class StillImage : public Image {
+ public:
+ static PassRefPtr<StillImage> create(const QPixmap& pixmap)
+ {
+ return adoptRef(new StillImage(pixmap));
+ }
+
+ static PassRefPtr<StillImage> createForRendering(const QPixmap* pixmap)
+ {
+ return adoptRef(new StillImage(pixmap));
+ }
+
+ // FIXME: StillImages are underreporting decoded sizes and will be unable
+ // to prune because these functions are not implemented yet.
+ virtual void destroyDecodedData(bool destroyAll = true) { Q_UNUSED(destroyAll); }
+ virtual unsigned decodedSize() const { return 0; }
+
+ virtual IntSize size() const;
+ virtual NativeImagePtr nativeImageForCurrentFrame();
+ virtual void draw(GraphicsContext*, const FloatRect& dstRect, const FloatRect& srcRect, ColorSpace styleColorSpace, CompositeOperator);
+
+ private:
+ StillImage(const QPixmap& pixmap);
+ StillImage(const QPixmap* pixmap);
+ ~StillImage();
+
+ const QPixmap* m_pixmap;
+ bool m_ownsPixmap;
+ };
+
+}
+
+#endif
diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp
new file mode 100644
index 0000000..6fdd7df
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.cpp
@@ -0,0 +1,214 @@
+/*
+ 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 "TextureMapperQt.h"
+
+#include <QtCore/qdebug.h>
+#include <QtGui/qpaintengine.h>
+#include <QtGui/qpixmap.h>
+
+#ifdef QT_OPENGL_LIB
+# include "opengl/TextureMapperGL.h"
+#endif
+
+namespace WebCore {
+
+void BitmapTextureQt::destroy()
+{
+ if (m_pixmap.paintingActive())
+ qFatal("Destroying an active pixmap");
+ m_pixmap = QPixmap();
+}
+
+void BitmapTextureQt::reset(const IntSize& size, bool isOpaque)
+{
+ BitmapTexture::reset(size, isOpaque);
+
+ if (size.width() > m_pixmap.size().width() || size.height() > m_pixmap.size().height() || m_pixmap.isNull())
+ m_pixmap = QPixmap(size.width(), size.height());
+ if (!isOpaque)
+ m_pixmap.fill(Qt::transparent);
+}
+
+PlatformGraphicsContext* BitmapTextureQt::beginPaint(const IntRect& dirtyRect)
+{
+ m_painter.begin(&m_pixmap);
+ TextureMapperQt::initialize(&m_painter);
+ m_painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ m_painter.fillRect(QRect(dirtyRect), Qt::transparent);
+ m_painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ return &m_painter;
+}
+
+void BitmapTextureQt::endPaint()
+{
+ m_painter.end();
+}
+
+bool BitmapTextureQt::save(const String& path)
+{
+ return m_pixmap.save(path, "PNG");
+}
+
+void BitmapTextureQt::setContentsToImage(Image* image)
+{
+ if (!image)
+ return;
+ const QPixmap* pixmap = image->nativeImageForCurrentFrame();
+ if (!pixmap)
+ return;
+ BitmapTexture::reset(pixmap->size(), !pixmap->hasAlphaChannel());
+ m_pixmap = *pixmap;
+}
+
+void BitmapTextureQt::pack()
+{
+ if (m_pixmap.isNull())
+ return;
+
+ m_image = m_pixmap.toImage();
+ m_pixmap = QPixmap();
+ m_isPacked = true;
+}
+
+void BitmapTextureQt::unpack()
+{
+ m_isPacked = false;
+ if (m_image.isNull())
+ return;
+
+ m_pixmap = QPixmap::fromImage(m_image);
+ m_image = QImage();
+}
+
+void TextureMapperQt::setClip(const IntRect& rect)
+{
+ QPainter* painter = m_currentSurface ? &m_currentSurface->m_painter : m_painter;
+ painter->setClipRect(rect);
+}
+
+TextureMapperQt::TextureMapperQt()
+ : m_currentSurface(0)
+{
+}
+
+void TextureMapperQt::setGraphicsContext(GraphicsContext* context)
+{
+ m_painter = context->platformContext();
+ initialize(m_painter);
+}
+
+void TextureMapperQt::bindSurface(BitmapTexture* surface)
+{
+ if (m_currentSurface == surface)
+ return;
+ if (m_currentSurface)
+ m_currentSurface->m_painter.end();
+ if (!surface) {
+ m_currentSurface = 0;
+ return;
+ }
+ BitmapTextureQt* surfaceQt = static_cast<BitmapTextureQt*>(surface);
+ if (!surfaceQt->m_painter.isActive())
+ surfaceQt->m_painter.begin(&surfaceQt->m_pixmap);
+ m_currentSurface = surfaceQt;
+}
+
+
+void TextureMapperQt::drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture)
+{
+ const BitmapTextureQt& textureQt = static_cast<const BitmapTextureQt&>(texture);
+ QPainter* painter = m_painter;
+ QPixmap pixmap = textureQt.m_pixmap;
+ if (m_currentSurface)
+ painter = &m_currentSurface->m_painter;
+
+ if (maskTexture && maskTexture->isValid()) {
+ const BitmapTextureQt* mask = static_cast<const BitmapTextureQt*>(maskTexture);
+ QPixmap intermediatePixmap(pixmap.size());
+ intermediatePixmap.fill(Qt::transparent);
+ QPainter maskPainter(&intermediatePixmap);
+ maskPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ maskPainter.drawPixmap(0, 0, pixmap);
+ maskPainter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
+ maskPainter.drawPixmap(QRect(0, 0, pixmap.width(), pixmap.height()), mask->m_pixmap, mask->sourceRect());
+ maskPainter.end();
+ pixmap = intermediatePixmap;
+ }
+
+ const qreal prevOpacity = painter->opacity();
+ const QTransform prevTransform = painter->transform();
+ painter->setOpacity(opacity);
+ painter->setTransform(matrix, true);
+ painter->drawPixmap(targetRect, pixmap, textureQt.sourceRect());
+ painter->setTransform(prevTransform);
+ painter->setOpacity(prevOpacity);
+}
+
+PassOwnPtr<TextureMapper> TextureMapper::create(GraphicsContext* context)
+{
+#ifdef QT_OPENGL_LIB
+ if (context && context->platformContext()->paintEngine()->type() == QPaintEngine::OpenGL2)
+ return new TextureMapperGL;
+#endif
+ return new TextureMapperQt;
+}
+
+PassRefPtr<BitmapTexture> TextureMapperQt::createTexture()
+{
+ return adoptRef(new BitmapTextureQt());
+}
+
+BitmapTextureQt::BitmapTextureQt()
+ : m_isPacked(false)
+{
+
+}
+
+#ifdef QT_OPENGL_LIB
+class RGBA32PremultimpliedBufferQt : public RGBA32PremultimpliedBuffer {
+public:
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& rect, bool opaque)
+ {
+ // m_image is only using during paint, it's safe to override it.
+ m_image = QImage(rect.size().width(), rect.size().height(), QImage::Format_ARGB32_Premultiplied);
+ if (!opaque)
+ m_image.fill(0);
+ m_painter.begin(&m_image);
+ TextureMapperQt::initialize(&m_painter);
+ m_painter.translate(-rect.x(), -rect.y());
+ return &m_painter;
+ }
+
+ virtual void endPaint() { m_painter.end(); }
+ virtual const void* data() const { return m_image.constBits(); }
+
+private:
+ QPainter m_painter;
+ QImage m_image;
+};
+
+PassRefPtr<RGBA32PremultimpliedBuffer> RGBA32PremultimpliedBuffer::create()
+{
+ return adoptRef(new RGBA32PremultimpliedBufferQt());
+}
+
+#endif
+};
diff --git a/Source/WebCore/platform/graphics/qt/TextureMapperQt.h b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h
new file mode 100644
index 0000000..e17b968
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TextureMapperQt.h
@@ -0,0 +1,76 @@
+/*
+ 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 "texmap/TextureMapper.h"
+
+#ifndef TextureMapperQt_h
+#define TextureMapperQt_h
+
+namespace WebCore {
+
+class BitmapTextureQt : public BitmapTexture {
+ friend class TextureMapperQt;
+public:
+ BitmapTextureQt();
+ ~BitmapTextureQt() { destroy(); }
+ virtual void destroy();
+ virtual IntSize size() const { return IntSize(m_pixmap.width(), m_pixmap.height()); }
+ virtual void reset(const IntSize&, bool opaque);
+ virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect);
+ virtual void endPaint();
+ virtual void setContentsToImage(Image*);
+ virtual bool save(const String& path);
+ virtual bool isValid() const { return !m_pixmap.isNull() || !m_image.isNull(); }
+ IntRect sourceRect() const { return IntRect(0, 0, contentSize().width(), contentSize().height()); }
+ virtual void pack();
+ virtual void unpack();
+ virtual bool isPacked() const { return m_isPacked; }
+
+private:
+ QPainter m_painter;
+ QPixmap m_pixmap;
+ QImage m_image;
+ bool m_isPacked;
+};
+
+class TextureMapperQt : public TextureMapper {
+public:
+ TextureMapperQt();
+
+ virtual void drawTexture(const BitmapTexture& texture, const IntRect& targetRect, const TransformationMatrix& matrix, float opacity, const BitmapTexture* maskTexture);
+ virtual void bindSurface(BitmapTexture* surface);
+ virtual void setClip(const IntRect&);
+ virtual void setGraphicsContext(GraphicsContext*);
+ virtual bool allowSurfaceForRoot() const { return false; }
+ virtual PassRefPtr<BitmapTexture> createTexture();
+
+ static void initialize(QPainter* painter)
+ {
+ painter->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform, false);
+ }
+
+ static PassOwnPtr<TextureMapper> create() { return new TextureMapperQt; }
+
+private:
+ QPainter* m_painter;
+ RefPtr<BitmapTextureQt> m_currentSurface;
+};
+
+}
+#endif
diff --git a/Source/WebCore/platform/graphics/qt/TileQt.cpp b/Source/WebCore/platform/graphics/qt/TileQt.cpp
new file mode 100644
index 0000000..096ce14
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TileQt.cpp
@@ -0,0 +1,179 @@
+/*
+ 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());
+ m_backBuffer->fill(m_backingStore->m_client->tiledBackingStoreBackgroundColor());
+ } 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
diff --git a/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp b/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
new file mode 100644
index 0000000..a5bc3c3
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TransformationMatrixQt.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "AffineTransform.h"
+#include "TransformationMatrix.h"
+
+#include "IntRect.h"
+#include "FloatRect.h"
+
+namespace WebCore {
+
+TransformationMatrix::operator QTransform() const
+{
+ return QTransform(m11(), m12(), m14(), m21(), m22(), m24(), m41(), m42(), m44());
+}
+
+AffineTransform::operator QTransform() const
+{
+ return QTransform(a(), b(), c(), d(), e(), f());
+}
+
+}
+
+// vim: ts=4 sw=4 et
diff --git a/Source/WebCore/platform/graphics/qt/TransparencyLayer.h b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h
new file mode 100644
index 0000000..5b2f8b2
--- /dev/null
+++ b/Source/WebCore/platform/graphics/qt/TransparencyLayer.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.org>
+ * Copyright (C) 2006 Allan Sandfeld Jensen <sandfeld@kde.org>
+ * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) 2008 Dirk Schulze <vbs85@gmx.de>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TransparencyLayer_h
+#define TransparencyLayer_h
+
+#include <QPaintEngine>
+#include <QPainter>
+#include <QPixmap>
+
+namespace WebCore {
+
+struct TransparencyLayer : FastAllocBase {
+ TransparencyLayer(const QPainter* p, const QRect &rect, qreal opacity, QPixmap& alphaMask)
+ : pixmap(rect.width(), rect.height())
+ , opacity(opacity)
+ , alphaMask(alphaMask)
+ , saveCounter(1) // see the comment for saveCounter
+ {
+ offset = rect.topLeft();
+ pixmap.fill(Qt::transparent);
+ painter.begin(&pixmap);
+ painter.setRenderHints(p->renderHints());
+ painter.translate(-offset);
+ painter.setPen(p->pen());
+ painter.setBrush(p->brush());
+ painter.setTransform(p->transform(), true);
+ painter.setOpacity(p->opacity());
+ painter.setFont(p->font());
+ if (painter.paintEngine()->hasFeature(QPaintEngine::PorterDuff))
+ painter.setCompositionMode(p->compositionMode());
+ }
+
+ TransparencyLayer()
+ {
+ }
+
+ QPixmap pixmap;
+ QPoint offset;
+ QPainter painter;
+ qreal opacity;
+ // for clipToImageBuffer
+ QPixmap alphaMask;
+ // saveCounter is only used in combination with alphaMask
+ // otherwise, its value is unspecified
+ int saveCounter;
+private:
+ TransparencyLayer(const TransparencyLayer &) {}
+ TransparencyLayer & operator=(const TransparencyLayer &) { return *this; }
+};
+
+} // namespace WebCore
+
+#endif // TransparencyLayer_h