Bug 1009478 - Make LayerActivity properties survive across reframes of an element. r=roc

This commit is contained in:
Markus Stange 2014-05-13 19:30:11 +02:00
Родитель 2bf68f16b6
Коммит a772659b8d
5 изменённых файлов: 81 добавлений и 8 удалений

Просмотреть файл

@ -505,6 +505,7 @@ GK_ATOM(lang, "lang")
GK_ATOM(language, "language")
GK_ATOM(last, "last")
GK_ATOM(layer, "layer")
GK_ATOM(LayerActivity, "LayerActivity")
GK_ATOM(layout, "layout")
GK_ATOM(leading, "leading")
GK_ATOM(leaf, "leaf")

Просмотреть файл

@ -29,6 +29,7 @@ class LayerActivity {
public:
LayerActivity(nsIFrame* aFrame)
: mFrame(aFrame)
, mContent(nullptr)
, mOpacityRestyleCount(0)
, mTransformRestyleCount(0)
, mLeftRestyleCount(0)
@ -60,7 +61,13 @@ public:
}
}
// While tracked, exactly one of mFrame or mContent is non-null, depending
// on whether this property is stored on a frame or on a content node.
// When this property is expired by the layer activity tracker, both mFrame
// and mContent are nulled-out and the property is deleted.
nsIFrame* mFrame;
nsIContent* mContent;
nsExpirationState mState;
// Number of restyle operations detected
uint8_t mOpacityRestyleCount;
@ -93,7 +100,7 @@ static LayerActivityTracker* gLayerActivityTracker = nullptr;
LayerActivity::~LayerActivity()
{
if (mFrame) {
if (mFrame || mContent) {
NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
gLayerActivityTracker->RemoveObject(this);
}
@ -113,15 +120,24 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
RemoveObject(aObject);
nsIFrame* f = aObject->mFrame;
nsIContent* c = aObject->mContent;
aObject->mFrame = nullptr;
aObject->mContent = nullptr;
// The pres context might have been detached during the delay -
// that's fine, just skip the paint.
if (f->PresContext()->GetContainerWeak()) {
f->SchedulePaint();
MOZ_ASSERT((f == nullptr) != (c == nullptr),
"A LayerActivity object should always have a reference to either its frame or its content");
if (f) {
// The pres context might have been detached during the delay -
// that's fine, just skip the paint.
if (f->PresContext()->GetContainerWeak()) {
f->SchedulePaint();
}
f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
f->Properties().Delete(LayerActivityProperty());
} else {
c->DeleteProperty(nsGkAtoms::LayerActivity);
}
f->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
f->Properties().Delete(LayerActivityProperty());
}
static LayerActivity*
@ -160,6 +176,39 @@ IncrementMutationCount(uint8_t* aCount)
*aCount = uint8_t(std::min(0xFF, *aCount + 1));
}
/* static */ void
ActiveLayerTracker::TransferActivityToContent(nsIFrame* aFrame, nsIContent* aContent)
{
if (!aFrame->HasAnyStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY)) {
return;
}
FrameProperties properties = aFrame->Properties();
LayerActivity* layerActivity =
static_cast<LayerActivity*>(properties.Remove(LayerActivityProperty()));
aFrame->RemoveStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
if (!layerActivity) {
return;
}
layerActivity->mFrame = nullptr;
layerActivity->mContent = aContent;
aContent->SetProperty(nsGkAtoms::LayerActivity, layerActivity,
nsINode::DeleteProperty<LayerActivity>, true);
}
/* static */ void
ActiveLayerTracker::TransferActivityToFrame(nsIContent* aContent, nsIFrame* aFrame)
{
LayerActivity* layerActivity = static_cast<LayerActivity*>(
aContent->UnsetProperty(nsGkAtoms::LayerActivity));
if (!layerActivity) {
return;
}
layerActivity->mContent = nullptr;
layerActivity->mFrame = aFrame;
aFrame->AddStateBits(NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY);
aFrame->Properties().Set(LayerActivityProperty(), layerActivity);
}
/* static */ void
ActiveLayerTracker::NotifyRestyle(nsIFrame* aFrame, nsCSSProperty aProperty)
{

Просмотреть файл

@ -8,6 +8,7 @@
#include "nsCSSProperty.h"
class nsIFrame;
class nsIContent;
namespace mozilla {
@ -64,6 +65,18 @@ public:
* as being animated for constructing active layers.
*/
static bool IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame);
/**
* Transfer the LayerActivity property to the frame's content node when the
* frame is about to be destroyed so that layer activity can be tracked
* throughout reframes of an element. Only call this when aFrame is the
* primary frame of aContent.
*/
static void TransferActivityToContent(nsIFrame* aFrame, nsIContent* aContent);
/**
* Transfer the LayerActivity property back to the content node's primary
* frame after the frame has been created.
*/
static void TransferActivityToFrame(nsIContent* aContent, nsIFrame* aFrame);
/*
* We track modifications to the content of certain frames (i.e. canvas frames)

Просмотреть файл

@ -93,6 +93,7 @@
#include "nsRefreshDriver.h"
#include "nsRuleProcessorData.h"
#include "nsTextNode.h"
#include "ActiveLayerTracker.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -3828,6 +3829,7 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
!aItem.mContent->GetPrimaryFrame())) &&
!(bits & FCDATA_SKIP_FRAMESET)) {
aItem.mContent->SetPrimaryFrame(primaryFrame);
ActiveLayerTracker::TransferActivityToFrame(aItem.mContent, primaryFrame);
}
}

Просмотреть файл

@ -84,6 +84,7 @@
#include "mozilla/css/ImageLoader.h"
#include "mozilla/gfx/Tools.h"
#include "nsPrintfCString.h"
#include "ActiveLayerTracker.h"
using namespace mozilla;
using namespace mozilla::css;
@ -648,6 +649,13 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
}
}
// This needs to happen before shell->NotifyDestroyingFrame because that
// clears our Properties() table.
bool isPrimaryFrame = (mContent && mContent->GetPrimaryFrame() == this);
if (isPrimaryFrame) {
ActiveLayerTracker::TransferActivityToContent(this, mContent);
}
shell->NotifyDestroyingFrame(this);
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
@ -663,7 +671,7 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
}
// Make sure that our deleted frame can't be returned from GetPrimaryFrame()
if (mContent && mContent->GetPrimaryFrame() == this) {
if (isPrimaryFrame) {
mContent->SetPrimaryFrame(nullptr);
}