LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGPatternFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 258 0 0.0 %
Date: 2012-06-02 Functions: 26 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
      18                 :  * Scooter Morris.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Scooter Morris <scootermorris@comcast.net>
      24                 :  *
      25                 :  * Alternatively, the contents of this file may be used under the terms of
      26                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      27                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      29                 :  * of those above. If you wish to allow use of your version of this file only
      30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      31                 :  * use your version of this file under the terms of the MPL, indicate your
      32                 :  * decision by deleting the provisions above and replace them with the notice
      33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      34                 :  * the provisions above, a recipient may use your version of this file under
      35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      36                 :  *
      37                 :  * ***** END LICENSE BLOCK ***** */
      38                 : 
      39                 : #include "nsSVGPatternFrame.h"
      40                 : 
      41                 : #include "nsGkAtoms.h"
      42                 : #include "nsIDOMSVGAnimatedRect.h"
      43                 : #include "SVGAnimatedTransformList.h"
      44                 : #include "nsStyleContext.h"
      45                 : #include "nsINameSpaceManager.h"
      46                 : #include "nsISVGChildFrame.h"
      47                 : #include "nsSVGRect.h"
      48                 : #include "nsSVGUtils.h"
      49                 : #include "nsSVGEffects.h"
      50                 : #include "nsSVGOuterSVGFrame.h"
      51                 : #include "nsSVGPatternElement.h"
      52                 : #include "nsSVGGeometryFrame.h"
      53                 : #include "gfxContext.h"
      54                 : #include "gfxPlatform.h"
      55                 : #include "gfxPattern.h"
      56                 : #include "gfxMatrix.h"
      57                 : #include "nsContentUtils.h"
      58                 : 
      59                 : using namespace mozilla;
      60                 : 
      61                 : //----------------------------------------------------------------------
      62                 : // Helper classes
      63                 : 
      64                 : class nsSVGPatternFrame::AutoPatternReferencer
      65                 : {
      66                 : public:
      67               0 :   AutoPatternReferencer(nsSVGPatternFrame *aFrame)
      68               0 :     : mFrame(aFrame)
      69                 :   {
      70                 :     // Reference loops should normally be detected in advance and handled, so
      71                 :     // we're not expecting to encounter them here
      72               0 :     NS_ABORT_IF_FALSE(!mFrame->mLoopFlag, "Undetected reference loop!");
      73               0 :     mFrame->mLoopFlag = true;
      74               0 :   }
      75               0 :   ~AutoPatternReferencer() {
      76               0 :     mFrame->mLoopFlag = false;
      77               0 :   }
      78                 : private:
      79                 :   nsSVGPatternFrame *mFrame;
      80                 : };
      81                 : 
      82                 : //----------------------------------------------------------------------
      83                 : // Implementation
      84                 : 
      85               0 : nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext) :
      86                 :   nsSVGPatternFrameBase(aContext),
      87                 :   mLoopFlag(false),
      88               0 :   mNoHRefURI(false)
      89                 : {
      90               0 : }
      91                 : 
      92               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGPatternFrame)
      93                 : 
      94                 : //----------------------------------------------------------------------
      95                 : // nsIFrame methods:
      96                 : 
      97                 : /* virtual */ void
      98               0 : nsSVGPatternFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
      99                 : {
     100               0 :   nsSVGEffects::InvalidateRenderingObservers(this);
     101               0 :   nsSVGPatternFrameBase::DidSetStyleContext(aOldStyleContext);
     102               0 : }
     103                 : 
     104                 : NS_IMETHODIMP
     105               0 : nsSVGPatternFrame::AttributeChanged(PRInt32         aNameSpaceID,
     106                 :                                     nsIAtom*        aAttribute,
     107                 :                                     PRInt32         aModType)
     108                 : {
     109               0 :   if (aNameSpaceID == kNameSpaceID_None &&
     110                 :       (aAttribute == nsGkAtoms::patternUnits ||
     111                 :        aAttribute == nsGkAtoms::patternContentUnits ||
     112                 :        aAttribute == nsGkAtoms::patternTransform ||
     113                 :        aAttribute == nsGkAtoms::x ||
     114                 :        aAttribute == nsGkAtoms::y ||
     115                 :        aAttribute == nsGkAtoms::width ||
     116                 :        aAttribute == nsGkAtoms::height ||
     117                 :        aAttribute == nsGkAtoms::preserveAspectRatio ||
     118                 :        aAttribute == nsGkAtoms::viewBox)) {
     119               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     120                 :   }
     121                 : 
     122               0 :   if (aNameSpaceID == kNameSpaceID_XLink &&
     123                 :       aAttribute == nsGkAtoms::href) {
     124                 :     // Blow away our reference, if any
     125               0 :     Properties().Delete(nsSVGEffects::HrefProperty());
     126               0 :     mNoHRefURI = false;
     127                 :     // And update whoever references us
     128               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     129                 :   }
     130                 : 
     131                 :   return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
     132               0 :                                                  aAttribute, aModType);
     133                 : }
     134                 : 
     135                 : #ifdef DEBUG
     136                 : NS_IMETHODIMP
     137               0 : nsSVGPatternFrame::Init(nsIContent* aContent,
     138                 :                         nsIFrame* aParent,
     139                 :                         nsIFrame* aPrevInFlow)
     140                 : {
     141               0 :   nsCOMPtr<nsIDOMSVGPatternElement> patternElement = do_QueryInterface(aContent);
     142               0 :   NS_ASSERTION(patternElement, "Content is not an SVG pattern");
     143                 : 
     144               0 :   return nsSVGPatternFrameBase::Init(aContent, aParent, aPrevInFlow);
     145                 : }
     146                 : #endif /* DEBUG */
     147                 : 
     148                 : nsIAtom*
     149               0 : nsSVGPatternFrame::GetType() const
     150                 : {
     151               0 :   return nsGkAtoms::svgPatternFrame;
     152                 : }
     153                 : 
     154                 : //----------------------------------------------------------------------
     155                 : // nsSVGContainerFrame methods:
     156                 : 
     157                 : // If our GetCanvasTM is getting called, we
     158                 : // need to return *our current* transformation
     159                 : // matrix, which depends on our units parameters
     160                 : // and X, Y, Width, and Height
     161                 : gfxMatrix
     162               0 : nsSVGPatternFrame::GetCanvasTM()
     163                 : {
     164               0 :   if (mCTM) {
     165               0 :     return *mCTM;
     166                 :   }
     167                 : 
     168                 :   // Do we know our rendering parent?
     169               0 :   if (mSource) {
     170                 :     // Yes, use it!
     171               0 :     return mSource->GetCanvasTM();
     172                 :   }
     173                 : 
     174                 :   // We get here when geometry in the <pattern> container is updated
     175               0 :   return gfxMatrix();
     176                 : }
     177                 : 
     178                 : nsresult
     179               0 : nsSVGPatternFrame::PaintPattern(gfxASurface** surface,
     180                 :                                 gfxMatrix* patternMatrix,
     181                 :                                 nsIFrame *aSource,
     182                 :                                 float aGraphicOpacity,
     183                 :                                 const gfxRect *aOverrideBounds)
     184                 : {
     185                 :   /*
     186                 :    * General approach:
     187                 :    *    Set the content geometry stuff
     188                 :    *    Calculate our bbox (using x,y,width,height & patternUnits &
     189                 :    *                        patternTransform)
     190                 :    *    Create the surface
     191                 :    *    Calculate the content transformation matrix
     192                 :    *    Get our children (we may need to get them from another Pattern)
     193                 :    *    Call SVGPaint on all of our children
     194                 :    *    Return
     195                 :    */
     196               0 :   *surface = nsnull;
     197                 : 
     198                 :   // Get the first child of the pattern data we will render
     199               0 :   nsIFrame* firstKid = GetPatternFirstChild();
     200               0 :   if (!firstKid)
     201               0 :     return NS_ERROR_FAILURE; // Either no kids or a bad reference
     202                 : 
     203                 :   /*
     204                 :    * Get the content geometry information.  This is a little tricky --
     205                 :    * our parent is probably a <defs>, but we are rendering in the context
     206                 :    * of some geometry source.  Our content geometry information needs to
     207                 :    * come from our rendering parent as opposed to our content parent.  We
     208                 :    * get that information from aSource, which is passed to us from the
     209                 :    * backend renderer.
     210                 :    *
     211                 :    * There are three "geometries" that we need:
     212                 :    *   1) The bounding box for the pattern.  We use this to get the
     213                 :    *      width and height for the surface, and as the return to
     214                 :    *      GetBBox.
     215                 :    *   2) The transformation matrix for the pattern.  This is not *quite*
     216                 :    *      the same as the canvas transformation matrix that we will
     217                 :    *      provide to our rendering children since we "fudge" it a little
     218                 :    *      to get the renderer to handle the translations correctly for us.
     219                 :    *   3) The CTM that we return to our children who make up the pattern.
     220                 :    */
     221                 : 
     222                 :   // Get all of the information we need from our "caller" -- i.e.
     223                 :   // the geometry that is being rendered with a pattern
     224               0 :   gfxRect callerBBox;
     225               0 :   gfxMatrix callerCTM;
     226               0 :   if (NS_FAILED(GetTargetGeometry(&callerCTM,
     227                 :                                   &callerBBox,
     228                 :                                   aSource,
     229                 :                                   aOverrideBounds)))
     230               0 :     return NS_ERROR_FAILURE;
     231                 : 
     232                 :   // Construct the CTM that we will provide to our children when we
     233                 :   // render them into the tile.
     234               0 :   gfxMatrix ctm = ConstructCTM(callerBBox, callerCTM, aSource);
     235               0 :   if (ctm.IsSingular()) {
     236               0 :     return NS_ERROR_FAILURE;
     237                 :   }
     238                 : 
     239                 :   // Get the pattern we are going to render
     240                 :   nsSVGPatternFrame *patternFrame =
     241               0 :     static_cast<nsSVGPatternFrame*>(firstKid->GetParent());
     242               0 :   if (patternFrame->mCTM) {
     243               0 :     *patternFrame->mCTM = ctm;
     244                 :   } else {
     245               0 :     patternFrame->mCTM = new gfxMatrix(ctm);
     246                 :   }
     247                 : 
     248                 :   // Get the bounding box of the pattern.  This will be used to determine
     249                 :   // the size of the surface, and will also be used to define the bounding
     250                 :   // box for the pattern tile.
     251               0 :   gfxRect bbox = GetPatternRect(callerBBox, callerCTM, aSource);
     252                 : 
     253                 :   // Get the pattern transform
     254               0 :   gfxMatrix patternTransform = GetPatternTransform();
     255                 : 
     256                 :   // Get the transformation matrix that we will hand to the renderer's pattern
     257                 :   // routine.
     258                 :   *patternMatrix = GetPatternMatrix(patternTransform,
     259               0 :                                     bbox, callerBBox, callerCTM);
     260                 : 
     261                 :   // Now that we have all of the necessary geometries, we can
     262                 :   // create our surface.
     263               0 :   gfxFloat patternWidth = bbox.Width();
     264               0 :   gfxFloat patternHeight = bbox.Height();
     265                 : 
     266                 :   bool resultOverflows;
     267                 :   gfxIntSize surfaceSize =
     268                 :     nsSVGUtils::ConvertToSurfaceSize(
     269               0 :       gfxSize(patternWidth * fabs(patternTransform.xx),
     270               0 :               patternHeight * fabs(patternTransform.yy)),
     271               0 :       &resultOverflows);
     272                 : 
     273                 :   // 0 disables rendering, < 0 is an error
     274               0 :   if (surfaceSize.width <= 0 || surfaceSize.height <= 0)
     275               0 :     return NS_ERROR_FAILURE;
     276                 : 
     277               0 :   if (resultOverflows ||
     278                 :       patternWidth != surfaceSize.width ||
     279                 :       patternHeight != surfaceSize.height) {
     280                 :     // scale drawing to pattern surface size
     281                 :     gfxMatrix tempTM =
     282                 :       gfxMatrix(surfaceSize.width / patternWidth, 0.0f,
     283                 :                 0.0f, surfaceSize.height / patternHeight,
     284               0 :                 0.0f, 0.0f);
     285               0 :     patternFrame->mCTM->PreMultiply(tempTM);
     286                 : 
     287                 :     // and rescale pattern to compensate
     288                 :     patternMatrix->Scale(patternWidth / surfaceSize.width,
     289               0 :                          patternHeight / surfaceSize.height);
     290                 :   }
     291                 : 
     292                 :   nsRefPtr<gfxASurface> tmpSurface =
     293               0 :     gfxPlatform::GetPlatform()->CreateOffscreenSurface(surfaceSize,
     294               0 :                                                        gfxASurface::CONTENT_COLOR_ALPHA);
     295               0 :   if (!tmpSurface || tmpSurface->CairoStatus())
     296               0 :     return NS_ERROR_FAILURE;
     297                 : 
     298               0 :   nsRenderingContext context;
     299               0 :   context.Init(aSource->PresContext()->DeviceContext(), tmpSurface);
     300               0 :   gfxContext* gfx = context.ThebesContext();
     301                 : 
     302                 :   // Fill with transparent black
     303               0 :   gfx->SetOperator(gfxContext::OPERATOR_CLEAR);
     304               0 :   gfx->Paint();
     305               0 :   gfx->SetOperator(gfxContext::OPERATOR_OVER);
     306                 : 
     307               0 :   if (aGraphicOpacity != 1.0f) {
     308               0 :     gfx->Save();
     309               0 :     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
     310                 :   }
     311                 : 
     312                 :   // OK, now render -- note that we use "firstKid", which
     313                 :   // we got at the beginning because it takes care of the
     314                 :   // referenced pattern situation for us
     315                 : 
     316               0 :   if (aSource->IsFrameOfType(nsIFrame::eSVGGeometry)) {
     317                 :     // Set the geometrical parent of the pattern we are rendering
     318               0 :     patternFrame->mSource = static_cast<nsSVGGeometryFrame*>(aSource);
     319                 :   }
     320                 : 
     321                 :   // Delay checking NS_FRAME_DRAWING_AS_PAINTSERVER bit until here so we can
     322                 :   // give back a clear surface if there's a loop
     323               0 :   if (!(patternFrame->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)) {
     324               0 :     patternFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
     325               0 :     for (nsIFrame* kid = firstKid; kid;
     326                 :          kid = kid->GetNextSibling()) {
     327                 :       // The CTM of each frame referencing us can be different
     328               0 :       nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     329               0 :       if (SVGFrame) {
     330                 :         SVGFrame->NotifySVGChanged(
     331                 :                           nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS |
     332               0 :                           nsISVGChildFrame::TRANSFORM_CHANGED);
     333                 :       }
     334               0 :       nsSVGUtils::PaintFrameWithEffects(&context, nsnull, kid);
     335                 :     }
     336               0 :     patternFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
     337                 :   }
     338                 : 
     339               0 :   patternFrame->mSource = nsnull;
     340                 : 
     341               0 :   if (aGraphicOpacity != 1.0f) {
     342               0 :     gfx->PopGroupToSource();
     343               0 :     gfx->Paint(aGraphicOpacity);
     344               0 :     gfx->Restore();
     345                 :   }
     346                 : 
     347                 :   // caller now owns the surface
     348               0 :   tmpSurface.forget(surface);
     349               0 :   return NS_OK;
     350                 : }
     351                 : 
     352                 : /* Will probably need something like this... */
     353                 : // How do we handle the insertion of a new frame?
     354                 : // We really don't want to rerender this every time,
     355                 : // do we?
     356                 : nsIFrame*
     357               0 : nsSVGPatternFrame::GetPatternFirstChild()
     358                 : {
     359                 :   // Do we have any children ourselves?
     360               0 :   nsIFrame* kid = mFrames.FirstChild();
     361               0 :   if (kid)
     362               0 :     return kid;
     363                 : 
     364                 :   // No, see if we chain to someone who does
     365               0 :   AutoPatternReferencer patternRef(this);
     366                 : 
     367               0 :   nsSVGPatternFrame* next = GetReferencedPatternIfNotInUse();
     368               0 :   if (!next)
     369               0 :     return nsnull;
     370                 : 
     371               0 :   return next->GetPatternFirstChild();
     372                 : }
     373                 : 
     374                 : PRUint16
     375               0 : nsSVGPatternFrame::GetEnumValue(PRUint32 aIndex, nsIContent *aDefault)
     376                 : {
     377                 :   nsSVGEnum& thisEnum =
     378               0 :     static_cast<nsSVGPatternElement *>(mContent)->mEnumAttributes[aIndex];
     379                 : 
     380               0 :   if (thisEnum.IsExplicitlySet())
     381               0 :     return thisEnum.GetAnimValue();
     382                 : 
     383               0 :   AutoPatternReferencer patternRef(this);
     384                 : 
     385               0 :   nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
     386                 :   return next ? next->GetEnumValue(aIndex, aDefault) :
     387                 :     static_cast<nsSVGPatternElement *>(aDefault)->
     388               0 :       mEnumAttributes[aIndex].GetAnimValue();
     389                 : }
     390                 : 
     391                 : SVGAnimatedTransformList*
     392               0 : nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
     393                 : {
     394                 :   SVGAnimatedTransformList *thisTransformList =
     395               0 :     static_cast<nsSVGPatternElement *>(mContent)->GetAnimatedTransformList();
     396                 : 
     397               0 :   if (thisTransformList->IsExplicitlySet())
     398               0 :     return thisTransformList;
     399                 : 
     400               0 :   AutoPatternReferencer patternRef(this);
     401                 : 
     402               0 :   nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
     403                 :   return next ? next->GetPatternTransformList(aDefault) :
     404               0 :     static_cast<nsSVGPatternElement *>(aDefault)->mPatternTransform.get();
     405                 : }
     406                 : 
     407                 : gfxMatrix
     408               0 : nsSVGPatternFrame::GetPatternTransform()
     409                 : {
     410                 :   SVGAnimatedTransformList* animTransformList =
     411               0 :     GetPatternTransformList(mContent);
     412               0 :   if (!animTransformList)
     413               0 :     return gfxMatrix();
     414                 : 
     415               0 :   return animTransformList->GetAnimValue().GetConsolidationMatrix();
     416                 : }
     417                 : 
     418                 : const nsSVGViewBox &
     419               0 : nsSVGPatternFrame::GetViewBox(nsIContent* aDefault)
     420                 : {
     421                 :   const nsSVGViewBox &thisViewBox =
     422               0 :     static_cast<nsSVGPatternElement *>(mContent)->mViewBox;
     423                 : 
     424               0 :   if (thisViewBox.IsValid())
     425               0 :     return thisViewBox;
     426                 : 
     427               0 :   AutoPatternReferencer patternRef(this);
     428                 : 
     429               0 :   nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
     430                 :   return next ? next->GetViewBox(aDefault) :
     431               0 :     static_cast<nsSVGPatternElement *>(aDefault)->mViewBox;
     432                 : }
     433                 : 
     434                 : const SVGAnimatedPreserveAspectRatio &
     435               0 : nsSVGPatternFrame::GetPreserveAspectRatio(nsIContent *aDefault)
     436                 : {
     437                 :   const SVGAnimatedPreserveAspectRatio &thisPar =
     438               0 :     static_cast<nsSVGPatternElement *>(mContent)->mPreserveAspectRatio;
     439                 : 
     440               0 :   if (thisPar.IsExplicitlySet())
     441               0 :     return thisPar;
     442                 : 
     443               0 :   AutoPatternReferencer patternRef(this);
     444                 : 
     445               0 :   nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
     446                 :   return next ? next->GetPreserveAspectRatio(aDefault) :
     447               0 :     static_cast<nsSVGPatternElement *>(aDefault)->mPreserveAspectRatio;
     448                 : }
     449                 : 
     450                 : const nsSVGLength2 *
     451               0 : nsSVGPatternFrame::GetLengthValue(PRUint32 aIndex, nsIContent *aDefault)
     452                 : {
     453                 :   const nsSVGLength2 *thisLength =
     454               0 :     &static_cast<nsSVGPatternElement *>(mContent)->mLengthAttributes[aIndex];
     455                 : 
     456               0 :   if (thisLength->IsExplicitlySet())
     457               0 :     return thisLength;
     458                 : 
     459               0 :   AutoPatternReferencer patternRef(this);
     460                 : 
     461               0 :   nsSVGPatternFrame *next = GetReferencedPatternIfNotInUse();
     462                 :   return next ? next->GetLengthValue(aIndex, aDefault) :
     463               0 :     &static_cast<nsSVGPatternElement *>(aDefault)->mLengthAttributes[aIndex];
     464                 : }
     465                 : 
     466                 : // Private (helper) methods
     467                 : nsSVGPatternFrame *
     468               0 : nsSVGPatternFrame::GetReferencedPattern()
     469                 : {
     470               0 :   if (mNoHRefURI)
     471               0 :     return nsnull;
     472                 : 
     473                 :   nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
     474               0 :     (Properties().Get(nsSVGEffects::HrefProperty()));
     475                 : 
     476               0 :   if (!property) {
     477                 :     // Fetch our pattern element's xlink:href attribute
     478               0 :     nsSVGPatternElement *pattern = static_cast<nsSVGPatternElement *>(mContent);
     479               0 :     nsAutoString href;
     480               0 :     pattern->mStringAttributes[nsSVGPatternElement::HREF].GetAnimValue(href, pattern);
     481               0 :     if (href.IsEmpty()) {
     482               0 :       mNoHRefURI = true;
     483               0 :       return nsnull; // no URL
     484                 :     }
     485                 : 
     486                 :     // Convert href to an nsIURI
     487               0 :     nsCOMPtr<nsIURI> targetURI;
     488               0 :     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     489               0 :     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
     490               0 :                                               mContent->GetCurrentDoc(), base);
     491                 : 
     492                 :     property =
     493               0 :       nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
     494               0 :     if (!property)
     495               0 :       return nsnull;
     496                 :   }
     497                 : 
     498               0 :   nsIFrame *result = property->GetReferencedFrame();
     499               0 :   if (!result)
     500               0 :     return nsnull;
     501                 : 
     502               0 :   nsIAtom* frameType = result->GetType();
     503               0 :   if (frameType != nsGkAtoms::svgPatternFrame)
     504               0 :     return nsnull;
     505                 : 
     506               0 :   return static_cast<nsSVGPatternFrame*>(result);
     507                 : }
     508                 : 
     509                 : nsSVGPatternFrame *
     510               0 : nsSVGPatternFrame::GetReferencedPatternIfNotInUse()
     511                 : {
     512               0 :   nsSVGPatternFrame *referenced = GetReferencedPattern();
     513               0 :   if (!referenced)
     514               0 :     return nsnull;
     515                 : 
     516               0 :   if (referenced->mLoopFlag) {
     517                 :     // XXXjwatt: we should really send an error to the JavaScript Console here:
     518               0 :     NS_WARNING("pattern reference loop detected while inheriting attribute!");
     519               0 :     return nsnull;
     520                 :   }
     521                 : 
     522               0 :   return referenced;
     523                 : }
     524                 : 
     525                 : // -------------------------------------------------------------------------
     526                 : // Helper functions
     527                 : // -------------------------------------------------------------------------
     528                 : 
     529                 : gfxRect
     530               0 : nsSVGPatternFrame::GetPatternRect(const gfxRect &aTargetBBox,
     531                 :                                   const gfxMatrix &aTargetCTM,
     532                 :                                   nsIFrame *aTarget)
     533                 : {
     534                 :   // Get our type
     535               0 :   PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNUNITS);
     536                 : 
     537                 :   // We need to initialize our box
     538                 :   float x,y,width,height;
     539                 : 
     540                 :   // Get the pattern x,y,width, and height
     541                 :   const nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
     542               0 :   tmpX = GetLengthValue(nsSVGPatternElement::X);
     543               0 :   tmpY = GetLengthValue(nsSVGPatternElement::Y);
     544               0 :   tmpHeight = GetLengthValue(nsSVGPatternElement::HEIGHT);
     545               0 :   tmpWidth = GetLengthValue(nsSVGPatternElement::WIDTH);
     546                 : 
     547               0 :   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     548               0 :     x = nsSVGUtils::ObjectSpace(aTargetBBox, tmpX);
     549               0 :     y = nsSVGUtils::ObjectSpace(aTargetBBox, tmpY);
     550               0 :     width = nsSVGUtils::ObjectSpace(aTargetBBox, tmpWidth);
     551               0 :     height = nsSVGUtils::ObjectSpace(aTargetBBox, tmpHeight);
     552                 :   } else {
     553               0 :     float scale = nsSVGUtils::MaxExpansion(aTargetCTM);
     554               0 :     x = nsSVGUtils::UserSpace(aTarget, tmpX) * scale;
     555               0 :     y = nsSVGUtils::UserSpace(aTarget, tmpY) * scale;
     556               0 :     width = nsSVGUtils::UserSpace(aTarget, tmpWidth) * scale;
     557               0 :     height = nsSVGUtils::UserSpace(aTarget, tmpHeight) * scale;
     558                 :   }
     559                 : 
     560               0 :   return gfxRect(x, y, width, height);
     561                 : }
     562                 : 
     563                 : gfxMatrix
     564               0 : nsSVGPatternFrame::ConstructCTM(const gfxRect &callerBBox,
     565                 :                                 const gfxMatrix &callerCTM,
     566                 :                                 nsIFrame *aTarget)
     567                 : {
     568               0 :   gfxMatrix tCTM;
     569               0 :   nsSVGSVGElement *ctx = nsnull;
     570               0 :   nsIContent* targetContent = aTarget->GetContent();
     571                 : 
     572                 :   // The objectBoundingBox conversion must be handled in the CTM:
     573               0 :   if (GetEnumValue(nsSVGPatternElement::PATTERNCONTENTUNITS) ==
     574                 :       nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     575               0 :     tCTM.Scale(callerBBox.Width(), callerBBox.Height());
     576                 :   } else {
     577               0 :     if (targetContent->IsSVG()) {
     578               0 :       ctx = static_cast<nsSVGElement*>(targetContent)->GetCtx();
     579                 :     }
     580               0 :     float scale = nsSVGUtils::MaxExpansion(callerCTM);
     581               0 :     tCTM.Scale(scale, scale);
     582                 :   }
     583                 : 
     584               0 :   const nsSVGViewBoxRect viewBox = GetViewBox().GetAnimValue();
     585                 : 
     586               0 :   if (viewBox.height <= 0.0f || viewBox.width <= 0.0f) {
     587               0 :     return tCTM;
     588                 :   }
     589                 : 
     590                 :   float viewportWidth, viewportHeight;
     591               0 :   if (targetContent->IsSVG()) {
     592                 :     // If we're dealing with an SVG target only retrieve the context once.
     593                 :     // Calling the nsIFrame* variant of GetAnimValue would look it up on
     594                 :     // every call.
     595                 :     viewportWidth =
     596               0 :       GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(ctx);
     597                 :     viewportHeight =
     598               0 :       GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(ctx);
     599                 :   } else {
     600                 :     // No SVG target, call the nsIFrame* variant of GetAnimValue.
     601                 :     viewportWidth =
     602               0 :       GetLengthValue(nsSVGPatternElement::WIDTH)->GetAnimValue(aTarget);
     603                 :     viewportHeight =
     604               0 :       GetLengthValue(nsSVGPatternElement::HEIGHT)->GetAnimValue(aTarget);
     605                 :   }
     606                 :   gfxMatrix tm = nsSVGUtils::GetViewBoxTransform(
     607                 :     static_cast<nsSVGPatternElement*>(mContent),
     608                 :     viewportWidth, viewportHeight,
     609                 :     viewBox.x, viewBox.y,
     610                 :     viewBox.width, viewBox.height,
     611               0 :     GetPreserveAspectRatio());
     612                 : 
     613               0 :   return tm * tCTM;
     614                 : }
     615                 : 
     616                 : // Given the matrix for the pattern element's own transform, this returns a
     617                 : // combined matrix including the transforms applicable to its target.
     618                 : gfxMatrix
     619               0 : nsSVGPatternFrame::GetPatternMatrix(const gfxMatrix &patternTransform,
     620                 :                                     const gfxRect &bbox,
     621                 :                                     const gfxRect &callerBBox,
     622                 :                                     const gfxMatrix &callerCTM)
     623                 : {
     624                 :   // We really want the pattern matrix to handle translations
     625               0 :   gfxFloat minx = bbox.X();
     626               0 :   gfxFloat miny = bbox.Y();
     627                 : 
     628               0 :   PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNCONTENTUNITS);
     629               0 :   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     630               0 :     minx += callerBBox.X();
     631               0 :     miny += callerBBox.Y();
     632                 :   }
     633                 : 
     634               0 :   float scale = 1.0f / nsSVGUtils::MaxExpansion(callerCTM);
     635               0 :   gfxMatrix patternMatrix = patternTransform;
     636               0 :   patternMatrix.Scale(scale, scale);
     637               0 :   patternMatrix.Translate(gfxPoint(minx, miny));
     638                 : 
     639                 :   return patternMatrix;
     640                 : }
     641                 : 
     642                 : nsresult
     643               0 : nsSVGPatternFrame::GetTargetGeometry(gfxMatrix *aCTM,
     644                 :                                      gfxRect *aBBox,
     645                 :                                      nsIFrame *aTarget,
     646                 :                                      const gfxRect *aOverrideBounds)
     647                 : {
     648               0 :   *aBBox = aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aTarget);
     649                 : 
     650                 :   // Sanity check
     651               0 :   PRUint16 type = GetEnumValue(nsSVGPatternElement::PATTERNUNITS);
     652               0 :   if (type == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     653               0 :     if (aBBox->Width() <= 0 || aBBox->Height() <= 0) {
     654               0 :       return NS_ERROR_FAILURE;
     655                 :     }
     656                 :   }
     657                 : 
     658                 :   // Get the transformation matrix from our calling geometry
     659               0 :   *aCTM = nsSVGUtils::GetCanvasTM(aTarget);
     660                 : 
     661                 :   // OK, now fix up the bounding box to reflect user coordinates
     662                 :   // We handle device unit scaling in pattern matrix
     663                 :   {
     664               0 :     float scale = nsSVGUtils::MaxExpansion(*aCTM);
     665               0 :     if (scale <= 0) {
     666               0 :       return NS_ERROR_FAILURE;
     667                 :     }
     668               0 :     aBBox->Scale(scale);
     669                 :   }
     670               0 :   return NS_OK;
     671                 : }
     672                 : 
     673                 : //----------------------------------------------------------------------
     674                 : // nsSVGPaintServerFrame methods:
     675                 : 
     676                 : already_AddRefed<gfxPattern>
     677               0 : nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
     678                 :                                          float aGraphicOpacity,
     679                 :                                          const gfxRect *aOverrideBounds)
     680                 : {
     681               0 :   if (aGraphicOpacity == 0.0f) {
     682               0 :     nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(0, 0, 0, 0));
     683               0 :     return pattern.forget();
     684                 :   }
     685                 : 
     686                 :   // Paint it!
     687               0 :   nsRefPtr<gfxASurface> surface;
     688               0 :   gfxMatrix pMatrix;
     689                 :   nsresult rv = PaintPattern(getter_AddRefs(surface), &pMatrix,
     690               0 :                              aSource, aGraphicOpacity, aOverrideBounds);
     691                 : 
     692               0 :   if (NS_FAILED(rv)) {
     693               0 :     return nsnull;
     694                 :   }
     695                 : 
     696               0 :   if (pMatrix.IsSingular()) {
     697               0 :     return nsnull;
     698                 :   }
     699                 : 
     700               0 :   pMatrix.Invert();
     701                 : 
     702               0 :   nsRefPtr<gfxPattern> pattern = new gfxPattern(surface);
     703                 : 
     704               0 :   if (!pattern || pattern->CairoStatus())
     705               0 :     return nsnull;
     706                 : 
     707               0 :   pattern->SetMatrix(pMatrix);
     708               0 :   pattern->SetExtend(gfxPattern::EXTEND_REPEAT);
     709               0 :   return pattern.forget();
     710                 : }
     711                 : 
     712                 : // -------------------------------------------------------------------------
     713                 : // Public functions
     714                 : // -------------------------------------------------------------------------
     715                 : 
     716               0 : nsIFrame* NS_NewSVGPatternFrame(nsIPresShell*   aPresShell,
     717                 :                                 nsStyleContext* aContext)
     718                 : {
     719               0 :   return new (aPresShell) nsSVGPatternFrame(aContext);
     720                 : }
     721                 : 

Generated by: LCOV version 1.7