Bug 1814398 - SVGImageElement should not derive from SVGGeometryElement r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D168674
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user