layout/svg/nsSVGPatternFrame.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

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

mercurial