CCLayerTreeHostCommon.cpp [plain text]
#include "config.h"
#include "cc/CCLayerTreeHostCommon.h"
#include "FloatQuad.h"
#include "IntRect.h"
#include "LayerChromium.h"
#include "RenderSurfaceChromium.h"
#include "TransformationMatrix.h"
#include "cc/CCActiveAnimation.h"
#include "cc/CCLayerAnimationController.h"
#include "cc/CCLayerImpl.h"
#include "cc/CCLayerIterator.h"
#include "cc/CCLayerSorter.h"
#include "cc/CCMathUtil.h"
#include "cc/CCRenderSurface.h"
namespace WebCore {
IntRect CCLayerTreeHostCommon::calculateVisibleRect(const IntRect& targetSurfaceRect, const IntRect& layerBoundRect, const TransformationMatrix& transform)
{
IntRect layerInSurfaceSpace = CCMathUtil::mapClippedRect(transform, layerBoundRect);
if (targetSurfaceRect.contains(layerInSurfaceSpace))
return layerBoundRect;
IntRect minimalSurfaceRect = targetSurfaceRect;
minimalSurfaceRect.intersect(layerInSurfaceSpace);
const TransformationMatrix surfaceToLayer = transform.inverse();
IntRect layerRect = enclosingIntRect(CCMathUtil::projectClippedRect(surfaceToLayer, FloatRect(minimalSurfaceRect)));
layerRect.intersect(layerBoundRect);
return layerRect;
}
template<typename LayerType>
static IntRect calculateVisibleLayerRect(LayerType* layer)
{
ASSERT(layer->targetRenderSurface());
if (!layer->doubleSided() && layer->screenSpaceTransform().isBackFaceVisible())
return IntRect();
IntRect targetSurfaceRect = layer->targetRenderSurface()->contentRect();
if (layer->usesLayerClipping())
targetSurfaceRect.intersect(layer->clipRect());
if (targetSurfaceRect.isEmpty() || layer->contentBounds().isEmpty())
return targetSurfaceRect;
const IntSize& bounds = layer->bounds();
const IntSize& contentBounds = layer->contentBounds();
const IntRect layerBoundRect = IntRect(IntPoint(), contentBounds);
TransformationMatrix transform = layer->drawTransform();
transform.scaleNonUniform(bounds.width() / static_cast<double>(contentBounds.width()),
bounds.height() / static_cast<double>(contentBounds.height()));
transform.translate(-contentBounds.width() / 2.0, -contentBounds.height() / 2.0);
IntRect visibleLayerRect = CCLayerTreeHostCommon::calculateVisibleRect(targetSurfaceRect, layerBoundRect, transform);
return visibleLayerRect;
}
static bool isScaleOrTranslation(const TransformationMatrix& m)
{
return !m.m12() && !m.m13() && !m.m14()
&& !m.m21() && !m.m23() && !m.m24()
&& !m.m31() && !m.m32() && !m.m43()
&& m.m44();
}
static inline bool layerOpacityIsOpaque(CCLayerImpl* layer)
{
return layer->opacity() == 1;
}
static inline bool layerOpacityIsOpaque(LayerChromium* layer)
{
return layer->opacity() == 1 && !layer->opacityIsAnimating();
}
static inline bool transformToParentIsKnown(CCLayerImpl*)
{
return true;
}
static inline bool transformToParentIsKnown(LayerChromium* layer)
{
return !layer->transformIsAnimating();
}
static inline bool transformToScreenIsKnown(CCLayerImpl*)
{
return true;
}
static inline bool transformToScreenIsKnown(LayerChromium* layer)
{
return !layer->screenSpaceTransformIsAnimating();
}
template<typename LayerType>
static bool layerShouldBeSkipped(LayerType* layer)
{
if (!layer->drawsContent() || layer->bounds().isEmpty())
return true;
if (!layer->doubleSided() && transformToScreenIsKnown(layer) && layer->screenSpaceTransform().isBackFaceVisible())
return true;
return false;
}
static inline bool subtreeShouldBeSkipped(CCLayerImpl* layer)
{
return !layer->opacity();
}
static inline bool subtreeShouldBeSkipped(LayerChromium* layer)
{
return !layer->opacity() && !layer->opacityIsAnimating();
}
template<typename LayerType>
static bool subtreeShouldRenderToSeparateSurface(LayerType* layer, bool axisAlignedWithRespectToParent)
{
bool descendantDrawsContent = layer->descendantDrawsContent();
if (layer->maskLayer())
return true;
if (layer->replicaLayer())
return true;
if (!layer->filters().isEmpty() || !layer->backgroundFilters().isEmpty())
return true;
if (layer->parent() && layer->parent()->preserves3D() && !layer->preserves3D() && descendantDrawsContent)
return true;
if (!transformToParentIsKnown(layer) && descendantDrawsContent)
return true;
if (layer->masksToBounds() && !axisAlignedWithRespectToParent && descendantDrawsContent)
return true;
if (!layerOpacityIsOpaque(layer) && !layer->preserves3D() && descendantDrawsContent)
return true;
return false;
}
template<typename LayerType, typename LayerList, typename RenderSurfaceType, typename LayerSorter>
static bool calculateDrawTransformsAndVisibilityInternal(LayerType* layer, LayerType* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, RenderSurfaceType* nearestAncestorThatMovesPixels, LayerList& renderSurfaceLayerList, LayerList& layerList, LayerSorter* layerSorter, int maxTextureSize)
{
if (subtreeShouldBeSkipped(layer))
return false;
float drawOpacity = layer->opacity();
bool drawOpacityIsAnimating = layer->opacityIsAnimating();
if (layer->parent() && layer->parent()->preserves3D()) {
drawOpacity *= layer->parent()->drawOpacity();
drawOpacityIsAnimating |= layer->parent()->drawOpacityIsAnimating();
}
IntSize bounds = layer->bounds();
FloatPoint anchorPoint = layer->anchorPoint();
FloatPoint position = layer->position() - layer->scrollDelta();
float centerOffsetX = (0.5 - anchorPoint.x()) * bounds.width();
float centerOffsetY = (0.5 - anchorPoint.y()) * bounds.height();
TransformationMatrix layerLocalTransform;
layerLocalTransform.scale(layer->pageScaleDelta());
layerLocalTransform.translate3d(position.x(), position.y(), layer->anchorPointZ());
layerLocalTransform.multiply(layer->transform());
layerLocalTransform.translate3d(centerOffsetX, centerOffsetY, -layer->anchorPointZ());
TransformationMatrix combinedTransform = parentMatrix;
combinedTransform = combinedTransform.multiply(layerLocalTransform);
bool animatingTransformToTarget = layer->transformIsAnimating();
bool animatingTransformToScreen = animatingTransformToTarget;
if (layer->parent()) {
animatingTransformToTarget |= layer->parent()->drawTransformIsAnimating();
animatingTransformToScreen |= layer->parent()->screenSpaceTransformIsAnimating();
}
FloatRect layerRect(-0.5 * layer->bounds().width(), -0.5 * layer->bounds().height(), layer->bounds().width(), layer->bounds().height());
IntRect transformedLayerRect;
TransformationMatrix nextHierarchyMatrix = fullHierarchyMatrix;
layer->setUsesLayerClipping(false);
if (subtreeShouldRenderToSeparateSurface(layer, isScaleOrTranslation(combinedTransform))) {
if (!layer->renderSurface())
layer->createRenderSurface();
RenderSurfaceType* renderSurface = layer->renderSurface();
renderSurface->clearLayerList();
TransformationMatrix drawTransform;
drawTransform.translate3d(0.5 * bounds.width(), 0.5 * bounds.height(), 0);
layer->setDrawTransform(drawTransform);
transformedLayerRect = IntRect(0, 0, bounds.width(), bounds.height());
renderSurface->setDrawOpacity(drawOpacity);
renderSurface->setDrawOpacityIsAnimating(drawOpacityIsAnimating);
layer->setDrawOpacity(1);
layer->setDrawOpacityIsAnimating(false);
TransformationMatrix surfaceOriginTransform = combinedTransform;
surfaceOriginTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
renderSurface->setOriginTransform(surfaceOriginTransform);
renderSurface->setTargetSurfaceTransformsAreAnimating(animatingTransformToTarget);
renderSurface->setScreenSpaceTransformsAreAnimating(animatingTransformToScreen);
animatingTransformToTarget = false;
layer->setDrawTransformIsAnimating(animatingTransformToTarget);
layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen);
nextHierarchyMatrix.multiply(surfaceOriginTransform);
renderSurface->setClipRect(layer->parent() ? layer->parent()->clipRect() : layer->clipRect());
layer->setUsesLayerClipping(false);
layer->setClipRect(IntRect());
if (layer->maskLayer()) {
renderSurface->setMaskLayer(layer->maskLayer());
layer->maskLayer()->setTargetRenderSurface(renderSurface);
} else
renderSurface->setMaskLayer(0);
if (layer->replicaLayer() && layer->replicaLayer()->maskLayer())
layer->replicaLayer()->maskLayer()->setTargetRenderSurface(renderSurface);
renderSurface->setFilters(layer->filters());
if (renderSurface->filters().hasFilterThatMovesPixels())
nearestAncestorThatMovesPixels = renderSurface;
renderSurface->setNearestAncestorThatMovesPixels(nearestAncestorThatMovesPixels);
renderSurface->setBackgroundFilters(layer->backgroundFilters());
renderSurfaceLayerList.append(layer);
} else {
layer->setDrawTransform(combinedTransform);
layer->setDrawTransformIsAnimating(animatingTransformToTarget);
layer->setScreenSpaceTransformIsAnimating(animatingTransformToScreen);
transformedLayerRect = enclosingIntRect(CCMathUtil::mapClippedRect(layer->drawTransform(), layerRect));
layer->setDrawOpacity(drawOpacity);
layer->setDrawOpacityIsAnimating(drawOpacityIsAnimating);
if (layer != rootLayer) {
ASSERT(layer->parent());
layer->clearRenderSurface();
layer->setClipRect(layer->parent()->clipRect());
if (layer->parent()->usesLayerClipping())
layer->setUsesLayerClipping(true);
layer->setTargetRenderSurface(layer->parent()->targetRenderSurface());
}
}
if (layer->masksToBounds()) {
IntRect clipRect = transformedLayerRect;
if (layer->usesLayerClipping())
clipRect.intersect(layer->clipRect());
layer->setClipRect(clipRect);
layer->setUsesLayerClipping(true);
}
TransformationMatrix layerScreenSpaceTransform = nextHierarchyMatrix;
layerScreenSpaceTransform.multiply(layer->drawTransform());
layerScreenSpaceTransform.translate3d(-0.5 * bounds.width(), -0.5 * bounds.height(), 0);
layer->setScreenSpaceTransform(layerScreenSpaceTransform);
if (layer->drawsContent()) {
IntRect drawableContentRect = transformedLayerRect;
if (layer->usesLayerClipping())
drawableContentRect.intersect(layer->clipRect());
layer->setDrawableContentRect(drawableContentRect);
} else
layer->setDrawableContentRect(IntRect());
TransformationMatrix sublayerMatrix = layer->drawTransform();
if (!layer->preserves3D()) {
sublayerMatrix.setM13(0);
sublayerMatrix.setM23(0);
sublayerMatrix.setM31(0);
sublayerMatrix.setM32(0);
sublayerMatrix.setM33(1);
sublayerMatrix.setM34(0);
sublayerMatrix.setM43(0);
}
sublayerMatrix.multiply(layer->sublayerTransform());
sublayerMatrix.translate3d(-bounds.width() * 0.5, -bounds.height() * 0.5, 0);
LayerList& descendants = (layer->renderSurface() ? layer->renderSurface()->layerList() : layerList);
unsigned sortingStartIndex = descendants.size();
if (!layerShouldBeSkipped(layer))
descendants.append(layer);
for (size_t i = 0; i < layer->children().size(); ++i) {
LayerType* child = layer->children()[i].get();
bool drawsContent = calculateDrawTransformsAndVisibilityInternal<LayerType, LayerList, RenderSurfaceType, LayerSorter>(child, rootLayer, sublayerMatrix, nextHierarchyMatrix, nearestAncestorThatMovesPixels, renderSurfaceLayerList, descendants, layerSorter, maxTextureSize);
if (drawsContent) {
if (child->renderSurface()) {
RenderSurfaceType* childRenderSurface = child->renderSurface();
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.unite(enclosingIntRect(childRenderSurface->drawableContentRect()));
layer->setDrawableContentRect(drawableContentRect);
descendants.append(child);
} else {
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.unite(child->drawableContentRect());
layer->setDrawableContentRect(drawableContentRect);
}
}
}
if (layer->masksToBounds() || layer->maskLayer()) {
IntRect drawableContentRect = layer->drawableContentRect();
drawableContentRect.intersect(transformedLayerRect);
layer->setDrawableContentRect(drawableContentRect);
}
if (layer->renderSurface() && layer != rootLayer) {
RenderSurfaceType* renderSurface = layer->renderSurface();
IntRect clippedContentRect = layer->drawableContentRect();
FloatPoint surfaceCenter = FloatRect(clippedContentRect).center();
FloatSize centerOffsetDueToClipping;
if (!layer->replicaLayer()) {
if (!renderSurface->clipRect().isEmpty() && !clippedContentRect.isEmpty()) {
IntRect surfaceClipRect = CCLayerTreeHostCommon::calculateVisibleRect(renderSurface->clipRect(), clippedContentRect, renderSurface->originTransform());
clippedContentRect.intersect(surfaceClipRect);
}
FloatPoint clippedSurfaceCenter = FloatRect(clippedContentRect).center();
centerOffsetDueToClipping = clippedSurfaceCenter - surfaceCenter;
}
clippedContentRect.setWidth(std::min(clippedContentRect.width(), maxTextureSize));
clippedContentRect.setHeight(std::min(clippedContentRect.height(), maxTextureSize));
if (clippedContentRect.isEmpty())
renderSurface->clearLayerList();
renderSurface->setContentRect(clippedContentRect);
layer->setClipRect(layer->drawableContentRect());
TransformationMatrix drawTransform = renderSurface->originTransform();
drawTransform.translate3d(surfaceCenter.x() + centerOffsetDueToClipping.width(), surfaceCenter.y() + centerOffsetDueToClipping.height(), 0);
renderSurface->setDrawTransform(drawTransform);
renderSurface->setScreenSpaceTransform(layer->screenSpaceTransform());
if (layer->replicaLayer()) {
TransformationMatrix replicaDrawTransform = renderSurface->originTransform();
replicaDrawTransform.translate(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y());
replicaDrawTransform.multiply(layer->replicaLayer()->transform());
replicaDrawTransform.translate(surfaceCenter.x() - anchorPoint.x() * bounds.width(), surfaceCenter.y() - anchorPoint.y() * bounds.height());
renderSurface->setReplicaDrawTransform(replicaDrawTransform);
TransformationMatrix surfaceOriginToReplicaOriginTransform;
surfaceOriginToReplicaOriginTransform.translate(layer->replicaLayer()->position().x(), layer->replicaLayer()->position().y());
surfaceOriginToReplicaOriginTransform.multiply(layer->replicaLayer()->transform());
surfaceOriginToReplicaOriginTransform.translate(-anchorPoint.x() * bounds.width(), -anchorPoint.y() * bounds.height());
TransformationMatrix replicaOriginTransform = layer->renderSurface()->originTransform() * surfaceOriginToReplicaOriginTransform;
renderSurface->setReplicaOriginTransform(replicaOriginTransform);
TransformationMatrix replicaScreenSpaceTransform = layer->renderSurface()->screenSpaceTransform() * surfaceOriginToReplicaOriginTransform;
renderSurface->setReplicaScreenSpaceTransform(replicaScreenSpaceTransform);
}
if (!layer->renderSurface()->layerList().size()) {
while (renderSurfaceLayerList.last() != layer) {
renderSurfaceLayerList.last()->clearRenderSurface();
renderSurfaceLayerList.removeLast();
}
ASSERT(renderSurfaceLayerList.last() == layer);
renderSurfaceLayerList.removeLast();
layer->clearRenderSurface();
return false;
}
}
if (sortingStartIndex == descendants.size())
return false;
if (descendants.size() && layer->preserves3D() && (!layer->parent() || !layer->parent()->preserves3D()))
sortLayers(&descendants.at(sortingStartIndex), descendants.end(), layerSorter);
return true;
}
template<typename LayerType, typename LayerList, typename RenderSurfaceType>
static void walkLayersAndCalculateVisibleLayerRects(const LayerList& renderSurfaceLayerList)
{
typedef CCLayerIterator<LayerType, LayerList, RenderSurfaceType, CCLayerIteratorActions::BackToFront> CCLayerIteratorType;
CCLayerIteratorType end = CCLayerIteratorType::end(&renderSurfaceLayerList);
for (CCLayerIteratorType it = CCLayerIteratorType::begin(&renderSurfaceLayerList); it != end; ++it) {
if (!it.representsTargetRenderSurface()) {
IntRect visibleLayerRect = calculateVisibleLayerRect(*it);
it->setVisibleLayerRect(visibleLayerRect);
}
}
}
void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(LayerChromium* layer, LayerChromium* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<RefPtr<LayerChromium> >& renderSurfaceLayerList, Vector<RefPtr<LayerChromium> >& layerList, int maxTextureSize)
{
WebCore::calculateDrawTransformsAndVisibilityInternal<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium, void>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, 0, maxTextureSize);
walkLayersAndCalculateVisibleLayerRects<LayerChromium, Vector<RefPtr<LayerChromium> >, RenderSurfaceChromium>(renderSurfaceLayerList);
}
void CCLayerTreeHostCommon::calculateDrawTransformsAndVisibility(CCLayerImpl* layer, CCLayerImpl* rootLayer, const TransformationMatrix& parentMatrix, const TransformationMatrix& fullHierarchyMatrix, Vector<CCLayerImpl*>& renderSurfaceLayerList, Vector<CCLayerImpl*>& layerList, CCLayerSorter* layerSorter, int maxTextureSize)
{
calculateDrawTransformsAndVisibilityInternal<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface, CCLayerSorter>(layer, rootLayer, parentMatrix, fullHierarchyMatrix, 0, renderSurfaceLayerList, layerList, layerSorter, maxTextureSize);
walkLayersAndCalculateVisibleLayerRects<CCLayerImpl, Vector<CCLayerImpl*>, CCRenderSurface>(renderSurfaceLayerList);
}
}