From 4efeaa92698d131aeda18040ee1c43c6c0091011 Mon Sep 17 00:00:00 2001 From: Cameron McCormack Date: Fri, 10 Aug 2012 21:13:43 +1000 Subject: [PATCH] Bug 655877 - Part 1: Move some path drawing functions from nsSVGGeometryFrame to nsSVGUtils. r=jwatt --- layout/svg/base/src/nsSVGFilterInstance.cpp | 4 +- layout/svg/base/src/nsSVGGeometryFrame.cpp | 201 +---------------- layout/svg/base/src/nsSVGGeometryFrame.h | 41 ---- layout/svg/base/src/nsSVGGlyphFrame.cpp | 9 +- .../svg/base/src/nsSVGPathGeometryFrame.cpp | 15 +- layout/svg/base/src/nsSVGUtils.cpp | 205 +++++++++++++++++- layout/svg/base/src/nsSVGUtils.h | 46 +++- 7 files changed, 259 insertions(+), 262 deletions(-) diff --git a/layout/svg/base/src/nsSVGFilterInstance.cpp b/layout/svg/base/src/nsSVGFilterInstance.cpp index 2fe0deeff7e8..4a01d8f964aa 100644 --- a/layout/svg/base/src/nsSVGFilterInstance.cpp +++ b/layout/svg/base/src/nsSVGFilterInstance.cpp @@ -357,9 +357,9 @@ nsSVGFilterInstance::BuildSourcePaint(PrimitiveInfo *aPrimitive) gfx->Multiply(matrix); gfx->Rectangle(r); if ((aPrimitive == &mFillPaint && - nsSVGUtils::SetupCairoFill(gfx, mTargetFrame)) || + nsSVGUtils::SetupCairoFillPaint(mTargetFrame, gfx)) || (aPrimitive == &mStrokePaint && - nsSVGUtils::SetupCairoStroke(gfx, mTargetFrame))) { + nsSVGUtils::SetupCairoStrokePaint(mTargetFrame, gfx))) { gfx->Fill(); } } diff --git a/layout/svg/base/src/nsSVGGeometryFrame.cpp b/layout/svg/base/src/nsSVGGeometryFrame.cpp index 565d4fdf11c0..9c8f9e1bfae4 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGGeometryFrame.cpp @@ -32,213 +32,14 @@ nsSVGGeometryFrame::Init(nsIContent* aContent, //---------------------------------------------------------------------- -float -nsSVGGeometryFrame::GetStrokeWidth() -{ - nsSVGElement *ctx = static_cast - (mContent->IsNodeOfType(nsINode::eTEXT) ? - mContent->GetParent() : mContent); - - return - nsSVGUtils::CoordToFloat(PresContext(), - ctx, - GetStyleSVG()->mStrokeWidth); -} - -bool -nsSVGGeometryFrame::GetStrokeDashData(FallibleTArray& dashes, - gfxFloat *dashOffset) -{ - PRUint32 count = GetStyleSVG()->mStrokeDasharrayLength; - if (!count || !dashes.SetLength(count)) { - return false; - } - - gfxFloat pathScale = 1.0; - - if (mContent->Tag() == nsGkAtoms::path) { - pathScale = static_cast(mContent)-> - GetPathLengthScale(nsSVGPathElement::eForStroking); - if (pathScale <= 0) { - return false; - } - } - - nsSVGElement *ctx = static_cast - (mContent->IsNodeOfType(nsINode::eTEXT) ? - mContent->GetParent() : mContent); - - const nsStyleCoord *dasharray = GetStyleSVG()->mStrokeDasharray; - nsPresContext *presContext = PresContext(); - gfxFloat totalLength = 0.0; - - for (PRUint32 i = 0; i < count; i++) { - dashes[i] = - nsSVGUtils::CoordToFloat(presContext, - ctx, - dasharray[i]) * pathScale; - if (dashes[i] < 0.0) { - return false; - } - totalLength += dashes[i]; - } - - *dashOffset = nsSVGUtils::CoordToFloat(presContext, - ctx, - GetStyleSVG()->mStrokeDashoffset); - - return (totalLength > 0.0); -} - PRUint16 nsSVGGeometryFrame::GetClipRule() { return GetStyleSVG()->mClipRule; } -float -nsSVGGeometryFrame::MaybeOptimizeOpacity(float aFillOrStrokeOpacity) -{ - float opacity = GetStyleDisplay()->mOpacity; - if (opacity < 1 && nsSVGUtils::CanOptimizeOpacity(this)) { - return aFillOrStrokeOpacity * opacity; - } - return aFillOrStrokeOpacity; -} - -bool -nsSVGGeometryFrame::HasStroke() -{ - const nsStyleSVG *style = GetStyleSVG(); - return style->mStroke.mType != eStyleSVGPaintType_None && - style->mStrokeOpacity > 0 && - GetStrokeWidth() > 0; -} - -void -nsSVGGeometryFrame::SetupCairoStrokeGeometry(gfxContext *aContext) -{ - float width = GetStrokeWidth(); - if (width <= 0) - return; - aContext->SetLineWidth(width); - - // Apply any stroke-specific transform - aContext->Multiply(nsSVGUtils::GetStrokeTransform(this)); - - const nsStyleSVG* style = GetStyleSVG(); - - switch (style->mStrokeLinecap) { - case NS_STYLE_STROKE_LINECAP_BUTT: - aContext->SetLineCap(gfxContext::LINE_CAP_BUTT); - break; - case NS_STYLE_STROKE_LINECAP_ROUND: - aContext->SetLineCap(gfxContext::LINE_CAP_ROUND); - break; - case NS_STYLE_STROKE_LINECAP_SQUARE: - aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE); - break; - } - - aContext->SetMiterLimit(style->mStrokeMiterlimit); - - switch (style->mStrokeLinejoin) { - case NS_STYLE_STROKE_LINEJOIN_MITER: - aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER); - break; - case NS_STYLE_STROKE_LINEJOIN_ROUND: - aContext->SetLineJoin(gfxContext::LINE_JOIN_ROUND); - break; - case NS_STYLE_STROKE_LINEJOIN_BEVEL: - aContext->SetLineJoin(gfxContext::LINE_JOIN_BEVEL); - break; - } -} - -void -nsSVGGeometryFrame::SetupCairoStrokeHitGeometry(gfxContext *aContext) -{ - SetupCairoStrokeGeometry(aContext); - - AutoFallibleTArray dashes; - gfxFloat dashOffset; - if (GetStrokeDashData(dashes, &dashOffset)) { - aContext->SetDash(dashes.Elements(), dashes.Length(), dashOffset); - } -} - -bool -nsSVGGeometryFrame::SetupCairoFill(gfxContext *aContext) -{ - return nsSVGUtils::SetupCairoFill(aContext, this); -} - -bool -nsSVGGeometryFrame::SetupCairoStroke(gfxContext *aContext) -{ - if (!HasStroke()) { - return false; - } - SetupCairoStrokeHitGeometry(aContext); - - return nsSVGUtils::SetupCairoStroke(aContext, this); -} - PRUint16 nsSVGGeometryFrame::GetHitTestFlags() { - PRUint16 flags = 0; - - switch(GetStyleVisibility()->mPointerEvents) { - case NS_STYLE_POINTER_EVENTS_NONE: - break; - case NS_STYLE_POINTER_EVENTS_AUTO: - case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED: - if (GetStyleVisibility()->IsVisible()) { - if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) - flags |= SVG_HIT_TEST_FILL; - if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None) - flags |= SVG_HIT_TEST_STROKE; - if (GetStyleSVG()->mStrokeOpacity > 0) - flags |= SVG_HIT_TEST_CHECK_MRECT; - } - break; - case NS_STYLE_POINTER_EVENTS_VISIBLEFILL: - if (GetStyleVisibility()->IsVisible()) { - flags |= SVG_HIT_TEST_FILL; - } - break; - case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE: - if (GetStyleVisibility()->IsVisible()) { - flags |= SVG_HIT_TEST_STROKE; - } - break; - case NS_STYLE_POINTER_EVENTS_VISIBLE: - if (GetStyleVisibility()->IsVisible()) { - flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE; - } - break; - case NS_STYLE_POINTER_EVENTS_PAINTED: - if (GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) - flags |= SVG_HIT_TEST_FILL; - if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None) - flags |= SVG_HIT_TEST_STROKE; - if (GetStyleSVG()->mStrokeOpacity) - flags |= SVG_HIT_TEST_CHECK_MRECT; - break; - case NS_STYLE_POINTER_EVENTS_FILL: - flags |= SVG_HIT_TEST_FILL; - break; - case NS_STYLE_POINTER_EVENTS_STROKE: - flags |= SVG_HIT_TEST_STROKE; - break; - case NS_STYLE_POINTER_EVENTS_ALL: - flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE; - break; - default: - NS_ERROR("not reached"); - break; - } - - return flags; + return nsSVGUtils::GetGeometryHitTestFlags(this); } diff --git a/layout/svg/base/src/nsSVGGeometryFrame.h b/layout/svg/base/src/nsSVGGeometryFrame.h index 4f0fada5e280..9b6b2726d2a3 100644 --- a/layout/svg/base/src/nsSVGGeometryFrame.h +++ b/layout/svg/base/src/nsSVGGeometryFrame.h @@ -23,10 +23,6 @@ struct nsStyleSVGPaint; typedef nsFrame nsSVGGeometryFrameBase; -#define SVG_HIT_TEST_FILL 0x01 -#define SVG_HIT_TEST_STROKE 0x02 -#define SVG_HIT_TEST_CHECK_MRECT 0x04 - /* nsSVGGeometryFrame is a base class for SVG objects that directly * have geometry (circle, ellipse, line, polyline, polygon, path, and * glyph frames). It knows how to convert the style information into @@ -59,31 +55,6 @@ public: virtual gfxMatrix GetCanvasTM(PRUint32 aFor) = 0; PRUint16 GetClipRule(); - float GetStrokeWidth(); - - /* - * Set up a cairo context for filling a path - * @return false to skip rendering - */ - bool SetupCairoFill(gfxContext *aContext); - /* - * @return false if there is no stroke - */ - bool HasStroke(); - /* - * Set up a cairo context for measuring a stroked path - */ - void SetupCairoStrokeGeometry(gfxContext *aContext); - /* - * Set up a cairo context for hit testing a stroked path - */ - void SetupCairoStrokeHitGeometry(gfxContext *aContext); - /* - * Set up a cairo context for stroking a path - * @return false to skip rendering - */ - bool SetupCairoStroke(gfxContext *aContext); - protected: /** * This function returns a set of bit flags indicating which parts of the @@ -92,18 +63,6 @@ protected: * property on the element. */ virtual PRUint16 GetHitTestFlags(); - - /** - * Returns the given 'fill-opacity' or 'stroke-opacity' value multiplied by - * the value of the 'opacity' property if it's possible to avoid the expense - * of creating and compositing an offscreen surface for 'opacity' by - * combining 'opacity' with the 'fill-opacity'/'stroke-opacity'. If not, the - * given 'fill-opacity'/'stroke-opacity' is returned unmodified. - */ - float MaybeOptimizeOpacity(float aFillOrStrokeOpacity); - -private: - bool GetStrokeDashData(FallibleTArray& dashes, gfxFloat *dashOffset); }; #endif // __NS_SVGGEOMETRYFRAME_H__ diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp index 5cb48adf4706..a5a7e324d9d0 100644 --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -677,7 +677,8 @@ nsSVGGlyphFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, // Account for stroke: if ((aFlags & nsSVGUtils::eBBoxIncludeStrokeGeometry) || - ((aFlags & nsSVGUtils::eBBoxIncludeStroke) && HasStroke())) { + ((aFlags & nsSVGUtils::eBBoxIncludeStroke) && + nsSVGUtils::HasStroke(this))) { bbox.UnionEdges(nsSVGUtils::PathExtentsToMaxStrokeExtents(pathExtents, this, aToBBoxUserspace)); @@ -949,13 +950,13 @@ nsSVGGlyphFrame::SetupCairoState(gfxContext *aContext, gfxPattern **aStrokePatte DrawMode toDraw = DrawMode(0); const nsStyleSVG* style = GetStyleSVG(); - if (HasStroke()) { + if (nsSVGUtils::HasStroke(this)) { gfxContextMatrixAutoSaveRestore matrixRestore(aContext); aContext->IdentityMatrix(); toDraw = DrawMode(toDraw | gfxFont::GLYPH_STROKE); - SetupCairoStrokeHitGeometry(aContext); + nsSVGUtils::SetupCairoStrokeHitGeometry(this, aContext); float opacity = style->mStrokeOpacity; nsSVGPaintServerFrame *ps = nsSVGEffects::GetPaintServer(this, &style->mStroke, @@ -982,7 +983,7 @@ nsSVGGlyphFrame::SetupCairoState(gfxContext *aContext, gfxPattern **aStrokePatte strokePattern.forget(aStrokePattern); } - if (SetupCairoFill(aContext)) { + if (nsSVGUtils::SetupCairoFillPaint(this, aContext)) { toDraw = DrawMode(toDraw | gfxFont::GLYPH_FILL); } diff --git a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp index d0c12550c448..94836bf4e7c8 100644 --- a/layout/svg/base/src/nsSVGPathGeometryFrame.cpp +++ b/layout/svg/base/src/nsSVGPathGeometryFrame.cpp @@ -188,7 +188,7 @@ nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext, MarkerProperties properties = GetMarkerProperties(this); if (properties.MarkersExist()) { - float strokeWidth = GetStrokeWidth(); + float strokeWidth = nsSVGUtils::GetStrokeWidth(this); nsTArray marks; static_cast @@ -258,7 +258,7 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint) if (hitTestFlags & SVG_HIT_TEST_FILL) isHit = tmpCtx->PointInFill(userSpacePoint); if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) { - SetupCairoStrokeHitGeometry(tmpCtx); + nsSVGUtils::SetupCairoStrokeHitGeometry(this, tmpCtx); isHit = tmpCtx->PointInStroke(userSpacePoint); } @@ -390,7 +390,8 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, // Account for stroke: if ((aFlags & nsSVGUtils::eBBoxIncludeStrokeGeometry) || - ((aFlags & nsSVGUtils::eBBoxIncludeStroke) && HasStroke())) { + ((aFlags & nsSVGUtils::eBBoxIncludeStroke) && + nsSVGUtils::HasStroke(this))) { // We can't use tmpCtx->GetUserStrokeExtent() since it doesn't work for // device space extents. Instead we approximate the stroke extents from // pathExtents using PathExtentsToMaxStrokeExtents. @@ -401,7 +402,7 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, // though, because if pathExtents is empty, its position will not have // been set. Happily we can use tmpCtx->GetUserStrokeExtent() to find // the center point of the extents even though it gets the extents wrong. - SetupCairoStrokeGeometry(tmpCtx); + nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx); pathExtents.MoveTo(tmpCtx->GetUserStrokeExtent().Center()); pathExtents.SizeTo(0, 0); } @@ -414,7 +415,7 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const gfxMatrix &aToBBoxUserspace, if ((aFlags & nsSVGUtils::eBBoxIncludeMarkers) != 0 && static_cast(mContent)->IsMarkable()) { - float strokeWidth = GetStrokeWidth(); + float strokeWidth = nsSVGUtils::GetStrokeWidth(this); MarkerProperties properties = GetMarkerProperties(this); if (properties.MarkersExist()) { @@ -567,11 +568,11 @@ nsSVGPathGeometryFrame::Render(nsRenderingContext *aContext) return; } - if (SetupCairoFill(gfx)) { + if (nsSVGUtils::SetupCairoFillPaint(this, gfx)) { gfx->Fill(); } - if (SetupCairoStroke(gfx)) { + if (nsSVGUtils::SetupCairoStroke(this, gfx)) { gfx->Stroke(); } diff --git a/layout/svg/base/src/nsSVGUtils.cpp b/layout/svg/base/src/nsSVGUtils.cpp index 7e57a2c379e2..8ace2e4ba7fe 100644 --- a/layout/svg/base/src/nsSVGUtils.cpp +++ b/layout/svg/base/src/nsSVGUtils.cpp @@ -48,6 +48,7 @@ #include "nsSVGLength2.h" #include "nsSVGMaskFrame.h" #include "nsSVGOuterSVGFrame.h" +#include "nsSVGPathElement.h" #include "nsSVGPathGeometryElement.h" #include "nsSVGPathGeometryFrame.h" #include "nsSVGPaintServerFrame.h" @@ -1655,7 +1656,7 @@ nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame) } if (style->mFill.mType == eStyleSVGPaintType_None || style->mFillOpacity <= 0 || - !static_cast(aFrame)->HasStroke()) { + !HasStroke(aFrame)) { return true; } return false; @@ -1762,7 +1763,7 @@ PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents, const gfxMatrix& aMatrix) { double style_expansion = - styleExpansionFactor * aFrame->GetStrokeWidth(); + styleExpansionFactor * nsSVGUtils::GetStrokeWidth(aFrame); gfxMatrix matrix = aMatrix; matrix.Multiply(nsSVGUtils::GetStrokeTransform(aFrame)); @@ -1865,7 +1866,7 @@ MaybeOptimizeOpacity(nsIFrame *aFrame, float aFillOrStrokeOpacity) } bool -nsSVGUtils::SetupCairoFill(gfxContext *aContext, nsIFrame *aFrame) +nsSVGUtils::SetupCairoFillPaint(nsIFrame *aFrame, gfxContext* aContext) { const nsStyleSVG* style = aFrame->GetStyleSVG(); if (style->mFill.mType == eStyleSVGPaintType_None) @@ -1886,7 +1887,7 @@ nsSVGUtils::SetupCairoFill(gfxContext *aContext, nsIFrame *aFrame) } bool -nsSVGUtils::SetupCairoStroke(gfxContext *aContext, nsIFrame *aFrame) +nsSVGUtils::SetupCairoStrokePaint(nsIFrame *aFrame, gfxContext* aContext) { const nsStyleSVG* style = aFrame->GetStyleSVG(); if (style->mStroke.mType == eStyleSVGPaintType_None) @@ -1907,3 +1908,199 @@ nsSVGUtils::SetupCairoStroke(gfxContext *aContext, nsIFrame *aFrame) return true; } + +bool +nsSVGUtils::HasStroke(nsIFrame* aFrame) +{ + const nsStyleSVG *style = aFrame->GetStyleSVG(); + return style->mStroke.mType != eStyleSVGPaintType_None && + style->mStrokeOpacity > 0 && + GetStrokeWidth(aFrame) > 0; +} + +float +nsSVGUtils::GetStrokeWidth(nsIFrame* aFrame) +{ + nsIContent* content = aFrame->GetContent(); + if (content->IsNodeOfType(nsINode::eTEXT)) { + content = content->GetParent(); + } + + nsSVGElement *ctx = static_cast(content); + + return nsSVGUtils::CoordToFloat(aFrame->PresContext(), ctx, + aFrame->GetStyleSVG()->mStrokeWidth); +} + +void +nsSVGUtils::SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext *aContext) +{ + float width = GetStrokeWidth(aFrame); + if (width <= 0) + return; + aContext->SetLineWidth(width); + + // Apply any stroke-specific transform + aContext->Multiply(GetStrokeTransform(aFrame)); + + const nsStyleSVG* style = aFrame->GetStyleSVG(); + + switch (style->mStrokeLinecap) { + case NS_STYLE_STROKE_LINECAP_BUTT: + aContext->SetLineCap(gfxContext::LINE_CAP_BUTT); + break; + case NS_STYLE_STROKE_LINECAP_ROUND: + aContext->SetLineCap(gfxContext::LINE_CAP_ROUND); + break; + case NS_STYLE_STROKE_LINECAP_SQUARE: + aContext->SetLineCap(gfxContext::LINE_CAP_SQUARE); + break; + } + + aContext->SetMiterLimit(style->mStrokeMiterlimit); + + switch (style->mStrokeLinejoin) { + case NS_STYLE_STROKE_LINEJOIN_MITER: + aContext->SetLineJoin(gfxContext::LINE_JOIN_MITER); + break; + case NS_STYLE_STROKE_LINEJOIN_ROUND: + aContext->SetLineJoin(gfxContext::LINE_JOIN_ROUND); + break; + case NS_STYLE_STROKE_LINEJOIN_BEVEL: + aContext->SetLineJoin(gfxContext::LINE_JOIN_BEVEL); + break; + } +} + +static bool +GetStrokeDashData(nsIFrame* aFrame, + FallibleTArray& aDashes, + gfxFloat* aDashOffset) +{ + const nsStyleSVG* style = aFrame->GetStyleSVG(); + + PRUint32 count = style->mStrokeDasharrayLength; + if (!count || !aDashes.SetLength(count)) { + return false; + } + + gfxFloat pathScale = 1.0; + + nsIContent* content = aFrame->GetContent(); + if (content->IsSVG() && content->Tag() == nsGkAtoms::path) { + pathScale = static_cast(content)-> + GetPathLengthScale(nsSVGPathElement::eForStroking); + if (pathScale <= 0) { + return false; + } + } + + if (content->IsNodeOfType(nsINode::eTEXT)) { + content = content->GetParent(); + } + + nsSVGElement *ctx = static_cast(content); + + const nsStyleCoord *dasharray = style->mStrokeDasharray; + nsPresContext *presContext = aFrame->PresContext(); + gfxFloat totalLength = 0.0; + + for (PRUint32 i = 0; i < count; i++) { + aDashes[i] = + nsSVGUtils::CoordToFloat(presContext, + ctx, + dasharray[i]) * pathScale; + if (aDashes[i] < 0.0) { + return false; + } + totalLength += aDashes[i]; + } + + *aDashOffset = nsSVGUtils::CoordToFloat(presContext, + ctx, + style->mStrokeDashoffset); + + return (totalLength > 0.0); +} + +void +nsSVGUtils::SetupCairoStrokeHitGeometry(nsIFrame* aFrame, gfxContext* aContext) +{ + SetupCairoStrokeGeometry(aFrame, aContext); + + AutoFallibleTArray dashes; + gfxFloat dashOffset; + if (GetStrokeDashData(aFrame, dashes, &dashOffset)) { + aContext->SetDash(dashes.Elements(), dashes.Length(), dashOffset); + } +} + +PRUint16 +nsSVGUtils::GetGeometryHitTestFlags(nsIFrame* aFrame) +{ + PRUint16 flags = 0; + + switch(aFrame->GetStyleVisibility()->mPointerEvents) { + case NS_STYLE_POINTER_EVENTS_NONE: + break; + case NS_STYLE_POINTER_EVENTS_AUTO: + case NS_STYLE_POINTER_EVENTS_VISIBLEPAINTED: + if (aFrame->GetStyleVisibility()->IsVisible()) { + if (aFrame->GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) + flags |= SVG_HIT_TEST_FILL; + if (aFrame->GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None) + flags |= SVG_HIT_TEST_STROKE; + if (aFrame->GetStyleSVG()->mStrokeOpacity > 0) + flags |= SVG_HIT_TEST_CHECK_MRECT; + } + break; + case NS_STYLE_POINTER_EVENTS_VISIBLEFILL: + if (aFrame->GetStyleVisibility()->IsVisible()) { + flags |= SVG_HIT_TEST_FILL; + } + break; + case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE: + if (aFrame->GetStyleVisibility()->IsVisible()) { + flags |= SVG_HIT_TEST_STROKE; + } + break; + case NS_STYLE_POINTER_EVENTS_VISIBLE: + if (aFrame->GetStyleVisibility()->IsVisible()) { + flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE; + } + break; + case NS_STYLE_POINTER_EVENTS_PAINTED: + if (aFrame->GetStyleSVG()->mFill.mType != eStyleSVGPaintType_None) + flags |= SVG_HIT_TEST_FILL; + if (aFrame->GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None) + flags |= SVG_HIT_TEST_STROKE; + if (aFrame->GetStyleSVG()->mStrokeOpacity) + flags |= SVG_HIT_TEST_CHECK_MRECT; + break; + case NS_STYLE_POINTER_EVENTS_FILL: + flags |= SVG_HIT_TEST_FILL; + break; + case NS_STYLE_POINTER_EVENTS_STROKE: + flags |= SVG_HIT_TEST_STROKE; + break; + case NS_STYLE_POINTER_EVENTS_ALL: + flags |= SVG_HIT_TEST_FILL | SVG_HIT_TEST_STROKE; + break; + default: + NS_ERROR("not reached"); + break; + } + + return flags; +} + +bool +nsSVGUtils::SetupCairoStroke(nsIFrame* aFrame, gfxContext* aContext) +{ + if (!HasStroke(aFrame)) { + return false; + } + SetupCairoStrokeHitGeometry(aFrame, aContext); + + return SetupCairoStrokePaint(aFrame, aContext); +} diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h index 142c338ff4c9..4fe05a91b608 100644 --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -90,6 +90,10 @@ class Element; #define SVG_WSP_DELIM "\x20\x9\xD\xA" #define SVG_COMMA_WSP_DELIM "," SVG_WSP_DELIM +#define SVG_HIT_TEST_FILL 0x01 +#define SVG_HIT_TEST_STROKE 0x02 +#define SVG_HIT_TEST_CHECK_MRECT 0x04 + inline bool IsSVGWhitespace(char aChar) { @@ -671,13 +675,47 @@ public: nsStyleSVGPaint nsStyleSVG::*aFillOrStroke); /** - * Set the graphics context ready for filling. + * Sets the current paint on the specified gfxContent to be the SVG 'fill' + * for the given frame. */ - static bool SetupCairoFill(gfxContext *aContext, nsIFrame *aFrame); + static bool SetupCairoFillPaint(nsIFrame* aFrame, gfxContext* aContext); + /** - * Set the graphics context ready for stroking. + * Sets the current paint on the specified gfxContent to be the SVG 'stroke' + * for the given frame. */ - static bool SetupCairoStroke(gfxContext *aContext, nsIFrame *aFrame); + static bool SetupCairoStrokePaint(nsIFrame* aFrame, gfxContext* aContext); + + /* + * @return false if there is no stroke + */ + static bool HasStroke(nsIFrame* aFrame); + + static float GetStrokeWidth(nsIFrame* aFrame); + + /* + * Set up a cairo context for measuring a stroked path + */ + static void SetupCairoStrokeGeometry(nsIFrame* aFrame, gfxContext *aContext); + + /* + * Set up a cairo context for hit testing a stroked path + */ + static void SetupCairoStrokeHitGeometry(nsIFrame* aFrame, gfxContext *aContext); + + /* + * Set up a cairo context for stroking, including setting up any stroke-related + * properties such as dashing and setting the current paint on the gfxContext. + */ + static bool SetupCairoStroke(nsIFrame* aFrame, gfxContext *aContext); + + /** + * This function returns a set of bit flags indicating which parts of the + * element (fill, stroke, bounds) should intercept pointer events. It takes + * into account the type of element and the value of the 'pointer-events' + * property on the element. + */ + static PRUint16 GetGeometryHitTestFlags(nsIFrame* aFrame); }; #endif