1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #ifndef CanvasRenderingContext2D_h
6 #define CanvasRenderingContext2D_h
9 #include "mozilla/dom/BasicRenderingContext2D.h"
10 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
11 #include "mozilla/dom/HTMLCanvasElement.h"
12 #include "mozilla/gfx/Rect.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/Attributes.h"
15 #include "mozilla/EnumeratedArray.h"
16 #include "mozilla/RefPtr.h"
17 #include "mozilla/SurfaceFromElementResult.h"
18 #include "mozilla/UniquePtr.h"
19 #include "FilterDescription.h"
20 #include "gfx2DGlue.h"
21 #include "nsICanvasRenderingContextInternal.h"
26 class nsGlobalWindowInner
;
38 class PersistentBufferProvider
;
39 enum class LayersBackend
: int8_t;
44 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
;
45 typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
49 class UTF8StringOrCanvasGradientOrCanvasPattern
;
50 class OwningUTF8StringOrCanvasGradientOrCanvasPattern
;
56 extern const mozilla::gfx::Float SIGMA_MAX
;
61 struct CanvasBidiProcessor
;
62 class CanvasDrawObserver
;
63 class CanvasShutdownObserver
;
66 class DOMMatrixReadOnly
;
67 struct DOMMatrix2DInit
;
70 ** CanvasRenderingContext2D
72 class CanvasRenderingContext2D final
: public nsICanvasRenderingContextInternal
,
73 public nsWrapperCache
,
74 public BasicRenderingContext2D
{
75 virtual ~CanvasRenderingContext2D();
78 explicit CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend
);
80 virtual JSObject
* WrapObject(JSContext
* aCx
,
81 JS::Handle
<JSObject
*> aGivenProto
) override
;
83 HTMLCanvasElement
* GetCanvas() const {
84 if (!mCanvasElement
|| mCanvasElement
->IsInNativeAnonymousSubtree()) {
88 // corresponds to changes to the old bindings made in bug 745025
89 return mCanvasElement
->GetOriginalCanvas();
92 void OnBeforePaintTransaction() override
;
93 void OnDidPaintTransaction() override
;
94 layers::PersistentBufferProvider
* GetBufferProvider() override
{
95 return mBufferProvider
;
99 void Restore() override
;
100 void Scale(double aX
, double aY
, mozilla::ErrorResult
& aError
) override
;
101 void Rotate(double aAngle
, mozilla::ErrorResult
& aError
) override
;
102 void Translate(double aX
, double aY
, mozilla::ErrorResult
& aError
) override
;
103 void Transform(double aM11
, double aM12
, double aM21
, double aM22
, double aDx
,
104 double aDy
, mozilla::ErrorResult
& aError
) override
;
105 already_AddRefed
<DOMMatrix
> GetTransform(
106 mozilla::ErrorResult
& aError
) override
;
107 void SetTransform(double aM11
, double aM12
, double aM21
, double aM22
,
108 double aDx
, double aDy
,
109 mozilla::ErrorResult
& aError
) override
;
110 void SetTransform(const DOMMatrix2DInit
& aInit
,
111 mozilla::ErrorResult
& aError
) override
;
112 void ResetTransform(mozilla::ErrorResult
& aError
) override
;
114 double GlobalAlpha() override
{ return CurrentState().globalAlpha
; }
116 // Useful for silencing cast warnings
117 static mozilla::gfx::Float
ToFloat(double aValue
) {
118 return mozilla::gfx::Float(aValue
);
121 void SetGlobalAlpha(double aGlobalAlpha
) override
{
122 if (aGlobalAlpha
>= 0.0 && aGlobalAlpha
<= 1.0) {
123 CurrentState().globalAlpha
= ToFloat(aGlobalAlpha
);
127 void GetGlobalCompositeOperation(nsAString
& aOp
,
128 mozilla::ErrorResult
& aError
) override
;
129 void SetGlobalCompositeOperation(const nsAString
& aOp
,
130 mozilla::ErrorResult
& aError
) override
;
133 OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) override
{
134 GetStyleAsUnion(aValue
, Style::STROKE
);
138 const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) override
{
139 SetStyleFromUnion(aValue
, Style::STROKE
);
143 OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) override
{
144 GetStyleAsUnion(aValue
, Style::FILL
);
148 const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) override
{
149 SetStyleFromUnion(aValue
, Style::FILL
);
152 already_AddRefed
<CanvasGradient
> CreateLinearGradient(double aX0
, double aY0
,
154 double aY1
) override
;
155 already_AddRefed
<CanvasGradient
> CreateRadialGradient(
156 double aX0
, double aY0
, double aR0
, double aX1
, double aY1
, double aR1
,
157 ErrorResult
& aError
) override
;
158 already_AddRefed
<CanvasGradient
> CreateConicGradient(double aAngle
,
160 double aCy
) override
;
161 already_AddRefed
<CanvasPattern
> CreatePattern(
162 const CanvasImageSource
& aElement
, const nsAString
& aRepeat
,
163 ErrorResult
& aError
) override
;
165 double ShadowOffsetX() override
{ return CurrentState().shadowOffset
.x
; }
167 void SetShadowOffsetX(double aShadowOffsetX
) override
{
168 CurrentState().shadowOffset
.x
= ToFloat(aShadowOffsetX
);
171 double ShadowOffsetY() override
{ return CurrentState().shadowOffset
.y
; }
173 void SetShadowOffsetY(double aShadowOffsetY
) override
{
174 CurrentState().shadowOffset
.y
= ToFloat(aShadowOffsetY
);
177 double ShadowBlur() override
{ return CurrentState().shadowBlur
; }
179 void SetShadowBlur(double aShadowBlur
) override
{
180 if (aShadowBlur
>= 0.0) {
181 CurrentState().shadowBlur
= ToFloat(aShadowBlur
);
185 void GetShadowColor(nsACString
& aShadowColor
) override
{
186 StyleColorToString(CurrentState().shadowColor
, aShadowColor
);
189 void GetFilter(nsACString
& aFilter
) { aFilter
= CurrentState().filterString
; }
191 void SetShadowColor(const nsACString
& aShadowColor
) override
;
192 void SetFilter(const nsACString
& aFilter
, mozilla::ErrorResult
& aError
);
193 void ClearRect(double aX
, double aY
, double aW
, double aH
) override
;
194 void FillRect(double aX
, double aY
, double aW
, double aH
) override
;
195 void StrokeRect(double aX
, double aY
, double aW
, double aH
) override
;
197 void Fill(const CanvasWindingRule
& aWinding
);
198 void Fill(const CanvasPath
& aPath
, const CanvasWindingRule
& aWinding
);
200 void Stroke(const CanvasPath
& aPath
);
201 void DrawFocusIfNeeded(mozilla::dom::Element
& aElement
, ErrorResult
& aRv
);
202 bool DrawCustomFocusRing(mozilla::dom::Element
& aElement
);
203 void Clip(const CanvasWindingRule
& aWinding
);
204 void Clip(const CanvasPath
& aPath
, const CanvasWindingRule
& aWinding
);
205 bool IsPointInPath(JSContext
* aCx
, double aX
, double aY
,
206 const CanvasWindingRule
& aWinding
,
207 nsIPrincipal
& aSubjectPrincipal
);
208 bool IsPointInPath(JSContext
* aCx
, const CanvasPath
& aPath
, double aX
,
209 double aY
, const CanvasWindingRule
& aWinding
,
211 bool IsPointInStroke(JSContext
* aCx
, double aX
, double aY
,
212 nsIPrincipal
& aSubjectPrincipal
);
213 bool IsPointInStroke(JSContext
* aCx
, const CanvasPath
& aPath
, double aX
,
214 double aY
, nsIPrincipal
&);
215 void FillText(const nsAString
& aText
, double aX
, double aY
,
216 const Optional
<double>& aMaxWidth
,
217 mozilla::ErrorResult
& aError
);
218 void StrokeText(const nsAString
& aText
, double aX
, double aY
,
219 const Optional
<double>& aMaxWidth
,
220 mozilla::ErrorResult
& aError
);
221 TextMetrics
* MeasureText(const nsAString
& aRawText
,
222 mozilla::ErrorResult
& aError
);
224 void AddHitRegion(const HitRegionOptions
& aOptions
,
225 mozilla::ErrorResult
& aError
);
226 void RemoveHitRegion(const nsAString
& aId
);
227 void ClearHitRegions();
229 void DrawImage(const CanvasImageSource
& aImage
, double aDx
, double aDy
,
230 mozilla::ErrorResult
& aError
) override
{
231 DrawImage(aImage
, 0.0, 0.0, 0.0, 0.0, aDx
, aDy
, 0.0, 0.0, 0, aError
);
234 void DrawImage(const CanvasImageSource
& aImage
, double aDx
, double aDy
,
235 double aDw
, double aDh
,
236 mozilla::ErrorResult
& aError
) override
{
237 DrawImage(aImage
, 0.0, 0.0, 0.0, 0.0, aDx
, aDy
, aDw
, aDh
, 2, aError
);
240 void DrawImage(const CanvasImageSource
& aImage
, double aSx
, double aSy
,
241 double aSw
, double aSh
, double aDx
, double aDy
, double aDw
,
242 double aDh
, mozilla::ErrorResult
& aError
) override
{
243 DrawImage(aImage
, aSx
, aSy
, aSw
, aSh
, aDx
, aDy
, aDw
, aDh
, 6, aError
);
246 already_AddRefed
<ImageData
> CreateImageData(JSContext
*, int32_t aSw
,
247 int32_t aSh
, ErrorResult
&);
248 already_AddRefed
<ImageData
> CreateImageData(JSContext
*, ImageData
&,
250 already_AddRefed
<ImageData
> GetImageData(JSContext
*, int32_t aSx
, int32_t aSy
,
251 int32_t aSw
, int32_t aSh
,
252 nsIPrincipal
& aSubjectPrincipal
,
254 void PutImageData(ImageData
&, int32_t aDx
, int32_t aDy
, ErrorResult
&);
255 void PutImageData(ImageData
&, int32_t aDx
, int32_t aDy
, int32_t aDirtyX
,
256 int32_t aDirtyY
, int32_t aDirtyWidth
, int32_t aDirtyHeight
,
259 double LineWidth() override
{ return CurrentState().lineWidth
; }
261 void SetLineWidth(double aWidth
) override
{
263 CurrentState().lineWidth
= ToFloat(aWidth
);
266 void GetLineCap(nsAString
& aLinecapStyle
) override
;
267 void SetLineCap(const nsAString
& aLinecapStyle
) override
;
268 void GetLineJoin(nsAString
& aLinejoinStyle
,
269 mozilla::ErrorResult
& aError
) override
;
270 void SetLineJoin(const nsAString
& aLinejoinStyle
) override
;
272 double MiterLimit() override
{ return CurrentState().miterLimit
; }
274 void SetMiterLimit(double aMiter
) override
{
276 CurrentState().miterLimit
= ToFloat(aMiter
);
280 void GetFont(nsACString
& aFont
) { aFont
= GetFont(); }
282 void SetFont(const nsACString
& aFont
, mozilla::ErrorResult
& aError
);
283 void GetTextAlign(nsAString
& aTextAlign
);
284 void SetTextAlign(const nsAString
& aTextAlign
);
285 void GetTextBaseline(nsAString
& aTextBaseline
);
286 void SetTextBaseline(const nsAString
& aTextBaseline
);
288 void ClosePath() override
{
289 EnsureWritablePath();
292 mPathBuilder
->Close();
294 mDSPathBuilder
->Close();
298 void MoveTo(double aX
, double aY
) override
{
299 EnsureWritablePath();
302 mPathBuilder
->MoveTo(mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
304 mDSPathBuilder
->MoveTo(mTarget
->GetTransform().TransformPoint(
305 mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
))));
309 void LineTo(double aX
, double aY
) override
{
310 EnsureWritablePath();
312 LineTo(mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
315 void QuadraticCurveTo(double aCpx
, double aCpy
, double aX
,
316 double aY
) override
{
317 EnsureWritablePath();
320 mPathBuilder
->QuadraticBezierTo(
321 mozilla::gfx::Point(ToFloat(aCpx
), ToFloat(aCpy
)),
322 mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
324 mozilla::gfx::Matrix transform
= mTarget
->GetTransform();
325 mDSPathBuilder
->QuadraticBezierTo(
326 transform
.TransformPoint(
327 mozilla::gfx::Point(ToFloat(aCpx
), ToFloat(aCpy
))),
328 transform
.TransformPoint(
329 mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
))));
333 void BezierCurveTo(double aCp1x
, double aCp1y
, double aCp2x
, double aCp2y
,
334 double aX
, double aY
) override
{
335 EnsureWritablePath();
337 BezierTo(mozilla::gfx::Point(ToFloat(aCp1x
), ToFloat(aCp1y
)),
338 mozilla::gfx::Point(ToFloat(aCp2x
), ToFloat(aCp2y
)),
339 mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
342 void ArcTo(double aX1
, double aY1
, double aX2
, double aY2
, double aRadius
,
343 mozilla::ErrorResult
& aError
) override
;
344 void Rect(double aX
, double aY
, double aW
, double aH
) override
;
345 void Arc(double aX
, double aY
, double aRadius
, double aStartAngle
,
346 double aEndAngle
, bool aAnticlockwise
,
347 mozilla::ErrorResult
& aError
) override
;
348 void Ellipse(double aX
, double aY
, double aRadiusX
, double aRadiusY
,
349 double aRotation
, double aStartAngle
, double aEndAngle
,
350 bool aAnticlockwise
, ErrorResult
& aError
) override
;
352 void GetMozCurrentTransform(JSContext
* aCx
,
353 JS::MutableHandle
<JSObject
*> aResult
,
354 mozilla::ErrorResult
& aError
);
355 void SetMozCurrentTransform(JSContext
* aCx
,
356 JS::Handle
<JSObject
*> aCurrentTransform
,
357 mozilla::ErrorResult
& aError
);
358 void GetMozCurrentTransformInverse(JSContext
* aCx
,
359 JS::MutableHandle
<JSObject
*> aResult
,
360 mozilla::ErrorResult
& aError
);
361 void SetMozCurrentTransformInverse(JSContext
* aCx
,
362 JS::Handle
<JSObject
*> aCurrentTransform
,
363 mozilla::ErrorResult
& aError
);
364 void GetFillRule(nsAString
& aFillRule
);
365 void SetFillRule(const nsAString
& aFillRule
);
367 void SetLineDash(const Sequence
<double>& aSegments
,
368 mozilla::ErrorResult
& aRv
) override
;
369 void GetLineDash(nsTArray
<double>& aSegments
) const override
;
371 void SetLineDashOffset(double aOffset
) override
;
372 double LineDashOffset() const override
;
374 void GetMozTextStyle(nsACString
& aMozTextStyle
) { GetFont(aMozTextStyle
); }
376 void SetMozTextStyle(const nsACString
& aMozTextStyle
,
377 mozilla::ErrorResult
& aError
) {
378 SetFont(aMozTextStyle
, aError
);
381 bool ImageSmoothingEnabled() override
{
382 return CurrentState().imageSmoothingEnabled
;
385 void SetImageSmoothingEnabled(bool aImageSmoothingEnabled
) override
{
386 if (aImageSmoothingEnabled
!= CurrentState().imageSmoothingEnabled
) {
387 CurrentState().imageSmoothingEnabled
= aImageSmoothingEnabled
;
391 void DrawWindow(nsGlobalWindowInner
& aWindow
, double aX
, double aY
, double aW
,
392 double aH
, const nsACString
& aBgColor
, uint32_t aFlags
,
393 nsIPrincipal
& aSubjectPrincipal
,
394 mozilla::ErrorResult
& aError
);
396 // Eventually this should be deprecated. Keeping for now to keep the binding
402 gfx::IntSize
GetSize() const { return gfx::IntSize(mWidth
, mHeight
); }
403 virtual int32_t GetWidth() override
{ return GetSize().width
; }
404 virtual int32_t GetHeight() override
{ return GetSize().height
; }
406 // nsICanvasRenderingContextInternal
408 * Gets the pres shell from either the canvas element or the doc shell
410 PresShell
* GetPresShell() final
;
411 NS_IMETHOD
SetDimensions(int32_t aWidth
, int32_t aHeight
) override
;
412 NS_IMETHOD
InitializeWithDrawTarget(
413 nsIDocShell
* aShell
, NotNull
<gfx::DrawTarget
*> aTarget
) override
;
415 NS_IMETHOD
GetInputStream(const char* aMimeType
,
416 const nsAString
& aEncoderOptions
,
417 nsIInputStream
** aStream
) override
;
419 already_AddRefed
<mozilla::gfx::SourceSurface
> GetSurfaceSnapshot(
420 gfxAlphaType
* aOutAlphaType
= nullptr) override
;
422 virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue
) override
;
423 bool GetIsOpaque() override
{ return mOpaque
; }
424 NS_IMETHOD
Reset() override
;
425 already_AddRefed
<Layer
> GetCanvasLayer(nsDisplayListBuilder
* aBuilder
,
427 LayerManager
* aManager
) override
;
429 bool UpdateWebRenderCanvasData(nsDisplayListBuilder
* aBuilder
,
430 WebRenderCanvasData
* aCanvasData
) override
;
432 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
433 CanvasRenderer
* aRenderer
) override
;
434 virtual bool ShouldForceInactiveLayer(LayerManager
* aManager
) override
;
435 void MarkContextClean() override
;
436 void MarkContextCleanForFrameCapture() override
;
437 bool IsContextCleanForFrameCapture() override
;
438 NS_IMETHOD
SetIsIPC(bool aIsIPC
) override
;
439 // this rect is in canvas device space
440 void Redraw(const mozilla::gfx::Rect
& aR
);
441 NS_IMETHOD
Redraw(const gfxRect
& aR
) override
{
445 NS_IMETHOD
SetContextOptions(JSContext
* aCx
, JS::Handle
<JS::Value
> aOptions
,
446 ErrorResult
& aRvForDictionaryInit
) override
;
449 * An abstract base class to be implemented by callers wanting to be notified
450 * that a refresh has occurred. Callers must ensure an observer is removed
451 * before it is destroyed.
453 virtual void DidRefresh() override
;
455 // this rect is in mTarget's current user space
456 void RedrawUser(const gfxRect
& aR
);
458 // nsISupports interface + CC
459 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
461 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(
462 CanvasRenderingContext2D
)
464 enum class CanvasMultiGetterType
: uint8_t {
470 enum class Style
: uint8_t { STROKE
= 0, FILL
, MAX
};
472 nsINode
* GetParentObject() { return mCanvasElement
; }
474 void LineTo(const mozilla::gfx::Point
& aPoint
) {
476 mPathBuilder
->LineTo(aPoint
);
478 mDSPathBuilder
->LineTo(mTarget
->GetTransform().TransformPoint(aPoint
));
482 void BezierTo(const mozilla::gfx::Point
& aCP1
,
483 const mozilla::gfx::Point
& aCP2
,
484 const mozilla::gfx::Point
& aCP3
) {
486 mPathBuilder
->BezierTo(aCP1
, aCP2
, aCP3
);
488 mozilla::gfx::Matrix transform
= mTarget
->GetTransform();
489 mDSPathBuilder
->BezierTo(transform
.TransformPoint(aCP1
),
490 transform
.TransformPoint(aCP2
),
491 transform
.TransformPoint(aCP3
));
495 virtual UniquePtr
<uint8_t[]> GetImageBuffer(int32_t* aFormat
) override
;
497 // Given a point, return hit region ID if it exists
498 nsString
GetHitRegion(const mozilla::gfx::Point
& aPoint
) override
;
500 // return true and fills in the bound rect if element has a hit region.
501 bool GetHitRegionRect(Element
* aElement
, nsRect
& aRect
) override
;
506 * Update CurrentState().filter with the filter description for
507 * CurrentState().filterChain.
508 * Flushes the PresShell, so the world can change if you call this function.
510 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void UpdateFilter();
513 nsresult
GetImageDataArray(JSContext
* aCx
, int32_t aX
, int32_t aY
,
514 uint32_t aWidth
, uint32_t aHeight
,
515 nsIPrincipal
& aSubjectPrincipal
,
518 void PutImageData_explicit(int32_t aX
, int32_t aY
, uint32_t aW
, uint32_t aH
,
519 dom::Uint8ClampedArray
* aArray
, bool aHasDirtyRect
,
520 int32_t aDirtyX
, int32_t aDirtyY
,
521 int32_t aDirtyWidth
, int32_t aDirtyHeight
,
524 bool CopyBufferProvider(layers::PersistentBufferProvider
& aOld
,
525 gfx::DrawTarget
& aTarget
, gfx::IntRect aCopyRect
);
528 * Internal method to complete initialisation, expects mTarget to have been
531 nsresult
Initialize(int32_t aWidth
, int32_t aHeight
);
533 nsresult
InitializeWithTarget(mozilla::gfx::DrawTarget
* aSurface
,
534 int32_t aWidth
, int32_t aHeight
);
537 * The number of living nsCanvasRenderingContexts. When this goes down to
538 * 0, we free the premultiply and unpremultiply tables, if they exist.
540 static uintptr_t sNumLivingContexts
;
542 static mozilla::gfx::DrawTarget
* sErrorTarget
;
544 void SetTransformInternal(const mozilla::gfx::Matrix
& aTransform
);
546 // Some helpers. Doesn't modify a color on failure.
547 void SetStyleFromUnion(
548 const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
,
550 void SetStyleFromString(const nsACString
& aStr
, Style aWhichStyle
);
552 void SetStyleFromGradient(CanvasGradient
& aGradient
, Style aWhichStyle
) {
553 CurrentState().SetGradientStyle(aWhichStyle
, &aGradient
);
556 void SetStyleFromPattern(CanvasPattern
& aPattern
, Style aWhichStyle
) {
557 CurrentState().SetPatternStyle(aWhichStyle
, &aPattern
);
560 void GetStyleAsUnion(OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
,
563 // Returns whether a color was successfully parsed.
564 bool ParseColor(const nsACString
& aString
, nscolor
* aColor
);
566 static void StyleColorToString(const nscolor
& aColor
, nsACString
& aStr
);
568 // Returns whether a filter was successfully parsed.
569 bool ParseFilter(const nsACString
& aString
,
570 StyleOwnedSlice
<StyleFilter
>& aFilterChain
,
571 ErrorResult
& aError
);
573 // Returns whether the font was successfully updated.
574 bool SetFontInternal(const nsACString
& aFont
, mozilla::ErrorResult
& aError
);
576 // Clears the target and updates mOpaque based on mOpaqueAttrValue and
577 // mContextAttributesHasAlpha.
578 void UpdateIsOpaque();
581 * Creates the error target, if it doesn't exist
583 static void EnsureErrorTarget();
585 /* This function ensures there is a writable pathbuilder available, this
586 * pathbuilder may be working in user space or in device space or
588 * After calling this function mPathTransformWillUpdate will be false
590 void EnsureWritablePath();
592 // Ensures a path in UserSpace is available.
593 void EnsureUserSpacePath(
594 const CanvasWindingRule
& aWinding
= CanvasWindingRule::Nonzero
);
597 * Needs to be called before updating the transform. This makes a call to
598 * EnsureTarget() so you don't have to.
600 void TransformWillUpdate();
602 // Report the fillRule has changed.
603 void FillRuleChanged();
606 * Create the backing surfacing, if it doesn't exist. If there is an error
607 * in creating the target then it will put sErrorTarget in place. If there
608 * is in turn an error in creating the sErrorTarget then they would both
609 * be null so IsTargetValid() would still return null.
611 * Returns true on success.
613 bool EnsureTarget(const gfx::Rect
* aCoveredRect
= nullptr,
614 bool aWillClear
= false);
616 void RestoreClipsAndTransformToTarget();
618 bool TrySharedTarget(RefPtr
<gfx::DrawTarget
>& aOutDT
,
619 RefPtr
<layers::PersistentBufferProvider
>& aOutProvider
);
621 bool TryBasicTarget(RefPtr
<gfx::DrawTarget
>& aOutDT
,
622 RefPtr
<layers::PersistentBufferProvider
>& aOutProvider
);
624 void RegisterAllocation();
626 void SetInitialState();
628 void SetErrorState();
631 * This method is run at the end of the event-loop spin where
632 * ScheduleStableStateCallback was called.
634 * We use it to unlock resources that need to be locked while drawing.
636 void OnStableState();
641 void ScheduleStableStateCallback();
644 * Disposes an old target and prepares to lazily create a new target.
646 * Parameters are the new dimensions to be used, or if either is negative,
647 * existing dimensions will be left unchanged.
649 void ClearTarget(int32_t aWidth
= -1, int32_t aHeight
= -1);
652 * Returns the target to the buffer provider. i.e. this will queue a frame for
655 void ReturnTarget(bool aForceReset
= false);
658 * Check if the target is valid after calling EnsureTarget.
660 bool IsTargetValid() const { return !!mTarget
&& mTarget
!= sErrorTarget
; }
663 * Returns the surface format this canvas should be allocated using. Takes
664 * into account mOpaque, platform requirements, etc.
666 mozilla::gfx::SurfaceFormat
GetSurfaceFormat() const;
669 * Returns true if we know for sure that the pattern for a given style is
670 * opaque. Usefull to know if we can discard the content below in certain
671 * situations. Optionally checks if the pattern is a color pattern.
673 bool PatternIsOpaque(Style aStyle
, bool* aIsColor
= nullptr) const;
675 SurfaceFromElementResult
CachedSurfaceFromElement(Element
* aElement
);
677 void DrawImage(const CanvasImageSource
& aImgElt
, double aSx
, double aSy
,
678 double aSw
, double aSh
, double aDx
, double aDy
, double aDw
,
679 double aDh
, uint8_t aOptional_argc
,
680 mozilla::ErrorResult
& aError
);
682 void DrawDirectlyToCanvas(const DirectDrawInfo
& aImage
,
683 mozilla::gfx::Rect
* aBounds
,
684 mozilla::gfx::Rect aDest
, mozilla::gfx::Rect aSrc
,
685 gfx::IntSize aImgSize
);
687 nsCString
& GetFont() {
688 /* will initilize the value if not set, else does nothing */
689 GetCurrentFontStyle();
691 return CurrentState().font
;
695 int32_t mWidth
, mHeight
;
697 // This is true when the canvas is valid, but of zero size, this requires
698 // specific behavior on some operations.
701 // The two ways to set the opaqueness of the canvas.
702 // mOpaqueAttrValue: Whether the <canvas> element has the moz-opaque attribute
703 // set. Can change during the lifetime of the context. Non-standard, should
704 // hopefully go away soon.
705 // mContextAttributesHasAlpha: The standard way of setting canvas opaqueness.
706 // Set at context initialization time and never changes.
707 bool mOpaqueAttrValue
;
708 bool mContextAttributesHasAlpha
;
710 // Determines the context's opaqueness. Is computed from mOpaqueAttrValue and
711 // mContextAttributesHasAlpha in UpdateIsOpaque().
714 // This is true when the next time our layer is retrieved we need to
715 // recreate it (i.e. our backing surface changed)
717 // This is needed for drawing in drawAsyncXULElement
720 bool mHasPendingStableStateCallback
;
722 // If mCanvasElement is not provided, then a docshell is
723 nsCOMPtr
<nsIDocShell
> mDocShell
;
725 // This is created lazily so it is necessary to call EnsureTarget before
726 // accessing it. In the event of an error it will be equal to
728 RefPtr
<mozilla::gfx::DrawTarget
> mTarget
;
730 RefPtr
<mozilla::layers::PersistentBufferProvider
> mBufferProvider
;
732 RefPtr
<CanvasShutdownObserver
> mShutdownObserver
;
733 void RemoveShutdownObserver();
734 bool AlreadyShutDown() const { return !mShutdownObserver
; }
737 * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
738 * Redraw is called, reset to false when Render is called.
740 bool mIsEntireFrameInvalid
;
742 * When this is set, the first call to Redraw(gfxRect) should set
743 * mIsEntireFrameInvalid since we expect it will be followed by
744 * many more Redraw calls.
746 bool mPredictManyRedrawCalls
;
749 * Flag to avoid unnecessary surface copies to FrameCaptureListeners in the
750 * case when the canvas is not currently being drawn into and not rendered
751 * but canvas capturing is still ongoing.
753 bool mIsCapturedFrameInvalid
;
756 * We also have a device space pathbuilder. The reason for this is as
757 * follows, when a path is being built, but the transform changes, we
758 * can no longer keep a single path in userspace, considering there's
759 * several 'user spaces' now. We therefore transform the current path
760 * into device space, and add all operations to this path in device
763 * When then finally executing a render, the Azure drawing API expects
764 * the path to be in userspace. We could then set an identity transform
765 * on the DrawTarget and do all drawing in device space. This is
766 * undesirable because it requires transforming patterns, gradients,
767 * clips, etc. into device space and it would not work for stroking.
768 * What we do instead is convert the path back to user space when it is
769 * drawn, and draw it with the current transform. This makes all drawing
772 * There's never both a device space path builder and a user space path
773 * builder present at the same time. There is also never a path and a
774 * path builder present at the same time. When writing proceeds on an
775 * existing path the Path is cleared and a new builder is created.
777 * mPath is always in user-space.
779 RefPtr
<mozilla::gfx::Path
> mPath
;
780 RefPtr
<mozilla::gfx::PathBuilder
> mDSPathBuilder
;
781 RefPtr
<mozilla::gfx::PathBuilder
> mPathBuilder
;
782 bool mPathTransformWillUpdate
;
783 mozilla::gfx::Matrix mPathToDS
;
786 * Number of times we've invalidated before calling redraw
788 uint32_t mInvalidateCount
;
789 static const uint32_t kCanvasMaxInvalidateCount
= 100;
792 * State information for hit regions
796 // fallback element for a11y
797 RefPtr
<Element
> mElement
;
798 // Path of the hit region in the 2d context coordinate space (not user
800 RefPtr
<gfx::Path
> mPath
;
803 nsTArray
<RegionInfo
> mHitRegionsOptions
;
808 * Returns true if a shadow should be drawn along with a
811 bool NeedToDrawShadow() {
812 const ContextState
& state
= CurrentState();
814 // The spec says we should not draw shadows if the operator is OVER.
815 // If it's over and the alpha value is zero, nothing needs to be drawn.
816 return NS_GET_A(state
.shadowColor
) != 0 &&
817 (state
.shadowBlur
!= 0.f
|| state
.shadowOffset
.x
!= 0.f
||
818 state
.shadowOffset
.y
!= 0.f
);
822 * Returns true if the result of a drawing operation should be
823 * drawn with a filter.
825 bool NeedToApplyFilter() {
826 return EnsureUpdatedFilter().mPrimitives
.Length() > 0;
830 * Calls UpdateFilter if the canvas's WriteOnly state has changed between the
831 * last call to UpdateFilter and now.
833 const gfx::FilterDescription
& EnsureUpdatedFilter() {
834 bool isWriteOnly
= mCanvasElement
&& mCanvasElement
->IsWriteOnly();
835 if (CurrentState().filterSourceGraphicTainted
!= isWriteOnly
) {
839 MOZ_ASSERT(CurrentState().filterSourceGraphicTainted
== isWriteOnly
);
840 return CurrentState().filter
;
843 bool NeedToCalculateBounds() {
844 return NeedToDrawShadow() || NeedToApplyFilter();
847 mozilla::gfx::CompositionOp
UsedOperation() {
848 if (NeedToDrawShadow() || NeedToApplyFilter()) {
849 // In this case the shadow or filter rendering will use the operator.
850 return mozilla::gfx::CompositionOp::OP_OVER
;
853 return CurrentState().op
;
859 enum class TextAlign
: uint8_t { START
, END
, LEFT
, RIGHT
, CENTER
};
861 enum class TextBaseline
: uint8_t {
870 enum class TextDrawOperation
: uint8_t { FILL
, STROKE
, MEASURE
};
873 gfxFontGroup
* GetCurrentFontStyle();
876 * Implementation of the fillText, strokeText, and measure functions with
877 * the operation abstracted to a flag.
878 * Returns a TextMetrics object _only_ if the operation is measure;
879 * drawing operations (fill or stroke) always return nullptr.
881 TextMetrics
* DrawOrMeasureText(const nsAString
& aText
, float aX
, float aY
,
882 const Optional
<double>& aMaxWidth
,
883 TextDrawOperation aOp
, ErrorResult
& aError
);
885 // A clip or a transform, recorded and restored in order.
887 explicit ClipState(mozilla::gfx::Path
* aClip
) : clip(aClip
) {}
889 explicit ClipState(const mozilla::gfx::Matrix
& aTransform
)
890 : transform(aTransform
) {}
892 bool IsClip() const { return !!clip
; }
894 RefPtr
<mozilla::gfx::Path
> clip
;
895 mozilla::gfx::Matrix transform
;
898 // state stack handling
902 ContextState(const ContextState
& aOther
);
905 void SetColorStyle(Style aWhichStyle
, nscolor aColor
);
906 void SetPatternStyle(Style aWhichStyle
, CanvasPattern
* aPat
);
907 void SetGradientStyle(Style aWhichStyle
, CanvasGradient
* aGrad
);
910 * returns true iff the given style is a solid color.
912 bool StyleIsColor(Style aWhichStyle
) const {
913 return !(patternStyles
[aWhichStyle
] || gradientStyles
[aWhichStyle
]);
916 int32_t ShadowBlurRadius() const {
917 static const gfxFloat GAUSSIAN_SCALE_FACTOR
=
918 (3 * sqrt(2 * M_PI
) / 4) * 1.5;
919 return (int32_t)floor(ShadowBlurSigma() * GAUSSIAN_SCALE_FACTOR
+ 0.5);
922 mozilla::gfx::Float
ShadowBlurSigma() const {
923 return std::min(SIGMA_MAX
, shadowBlur
/ 2.0f
);
926 nsTArray
<ClipState
> clipsAndTransforms
;
928 RefPtr
<gfxFontGroup
> fontGroup
;
929 RefPtr
<nsAtom
> fontLanguage
;
932 EnumeratedArray
<Style
, Style::MAX
, RefPtr
<CanvasGradient
>> gradientStyles
;
933 EnumeratedArray
<Style
, Style::MAX
, RefPtr
<CanvasPattern
>> patternStyles
;
934 EnumeratedArray
<Style
, Style::MAX
, nscolor
> colorStyles
;
937 TextAlign textAlign
= TextAlign::START
;
938 TextBaseline textBaseline
= TextBaseline::ALPHABETIC
;
940 nscolor shadowColor
= 0;
942 mozilla::gfx::Matrix transform
;
943 mozilla::gfx::Point shadowOffset
;
944 mozilla::gfx::Float lineWidth
= 1.0f
;
945 mozilla::gfx::Float miterLimit
= 10.0f
;
946 mozilla::gfx::Float globalAlpha
= 1.0f
;
947 mozilla::gfx::Float shadowBlur
= 0.0f
;
949 nsTArray
<mozilla::gfx::Float
> dash
;
950 mozilla::gfx::Float dashOffset
= 0.0f
;
952 mozilla::gfx::CompositionOp op
= mozilla::gfx::CompositionOp::OP_OVER
;
953 mozilla::gfx::FillRule fillRule
= mozilla::gfx::FillRule::FILL_WINDING
;
954 mozilla::gfx::CapStyle lineCap
= mozilla::gfx::CapStyle::BUTT
;
955 mozilla::gfx::JoinStyle lineJoin
= mozilla::gfx::JoinStyle::MITER_OR_BEVEL
;
957 nsCString filterString
{"none"};
958 StyleOwnedSlice
<StyleFilter
> filterChain
;
959 // RAII object that we obtain when we start to observer SVG filter elements
960 // for rendering changes. When released we stop observing the SVG elements.
961 nsCOMPtr
<nsISupports
> autoSVGFiltersObserver
;
962 mozilla::gfx::FilterDescription filter
;
963 nsTArray
<RefPtr
<mozilla::gfx::SourceSurface
>> filterAdditionalImages
;
965 // This keeps track of whether the canvas was "tainted" or not when
966 // we last used a filter. This is a security measure, whereby the
967 // canvas is flipped to write-only if a cross-origin image is drawn to it.
968 // This is to stop bad actors from reading back data they shouldn't have
971 // This also limits what filters we can apply to the context; in particular
972 // feDisplacementMap is restricted.
974 // We keep track of this to ensure that if this gets out of sync with the
975 // tainted state of the canvas itself, we update our filters accordingly.
976 bool filterSourceGraphicTainted
= false;
978 bool imageSmoothingEnabled
= true;
979 bool fontExplicitLanguage
= false;
982 AutoTArray
<ContextState
, 3> mStyleStack
;
984 inline ContextState
& CurrentState() {
985 return mStyleStack
[mStyleStack
.Length() - 1];
988 inline const ContextState
& CurrentState() const {
989 return mStyleStack
[mStyleStack
.Length() - 1];
992 friend class CanvasGeneralPattern
;
993 friend class AdjustedTarget
;
994 friend class AdjustedTargetForShadow
;
995 friend class AdjustedTargetForFilter
;
998 void GetAppUnitsValues(int32_t* aPerDevPixel
, int32_t* aPerCSSPixel
);
1000 friend struct CanvasBidiProcessor
;
1001 friend class CanvasDrawObserver
;
1002 friend class ImageBitmap
;
1004 void SetWriteOnly();
1006 bool IsWriteOnly() const { return mWriteOnly
; }
1009 bool mClipsNeedConverting
= false;
1012 size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D
* aContext
);
1015 } // namespace mozilla
1017 #endif /* CanvasRenderingContext2D_h */