Bug 1555356 - Make images inside of SVGs active. r=aosmond

(rebased Alexis' patch)

Differential Revision: https://phabricator.services.mozilla.com/D59925
This commit is contained in:
Bert Peers 2020-05-15 18:49:52 +00:00
Родитель 6c52620bc9
Коммит 2546aafcc2
8 изменённых файлов: 362 добавлений и 54 удалений

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

@ -14,6 +14,7 @@
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/layout/SVGGeometryFrame.h"
#include "mozilla/layers/AnimationHelper.h"
#include "mozilla/layers/ClipManager.h"
#include "mozilla/layers/ImageClient.h"
@ -1051,14 +1052,22 @@ class WebRenderGroupData : public WebRenderUserData {
DIGroup mFollowingGroup;
};
static bool IsItemProbablyActive(nsDisplayItem* aItem,
nsDisplayListBuilder* aDisplayListBuilder,
bool aParentActive = true);
static bool IsItemProbablyActive(
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder, bool aParentActive = true);
static bool HasActiveChildren(const nsDisplayList& aList,
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) {
for (nsDisplayItem* i = aList.GetBottom(); i; i = i->GetAbove()) {
if (IsItemProbablyActive(i, aDisplayListBuilder, false)) {
if (IsItemProbablyActive(i, aBuilder, aResources, aSc, aManager,
aDisplayListBuilder, false)) {
return true;
}
}
@ -1072,9 +1081,12 @@ static bool HasActiveChildren(const nsDisplayList& aList,
//
// We can't easily use GetLayerState because it wants a bunch of layers related
// information.
static bool IsItemProbablyActive(nsDisplayItem* aItem,
nsDisplayListBuilder* aDisplayListBuilder,
bool aParentActive) {
static bool IsItemProbablyActive(
nsDisplayItem* aItem, mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder, bool aParentActive) {
switch (aItem->GetType()) {
case DisplayItemType::TYPE_TRANSFORM: {
nsDisplayTransform* transformItem =
@ -1085,33 +1097,41 @@ static bool IsItemProbablyActive(nsDisplayItem* aItem,
GP("active: %d\n", transformItem->MayBeAnimated(aDisplayListBuilder));
return transformItem->MayBeAnimated(aDisplayListBuilder, false) ||
!is2D ||
HasActiveChildren(*transformItem->GetChildren(),
aDisplayListBuilder);
HasActiveChildren(*transformItem->GetChildren(), aBuilder,
aResources, aSc, aManager, aDisplayListBuilder);
}
case DisplayItemType::TYPE_OPACITY: {
nsDisplayOpacity* opacityItem = static_cast<nsDisplayOpacity*>(aItem);
bool active = opacityItem->NeedsActiveLayer(aDisplayListBuilder,
opacityItem->Frame(), false);
GP("active: %d\n", active);
return active || HasActiveChildren(*opacityItem->GetChildren(),
aDisplayListBuilder);
return active ||
HasActiveChildren(*opacityItem->GetChildren(), aBuilder,
aResources, aSc, aManager, aDisplayListBuilder);
}
case DisplayItemType::TYPE_FOREIGN_OBJECT: {
return true;
}
case DisplayItemType::TYPE_SVG_GEOMETRY: {
auto* svgItem = static_cast<nsDisplaySVGGeometry*>(aItem);
return svgItem->ShouldBeActive(aBuilder, aResources, aSc, aManager,
aDisplayListBuilder);
}
case DisplayItemType::TYPE_BLEND_MODE: {
/* BLEND_MODE needs to be active if it might have a previous sibling
* that is active. We use the activeness of the parent as a rough
* proxy for this situation. */
return aParentActive ||
HasActiveChildren(*aItem->GetChildren(), aDisplayListBuilder);
HasActiveChildren(*aItem->GetChildren(), aBuilder, aResources, aSc,
aManager, aDisplayListBuilder);
}
case DisplayItemType::TYPE_WRAP_LIST:
case DisplayItemType::TYPE_CONTAINER:
case DisplayItemType::TYPE_MASK:
case DisplayItemType::TYPE_PERSPECTIVE: {
if (aItem->GetChildren()) {
return HasActiveChildren(*aItem->GetChildren(), aDisplayListBuilder);
return HasActiveChildren(*aItem->GetChildren(), aBuilder, aResources,
aSc, aManager, aDisplayListBuilder);
}
return false;
}
@ -1137,8 +1157,11 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
nsDisplayItem* item = aList->GetBottom();
nsDisplayItem* startOfCurrentGroup = item;
RenderRootStateManager* manager =
aCommandBuilder->mManager->GetRenderRootStateManager();
while (item) {
if (IsItemProbablyActive(item, mDisplayListBuilder)) {
if (IsItemProbablyActive(item, aBuilder, aResources, aSc, manager,
mDisplayListBuilder)) {
// We're going to be starting a new group.
RefPtr<WebRenderGroupData> groupData =
aCommandBuilder->CreateOrRecycleWebRenderUserData<WebRenderGroupData>(
@ -1199,8 +1222,6 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
sIndent++;
// Note: this call to CreateWebRenderCommands can recurse back into
// this function.
RenderRootStateManager* manager =
aCommandBuilder->mManager->GetRenderRootStateManager();
bool createdWRCommands = item->CreateWebRenderCommands(
aBuilder, aResources, aSc, manager, mDisplayListBuilder);
sIndent--;

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

@ -4,7 +4,7 @@
== image-filter-01.svg image-filter-01-ref.svg
== image-load-01.svg ../pass.svg
fuzzy-if(Android&&!browserIsRemote,0-4,0-32) == image-opacity-01.svg image-opacity-01-ref.svg # Bug 779514 for Android
fuzzy-if(Android,0-4,0-34) == image-opacity-02.svg image-opacity-02-ref.svg # Bug 776039 for Android
fuzzy-if(Android,0-4,0-34) fuzzy-if(webrender,0-1,0-100) == image-opacity-02.svg image-opacity-02-ref.svg # Bug 776039 for Android
== image-rotate-01.svg image-rotate-01-ref.svg
== image-rotate-02a.svg image-rotate-02-ref.svg
== image-rotate-02b.svg image-rotate-02-ref.svg

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

@ -63,7 +63,7 @@ fuzzy(0-11,0-7155) == blur-inside-clipPath.svg blur-inside-clipPath-ref.svg
== clip-01.svg pass.svg
== clip-02a.svg clip-02-ref.svg
== clip-02b.svg clip-02-ref.svg
== clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
fuzzy-if(webrender,0-1,0-10000) == clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
== clip-use-element-01.svg pass.svg
== clip-use-element-02.svg pass.svg
@ -370,7 +370,7 @@ fuzzy-if(skiaContent,0-1,0-400) == path-06.svg path-06-ref.svg
== pathLength-02.svg pass.svg
== pattern-basic-01.svg pass.svg
fuzzy(0-1,0-5) == pattern-big-image.html pattern-big-image-ref.html
fuzzy(0-1,0-5) fuzzy-if(webrender,0-2,0-61) == pattern-big-image.html pattern-big-image-ref.html
== pattern-css-transform.html pattern-css-transform-ref.html
== pattern-invalid-01.svg pattern-invalid-01-ref.svg
fuzzy-if(skiaContent,0-1,0-5) == pattern-live-01a.svg pattern-live-01-ref.svg

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

@ -53,39 +53,6 @@ NS_QUERYFRAME_HEAD(SVGGeometryFrame)
NS_QUERYFRAME_ENTRY(SVGGeometryFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
//----------------------------------------------------------------------
// Display list item:
class nsDisplaySVGGeometry final : public nsPaintedDisplayItem {
typedef mozilla::image::imgDrawingParams imgDrawingParams;
public:
nsDisplaySVGGeometry(nsDisplayListBuilder* aBuilder, SVGGeometryFrame* aFrame)
: nsPaintedDisplayItem(aBuilder, aFrame) {
MOZ_COUNT_CTOR(nsDisplaySVGGeometry);
MOZ_ASSERT(aFrame, "Must have a frame!");
}
#ifdef NS_BUILD_REFCNT_LOGGING
MOZ_COUNTED_DTOR_OVERRIDE(nsDisplaySVGGeometry)
#endif
NS_DISPLAY_DECL_NAME("nsDisplaySVGGeometry", TYPE_SVG_GEOMETRY)
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) override;
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
nsDisplayItemGeometry* AllocateGeometry(
nsDisplayListBuilder* aBuilder) override {
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
}
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const override;
};
void nsDisplaySVGGeometry::HitTest(nsDisplayListBuilder* aBuilder,
const nsRect& aRect, HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) {

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

@ -10,6 +10,7 @@
#include "mozilla/Attributes.h"
#include "gfxMatrix.h"
#include "gfxRect.h"
#include "nsDisplayList.h"
#include "nsFrame.h"
#include "nsSVGDisplayableFrame.h"
#include "nsLiteralString.h"
@ -19,13 +20,13 @@
namespace mozilla {
class SVGGeometryFrame;
class SVGMarkerObserver;
class nsDisplaySVGGeometry;
namespace gfx {
class DrawTarget;
} // namespace gfx
} // namespace mozilla
class gfxContext;
class nsDisplaySVGGeometry;
class nsAtom;
class nsIFrame;
class nsSVGMarkerFrame;
@ -47,7 +48,7 @@ class SVGGeometryFrame : public nsFrame, public nsSVGDisplayableFrame {
friend nsIFrame* ::NS_NewSVGGeometryFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
friend class ::nsDisplaySVGGeometry;
friend class nsDisplaySVGGeometry;
protected:
SVGGeometryFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
@ -118,6 +119,16 @@ class SVGGeometryFrame : public nsFrame, public nsSVGDisplayableFrame {
void Render(gfxContext* aContext, uint32_t aRenderComponents,
const gfxMatrix& aTransform, imgDrawingParams& aImgParams);
virtual bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder, nsDisplaySVGGeometry* aItem,
bool aDryRun) {
MOZ_RELEASE_ASSERT(aDryRun, "You shouldn't be calling this directly");
return false;
}
/**
* @param aMatrix The transform that must be multiplied onto aContext to
* establish this frame's SVG user space.
@ -125,6 +136,72 @@ class SVGGeometryFrame : public nsFrame, public nsSVGDisplayableFrame {
void PaintMarkers(gfxContext& aContext, const gfxMatrix& aTransform,
imgDrawingParams& aImgParams);
};
//----------------------------------------------------------------------
// Display list item:
class nsDisplaySVGGeometry final : public nsPaintedDisplayItem {
typedef mozilla::image::imgDrawingParams imgDrawingParams;
public:
nsDisplaySVGGeometry(nsDisplayListBuilder* aBuilder, SVGGeometryFrame* aFrame)
: nsPaintedDisplayItem(aBuilder, aFrame) {
MOZ_COUNT_CTOR(nsDisplaySVGGeometry);
MOZ_ASSERT(aFrame, "Must have a frame!");
}
#ifdef NS_BUILD_REFCNT_LOGGING
virtual ~nsDisplaySVGGeometry() { MOZ_COUNT_DTOR(nsDisplaySVGGeometry); }
#endif
NS_DISPLAY_DECL_NAME("nsDisplaySVGGeometry", TYPE_SVG_GEOMETRY)
virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
HitTestState* aState,
nsTArray<nsIFrame*>* aOutFrames) override;
virtual void Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) override;
nsDisplayItemGeometry* AllocateGeometry(
nsDisplayListBuilder* aBuilder) override {
return new nsDisplayItemGenericImageGeometry(this, aBuilder);
}
void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
const nsDisplayItemGeometry* aGeometry,
nsRegion* aInvalidRegion) const 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) {
// We delegate this question to the parent frame to take advantage of
// the SVGGeometryFrame inheritance hierarchy which provides actual
// implementation details. The dryRun flag prevents serious side-effects.
auto* frame = static_cast<SVGGeometryFrame*>(mFrame);
return frame->CreateWebRenderCommands(aBuilder, aResources, aSc, aManager,
aDisplayListBuilder, this,
/*aDryRun=*/true);
}
virtual bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder) override {
// We delegate this question to the parent frame to take advantage of
// the SVGGeometryFrame inheritance hierarchy which provides actual
// implementation details.
auto* frame = static_cast<SVGGeometryFrame*>(mFrame);
bool result = frame->CreateWebRenderCommands(aBuilder, aResources, aSc,
aManager, aDisplayListBuilder,
this, /*aDryRun=*/false);
MOZ_ASSERT(result, "ShouldBeActive inconsistent with CreateWRCommands?");
return result;
}
};
} // namespace mozilla
#endif // __SVGGEOMETRYFRAME_H__

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

@ -17,6 +17,7 @@ if CONFIG['ENABLE_TESTS']:
EXPORTS += [
'nsFilterInstance.h',
'nsSVGDisplayableFrame.h',
'nsSVGFilterInstance.h',
'nsSVGForeignObjectFrame.h',
'nsSVGImageFrame.h',
@ -31,6 +32,10 @@ EXPORTS.mozilla += [
'SVGContextPaint.h',
]
EXPORTS.mozilla.layout += [
'SVGGeometryFrame.h',
]
UNIFIED_SOURCES += [
'nsCSSClipPathInstance.cpp',
'nsCSSFilterInstance.cpp',

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

@ -10,6 +10,8 @@
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/layers/RenderRootStateManager.h"
#include "mozilla/layers/WebRenderLayerManager.h"
#include "imgIContainer.h"
#include "nsContainerFrame.h"
#include "nsIImageLoadingContent.h"
@ -31,6 +33,7 @@ using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
using namespace mozilla::image;
using namespace mozilla::dom::SVGPreserveAspectRatio_Binding;
namespace SVGT = SVGGeometryProperty::Tags;
// ---------------------------------------------------------------------
@ -382,6 +385,233 @@ void nsSVGImageFrame::PaintSVG(gfxContext& aContext,
}
}
bool nsSVGImageFrame::CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder, nsDisplaySVGGeometry* aItem,
bool aDryRun) {
if (!StyleVisibility()->IsVisible()) {
return true;
}
float opacity = 1.0f;
if (nsSVGUtils::CanOptimizeOpacity(this)) {
opacity = StyleEffects()->mOpacity;
}
if (opacity != 1.0f) {
// FIXME: not implemented, might be trivial
return false;
}
if (StyleEffects()->mMixBlendMode != StyleBlend::Normal) {
// FIXME: not implemented
return false;
}
// try to setup the image
if (!mImageContainer) {
nsCOMPtr<imgIRequest> currentRequest;
nsCOMPtr<nsIImageLoadingContent> imageLoader =
do_QueryInterface(GetContent());
if (imageLoader) {
imageLoader->GetRequest(nsIImageLoadingContent::CURRENT_REQUEST,
getter_AddRefs(currentRequest));
}
if (currentRequest) {
currentRequest->GetImage(getter_AddRefs(mImageContainer));
}
}
if (!mImageContainer) {
// nothing to draw (yet)
return true;
}
uint32_t flags = imgIContainer::FLAG_ASYNC_NOTIFY;
if (aDisplayListBuilder->ShouldSyncDecodeImages()) {
flags |= imgIContainer::FLAG_SYNC_DECODE;
}
if (aDisplayListBuilder->IsPaintingToWindow()) {
flags |= imgIContainer::FLAG_HIGH_QUALITY_SCALING;
}
// Compute bounds of the image
nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
int32_t appUnitsPerCSSPixel = AppUnitsPerCSSPixel();
float x, y, width, height;
SVGImageElement* imgElem = static_cast<SVGImageElement*>(GetContent());
SVGGeometryProperty::ResolveAll<SVGT::X, SVGT::Y, SVGT::Width, SVGT::Height>(
imgElem, &x, &y, &width, &height);
NS_ASSERTION(width > 0 && height > 0,
"Should only be painting things with valid width/height");
auto toReferenceFrame = aItem->ToReferenceFrame();
auto appRect = nsLayoutUtils::RoundGfxRectToAppRect(Rect(0, 0, width, height),
appUnitsPerCSSPixel);
appRect += toReferenceFrame;
auto destRect = LayoutDeviceRect::FromAppUnits(appRect, appUnitsPerDevPx);
auto clipRect = destRect;
if (StyleDisplay()->IsScrollableOverflow()) {
// Apply potential non-trivial clip
auto cssClip = nsSVGUtils::GetClipRectForFrame(this, 0, 0, width, height);
auto appClip =
nsLayoutUtils::RoundGfxRectToAppRect(cssClip, appUnitsPerCSSPixel);
appClip += toReferenceFrame;
clipRect = LayoutDeviceRect::FromAppUnits(appClip, appUnitsPerDevPx);
// Apply preserveAspectRatio
if (mImageContainer->GetType() == imgIContainer::TYPE_RASTER) {
int32_t nativeWidth, nativeHeight;
if (NS_FAILED(mImageContainer->GetWidth(&nativeWidth)) ||
NS_FAILED(mImageContainer->GetHeight(&nativeHeight)) ||
nativeWidth == 0 || nativeHeight == 0) {
// Image has no size; nothing to draw
return true;
}
auto preserveAspectRatio = imgElem->mPreserveAspectRatio.GetAnimValue();
uint16_t align = preserveAspectRatio.GetAlign();
uint16_t meetOrSlice = preserveAspectRatio.GetMeetOrSlice();
// default to the defaults
if (align == SVG_PRESERVEASPECTRATIO_UNKNOWN) {
align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
}
if (meetOrSlice == SVG_MEETORSLICE_UNKNOWN) {
meetOrSlice = SVG_MEETORSLICE_MEET;
}
// aspect > 1 is horizontal
// aspect < 1 is vertical
float nativeAspect = ((float)nativeWidth) / ((float)nativeHeight);
float viewAspect = width / height;
// "Meet" is "fit image to view"; "Slice" is "cover view with image".
//
// Whether we meet or slice, one side of the destRect will always be
// perfectly spanned by our image. The only questions to answer are
// "which side won't span perfectly" and "should that side be grown
// or shrunk".
//
// Because we fit our image to the destRect, this all just reduces to:
// "if meet, shrink to fit. if slice, grow to fit."
if (align != SVG_PRESERVEASPECTRATIO_NONE && nativeAspect != viewAspect) {
// Slightly redundant bools, but they make the conditions clearer
bool tooTall = nativeAspect > viewAspect;
bool tooWide = nativeAspect < viewAspect;
if ((meetOrSlice == SVG_MEETORSLICE_MEET && tooTall) ||
(meetOrSlice == SVG_MEETORSLICE_SLICE && tooWide)) {
// Adjust height and realign y
auto oldHeight = destRect.height;
destRect.height = destRect.width / nativeAspect;
auto heightChange = oldHeight - destRect.height;
switch (align) {
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
// align to top (no-op)
break;
case SVG_PRESERVEASPECTRATIO_XMINYMID:
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
// align to center
destRect.y += heightChange / 2.0f;
break;
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
// align to bottom
destRect.y += heightChange;
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown value for align");
}
} else if ((meetOrSlice == SVG_MEETORSLICE_MEET && tooWide) ||
(meetOrSlice == SVG_MEETORSLICE_SLICE && tooTall)) {
// Adjust width and realign x
auto oldWidth = destRect.width;
destRect.width = destRect.height * nativeAspect;
auto widthChange = oldWidth - destRect.width;
switch (align) {
case SVG_PRESERVEASPECTRATIO_XMINYMIN:
case SVG_PRESERVEASPECTRATIO_XMINYMID:
case SVG_PRESERVEASPECTRATIO_XMINYMAX:
// align to left (no-op)
break;
case SVG_PRESERVEASPECTRATIO_XMIDYMIN:
case SVG_PRESERVEASPECTRATIO_XMIDYMID:
case SVG_PRESERVEASPECTRATIO_XMIDYMAX:
// align to center
destRect.x += widthChange / 2.0f;
break;
case SVG_PRESERVEASPECTRATIO_XMAXYMIN:
case SVG_PRESERVEASPECTRATIO_XMAXYMID:
case SVG_PRESERVEASPECTRATIO_XMAXYMAX:
// align to right
destRect.x += widthChange;
break;
default:
MOZ_ASSERT_UNREACHABLE("Unknown value for align");
}
}
}
}
}
Maybe<SVGImageContext> svgContext;
if (mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
// Forward preserveAspectRatio to inner SVGs
svgContext.emplace(Some(CSSIntSize::Truncate(width, height)),
Some(imgElem->mPreserveAspectRatio.GetAnimValue()));
}
IntSize decodeSize = nsLayoutUtils::ComputeImageContainerDrawingParameters(
mImageContainer, this, destRect, aSc, flags, svgContext);
RefPtr<layers::ImageContainer> container;
ImgDrawResult drawResult = mImageContainer->GetImageContainerAtSize(
aManager->LayerManager(), decodeSize, svgContext, flags,
getter_AddRefs(container));
// While we got a container, it may not contain a fully decoded surface. If
// that is the case, and we have an image we were previously displaying which
// has a fully decoded surface, then we should prefer the previous image.
switch (drawResult) {
case ImgDrawResult::NOT_READY:
case ImgDrawResult::INCOMPLETE:
case ImgDrawResult::TEMPORARY_ERROR:
// nothing to draw (yet)
return true;
case ImgDrawResult::NOT_SUPPORTED:
// things we haven't implemented for WR yet
return false;
default:
// image is ready to draw
break;
}
// Don't do any actual mutations to state if we're doing a dry run
// (used to decide if we're making this into an active layer)
if (!aDryRun) {
// If the image container is empty, we don't want to fallback. Any other
// failure will be due to resource constraints and fallback is unlikely to
// help us. Hence we can ignore the return value from PushImage.
if (container) {
aManager->CommandBuilder().PushImage(aItem, container, aBuilder,
aResources, aSc, destRect, clipRect);
}
nsDisplayItemGenericImageGeometry::UpdateDrawResult(aItem, drawResult);
}
return true;
}
nsIFrame* nsSVGImageFrame::GetFrameForPoint(const gfxPoint& aPoint) {
if (!(GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) && !GetHitTestFlags()) {
return nullptr;

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

@ -50,6 +50,14 @@ class nsSVGImageFrame final : public mozilla::SVGGeometryFrame,
friend nsIFrame* NS_NewSVGImageFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle);
virtual bool CreateWebRenderCommands(
mozilla::wr::DisplayListBuilder& aBuilder,
mozilla::wr::IpcResourceUpdateQueue& aResources,
const mozilla::layers::StackingContextHelper& aSc,
mozilla::layers::RenderRootStateManager* aManager,
nsDisplayListBuilder* aDisplayListBuilder,
mozilla::nsDisplaySVGGeometry* aItem, bool aDryRun) override;
protected:
explicit nsSVGImageFrame(ComputedStyle* aStyle, nsPresContext* aPresContext)
: SVGGeometryFrame(aStyle, aPresContext, kClassID),