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

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : // Main header first:
       7             : #include "nsSVGPatternFrame.h"
       8             : 
       9             : // Keep others in (case-insensitive) order:
      10             : #include "AutoReferenceChainGuard.h"
      11             : #include "gfx2DGlue.h"
      12             : #include "gfxContext.h"
      13             : #include "gfxMatrix.h"
      14             : #include "gfxPattern.h"
      15             : #include "gfxPlatform.h"
      16             : #include "mozilla/gfx/2D.h"
      17             : #include "nsContentUtils.h"
      18             : #include "nsGkAtoms.h"
      19             : #include "nsSVGDisplayableFrame.h"
      20             : #include "nsStyleContext.h"
      21             : #include "nsSVGEffects.h"
      22             : #include "SVGGeometryFrame.h"
      23             : #include "mozilla/dom/SVGPatternElement.h"
      24             : #include "nsSVGUtils.h"
      25             : #include "nsSVGAnimatedTransformList.h"
      26             : #include "SVGContentUtils.h"
      27             : 
      28             : using namespace mozilla;
      29             : using namespace mozilla::dom;
      30             : using namespace mozilla::gfx;
      31             : using namespace mozilla::image;
      32             : 
      33             : //----------------------------------------------------------------------
      34             : // Implementation
      35             : 
      36           0 : nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext)
      37             :   : nsSVGPaintServerFrame(aContext, kClassID)
      38             :   , mSource(nullptr)
      39             :   , mLoopFlag(false)
      40           0 :   , mNoHRefURI(false)
      41             : {
      42           0 : }
      43             : 
      44           0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGPatternFrame)
      45             : 
      46             : //----------------------------------------------------------------------
      47             : // nsIFrame methods:
      48             : 
      49             : nsresult
      50           0 : nsSVGPatternFrame::AttributeChanged(int32_t         aNameSpaceID,
      51             :                                     nsIAtom*        aAttribute,
      52             :                                     int32_t         aModType)
      53             : {
      54           0 :   if (aNameSpaceID == kNameSpaceID_None &&
      55           0 :       (aAttribute == nsGkAtoms::patternUnits ||
      56           0 :        aAttribute == nsGkAtoms::patternContentUnits ||
      57           0 :        aAttribute == nsGkAtoms::patternTransform ||
      58           0 :        aAttribute == nsGkAtoms::x ||
      59           0 :        aAttribute == nsGkAtoms::y ||
      60           0 :        aAttribute == nsGkAtoms::width ||
      61           0 :        aAttribute == nsGkAtoms::height ||
      62           0 :        aAttribute == nsGkAtoms::preserveAspectRatio ||
      63           0 :        aAttribute == nsGkAtoms::viewBox)) {
      64           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
      65             :   }
      66             : 
      67           0 :   if ((aNameSpaceID == kNameSpaceID_XLink ||
      68           0 :        aNameSpaceID == kNameSpaceID_None) &&
      69           0 :       aAttribute == nsGkAtoms::href) {
      70             :     // Blow away our reference, if any
      71           0 :     DeleteProperty(nsSVGEffects::HrefAsPaintingProperty());
      72           0 :     mNoHRefURI = false;
      73             :     // And update whoever references us
      74           0 :     nsSVGEffects::InvalidateDirectRenderingObservers(this);
      75             :   }
      76             : 
      77           0 :   return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
      78           0 :                                                  aAttribute, aModType);
      79             : }
      80             : 
      81             : #ifdef DEBUG
      82             : void
      83           0 : nsSVGPatternFrame::Init(nsIContent*       aContent,
      84             :                         nsContainerFrame* aParent,
      85             :                         nsIFrame*         aPrevInFlow)
      86             : {
      87           0 :   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::pattern), "Content is not an SVG pattern");
      88             : 
      89           0 :   nsSVGPaintServerFrame::Init(aContent, aParent, aPrevInFlow);
      90           0 : }
      91             : #endif /* DEBUG */
      92             : 
      93             : //----------------------------------------------------------------------
      94             : // nsSVGContainerFrame methods:
      95             : 
      96             : // If our GetCanvasTM is getting called, we
      97             : // need to return *our current* transformation
      98             : // matrix, which depends on our units parameters
      99             : // and X, Y, Width, and Height
     100             : gfxMatrix
     101           0 : nsSVGPatternFrame::GetCanvasTM()
     102             : {
     103           0 :   if (mCTM) {
     104           0 :     return *mCTM;
     105             :   }
     106             : 
     107             :   // Do we know our rendering parent?
     108           0 :   if (mSource) {
     109             :     // Yes, use it!
     110           0 :     return mSource->GetCanvasTM();
     111             :   }
     112             : 
     113             :   // We get here when geometry in the <pattern> container is updated
     114           0 :   return gfxMatrix();
     115             : }
     116             : 
     117             : // -------------------------------------------------------------------------
     118             : // Helper functions
     119             : // -------------------------------------------------------------------------
     120             : 
     121             : /** Calculate the maximum expansion of a matrix */
     122             : static float
     123           0 : MaxExpansion(const Matrix &aMatrix)
     124             : {
     125             :   // maximum expansion derivation from
     126             :   // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
     127             :   // and also implemented in cairo_matrix_transformed_circle_major_axis
     128           0 :   double a = aMatrix._11;
     129           0 :   double b = aMatrix._12;
     130           0 :   double c = aMatrix._21;
     131           0 :   double d = aMatrix._22;
     132           0 :   double f = (a * a + b * b + c * c + d * d) / 2;
     133           0 :   double g = (a * a + b * b - c * c - d * d) / 2;
     134           0 :   double h = a * c + b * d;
     135           0 :   return sqrt(f + sqrt(g * g + h * h));
     136             : }
     137             : 
     138             : // The SVG specification says that the 'patternContentUnits' attribute "has no effect if
     139             : // attribute ‘viewBox’ is specified". We still need to include a bbox scale
     140             : // if the viewBox is specified and _patternUnits_ is set to or defaults to
     141             : // objectBoundingBox though, since in that case the viewBox is relative to the bbox
     142             : static bool
     143           0 : IncludeBBoxScale(const nsSVGViewBox& aViewBox,
     144             :                  uint32_t aPatternContentUnits, uint32_t aPatternUnits)
     145             : {
     146           0 :   return (!aViewBox.IsExplicitlySet() &&
     147           0 :           aPatternContentUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) ||
     148           0 :          (aViewBox.IsExplicitlySet() &&
     149           0 :           aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     150             : }
     151             : 
     152             : // Given the matrix for the pattern element's own transform, this returns a
     153             : // combined matrix including the transforms applicable to its target.
     154             : static Matrix
     155           0 : GetPatternMatrix(uint16_t aPatternUnits,
     156             :                  const Matrix &patternTransform,
     157             :                  const gfxRect &bbox,
     158             :                  const gfxRect &callerBBox,
     159             :                  const Matrix &callerCTM)
     160             : {
     161             :   // We really want the pattern matrix to handle translations
     162           0 :   gfxFloat minx = bbox.X();
     163           0 :   gfxFloat miny = bbox.Y();
     164             : 
     165           0 :   if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     166           0 :     minx += callerBBox.X();
     167           0 :     miny += callerBBox.Y();
     168             :   }
     169             : 
     170           0 :   float scale = 1.0f / MaxExpansion(callerCTM);
     171           0 :   Matrix patternMatrix = patternTransform;
     172           0 :   patternMatrix.PreScale(scale, scale);
     173           0 :   patternMatrix.PreTranslate(minx, miny);
     174             : 
     175           0 :   return patternMatrix;
     176             : }
     177             : 
     178             : static nsresult
     179           0 : GetTargetGeometry(gfxRect *aBBox,
     180             :                   const nsSVGViewBox &aViewBox,
     181             :                   uint16_t aPatternContentUnits,
     182             :                   uint16_t aPatternUnits,
     183             :                   nsIFrame *aTarget,
     184             :                   const Matrix &aContextMatrix,
     185             :                   const gfxRect *aOverrideBounds)
     186             : {
     187             :   *aBBox =
     188             :     aOverrideBounds
     189             :       ? *aOverrideBounds
     190             :       : nsSVGUtils::GetBBox(aTarget, nsSVGUtils::eUseFrameBoundsForOuterSVG |
     191           0 :                                      nsSVGUtils::eBBoxIncludeFillGeometry);
     192             : 
     193             :   // Sanity check
     194           0 :   if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits) &&
     195           0 :       (aBBox->Width() <= 0 || aBBox->Height() <= 0)) {
     196           0 :     return NS_ERROR_FAILURE;
     197             :   }
     198             : 
     199             :   // OK, now fix up the bounding box to reflect user coordinates
     200             :   // We handle device unit scaling in pattern matrix
     201           0 :   float scale = MaxExpansion(aContextMatrix);
     202           0 :   if (scale <= 0) {
     203           0 :     return NS_ERROR_FAILURE;
     204             :   }
     205           0 :   aBBox->Scale(scale);
     206           0 :   return NS_OK;
     207             : }
     208             : 
     209             : already_AddRefed<SourceSurface>
     210           0 : nsSVGPatternFrame::PaintPattern(const DrawTarget* aDrawTarget,
     211             :                                 Matrix* patternMatrix,
     212             :                                 const Matrix &aContextMatrix,
     213             :                                 nsIFrame *aSource,
     214             :                                 nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
     215             :                                 float aGraphicOpacity,
     216             :                                 const gfxRect *aOverrideBounds,
     217             :                                 imgDrawingParams& aImgParams)
     218             : {
     219             :   /*
     220             :    * General approach:
     221             :    *    Set the content geometry stuff
     222             :    *    Calculate our bbox (using x,y,width,height & patternUnits &
     223             :    *                        patternTransform)
     224             :    *    Create the surface
     225             :    *    Calculate the content transformation matrix
     226             :    *    Get our children (we may need to get them from another Pattern)
     227             :    *    Call SVGPaint on all of our children
     228             :    *    Return
     229             :    */
     230             : 
     231           0 :   nsSVGPatternFrame* patternWithChildren = GetPatternWithChildren();
     232           0 :   if (!patternWithChildren) {
     233             :     // Either no kids or a bad reference
     234           0 :     return nullptr;
     235             :   }
     236           0 :   nsIFrame* firstKid = patternWithChildren->mFrames.FirstChild();
     237             : 
     238           0 :   const nsSVGViewBox& viewBox = GetViewBox();
     239             : 
     240             :   uint16_t patternContentUnits =
     241           0 :     GetEnumValue(SVGPatternElement::PATTERNCONTENTUNITS);
     242             :   uint16_t patternUnits =
     243           0 :     GetEnumValue(SVGPatternElement::PATTERNUNITS);
     244             : 
     245             :   /*
     246             :    * Get the content geometry information.  This is a little tricky --
     247             :    * our parent is probably a <defs>, but we are rendering in the context
     248             :    * of some geometry source.  Our content geometry information needs to
     249             :    * come from our rendering parent as opposed to our content parent.  We
     250             :    * get that information from aSource, which is passed to us from the
     251             :    * backend renderer.
     252             :    *
     253             :    * There are three "geometries" that we need:
     254             :    *   1) The bounding box for the pattern.  We use this to get the
     255             :    *      width and height for the surface, and as the return to
     256             :    *      GetBBox.
     257             :    *   2) The transformation matrix for the pattern.  This is not *quite*
     258             :    *      the same as the canvas transformation matrix that we will
     259             :    *      provide to our rendering children since we "fudge" it a little
     260             :    *      to get the renderer to handle the translations correctly for us.
     261             :    *   3) The CTM that we return to our children who make up the pattern.
     262             :    */
     263             : 
     264             :   // Get all of the information we need from our "caller" -- i.e.
     265             :   // the geometry that is being rendered with a pattern
     266           0 :   gfxRect callerBBox;
     267           0 :   if (NS_FAILED(GetTargetGeometry(&callerBBox,
     268             :                                   viewBox,
     269             :                                   patternContentUnits, patternUnits,
     270             :                                   aSource,
     271             :                                   aContextMatrix,
     272             :                                   aOverrideBounds))) {
     273           0 :     return nullptr;
     274             :   }
     275             : 
     276             :   // Construct the CTM that we will provide to our children when we
     277             :   // render them into the tile.
     278             :   gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
     279           0 :                                callerBBox, aContextMatrix, aSource);
     280           0 :   if (ctm.IsSingular()) {
     281           0 :     return nullptr;
     282             :   }
     283             : 
     284           0 :   if (patternWithChildren->mCTM) {
     285           0 :     *patternWithChildren->mCTM = ctm;
     286             :   } else {
     287           0 :     patternWithChildren->mCTM = new gfxMatrix(ctm);
     288             :   }
     289             : 
     290             :   // Get the bounding box of the pattern.  This will be used to determine
     291             :   // the size of the surface, and will also be used to define the bounding
     292             :   // box for the pattern tile.
     293           0 :   gfxRect bbox = GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource);
     294           0 :   if (bbox.Width() <= 0.0 || bbox.Height() <= 0.0) {
     295           0 :     return nullptr;
     296             :   }
     297             : 
     298             :   // Get the pattern transform
     299           0 :   Matrix patternTransform = ToMatrix(GetPatternTransform());
     300             : 
     301             :   // revert the vector effect transform so that the pattern appears unchanged
     302           0 :   if (aFillOrStroke == &nsStyleSVG::mStroke) {
     303           0 :     gfxMatrix userToOuterSVG;
     304           0 :     if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
     305           0 :       patternTransform *= ToMatrix(userToOuterSVG);
     306           0 :       if (patternTransform.IsSingular()) {
     307           0 :         NS_WARNING("Singular matrix painting non-scaling-stroke");
     308           0 :         return nullptr;
     309             :       }
     310             :     }
     311             :   }
     312             : 
     313             :   // Get the transformation matrix that we will hand to the renderer's pattern
     314             :   // routine.
     315             :   *patternMatrix = GetPatternMatrix(patternUnits, patternTransform,
     316           0 :                                     bbox, callerBBox, aContextMatrix);
     317           0 :   if (patternMatrix->IsSingular()) {
     318           0 :     return nullptr;
     319             :   }
     320             : 
     321             :   // Now that we have all of the necessary geometries, we can
     322             :   // create our surface.
     323           0 :   gfxRect transformedBBox = ThebesRect(patternTransform.TransformBounds(ToRect(bbox)));
     324             : 
     325             :   bool resultOverflows;
     326             :   IntSize surfaceSize =
     327             :     nsSVGUtils::ConvertToSurfaceSize(
     328           0 :       transformedBBox.Size(), &resultOverflows);
     329             : 
     330             :   // 0 disables rendering, < 0 is an error
     331           0 :   if (surfaceSize.width <= 0 || surfaceSize.height <= 0) {
     332           0 :     return nullptr;
     333             :   }
     334             : 
     335           0 :   gfxFloat patternWidth = bbox.Width();
     336           0 :   gfxFloat patternHeight = bbox.Height();
     337             : 
     338           0 :   if (resultOverflows ||
     339           0 :       patternWidth != surfaceSize.width ||
     340           0 :       patternHeight != surfaceSize.height) {
     341             :     // scale drawing to pattern surface size
     342             :     gfxMatrix tempTM =
     343           0 :       gfxMatrix(surfaceSize.width / patternWidth, 0.0,
     344           0 :                 0.0, surfaceSize.height / patternHeight,
     345           0 :                 0.0, 0.0);
     346           0 :     patternWithChildren->mCTM->PreMultiply(tempTM);
     347             : 
     348             :     // and rescale pattern to compensate
     349           0 :     patternMatrix->PreScale(patternWidth / surfaceSize.width,
     350           0 :                             patternHeight / surfaceSize.height);
     351             :   }
     352             : 
     353             :   RefPtr<DrawTarget> dt =
     354           0 :     aDrawTarget->CreateSimilarDrawTarget(surfaceSize, SurfaceFormat::B8G8R8A8);
     355           0 :   if (!dt || !dt->IsValid()) {
     356           0 :     return nullptr;
     357             :   }
     358           0 :   dt->ClearRect(Rect(0, 0, surfaceSize.width, surfaceSize.height));
     359             : 
     360           0 :   RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
     361           0 :   MOZ_ASSERT(ctx); // already checked the draw target above
     362             : 
     363           0 :   if (aGraphicOpacity != 1.0f) {
     364           0 :     ctx->Save();
     365           0 :     ctx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, aGraphicOpacity);
     366             :   }
     367             : 
     368             :   // OK, now render -- note that we use "firstKid", which
     369             :   // we got at the beginning because it takes care of the
     370             :   // referenced pattern situation for us
     371             : 
     372           0 :   if (aSource->IsFrameOfType(nsIFrame::eSVGGeometry)) {
     373             :     // Set the geometrical parent of the pattern we are rendering
     374           0 :     patternWithChildren->mSource = static_cast<SVGGeometryFrame*>(aSource);
     375             :   }
     376             : 
     377             :   // Delay checking NS_FRAME_DRAWING_AS_PAINTSERVER bit until here so we can
     378             :   // give back a clear surface if there's a loop
     379           0 :   if (!(patternWithChildren->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)) {
     380           0 :     AutoSetRestorePaintServerState paintServer(patternWithChildren);
     381           0 :     for (nsIFrame* kid = firstKid; kid;
     382             :          kid = kid->GetNextSibling()) {
     383             :       // The CTM of each frame referencing us can be different
     384           0 :       nsSVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
     385           0 :       if (SVGFrame) {
     386           0 :         SVGFrame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
     387             :       }
     388           0 :       gfxMatrix tm = *(patternWithChildren->mCTM);
     389           0 :       if (kid->GetContent()->IsSVGElement()) {
     390           0 :         tm = static_cast<nsSVGElement*>(kid->GetContent())->
     391           0 :                PrependLocalTransformsTo(tm, eUserSpaceToParent);
     392             :       }
     393             : 
     394           0 :       nsSVGUtils::PaintFrameWithEffects(kid, *ctx, tm, aImgParams);
     395             :     }
     396             :   }
     397             : 
     398           0 :   patternWithChildren->mSource = nullptr;
     399             : 
     400           0 :   if (aGraphicOpacity != 1.0f) {
     401           0 :     ctx->PopGroupAndBlend();
     402           0 :     ctx->Restore();
     403             :   }
     404             : 
     405             :   // caller now owns the surface
     406           0 :   return dt->Snapshot();
     407             : }
     408             : 
     409             : /* Will probably need something like this... */
     410             : // How do we handle the insertion of a new frame?
     411             : // We really don't want to rerender this every time,
     412             : // do we?
     413             : nsSVGPatternFrame*
     414           0 : nsSVGPatternFrame::GetPatternWithChildren()
     415             : {
     416             :   // Do we have any children ourselves?
     417           0 :   if (!mFrames.IsEmpty())
     418           0 :     return this;
     419             : 
     420             :   // No, see if we chain to someone who does
     421             : 
     422             :   // Before we recurse, make sure we'll break reference loops and over long
     423             :   // reference chains:
     424             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     425             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     426           0 :                                         &sRefChainLengthCounter);
     427           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     428             :     // Break reference chain
     429           0 :     return nullptr;
     430             :   }
     431             : 
     432           0 :   nsSVGPatternFrame* next = GetReferencedPattern();
     433           0 :   if (!next)
     434           0 :     return nullptr;
     435             : 
     436           0 :   return next->GetPatternWithChildren();
     437             : }
     438             : 
     439             : uint16_t
     440           0 : nsSVGPatternFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
     441             : {
     442             :   nsSVGEnum& thisEnum =
     443           0 :     static_cast<SVGPatternElement *>(mContent)->mEnumAttributes[aIndex];
     444             : 
     445           0 :   if (thisEnum.IsExplicitlySet())
     446           0 :     return thisEnum.GetAnimValue();
     447             : 
     448             :   // Before we recurse, make sure we'll break reference loops and over long
     449             :   // reference chains:
     450             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     451             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     452           0 :                                         &sRefChainLengthCounter);
     453           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     454             :     // Break reference chain
     455             :     return static_cast<SVGPatternElement *>(aDefault)->
     456           0 :              mEnumAttributes[aIndex].GetAnimValue();
     457             :   }
     458             : 
     459           0 :   nsSVGPatternFrame *next = GetReferencedPattern();
     460           0 :   return next ? next->GetEnumValue(aIndex, aDefault)
     461             :               : static_cast<SVGPatternElement*>(aDefault)->
     462           0 :                   mEnumAttributes[aIndex].GetAnimValue();
     463             : }
     464             : 
     465             : nsSVGAnimatedTransformList*
     466           0 : nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
     467             : {
     468             :   nsSVGAnimatedTransformList *thisTransformList =
     469           0 :     static_cast<SVGPatternElement *>(mContent)->GetAnimatedTransformList();
     470             : 
     471           0 :   if (thisTransformList && thisTransformList->IsExplicitlySet())
     472           0 :     return thisTransformList;
     473             : 
     474             :   // Before we recurse, make sure we'll break reference loops and over long
     475             :   // reference chains:
     476             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     477             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     478           0 :                                         &sRefChainLengthCounter);
     479           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     480             :     // Break reference chain
     481           0 :     return static_cast<SVGPatternElement*>(aDefault)->mPatternTransform.get();
     482             :   }
     483             : 
     484           0 :   nsSVGPatternFrame *next = GetReferencedPattern();
     485           0 :   return next ? next->GetPatternTransformList(aDefault)
     486           0 :               : static_cast<SVGPatternElement*>(aDefault)->mPatternTransform.get();
     487             : }
     488             : 
     489             : gfxMatrix
     490           0 : nsSVGPatternFrame::GetPatternTransform()
     491             : {
     492             :   nsSVGAnimatedTransformList* animTransformList =
     493           0 :     GetPatternTransformList(mContent);
     494           0 :   if (!animTransformList)
     495           0 :     return gfxMatrix();
     496             : 
     497           0 :   return animTransformList->GetAnimValue().GetConsolidationMatrix();
     498             : }
     499             : 
     500             : const nsSVGViewBox &
     501           0 : nsSVGPatternFrame::GetViewBox(nsIContent* aDefault)
     502             : {
     503             :   const nsSVGViewBox &thisViewBox =
     504           0 :     static_cast<SVGPatternElement *>(mContent)->mViewBox;
     505             : 
     506           0 :   if (thisViewBox.IsExplicitlySet())
     507           0 :     return thisViewBox;
     508             : 
     509             :   // Before we recurse, make sure we'll break reference loops and over long
     510             :   // reference chains:
     511             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     512             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     513           0 :                                         &sRefChainLengthCounter);
     514           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     515             :     // Break reference chain
     516           0 :     return static_cast<SVGPatternElement *>(aDefault)->mViewBox;
     517             :   }
     518             : 
     519           0 :   nsSVGPatternFrame *next = GetReferencedPattern();
     520           0 :   return next ? next->GetViewBox(aDefault)
     521           0 :               : static_cast<SVGPatternElement *>(aDefault)->mViewBox;
     522             : }
     523             : 
     524             : const SVGAnimatedPreserveAspectRatio &
     525           0 : nsSVGPatternFrame::GetPreserveAspectRatio(nsIContent *aDefault)
     526             : {
     527             :   const SVGAnimatedPreserveAspectRatio &thisPar =
     528           0 :     static_cast<SVGPatternElement *>(mContent)->mPreserveAspectRatio;
     529             : 
     530           0 :   if (thisPar.IsExplicitlySet())
     531           0 :     return thisPar;
     532             : 
     533             :   // Before we recurse, make sure we'll break reference loops and over long
     534             :   // reference chains:
     535             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     536             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     537           0 :                                         &sRefChainLengthCounter);
     538           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     539             :     // Break reference chain
     540           0 :     return static_cast<SVGPatternElement *>(aDefault)->mPreserveAspectRatio;
     541             :   }
     542             : 
     543           0 :   nsSVGPatternFrame *next = GetReferencedPattern();
     544           0 :   return next ? next->GetPreserveAspectRatio(aDefault)
     545           0 :               : static_cast<SVGPatternElement *>(aDefault)->mPreserveAspectRatio;
     546             : }
     547             : 
     548             : const nsSVGLength2 *
     549           0 : nsSVGPatternFrame::GetLengthValue(uint32_t aIndex, nsIContent *aDefault)
     550             : {
     551             :   const nsSVGLength2 *thisLength =
     552           0 :     &static_cast<SVGPatternElement *>(mContent)->mLengthAttributes[aIndex];
     553             : 
     554           0 :   if (thisLength->IsExplicitlySet())
     555           0 :     return thisLength;
     556             : 
     557             :   // Before we recurse, make sure we'll break reference loops and over long
     558             :   // reference chains:
     559             :   static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
     560             :   AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
     561           0 :                                         &sRefChainLengthCounter);
     562           0 :   if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
     563             :     // Break reference chain
     564           0 :     return &static_cast<SVGPatternElement *>(aDefault)->mLengthAttributes[aIndex];
     565             :   }
     566             : 
     567           0 :   nsSVGPatternFrame *next = GetReferencedPattern();
     568           0 :   return next ? next->GetLengthValue(aIndex, aDefault)
     569           0 :               : &static_cast<SVGPatternElement *>(aDefault)->mLengthAttributes[aIndex];
     570             : }
     571             : 
     572             : // Private (helper) methods
     573             : nsSVGPatternFrame *
     574           0 : nsSVGPatternFrame::GetReferencedPattern()
     575             : {
     576           0 :   if (mNoHRefURI)
     577           0 :     return nullptr;
     578             : 
     579             :   nsSVGPaintingProperty *property =
     580           0 :     GetProperty(nsSVGEffects::HrefAsPaintingProperty());
     581             : 
     582           0 :   if (!property) {
     583             :     // Fetch our pattern element's href or xlink:href attribute
     584           0 :     SVGPatternElement *pattern = static_cast<SVGPatternElement *>(mContent);
     585           0 :     nsAutoString href;
     586           0 :     if (pattern->mStringAttributes[SVGPatternElement::HREF].IsExplicitlySet()) {
     587             :       pattern->mStringAttributes[SVGPatternElement::HREF]
     588           0 :         .GetAnimValue(href, pattern);
     589             :     } else {
     590             :       pattern->mStringAttributes[SVGPatternElement::XLINK_HREF]
     591           0 :         .GetAnimValue(href, pattern);
     592             :     }
     593             : 
     594           0 :     if (href.IsEmpty()) {
     595           0 :       mNoHRefURI = true;
     596           0 :       return nullptr; // no URL
     597             :     }
     598             : 
     599             :     // Convert href to an nsIURI
     600           0 :     nsCOMPtr<nsIURI> targetURI;
     601           0 :     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     602           0 :     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
     603           0 :                                               mContent->GetUncomposedDoc(), base);
     604             : 
     605             :     property =
     606           0 :       nsSVGEffects::GetPaintingProperty(targetURI, this,
     607           0 :                                         nsSVGEffects::HrefAsPaintingProperty());
     608           0 :     if (!property)
     609           0 :       return nullptr;
     610             :   }
     611             : 
     612           0 :   nsIFrame *result = property->GetReferencedFrame();
     613           0 :   if (!result)
     614           0 :     return nullptr;
     615             : 
     616           0 :   LayoutFrameType frameType = result->Type();
     617           0 :   if (frameType != LayoutFrameType::SVGPattern)
     618           0 :     return nullptr;
     619             : 
     620           0 :   return static_cast<nsSVGPatternFrame*>(result);
     621             : }
     622             : 
     623             : gfxRect
     624           0 : nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
     625             :                                   const gfxRect &aTargetBBox,
     626             :                                   const Matrix &aTargetCTM,
     627             :                                   nsIFrame *aTarget)
     628             : {
     629             :   // We need to initialize our box
     630             :   float x,y,width,height;
     631             : 
     632             :   // Get the pattern x,y,width, and height
     633             :   const nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
     634           0 :   tmpX = GetLengthValue(SVGPatternElement::ATTR_X);
     635           0 :   tmpY = GetLengthValue(SVGPatternElement::ATTR_Y);
     636           0 :   tmpHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT);
     637           0 :   tmpWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH);
     638             : 
     639           0 :   if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
     640           0 :     x = nsSVGUtils::ObjectSpace(aTargetBBox, tmpX);
     641           0 :     y = nsSVGUtils::ObjectSpace(aTargetBBox, tmpY);
     642           0 :     width = nsSVGUtils::ObjectSpace(aTargetBBox, tmpWidth);
     643           0 :     height = nsSVGUtils::ObjectSpace(aTargetBBox, tmpHeight);
     644             :   } else {
     645           0 :     float scale = MaxExpansion(aTargetCTM);
     646           0 :     x = nsSVGUtils::UserSpace(aTarget, tmpX) * scale;
     647           0 :     y = nsSVGUtils::UserSpace(aTarget, tmpY) * scale;
     648           0 :     width = nsSVGUtils::UserSpace(aTarget, tmpWidth) * scale;
     649           0 :     height = nsSVGUtils::UserSpace(aTarget, tmpHeight) * scale;
     650             :   }
     651             : 
     652           0 :   return gfxRect(x, y, width, height);
     653             : }
     654             : 
     655             : gfxMatrix
     656           0 : nsSVGPatternFrame::ConstructCTM(const nsSVGViewBox& aViewBox,
     657             :                                 uint16_t aPatternContentUnits,
     658             :                                 uint16_t aPatternUnits,
     659             :                                 const gfxRect &callerBBox,
     660             :                                 const Matrix &callerCTM,
     661             :                                 nsIFrame *aTarget)
     662             : {
     663           0 :   SVGSVGElement *ctx = nullptr;
     664           0 :   nsIContent* targetContent = aTarget->GetContent();
     665             :   gfxFloat scaleX, scaleY;
     666             : 
     667             :   // The objectBoundingBox conversion must be handled in the CTM:
     668           0 :   if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits)) {
     669           0 :     scaleX = callerBBox.Width();
     670           0 :     scaleY = callerBBox.Height();
     671             :   } else {
     672           0 :     if (targetContent->IsSVGElement()) {
     673           0 :       ctx = static_cast<nsSVGElement*>(targetContent)->GetCtx();
     674             :     }
     675           0 :     scaleX = scaleY = MaxExpansion(callerCTM);
     676             :   }
     677             : 
     678           0 :   if (!aViewBox.IsExplicitlySet()) {
     679           0 :     return gfxMatrix(scaleX, 0.0, 0.0, scaleY, 0.0, 0.0);
     680             :   }
     681           0 :   const nsSVGViewBoxRect viewBoxRect = aViewBox.GetAnimValue();
     682             : 
     683           0 :   if (viewBoxRect.height <= 0.0f || viewBoxRect.width <= 0.0f) {
     684           0 :     return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     685             :   }
     686             : 
     687             :   float viewportWidth, viewportHeight;
     688           0 :   if (targetContent->IsSVGElement()) {
     689             :     // If we're dealing with an SVG target only retrieve the context once.
     690             :     // Calling the nsIFrame* variant of GetAnimValue would look it up on
     691             :     // every call.
     692             :     viewportWidth =
     693           0 :       GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(ctx);
     694             :     viewportHeight =
     695           0 :       GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(ctx);
     696             :   } else {
     697             :     // No SVG target, call the nsIFrame* variant of GetAnimValue.
     698             :     viewportWidth =
     699           0 :       GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(aTarget);
     700             :     viewportHeight =
     701           0 :       GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(aTarget);
     702             :   }
     703             : 
     704           0 :   if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
     705           0 :     return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     706             :   }
     707             : 
     708             :   Matrix tm = SVGContentUtils::GetViewBoxTransform(
     709           0 :     viewportWidth * scaleX, viewportHeight * scaleY,
     710           0 :     viewBoxRect.x, viewBoxRect.y,
     711           0 :     viewBoxRect.width, viewBoxRect.height,
     712           0 :     GetPreserveAspectRatio());
     713             : 
     714           0 :   return ThebesMatrix(tm);
     715             : }
     716             : 
     717             : //----------------------------------------------------------------------
     718             : // nsSVGPaintServerFrame methods:
     719             : already_AddRefed<gfxPattern>
     720           0 : nsSVGPatternFrame::GetPaintServerPattern(nsIFrame *aSource,
     721             :                                          const DrawTarget* aDrawTarget,
     722             :                                          const gfxMatrix& aContextMatrix,
     723             :                                          nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
     724             :                                          float aGraphicOpacity,
     725             :                                          imgDrawingParams& aImgParams,
     726             :                                          const gfxRect *aOverrideBounds)
     727             : {
     728           0 :   if (aGraphicOpacity == 0.0f) {
     729           0 :     return do_AddRef(new gfxPattern(Color()));
     730             :   }
     731             : 
     732             :   // Paint it!
     733           0 :   Matrix pMatrix;
     734             :   RefPtr<SourceSurface> surface =
     735           0 :     PaintPattern(aDrawTarget, &pMatrix, ToMatrix(aContextMatrix), aSource,
     736           0 :                  aFillOrStroke, aGraphicOpacity, aOverrideBounds, aImgParams);
     737             : 
     738           0 :   if (!surface) {
     739           0 :     return nullptr;
     740             :   }
     741             : 
     742           0 :   RefPtr<gfxPattern> pattern = new gfxPattern(surface, pMatrix);
     743             : 
     744           0 :   if (!pattern) {
     745           0 :     return nullptr;
     746             :   }
     747             : 
     748           0 :   pattern->SetExtend(ExtendMode::REPEAT);
     749           0 :   return pattern.forget();
     750             : }
     751             : 
     752             : // -------------------------------------------------------------------------
     753             : // Public functions
     754             : // -------------------------------------------------------------------------
     755             : 
     756           0 : nsIFrame* NS_NewSVGPatternFrame(nsIPresShell*   aPresShell,
     757             :                                 nsStyleContext* aContext)
     758             : {
     759           0 :   return new (aPresShell) nsSVGPatternFrame(aContext);
     760             : }
     761             : 

Generated by: LCOV version 1.13