summaryrefslogtreecommitdiffstats
path: root/WebCore/platform/graphics/qt
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-05-11 18:35:50 +0100
committerBen Murdoch <benm@google.com>2010-05-14 10:23:05 +0100
commit21939df44de1705786c545cd1bf519d47250322d (patch)
treeef56c310f5c0cdc379c2abb2e212308a3281ce20 /WebCore/platform/graphics/qt
parent4ff1d8891d520763f17675827154340c7c740f90 (diff)
downloadexternal_webkit-21939df44de1705786c545cd1bf519d47250322d.zip
external_webkit-21939df44de1705786c545cd1bf519d47250322d.tar.gz
external_webkit-21939df44de1705786c545cd1bf519d47250322d.tar.bz2
Merge Webkit at r58956: Initial merge by Git.
Change-Id: I1d9fb60ea2c3f2ddc04c17a871acdb39353be228
Diffstat (limited to 'WebCore/platform/graphics/qt')
-rw-r--r--WebCore/platform/graphics/qt/FontQt.cpp8
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp93
-rw-r--r--WebCore/platform/graphics/qt/GraphicsContextQt.cpp16
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.cpp304
-rw-r--r--WebCore/platform/graphics/qt/GraphicsLayerQt.h4
-rw-r--r--WebCore/platform/graphics/qt/ImageDecoderQt.cpp4
-rw-r--r--WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp6
-rw-r--r--WebCore/platform/graphics/qt/PathQt.cpp29
8 files changed, 293 insertions, 171 deletions
diff --git a/WebCore/platform/graphics/qt/FontQt.cpp b/WebCore/platform/graphics/qt/FontQt.cpp
index 974c179..946faeb 100644
--- a/WebCore/platform/graphics/qt/FontQt.cpp
+++ b/WebCore/platform/graphics/qt/FontQt.cpp
@@ -180,13 +180,7 @@ float Font::floatWidthForComplexText(const TextRun& run, HashSet<const SimpleFon
String sanitized = Font::normalizeSpaces(String(run.characters(), run.length()));
QString string = fromRawDataWithoutRef(sanitized);
- QTextLayout layout(string, font());
- QTextLine line = setupLayout(&layout, run);
-#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
- int w = int(line.horizontalAdvance());
-#else
- int w = int(line.naturalTextWidth());
-#endif
+ 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;
diff --git a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
index b0dd289..8dfb967 100644
--- a/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp
@@ -154,8 +154,7 @@ public:
~GraphicsContext3DInternal();
bool isContextValid() { return m_contextValid; }
-
-
+ QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient);
glActiveTextureType activeTexture;
glAttachShaderType attachShader;
@@ -248,6 +247,7 @@ public:
glVertexAttribPointerType vertexAttribPointer;
GraphicsContext3D::Attributes m_attrs;
+ HostWindow* m_hostWindow;
QGLWidget* m_glWidget;
GLuint m_texture;
GLuint m_mainFbo;
@@ -258,7 +258,6 @@ public:
private:
- QGLWidget* getOwnerGLWidget(QWebPageClient* webPageClient);
void* getProcAddress(const String& proc);
bool m_contextValid;
};
@@ -268,9 +267,20 @@ private:
#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
+}
+
GraphicsContext3DInternal::GraphicsContext3DInternal(GraphicsContext3D::Attributes attrs, HostWindow* hostWindow)
: m_attrs(attrs)
+ , m_hostWindow(hostWindow)
, m_glWidget(0)
, m_texture(0)
, m_mainFbo(0)
@@ -515,7 +525,7 @@ void GraphicsContext3D::beginPaint(WebGLRenderingContext* context)
glReadPixels(/* x */ 0, /* y */ 0, m_currentWidth, m_currentHeight, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, m_internal->m_pixels.bits());
QPainter* p = imageBuffer->context()->platformContext();
- p->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.transformed(QMatrix().rotate(180)));
+ p->drawImage(/* x */ 0, /* y */ 0, m_internal->m_pixels.rgbSwapped().transformed(QMatrix().rotate(180)));
m_internal->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_internal->m_currentFbo);
}
@@ -524,6 +534,23 @@ void GraphicsContext3D::endPaint()
{
}
+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(QPointF(0, 0), 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))
@@ -1466,56 +1493,19 @@ long GraphicsContext3D::getVertexAttribOffset(unsigned long index, unsigned long
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, unsigned internalformat, unsigned width, unsigned height, unsigned border, unsigned format, unsigned type, void* pixels)
{
+ m_internal->m_glWidget->makeCurrent();
glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
return 0;
}
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, Image* image, bool flipY, bool premultiplyAlpha)
-{
- ASSERT(image);
-
- m_internal->m_glWidget->makeCurrent();
-
- Vector<uint8_t> imageData;
- GLuint format;
- GLuint internalFormat;
-
- if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) {
- LOG_ERROR("GraphicsContext3D::texImage2D: could not extract Image data");
- return -1;
- }
-
- glTexImage2D(target, level, internalFormat, image->width(), image->height(),
- /* border */ 0, format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data());
-
- return 0;
-}
-
+
int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, unsigned width, unsigned height, unsigned format, unsigned type, void* pixels)
{
+ m_internal->m_glWidget->makeCurrent();
glTexSubImage2D(target, level, xoff, yoff, width, height, format, type, pixels);
return 0;
}
-int GraphicsContext3D::texSubImage2D(unsigned target, unsigned level, unsigned xoff, unsigned yoff, Image* image, bool flipY, bool premultiplyAlpha)
-{
- ASSERT(image);
-
- Vector<uint8_t> imageData;
- GLuint format;
- GLuint internalFormat;
-
- if (!extractImageData(image, flipY, premultiplyAlpha, imageData, &format, &internalFormat)) {
- LOG_ERROR("GraphicsContext3D::texSubImage2D: could not extract Image data");
- return -1;
- }
-
- glTexSubImage2D(target, level, xoff, yoff, image->width(), image->height(),
- format, GraphicsContext3D::UNSIGNED_BYTE, imageData.data());
-
- return 0;
-}
-
unsigned GraphicsContext3D::createBuffer()
{
m_internal->m_glWidget->makeCurrent();
@@ -1630,18 +1620,17 @@ bool GraphicsContext3D::getImageData(Image* image,
AlphaOp* neededAlphaOp,
unsigned int* format)
{
- QImage::Format imageFormat = (!premultiplyAlpha) ?
- QImage::Format_ARGB32 :
- QImage::Format_ARGB32_Premultiplied;
-
- QPixmap* nativePixmap = image->nativeImageForCurrentFrame();
*hasAlphaChannel = true;
- *neededAlphaOp = kAlphaDoNothing;
*format = GraphicsContext3D::RGBA;
- QImage nativeImage = nativePixmap->toImage().convertToFormat(imageFormat);
- outputVector.append(nativeImage.bits(), nativeImage.byteCount());
+ *neededAlphaOp = kAlphaDoNothing;
+ if (!premultiplyAlpha && *hasAlphaChannel)
+ *neededAlphaOp = kAlphaDoUnmultiply;
+
+ QPixmap* nativePixmap = image->nativeImageForCurrentFrame();
+ QImage nativeImage = nativePixmap->toImage().convertToFormat(QImage::Format_ARGB32);
+ outputVector.append(nativeImage.rgbSwapped().bits(), nativeImage.byteCount());
return true;
}
diff --git a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
index edac268..0100b72 100644
--- a/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsContextQt.cpp
@@ -641,12 +641,12 @@ void GraphicsContext::fillRect(const FloatRect& rect)
}
}
-void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace colorSpace)
+void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace colorSpace)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !color.isValid())
return;
- m_data->solidColor.setColor(c);
+ m_data->solidColor.setColor(color);
QPainter* p = m_data->p();
if (m_common->state.shadowColor.isValid())
drawBorderlessRectShadow(this, p, rect);
@@ -655,7 +655,7 @@ void GraphicsContext::fillRect(const FloatRect& rect, const Color& c, ColorSpace
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.alpha())
+ if (paintingDisabled() || !color.isValid() || !color.alpha())
return;
Path path = Path::createRoundedRectangle(rect, topLeft, topRight, bottomLeft, bottomRight);
@@ -717,7 +717,7 @@ void GraphicsContext::drawFocusRing(const Vector<Path>& paths, int width, int of
*/
void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int /* width */, int /* offset */, const Color& color)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !color.isValid())
return;
unsigned rectCount = rects.size();
@@ -1141,8 +1141,9 @@ void GraphicsContext::setURLForRect(const KURL&, const IntRect&)
void GraphicsContext::setPlatformStrokeColor(const Color& color, ColorSpace colorSpace)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !color.isValid())
return;
+
QPainter* p = m_data->p();
QPen newPen(p->pen());
m_data->solidColor.setColor(color);
@@ -1172,8 +1173,9 @@ void GraphicsContext::setPlatformStrokeThickness(float thickness)
void GraphicsContext::setPlatformFillColor(const Color& color, ColorSpace colorSpace)
{
- if (paintingDisabled())
+ if (paintingDisabled() || !color.isValid())
return;
+
m_data->solidColor.setColor(color);
m_data->p()->setBrush(m_data->solidColor);
}
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
index 834cd4f..86c01de 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.cpp
@@ -32,15 +32,13 @@
#include <QtCore/qmetaobject.h>
#include <QtCore/qset.h>
#include <QtCore/qtimer.h>
-#include <QtGui/qbitmap.h>
#include <QtGui/qcolor.h>
#include <QtGui/qgraphicseffect.h>
#include <QtGui/qgraphicsitem.h>
#include <QtGui/qgraphicsscene.h>
-#include <QtGui/qmatrix4x4.h>
#include <QtGui/qpainter.h>
-#include <QtGui/qpalette.h>
#include <QtGui/qpixmap.h>
+#include <QtGui/qpixmapcache.h>
#include <QtGui/qstyleoption.h>
namespace WebCore {
@@ -132,7 +130,9 @@ public:
};
// the compositor lets us special-case images and colors, so we try to do so
- enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType};
+ enum StaticContentType { HTMLContentType, PixmapContentType, ColorContentType, MediaContentType, Canvas3DContentType};
+
+ const GraphicsLayerQtImpl* rootLayer() const;
GraphicsLayerQtImpl(GraphicsLayerQt* newLayer);
virtual ~GraphicsLayerQtImpl();
@@ -142,24 +142,25 @@ public:
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
+ // 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&);
- QTransform computeTransform(const TransformationMatrix& baseTransform) const;
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);
- // optimization: returns true if this or an ancestor has a transform animation running.
- // this enables us to use ItemCoordinatesCache while the animation is running, otherwise we have to recache for every frame
- bool isTransformAnimationRunning() const;
-
public slots:
// we need to notify the client (aka the layer compositor) when the animation actually starts
void notifyAnimationStarted();
@@ -175,6 +176,7 @@ public:
GraphicsLayerQt* m_layer;
TransformationMatrix m_baseTransform;
+ TransformationMatrix m_transformRelativeToRootLayer;
bool m_transformAnimationRunning;
bool m_opacityAnimationRunning;
QWeakPointer<MaskEffectQt> m_maskEffect;
@@ -203,6 +205,7 @@ public:
int m_changeMask;
QSizeF m_size;
+ QPixmapCache::Key m_backingStoreKey;
#ifndef QT_NO_ANIMATION
QList<QWeakPointer<QAbstractAnimation> > m_animations;
#endif
@@ -236,6 +239,10 @@ public:
}
} m_state;
+#if ENABLE(3D_CANVAS)
+ const GraphicsContext3D* m_gc3D;
+#endif
+
#ifndef QT_NO_ANIMATION
friend class AnimationQtBase;
#endif
@@ -247,6 +254,9 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
, m_transformAnimationRunning(false)
, m_opacityAnimationRunning(false)
, m_changeMask(NoChanges)
+#if ENABLE(3D_CANVAS)
+ , m_gc3D(0)
+#endif
{
// we use graphics-view for compositing, not for interactivity
setAcceptedMouseButtons(Qt::NoButton);
@@ -255,9 +265,6 @@ GraphicsLayerQtImpl::GraphicsLayerQtImpl(GraphicsLayerQt* newLayer)
// they are ignored and passed to the item below.
setEnabled(true);
- // we'll set the cache when we know what's going on
- setCacheMode(ItemCoordinateCache);
-
connect(this, SIGNAL(notifyAnimationStartedAsync()), this, SLOT(notifyAnimationStarted()), Qt::QueuedConnection);
}
@@ -283,65 +290,138 @@ GraphicsLayerQtImpl::~GraphicsLayerQtImpl()
#endif
}
-void GraphicsLayerQtImpl::updateTransform()
+const GraphicsLayerQtImpl* GraphicsLayerQtImpl::rootLayer() const
{
- setBaseTransform(isTransformAnimationRunning() ? m_baseTransform : m_layer->transform());
+ if (const GraphicsLayerQtImpl* parent = qobject_cast<const GraphicsLayerQtImpl*>(parentObject()))
+ return parent->rootLayer();
+ return this;
}
-void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
-{
- m_baseTransform = baseTransform;
- setTransform(computeTransform(baseTransform));
-}
-QTransform GraphicsLayerQtImpl::computeTransform(const TransformationMatrix& baseTransform) const
+
+QPixmap GraphicsLayerQtImpl::recache(const QRegion& regionToUpdate)
{
- if (!m_layer)
- return baseTransform;
+ if (!m_layer->drawsContent())
+ return QPixmap();
- TransformationMatrix computedTransform;
+ QRegion region = regionToUpdate;
+ QPixmap pixmap;
- // The origin for childrenTransform is always the center of the ancestor which contains the childrenTransform.
- // this has to do with how WebCore implements -webkit-perspective and -webkit-perspective-origin, which are the CSS
- // attribute that call setChildrenTransform
- QPointF offset = -pos() - boundingRect().bottomRight() / 2;
+ // We might be drawing into an existing cache.
+ if (!QPixmapCache::find(m_backingStoreKey, &pixmap))
+ region = QRegion(QRect(0, 0, m_size.width(), m_size.height()));
- for (const GraphicsLayerQtImpl* ancestor = this; (ancestor = qobject_cast<GraphicsLayerQtImpl*>(ancestor->parentObject())); ) {
- if (!ancestor->m_state.childrenTransform.isIdentity()) {
- const QPointF offset = mapFromItem(ancestor, QPointF(ancestor->m_size.width() / 2, ancestor->m_size.height() / 2));
- computedTransform
- .translate(offset.x(), offset.y())
- .multLeft(ancestor->m_state.childrenTransform)
- .translate(-offset.x(), -offset.y());
- break;
- }
+ if (m_size != pixmap.size()) {
+ pixmap = QPixmap(m_size.toSize());
+ if (!m_layer->contentsOpaque())
+ pixmap.fill(Qt::transparent);
+ m_pendingContent.regionToUpdate = QRegion(QRect(QPoint(0, 0), m_size.toSize()));
}
+ QPainter painter(&pixmap);
+ GraphicsContext gc(&painter);
+
+ // Clear the area in cache that we're drawing into
+ painter.setCompositionMode(QPainter::CompositionMode_Clear);
+ painter.fillRect(region.boundingRect(), Qt::transparent);
+
+ // Render the actual contents into the cache
+ painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ m_layer->paintGraphicsLayerContents(gc, region.boundingRect());
+
+ m_backingStoreKey = QPixmapCache::insert(pixmap);
+ return pixmap;
+}
+
+void GraphicsLayerQtImpl::updateTransform()
+{
+ if (!m_transformAnimationRunning)
+ m_baseTransform = m_layer->transform();
+
+ TransformationMatrix localTransform;
+
+ GraphicsLayerQtImpl* parent = qobject_cast<GraphicsLayerQtImpl*>(parentObject());
+
// webkit has relative-to-size originPoint, graphics-view has a pixel originPoint, here we convert
// we have to manage this ourselves because QGraphicsView's transformOrigin is incompatible
const qreal originX = m_state.anchorPoint.x() * m_size.width();
const qreal originY = m_state.anchorPoint.y() * m_size.height();
- computedTransform
- .translate3d(originX, originY, m_state.anchorPoint.z())
- .multLeft(baseTransform)
+
+ // We ignore QGraphicsItem::pos completely, and use only transforms - because 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());
- // now we project to 2D
- return QTransform(computedTransform);
+ // 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;
+ }
+
+ // Simplistic depth test - we stack the item behind its parent if its computed z is lower than the parent's computed z at the item's center point.
+ if (parent) {
+ const QPointF centerPointMappedToRoot = rootLayer()->mapFromItem(this, m_size.width() / 2, m_size.height() / 2);
+ setFlag(ItemStacksBehindParent,
+ m_transformRelativeToRootLayer.mapPoint(FloatPoint3D(centerPointMappedToRoot.x(), centerPointMappedToRoot.y(), 0)).z() <
+ parent->m_transformRelativeToRootLayer.mapPoint(FloatPoint3D(centerPointMappedToRoot.x(), centerPointMappedToRoot.y(), 0)).z());
+ }
+
+ // 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();
+ for (QList<QGraphicsItem*>::const_iterator it = children.begin(); it != children.end(); ++it)
+ if (GraphicsLayerQtImpl* layer= qobject_cast<GraphicsLayerQtImpl*>((*it)->toGraphicsObject()))
+ layer->updateTransform();
}
-bool GraphicsLayerQtImpl::isTransformAnimationRunning() const
+void GraphicsLayerQtImpl::setBaseTransform(const TransformationMatrix& baseTransform)
{
- if (m_transformAnimationRunning)
- return true;
- if (GraphicsLayerQtImpl* parent = qobject_cast<GraphicsLayerQtImpl*>(parentObject()))
- return parent->isTransformAnimationRunning();
- return false;
+ 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());
@@ -370,9 +450,11 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte
switch (m_currentContent.contentType) {
case HTMLContentType:
if (m_state.drawsContent) {
- // this is the expensive bit. we try to minimize calls to this area by proper caching
- GraphicsContext gc(painter);
- m_layer->paintGraphicsLayerContents(gc, option->rect);
+ 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_backingStoreKey, &backingStore) || backingStore.size() != m_size.toSize())
+ backingStore = recache(QRegion(m_state.contentsRect));
+ painter->drawPixmap(0, 0, backingStore);
}
break;
case PixmapContentType:
@@ -384,6 +466,11 @@ void GraphicsLayerQtImpl::paint(QPainter* painter, const QStyleOptionGraphicsIte
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
}
}
@@ -457,9 +544,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
}
}
- if ((m_changeMask & PositionChange) && (m_layer->position() != m_state.pos))
- setPos(m_layer->position().x(), m_layer->position().y());
-
if (m_changeMask & SizeChange) {
if (m_layer->size() != m_state.size) {
prepareGeometryChange();
@@ -472,7 +556,7 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
if (scene())
scene()->update();
- if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange)) {
+ if (m_changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | BackfaceVisibilityChange | PositionChange)) {
// 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;
@@ -484,19 +568,13 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
update();
setFlag(ItemHasNoContents, false);
- // no point in caching a directly composited pixmap into another pixmap
- setCacheMode(NoCache);
-
break;
case MediaContentType:
setFlag(ItemHasNoContents, true);
- setCacheMode(NoCache);
m_pendingContent.mediaLayer.data()->setParentItem(this);
break;
case ColorContentType:
- // no point in caching a solid-color rectangle
- setCacheMode(NoCache);
if (m_pendingContent.contentType != m_currentContent.contentType || m_pendingContent.contentsBackgroundColor != m_currentContent.contentsBackgroundColor)
update();
m_state.drawsContent = false;
@@ -509,15 +587,21 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
case HTMLContentType:
if (m_pendingContent.contentType != m_currentContent.contentType)
update();
- if (!m_state.drawsContent && m_layer->drawsContent()) {
+ if (!m_state.drawsContent && m_layer->drawsContent())
update();
- if (m_layer->drawsContent() && !m_maskEffect)
- setCacheMode(ItemCoordinateCache);
- } else if (!m_layer->drawsContent())
- setCacheMode(NoCache);
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
}
}
@@ -544,15 +628,16 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
if (m_maskEffect)
m_maskEffect.data()->update();
- else if (m_changeMask & DisplayChange)
+ else if (m_changeMask & DisplayChange) {
+ // Recache now: all the content is ready and we don't want to wait until the paint event.
+ recache(m_pendingContent.regionToUpdate);
update(m_pendingContent.regionToUpdate.boundingRect());
+ m_pendingContent.regionToUpdate = QRegion();
+ }
if ((m_changeMask & BackgroundColorChange) && (m_pendingContent.backgroundColor != m_currentContent.backgroundColor))
update();
- // FIXME: the following flags are currently not handled, as they don't have a clear test or are in low priority
- // GeometryOrientationChange, ContentsOrientationChange, BackfaceVisibilityChange, ChildrenTransformChange, Preserves3DChange
-
m_state.maskLayer = m_layer->maskLayer();
m_state.pos = m_layer->position();
m_state.anchorPoint = m_layer->anchorPoint();
@@ -572,7 +657,6 @@ void GraphicsLayerQtImpl::flushChanges(bool recursive, bool forceUpdateTransform
m_currentContent.contentType = m_pendingContent.contentType;
m_currentContent.mediaLayer = m_pendingContent.mediaLayer;
m_currentContent.backgroundColor = m_pendingContent.backgroundColor;
- m_currentContent.regionToUpdate |= m_pendingContent.regionToUpdate;
m_currentContent.contentsBackgroundColor = m_pendingContent.contentsBackgroundColor;
m_pendingContent.regionToUpdate = QRegion();
m_changeMask = NoChanges;
@@ -871,6 +955,23 @@ void GraphicsLayerQt::setContentsBackgroundColor(const Color& 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) {
@@ -1106,8 +1207,6 @@ public:
{
if (m_fillsForwards)
setCurrentTime(1);
- else if (m_layer && m_layer.data()->m_layer)
- m_layer.data()->setBaseTransform(m_layer.data()->m_layer->transform());
}
// the idea is that we let WebCore manage the transform-operations
@@ -1118,33 +1217,25 @@ public:
{
TransformationMatrix transformMatrix;
- // sometimes the animation values from WebCore are misleading and we have to use the actual matrix as source
- // The Mac implementation simply doesn't try to accelerate those (e.g. 360deg rotation), but we do.
- if (progress == 1 || !targetOperations.size() || sourceOperations == targetOperations) {
- TransformationMatrix sourceMatrix;
- sourceOperations.apply(m_boxSize, sourceMatrix);
- transformMatrix = m_sourceMatrix;
- transformMatrix.blend(sourceMatrix, 1 - progress);
- } else {
- 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;
- }
+ 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);
- }
+ if (validTransformLists) {
+ for (size_t i = 0; i < targetOperations.size(); ++i)
+ targetOperations.operations()[i]->blend(sourceOperations.at(i), progress)->apply(transformMatrix, m_boxSize);
+ } else {
+ targetOperations.apply(m_boxSize, transformMatrix);
+ transformMatrix.blend(m_sourceMatrix, progress);
}
+
m_layer.data()->setBaseTransform(transformMatrix);
if (m_fillsForwards)
m_layer.data()->m_layer->setTransform(m_layer.data()->m_baseTransform);
@@ -1163,7 +1254,10 @@ public:
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());
}
}
@@ -1181,8 +1275,6 @@ public:
{
if (m_fillsForwards)
setCurrentTime(1);
- else if (m_layer && m_layer.data()->m_layer)
- m_layer.data()->setOpacity(m_layer.data()->m_layer->opacity());
}
virtual void applyFrame(const qreal& fromValue, const qreal& toValue, qreal progress)
{
@@ -1204,6 +1296,12 @@ public:
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());
+
}
};
@@ -1269,6 +1367,8 @@ void GraphicsLayerQt::removeAnimationsForProperty(AnimatedPropertyID id)
if (*it) {
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;
@@ -1283,7 +1383,9 @@ void GraphicsLayerQt::removeAnimationsForKeyframes(const String& name)
if (*it) {
AnimationQtBase* anim = static_cast<AnimationQtBase*>((*it).data());
if (anim && anim->m_keyframesName == QString(name)) {
- (*it).data()->deleteLater();
+ // 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;
}
diff --git a/WebCore/platform/graphics/qt/GraphicsLayerQt.h b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
index 9e5832f..6de5a6e 100644
--- a/WebCore/platform/graphics/qt/GraphicsLayerQt.h
+++ b/WebCore/platform/graphics/qt/GraphicsLayerQt.h
@@ -74,6 +74,10 @@ public:
virtual void setContentsToImage(Image*);
virtual void setContentsToMedia(PlatformLayer*);
virtual void setContentsBackgroundColor(const Color&);
+#if ENABLE(3D_CANVAS)
+ virtual void setContentsToGraphicsContext3D(const GraphicsContext3D*);
+ virtual void setGraphicsContext3DNeedsDisplay();
+#endif
virtual void setGeometryOrientation(CompositingCoordinatesOrientation orientation);
virtual void setContentsOrientation(CompositingCoordinatesOrientation orientation);
virtual void distributeOpacity(float);
diff --git a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
index b48b278..a8110ca 100644
--- a/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
+++ b/WebCore/platform/graphics/qt/ImageDecoderQt.cpp
@@ -123,12 +123,14 @@ int ImageDecoderQt::repetitionCount() const
// Qt | WebCore | description
// -1 | 0 | infinite animation
// 0 | cAnimationLoopOnce | show every frame once
- // n | n | no idea if that is supported
+ // n | n+1 | Qt returns the # of iterations - 1
// n/a | cAnimationNone | show only the first frame
if (m_repetitionCount == -1)
m_repetitionCount = 0;
else if (m_repetitionCount == 0)
m_repetitionCount = cAnimationLoopOnce;
+ else
+ ++m_repetitionCount;
}
return m_repetitionCount;
diff --git a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
index bdac2a4..4d7b7b0 100644
--- a/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
+++ b/WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp
@@ -77,7 +77,7 @@ MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& mime, c
if (!mime.startsWith("audio/") && !mime.startsWith("video/"))
return MediaPlayer::IsNotSupported;
- if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMultimedia::ProbablySupported)
+ if (QMediaPlayer::hasSupport(mime, QStringList(codec)) >= QtMediaServices::ProbablySupported)
return MediaPlayer::IsSupported;
return MediaPlayer::MayBeSupported;
@@ -344,8 +344,8 @@ unsigned MediaPlayerPrivate::bytesLoaded() const
unsigned MediaPlayerPrivate::totalBytes() const
{
- if (m_mediaPlayer->availableMetaData().contains(QtMultimedia::Size))
- return m_mediaPlayer->metaData(QtMultimedia::Size).toInt();
+ if (m_mediaPlayer->availableMetaData().contains(QtMediaServices::Size))
+ return m_mediaPlayer->metaData(QtMediaServices::Size).toInt();
return 100;
}
diff --git a/WebCore/platform/graphics/qt/PathQt.cpp b/WebCore/platform/graphics/qt/PathQt.cpp
index ee4af7f..4b0c21f 100644
--- a/WebCore/platform/graphics/qt/PathQt.cpp
+++ b/WebCore/platform/graphics/qt/PathQt.cpp
@@ -69,12 +69,41 @@ Path& Path::operator=(const Path& other)
return *this;
}
+// Check whether a point is on the border
+bool isPointOnPathBorder(const QPolygonF& border, const QPointF& p)
+{
+ QPointF p1 = border.at(0);
+ QPointF p2;
+
+ for (int i = 1; i < border.size(); ++i) {
+ p2 = border.at(i);
+ // (x1<=x<=x2||x1=>x>=x2) && (y1<=y<=y2||y1=>y>=y2) && (y2-y1)(x-x1) == (y-y1)(x2-x1)
+ // In which, (y2-y1)(x-x1) == (y-y1)(x2-x1) is from (y2-y1)/(x2-x1) == (y-y1)/(x-x1)
+ // it want to check the slope between p1 and p2 is same with slope between p and p1,
+ // if so then the three points lie on the same line.
+ // In which, (x1<=x<=x2||x1=>x>=x2) && (y1<=y<=y2||y1=>y>=y2) want to make sure p is
+ // between p1 and p2, not outside.
+ if (((p.x() <= p1.x() && p.x() >= p2.x()) || (p.x() >= p1.x() && p.x() <= p2.x()))
+ && ((p.y() <= p1.y() && p.y() >= p2.y()) || (p.y() >= p1.y() && p.y() <= p2.y()))
+ && (p2.y() - p1.y()) * (p.x() - p1.x()) == (p.y() - p1.y()) * (p2.x() - p1.x())) {
+ 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;