Bug 728983. Part 2: When display items for multiple frames are merged, track the merged frames and mark them all as having an associated container layer. This ensures that invalidations are processed correctly. r=mattwoodrow

This commit is contained in:
Robert O'Callahan 2012-04-17 17:45:04 +12:00
parent 8de539221c
commit ff25496dd5
5 changed files with 109 additions and 29 deletions

View File

@ -155,9 +155,9 @@ public:
CollectOldLayers();
}
void SetInvalidThebesContent(const nsIntRegion& aRegion)
void AddInvalidThebesContent(const nsIntRegion& aRegion)
{
mInvalidThebesContent = aRegion;
mInvalidThebesContent.Or(mInvalidThebesContent, aRegion);
}
void SetInvalidateAllThebesContent()
{
@ -207,6 +207,8 @@ public:
mAppUnitsPerDevPixel);
}
const FrameLayerBuilder::ContainerParameters& ScaleParameters() { return mParameters; };
protected:
/**
* We keep a stack of these to represent the ThebesLayers that are
@ -500,6 +502,8 @@ FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder)
bool
FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer()
{
if (mIsSharingContainerLayer)
return true;
for (PRUint32 i = 0; i < mData.Length(); ++i) {
if (mData[i].mLayer->GetType() == Layer::TYPE_CONTAINER &&
mData[i].mLayerState != LAYER_ACTIVE_EMPTY)
@ -1191,7 +1195,7 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState,
/* Mark as available for conversion to image layer if this is a nsDisplayImage and
* we are the first visible item in the ThebesLayerData object.
*/
if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) {
if (mVisibleRegion.IsEmpty() && aItem->GetType() == nsDisplayItem::TYPE_IMAGE) {
mImage = static_cast<nsDisplayImage*>(aItem);
mImageClip = aClip;
} else {
@ -1829,6 +1833,40 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
return result;
}
static void
ApplyThebesLayerInvalidation(nsDisplayListBuilder* aBuilder,
nsIFrame* aContainerFrame,
nsDisplayItem* aContainerItem,
ContainerState& aState,
nsPoint* aCurrentOffset)
{
FrameProperties props = aContainerFrame->Properties();
nsPoint* offsetAtLastPaint = static_cast<nsPoint*>
(props.Get(ThebesLayerLastPaintOffsetProperty()));
*aCurrentOffset = aContainerItem ? aContainerItem->ToReferenceFrame()
: aBuilder->ToReferenceFrame(aContainerFrame);
nsRegion* invalidThebesContent = static_cast<nsRegion*>
(props.Get(ThebesLayerInvalidRegionProperty()));
if (invalidThebesContent) {
nsPoint offset = offsetAtLastPaint ? *offsetAtLastPaint : *aCurrentOffset;
invalidThebesContent->MoveBy(offset);
const FrameLayerBuilder::ContainerParameters& scaleParameters = aState.ScaleParameters();
aState.AddInvalidThebesContent(invalidThebesContent->
ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
aState.GetAppUnitsPerDevPixel()));
// We have to preserve the current contents of invalidThebesContent
// because there might be multiple container layers for the same
// frame and we need to invalidate the ThebesLayer children of all
// of them.
invalidThebesContent->MoveBy(-offset);
} else {
// The region was deleted to indicate that everything should be
// invalidated.
aState.SetInvalidateAllThebesContent();
}
}
already_AddRefed<ContainerLayer>
FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
@ -1838,7 +1876,6 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
const ContainerParameters& aParameters,
const gfx3DMatrix* aTransform)
{
FrameProperties props = aContainerFrame->Properties();
PRUint32 containerDisplayItemKey =
aContainerItem ? aContainerItem->GetPerFrameKey() : 0;
NS_ASSERTION(aContainerFrame, "Container display items here should have a frame");
@ -1893,30 +1930,27 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder,
entry->mData.AppendElement(
DisplayItemData(containerLayer, containerDisplayItemKey, LAYER_ACTIVE));
}
nsPoint* offsetAtLastPaint = static_cast<nsPoint*>
(props.Get(ThebesLayerLastPaintOffsetProperty()));
nsPoint currentOffset = aBuilder->ToReferenceFrame(aContainerFrame);
nsRegion* invalidThebesContent(static_cast<nsRegion*>
(props.Get(ThebesLayerInvalidRegionProperty())));
if (invalidThebesContent) {
nsPoint offset = offsetAtLastPaint ? *offsetAtLastPaint : currentOffset;
invalidThebesContent->MoveBy(offset);
state.SetInvalidThebesContent(invalidThebesContent->
ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale,
state.GetAppUnitsPerDevPixel()));
// We have to preserve the current contents of invalidThebesContent
// because there might be multiple container layers for the same
// frame and we need to invalidate the ThebesLayer children of all
// of them.
invalidThebesContent->MoveBy(-offset);
} else {
// The region was deleted to indicate that everything should be
// invalidated.
state.SetInvalidateAllThebesContent();
}
nsPoint currentOffset;
ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state,
&currentOffset);
SetHasContainerLayer(aContainerFrame, currentOffset);
nsAutoTArray<nsIFrame*,4> mergedFrames;
if (aContainerItem) {
aContainerItem->GetMergedFrames(&mergedFrames);
}
for (PRUint32 i = 0; i < mergedFrames.Length(); ++i) {
nsIFrame* mergedFrame = mergedFrames[i];
DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame);
if (entry) {
// Ensure that UpdateDisplayItemDataForFrame recognizes that we
// still have a container layer associated with this frame.
entry->mIsSharingContainerLayer = true;
}
ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nsnull, state,
&currentOffset);
SetHasContainerLayer(mergedFrame, currentOffset);
}
}
Clip clip;

View File

@ -440,9 +440,9 @@ protected:
*/
class DisplayItemDataEntry : public nsPtrHashKey<nsIFrame> {
public:
DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey<nsIFrame>(key) {}
DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey<nsIFrame>(key), mIsSharingContainerLayer(false) {}
DisplayItemDataEntry(DisplayItemDataEntry &toCopy) :
nsPtrHashKey<nsIFrame>(toCopy.mKey)
nsPtrHashKey<nsIFrame>(toCopy.mKey), mIsSharingContainerLayer(toCopy.mIsSharingContainerLayer)
{
// This isn't actually a copy-constructor; notice that it steals toCopy's
// array. Be careful.
@ -452,6 +452,7 @@ protected:
bool HasNonEmptyContainerLayer();
nsAutoTArray<DisplayItemData, 1> mData;
bool mIsSharingContainerLayer;
enum { ALLOW_MEMMOVE = false };
};

View File

@ -0,0 +1,21 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<body>
<div style="-moz-column-count:2; column-count:2; width:300px; height:100px;">
<div id="o" style="opacity:0.5; width:100px; height:200px; background:lime;">
<div id="d" style="height:50px; width:80px; background:green; padding:2px">Text</div>
</div>
</div>
<script>
var o = document.getElementById("o");
var d = document.getElementById("d");
document.body.getBoundingClientRect();
o.style.opacity = 0.8;
function doTest() {
o.style.opacity = 0.9;
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</body>
</html>

View File

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html class="reftest-wait">
<body>
<div style="-moz-column-count:2; column-count:2; width:300px; height:100px;">
<div id="o" style="opacity:0.5; width:100px; height:200px; background:lime;">
<div id="d" style="height:50px; width:80px; background:red; padding:2px">Text</div>
</div>
</div>
<script>
var o = document.getElementById("o");
var d = document.getElementById("d");
document.body.getBoundingClientRect();
o.style.opacity = 0.8;
function doTest() {
o.style.opacity = 0.9;
document.body.getBoundingClientRect();
d.style.background = "green";
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</body>
</html>

View File

@ -1694,6 +1694,7 @@ fuzzy-if(d2d,1,19) fuzzy-if(cocoaWidget,1,170) == 718521.html 718521-ref.html
== 720987.html 720987-ref.html
== 722923-1.html 722923-1-ref.html
== 723484-1.html 723484-1-ref.html
== 728983-1.html 728983-1-ref.html
== 729143-1.html 729143-1-ref.html
== 731521-1.html 731521-1-ref.html
needs-focus == 731726-1.html 731726-1-ref.html