Bug 1299876 - Part 1. Correct the algorithm of stroke box computing.
MozReview-Commit-ID: F3hXSuFCosV
--- a/layout/svg/nsCSSClipPathInstance.cpp
+++ b/layout/svg/nsCSSClipPathInstance.cpp
@@ -9,16 +9,17 @@
#include "gfx2DGlue.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "nsCSSRendering.h"
#include "nsIFrame.h"
#include "nsRenderingContext.h"
#include "nsRuleNode.h"
+#include "SVGUseElement.h"
using namespace mozilla;
using namespace mozilla::gfx;
/* static*/ void
nsCSSClipPathInstance::ApplyBasicShapeClip(gfxContext& aContext,
nsIFrame* aFrame)
{
@@ -57,31 +58,94 @@ nsCSSClipPathInstance::HitTestBasicShape
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
RefPtr<Path> path = instance.CreateClipPath(drawTarget);
float pixelRatio = float(nsPresContext::AppUnitsPerCSSPixel()) /
aFrame->PresContext()->AppUnitsPerDevPixel();
return path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
}
+static
+gfxRect ComputeStrokeBoundingBox(nsIFrame* aFrame)
+{
+ if (!aFrame) {
+ return gfxRect();
+ }
+
+ nsIContent* content = aFrame->GetContent();
+ gfxRect result = nsSVGUtils::GetBBox(aFrame,
+ nsSVGUtils::eBBoxIncludeFill);
+ if (nsSVGUtils::HasStroke(aFrame)) {
+ const nsStyleSVG* style = aFrame->StyleSVG();
+ float delta = nsSVGUtils::GetStrokeWidth(aFrame) / 2.0;
+
+ if (!content->IsAnyOfSVGElements(nsGkAtoms::rect, nsGkAtoms::ellipse,
+ nsGkAtoms::circle, nsGkAtoms::image)) {
+ if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER) {
+ float miter = style->mStrokeMiterlimit;
+ delta = (miter < M_SQRT2 &&
+ style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE)
+ ? delta * M_SQRT2 : miter;
+ } else if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
+ delta *= M_SQRT2;
+ }
+ }
+
+ result.Inflate(delta);
+ }
+
+ return result;
+}
+
nsRect
nsCSSClipPathInstance::ComputeSVGReferenceRect()
{
MOZ_ASSERT(mTargetFrame->GetContent()->IsSVGElement());
nsRect r;
// For SVG elements without associated CSS layout box, the used value for
// content-box, padding-box, border-box and margin-box is fill-box.
switch (mClipPathStyle.GetReferenceBox()) {
case StyleClipPathGeometryBox::Stroke: {
- // XXX Bug 1299876
- // The size of srtoke-box is not correct if this graphic element has
- // specific stroke-linejoin or stroke-linecap.
- gfxRect bbox = nsSVGUtils::GetBBox(mTargetFrame,
- nsSVGUtils::eBBoxIncludeFill | nsSVGUtils::eBBoxIncludeStroke);
+ nsIContent* content = mTargetFrame->GetContent();
+ gfxRect bbox;
+
+ if ((content->IsSVGElement(nsGkAtoms::a) &&
+ nsContentUtils::HasNonEmptyTextContent(content,
+ nsContentUtils::eDontRecurseIntoChildren)) ||
+ (content->IsAnyOfSVGElements(nsGkAtoms::circle, nsGkAtoms::ellipse,
+ nsGkAtoms::line, nsGkAtoms::path,
+ nsGkAtoms::polygon, nsGkAtoms::polyline,
+ nsGkAtoms::rect, nsGkAtoms::text))) {
+ // a graphics element without <use> or <image> or an <a> element with
+ // a text content element
+ bbox = ComputeStrokeBoundingBox(mTargetFrame);
+ } else if (content->IsAnyOfSVGElements(nsGkAtoms::a, nsGkAtoms::defs,
+ nsGkAtoms::glyphRef, nsGkAtoms::g,
+ nsGkAtoms::marker,
+ nsGkAtoms::mask,
+ nsGkAtoms::missingGlyph,
+ nsGkAtoms::pattern,
+ nsGkAtoms::svgSwitch,
+ nsGkAtoms::symbol)) {
+ // a container element or <use>
+ nsIContent* root = content->IsSVGElement(nsGkAtoms::use)
+ ? static_cast<SVGUseElement*>(content)->GetAnonymousContent()
+ : content;
+ for (nsIContent* child = root->GetFirstChild();
+ child && child->GetParentNode() == root;
+ child = child->GetNextSibling()) {
+ bbox =
+ bbox.Union(ComputeStrokeBoundingBox(child->GetPrimaryFrame()));
+ }
+ } else {
+ // an image element.
+ bbox = nsSVGUtils::GetBBox(mTargetFrame, nsSVGUtils::eBBoxIncludeFill);
+ }
+
r = nsLayoutUtils::RoundGfxRectToAppRect(bbox,
nsPresContext::AppUnitsPerCSSPixel());
break;
}
case StyleClipPathGeometryBox::View: {
nsIContent* content = mTargetFrame->GetContent();
nsSVGElement* element = static_cast<nsSVGElement*>(content);
SVGSVGElement* svgElement = element->GetCtx();