gecko-dev/gfx/layers/composite/ThebesLayerComposite.cpp
Ryan VanderMeulen d2b6c8631b Backed out 7 changesets (bug 883646) for reftest-ipc failures.
Backed out changeset 2272804a8e71 (bug 883646)
Backed out changeset e39d3bdf847a (bug 883646)
Backed out changeset bf46fc332efe (bug 883646)
Backed out changeset 6bb558c3136f (bug 883646)
Backed out changeset d7d5d16e27e0 (bug 883646)
Backed out changeset 14c73096a132 (bug 883646)
Backed out changeset 89f6185a271b (bug 883646)
2013-06-20 17:36:39 -04:00

292 lines
9.1 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ipc/AutoOpenSurface.h"
#include "mozilla/layers/PLayerTransaction.h"
#include "TiledLayerBuffer.h"
// This must occur *after* layers/PLayerTransaction.h to avoid
// typedefs conflicts.
#include "mozilla/Util.h"
#include "mozilla/layers/ShadowLayers.h"
#include "ThebesLayerBuffer.h"
#include "ThebesLayerComposite.h"
#include "mozilla/layers/ContentHost.h"
#include "gfxUtils.h"
#include "gfx2DGlue.h"
#include "mozilla/layers/CompositorTypes.h" // for TextureInfo
#include "mozilla/layers/Effects.h"
namespace mozilla {
namespace layers {
ThebesLayerComposite::ThebesLayerComposite(LayerManagerComposite *aManager)
: ThebesLayer(aManager, nullptr)
, LayerComposite(aManager)
, mBuffer(nullptr)
{
MOZ_COUNT_CTOR(ThebesLayerComposite);
mImplData = static_cast<LayerComposite*>(this);
}
ThebesLayerComposite::~ThebesLayerComposite()
{
MOZ_COUNT_DTOR(ThebesLayerComposite);
if (mBuffer) {
mBuffer->Detach();
}
}
void
ThebesLayerComposite::SetCompositableHost(CompositableHost* aHost)
{
mBuffer= static_cast<ContentHost*>(aHost);
}
void
ThebesLayerComposite::Disconnect()
{
Destroy();
}
void
ThebesLayerComposite::Destroy()
{
if (!mDestroyed) {
if (mBuffer) {
mBuffer->Detach();
}
mBuffer = nullptr;
mDestroyed = true;
}
}
Layer*
ThebesLayerComposite::GetLayer()
{
return this;
}
TiledLayerComposer*
ThebesLayerComposite::GetTiledLayerComposer()
{
return mBuffer->AsTiledLayerComposer();
}
LayerRenderState
ThebesLayerComposite::GetRenderState()
{
if (!mBuffer || mDestroyed) {
return LayerRenderState();
}
return mBuffer->GetRenderState();
}
void
ThebesLayerComposite::RenderLayer(const nsIntPoint& aOffset,
const nsIntRect& aClipRect)
{
if (!mBuffer) {
return;
}
gfx::Matrix4x4 transform;
ToMatrix4x4(GetEffectiveTransform(), transform);
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
nsRefPtr<gfxImageSurface> surf = mBuffer->GetAsSurface();
WriteSnapshotToDumpFile(this, surf);
}
#endif
EffectChain effectChain;
LayerManagerComposite::AddMaskEffect(mMaskLayer, effectChain);
nsIntRegion visibleRegion = GetEffectiveVisibleRegion();
TiledLayerProperties tiledLayerProps;
if (mRequiresTiledProperties) {
// calculating these things can be a little expensive, so don't
// do them if we don't have to
tiledLayerProps.mVisibleRegion = visibleRegion;
tiledLayerProps.mDisplayPort = GetDisplayPort();
tiledLayerProps.mEffectiveResolution = GetEffectiveResolution();
tiledLayerProps.mCompositionBounds = GetCompositionBounds();
tiledLayerProps.mRetainTiles = !mIsFixedPosition;
tiledLayerProps.mValidRegion = mValidRegion;
}
mBuffer->SetPaintWillResample(MayResample());
mBuffer->Composite(effectChain,
GetEffectiveOpacity(),
transform,
gfx::Point(aOffset.x, aOffset.y),
gfx::FILTER_LINEAR,
clipRect,
&visibleRegion,
mRequiresTiledProperties ? &tiledLayerProps
: nullptr);
if (mRequiresTiledProperties) {
mValidRegion = tiledLayerProps.mValidRegion;
}
mCompositeManager->GetCompositor()->MakeCurrent();
}
CompositableHost*
ThebesLayerComposite::GetCompositableHost() {
return mBuffer.get();
}
void
ThebesLayerComposite::CleanupResources()
{
mBuffer = nullptr;
}
gfxSize
ThebesLayerComposite::GetEffectiveResolution()
{
// Work out render resolution by multiplying the resolution of our ancestors.
// Only container layers can have frame metrics, so we start off with a
// resolution of 1, 1.
// XXX For large layer trees, it would be faster to do this once from the
// root node upwards and store the value on each layer.
gfxSize resolution(1, 1);
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
const FrameMetrics& metrics = parent->GetFrameMetrics();
resolution.width *= metrics.mResolution.width;
resolution.height *= metrics.mResolution.height;
}
return resolution;
}
gfxRect
ThebesLayerComposite::GetDisplayPort()
{
// We use GetTransform instead of GetEffectiveTransform in this function
// as we want the transform of the shadowable layers and not that of the
// shadow layers, which may have been modified due to async scrolling/
// zooming.
gfx3DMatrix transform = GetTransform();
// Find out the area of the nearest display-port to invalidate retained
// tiles.
gfxRect displayPort;
gfxSize parentResolution = GetEffectiveResolution();
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
const FrameMetrics& metrics = parent->GetFrameMetrics();
if (displayPort.IsEmpty()) {
if (!metrics.mDisplayPort.IsEmpty()) {
// We use the bounds to cut down on complication/computation time.
// This will be incorrect when the transform involves rotation, but
// it'd be quite hard to retain invalid tiles correctly in this
// situation anyway.
displayPort = gfxRect(metrics.mDisplayPort.x,
metrics.mDisplayPort.y,
metrics.mDisplayPort.width,
metrics.mDisplayPort.height);
displayPort.ScaleRoundOut(parentResolution.width, parentResolution.height);
}
parentResolution.width /= metrics.mResolution.width;
parentResolution.height /= metrics.mResolution.height;
}
if (parent->UseIntermediateSurface()) {
transform.PreMultiply(parent->GetTransform());
}
}
// If no display port was found, use the widget size from the layer manager.
if (displayPort.IsEmpty()) {
LayerManagerComposite* manager = static_cast<LayerManagerComposite*>(Manager());
const nsIntSize& widgetSize = manager->GetWidgetSize();
displayPort.width = widgetSize.width;
displayPort.height = widgetSize.height;
}
// Transform the display port into layer space.
displayPort = transform.Inverse().TransformBounds(displayPort);
return displayPort;
}
gfxRect
ThebesLayerComposite::GetCompositionBounds()
{
// Walk up the tree, looking for a display-port - if we find one, we know
// that this layer represents a content node and we can use its first
// scrollable child, in conjunction with its content area and viewport offset
// to establish the screen coordinates to which the content area will be
// rendered.
gfxRect compositionBounds;
ContainerLayer* scrollableLayer = nullptr;
for (ContainerLayer* parent = GetParent(); parent; parent = parent->GetParent()) {
const FrameMetrics& parentMetrics = parent->GetFrameMetrics();
if (parentMetrics.IsScrollable())
scrollableLayer = parent;
if (!parentMetrics.mDisplayPort.IsEmpty() && scrollableLayer) {
// Get the composition bounds, so as not to waste rendering time.
compositionBounds = gfxRect(parentMetrics.mCompositionBounds.x,
parentMetrics.mCompositionBounds.y,
parentMetrics.mCompositionBounds.width,
parentMetrics.mCompositionBounds.height);
// Calculate the scale transform applied to the root layer to determine
// the content resolution.
Layer* rootLayer = Manager()->GetRoot();
const gfx3DMatrix& rootTransform = rootLayer->GetTransform();
LayerToCSSScale scale(rootTransform.GetXScale(),
rootTransform.GetYScale());
// Get the content document bounds, in screen-space.
const FrameMetrics& metrics = scrollableLayer->GetFrameMetrics();
const LayerIntRect content = RoundedToInt(metrics.mScrollableRect / scale);
gfx::Point scrollOffset =
gfx::Point((metrics.mScrollOffset.x * metrics.LayersPixelsPerCSSPixel().width) / scale.scale,
(metrics.mScrollOffset.y * metrics.LayersPixelsPerCSSPixel().height) / scale.scale);
const nsIntPoint contentOrigin(
content.x - NS_lround(scrollOffset.x),
content.y - NS_lround(scrollOffset.y));
gfxRect contentRect = gfxRect(contentOrigin.x, contentOrigin.y,
content.width, content.height);
gfxRect contentBounds = scrollableLayer->GetEffectiveTransform().
TransformBounds(contentRect);
// Clip the composition bounds to the content bounds
compositionBounds.IntersectRect(compositionBounds, contentBounds);
break;
}
}
return compositionBounds;
}
#ifdef MOZ_LAYERS_HAVE_LOG
nsACString&
ThebesLayerComposite::PrintInfo(nsACString& aTo, const char* aPrefix)
{
ThebesLayer::PrintInfo(aTo, aPrefix);
aTo += "\n";
if (mBuffer) {
nsAutoCString pfx(aPrefix);
pfx += " ";
mBuffer->PrintInfo(aTo, pfx.get());
}
return aTo;
}
#endif
} /* layers */
} /* mozilla */