LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGGradientFrame.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 245 0 0.0 %
Date: 2012-06-02 Functions: 38 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) 2004
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Scooter Morris <scootermorris@comcast.net>
      24                 :  *   Jonathan Watt <jwatt@jwatt.org>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "nsIDOMSVGAnimatedNumber.h"
      41                 : #include "nsIDOMSVGAnimTransformList.h"
      42                 : #include "SVGAnimatedTransformList.h"
      43                 : #include "nsSVGEffects.h"
      44                 : #include "nsIDOMSVGStopElement.h"
      45                 : #include "nsSVGGradientElement.h"
      46                 : #include "nsSVGGeometryFrame.h"
      47                 : #include "nsSVGGradientFrame.h"
      48                 : #include "gfxContext.h"
      49                 : #include "gfxPattern.h"
      50                 : #include "nsContentUtils.h"
      51                 : 
      52                 : using mozilla::SVGAnimatedTransformList;
      53                 : 
      54                 : //----------------------------------------------------------------------
      55                 : // Helper classes
      56                 : 
      57                 : class nsSVGGradientFrame::AutoGradientReferencer
      58                 : {
      59                 : public:
      60               0 :   AutoGradientReferencer(nsSVGGradientFrame *aFrame)
      61               0 :     : mFrame(aFrame)
      62                 :   {
      63                 :     // Reference loops should normally be detected in advance and handled, so
      64                 :     // we're not expecting to encounter them here
      65               0 :     NS_ABORT_IF_FALSE(!mFrame->mLoopFlag, "Undetected reference loop!");
      66               0 :     mFrame->mLoopFlag = true;
      67               0 :   }
      68               0 :   ~AutoGradientReferencer() {
      69               0 :     mFrame->mLoopFlag = false;
      70               0 :   }
      71                 : private:
      72                 :   nsSVGGradientFrame *mFrame;
      73                 : };
      74                 : 
      75                 : //----------------------------------------------------------------------
      76                 : // Implementation
      77                 : 
      78               0 : nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) :
      79                 :   nsSVGGradientFrameBase(aContext),
      80                 :   mLoopFlag(false),
      81               0 :   mNoHRefURI(false)
      82                 : {
      83               0 : }
      84                 : 
      85               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGGradientFrame)
      86                 : 
      87                 : //----------------------------------------------------------------------
      88                 : // nsIFrame methods:
      89                 : 
      90                 : /* virtual */ void
      91               0 : nsSVGGradientFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
      92                 : {
      93               0 :   nsSVGEffects::InvalidateRenderingObservers(this);
      94               0 :   nsSVGGradientFrameBase::DidSetStyleContext(aOldStyleContext);
      95               0 : }
      96                 : 
      97                 : NS_IMETHODIMP
      98               0 : nsSVGGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
      99                 :                                      nsIAtom*        aAttribute,
     100                 :                                      PRInt32         aModType)
     101                 : {
     102               0 :   if (aNameSpaceID == kNameSpaceID_None &&
     103                 :       (aAttribute == nsGkAtoms::gradientUnits ||
     104                 :        aAttribute == nsGkAtoms::gradientTransform ||
     105                 :        aAttribute == nsGkAtoms::spreadMethod)) {
     106               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     107               0 :   } else if (aNameSpaceID == kNameSpaceID_XLink &&
     108                 :              aAttribute == nsGkAtoms::href) {
     109                 :     // Blow away our reference, if any
     110               0 :     Properties().Delete(nsSVGEffects::HrefProperty());
     111               0 :     mNoHRefURI = false;
     112                 :     // And update whoever references us
     113               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     114                 :   }
     115                 : 
     116                 :   return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
     117               0 :                                                   aAttribute, aModType);
     118                 : }
     119                 : 
     120                 : //----------------------------------------------------------------------
     121                 : 
     122                 : PRUint32
     123               0 : nsSVGGradientFrame::GetStopCount()
     124                 : {
     125               0 :   return GetStopFrame(-1, nsnull);
     126                 : }
     127                 : 
     128                 : void
     129               0 : nsSVGGradientFrame::GetStopInformation(PRInt32 aIndex,
     130                 :                                        float *aOffset,
     131                 :                                        nscolor *aStopColor,
     132                 :                                        float *aStopOpacity)
     133                 : {
     134               0 :   *aOffset = 0.0f;
     135               0 :   *aStopColor = NS_RGBA(0, 0, 0, 0);
     136               0 :   *aStopOpacity = 1.0f;
     137                 : 
     138               0 :   nsIFrame *stopFrame = nsnull;
     139               0 :   GetStopFrame(aIndex, &stopFrame);
     140                 :   nsCOMPtr<nsIDOMSVGStopElement> stopElement =
     141               0 :     do_QueryInterface(stopFrame->GetContent());
     142                 : 
     143               0 :   if (stopElement) {
     144               0 :     nsCOMPtr<nsIDOMSVGAnimatedNumber> aNum;
     145               0 :     stopElement->GetOffset(getter_AddRefs(aNum));
     146                 : 
     147               0 :     aNum->GetAnimVal(aOffset);
     148               0 :     if (*aOffset < 0.0f)
     149               0 :       *aOffset = 0.0f;
     150               0 :     else if (*aOffset > 1.0f)
     151               0 :       *aOffset = 1.0f;
     152                 :   }
     153                 : 
     154               0 :   *aStopColor   = stopFrame->GetStyleSVGReset()->mStopColor;
     155               0 :   *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity;
     156               0 : }
     157                 : 
     158                 : PRUint16
     159               0 : nsSVGGradientFrame::GetEnumValue(PRUint32 aIndex, nsIContent *aDefault)
     160                 : {
     161                 :   const nsSVGEnum& thisEnum =
     162               0 :     static_cast<nsSVGGradientElement *>(mContent)->mEnumAttributes[aIndex];
     163                 : 
     164               0 :   if (thisEnum.IsExplicitlySet())
     165               0 :     return thisEnum.GetAnimValue();
     166                 : 
     167               0 :   AutoGradientReferencer gradientRef(this);
     168                 : 
     169               0 :   nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
     170                 :   return next ? next->GetEnumValue(aIndex, aDefault) :
     171                 :     static_cast<nsSVGGradientElement *>(aDefault)->
     172               0 :       mEnumAttributes[aIndex].GetAnimValue();
     173                 : }
     174                 : 
     175                 : const SVGAnimatedTransformList*
     176               0 : nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
     177                 : {
     178                 :   SVGAnimatedTransformList *thisTransformList =
     179               0 :     static_cast<nsSVGGradientElement *>(mContent)->GetAnimatedTransformList();
     180                 : 
     181               0 :   if (thisTransformList->IsExplicitlySet())
     182               0 :     return thisTransformList;
     183                 : 
     184               0 :   AutoGradientReferencer gradientRef(this);
     185                 : 
     186               0 :   nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
     187                 :   return next ? next->GetGradientTransformList(aDefault) :
     188                 :     static_cast<const nsSVGGradientElement *>(aDefault)
     189               0 :       ->mGradientTransform.get();
     190                 : }
     191                 : 
     192                 : gfxMatrix
     193               0 : nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
     194                 :                                          const gfxRect *aOverrideBounds)
     195                 : {
     196               0 :   gfxMatrix bboxMatrix;
     197                 : 
     198               0 :   PRUint16 gradientUnits = GetGradientUnits();
     199               0 :   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
     200                 :     // If this gradient is applied to text, our caller
     201                 :     // will be the glyph, which is not a container, so we
     202                 :     // need to get the parent
     203               0 :     if (aSource->GetContent()->IsNodeOfType(nsINode::eTEXT))
     204               0 :       mSource = aSource->GetParent();
     205                 :     else
     206               0 :       mSource = aSource;
     207                 :   } else {
     208               0 :     NS_ASSERTION(
     209                 :       gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     210                 :       "Unknown gradientUnits type");
     211                 :     // objectBoundingBox is the default anyway
     212                 : 
     213                 :     gfxRect bbox =
     214               0 :       aOverrideBounds ? *aOverrideBounds : nsSVGUtils::GetBBox(aSource);
     215                 :     bboxMatrix =
     216               0 :       gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
     217                 :   }
     218                 : 
     219                 :   const SVGAnimatedTransformList* animTransformList =
     220               0 :     GetGradientTransformList(mContent);
     221               0 :   if (!animTransformList)
     222               0 :     return bboxMatrix;
     223                 : 
     224                 :   gfxMatrix gradientTransform =
     225               0 :     animTransformList->GetAnimValue().GetConsolidationMatrix();
     226               0 :   return bboxMatrix.PreMultiply(gradientTransform);
     227                 : }
     228                 : 
     229                 : nsSVGLinearGradientElement *
     230               0 : nsSVGGradientFrame::GetLinearGradientWithLength(PRUint32 aIndex,
     231                 :   nsSVGLinearGradientElement* aDefault)
     232                 : {
     233                 :   // If this was a linear gradient with the required length, we would have
     234                 :   // already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
     235                 :   // Since we didn't find the length, continue looking down the chain.
     236                 : 
     237               0 :   AutoGradientReferencer gradientRef(this);
     238                 : 
     239               0 :   nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
     240               0 :   return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
     241                 : }
     242                 : 
     243                 : nsSVGRadialGradientElement *
     244               0 : nsSVGGradientFrame::GetRadialGradientWithLength(PRUint32 aIndex,
     245                 :   nsSVGRadialGradientElement* aDefault)
     246                 : {
     247                 :   // If this was a radial gradient with the required length, we would have
     248                 :   // already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
     249                 :   // Since we didn't find the length, continue looking down the chain.
     250                 : 
     251               0 :   AutoGradientReferencer gradientRef(this);
     252                 : 
     253               0 :   nsSVGGradientFrame *next = GetReferencedGradientIfNotInUse();
     254               0 :   return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
     255                 : }
     256                 : 
     257                 : //----------------------------------------------------------------------
     258                 : // nsSVGPaintServerFrame methods:
     259                 : 
     260                 : already_AddRefed<gfxPattern>
     261               0 : nsSVGGradientFrame::GetPaintServerPattern(nsIFrame *aSource,
     262                 :                                            float aGraphicOpacity,
     263                 :                                            const gfxRect *aOverrideBounds)
     264                 : {
     265                 :   // Get the transform list (if there is one)
     266               0 :   gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
     267                 : 
     268               0 :   if (patternMatrix.IsSingular())
     269               0 :     return nsnull;
     270                 : 
     271               0 :   PRUint32 nStops = GetStopCount();
     272                 : 
     273                 :   // SVG specification says that no stops should be treated like
     274                 :   // the corresponding fill or stroke had "none" specified.
     275               0 :   if (nStops == 0) {
     276               0 :     nsRefPtr<gfxPattern> pattern = new gfxPattern(gfxRGBA(0, 0, 0, 0));
     277               0 :     return pattern.forget();
     278                 :   }
     279                 : 
     280               0 :   patternMatrix.Invert();
     281                 : 
     282               0 :   nsRefPtr<gfxPattern> gradient = CreateGradient();
     283               0 :   if (!gradient || gradient->CairoStatus())
     284               0 :     return nsnull;
     285                 : 
     286               0 :   PRUint16 aSpread = GetSpreadMethod();
     287               0 :   if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_PAD)
     288               0 :     gradient->SetExtend(gfxPattern::EXTEND_PAD);
     289               0 :   else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REFLECT)
     290               0 :     gradient->SetExtend(gfxPattern::EXTEND_REFLECT);
     291               0 :   else if (aSpread == nsIDOMSVGGradientElement::SVG_SPREADMETHOD_REPEAT)
     292               0 :     gradient->SetExtend(gfxPattern::EXTEND_REPEAT);
     293                 : 
     294               0 :   gradient->SetMatrix(patternMatrix);
     295                 : 
     296                 :   // setup stops
     297               0 :   float lastOffset = 0.0f;
     298                 : 
     299               0 :   for (PRUint32 i = 0; i < nStops; i++) {
     300                 :     float offset, stopOpacity;
     301                 :     nscolor stopColor;
     302                 : 
     303               0 :     GetStopInformation(i, &offset, &stopColor, &stopOpacity);
     304                 : 
     305               0 :     if (offset < lastOffset)
     306               0 :       offset = lastOffset;
     307                 :     else
     308               0 :       lastOffset = offset;
     309                 : 
     310                 :     gradient->AddColorStop(offset,
     311                 :                            gfxRGBA(NS_GET_R(stopColor)/255.0,
     312                 :                                    NS_GET_G(stopColor)/255.0,
     313                 :                                    NS_GET_B(stopColor)/255.0,
     314                 :                                    NS_GET_A(stopColor)/255.0 *
     315               0 :                                      stopOpacity * aGraphicOpacity));
     316                 :   }
     317                 : 
     318               0 :   return gradient.forget();
     319                 : }
     320                 : 
     321                 : // Private (helper) methods
     322                 : 
     323                 : nsSVGGradientFrame *
     324               0 : nsSVGGradientFrame::GetReferencedGradient()
     325                 : {
     326               0 :   if (mNoHRefURI)
     327               0 :     return nsnull;
     328                 : 
     329                 :   nsSVGPaintingProperty *property = static_cast<nsSVGPaintingProperty*>
     330               0 :     (Properties().Get(nsSVGEffects::HrefProperty()));
     331                 : 
     332               0 :   if (!property) {
     333                 :     // Fetch our gradient element's xlink:href attribute
     334               0 :     nsSVGGradientElement *grad = static_cast<nsSVGGradientElement *>(mContent);
     335               0 :     nsAutoString href;
     336               0 :     grad->mStringAttributes[nsSVGGradientElement::HREF].GetAnimValue(href, grad);
     337               0 :     if (href.IsEmpty()) {
     338               0 :       mNoHRefURI = true;
     339               0 :       return nsnull; // no URL
     340                 :     }
     341                 : 
     342                 :     // Convert href to an nsIURI
     343               0 :     nsCOMPtr<nsIURI> targetURI;
     344               0 :     nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
     345               0 :     nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
     346               0 :                                               mContent->GetCurrentDoc(), base);
     347                 : 
     348                 :     property =
     349               0 :       nsSVGEffects::GetPaintingProperty(targetURI, this, nsSVGEffects::HrefProperty());
     350               0 :     if (!property)
     351               0 :       return nsnull;
     352                 :   }
     353                 : 
     354               0 :   nsIFrame *result = property->GetReferencedFrame();
     355               0 :   if (!result)
     356               0 :     return nsnull;
     357                 : 
     358               0 :   nsIAtom* frameType = result->GetType();
     359               0 :   if (frameType != nsGkAtoms::svgLinearGradientFrame &&
     360                 :       frameType != nsGkAtoms::svgRadialGradientFrame)
     361               0 :     return nsnull;
     362                 : 
     363               0 :   return static_cast<nsSVGGradientFrame*>(result);
     364                 : }
     365                 : 
     366                 : nsSVGGradientFrame *
     367               0 : nsSVGGradientFrame::GetReferencedGradientIfNotInUse()
     368                 : {
     369               0 :   nsSVGGradientFrame *referenced = GetReferencedGradient();
     370               0 :   if (!referenced)
     371               0 :     return nsnull;
     372                 : 
     373               0 :   if (referenced->mLoopFlag) {
     374                 :     // XXXjwatt: we should really send an error to the JavaScript Console here:
     375               0 :     NS_WARNING("gradient reference loop detected while inheriting attribute!");
     376               0 :     return nsnull;
     377                 :   }
     378                 : 
     379               0 :   return referenced;
     380                 : }
     381                 : 
     382                 : PRInt32
     383               0 : nsSVGGradientFrame::GetStopFrame(PRInt32 aIndex, nsIFrame * *aStopFrame)
     384                 : {
     385               0 :   PRInt32 stopCount = 0;
     386               0 :   nsIFrame *stopFrame = nsnull;
     387               0 :   for (stopFrame = mFrames.FirstChild(); stopFrame;
     388                 :        stopFrame = stopFrame->GetNextSibling()) {
     389               0 :     if (stopFrame->GetType() == nsGkAtoms::svgStopFrame) {
     390                 :       // Is this the one we're looking for?
     391               0 :       if (stopCount++ == aIndex)
     392               0 :         break; // Yes, break out of the loop
     393                 :     }
     394                 :   }
     395               0 :   if (stopCount > 0) {
     396               0 :     if (aStopFrame)
     397               0 :       *aStopFrame = stopFrame;
     398               0 :     return stopCount;
     399                 :   }
     400                 : 
     401                 :   // Our gradient element doesn't have stops - try to "inherit" them
     402                 : 
     403               0 :   AutoGradientReferencer gradientRef(this);
     404               0 :   nsSVGGradientFrame* next = GetReferencedGradientIfNotInUse();
     405               0 :   if (!next)
     406               0 :     return nsnull;
     407                 : 
     408               0 :   return next->GetStopFrame(aIndex, aStopFrame);
     409                 : }
     410                 : 
     411                 : // -------------------------------------------------------------------------
     412                 : // Linear Gradients
     413                 : // -------------------------------------------------------------------------
     414                 : 
     415                 : #ifdef DEBUG
     416                 : NS_IMETHODIMP
     417               0 : nsSVGLinearGradientFrame::Init(nsIContent* aContent,
     418                 :                                nsIFrame* aParent,
     419                 :                                nsIFrame* aPrevInFlow)
     420                 : {
     421               0 :   nsCOMPtr<nsIDOMSVGLinearGradientElement> grad = do_QueryInterface(aContent);
     422               0 :   NS_ASSERTION(grad, "Content is not an SVG linearGradient");
     423                 : 
     424               0 :   return nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
     425                 : }
     426                 : #endif /* DEBUG */
     427                 : 
     428                 : nsIAtom*
     429               0 : nsSVGLinearGradientFrame::GetType() const
     430                 : {
     431               0 :   return nsGkAtoms::svgLinearGradientFrame;
     432                 : }
     433                 : 
     434                 : NS_IMETHODIMP
     435               0 : nsSVGLinearGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
     436                 :                                            nsIAtom*        aAttribute,
     437                 :                                            PRInt32         aModType)
     438                 : {
     439               0 :   if (aNameSpaceID == kNameSpaceID_None &&
     440                 :       (aAttribute == nsGkAtoms::x1 ||
     441                 :        aAttribute == nsGkAtoms::y1 ||
     442                 :        aAttribute == nsGkAtoms::x2 ||
     443                 :        aAttribute == nsGkAtoms::y2)) {
     444               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     445                 :   }
     446                 : 
     447                 :   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
     448               0 :                                               aAttribute, aModType);
     449                 : }
     450                 : 
     451                 : //----------------------------------------------------------------------
     452                 : 
     453                 : float
     454               0 : nsSVGLinearGradientFrame::GetLengthValue(PRUint32 aIndex)
     455                 : {
     456                 :   nsSVGLinearGradientElement* lengthElement =
     457                 :     GetLinearGradientWithLength(aIndex,
     458               0 :       static_cast<nsSVGLinearGradientElement *>(mContent));
     459                 :   // We passed in mContent as a fallback, so, assuming mContent is non-null, the
     460                 :   // return value should also be non-null.
     461               0 :   NS_ABORT_IF_FALSE(lengthElement,
     462                 :     "Got unexpected null element from GetLinearGradientWithLength");
     463               0 :   const nsSVGLength2 &length = lengthElement->mLengthAttributes[aIndex];
     464                 : 
     465                 :   // Object bounding box units are handled by setting the appropriate
     466                 :   // transform in GetGradientTransform, but we need to handle user
     467                 :   // space units as part of the individual Get* routines.  Fixes 323669.
     468                 : 
     469               0 :   PRUint16 gradientUnits = GetGradientUnits();
     470               0 :   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
     471               0 :     return nsSVGUtils::UserSpace(mSource, &length);
     472                 :   }
     473                 : 
     474               0 :   NS_ASSERTION(
     475                 :     gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     476                 :     "Unknown gradientUnits type");
     477                 : 
     478               0 :   return length.GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
     479                 : }
     480                 : 
     481                 : nsSVGLinearGradientElement *
     482               0 : nsSVGLinearGradientFrame::GetLinearGradientWithLength(PRUint32 aIndex,
     483                 :   nsSVGLinearGradientElement* aDefault)
     484                 : {
     485                 :   nsSVGLinearGradientElement* thisElement =
     486               0 :     static_cast<nsSVGLinearGradientElement *>(mContent);
     487               0 :   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
     488                 : 
     489               0 :   if (length.IsExplicitlySet()) {
     490               0 :     return thisElement;
     491                 :   }
     492                 : 
     493                 :   return nsSVGLinearGradientFrameBase::GetLinearGradientWithLength(aIndex,
     494               0 :                                                                    aDefault);
     495                 : }
     496                 : 
     497                 : already_AddRefed<gfxPattern>
     498               0 : nsSVGLinearGradientFrame::CreateGradient()
     499                 : {
     500                 :   float x1, y1, x2, y2;
     501                 : 
     502               0 :   x1 = GetLengthValue(nsSVGLinearGradientElement::X1);
     503               0 :   y1 = GetLengthValue(nsSVGLinearGradientElement::Y1);
     504               0 :   x2 = GetLengthValue(nsSVGLinearGradientElement::X2);
     505               0 :   y2 = GetLengthValue(nsSVGLinearGradientElement::Y2);
     506                 : 
     507               0 :   gfxPattern *pattern = new gfxPattern(x1, y1, x2, y2);
     508               0 :   NS_IF_ADDREF(pattern);
     509               0 :   return pattern;
     510                 : }
     511                 : 
     512                 : // -------------------------------------------------------------------------
     513                 : // Radial Gradients
     514                 : // -------------------------------------------------------------------------
     515                 : 
     516                 : #ifdef DEBUG
     517                 : NS_IMETHODIMP
     518               0 : nsSVGRadialGradientFrame::Init(nsIContent* aContent,
     519                 :                                nsIFrame* aParent,
     520                 :                                nsIFrame* aPrevInFlow)
     521                 : {
     522               0 :   nsCOMPtr<nsIDOMSVGRadialGradientElement> grad = do_QueryInterface(aContent);
     523               0 :   NS_ASSERTION(grad, "Content is not an SVG radialGradient");
     524                 : 
     525               0 :   return nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
     526                 : }
     527                 : #endif /* DEBUG */
     528                 : 
     529                 : nsIAtom*
     530               0 : nsSVGRadialGradientFrame::GetType() const
     531                 : {
     532               0 :   return nsGkAtoms::svgRadialGradientFrame;
     533                 : }
     534                 : 
     535                 : NS_IMETHODIMP
     536               0 : nsSVGRadialGradientFrame::AttributeChanged(PRInt32         aNameSpaceID,
     537                 :                                            nsIAtom*        aAttribute,
     538                 :                                            PRInt32         aModType)
     539                 : {
     540               0 :   if (aNameSpaceID == kNameSpaceID_None &&
     541                 :       (aAttribute == nsGkAtoms::r ||
     542                 :        aAttribute == nsGkAtoms::cx ||
     543                 :        aAttribute == nsGkAtoms::cy ||
     544                 :        aAttribute == nsGkAtoms::fx ||
     545                 :        aAttribute == nsGkAtoms::fy)) {
     546               0 :     nsSVGEffects::InvalidateRenderingObservers(this);
     547                 :   }
     548                 : 
     549                 :   return nsSVGGradientFrame::AttributeChanged(aNameSpaceID,
     550               0 :                                               aAttribute, aModType);
     551                 : }
     552                 : 
     553                 : //----------------------------------------------------------------------
     554                 : 
     555                 : float
     556               0 : nsSVGRadialGradientFrame::GetLengthValue(PRUint32 aIndex)
     557                 : {
     558                 :   nsSVGRadialGradientElement* lengthElement =
     559                 :     GetRadialGradientWithLength(aIndex,
     560               0 :       static_cast<nsSVGRadialGradientElement *>(mContent));
     561                 :   // We passed in mContent as a fallback, so, assuming mContent is non-null,
     562                 :   // the return value should also be non-null.
     563               0 :   NS_ABORT_IF_FALSE(lengthElement,
     564                 :     "Got unexpected null element from GetRadialGradientWithLength");
     565               0 :   return GetLengthValueFromElement(aIndex, *lengthElement);
     566                 : }
     567                 : 
     568                 : float
     569               0 : nsSVGRadialGradientFrame::GetLengthValue(PRUint32 aIndex, float aDefaultValue)
     570                 : {
     571                 :   nsSVGRadialGradientElement* lengthElement =
     572               0 :     GetRadialGradientWithLength(aIndex, nsnull);
     573                 : 
     574                 :   return lengthElement ? GetLengthValueFromElement(aIndex, *lengthElement)
     575               0 :                        : aDefaultValue;
     576                 : }
     577                 : 
     578                 : float
     579               0 : nsSVGRadialGradientFrame::GetLengthValueFromElement(PRUint32 aIndex,
     580                 :   nsSVGRadialGradientElement& aElement)
     581                 : {
     582               0 :   const nsSVGLength2 &length = aElement.mLengthAttributes[aIndex];
     583                 : 
     584                 :   // Object bounding box units are handled by setting the appropriate
     585                 :   // transform in GetGradientTransform, but we need to handle user
     586                 :   // space units as part of the individual Get* routines.  Fixes 323669.
     587                 : 
     588               0 :   PRUint16 gradientUnits = GetGradientUnits();
     589               0 :   if (gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
     590               0 :     return nsSVGUtils::UserSpace(mSource, &length);
     591                 :   }
     592                 : 
     593               0 :   NS_ASSERTION(
     594                 :     gradientUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
     595                 :     "Unknown gradientUnits type");
     596                 : 
     597               0 :   return length.GetAnimValue(static_cast<nsSVGSVGElement*>(nsnull));
     598                 : }
     599                 : 
     600                 : nsSVGRadialGradientElement *
     601               0 : nsSVGRadialGradientFrame::GetRadialGradientWithLength(PRUint32 aIndex,
     602                 :   nsSVGRadialGradientElement* aDefault)
     603                 : {
     604                 :   nsSVGRadialGradientElement* thisElement =
     605               0 :     static_cast<nsSVGRadialGradientElement *>(mContent);
     606               0 :   const nsSVGLength2 &length = thisElement->mLengthAttributes[aIndex];
     607                 : 
     608               0 :   if (length.IsExplicitlySet()) {
     609               0 :     return thisElement;
     610                 :   }
     611                 : 
     612                 :   return nsSVGRadialGradientFrameBase::GetRadialGradientWithLength(aIndex,
     613               0 :                                                                    aDefault);
     614                 : }
     615                 : 
     616                 : already_AddRefed<gfxPattern>
     617               0 : nsSVGRadialGradientFrame::CreateGradient()
     618                 : {
     619                 :   float cx, cy, r, fx, fy;
     620                 : 
     621               0 :   cx = GetLengthValue(nsSVGRadialGradientElement::CX);
     622               0 :   cy = GetLengthValue(nsSVGRadialGradientElement::CY);
     623               0 :   r  = GetLengthValue(nsSVGRadialGradientElement::R);
     624                 :   // If fx or fy are not set, use cx/cy instead
     625               0 :   fx = GetLengthValue(nsSVGRadialGradientElement::FX, cx);
     626               0 :   fy = GetLengthValue(nsSVGRadialGradientElement::FY, cy);
     627                 : 
     628               0 :   if (fx != cx || fy != cy) {
     629                 :     // The focal point (fFx and fFy) must be clamped to be *inside* - not on -
     630                 :     // the circumference of the gradient or we'll get rendering anomalies. We
     631                 :     // calculate the distance from the focal point to the gradient center and
     632                 :     // make sure it is *less* than the gradient radius.
     633                 :     // 1/128 is the limit of the fractional part of cairo's 24.8 fixed point
     634                 :     // representation divided by 2 to ensure that we get different cairo
     635                 :     // fractions
     636               0 :     double dMax = NS_MAX(0.0, r - 1.0/128);
     637               0 :     float dx = fx - cx;
     638               0 :     float dy = fy - cy;
     639               0 :     double d = sqrt((dx * dx) + (dy * dy));
     640               0 :     if (d > dMax) {
     641               0 :       double angle = atan2(dy, dx);
     642               0 :       fx = (float)(dMax * cos(angle)) + cx;
     643               0 :       fy = (float)(dMax * sin(angle)) + cy;
     644                 :     }
     645                 :   }
     646                 : 
     647               0 :   gfxPattern *pattern = new gfxPattern(fx, fy, 0, cx, cy, r);
     648               0 :   NS_IF_ADDREF(pattern);
     649               0 :   return pattern;
     650                 : }
     651                 : 
     652                 : // -------------------------------------------------------------------------
     653                 : // Public functions
     654                 : // -------------------------------------------------------------------------
     655                 : 
     656                 : nsIFrame*
     657               0 : NS_NewSVGLinearGradientFrame(nsIPresShell*   aPresShell,
     658                 :                              nsStyleContext* aContext)
     659                 : {
     660               0 :   return new (aPresShell) nsSVGLinearGradientFrame(aContext);
     661                 : }
     662                 : 
     663               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGLinearGradientFrame)
     664                 : 
     665                 : nsIFrame*
     666               0 : NS_NewSVGRadialGradientFrame(nsIPresShell*   aPresShell,
     667                 :                              nsStyleContext* aContext)
     668                 : {
     669               0 :   return new (aPresShell) nsSVGRadialGradientFrame(aContext);
     670                 : }
     671                 : 
     672               0 : NS_IMPL_FRAMEARENA_HELPERS(nsSVGRadialGradientFrame)

Generated by: LCOV version 1.7