зеркало из https://github.com/mozilla/gecko-dev.git
Bug 564991. Part 22: Mark scrolled elements as inactive after a timeout. r=mats
This commit is contained in:
Родитель
2eeaed4ebb
Коммит
06e139fe2b
|
@ -1272,6 +1272,26 @@ IsSmoothScrollingEnabled()
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
class ScrollFrameActivityTracker : public nsExpirationTracker<nsGfxScrollFrameInner,4> {
|
||||
public:
|
||||
// Wait for 75-100ms between scrolls before we switch the appearance back to
|
||||
// subpixel AA. That's 4 generations of 25ms each.
|
||||
enum { TIMEOUT_MS = 25 };
|
||||
ScrollFrameActivityTracker()
|
||||
: nsExpirationTracker<nsGfxScrollFrameInner,4>(TIMEOUT_MS) {}
|
||||
~ScrollFrameActivityTracker() {
|
||||
AgeAllGenerations();
|
||||
}
|
||||
|
||||
virtual void NotifyExpired(nsGfxScrollFrameInner *aObject) {
|
||||
RemoveObject(aObject);
|
||||
aObject->mScrollingActive = PR_FALSE;
|
||||
aObject->mOuter->InvalidateOverflowRect();
|
||||
}
|
||||
};
|
||||
|
||||
static ScrollFrameActivityTracker *gScrollFrameActivityTracker = nsnull;
|
||||
|
||||
nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
|
||||
PRBool aIsRoot,
|
||||
PRBool aIsXUL)
|
||||
|
@ -1307,6 +1327,14 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
|
|||
|
||||
nsGfxScrollFrameInner::~nsGfxScrollFrameInner()
|
||||
{
|
||||
if (mActivityExpirationState.IsTracked()) {
|
||||
gScrollFrameActivityTracker->RemoveObject(this);
|
||||
}
|
||||
if (gScrollFrameActivityTracker &&
|
||||
gScrollFrameActivityTracker->IsEmpty()) {
|
||||
delete gScrollFrameActivityTracker;
|
||||
gScrollFrameActivityTracker = nsnull;
|
||||
}
|
||||
delete mAsyncScroll;
|
||||
}
|
||||
|
||||
|
@ -1562,6 +1590,41 @@ InvalidateFixedBackgroundFrames(nsIFrame* aRootFrame,
|
|||
InvalidateFixedBackgroundFramesFromList(&builder, list);
|
||||
}
|
||||
|
||||
PRBool nsGfxScrollFrameInner::IsAlwaysActive() const
|
||||
{
|
||||
// The root scrollframe for a non-chrome document which is the direct
|
||||
// child of a chrome document is always treated as "active".
|
||||
if (!mIsRoot)
|
||||
return PR_FALSE;
|
||||
nsPresContext* presContext = mOuter->PresContext();
|
||||
if (presContext->IsChrome())
|
||||
return PR_FALSE;
|
||||
nsIFrame* rootFrame = mOuter->PresContext()->PresShell()->GetRootFrame();
|
||||
nsIFrame* rootParent = nsLayoutUtils::GetCrossDocParentFrame(rootFrame);
|
||||
return !rootParent || rootParent->PresContext()->IsChrome();
|
||||
}
|
||||
|
||||
PRBool nsGfxScrollFrameInner::IsScrollingActive() const
|
||||
{
|
||||
return mScrollingActive || IsAlwaysActive();
|
||||
}
|
||||
|
||||
void nsGfxScrollFrameInner::MarkActive()
|
||||
{
|
||||
if (IsAlwaysActive())
|
||||
return;
|
||||
|
||||
mScrollingActive = PR_TRUE;
|
||||
if (mActivityExpirationState.IsTracked()) {
|
||||
gScrollFrameActivityTracker->MarkUsed(this);
|
||||
} else {
|
||||
if (!gScrollFrameActivityTracker) {
|
||||
gScrollFrameActivityTracker = new ScrollFrameActivityTracker();
|
||||
}
|
||||
gScrollFrameActivityTracker->AddObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
void nsGfxScrollFrameInner::ScrollVisual(nsIntPoint aPixDelta)
|
||||
{
|
||||
nsRootPresContext* rootPresContext =
|
||||
|
@ -1595,10 +1658,10 @@ void nsGfxScrollFrameInner::ScrollVisual(nsIntPoint aPixDelta)
|
|||
// to be consistent with the view and frame hierarchy.
|
||||
PRUint32 flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT;
|
||||
nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter);
|
||||
if (CanScrollWithBlitting(mOuter, displayRoot) && mScrollingActive) {
|
||||
if (IsScrollingActive() && CanScrollWithBlitting(mOuter, displayRoot)) {
|
||||
flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS;
|
||||
}
|
||||
mScrollingActive = PR_TRUE;
|
||||
MarkActive();
|
||||
mOuter->InvalidateWithFlags(mScrollPort, flags);
|
||||
|
||||
if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) {
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#ifdef MOZ_SVG
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#endif
|
||||
#include "nsExpirationTracker.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsIPresShell;
|
||||
|
@ -213,7 +214,7 @@ public:
|
|||
nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState);
|
||||
PRBool IsLTR() const;
|
||||
PRBool IsScrollbarOnRight() const;
|
||||
PRBool IsScrollingActive() { return mScrollingActive; }
|
||||
PRBool IsScrollingActive() const;
|
||||
// adjust the scrollbar rectangle aRect to account for any visible resizer.
|
||||
// aHasResizer specifies if there is a content resizer, however this method
|
||||
// will also check if a widget resizer is present as well.
|
||||
|
@ -227,6 +228,10 @@ public:
|
|||
const nsRect& aContentArea,
|
||||
const nsRect& aOldScrollArea);
|
||||
|
||||
PRBool IsAlwaysActive() const;
|
||||
void MarkActive();
|
||||
nsExpirationState* GetExpirationState() { return &mActivityExpirationState; }
|
||||
|
||||
// owning references to the nsIAnonymousContentCreator-built content
|
||||
nsCOMPtr<nsIContent> mHScrollbarContent;
|
||||
nsCOMPtr<nsIContent> mVScrollbarContent;
|
||||
|
@ -253,6 +258,8 @@ public:
|
|||
nsPoint mRestorePos;
|
||||
nsPoint mLastPos;
|
||||
|
||||
nsExpirationState mActivityExpirationState;
|
||||
|
||||
PRPackedBool mNeverHasVerticalScrollbar:1;
|
||||
PRPackedBool mNeverHasHorizontalScrollbar:1;
|
||||
PRPackedBool mHasVerticalScrollbar:1;
|
||||
|
|
|
@ -259,12 +259,20 @@ template <class T, PRUint32 K> class nsExpirationTracker {
|
|||
|
||||
friend class Iterator;
|
||||
|
||||
PRBool IsEmpty() {
|
||||
for (PRUint32 i = 0; i < K; ++i) {
|
||||
if (!mGenerations[i].IsEmpty())
|
||||
return PR_FALSE;
|
||||
}
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* This must be overridden to catch notifications. It is called whenever
|
||||
* we detect that an object has not been used for at least (K-1)*mTimerPeriod
|
||||
* seconds. If timer events are not delayed, it will be called within
|
||||
* roughly K*mTimerPeriod seconds after the last use. (Unless AgeOneGeneration
|
||||
* milliseconds. If timer events are not delayed, it will be called within
|
||||
* roughly K*mTimerPeriod milliseconds after the last use. (Unless AgeOneGeneration
|
||||
* or AgeAllGenerations have been called to accelerate the aging process.)
|
||||
*
|
||||
* NOTE: These bounds ignore delays in timer firings due to actual work being
|
||||
|
@ -298,13 +306,10 @@ template <class T, PRUint32 K> class nsExpirationTracker {
|
|||
nsExpirationTracker* tracker = static_cast<nsExpirationTracker*>(aThis);
|
||||
tracker->AgeOneGeneration();
|
||||
// Cancel the timer if we have no objects to track
|
||||
PRUint32 i;
|
||||
for (i = 0; i < K; ++i) {
|
||||
if (!tracker->mGenerations[i].IsEmpty())
|
||||
return;
|
||||
if (tracker->IsEmpty()) {
|
||||
tracker->mTimer->Cancel();
|
||||
tracker->mTimer = nsnull;
|
||||
}
|
||||
tracker->mTimer->Cancel();
|
||||
tracker->mTimer = nsnull;
|
||||
}
|
||||
|
||||
nsresult CheckStartTimer() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче