Bug 1814398 - SVGImageElement should not derive from SVGGeometryElement r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D168674
This commit is contained in:
Robert Longson
2023-02-16 08:56:46 +00:00
parent cecd32f5be
commit 32dd1416bc
10 changed files with 267 additions and 87 deletions

View File

@@ -252,13 +252,10 @@ SVGImageElement::IsAttributeMapped(const nsAtom* name) const {
}
//----------------------------------------------------------------------
// SVGGeometryElement methods
// SVGImageElement methods
/* For the purposes of the update/invalidation logic pretend to
be a rectangle. */
bool SVGImageElement::GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
void SVGImageElement::GetGeometryBounds(Rect* aBounds,
const Matrix& aToBoundsSpace) {
Rect rect;
DebugOnly<bool> ok =
@@ -273,16 +270,6 @@ bool SVGImageElement::GetGeometryBounds(
}
*aBounds = aToBoundsSpace.TransformBounds(rect);
return true;
}
already_AddRefed<Path> SVGImageElement::BuildPath(PathBuilder* aBuilder) {
// To get bound, the faster method GetGeometryBounds() should already return
// success. For render and hittest, SVGImageFrame should have its own
// implementation that doesn't need to build path for an image.
MOZ_ASSERT_UNREACHABLE(
"There is no reason to call BuildPath for SVGImageElement");
return nullptr;
}
//----------------------------------------------------------------------

View File

@@ -12,6 +12,7 @@
#include "mozilla/dom/SVGAnimatedString.h"
#include "mozilla/dom/SVGGeometryElement.h"
#include "mozilla/dom/SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/gfx/2D.h"
nsresult NS_NewSVGImageElement(
nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
@@ -22,7 +23,7 @@ class SVGImageFrame;
namespace dom {
class DOMSVGAnimatedPreserveAspectRatio;
using SVGImageElementBase = SVGGeometryElement;
using SVGImageElementBase = SVGGraphicsElement;
class SVGImageElement : public SVGImageElementBase,
public nsImageLoadingContent {
@@ -54,11 +55,6 @@ class SVGImageElement : public SVGImageElementBase,
nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
bool IsNodeOfType(uint32_t aFlags) const override {
// <image> is not really a SVGGeometryElement, we should
// ignore eSHAPE flag accepted by SVGGeometryElement.
return SVGGraphicsElement::IsNodeOfType(aFlags);
}
nsresult BindToTree(BindContext&, nsINode& aParent) override;
void UnbindFromTree(bool aNullParent) override;
@@ -69,13 +65,6 @@ class SVGImageElement : public SVGImageElementBase,
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override;
// SVGGeometryElement methods:
bool GetGeometryBounds(
Rect* aBounds, const StrokeOptions& aStrokeOptions,
const Matrix& aToBoundsSpace,
const Matrix* aToNonScalingStrokeSpace = nullptr) override;
already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
// SVGSVGElement methods:
bool HasValidDimensions() const override;
@@ -91,6 +80,8 @@ class SVGImageElement : public SVGImageElementBase,
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
already_AddRefed<DOMSVGAnimatedString> Href();
void GetGeometryBounds(gfx::Rect* aBounds, const gfx::Matrix& aToBoundsSpace);
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
SetAttr(nsGkAtoms::decoding, aDecoding, aError);
}

View File

@@ -12,6 +12,7 @@
#include "mozilla/ProfilerLabels.h"
#include "mozilla/StaticPrefs_gfx.h"
#include "mozilla/SVGGeometryFrame.h"
#include "mozilla/SVGImageFrame.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
@@ -1125,6 +1126,26 @@ static ItemActivity HasActiveChildren(
return activity;
}
static ItemActivity AssessBounds(
const mozilla::layers::StackingContextHelper& aSc, const nsRect& aBounds) {
// Arbitrary threshold up for adjustments. What we want to avoid here
// is alternating between active and non active items and create a lot
// of overlapping blobs, so we only make images active if they are
// costly enough that it's worth the risk of having more layers. As we
// move more blob items into wr display items it will become less of a
// concern.
constexpr float largeish = 512;
float width = aBounds.width * aSc.GetInheritedScale().xScale;
float height = aBounds.height * aSc.GetInheritedScale().yScale;
if (width > largeish || height > largeish) {
return ItemActivity::Should;
}
return ItemActivity::Could;
}
// This function decides whether we want to treat this item as "active", which
// means that it's a container item which we will turn into a WebRender
// StackingContext, or whether we treat it as "inactive" and include it inside
@@ -1175,29 +1196,28 @@ static ItemActivity IsItemProbablyActive(
}
case DisplayItemType::TYPE_SVG_GEOMETRY: {
auto* svgItem = static_cast<DisplaySVGGeometry*>(aItem);
if (StaticPrefs::gfx_webrender_svg_shapes() && aUniformlyScaled &&
svgItem->ShouldBeActive(aBuilder, aResources, aSc, aManager,
aDisplayListBuilder)) {
if (aHasActivePrecedingSibling) {
return ItemActivity::Should;
}
bool snap = false;
return AssessBounds(aSc, aItem->GetBounds(aDisplayListBuilder, &snap));
}
return ItemActivity::No;
}
case DisplayItemType::TYPE_SVG_IMAGE: {
auto* svgItem = static_cast<DisplaySVGImage*>(aItem);
if (StaticPrefs::gfx_webrender_svg_images() && aUniformlyScaled &&
svgItem->ShouldBeActive(aBuilder, aResources, aSc, aManager,
aDisplayListBuilder)) {
bool snap = false;
auto bounds = aItem->GetBounds(aDisplayListBuilder, &snap);
// Arbitrary threshold up for adjustments. What we want to avoid here
// is alternating between active and non active items and create a lot
// of overlapping blobs, so we only make images active if they are
// costly enough that it's worth the risk of having more layers. As we
// move more blob items into wr dislplay items it will become less of a
// concern.
const int32_t largeish = 512;
float width = bounds.width * aSc.GetInheritedScale().xScale;
float height = bounds.height * aSc.GetInheritedScale().yScale;
if (aHasActivePrecedingSibling || width > largeish ||
height > largeish) {
if (aHasActivePrecedingSibling) {
return ItemActivity::Should;
}
return ItemActivity::Could;
bool snap = false;
return AssessBounds(aSc, aItem->GetBounds(aDisplayListBuilder, &snap));
}
return ItemActivity::No;

View File

@@ -75,6 +75,7 @@ DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT,
DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION,
TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, TYPE_IS_CONTENTFUL)
DECLARE_DISPLAY_ITEM_TYPE(SVG_IMAGE, TYPE_IS_CONTENTFUL)
DECLARE_DISPLAY_ITEM_TYPE(SVG_TEXT, TYPE_IS_CONTENTFUL)
DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, TYPE_IS_CONTAINER)
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)

View File

@@ -171,9 +171,9 @@ void SVGGeometryFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return;
}
const auto* styleSVG = StyleSVG();
if (Type() != LayoutFrameType::SVGImage && styleSVG->mFill.kind.IsNone() &&
styleSVG->mStroke.kind.IsNone() && styleSVG->mMarkerEnd.IsNone() &&
styleSVG->mMarkerMid.IsNone() && styleSVG->mMarkerStart.IsNone()) {
if (styleSVG->mFill.kind.IsNone() && styleSVG->mStroke.kind.IsNone() &&
styleSVG->mMarkerEnd.IsNone() && styleSVG->mMarkerMid.IsNone() &&
styleSVG->mMarkerStart.IsNone()) {
return;
}
@@ -705,10 +705,6 @@ bool SVGGeometryFrame::IsInvisible() const {
return true;
}
if (IsSVGImageFrame()) {
return false;
}
const nsStyleSVG* style = StyleSVG();
SVGContextPaint* contextPaint =
SVGContextPaint::GetContextPaint(GetContent());

View File

@@ -97,7 +97,7 @@ class SVGGeometryFrame : public nsIFrame, public ISVGDisplayableFrame {
bool IsInvisible() const;
protected:
private:
// ISVGDisplayableFrame interface:
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
imgDrawingParams& aImgParams,
@@ -115,14 +115,13 @@ class SVGGeometryFrame : public nsIFrame, public ISVGDisplayableFrame {
* into account the type of element and the value of the 'pointer-events'
* property on the element.
*/
virtual uint16_t GetHitTestFlags();
uint16_t GetHitTestFlags();
private:
enum { eRenderFill = 1, eRenderStroke = 2 };
void Render(gfxContext* aContext, uint32_t aRenderComponents,
const gfxMatrix& aTransform, imgDrawingParams& aImgParams);
virtual bool CreateWebRenderCommands(
bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
@@ -180,7 +179,7 @@ class DisplaySVGGeometry final : public nsPaintedDisplayItem {
/*aDryRun=*/true);
}
virtual bool CreateWebRenderCommands(
bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,

View File

@@ -20,7 +20,6 @@
#include "nsLayoutUtils.h"
#include "imgINotificationObserver.h"
#include "SVGGeometryProperty.h"
#include "SVGGeometryFrame.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_image.h"
#include "mozilla/SVGContentUtils.h"
@@ -57,9 +56,44 @@ class SVGImageListener final : public imgINotificationObserver {
// ---------------------------------------------------------------------
// nsQueryFrame methods
NS_QUERYFRAME_HEAD(SVGImageFrame)
NS_QUERYFRAME_ENTRY(ISVGDisplayableFrame)
NS_QUERYFRAME_ENTRY(SVGImageFrame)
NS_QUERYFRAME_TAIL_INHERITING(SVGGeometryFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsIFrame)
void DisplaySVGImage::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect, HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) {
auto* frame = static_cast<SVGImageFrame*>(mFrame);
nsPoint pointRelativeToReferenceFrame = aRect.Center();
// ToReferenceFrame() includes frame->GetPosition(), our user space position.
nsPoint userSpacePtInAppUnits = pointRelativeToReferenceFrame -
(ToReferenceFrame() - frame->GetPosition());
gfxPoint userSpacePt =
gfxPoint(userSpacePtInAppUnits.x, userSpacePtInAppUnits.y) /
AppUnitsPerCSSPixel();
if (frame->GetFrameForPoint(userSpacePt)) {
aOutFrames->AppendElement(frame);
}
}
void DisplaySVGImage::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
uint32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
// ToReferenceFrame includes our mRect offset, but painting takes
// account of that too. To avoid double counting, we subtract that
// here.
nsPoint offset = ToReferenceFrame() - mFrame->GetPosition();
gfxPoint devPixelOffset =
nsLayoutUtils::PointToGfxPoint(offset, appUnitsPerDevPixel);
gfxMatrix tm = SVGUtils::GetCSSPxToDevPxMatrix(mFrame) *
gfxMatrix::Translation(devPixelOffset);
imgDrawingParams imgParams(aBuilder->GetImageDecodeFlags());
static_cast<SVGImageFrame*>(mFrame)->PaintSVG(*aCtx, tm, imgParams);
}
} // namespace mozilla
@@ -91,7 +125,8 @@ void SVGImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
"Content is not an SVG image!");
SVGGeometryFrame::Init(aContent, aParent, aPrevInFlow);
AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
nsIFrame::Init(aContent, aParent, aPrevInFlow);
if (HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
// Non-display frames are likely to be patterns, masks or the like.
@@ -143,7 +178,7 @@ void SVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
/* virtual */
void SVGImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
SVGGeometryFrame::DidSetComputedStyle(aOldStyle);
nsIFrame::DidSetComputedStyle(aOldStyle);
if (!mImageContainer || !aOldStyle) {
return;
@@ -170,6 +205,11 @@ void SVGImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
// TODO(heycam): We should handle aspect-ratio, like nsImageFrame does.
}
bool SVGImageFrame::IsSVGTransformed(gfx::Matrix* aOwnTransform,
gfx::Matrix* aFromParentTransform) const {
return SVGUtils::IsSVGTransformed(this, aOwnTransform, aFromParentTransform);
}
//----------------------------------------------------------------------
// nsIFrame methods:
@@ -206,7 +246,7 @@ nsresult SVGImageFrame::AttributeChanged(int32_t aNameSpaceID,
}
}
return SVGGeometryFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
return nsIFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
void SVGImageFrame::OnVisibilityChange(
@@ -217,7 +257,7 @@ void SVGImageFrame::OnVisibilityChange(
imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
}
SVGGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
nsIFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
}
gfx::Matrix SVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
@@ -437,12 +477,44 @@ void SVGImageFrame::PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
}
}
void SVGImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) {
if (!static_cast<const SVGElement*>(GetContent())->HasValidDimensions()) {
return;
}
if (aBuilder->IsForPainting()) {
if (!IsVisibleForPainting()) {
return;
}
if (StyleEffects()->mOpacity == 0.0f) {
return;
}
aBuilder->BuildCompositorHitTestInfoIfNeeded(this,
aLists.BorderBackground());
}
DisplayOutline(aBuilder, aLists);
aLists.Content()->AppendNewToTop<DisplaySVGImage>(aBuilder, this);
}
bool SVGImageFrame::IsInvisible() const {
if (!StyleVisibility()->IsVisible()) {
return true;
}
// Anything below will round to zero later down the pipeline.
constexpr float opacity_threshold = 1.0 / 128.0;
return StyleEffects()->mOpacity <= opacity_threshold;
}
bool SVGImageFrame::CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder, DisplaySVGGeometry* aItem,
nsDisplayListBuilder* aDisplayListBuilder, DisplaySVGImage* aItem,
bool aDryRun) {
if (!StyleVisibility()->IsVisible()) {
return true;
@@ -712,10 +784,7 @@ nsIFrame* SVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) {
}
//----------------------------------------------------------------------
// SVGGeometryFrame methods:
// Lie about our fill/stroke so that covered region and hit detection work
// properly
// SVGImageFrame methods:
void SVGImageFrame::ReflowSVG() {
NS_ASSERTION(SVGUtils::OuterSVGIsCallingReflowSVG(this),
@@ -823,6 +892,36 @@ uint16_t SVGImageFrame::GetHitTestFlags() {
return flags;
}
void SVGImageFrame::NotifySVGChanged(uint32_t aFlags) {
MOZ_ASSERT(aFlags & (TRANSFORM_CHANGED | COORD_CONTEXT_CHANGED),
"Invalidation logic may need adjusting");
}
SVGBBox SVGImageFrame::GetBBoxContribution(const Matrix& aToBBoxUserspace,
uint32_t aFlags) {
SVGBBox bbox;
if (aToBBoxUserspace.IsSingular()) {
// XXX ReportToConsole
return bbox;
}
if ((aFlags & SVGUtils::eForGetClientRects) &&
aToBBoxUserspace.PreservesAxisAlignedRectangles()) {
Rect rect = NSRectToRect(mRect, AppUnitsPerCSSPixel());
bbox = aToBBoxUserspace.TransformBounds(rect);
return bbox;
}
auto* element = static_cast<SVGImageElement*>(GetContent());
Rect simpleBounds;
element->GetGeometryBounds(&simpleBounds, aToBBoxUserspace);
bbox = simpleBounds;
return bbox;
}
//----------------------------------------------------------------------
// SVGImageListener implementation

View File

@@ -13,12 +13,14 @@
#include "mozilla/gfx/2D.h"
#include "imgIContainer.h"
#include "nsContainerFrame.h"
#include "nsDisplayList.h"
#include "imgINotificationObserver.h"
#include "mozilla/SVGGeometryFrame.h"
#include "mozilla/ISVGDisplayableFrame.h"
#include "nsIReflowCallback.h"
#include "mozilla/Unused.h"
namespace mozilla {
class DisplaySVGImage;
class PresShell;
} // namespace mozilla
@@ -27,23 +29,27 @@ nsIFrame* NS_NewSVGImageFrame(mozilla::PresShell* aPresShell,
namespace mozilla {
class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
class SVGImageFrame final : public nsIFrame,
public ISVGDisplayableFrame,
public nsIReflowCallback {
friend nsIFrame* ::NS_NewSVGImageFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
friend class DisplaySVGImage;
bool CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
wr::IpcResourceUpdateQueue& aResources,
const layers::StackingContextHelper& aSc,
layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder,
DisplaySVGGeometry* aItem,
bool aDryRun) override;
DisplaySVGImage* aItem, bool aDryRun);
protected:
explicit SVGImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
: SVGGeometryFrame(aStyle, aPresContext, kClassID),
: nsIFrame(aStyle, aPresContext, kClassID),
mReflowCallbackPosted(false),
mForceSyncDecoding(false) {
AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_MAY_BE_TRANSFORMED);
EnableVisibilityTracking();
}
@@ -54,16 +60,27 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
NS_DECL_FRAMEARENA_HELPERS(SVGImageFrame)
// ISVGDisplayableFrame interface:
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
imgDrawingParams& aImgParams,
const nsIntRect* aDirtyRect = nullptr) override;
nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
void ReflowSVG() override;
// SVGGeometryFrame methods:
uint16_t GetHitTestFlags() override;
void NotifySVGChanged(uint32_t aFlags) override;
SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace,
uint32_t aFlags) override;
bool IsDisplayContainer() override { return false; }
// nsIFrame interface:
bool IsFrameOfType(uint32_t aFlags) const override {
if (aFlags & eSupportsContainLayoutAndPaint) {
return false;
}
return nsIFrame::IsFrameOfType(aFlags & ~nsIFrame::eSVG);
}
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
int32_t aModType) override;
@@ -77,6 +94,9 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
PostDestroyData& aPostDestroyData) override;
void DidSetComputedStyle(ComputedStyle* aOldStyle) final;
bool IsSVGTransformed(Matrix* aOwnTransforms = nullptr,
Matrix* aFromParentTransforms = nullptr) const override;
bool GetIntrinsicImageDimensions(gfx::Size& aSize,
AspectRatio& aAspectRatio) const;
@@ -93,7 +113,12 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
/// Always sync decode our image when painting if @aForce is true.
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
// SVGImageFrame methods:
bool IsInvisible() const;
private:
uint16_t GetHitTestFlags();
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
int32_t aNativeHeight);
gfx::Matrix GetVectorImageTransform();
@@ -110,6 +135,60 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
friend class SVGImageListener;
};
//----------------------------------------------------------------------
// Display list item:
class DisplaySVGImage final : public nsPaintedDisplayItem {
using imgDrawingParams = image::imgDrawingParams;
public:
DisplaySVGImage(nsDisplayListBuilder* aBuilder, SVGImageFrame* aFrame)
: nsPaintedDisplayItem(aBuilder, aFrame) {
MOZ_COUNT_CTOR(DisplaySVGImage);
MOZ_ASSERT(aFrame, "Must have a frame!");
}
MOZ_COUNTED_DTOR_OVERRIDE(DisplaySVGImage)
NS_DISPLAY_DECL_NAME("DisplaySVGImage", TYPE_SVG_IMAGE)
void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState, nsTArray<nsIFrame*>* aOutFrames) override;
void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
// Whether this part of the SVG should be natively handled by webrender,
// potentially becoming an "active layer" inside a blob image.
bool ShouldBeActive(mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) {
auto* frame = static_cast<SVGImageFrame*>(mFrame);
return frame->CreateWebRenderCommands(aBuilder, aResources, aSc, aManager,
aDisplayListBuilder, this,
/*aDryRun=*/true);
}
bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override {
auto* frame = static_cast<SVGImageFrame*>(mFrame);
bool result = frame->CreateWebRenderCommands(aBuilder, aResources, aSc,
aManager, aDisplayListBuilder,
this, /*aDryRun=*/false);
MOZ_ASSERT(result, "ShouldBeActive inconsistent with CreateWRCommands?");
return result;
}
bool IsInvisible() const override {
auto* frame = static_cast<SVGImageFrame*>(mFrame);
return frame->IsInvisible();
}
};
} // namespace mozilla
#endif // LAYOUT_SVG_SVGIMAGEFRAME_H_

View File

@@ -42,6 +42,7 @@
#include "mozilla/SVGForeignObjectFrame.h"
#include "mozilla/SVGIntegrationUtils.h"
#include "mozilla/SVGGeometryFrame.h"
#include "mozilla/SVGImageFrame.h"
#include "mozilla/SVGMaskFrame.h"
#include "mozilla/SVGObserverUtils.h"
#include "mozilla/SVGOuterSVGFrame.h"
@@ -341,24 +342,26 @@ nsIFrame* SVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame,
gfxMatrix SVGUtils::GetCanvasTM(nsIFrame* aFrame) {
// XXX yuck, we really need a common interface for GetCanvasTM
if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
if (!aFrame->IsFrameOfType(nsIFrame::eSVG) || aFrame->IsSVGOuterSVGFrame()) {
return GetCSSPxToDevPxMatrix(aFrame);
}
LayoutFrameType type = aFrame->Type();
if (type == LayoutFrameType::SVGForeignObject) {
// ForeignObjectFrame caches its canvasTM
if (aFrame->IsSVGForeignObjectFrame()) {
return static_cast<SVGForeignObjectFrame*>(aFrame)->GetCanvasTM();
}
if (type == LayoutFrameType::SVGOuterSVG) {
return GetCSSPxToDevPxMatrix(aFrame);
}
SVGContainerFrame* containerFrame = do_QueryFrame(aFrame);
if (containerFrame) {
// Container frames cache their canvasTM
if (SVGContainerFrame* containerFrame = do_QueryFrame(aFrame)) {
return containerFrame->GetCanvasTM();
}
return static_cast<SVGGeometryFrame*>(aFrame)->GetCanvasTM();
MOZ_ASSERT(aFrame->GetParent()->IsFrameOfType(nsIFrame::eSVGContainer));
auto* parent = static_cast<SVGContainerFrame*>(aFrame->GetParent());
auto* content = static_cast<SVGElement*>(aFrame->GetContent());
return content->PrependLocalTransformsTo(parent->GetCanvasTM());
}
bool SVGUtils::IsSVGTransformed(const nsIFrame* aFrame,

View File

@@ -6385,6 +6385,11 @@
value: true
mirror: always
- name: gfx.webrender.svg-shapes
type: RelaxedAtomicBool
value: true
mirror: always
- name: gfx.webrender.debug.blob.paint-flashing
type: RelaxedAtomicBool
value: false