|
Packit |
f0b94e |
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
Packit |
f0b94e |
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
Packit |
f0b94e |
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
Packit |
f0b94e |
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
Packit |
f0b94e |
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
// Main header first:
|
|
Packit |
f0b94e |
#include "nsCSSClipPathInstance.h"
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
#include "gfx2DGlue.h"
|
|
Packit |
f0b94e |
#include "gfxContext.h"
|
|
Packit |
f0b94e |
#include "gfxPlatform.h"
|
|
Packit |
f0b94e |
#include "mozilla/gfx/2D.h"
|
|
Packit |
f0b94e |
#include "mozilla/gfx/PathHelpers.h"
|
|
Packit |
f0b94e |
#include "mozilla/ShapeUtils.h"
|
|
Packit |
f0b94e |
#include "nsCSSRendering.h"
|
|
Packit |
f0b94e |
#include "nsIFrame.h"
|
|
Packit |
f0b94e |
#include "nsLayoutUtils.h"
|
|
Packit |
f0b94e |
#ifdef MOZ_OLD_STYLE
|
|
Packit |
f0b94e |
#include "nsRuleNode.h"
|
|
Packit |
f0b94e |
#endif
|
|
Packit |
f0b94e |
#include "nsSVGElement.h"
|
|
Packit |
f0b94e |
#include "nsSVGUtils.h"
|
|
Packit |
f0b94e |
#include "nsSVGViewBox.h"
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
using namespace mozilla;
|
|
Packit |
f0b94e |
using namespace mozilla::dom;
|
|
Packit |
f0b94e |
using namespace mozilla::gfx;
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
/* static*/ void nsCSSClipPathInstance::ApplyBasicShapeClip(
|
|
Packit |
f0b94e |
gfxContext& aContext, nsIFrame* aFrame) {
|
|
Packit |
f0b94e |
auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
#ifdef DEBUG
|
|
Packit |
f0b94e |
StyleShapeSourceType type = clipPathStyle.GetType();
|
|
Packit |
f0b94e |
MOZ_ASSERT(
|
|
Packit |
f0b94e |
type == StyleShapeSourceType::Shape || type == StyleShapeSourceType::Box,
|
|
Packit |
f0b94e |
"This function is used with basic-shape and geometry-box only.");
|
|
Packit |
f0b94e |
#endif
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsCSSClipPathInstance instance(aFrame, clipPathStyle);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
aContext.NewPath();
|
|
Packit |
f0b94e |
RefPtr<Path> path = instance.CreateClipPath(aContext.GetDrawTarget());
|
|
Packit |
f0b94e |
aContext.SetPath(path);
|
|
Packit |
f0b94e |
aContext.Clip();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
/* static*/ bool nsCSSClipPathInstance::HitTestBasicShapeClip(
|
|
Packit |
f0b94e |
nsIFrame* aFrame, const gfxPoint& aPoint) {
|
|
Packit |
f0b94e |
auto& clipPathStyle = aFrame->StyleSVGReset()->mClipPath;
|
|
Packit |
f0b94e |
StyleShapeSourceType type = clipPathStyle.GetType();
|
|
Packit |
f0b94e |
MOZ_ASSERT(type != StyleShapeSourceType::None, "unexpected none value");
|
|
Packit |
f0b94e |
// In the future nsCSSClipPathInstance may handle <clipPath> references as
|
|
Packit |
f0b94e |
// well. For the time being return early.
|
|
Packit |
f0b94e |
if (type == StyleShapeSourceType::URL) {
|
|
Packit |
f0b94e |
return false;
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsCSSClipPathInstance instance(aFrame, clipPathStyle);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
RefPtr<DrawTarget> drawTarget =
|
|
Packit |
f0b94e |
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
|
Packit |
f0b94e |
RefPtr<Path> path = instance.CreateClipPath(drawTarget);
|
|
Packit |
f0b94e |
float pixelRatio = float(nsPresContext::AppUnitsPerCSSPixel()) /
|
|
Packit |
f0b94e |
aFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
return path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
/* static */ Rect nsCSSClipPathInstance::GetBoundingRectForBasicShapeClip(
|
|
Packit |
f0b94e |
nsIFrame* aFrame, const StyleShapeSource& aClipPathStyle) {
|
|
Packit |
f0b94e |
MOZ_ASSERT(aClipPathStyle.GetType() == StyleShapeSourceType::Shape ||
|
|
Packit |
f0b94e |
aClipPathStyle.GetType() == StyleShapeSourceType::Box);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsCSSClipPathInstance instance(aFrame, aClipPathStyle);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
RefPtr<DrawTarget> drawTarget =
|
|
Packit |
f0b94e |
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
|
Packit |
f0b94e |
RefPtr<Path> path = instance.CreateClipPath(drawTarget);
|
|
Packit |
f0b94e |
return path->GetBounds();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
already_AddRefed<Path> nsCSSClipPathInstance::CreateClipPath(
|
|
Packit |
f0b94e |
DrawTarget* aDrawTarget) {
|
|
Packit |
f0b94e |
nsRect r = nsLayoutUtils::ComputeGeometryBox(
|
|
Packit |
f0b94e |
mTargetFrame, mClipPathStyle.GetReferenceBox());
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
if (mClipPathStyle.GetType() != StyleShapeSourceType::Shape) {
|
|
Packit |
f0b94e |
// TODO Clip to border-radius/reference box if no shape
|
|
Packit |
f0b94e |
// was specified.
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nscoord appUnitsPerDevPixel =
|
|
Packit |
f0b94e |
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
r = ToAppUnits(r.ToNearestPixels(appUnitsPerDevPixel), appUnitsPerDevPixel);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
|
|
Packit |
f0b94e |
switch (basicShape->GetShapeType()) {
|
|
Packit |
f0b94e |
case StyleBasicShapeType::Circle:
|
|
Packit |
f0b94e |
return CreateClipPathCircle(aDrawTarget, r);
|
|
Packit |
f0b94e |
case StyleBasicShapeType::Ellipse:
|
|
Packit |
f0b94e |
return CreateClipPathEllipse(aDrawTarget, r);
|
|
Packit |
f0b94e |
case StyleBasicShapeType::Polygon:
|
|
Packit |
f0b94e |
return CreateClipPathPolygon(aDrawTarget, r);
|
|
Packit |
f0b94e |
case StyleBasicShapeType::Inset:
|
|
Packit |
f0b94e |
return CreateClipPathInset(aDrawTarget, r);
|
|
Packit |
f0b94e |
break;
|
|
Packit |
f0b94e |
default:
|
|
Packit |
f0b94e |
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected shape type");
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
// Return an empty Path:
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
already_AddRefed<Path> nsCSSClipPathInstance::CreateClipPathCircle(
|
|
Packit |
f0b94e |
DrawTarget* aDrawTarget, const nsRect& aRefBox) {
|
|
Packit |
f0b94e |
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsPoint center =
|
|
Packit |
f0b94e |
ShapeUtils::ComputeCircleOrEllipseCenter(basicShape, aRefBox);
|
|
Packit |
f0b94e |
nscoord r = ShapeUtils::ComputeCircleRadius(basicShape, center, aRefBox);
|
|
Packit |
f0b94e |
nscoord appUnitsPerDevPixel =
|
|
Packit |
f0b94e |
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
builder->Arc(Point(center.x, center.y) / appUnitsPerDevPixel,
|
|
Packit |
f0b94e |
r / appUnitsPerDevPixel, 0, Float(2 * M_PI));
|
|
Packit |
f0b94e |
builder->Close();
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
already_AddRefed<Path> nsCSSClipPathInstance::CreateClipPathEllipse(
|
|
Packit |
f0b94e |
DrawTarget* aDrawTarget, const nsRect& aRefBox) {
|
|
Packit |
f0b94e |
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsPoint center =
|
|
Packit |
f0b94e |
ShapeUtils::ComputeCircleOrEllipseCenter(basicShape, aRefBox);
|
|
Packit |
f0b94e |
nsSize radii = ShapeUtils::ComputeEllipseRadii(basicShape, center, aRefBox);
|
|
Packit |
f0b94e |
nscoord appUnitsPerDevPixel =
|
|
Packit |
f0b94e |
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
EllipseToBezier(builder.get(),
|
|
Packit |
f0b94e |
Point(center.x, center.y) / appUnitsPerDevPixel,
|
|
Packit |
f0b94e |
Size(radii.width, radii.height) / appUnitsPerDevPixel);
|
|
Packit |
f0b94e |
builder->Close();
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
already_AddRefed<Path> nsCSSClipPathInstance::CreateClipPathPolygon(
|
|
Packit |
f0b94e |
DrawTarget* aDrawTarget, const nsRect& aRefBox) {
|
|
Packit |
f0b94e |
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
|
|
Packit |
f0b94e |
FillRule fillRule = basicShape->GetFillRule() == StyleFillRule::Nonzero
|
|
Packit |
f0b94e |
? FillRule::FILL_WINDING
|
|
Packit |
f0b94e |
: FillRule::FILL_EVEN_ODD;
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(fillRule);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsTArray<nsPoint> vertices =
|
|
Packit |
f0b94e |
ShapeUtils::ComputePolygonVertices(basicShape, aRefBox);
|
|
Packit |
f0b94e |
if (vertices.IsEmpty()) {
|
|
Packit |
f0b94e |
MOZ_ASSERT_UNREACHABLE(
|
|
Packit |
f0b94e |
"ComputePolygonVertices() should've given us some vertices!");
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
nscoord appUnitsPerDevPixel =
|
|
Packit |
f0b94e |
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
builder->MoveTo(NSPointToPoint(vertices[0], appUnitsPerDevPixel));
|
|
Packit |
f0b94e |
for (size_t i = 1; i < vertices.Length(); ++i) {
|
|
Packit |
f0b94e |
builder->LineTo(NSPointToPoint(vertices[i], appUnitsPerDevPixel));
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
builder->Close();
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
already_AddRefed<Path> nsCSSClipPathInstance::CreateClipPathInset(
|
|
Packit |
f0b94e |
DrawTarget* aDrawTarget, const nsRect& aRefBox) {
|
|
Packit |
f0b94e |
const UniquePtr<StyleBasicShape>& basicShape = mClipPathStyle.GetBasicShape();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nscoord appUnitsPerDevPixel =
|
|
Packit |
f0b94e |
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
nsRect insetRect = ShapeUtils::ComputeInsetRect(basicShape, aRefBox);
|
|
Packit |
f0b94e |
const Rect insetRectPixels = NSRectToRect(insetRect, appUnitsPerDevPixel);
|
|
Packit |
f0b94e |
nscoord appUnitsRadii[8];
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
if (ShapeUtils::ComputeInsetRadii(basicShape, insetRect, aRefBox,
|
|
Packit |
f0b94e |
appUnitsRadii)) {
|
|
Packit |
f0b94e |
RectCornerRadii corners;
|
|
Packit |
f0b94e |
nsCSSRendering::ComputePixelRadii(appUnitsRadii, appUnitsPerDevPixel,
|
|
Packit |
f0b94e |
&corners);
|
|
Packit |
f0b94e |
|
|
Packit |
f0b94e |
AppendRoundedRectToPath(builder, insetRectPixels, corners, true);
|
|
Packit |
f0b94e |
} else {
|
|
Packit |
f0b94e |
AppendRectToPath(builder, insetRectPixels, true);
|
|
Packit |
f0b94e |
}
|
|
Packit |
f0b94e |
return builder->Finish();
|
|
Packit |
f0b94e |
}
|