mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 655877 - Part 1: Move some path drawing functions from nsSVGGeometryFrame to nsSVGUtils. r=jwatt
This commit is contained in:
parent
bad716eec5
commit
4efeaa9269
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -32,213 +32,14 @@ nsSVGGeometryFrame::Init(nsIContent* aContent,
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
float
|
||||
nsSVGGeometryFrame::GetStrokeWidth()
|
||||
{
|
||||
nsSVGElement *ctx = static_cast<nsSVGElement*>
|
||||
(mContent->IsNodeOfType(nsINode::eTEXT) ?
|
||||
mContent->GetParent() : mContent);
|
||||
|
||||
return
|
||||
nsSVGUtils::CoordToFloat(PresContext(),
|
||||
ctx,
|
||||
GetStyleSVG()->mStrokeWidth);
|
||||
}
|
||||
|
||||
bool
|
||||
nsSVGGeometryFrame::GetStrokeDashData(FallibleTArray<gfxFloat>& 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<nsSVGPathElement*>(mContent)->
|
||||
GetPathLengthScale(nsSVGPathElement::eForStroking);
|
||||
if (pathScale <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsSVGElement *ctx = static_cast<nsSVGElement*>
|
||||
(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<gfxFloat, 10> 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);
|
||||
}
|
||||
|
@ -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<gfxFloat>& dashes, gfxFloat *dashOffset);
|
||||
};
|
||||
|
||||
#endif // __NS_SVGGEOMETRYFRAME_H__
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext,
|
||||
MarkerProperties properties = GetMarkerProperties(this);
|
||||
|
||||
if (properties.MarkersExist()) {
|
||||
float strokeWidth = GetStrokeWidth();
|
||||
float strokeWidth = nsSVGUtils::GetStrokeWidth(this);
|
||||
|
||||
nsTArray<nsSVGMark> marks;
|
||||
static_cast<nsSVGPathGeometryElement*>
|
||||
@ -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<nsSVGPathGeometryElement*>(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();
|
||||
}
|
||||
|
||||
|
@ -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<nsSVGPathGeometryFrame*>(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<nsSVGElement*>(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<gfxFloat>& 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<nsSVGPathElement*>(content)->
|
||||
GetPathLengthScale(nsSVGPathElement::eForStroking);
|
||||
if (pathScale <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (content->IsNodeOfType(nsINode::eTEXT)) {
|
||||
content = content->GetParent();
|
||||
}
|
||||
|
||||
nsSVGElement *ctx = static_cast<nsSVGElement*>(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<gfxFloat, 10> 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);
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user