Bug 1246764 - Part 3: Layout part for |clip-path: path()|. r=jwatt

Create clip-path for the path function and reuse some APIs in
nsCSSClipPathInstance, so we don't have to update the code flow.

Differential Revision: https://phabricator.services.mozilla.com/D3635
This commit is contained in:
Boris Chiou 2018-08-15 12:27:38 -07:00
parent a1909a88ff
commit 7ba34b6df6
5 changed files with 52 additions and 19 deletions

View File

@ -560,7 +560,8 @@ SVGPathData::BuildPathForMeasuring() const
SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
PathBuilder* aBuilder,
uint8_t aStrokeLineCap,
Float aStrokeWidth)
Float aStrokeWidth,
float aZoomFactor)
{
if (aPath.IsEmpty() || !aPath[0].IsMoveTo()) {
return nullptr; // paths without an initial moveto are invalid
@ -592,6 +593,10 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
Point cp1, cp2; // previous bezier's control points
Point tcp1, tcp2; // temporaries
auto scale = [aZoomFactor](const Point& p) {
return Point(p.x * aZoomFactor, p.y * aZoomFactor);
};
// Regarding cp1 and cp2: If the previous segment was a cubic bezier curve,
// then cp2 is its second control point. If the previous segment was a
// quadratic curve, then cp1 is its (only) control point.
@ -610,7 +615,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT;
const Point& p = toGfxPoint(cmd.move_to.point);
pathStart = segEnd = cmd.move_to.absolute ? p : segStart + p;
aBuilder->MoveTo(segEnd);
aBuilder->MoveTo(scale(segEnd));
subpathHasLength = false;
break;
}
@ -619,7 +624,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
segEnd = cmd.line_to.absolute ? p : segStart + p;
if (segEnd != segStart) {
subpathHasLength = true;
aBuilder->LineTo(segEnd);
aBuilder->LineTo(scale(segEnd));
}
break;
}
@ -636,7 +641,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
subpathHasLength = true;
aBuilder->BezierTo(cp1, cp2, segEnd);
aBuilder->BezierTo(scale(cp1), scale(cp2), scale(segEnd));
}
break;
@ -655,7 +660,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart || segEnd != cp1) {
subpathHasLength = true;
aBuilder->BezierTo(tcp1, tcp2, segEnd);
aBuilder->BezierTo(scale(tcp1), scale(tcp2), scale(segEnd));
}
break;
@ -669,12 +674,12 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart) {
subpathHasLength = true;
if (radii.x == 0.0f || radii.y == 0.0f) {
aBuilder->LineTo(segEnd);
aBuilder->LineTo(scale(segEnd));
} else {
nsSVGArcConverter converter(segStart, segEnd, radii, arc.angle,
arc.large_arc_flag, arc.sweep_flag);
while (converter.GetNextSegment(&cp1, &cp2, &segEnd)) {
aBuilder->BezierTo(cp1, cp2, segEnd);
aBuilder->BezierTo(scale(cp1), scale(cp2), scale(segEnd));
}
}
}
@ -689,7 +694,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart) {
subpathHasLength = true;
aBuilder->LineTo(segEnd);
aBuilder->LineTo(scale(segEnd));
}
break;
@ -702,7 +707,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart) {
subpathHasLength = true;
aBuilder->LineTo(segEnd);
aBuilder->LineTo(scale(segEnd));
}
break;
@ -718,7 +723,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart || segEnd != cp1 || segEnd != cp2) {
subpathHasLength = true;
aBuilder->BezierTo(cp1, cp2, segEnd);
aBuilder->BezierTo(scale(cp1), scale(cp2), scale(segEnd));
}
break;
@ -734,7 +739,7 @@ SVGPathData::BuildPath(const nsTArray<StylePathCommand>& aPath,
if (segEnd != segStart || segEnd != cp1) {
subpathHasLength = true;
aBuilder->BezierTo(tcp1, tcp2, segEnd);
aBuilder->BezierTo(scale(tcp1), scale(tcp2), scale(segEnd));
}
break;
}

View File

@ -178,7 +178,8 @@ public:
BuildPath(const nsTArray<StylePathCommand>& aPath,
PathBuilder* aBuilder,
uint8_t aCapStyle,
Float aStrokeWidth);
Float aStrokeWidth,
float aZoomFactor = 1.0);
const_iterator begin() const { return mData.Elements(); }
const_iterator end() const { return mData.Elements() + mData.Length(); }

View File

@ -10,6 +10,7 @@
#include "gfx2DGlue.h"
#include "gfxContext.h"
#include "gfxPlatform.h"
#include "mozilla/dom/SVGPathData.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "mozilla/ShapeUtils.h"
@ -33,8 +34,9 @@ nsCSSClipPathInstance::ApplyBasicShapeClip(gfxContext& aContext,
#ifdef DEBUG
StyleShapeSourceType type = clipPathStyle.GetType();
MOZ_ASSERT(type == StyleShapeSourceType::Shape ||
type == StyleShapeSourceType::Box,
"This function is used with basic-shape and geometry-box only.");
type == StyleShapeSourceType::Box ||
type == StyleShapeSourceType::Path,
"This is used with basic-shape, geometry-box, and path() only");
#endif
nsCSSClipPathInstance instance(aFrame, clipPathStyle);
@ -69,11 +71,13 @@ nsCSSClipPathInstance::HitTestBasicShapeClip(nsIFrame* aFrame,
}
/* static */ Rect
nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(nsIFrame* aFrame,
const StyleShapeSource& aClipPathStyle)
nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(
nsIFrame* aFrame,
const StyleShapeSource& aClipPathStyle)
{
MOZ_ASSERT(aClipPathStyle.GetType() == StyleShapeSourceType::Shape ||
aClipPathStyle.GetType() == StyleShapeSourceType::Box);
aClipPathStyle.GetType() == StyleShapeSourceType::Box ||
aClipPathStyle.GetType() == StyleShapeSourceType::Path);
nsCSSClipPathInstance instance(aFrame, aClipPathStyle);
@ -86,6 +90,10 @@ nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(nsIFrame* aFrame,
already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPath(DrawTarget* aDrawTarget)
{
if (mClipPathStyle.GetType() == StyleShapeSourceType::Path) {
return CreateClipPathPath(aDrawTarget);
}
nsRect r =
nsLayoutUtils::ComputeGeometryBox(mTargetFrame,
mClipPathStyle.GetReferenceBox());
@ -213,3 +221,18 @@ nsCSSClipPathInstance::CreateClipPathInset(DrawTarget* aDrawTarget,
}
return builder->Finish();
}
already_AddRefed<Path>
nsCSSClipPathInstance::CreateClipPathPath(DrawTarget* aDrawTarget)
{
const StyleSVGPath* path = mClipPathStyle.GetPath();
MOZ_ASSERT(path);
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(
path->FillRule() == StyleFillRule::Nonzero ? FillRule::FILL_WINDING
: FillRule::FILL_EVEN_ODD);
float scale = float(AppUnitsPerCSSPixel()) /
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
return SVGPathData::BuildPath(
path->Path(), builder, NS_STYLE_STROKE_LINECAP_BUTT, 0.0, scale);
}

View File

@ -29,8 +29,10 @@ public:
static bool HitTestBasicShapeClip(nsIFrame* aFrame,
const gfxPoint& aPoint);
static Rect GetBoundingRectForBasicShapeClip(nsIFrame* aFrame,
const StyleShapeSource& aClipPathStyle);
static Rect GetBoundingRectForBasicShapeClip(
nsIFrame* aFrame,
const StyleShapeSource& aClipPathStyle);
private:
explicit nsCSSClipPathInstance(nsIFrame* aFrame,
const StyleShapeSource aClipPathStyle)
@ -53,6 +55,7 @@ private:
already_AddRefed<Path> CreateClipPathInset(DrawTarget* aDrawTarget,
const nsRect& aRefBox);
already_AddRefed<Path> CreateClipPathPath(DrawTarget* aDrawTarget);
/**
* The frame for the element that is currently being clipped.

View File

@ -523,6 +523,7 @@ nsSVGUtils::DetermineMaskUsage(nsIFrame* aFrame, bool aHandleOpacity,
break;
case StyleShapeSourceType::Shape:
case StyleShapeSourceType::Box:
case StyleShapeSourceType::Path:
aUsage.shouldApplyBasicShape = true;
break;
case StyleShapeSourceType::None: