LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGIntegrationUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 220 0 0.0 %
Date: 2012-06-02 Functions: 23 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla SVG project.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is IBM Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   rocallahan@mozilla.com
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "nsSVGIntegrationUtils.h"
      39                 : 
      40                 : #include "nsSVGUtils.h"
      41                 : #include "nsSVGEffects.h"
      42                 : #include "nsRegion.h"
      43                 : #include "nsLayoutUtils.h"
      44                 : #include "nsDisplayList.h"
      45                 : #include "nsSVGFilterPaintCallback.h"
      46                 : #include "nsSVGFilterFrame.h"
      47                 : #include "nsSVGClipPathFrame.h"
      48                 : #include "nsSVGMaskFrame.h"
      49                 : #include "gfxPlatform.h"
      50                 : #include "gfxDrawable.h"
      51                 : #include "nsSVGPaintServerFrame.h"
      52                 : 
      53                 : // ----------------------------------------------------------------------
      54                 : 
      55                 : bool
      56               0 : nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
      57                 : {
      58               0 :   if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
      59               0 :     return false;
      60                 :   }
      61               0 :   const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
      62               0 :   return (style->mFilter || style->mClipPath || style->mMask);
      63                 : }
      64                 : 
      65                 : /* static */ nsRect
      66               0 : nsSVGIntegrationUtils::GetNonSVGUserSpace(nsIFrame* aFirst)
      67                 : {
      68               0 :   NS_ASSERTION(!aFirst->GetPrevContinuation(), "Not first continuation");
      69               0 :   return nsLayoutUtils::GetAllInFlowRectsUnion(aFirst, aFirst);
      70                 : }
      71                 : 
      72                 : static nsRect
      73               0 : GetPreEffectsOverflowRect(nsIFrame* aFrame)
      74                 : {
      75                 :   nsRect* r = static_cast<nsRect*>
      76               0 :     (aFrame->Properties().Get(nsIFrame::PreEffectsBBoxProperty()));
      77               0 :   if (r)
      78               0 :     return *r;
      79               0 :   return aFrame->GetVisualOverflowRect();
      80                 : }
      81                 : 
      82               0 : struct BBoxCollector : public nsLayoutUtils::BoxCallback {
      83                 :   nsIFrame*     mReferenceFrame;
      84                 :   nsIFrame*     mCurrentFrame;
      85                 :   const nsRect& mCurrentFrameOverflowArea;
      86                 :   nsRect        mResult;
      87                 : 
      88               0 :   BBoxCollector(nsIFrame* aReferenceFrame, nsIFrame* aCurrentFrame,
      89                 :                 const nsRect& aCurrentFrameOverflowArea)
      90                 :     : mReferenceFrame(aReferenceFrame), mCurrentFrame(aCurrentFrame),
      91               0 :       mCurrentFrameOverflowArea(aCurrentFrameOverflowArea) {}
      92                 : 
      93               0 :   virtual void AddBox(nsIFrame* aFrame) {
      94                 :     nsRect overflow = aFrame == mCurrentFrame ? mCurrentFrameOverflowArea
      95               0 :         : GetPreEffectsOverflowRect(aFrame);
      96               0 :     mResult.UnionRect(mResult, overflow + aFrame->GetOffsetTo(mReferenceFrame));
      97               0 :   }
      98                 : };
      99                 : 
     100                 : static nsRect
     101               0 : GetSVGBBox(nsIFrame* aNonSVGFrame, nsIFrame* aCurrentFrame,
     102                 :            const nsRect& aCurrentOverflow, const nsRect& aUserSpaceRect)
     103                 : {
     104               0 :   NS_ASSERTION(!aNonSVGFrame->GetPrevContinuation(),
     105                 :                "Need first continuation here");
     106                 :   // Compute union of all overflow areas relative to 'first'.
     107               0 :   BBoxCollector collector(aNonSVGFrame, aCurrentFrame, aCurrentOverflow);
     108               0 :   nsLayoutUtils::GetAllInFlowBoxes(aNonSVGFrame, &collector);
     109                 :   // Get it into "user space" for non-SVG frames
     110               0 :   return collector.mResult - aUserSpaceRect.TopLeft();
     111                 : }
     112                 : 
     113                 : nsRect
     114               0 : nsSVGIntegrationUtils::ComputeFrameEffectsRect(nsIFrame* aFrame,
     115                 :                                                const nsRect& aOverflowRect)
     116                 : {
     117                 :   nsIFrame* firstFrame =
     118               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
     119                 :   nsSVGEffects::EffectProperties effectProperties =
     120               0 :     nsSVGEffects::GetEffectProperties(firstFrame);
     121                 :   nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
     122               0 :     effectProperties.mFilter->GetFilterFrame() : nsnull;
     123               0 :   if (!filterFrame)
     124               0 :     return aOverflowRect;
     125                 : 
     126                 :   // XXX this isn't really right. We can't compute the correct filter
     127                 :   // bbox until all aFrame's continuations have been reflowed.
     128                 :   // but then it's too late to set the overflow areas for the earlier frames.
     129               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
     130               0 :   nsRect r = GetSVGBBox(firstFrame, aFrame, aOverflowRect, userSpaceRect);
     131                 :   // r is relative to user space
     132               0 :   PRUint32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
     133               0 :   nsIntRect p = r.ToOutsidePixels(appUnitsPerDevPixel);
     134               0 :   p = filterFrame->GetFilterBBox(firstFrame, &p);
     135               0 :   r = p.ToAppUnits(appUnitsPerDevPixel);
     136                 :   // Make it relative to aFrame again
     137               0 :   return r + userSpaceRect.TopLeft() - aFrame->GetOffsetTo(firstFrame);
     138                 : }
     139                 : 
     140                 : nsRect
     141               0 : nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(nsIFrame* aFrame,
     142                 :                                                       const nsRect& aInvalidRect)
     143                 : {
     144                 :   // Don't bother calling GetEffectProperties; the filter property should
     145                 :   // already have been set up during reflow/ComputeFrameEffectsRect
     146                 :   nsIFrame* firstFrame =
     147               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
     148                 :   nsSVGEffects::EffectProperties effectProperties =
     149               0 :     nsSVGEffects::GetEffectProperties(firstFrame);
     150               0 :   if (!effectProperties.mFilter)
     151               0 :     return aInvalidRect;
     152                 : 
     153               0 :   nsSVGFilterProperty *prop = nsSVGEffects::GetFilterProperty(firstFrame);
     154               0 :   if (!prop || !prop->IsInObserverList()) {
     155               0 :     return aInvalidRect;
     156                 :   }
     157                 : 
     158               0 :   nsSVGFilterFrame* filterFrame = prop->GetFilterFrame();
     159               0 :   if (!filterFrame) {
     160                 :     // The frame is either not there or not currently available,
     161                 :     // perhaps because we're in the middle of tearing stuff down.
     162                 :     // Be conservative.
     163               0 :     return aFrame->GetVisualOverflowRect();
     164                 :   }
     165                 : 
     166               0 :   PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
     167               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
     168               0 :   nsPoint offset = aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
     169               0 :   nsRect r = aInvalidRect + offset;
     170               0 :   nsIntRect p = r.ToOutsidePixels(appUnitsPerDevPixel);
     171               0 :   p = filterFrame->GetInvalidationBBox(firstFrame, p);
     172               0 :   r = p.ToAppUnits(appUnitsPerDevPixel);
     173               0 :   return r - offset;
     174                 : }
     175                 : 
     176                 : nsRect
     177               0 : nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(nsIFrame* aFrame,
     178                 :                                                        const nsRect& aDamageRect)
     179                 : {
     180                 :   // Don't bother calling GetEffectProperties; the filter property should
     181                 :   // already have been set up during reflow/ComputeFrameEffectsRect
     182                 :   nsIFrame* firstFrame =
     183               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
     184                 :   nsSVGFilterFrame* filterFrame =
     185               0 :     nsSVGEffects::GetFilterFrame(firstFrame);
     186               0 :   if (!filterFrame)
     187               0 :     return aDamageRect;
     188                 :   
     189               0 :   PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
     190               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
     191               0 :   nsPoint offset = aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
     192               0 :   nsRect r = aDamageRect + offset;
     193               0 :   nsIntRect p = r.ToOutsidePixels(appUnitsPerDevPixel);
     194               0 :   p = filterFrame->GetSourceForInvalidArea(firstFrame, p);
     195               0 :   r = p.ToAppUnits(appUnitsPerDevPixel);
     196               0 :   return r - offset;
     197                 : }
     198                 : 
     199                 : bool
     200               0 : nsSVGIntegrationUtils::HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt)
     201                 : {
     202                 :   nsIFrame* firstFrame =
     203               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
     204               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
     205                 :   // get point relative to userSpaceRect
     206               0 :   nsPoint pt = aPt + aFrame->GetOffsetTo(firstFrame) - userSpaceRect.TopLeft();
     207               0 :   return nsSVGUtils::HitTestClip(firstFrame, pt);
     208                 : }
     209                 : 
     210                 : class RegularFramePaintCallback : public nsSVGFilterPaintCallback
     211                 : {
     212                 : public:
     213               0 :   RegularFramePaintCallback(nsDisplayListBuilder* aBuilder,
     214                 :                             nsDisplayList* aInnerList,
     215                 :                             nsIFrame* aFrame,
     216                 :                             const nsPoint& aOffset)
     217                 :     : mBuilder(aBuilder), mInnerList(aInnerList), mFrame(aFrame),
     218               0 :       mOffset(aOffset) {}
     219                 : 
     220               0 :   virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
     221                 :                      const nsIntRect* aDirtyRect)
     222                 :   {
     223               0 :     nsRenderingContext::AutoPushTranslation push(aContext, -mOffset);
     224               0 :     mInnerList->PaintForFrame(mBuilder, aContext, mFrame, nsDisplayList::PAINT_DEFAULT);
     225               0 :   }
     226                 : 
     227                 : private:
     228                 :   nsDisplayListBuilder* mBuilder;
     229                 :   nsDisplayList* mInnerList;
     230                 :   nsIFrame* mFrame;
     231                 :   nsPoint mOffset;
     232                 : };
     233                 : 
     234                 : void
     235               0 : nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
     236                 :                                               nsIFrame* aEffectsFrame,
     237                 :                                               const nsRect& aDirtyRect,
     238                 :                                               nsDisplayListBuilder* aBuilder,
     239                 :                                               nsDisplayList* aInnerList)
     240                 : {
     241                 : #ifdef DEBUG
     242               0 :   nsISVGChildFrame *svgChildFrame = do_QueryFrame(aEffectsFrame);
     243               0 :   NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame");
     244                 : #endif
     245                 : 
     246               0 :   float opacity = aEffectsFrame->GetStyleDisplay()->mOpacity;
     247               0 :   if (opacity == 0.0f)
     248               0 :     return;
     249                 : 
     250                 :   /* Properties are added lazily and may have been removed by a restyle,
     251                 :      so make sure all applicable ones are set again. */
     252                 :   nsIFrame* firstFrame =
     253               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aEffectsFrame);
     254                 :   nsSVGEffects::EffectProperties effectProperties =
     255               0 :     nsSVGEffects::GetEffectProperties(firstFrame);
     256                 : 
     257                 :   /* SVG defines the following rendering model:
     258                 :    *
     259                 :    *  1. Render geometry
     260                 :    *  2. Apply filter
     261                 :    *  3. Apply clipping, masking, group opacity
     262                 :    *
     263                 :    * We follow this, but perform a couple of optimizations:
     264                 :    *
     265                 :    * + Use cairo's clipPath when representable natively (single object
     266                 :    *   clip region).
     267                 :    *
     268                 :    * + Merge opacity and masking if both used together.
     269                 :    */
     270                 : 
     271               0 :   bool isOK = true;
     272               0 :   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
     273               0 :   nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
     274               0 :   nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
     275                 : 
     276               0 :   bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
     277                 : 
     278               0 :   if (!isOK) {
     279                 :     // Some resource is missing. We shouldn't paint anything.
     280               0 :     return;
     281                 :   }
     282                 : 
     283               0 :   gfxContext* gfx = aCtx->ThebesContext();
     284               0 :   gfxMatrix savedCTM = gfx->CurrentMatrix();
     285                 : 
     286                 :   //SVGAutoRenderState autoRenderState(aCtx, SVGAutoRenderState::NORMAL);
     287                 : 
     288               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame) + aBuilder->ToReferenceFrame(firstFrame);
     289               0 :   PRInt32 appUnitsPerDevPixel = aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
     290               0 :   userSpaceRect = userSpaceRect.ToNearestPixels(appUnitsPerDevPixel).ToAppUnits(appUnitsPerDevPixel);
     291               0 :   aCtx->Translate(userSpaceRect.TopLeft());
     292                 : 
     293               0 :   gfxMatrix matrix = GetInitialMatrix(aEffectsFrame);
     294                 : 
     295               0 :   bool complexEffects = false;
     296                 :   /* Check if we need to do additional operations on this child's
     297                 :    * rendering, which necessitates rendering into another surface. */
     298               0 :   if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
     299               0 :     complexEffects = true;
     300               0 :     gfx->Save();
     301               0 :     aCtx->IntersectClip(aEffectsFrame->GetVisualOverflowRect());
     302               0 :     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     303                 :   }
     304                 : 
     305                 :   /* If this frame has only a trivial clipPath, set up cairo's clipping now so
     306                 :    * we can just do normal painting and get it clipped appropriately.
     307                 :    */
     308               0 :   if (clipPathFrame && isTrivialClip) {
     309               0 :     gfx->Save();
     310               0 :     clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
     311                 :   }
     312                 : 
     313                 :   /* Paint the child */
     314               0 :   if (filterFrame) {
     315                 :     RegularFramePaintCallback paint(aBuilder, aInnerList, aEffectsFrame,
     316               0 :                                     userSpaceRect.TopLeft());
     317               0 :     nsIntRect r = (aDirtyRect - userSpaceRect.TopLeft()).ToOutsidePixels(appUnitsPerDevPixel);
     318               0 :     filterFrame->FilterPaint(aCtx, aEffectsFrame, &paint, &r);
     319                 :   } else {
     320               0 :     gfx->SetMatrix(savedCTM);
     321                 :     aInnerList->PaintForFrame(aBuilder, aCtx, aEffectsFrame,
     322               0 :                               nsDisplayList::PAINT_DEFAULT);
     323               0 :     aCtx->Translate(userSpaceRect.TopLeft());
     324                 :   }
     325                 : 
     326               0 :   if (clipPathFrame && isTrivialClip) {
     327               0 :     gfx->Restore();
     328                 :   }
     329                 : 
     330                 :   /* No more effects, we're done. */
     331               0 :   if (!complexEffects) {
     332               0 :     gfx->SetMatrix(savedCTM);
     333                 :     return;
     334                 :   }
     335                 : 
     336               0 :   gfx->PopGroupToSource();
     337                 : 
     338                 :   nsRefPtr<gfxPattern> maskSurface =
     339                 :     maskFrame ? maskFrame->ComputeMaskAlpha(aCtx, aEffectsFrame,
     340               0 :                                             matrix, opacity) : nsnull;
     341                 : 
     342               0 :   nsRefPtr<gfxPattern> clipMaskSurface;
     343               0 :   if (clipPathFrame && !isTrivialClip) {
     344               0 :     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     345                 : 
     346               0 :     nsresult rv = clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
     347               0 :     clipMaskSurface = gfx->PopGroup();
     348                 : 
     349               0 :     if (NS_SUCCEEDED(rv) && clipMaskSurface) {
     350                 :       // Still more set after clipping, so clip to another surface
     351               0 :       if (maskSurface || opacity != 1.0f) {
     352               0 :         gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     353               0 :         gfx->Mask(clipMaskSurface);
     354               0 :         gfx->PopGroupToSource();
     355                 :       } else {
     356               0 :         gfx->Mask(clipMaskSurface);
     357                 :       }
     358                 :     }
     359                 :   }
     360                 : 
     361               0 :   if (maskSurface) {
     362               0 :     gfx->Mask(maskSurface);
     363               0 :   } else if (opacity != 1.0f) {
     364               0 :     gfx->Paint(opacity);
     365                 :   }
     366                 : 
     367               0 :   gfx->Restore();
     368               0 :   gfx->SetMatrix(savedCTM);
     369                 : }
     370                 : 
     371                 : gfxMatrix
     372               0 : nsSVGIntegrationUtils::GetInitialMatrix(nsIFrame* aNonSVGFrame)
     373                 : {
     374               0 :   NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
     375                 :                "SVG frames should not get here");
     376               0 :   PRInt32 appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
     377                 :   float devPxPerCSSPx =
     378               0 :     1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
     379                 : 
     380                 :   return gfxMatrix(devPxPerCSSPx, 0.0,
     381                 :                    0.0, devPxPerCSSPx,
     382               0 :                    0.0, 0.0);
     383                 : }
     384                 : 
     385                 : gfxRect
     386               0 : nsSVGIntegrationUtils::GetSVGRectForNonSVGFrame(nsIFrame* aNonSVGFrame)
     387                 : {
     388               0 :   NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
     389                 :                "SVG frames should not get here");
     390                 :   nsIFrame* firstFrame =
     391               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
     392               0 :   nsRect r = GetNonSVGUserSpace(firstFrame);
     393               0 :   nsPresContext* presContext = firstFrame->PresContext();
     394               0 :   return gfxRect(0, 0, presContext->AppUnitsToFloatCSSPixels(r.width),
     395               0 :                        presContext->AppUnitsToFloatCSSPixels(r.height));
     396                 : }
     397                 : 
     398                 : gfxRect
     399               0 : nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
     400                 : {
     401               0 :   NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
     402                 :                "SVG frames should not get here");
     403                 :   nsIFrame* firstFrame =
     404               0 :     nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
     405               0 :   nsRect userSpaceRect = GetNonSVGUserSpace(firstFrame);
     406               0 :   nsRect r = GetSVGBBox(firstFrame, nsnull, nsRect(), userSpaceRect);
     407               0 :   gfxRect result(r.x, r.y, r.width, r.height);
     408               0 :   nsPresContext* presContext = aNonSVGFrame->PresContext();
     409               0 :   result.ScaleInverse(presContext->AppUnitsPerCSSPixel());
     410                 :   return result;
     411                 : }
     412                 : 
     413               0 : class PaintFrameCallback : public gfxDrawingCallback {
     414                 : public:
     415               0 :   PaintFrameCallback(nsIFrame* aFrame,
     416                 :                      nsIFrame* aTarget,
     417                 :                      const nsSize aPaintServerSize,
     418                 :                      const gfxIntSize aRenderSize)
     419                 :    : mFrame(aFrame)
     420                 :    , mTarget(aTarget)
     421                 :    , mPaintServerSize(aPaintServerSize)
     422               0 :    , mRenderSize(aRenderSize)
     423               0 :   {}
     424                 :   virtual bool operator()(gfxContext* aContext,
     425                 :                             const gfxRect& aFillRect,
     426                 :                             const gfxPattern::GraphicsFilter& aFilter,
     427                 :                             const gfxMatrix& aTransform);
     428                 : private:
     429                 :   nsIFrame* mFrame;
     430                 :   nsIFrame* mTarget;
     431                 :   nsSize mPaintServerSize;
     432                 :   gfxIntSize mRenderSize;
     433                 : };
     434                 : 
     435                 : bool
     436               0 : PaintFrameCallback::operator()(gfxContext* aContext,
     437                 :                                const gfxRect& aFillRect,
     438                 :                                const gfxPattern::GraphicsFilter& aFilter,
     439                 :                                const gfxMatrix& aTransform)
     440                 : {
     441               0 :   if (mFrame->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)
     442               0 :     return false;
     443                 : 
     444               0 :   mFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
     445                 : 
     446               0 :   nsRenderingContext context;
     447               0 :   context.Init(mFrame->PresContext()->DeviceContext(), aContext);
     448               0 :   aContext->Save();
     449                 : 
     450                 :   // Clip to aFillRect so that we don't paint outside.
     451               0 :   aContext->NewPath();
     452               0 :   aContext->Rectangle(aFillRect);
     453               0 :   aContext->Clip();
     454               0 :   gfxMatrix savedMatrix(aContext->CurrentMatrix());
     455                 : 
     456               0 :   aContext->Multiply(gfxMatrix(aTransform).Invert());
     457                 : 
     458                 :   // nsLayoutUtils::PaintFrame will anchor its painting at mFrame. But we want
     459                 :   // to have it anchored at the top left corner of the bounding box of all of
     460                 :   // mFrame's continuations. So we add a translation transform.
     461               0 :   nsRect bbox = nsSVGIntegrationUtils::GetNonSVGUserSpace(mFrame);
     462               0 :   PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
     463               0 :   gfxPoint offset = gfxPoint(bbox.x, bbox.y) / appUnitsPerDevPixel;
     464               0 :   aContext->Multiply(gfxMatrix().Translate(-offset));
     465                 : 
     466                 :   gfxSize paintServerSize =
     467                 :     gfxSize(mPaintServerSize.width, mPaintServerSize.height) /
     468               0 :       mFrame->PresContext()->AppUnitsPerDevPixel();
     469                 : 
     470                 :   // nsLayoutUtils::PaintFrame wants to render with paintServerSize, but we
     471                 :   // want it to render with mRenderSize, so we need to set up a scale transform.
     472               0 :   gfxFloat scaleX = mRenderSize.width / paintServerSize.width;
     473               0 :   gfxFloat scaleY = mRenderSize.height / paintServerSize.height;
     474               0 :   gfxMatrix scaleMatrix = gfxMatrix().Scale(scaleX, scaleY);
     475               0 :   aContext->Multiply(scaleMatrix);
     476                 : 
     477                 :   // Draw.
     478               0 :   nsRect dirty(bbox.x, bbox.y, mPaintServerSize.width, mPaintServerSize.height);
     479                 :   nsLayoutUtils::PaintFrame(&context, mFrame,
     480                 :                             dirty, NS_RGBA(0, 0, 0, 0),
     481                 :                             nsLayoutUtils::PAINT_IN_TRANSFORM |
     482               0 :                             nsLayoutUtils::PAINT_ALL_CONTINUATIONS);
     483                 : 
     484               0 :   aContext->SetMatrix(savedMatrix);
     485               0 :   aContext->Restore();
     486                 : 
     487               0 :   mFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
     488                 : 
     489               0 :   return true;
     490                 : }
     491                 : 
     492                 : static already_AddRefed<gfxDrawable>
     493               0 : DrawableFromPaintServer(nsIFrame*         aFrame,
     494                 :                         nsIFrame*         aTarget,
     495                 :                         const nsSize&     aPaintServerSize,
     496                 :                         const gfxIntSize& aRenderSize)
     497                 : {
     498                 :   // aPaintServerSize is the size that would be filled when using
     499                 :   // background-repeat:no-repeat and background-size:auto. For normal background
     500                 :   // images, this would be the intrinsic size of the image; for gradients and
     501                 :   // patterns this would be the whole target frame fill area.
     502                 :   // aRenderSize is what we will be actually filling after accounting for
     503                 :   // background-size.
     504               0 :   if (aFrame->IsFrameOfType(nsIFrame::eSVGPaintServer)) {
     505                 :     // aFrame is either a pattern or a gradient. These fill the whole target
     506                 :     // frame by default, so aPaintServerSize is the whole target background fill
     507                 :     // area.
     508                 :     nsSVGPaintServerFrame* server =
     509               0 :       static_cast<nsSVGPaintServerFrame*>(aFrame);
     510                 : 
     511                 :     gfxRect overrideBounds(0, 0,
     512               0 :                            aPaintServerSize.width, aPaintServerSize.height);
     513               0 :     overrideBounds.ScaleInverse(aFrame->PresContext()->AppUnitsPerDevPixel());
     514                 :     nsRefPtr<gfxPattern> pattern =
     515               0 :       server->GetPaintServerPattern(aTarget, 1.0, &overrideBounds);
     516                 : 
     517               0 :     if (!pattern)
     518               0 :       return nsnull;
     519                 : 
     520                 :     // pattern is now set up to fill aPaintServerSize. But we want it to
     521                 :     // fill aRenderSize, so we need to add a scaling transform.
     522                 :     // We couldn't just have set overrideBounds to aRenderSize - it would have
     523                 :     // worked for gradients, but for patterns it would result in a different
     524                 :     // pattern size.
     525               0 :     gfxFloat scaleX = overrideBounds.Width() / aRenderSize.width;
     526               0 :     gfxFloat scaleY = overrideBounds.Height() / aRenderSize.height;
     527               0 :     gfxMatrix scaleMatrix = gfxMatrix().Scale(scaleX, scaleY);
     528               0 :     pattern->SetMatrix(scaleMatrix.Multiply(pattern->GetMatrix()));
     529                 :     nsRefPtr<gfxDrawable> drawable =
     530               0 :       new gfxPatternDrawable(pattern, aRenderSize);
     531               0 :     return drawable.forget();
     532                 :   }
     533                 : 
     534                 :   // We don't want to paint into a surface as long as we don't need to, so we
     535                 :   // set up a drawing callback.
     536                 :   nsRefPtr<gfxDrawingCallback> cb =
     537               0 :     new PaintFrameCallback(aFrame, aTarget, aPaintServerSize, aRenderSize);
     538               0 :   nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, aRenderSize);
     539               0 :   return drawable.forget();
     540                 : }
     541                 : 
     542                 : /* static */ void
     543               0 : nsSVGIntegrationUtils::DrawPaintServer(nsRenderingContext* aRenderingContext,
     544                 :                                        nsIFrame*            aTarget,
     545                 :                                        nsIFrame*            aPaintServer,
     546                 :                                        gfxPattern::GraphicsFilter aFilter,
     547                 :                                        const nsRect&        aDest,
     548                 :                                        const nsRect&        aFill,
     549                 :                                        const nsPoint&       aAnchor,
     550                 :                                        const nsRect&        aDirty,
     551                 :                                        const nsSize&        aPaintServerSize)
     552                 : {
     553               0 :   if (aDest.IsEmpty() || aFill.IsEmpty())
     554               0 :     return;
     555                 : 
     556               0 :   PRInt32 appUnitsPerDevPixel = aTarget->PresContext()->AppUnitsPerDevPixel();
     557               0 :   nsRect destSize = aDest - aDest.TopLeft();
     558               0 :   nsIntSize roundedOut = destSize.ToOutsidePixels(appUnitsPerDevPixel).Size();
     559               0 :   gfxIntSize imageSize(roundedOut.width, roundedOut.height);
     560                 :   nsRefPtr<gfxDrawable> drawable =
     561               0 :     DrawableFromPaintServer(aPaintServer, aTarget, aPaintServerSize, imageSize);
     562                 : 
     563               0 :   if (drawable) {
     564                 :     nsLayoutUtils::DrawPixelSnapped(aRenderingContext, drawable, aFilter,
     565               0 :                                     aDest, aFill, aAnchor, aDirty);
     566                 :   }
     567                 : }

Generated by: LCOV version 1.7