LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGFilterInstance.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 322 0 0.0 %
Date: 2012-06-02 Functions: 19 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                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      25                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "nsSVGFilterInstance.h"
      38                 : #include "nsSVGUtils.h"
      39                 : #include "nsIDOMSVGUnitTypes.h"
      40                 : #include "gfxPlatform.h"
      41                 : #include "nsSVGFilterPaintCallback.h"
      42                 : #include "nsSVGFilterElement.h"
      43                 : #include "nsLayoutUtils.h"
      44                 : #include "gfxUtils.h"
      45                 : 
      46                 : float
      47               0 : nsSVGFilterInstance::GetPrimitiveNumber(PRUint8 aCtxType, float aValue) const
      48                 : {
      49                 :   nsSVGLength2 val;
      50                 :   val.Init(aCtxType, 0xff, aValue,
      51               0 :            nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
      52                 : 
      53                 :   float value;
      54               0 :   if (mPrimitiveUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
      55               0 :     value = nsSVGUtils::ObjectSpace(mTargetBBox, &val);
      56                 :   } else {
      57               0 :     value = nsSVGUtils::UserSpace(mTargetFrame, &val);
      58                 :   }
      59                 : 
      60               0 :   switch (aCtxType) {
      61                 :   case nsSVGUtils::X:
      62               0 :     return value * mFilterSpaceSize.width / mFilterRect.Width();
      63                 :   case nsSVGUtils::Y:
      64               0 :     return value * mFilterSpaceSize.height / mFilterRect.Height();
      65                 :   case nsSVGUtils::XY:
      66                 :   default:
      67                 :     return value * nsSVGUtils::ComputeNormalizedHypotenuse(
      68               0 :                      mFilterSpaceSize.width / mFilterRect.Width(),
      69               0 :                      mFilterSpaceSize.height / mFilterRect.Height());
      70                 :   }
      71                 : }
      72                 : 
      73                 : void
      74               0 : nsSVGFilterInstance::ConvertLocation(float aValues[3]) const
      75                 : {
      76                 :   nsSVGLength2 val[4];
      77                 :   val[0].Init(nsSVGUtils::X, 0xff, aValues[0],
      78               0 :               nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
      79               0 :   val[1].Init(nsSVGUtils::Y, 0xff, aValues[1],
      80               0 :               nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
      81                 :   // Dummy width/height values
      82                 :   val[2].Init(nsSVGUtils::X, 0xff, 0,
      83               0 :               nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
      84                 :   val[3].Init(nsSVGUtils::Y, 0xff, 0,
      85               0 :               nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER);
      86                 : 
      87                 :   gfxRect feArea = nsSVGUtils::GetRelativeRect(mPrimitiveUnits,
      88               0 :     val, mTargetBBox, mTargetFrame);
      89               0 :   aValues[0] = feArea.X();
      90               0 :   aValues[1] = feArea.Y();
      91               0 :   aValues[2] = GetPrimitiveNumber(nsSVGUtils::XY, aValues[2]);
      92               0 : }
      93                 : 
      94                 : already_AddRefed<gfxImageSurface>
      95               0 : nsSVGFilterInstance::CreateImage()
      96                 : {
      97                 :   nsRefPtr<gfxImageSurface> surface =
      98                 :     new gfxImageSurface(gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
      99               0 :                         gfxASurface::ImageFormatARGB32);
     100                 : 
     101               0 :   if (!surface || surface->CairoStatus())
     102               0 :     return nsnull;
     103                 : 
     104               0 :   surface->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
     105                 : 
     106               0 :   gfxImageSurface *retval = nsnull;
     107               0 :   surface.swap(retval);
     108               0 :   return retval;
     109                 : }
     110                 : 
     111                 : gfxRect
     112               0 : nsSVGFilterInstance::UserSpaceToFilterSpace(const gfxRect& aRect) const
     113                 : {
     114               0 :   gfxRect r = aRect - mFilterRect.TopLeft();
     115               0 :   r.Scale(mFilterSpaceSize.width / mFilterRect.Width(),
     116               0 :           mFilterSpaceSize.height / mFilterRect.Height());
     117                 :   return r;
     118                 : }
     119                 : 
     120                 : gfxPoint
     121               0 : nsSVGFilterInstance::FilterSpaceToUserSpace(const gfxPoint& aPt) const
     122                 : {
     123               0 :   return gfxPoint(aPt.x * mFilterRect.Width() / mFilterSpaceSize.width + mFilterRect.X(),
     124               0 :                   aPt.y * mFilterRect.Height() / mFilterSpaceSize.height + mFilterRect.Y());
     125                 : }
     126                 : 
     127                 : gfxMatrix
     128               0 : nsSVGFilterInstance::GetUserSpaceToFilterSpaceTransform() const
     129                 : {
     130               0 :   gfxFloat widthScale = mFilterSpaceSize.width / mFilterRect.Width();
     131               0 :   gfxFloat heightScale = mFilterSpaceSize.height / mFilterRect.Height();
     132                 :   return gfxMatrix(widthScale, 0.0f,
     133                 :                    0.0f, heightScale,
     134               0 :                    -mFilterRect.X() * widthScale, -mFilterRect.Y() * heightScale);
     135                 : }
     136                 : 
     137                 : void
     138               0 : nsSVGFilterInstance::ComputeFilterPrimitiveSubregion(PrimitiveInfo* aPrimitive)
     139                 : {
     140               0 :   nsSVGFE* fE = aPrimitive->mFE;
     141                 : 
     142               0 :   gfxRect defaultFilterSubregion(0,0,0,0);
     143               0 :   if (fE->SubregionIsUnionOfRegions()) {
     144               0 :     for (PRUint32 i = 0; i < aPrimitive->mInputs.Length(); ++i) {
     145                 :       defaultFilterSubregion =
     146                 :           defaultFilterSubregion.Union(
     147               0 :               aPrimitive->mInputs[i]->mImage.mFilterPrimitiveSubregion);
     148                 :     }
     149                 :   } else {
     150                 :     defaultFilterSubregion =
     151               0 :       gfxRect(0, 0, mFilterSpaceSize.width, mFilterSpaceSize.height);
     152                 :   }
     153                 : 
     154                 :   gfxRect feArea = nsSVGUtils::GetRelativeRect(mPrimitiveUnits,
     155               0 :     &fE->mLengthAttributes[nsSVGFE::X], mTargetBBox, mTargetFrame);
     156               0 :   gfxRect region = UserSpaceToFilterSpace(feArea);
     157                 : 
     158               0 :   if (!fE->mLengthAttributes[nsSVGFE::X].IsExplicitlySet())
     159               0 :     region.x = defaultFilterSubregion.X();
     160               0 :   if (!fE->mLengthAttributes[nsSVGFE::Y].IsExplicitlySet())
     161               0 :     region.y = defaultFilterSubregion.Y();
     162               0 :   if (!fE->mLengthAttributes[nsSVGFE::WIDTH].IsExplicitlySet())
     163               0 :     region.width = defaultFilterSubregion.Width();
     164               0 :   if (!fE->mLengthAttributes[nsSVGFE::HEIGHT].IsExplicitlySet())
     165               0 :     region.height = defaultFilterSubregion.Height();
     166                 : 
     167                 :   // We currently require filter primitive subregions to be pixel-aligned.
     168                 :   // Following the spec, any pixel partially in the region is included
     169                 :   // in the region.
     170               0 :   region.RoundOut();
     171               0 :   aPrimitive->mImage.mFilterPrimitiveSubregion = region;
     172               0 : }
     173                 : 
     174                 : nsresult
     175               0 : nsSVGFilterInstance::BuildSources()
     176                 : {
     177               0 :   gfxRect filterRegion = gfxRect(0, 0, mFilterSpaceSize.width, mFilterSpaceSize.height);
     178               0 :   mSourceColorAlpha.mImage.mFilterPrimitiveSubregion = filterRegion;
     179               0 :   mSourceAlpha.mImage.mFilterPrimitiveSubregion = filterRegion;
     180                 : 
     181               0 :   nsIntRect sourceBoundsInt;
     182               0 :   gfxRect sourceBounds = UserSpaceToFilterSpace(mTargetBBox);
     183               0 :   sourceBounds.RoundOut();
     184                 :   // Detect possible float->int overflow
     185               0 :   if (!gfxUtils::GfxRectToIntRect(sourceBounds, &sourceBoundsInt))
     186               0 :     return NS_ERROR_FAILURE;
     187               0 :   sourceBoundsInt.UnionRect(sourceBoundsInt, mTargetBounds);
     188                 : 
     189               0 :   mSourceColorAlpha.mResultBoundingBox = sourceBoundsInt;
     190               0 :   mSourceAlpha.mResultBoundingBox = sourceBoundsInt;
     191               0 :   return NS_OK;
     192                 : }
     193                 : 
     194                 : nsresult
     195               0 : nsSVGFilterInstance::BuildPrimitives()
     196                 : {
     197                 :   // First build mFilterInfo. It's important that we don't change that
     198                 :   // array after we start storing pointers to its elements!
     199               0 :   PRUint32 count = mFilterElement->GetChildCount();
     200                 :   PRUint32 i;
     201               0 :   for (i = 0; i < count; ++i) {
     202               0 :     nsIContent* child = mFilterElement->GetChildAt(i);
     203               0 :     nsRefPtr<nsSVGFE> primitive;
     204               0 :     CallQueryInterface(child, (nsSVGFE**)getter_AddRefs(primitive));
     205               0 :     if (!primitive)
     206               0 :       continue;
     207                 : 
     208               0 :     PrimitiveInfo* info = mPrimitives.AppendElement();
     209               0 :     info->mFE = primitive;
     210                 :   }
     211                 : 
     212                 :   // Now fill in all the links
     213               0 :   nsTHashtable<ImageAnalysisEntry> imageTable;
     214               0 :   imageTable.Init(10);
     215                 : 
     216               0 :   for (i = 0; i < mPrimitives.Length(); ++i) {
     217               0 :     PrimitiveInfo* info = &mPrimitives[i];
     218               0 :     nsSVGFE* filter = info->mFE;
     219               0 :     nsAutoTArray<nsSVGStringInfo,2> sources;
     220               0 :     filter->GetSourceImageNames(sources);
     221                 :  
     222               0 :     for (PRUint32 j=0; j<sources.Length(); ++j) {
     223               0 :       nsAutoString str;
     224               0 :       sources[j].mString->GetAnimValue(str, sources[j].mElement);
     225                 :       PrimitiveInfo* sourceInfo;
     226                 : 
     227               0 :       if (str.EqualsLiteral("SourceGraphic")) {
     228               0 :         sourceInfo = &mSourceColorAlpha;
     229               0 :       } else if (str.EqualsLiteral("SourceAlpha")) {
     230               0 :         sourceInfo = &mSourceAlpha;
     231               0 :       } else if (str.EqualsLiteral("BackgroundImage") ||
     232               0 :                  str.EqualsLiteral("BackgroundAlpha") ||
     233               0 :                  str.EqualsLiteral("FillPaint") ||
     234               0 :                  str.EqualsLiteral("StrokePaint")) {
     235               0 :         return NS_ERROR_NOT_IMPLEMENTED;
     236               0 :       } else if (str.EqualsLiteral("")) {
     237               0 :         sourceInfo = i == 0 ? &mSourceColorAlpha : &mPrimitives[i - 1];
     238                 :       } else {
     239               0 :         ImageAnalysisEntry* entry = imageTable.GetEntry(str);
     240               0 :         if (!entry)
     241               0 :           return NS_ERROR_FAILURE;
     242               0 :         sourceInfo = entry->mInfo;
     243                 :       }
     244                 :       
     245               0 :       ++sourceInfo->mImageUsers;
     246               0 :       info->mInputs.AppendElement(sourceInfo);
     247                 :     }
     248                 : 
     249               0 :     ComputeFilterPrimitiveSubregion(info);
     250                 : 
     251               0 :     nsAutoString str;
     252               0 :     filter->GetResultImageName().GetAnimValue(str, filter);
     253                 : 
     254               0 :     ImageAnalysisEntry* entry = imageTable.PutEntry(str);
     255               0 :     if (entry) {
     256               0 :       entry->mInfo = info;
     257                 :     }
     258                 :     
     259                 :     // The last filter primitive is the filter result, so mark it used
     260               0 :     if (i == mPrimitives.Length() - 1) {
     261               0 :       ++info->mImageUsers;
     262                 :     }
     263                 :   }
     264                 : 
     265               0 :   return NS_OK;
     266                 : }
     267                 : 
     268                 : void
     269               0 : nsSVGFilterInstance::ComputeResultBoundingBoxes()
     270                 : {
     271               0 :   for (PRUint32 i = 0; i < mPrimitives.Length(); ++i) {
     272               0 :     PrimitiveInfo* info = &mPrimitives[i];
     273               0 :     nsAutoTArray<nsIntRect,2> sourceBBoxes;
     274               0 :     for (PRUint32 j = 0; j < info->mInputs.Length(); ++j) {
     275               0 :       sourceBBoxes.AppendElement(info->mInputs[j]->mResultBoundingBox);
     276                 :     }
     277                 :     
     278               0 :     nsIntRect resultBBox = info->mFE->ComputeTargetBBox(sourceBBoxes, *this);
     279               0 :     ClipToFilterSpace(&resultBBox);
     280               0 :     nsSVGUtils::ClipToGfxRect(&resultBBox, info->mImage.mFilterPrimitiveSubregion);
     281               0 :     info->mResultBoundingBox = resultBBox;
     282                 :   }
     283               0 : }
     284                 : 
     285                 : void
     286               0 : nsSVGFilterInstance::ComputeResultChangeBoxes()
     287                 : {
     288               0 :   for (PRUint32 i = 0; i < mPrimitives.Length(); ++i) {
     289               0 :     PrimitiveInfo* info = &mPrimitives[i];
     290               0 :     nsAutoTArray<nsIntRect,2> sourceChangeBoxes;
     291               0 :     for (PRUint32 j = 0; j < info->mInputs.Length(); ++j) {
     292               0 :       sourceChangeBoxes.AppendElement(info->mInputs[j]->mResultChangeBox);
     293                 :     }
     294                 : 
     295               0 :     nsIntRect resultChangeBox = info->mFE->ComputeChangeBBox(sourceChangeBoxes, *this);
     296               0 :     info->mResultChangeBox.IntersectRect(resultChangeBox, info->mResultBoundingBox);
     297                 :   }
     298               0 : }
     299                 : 
     300                 : void
     301               0 : nsSVGFilterInstance::ComputeNeededBoxes()
     302                 : {
     303               0 :   if (mPrimitives.IsEmpty())
     304               0 :     return;
     305                 : 
     306                 :   // In the end, we need whatever the final filter primitive will draw that
     307                 :   // intersects the destination dirty area.
     308               0 :   mPrimitives[mPrimitives.Length() - 1].mResultNeededBox.IntersectRect(
     309               0 :     mPrimitives[mPrimitives.Length() - 1].mResultBoundingBox, mDirtyOutputRect);
     310                 : 
     311               0 :   for (PRInt32 i = mPrimitives.Length() - 1; i >= 0; --i) {
     312               0 :     PrimitiveInfo* info = &mPrimitives[i];
     313               0 :     nsAutoTArray<nsIntRect,2> sourceBBoxes;
     314               0 :     for (PRUint32 j = 0; j < info->mInputs.Length(); ++j) {
     315               0 :       sourceBBoxes.AppendElement(info->mInputs[j]->mResultBoundingBox);
     316                 :     }
     317                 :     
     318                 :     info->mFE->ComputeNeededSourceBBoxes(
     319               0 :       info->mResultNeededBox, sourceBBoxes, *this);
     320                 :     // Update each source with the rectangle we need
     321               0 :     for (PRUint32 j = 0; j < info->mInputs.Length(); ++j) {
     322               0 :       nsIntRect* r = &info->mInputs[j]->mResultNeededBox;
     323               0 :       r->UnionRect(*r, sourceBBoxes[j]);
     324                 :       // Keep everything within the filter effects region
     325               0 :       ClipToFilterSpace(r);
     326               0 :       nsSVGUtils::ClipToGfxRect(r, info->mInputs[j]->mImage.mFilterPrimitiveSubregion);
     327                 :     }
     328                 :   }
     329                 : }
     330                 : 
     331                 : nsIntRect
     332               0 : nsSVGFilterInstance::ComputeUnionOfAllNeededBoxes()
     333                 : {
     334               0 :   nsIntRect r;
     335                 :   r.UnionRect(mSourceColorAlpha.mResultNeededBox,
     336               0 :               mSourceAlpha.mResultNeededBox);
     337               0 :   for (PRUint32 i = 0; i < mPrimitives.Length(); ++i) {
     338               0 :     r.UnionRect(r, mPrimitives[i].mResultNeededBox);
     339                 :   }
     340                 :   return r;
     341                 : }
     342                 : 
     343                 : nsresult
     344               0 : nsSVGFilterInstance::BuildSourceImages()
     345                 : {
     346               0 :   nsIntRect neededRect;
     347                 :   neededRect.UnionRect(mSourceColorAlpha.mResultNeededBox,
     348               0 :                        mSourceAlpha.mResultNeededBox);
     349               0 :   if (neededRect.IsEmpty())
     350               0 :     return NS_OK;
     351                 : 
     352               0 :   nsRefPtr<gfxImageSurface> sourceColorAlpha = CreateImage();
     353               0 :   if (!sourceColorAlpha)
     354               0 :     return NS_ERROR_OUT_OF_MEMORY;
     355                 : 
     356                 :   {
     357                 :     // Paint to an offscreen surface first, then copy it to an image
     358                 :     // surface. This can be faster especially when the stuff we're painting
     359                 :     // contains native themes.
     360                 :     nsRefPtr<gfxASurface> offscreen =
     361               0 :       gfxPlatform::GetPlatform()->CreateOffscreenSurface(
     362                 :               gfxIntSize(mSurfaceRect.width, mSurfaceRect.height),
     363               0 :               gfxASurface::CONTENT_COLOR_ALPHA);
     364               0 :     if (!offscreen || offscreen->CairoStatus())
     365               0 :       return NS_ERROR_OUT_OF_MEMORY;
     366               0 :     offscreen->SetDeviceOffset(gfxPoint(-mSurfaceRect.x, -mSurfaceRect.y));
     367                 : 
     368               0 :     nsRenderingContext tmpCtx;
     369               0 :     tmpCtx.Init(mTargetFrame->PresContext()->DeviceContext(), offscreen);
     370               0 :     gfxMatrix userSpaceToFilterSpace = GetUserSpaceToFilterSpaceTransform();
     371                 : 
     372               0 :     gfxRect r(neededRect.x, neededRect.y, neededRect.width, neededRect.height);
     373               0 :     gfxMatrix m = userSpaceToFilterSpace;
     374               0 :     m.Invert();
     375               0 :     r = m.TransformBounds(r);
     376               0 :     r.RoundOut();
     377               0 :     nsIntRect dirty;
     378               0 :     if (!gfxUtils::GfxRectToIntRect(r, &dirty))
     379               0 :       return NS_ERROR_FAILURE;
     380                 : 
     381                 :     // SVG graphics paint to device space, so we need to set an initial device
     382                 :     // space to filter space transform on the gfxContext that SourceGraphic
     383                 :     // and SourceAlpha will paint to.
     384                 :     //
     385                 :     // (In theory it would be better to minimize error by having filtered SVG
     386                 :     // graphics temporarily paint to user space when painting the sources and
     387                 :     // only set a user space to filter space transform on the gfxContext
     388                 :     // (since that would eliminate the transform multiplications from user
     389                 :     // space to device space and back again). However, that would make the
     390                 :     // code more complex while being hard to get right without introducing
     391                 :     // subtle bugs, and in practice it probably makes no real difference.)
     392               0 :     gfxMatrix deviceToFilterSpace = GetFilterSpaceToDeviceSpaceTransform().Invert();
     393               0 :     tmpCtx.ThebesContext()->Multiply(deviceToFilterSpace);
     394               0 :     mPaintCallback->Paint(&tmpCtx, mTargetFrame, &dirty);
     395                 : 
     396               0 :     gfxContext copyContext(sourceColorAlpha);
     397               0 :     copyContext.SetSource(offscreen);
     398               0 :     copyContext.Paint();
     399                 :   }
     400                 : 
     401               0 :   if (!mSourceColorAlpha.mResultNeededBox.IsEmpty()) {
     402               0 :     NS_ASSERTION(mSourceColorAlpha.mImageUsers > 0, "Some user must have needed this");
     403               0 :     mSourceColorAlpha.mImage.mImage = sourceColorAlpha;
     404                 :     // color model is PREMULTIPLIED SRGB by default.
     405                 :   }
     406                 : 
     407               0 :   if (!mSourceAlpha.mResultNeededBox.IsEmpty()) {
     408               0 :     NS_ASSERTION(mSourceAlpha.mImageUsers > 0, "Some user must have needed this");
     409                 : 
     410               0 :     mSourceAlpha.mImage.mImage = CreateImage();
     411               0 :     if (!mSourceAlpha.mImage.mImage)
     412               0 :       return NS_ERROR_OUT_OF_MEMORY;
     413                 :     // color model is PREMULTIPLIED SRGB by default.
     414                 : 
     415                 :     // Clear the color channel
     416               0 :     const PRUint32* src = reinterpret_cast<PRUint32*>(sourceColorAlpha->Data());
     417               0 :     PRUint32* dest = reinterpret_cast<PRUint32*>(mSourceAlpha.mImage.mImage->Data());
     418               0 :     for (PRInt32 y = 0; y < mSurfaceRect.height; y++) {
     419               0 :       PRUint32 rowOffset = (mSourceAlpha.mImage.mImage->Stride()*y) >> 2;
     420               0 :       for (PRInt32 x = 0; x < mSurfaceRect.width; x++) {
     421               0 :         dest[rowOffset + x] = src[rowOffset + x] & 0xFF000000U;
     422                 :       }
     423                 :     }
     424               0 :     mSourceAlpha.mImage.mConstantColorChannels = true;
     425                 :   }
     426                 :   
     427               0 :   return NS_OK;
     428                 : }
     429                 : 
     430                 : void
     431               0 : nsSVGFilterInstance::EnsureColorModel(PrimitiveInfo* aPrimitive,
     432                 :                                       ColorModel aColorModel)
     433                 : {
     434               0 :   ColorModel currentModel = aPrimitive->mImage.mColorModel;
     435               0 :   if (aColorModel == currentModel)
     436               0 :     return;
     437                 : 
     438               0 :   PRUint8* data = aPrimitive->mImage.mImage->Data();
     439               0 :   PRInt32 stride = aPrimitive->mImage.mImage->Stride();
     440                 : 
     441               0 :   nsIntRect r = aPrimitive->mResultNeededBox - mSurfaceRect.TopLeft();
     442                 : 
     443               0 :   if (currentModel.mAlphaChannel == ColorModel::PREMULTIPLIED) {
     444               0 :     nsSVGUtils::UnPremultiplyImageDataAlpha(data, stride, r);
     445                 :   }
     446               0 :   if (aColorModel.mColorSpace != currentModel.mColorSpace) {
     447               0 :     if (aColorModel.mColorSpace == ColorModel::LINEAR_RGB) {
     448               0 :       nsSVGUtils::ConvertImageDataToLinearRGB(data, stride, r);
     449                 :     } else {
     450               0 :       nsSVGUtils::ConvertImageDataFromLinearRGB(data, stride, r);
     451                 :     }
     452                 :   }
     453               0 :   if (aColorModel.mAlphaChannel == ColorModel::PREMULTIPLIED) {
     454               0 :     nsSVGUtils::PremultiplyImageDataAlpha(data, stride, r);
     455                 :   }
     456               0 :   aPrimitive->mImage.mColorModel = aColorModel;
     457                 : }
     458                 : 
     459                 : nsresult
     460               0 : nsSVGFilterInstance::Render(gfxASurface** aOutput)
     461                 : {
     462               0 :   *aOutput = nsnull;
     463                 : 
     464               0 :   nsresult rv = BuildSources();
     465               0 :   if (NS_FAILED(rv))
     466               0 :     return rv;
     467                 : 
     468               0 :   rv = BuildPrimitives();
     469               0 :   if (NS_FAILED(rv))
     470               0 :     return rv;
     471                 : 
     472               0 :   if (mPrimitives.IsEmpty()) {
     473                 :     // Nothing should be rendered.
     474               0 :     return NS_OK;
     475                 :   }
     476                 : 
     477               0 :   ComputeResultBoundingBoxes();
     478               0 :   ComputeNeededBoxes();
     479                 :   // For now, we make all surface sizes equal to the union of the
     480                 :   // bounding boxes needed for each temporary image
     481               0 :   mSurfaceRect = ComputeUnionOfAllNeededBoxes();
     482                 : 
     483               0 :   rv = BuildSourceImages();
     484               0 :   if (NS_FAILED(rv))
     485               0 :     return rv;
     486                 : 
     487               0 :   for (PRUint32 i = 0; i < mPrimitives.Length(); ++i) {
     488               0 :     PrimitiveInfo* primitive = &mPrimitives[i];
     489                 : 
     490               0 :     nsIntRect dataRect;
     491                 :     // Since mResultNeededBox is clipped to the filter primitive subregion,
     492                 :     // dataRect is also limited to the filter primitive subregion.
     493               0 :     if (!dataRect.IntersectRect(primitive->mResultNeededBox, mSurfaceRect))
     494               0 :       continue;
     495               0 :     dataRect -= mSurfaceRect.TopLeft();
     496                 : 
     497               0 :     primitive->mImage.mImage = CreateImage();
     498               0 :     if (!primitive->mImage.mImage)
     499               0 :       return NS_ERROR_OUT_OF_MEMORY;
     500                 : 
     501               0 :     nsAutoTArray<const Image*,2> inputs;
     502               0 :     for (PRUint32 j = 0; j < primitive->mInputs.Length(); ++j) {
     503               0 :       PrimitiveInfo* input = primitive->mInputs[j];
     504                 :       
     505               0 :       if (!input->mImage.mImage) {
     506                 :         // This image data is not really going to be used, but we'd better
     507                 :         // have an image object here so the filter primitive doesn't die.
     508               0 :         input->mImage.mImage = CreateImage();
     509               0 :         if (!input->mImage.mImage)
     510               0 :           return NS_ERROR_OUT_OF_MEMORY;
     511                 :       }
     512                 :       
     513                 :       ColorModel desiredColorModel =
     514               0 :         primitive->mFE->GetInputColorModel(this, j, &input->mImage);
     515               0 :       if (j == 0) {
     516                 :         // the output colour model is whatever in1 is if there is an in1
     517               0 :         primitive->mImage.mColorModel = desiredColorModel;
     518                 :       }
     519               0 :       EnsureColorModel(input, desiredColorModel);
     520               0 :       NS_ASSERTION(input->mImage.mImage->Stride() == primitive->mImage.mImage->Stride(),
     521                 :                    "stride mismatch");
     522               0 :       inputs.AppendElement(&input->mImage);
     523                 :     }
     524                 : 
     525               0 :     if (primitive->mInputs.Length() == 0) {
     526               0 :       primitive->mImage.mColorModel = primitive->mFE->GetOutputColorModel(this);
     527                 :     }
     528                 : 
     529               0 :     rv = primitive->mFE->Filter(this, inputs, &primitive->mImage, dataRect);
     530               0 :     if (NS_FAILED(rv))
     531               0 :       return rv;
     532                 : 
     533               0 :     for (PRUint32 j = 0; j < primitive->mInputs.Length(); ++j) {
     534               0 :       PrimitiveInfo* input = primitive->mInputs[j];
     535               0 :       --input->mImageUsers;
     536               0 :       NS_ASSERTION(input->mImageUsers >= 0, "Bad mImageUsers tracking");
     537               0 :       if (input->mImageUsers == 0) {
     538                 :         // Release the image, it's no longer needed
     539               0 :         input->mImage.mImage = nsnull;
     540                 :       }
     541                 :     }
     542                 :   }
     543                 :   
     544               0 :   PrimitiveInfo* result = &mPrimitives[mPrimitives.Length() - 1];
     545               0 :   ColorModel premulSRGB; // default
     546               0 :   EnsureColorModel(result, premulSRGB);
     547               0 :   gfxImageSurface* surf = nsnull;
     548               0 :   result->mImage.mImage.swap(surf);
     549               0 :   *aOutput = surf;
     550               0 :   return NS_OK;
     551                 : }
     552                 : 
     553                 : nsresult
     554               0 : nsSVGFilterInstance::ComputeOutputDirtyRect(nsIntRect* aDirty)
     555                 : {
     556               0 :   *aDirty = nsIntRect();
     557                 : 
     558               0 :   nsresult rv = BuildSources();
     559               0 :   if (NS_FAILED(rv))
     560               0 :     return rv;
     561                 : 
     562               0 :   rv = BuildPrimitives();
     563               0 :   if (NS_FAILED(rv))
     564               0 :     return rv;
     565                 : 
     566               0 :   if (mPrimitives.IsEmpty()) {
     567                 :     // Nothing should be rendered, so nothing can be dirty.
     568               0 :     return NS_OK;
     569                 :   }
     570                 : 
     571               0 :   ComputeResultBoundingBoxes();
     572                 : 
     573               0 :   mSourceColorAlpha.mResultChangeBox = mDirtyInputRect;
     574               0 :   mSourceAlpha.mResultChangeBox = mDirtyInputRect;
     575               0 :   ComputeResultChangeBoxes();
     576                 : 
     577               0 :   PrimitiveInfo* result = &mPrimitives[mPrimitives.Length() - 1];
     578               0 :   *aDirty = result->mResultChangeBox;
     579               0 :   return NS_OK;
     580                 : }
     581                 : 
     582                 : nsresult
     583               0 : nsSVGFilterInstance::ComputeSourceNeededRect(nsIntRect* aDirty)
     584                 : {
     585               0 :   nsresult rv = BuildSources();
     586               0 :   if (NS_FAILED(rv))
     587               0 :     return rv;
     588                 : 
     589               0 :   rv = BuildPrimitives();
     590               0 :   if (NS_FAILED(rv))
     591               0 :     return rv;
     592                 : 
     593               0 :   if (mPrimitives.IsEmpty()) {
     594                 :     // Nothing should be rendered, so nothing is needed.
     595               0 :     return NS_OK;
     596                 :   }
     597                 : 
     598               0 :   ComputeResultBoundingBoxes();
     599               0 :   ComputeNeededBoxes();
     600                 :   aDirty->UnionRect(mSourceColorAlpha.mResultNeededBox,
     601               0 :                     mSourceAlpha.mResultNeededBox);
     602               0 :   return NS_OK;
     603                 : }
     604                 : 
     605                 : nsresult
     606               0 : nsSVGFilterInstance::ComputeOutputBBox(nsIntRect* aDirty)
     607                 : {
     608               0 :   nsresult rv = BuildSources();
     609               0 :   if (NS_FAILED(rv))
     610               0 :     return rv;
     611                 : 
     612               0 :   rv = BuildPrimitives();
     613               0 :   if (NS_FAILED(rv))
     614               0 :     return rv;
     615                 : 
     616               0 :   if (mPrimitives.IsEmpty()) {
     617                 :     // Nothing should be rendered.
     618               0 :     *aDirty = nsIntRect();
     619               0 :     return NS_OK;
     620                 :   }
     621                 : 
     622               0 :   ComputeResultBoundingBoxes();
     623                 : 
     624               0 :   PrimitiveInfo* result = &mPrimitives[mPrimitives.Length() - 1];
     625               0 :   *aDirty = result->mResultBoundingBox;
     626               0 :   return NS_OK;
     627                 : }

Generated by: LCOV version 1.7