mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 830734 - Implement Path primitives. r=roc
This commit is contained in:
parent
6d53ad178c
commit
f0b9b7d32e
@ -1691,6 +1691,29 @@ CanvasRenderingContext2D::Fill(const CanvasWindingRule& winding)
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::Fill(const CanvasPath& path, const CanvasWindingRule& winding)
|
||||
{
|
||||
EnsureTarget();
|
||||
|
||||
RefPtr<gfx::Path> gfxpath = path.GetPath(winding, mTarget);
|
||||
|
||||
if (!gfxpath) {
|
||||
return;
|
||||
}
|
||||
|
||||
mgfx::Rect bounds;
|
||||
|
||||
if (NeedToDrawShadow()) {
|
||||
bounds = gfxpath->GetBounds(mTarget->GetTransform());
|
||||
}
|
||||
|
||||
AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)->
|
||||
Fill(gfxpath, CanvasGeneralPattern().ForStyle(this, STYLE_FILL, mTarget),
|
||||
DrawOptions(CurrentState().globalAlpha, UsedOperation()));
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::Stroke()
|
||||
{
|
||||
@ -1720,6 +1743,37 @@ CanvasRenderingContext2D::Stroke()
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::Stroke(const CanvasPath& path)
|
||||
{
|
||||
EnsureTarget();
|
||||
|
||||
RefPtr<gfx::Path> gfxpath = path.GetPath(CanvasWindingRule::Nonzero, mTarget);
|
||||
|
||||
if (!gfxpath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ContextState &state = CurrentState();
|
||||
|
||||
StrokeOptions strokeOptions(state.lineWidth, state.lineJoin,
|
||||
state.lineCap, state.miterLimit,
|
||||
state.dash.Length(), state.dash.Elements(),
|
||||
state.dashOffset);
|
||||
|
||||
mgfx::Rect bounds;
|
||||
if (NeedToDrawShadow()) {
|
||||
bounds =
|
||||
gfxpath->GetStrokedBounds(strokeOptions, mTarget->GetTransform());
|
||||
}
|
||||
|
||||
AdjustedTarget(this, bounds.IsEmpty() ? nullptr : &bounds)->
|
||||
Stroke(gfxpath, CanvasGeneralPattern().ForStyle(this, STYLE_STROKE, mTarget),
|
||||
strokeOptions, DrawOptions(state.globalAlpha, UsedOperation()));
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
void CanvasRenderingContext2D::DrawFocusIfNeeded(mozilla::dom::Element& aElement)
|
||||
{
|
||||
EnsureUserSpacePath();
|
||||
@ -1800,6 +1854,21 @@ CanvasRenderingContext2D::Clip(const CanvasWindingRule& winding)
|
||||
CurrentState().clipsPushed.push_back(mPath);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::Clip(const CanvasPath& path, const CanvasWindingRule& winding)
|
||||
{
|
||||
EnsureTarget();
|
||||
|
||||
RefPtr<gfx::Path> gfxpath = path.GetPath(winding, mTarget);
|
||||
|
||||
if (!gfxpath) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTarget->PushClip(gfxpath);
|
||||
CurrentState().clipsPushed.push_back(gfxpath);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasRenderingContext2D::ArcTo(double x1, double y1, double x2,
|
||||
double y2, double radius,
|
||||
@ -4226,5 +4295,212 @@ CanvasRenderingContext2D::ShouldForceInactiveLayer(LayerManager *aManager)
|
||||
return !aManager->CanUseCanvasLayerForSize(IntSize(mWidth, mHeight));
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(CanvasPath, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(CanvasPath, Release)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(CanvasPath)
|
||||
|
||||
CanvasPath::CanvasPath(nsCOMPtr<nsISupports> aParent) : mParent(aParent)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
|
||||
mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder();
|
||||
}
|
||||
|
||||
CanvasPath::CanvasPath(nsCOMPtr<nsISupports> aParent, RefPtr<PathBuilder> aPathBuilder): mParent(aParent), mPathBuilder(aPathBuilder)
|
||||
{
|
||||
SetIsDOMBinding();
|
||||
|
||||
if (!mPathBuilder) {
|
||||
mPathBuilder = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget()->CreatePathBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
CanvasPath::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return Path2DBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasPath>
|
||||
CanvasPath::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<CanvasPath> path = new CanvasPath(aGlobal.GetAsSupports());
|
||||
return path.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<CanvasPath>
|
||||
CanvasPath::Constructor(const GlobalObject& aGlobal, CanvasPath& aCanvasPath, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<gfx::Path> tempPath = aCanvasPath.GetPath(CanvasWindingRule::Nonzero,
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget());
|
||||
|
||||
nsRefPtr<CanvasPath> path = new CanvasPath(aGlobal.GetAsSupports(), tempPath->CopyToBuilder());
|
||||
return path.forget();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::ClosePath()
|
||||
{
|
||||
mPathBuilder->Close();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::MoveTo(double x, double y)
|
||||
{
|
||||
mPathBuilder->MoveTo(Point(ToFloat(x), ToFloat(y)));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::LineTo(double x, double y)
|
||||
{
|
||||
mPathBuilder->LineTo(Point(ToFloat(x), ToFloat(y)));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::QuadraticCurveTo(double cpx, double cpy, double x, double y)
|
||||
{
|
||||
mPathBuilder->QuadraticBezierTo(gfx::Point(ToFloat(cpx), ToFloat(cpy)),
|
||||
gfx::Point(ToFloat(x), ToFloat(y)));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::BezierCurveTo(double cp1x, double cp1y,
|
||||
double cp2x, double cp2y,
|
||||
double x, double y)
|
||||
{
|
||||
BezierTo(gfx::Point(ToFloat(cp1x), ToFloat(cp1y)),
|
||||
gfx::Point(ToFloat(cp2x), ToFloat(cp2y)),
|
||||
gfx::Point(ToFloat(x), ToFloat(y)));
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::ArcTo(double x1, double y1, double x2, double y2, double radius,
|
||||
ErrorResult& error)
|
||||
{
|
||||
if (radius < 0) {
|
||||
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Current point in user space!
|
||||
Point p0 = mPathBuilder->CurrentPoint();
|
||||
Point p1(x1, y1);
|
||||
Point p2(x2, y2);
|
||||
|
||||
// Execute these calculations in double precision to avoid cumulative
|
||||
// rounding errors.
|
||||
double dir, a2, b2, c2, cosx, sinx, d, anx, any,
|
||||
bnx, bny, x3, y3, x4, y4, cx, cy, angle0, angle1;
|
||||
bool anticlockwise;
|
||||
|
||||
if (p0 == p1 || p1 == p2 || radius == 0) {
|
||||
LineTo(p1.x, p1.y);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for colinearity
|
||||
dir = (p2.x - p1.x) * (p0.y - p1.y) + (p2.y - p1.y) * (p1.x - p0.x);
|
||||
if (dir == 0) {
|
||||
LineTo(p1.x, p1.y);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// XXX - Math for this code was already available from the non-azure code
|
||||
// and would be well tested. Perhaps converting to bezier directly might
|
||||
// be more efficient longer run.
|
||||
a2 = (p0.x-x1)*(p0.x-x1) + (p0.y-y1)*(p0.y-y1);
|
||||
b2 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
|
||||
c2 = (p0.x-x2)*(p0.x-x2) + (p0.y-y2)*(p0.y-y2);
|
||||
cosx = (a2+b2-c2)/(2*sqrt(a2*b2));
|
||||
|
||||
sinx = sqrt(1 - cosx*cosx);
|
||||
d = radius / ((1 - cosx) / sinx);
|
||||
|
||||
anx = (x1-p0.x) / sqrt(a2);
|
||||
any = (y1-p0.y) / sqrt(a2);
|
||||
bnx = (x1-x2) / sqrt(b2);
|
||||
bny = (y1-y2) / sqrt(b2);
|
||||
x3 = x1 - anx*d;
|
||||
y3 = y1 - any*d;
|
||||
x4 = x1 - bnx*d;
|
||||
y4 = y1 - bny*d;
|
||||
anticlockwise = (dir < 0);
|
||||
cx = x3 + any*radius*(anticlockwise ? 1 : -1);
|
||||
cy = y3 - anx*radius*(anticlockwise ? 1 : -1);
|
||||
angle0 = atan2((y3-cy), (x3-cx));
|
||||
angle1 = atan2((y4-cy), (x4-cx));
|
||||
|
||||
|
||||
LineTo(x3, y3);
|
||||
|
||||
Arc(cx, cy, radius, angle0, angle1, anticlockwise, error);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::Rect(double x, double y, double w, double h)
|
||||
{
|
||||
MoveTo(x, y);
|
||||
LineTo(x + w, y);
|
||||
LineTo(x + w, y + h);
|
||||
LineTo(x, y + h);
|
||||
ClosePath();
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::Arc(double x, double y, double radius,
|
||||
double startAngle, double endAngle, bool anticlockwise,
|
||||
ErrorResult& error)
|
||||
{
|
||||
if (radius < 0.0) {
|
||||
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ArcToBezier(this, Point(x, y), Size(radius, radius), startAngle, endAngle, anticlockwise);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::LineTo(const gfx::Point& aPoint)
|
||||
{
|
||||
mPathBuilder->LineTo(aPoint);
|
||||
}
|
||||
|
||||
void
|
||||
CanvasPath::BezierTo(const gfx::Point& aCP1,
|
||||
const gfx::Point& aCP2,
|
||||
const gfx::Point& aCP3)
|
||||
{
|
||||
mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
|
||||
}
|
||||
|
||||
RefPtr<gfx::Path>
|
||||
CanvasPath::GetPath(const CanvasWindingRule& winding, const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const
|
||||
{
|
||||
FillRule fillRule = FillRule::FILL_WINDING;
|
||||
if (winding == CanvasWindingRule::Evenodd) {
|
||||
fillRule = FillRule::FILL_EVEN_ODD;
|
||||
}
|
||||
|
||||
RefPtr<Path> mTempPath = mPathBuilder->Finish();
|
||||
if (!mTempPath)
|
||||
return mTempPath;
|
||||
|
||||
// retarget our backend if we're used with a different backend
|
||||
if (mTempPath->GetBackendType() != mTarget->GetType()) {
|
||||
mPathBuilder = mTarget->CreatePathBuilder(fillRule);
|
||||
mTempPath->StreamToSink(mPathBuilder);
|
||||
mTempPath = mPathBuilder->Finish();
|
||||
} else if (mTempPath->GetFillRule() != fillRule) {
|
||||
mPathBuilder = mTempPath->CopyToBuilder(fillRule);
|
||||
mTempPath = mPathBuilder->Finish();
|
||||
}
|
||||
|
||||
mPathBuilder = mTempPath->CopyToBuilder();
|
||||
|
||||
return mTempPath;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,57 @@ extern const mozilla::gfx::Float SIGMA_MAX;
|
||||
|
||||
template<typename T> class Optional;
|
||||
|
||||
class CanvasPath :
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPath)
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPath)
|
||||
|
||||
nsCOMPtr<nsISupports> GetParentObject() { return mParent; }
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope);
|
||||
|
||||
static already_AddRefed<CanvasPath> Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& rv);
|
||||
static already_AddRefed<CanvasPath> Constructor(const GlobalObject& aGlobal,
|
||||
CanvasPath& aCanvasPath,
|
||||
ErrorResult& rv);
|
||||
|
||||
void ClosePath();
|
||||
void MoveTo(double x, double y);
|
||||
void LineTo(double x, double y);
|
||||
void QuadraticCurveTo(double cpx, double cpy, double x, double y);
|
||||
void BezierCurveTo(double cp1x, double cp1y,
|
||||
double cp2x, double cp2y,
|
||||
double x, double y);
|
||||
void ArcTo(double x1, double y1, double x2, double y2, double radius,
|
||||
ErrorResult& error);
|
||||
void Rect(double x, double y, double w, double h);
|
||||
void Arc(double x, double y, double radius,
|
||||
double startAngle, double endAngle, bool anticlockwise,
|
||||
ErrorResult& error);
|
||||
|
||||
void LineTo(const gfx::Point& aPoint);
|
||||
void BezierTo(const gfx::Point& aCP1,
|
||||
const gfx::Point& aCP2,
|
||||
const gfx::Point& aCP3);
|
||||
|
||||
mozilla::RefPtr<mozilla::gfx::Path> GetPath(const CanvasWindingRule& winding,
|
||||
const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const;
|
||||
|
||||
CanvasPath(nsCOMPtr<nsISupports> aParent);
|
||||
CanvasPath(nsCOMPtr<nsISupports> aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
|
||||
virtual ~CanvasPath() {}
|
||||
|
||||
private:
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
|
||||
|
||||
mutable RefPtr<gfx::PathBuilder> mPathBuilder;
|
||||
};
|
||||
|
||||
struct CanvasBidiProcessor;
|
||||
class CanvasRenderingContext2DUserData;
|
||||
|
||||
@ -172,10 +223,13 @@ public:
|
||||
void StrokeRect(double x, double y, double w, double h);
|
||||
void BeginPath();
|
||||
void Fill(const CanvasWindingRule& winding);
|
||||
void Fill(const CanvasPath& path, const CanvasWindingRule& winding);
|
||||
void Stroke();
|
||||
void Stroke(const CanvasPath& path);
|
||||
void DrawFocusIfNeeded(mozilla::dom::Element& element);
|
||||
bool DrawCustomFocusRing(mozilla::dom::Element& element);
|
||||
void Clip(const CanvasWindingRule& winding);
|
||||
void Clip(const CanvasPath& path, const CanvasWindingRule& winding);
|
||||
bool IsPointInPath(double x, double y, const CanvasWindingRule& winding);
|
||||
bool IsPointInStroke(double x, double y);
|
||||
void FillText(const nsAString& text, double x, double y,
|
||||
|
@ -858,6 +858,11 @@ DOMInterfaces = {
|
||||
'resultNotAddRefed': [ 'coneGain', 'distanceGain' ],
|
||||
},
|
||||
|
||||
'Path2D': {
|
||||
'nativeType': 'mozilla::dom::CanvasPath',
|
||||
'headerFile': 'CanvasRenderingContext2D.h'
|
||||
},
|
||||
|
||||
'PeerConnectionImpl': {
|
||||
'nativeType': 'sipcc::PeerConnectionImpl',
|
||||
'headerFile': 'PeerConnectionImpl.h',
|
||||
|
@ -84,9 +84,9 @@ interface CanvasRenderingContext2D {
|
||||
// path API (see also CanvasPathMethods)
|
||||
void beginPath();
|
||||
void fill(optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void fill(Path path);
|
||||
void fill(Path2D path, optional CanvasWindingRule winding = "nonzero");
|
||||
void stroke();
|
||||
// NOT IMPLEMENTED void stroke(Path path);
|
||||
void stroke(Path2D path);
|
||||
[Pref="canvas.focusring.enabled"] void drawFocusIfNeeded(Element element);
|
||||
// NOT IMPLEMENTED void drawSystemFocusRing(Path path, HTMLElement element);
|
||||
[Pref="canvas.customfocusring.enabled"] boolean drawCustomFocusRing(Element element);
|
||||
@ -94,7 +94,7 @@ interface CanvasRenderingContext2D {
|
||||
// NOT IMPLEMENTED void scrollPathIntoView();
|
||||
// NOT IMPLEMENTED void scrollPathIntoView(Path path);
|
||||
void clip(optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void clip(Path path);
|
||||
void clip(Path2D path, optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED void resetClip();
|
||||
boolean isPointInPath(unrestricted double x, unrestricted double y, optional CanvasWindingRule winding = "nonzero");
|
||||
// NOT IMPLEMENTED boolean isPointInPath(Path path, unrestricted double x, unrestricted double y);
|
||||
@ -313,3 +313,9 @@ interface TextMetrics {
|
||||
|
||||
};
|
||||
|
||||
[Pref="canvas.path.enabled",
|
||||
Constructor,
|
||||
Constructor(Path2D other)]
|
||||
interface Path2D
|
||||
{};
|
||||
Path2D implements CanvasPathMethods;
|
||||
|
@ -460,6 +460,8 @@ pref("accessibility.tabfocus_applies_to_xul", true);
|
||||
pref("canvas.focusring.enabled", false);
|
||||
pref("canvas.customfocusring.enabled", false);
|
||||
pref("canvas.hitregions.enabled", false);
|
||||
// Add support for canvas path objects
|
||||
pref("canvas.path.enabled", false);
|
||||
|
||||
// We want the ability to forcibly disable platform a11y, because
|
||||
// some non-a11y-related components attempt to bring it up. See bug
|
||||
|
Loading…
Reference in New Issue
Block a user