Bug 977831. Store layer event regions on thebes layer data in appunits relative to the reference frame until we finalize the thebes layer and then convert to layer coordinates. r=roc

Event regions weren't in a workable state prior to this. They were already stored relative to the reference frame, but in layer pixels.

Inside inactive layer managers the scale is always 1 regardless of the scale on the containing thebes layer (which is the scale it will actually be drawn at), and so the event regions did not take into account scale in this situation.

Storing the regions in appunits relative to the reference frame means we can just transform to the new reference frame (if it is different) when passing event regions up and out of inactive layer managers. The proper scale will be applied when we apply the event regions to the layer.
This commit is contained in:
Timothy Nikkel 2014-06-19 22:56:36 -05:00
parent 19395503a7
commit cad2a6f66e

View File

@ -267,12 +267,12 @@ public:
const nsIFrame* GetAnimatedGeometryRoot() { return mAnimatedGeometryRoot; }
/**
* Add aHitRegion and aDispatchToContentHitRegion to the hit regions for
* this ThebesLayer.
* Add aHitRegion, aMaybeHitRegion, and aDispatchToContentHitRegion to the
* hit regions for this ThebesLayer.
*/
void AccumulateEventRegions(const nsIntRegion& aHitRegion,
const nsIntRegion& aMaybeHitRegion,
const nsIntRegion& aDispatchToContentHitRegion)
void AccumulateEventRegions(const nsRegion& aHitRegion,
const nsRegion& aMaybeHitRegion,
const nsRegion& aDispatchToContentHitRegion)
{
mHitRegion.Or(mHitRegion, aHitRegion);
mMaybeHitRegion.Or(mMaybeHitRegion, aMaybeHitRegion);
@ -372,15 +372,15 @@ public:
/**
* The definitely-hit region for this ThebesLayer.
*/
nsIntRegion mHitRegion;
nsRegion mHitRegion;
/**
* The maybe-hit region for this ThebesLayer.
*/
nsIntRegion mMaybeHitRegion;
nsRegion mMaybeHitRegion;
/**
* The dispatch-to-content hit region for this ThebesLayer.
*/
nsIntRegion mDispatchToContentHitRegion;
nsRegion mDispatchToContentHitRegion;
/**
* The "active scrolled root" for all content in the layer. Must
* be non-null; all content in a ThebesLayer must have the same
@ -498,8 +498,9 @@ public:
{
nsPresContext* presContext = aContainerFrame->PresContext();
mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
mBuilder->FindReferenceFrameFor(mContainerFrame);
mContainerReferenceFrame =
const_cast<nsIFrame*>(aContainerItem ? aContainerItem->ReferenceFrameForChildren() :
mBuilder->FindReferenceFrameFor(mContainerFrame));
mContainerAnimatedGeometryRoot = aContainerItem
? nsLayoutUtils::GetAnimatedGeometryRootFor(aContainerItem, aBuilder)
: mContainerReferenceFrame;
@ -707,7 +708,7 @@ protected:
LayerManager* mManager;
FrameLayerBuilder* mLayerBuilder;
nsIFrame* mContainerFrame;
const nsIFrame* mContainerReferenceFrame;
nsIFrame* mContainerReferenceFrame;
const nsIFrame* mContainerAnimatedGeometryRoot;
ContainerLayer* mContainerLayer;
ContainerLayerParameters mParameters;
@ -1837,39 +1838,6 @@ ContainerState::SetFixedPositionLayerData(Layer* aLayer,
viewportFrame, anchorRect, aFixedPosFrame, presContext, mParameters);
}
static gfx3DMatrix
GetTransformToRoot(Layer* aLayer)
{
Matrix4x4 transform = aLayer->GetTransform();
for (Layer* l = aLayer->GetParent(); l; l = l->GetParent()) {
transform = transform * l->GetTransform();
}
gfx3DMatrix result;
To3DMatrix(transform, result);
return result;
}
static void
AddTransformedBoundsToRegion(const nsIntRegion& aRegion,
const gfx3DMatrix& aTransform,
nsIntRegion* aDest)
{
nsIntRect bounds = aRegion.GetBounds();
if (bounds.IsEmpty()) {
return;
}
gfxRect transformed =
aTransform.TransformBounds(gfxRect(bounds.x, bounds.y, bounds.width, bounds.height));
transformed.RoundOut();
nsIntRect intRect;
if (!gfxUtils::GfxRectToIntRect(transformed, &intRect)) {
// This should only fail if coordinates are too big to fit in an int32
*aDest = nsIntRect(-INT32_MAX/2, -INT32_MAX/2, INT32_MAX, INT32_MAX);
return;
}
aDest->Or(*aDest, intRect);
}
static bool
CanOptimizeAwayThebesLayer(ThebesLayerData* aData,
FrameLayerBuilder* aLayerBuilder)
@ -2044,28 +2012,47 @@ ContainerState::PopThebesLayerData()
ThebesLayerData* containingThebesLayerData =
mLayerBuilder->GetContainingThebesLayerData();
if (containingThebesLayerData) {
gfx3DMatrix matrix = GetTransformToRoot(layer);
nsIntPoint translatedDest = GetTranslationForThebesLayer(containingThebesLayerData->mLayer);
matrix.TranslatePost(-gfxPoint3D(translatedDest.x, translatedDest.y, 0));
AddTransformedBoundsToRegion(data->mDispatchToContentHitRegion, matrix,
&containingThebesLayerData->mDispatchToContentHitRegion);
AddTransformedBoundsToRegion(data->mMaybeHitRegion, matrix,
&containingThebesLayerData->mMaybeHitRegion);
nsRect rect = nsLayoutUtils::TransformFrameRectToAncestor(
mContainerReferenceFrame,
data->mDispatchToContentHitRegion.GetBounds(),
containingThebesLayerData->mReferenceFrame);
containingThebesLayerData->mDispatchToContentHitRegion.Or(
containingThebesLayerData->mDispatchToContentHitRegion, rect);
rect = nsLayoutUtils::TransformFrameRectToAncestor(
mContainerReferenceFrame,
data->mMaybeHitRegion.GetBounds(),
containingThebesLayerData->mReferenceFrame);
containingThebesLayerData->mMaybeHitRegion.Or(
containingThebesLayerData->mMaybeHitRegion, rect);
// Our definitely-hit region must go to the maybe-hit-region since
// this function is an approximation.
gfx3DMatrix matrix = nsLayoutUtils::GetTransformToAncestor(
mContainerReferenceFrame, containingThebesLayerData->mReferenceFrame);
gfxMatrix matrix2D;
bool isPrecise = matrix.Is2D(&matrix2D) && !matrix2D.HasNonAxisAlignedTransform();
AddTransformedBoundsToRegion(data->mHitRegion, matrix,
isPrecise ? &containingThebesLayerData->mHitRegion
: &containingThebesLayerData->mMaybeHitRegion);
rect = nsLayoutUtils::TransformFrameRectToAncestor(
mContainerReferenceFrame,
data->mHitRegion.GetBounds(),
containingThebesLayerData->mReferenceFrame);
nsRegion* dest = isPrecise ? &containingThebesLayerData->mHitRegion
: &containingThebesLayerData->mMaybeHitRegion;
dest->Or(*dest, rect);
} else {
EventRegions regions;
regions.mHitRegion.Swap(&data->mHitRegion);
regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
// Points whose hit-region status we're not sure about need to be dispatched
// to the content thread.
regions.mDispatchToContentHitRegion.Sub(data->mMaybeHitRegion, regions.mHitRegion);
nsIntRegion maybeHitRegion = ScaleRegionToOutsidePixels(data->mMaybeHitRegion);
regions.mDispatchToContentHitRegion.Sub(maybeHitRegion, regions.mHitRegion);
regions.mDispatchToContentHitRegion.Or(regions.mDispatchToContentHitRegion,
data->mDispatchToContentHitRegion);
ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion));
nsIntPoint translation = -GetTranslationForThebesLayer(data->mLayer);
regions.mHitRegion.MoveBy(translation);
regions.mDispatchToContentHitRegion.MoveBy(translation);
layer->SetEventRegions(regions);
}
@ -2641,9 +2628,9 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList,
if (itemType == nsDisplayItem::TYPE_LAYER_EVENT_REGIONS) {
nsDisplayLayerEventRegions* eventRegions =
static_cast<nsDisplayLayerEventRegions*>(item);
data->AccumulateEventRegions(ScaleRegionToOutsidePixels(eventRegions->HitRegion()),
ScaleRegionToOutsidePixels(eventRegions->MaybeHitRegion()),
ScaleRegionToOutsidePixels(eventRegions->DispatchToContentHitRegion()));
data->AccumulateEventRegions(eventRegions->HitRegion(),
eventRegions->MaybeHitRegion(),
eventRegions->DispatchToContentHitRegion());
} else {
// check to see if the new item has rounded rect clips in common with
// other items in the layer