Bug 1702375 [wpt PR 28327] - Update docs to point directly at RuntimeEnabledFeatures...
[gecko.git] / dom / canvas / CanvasRenderingContext2D.h
blobc3e0c3a906b27e12ae4fa25152dc6fe4f6adbfd8
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
8 #include <vector>
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"
22 #include "nsBidi.h"
23 #include "nsColor.h"
25 class gfxFontGroup;
26 class nsGlobalWindowInner;
27 class nsXULElement;
29 namespace mozilla {
30 class ErrorResult;
31 class PresShell;
33 namespace gl {
34 class SourceSurface;
35 } // namespace gl
37 namespace layers {
38 class PersistentBufferProvider;
39 enum class LayersBackend : int8_t;
40 } // namespace layers
42 namespace dom {
43 class
44 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap;
45 typedef HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrImageBitmap
46 CanvasImageSource;
47 class ImageBitmap;
48 class ImageData;
49 class UTF8StringOrCanvasGradientOrCanvasPattern;
50 class OwningUTF8StringOrCanvasGradientOrCanvasPattern;
51 class TextMetrics;
52 class CanvasGradient;
53 class CanvasPath;
54 class CanvasPattern;
56 extern const mozilla::gfx::Float SIGMA_MAX;
58 template <typename T>
59 class Optional;
61 struct CanvasBidiProcessor;
62 class CanvasDrawObserver;
63 class CanvasShutdownObserver;
65 class DOMMatrix;
66 class DOMMatrixReadOnly;
67 struct DOMMatrix2DInit;
69 /**
70 ** CanvasRenderingContext2D
71 **/
72 class CanvasRenderingContext2D final : public nsICanvasRenderingContextInternal,
73 public nsWrapperCache,
74 public BasicRenderingContext2D {
75 virtual ~CanvasRenderingContext2D();
77 public:
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()) {
85 return nullptr;
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;
98 void Save() override;
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;
132 void GetStrokeStyle(
133 OwningUTF8StringOrCanvasGradientOrCanvasPattern& aValue) override {
134 GetStyleAsUnion(aValue, Style::STROKE);
137 void SetStrokeStyle(
138 const UTF8StringOrCanvasGradientOrCanvasPattern& aValue) override {
139 SetStyleFromUnion(aValue, Style::STROKE);
142 void GetFillStyle(
143 OwningUTF8StringOrCanvasGradientOrCanvasPattern& aValue) override {
144 GetStyleAsUnion(aValue, Style::FILL);
147 void SetFillStyle(
148 const UTF8StringOrCanvasGradientOrCanvasPattern& aValue) override {
149 SetStyleFromUnion(aValue, Style::FILL);
152 already_AddRefed<CanvasGradient> CreateLinearGradient(double aX0, double aY0,
153 double aX1,
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,
159 double aCx,
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;
196 void BeginPath();
197 void Fill(const CanvasWindingRule& aWinding);
198 void Fill(const CanvasPath& aPath, const CanvasWindingRule& aWinding);
199 void Stroke();
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,
210 nsIPrincipal&);
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&,
249 ErrorResult&);
250 already_AddRefed<ImageData> GetImageData(JSContext*, int32_t aSx, int32_t aSy,
251 int32_t aSw, int32_t aSh,
252 nsIPrincipal& aSubjectPrincipal,
253 ErrorResult&);
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,
257 ErrorResult&);
259 double LineWidth() override { return CurrentState().lineWidth; }
261 void SetLineWidth(double aWidth) override {
262 if (aWidth > 0.0) {
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 {
275 if (aMiter > 0.0) {
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();
291 if (mPathBuilder) {
292 mPathBuilder->Close();
293 } else {
294 mDSPathBuilder->Close();
298 void MoveTo(double aX, double aY) override {
299 EnsureWritablePath();
301 if (mPathBuilder) {
302 mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
303 } else {
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();
319 if (mPathBuilder) {
320 mPathBuilder->QuadraticBezierTo(
321 mozilla::gfx::Point(ToFloat(aCpx), ToFloat(aCpy)),
322 mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
323 } else {
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
397 // functional.
398 void Demote();
400 nsresult Redraw();
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,
426 Layer* aOldLayer,
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 {
442 Redraw(ToRect(aR));
443 return NS_OK;
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 {
465 STRING = 0,
466 PATTERN = 1,
467 GRADIENT = 2
470 enum class Style : uint8_t { STROKE = 0, FILL, MAX };
472 nsINode* GetParentObject() { return mCanvasElement; }
474 void LineTo(const mozilla::gfx::Point& aPoint) {
475 if (mPathBuilder) {
476 mPathBuilder->LineTo(aPoint);
477 } else {
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) {
485 if (mPathBuilder) {
486 mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
487 } else {
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;
503 void OnShutdown();
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();
512 protected:
513 nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
514 uint32_t aWidth, uint32_t aHeight,
515 nsIPrincipal& aSubjectPrincipal,
516 JSObject** aRetval);
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,
522 ErrorResult&);
524 bool CopyBufferProvider(layers::PersistentBufferProvider& aOld,
525 gfx::DrawTarget& aTarget, gfx::IntRect aCopyRect);
528 * Internal method to complete initialisation, expects mTarget to have been
529 * set
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,
549 Style aWhichStyle);
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,
561 Style aWhichStyle);
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
587 * device space.
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();
639 * Cf. 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
653 * rendering.
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;
694 // Member vars
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.
699 bool mZero;
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().
712 bool mOpaque;
714 // This is true when the next time our layer is retrieved we need to
715 // recreate it (i.e. our backing surface changed)
716 bool mResetLayer;
717 // This is needed for drawing in drawAsyncXULElement
718 bool mIPC;
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
727 // sErrorTarget.
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
761 * space.
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
770 * occur correctly.
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
794 struct RegionInfo {
795 nsString mId;
796 // fallback element for a11y
797 RefPtr<Element> mElement;
798 // Path of the hit region in the 2d context coordinate space (not user
799 // space)
800 RefPtr<gfx::Path> mPath;
803 nsTArray<RegionInfo> mHitRegionsOptions;
805 nsBidi mBidiEngine;
808 * Returns true if a shadow should be drawn along with a
809 * drawing operation.
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) {
836 UpdateFilter();
837 EnsureTarget();
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;
856 // text
858 protected:
859 enum class TextAlign : uint8_t { START, END, LEFT, RIGHT, CENTER };
861 enum class TextBaseline : uint8_t {
862 TOP,
863 HANGING,
864 MIDDLE,
865 ALPHABETIC,
866 IDEOGRAPHIC,
867 BOTTOM
870 enum class TextDrawOperation : uint8_t { FILL, STROKE, MEASURE };
872 protected:
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.
886 struct ClipState {
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
899 class ContextState {
900 public:
901 ContextState();
902 ContextState(const ContextState& aOther);
903 ~ContextState();
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;
930 nsFont fontFont;
932 EnumeratedArray<Style, Style::MAX, RefPtr<CanvasGradient>> gradientStyles;
933 EnumeratedArray<Style, Style::MAX, RefPtr<CanvasPattern>> patternStyles;
934 EnumeratedArray<Style, Style::MAX, nscolor> colorStyles;
936 nsCString font;
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
969 // access to.
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;
997 // other helpers
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; }
1008 bool mWriteOnly;
1009 bool mClipsNeedConverting = false;
1012 size_t BindingJSObjectMallocBytes(CanvasRenderingContext2D* aContext);
1014 } // namespace dom
1015 } // namespace mozilla
1017 #endif /* CanvasRenderingContext2D_h */