diff options
Diffstat (limited to 'Source/WebCore/platform/graphics/texmap')
6 files changed, 1837 insertions, 0 deletions
diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp new file mode 100644 index 0000000..4698239 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.cpp @@ -0,0 +1,387 @@ +/* + 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 "GraphicsLayerTextureMapper.h" + +#include "TextureMapperNode.h" + +namespace WebCore { + +GraphicsLayerTextureMapper::GraphicsLayerTextureMapper(GraphicsLayerClient* client) + : GraphicsLayer(client) + , m_node(new TextureMapperNode()) + , m_changeMask(0) +{ +} + +void GraphicsLayerTextureMapper::notifyChange(TextureMapperNode::ChangeMask changeMask) +{ + m_changeMask |= changeMask; + if (!client()) + return; + client()->notifySyncRequired(this); +} + +void GraphicsLayerTextureMapper::didSynchronize() +{ + m_syncQueued = false; + m_changeMask = 0; + m_pendingContent.needsDisplay = false; + m_pendingContent.needsDisplayRect = IntRect(); +} + +void GraphicsLayerTextureMapper::setName(const String& name) +{ + GraphicsLayer::setName(name); +} + +GraphicsLayerTextureMapper::~GraphicsLayerTextureMapper() +{ +} + +/* \reimp (GraphicsLayer.h): The current size might change, thus we need to update the whole display. +*/ +void GraphicsLayerTextureMapper::setNeedsDisplay() +{ + m_pendingContent.needsDisplay = true; + notifyChange(TextureMapperNode::DisplayChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setNeedsDisplayInRect(const FloatRect& rect) +{ + if (m_pendingContent.needsDisplay) + return; + m_pendingContent.needsDisplayRect.unite(IntRect(rect)); + notifyChange(TextureMapperNode::DisplayChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setParent(GraphicsLayer* layer) +{ + notifyChange(TextureMapperNode::ParentChange); + GraphicsLayer::setParent(layer); +} + +/* \reimp (GraphicsLayer.h) +*/ +bool GraphicsLayerTextureMapper::setChildren(const Vector<GraphicsLayer*>& children) +{ + notifyChange(TextureMapperNode::ChildrenChange); + return GraphicsLayer::setChildren(children); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChild(GraphicsLayer* layer) +{ + notifyChange(TextureMapperNode::ChildrenChange); + GraphicsLayer::addChild(layer); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildAtIndex(GraphicsLayer* layer, int index) +{ + GraphicsLayer::addChildAtIndex(layer, index); + notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildAbove(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + GraphicsLayer::addChildAbove(layer, sibling); + notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::addChildBelow(GraphicsLayer* layer, GraphicsLayer* sibling) +{ + + GraphicsLayer::addChildBelow(layer, sibling); + notifyChange(TextureMapperNode::ChildrenChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +bool GraphicsLayerTextureMapper::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* newChild) +{ + if (GraphicsLayer::replaceChild(oldChild, newChild)) { + notifyChange(TextureMapperNode::ChildrenChange); + return true; + } + return false; +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::removeFromParent() +{ + if (!parent()) + return; + notifyChange(TextureMapperNode::ParentChange); + GraphicsLayer::removeFromParent(); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setMaskLayer(GraphicsLayer* value) +{ + if (value == maskLayer()) + return; + GraphicsLayer::setMaskLayer(value); + notifyChange(TextureMapperNode::MaskLayerChange); +} + + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setReplicatedByLayer(GraphicsLayer* value) +{ + if (value == replicaLayer()) + return; + GraphicsLayer::setReplicatedByLayer(value); + notifyChange(TextureMapperNode::ReplicaLayerChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setPosition(const FloatPoint& value) +{ + if (value == position()) + return; + GraphicsLayer::setPosition(value); + notifyChange(TextureMapperNode::PositionChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setAnchorPoint(const FloatPoint3D& value) +{ + if (value == anchorPoint()) + return; + GraphicsLayer::setAnchorPoint(value); + notifyChange(TextureMapperNode::AnchorPointChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setSize(const FloatSize& value) +{ + if (value == size()) + return; + + GraphicsLayer::setSize(value); + notifyChange(TextureMapperNode::SizeChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setTransform(const TransformationMatrix& value) +{ + if (value == transform()) + return; + + GraphicsLayer::setTransform(value); + notifyChange(TextureMapperNode::TransformChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setChildrenTransform(const TransformationMatrix& value) +{ + if (value == childrenTransform()) + return; + GraphicsLayer::setChildrenTransform(value); + notifyChange(TextureMapperNode::ChildrenTransformChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setPreserves3D(bool value) +{ + if (value == preserves3D()) + return; + GraphicsLayer::setPreserves3D(value); + notifyChange(TextureMapperNode::Preserves3DChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setMasksToBounds(bool value) +{ + if (value == masksToBounds()) + return; + GraphicsLayer::setMasksToBounds(value); + notifyChange(TextureMapperNode::MasksToBoundsChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setDrawsContent(bool value) +{ + if (value == drawsContent()) + return; + notifyChange(TextureMapperNode::DrawsContentChange); + GraphicsLayer::setDrawsContent(value); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setBackgroundColor(const Color& value) +{ + if (value == m_pendingContent.backgroundColor) + return; + m_pendingContent.backgroundColor = value; + GraphicsLayer::setBackgroundColor(value); + notifyChange(TextureMapperNode::BackgroundColorChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::clearBackgroundColor() +{ + if (!m_pendingContent.backgroundColor.isValid()) + return; + m_pendingContent.backgroundColor = Color(); + GraphicsLayer::clearBackgroundColor(); + notifyChange(TextureMapperNode::BackgroundColorChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsOpaque(bool value) +{ + if (value == contentsOpaque()) + return; + notifyChange(TextureMapperNode::ContentsOpaqueChange); + GraphicsLayer::setContentsOpaque(value); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setBackfaceVisibility(bool value) +{ + if (value == backfaceVisibility()) + return; + GraphicsLayer::setBackfaceVisibility(value); + notifyChange(TextureMapperNode::BackfaceVisibilityChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setOpacity(float value) +{ + if (value == opacity()) + return; + GraphicsLayer::setOpacity(value); + notifyChange(TextureMapperNode::OpacityChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsRect(const IntRect& value) +{ + if (value == contentsRect()) + return; + GraphicsLayer::setContentsRect(value); + notifyChange(TextureMapperNode::ContentsRectChange); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsToImage(Image* image) +{ + notifyChange(TextureMapperNode::ContentChange); + m_pendingContent.contentType = image ? TextureMapperNode::DirectImageContentType : TextureMapperNode::HTMLContentType; + m_pendingContent.image = image; + GraphicsLayer::setContentsToImage(image); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsBackgroundColor(const Color& color) +{ + notifyChange(TextureMapperNode::ContentChange); + m_pendingContent.contentType = TextureMapperNode::ColorContentType; + m_pendingContent.backgroundColor = color; + GraphicsLayer::setContentsBackgroundColor(color); +} + + +void GraphicsLayerTextureMapper::setContentsToMedia(PlatformLayer* media) +{ + GraphicsLayer::setContentsToMedia(media); + notifyChange(TextureMapperNode::ContentChange); + m_pendingContent.contentType = media ? TextureMapperNode::MediaContentType : TextureMapperNode::HTMLContentType; + if (media) + m_pendingContent.media = static_cast<TextureMapperVideoLayer*>(media); + else + m_pendingContent.media = 0; +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::setContentsOrientation(CompositingCoordinatesOrientation orientation) +{ + if (contentsOrientation() == orientation) + return; + notifyChange(TextureMapperNode::ContentsOrientationChange); + GraphicsLayer::setContentsOrientation(orientation); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::syncCompositingStateForThisLayerOnly() +{ + m_node->syncCompositingState(this, false); +} + +/* \reimp (GraphicsLayer.h) +*/ +void GraphicsLayerTextureMapper::syncCompositingState() +{ + m_node->syncCompositingState(this, true); +} + +/* \reimp (GraphicsLayer.h) + */ +NativeLayer GraphicsLayerTextureMapper::nativeLayer() const +{ + return m_node.get(); +} + +/* \reimp (GraphicsLayer.h) +*/ +PlatformLayer* GraphicsLayerTextureMapper::platformLayer() const +{ + return m_node.get(); +} + +PassOwnPtr<GraphicsLayer> GraphicsLayer::create(GraphicsLayerClient* client) +{ + return new GraphicsLayerTextureMapper(client); +} + +} diff --git a/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h new file mode 100644 index 0000000..85fa3ee --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/GraphicsLayerTextureMapper.h @@ -0,0 +1,107 @@ +/* + 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 GraphicsLayerTextureMapper_h +#define GraphicsLayerTextureMapper_h + +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "GraphicsLayerClient.h" +#include "Image.h" +#include "TextureMapperNode.h" + +#if ENABLE(3D_CANVAS) +#include "GraphicsContext3D.h" +#endif + +namespace WebCore { + +class TextureMapperNode; +class BitmapTexture; +class TextureMapper; + +class GraphicsLayerTextureMapper : public GraphicsLayer { + friend class TextureMapperNode; + +public: + GraphicsLayerTextureMapper(GraphicsLayerClient*); + virtual ~GraphicsLayerTextureMapper(); + + // reimps from GraphicsLayer.h + virtual void setNeedsDisplay(); + virtual void setNeedsDisplayInRect(const FloatRect&); + virtual void setParent(GraphicsLayer* layer); + 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); + virtual void setReplicatedByLayer(GraphicsLayer*); + 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 setContentsOrientation(CompositingCoordinatesOrientation orientation); + virtual void syncCompositingState(); + virtual void syncCompositingStateForThisLayerOnly(); + virtual void setName(const String& name); + virtual NativeLayer nativeLayer() const; + virtual PlatformLayer* platformLayer() const; + + virtual bool addAnimation(const KeyframeValueList&, const IntSize& /*boxSize*/, const Animation*, const String& /*keyframesName*/, double /*timeOffset*/) { return false; } + + void notifyChange(TextureMapperNode::ChangeMask changeMask); + inline TextureMapperNode::ContentData& pendingContent() { return m_pendingContent; } + inline int changeMask() const { return m_changeMask; } + void didSynchronize(); + +private: + OwnPtr<TextureMapperNode> m_node; + bool m_syncQueued; + int m_changeMask; + TextureMapperNode::ContentData m_pendingContent; +}; + +inline static GraphicsLayerTextureMapper* toGraphicsLayerTextureMapper(GraphicsLayer* layer) +{ + return static_cast<GraphicsLayerTextureMapper*>(layer); +} + +} +#endif // GraphicsLayerTextureMapper_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapper.h b/Source/WebCore/platform/graphics/texmap/TextureMapper.h new file mode 100644 index 0000000..589fda1 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapper.h @@ -0,0 +1,135 @@ +/* + 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 TextureMapper_h +#define TextureMapper_h + +#if USE(ACCELERATED_COMPOSITING) +#if (defined(QT_OPENGL_LIB)) + #if defined(QT_OPENGL_ES_2) && !defined(TEXMAP_OPENGL_ES_2) + #define TEXMAP_OPENGL_ES_2 + #endif +#endif + +#include "GraphicsContext.h" +#include "IntRect.h" +#include "IntSize.h" +#include "TransformationMatrix.h" + +/* + TextureMapper is a mechanism that enables hardware acceleration of CSS animations (accelerated compositing) without + a need for a platform specific scene-graph library like CoreAnimations or QGraphicsView. +*/ + +namespace WebCore { + +class TextureMapper; + +// A 2D texture that can be the target of software or GL rendering. +class BitmapTexture : public RefCounted<BitmapTexture> { +public: + BitmapTexture() : m_lockCount(0) {} + virtual ~BitmapTexture() { } + + virtual bool allowOfflineTextureUpload() const { return false; } + virtual void destroy() = 0; + virtual IntSize size() const = 0; + virtual bool isValid() const = 0; + virtual void reset(const IntSize& size, bool opaque = false) + { + m_isOpaque = opaque; + m_contentSize = size; + } + + virtual void pack() { } + virtual void unpack() { } + virtual bool isPacked() const { return false; } + + virtual PlatformGraphicsContext* beginPaint(const IntRect& dirtyRect) = 0; + virtual void endPaint() = 0; + virtual PlatformGraphicsContext* beginPaintMedia() + { + return beginPaint(IntRect(0, 0, size().width(), size().height())); + } + virtual void setContentsToImage(Image*) = 0; + virtual bool save(const String& filename) { return false; } + + inline void lock() { ++m_lockCount; } + inline void unlock() { --m_lockCount; } + inline bool isLocked() { return m_lockCount; } + inline IntSize contentSize() const { return m_contentSize; } + inline void setOffset(const IntPoint& o) { m_offset = o; } + inline IntPoint offset() const { return m_offset; } + +protected: + +private: + int m_lockCount; + IntSize m_contentSize; + bool m_isOpaque; + IntPoint m_offset; +}; + +// A "context" class used to encapsulate accelerated texture mapping functions: i.e. drawing a texture +// onto the screen or into another texture with a specified transform, opacity and mask. +class TextureMapper { + friend class BitmapTexture; + +public: + static PassOwnPtr<TextureMapper> create(GraphicsContext* graphicsContext = 0); + virtual ~TextureMapper() { } + + virtual void drawTexture(const BitmapTexture& texture, const IntRect& target, const TransformationMatrix& matrix = TransformationMatrix(), float opacity = 1.0f, const BitmapTexture* maskTexture = 0) = 0; + + // makes a surface the target for the following drawTexture calls. + virtual void bindSurface(BitmapTexture* surface) = 0; + virtual void paintToTarget(const BitmapTexture& texture, const IntSize&, const TransformationMatrix& matrix, float opacity, const IntRect& visibleRect) + { + drawTexture(texture, IntRect(0, 0, texture.contentSize().width(), texture.contentSize().height()), matrix, opacity, 0); + } + + virtual void setGraphicsContext(GraphicsContext*) { } + virtual void setClip(const IntRect&) = 0; + virtual bool allowSurfaceForRoot() const = 0; + virtual PassRefPtr<BitmapTexture> createTexture() = 0; + + void setImageInterpolationQuality(InterpolationQuality quality) { m_interpolationQuality = quality; } + void setTextDrawingMode(TextDrawingModeFlags mode) { m_textDrawingMode = mode; } + + InterpolationQuality imageInterpolationQuality() const { return m_interpolationQuality; } + TextDrawingModeFlags textDrawingMode() const { return m_textDrawingMode; } + + void setViewportSize(const IntSize&); + +protected: + TextureMapper() + : m_interpolationQuality(InterpolationDefault) + , m_textDrawingMode(TextModeFill) + {} + +private: + InterpolationQuality m_interpolationQuality; + TextDrawingModeFlags m_textDrawingMode; +}; + +}; + +#endif + +#endif diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp new file mode 100644 index 0000000..09051f9 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp @@ -0,0 +1,877 @@ +/* + 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 "TextureMapperNode.h" + +#include "GraphicsLayerTextureMapper.h" + +namespace WebCore { + +class TextureMapperCache { +public: + void mark(BitmapTexture* texture); + + class Entry { + public: + RefPtr<BitmapTexture> texture; + Entry() : previousCost(0) { } + inline int computeCost() const + { + if (!texture || !texture->isValid() || texture->isPacked()) + return 0; + const IntSize textureSize = texture->size(); + // An image's cost in bytes is width * height * bytes per pixel (4). + return textureSize.width() * textureSize.height() * 4; + } + Entry(BitmapTexture* newTexture) + : texture(newTexture) + { + } + bool operator==(const Entry& other) const { return texture == other.texture; } + int previousCost; + }; + + TextureMapperCache() + : m_totalCost(0) + { + } + + void purge(); + Vector<Entry> m_data; + int m_totalCost; +#ifndef TEXMAP_TEXTURE_CACHE_KBS +#define TEXMAP_TEXTURE_CACHE_KBS 24 * 1024 +#endif + static const int MaxCost = TEXMAP_TEXTURE_CACHE_KBS * 1024; + static const int PurgeAmount = MaxCost / 4; +}; + + +void TextureMapperCache::purge() +{ + const int size = m_data.size(); + + if (m_totalCost <= TextureMapperCache::MaxCost) + return; + + // Ensure that we have the right count. It might be inaccurate if content changed size. + // We only do this when we're actually ready to purge. + m_totalCost = 0; + for (int i = 0; i < size; ++i) + m_totalCost += m_data[i].computeCost(); + + for (int i = size-1; i >= 0 && m_totalCost > TextureMapperCache::MaxCost - TextureMapperCache::PurgeAmount; --i) { + Entry& entry = m_data[i]; + if (entry.texture->isLocked() || !entry.texture->isValid() || entry.texture->isPacked()) + continue; + m_totalCost -= entry.previousCost; + entry.texture->pack(); + m_data.remove(i); + } +} + +void TextureMapperCache::mark(BitmapTexture* texture) +{ + if (!texture || !texture->isValid()) + return; + + Entry entry(texture); + size_t index = m_data.find(entry); + if (!index) + return; + + int previousCost = 0; + + if (index < m_data.size()) { + previousCost = m_data[index].previousCost; + m_data.remove(index); + } + const int cost = entry.computeCost(); + m_totalCost -= previousCost; + m_totalCost += (entry.previousCost = cost); + m_data.prepend(entry); +} + +class TextureMapperCacheLock { +public: + TextureMapperCacheLock(BitmapTexture* texture) : m_texture(texture) + { + if (m_texture) + m_texture->lock(); + } + ~TextureMapperCacheLock() + { + if (m_texture) + m_texture->unlock(); + } + +private: + RefPtr<BitmapTexture> m_texture; +}; + + +TextureMapperCache* TextureMapperNode::cache() +{ + TextureMapperNode* root = rootLayer(); + if (!root) + return 0; + if (!root->m_cache) + root->m_cache = new TextureMapperCache; + return root->m_cache; +} + +void TextureMapperNode::setNeedsDisplayInRect(IntRect rect) +{ + if (m_platformClient) { + if (m_state.hasSurfaceDescendants) { + m_platformClient->setNeedsDisplay(); + return; + } + rect.intersect(IntRect(0, 0, m_size.width(), m_size.height())); + if (rect.isEmpty()) + return; + m_platformClient->setNeedsDisplayInRect(rect); + return; + } + + if (!m_parent) + return; + + m_parent->setNeedsDisplayInRect(rect); +} + +void TextureMapperNode::setNeedsDisplay() +{ + if (m_effectTarget) + m_effectTarget->setNeedsDisplay(); + if (m_transforms.targetBoundingRect.isEmpty()) + return; + if (m_state.drawsContent || m_currentContent.contentType != HTMLContentType) + setNeedsDisplayInRect(m_transforms.targetBoundingRect); +} + +void TextureMapperNode::setPlatformLayerClient(TextureMapperLayerClient* client) +{ + m_platformClient = client; +} + +int TextureMapperNode::compareGraphicsLayersZValue(const void* a, const void* b) +{ + typedef const TextureMapperNode* NodePtr; + const NodePtr* nodeA = static_cast<const NodePtr*>(a); + const NodePtr* nodeB = static_cast<const NodePtr*>(b); + return int(((*nodeA)->m_transforms.centerZ - (*nodeB)->m_transforms.centerZ) * 1000); +} + +void TextureMapperNode::sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last) +{ + qsort(array.data(), array.size(), sizeof(TextureMapperNode*), TextureMapperNode::compareGraphicsLayersZValue); +} + +bool TextureMapperNode::hasSurfaceDescendants() const +{ + if (m_layerType == ClipLayer || m_layerType == TransparencyLayer || m_state.replicaLayer) + return true; + + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* child = m_children[i]) { + if (child->hasSurfaceDescendants()) + return true; + } + } + return false; +} + +int TextureMapperNode::countDescendantsWithContent() const +{ + if (!m_state.visible || m_state.opacity < 0.001) + return 0; + + int descendantsWithContent = (m_state.drawsContent || m_currentContent.contentType != HTMLContentType) ? 1 : 0; + + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* child = m_children[i]) + descendantsWithContent += child->countDescendantsWithContent(); + } + + return descendantsWithContent; +} + +TextureMapperNode* TextureMapperNode::toTextureMapperNode(GraphicsLayer* layer) +{ + return layer ? static_cast<TextureMapperNode*>(layer->platformLayer()) : 0; +} + +void TextureMapperNode::computeLayerType() +{ + const bool selfHasContent = m_state.drawsContent || (m_currentContent.contentType != HTMLContentType); + const bool hasDescendantsWithContent = m_state.descendantsWithContent - (selfHasContent ? 1 : 0); + const bool hasTransparency = m_state.opacity < 0.99 || m_state.maskLayer; + const bool hasReplica = m_state.replicaLayer; + + // DefaultLayer: draws itself and its children directly to the current framebuffer. + // any layer that doesn't conform to the other rules is a DefaultLayer. + m_layerType = DefaultLayer; + + // RootLayer: the top level. Draws to a framebuffer, and the target texture draws into the viewport. + // only one layer is the root layer. + if (!m_parent && !m_effectTarget) { + m_layerType = RootLayer; + return; + } + + // A layer with no contents is always a default layer. + if (!m_state.descendantsWithContent) + return; + + // ClipLayer: creates a new framebuffer, the size of the layer, and then paints it to the enclosing BitmapTexture with the layer's transform/opacity. + // A clip layer is a layer that masks to bounds, doesn't preserve 3D, has children, and has a transparency/mask or a non-rectangular transform. + if (hasDescendantsWithContent && m_state.maskLayer) { + m_layerType = ClipLayer; + return; + } + + // ScissorLayer: draws to the current framebuffer, and applies an extra scissor before drawing its children. + // A scissor layer is a layer with children that masks to bounds, is not a transparency layer, and has a rectangular clip. + if (m_state.masksToBounds && hasDescendantsWithContent) { + if (hasTransparency || !m_state.transform.isIdentityOrTranslation() || m_parent->m_state.preserves3D) + m_layerType = ClipLayer; + else + m_layerType = ScissorLayer; + return; + } + + // TransparencyLayer: creates a new framebuffer idetical in size to the current framebuffer. Then draws the fb's texture to the current framebuffer with identity transform. + // Used for layers with children and transparency/mask that preserve 3D or don't mask to bounds. + if ((hasReplica && hasDescendantsWithContent) || (hasReplica && hasTransparency) || (hasTransparency && m_state.descendantsWithContent > 1)) + m_layerType = TransparencyLayer; +} + +void TextureMapperNode::initializeTextureMapper(TextureMapper* textureMapper) +{ + if (m_texture) + return; + m_surface = textureMapper->createTexture(); + m_replicaSurface = textureMapper->createTexture(); + m_texture = textureMapper->createTexture(); + cache()->mark(m_texture.get()); +} + +TextureMapperNode::TextureMapperNode() + : m_layerType(DefaultLayer) + , m_surface(0) + , m_parent(0) + , m_effectTarget(0) + , m_platformClient(0) + , m_cache(0) +{ +} + +TextureMapperNode* TextureMapperNode::rootLayer() +{ + if (m_effectTarget) + return m_effectTarget->rootLayer(); + if (m_parent) + return m_parent->rootLayer(); + return this; +} + +void TextureMapperNode::invalidateTransform() +{ + m_transforms.dirty = true; + if (m_layerType != ClipLayer) + m_state.dirty = true; + if (m_state.replicaLayer) + m_state.replicaLayer->invalidateTransform(); + const int size = m_children.size(); + for (int i = 0; i < size; ++i) { + if (TextureMapperNode* layer = m_children[i]) + layer->invalidateTransform(); + } +} + +void TextureMapperNode::computeLocalTransform() +{ + if (!m_transforms.localDirty) + return; + const float originX = m_state.anchorPoint.x() * m_size.width(); + const float originY = m_state.anchorPoint.y() * m_size.height(); + m_transforms.local = + TransformationMatrix() + .translate3d(originX + m_state.pos.x(), originY + m_state.pos.y(), m_state.anchorPoint.z()) + .multLeft(m_state.transform) + .translate3d(-originX, -originY, -m_state.anchorPoint.z()); + m_transforms.localDirty = false; +} + +void TextureMapperNode::flattenTo2DSpaceIfNecessary() +{ + if (m_state.preserves3D) + return; + + m_transforms.forDescendants.setM13(0); + m_transforms.forDescendants.setM23(0); + m_transforms.forDescendants.setM31(0); + m_transforms.forDescendants.setM32(0); + m_transforms.forDescendants.setM33(1); + m_transforms.forDescendants.setM34(0); + m_transforms.forDescendants.setM43(0); +} + +IntSize TextureMapperNode::nearestSurfaceSize() const +{ + if (m_layerType == ClipLayer || m_layerType == RootLayer) + return m_surface && !m_surface->size().isEmpty() ? m_surface->size() : m_size; + return m_parent->nearestSurfaceSize(); +} + +void TextureMapperNode::computeReplicaTransform() +{ + if (!m_state.replicaLayer) + return; + + m_nearestSurfaceSize = nearestSurfaceSize(); + + if (m_layerType != TransparencyLayer) { + m_transforms.replica = TransformationMatrix(m_transforms.target).multLeft(m_state.replicaLayer->m_transforms.local); + return; + } + + const float originX = m_transforms.target.m41(); + const float originY = m_transforms.target.m42(); + m_transforms.replica = + TransformationMatrix() + .translate(originX, originY) + .multLeft(m_state.replicaLayer->m_transforms.local) + .translate(-originX, -originY); +} + +void TextureMapperNode::computeTransformations() +{ + if (!m_transforms.dirty) + return; + + m_transforms.dirty = false; + if ((m_size.isEmpty() && m_state.masksToBounds)) + return; + + TextureMapperNode* parent = m_parent; + computeLocalTransform(); + + m_transforms.target = TransformationMatrix(parent ? parent->m_transforms.forDescendants : TransformationMatrix()).multLeft(m_transforms.local); + m_transforms.forDescendants = (m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target); + + if (m_effectTarget) + return; + + m_transforms.targetBoundingRect = IntRect(m_transforms.target.mapRect(entireRect())); + if (m_state.replicaLayer) + m_state.replicaLayer->computeTransformations(); + + flattenTo2DSpaceIfNecessary(); + + if (!m_state.backfaceVisibility && m_transforms.target.inverse().m33() < 0) { + m_state.visible = false; + return; + } + m_state.visible = true; + + if (parent && parent->m_state.preserves3D) + m_transforms.centerZ = m_transforms.target.mapPoint(FloatPoint3D(m_size.width() / 2, m_size.height() / 2, 0)).z(); + + if (!m_children.size()) + return; + + if (m_state.childrenTransform.isIdentity()) + return; + + const FloatPoint centerPoint = FloatPoint(m_size.width() / 2, m_size.height() / 2); + if (m_transforms.perspectiveDirty) + m_transforms.perspective = TransformationMatrix() + .translate(centerPoint.x(), centerPoint.y()) + .multLeft(m_state.childrenTransform) + .translate(-centerPoint.x(), -centerPoint.y()); + m_transforms.perspectiveDirty = false; + m_transforms.forDescendants.multLeft(m_transforms.perspective); +} + +void TextureMapperNode::uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect, GraphicsLayer* layer) +{ + if (m_size.isEmpty() || !layer) { + m_texture->destroy(); + return; + } + + if (m_currentContent.contentType == DirectImageContentType) { + if (m_currentContent.image) + m_texture->setContentsToImage(m_currentContent.image.get()); + return; + } + + if (m_currentContent.contentType == MediaContentType) { + if (!m_currentContent.media) + return; + m_texture->reset(m_size, true); + PlatformGraphicsContext* platformContext = m_texture->beginPaintMedia(); + GraphicsContext context(platformContext); + m_currentContent.media->paint(&context); + m_texture->endPaint(); + return; + } + + const bool needsReset = (m_texture->contentSize() != m_size) || !m_texture->isValid(); + if ((m_currentContent.contentType != HTMLContentType) + || (!m_currentContent.needsDisplay && m_currentContent.needsDisplayRect.isEmpty() && !needsReset)) + return; + + IntRect dirtyRect = IntRect(0, 0, m_size.width(), m_size.height()); + if (!needsReset && !m_currentContent.needsDisplay) + dirtyRect.intersect(m_currentContent.needsDisplayRect); + + if (needsReset) + m_texture->reset(m_size, m_state.contentsOpaque); + + { + GraphicsContext context(m_texture->beginPaint(dirtyRect)); + if (textureMapper) { + context.setImageInterpolationQuality(textureMapper->imageInterpolationQuality()); + context.setTextDrawingMode(textureMapper->textDrawingMode()); + } + layer->paintGraphicsLayerContents(context, dirtyRect); + } + m_texture->endPaint(); + m_currentContent.needsDisplay = false; +} + + +void TextureMapperNode::paint(TextureMapper* textureMapper, const TextureMapperContentLayer::PaintOptions& options) +{ + ASSERT(m_layerType == RootLayer); + if (m_size.isEmpty()) + return; + + TexmapPaintOptions opt; + opt.opacity = 1; + opt.rootLayer = this; + opt.scissorRect = options.targetRect; + opt.visibleRect = options.visibleRect; + opt.textureMapper = textureMapper; + opt.surface = 0; + opt.cache = m_cache; + paintRecursive(opt); + + if (textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) { + textureMapper->bindSurface(0); + textureMapper->paintToTarget(*m_surface.get(), options.viewportSize, options.transform, options.opacity * m_state.opacity, options.targetRect); + } + m_cache->purge(); +} + +void TextureMapperNode::paintSelf(const TexmapPaintOptions& options) +{ + if (m_size.isEmpty() || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType)) + return; + + RefPtr<BitmapTexture> replicaMaskTexture; + m_texture->unpack(); + + RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->m_texture : 0; + if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer) + replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->m_texture; + + if (maskTexture) + maskTexture->unpack(); + + if (replicaMaskTexture) + replicaMaskTexture->unpack(); + + const float opacity = options.isSurface ? 1 : options.opacity; + + if (m_state.replicaLayer && !options.isSurface) + options.textureMapper->drawTexture(*m_texture.get(), replicaRect(), m_transforms.replica, + opacity * m_state.replicaLayer->m_state.opacity, + replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); + + const IntRect rect = m_layerType == ClipLayer ? entireRect() : targetRect(); + const TransformationMatrix transform = m_layerType == ClipLayer ? TransformationMatrix() : m_transforms.target; + options.textureMapper->drawTexture(*m_texture.get(), rect, transform, opacity, options.isSurface ? 0 : maskTexture.get()); + options.cache->mark(m_texture.get()); +} + +bool TextureMapperNode::paintReplica(const TexmapPaintOptions& options) +{ + BitmapTexture& texture = *m_surface.get(); + TextureMapperNode* replica = m_state.replicaLayer; + RefPtr<BitmapTexture> maskTexture; + if (TextureMapperNode* mask = m_state.maskLayer) + maskTexture = mask->m_texture; + RefPtr<BitmapTexture> replicaMaskTexture; + if (!replica) + return false; + + if (replica && replica->m_state.maskLayer) + replicaMaskTexture = replica->m_state.maskLayer->m_texture; + + if (replicaMaskTexture) + replicaMaskTexture->unpack(); + ASSERT(m_replicaSurface); + m_replicaSurface->reset(options.surface->size()); + m_replicaSurface->setOffset(options.surface->offset()); + options.cache->mark(m_replicaSurface.get()); + options.textureMapper->bindSurface(m_replicaSurface.get()); + options.textureMapper->drawTexture(texture, replicaRect(), m_transforms.replica, replica->m_state.opacity, replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get()); + options.textureMapper->drawTexture(texture, IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), 1.0f, maskTexture.get()); + options.textureMapper->bindSurface(options.surface); + options.cache->mark(options.surface); + options.textureMapper->drawTexture(*m_replicaSurface.get(), IntRect(IntPoint(0, 0), options.surface->size()), TransformationMatrix(), options.opacity, 0); + return true; +} + +void TextureMapperNode::paintSurface(const TexmapPaintOptions& options) +{ + if (m_layerType == RootLayer || m_layerType == DefaultLayer || m_layerType == ScissorLayer) + return; + + RefPtr<BitmapTexture> maskTexture; + if (TextureMapperNode* mask = m_state.maskLayer) + maskTexture = mask->m_texture; + + ASSERT(m_surface); + BitmapTexture& texture = *m_surface.get(); + if (maskTexture) + maskTexture->unpack(); + texture.unpack(); + + if (paintReplica(options)) + return; + + options.textureMapper->bindSurface(options.surface); + options.textureMapper->drawTexture(texture, + m_layerType == TransparencyLayer ? IntRect(IntPoint(0, 0), options.surface->size()) : + targetRect(), + m_layerType == TransparencyLayer ? TransformationMatrix() : m_transforms.target, + options.opacity, maskTexture.get()); + options.cache->mark(&texture); +} + +void TextureMapperNode::paintSelfAndChildren(const TexmapPaintOptions& options, TexmapPaintOptions& optionsForDescendants) +{ + bool didPaintSelf = false; + if (!m_state.preserves3D || m_children.isEmpty()) { + paintSelf(options); + didPaintSelf = true; + } + + if (m_children.isEmpty() && !options.isSurface) + return; + + if (m_layerType == ScissorLayer) + optionsForDescendants.scissorRect.intersect(m_transforms.target.mapRect(IntRect(0, 0, m_size.width(), m_size.height()))); + + for (int i = 0; i < m_children.size(); ++i) { + TextureMapperNode* layer = m_children[i]; + if (!layer) + continue; + + if (!didPaintSelf && layer->m_transforms.centerZ >= 0) { + paintSelf(options); + didPaintSelf = true; + } + layer->paintRecursive(optionsForDescendants); + if (options.isSurface) { + ASSERT(m_surface); + options.cache->mark(m_surface.get()); + options.textureMapper->bindSurface(m_surface.get()); + } + } + if (!didPaintSelf) { + paintSelf(options); + didPaintSelf = true; + } +} + +void TextureMapperNode::paintRecursive(TexmapPaintOptions options) +{ + bool isDirty = m_state.dirty; + m_state.dirty = false; + + if ((m_size.isEmpty() && (m_state.masksToBounds + || m_children.isEmpty())) || !m_state.visible || options.opacity < 0.01 || m_state.opacity < 0.01) + return; + + computeReplicaTransform(); + + if (m_state.maskLayer) + m_state.maskLayer->m_state.dirty = false; + + if (m_state.replicaLayer) { + m_state.replicaLayer->m_state.dirty = false; + if (m_state.replicaLayer->m_state.maskLayer) + m_state.replicaLayer->m_state.maskLayer->m_state.dirty = false; + } + + const bool isSurface = (m_layerType == ClipLayer + || m_layerType == TransparencyLayer + || (m_layerType == RootLayer + && (options.textureMapper->allowSurfaceForRoot() || m_state.hasSurfaceDescendants) + )); + + const IntRect boundingRectfromNearestSurface = m_transforms.targetBoundingRect; + + options.opacity *= m_state.opacity; + + TexmapPaintOptions optionsForDescendants(options); + optionsForDescendants.opacity = isSurface ? 1 : options.opacity; + options.isSurface = isSurface; + + if (m_layerType == ClipLayer) { + optionsForDescendants.visibleRect = TransformationMatrix().translate(-boundingRectfromNearestSurface.x(), -boundingRectfromNearestSurface.y()).mapRect(options.visibleRect); + optionsForDescendants.scissorRect = IntRect(0, 0, m_size.width(), m_size.height()); + } + + if (m_layerType == ScissorLayer) + optionsForDescendants.scissorRect.intersect(m_transforms.targetBoundingRect); + options.textureMapper->setClip(optionsForDescendants.scissorRect); + + TextureMapperCacheLock(m_texture.get()); + TextureMapperCacheLock(m_surface.get()); + TextureMapperCacheLock(m_replicaSurface.get()); + + options.cache->purge(); + + if (isSurface) { + ASSERT(m_surface); + if (!m_surface->isValid()) + isDirty = true; + if (m_state.tiled) { + m_surface->reset(options.visibleRect.size()); + m_surface->setOffset(options.visibleRect.location()); + } else if (isDirty) + m_surface->reset(m_layerType == TransparencyLayer ? options.surface->size() : m_size); + options.cache->mark(m_surface.get()); + options.textureMapper->bindSurface(m_surface.get()); + optionsForDescendants.surface = m_surface.get(); + } else if (m_surface) + m_surface->destroy(); + + if (isDirty || !isSurface || m_state.tiled || !m_surface->isValid()) + paintSelfAndChildren(options, optionsForDescendants); + + paintSurface(options); +} + +TextureMapperNode::~TextureMapperNode() +{ + setNeedsDisplay(); + { + const int childrenSize = m_children.size(); + for (int i = childrenSize-1; i >= 0; --i) { + ASSERT(m_children[i]->m_parent == this); + m_children[i]->m_parent = 0; + } + } + if (m_parent) + m_parent->m_children.remove(m_parent->m_children.find(this)); + if (m_cache) + delete m_cache; +} + +void TextureMapperNode::performPostSyncOperations() +{ + const LayerType prevLayerType = m_layerType; + computeLayerType(); + if (prevLayerType != m_layerType) + m_state.dirty = true; + if (m_transforms.dirty) + setNeedsDisplay(); + + computeTransformations(); + if (m_state.maskLayer && !m_state.dirty) + m_state.dirty = m_state.maskLayer->m_state.dirty; + if (m_state.replicaLayer && !m_state.dirty) + m_state.dirty = m_state.replicaLayer->m_state.dirty; + + const int size = m_children.size(); + + for (int i = size - 1; i >= 0; --i) { + TextureMapperNode* layer = m_children[i]; + + layer->performPostSyncOperations(); + if (!m_state.dirty) + m_state.dirty = layer->m_state.dirty; + } + m_state.hasSurfaceDescendants = hasSurfaceDescendants(); + if (m_state.dirty) + m_state.descendantsWithContent = countDescendantsWithContent(); + + if (m_state.preserves3D) + sortByZOrder(m_children, 0, size); + if (m_state.dirty) + setNeedsDisplay(); +} + +void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphicsLayer, bool recurse) +{ + TextureMapper* textureMapper = rootLayer()->m_platformClient->textureMapper(); + syncCompositingStateInternal(graphicsLayer, recurse, textureMapper); + performPostSyncOperations(); +} + +void TextureMapperNode::syncCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper) +{ + const int changeMask = graphicsLayer->changeMask(); + initializeTextureMapper(textureMapper); + const TextureMapperNode::ContentData& pendingContent = graphicsLayer->pendingContent(); + if (changeMask == NoChanges && pendingContent.needsDisplayRect.isEmpty() && !pendingContent.needsDisplay) + return; + + setNeedsDisplay(); + if (m_parent) + m_parent->m_state.dirty = true; + + if (m_currentContent.contentType == HTMLContentType && (changeMask & ParentChange)) { + // The WebCore compositor manages item ownership. We have to make sure graphicsview doesn't + // try to snatch that ownership. + + if (!graphicsLayer->parent()) + m_parent = 0; + else + m_parent = toTextureMapperNode(graphicsLayer->parent()); + + if (!graphicsLayer->parent() && m_parent) { + size_t index = m_parent->m_children.find(this); + m_parent->m_children.remove(index); + } + } + + if (changeMask & ChildrenChange) { + m_children.clear(); + for (size_t i = 0; i < graphicsLayer->children().size(); ++i) { + if (TextureMapperNode* child = toTextureMapperNode(graphicsLayer->children()[i])) { + if (!child) + continue; + m_children.append(child); + child->m_parent = this; + } + } + m_state.dirty = true; + } + + if (changeMask & (SizeChange | ContentsRectChange)) { + IntSize wantedSize = IntSize(graphicsLayer->size().width(), graphicsLayer->size().height()); + if (wantedSize.isEmpty() && pendingContent.contentType == HTMLContentType) + wantedSize = IntSize(graphicsLayer->contentsRect().width(), graphicsLayer->contentsRect().height()); + + if (wantedSize != m_size) { + m_size = IntSize(wantedSize.width(), wantedSize.height()); + if (m_platformClient) + m_platformClient->setSizeChanged(m_size); + const bool needsTiling = m_size.width() > 2000 || m_size.height() > 2000; + if (m_state.tiled != needsTiling) + m_state.tiled = needsTiling; + m_state.dirty = true; + } + } + + if (changeMask & MaskLayerChange) { + if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->maskLayer())) + layer->m_effectTarget = this; + } + + if (changeMask & ReplicaLayerChange) { + if (TextureMapperNode* layer = toTextureMapperNode(graphicsLayer->replicaLayer())) + layer->m_effectTarget = this; + } + + if (changeMask & (TransformChange | SizeChange | AnchorPointChange | PositionChange)) + m_transforms.localDirty = true; + + if (changeMask & (ChildrenTransformChange | SizeChange)) + m_transforms.perspectiveDirty = true; + + if (changeMask & (ChildrenTransformChange | Preserves3DChange | TransformChange | AnchorPointChange | SizeChange | ContentsRectChange | BackfaceVisibilityChange | PositionChange | MaskLayerChange | DrawsContentChange | ContentChange | ReplicaLayerChange)) { + // 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. + invalidateTransform(); + } + + if (changeMask & DisplayChange) + m_state.dirty = true; + + m_state.maskLayer = toTextureMapperNode(graphicsLayer->maskLayer()); + m_state.replicaLayer = toTextureMapperNode(graphicsLayer->replicaLayer()); + m_state.pos = graphicsLayer->position(); + m_state.anchorPoint = graphicsLayer->anchorPoint(); + m_state.size = graphicsLayer->size(); + m_state.transform = graphicsLayer->transform(); + m_state.contentsRect = graphicsLayer->contentsRect(); + m_state.opacity = graphicsLayer->opacity(); + m_state.contentsRect = graphicsLayer->contentsRect(); + m_state.preserves3D = graphicsLayer->preserves3D(); + m_state.masksToBounds = graphicsLayer->masksToBounds(); + m_state.drawsContent = graphicsLayer->drawsContent(); + m_state.contentsOpaque = graphicsLayer->contentsOpaque(); + m_state.backfaceVisibility = graphicsLayer->backfaceVisibility(); + m_state.childrenTransform = graphicsLayer->childrenTransform(); + m_currentContent.contentType = pendingContent.contentType; + m_currentContent.image = pendingContent.image; + m_currentContent.media = pendingContent.media; + m_currentContent.backgroundColor = pendingContent.backgroundColor; + m_currentContent.needsDisplay = m_currentContent.needsDisplay || pendingContent.needsDisplay; + m_currentContent.needsDisplayRect.unite(pendingContent.needsDisplayRect); + +} + +void TextureMapperNode::syncCompositingStateInternal(GraphicsLayerTextureMapper* graphicsLayer, bool recurse, TextureMapper* textureMapper) +{ + syncCompositingStateSelf(graphicsLayer, textureMapper); + + graphicsLayer->didSynchronize(); + + if (m_state.maskLayer) { + m_state.maskLayer->syncCompositingStateInternal(toGraphicsLayerTextureMapper(graphicsLayer->maskLayer()), false, textureMapper); + if (m_state.maskLayer->m_size.isEmpty()) + m_state.maskLayer->m_size = m_size; + } + + if (m_state.replicaLayer) + m_state.replicaLayer->syncCompositingStateInternal(toGraphicsLayerTextureMapper(graphicsLayer->replicaLayer()), false, textureMapper); + + if (m_state.dirty) + uploadTextureFromContent(textureMapper, m_state.visibleRect, graphicsLayer); + + m_currentContent.needsDisplayRect = IntRect(); + m_currentContent.needsDisplay = false; + + if (!recurse) + return; + + Vector<GraphicsLayer*> children = graphicsLayer->children(); + for (int i = children.size() - 1; i >= 0; --i) { + TextureMapperNode* node = toTextureMapperNode(children[i]); + if (!node) + continue; + node->syncCompositingStateInternal(toGraphicsLayerTextureMapper(children[i]), true, textureMapper); + } +} + +} diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h new file mode 100644 index 0000000..9694043 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h @@ -0,0 +1,252 @@ +/* + 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 TextureMapperNode_h +#define TextureMapperNode_h + +#include "CurrentTime.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "GraphicsLayer.h" +#include "HashMap.h" +#include "Image.h" +#include "RefCounted.h" +#include "TextureMapper.h" +#include "TextureMapperPlatformLayer.h" +#include "Timer.h" +#include "TransformOperations.h" +#include "TranslateTransformOperation.h" +#include "UnitBezier.h" + +namespace WebCore { + +class TextureMapperNode; +class TextureMapperCache; +class GraphicsLayerTextureMapper; + +struct TexmapPaintOptions { + BitmapTexture* surface; + TextureMapper* textureMapper; + TextureMapperNode* rootLayer; + float opacity; + IntRect scissorRect; + IntRect visibleRect; + bool isSurface; + TextureMapperCache* cache; +}; + +class TextureMapperNode : public TextureMapperContentLayer { + +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 << 9), + OpacityChange = (1L << 10), + ContentsRectChange = (1L << 11), + + Preserves3DChange = (1L << 12), + MasksToBoundsChange = (1L << 13), + DrawsContentChange = (1L << 14), + ContentsOpaqueChange = (1L << 15), + + BackfaceVisibilityChange = (1L << 16), + ChildrenTransformChange = (1L << 17), + DisplayChange = (1L << 18), + BackgroundColorChange = (1L << 19), + + ReplicaLayerChange = (1L << 20) + }; + // The compositor lets us special-case images and colors, so we try to do so. + enum ContentType { HTMLContentType, DirectImageContentType, ColorContentType, MediaContentType, Canvas3DContentType}; + struct ContentData { + IntRect needsDisplayRect; + bool needsDisplay; + Color backgroundColor; + + ContentType contentType; + RefPtr<Image> image; + TextureMapperVideoLayer* media; + + ContentData() + : needsDisplay(false) + , contentType(HTMLContentType) + , image(0) + , media(0) + { + } + }; + + + TextureMapperNode(); + virtual ~TextureMapperNode(); + + void syncCompositingState(GraphicsLayerTextureMapper*, bool recursive); + +protected: + // Reimps from TextureMapperContentLayer + virtual IntSize size() const { return m_size; } + virtual void setPlatformLayerClient(TextureMapperLayerClient*); + virtual void paint(TextureMapper*, const TextureMapperContentLayer::PaintOptions&); + +private: + TextureMapperNode* rootLayer(); + void clearDirectImage(); + void computeTransformations(); + IntSize nearestSurfaceSize() const; + void computeReplicaTransform(); + void computeLayerType(); + void computeLocalTransform(); + void flattenTo2DSpaceIfNecessary(); + void initializeTextureMapper(TextureMapper*); + void invalidateTransform(); + void notifyChange(ChangeMask); + void setNeedsDisplay(); + void setNeedsDisplayInRect(IntRect); + void performPostSyncOperations(); + void syncCompositingStateInternal(GraphicsLayerTextureMapper*, bool recursive, TextureMapper*); + void syncCompositingStateSelf(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper); + TextureMapperCache* cache(); + + void paintRecursive(TexmapPaintOptions options); + bool paintReplica(const TexmapPaintOptions& options); + void paintSurface(const TexmapPaintOptions& options); + void paintSelf(const TexmapPaintOptions& options); + void paintSelfAndChildren(const TexmapPaintOptions& options, TexmapPaintOptions& optionsForDescendants); + void uploadTextureFromContent(TextureMapper* textureMapper, const IntRect& visibleRect, GraphicsLayer* layer); + + int countDescendantsWithContent() const; + bool hasSurfaceDescendants() const; + + TextureMapper* textureMapper(); + + + static TextureMapperNode* toTextureMapperNode(GraphicsLayer*); + static int compareGraphicsLayersZValue(const void* a, const void* b); + static void sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last); + struct TransformData { + TransformationMatrix base, target, replica, forDescendants, perspective, local; + IntRect targetBoundingRect; + float centerZ; + bool dirty, localDirty, perspectiveDirty; + IntRect boundingRectFromRoot; + TransformData() : dirty(true), localDirty(true), perspectiveDirty(true) { } + }; + + TransformData m_transforms; + + enum LayerType { + DefaultLayer, + RootLayer, + ScissorLayer, + ClipLayer, + TransparencyLayer + }; + + LayerType m_layerType; + + inline IntRect targetRect() const + { + return m_currentContent.contentType == HTMLContentType ? entireRect() : m_state.contentsRect; + } + + inline IntRect entireRect() const + { + return IntRect(0, 0, m_size.width(), m_size.height()); + } + + inline IntRect replicaRect() const + { + return m_layerType == TransparencyLayer ? IntRect(0, 0, m_nearestSurfaceSize.width(), m_nearestSurfaceSize.height()) : entireRect(); + } + + RefPtr<BitmapTexture> m_texture; + RefPtr<BitmapTexture> m_surface, m_replicaSurface; + + ContentData m_currentContent; + + Vector<TextureMapperNode*> m_children; + TextureMapperNode* m_parent; + TextureMapperNode* m_effectTarget; + IntSize m_size, m_nearestSurfaceSize; + String m_name; + TextureMapperLayerClient* m_platformClient; + + struct State { + FloatPoint pos; + FloatPoint3D anchorPoint; + FloatSize size; + TransformationMatrix transform; + TransformationMatrix childrenTransform; + Color backgroundColor; + Color currentColor; + GraphicsLayer::CompositingCoordinatesOrientation geoOrientation; + GraphicsLayer::CompositingCoordinatesOrientation contentsOrientation; + float opacity; + IntRect contentsRect; + int descendantsWithContent; + TextureMapperNode* maskLayer; + TextureMapperNode* replicaLayer; + bool preserves3D; + bool masksToBounds; + bool drawsContent; + bool contentsOpaque; + bool backfaceVisibility; + bool visible; + bool dirty; + bool tiled; + bool hasSurfaceDescendants; + IntRect visibleRect; + + State() + : opacity(1.f) + , descendantsWithContent(0) + , maskLayer(0) + , replicaLayer(0) + , preserves3D(false) + , masksToBounds(false) + , drawsContent(false) + , contentsOpaque(false) + , backfaceVisibility(false) + , visible(true) + , dirty(true) + , tiled(false) + , hasSurfaceDescendants(false) + { + } + }; + + State m_state; + TextureMapperCache* m_cache; +}; + +} +#endif // TextureMapperNode_h diff --git a/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h new file mode 100644 index 0000000..2a38b90 --- /dev/null +++ b/Source/WebCore/platform/graphics/texmap/TextureMapperPlatformLayer.h @@ -0,0 +1,79 @@ +/* + 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 TextureMapperPlatformLayer_h +#define TextureMapperPlatformLayer_h + +namespace WebCore { + +class GraphicsContext; +class IntRect; +class IntSize; +class TextureMapper; +class TransformationMatrix; + + +// Glue layer to connect the texmap layer to the platform specific container. +class TextureMapperLayerClient { +public: + virtual ~TextureMapperLayerClient() {} + virtual void setNeedsDisplay() = 0; + virtual void setNeedsDisplayInRect(const IntRect& rect) = 0; + virtual void setSizeChanged(const IntSize&) = 0; + virtual TextureMapper* textureMapper() = 0; +}; + +class TextureMapperPlatformLayer { +public: + enum Type { + ContentLayer, + VideoLayer + }; + + virtual Type layerType() const = 0; + virtual ~TextureMapperPlatformLayer() {} +}; + +class TextureMapperContentLayer : public TextureMapperPlatformLayer { +public: + struct PaintOptions { + IntRect visibleRect; + IntRect targetRect; + IntSize viewportSize; + TransformationMatrix transform; + float opacity; + }; + + virtual void setPlatformLayerClient(TextureMapperLayerClient*) = 0; + virtual void paint(TextureMapper*, const PaintOptions&) {} + virtual IntSize size() const = 0; + virtual Type layerType() const { return ContentLayer; } +}; + +#if ENABLE(VIDEO) +class TextureMapperVideoLayer : public TextureMapperPlatformLayer { +public: + virtual void paint(GraphicsContext*) = 0; + virtual Type layerType() const { return VideoLayer; } +}; +#endif + +} + +#endif // TextureMapperPlatformLayer_h |