Files
palemoon27/gfx/layers/LayerTreeInvalidation.cpp
T
roytam1 fc21d5d094 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1140148 - Update reftest manifests for Android 4.3 emulator; r=dminor (69b7ed099)
- Bug 742176 - Remove/reduce fuzz annotations for tests that no longer appear to be affected by bad overflow areas. r=ehsan (8fac68e26)
- pieces of older patches (6d4b30aed)
- Bug 1153574 - Re-enable Mulet reftests taskcluster-specific disables. r=ahal, a=test-only (72ed7dbc2)
- part of Bug 1138442 - Disable reftests on Mulet in parity with B2G/B2G (8baf07b3c)
- Bug 1073209 - Eliminate usage of CreateSamplingRestrictedDrawable on OS X. r=jrmuizel (86bee3fbc)
- Bug 1148889 - Fuzz some android tests. r=mstange (f63be045e)
- Mark unaccelerated antialiasing reftest failures with APZ as fuzzy. (bug 1157716, r=mstange) (4c0c0f034)
- Bug 1156197. Just use the return value of the cols DOM property for determining the default number of rendered columns for a textarea. r=ms2ger (16ab3064f)
- uniform emoji tests here (5a1e9802c)
- mulet was missing (433a50d93)
- Bug 1141511 - Disable some gtk2Widget-dependant reftests on Mulet. r=ahal (80d3cef05)
- Bug 1141607. Fix the initial value of outline-color to actually be correct. r=dbaron (309275f24)
- part of Bug 1138442 - Disable reftests on Mulet in parity with B2G/B2G (b7a3bb189)
- Bug 1141511 - Disable some gtk2Widget-dependant reftests on Mulet. r=ahal (1afac0742)
- Bug 1153845 - For CSS filters, make the primitive subregions big enough to contain the whole pre-filter visual overflow rect. r=roc (6d56dd6f9)
- annotate (090064379)
- boh (39f7c5aba)
- Bug 1170158 - Apply GTK2 reftest exceptions to GTK3. r=karlt (1f1299503)
- Bug 1165185 - Try to avoid invalidations when scrolling transformed elements. r=roc (d4693eb11)
- Bug 1165185 - Nudge layer prescale to integers. r=roc (2ac6881fc)
- remove spurious file (58fc9059b)
- Bug 1145730 - Restrict the async transforms applied to mask layers to those caused by fixed-position adjustment. r=kats (ebdcc1223)
- Bug 1146024 - Fix up input routing for APZ on Fennec. r=kats (85e8b249b)
- Bug 1146024 - Followup to fix non-android bustage on a CLOSED TREE. r=bustage (1ccd4a58f)
- Bug 1133905. Add some reftests. (89c9f9c8c)
- Bug 1133905. Make layout place scrollbars at the scroll position clamping scrollport size when one is set so that scrollbars are positioned properly on b2g. r=mstange (841279606)
- Bug 1155359 - Add a reftest; r=gw280 (a6e7aeb78)
- Bug 1155359 follow-up: Disable the test on B2G and Mulet (d709b7c54)
- Bug 1157726: Updated algorithm to match ICU implementation of support for bidi isolates. r=smontagu (96d9801e1)
- Bug 1154892 - mozinstall fails to install on Mac with paths which contain white spaces. r=chmanchester (1bddadcdd)
- Bug 1151908 - Updating our character property data with new Bidi info from Unicode 6.3. r=smontagu (c34f88172)
- Bug 817406 part 2 - Tests for propagating 'direction' to the viewport. (3bc7bfa40)
- Bug 1139306. Adjust heights of scrollable area so scrollbar sizes almost match in reftests now that RTL scrollbars correctly show in these reftests. r=smontagu (9c77c96ed)
- Bug 817406 part 3 - Increase the fuzz factors slightly on a few tests for bug 1133905. (22d8a4cbc)
- Bug 1148582. Part 3 follow up. Properly test if a scroll frame uses async scrolling when determining if it needs its clip put on its layer. r=mstange (13beb6a24)
- Fix tests that depend on synchronous scrolling. (bug 1140293, r=mstange,masayuki,kgilbert) (578d2ff1e)
- fix order because of mispatch (75279e185)
- Bug 1162009 - Add TOUCH_CANCEL sending on e10s. r=kats (0fc5574ac)
- Bug 1162179 - Don't create APZCTreeManagers for windows which aren't multiprocess. r=dvander (135d115e0)
- Enable APZ for all Desktop windows if E10s is enabled. (bug 1163115, r=kats) (354729297)
- Fix wheel events not applying root scroll delta overrides. (bug 1147223 part 1, r=kats) (6d650c449)
- fix patch order (08b9ad9bd)
- Improve bad APZ wheel pref detection in about:support. (bug 1147223 part 2, r=kats) (292fa3634)
- Bug 1151890 - Explicitly set a null MessageLoop for the APZ controller thread on OS X. r=mstange (a4fe37d78)
- Bug 1148868 - Put the APZ event thread on Mac behind a pref layers.async-pan-zoom.separate-event-thread that defaults to false. r=dvander (827a7cca7)
- Backed out changeset c5af69669855 (bug 1124084) for various regressions. (28d328c8d)
- Bug 1141819 - Don't implicitly dispatch a runnable to the main thread in RasterImage::StartDecoding. r=baku (1d1233319)
- Bug 1124088 - Rename decode-on-draw to decode-only-on-draw. r=tn (83c24cdb7)
- Bug 1149893 - Add a pref that makes us decode all images immediately. r=baku (6432ae587)
- Bug 1156401 - Fix ContextMenu handling when building Fennec with C++ APZ. r=kats, r=botond (dd784945c)
- Bug 1168629. Always make sure that there is at least one layer with the metrics for the root scroll frame/root element. r=botond,kats (06f19aef3)
- Bug 1154478 - Rename gfxPrefs::LayoutEventRegionsEnabled to LayoutEventRegionsEnabledDoNotUseDirectly. r=kats (68790b756)
- Don't expand displayports beyond the maximum texture size. (bug 1135907, r=kats) (805866f66)
- Bug 1138444 - Add Mulet detection for reftests. r=jgriffin (cc9378556)
- Use widgets for APZ checks, rather than gfxPrefs. (bug 1162064, r=kats,mstange) (40d2823a5)
- Bug 1151993 - Apply shrink-wrapping to block frames that are orthogonal to their containing block. r=smontagu (9fdd76008)
- Bug 1156021 - Use containing block inline-size (as appropriate for writing mode) to compute text-indent when specified as percentage. r=dbaron (c7fcb4193)
- Bug 1152941 - Always use unconstrained block-size when reflowing an orthogonal child block, to avoid incomplete reflow across orthogonal boundary. r=dbaron (5f4748c5a)
- Bug 1163238 - Don't set available block-size to unconstrained for orthogonal-block reflow state until after InitConstraints etc. r=dholbert (07ca784bf)
- Bug 1155798: Drop end-of-line whitespace from C++ files in layout/tables. (whitespace-only, no review, DONTBUILD) (6ad9c50d8)
- Bug 1155880 part 1: Rename nsITableLayoutStrategy::ComputeColumnWidths and associated comments to use "ISize" instead of "Width". r=jfkthame (c3bec937b)
- Bug 1155880 part 2: Rename nsTableColFrame Get/Set/ResetFinalWidth methods to use ISize instead of Width. r=jfkthame (1d2bfd990)
- Bug 1155880 part 3: Rename nsTableFrame::GetColumnWidth to use "ISize" instead of "Width". r=jfkthame (8a0d7a3c8)
- Bug 1159101 part 1 - Alter dependencies among headers of table struct frames. r=roc (b943ee1c3)
- Bug 1159101 part 2 - Add GetTableFrame() for table inner frames. r=roc (6641affa7)
- Bug 1145036 part 1 - Rename mBorderSpacingX/Y to mBorderSpacingCol/Row. r=heycam (7e91504af)
- Bug 1145036 part 2 - Rename nsTableFrame::GetCellSpacingX/Y to GetCol/RowSpacing. r=roc (b439569de)
- Bug 1159101 part 3 - Replace most of nsTableFrame::GetTableFrame() usage with new GetTableFrame() methods. r=roc (4bdf27d00)
- Bug 1159990 - Add TableArea struct and replace nsIntRect with it for table damage area. r=roc (ebca44c12)
2020-12-21 13:33:23 +08:00

493 lines
16 KiB
C++

/*-*- Mode: C++; tab-width: 2; 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 "LayerTreeInvalidation.h"
#include <stdint.h> // for uint32_t
#include "ImageContainer.h" // for ImageContainer
#include "ImageLayers.h" // for ImageLayer, etc
#include "Layers.h" // for Layer, ContainerLayer, etc
#include "Units.h" // for ParentLayerIntRect
#include "gfxColor.h" // for gfxRGBA
#include "GraphicsFilter.h" // for GraphicsFilter
#include "gfxRect.h" // for gfxRect
#include "gfxUtils.h" // for gfxUtils
#include "mozilla/gfx/BaseSize.h" // for BaseSize
#include "mozilla/gfx/Point.h" // for IntSize
#include "mozilla/mozalloc.h" // for operator new, etc
#include "nsAutoPtr.h" // for nsRefPtr, nsAutoPtr, etc
#include "nsDataHashtable.h" // for nsDataHashtable
#include "nsDebug.h" // for NS_ASSERTION
#include "nsHashKeys.h" // for nsPtrHashKey
#include "nsISupportsImpl.h" // for Layer::AddRef, etc
#include "nsRect.h" // for IntRect
#include "nsTArray.h" // for nsAutoTArray, nsTArray_Impl
using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
struct LayerPropertiesBase;
UniquePtr<LayerPropertiesBase> CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask = false);
static IntRect
TransformRect(const IntRect& aRect, const Matrix4x4& aTransform)
{
if (aRect.IsEmpty()) {
return IntRect();
}
Rect rect(aRect.x, aRect.y, aRect.width, aRect.height);
rect = aTransform.TransformBounds(rect);
rect.RoundOut();
IntRect intRect;
if (!gfxUtils::GfxRectToIntRect(ThebesRect(rect), &intRect)) {
return IntRect();
}
return intRect;
}
static void
AddTransformedRegion(nsIntRegion& aDest, const nsIntRegion& aSource, const Matrix4x4& aTransform)
{
nsIntRegionRectIterator iter(aSource);
const IntRect *r;
while ((r = iter.Next())) {
aDest.Or(aDest, TransformRect(*r, aTransform));
}
aDest.SimplifyOutward(20);
}
static void
AddRegion(nsIntRegion& aDest, const nsIntRegion& aSource)
{
aDest.Or(aDest, aSource);
aDest.SimplifyOutward(20);
}
/**
* Walks over this layer, and all descendant layers.
* If any of these are a ContainerLayer that reports invalidations to a PresShell,
* then report that the entire bounds have changed.
*/
static void
NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback)
{
aLayer->ClearInvalidRect();
ContainerLayer* container = aLayer->AsContainerLayer();
if (aLayer->GetMaskLayer()) {
NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback);
}
if (!container) {
return;
}
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
NotifySubdocumentInvalidationRecursive(child, aCallback);
}
aCallback(container, container->GetVisibleRegion());
}
struct LayerPropertiesBase : public LayerProperties
{
explicit LayerPropertiesBase(Layer* aLayer)
: mLayer(aLayer)
, mMaskLayer(nullptr)
, mVisibleRegion(aLayer->GetVisibleRegion())
, mInvalidRegion(aLayer->GetInvalidRegion())
, mPostXScale(aLayer->GetPostXScale())
, mPostYScale(aLayer->GetPostYScale())
, mOpacity(aLayer->GetLocalOpacity())
, mUseClipRect(!!aLayer->GetClipRect())
{
MOZ_COUNT_CTOR(LayerPropertiesBase);
if (aLayer->GetMaskLayer()) {
mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer(), true);
}
if (mUseClipRect) {
mClipRect = *aLayer->GetClipRect();
}
mTransform = aLayer->GetLocalTransform();
}
LayerPropertiesBase()
: mLayer(nullptr)
, mMaskLayer(nullptr)
{
MOZ_COUNT_CTOR(LayerPropertiesBase);
}
~LayerPropertiesBase()
{
MOZ_COUNT_DTOR(LayerPropertiesBase);
}
virtual nsIntRegion ComputeDifferences(Layer* aRoot,
NotifySubDocInvalidationFunc aCallback,
bool* aGeometryChanged);
virtual void MoveBy(const IntPoint& aOffset);
nsIntRegion ComputeChange(NotifySubDocInvalidationFunc aCallback,
bool& aGeometryChanged)
{
bool transformChanged = !mTransform.FuzzyEqualsMultiplicative(mLayer->GetLocalTransform()) ||
mLayer->GetPostXScale() != mPostXScale ||
mLayer->GetPostYScale() != mPostYScale;
Layer* otherMask = mLayer->GetMaskLayer();
const Maybe<ParentLayerIntRect>& otherClip = mLayer->GetClipRect();
nsIntRegion result;
if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask ||
(mUseClipRect != !!otherClip) ||
mLayer->GetLocalOpacity() != mOpacity ||
transformChanged)
{
aGeometryChanged = true;
result = OldTransformedBounds();
AddRegion(result, NewTransformedBounds());
// We can't bail out early because we need to update mChildrenChanged.
}
AddRegion(result, ComputeChangeInternal(aCallback, aGeometryChanged));
AddTransformedRegion(result, mLayer->GetInvalidRegion(), mTransform);
if (mMaskLayer && otherMask) {
AddTransformedRegion(result, mMaskLayer->ComputeChange(aCallback, aGeometryChanged),
mTransform);
}
if (mUseClipRect && otherClip) {
if (!mClipRect.IsEqualInterior(*otherClip)) {
aGeometryChanged = true;
nsIntRegion tmp;
tmp.Xor(ParentLayerIntRect::ToUntyped(mClipRect), ParentLayerIntRect::ToUntyped(*otherClip));
AddRegion(result, tmp);
}
}
mLayer->ClearInvalidRect();
return result;
}
IntRect NewTransformedBounds()
{
return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetLocalTransform());
}
IntRect OldTransformedBounds()
{
return TransformRect(mVisibleRegion.GetBounds(), mTransform);
}
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
bool& aGeometryChanged)
{
return IntRect();
}
nsRefPtr<Layer> mLayer;
UniquePtr<LayerPropertiesBase> mMaskLayer;
nsIntRegion mVisibleRegion;
nsIntRegion mInvalidRegion;
Matrix4x4 mTransform;
float mPostXScale;
float mPostYScale;
float mOpacity;
ParentLayerIntRect mClipRect;
bool mUseClipRect;
};
struct ContainerLayerProperties : public LayerPropertiesBase
{
explicit ContainerLayerProperties(ContainerLayer* aLayer)
: LayerPropertiesBase(aLayer)
, mPreXScale(aLayer->GetPreXScale())
, mPreYScale(aLayer->GetPreYScale())
{
for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) {
mChildren.AppendElement(Move(CloneLayerTreePropertiesInternal(child)));
}
}
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
bool& aGeometryChanged)
{
ContainerLayer* container = mLayer->AsContainerLayer();
nsIntRegion result;
bool childrenChanged = false;
if (mPreXScale != container->GetPreXScale() ||
mPreYScale != container->GetPreYScale()) {
aGeometryChanged = true;
result = OldTransformedBounds();
AddRegion(result, NewTransformedBounds());
childrenChanged = true;
// Can't bail out early, we need to update the child container layers
}
// A low frame rate is especially visible to users when scrolling, so we
// particularly want to avoid unnecessary invalidation at that time. For us
// here, that means avoiding unnecessary invalidation of child items when
// other children are added to or removed from our container layer, since
// that may be caused by children being scrolled in or out of view. We are
// less concerned with children changing order.
// TODO: Consider how we could avoid unnecessary invalidation when children
// change order, and whether the overhead would be worth it.
nsDataHashtable<nsPtrHashKey<Layer>, uint32_t> oldIndexMap(mChildren.Length());
for (uint32_t i = 0; i < mChildren.Length(); ++i) {
oldIndexMap.Put(mChildren[i]->mLayer, i);
}
uint32_t i = 0; // cursor into the old child list mChildren
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
bool invalidateChildsCurrentArea = false;
if (i < mChildren.Length()) {
uint32_t childsOldIndex;
if (oldIndexMap.Get(child, &childsOldIndex)) {
if (childsOldIndex >= i) {
// Invalidate the old areas of layers that used to be between the
// current |child| and the previous |child| that was also in the
// old list mChildren (if any of those children have been reordered
// rather than removed, we will invalidate their new area when we
// encounter them in the new list):
for (uint32_t j = i; j < childsOldIndex; ++j) {
AddRegion(result, mChildren[j]->OldTransformedBounds());
childrenChanged |= true;
}
// Invalidate any regions of the child that have changed:
nsIntRegion region = mChildren[childsOldIndex]->ComputeChange(aCallback, aGeometryChanged);
i = childsOldIndex + 1;
if (!region.IsEmpty()) {
AddRegion(result, region);
childrenChanged |= true;
}
} else {
// We've already seen this child in mChildren (which means it must
// have been reordered) and invalidated its old area. We need to
// invalidate its new area too:
invalidateChildsCurrentArea = true;
}
} else {
// |child| is new
invalidateChildsCurrentArea = true;
}
} else {
// |child| is new, or was reordered to a higher index
invalidateChildsCurrentArea = true;
}
if (invalidateChildsCurrentArea) {
aGeometryChanged = true;
AddTransformedRegion(result, child->GetVisibleRegion(), child->GetLocalTransform());
if (aCallback) {
NotifySubdocumentInvalidationRecursive(child, aCallback);
} else {
ClearInvalidations(child);
}
}
childrenChanged |= invalidateChildsCurrentArea;
}
// Process remaining removed children.
while (i < mChildren.Length()) {
childrenChanged |= true;
AddRegion(result, mChildren[i]->OldTransformedBounds());
i++;
}
if (aCallback) {
aCallback(container, result);
}
if (childrenChanged) {
container->SetChildrenChanged(true);
}
result.Transform(gfx::To3DMatrix(mLayer->GetLocalTransform()));
return result;
}
// The old list of children:
nsAutoTArray<UniquePtr<LayerPropertiesBase>,1> mChildren;
float mPreXScale;
float mPreYScale;
};
struct ColorLayerProperties : public LayerPropertiesBase
{
explicit ColorLayerProperties(ColorLayer *aLayer)
: LayerPropertiesBase(aLayer)
, mColor(aLayer->GetColor())
, mBounds(aLayer->GetBounds())
{ }
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
bool& aGeometryChanged)
{
ColorLayer* color = static_cast<ColorLayer*>(mLayer.get());
if (mColor != color->GetColor()) {
aGeometryChanged = true;
return NewTransformedBounds();
}
nsIntRegion boundsDiff;
boundsDiff.Xor(mBounds, color->GetBounds());
nsIntRegion result;
AddTransformedRegion(result, boundsDiff, mTransform);
return result;
}
gfxRGBA mColor;
IntRect mBounds;
};
struct ImageLayerProperties : public LayerPropertiesBase
{
explicit ImageLayerProperties(ImageLayer* aImage, bool aIsMask)
: LayerPropertiesBase(aImage)
, mContainer(aImage->GetContainer())
, mFilter(aImage->GetFilter())
, mScaleToSize(aImage->GetScaleToSize())
, mScaleMode(aImage->GetScaleMode())
, mIsMask(aIsMask)
{
}
virtual nsIntRegion ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback,
bool& aGeometryChanged)
{
ImageLayer* imageLayer = static_cast<ImageLayer*>(mLayer.get());
if (!imageLayer->GetVisibleRegion().IsEqual(mVisibleRegion)) {
aGeometryChanged = true;
IntRect result = NewTransformedBounds();
result = result.Union(OldTransformedBounds());
return result;
}
ImageContainer* container = imageLayer->GetContainer();
if (mContainer != container ||
mFilter != imageLayer->GetFilter() ||
mScaleToSize != imageLayer->GetScaleToSize() ||
mScaleMode != imageLayer->GetScaleMode()) {
aGeometryChanged = true;
if (mIsMask) {
// Mask layers have an empty visible region, so we have to
// use the image size instead.
IntSize size = container->GetCurrentSize();
IntRect rect(0, 0, size.width, size.height);
return TransformRect(rect, mLayer->GetLocalTransform());
} else {
return NewTransformedBounds();
}
}
return IntRect();
}
nsRefPtr<ImageContainer> mContainer;
GraphicsFilter mFilter;
gfx::IntSize mScaleToSize;
ScaleMode mScaleMode;
bool mIsMask;
};
UniquePtr<LayerPropertiesBase>
CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
{
if (!aRoot) {
return MakeUnique<LayerPropertiesBase>();
}
MOZ_ASSERT(!aIsMask || aRoot->GetType() == Layer::TYPE_IMAGE);
switch (aRoot->GetType()) {
case Layer::TYPE_CONTAINER:
case Layer::TYPE_REF:
return MakeUnique<ContainerLayerProperties>(aRoot->AsContainerLayer());
case Layer::TYPE_COLOR:
return MakeUnique<ColorLayerProperties>(static_cast<ColorLayer*>(aRoot));
case Layer::TYPE_IMAGE:
return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
default:
return MakeUnique<LayerPropertiesBase>(aRoot);
}
return UniquePtr<LayerPropertiesBase>(nullptr);
}
/* static */ UniquePtr<LayerProperties>
LayerProperties::CloneFrom(Layer* aRoot)
{
return CloneLayerTreePropertiesInternal(aRoot);
}
/* static */ void
LayerProperties::ClearInvalidations(Layer *aLayer)
{
aLayer->ClearInvalidRect();
if (aLayer->GetMaskLayer()) {
ClearInvalidations(aLayer->GetMaskLayer());
}
ContainerLayer* container = aLayer->AsContainerLayer();
if (!container) {
return;
}
for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) {
ClearInvalidations(child);
}
}
nsIntRegion
LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback,
bool* aGeometryChanged = nullptr)
{
NS_ASSERTION(aRoot, "Must have a layer tree to compare against!");
if (mLayer != aRoot) {
if (aCallback) {
NotifySubdocumentInvalidationRecursive(aRoot, aCallback);
} else {
ClearInvalidations(aRoot);
}
IntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(),
aRoot->GetLocalTransform());
result = result.Union(OldTransformedBounds());
if (aGeometryChanged != nullptr) {
*aGeometryChanged = true;
}
return result;
} else {
bool geometryChanged = (aGeometryChanged != nullptr) ? *aGeometryChanged : false;
nsIntRegion invalid = ComputeChange(aCallback, geometryChanged);
if (aGeometryChanged != nullptr) {
*aGeometryChanged = geometryChanged;
}
return invalid;
}
}
void
LayerPropertiesBase::MoveBy(const IntPoint& aOffset)
{
mTransform.PostTranslate(aOffset.x, aOffset.y, 0);
}
} // namespace layers
} // namespace mozilla