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

This is done using a similar approach to CreateWebRenderCommands
but slightly modified. In particular the active layer check needs
to be done before we're ready to CreateWebRenderCommands, but once
we decide to activate an item, we can't let CreateWebRenderCommands
fail. Unfortunately, the need to query ImageLib for support means
we need to do basically ~all of the work of CreateWebRenderCommands
to do this check.

As such, this introduces a modified version of CreateWebRenderCommands
that SVGGeometryFrames implement with a "dry run" flag. When true,
it runs the same code but stops short of mutating the WR DL/state.

ImageLib may be encouraged to do some extra work that could be thrown
away, but I'm not sure there's any way to avoid that.

For now, only SVGImageFrame actually provides an implementation. The
bulk of the implementation is handling the on-by-default
preserveAspectRatio feature of SVG images. It was cleaner to just
reimplement that logic than reuse the existing preserveAspectRatio
code, as it was too tangled up in the particulars of how the PaintSVG
path is designed.

Differential Revision: https://phabricator.services.mozilla.com/D59925

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alexis Beingessner 2020-02-14 14:50:36 +00:00
Родитель 6f7cc8920f
Коммит 6b442a22a5
8 изменённых файлов: 363 добавлений и 55 удалений

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

@ -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"
@ -1101,14 +1102,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;
}
}
@ -1122,9 +1131,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 =
@ -1135,33 +1147,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;
}
@ -1187,8 +1207,12 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
nsDisplayItem* item = aList->GetBottom();
nsDisplayItem* startOfCurrentGroup = item;
RenderRootStateManager* manager =
aCommandBuilder->mManager->GetRenderRootStateManager(
aBuilder.GetRenderRoot());
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>(
@ -1251,9 +1275,6 @@ void Grouper::ConstructGroups(nsDisplayListBuilder* aDisplayListBuilder,
sIndent++;
// Note: this call to CreateWebRenderCommands can recurse back into
// this function.
RenderRootStateManager* manager =
aCommandBuilder->mManager->GetRenderRootStateManager(
aBuilder.GetRenderRoot());
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-64) == 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
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;
};
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 != NS_STYLE_BLEND_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),