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
|
void SVGImageElement::GetGeometryBounds(Rect* aBounds,
|
||||||
be a rectangle. */
|
const Matrix& aToBoundsSpace) {
|
||||||
bool SVGImageElement::GetGeometryBounds(
|
|
||||||
Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
|
||||||
const Matrix& aToBoundsSpace, const Matrix* aToNonScalingStrokeSpace) {
|
|
||||||
Rect rect;
|
Rect rect;
|
||||||
|
|
||||||
DebugOnly<bool> ok =
|
DebugOnly<bool> ok =
|
||||||
@@ -273,16 +270,6 @@ bool SVGImageElement::GetGeometryBounds(
|
|||||||
}
|
}
|
||||||
|
|
||||||
*aBounds = aToBoundsSpace.TransformBounds(rect);
|
*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/SVGAnimatedString.h"
|
||||||
#include "mozilla/dom/SVGGeometryElement.h"
|
#include "mozilla/dom/SVGGeometryElement.h"
|
||||||
#include "mozilla/dom/SVGAnimatedPreserveAspectRatio.h"
|
#include "mozilla/dom/SVGAnimatedPreserveAspectRatio.h"
|
||||||
|
#include "mozilla/gfx/2D.h"
|
||||||
|
|
||||||
nsresult NS_NewSVGImageElement(
|
nsresult NS_NewSVGImageElement(
|
||||||
nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||||
@@ -22,7 +23,7 @@ class SVGImageFrame;
|
|||||||
namespace dom {
|
namespace dom {
|
||||||
class DOMSVGAnimatedPreserveAspectRatio;
|
class DOMSVGAnimatedPreserveAspectRatio;
|
||||||
|
|
||||||
using SVGImageElementBase = SVGGeometryElement;
|
using SVGImageElementBase = SVGGraphicsElement;
|
||||||
|
|
||||||
class SVGImageElement : public SVGImageElementBase,
|
class SVGImageElement : public SVGImageElementBase,
|
||||||
public nsImageLoadingContent {
|
public nsImageLoadingContent {
|
||||||
@@ -54,11 +55,6 @@ class SVGImageElement : public SVGImageElementBase,
|
|||||||
nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
|
||||||
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
|
const nsAttrValue* aValue, const nsAttrValue* aOldValue,
|
||||||
nsIPrincipal* aSubjectPrincipal, bool aNotify) override;
|
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;
|
nsresult BindToTree(BindContext&, nsINode& aParent) override;
|
||||||
void UnbindFromTree(bool aNullParent) override;
|
void UnbindFromTree(bool aNullParent) override;
|
||||||
@@ -69,13 +65,6 @@ class SVGImageElement : public SVGImageElementBase,
|
|||||||
|
|
||||||
NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* name) const override;
|
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:
|
// SVGSVGElement methods:
|
||||||
bool HasValidDimensions() const override;
|
bool HasValidDimensions() const override;
|
||||||
|
|
||||||
@@ -91,6 +80,8 @@ class SVGImageElement : public SVGImageElementBase,
|
|||||||
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
|
||||||
already_AddRefed<DOMSVGAnimatedString> Href();
|
already_AddRefed<DOMSVGAnimatedString> Href();
|
||||||
|
|
||||||
|
void GetGeometryBounds(gfx::Rect* aBounds, const gfx::Matrix& aToBoundsSpace);
|
||||||
|
|
||||||
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
|
void SetDecoding(const nsAString& aDecoding, ErrorResult& aError) {
|
||||||
SetAttr(nsGkAtoms::decoding, aDecoding, aError);
|
SetAttr(nsGkAtoms::decoding, aDecoding, aError);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "mozilla/ProfilerLabels.h"
|
#include "mozilla/ProfilerLabels.h"
|
||||||
#include "mozilla/StaticPrefs_gfx.h"
|
#include "mozilla/StaticPrefs_gfx.h"
|
||||||
#include "mozilla/SVGGeometryFrame.h"
|
#include "mozilla/SVGGeometryFrame.h"
|
||||||
|
#include "mozilla/SVGImageFrame.h"
|
||||||
#include "mozilla/UniquePtr.h"
|
#include "mozilla/UniquePtr.h"
|
||||||
#include "mozilla/gfx/2D.h"
|
#include "mozilla/gfx/2D.h"
|
||||||
#include "mozilla/gfx/Logging.h"
|
#include "mozilla/gfx/Logging.h"
|
||||||
@@ -1125,6 +1126,26 @@ static ItemActivity HasActiveChildren(
|
|||||||
return activity;
|
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
|
// 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
|
// 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
|
// StackingContext, or whether we treat it as "inactive" and include it inside
|
||||||
@@ -1175,29 +1196,28 @@ static ItemActivity IsItemProbablyActive(
|
|||||||
}
|
}
|
||||||
case DisplayItemType::TYPE_SVG_GEOMETRY: {
|
case DisplayItemType::TYPE_SVG_GEOMETRY: {
|
||||||
auto* svgItem = static_cast<DisplaySVGGeometry*>(aItem);
|
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 &&
|
if (StaticPrefs::gfx_webrender_svg_images() && aUniformlyScaled &&
|
||||||
svgItem->ShouldBeActive(aBuilder, aResources, aSc, aManager,
|
svgItem->ShouldBeActive(aBuilder, aResources, aSc, aManager,
|
||||||
aDisplayListBuilder)) {
|
aDisplayListBuilder)) {
|
||||||
bool snap = false;
|
if (aHasActivePrecedingSibling) {
|
||||||
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) {
|
|
||||||
return ItemActivity::Should;
|
return ItemActivity::Should;
|
||||||
}
|
}
|
||||||
|
bool snap = false;
|
||||||
return ItemActivity::Could;
|
return AssessBounds(aSc, aItem->GetBounds(aDisplayListBuilder, &snap));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ItemActivity::No;
|
return ItemActivity::No;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT,
|
|||||||
DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION,
|
DECLARE_DISPLAY_ITEM_TYPE(STICKY_POSITION,
|
||||||
TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
|
TYPE_RENDERS_NO_IMAGES | TYPE_IS_CONTAINER)
|
||||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_GEOMETRY, TYPE_IS_CONTENTFUL)
|
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_TEXT, TYPE_IS_CONTENTFUL)
|
||||||
DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, TYPE_IS_CONTAINER)
|
DECLARE_DISPLAY_ITEM_TYPE(SVG_WRAPPER, TYPE_IS_CONTAINER)
|
||||||
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
|
DECLARE_DISPLAY_ITEM_TYPE(TABLE_BACKGROUND_COLOR, TYPE_RENDERS_NO_IMAGES)
|
||||||
|
|||||||
@@ -171,9 +171,9 @@ void SVGGeometryFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto* styleSVG = StyleSVG();
|
const auto* styleSVG = StyleSVG();
|
||||||
if (Type() != LayoutFrameType::SVGImage && styleSVG->mFill.kind.IsNone() &&
|
if (styleSVG->mFill.kind.IsNone() && styleSVG->mStroke.kind.IsNone() &&
|
||||||
styleSVG->mStroke.kind.IsNone() && styleSVG->mMarkerEnd.IsNone() &&
|
styleSVG->mMarkerEnd.IsNone() && styleSVG->mMarkerMid.IsNone() &&
|
||||||
styleSVG->mMarkerMid.IsNone() && styleSVG->mMarkerStart.IsNone()) {
|
styleSVG->mMarkerStart.IsNone()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,10 +705,6 @@ bool SVGGeometryFrame::IsInvisible() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsSVGImageFrame()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const nsStyleSVG* style = StyleSVG();
|
const nsStyleSVG* style = StyleSVG();
|
||||||
SVGContextPaint* contextPaint =
|
SVGContextPaint* contextPaint =
|
||||||
SVGContextPaint::GetContextPaint(GetContent());
|
SVGContextPaint::GetContextPaint(GetContent());
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ class SVGGeometryFrame : public nsIFrame, public ISVGDisplayableFrame {
|
|||||||
|
|
||||||
bool IsInvisible() const;
|
bool IsInvisible() const;
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
// ISVGDisplayableFrame interface:
|
// ISVGDisplayableFrame interface:
|
||||||
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
||||||
imgDrawingParams& aImgParams,
|
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'
|
* into account the type of element and the value of the 'pointer-events'
|
||||||
* property on the element.
|
* property on the element.
|
||||||
*/
|
*/
|
||||||
virtual uint16_t GetHitTestFlags();
|
uint16_t GetHitTestFlags();
|
||||||
|
|
||||||
private:
|
|
||||||
enum { eRenderFill = 1, eRenderStroke = 2 };
|
enum { eRenderFill = 1, eRenderStroke = 2 };
|
||||||
void Render(gfxContext* aContext, uint32_t aRenderComponents,
|
void Render(gfxContext* aContext, uint32_t aRenderComponents,
|
||||||
const gfxMatrix& aTransform, imgDrawingParams& aImgParams);
|
const gfxMatrix& aTransform, imgDrawingParams& aImgParams);
|
||||||
|
|
||||||
virtual bool CreateWebRenderCommands(
|
bool CreateWebRenderCommands(
|
||||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
const mozilla::layers::StackingContextHelper& aSc,
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
@@ -180,7 +179,7 @@ class DisplaySVGGeometry final : public nsPaintedDisplayItem {
|
|||||||
/*aDryRun=*/true);
|
/*aDryRun=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool CreateWebRenderCommands(
|
bool CreateWebRenderCommands(
|
||||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
const mozilla::layers::StackingContextHelper& aSc,
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
#include "nsLayoutUtils.h"
|
#include "nsLayoutUtils.h"
|
||||||
#include "imgINotificationObserver.h"
|
#include "imgINotificationObserver.h"
|
||||||
#include "SVGGeometryProperty.h"
|
#include "SVGGeometryProperty.h"
|
||||||
#include "SVGGeometryFrame.h"
|
|
||||||
#include "mozilla/PresShell.h"
|
#include "mozilla/PresShell.h"
|
||||||
#include "mozilla/StaticPrefs_image.h"
|
#include "mozilla/StaticPrefs_image.h"
|
||||||
#include "mozilla/SVGContentUtils.h"
|
#include "mozilla/SVGContentUtils.h"
|
||||||
@@ -57,9 +56,44 @@ class SVGImageListener final : public imgINotificationObserver {
|
|||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// nsQueryFrame methods
|
// nsQueryFrame methods
|
||||||
|
|
||||||
NS_QUERYFRAME_HEAD(SVGImageFrame)
|
NS_QUERYFRAME_HEAD(SVGImageFrame)
|
||||||
|
NS_QUERYFRAME_ENTRY(ISVGDisplayableFrame)
|
||||||
NS_QUERYFRAME_ENTRY(SVGImageFrame)
|
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
|
} // namespace mozilla
|
||||||
|
|
||||||
@@ -91,7 +125,8 @@ void SVGImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|||||||
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
|
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
|
||||||
"Content is not an SVG 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)) {
|
if (HasAnyStateBits(NS_FRAME_IS_NONDISPLAY)) {
|
||||||
// Non-display frames are likely to be patterns, masks or the like.
|
// Non-display frames are likely to be patterns, masks or the like.
|
||||||
@@ -143,7 +178,7 @@ void SVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot,
|
|||||||
|
|
||||||
/* virtual */
|
/* virtual */
|
||||||
void SVGImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
void SVGImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
||||||
SVGGeometryFrame::DidSetComputedStyle(aOldStyle);
|
nsIFrame::DidSetComputedStyle(aOldStyle);
|
||||||
|
|
||||||
if (!mImageContainer || !aOldStyle) {
|
if (!mImageContainer || !aOldStyle) {
|
||||||
return;
|
return;
|
||||||
@@ -170,6 +205,11 @@ void SVGImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
|||||||
// TODO(heycam): We should handle aspect-ratio, like nsImageFrame does.
|
// 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:
|
// 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(
|
void SVGImageFrame::OnVisibilityChange(
|
||||||
@@ -217,7 +257,7 @@ void SVGImageFrame::OnVisibilityChange(
|
|||||||
imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
|
imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
|
nsIFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx::Matrix SVGImageFrame::GetRasterImageTransform(int32_t aNativeWidth,
|
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(
|
bool SVGImageFrame::CreateWebRenderCommands(
|
||||||
mozilla::wr::DisplayListBuilder& aBuilder,
|
mozilla::wr::DisplayListBuilder& aBuilder,
|
||||||
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
mozilla::wr::IpcResourceUpdateQueue& aResources,
|
||||||
const mozilla::layers::StackingContextHelper& aSc,
|
const mozilla::layers::StackingContextHelper& aSc,
|
||||||
mozilla::layers::RenderRootStateManager* aManager,
|
mozilla::layers::RenderRootStateManager* aManager,
|
||||||
nsDisplayListBuilder* aDisplayListBuilder, DisplaySVGGeometry* aItem,
|
nsDisplayListBuilder* aDisplayListBuilder, DisplaySVGImage* aItem,
|
||||||
bool aDryRun) {
|
bool aDryRun) {
|
||||||
if (!StyleVisibility()->IsVisible()) {
|
if (!StyleVisibility()->IsVisible()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -712,10 +784,7 @@ nsIFrame* SVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// SVGGeometryFrame methods:
|
// SVGImageFrame methods:
|
||||||
|
|
||||||
// Lie about our fill/stroke so that covered region and hit detection work
|
|
||||||
// properly
|
|
||||||
|
|
||||||
void SVGImageFrame::ReflowSVG() {
|
void SVGImageFrame::ReflowSVG() {
|
||||||
NS_ASSERTION(SVGUtils::OuterSVGIsCallingReflowSVG(this),
|
NS_ASSERTION(SVGUtils::OuterSVGIsCallingReflowSVG(this),
|
||||||
@@ -823,6 +892,36 @@ uint16_t SVGImageFrame::GetHitTestFlags() {
|
|||||||
return flags;
|
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
|
// SVGImageListener implementation
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,14 @@
|
|||||||
#include "mozilla/gfx/2D.h"
|
#include "mozilla/gfx/2D.h"
|
||||||
#include "imgIContainer.h"
|
#include "imgIContainer.h"
|
||||||
#include "nsContainerFrame.h"
|
#include "nsContainerFrame.h"
|
||||||
|
#include "nsDisplayList.h"
|
||||||
#include "imgINotificationObserver.h"
|
#include "imgINotificationObserver.h"
|
||||||
#include "mozilla/SVGGeometryFrame.h"
|
#include "mozilla/ISVGDisplayableFrame.h"
|
||||||
#include "nsIReflowCallback.h"
|
#include "nsIReflowCallback.h"
|
||||||
#include "mozilla/Unused.h"
|
#include "mozilla/Unused.h"
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
class DisplaySVGImage;
|
||||||
class PresShell;
|
class PresShell;
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
@@ -27,23 +29,27 @@ nsIFrame* NS_NewSVGImageFrame(mozilla::PresShell* aPresShell,
|
|||||||
|
|
||||||
namespace mozilla {
|
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,
|
friend nsIFrame* ::NS_NewSVGImageFrame(mozilla::PresShell* aPresShell,
|
||||||
ComputedStyle* aStyle);
|
ComputedStyle* aStyle);
|
||||||
|
|
||||||
|
friend class DisplaySVGImage;
|
||||||
|
|
||||||
bool CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
|
bool CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
|
||||||
wr::IpcResourceUpdateQueue& aResources,
|
wr::IpcResourceUpdateQueue& aResources,
|
||||||
const layers::StackingContextHelper& aSc,
|
const layers::StackingContextHelper& aSc,
|
||||||
layers::RenderRootStateManager* aManager,
|
layers::RenderRootStateManager* aManager,
|
||||||
nsDisplayListBuilder* aDisplayListBuilder,
|
nsDisplayListBuilder* aDisplayListBuilder,
|
||||||
DisplaySVGGeometry* aItem,
|
DisplaySVGImage* aItem, bool aDryRun);
|
||||||
bool aDryRun) override;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit SVGImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
|
explicit SVGImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
|
||||||
: SVGGeometryFrame(aStyle, aPresContext, kClassID),
|
: nsIFrame(aStyle, aPresContext, kClassID),
|
||||||
mReflowCallbackPosted(false),
|
mReflowCallbackPosted(false),
|
||||||
mForceSyncDecoding(false) {
|
mForceSyncDecoding(false) {
|
||||||
|
AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_MAY_BE_TRANSFORMED);
|
||||||
EnableVisibilityTracking();
|
EnableVisibilityTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,16 +60,27 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
|
|||||||
NS_DECL_FRAMEARENA_HELPERS(SVGImageFrame)
|
NS_DECL_FRAMEARENA_HELPERS(SVGImageFrame)
|
||||||
|
|
||||||
// ISVGDisplayableFrame interface:
|
// ISVGDisplayableFrame interface:
|
||||||
|
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||||
|
const nsDisplayListSet& aLists) override;
|
||||||
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
void PaintSVG(gfxContext& aContext, const gfxMatrix& aTransform,
|
||||||
imgDrawingParams& aImgParams,
|
imgDrawingParams& aImgParams,
|
||||||
const nsIntRect* aDirtyRect = nullptr) override;
|
const nsIntRect* aDirtyRect = nullptr) override;
|
||||||
nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
|
nsIFrame* GetFrameForPoint(const gfxPoint& aPoint) override;
|
||||||
void ReflowSVG() override;
|
void ReflowSVG() override;
|
||||||
|
void NotifySVGChanged(uint32_t aFlags) override;
|
||||||
// SVGGeometryFrame methods:
|
SVGBBox GetBBoxContribution(const Matrix& aToBBoxUserspace,
|
||||||
uint16_t GetHitTestFlags() override;
|
uint32_t aFlags) override;
|
||||||
|
bool IsDisplayContainer() override { return false; }
|
||||||
|
|
||||||
// nsIFrame interface:
|
// 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,
|
nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
|
||||||
int32_t aModType) override;
|
int32_t aModType) override;
|
||||||
|
|
||||||
@@ -77,6 +94,9 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
|
|||||||
PostDestroyData& aPostDestroyData) override;
|
PostDestroyData& aPostDestroyData) override;
|
||||||
void DidSetComputedStyle(ComputedStyle* aOldStyle) final;
|
void DidSetComputedStyle(ComputedStyle* aOldStyle) final;
|
||||||
|
|
||||||
|
bool IsSVGTransformed(Matrix* aOwnTransforms = nullptr,
|
||||||
|
Matrix* aFromParentTransforms = nullptr) const override;
|
||||||
|
|
||||||
bool GetIntrinsicImageDimensions(gfx::Size& aSize,
|
bool GetIntrinsicImageDimensions(gfx::Size& aSize,
|
||||||
AspectRatio& aAspectRatio) const;
|
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.
|
/// Always sync decode our image when painting if @aForce is true.
|
||||||
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
|
void SetForceSyncDecoding(bool aForce) { mForceSyncDecoding = aForce; }
|
||||||
|
|
||||||
|
// SVGImageFrame methods:
|
||||||
|
bool IsInvisible() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint16_t GetHitTestFlags();
|
||||||
|
|
||||||
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
|
gfx::Matrix GetRasterImageTransform(int32_t aNativeWidth,
|
||||||
int32_t aNativeHeight);
|
int32_t aNativeHeight);
|
||||||
gfx::Matrix GetVectorImageTransform();
|
gfx::Matrix GetVectorImageTransform();
|
||||||
@@ -110,6 +135,60 @@ class SVGImageFrame final : public SVGGeometryFrame, public nsIReflowCallback {
|
|||||||
friend class SVGImageListener;
|
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
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif // LAYOUT_SVG_SVGIMAGEFRAME_H_
|
#endif // LAYOUT_SVG_SVGIMAGEFRAME_H_
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
#include "mozilla/SVGForeignObjectFrame.h"
|
#include "mozilla/SVGForeignObjectFrame.h"
|
||||||
#include "mozilla/SVGIntegrationUtils.h"
|
#include "mozilla/SVGIntegrationUtils.h"
|
||||||
#include "mozilla/SVGGeometryFrame.h"
|
#include "mozilla/SVGGeometryFrame.h"
|
||||||
|
#include "mozilla/SVGImageFrame.h"
|
||||||
#include "mozilla/SVGMaskFrame.h"
|
#include "mozilla/SVGMaskFrame.h"
|
||||||
#include "mozilla/SVGObserverUtils.h"
|
#include "mozilla/SVGObserverUtils.h"
|
||||||
#include "mozilla/SVGOuterSVGFrame.h"
|
#include "mozilla/SVGOuterSVGFrame.h"
|
||||||
@@ -341,24 +342,26 @@ nsIFrame* SVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame,
|
|||||||
gfxMatrix SVGUtils::GetCanvasTM(nsIFrame* aFrame) {
|
gfxMatrix SVGUtils::GetCanvasTM(nsIFrame* aFrame) {
|
||||||
// XXX yuck, we really need a common interface for GetCanvasTM
|
// 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);
|
return GetCSSPxToDevPxMatrix(aFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
LayoutFrameType type = aFrame->Type();
|
// ForeignObjectFrame caches its canvasTM
|
||||||
if (type == LayoutFrameType::SVGForeignObject) {
|
if (aFrame->IsSVGForeignObjectFrame()) {
|
||||||
return static_cast<SVGForeignObjectFrame*>(aFrame)->GetCanvasTM();
|
return static_cast<SVGForeignObjectFrame*>(aFrame)->GetCanvasTM();
|
||||||
}
|
}
|
||||||
if (type == LayoutFrameType::SVGOuterSVG) {
|
|
||||||
return GetCSSPxToDevPxMatrix(aFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
SVGContainerFrame* containerFrame = do_QueryFrame(aFrame);
|
// Container frames cache their canvasTM
|
||||||
if (containerFrame) {
|
if (SVGContainerFrame* containerFrame = do_QueryFrame(aFrame)) {
|
||||||
return containerFrame->GetCanvasTM();
|
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,
|
bool SVGUtils::IsSVGTransformed(const nsIFrame* aFrame,
|
||||||
|
|||||||
@@ -6385,6 +6385,11 @@
|
|||||||
value: true
|
value: true
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
||||||
|
- name: gfx.webrender.svg-shapes
|
||||||
|
type: RelaxedAtomicBool
|
||||||
|
value: true
|
||||||
|
mirror: always
|
||||||
|
|
||||||
- name: gfx.webrender.debug.blob.paint-flashing
|
- name: gfx.webrender.debug.blob.paint-flashing
|
||||||
type: RelaxedAtomicBool
|
type: RelaxedAtomicBool
|
||||||
value: false
|
value: false
|
||||||
|
|||||||
Reference in New Issue
Block a user