LCOV - code coverage report
Current view: top level - layout/svg - nsFilterInstance.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 269 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 28 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : // Main header first:
       7             : #include "nsFilterInstance.h"
       8             : 
       9             : // MFBT headers next:
      10             : #include "mozilla/UniquePtr.h"
      11             : 
      12             : // Keep others in (case-insensitive) order:
      13             : #include "DrawResult.h"
      14             : #include "gfx2DGlue.h"
      15             : #include "gfxContext.h"
      16             : #include "gfxPlatform.h"
      17             : #include "gfxUtils.h"
      18             : #include "mozilla/gfx/Helpers.h"
      19             : #include "mozilla/gfx/PatternHelpers.h"
      20             : #include "nsSVGDisplayableFrame.h"
      21             : #include "nsCSSFilterInstance.h"
      22             : #include "nsSVGFilterInstance.h"
      23             : #include "nsSVGFilterPaintCallback.h"
      24             : #include "nsSVGUtils.h"
      25             : #include "SVGContentUtils.h"
      26             : #include "FilterSupport.h"
      27             : #include "gfx2DGlue.h"
      28             : 
      29             : using namespace mozilla;
      30             : using namespace mozilla::dom;
      31             : using namespace mozilla::gfx;
      32             : using namespace mozilla::image;
      33             : 
      34             : FilterDescription
      35           0 : nsFilterInstance::GetFilterDescription(nsIContent* aFilteredElement,
      36             :                                        const nsTArray<nsStyleFilter>& aFilterChain,
      37             :                                        bool aFilterInputIsTainted,
      38             :                                        const UserSpaceMetrics& aMetrics,
      39             :                                        const gfxRect& aBBox,
      40             :                                        nsTArray<RefPtr<SourceSurface>>& aOutAdditionalImages)
      41             : {
      42           0 :   gfxMatrix identity;
      43             :   nsFilterInstance instance(nullptr, aFilteredElement, aMetrics,
      44             :                             aFilterChain, aFilterInputIsTainted, nullptr,
      45           0 :                             identity, nullptr, nullptr, nullptr, &aBBox);
      46           0 :   if (!instance.IsInitialized()) {
      47           0 :     return FilterDescription();
      48             :   }
      49           0 :   return instance.ExtractDescriptionAndAdditionalImages(aOutAdditionalImages);
      50             : }
      51             : 
      52             : static UniquePtr<UserSpaceMetrics>
      53           0 : UserSpaceMetricsForFrame(nsIFrame* aFrame)
      54             : {
      55           0 :   if (aFrame->GetContent()->IsSVGElement()) {
      56           0 :     nsSVGElement* element = static_cast<nsSVGElement*>(aFrame->GetContent());
      57           0 :     return MakeUnique<SVGElementMetrics>(element);
      58             :   }
      59           0 :   return MakeUnique<NonSVGFrameUserSpaceMetrics>(aFrame);
      60             : }
      61             : 
      62             : void
      63           0 : nsFilterInstance::PaintFilteredFrame(nsIFrame *aFilteredFrame,
      64             :                                      DrawTarget* aDrawTarget,
      65             :                                      const gfxMatrix& aTransform,
      66             :                                      nsSVGFilterPaintCallback *aPaintCallback,
      67             :                                      const nsRegion *aDirtyArea,
      68             :                                      imgDrawingParams& aImgParams)
      69             : {
      70           0 :   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
      71           0 :   UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
      72             :   // Hardcode InputIsTainted to true because we don't want JS to be able to
      73             :   // read the rendered contents of aFilteredFrame.
      74             :   nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
      75           0 :                             *metrics, filterChain, /* InputIsTainted */ true,
      76             :                             aPaintCallback, aTransform, aDirtyArea, nullptr,
      77           0 :                             nullptr, nullptr);
      78           0 :   if (instance.IsInitialized()) {
      79           0 :     instance.Render(aDrawTarget, aImgParams);
      80             :   }
      81           0 : }
      82             : 
      83             : nsRegion
      84           0 : nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
      85             :                                          const nsRegion& aPreFilterDirtyRegion)
      86             : {
      87           0 :   if (aPreFilterDirtyRegion.IsEmpty()) {
      88           0 :     return nsRegion();
      89             :   }
      90             : 
      91           0 :   gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
      92           0 :   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
      93           0 :   UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
      94             :   // Hardcode InputIsTainted to true because we don't want JS to be able to
      95             :   // read the rendered contents of aFilteredFrame.
      96             :   nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
      97           0 :                             *metrics, filterChain, /* InputIsTainted */ true,
      98           0 :                             nullptr, tm, nullptr, &aPreFilterDirtyRegion);
      99           0 :   if (!instance.IsInitialized()) {
     100           0 :     return nsRegion();
     101             :   }
     102             : 
     103             :   // We've passed in the source's dirty area so the instance knows about it.
     104             :   // Now we can ask the instance to compute the area of the filter output
     105             :   // that's dirty.
     106           0 :   return instance.ComputePostFilterDirtyRegion();
     107             : }
     108             : 
     109             : nsRegion
     110           0 : nsFilterInstance::GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
     111             :                                          const nsRegion& aPostFilterDirtyRegion)
     112             : {
     113           0 :   gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
     114           0 :   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
     115           0 :   UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
     116             :   // Hardcode InputIsTainted to true because we don't want JS to be able to
     117             :   // read the rendered contents of aFilteredFrame.
     118             :   nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
     119           0 :                             *metrics, filterChain, /* InputIsTainted */ true,
     120           0 :                             nullptr, tm, &aPostFilterDirtyRegion);
     121           0 :   if (!instance.IsInitialized()) {
     122           0 :     return nsRect();
     123             :   }
     124             : 
     125             :   // Now we can ask the instance to compute the area of the source
     126             :   // that's needed.
     127           0 :   return instance.ComputeSourceNeededRect();
     128             : }
     129             : 
     130             : nsRect
     131           0 : nsFilterInstance::GetPostFilterBounds(nsIFrame *aFilteredFrame,
     132             :                                       const gfxRect *aOverrideBBox,
     133             :                                       const nsRect *aPreFilterBounds)
     134             : {
     135           0 :   MOZ_ASSERT(!(aFilteredFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
     136             :              !(aFilteredFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
     137             :              "Non-display SVG do not maintain visual overflow rects");
     138             : 
     139           0 :   nsRegion preFilterRegion;
     140           0 :   nsRegion* preFilterRegionPtr = nullptr;
     141           0 :   if (aPreFilterBounds) {
     142           0 :     preFilterRegion = *aPreFilterBounds;
     143           0 :     preFilterRegionPtr = &preFilterRegion;
     144             :   }
     145             : 
     146           0 :   gfxMatrix tm = nsSVGUtils::GetCanvasTM(aFilteredFrame);
     147           0 :   auto& filterChain = aFilteredFrame->StyleEffects()->mFilters;
     148           0 :   UniquePtr<UserSpaceMetrics> metrics = UserSpaceMetricsForFrame(aFilteredFrame);
     149             :   // Hardcode InputIsTainted to true because we don't want JS to be able to
     150             :   // read the rendered contents of aFilteredFrame.
     151             :   nsFilterInstance instance(aFilteredFrame, aFilteredFrame->GetContent(),
     152           0 :                             *metrics, filterChain, /* InputIsTainted */ true,
     153             :                             nullptr, tm, nullptr, preFilterRegionPtr,
     154           0 :                             aPreFilterBounds, aOverrideBBox);
     155           0 :   if (!instance.IsInitialized()) {
     156           0 :     return nsRect();
     157             :   }
     158             : 
     159           0 :   return instance.ComputePostFilterExtents();
     160             : }
     161             : 
     162           0 : nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
     163             :                                    nsIContent* aTargetContent,
     164             :                                    const UserSpaceMetrics& aMetrics,
     165             :                                    const nsTArray<nsStyleFilter>& aFilterChain,
     166             :                                    bool aFilterInputIsTainted,
     167             :                                    nsSVGFilterPaintCallback *aPaintCallback,
     168             :                                    const gfxMatrix& aPaintTransform,
     169             :                                    const nsRegion *aPostFilterDirtyRegion,
     170             :                                    const nsRegion *aPreFilterDirtyRegion,
     171             :                                    const nsRect *aPreFilterVisualOverflowRectOverride,
     172           0 :                                    const gfxRect *aOverrideBBox)
     173             :   : mTargetFrame(aTargetFrame)
     174             :   , mTargetContent(aTargetContent)
     175             :   , mMetrics(aMetrics)
     176             :   , mPaintCallback(aPaintCallback)
     177             :   , mPaintTransform(aPaintTransform)
     178           0 :   , mInitialized(false)
     179             : {
     180           0 :   if (aOverrideBBox) {
     181           0 :     mTargetBBox = *aOverrideBBox;
     182             :   } else {
     183           0 :     MOZ_ASSERT(mTargetFrame, "Need to supply a frame when there's no aOverrideBBox");
     184             :     mTargetBBox = nsSVGUtils::GetBBox(mTargetFrame,
     185             :                                       nsSVGUtils::eUseFrameBoundsForOuterSVG |
     186           0 :                                       nsSVGUtils::eBBoxIncludeFillGeometry);
     187             :   }
     188             : 
     189             :   // Compute user space to filter space transforms.
     190           0 :   if (!ComputeUserSpaceToFilterSpaceScale()) {
     191           0 :     return;
     192             :   }
     193             : 
     194           0 :   if (!ComputeTargetBBoxInFilterSpace()) {
     195           0 :     return;
     196             :   }
     197             : 
     198             :   // Get various transforms:
     199             :   gfxMatrix filterToUserSpace(mFilterSpaceToUserSpaceScale.width, 0.0f,
     200             :                               0.0f, mFilterSpaceToUserSpaceScale.height,
     201           0 :                               0.0f, 0.0f);
     202             : 
     203             :   mFilterSpaceToFrameSpaceInCSSPxTransform =
     204           0 :     filterToUserSpace * GetUserSpaceToFrameSpaceInCSSPxTransform();
     205             :   // mFilterSpaceToFrameSpaceInCSSPxTransform is always invertible
     206           0 :   mFrameSpaceInCSSPxToFilterSpaceTransform =
     207             :     mFilterSpaceToFrameSpaceInCSSPxTransform;
     208           0 :   mFrameSpaceInCSSPxToFilterSpaceTransform.Invert();
     209             : 
     210           0 :   nsIntRect targetBounds;
     211           0 :   if (aPreFilterVisualOverflowRectOverride) {
     212             :     targetBounds =
     213           0 :       FrameSpaceToFilterSpace(aPreFilterVisualOverflowRectOverride);
     214           0 :   } else if (mTargetFrame) {
     215           0 :     nsRect preFilterVOR = mTargetFrame->GetPreEffectsVisualOverflowRect();
     216           0 :     targetBounds = FrameSpaceToFilterSpace(&preFilterVOR);
     217             :   }
     218           0 :   mTargetBounds.UnionRect(mTargetBBoxInFilterSpace, targetBounds);
     219             : 
     220             :   // Build the filter graph.
     221           0 :   if (NS_FAILED(BuildPrimitives(aFilterChain, aTargetFrame,
     222             :                                 aFilterInputIsTainted))) {
     223           0 :     return;
     224             :   }
     225             : 
     226             :   // Convert the passed in rects from frame space to filter space:
     227           0 :   mPostFilterDirtyRegion = FrameSpaceToFilterSpace(aPostFilterDirtyRegion);
     228           0 :   mPreFilterDirtyRegion = FrameSpaceToFilterSpace(aPreFilterDirtyRegion);
     229             : 
     230           0 :   mInitialized = true;
     231             : }
     232             : 
     233             : bool
     234           0 : nsFilterInstance::ComputeTargetBBoxInFilterSpace()
     235             : {
     236           0 :   gfxRect targetBBoxInFilterSpace = UserSpaceToFilterSpace(mTargetBBox);
     237           0 :   targetBBoxInFilterSpace.RoundOut();
     238             : 
     239           0 :   return gfxUtils::GfxRectToIntRect(targetBBoxInFilterSpace,
     240           0 :                                     &mTargetBBoxInFilterSpace);
     241             : }
     242             : 
     243             : bool
     244           0 : nsFilterInstance::ComputeUserSpaceToFilterSpaceScale()
     245             : {
     246           0 :   if (mTargetFrame) {
     247           0 :     mUserSpaceToFilterSpaceScale = mPaintTransform.ScaleFactors(true);
     248           0 :     if (mUserSpaceToFilterSpaceScale.width <= 0.0f ||
     249           0 :         mUserSpaceToFilterSpaceScale.height <= 0.0f) {
     250             :       // Nothing should be rendered.
     251           0 :       return false;
     252             :     }
     253             :   } else {
     254           0 :     mUserSpaceToFilterSpaceScale = gfxSize(1.0, 1.0);
     255             :   }
     256             : 
     257           0 :   mFilterSpaceToUserSpaceScale =
     258           0 :     gfxSize(1.0f / mUserSpaceToFilterSpaceScale.width,
     259           0 :             1.0f / mUserSpaceToFilterSpaceScale.height);
     260             : 
     261           0 :   return true;
     262             : }
     263             : 
     264             : gfxRect
     265           0 : nsFilterInstance::UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const
     266             : {
     267           0 :   gfxRect filterSpaceRect = aUserSpaceRect;
     268           0 :   filterSpaceRect.Scale(mUserSpaceToFilterSpaceScale.width,
     269           0 :                         mUserSpaceToFilterSpaceScale.height);
     270           0 :   return filterSpaceRect;
     271             : }
     272             : 
     273             : gfxRect
     274           0 : nsFilterInstance::FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const
     275             : {
     276           0 :   gfxRect userSpaceRect = aFilterSpaceRect;
     277           0 :   userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width,
     278           0 :                       mFilterSpaceToUserSpaceScale.height);
     279           0 :   return userSpaceRect;
     280             : }
     281             : 
     282             : nsresult
     283           0 : nsFilterInstance::BuildPrimitives(const nsTArray<nsStyleFilter>& aFilterChain,
     284             :                                   nsIFrame* aTargetFrame,
     285             :                                   bool aFilterInputIsTainted)
     286             : {
     287           0 :   NS_ASSERTION(!mPrimitiveDescriptions.Length(),
     288             :                "expected to start building primitives from scratch");
     289             : 
     290           0 :   for (uint32_t i = 0; i < aFilterChain.Length(); i++) {
     291             :     bool inputIsTainted =
     292           0 :       mPrimitiveDescriptions.IsEmpty() ? aFilterInputIsTainted :
     293           0 :         mPrimitiveDescriptions.LastElement().IsTainted();
     294           0 :     nsresult rv = BuildPrimitivesForFilter(aFilterChain[i], aTargetFrame, inputIsTainted);
     295           0 :     if (NS_FAILED(rv)) {
     296           0 :       return rv;
     297             :     }
     298             :   }
     299             : 
     300           0 :   mFilterDescription = FilterDescription(mPrimitiveDescriptions);
     301             : 
     302           0 :   return NS_OK;
     303             : }
     304             : 
     305             : nsresult
     306           0 : nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter,
     307             :                                            nsIFrame* aTargetFrame,
     308             :                                            bool aInputIsTainted)
     309             : {
     310           0 :   NS_ASSERTION(mUserSpaceToFilterSpaceScale.width > 0.0f &&
     311             :                mFilterSpaceToUserSpaceScale.height > 0.0f,
     312             :                "scale factors between spaces should be positive values");
     313             : 
     314           0 :   if (aFilter.GetType() == NS_STYLE_FILTER_URL) {
     315             :     // Build primitives for an SVG filter.
     316             :     nsSVGFilterInstance svgFilterInstance(aFilter, aTargetFrame,
     317             :                                           mTargetContent,
     318           0 :                                           mMetrics, mTargetBBox,
     319           0 :                                           mUserSpaceToFilterSpaceScale);
     320           0 :     if (!svgFilterInstance.IsInitialized()) {
     321           0 :       return NS_ERROR_FAILURE;
     322             :     }
     323             : 
     324           0 :     return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages,
     325           0 :                                              aInputIsTainted);
     326             :   }
     327             : 
     328             :   // Build primitives for a CSS filter.
     329             : 
     330             :   // If we don't have a frame, use opaque black for shadows with unspecified
     331             :   // shadow colors.
     332             :   nscolor shadowFallbackColor =
     333           0 :     mTargetFrame ? mTargetFrame->StyleColor()->mColor : NS_RGB(0,0,0);
     334             : 
     335             :   nsCSSFilterInstance cssFilterInstance(aFilter, shadowFallbackColor,
     336             :                                         mTargetBounds,
     337           0 :                                         mFrameSpaceInCSSPxToFilterSpaceTransform);
     338           0 :   return cssFilterInstance.BuildPrimitives(mPrimitiveDescriptions, aInputIsTainted);
     339             : }
     340             : 
     341             : static void
     342           0 : UpdateNeededBounds(const nsIntRegion& aRegion, nsIntRect& aBounds)
     343             : {
     344           0 :   aBounds = aRegion.GetBounds();
     345             : 
     346             :   bool overflow;
     347             :   IntSize surfaceSize =
     348           0 :    nsSVGUtils::ConvertToSurfaceSize(SizeDouble(aBounds.Size()), &overflow);
     349           0 :   if (overflow) {
     350           0 :     aBounds.SizeTo(surfaceSize);
     351             :   }
     352           0 : }
     353             : 
     354             : void
     355           0 : nsFilterInstance::ComputeNeededBoxes()
     356             : {
     357           0 :   if (mPrimitiveDescriptions.IsEmpty())
     358           0 :     return;
     359             : 
     360           0 :   nsIntRegion sourceGraphicNeededRegion;
     361           0 :   nsIntRegion fillPaintNeededRegion;
     362           0 :   nsIntRegion strokePaintNeededRegion;
     363             : 
     364           0 :   FilterSupport::ComputeSourceNeededRegions(
     365             :     mFilterDescription, mPostFilterDirtyRegion,
     366           0 :     sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
     367             : 
     368           0 :   sourceGraphicNeededRegion.And(sourceGraphicNeededRegion, mTargetBounds);
     369             : 
     370           0 :   UpdateNeededBounds(sourceGraphicNeededRegion, mSourceGraphic.mNeededBounds);
     371           0 :   UpdateNeededBounds(fillPaintNeededRegion, mFillPaint.mNeededBounds);
     372           0 :   UpdateNeededBounds(strokePaintNeededRegion, mStrokePaint.mNeededBounds);
     373             : }
     374             : 
     375             : void
     376           0 : nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
     377             :                                    imgDrawingParams& aImgParams)
     378             : {
     379           0 :   MOZ_ASSERT(mTargetFrame);
     380           0 :   nsIntRect neededRect = aSource->mNeededBounds;
     381           0 :   if (neededRect.IsEmpty()) {
     382           0 :     return;
     383             :   }
     384             : 
     385             :   RefPtr<DrawTarget> offscreenDT =
     386           0 :     gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
     387           0 :       neededRect.Size(), SurfaceFormat::B8G8R8A8);
     388           0 :   if (!offscreenDT || !offscreenDT->IsValid()) {
     389           0 :     return;
     390             :   }
     391             : 
     392           0 :   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
     393           0 :   MOZ_ASSERT(ctx); // already checked the draw target above
     394           0 :   gfxContextAutoSaveRestore saver(ctx);
     395             : 
     396           0 :   ctx->SetMatrix(mPaintTransform *
     397           0 :                  gfxMatrix::Translation(-neededRect.TopLeft()));
     398           0 :   GeneralPattern pattern;
     399           0 :   if (aSource == &mFillPaint) {
     400           0 :     nsSVGUtils::MakeFillPatternFor(mTargetFrame, ctx, &pattern, aImgParams);
     401           0 :   } else if (aSource == &mStrokePaint) {
     402           0 :     nsSVGUtils::MakeStrokePatternFor(mTargetFrame, ctx, &pattern, aImgParams);
     403             :   }
     404             : 
     405           0 :   if (pattern.GetPattern()) {
     406           0 :     offscreenDT->FillRect(ToRect(FilterSpaceToUserSpace(ThebesRect(neededRect))),
     407           0 :                           pattern);
     408             :   }
     409             : 
     410           0 :   aSource->mSourceSurface = offscreenDT->Snapshot();
     411           0 :   aSource->mSurfaceRect = neededRect;
     412             : }
     413             : 
     414             : void
     415           0 : nsFilterInstance::BuildSourcePaints(imgDrawingParams& aImgParams)
     416             : {
     417           0 :   if (!mFillPaint.mNeededBounds.IsEmpty()) {
     418           0 :     BuildSourcePaint(&mFillPaint, aImgParams);
     419             :   }
     420             : 
     421           0 :   if (!mStrokePaint.mNeededBounds.IsEmpty()) {
     422           0 :     BuildSourcePaint(&mStrokePaint, aImgParams);
     423             :   }
     424           0 : }
     425             : 
     426             : void
     427           0 : nsFilterInstance::BuildSourceImage(imgDrawingParams& aImgParams)
     428             : {
     429           0 :   MOZ_ASSERT(mTargetFrame);
     430             : 
     431           0 :   nsIntRect neededRect = mSourceGraphic.mNeededBounds;
     432           0 :   if (neededRect.IsEmpty()) {
     433           0 :     return;
     434             :   }
     435             : 
     436             :   RefPtr<DrawTarget> offscreenDT =
     437           0 :     gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
     438           0 :       neededRect.Size(), SurfaceFormat::B8G8R8A8);
     439           0 :   if (!offscreenDT || !offscreenDT->IsValid()) {
     440           0 :     return;
     441             :   }
     442             : 
     443           0 :   gfxRect r = FilterSpaceToUserSpace(ThebesRect(neededRect));
     444           0 :   r.RoundOut();
     445           0 :   nsIntRect dirty;
     446           0 :   if (!gfxUtils::GfxRectToIntRect(r, &dirty)){
     447           0 :     return;
     448             :   }
     449             : 
     450             :   // SVG graphics paint to device space, so we need to set an initial device
     451             :   // space to filter space transform on the gfxContext that SourceGraphic
     452             :   // and SourceAlpha will paint to.
     453             :   //
     454             :   // (In theory it would be better to minimize error by having filtered SVG
     455             :   // graphics temporarily paint to user space when painting the sources and
     456             :   // only set a user space to filter space transform on the gfxContext
     457             :   // (since that would eliminate the transform multiplications from user
     458             :   // space to device space and back again). However, that would make the
     459             :   // code more complex while being hard to get right without introducing
     460             :   // subtle bugs, and in practice it probably makes no real difference.)
     461           0 :   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(offscreenDT);
     462           0 :   MOZ_ASSERT(ctx); // already checked the draw target above
     463           0 :   gfxMatrix devPxToCssPxTM = nsSVGUtils::GetCSSPxToDevPxMatrix(mTargetFrame);
     464           0 :   DebugOnly<bool> invertible = devPxToCssPxTM.Invert();
     465           0 :   MOZ_ASSERT(invertible);
     466           0 :   ctx->SetMatrix(devPxToCssPxTM * mPaintTransform *
     467           0 :                  gfxMatrix::Translation(-neededRect.TopLeft()));
     468             : 
     469           0 :   mPaintCallback->Paint(*ctx, mTargetFrame, mPaintTransform, &dirty, aImgParams);
     470             : 
     471           0 :   mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
     472           0 :   mSourceGraphic.mSurfaceRect = neededRect;
     473             : }
     474             : 
     475             : void
     476           0 : nsFilterInstance::Render(DrawTarget* aDrawTarget, imgDrawingParams& aImgParams)
     477             : {
     478           0 :   MOZ_ASSERT(mTargetFrame, "Need a frame for rendering");
     479             : 
     480           0 :   if (mPrimitiveDescriptions.IsEmpty()) {
     481             :     // An filter without any primitive. Treat it as success and paint nothing.
     482           0 :     return;
     483             :   }
     484             : 
     485             :   nsIntRect filterRect =
     486           0 :     mPostFilterDirtyRegion.GetBounds().Intersect(OutputFilterSpaceBounds());
     487           0 :   if (filterRect.IsEmpty() || mPaintTransform.IsSingular()) {
     488           0 :     return;
     489             :   }
     490             : 
     491           0 :   AutoRestoreTransform autoRestoreTransform(aDrawTarget);
     492             :   Matrix newTM =
     493           0 :     aDrawTarget->GetTransform().PreTranslate(filterRect.x, filterRect.y);
     494           0 :   aDrawTarget->SetTransform(newTM);
     495             : 
     496           0 :   ComputeNeededBoxes();
     497             : 
     498           0 :   BuildSourceImage(aImgParams);
     499           0 :   BuildSourcePaints(aImgParams);
     500             : 
     501           0 :   FilterSupport::RenderFilterDescription(
     502           0 :     aDrawTarget, mFilterDescription, IntRectToRect(filterRect),
     503             :     mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
     504             :     mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
     505             :     mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
     506           0 :     mInputImages, Point(0, 0));
     507             : }
     508             : 
     509             : nsRegion
     510           0 : nsFilterInstance::ComputePostFilterDirtyRegion()
     511             : {
     512           0 :   if (mPreFilterDirtyRegion.IsEmpty() || mPrimitiveDescriptions.IsEmpty()) {
     513           0 :     return nsRegion();
     514             :   }
     515             : 
     516             :   nsIntRegion resultChangeRegion =
     517             :     FilterSupport::ComputeResultChangeRegion(mFilterDescription,
     518           0 :       mPreFilterDirtyRegion, nsIntRegion(), nsIntRegion());
     519           0 :   return FilterSpaceToFrameSpace(resultChangeRegion);
     520             : }
     521             : 
     522             : nsRect
     523           0 : nsFilterInstance::ComputePostFilterExtents()
     524             : {
     525           0 :   if (mPrimitiveDescriptions.IsEmpty()) {
     526           0 :     return nsRect();
     527             :   }
     528             : 
     529             :   nsIntRegion postFilterExtents =
     530           0 :     FilterSupport::ComputePostFilterExtents(mFilterDescription, mTargetBounds);
     531           0 :   return FilterSpaceToFrameSpace(postFilterExtents.GetBounds());
     532             : }
     533             : 
     534             : nsRect
     535           0 : nsFilterInstance::ComputeSourceNeededRect()
     536             : {
     537           0 :   ComputeNeededBoxes();
     538           0 :   return FilterSpaceToFrameSpace(mSourceGraphic.mNeededBounds);
     539             : }
     540             : 
     541             : nsIntRect
     542           0 : nsFilterInstance::OutputFilterSpaceBounds() const
     543             : {
     544           0 :   uint32_t numPrimitives = mPrimitiveDescriptions.Length();
     545           0 :   if (numPrimitives <= 0)
     546           0 :     return nsIntRect();
     547             : 
     548           0 :   return mPrimitiveDescriptions[numPrimitives - 1].PrimitiveSubregion();
     549             : }
     550             : 
     551             : nsIntRect
     552           0 : nsFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const
     553             : {
     554           0 :   nsIntRect rect = OutputFilterSpaceBounds();
     555           0 :   if (aRect) {
     556           0 :     if (aRect->IsEmpty()) {
     557           0 :       return nsIntRect();
     558             :     }
     559             :     gfxRect rectInCSSPx =
     560           0 :       nsLayoutUtils::RectToGfxRect(*aRect, nsPresContext::AppUnitsPerCSSPixel());
     561             :     gfxRect rectInFilterSpace =
     562           0 :       mFrameSpaceInCSSPxToFilterSpaceTransform.TransformBounds(rectInCSSPx);
     563           0 :     rectInFilterSpace.RoundOut();
     564           0 :     nsIntRect intRect;
     565           0 :     if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) {
     566           0 :       rect = intRect;
     567             :     }
     568             :   }
     569           0 :   return rect;
     570             : }
     571             : 
     572             : nsRect
     573           0 : nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const
     574             : {
     575           0 :   if (aRect.IsEmpty()) {
     576           0 :     return nsRect();
     577             :   }
     578           0 :   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
     579           0 :   r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r);
     580             :   // nsLayoutUtils::RoundGfxRectToAppRect rounds out.
     581           0 :   return nsLayoutUtils::RoundGfxRectToAppRect(r, nsPresContext::AppUnitsPerCSSPixel());
     582             : }
     583             : 
     584             : nsIntRegion
     585           0 : nsFilterInstance::FrameSpaceToFilterSpace(const nsRegion* aRegion) const
     586             : {
     587           0 :   if (!aRegion) {
     588           0 :     return OutputFilterSpaceBounds();
     589             :   }
     590           0 :   nsIntRegion result;
     591           0 :   for (auto iter = aRegion->RectIter(); !iter.Done(); iter.Next()) {
     592             :     // FrameSpaceToFilterSpace rounds out, so this works.
     593           0 :     result.Or(result, FrameSpaceToFilterSpace(&iter.Get()));
     594             :   }
     595           0 :   return result;
     596             : }
     597             : 
     598             : nsRegion
     599           0 : nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const
     600             : {
     601           0 :   nsRegion result;
     602           0 :   for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
     603             :     // FilterSpaceToFrameSpace rounds out, so this works.
     604           0 :     result.Or(result, FilterSpaceToFrameSpace(iter.Get()));
     605             :   }
     606           0 :   return result;
     607             : }
     608             : 
     609             : gfxMatrix
     610           0 : nsFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform() const
     611             : {
     612           0 :   if (!mTargetFrame) {
     613           0 :     return gfxMatrix();
     614             :   }
     615           0 :   return gfxMatrix::Translation(-nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mTargetFrame));
     616             : }

Generated by: LCOV version 1.13