Bug 1484780 - Cache gfx::Path to avoid building and flattening path at each restyle cycle. r=heycam

In most cases, we run an animation on an object by changing its
offset-distance/offset-rotate, but keep its offset-path the same.
Building and flattening the path is sometime expensive, especially for
large path, so caching it makes sense to us and have a significant
performance improvement. This is for the main thread motion path
animations.

Note: Even though we support compositor animations for motion path,
nsIFrame::GetTransformMatrix() is still called during the animations for
other usages, so we may still build the gfx::Path on the main thread
without this patch, so this improvement becomes necessary for most cases.

Differential Revision: https://phabricator.services.mozilla.com/D46667

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Boris Chiou 2019-11-07 03:17:58 +00:00
Родитель 21a6f50b1a
Коммит abda0eb288
3 изменённых файлов: 30 добавлений и 10 удалений

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

@ -439,17 +439,10 @@ static OffsetPathData GenerateOffsetPathData(const nsIFrame* aFrame) {
const StyleOffsetPath& path = aFrame->StyleDisplay()->mOffsetPath;
switch (path.tag) {
case StyleOffsetPath::Tag::Path: {
// Here we only need to build a valid path for motion path, so
// using the default values of stroke-width, stoke-linecap, and fill-rule
// is fine for now because what we want is get the point and its normal
// vector along the path, instead of rendering it.
// FIXME: Use cache for main-thread in Bug 1484780.
RefPtr<gfx::PathBuilder> builder =
gfxPlatform::GetPlatform()
->ScreenReferenceDrawTarget()
->CreatePathBuilder(gfx::FillRule::FILL_WINDING);
RefPtr<gfx::Path> gfxPath =
MotionPathUtils::BuildPath(path.AsPath(), builder);
aFrame->GetProperty(nsIFrame::OffsetPathCache());
MOZ_ASSERT(gfxPath,
"Should have a valid cached gfx::Path for offset-path");
return OffsetPathData::Path(path.AsPath(), gfxPath.forget());
}
case StyleOffsetPath::Tag::Ray:

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

@ -112,6 +112,7 @@
#include "mozilla/ServoStyleSet.h"
#include "mozilla/ServoStyleSetInlines.h"
#include "mozilla/css/ImageLoader.h"
#include "mozilla/dom/SVGPathData.h"
#include "mozilla/dom/TouchEvent.h"
#include "mozilla/gfx/Tools.h"
#include "mozilla/layers/WebRenderUserData.h"
@ -1335,6 +1336,30 @@ void nsFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
PresContext()->SetBidiEnabled();
}
// The following part is for caching offset-path:path(). We cache the
// flatten gfx path, so we don't have to rebuild and re-flattern it at
// each cycle if we have animations on offset-* with a fixed offset-path.
const StyleOffsetPath* oldPath =
aOldComputedStyle ? &aOldComputedStyle->StyleDisplay()->mOffsetPath
: nullptr;
const StyleOffsetPath& newPath = StyleDisplay()->mOffsetPath;
if (!oldPath || *oldPath != newPath) {
if (newPath.IsPath()) {
// Here we only need to build a valid path for motion path, so
// using the default values of stroke-width, stoke-linecap, and fill-rule
// is fine for now because what we want is to get the point and its normal
// vector along the path, instead of rendering it.
RefPtr<gfx::PathBuilder> builder =
gfxPlatform::GetPlatform()
->ScreenReferenceDrawTarget()
->CreatePathBuilder(gfx::FillRule::FILL_WINDING);
SetProperty(nsIFrame::OffsetPathCache(),
MotionPathUtils::BuildPath(newPath.AsPath(), builder).take());
} else if (oldPath) {
DeleteProperty(nsIFrame::OffsetPathCache());
}
}
RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS | NS_FRAME_SIMPLE_DISPLAYLIST);
mMayHaveRoundedCorners = true;

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

@ -1257,6 +1257,8 @@ class nsIFrame : public nsQueryFrame {
NS_DECLARE_FRAME_PROPERTY_WITHOUT_DTOR(PlaceholderFrameProperty,
nsPlaceholderFrame)
NS_DECLARE_FRAME_PROPERTY_RELEASABLE(OffsetPathCache, mozilla::gfx::Path)
mozilla::FrameBidiData GetBidiData() const {
bool exists;
mozilla::FrameBidiData bidiData = GetProperty(BidiDataProperty(), &exists);