Bug 1372458 - Fold opacity into filter drawing rather than using a temporary surface. r?mstange,Bas
MozReview-Commit-ID: GOBTUhN7fcC
--- a/gfx/2d/DrawTargetD2D1.cpp
+++ b/gfx/2d/DrawTargetD2D1.cpp
@@ -250,17 +250,34 @@ DrawTargetD2D1::DrawFilter(FilterNode *a
PrepareForDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
mDC->SetAntialiasMode(D2DAAMode(aOptions.mAntialiasMode));
FilterNodeD2D1* node = static_cast<FilterNodeD2D1*>(aNode);
node->WillDraw(this);
- mDC->DrawImage(node->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
+ if (aOptions.mAlpha == 1.0f) {
+ mDC->DrawImage(node->OutputEffect(), D2DPoint(aDestPoint), D2DRect(aSourceRect));
+ } else {
+ RefPtr<ID2D1Image> image;
+ node->OutputEffect()->GetOutput(getter_AddRefs(image));
+
+ Matrix mat = Matrix::Translation(aDestPoint);
+
+ RefPtr<ID2D1ImageBrush> imageBrush;
+ mDC->CreateImageBrush(image,
+ D2D1::ImageBrushProperties(D2DRect(aSourceRect)),
+ D2D1::BrushProperties(aOptions.mAlpha, D2DMatrix(mat)),
+ getter_AddRefs(imageBrush));
+ mDC->FillRectangle(D2D1::RectF(aDestPoint.x, aDestPoint.y,
+ aDestPoint.x + aSourceRect.width,
+ aDestPoint.y + aSourceRect.height),
+ imageBrush);
+ }
FinalizeDrawing(aOptions.mCompositionOp, ColorPattern(Color()));
}
void
DrawTargetD2D1::DrawSurfaceWithShadow(SourceSurface *aSurface,
const Point &aDest,
const Color &aColor,
--- a/layout/svg/nsFilterInstance.cpp
+++ b/layout/svg/nsFilterInstance.cpp
@@ -60,17 +60,18 @@ UserSpaceMetricsForFrame(nsIFrame* aFram
return MakeUnique<NonSVGFrameUserSpaceMetrics>(aFrame);
}
void
nsFilterInstance::PaintFilteredFrame(nsIFrame *aFilteredFrame,
gfxContext* aCtx,
nsSVGFilterPaintCallback *aPaintCallback,
const nsRegion *aDirtyArea,
- imgDrawingParams& aImgParams)
+ imgDrawingParams& aImgParams,
+ float aOpacity)
{
auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
gfxContextMatrixAutoSaveRestore autoSR(aCtx);
gfxSize scaleFactors = aCtx->CurrentMatrixDouble().ScaleFactors(true);
if (scaleFactors.IsEmpty()) {
return;
@@ -92,17 +93,17 @@ nsFilterInstance::PaintFilteredFrame(nsI
// Hardcode InputIsTainted to true because we don't want JS to be able to
// read the rendered contents of aFilteredFrame.
nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
*metrics, filterChain, /* InputIsTainted */ true,
aPaintCallback, scaleMatrixInDevUnits,
aDirtyArea, nullptr, nullptr, nullptr);
if (instance.IsInitialized()) {
- instance.Render(aCtx, aImgParams);
+ instance.Render(aCtx, aImgParams, aOpacity);
}
}
nsRegion
nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
const nsRegion& aPreFilterDirtyRegion)
{
if (aPreFilterDirtyRegion.IsEmpty()) {
@@ -488,17 +489,17 @@ nsFilterInstance::BuildSourceImage(DrawT
mPaintCallback->Paint(*ctx, mTargetFrame, mPaintTransform, &dirty, aImgParams);
mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
mSourceGraphic.mSurfaceRect = neededRect;
}
void
-nsFilterInstance::Render(gfxContext* aCtx, imgDrawingParams& aImgParams)
+nsFilterInstance::Render(gfxContext* aCtx, imgDrawingParams& aImgParams, float aOpacity)
{
MOZ_ASSERT(mTargetFrame, "Need a frame for rendering");
if (mPrimitiveDescriptions.IsEmpty()) {
// An filter without any primitive. Treat it as success and paint nothing.
return;
}
@@ -516,17 +517,17 @@ nsFilterInstance::Render(gfxContext* aCt
BuildSourceImage(aCtx->GetDrawTarget(), aImgParams);
BuildSourcePaints(aImgParams);
FilterSupport::RenderFilterDescription(
aCtx->GetDrawTarget(), mFilterDescription, IntRectToRect(filterRect),
mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
- mInputImages, Point(0, 0));
+ mInputImages, Point(0, 0), DrawOptions(aOpacity));
}
nsRegion
nsFilterInstance::ComputePostFilterDirtyRegion()
{
if (mPreFilterDirtyRegion.IsEmpty() || mPrimitiveDescriptions.IsEmpty()) {
return nsRegion();
}
--- a/layout/svg/nsFilterInstance.h
+++ b/layout/svg/nsFilterInstance.h
@@ -83,17 +83,18 @@ public:
* @param aDirtyArea The area than needs to be painted, in aFilteredFrame's
* frame space (i.e. relative to its origin, the top-left corner of its
* border box).
*/
static void PaintFilteredFrame(nsIFrame *aFilteredFrame,
gfxContext* aCtx,
nsSVGFilterPaintCallback *aPaintCallback,
const nsRegion* aDirtyArea,
- imgDrawingParams& aImgParams);
+ imgDrawingParams& aImgParams,
+ float aOpacity = 1.0f);
/**
* Returns the post-filter area that could be dirtied when the given
* pre-filter area of aFilteredFrame changes.
* @param aPreFilterDirtyRegion The pre-filter area of aFilteredFrame that has
* changed, relative to aFilteredFrame, in app units.
*/
static nsRegion GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
@@ -163,17 +164,17 @@ private:
bool IsInitialized() const { return mInitialized; }
/**
* Draws the filter output into aDrawTarget. The area that
* needs to be painted must have been specified before calling this method
* by passing it as the aPostFilterDirtyRegion argument to the
* nsFilterInstance constructor.
*/
- void Render(gfxContext* aCtx, imgDrawingParams& aImgParams);
+ void Render(gfxContext* aCtx, imgDrawingParams& aImgParams, float aOpacity = 1.0f);
const FilterDescription& ExtractDescriptionAndAdditionalImages(nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages)
{
mInputImages.SwapElements(aOutAdditionalImages);
return mFilterDescription;
}
/**
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -1084,32 +1084,23 @@ nsSVGIntegrationUtils::PaintFilter(const
return;
}
gfxContext& context = aParams.ctx;
gfxContextAutoSaveRestore autoSR(&context);
EffectOffsets offsets = MoveContextOriginToUserSpace(firstFrame, aParams);
- if (opacity != 1.0f) {
- context.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
- nullptr, Matrix());
- }
-
/* Paint the child and apply filters */
RegularFramePaintCallback callback(aParams.builder, aParams.layerManager,
offsets.offsetToUserSpaceInDevPx);
nsRegion dirtyRegion = aParams.dirtyRect - offsets.offsetToBoundingBox;
nsFilterInstance::PaintFilteredFrame(frame, &context, &callback,
- &dirtyRegion, aParams.imgParams);
-
- if (opacity != 1.0f) {
- context.PopGroupAndBlend();
- }
+ &dirtyRegion, aParams.imgParams, opacity);
}
class PaintFrameCallback : public gfxDrawingCallback {
public:
PaintFrameCallback(nsIFrame* aFrame,
const nsSize aPaintServerSize,
const IntSize aRenderSize,
uint32_t aFlags)