Bug 1257315 (Part 1) - Add a visualization of visibility tracking to the APZ minimap. r=botond,mattwoodrow

This commit is contained in:
Seth Fowler 2016-03-18 18:38:57 -07:00
Родитель 996c2cdf8c
Коммит d8b3579dd9
13 изменённых файлов: 267 добавлений и 10 удалений

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

@ -539,6 +539,8 @@ public:
static TabChild* GetFrom(nsIPresShell* aPresShell);
static TabChild* GetFrom(uint64_t aLayersId);
uint64_t LayersId() { return mLayersId; }
void DidComposite(uint64_t aTransactionId,
const TimeStamp& aCompositeStart,
const TimeStamp& aCompositeEnd);

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

@ -8,6 +8,7 @@
#include <stdint.h> // for uint32_t, uint64_t
#include "Units.h" // for CSSRect, CSSPixel, etc
#include "mozilla/HashFunctions.h" // for HashGeneric
#include "mozilla/Maybe.h"
#include "mozilla/gfx/BasePoint.h" // for BasePoint
#include "mozilla/gfx/Rect.h" // for RoundedIn
@ -866,6 +867,11 @@ struct ScrollableLayerGuid {
}
return false;
}
uint32_t Hash() const
{
return HashGeneric(mLayersId, mPresShellId, mScrollId);
}
};
template <int LogLevel>

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

@ -496,11 +496,12 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
const int verticalPadding = 10;
const int horizontalPadding = 5;
gfx::Color backgroundColor(0.3f, 0.3f, 0.3f, 0.3f);
gfx::Color tileActiveColor(1, 1, 1, 0.5f);
gfx::Color tileActiveColor(1, 1, 1, 0.4f);
gfx::Color tileBorderColor(0, 0, 0, 0.1f);
gfx::Color pageBorderColor(0, 0, 0);
gfx::Color displayPortColor(0, 1.f, 0);
gfx::Color viewPortColor(0, 0, 1.f);
gfx::Color viewPortColor(0, 0, 1.f, 0.3f);
gfx::Color visibilityColor(1.f, 0, 0);
// Rects
const FrameMetrics& fm = aLayer->GetFrameMetrics(0);
@ -551,12 +552,45 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager,
}
*/
// Render the scrollable area.
r = transform.TransformBounds(scrollRect.ToUnknownRect());
compositor->SlowDrawRect(r, pageBorderColor, clipRect, aContainer->GetEffectiveTransform());
// If enabled, render information about visibility.
if (gfxPrefs::APZMinimapVisibilityEnabled()) {
// Retrieve the APZC scrollable layer guid, which we'll use to get the
// appropriate visibility information from the layer manager.
AsyncPanZoomController* controller = aLayer->GetAsyncPanZoomController(0);
MOZ_ASSERT(controller);
ScrollableLayerGuid guid = controller->GetGuid();
// Get the approximately visible region.
static CSSIntRegion emptyRegion;
CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid);
if (!visibleRegion) {
visibleRegion = &emptyRegion;
}
// Iterate through and draw the rects in the region.
for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter();
!iterator.Done();
iterator.Next())
{
CSSIntRect rect = iterator.Get();
LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel();
Rect r = transform.TransformBounds(scaledRect.ToUnknownRect());
compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform());
}
}
// Render the displayport.
r = transform.TransformBounds(dp.ToUnknownRect());
compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform());
r = transform.TransformBounds(dp.ToUnknownRect());
compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform());
// Render the viewport.
r = transform.TransformBounds(viewRect.ToUnknownRect());
compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2);
}

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

@ -220,6 +220,20 @@ public:
mInvalidRegion.Or(mInvalidRegion, aRegion);
}
void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion)
{
CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid);
MOZ_ASSERT(regionForScrollFrame);
*regionForScrollFrame = aRegion;
}
CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid)
{
return mVisibleRegions.Get(aGuid);
}
Compositor* GetCompositor() const
{
return mCompositor;
@ -355,6 +369,11 @@ private:
gfx::IntRect mTargetBounds;
nsIntRegion mInvalidRegion;
typedef nsClassHashtable<nsGenericHashKey<ScrollableLayerGuid>,
CSSIntRegion> VisibleRegions;
VisibleRegions mVisibleRegions;
UniquePtr<FPSState> mFPS;
bool mInTransaction;

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

@ -704,6 +704,17 @@ CompositorChild::SendRequestNotifyAfterRemotePaint()
return PCompositorChild::SendRequestNotifyAfterRemotePaint();
}
bool
CompositorChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion)
{
MOZ_ASSERT(mCanSend);
if (!mCanSend) {
return true;
}
return PCompositorChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion);
}
} // namespace layers
} // namespace mozilla

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

@ -126,6 +126,8 @@ public:
bool SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray<float>* intervals);
bool SendNotifyRegionInvalidated(const nsIntRegion& region);
bool SendRequestNotifyAfterRemotePaint();
bool SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const mozilla::CSSIntRegion& aRegion);
private:
// Private destructor, to discourage deletion outside of Release():

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

@ -938,6 +938,19 @@ CompositorParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex,
return true;
}
bool
CompositorParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion)
{
if (mLayerManager) {
mLayerManager->UpdateApproximatelyVisibleRegion(aGuid, aRegion);
// We need to recomposite to update the minimap.
ScheduleComposition();
}
return true;
}
void
CompositorParent::ActorDestroy(ActorDestroyReason why)
{
@ -1931,6 +1944,21 @@ public:
virtual bool RecvNotifyRegionInvalidated(const nsIntRegion& aRegion) override { return true; }
virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; }
virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray<float>* intervals) override { return true; }
virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion) override
{
CompositorParent* parent;
{ // scope lock
MonitorAutoLock lock(*sIndirectLayerTreesLock);
parent = sIndirectLayerTrees[aGuid.mLayersId].mParent;
}
if (parent) {
return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion);
}
return true;
}
virtual bool RecvGetTileSize(int32_t* aWidth, int32_t* aHeight) override
{
*aWidth = gfxPlatform::GetPlatform()->GetTileWidth();

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

@ -251,6 +251,9 @@ public:
// @see CrossProcessCompositorParent::RecvRequestNotifyAfterRemotePaint
virtual bool RecvRequestNotifyAfterRemotePaint() override { return true; };
virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid,
const CSSIntRegion& aRegion) override;
virtual void ActorDestroy(ActorDestroyReason why) override;
virtual void ShadowLayersUpdated(LayerTransactionParent* aLayerTree,

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

@ -17,10 +17,12 @@ using struct mozilla::layers::TextureFactoryIdentifier from "mozilla/layers/Comp
using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h";
using mozilla::layers::MaybeZoomConstraints from "FrameMetrics.h";
using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
using mozilla::layers::LayersBackend from "mozilla/layers/LayersTypes.h";
using mozilla::layers::TouchBehaviorFlags from "mozilla/layers/APZUtils.h";
using mozilla::CrossProcessMutexHandle from "mozilla/ipc/CrossProcessMutex.h";
using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
using mozilla::CSSIntRegion from "Units.h";
using mozilla::LayoutDeviceIntPoint from "Units.h";
using mozilla::LayoutDeviceIntRegion from "Units.h";
using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
@ -178,6 +180,11 @@ parent:
*/
async RequestNotifyAfterRemotePaint();
// The child sends a region containing rects associated with the provided
// scrollable layer GUID that the child considers 'approximately visible'.
// We visualize this information in the APZ minimap.
async NotifyApproximatelyVisibleRegion(ScrollableLayerGuid guid, CSSIntRegion region);
child:
// Send back Compositor Frame Metrics from APZCs so tiled layers can
// update progressively.

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

@ -167,6 +167,7 @@ private:
DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5);
DECL_GFX_PREF(Live, "apz.min_skate_speed", APZMinSkateSpeed, float, 1.0f);
DECL_GFX_PREF(Live, "apz.minimap.enabled", APZMinimap, bool, false);
DECL_GFX_PREF(Live, "apz.minimap.visibility.enabled", APZMinimapVisibilityEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.overscroll.enabled", APZOverscrollEnabled, bool, false);
DECL_GFX_PREF(Live, "apz.overscroll.min_pan_distance_ratio", APZMinPanDistanceRatio, float, 1.0f);
DECL_GFX_PREF(Live, "apz.overscroll.spring_friction", APZOverscrollSpringFriction, float, 0.015f);

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

@ -159,6 +159,7 @@
#endif
#include "mozilla/layers/CompositorChild.h"
#include "GeckoProfiler.h"
#include "gfxPlatform.h"
#include "Layers.h"
@ -5530,13 +5531,65 @@ PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll)
}
}
static void
AddFrameToVisibleRegions(nsIFrame* aFrame,
nsViewManager* aViewManager,
Maybe<VisibleRegions>& aVisibleRegions)
{
if (!aVisibleRegions) {
return;
}
MOZ_ASSERT(aFrame);
MOZ_ASSERT(aViewManager);
// Retrieve the view ID for this frame (which we obtain from the enclosing
// scrollable frame).
nsIScrollableFrame* scrollableFrame =
nsLayoutUtils::GetNearestScrollableFrame(aFrame,
nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE |
nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT);
if (!scrollableFrame) {
return;
}
nsIFrame* scrollableFrameAsFrame = do_QueryFrame(scrollableFrame);
MOZ_ASSERT(scrollableFrameAsFrame);
nsIContent* scrollableFrameContent = scrollableFrameAsFrame->GetContent();
if (!scrollableFrameContent) {
return;
}
ViewID viewID;
if (!nsLayoutUtils::FindIDFor(scrollableFrameContent, &viewID)) {
return ;
}
// Update the visible region for the appropriate view ID.
nsRect frameRectInScrolledFrameSpace = aFrame->GetVisualOverflowRect();
nsLayoutUtils::TransformResult result =
nsLayoutUtils::TransformRect(aFrame,
scrollableFrame->GetScrolledFrame(),
frameRectInScrolledFrameSpace);
if (result != nsLayoutUtils::TransformResult::TRANSFORM_SUCCEEDED) {
return;
}
CSSIntRegion* regionForView = aVisibleRegions->LookupOrAdd(viewID);
MOZ_ASSERT(regionForView);
regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace));
}
/* static */ void
PresShell::MarkImagesInListVisible(const nsDisplayList& aList)
PresShell::MarkImagesInListVisible(const nsDisplayList& aList,
Maybe<VisibleRegions>& aVisibleRegions)
{
for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) {
nsDisplayList* sublist = item->GetChildren();
if (sublist) {
MarkImagesInListVisible(*sublist);
MarkImagesInListVisible(*sublist, aVisibleRegions);
continue;
}
nsIFrame* f = item->Frame();
@ -5553,6 +5606,8 @@ PresShell::MarkImagesInListVisible(const nsDisplayList& aList)
// content was added to mVisibleImages, so we need to increment its visible count
content->IncrementVisibleCount();
}
AddFrameToVisibleRegions(f, presShell->mViewManager, aVisibleRegions);
}
}
}
@ -5611,6 +5666,53 @@ DecrementVisibleCount(nsTHashtable<nsRefPtrHashKey<nsIImageLoadingContent>>& aIm
}
}
static void
NotifyCompositorOfVisibleRegionsChange(PresShell* aPresShell,
const Maybe<VisibleRegions>& aRegions)
{
if (!aRegions) {
return;
}
MOZ_ASSERT(aPresShell);
// Retrieve the layers ID and pres shell ID.
TabChild* tabChild = TabChild::GetFrom(aPresShell);
if (!tabChild) {
return;
}
const uint64_t layersId = tabChild->LayersId();
const uint32_t presShellId = aPresShell->GetPresShellId();
// Retrieve the CompositorChild.
LayerManager* layerManager = aPresShell->GetLayerManager();
if (!layerManager) {
return;
}
ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager();
if (!clientLayerManager) {
return;
}
CompositorChild* compositorChild = clientLayerManager->GetCompositorChild();
if (!compositorChild) {
return;
}
// Send the approximately visible regions to the compositor.
for (auto iter = aRegions->ConstIter(); !iter.Done(); iter.Next()) {
const ViewID viewId = iter.Key();
const CSSIntRegion* region = iter.UserData();
MOZ_ASSERT(region);
const ScrollableLayerGuid guid(layersId, presShellId, viewId);
compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region);
}
}
void
PresShell::RebuildImageVisibilityDisplayList(const nsDisplayList& aList)
{
@ -5620,9 +5722,22 @@ PresShell::RebuildImageVisibilityDisplayList(const nsDisplayList& aList)
// oldVisibleImages.
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > oldVisibleImages;
mVisibleImages.SwapElements(oldVisibleImages);
MarkImagesInListVisible(aList);
// If we're visualizing visible regions, create a VisibleRegions object to
// store information about them. The functions we call will populate this
// object and send it to the compositor only if it's Some(), so we don't
// need to check the prefs everywhere.
Maybe<VisibleRegions> visibleRegions;
if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
visibleRegions.emplace();
}
MarkImagesInListVisible(aList, visibleRegions);
DecrementVisibleCount(oldVisibleImages,
nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION, this);
NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
}
/* static */ void
@ -5656,6 +5771,7 @@ PresShell::ClearVisibleImagesList(uint32_t aNonvisibleAction)
void
PresShell::MarkImagesInSubtreeVisible(nsIFrame* aFrame,
const nsRect& aRect,
Maybe<VisibleRegions>& aVisibleRegions,
bool aRemoveOnly /* = false */)
{
MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell");
@ -5669,6 +5785,8 @@ PresShell::MarkImagesInSubtreeVisible(nsIFrame* aFrame,
// content was added to mVisibleImages, so we need to increment its visible count
content->IncrementVisibleCount();
}
AddFrameToVisibleRegions(aFrame, mViewManager, aVisibleRegions);
}
nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame);
@ -5737,7 +5855,7 @@ PresShell::MarkImagesInSubtreeVisible(nsIFrame* aFrame,
}
}
}
MarkImagesInSubtreeVisible(child, r);
MarkImagesInSubtreeVisible(child, r, aVisibleRegions);
}
}
}
@ -5764,14 +5882,26 @@ PresShell::RebuildImageVisibility(nsRect* aRect,
nsTHashtable< nsRefPtrHashKey<nsIImageLoadingContent> > oldVisibleImages;
mVisibleImages.SwapElements(oldVisibleImages);
// If we're visualizing visible regions, create a VisibleRegions object to
// store information about them. The functions we call will populate this
// object and send it to the compositor only if it's Some(), so we don't
// need to check the prefs everywhere.
Maybe<VisibleRegions> visibleRegions;
if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) {
visibleRegions.emplace();
}
nsRect vis(nsPoint(0, 0), rootFrame->GetSize());
if (aRect) {
vis = *aRect;
}
MarkImagesInSubtreeVisible(rootFrame, vis, aRemoveOnly);
MarkImagesInSubtreeVisible(rootFrame, vis, visibleRegions, aRemoveOnly);
DecrementVisibleCount(oldVisibleImages,
nsIImageLoadingContent::ON_NONVISIBLE_NO_ACTION, this);
NotifyCompositorOfVisibleRegionsChange(this, visibleRegions);
}
void

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

@ -52,7 +52,14 @@ class nsPresShellEventCB;
class nsAutoCauseReflowNotifier;
namespace mozilla {
class EventDispatchingCallback;
// A hash table type for tracking visible regions, for use by the visibility
// code in PresShell. The mapping is from view IDs to regions in the
// coordinate system of that view's scrolled frame.
typedef nsClassHashtable<nsUint64HashKey, mozilla::CSSIntRegion> VisibleRegions;
} // namespace mozilla
// 250ms. This is actually pref-controlled, but we use this value if we fail
@ -65,6 +72,9 @@ class PresShell final : public nsIPresShell,
public nsIObserver,
public nsSupportsWeakReference
{
template <typename T> using Maybe = mozilla::Maybe<T>;
using VisibleRegions = mozilla::VisibleRegions;
public:
PresShell();
@ -468,7 +478,7 @@ protected:
: mResolution(aPresShell->mResolution)
, mRenderFlags(aPresShell->mRenderFlags)
{ }
mozilla::Maybe<float> mResolution;
Maybe<float> mResolution;
RenderFlags mRenderFlags;
};
@ -740,8 +750,11 @@ protected:
void ClearVisibleImagesList(uint32_t aNonvisibleAction);
static void ClearImageVisibilityVisited(nsView* aView, bool aClear);
static void MarkImagesInListVisible(const nsDisplayList& aList);
void MarkImagesInSubtreeVisible(nsIFrame* aFrame, const nsRect& aRect,
static void MarkImagesInListVisible(const nsDisplayList& aList,
Maybe<VisibleRegions>& aVisibleRegions);
void MarkImagesInSubtreeVisible(nsIFrame* aFrame,
const nsRect& aRect,
Maybe<VisibleRegions>& aVisibleRegions,
bool aRemoveOnly = false);
// Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent.

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

@ -585,6 +585,7 @@ pref("apz.max_velocity_inches_per_ms", "-1.0");
pref("apz.max_velocity_queue_size", 5);
pref("apz.min_skate_speed", "1.0");
pref("apz.minimap.enabled", false);
pref("apz.minimap.visibility.enabled", false);
pref("apz.overscroll.enabled", false);
pref("apz.overscroll.min_pan_distance_ratio", "1.0");
pref("apz.overscroll.spring_friction", "0.015");