Bug 788044 - Make inactive layer subtrees relative to the ContainerLayer, not the reference frame. r=roc

This commit is contained in:
Matt Woodrow 2012-09-17 10:25:33 +12:00
parent b5fbe43bed
commit ad9a9edc59
13 changed files with 100 additions and 40 deletions

View File

@ -964,6 +964,8 @@ Layer::PrintInfo(nsACString& aTo, const char* aPrefix)
}
if (!mVisibleRegion.IsEmpty()) {
AppendToString(aTo, mVisibleRegion, " [visible=", "]");
} else {
aTo += " [not visible]";
}
if (1.0 != mOpacity) {
aTo.AppendPrintf(" [opacity=%g]", mOpacity);

View File

@ -496,6 +496,7 @@ public:
mMaskClipCount(0),
mForcedBackgroundColor(NS_RGBA(0,0,0,0)),
mXScale(1.f), mYScale(1.f),
mTranslation(0, 0),
mActiveScrolledRootPosition(0, 0) {}
/**
@ -516,6 +517,14 @@ public:
*/
float mXScale, mYScale;
/**
* The offset from the ThebesLayer's 0,0 to the
* reference frame. This isn't necessarily the same as the transform
* set on the ThebesLayer since we might also be applying an extra
* offset specified by the parent ContainerLayer/
*/
nsIntPoint mTranslation;
/**
* We try to make 0,0 of the ThebesLayer be the top-left of the
* border-box of the "active scrolled root" frame (i.e. the nearest ancestor
@ -1078,13 +1087,12 @@ ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer)
static nsIntPoint
GetTranslationForThebesLayer(ThebesLayer* aLayer)
{
gfxMatrix transform;
if (!aLayer->GetTransform().Is2D(&transform) ||
transform.HasNonIntegerTranslation()) {
NS_ERROR("ThebesLayers should have integer translations only");
return nsIntPoint(0, 0);
}
return nsIntPoint(int32_t(transform.x0), int32_t(transform.y0));
ThebesDisplayItemLayerUserData* data =
static_cast<ThebesDisplayItemLayerUserData*>
(aLayer->GetUserData(&gThebesDisplayItemLayerUserData));
NS_ASSERTION(data, "Must be a tracked thebes layer!");
return data->mTranslation;
}
static const double SUBPIXEL_OFFSET_EPSILON = 0.02;
@ -1187,6 +1195,8 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot,
// is close to data->mActiveScrolledRootPosition if possible.
nsIntPoint pixOffset(RoundToMatchResidual(scaledOffset.x, data->mActiveScrolledRootPosition.x),
RoundToMatchResidual(scaledOffset.y, data->mActiveScrolledRootPosition.y));
data->mTranslation = pixOffset;
pixOffset += mParameters.mOffset;
gfxMatrix matrix;
matrix.Translate(gfxPoint(pixOffset.x, pixOffset.y));
layer->SetBaseTransform(gfx3DMatrix::From2D(matrix));
@ -1340,7 +1350,7 @@ ContainerState::PopThebesLayerData()
if (imageContainer) {
nsRefPtr<ImageLayer> imageLayer = CreateOrRecycleImageLayer(data->mLayer);
imageLayer->SetContainer(imageContainer);
data->mImage->ConfigureLayer(imageLayer);
data->mImage->ConfigureLayer(imageLayer, mParameters.mOffset);
imageLayer->SetPostScale(mParameters.mXScale,
mParameters.mYScale);
if (data->mItemClip.mHaveClipRect) {
@ -1364,6 +1374,7 @@ ContainerState::PopThebesLayerData()
// a rectangle, it must therefore contain the visible region's GetBounds.
// Note that the visible region is already clipped appropriately.
nsIntRect visibleRect = data->mVisibleRegion.GetBounds();
visibleRect.MoveBy(mParameters.mOffset);
colorLayer->SetClipRect(&visibleRect);
layer = colorLayer;
@ -1395,7 +1406,7 @@ ContainerState::PopThebesLayerData()
// Convert from relative to the container to relative to the
// ThebesLayer itself.
nsIntRegion rgn = data->mVisibleRegion;
rgn.MoveBy(-nsIntPoint(int32_t(transform.x0), int32_t(transform.y0)));
rgn.MoveBy(-GetTranslationForThebesLayer(data->mLayer));
layer->SetVisibleRegion(rgn);
}
@ -1874,8 +1885,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
"If we have rounded rects, we must have a clip rect");
// It has its own layer. Update that layer's clip and visible rects.
if (aClip.mHaveClipRect) {
ownLayer->IntersectClipRect(
ScaleToNearestPixels(aClip.NonRoundedIntersection()));
nsIntRect clip = ScaleToNearestPixels(aClip.NonRoundedIntersection());
clip.MoveBy(mParameters.mOffset);
ownLayer->IntersectClipRect(clip);
}
ThebesLayerData* data = GetTopThebesLayerData();
if (data) {
@ -1888,6 +1900,7 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
data->mDrawAboveRegion.Or(data->mDrawAboveRegion, itemDrawRect);
data->mDrawAboveRegion.SimplifyOutward(4);
}
itemVisibleRect.MoveBy(mParameters.mOffset);
RestrictVisibleRegionForLayer(ownLayer, itemVisibleRect);
// rounded rectangle clipping using mask layers
@ -2156,17 +2169,32 @@ ContainerState::Finish(uint32_t* aTextContentFlags)
static FrameLayerBuilder::ContainerParameters
ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
nsDisplayListBuilder* aDisplayListBuilder,
nsIFrame* aContainerFrame,
const gfx3DMatrix* aTransform,
const FrameLayerBuilder::ContainerParameters& aIncomingScale,
ContainerLayer* aLayer)
ContainerLayer* aLayer,
LayerState aState)
{
nsIntPoint offset;
gfx3DMatrix transform =
gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
if (aTransform) {
// aTransform is applied first, then the scale is applied to the result
transform = (*aTransform)*transform;
}
if (aContainerFrame && aState == LAYER_INACTIVE) {
// When we have an inactive ContainerLayer, translate the container by the offset to the
// reference frame (and offset all child layers by the reverse) so that the coordinate
// space of the child layers isn't affected by scrolling.
nsPoint appUnitOffset = aDisplayListBuilder->ToReferenceFrame(aContainerFrame);
nscoord appUnitsPerDevPixel = aContainerFrame->PresContext()->AppUnitsPerDevPixel();
offset = nsIntPoint(
int32_t(NSAppUnitsToDoublePixels(appUnitOffset.x, appUnitsPerDevPixel)*aIncomingScale.mXScale),
int32_t(NSAppUnitsToDoublePixels(appUnitOffset.y, appUnitsPerDevPixel)*aIncomingScale.mYScale));
}
transform = transform * gfx3DMatrix::Translation(offset.x + aIncomingScale.mOffset.x, offset.y + aIncomingScale.mOffset.y, 0);
gfxMatrix transform2d;
bool canDraw2D = transform.CanDraw2D(&transform2d);
@ -2219,7 +2247,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
1.0f/float(scale.height));
FrameLayerBuilder::ContainerParameters
result(scale.width, scale.height, aIncomingScale);
result(scale.width, scale.height, -offset, aIncomingScale);
if (aTransform) {
result.mInTransformedSubtree = true;
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
@ -2407,8 +2435,9 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
containerLayer->SetUserData(&gLayerOwnerUserData,
new LayerOwnerUserData(aContainerFrame));
if (aContainerItem &&
aContainerItem->GetLayerState(aBuilder, aManager, aParameters) == LAYER_ACTIVE_EMPTY) {
LayerState state = aContainerItem ? aContainerItem->GetLayerState(aBuilder, aManager, aParameters) : LAYER_ACTIVE;
if (aContainerItem && state == LAYER_ACTIVE_EMPTY) {
// Empty layers only have metadata and should never have display items. We
// early exit because later, invalidation will walk up the frame tree to
// determine which thebes layer gets invalidated. Since an empty layer
@ -2418,8 +2447,8 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
}
ContainerParameters scaleParameters =
ChooseScaleAndSetTransform(this, aContainerFrame, aTransform, aParameters,
containerLayer);
ChooseScaleAndSetTransform(this, aBuilder, aContainerFrame, aTransform, aParameters,
containerLayer, state);
uint32_t oldGeneration = mContainerLayerGeneration;
mContainerLayerGeneration = ++mMaxContainerLayerGeneration;
@ -2531,6 +2560,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
}
NS_ASSERTION(bounds.IsEqualInterior(aChildren.GetBounds(aBuilder)), "Wrong bounds");
pixBounds.MoveBy(nsIntPoint(scaleParameters.mOffset.x, scaleParameters.mOffset.y));
containerLayer->SetVisibleRegion(pixBounds);
// Make sure that rounding the visible region out didn't add any area
// we won't paint
@ -3349,7 +3379,10 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
}
maskLayer->SetContainer(container);
maskLayer->SetBaseTransform(gfx3DMatrix::From2D(maskTransform.Invert()));
gfx3DMatrix matrix = gfx3DMatrix::From2D(maskTransform.Invert());
matrix.Translate(gfxPoint3D(mParameters.mOffset.x, mParameters.mOffset.y, 0));
maskLayer->SetBaseTransform(matrix);
// save the details of the clip in user data
userData->mScaleX = newData.mScaleX;

View File

@ -145,13 +145,21 @@ public:
mDisableSubpixelAntialiasingInDescendants(false)
{}
ContainerParameters(float aXScale, float aYScale,
const nsIntPoint& aOffset,
const ContainerParameters& aParent) :
mXScale(aXScale), mYScale(aYScale),
mOffset(aOffset),
mInTransformedSubtree(aParent.mInTransformedSubtree),
mInActiveTransformedSubtree(aParent.mInActiveTransformedSubtree),
mDisableSubpixelAntialiasingInDescendants(aParent.mDisableSubpixelAntialiasingInDescendants)
{}
float mXScale, mYScale;
/**
* An offset to append to the transform set on all child layers created.
*/
nsIntPoint mOffset;
bool mInTransformedSubtree;
bool mInActiveTransformedSubtree;
bool mDisableSubpixelAntialiasingInDescendants;

View File

@ -72,7 +72,7 @@ public:
const ContainerParameters& aContainerParameters)
{
return static_cast<nsHTMLCanvasFrame*>(mFrame)->
BuildLayer(aBuilder, aManager, this);
BuildLayer(aBuilder, aManager, this, aContainerParameters);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
@ -254,7 +254,8 @@ nsHTMLCanvasFrame::GetInnerArea() const
already_AddRefed<Layer>
nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem)
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters)
{
nsRect area = GetContentRect() - GetPosition() + aItem->ToReferenceFrame();
nsHTMLCanvasElement* element = static_cast<nsHTMLCanvasElement*>(GetContent());
@ -279,7 +280,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
// Transform the canvas into the right place
gfxMatrix transform;
transform.Translate(r.TopLeft());
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
transform.Scale(r.Width()/canvasSize.width, r.Height()/canvasSize.height);
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
layer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(this));

View File

@ -13,6 +13,7 @@
#include "nsString.h"
#include "nsAString.h"
#include "nsIIOService.h"
#include "FrameLayerBuilder.h"
namespace mozilla {
namespace layers {
@ -31,6 +32,7 @@ class nsHTMLCanvasFrame : public nsContainerFrame
public:
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
NS_DECL_FRAMEARENA_HELPERS
@ -46,7 +48,8 @@ public:
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem);
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters);
/* get the size of the canvas's image */
nsIntSize GetCanvasSize();

View File

@ -1268,12 +1268,12 @@ nsDisplayImage::BuildLayer(nsDisplayListBuilder* aBuilder,
nsRefPtr<ImageLayer> layer = aManager->CreateImageLayer();
layer->SetContainer(container);
ConfigureLayer(layer);
ConfigureLayer(layer, aParameters.mOffset);
return layer.forget();
}
void
nsDisplayImage::ConfigureLayer(ImageLayer *aLayer)
nsDisplayImage::ConfigureLayer(ImageLayer *aLayer, const nsIntPoint& aOffset)
{
aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame));
@ -1287,7 +1287,7 @@ nsDisplayImage::ConfigureLayer(ImageLayer *aLayer)
const gfxRect destRect = GetDestRect();
gfxMatrix transform;
transform.Translate(destRect.TopLeft());
transform.Translate(destRect.TopLeft() + aOffset);
transform.Scale(destRect.Width()/imageWidth,
destRect.Height()/imageHeight);
aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform));

View File

@ -399,7 +399,7 @@ public:
* Configure an ImageLayer for this display item.
* Set the required filter and scaling transform.
*/
void ConfigureLayer(ImageLayer* aLayer);
void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset);
NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE)
private:

View File

@ -912,7 +912,7 @@ public:
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
{
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@ -982,7 +982,7 @@ public:
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
{
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
@ -1609,7 +1609,8 @@ nsObjectFrame::GetLayerState(nsDisplayListBuilder* aBuilder,
already_AddRefed<Layer>
nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem)
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters)
{
if (!mInstanceOwner)
return nullptr;
@ -1729,7 +1730,7 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
// Set a transform on the layer to draw the plugin in the right place
gfxMatrix transform;
transform.Translate(r.TopLeft());
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
layer->SetVisibleRegion(nsIntRect(0, 0, size.width, size.height));

View File

@ -45,6 +45,7 @@ public:
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
NS_DECL_FRAMEARENA_HELPERS
@ -142,7 +143,8 @@ public:
*/
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem);
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters);
LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager);
@ -317,7 +319,8 @@ public:
{
return static_cast<nsObjectFrame*>(mFrame)->BuildLayer(aBuilder,
aManager,
this);
this,
aContainerParameters);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,

View File

@ -158,7 +158,8 @@ CorrectForAspectRatio(const gfxRect& aRect, const nsIntSize& aRatio)
already_AddRefed<Layer>
nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem)
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters)
{
nsRect area = GetContentRect() - GetPosition() + aItem->ToReferenceFrame();
nsHTMLVideoElement* element = static_cast<nsHTMLVideoElement*>(GetContent());
@ -206,7 +207,7 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder,
layer->SetContentFlags(Layer::CONTENT_OPAQUE);
// Set a transform on the layer to draw the video in the right place
gfxMatrix transform;
transform.Translate(r.TopLeft());
transform.Translate(r.TopLeft() + aContainerParameters.mOffset);
transform.Scale(r.Width()/frameSize.width, r.Height()/frameSize.height);
layer->SetBaseTransform(gfx3DMatrix::From2D(transform));
layer->SetVisibleRegion(nsIntRect(0, 0, frameSize.width, frameSize.height));
@ -345,7 +346,7 @@ public:
LayerManager* aManager,
const ContainerParameters& aContainerParameters)
{
return static_cast<nsVideoFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this);
return static_cast<nsVideoFrame*>(mFrame)->BuildLayer(aBuilder, aManager, this, aContainerParameters);
}
virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,

View File

@ -17,6 +17,7 @@
#include "nsITimer.h"
#include "nsTArray.h"
#include "nsIAnonymousContentCreator.h"
#include "FrameLayerBuilder.h"
namespace mozilla {
namespace layers {
@ -35,6 +36,7 @@ class nsVideoFrame : public nsContainerFrame, public nsIAnonymousContentCreator
public:
typedef mozilla::layers::Layer Layer;
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
nsVideoFrame(nsStyleContext* aContext);
@ -93,7 +95,8 @@ public:
already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
nsDisplayItem* aItem);
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters);
protected:

View File

@ -621,7 +621,8 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
nsIFrame* aFrame,
LayerManager* aManager,
const nsIntRect& aVisibleRect,
nsDisplayItem* aItem)
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters)
{
NS_ABORT_IF_FALSE(aFrame,
"makes no sense to have a shadow tree without a frame");
@ -658,7 +659,8 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder,
layer->SetVisibleRegion(aVisibleRect);
nsIntPoint rootFrameOffset = GetRootFrameOffset(aFrame, aBuilder);
layer->SetBaseTransform(
gfx3DMatrix::Translation(rootFrameOffset.x, rootFrameOffset.y, 0.0));
gfx3DMatrix::Translation(rootFrameOffset.x + aContainerParameters.mOffset.x,
rootFrameOffset.y + aContainerParameters.mOffset.y, 0.0));
return layer.forget();
}
@ -927,7 +929,8 @@ nsDisplayRemote::BuildLayer(nsDisplayListBuilder* aBuilder,
{
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
nsIntRect visibleRect = GetVisibleRect().ToNearestPixels(appUnitsPerDevPixel);
nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this);
visibleRect += aContainerParameters.mOffset;
nsRefPtr<Layer> layer = mRemoteFrame->BuildLayer(aBuilder, mFrame, aManager, visibleRect, this, aContainerParameters);
return layer.forget();
}

View File

@ -44,6 +44,7 @@ class RenderFrameParent : public PRenderFrameParent,
typedef mozilla::layers::LayerManager LayerManager;
typedef mozilla::layers::TargetConfig TargetConfig;
typedef mozilla::layers::ShadowLayersParent ShadowLayersParent;
typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
typedef FrameMetrics::ViewID ViewID;
public:
@ -84,7 +85,8 @@ public:
nsIFrame* aFrame,
LayerManager* aManager,
const nsIntRect& aVisibleRect,
nsDisplayItem* aItem);
nsDisplayItem* aItem,
const ContainerParameters& aContainerParameters);
void OwnerContentChanged(nsIContent* aContent);