Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp (97162 => 97163)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp 2011-10-11 17:41:02 UTC (rev 97162)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.cpp 2011-10-11 17:43:00 UTC (rev 97163)
@@ -173,29 +173,31 @@
void TextureMapperNode::computeTiles()
{
+ if (m_state.tileOwnership == ExternallyManagedTiles)
+ return;
if (m_currentContent.contentType == HTMLContentType && !m_state.drawsContent) {
- m_tiles.clear();
+ m_ownedTiles.clear();
return;
}
Vector<FloatRect> tilesToAdd;
Vector<int> tilesToRemove;
const int TileEraseThreshold = 6;
FloatSize size = contentSize();
- FloatRect contentRect(0, 0, size.width() * m_state.contentScale, size.height() * m_state.contentScale);
+ FloatRect contentRect(0, 0, size.width(), size.height());
for (float y = 0; y < contentRect.height(); y += gTileDimension) {
for (float x = 0; x < contentRect.width(); x += gTileDimension) {
FloatRect tileRect(x, y, gTileDimension, gTileDimension);
tileRect.intersect(contentRect);
FloatRect tileRectInRootCoordinates = tileRect;
- tileRectInRootCoordinates.scale(1.0 / m_state.contentScale);
+ tileRectInRootCoordinates.scale(1.0);
tileRectInRootCoordinates = m_transforms.target.mapRect(tileRectInRootCoordinates);
tilesToAdd.append(tileRect);
}
}
- for (int i = m_tiles.size() - 1; i >= 0; --i) {
- const FloatRect oldTile = m_tiles[i].rect;
+ for (int i = m_ownedTiles.size() - 1; i >= 0; --i) {
+ const FloatRect oldTile = m_ownedTiles[i].rect;
bool found = false;
for (int j = tilesToAdd.size() - 1; j >= 0; --j) {
@@ -214,27 +216,73 @@
for (size_t i = 0; i < tilesToAdd.size(); ++i) {
if (!tilesToRemove.isEmpty()) {
- Tile& tile = m_tiles[tilesToRemove[0]];
+ OwnedTile& tile = m_ownedTiles[tilesToRemove[0]];
tilesToRemove.remove(0);
tile.rect = tilesToAdd[i];
tile.needsReset = true;
continue;
}
- Tile tile;
+ OwnedTile tile;
tile.rect = tilesToAdd[i];
tile.needsReset = true;
- m_tiles.append(tile);
+ m_ownedTiles.append(tile);
}
- for (size_t i = 0; i < tilesToRemove.size() && m_tiles.size() > TileEraseThreshold; ++i)
- m_tiles.remove(tilesToRemove[i]);
+ for (size_t i = 0; i < tilesToRemove.size() && m_ownedTiles.size() > TileEraseThreshold; ++i)
+ m_ownedTiles.remove(tilesToRemove[i]);
}
+static void clampRect(IntRect& rect, int dimension)
+{
+ rect.shiftXEdgeTo(rect.x() - rect.x() % dimension);
+ rect.shiftYEdgeTo(rect.y() - rect.y() % dimension);
+ rect.shiftMaxXEdgeTo(rect.maxX() - rect.x() % dimension + dimension);
+ rect.shiftMaxYEdgeTo(rect.maxY() - rect.y() % dimension + dimension);
+}
+
+bool TextureMapperNode::collectVisibleContentsRects(NodeRectMap& rectMap, const FloatRect& rootVisibleRect)
+{
+ if (!m_state.visible || m_state.opacity < 0.01)
+ return false;
+ bool exists = false;
+
+ for (int i = 0; i < m_children.size(); ++i)
+ exists = m_children[i]->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists;
+ if (m_state.maskLayer)
+ exists = m_state.maskLayer->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists;
+ if (m_state.replicaLayer)
+ exists = m_state.replicaLayer->collectVisibleContentsRects(rectMap, rootVisibleRect) || exists;
+
+ // Non-invertible layers are not visible.
+ if (!m_transforms.target.isInvertible())
+ return exists;
+
+ static const int tilingThreshold = 256;
+
+ IntRect visibleContentsRect(0, 0, m_size.width(), m_size.height());
+ if (m_size.width() > tilingThreshold || m_size.height() > tilingThreshold) {
+ IntRect visibleRectInLocalCoordinates = enclosingIntRect(TransformationMatrix(m_transforms.target).inverse().mapRect(rootVisibleRect));
+ if (!visibleRectInLocalCoordinates.isEmpty())
+ clampRect(visibleRectInLocalCoordinates, gTileDimension);
+ visibleContentsRect.intersect(visibleRectInLocalCoordinates);
+ }
+
+ if (visibleContentsRect.isEmpty() || visibleContentsRect == m_state.visibleRect)
+ return exists;
+
+ m_state.visibleRect = visibleContentsRect;
+ rectMap.add(this, m_state.visibleRect);
+
+ return true;
+}
+
void TextureMapperNode::renderContent(TextureMapper* textureMapper, GraphicsLayer* layer)
{
+ if (m_state.tileOwnership == ExternallyManagedTiles)
+ return;
if (m_size.isEmpty() || !layer || (!m_state.drawsContent && m_currentContent.contentType == HTMLContentType)) {
- m_tiles.clear();
+ m_ownedTiles.clear();
return;
}
@@ -246,10 +294,9 @@
// FIXME: Add directly composited images.
FloatRect dirtyRect = m_currentContent.needsDisplay ? entireRect() : m_currentContent.needsDisplayRect;
- dirtyRect.scale(m_state.contentScale);
- for (size_t tileIndex = 0; tileIndex < m_tiles.size(); ++tileIndex) {
- Tile& tile = m_tiles[tileIndex];
+ for (size_t tileIndex = 0; tileIndex < m_ownedTiles.size(); ++tileIndex) {
+ OwnedTile& tile = m_ownedTiles[tileIndex];
FloatRect rect = dirtyRect;
if (!tile.texture)
tile.texture = textureMapper->createTexture();
@@ -276,9 +323,7 @@
context.setImageInterpolationQuality(textureMapper->imageInterpolationQuality());
context.setTextDrawingMode(textureMapper->textDrawingMode());
context.translate(offset.x(), offset.y());
- context.scale(FloatSize(m_state.contentScale, m_state.contentScale));
FloatRect scaledContentRect(contentRect);
- scaledContentRect.scale(1.0 / m_state.contentScale);
if (m_currentContent.contentType == DirectImageContentType)
context.drawImage(m_currentContent.image.get(), ColorSpaceDeviceRGB, IntPoint(0, 0));
else
@@ -309,10 +354,10 @@
FloatRect TextureMapperNode::targetRectForTileRect(const FloatRect& targetRect, const FloatRect& tileRect) const
{
return FloatRect(
- targetRect.x() + (tileRect.x() - targetRect.x()) / m_state.contentScale,
- targetRect.y() + (tileRect.y() - targetRect.y()) / m_state.contentScale,
- tileRect.width() / m_state.contentScale,
- tileRect.height() / m_state.contentScale);
+ targetRect.x() + (tileRect.x() - targetRect.x()),
+ targetRect.y() + (tileRect.y() - targetRect.y()),
+ tileRect.width(),
+ tileRect.height());
}
void TextureMapperNode::paintSelf(const TextureMapperPaintOptions& options)
@@ -328,10 +373,9 @@
if (m_state.replicaLayer && m_state.replicaLayer->m_state.maskLayer)
replicaMaskTexture = m_state.replicaLayer->m_state.maskLayer->texture();
- const float opacity = options.isSurface ? 1 : options.opacity;
+ float opacity = options.isSurface ? 1 : options.opacity;
+ FloatRect targetRect = this->targetRect();
- const FloatRect targetRect = this->targetRect();
-
if (m_currentContent.contentType == MediaContentType && m_currentContent.media) {
if (m_state.replicaLayer && !options.isSurface)
m_currentContent.media->paintToTextureMapper(options.textureMapper, targetRect,
@@ -342,16 +386,56 @@
return;
}
- for (size_t i = 0; i < m_tiles.size(); ++i) {
- BitmapTexture* texture = m_tiles[i].texture.get();
+ Vector<ExternallyManagedTile> tilesToPaint;
+
+
+ if (m_state.tileOwnership == ExternallyManagedTiles) {
+ // Sort tiles, with current scale factor last.
+ Vector<ExternallyManagedTile*> tiles;
+ HashMap<int, ExternallyManagedTile>::iterator end = m_externallyManagedTiles.end();
+ for (HashMap<int, ExternallyManagedTile>::iterator it = m_externallyManagedTiles.begin(); it != end; ++it) {
+ if (!it->second.frontBuffer.texture)
+ continue;
+
+ if (it->second.scale == m_state.contentScale) {
+ tiles.append(&it->second);
+ continue;
+ }
+
+ // This creates a transitional effect looks good only when there's no transparency, so we only use it when the opacity for the layer is above a certain threshold.
+ if (opacity > 0.95)
+ tiles.prepend(&it->second);
+ }
+
+ TransformationMatrix replicaMatrix;
+ for (int i = 0; i < tiles.size(); ++i) {
+ ExternallyManagedTile& tile = *tiles[i];
+ FloatRect rect = tile.frontBuffer.targetRect;
+
+ float replicaOpacity = 1.0;
+ if (m_state.replicaLayer) {
+ replicaMatrix = TransformationMatrix(m_transforms.target).scale(1.0 / tile.scale).multiply(m_state.replicaLayer->m_transforms.local);
+ replicaOpacity = opacity * m_state.replicaLayer->m_opacity;
+ }
+ BitmapTexture& texture = *tile.frontBuffer.texture;
+ if (m_state.replicaLayer)
+ options.textureMapper->drawTexture(texture, rect, replicaMatrix, replicaOpacity, replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get());
+ options.textureMapper->drawTexture(texture, rect, m_transforms.target, opacity, options.isSurface ? 0 : maskTexture.get());
+ }
+ return;
+ }
+
+ // Now we paint owned tiles, if we're in OwnedTileMode.
+ for (size_t i = 0; i < m_ownedTiles.size(); ++i) {
+ BitmapTexture* texture = m_ownedTiles[i].texture.get();
if (m_state.replicaLayer && !options.isSurface) {
- options.textureMapper->drawTexture(*texture, targetRectForTileRect(targetRect, m_tiles[i].rect),
+ options.textureMapper->drawTexture(*texture, targetRectForTileRect(targetRect, m_ownedTiles[i].rect),
TransformationMatrix(m_transforms.target).multiply(m_state.replicaLayer->m_transforms.local),
opacity * m_state.replicaLayer->m_opacity,
replicaMaskTexture ? replicaMaskTexture.get() : maskTexture.get());
}
- const FloatRect rect = targetRectForTileRect(targetRect, m_tiles[i].rect);
+ const FloatRect rect = targetRectForTileRect(targetRect, m_ownedTiles[i].rect);
options.textureMapper->drawTexture(*texture, rect, m_transforms.target, opacity, options.isSurface ? 0 : maskTexture.get());
}
}
@@ -512,6 +596,81 @@
m_parent->m_children.remove(m_parent->m_children.find(this));
}
+#if ENABLE(TILED_BACKING_STORE)
+int TextureMapperNode::createContentsTile(float scale)
+{
+ static int nextID = 0;
+ int id = ++nextID;
+ m_externallyManagedTiles.add(id, ExternallyManagedTile(scale));
+ m_state.contentScale = scale;
+ return id;
+}
+
+void TextureMapperNode::removeContentsTile(int id)
+{
+ m_externallyManagedTiles.remove(id);
+}
+
+void TextureMapperNode::setTileBackBufferTextureForDirectlyCompositedImage(int id, const IntRect& sourceRect, const FloatRect& targetRect, BitmapTexture* texture)
+{
+ HashMap<int, ExternallyManagedTile>::iterator it = m_externallyManagedTiles.find(id);
+
+ if (it == m_externallyManagedTiles.end())
+ return;
+
+ ExternallyManagedTile& tile = it->second;
+
+ tile.backBuffer.sourceRect = sourceRect;
+ tile.backBuffer.targetRect = targetRect;
+ tile.backBuffer.texture = texture;
+ tile.isBackBufferUpdated = true;
+ tile.isDirectlyCompositedImage = true;
+}
+
+void TextureMapperNode::clearAllDirectlyCompositedImageTiles()
+{
+ for (HashMap<int, ExternallyManagedTile>::iterator it = m_externallyManagedTiles.begin(); it != m_externallyManagedTiles.end(); ++it) {
+ if (it->second.isDirectlyCompositedImage)
+ m_externallyManagedTiles.remove(it);
+ }
+}
+
+void TextureMapperNode::setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, void* bits, BitmapTexture::PixelFormat format)
+{
+ ASSERT(m_textureMapper);
+
+ HashMap<int, ExternallyManagedTile>::iterator it = m_externallyManagedTiles.find(id);
+ if (it == m_externallyManagedTiles.end())
+ return;
+
+ ExternallyManagedTile& tile = it->second;
+
+ tile.backBuffer.sourceRect = sourceRect;
+ tile.backBuffer.targetRect = FloatRect(targetRect);
+ tile.backBuffer.targetRect.scale(1.0 / tile.scale);
+
+ if (!tile.backBuffer.texture)
+ tile.backBuffer.texture = m_textureMapper->createTexture();
+ tile.backBuffer.texture->reset(sourceRect.size(), false);
+ tile.backBuffer.texture->updateContents(format, sourceRect, bits);
+ tile.isBackBufferUpdated = true;
+}
+
+void TextureMapperNode::swapContentsBuffers()
+{
+ HashMap<int, ExternallyManagedTile>::iterator end = m_externallyManagedTiles.end();
+ for (HashMap<int, ExternallyManagedTile>::iterator it = m_externallyManagedTiles.begin(); it != end; ++it) {
+ ExternallyManagedTile& tile = it->second;
+ if (!tile.isBackBufferUpdated)
+ continue;
+ tile.isBackBufferUpdated = false;
+ ExternallyManagedTileBuffer swapBuffer = tile.frontBuffer;
+ tile.frontBuffer = tile.backBuffer;
+ tile.backBuffer = swapBuffer;
+ }
+}
+#endif
+
void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphicsLayer, int options)
{
syncCompositingState(graphicsLayer, rootLayer()->m_textureMapper, options);
@@ -521,6 +680,7 @@
{
int changeMask = graphicsLayer->changeMask();
const TextureMapperNode::ContentData& pendingContent = graphicsLayer->pendingContent();
+ swapContentsBuffers();
if (changeMask == NoChanges && graphicsLayer->m_animations.isEmpty() && pendingContent.needsDisplayRect.isEmpty() && !pendingContent.needsDisplay)
return;
@@ -562,7 +722,7 @@
wantedSize = FloatSize(graphicsLayer->contentsRect().width(), graphicsLayer->contentsRect().height());
if (wantedSize != m_size)
- m_tiles.clear();
+ m_ownedTiles.clear();
m_size = wantedSize;
}
@@ -816,7 +976,7 @@
void TextureMapperNode::syncCompositingState(GraphicsLayerTextureMapper* graphicsLayer, TextureMapper* textureMapper, int options)
{
- if (graphicsLayer) {
+ if (graphicsLayer && !(options & ComputationsOnly)) {
syncCompositingStateSelf(graphicsLayer, textureMapper);
graphicsLayer->didSynchronize();
}
@@ -843,7 +1003,7 @@
renderContent(textureMapper, graphicsLayer);
if (!(options & TraverseDescendants))
- return;
+ options = ComputationsOnly;
if (graphicsLayer) {
Vector<GraphicsLayer*> children = graphicsLayer->children();
Modified: trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h (97162 => 97163)
--- trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h 2011-10-11 17:41:02 UTC (rev 97162)
+++ trunk/Source/WebCore/platform/graphics/texmap/TextureMapperNode.h 2011-10-11 17:43:00 UTC (rev 97163)
@@ -24,6 +24,7 @@
#include "GraphicsContext.h"
#include "GraphicsLayer.h"
#include "Image.h"
+#include "IntPointHash.h"
#include "TextureMapper.h"
#include "Timer.h"
#include "TransformOperations.h"
@@ -103,9 +104,17 @@
};
enum SyncOptions {
- TraverseDescendants = 1
+ TraverseDescendants = 1,
+ ComputationsOnly = 2
};
+ enum TileOwnership {
+ OwnedTiles,
+ ExternallyManagedTiles
+ };
+
+ typedef HashMap<TextureMapperNode*, FloatRect> NodeRectMap;
+
// The compositor lets us special-case images and colors, so we try to do so.
enum ContentType { HTMLContentType, DirectImageContentType, ColorContentType, MediaContentType, Canvas3DContentType};
struct ContentData {
@@ -132,7 +141,7 @@
void syncCompositingState(GraphicsLayerTextureMapper*, int syncOptions = 0);
void syncCompositingState(GraphicsLayerTextureMapper*, TextureMapper*, int syncOptions = 0);
- IntSize size() const { return IntSize(m_size.width() + .5, m_size.height() + .5); }
+ IntSize size() const { return IntSize(m_size.width(), m_size.height()); }
void setTransform(const TransformationMatrix&);
void setOpacity(float value) { m_opacity = value; }
void setTextureMapper(TextureMapper* texmap) { m_textureMapper = texmap; }
@@ -140,19 +149,30 @@
void paint();
- bool needsToComputeBoundingRect() const;
+#if ENABLE(TILED_BACKING_STORE)
+ void setTileOwnership(TileOwnership ownership) { m_state.tileOwnership = ownership; }
+ int createContentsTile(float scale);
+ void removeContentsTile(int id);
+ void setContentsTileBackBuffer(int id, const IntRect& sourceRect, const IntRect& targetRect, void* bits, BitmapTexture::PixelFormat);
+ void setTileBackBufferTextureForDirectlyCompositedImage(int id, const IntRect& sourceRect, const FloatRect& targetRect, BitmapTexture*);
+ void clearAllDirectlyCompositedImageTiles();
+ bool collectVisibleContentsRects(NodeRectMap&, const FloatRect&);
+#endif
+ void setID(int id) { m_id = id; }
+ int id() const { return m_id; }
const TextureMapperPlatformLayer* media() const { return m_currentContent.media; }
private:
TextureMapperNode* rootLayer();
void computeAllTransforms();
+ void computeVisibleRect(const FloatRect& rootVisibleRect);
void computePerspectiveTransformIfNeeded();
void computeReplicaTransformIfNeeded();
void computeOverlapsIfNeeded();
void computeLocalTransformIfNeeded();
- void computeBoundingRectFromRootIfNeeded();
void computeTiles();
+ void swapContentsBuffers();
int countDescendantsWithContent() const;
FloatRect targetRectForTileRect(const FloatRect& totalTargetRect, const FloatRect& tileRect) const;
void invalidateViewport(const FloatRect&);
@@ -162,7 +182,7 @@
static int compareGraphicsLayersZValue(const void* a, const void* b);
static void sortByZOrder(Vector<TextureMapperNode* >& array, int first, int last);
- BitmapTexture* texture() { return m_tiles.isEmpty() ? 0 : m_tiles[0].texture.get(); }
+ BitmapTexture* texture() { return m_ownedTiles.isEmpty() ? 0 : m_ownedTiles[0].texture.get(); }
void paintRecursive(TextureMapperPaintOptions);
bool paintReflection(const TextureMapperPaintOptions&, BitmapTexture* surface);
@@ -185,10 +205,7 @@
TransformationMatrix local;
TransformationMatrix base;
TransformationMatrix perspective;
- FloatRect targetBoundingRect;
float centerZ;
- FloatRect boundingRectFromRoot;
- FloatRect boundingRectFromRootForDescendants;
TransformData() { }
};
@@ -208,14 +225,39 @@
{
return m_currentContent.contentType == DirectImageContentType && m_currentContent.image ? m_currentContent.image->size() : m_size;
}
- struct Tile {
+ struct OwnedTile {
FloatRect rect;
RefPtr<BitmapTexture> texture;
bool needsReset;
};
- Vector<Tile> m_tiles;
+ Vector<OwnedTile> m_ownedTiles;
+#if ENABLE(TILED_BACKING_STORE)
+ struct ExternallyManagedTileBuffer {
+ FloatRect sourceRect;
+ FloatRect targetRect;
+ RefPtr<BitmapTexture> texture;
+ };
+
+ struct ExternallyManagedTile {
+ bool isBackBufferUpdated;
+ bool isDirectlyCompositedImage;
+ float scale;
+ ExternallyManagedTileBuffer frontBuffer;
+ ExternallyManagedTileBuffer backBuffer;
+
+ ExternallyManagedTile(float scale = 1.0)
+ : isBackBufferUpdated(false)
+ , isDirectlyCompositedImage(false)
+ , scale(scale)
+ {
+ }
+ };
+
+ HashMap<int, ExternallyManagedTile> m_externallyManagedTiles;
+#endif
+
ContentData m_currentContent;
Vector<TextureMapperNode*> m_children;
@@ -224,6 +266,7 @@
FloatSize m_size;
float m_opacity;
String m_name;
+ int m_id;
struct State {
FloatPoint pos;
@@ -245,10 +288,11 @@
bool needsReset: 1;
bool mightHaveOverlaps : 1;
bool needsRepaint;
- FloatRect visibleRect;
- FloatRect rootVisibleRect;
+ IntRect visibleRect;
float contentScale;
-
+#if ENABLE(TILED_BACKING_STORE)
+ TileOwnership tileOwnership;
+#endif
State()
: opacity(1.f)
, maskLayer(0)
@@ -261,7 +305,11 @@
, visible(true)
, needsReset(false)
, mightHaveOverlaps(false)
+ , needsRepaint(false)
, contentScale(1.0f)
+#if ENABLE(TILED_BACKING_STORE)
+ , tileOwnership(OwnedTiles)
+#endif
{
}
};