layout/svg/nsFilterInstance.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     6 // Main header first:
     7 #include "nsFilterInstance.h"
     9 // Keep others in (case-insensitive) order:
    10 #include "gfxPlatform.h"
    11 #include "gfxUtils.h"
    12 #include "nsISVGChildFrame.h"
    13 #include "nsRenderingContext.h"
    14 #include "nsSVGFilterInstance.h"
    15 #include "nsSVGFilterPaintCallback.h"
    16 #include "nsSVGUtils.h"
    17 #include "SVGContentUtils.h"
    18 #include "FilterSupport.h"
    19 #include "gfx2DGlue.h"
    21 using namespace mozilla;
    22 using namespace mozilla::dom;
    23 using namespace mozilla::gfx;
    25 nsresult
    26 nsFilterInstance::PaintFilteredFrame(nsRenderingContext *aContext,
    27                                      nsIFrame *aFilteredFrame,
    28                                      nsSVGFilterPaintCallback *aPaintCallback,
    29                                      const nsRegion *aDirtyArea,
    30                                      nsIFrame* aTransformRoot)
    31 {
    32   nsFilterInstance instance(aFilteredFrame, aPaintCallback, aDirtyArea,
    33                             nullptr, nullptr, nullptr,
    34                             aTransformRoot);
    35   if (!instance.IsInitialized()) {
    36     return NS_OK;
    37   }
    38   return instance.Render(aContext->ThebesContext());
    39 }
    41 nsRegion
    42 nsFilterInstance::GetPostFilterDirtyArea(nsIFrame *aFilteredFrame,
    43                                          const nsRegion& aPreFilterDirtyRegion)
    44 {
    45   if (aPreFilterDirtyRegion.IsEmpty()) {
    46     return nsRegion();
    47   }
    49   nsFilterInstance instance(aFilteredFrame, nullptr, nullptr,
    50                             &aPreFilterDirtyRegion);
    51   if (!instance.IsInitialized()) {
    52     return nsRegion();
    53   }
    54   // We've passed in the source's dirty area so the instance knows about it.
    55   // Now we can ask the instance to compute the area of the filter output
    56   // that's dirty.
    57   nsRegion dirtyRegion;
    58   nsresult rv = instance.ComputePostFilterDirtyRegion(&dirtyRegion);
    59   if (NS_SUCCEEDED(rv)) {
    60     return dirtyRegion;
    61   }
    62   return nsRegion();
    63 }
    65 nsRegion
    66 nsFilterInstance::GetPreFilterNeededArea(nsIFrame *aFilteredFrame,
    67                                          const nsRegion& aPostFilterDirtyRegion)
    68 {
    69   nsFilterInstance instance(aFilteredFrame, nullptr, &aPostFilterDirtyRegion);
    70   if (!instance.IsInitialized()) {
    71     return nsRect();
    72   }
    73   // Now we can ask the instance to compute the area of the source
    74   // that's needed.
    75   nsRect neededRect;
    76   nsresult rv = instance.ComputeSourceNeededRect(&neededRect);
    77   if (NS_SUCCEEDED(rv)) {
    78     return neededRect;
    79   }
    80   return nsRegion();
    81 }
    83 nsRect
    84 nsFilterInstance::GetPostFilterBounds(nsIFrame *aFilteredFrame,
    85                                       const gfxRect *aOverrideBBox,
    86                                       const nsRect *aPreFilterBounds)
    87 {
    88   MOZ_ASSERT(!(aFilteredFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) ||
    89              !(aFilteredFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY),
    90              "Non-display SVG do not maintain visual overflow rects");
    92   nsRegion preFilterRegion;
    93   nsRegion* preFilterRegionPtr = nullptr;
    94   if (aPreFilterBounds) {
    95     preFilterRegion = *aPreFilterBounds;
    96     preFilterRegionPtr = &preFilterRegion;
    97   }
    98   nsFilterInstance instance(aFilteredFrame, nullptr, nullptr,
    99                             preFilterRegionPtr, aPreFilterBounds,
   100                             aOverrideBBox);
   101   if (!instance.IsInitialized()) {
   102     return nsRect();
   103   }
   104   nsRect bbox;
   105   nsresult rv = instance.ComputePostFilterExtents(&bbox);
   106   if (NS_SUCCEEDED(rv)) {
   107     return bbox;
   108   }
   109   return nsRect();
   110 }
   112 nsFilterInstance::nsFilterInstance(nsIFrame *aTargetFrame,
   113                                    nsSVGFilterPaintCallback *aPaintCallback,
   114                                    const nsRegion *aPostFilterDirtyRegion,
   115                                    const nsRegion *aPreFilterDirtyRegion,
   116                                    const nsRect *aPreFilterVisualOverflowRectOverride,
   117                                    const gfxRect *aOverrideBBox,
   118                                    nsIFrame* aTransformRoot) :
   119   mTargetFrame(aTargetFrame),
   120   mPaintCallback(aPaintCallback),
   121   mTransformRoot(aTransformRoot),
   122   mInitialized(false) {
   124   mTargetBBox = aOverrideBBox ?
   125     *aOverrideBBox : nsSVGUtils::GetBBox(mTargetFrame);
   127   nsresult rv = ComputeUserSpaceToFilterSpaceScale();
   128   if (NS_FAILED(rv)) {
   129     return;
   130   }
   132   rv = BuildPrimitives();
   133   if (NS_FAILED(rv)) {
   134     return;
   135   }
   137   if (mPrimitiveDescriptions.IsEmpty()) {
   138     // Nothing should be rendered.
   139     return;
   140   }
   142   // Get various transforms:
   144   gfxMatrix filterToUserSpace(mFilterSpaceToUserSpaceScale.width, 0.0f,
   145                               0.0f, mFilterSpaceToUserSpaceScale.height,
   146                               0.0f, 0.0f);
   148   // Only used (so only set) when we paint:
   149   if (mPaintCallback) {
   150     mFilterSpaceToDeviceSpaceTransform = filterToUserSpace *
   151               nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING);
   152   }
   154   // Convert the passed in rects from frame to filter space:
   156   mAppUnitsPerCSSPx = mTargetFrame->PresContext()->AppUnitsPerCSSPixel();
   158   mFilterSpaceToFrameSpaceInCSSPxTransform =
   159     filterToUserSpace * GetUserSpaceToFrameSpaceInCSSPxTransform();
   160   // mFilterSpaceToFrameSpaceInCSSPxTransform is always invertible
   161   mFrameSpaceInCSSPxToFilterSpaceTransform =
   162     mFilterSpaceToFrameSpaceInCSSPxTransform;
   163   mFrameSpaceInCSSPxToFilterSpaceTransform.Invert();
   165   mPostFilterDirtyRegion = FrameSpaceToFilterSpace(aPostFilterDirtyRegion);
   166   mPreFilterDirtyRegion = FrameSpaceToFilterSpace(aPreFilterDirtyRegion);
   167   if (aPreFilterVisualOverflowRectOverride) {
   168     mTargetBounds = 
   169       FrameSpaceToFilterSpace(aPreFilterVisualOverflowRectOverride);
   170   } else {
   171     nsRect preFilterVOR = mTargetFrame->GetPreEffectsVisualOverflowRect();
   172     mTargetBounds = FrameSpaceToFilterSpace(&preFilterVOR);
   173   }
   175   mInitialized = true;
   176 }
   178 nsresult
   179 nsFilterInstance::ComputeUserSpaceToFilterSpaceScale()
   180 {
   181   gfxMatrix canvasTransform =
   182     nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_OUTERSVG_TM);
   183   if (canvasTransform.IsSingular()) {
   184     // Nothing should be rendered.
   185     return NS_ERROR_FAILURE;
   186   }
   188   mUserSpaceToFilterSpaceScale = canvasTransform.ScaleFactors(true);
   189   if (mUserSpaceToFilterSpaceScale.width <= 0.0f ||
   190       mUserSpaceToFilterSpaceScale.height <= 0.0f) {
   191     // Nothing should be rendered.
   192     return NS_ERROR_FAILURE;
   193   }
   195   mFilterSpaceToUserSpaceScale = gfxSize(1.0f / mUserSpaceToFilterSpaceScale.width,
   196                                          1.0f / mUserSpaceToFilterSpaceScale.height);
   197   return NS_OK;
   198 }
   200 gfxRect
   201 nsFilterInstance::UserSpaceToFilterSpace(const gfxRect& aUserSpaceRect) const
   202 {
   203   gfxRect filterSpaceRect = aUserSpaceRect;
   204   filterSpaceRect.Scale(mUserSpaceToFilterSpaceScale.width,
   205                         mUserSpaceToFilterSpaceScale.height);
   206   return filterSpaceRect;
   207 }
   209 gfxRect
   210 nsFilterInstance::FilterSpaceToUserSpace(const gfxRect& aFilterSpaceRect) const
   211 {
   212   gfxRect userSpaceRect = aFilterSpaceRect;
   213   userSpaceRect.Scale(mFilterSpaceToUserSpaceScale.width,
   214                       mFilterSpaceToUserSpaceScale.height);
   215   return userSpaceRect;
   216 }
   218 nsresult
   219 nsFilterInstance::BuildPrimitives()
   220 {
   221   NS_ASSERTION(!mPrimitiveDescriptions.Length(),
   222                "expected to start building primitives from scratch");
   224   const nsTArray<nsStyleFilter>& filters = mTargetFrame->StyleSVGReset()->mFilters;
   225   for (uint32_t i = 0; i < filters.Length(); i++) {
   226     nsresult rv = BuildPrimitivesForFilter(filters[i]);
   227     if (NS_FAILED(rv)) {
   228       return rv;
   229     }
   230   }
   231   return NS_OK;
   232 }
   234 nsresult
   235 nsFilterInstance::BuildPrimitivesForFilter(const nsStyleFilter& aFilter)
   236 {
   237   NS_ASSERTION(mUserSpaceToFilterSpaceScale.width > 0.0f &&
   238                mFilterSpaceToUserSpaceScale.height > 0.0f,
   239                "scale factors between spaces should be positive values");
   241   if (aFilter.GetType() == NS_STYLE_FILTER_URL) {
   242     // Build primitives for an SVG filter.
   243     nsSVGFilterInstance svgFilterInstance(aFilter, mTargetFrame, mTargetBBox,
   244                                           mUserSpaceToFilterSpaceScale,
   245                                           mFilterSpaceToUserSpaceScale);
   246     if (!svgFilterInstance.IsInitialized()) {
   247       return NS_ERROR_FAILURE;
   248     }
   250     // For now, we use the last SVG filter region as the overall filter region
   251     // for the filter chain. Eventually, we will compute the overall filter
   252     // using all of the generated FilterPrimitiveDescriptions.
   253     mUserSpaceBounds = svgFilterInstance.GetFilterRegion();
   254     mFilterSpaceBounds = svgFilterInstance.GetFilterSpaceBounds();
   256     // If this overflows, we can at least paint the maximum surface size.
   257     bool overflow;
   258     gfxIntSize surfaceSize =
   259       nsSVGUtils::ConvertToSurfaceSize(mFilterSpaceBounds.Size(), &overflow);
   260     mFilterSpaceBounds.SizeTo(surfaceSize);
   262     return svgFilterInstance.BuildPrimitives(mPrimitiveDescriptions, mInputImages);
   263   }
   265   // Eventually, we will build primitives for CSS filters, too.
   266   return NS_ERROR_FAILURE;
   267 }
   269 void
   270 nsFilterInstance::ComputeNeededBoxes()
   271 {
   272   if (mPrimitiveDescriptions.IsEmpty())
   273     return;
   275   nsIntRegion sourceGraphicNeededRegion;
   276   nsIntRegion fillPaintNeededRegion;
   277   nsIntRegion strokePaintNeededRegion;
   279   FilterDescription filter(mPrimitiveDescriptions, ToIntRect(mFilterSpaceBounds));
   280   FilterSupport::ComputeSourceNeededRegions(
   281     filter, mPostFilterDirtyRegion,
   282     sourceGraphicNeededRegion, fillPaintNeededRegion, strokePaintNeededRegion);
   284   nsIntRect sourceBoundsInt;
   285   gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
   286   sourceBounds.RoundOut();
   287   // Detect possible float->int overflow
   288   if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
   289     return;
   290   sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
   292   sourceGraphicNeededRegion.And(sourceGraphicNeededRegion, sourceBoundsInt);
   294   mSourceGraphic.mNeededBounds = sourceGraphicNeededRegion.GetBounds();
   295   mFillPaint.mNeededBounds = fillPaintNeededRegion.GetBounds();
   296   mStrokePaint.mNeededBounds = strokePaintNeededRegion.GetBounds();
   297 }
   299 nsresult
   300 nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
   301                                    gfxASurface* aTargetSurface,
   302                                    DrawTarget* aTargetDT)
   303 {
   304   nsIntRect neededRect = aSource->mNeededBounds;
   306   RefPtr<DrawTarget> offscreenDT;
   307   nsRefPtr<gfxASurface> offscreenSurface;
   308   nsRefPtr<gfxContext> ctx;
   309   if (aTargetSurface) {
   310     offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
   311       neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA);
   312     if (!offscreenSurface || offscreenSurface->CairoStatus()) {
   313       return NS_ERROR_OUT_OF_MEMORY;
   314     }
   315     ctx = new gfxContext(offscreenSurface);
   316   } else {
   317     offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
   318       ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8);
   319     if (!offscreenDT) {
   320       return NS_ERROR_OUT_OF_MEMORY;
   321     }
   322     ctx = new gfxContext(offscreenDT);
   323   }
   325   ctx->Translate(-neededRect.TopLeft());
   327   nsRefPtr<nsRenderingContext> tmpCtx(new nsRenderingContext());
   328   tmpCtx->Init(mTargetFrame->PresContext()->DeviceContext(), ctx);
   330   gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
   331   gfxContext *gfx = tmpCtx->ThebesContext();
   332   gfx->Multiply(deviceToFilterSpace);
   334   gfx->Save();
   336   gfxMatrix matrix =
   337     nsSVGUtils::GetCanvasTM(mTargetFrame, nsISVGChildFrame::FOR_PAINTING,
   338                             mTransformRoot);
   339   if (!matrix.IsSingular()) {
   340     gfx->Multiply(matrix);
   341     gfx->Rectangle(mUserSpaceBounds);
   342     if ((aSource == &mFillPaint && 
   343          nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) ||
   344         (aSource == &mStrokePaint &&
   345          nsSVGUtils::SetupCairoStrokePaint(mTargetFrame, gfx))) {
   346       gfx->Fill();
   347     }
   348   }
   349   gfx->Restore();
   351   if (offscreenSurface) {
   352     aSource->mSourceSurface =
   353       gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface);
   354   } else {
   355     aSource->mSourceSurface = offscreenDT->Snapshot();
   356   }
   357   aSource->mSurfaceRect = ToIntRect(neededRect);
   359   return NS_OK;
   360 }
   362 nsresult
   363 nsFilterInstance::BuildSourcePaints(gfxASurface* aTargetSurface,
   364                                     DrawTarget* aTargetDT)
   365 {
   366   nsresult rv = NS_OK;
   368   if (!mFillPaint.mNeededBounds.IsEmpty()) {
   369     rv = BuildSourcePaint(&mFillPaint, aTargetSurface, aTargetDT);
   370     NS_ENSURE_SUCCESS(rv, rv);
   371   }
   373   if (!mStrokePaint.mNeededBounds.IsEmpty()) {
   374     rv = BuildSourcePaint(&mStrokePaint, aTargetSurface, aTargetDT);
   375     NS_ENSURE_SUCCESS(rv, rv);
   376   }
   377   return  rv;
   378 }
   380 nsresult
   381 nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface,
   382                                    DrawTarget* aTargetDT)
   383 {
   384   nsIntRect neededRect = mSourceGraphic.mNeededBounds;
   385   if (neededRect.IsEmpty()) {
   386     return NS_OK;
   387   }
   389   RefPtr<DrawTarget> offscreenDT;
   390   nsRefPtr<gfxASurface> offscreenSurface;
   391   nsRefPtr<gfxContext> ctx;
   392   if (aTargetSurface) {
   393     offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
   394       neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA);
   395     if (!offscreenSurface || offscreenSurface->CairoStatus()) {
   396       return NS_ERROR_OUT_OF_MEMORY;
   397     }
   398     ctx = new gfxContext(offscreenSurface);
   399   } else {
   400     offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
   401       ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8);
   402     if (!offscreenDT) {
   403       return NS_ERROR_OUT_OF_MEMORY;
   404     }
   405     ctx = new gfxContext(offscreenDT);
   406   }
   408   ctx->Translate(-neededRect.TopLeft());
   410   nsRefPtr<nsRenderingContext> tmpCtx(new nsRenderingContext());
   411   tmpCtx->Init(mTargetFrame->PresContext()->DeviceContext(), ctx);
   413   gfxRect r = FilterSpaceToUserSpace(neededRect);
   414   r.RoundOut();
   415   nsIntRect dirty;
   416   if (!gfxUtils::GfxRectToIntRect(r, &dirty))
   417     return NS_ERROR_FAILURE;
   419   // SVG graphics paint to device space, so we need to set an initial device
   420   // space to filter space transform on the gfxContext that SourceGraphic
   421   // and SourceAlpha will paint to.
   422   //
   423   // (In theory it would be better to minimize error by having filtered SVG
   424   // graphics temporarily paint to user space when painting the sources and
   425   // only set a user space to filter space transform on the gfxContext
   426   // (since that would eliminate the transform multiplications from user
   427   // space to device space and back again). However, that would make the
   428   // code more complex while being hard to get right without introducing
   429   // subtle bugs, and in practice it probably makes no real difference.)
   430   gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
   431   tmpCtx->ThebesContext()->Multiply(deviceToFilterSpace);
   432   mPaintCallback->Paint(tmpCtx, mTargetFrame, &dirty, mTransformRoot);
   434   RefPtr<SourceSurface> sourceGraphicSource;
   436   if (offscreenSurface) {
   437     sourceGraphicSource =
   438       gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface);
   439   } else {
   440     sourceGraphicSource = offscreenDT->Snapshot();
   441   }
   443   mSourceGraphic.mSourceSurface = sourceGraphicSource;
   444   mSourceGraphic.mSurfaceRect = ToIntRect(neededRect);
   446   return NS_OK;
   447 }
   449 nsresult
   450 nsFilterInstance::Render(gfxContext* aContext)
   451 {
   452   nsIntRect filterRect = mPostFilterDirtyRegion.GetBounds().Intersect(mFilterSpaceBounds);
   453   gfxMatrix ctm = GetFilterSpaceToDeviceSpaceTransform();
   455   if (filterRect.IsEmpty() || ctm.IsSingular()) {
   456     return NS_OK;
   457   }
   459   Matrix oldDTMatrix;
   460   nsRefPtr<gfxASurface> resultImage;
   461   RefPtr<DrawTarget> dt;
   462   if (aContext->IsCairo()) {
   463     resultImage =
   464       gfxPlatform::GetPlatform()->CreateOffscreenSurface(filterRect.Size().ToIntSize(),
   465                                                          gfxContentType::COLOR_ALPHA);
   466     if (!resultImage || resultImage->CairoStatus())
   467       return NS_ERROR_OUT_OF_MEMORY;
   469     // Create a Cairo DrawTarget around resultImage.
   470     dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
   471            resultImage, ToIntSize(filterRect.Size()));
   472   } else {
   473     // When we have a DrawTarget-backed context, we can call DrawFilter
   474     // directly on the target DrawTarget and don't need a temporary DT.
   475     dt = aContext->GetDrawTarget();
   476     oldDTMatrix = dt->GetTransform();
   477     Matrix matrix = ToMatrix(ctm);
   478     matrix.Translate(filterRect.x, filterRect.y);
   479     dt->SetTransform(matrix * oldDTMatrix);
   480   }
   482   ComputeNeededBoxes();
   484   nsresult rv = BuildSourceImage(resultImage, dt);
   485   if (NS_FAILED(rv))
   486     return rv;
   487   rv = BuildSourcePaints(resultImage, dt);
   488   if (NS_FAILED(rv))
   489     return rv;
   491   IntRect filterSpaceBounds = ToIntRect(mFilterSpaceBounds);
   492   FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
   494   FilterSupport::RenderFilterDescription(
   495     dt, filter, ToRect(filterRect),
   496     mSourceGraphic.mSourceSurface, mSourceGraphic.mSurfaceRect,
   497     mFillPaint.mSourceSurface, mFillPaint.mSurfaceRect,
   498     mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
   499     mInputImages);
   501   if (resultImage) {
   502     aContext->Save();
   503     aContext->Multiply(ctm);
   504     aContext->Translate(filterRect.TopLeft());
   505     aContext->SetSource(resultImage);
   506     aContext->Paint();
   507     aContext->Restore();
   508   } else {
   509     dt->SetTransform(oldDTMatrix);
   510   }
   512   return NS_OK;
   513 }
   515 nsresult
   516 nsFilterInstance::ComputePostFilterDirtyRegion(nsRegion* aPostFilterDirtyRegion)
   517 {
   518   *aPostFilterDirtyRegion = nsRegion();
   519   if (mPreFilterDirtyRegion.IsEmpty()) {
   520     return NS_OK;
   521   }
   523   IntRect filterSpaceBounds = ToIntRect(mFilterSpaceBounds);
   524   FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
   525   nsIntRegion resultChangeRegion =
   526     FilterSupport::ComputeResultChangeRegion(filter,
   527       mPreFilterDirtyRegion, nsIntRegion(), nsIntRegion());
   528   *aPostFilterDirtyRegion =
   529     FilterSpaceToFrameSpace(resultChangeRegion);
   530   return NS_OK;
   531 }
   533 nsresult
   534 nsFilterInstance::ComputePostFilterExtents(nsRect* aPostFilterExtents)
   535 {
   536   *aPostFilterExtents = nsRect();
   538   nsIntRect sourceBoundsInt;
   539   gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
   540   sourceBounds.RoundOut();
   541   // Detect possible float->int overflow
   542   if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
   543     return NS_ERROR_FAILURE;
   544   sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
   546   IntRect filterSpaceBounds = ToIntRect(mFilterSpaceBounds);
   547   FilterDescription filter(mPrimitiveDescriptions, filterSpaceBounds);
   548   nsIntRegion postFilterExtents =
   549     FilterSupport::ComputePostFilterExtents(filter, sourceBoundsInt);
   550   *aPostFilterExtents = FilterSpaceToFrameSpace(postFilterExtents.GetBounds());
   551   return NS_OK;
   552 }
   554 nsresult
   555 nsFilterInstance::ComputeSourceNeededRect(nsRect* aDirty)
   556 {
   557   ComputeNeededBoxes();
   558   *aDirty = FilterSpaceToFrameSpace(mSourceGraphic.mNeededBounds);
   560   return NS_OK;
   561 }
   563 nsIntRect
   564 nsFilterInstance::FrameSpaceToFilterSpace(const nsRect* aRect) const
   565 {
   566   nsIntRect rect = mFilterSpaceBounds;
   567   if (aRect) {
   568     if (aRect->IsEmpty()) {
   569       return nsIntRect();
   570     }
   571     gfxRect rectInCSSPx =
   572       nsLayoutUtils::RectToGfxRect(*aRect, mAppUnitsPerCSSPx);
   573     gfxRect rectInFilterSpace =
   574       mFrameSpaceInCSSPxToFilterSpaceTransform.TransformBounds(rectInCSSPx);
   575     rectInFilterSpace.RoundOut();
   576     nsIntRect intRect;
   577     if (gfxUtils::GfxRectToIntRect(rectInFilterSpace, &intRect)) {
   578       rect = intRect;
   579     }
   580   }
   581   return rect;
   582 }
   584 nsRect
   585 nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRect& aRect) const
   586 {
   587   if (aRect.IsEmpty()) {
   588     return nsRect();
   589   }
   590   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
   591   r = mFilterSpaceToFrameSpaceInCSSPxTransform.TransformBounds(r);
   592   // nsLayoutUtils::RoundGfxRectToAppRect rounds out.
   593   return nsLayoutUtils::RoundGfxRectToAppRect(r, mAppUnitsPerCSSPx);
   594 }
   596 nsIntRegion
   597 nsFilterInstance::FrameSpaceToFilterSpace(const nsRegion* aRegion) const
   598 {
   599   if (!aRegion) {
   600     return mFilterSpaceBounds;
   601   }
   602   nsIntRegion result;
   603   nsRegionRectIterator it(*aRegion);
   604   while (const nsRect* r = it.Next()) {
   605     // FrameSpaceToFilterSpace rounds out, so this works.
   606     result.Or(result, FrameSpaceToFilterSpace(r));
   607   }
   608   return result;
   609 }
   611 nsRegion
   612 nsFilterInstance::FilterSpaceToFrameSpace(const nsIntRegion& aRegion) const
   613 {
   614   nsRegion result;
   615   nsIntRegionRectIterator it(aRegion);
   616   while (const nsIntRect* r = it.Next()) {
   617     // FilterSpaceToFrameSpace rounds out, so this works.
   618     result.Or(result, FilterSpaceToFrameSpace(*r));
   619   }
   620   return result;
   621 }
   623 gfxMatrix
   624 nsFilterInstance::GetUserSpaceToFrameSpaceInCSSPxTransform() const
   625 {
   626   return gfxMatrix().Translate(-nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(mTargetFrame));
   627 }

mercurial