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/CanvasRenderingContext2DBinding.h"
10 #include "mozilla/dom/HTMLCanvasElement.h"
11 #include "mozilla/intl/Bidi.h"
12 #include "mozilla/gfx/Rect.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/Atomics.h"
15 #include "mozilla/Attributes.h"
16 #include "mozilla/EnumeratedArray.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/MruCache.h"
19 #include "mozilla/RefPtr.h"
20 #include "mozilla/SurfaceFromElementResult.h"
21 #include "mozilla/ThreadLocal.h"
22 #include "mozilla/UniquePtr.h"
23 #include "FilterDescription.h"
24 #include "gfx2DGlue.h"
25 #include "gfxFontConstants.h"
26 #include "gfxTextRun.h"
28 #include "nsICanvasRenderingContextInternal.h"
30 #include "nsRFPService.h"
34 class nsGlobalWindowInner
;
39 class ISVGFilterObserverList
;
47 class PersistentBufferProvider
;
48 enum class LayersBackend
: int8_t;
53 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrOffscreenCanvasOrImageBitmapOrVideoFrame
;
54 using CanvasImageSource
=
55 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrOffscreenCanvasOrImageBitmapOrVideoFrame
;
58 class UTF8StringOrCanvasGradientOrCanvasPattern
;
59 class OwningUTF8StringOrCanvasGradientOrCanvasPattern
;
65 extern const mozilla::gfx::Float SIGMA_MAX
;
70 struct CanvasBidiProcessor
;
71 class CanvasDrawObserver
;
72 class CanvasShutdownObserver
;
75 class DOMMatrixReadOnly
;
76 struct DOMMatrix2DInit
;
79 ** CanvasRenderingContext2D
81 class CanvasRenderingContext2D
: public nsICanvasRenderingContextInternal
,
82 public nsWrapperCache
{
84 virtual ~CanvasRenderingContext2D();
87 explicit CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend
);
89 virtual JSObject
* WrapObject(JSContext
* aCx
,
90 JS::Handle
<JSObject
*> aGivenProto
) override
;
92 HTMLCanvasElement
* GetCanvas() const {
93 if (!mCanvasElement
|| mCanvasElement
->IsInNativeAnonymousSubtree()) {
97 // corresponds to changes to the old bindings made in bug 745025
98 return mCanvasElement
->GetOriginalCanvas();
101 void GetContextAttributes(CanvasRenderingContext2DSettings
& aSettings
) const;
103 void GetDebugInfo(bool aEnsureTarget
,
104 CanvasRenderingContext2DDebugInfo
& aDebugInfo
,
105 ErrorResult
& aError
);
107 void OnMemoryPressure() override
;
108 void OnBeforePaintTransaction() override
;
109 void OnDidPaintTransaction() override
;
110 layers::PersistentBufferProvider
* GetBufferProvider() override
;
112 Maybe
<layers::SurfaceDescriptor
> GetFrontBuffer(
113 WebGLFramebufferJS
*, const bool webvr
= false) override
;
115 already_AddRefed
<layers::FwdTransactionTracker
> UseCompositableForwarder(
116 layers::CompositableForwarder
* aForwarder
) override
;
122 // reset the rendering context to its default state
123 // Userland polyfill is `c2d.width = c2d.width;`
124 SetDimensions(GetWidth(), GetHeight());
127 void Scale(double aX
, double aY
, mozilla::ErrorResult
& aError
);
128 void Rotate(double aAngle
, mozilla::ErrorResult
& aError
);
129 void Translate(double aX
, double aY
, mozilla::ErrorResult
& aError
);
130 void Transform(double aM11
, double aM12
, double aM21
, double aM22
, double aDx
,
131 double aDy
, mozilla::ErrorResult
& aError
);
132 already_AddRefed
<DOMMatrix
> GetTransform(mozilla::ErrorResult
& aError
);
133 void SetTransform(double aM11
, double aM12
, double aM21
, double aM22
,
134 double aDx
, double aDy
, mozilla::ErrorResult
& aError
);
135 void SetTransform(const DOMMatrix2DInit
& aInit
, mozilla::ErrorResult
& aError
);
136 void ResetTransform(mozilla::ErrorResult
& aError
);
138 double GlobalAlpha() { return CurrentState().globalAlpha
; }
140 // Useful for silencing cast warnings
141 static mozilla::gfx::Float
ToFloat(double aValue
) {
142 return mozilla::gfx::Float(aValue
);
145 void SetGlobalAlpha(double aGlobalAlpha
) {
146 if (aGlobalAlpha
>= 0.0 && aGlobalAlpha
<= 1.0) {
147 CurrentState().globalAlpha
= ToFloat(aGlobalAlpha
);
151 enum class ResolveCurrentColor
: bool { No
, Yes
};
152 Maybe
<nscolor
> ParseColor(const nsACString
&,
153 ResolveCurrentColor
= ResolveCurrentColor::Yes
);
155 void GetGlobalCompositeOperation(nsAString
& aOp
,
156 mozilla::ErrorResult
& aError
);
157 void SetGlobalCompositeOperation(const nsAString
& aOp
,
158 mozilla::ErrorResult
& aError
);
160 void GetStrokeStyle(OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) {
161 GetStyleAsUnion(aValue
, Style::STROKE
);
164 void SetStrokeStyle(const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) {
165 SetStyleFromUnion(aValue
, Style::STROKE
);
168 void GetFillStyle(OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) {
169 GetStyleAsUnion(aValue
, Style::FILL
);
172 void SetFillStyle(const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
) {
173 SetStyleFromUnion(aValue
, Style::FILL
);
176 already_AddRefed
<CanvasGradient
> CreateLinearGradient(double aX0
, double aY0
,
177 double aX1
, double aY1
);
178 already_AddRefed
<CanvasGradient
> CreateRadialGradient(double aX0
, double aY0
,
179 double aR0
, double aX1
,
180 double aY1
, double aR1
,
181 ErrorResult
& aError
);
182 already_AddRefed
<CanvasGradient
> CreateConicGradient(double aAngle
,
183 double aCx
, double aCy
);
184 already_AddRefed
<CanvasPattern
> CreatePattern(
185 const CanvasImageSource
& aElement
, const nsAString
& aRepeat
,
186 ErrorResult
& aError
);
188 double ShadowOffsetX() { return CurrentState().shadowOffset
.x
; }
190 void SetShadowOffsetX(double aShadowOffsetX
) {
191 CurrentState().shadowOffset
.x
= ToFloat(aShadowOffsetX
);
194 double ShadowOffsetY() { return CurrentState().shadowOffset
.y
; }
196 void SetShadowOffsetY(double aShadowOffsetY
) {
197 CurrentState().shadowOffset
.y
= ToFloat(aShadowOffsetY
);
200 double ShadowBlur() { return CurrentState().shadowBlur
; }
202 void SetShadowBlur(double aShadowBlur
) {
203 if (aShadowBlur
>= 0.0) {
204 CurrentState().shadowBlur
= ToFloat(aShadowBlur
);
208 void GetShadowColor(nsACString
& aShadowColor
) {
209 StyleColorToString(CurrentState().shadowColor
, aShadowColor
);
212 void GetFilter(nsACString
& aFilter
) { aFilter
= CurrentState().filterString
; }
214 void SetShadowColor(const nsACString
& aShadowColor
);
215 void SetFilter(const nsACString
& aFilter
, mozilla::ErrorResult
& aError
);
216 void ClearRect(double aX
, double aY
, double aW
, double aH
);
217 void FillRect(double aX
, double aY
, double aW
, double aH
);
218 void StrokeRect(double aX
, double aY
, double aW
, double aH
);
220 void Fill(const CanvasWindingRule
& aWinding
);
221 void Fill(const CanvasPath
& aPath
, const CanvasWindingRule
& aWinding
);
223 void Stroke(const CanvasPath
& aPath
);
224 void DrawFocusIfNeeded(mozilla::dom::Element
& aElement
, ErrorResult
& aRv
);
225 bool DrawCustomFocusRing(mozilla::dom::Element
& aElement
);
226 void Clip(const CanvasWindingRule
& aWinding
);
227 void Clip(const CanvasPath
& aPath
, const CanvasWindingRule
& aWinding
);
228 bool IsPointInPath(JSContext
* aCx
, double aX
, double aY
,
229 const CanvasWindingRule
& aWinding
,
230 nsIPrincipal
& aSubjectPrincipal
);
231 bool IsPointInPath(JSContext
* aCx
, const CanvasPath
& aPath
, double aX
,
232 double aY
, const CanvasWindingRule
& aWinding
,
234 bool IsPointInStroke(JSContext
* aCx
, double aX
, double aY
,
235 nsIPrincipal
& aSubjectPrincipal
);
236 bool IsPointInStroke(JSContext
* aCx
, const CanvasPath
& aPath
, double aX
,
237 double aY
, nsIPrincipal
&);
238 void FillText(const nsAString
& aText
, double aX
, double aY
,
239 const Optional
<double>& aMaxWidth
,
240 mozilla::ErrorResult
& aError
);
241 void StrokeText(const nsAString
& aText
, double aX
, double aY
,
242 const Optional
<double>& aMaxWidth
,
243 mozilla::ErrorResult
& aError
);
244 UniquePtr
<TextMetrics
> MeasureText(const nsAString
& aRawText
,
245 mozilla::ErrorResult
& aError
);
247 void DrawImage(const CanvasImageSource
& aImage
, double aDx
, double aDy
,
248 mozilla::ErrorResult
& aError
) {
249 DrawImage(aImage
, 0.0, 0.0, 0.0, 0.0, aDx
, aDy
, 0.0, 0.0, 0, aError
);
252 void DrawImage(const CanvasImageSource
& aImage
, double aDx
, double aDy
,
253 double aDw
, double aDh
, mozilla::ErrorResult
& aError
) {
254 DrawImage(aImage
, 0.0, 0.0, 0.0, 0.0, aDx
, aDy
, aDw
, aDh
, 2, aError
);
257 void DrawImage(const CanvasImageSource
& aImage
, double aSx
, double aSy
,
258 double aSw
, double aSh
, double aDx
, double aDy
, double aDw
,
259 double aDh
, mozilla::ErrorResult
& aError
) {
260 DrawImage(aImage
, aSx
, aSy
, aSw
, aSh
, aDx
, aDy
, aDw
, aDh
, 6, aError
);
263 already_AddRefed
<ImageData
> CreateImageData(JSContext
*, int32_t aSw
,
264 int32_t aSh
, ErrorResult
&);
265 already_AddRefed
<ImageData
> CreateImageData(JSContext
*, ImageData
&,
267 already_AddRefed
<ImageData
> GetImageData(JSContext
*, int32_t aSx
, int32_t aSy
,
268 int32_t aSw
, int32_t aSh
,
269 nsIPrincipal
& aSubjectPrincipal
,
271 void PutImageData(ImageData
&, int32_t aDx
, int32_t aDy
, ErrorResult
&);
272 void PutImageData(ImageData
&, int32_t aDx
, int32_t aDy
, int32_t aDirtyX
,
273 int32_t aDirtyY
, int32_t aDirtyWidth
, int32_t aDirtyHeight
,
276 double LineWidth() { return CurrentState().lineWidth
; }
278 void SetLineWidth(double aWidth
) {
280 CurrentState().lineWidth
= ToFloat(aWidth
);
284 CanvasLineCap
LineCap() { return CurrentState().lineCap
; }
285 void SetLineCap(const CanvasLineCap
& aLinecapStyle
) {
286 CurrentState().lineCap
= aLinecapStyle
;
289 CanvasLineJoin
LineJoin() { return CurrentState().lineJoin
; }
290 void SetLineJoin(const CanvasLineJoin
& aLinejoinStyle
) {
291 CurrentState().lineJoin
= aLinejoinStyle
;
294 double MiterLimit() { return CurrentState().miterLimit
; }
296 void SetMiterLimit(double aMiter
) {
298 CurrentState().miterLimit
= ToFloat(aMiter
);
302 void GetFont(nsACString
& aFont
) { aFont
= GetFont(); }
304 void SetFont(const nsACString
& aFont
, mozilla::ErrorResult
& aError
);
306 CanvasTextAlign
TextAlign() { return CurrentState().textAlign
; }
307 void SetTextAlign(const CanvasTextAlign
& aTextAlign
) {
308 CurrentState().textAlign
= aTextAlign
;
311 CanvasTextBaseline
TextBaseline() { return CurrentState().textBaseline
; }
312 void SetTextBaseline(const CanvasTextBaseline
& aTextBaseline
) {
313 CurrentState().textBaseline
= aTextBaseline
;
316 CanvasDirection
Direction() { return CurrentState().textDirection
; }
317 void SetDirection(const CanvasDirection
& aDirection
) {
318 CurrentState().textDirection
= aDirection
;
321 CanvasFontKerning
FontKerning() { return CurrentState().fontKerning
; }
322 void SetFontKerning(const CanvasFontKerning
& aFontKerning
) {
323 if (CurrentState().fontKerning
!= aFontKerning
) {
324 CurrentState().fontKerning
= aFontKerning
;
325 CurrentState().fontGroup
= nullptr;
329 CanvasFontStretch
FontStretch() { return CurrentState().fontStretch
; }
330 void SetFontStretch(const CanvasFontStretch
& aFontStretch
) {
331 if (CurrentState().fontStretch
!= aFontStretch
) {
332 CurrentState().fontStretch
= aFontStretch
;
333 CurrentState().fontGroup
= nullptr;
337 CanvasFontVariantCaps
FontVariantCaps() {
338 return CurrentState().fontVariantCaps
;
340 void SetFontVariantCaps(const CanvasFontVariantCaps
& aFontVariantCaps
) {
341 if (CurrentState().fontVariantCaps
!= aFontVariantCaps
) {
342 CurrentState().fontVariantCaps
= aFontVariantCaps
;
343 CurrentState().fontGroup
= nullptr;
347 CanvasTextRendering
TextRendering() { return CurrentState().textRendering
; }
348 void SetTextRendering(const CanvasTextRendering
& aTextRendering
) {
349 CurrentState().textRendering
= aTextRendering
;
352 void GetLetterSpacing(nsACString
& aLetterSpacing
);
353 void SetLetterSpacing(const nsACString
& aLetterSpacing
);
354 void GetWordSpacing(nsACString
& aWordSpacing
);
355 void SetWordSpacing(const nsACString
& aWordSpacing
);
357 void EnsureCapped() {
359 mPathBuilder
->LineTo(mPathBuilder
->CurrentPoint());
364 void EnsureActivePath() {
365 if (mPathPruned
&& !mPathBuilder
->IsActive()) {
366 mPathBuilder
->MoveTo(mPathBuilder
->CurrentPoint());
372 if (!EnsureWritablePath()) {
376 mPathBuilder
->Close();
380 void MoveTo(double aX
, double aY
) {
381 if (!EnsureWritablePath()) {
385 mozilla::gfx::Point
pos(ToFloat(aX
), ToFloat(aY
));
386 if (!pos
.IsFinite()) {
391 mPathBuilder
->MoveTo(pos
);
394 void LineTo(double aX
, double aY
) {
395 if (!EnsureWritablePath()) {
399 LineTo(mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
402 void QuadraticCurveTo(double aCpx
, double aCpy
, double aX
, double aY
) {
403 if (!EnsureWritablePath()) {
407 mozilla::gfx::Point
cp1(ToFloat(aCpx
), ToFloat(aCpy
));
408 mozilla::gfx::Point
cp2(ToFloat(aX
), ToFloat(aY
));
409 if (!cp1
.IsFinite() || !cp2
.IsFinite()) {
413 if (cp1
== mPathBuilder
->CurrentPoint() && cp1
== cp2
) {
418 mPathBuilder
->QuadraticBezierTo(cp1
, cp2
);
422 void BezierCurveTo(double aCp1x
, double aCp1y
, double aCp2x
, double aCp2y
,
423 double aX
, double aY
) {
424 if (!EnsureWritablePath()) {
428 BezierTo(mozilla::gfx::Point(ToFloat(aCp1x
), ToFloat(aCp1y
)),
429 mozilla::gfx::Point(ToFloat(aCp2x
), ToFloat(aCp2y
)),
430 mozilla::gfx::Point(ToFloat(aX
), ToFloat(aY
)));
433 void ArcTo(double aX1
, double aY1
, double aX2
, double aY2
, double aRadius
,
434 mozilla::ErrorResult
& aError
);
435 void Rect(double aX
, double aY
, double aW
, double aH
);
437 double aX
, double aY
, double aW
, double aH
,
438 const UnrestrictedDoubleOrDOMPointInitOrUnrestrictedDoubleOrDOMPointInitSequence
&
440 ErrorResult
& aError
);
441 void Arc(double aX
, double aY
, double aRadius
, double aStartAngle
,
442 double aEndAngle
, bool aAnticlockwise
, mozilla::ErrorResult
& aError
);
443 void Ellipse(double aX
, double aY
, double aRadiusX
, double aRadiusY
,
444 double aRotation
, double aStartAngle
, double aEndAngle
,
445 bool aAnticlockwise
, ErrorResult
& aError
);
447 void GetFillRule(nsAString
& aFillRule
);
448 void SetFillRule(const nsAString
& aFillRule
);
450 void SetLineDash(const Sequence
<double>& aSegments
,
451 mozilla::ErrorResult
& aRv
);
452 void GetLineDash(nsTArray
<double>& aSegments
) const;
454 void SetLineDashOffset(double aOffset
);
455 double LineDashOffset() const;
457 bool ImageSmoothingEnabled() { return CurrentState().imageSmoothingEnabled
; }
459 void SetImageSmoothingEnabled(bool aImageSmoothingEnabled
) {
460 if (aImageSmoothingEnabled
!= CurrentState().imageSmoothingEnabled
) {
461 CurrentState().imageSmoothingEnabled
= aImageSmoothingEnabled
;
465 void DrawWindow(nsGlobalWindowInner
& aWindow
, double aX
, double aY
, double aW
,
466 double aH
, const nsACString
& aBgColor
, uint32_t aFlags
,
467 nsIPrincipal
& aSubjectPrincipal
,
468 mozilla::ErrorResult
& aError
);
470 // Eventually this should be deprecated. Keeping for now to keep the binding
476 gfx::IntSize
GetSize() const { return gfx::IntSize(mWidth
, mHeight
); }
477 int32_t GetWidth() override
{ return GetSize().width
; }
478 int32_t GetHeight() override
{ return GetSize().height
; }
480 // nsICanvasRenderingContextInternal
482 * Gets the pres shell from either the canvas element or the doc shell
484 PresShell
* GetPresShell() final
;
485 nsresult
Initialize() override
;
486 NS_IMETHOD
SetDimensions(int32_t aWidth
, int32_t aHeight
) override
;
487 NS_IMETHOD
InitializeWithDrawTarget(
488 nsIDocShell
* aShell
, NotNull
<gfx::DrawTarget
*> aTarget
) override
;
490 NS_IMETHOD
GetInputStream(const char* aMimeType
,
491 const nsAString
& aEncoderOptions
,
492 nsIInputStream
** aStream
) override
;
494 already_AddRefed
<mozilla::gfx::SourceSurface
> GetOptimizedSnapshot(
495 mozilla::gfx::DrawTarget
* aTarget
, gfxAlphaType
* aOutAlphaType
) override
;
497 already_AddRefed
<mozilla::gfx::SourceSurface
> GetSurfaceSnapshot(
498 gfxAlphaType
* aOutAlphaType
= nullptr) override
{
499 return GetOptimizedSnapshot(nullptr, aOutAlphaType
);
502 virtual void SetOpaqueValueFromOpaqueAttr(bool aOpaqueAttrValue
) override
;
503 bool GetIsOpaque() override
{ return mOpaque
; }
504 void ResetBitmap(bool aFreeBuffer
);
505 void ResetBitmap() override
{ ResetBitmap(true); }
507 bool UpdateWebRenderCanvasData(nsDisplayListBuilder
* aBuilder
,
508 WebRenderCanvasData
* aCanvasData
) override
;
510 bool InitializeCanvasRenderer(nsDisplayListBuilder
* aBuilder
,
511 CanvasRenderer
* aRenderer
) override
;
512 void MarkContextClean() override
;
513 void MarkContextCleanForFrameCapture() override
{
514 mFrameCaptureState
= FrameCaptureState::CLEAN
;
516 Watchable
<FrameCaptureState
>* GetFrameCaptureState() override
{
517 return &mFrameCaptureState
;
519 // this rect is in canvas device space
520 void Redraw(const mozilla::gfx::Rect
& aR
);
521 NS_IMETHOD
Redraw(const gfxRect
& aR
) override
{
525 NS_IMETHOD
SetContextOptions(JSContext
* aCx
, JS::Handle
<JS::Value
> aOptions
,
526 ErrorResult
& aRvForDictionaryInit
) override
;
529 * An abstract base class to be implemented by callers wanting to be notified
530 * that a refresh has occurred. Callers must ensure an observer is removed
531 * before it is destroyed.
533 virtual void DidRefresh() override
;
535 // this rect is in mTarget's current user space
536 void RedrawUser(const gfxRect
& aR
);
538 // nsISupports interface + CC
539 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
541 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_WRAPPERCACHE_CLASS(
542 CanvasRenderingContext2D
)
544 enum class CanvasMultiGetterType
: uint8_t {
550 enum class Style
: uint8_t { STROKE
= 0, FILL
, MAX
};
552 void LineTo(const mozilla::gfx::Point
& aPoint
) {
553 mFeatureUsage
|= CanvasFeatureUsage::LineTo
;
555 if (!aPoint
.IsFinite()) {
558 if (mPathBuilder
->CurrentPoint() == aPoint
) {
563 mPathBuilder
->LineTo(aPoint
);
567 void BezierTo(const mozilla::gfx::Point
& aCP1
,
568 const mozilla::gfx::Point
& aCP2
,
569 const mozilla::gfx::Point
& aCP3
) {
570 if (!aCP1
.IsFinite() || !aCP2
.IsFinite() || !aCP3
.IsFinite()) {
574 if (aCP1
== mPathBuilder
->CurrentPoint() && aCP1
== aCP2
&& aCP1
== aCP3
) {
579 mPathBuilder
->BezierTo(aCP1
, aCP2
, aCP3
);
583 virtual UniquePtr
<uint8_t[]> GetImageBuffer(
584 int32_t* out_format
, gfx::IntSize
* out_imageSize
) override
;
588 bool IsContextLost() const { return mIsContextLost
; }
589 void OnRemoteCanvasLost();
590 void OnRemoteCanvasRestored();
593 * Update CurrentState().filter with the filter description for
594 * CurrentState().filterChain.
595 * Flushes the PresShell if aFlushIsNeeded is true, so the world can change
596 * if you call this function.
598 MOZ_CAN_RUN_SCRIPT_BOUNDARY
void UpdateFilter(bool aFlushIfNeeded
);
600 CanvasFeatureUsage
FeatureUsage() const { return mFeatureUsage
; }
604 * Helper to parse a value for the letterSpacing or wordSpacing attribute.
605 * If successful, returns the result in aValue, and the whitespace-normalized
606 * value string in aNormalized; if unsuccessful these are left untouched.
608 void ParseSpacing(const nsACString
& aSpacing
, float* aValue
,
609 nsACString
& aNormalized
);
611 already_AddRefed
<const ComputedStyle
> ResolveStyleForProperty(
612 nsCSSPropertyID aProperty
, const nsACString
& aValue
);
614 nsresult
GetImageDataArray(JSContext
* aCx
, int32_t aX
, int32_t aY
,
615 uint32_t aWidth
, uint32_t aHeight
,
616 nsIPrincipal
& aSubjectPrincipal
,
619 void PutImageData_explicit(int32_t aX
, int32_t aY
, ImageData
&,
620 bool aHasDirtyRect
, int32_t aDirtyX
,
621 int32_t aDirtyY
, int32_t aDirtyWidth
,
622 int32_t aDirtyHeight
, ErrorResult
&);
624 bool CopyBufferProvider(layers::PersistentBufferProvider
& aOld
,
625 gfx::DrawTarget
& aTarget
, gfx::IntRect aCopyRect
);
628 * Internal method to complete initialisation, expects mTarget to have been
631 nsresult
Initialize(int32_t aWidth
, int32_t aHeight
);
633 nsresult
InitializeWithTarget(mozilla::gfx::DrawTarget
* aSurface
,
634 int32_t aWidth
, int32_t aHeight
);
637 * The number of living nsCanvasRenderingContexts. When this goes down to
638 * 0, we free the premultiply and unpremultiply tables, if they exist.
640 static MOZ_THREAD_LOCAL(uintptr_t) sNumLivingContexts
;
642 static MOZ_THREAD_LOCAL(mozilla::gfx::DrawTarget
*) sErrorTarget
;
644 void SetTransformInternal(const mozilla::gfx::Matrix
& aTransform
);
646 // Some helpers. Doesn't modify a color on failure.
647 void SetStyleFromUnion(
648 const UTF8StringOrCanvasGradientOrCanvasPattern
& aValue
,
650 void SetStyleFromString(const nsACString
& aStr
, Style aWhichStyle
);
652 void SetStyleFromGradient(CanvasGradient
& aGradient
, Style aWhichStyle
) {
653 CurrentState().SetGradientStyle(aWhichStyle
, &aGradient
);
656 void SetStyleFromPattern(CanvasPattern
& aPattern
, Style aWhichStyle
) {
657 CurrentState().SetPatternStyle(aWhichStyle
, &aPattern
);
660 void GetStyleAsUnion(OwningUTF8StringOrCanvasGradientOrCanvasPattern
& aValue
,
663 static void StyleColorToString(const nscolor
& aColor
, nsACString
& aStr
);
665 // Returns whether a filter was successfully parsed.
666 bool ParseFilter(const nsACString
& aString
,
667 StyleOwnedSlice
<StyleFilter
>& aFilterChain
,
668 ErrorResult
& aError
);
670 // Returns whether the font was successfully updated.
671 bool SetFontInternal(const nsACString
& aFont
, mozilla::ErrorResult
& aError
);
673 // Helper for SetFontInternal in the case where we have no PresShell.
674 bool SetFontInternalDisconnected(const nsACString
& aFont
,
675 mozilla::ErrorResult
& aError
);
677 // Update the resolved values for letterSpacing and wordSpacing, if present,
678 // following a potential change to font-relative dimensions.
679 void UpdateSpacing();
681 // Clears the target and updates mOpaque based on mOpaqueAttrValue and
682 // mContextAttributesHasAlpha.
683 void UpdateIsOpaque();
685 // Shared implementation for Stroke() and Stroke(CanvasPath) methods.
686 void StrokeImpl(const mozilla::gfx::Path
& aPath
);
688 // Shared implementation for Fill() methods.
689 void FillImpl(const mozilla::gfx::Path
& aPath
);
692 * Creates the error target, if it doesn't exist
694 static void EnsureErrorTarget();
696 /* This function ensures there is a writable pathbuilder available
698 bool EnsureWritablePath();
700 // Ensures a path in UserSpace is available.
701 void EnsureUserSpacePath(
702 const CanvasWindingRule
& aWinding
= CanvasWindingRule::Nonzero
);
705 * Needs to be called before updating the transform. This makes a call to
706 * EnsureTarget() so you don't have to.
708 void TransformCurrentPath(const mozilla::gfx::Matrix
& aTransform
);
710 // Report the fillRule has changed.
711 void FillRuleChanged();
714 * Create the backing surfacing, if it doesn't exist. If there is an error
715 * in creating the target then it will put sErrorTarget in place. If there
716 * is in turn an error in creating the sErrorTarget then they would both
717 * be null so IsTargetValid() would still return null.
719 * Returns true on success.
721 bool EnsureTarget(ErrorResult
& aError
,
722 const gfx::Rect
* aCoveredRect
= nullptr,
723 bool aWillClear
= false, bool aSkipTransform
= false);
725 bool EnsureTarget(const gfx::Rect
* aCoveredRect
= nullptr,
726 bool aWillClear
= false, bool aSkipTransform
= false) {
727 IgnoredErrorResult error
;
728 return EnsureTarget(error
, aCoveredRect
, aWillClear
, aSkipTransform
);
731 // Attempt to borrow a new target from an existing buffer provider.
732 bool BorrowTarget(const gfx::IntRect
& aPersistedRect
, bool aNeedsClear
);
734 void RestoreClipsAndTransformToTarget();
736 bool TryAcceleratedTarget(
737 RefPtr
<gfx::DrawTarget
>& aOutDT
,
738 RefPtr
<layers::PersistentBufferProvider
>& aOutProvider
);
740 bool TrySharedTarget(RefPtr
<gfx::DrawTarget
>& aOutDT
,
741 RefPtr
<layers::PersistentBufferProvider
>& aOutProvider
);
743 bool TryBasicTarget(RefPtr
<gfx::DrawTarget
>& aOutDT
,
744 RefPtr
<layers::PersistentBufferProvider
>& aOutProvider
,
745 ErrorResult
& aError
);
747 void RegisterAllocation();
749 void SetInitialState();
751 void SetErrorState();
754 * This method is run at the end of the event-loop spin where
755 * ScheduleStableStateCallback was called.
757 * We use it to unlock resources that need to be locked while drawing.
759 void OnStableState();
764 void ScheduleStableStateCallback();
767 * Disposes an old target and prepares to lazily create a new target.
769 * Parameters are the new dimensions to be used, or if either is negative,
770 * existing dimensions will be left unchanged.
772 void ClearTarget(int32_t aWidth
= -1, int32_t aHeight
= -1);
775 * Returns the target to the buffer provider. i.e. this will queue a frame for
778 void ReturnTarget(bool aForceReset
= false);
781 * Check if the target is valid after calling EnsureTarget.
783 bool IsTargetValid() const {
784 return !!mTarget
&& mTarget
!= sErrorTarget
.get() && !mIsContextLost
;
788 * Returns the surface format this canvas should be allocated using. Takes
789 * into account mOpaque, platform requirements, etc.
791 mozilla::gfx::SurfaceFormat
GetSurfaceFormat() const;
794 * Returns true if we know for sure that the pattern for a given style is
795 * opaque. Usefull to know if we can discard the content below in certain
796 * situations. Optionally checks if the pattern is a color pattern.
798 bool PatternIsOpaque(Style aStyle
, bool* aIsColor
= nullptr) const;
800 SurfaceFromElementResult
CachedSurfaceFromElement(Element
* aElement
);
802 void DrawImage(const CanvasImageSource
& aImgElt
, double aSx
, double aSy
,
803 double aSw
, double aSh
, double aDx
, double aDy
, double aDw
,
804 double aDh
, uint8_t aOptional_argc
,
805 mozilla::ErrorResult
& aError
);
807 void DrawDirectlyToCanvas(const DirectDrawInfo
& aImage
,
808 mozilla::gfx::Rect
* aBounds
,
809 mozilla::gfx::Rect aDest
, mozilla::gfx::Rect aSrc
,
810 gfx::IntSize aImgSize
);
812 nsCString
& GetFont() {
813 /* will initilize the value if not set, else does nothing */
814 GetCurrentFontStyle();
816 return CurrentState().font
;
819 bool UseSoftwareRendering() const;
822 int32_t mWidth
, mHeight
;
824 // This is true when the canvas is valid, but of zero size, this requires
825 // specific behavior on some operations.
828 // The two ways to set the opaqueness of the canvas.
829 // mOpaqueAttrValue: Whether the <canvas> element has the moz-opaque attribute
830 // set. Can change during the lifetime of the context. Non-standard, should
831 // hopefully go away soon.
832 // mContextAttributesHasAlpha: The standard way of setting canvas opaqueness.
833 // Set at context initialization time and never changes.
834 bool mOpaqueAttrValue
;
835 bool mContextAttributesHasAlpha
;
837 // Determines the context's opaqueness. Is computed from mOpaqueAttrValue and
838 // mContextAttributesHasAlpha in UpdateIsOpaque().
841 // This is true when the next time our layer is retrieved we need to
842 // recreate it (i.e. our backing surface changed)
844 // This is needed for drawing in drawAsyncXULElement
847 bool mHasPendingStableStateCallback
;
849 // If mCanvasElement is not provided, then a docshell is
850 nsCOMPtr
<nsIDocShell
> mDocShell
;
852 // This is created lazily so it is necessary to call EnsureTarget before
853 // accessing it. In the event of an error it will be equal to
855 RefPtr
<mozilla::gfx::DrawTarget
> mTarget
;
857 RefPtr
<mozilla::layers::PersistentBufferProvider
> mBufferProvider
;
858 bool mBufferNeedsClear
= false;
860 // Whether we should try to create an accelerated buffer provider.
861 bool mAllowAcceleration
= true;
862 // Whether the application expects to use operations that perform poorly with
864 bool mWillReadFrequently
= false;
865 // Whether to force software rendering
866 bool mForceSoftwareRendering
= false;
867 // Whether or not we have already shutdown.
868 bool mHasShutdown
= false;
869 // Whether or not remote canvas is currently unavailable.
870 bool mIsContextLost
= false;
871 // Whether or not we can restore the context after restoration.
872 bool mAllowContextRestore
= true;
874 bool AddShutdownObserver();
875 void RemoveShutdownObserver();
876 bool AlreadyShutDown() const { return mHasShutdown
; }
879 * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
880 * Redraw is called, reset to false when Render is called.
882 bool mIsEntireFrameInvalid
;
884 * When this is set, the first call to Redraw(gfxRect) should set
885 * mIsEntireFrameInvalid since we expect it will be followed by
886 * many more Redraw calls.
888 bool mPredictManyRedrawCalls
;
891 * Flag to avoid unnecessary surface copies to FrameCaptureListeners in the
892 * case when the canvas is not currently being drawn into and not rendered
893 * but canvas capturing is still ongoing.
895 Watchable
<FrameCaptureState
> mFrameCaptureState
;
898 * We also have a device space pathbuilder. The reason for this is as
899 * follows, when a path is being built, but the transform changes, we
900 * can no longer keep a single path in userspace, considering there's
901 * several 'user spaces' now. We therefore transform the current path
902 * into device space, and add all operations to this path in device
905 * When then finally executing a render, the Azure drawing API expects
906 * the path to be in userspace. We could then set an identity transform
907 * on the DrawTarget and do all drawing in device space. This is
908 * undesirable because it requires transforming patterns, gradients,
909 * clips, etc. into device space and it would not work for stroking.
910 * What we do instead is convert the path back to user space when it is
911 * drawn, and draw it with the current transform. This makes all drawing
914 * There's never both a device space path builder and a user space path
915 * builder present at the same time. There is also never a path and a
916 * path builder present at the same time. When writing proceeds on an
917 * existing path the Path is cleared and a new builder is created.
919 * mPath is always in user-space.
921 RefPtr
<mozilla::gfx::Path
> mPath
;
922 RefPtr
<mozilla::gfx::PathBuilder
> mPathBuilder
;
923 bool mPathPruned
= false;
924 mozilla::gfx::Matrix mPathTransform
;
925 bool mPathTransformDirty
= false;
927 void FlushPathTransform();
930 * Number of times we've invalidated before calling redraw
932 uint32_t mInvalidateCount
;
933 static const uint32_t kCanvasMaxInvalidateCount
= 100;
935 mozilla::intl::Bidi mBidiEngine
;
938 * Returns true if a shadow should be drawn along with a
941 bool NeedToDrawShadow() {
942 const ContextState
& state
= CurrentState();
944 // The spec says we should not draw shadows if the operator is OVER.
945 // If it's over and the alpha value is zero, nothing needs to be drawn.
946 return NS_GET_A(state
.shadowColor
) != 0 &&
947 (state
.shadowBlur
!= 0.f
|| state
.shadowOffset
.x
!= 0.f
||
948 state
.shadowOffset
.y
!= 0.f
);
952 * Returns true if the result of a drawing operation should be
953 * drawn with a filter.
955 bool NeedToApplyFilter() {
956 return EnsureUpdatedFilter().mPrimitives
.Length() > 0;
960 * Calls UpdateFilter if the canvas's WriteOnly state has changed between the
961 * last call to UpdateFilter and now.
963 const gfx::FilterDescription
& EnsureUpdatedFilter() {
964 bool isWriteOnly
= mCanvasElement
&& mCanvasElement
->IsWriteOnly();
965 if (CurrentState().filterSourceGraphicTainted
!= isWriteOnly
) {
966 UpdateFilter(/* aFlushIfNeeded = */ true);
969 MOZ_ASSERT(CurrentState().filterSourceGraphicTainted
== isWriteOnly
);
970 return CurrentState().filter
;
973 bool NeedToCalculateBounds() {
974 return NeedToDrawShadow() || NeedToApplyFilter();
980 gfxFontGroup
* GetCurrentFontStyle();
983 enum class TextDrawOperation
: uint8_t { FILL
, STROKE
, MEASURE
};
986 * Implementation of the fillText, strokeText, and measure functions with
987 * the operation abstracted to a flag.
988 * Returns a TextMetrics object _only_ if the operation is measure;
989 * drawing operations (fill or stroke) always return nullptr.
991 UniquePtr
<TextMetrics
> DrawOrMeasureText(const nsAString
& aText
, float aX
,
993 const Optional
<double>& aMaxWidth
,
994 TextDrawOperation aOp
,
995 ErrorResult
& aError
);
997 // A clip or a transform, recorded and restored in order.
999 explicit ClipState(mozilla::gfx::Path
* aClip
) : clip(aClip
) {}
1001 explicit ClipState(const mozilla::gfx::Matrix
& aTransform
)
1002 : transform(aTransform
) {}
1004 bool IsClip() const { return !!clip
; }
1006 RefPtr
<mozilla::gfx::Path
> clip
;
1007 mozilla::gfx::Matrix transform
;
1010 // state stack handling
1011 class ContextState
{
1014 ContextState(const ContextState
& aOther
);
1017 void SetColorStyle(Style aWhichStyle
, nscolor aColor
);
1018 void SetPatternStyle(Style aWhichStyle
, CanvasPattern
* aPat
);
1019 void SetGradientStyle(Style aWhichStyle
, CanvasGradient
* aGrad
);
1022 * returns true iff the given style is a solid color.
1024 bool StyleIsColor(Style aWhichStyle
) const {
1025 return !(patternStyles
[aWhichStyle
] || gradientStyles
[aWhichStyle
]);
1028 int32_t ShadowBlurRadius() const {
1029 static const gfxFloat GAUSSIAN_SCALE_FACTOR
=
1030 (3 * sqrt(2 * M_PI
) / 4) * 1.5;
1031 return (int32_t)floor(ShadowBlurSigma() * GAUSSIAN_SCALE_FACTOR
+ 0.5);
1034 mozilla::gfx::Float
ShadowBlurSigma() const {
1035 return std::min(SIGMA_MAX
, shadowBlur
/ 2.0f
);
1038 ElementOrArray
<ClipState
> clipsAndTransforms
;
1040 RefPtr
<gfxFontGroup
> fontGroup
;
1041 RefPtr
<nsAtom
> fontLanguage
;
1044 EnumeratedArray
<Style
, RefPtr
<CanvasGradient
>, size_t(Style::MAX
)>
1046 EnumeratedArray
<Style
, RefPtr
<CanvasPattern
>, size_t(Style::MAX
)>
1048 EnumeratedArray
<Style
, nscolor
, size_t(Style::MAX
)> colorStyles
;
1051 CanvasTextAlign textAlign
= CanvasTextAlign::Start
;
1052 CanvasTextBaseline textBaseline
= CanvasTextBaseline::Alphabetic
;
1053 CanvasDirection textDirection
= CanvasDirection::Inherit
;
1054 CanvasFontKerning fontKerning
= CanvasFontKerning::Auto
;
1055 CanvasFontStretch fontStretch
= CanvasFontStretch::Normal
;
1056 CanvasFontVariantCaps fontVariantCaps
= CanvasFontVariantCaps::Normal
;
1057 CanvasTextRendering textRendering
= CanvasTextRendering::Auto
;
1059 gfx::Float letterSpacing
= 0.0f
;
1060 gfx::Float wordSpacing
= 0.0f
;
1061 mozilla::StyleLineHeight fontLineHeight
=
1062 mozilla::StyleLineHeight::Normal();
1063 nsCString letterSpacingStr
;
1064 nsCString wordSpacingStr
;
1066 nscolor shadowColor
= 0;
1068 mozilla::gfx::Matrix transform
;
1069 mozilla::gfx::Point shadowOffset
;
1070 mozilla::gfx::Float lineWidth
= 1.0f
;
1071 mozilla::gfx::Float miterLimit
= 10.0f
;
1072 mozilla::gfx::Float globalAlpha
= 1.0f
;
1073 mozilla::gfx::Float shadowBlur
= 0.0f
;
1075 nsTArray
<mozilla::gfx::Float
> dash
;
1076 mozilla::gfx::Float dashOffset
= 0.0f
;
1078 mozilla::gfx::CompositionOp op
= mozilla::gfx::CompositionOp::OP_OVER
;
1079 mozilla::gfx::FillRule fillRule
= mozilla::gfx::FillRule::FILL_WINDING
;
1080 CanvasLineCap lineCap
= CanvasLineCap::Butt
;
1081 CanvasLineJoin lineJoin
= CanvasLineJoin::Miter
;
1083 nsCString filterString
{"none"};
1084 StyleOwnedSlice
<StyleFilter
> filterChain
;
1085 // RAII object that we obtain when we start to observer SVG filter elements
1086 // for rendering changes. When released we stop observing the SVG elements.
1087 nsCOMPtr
<ISVGFilterObserverList
> autoSVGFiltersObserver
;
1088 mozilla::gfx::FilterDescription filter
;
1089 nsTArray
<RefPtr
<mozilla::gfx::SourceSurface
>> filterAdditionalImages
;
1091 // This keeps track of whether the canvas was "tainted" or not when
1092 // we last used a filter. This is a security measure, whereby the
1093 // canvas is flipped to write-only if a cross-origin image is drawn to it.
1094 // This is to stop bad actors from reading back data they shouldn't have
1097 // This also limits what filters we can apply to the context; in particular
1098 // feDisplacementMap is restricted.
1100 // We keep track of this to ensure that if this gets out of sync with the
1101 // tainted state of the canvas itself, we update our filters accordingly.
1102 bool filterSourceGraphicTainted
= false;
1104 bool imageSmoothingEnabled
= true;
1105 bool fontExplicitLanguage
= false;
1108 AutoTArray
<ContextState
, 3> mStyleStack
;
1110 inline ContextState
& CurrentState() {
1111 return mStyleStack
[mStyleStack
.Length() - 1];
1114 inline const ContextState
& CurrentState() const {
1115 return mStyleStack
[mStyleStack
.Length() - 1];
1118 struct FontStyleCacheKey
{
1119 FontStyleCacheKey() = default;
1120 FontStyleCacheKey(const nsACString
& aFont
, uint64_t aGeneration
)
1121 : mFont(aFont
), mGeneration(aGeneration
) {}
1123 uint64_t mGeneration
= 0;
1126 struct FontStyleData
{
1127 FontStyleCacheKey mKey
;
1128 nsCString mUsedFont
;
1129 RefPtr
<const ComputedStyle
> mStyle
;
1132 class FontStyleCache
1133 : public MruCache
<FontStyleCacheKey
, FontStyleData
, FontStyleCache
> {
1135 static HashNumber
Hash(const FontStyleCacheKey
& aKey
) {
1136 HashNumber hash
= HashString(aKey
.mFont
);
1137 return AddToHash(hash
, aKey
.mGeneration
);
1139 static bool Match(const FontStyleCacheKey
& aKey
,
1140 const FontStyleData
& aVal
) {
1141 return aVal
.mKey
.mGeneration
== aKey
.mGeneration
&&
1142 aVal
.mKey
.mFont
== aKey
.mFont
;
1146 FontStyleCache mFontStyleCache
;
1148 struct ColorStyleCacheEntry
{
1150 Maybe
<nscolor
> mColor
;
1151 bool mWasCurrentColor
= false;
1153 class ColorStyleCache
1154 : public MruCache
<nsACString
, ColorStyleCacheEntry
, ColorStyleCache
> {
1156 static HashNumber
Hash(const nsACString
& aKey
) { return HashString(aKey
); }
1157 static bool Match(const nsACString
& aKey
,
1158 const ColorStyleCacheEntry
& aVal
) {
1159 return aVal
.mKey
== aKey
;
1162 ColorStyleCache mColorStyleCache
;
1164 ColorStyleCacheEntry
ParseColorSlow(const nsACString
&);
1166 mozilla::gfx::PaletteCache mPaletteCache
;
1168 friend class CanvasGeneralPattern
;
1169 friend class AdjustedTarget
;
1170 friend class AdjustedTargetForShadow
;
1171 friend class AdjustedTargetForFilter
;
1174 void GetAppUnitsValues(int32_t* aPerDevPixel
, int32_t* aPerCSSPixel
);
1176 friend struct CanvasBidiProcessor
;
1177 friend class CanvasDrawObserver
;
1178 friend class ImageBitmap
;
1180 void SetWriteOnly();
1182 bool IsWriteOnly() const { return mWriteOnly
; }
1185 bool mClipsNeedConverting
= false;
1187 uint8_t mFillTextCalls
= 0;
1188 // Flags used by the fingerprinting detection heuristic
1189 CanvasFeatureUsage mFeatureUsage
= CanvasFeatureUsage::None
;
1191 virtual void AddZoneWaitingForGC();
1192 virtual void AddAssociatedMemory();
1193 virtual void RemoveAssociatedMemory();
1196 size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D
* aContext
);
1199 } // namespace mozilla
1201 #endif /* CanvasRenderingContext2D_h */