diff --git a/layout/svg/base/src/nsSVGGradientFrame.cpp b/layout/svg/base/src/nsSVGGradientFrame.cpp index 97d4016cdba..211129813d7 100644 --- a/layout/svg/base/src/nsSVGGradientFrame.cpp +++ b/layout/svg/base/src/nsSVGGradientFrame.cpp @@ -148,6 +148,7 @@ protected: // nsSVGGradientFrame *mNextGrad; + PRBool mLoopFlag; private: // Cached values @@ -275,6 +276,7 @@ nsSVGGradientFrame::~nsSVGGradientFrame() // Remove observers on gradient attributes if (mGradientUnits) NS_REMOVE_SVGVALUE_OBSERVER(mGradientUnits); if (mSpreadMethod) NS_REMOVE_SVGVALUE_OBSERVER(mSpreadMethod); + if (mNextGrad) mNextGrad->RemoveObserver(this); } //---------------------------------------------------------------------- @@ -302,6 +304,16 @@ NS_IMETHODIMP nsSVGGradientFrame::DidModifySVGObservable(nsISVGValue* observable, nsISVGValue::modificationType aModType) { + nsCOMPtr gradient = do_QueryInterface(observable); + // Is this a gradient we are observing that is going away? + if (mNextGrad && aModType == nsISVGValue::mod_die && gradient) { + // Yes, we need to handle this differently + nsISVGGradient *grad; + CallQueryInterface(mNextGrad, &grad); + if (grad == gradient) { + mNextGrad = nsnull; + } + } // Something we depend on was modified -- pass it on! DidModify(aModType); return NS_OK; @@ -338,7 +350,10 @@ nsSVGGradientFrame::GetStopCount(PRUint32 *aStopCount) // No stops? check for URI target if (checkURITarget()) rv = mNextGrad->GetStopCount(aStopCount); + else + rv = NS_ERROR_FAILURE; } + mLoopFlag = PR_FALSE; return rv; } @@ -346,24 +361,27 @@ NS_IMETHODIMP nsSVGGradientFrame::GetStopOffset(PRInt32 aIndex, float *aOffset) { nsIDOMSVGStopElement *stopElement = nsnull; + nsresult rv = NS_OK; PRInt32 stopCount = GetStopElement(aIndex, &stopElement, nsnull); - if (stopCount == 0 && !stopElement) { - // No stops? check for URI target - if (checkURITarget()) - return mNextGrad->GetStopOffset(aIndex, aOffset); - } - if (!stopElement) { - *aOffset = nsnull; + + if (stopCount && !stopElement) { + *aOffset = 0.0f; return NS_ERROR_FAILURE; } - nsCOMPtr aNum; - stopElement->GetOffset(getter_AddRefs(aNum)); - aNum->GetAnimVal(aOffset); - if (*aOffset < 0.0f) - *aOffset = 0.0f; - if (*aOffset > 1.0f) - *aOffset = 1.0f; - return NS_OK; + + if (stopCount == 0 && !stopElement && checkURITarget()) { + rv = mNextGrad->GetStopOffset(aIndex, aOffset); + } else { + nsCOMPtr aNum; + stopElement->GetOffset(getter_AddRefs(aNum)); + aNum->GetAnimVal(aOffset); + if (*aOffset < 0.0f) + *aOffset = 0.0f; + if (*aOffset > 1.0f) + *aOffset = 1.0f; + } + mLoopFlag = PR_FALSE; + return rv; } NS_IMETHODIMP @@ -371,19 +389,19 @@ nsSVGGradientFrame::GetStopColorType(PRInt32 aIndex, PRUint16 *aStopColorType) { nsIDOMSVGStopElement *stopElement = nsnull; nsIFrame *stopFrame = nsnull; + nsresult rv = NS_OK; PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); - if (stopCount == 0 && !stopElement) { - // No stops? check for URI target - if (checkURITarget()) - return mNextGrad->GetStopColorType(aIndex, aStopColorType); - } - if (!stopElement) { + if (stopCount && !stopElement) { *aStopColorType = 0; return NS_ERROR_FAILURE; } - - *aStopColorType = stopFrame->GetStyleSVGReset()->mStopColor.mType; - return NS_OK; + if (stopCount == 0 && !stopElement && checkURITarget()) { + rv = mNextGrad->GetStopColorType(aIndex, aStopColorType); + } else { + *aStopColorType = stopFrame->GetStyleSVGReset()->mStopColor.mType; + } + mLoopFlag = PR_FALSE; + return rv; } NS_IMETHODIMP @@ -391,19 +409,25 @@ nsSVGGradientFrame::GetStopColor(PRInt32 aIndex, nscolor *aStopColor) { nsIDOMSVGStopElement *stopElement = nsnull; nsIFrame *stopFrame = nsnull; + nsresult rv = NS_OK; PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); - if (stopCount == 0 && !stopElement) { - // No stops? check for URI target - if (checkURITarget()) - return mNextGrad->GetStopColor(aIndex, aStopColor); - } - NS_ASSERTION(stopFrame, "No stop frame found!"); - if (!stopFrame) { + if (stopCount && !stopElement) { *aStopColor = 0; return NS_ERROR_FAILURE; } - *aStopColor = stopFrame->GetStyleSVGReset()->mStopColor.mPaint.mColor; - return NS_OK; + if (stopCount == 0 && !stopElement && checkURITarget()) { + rv = mNextGrad->GetStopColor(aIndex, aStopColor); + } else { + NS_ASSERTION(stopFrame, "No stop frame found!"); + if (!stopFrame) { + *aStopColor = 0; + rv = NS_ERROR_FAILURE; + } else { + *aStopColor = stopFrame->GetStyleSVGReset()->mStopColor.mPaint.mColor; + } + } + mLoopFlag = PR_FALSE; + return rv; } NS_IMETHODIMP @@ -411,19 +435,25 @@ nsSVGGradientFrame::GetStopOpacity(PRInt32 aIndex, float *aStopOpacity) { nsIDOMSVGStopElement *stopElement = nsnull; nsIFrame *stopFrame = nsnull; + nsresult rv = NS_OK; PRInt32 stopCount = GetStopElement(aIndex, &stopElement, &stopFrame); - if (stopCount == 0 && !stopElement) { - // No stops? check for URI target - if (checkURITarget()) - return mNextGrad->GetStopOpacity(aIndex, aStopOpacity); - } - if (!stopFrame) { - *aStopOpacity = 1.0f; + if (stopCount && !stopElement) { + *aStopOpacity = 0; return NS_ERROR_FAILURE; } - - *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity; - return NS_OK; + if (stopCount == 0 && !stopElement && checkURITarget()) { + rv = mNextGrad->GetStopOpacity(aIndex, aStopOpacity); + } else { + NS_ASSERTION(stopFrame, "No stop frame found!"); + if (!stopFrame) { + *aStopOpacity = 1.0f; + rv = NS_ERROR_FAILURE; + } else { + *aStopOpacity = stopFrame->GetStyleSVGReset()->mStopOpacity; + } + } + mLoopFlag = PR_FALSE; + return rv; } NS_IMETHODIMP @@ -509,6 +539,7 @@ nsSVGGradientFrame::GetGradientTransform(nsIDOMSVGMatrix **aGradientTransform, } else { // Yes, get it from the target mNextGrad->GetGradientTransform(getter_AddRefs(gradientTransform), nsnull); + mLoopFlag = PR_FALSE; } bboxTransform->Multiply(gradientTransform, aGradientTransform); @@ -548,6 +579,7 @@ nsSVGGradientFrame::PrivateGetGradientUnits(nsIDOMSVGAnimatedEnumeration * *aEnu } else { // Yes, get it from the target mNextGrad->PrivateGetGradientUnits(aEnum); + mLoopFlag = PR_FALSE; } return NS_OK; } @@ -567,26 +599,20 @@ nsSVGGradientFrame::PrivateGetSpreadMethod(nsIDOMSVGAnimatedEnumeration * *aEnum } else { // Yes, get it from the target mNextGrad->PrivateGetSpreadMethod(aEnum); + mLoopFlag = PR_FALSE; } return NS_OK; } NS_IMETHODIMP nsSVGGradientFrame::GetNextGradient(nsISVGGradient * *aNextGrad, PRUint32 aType) { - if (checkURITarget()) { - // OK, we have a reference. We need to find the next reference that points to - // our type - PRUint32 nextType; - mNextGrad->GetGradientType(&nextType); - if (nextType == aType) { - *aNextGrad = mNextGrad; - return NS_OK; - } else { - return mNextGrad->GetNextGradient(aNextGrad, aType); - } + PRUint32 nextType; + mNextGrad->GetGradientType(&nextType); + if (nextType == aType) { + *aNextGrad = mNextGrad; + return NS_OK; } else { - *aNextGrad = nsnull; - return NS_ERROR_FAILURE; + return mNextGrad->GetNextGradient(aNextGrad, aType); } } @@ -604,6 +630,7 @@ nsSVGGradientFrame::checkURITarget(nsIAtom *attr) { PRBool nsSVGGradientFrame::checkURITarget(void) { nsIFrame *aNextGrad; + mLoopFlag = PR_TRUE; // Set our loop detection flag // Have we already figured out the next Gradient? if (mNextGrad != nsnull) { return PR_TRUE; @@ -624,7 +651,15 @@ nsSVGGradientFrame::checkURITarget(void) { if ((frameType != nsLayoutAtoms::svgLinearGradientFrame) && (frameType != nsLayoutAtoms::svgRadialGradientFrame)) return PR_FALSE; + mNextGrad = (nsSVGGradientFrame *)aNextGrad; + if (mNextGrad->mLoopFlag) { + // Yes, remove the reference and return an error + NS_WARNING("Gradient loop detected!"); + CopyUTF8toUTF16("", mNextGradStr); + mNextGrad = nsnull; + return PR_FALSE; + } // Add ourselves to the observer list if (mNextGrad) { // Can't use the NS_ADD macro here because of nsISupports ambiguity @@ -703,6 +738,7 @@ nsSVGLinearGradientFrame::PrivateGetX1(nsIDOMSVGLength * *aX1) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; aLNgrad->PrivateGetX1(aX1); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -712,6 +748,7 @@ nsSVGLinearGradientFrame::PrivateGetX1(nsIDOMSVGLength * *aX1) nsCOMPtr aLen; aLgrad->GetX1(getter_AddRefs(aLen)); aLen->GetAnimVal(aX1); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -730,6 +767,7 @@ nsSVGLinearGradientFrame::PrivateGetY1(nsIDOMSVGLength * *aY1) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; aLNgrad->PrivateGetY1(aY1); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -739,6 +777,7 @@ nsSVGLinearGradientFrame::PrivateGetY1(nsIDOMSVGLength * *aY1) nsCOMPtr aLen; aLgrad->GetY1(getter_AddRefs(aLen)); aLen->GetAnimVal(aY1); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -757,6 +796,7 @@ nsSVGLinearGradientFrame::PrivateGetX2(nsIDOMSVGLength * *aX2) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; aLNgrad->PrivateGetX2(aX2); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -766,6 +806,7 @@ nsSVGLinearGradientFrame::PrivateGetX2(nsIDOMSVGLength * *aX2) nsCOMPtr aLen; aLgrad->GetX2(getter_AddRefs(aLen)); aLen->GetAnimVal(aX2); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -784,6 +825,7 @@ nsSVGLinearGradientFrame::PrivateGetY2(nsIDOMSVGLength * *aY2) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_LINEAR_GRADIENT) == NS_OK) { nsSVGLinearGradientFrame *aLNgrad = (nsSVGLinearGradientFrame *)aNextGrad; aLNgrad->PrivateGetY2(aY2); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -793,6 +835,7 @@ nsSVGLinearGradientFrame::PrivateGetY2(nsIDOMSVGLength * *aY2) nsCOMPtr aLen; aLgrad->GetY2(getter_AddRefs(aLen)); aLen->GetAnimVal(aY2); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -892,6 +935,7 @@ nsSVGRadialGradientFrame::PrivateGetCx(nsIDOMSVGLength * *aCx) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; aRNgrad->PrivateGetCx(aCx); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -901,6 +945,7 @@ nsSVGRadialGradientFrame::PrivateGetCx(nsIDOMSVGLength * *aCx) nsCOMPtr aLen; aRgrad->GetCx(getter_AddRefs(aLen)); aLen->GetAnimVal(aCx); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -919,6 +964,7 @@ nsSVGRadialGradientFrame::PrivateGetCy(nsIDOMSVGLength * *aCy) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; aRNgrad->PrivateGetCy(aCy); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -928,6 +974,7 @@ nsSVGRadialGradientFrame::PrivateGetCy(nsIDOMSVGLength * *aCy) nsCOMPtr aLen; aRgrad->GetCy(getter_AddRefs(aLen)); aLen->GetAnimVal(aCy); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -946,6 +993,7 @@ nsSVGRadialGradientFrame::PrivateGetR(nsIDOMSVGLength * *aR) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; aRNgrad->PrivateGetR(aR); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -955,6 +1003,7 @@ nsSVGRadialGradientFrame::PrivateGetR(nsIDOMSVGLength * *aR) nsCOMPtr aLen; aRgrad->GetR(getter_AddRefs(aLen)); aLen->GetAnimVal(aR); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -973,6 +1022,7 @@ nsSVGRadialGradientFrame::PrivateGetFx(nsIDOMSVGLength * *aFx) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; aRNgrad->PrivateGetFx(aFx); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -987,6 +1037,7 @@ nsSVGRadialGradientFrame::PrivateGetFx(nsIDOMSVGLength * *aFx) nsCOMPtr aLen; aRgrad->GetFx(getter_AddRefs(aLen)); aLen->GetAnimVal(aFx); + mLoopFlag = PR_FALSE; return NS_OK; } @@ -1005,6 +1056,7 @@ nsSVGRadialGradientFrame::PrivateGetFy(nsIDOMSVGLength * *aFy) if (nsSVGGradientFrame::GetNextGradient(&aNextGrad, nsISVGGradient::SVG_RADIAL_GRADIENT) == NS_OK) { nsSVGRadialGradientFrame *aRNgrad = (nsSVGRadialGradientFrame *)aNextGrad; aRNgrad->PrivateGetFy(aFy); + mLoopFlag = PR_FALSE; return NS_OK; } // There are no gradients in the list with our type -- fall through @@ -1013,6 +1065,7 @@ nsSVGRadialGradientFrame::PrivateGetFy(nsIDOMSVGLength * *aFy) // See if the value was explicitly set -- the spec // states that if there is no explicit fy value, we return the cy value // see http://www.w3.org/TR/SVG11/pservers.html#RadialGradients + mLoopFlag = PR_FALSE; if (!mContent->HasAttr(kNameSpaceID_None, nsSVGAtoms::fy)) return PrivateGetCy(aFy); // No, return the values @@ -1122,6 +1175,7 @@ nsresult NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell, it->mNextGrad = nsnull; } + it->mLoopFlag = PR_FALSE; *aNewFrame = it; return NS_OK; @@ -1157,6 +1211,7 @@ nsresult NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell, it->mNextGrad = nsnull; } + it->mLoopFlag = PR_FALSE; *aNewFrame = it; return NS_OK; @@ -1180,6 +1235,5 @@ nsresult NS_GetSVGGradient(nsISVGGradient **aGrad, nsIURI *aURI, nsIContent *aCo uriSpec, aContent, aPresShell))) { return NS_ERROR_FAILURE; } - return result->QueryInterface(NS_GET_IID(nsISVGGradient), (void **)aGrad); }