Bug 1301245 - Part 3. Impelment EffectProperties::GetMaskSource. draft
authorcku <cku@mozilla.com>
Thu, 20 Jul 2017 11:26:13 +0800
changeset 612862 1e36844c06dbe6ee659ba7d442f5c531164dbe52
parent 612861 0fb921b21806c8f3aea9597d401eff4be14bee0c
child 612863 c8bcc59c99b0dfd87530a2e45bbe17860c9b4726
push id69621
push userbmo:cku@mozilla.com
push dateFri, 21 Jul 2017 04:42:07 +0000
bugs1301245
milestone56.0a1
Bug 1301245 - Part 3. Impelment EffectProperties::GetMaskSource. MozReview-Commit-ID: 3W1n5nj1J2b
layout/painting/nsDisplayList.cpp
layout/svg/nsSVGEffects.cpp
layout/svg/nsSVGEffects.h
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGUtils.cpp
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -8363,19 +8363,19 @@ ComputeMaskGeometry(PaintFramesParams& a
   // make sure all applicable ones are set again.
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParams.frame);
 
   const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
 
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
-  nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
-
-  if (maskFrames.Length() == 0) {
+  MaskSourceArray sources = effectProperties.GetMaskSource();
+
+  if (sources.Length() == 0) {
     return;
   }
 
   gfxContext& ctx = aParams.ctx;
   nsIFrame* frame = aParams.frame;
 
   nsPoint offsetToUserSpace = ComputeOffsetToUserSpace(aParams);
   gfxPoint devPixelOffsetToUserSpace =
@@ -8385,25 +8385,25 @@ ComputeMaskGeometry(PaintFramesParams& a
   gfxContextMatrixAutoSaveRestore matSR(&ctx);
   ctx.SetMatrix(ctx.CurrentMatrix().PreTranslate(devPixelOffsetToUserSpace));
 
   // Convert boaderArea and dirtyRect to user space.
   int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
   nsRect userSpaceBorderArea = aParams.borderArea - offsetToUserSpace;
   nsRect userSpaceDirtyRect = aParams.dirtyRect - offsetToUserSpace;
 
-  // Union all mask layer rectangles in user space.
+  // Union all mask layer bounds in user space.
   gfxRect maskInUserSpace;
-  for (size_t i = 0; i < maskFrames.Length() ; i++) {
-    nsSVGMaskFrame* maskFrame = maskFrames[i];
+  for (size_t i = 0; i < sources.Length() ; i++) {
+    MaskSource source = sources[i];
     gfxRect currentMaskSurfaceRect;
 
-    if (maskFrame) {
-      currentMaskSurfaceRect = maskFrame->GetMaskArea(aParams.frame);
-    } else {
+    if (source.first() == MaskSourceType::SVGMask) {
+      currentMaskSurfaceRect = source.second()->GetMaskArea(aParams.frame);
+    } else if (source.first() == MaskSourceType::ImageMask) {
       nsCSSRendering::ImageLayerClipState clipState;
       nsCSSRendering::GetImageLayerClip(svgReset->mMask.mLayers[i],
                                        frame,
                                        *frame->StyleBorder(),
                                        userSpaceBorderArea,
                                        userSpaceDirtyRect,
                                        false, /* aWillPaintBorder */
                                        appUnitsPerDevPixel,
@@ -8688,18 +8688,18 @@ nsDisplayMask::PrintEffects(nsACString& 
   if (style->HasClipPath() && !clipPathFrame) {
     if (!first) {
       aTo += ", ";
     }
     aTo += "clip(basic-shape)";
     first = false;
   }
 
-  nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
-  if (!masks.IsEmpty() && masks[0]) {
+  MaskSourceArray masks = effectProperties.GetMaskSource();
+  if (!masks.IsEmpty() && masks[0].first() == MaskSourceType::SVGMask) {
     if (!first) {
       aTo += ", ";
     }
     aTo += "mask";
   }
   aTo += ")";
 }
 #endif
--- a/layout/svg/nsSVGEffects.cpp
+++ b/layout/svg/nsSVGEffects.cpp
@@ -651,34 +651,49 @@ nsSVGEffects::EffectProperties::GetClipP
     return nullptr;
 
   nsSVGClipPathFrame* frame = static_cast<nsSVGClipPathFrame*>(
     mClipPath->GetReferencedFrame(LayoutFrameType::SVGClipPath, nullptr));
 
   return frame;
 }
 
-nsTArray<nsSVGMaskFrame *>
-nsSVGEffects::EffectProperties::GetMaskFrames()
+MaskSourceArray
+nsSVGEffects::EffectProperties::GetMaskSource()
 {
-  nsTArray<nsSVGMaskFrame *> result;
+  MaskSourceArray result;
   if (!mMask)
     return result;
 
-  bool ok = true;
   const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
   for (size_t i = 0; i < props.Length(); i++) {
+    nsSVGMaskFrame* maskFrame = nullptr;
+    MaskSourceType type = MaskSourceType::Uncertain;
+
     if (props[i]) {
-      nsSVGMaskFrame* maskFrame = static_cast<nsSVGMaskFrame*>(
+      bool ok = true;
+      maskFrame = static_cast<nsSVGMaskFrame*>(
         props[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok));
       MOZ_ASSERT(!maskFrame || ok);
-      result.AppendElement(maskFrame);
+      MOZ_ASSERT_IF(!ok, !maskFrame);
+
+      if (!ok) {
+        type = MaskSourceType::ImageMask;
+      } else {
+        type = maskFrame ? MaskSourceType::SVGMask
+                         : MaskSourceType::Uncertain;
+      }
     } else {
-      result.AppendElement(nullptr);
+      type = MaskSourceType::ImageMask;
     }
+
+    MOZ_ASSERT_IF(type == MaskSourceType::SVGMask, maskFrame);
+    MOZ_ASSERT_IF(type == MaskSourceType::ImageMask ||
+                  type == MaskSourceType::Uncertain, !maskFrame);
+    result.AppendElement(MakePair(type, maskFrame));
   }
 
   return result;
 }
 
 bool
 nsSVGEffects::EffectProperties::HasNoOrValidEffects()
 {
--- a/layout/svg/nsSVGEffects.h
+++ b/layout/svg/nsSVGEffects.h
@@ -418,16 +418,28 @@ public:
    * to them.
    */
   void RemoveAll();
 
 private:
   nsTHashtable<nsPtrHashKey<nsSVGRenderingObserver> > mObservers;
 };
 
+enum class MaskSourceType: uint8_t {
+  Uncertain = 0,  // Initial state, we don't know the tyep of this css
+                  // mask yet. Keep stay in this state before we are certain
+                  // the type of this mask source.
+  SVGMask = 1,    // This css mask is an SVG mask.
+  ImageMask = 2   // This css mask is a mask other than an SVG mask.
+                  // It can be an image mask or a gradient mask, for example.
+};
+
+typedef mozilla::Pair<MaskSourceType, nsSVGMaskFrame*> MaskSource;
+typedef nsTArray<MaskSource> MaskSourceArray;
+
 class nsSVGEffects
 {
 public:
   typedef mozilla::dom::Element Element;
   typedef nsInterfaceHashtable<nsURIHashKey, nsIMutationObserver>
     URIObserverHashtable;
 
   using PaintingPropertyDescriptor =
@@ -474,19 +486,19 @@ public:
     nsSVGPaintingProperty* mClipPath;
 
     /**
      * @return the clip-path frame, or null if there is no clip-path frame
      */
     nsSVGClipPathFrame* GetClipPathFrame();
 
     /**
-     * @return an array which contains all SVG mask frames.
+     * @return an array which contains all mask sources.
      */
-    nsTArray<nsSVGMaskFrame*> GetMaskFrames();
+    MaskSourceArray GetMaskSource();
 
     /*
      * @return true if all effects we have are valid or we have no effect
      * at all.
      */
     bool HasNoOrValidEffects();
 
     /*
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -409,80 +409,90 @@ private:
 typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
 
 /**
  * Paint css-positioned-mask onto a given target(aMaskDT).
  */
 static void
 PaintMaskSurface(const PaintFramesParams& aParams,
                  DrawTarget* aMaskDT, float aOpacity, nsStyleContext* aSC,
-                 const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+                 const MaskSourceArray& aSources,
                  const gfxMatrix& aMaskSurfaceMatrix,
                  const nsPoint& aOffsetToUserSpace)
 {
-  MOZ_ASSERT(aMaskFrames.Length() > 0);
+  MOZ_ASSERT(aSources.Length() > 0);
   MOZ_ASSERT(aMaskDT->GetFormat() == SurfaceFormat::A8);
-  MOZ_ASSERT(aOpacity == 1.0 || aMaskFrames.Length() == 1);
+  MOZ_ASSERT(aOpacity == 1.0 || aSources.Length() == 1);
 
   const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
   gfxMatrix cssPxToDevPxMatrix =
     nsSVGUtils::GetCSSPxToDevPxMatrix(aParams.frame);
 
   nsPresContext* presContext = aParams.frame->PresContext();
   gfxPoint devPixelOffsetToUserSpace =
     nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
                                    presContext->AppUnitsPerDevPixel());
 
   RefPtr<gfxContext> maskContext = gfxContext::CreateOrNull(aMaskDT);
   MOZ_ASSERT(maskContext);
   maskContext->SetMatrix(aMaskSurfaceMatrix);
 
   // Multiple SVG masks interleave with image mask. Paint each layer onto
   // aMaskDT one at a time.
-  for (int i = aMaskFrames.Length() - 1; i >= 0 ; i--) {
-    nsSVGMaskFrame *maskFrame = aMaskFrames[i];
-    CompositionOp compositionOp = (i == int(aMaskFrames.Length() - 1))
+  for (int i = aSources.Length() - 1; i >= 0 ; i--) {
+    MaskSource source = aSources[i];
+    CompositionOp compositionOp = (i == int(aSources.Length() - 1))
       ? CompositionOp::OP_OVER
       : nsCSSRendering::GetGFXCompositeMode(svgReset->mMask.mLayers[i].mComposite);
 
-    // maskFrame != nullptr means we get a SVG mask.
-    // maskFrame == nullptr means we get an image mask.
-    if (maskFrame) {
+    if (source.first() == MaskSourceType::SVGMask) {
+      MOZ_ASSERT(source.second());
+
       Matrix svgMaskMatrix;
       nsSVGMaskFrame::MaskParams params(maskContext, aParams.frame,
                                         cssPxToDevPxMatrix,
                                         aOpacity, &svgMaskMatrix,
                                         svgReset->mMask.mLayers[i].mMaskMode,
                                         aParams.imgParams);
-      RefPtr<SourceSurface> svgMask = maskFrame->GetMaskForMaskedFrame(params);
+      RefPtr<SourceSurface> svgMask =
+       source.second()->GetMaskForMaskedFrame(params);
       if (svgMask) {
         gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
         maskContext->Multiply(ThebesMatrix(svgMaskMatrix));
         aMaskDT->MaskSurface(ColorPattern(Color(0.0, 0.0, 0.0, 1.0)), svgMask,
                              Point(0, 0),
                              DrawOptions(1.0, compositionOp));
       }
-    } else {
+    } else if (source.first() == MaskSourceType::ImageMask) {
+      MOZ_ASSERT(!source.second());
+
       gfxContextMatrixAutoSaveRestore matRestore(maskContext);
 
       maskContext->Multiply(gfxMatrix::Translation(-devPixelOffsetToUserSpace));
       nsCSSRendering::PaintBGParams  params =
         nsCSSRendering::PaintBGParams::ForSingleLayer(*presContext,
                                                       aParams.dirtyRect,
                                                       aParams.borderArea,
                                                       aParams.frame,
                                                       aParams.builder->GetBackgroundPaintFlags() |
                                                       nsCSSRendering::PAINTBG_MASK_IMAGE,
                                                       i, compositionOp,
                                                       aOpacity);
 
       aParams.imgParams.result &=
         nsCSSRendering::PaintStyleImageLayerWithSC(params, *maskContext, aSC,
                                               *aParams.frame->StyleBorder());
+    } else {
+      MOZ_ASSERT(source.first() == MaskSourceType::Uncertain);
+      MOZ_ASSERT(!source.second());
+
+      // We do not know the type of this mask yet. No bother to paint anything,
+      // return DrawResult::NOT_READY directly.
+      aParams.imgParams.result &= DrawResult::NOT_READY;
     }
   }
 }
 
 struct MaskPaintResult {
   RefPtr<SourceSurface> maskSurface;
   Matrix maskTransform;
   bool transparentBlackMask;
@@ -492,36 +502,37 @@ struct MaskPaintResult {
     : transparentBlackMask(false)
     , opacityApplied(false)
   {}
 };
 
 static MaskPaintResult
 CreateAndPaintMaskSurface(const PaintFramesParams& aParams,
                           float aOpacity, nsStyleContext* aSC,
-                          const nsTArray<nsSVGMaskFrame*>& aMaskFrames,
+                          const MaskSourceArray& aSources,
                           const nsPoint& aOffsetToUserSpace)
 {
   const nsStyleSVGReset *svgReset = aSC->StyleSVGReset();
-  MOZ_ASSERT(aMaskFrames.Length() > 0);
+  MOZ_ASSERT(aSources.Length() > 0);
   MaskPaintResult paintResult;
 
   gfxContext& ctx = aParams.ctx;
 
   // Optimization for single SVG mask.
-  if (((aMaskFrames.Length() == 1) && aMaskFrames[0])) {
+  if ((aSources.Length() == 1) &&
+      aSources[0].first() == MaskSourceType::SVGMask) {
     gfxMatrix cssPxToDevPxMatrix =
       nsSVGUtils::GetCSSPxToDevPxMatrix(aParams.frame);
     paintResult.opacityApplied = true;
     nsSVGMaskFrame::MaskParams params(&ctx, aParams.frame, cssPxToDevPxMatrix,
                                       aOpacity, &paintResult.maskTransform,
                                       svgReset->mMask.mLayers[0].mMaskMode,
                                       aParams.imgParams);
     paintResult.maskSurface =
-      aMaskFrames[0]->GetMaskForMaskedFrame(params);
+      aSources[0].second()->GetMaskForMaskedFrame(params);
 
     if (!paintResult.maskSurface) {
       paintResult.transparentBlackMask = true;
     }
 
     return paintResult;
   }
 
@@ -537,26 +548,26 @@ CreateAndPaintMaskSurface(const PaintFra
   if (!maskDT || !maskDT->IsValid()) {
     return paintResult;
   }
 
   // We can paint mask along with opacity only if
   // 1. There is only one mask, or
   // 2. No overlap among masks.
   // Collision detect in #2 is not that trivial, we only accept #1 here.
-  paintResult.opacityApplied = (aMaskFrames.Length() == 1);
+  paintResult.opacityApplied = (aSources.Length() == 1);
 
   // Set context's matrix on maskContext, offset by the maskSurfaceRect's
   // position. This makes sure that we combine the masks in device space.
   gfxMatrix maskSurfaceMatrix =
     ctx.CurrentMatrix() * gfxMatrix::Translation(-aParams.maskRect.TopLeft());
 
   PaintMaskSurface(aParams, maskDT,
                    paintResult.opacityApplied ? aOpacity : 1.0,
-                   aSC, aMaskFrames, maskSurfaceMatrix,
+                   aSC, aSources, maskSurfaceMatrix,
                    aOffsetToUserSpace);
 
   if (aParams.imgParams.result != DrawResult::SUCCESS) {
     // Now we know the status of mask resource since we used it while painting.
     // According to the return value of PaintMaskSurface, we know whether mask
     // resource is resolvable or not.
     //
     // For a HTML doc:
@@ -698,28 +709,27 @@ MoveContextOriginToUserSpace(nsIFrame* a
 
 bool
 nsSVGIntegrationUtils::IsMaskResourceReady(nsIFrame* aFrame)
 {
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
-  nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
+  MaskSourceArray sources = effectProperties.GetMaskSource();
   const nsStyleSVGReset* svgReset = firstFrame->StyleSVGReset();
 
-  for (uint32_t i = 0; i < maskFrames.Length(); i++) {
-    // Refers to a valid SVG mask.
-    if (maskFrames[i]) {
-      continue;
-    }
-
-    // Refers to an external resource, which is not ready yet.
-    if (!svgReset->mMask.mLayers[i].mImage.IsComplete()) {
+  for (uint32_t i = 0; i < sources.Length(); i++) {
+    if (sources[i].first() == MaskSourceType::Uncertain) {
       return false;
+    } else if (sources[i].first() == MaskSourceType::ImageMask) {
+      // Refers to an external resource, which is not ready yet.
+      if (!svgReset->mMask.mLayers[i].mImage.IsComplete()) {
+        return false;
+      }
     }
   }
 
   // Either all mask resources are ready, or no mask resource is needed.
   return true;
 }
 
 class AutoPopGroup
@@ -768,20 +778,20 @@ nsSVGIntegrationUtils::PaintMask(const P
     //
     // Create one extra draw target for drawing positioned mask, so that we do
     // not have to copy the content of maskTarget before painting
     // clip-path into it.
     maskTarget = maskTarget->CreateSimilarDrawTarget(maskTarget->GetSize(),
                                                      SurfaceFormat::A8);
   }
 
-  nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
+  MaskSourceArray sources = effectProperties.GetMaskSource();
   AutoPopGroup autoPop;
   bool shouldPushOpacity = (maskUsage.opacity != 1.0) &&
-                           (maskFrames.Length() != 1);
+                           (sources.Length() != 1);
   if (shouldPushOpacity) {
     ctx.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, maskUsage.opacity);
     autoPop.SetContext(&ctx);
   }
 
   gfxContextMatrixAutoSaveRestore matSR;
 
   // Paint clip-path-basic-shape onto ctx
@@ -806,17 +816,17 @@ nsSVGIntegrationUtils::PaintMask(const P
   // Paint mask onto ctx.
   if (maskUsage.shouldGenerateMaskLayer) {
     matSR.Restore();
     matSR.SetContext(&ctx);
 
     EffectOffsets offsets = MoveContextOriginToUserSpace(frame, aParams);
     PaintMaskSurface(aParams, maskTarget,
                      shouldPushOpacity ?  1.0 : maskUsage.opacity,
-                     firstFrame->StyleContext(), maskFrames,
+                     firstFrame->StyleContext(), sources,
                      ctx.CurrentMatrix(),
                      offsets.offsetToUserSpace);
   }
 
   // Paint clip-path onto ctx.
   if (maskUsage.shouldGenerateClipMaskLayer || maskUsage.shouldApplyClipPath) {
     matSR.Restore();
     matSR.SetContext(&ctx);
@@ -875,17 +885,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
 
   gfxMatrix cssPxToDevPxMatrix = nsSVGUtils::GetCSSPxToDevPxMatrix(frame);
-  nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
+  MaskSourceArray sources = effectProperties.GetMaskSource();
 
   bool shouldGenerateMask = (maskUsage.opacity != 1.0f ||
                              maskUsage.shouldGenerateClipMaskLayer ||
                              maskUsage.shouldGenerateMaskLayer);
   bool shouldPushMask = false;
 
   /* Check if we need to do additional operations on this child's
    * rendering, which necessitates rendering into another surface. */
@@ -901,17 +911,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipP
 
       // For css-mask, we want to generate a mask for each continuation frame,
       // so we setup context matrix by the position of the current frame,
       // instead of the first continuation frame.
       EffectOffsets offsets = MoveContextOriginToUserSpace(frame, aParams);
       MaskPaintResult paintResult =
         CreateAndPaintMaskSurface(aParams, maskUsage.opacity,
                                   firstFrame->StyleContext(),
-                                  maskFrames, offsets.offsetToUserSpace);
+                                  sources, offsets.offsetToUserSpace);
 
       if (paintResult.transparentBlackMask) {
         return;
       }
 
       maskSurface = paintResult.maskSurface;
       if (maskSurface) {
         shouldPushMask = true;
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -505,26 +505,27 @@ nsSVGUtils::DetermineMaskUsage(nsIFrame*
 
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(aFrame);
 
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
   const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
 
-  nsTArray<nsSVGMaskFrame*> maskFrames = effectProperties.GetMaskFrames();
+  MaskSourceArray sources = effectProperties.GetMaskSource();
 
 #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
-  aUsage.shouldGenerateMaskLayer = (maskFrames.Length() > 0);
+  aUsage.shouldGenerateMaskLayer = (sources.Length() > 0);
 #else
   // Since we do not support image mask so far, we should treat any
   // unresolvable mask as no mask. Otherwise, any object with a valid image
   // mask, e.g. url("xxx.png"), will become invisible just because we can not
   // handle image mask correctly. (See bug 1294171)
-  aUsage.shouldGenerateMaskLayer = maskFrames.Length() == 1 && maskFrames[0];
+  aUsage.shouldGenerateMaskLayer =
+    sources.Length() == 1 && sources[0].second();
 #endif
 
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
   MOZ_ASSERT(!clipPathFrame ||
              svgReset->mClipPath.GetType() == StyleShapeSourceType::URL);
 
   switch (svgReset->mClipPath.GetType()) {
     case StyleShapeSourceType::URL:
@@ -739,18 +740,19 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(aFrame);
   if (effectProperties.HasInvalidEffects()) {
     // Some resource is invalid. We shouldn't paint anything.
     return;
   }
 
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame();
-  nsTArray<nsSVGMaskFrame*> masks = effectProperties.GetMaskFrames();
-  nsSVGMaskFrame *maskFrame = masks.IsEmpty() ? nullptr : masks[0];
+  MaskSourceArray sources = effectProperties.GetMaskSource();
+  nsSVGMaskFrame *maskFrame = sources.IsEmpty() ? nullptr
+                                                : sources[0].second();
 
   MixModeBlender blender(aFrame, &aContext);
   gfxContext* target = blender.ShouldCreateDrawTargetForBlend()
                        ? blender.CreateBlendTarget(aTransform) : &aContext;
 
   if (!target) {
     return;
   }