diff --git a/layout/svg/base/src/nsSVGImageFrame.cpp b/layout/svg/base/src/nsSVGImageFrame.cpp index dceb59eba64..2126e9d89c7 100644 --- a/layout/svg/base/src/nsSVGImageFrame.cpp +++ b/layout/svg/base/src/nsSVGImageFrame.cpp @@ -91,6 +91,7 @@ public: // nsISVGChildFrame interface: NS_IMETHOD PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect); + NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit); // nsSVGGeometryFrame overload: // Lie about our fill/stroke so hit detection works @@ -120,6 +121,8 @@ public: #endif private: + already_AddRefed GetImageTransform(); + nsCOMPtr mPreserveAspectRatio; nsCOMPtr mListener; @@ -215,6 +218,37 @@ nsSVGImageFrame::AttributeChanged(PRInt32 aNameSpaceID, aAttribute, aModType); } +already_AddRefed +nsSVGImageFrame::GetImageTransform() +{ + nsCOMPtr ctm; + GetCanvasTM(getter_AddRefs(ctm)); + + float x, y, width, height; + nsSVGElement *element = NS_STATIC_CAST(nsSVGElement*, mContent); + element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); + + PRUint32 nativeWidth, nativeHeight; + nativeWidth = cairo_image_surface_get_width(mSurface); + nativeHeight = cairo_image_surface_get_height(mSurface); + + nsCOMPtr image = do_QueryInterface(mContent); + nsCOMPtr ratio; + image->GetPreserveAspectRatio(getter_AddRefs(ratio)); + + nsCOMPtr trans, ctmXY, fini; + trans = nsSVGUtils::GetViewBoxTransform(width, height, + 0, 0, + nativeWidth, nativeHeight, + ratio); + ctm->Translate(x, y, getter_AddRefs(ctmXY)); + ctmXY->Multiply(trans, getter_AddRefs(fini)); + + nsIDOMSVGMatrix *retval = nsnull; + fini.swap(retval); + return retval; +} + //---------------------------------------------------------------------- // nsISVGChildFrame methods: NS_IMETHODIMP @@ -254,21 +288,7 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) nsSVGElement *element = NS_STATIC_CAST(nsSVGElement*, mContent); element->GetAnimatedLengthValues(&x, &y, &width, &height, nsnull); - PRUint32 nativeWidth, nativeHeight; - nativeWidth = cairo_image_surface_get_width(mSurface); - nativeHeight = cairo_image_surface_get_height(mSurface); - - nsCOMPtr image = do_QueryInterface(mContent); - nsCOMPtr ratio; - image->GetPreserveAspectRatio(getter_AddRefs(ratio)); - - nsCOMPtr trans, ctmXY, fini; - trans = nsSVGUtils::GetViewBoxTransform(width, height, - 0, 0, - nativeWidth, nativeHeight, - ratio); - ctm->Translate(x, y, getter_AddRefs(ctmXY)); - ctmXY->Multiply(trans, getter_AddRefs(fini)); + nsCOMPtr fini = GetImageTransform(); if (GetStyleDisplay()->IsScrollableOverflow()) { canvas->PushClip(); @@ -293,6 +313,27 @@ nsSVGImageFrame::PaintSVG(nsISVGRendererCanvas* canvas, nsRect *aDirtyRect) return NS_OK; } +NS_IMETHODIMP +nsSVGImageFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit) +{ + if (GetStyleDisplay()->IsScrollableOverflow() && mSurface) { + PRUint32 nativeWidth, nativeHeight; + nativeWidth = cairo_image_surface_get_width(mSurface); + nativeHeight = cairo_image_surface_get_height(mSurface); + + nsCOMPtr fini = GetImageTransform(); + + if (!nsSVGUtils::HitTestRect(fini, + 0, 0, nativeWidth, nativeHeight, + x, y)) { + *hit = nsnull; + return NS_OK; + } + } + + return nsSVGPathGeometryFrame::GetFrameForPointSVG(x, y, hit); +} + nsIAtom * nsSVGImageFrame::GetType() const { diff --git a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp index 4c50719e7fd..b6af68b3a82 100644 --- a/layout/svg/base/src/nsSVGInnerSVGFrame.cpp +++ b/layout/svg/base/src/nsSVGInnerSVGFrame.cpp @@ -92,7 +92,8 @@ public: NS_IMETHOD NotifyCanvasTMChanged(PRBool suppressInvalidation); NS_IMETHOD SetMatrixPropagation(PRBool aPropagate); NS_IMETHOD SetOverrideCTM(nsIDOMSVGMatrix *aCTM); - + NS_IMETHOD GetFrameForPointSVG(float x, float y, nsIFrame** hit); + // nsSVGContainerFrame methods: virtual already_AddRefed GetCanvasTM(); @@ -235,6 +236,31 @@ nsSVGInnerSVGFrame::SetOverrideCTM(nsIDOMSVGMatrix *aCTM) return NS_OK; } +NS_IMETHODIMP +nsSVGInnerSVGFrame::GetFrameForPointSVG(float x, float y, nsIFrame** hit) +{ + if (GetStyleDisplay()->IsScrollableOverflow()) { + float clipX, clipY, clipWidth, clipHeight; + nsCOMPtr clipTransform; + + nsSVGElement *svg = NS_STATIC_CAST(nsSVGElement*, mContent); + svg->GetAnimatedLengthValues(&clipX, &clipY, &clipWidth, &clipHeight, nsnull); + + nsSVGContainerFrame *parent = NS_STATIC_CAST(nsSVGContainerFrame*, + mParent); + clipTransform = parent->GetCanvasTM(); + + if (!nsSVGUtils::HitTestRect(clipTransform, + clipX, clipY, clipWidth, clipHeight, + x, y)) { + *hit = nsnull; + return NS_OK; + } + } + + return nsSVGInnerSVGFrameBase::GetFrameForPointSVG(x, y, hit); +} + //---------------------------------------------------------------------- // nsISVGSVGFrame methods: diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 7015e17ec18..b0b16b00567 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -965,3 +965,29 @@ nsSVGUtils::ConvertSVGMatrixToCairo(nsIDOMSVGMatrix *aMatrix) cairo_matrix_t m = { A, B, C, D, E, F }; return m; } + +PRBool +nsSVGUtils::HitTestRect(nsIDOMSVGMatrix *aMatrix, + float aRX, float aRY, float aRWidth, float aRHeight, + float aX, float aY) +{ + PRBool result = PR_TRUE; + + if (aMatrix) { + cairo_matrix_t matrix = ConvertSVGMatrixToCairo(aMatrix); + cairo_t *ctx = cairo_create(GetCairoComputationalSurface()); + cairo_set_tolerance(ctx, 1.0); + + cairo_set_matrix(ctx, &matrix); + cairo_new_path(ctx); + cairo_rectangle(ctx, aRX, aRY, aRWidth, aRHeight); + cairo_identity_matrix(ctx); + + if (!cairo_in_fill(ctx, aX, aY)) + result = PR_FALSE; + + cairo_destroy(ctx); + } + + return result; +} diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 30e3f39def3..ca141d7eb82 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -260,6 +260,14 @@ public: static cairo_matrix_t ConvertSVGMatrixToCairo(nsIDOMSVGMatrix *aMatrix); + /* + * Hit test a given rectangle/matrix. + */ + static PRBool + HitTestRect(nsIDOMSVGMatrix *aMatrix, + float aRX, float aRY, float aRWidth, float aRHeight, + float aX, float aY); + private: /* Cairo computational (nil) surface */ static cairo_surface_t *mCairoComputationalSurface;