diff options
author | Ben Murdoch <benm@google.com> | 2010-05-11 18:35:50 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-05-14 10:23:05 +0100 |
commit | 21939df44de1705786c545cd1bf519d47250322d (patch) | |
tree | ef56c310f5c0cdc379c2abb2e212308a3281ce20 /WebCore/platform/graphics/qt | |
parent | 4ff1d8891d520763f17675827154340c7c740f90 (diff) | |
download | external_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.cpp | 8 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContext3DQt.cpp | 93 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsContextQt.cpp | 16 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsLayerQt.cpp | 304 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/GraphicsLayerQt.h | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/ImageDecoderQt.cpp | 4 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/MediaPlayerPrivateQt.cpp | 6 | ||||
-rw-r--r-- | WebCore/platform/graphics/qt/PathQt.cpp | 29 |
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; |