gecko-dev/layout/xul/nsImageBoxFrame.h
Andrew Osmond 19dc40f412 Bug 1464927 - Make nsImageBoxFrame fallback from WebRender consistently with nsImageFrame. r=tnikkel
Vector images don't support image containers if they are animated. In
order to support this with WebRender, we would need to know when the
generated shared surface was composited, so that we can update the image
container on the next refresh tick. Because images use a different code
path (not ImageClient), we don't have the ability at present. Changing
vector images naively and just updating on every refresh tick if there
is an image container to avoid fallback causes the animation to be very
janky.

Given nsImageFrame is already using fallback properly in this situation,
then we can just fix nsImageBoxFrame to do the same. This gives
acceptable performance without any visible slowness on the animation.
2018-06-22 09:32:27 -04:00

187 lines
6.8 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsImageBoxFrame_h___
#define nsImageBoxFrame_h___
#include "mozilla/Attributes.h"
#include "nsLeafBoxFrame.h"
#include "imgILoader.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
class imgRequestProxy;
class nsImageBoxFrame;
class nsDisplayXULImage;
class nsImageBoxListener final : public imgINotificationObserver
{
public:
explicit nsImageBoxListener(nsImageBoxFrame *frame);
NS_DECL_ISUPPORTS
NS_DECL_IMGINOTIFICATIONOBSERVER
void ClearFrame() { mFrame = nullptr; }
private:
virtual ~nsImageBoxListener();
nsImageBoxFrame *mFrame;
};
class nsImageBoxFrame final : public nsLeafBoxFrame
{
public:
typedef mozilla::image::ImgDrawResult ImgDrawResult;
typedef mozilla::layers::ImageContainer ImageContainer;
typedef mozilla::layers::LayerManager LayerManager;
friend class nsDisplayXULImage;
NS_DECL_FRAMEARENA_HELPERS(nsImageBoxFrame)
virtual nsSize GetXULPrefSize(nsBoxLayoutState& aBoxLayoutState) override;
virtual nsSize GetXULMinSize(nsBoxLayoutState& aBoxLayoutState) override;
virtual nscoord GetXULBoxAscent(nsBoxLayoutState& aBoxLayoutState) override;
virtual void MarkIntrinsicISizesDirty() override;
nsresult Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData);
friend nsIFrame* NS_NewImageBoxFrame(nsIPresShell* aPresShell, ComputedStyle* aStyle);
virtual void Init(nsIContent* aContent,
nsContainerFrame* aParent,
nsIFrame* asPrevInFlow) override;
virtual nsresult AttributeChanged(int32_t aNameSpaceID,
nsAtom* aAttribute,
int32_t aModType) override;
virtual void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
virtual void DestroyFrom(nsIFrame* aDestructRoot, PostDestroyData& aPostDestroyData) override;
#ifdef DEBUG_FRAME_DUMP
virtual nsresult GetFrameName(nsAString& aResult) const override;
#endif
/**
* Update mUseSrcAttr from appropriate content attributes or from
* style, throw away the current image, and load the appropriate
* image.
* */
void UpdateImage();
/**
* Update mLoadFlags from content attributes. Does not attempt to reload the
* image using the new load flags.
*/
void UpdateLoadFlags();
virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
virtual ~nsImageBoxFrame();
already_AddRefed<imgIContainer> GetImageContainerForPainting(const nsPoint& aPt,
ImgDrawResult& aDrawResult,
Maybe<nsPoint>& aAnchorPoint,
nsRect& aDest);
ImgDrawResult PaintImage(gfxContext& aRenderingContext,
const nsRect& aDirtyRect,
nsPoint aPt, uint32_t aFlags);
Maybe<ImgDrawResult> CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayItem* aItem,
nsPoint aPt,
uint32_t aFlags);
bool CanOptimizeToImageLayer();
nsRect GetDestRect(const nsPoint& aOffset, Maybe<nsPoint>& aAnchorPoint);
protected:
explicit nsImageBoxFrame(ComputedStyle* aStyle);
virtual void GetImageSize();
private:
nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
nsresult OnDecodeComplete(imgIRequest* aRequest);
nsresult OnLoadComplete(imgIRequest* aRequest, nsresult aStatus);
nsresult OnImageIsAnimated(imgIRequest* aRequest);
nsresult OnFrameUpdate(imgIRequest* aRequest);
nsRect mSubRect; ///< If set, indicates that only the portion of the image specified by the rect should be used.
nsSize mIntrinsicSize;
nsSize mImageSize;
RefPtr<imgRequestProxy> mImageRequest;
nsCOMPtr<imgINotificationObserver> mListener;
int32_t mLoadFlags;
// Boolean variable to determine if the current image request has been
// registered with the refresh driver.
bool mRequestRegistered;
bool mUseSrcAttr; ///< Whether or not the image src comes from an attribute.
bool mSuppressStyleCheck;
}; // class nsImageBoxFrame
class nsDisplayXULImage final : public nsDisplayImageContainer
{
public:
nsDisplayXULImage(nsDisplayListBuilder* aBuilder,
nsImageBoxFrame* aFrame) :
nsDisplayImageContainer(aBuilder, aFrame) {
MOZ_COUNT_CTOR(nsDisplayXULImage);
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplayXULImage() {
MOZ_COUNT_DTOR(nsDisplayXULImage);
}
#endif
virtual bool CanOptimizeToImageLayer(LayerManager* aManager,
nsDisplayListBuilder* aBuilder) override;
virtual already_AddRefed<imgIContainer> GetImage() override;
virtual nsRect GetDestRect() const override;
virtual void UpdateDrawResult(mozilla::image::ImgDrawResult aResult) override
{
nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, aResult);
}
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override
{
*aSnap = true;
return nsRect(ToReferenceFrame(), Frame()->GetSize());
}
virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) override;
virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const override;
// Doesn't handle HitTest because nsLeafBoxFrame already creates an
// event receiver for us
virtual void Paint(nsDisplayListBuilder* aBuilder,
gfxContext* aCtx) override;
virtual bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const StackingContextHelper& aSc,
mozilla::layers::WebRenderLayerManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override;
NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE)
};
#endif /* nsImageBoxFrame_h___ */