Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / canvas / CanvasRenderingContext2D.h
blob50dbb77686b5caacb486609667aba5bd5ba1e8c8
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/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"
27 #include "gfxUtils.h"
28 #include "nsICanvasRenderingContextInternal.h"
29 #include "nsColor.h"
30 #include "nsRFPService.h"
31 #include "nsIFrame.h"
33 class gfxFontGroup;
34 class nsGlobalWindowInner;
35 class nsXULElement;
37 namespace mozilla {
38 class ErrorResult;
39 class ISVGFilterObserverList;
40 class PresShell;
42 namespace gl {
43 class SourceSurface;
44 } // namespace gl
46 namespace layers {
47 class PersistentBufferProvider;
48 enum class LayersBackend : int8_t;
49 } // namespace layers
51 namespace dom {
52 class
53 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrOffscreenCanvasOrImageBitmapOrVideoFrame;
54 using CanvasImageSource =
55 HTMLImageElementOrSVGImageElementOrHTMLCanvasElementOrHTMLVideoElementOrOffscreenCanvasOrImageBitmapOrVideoFrame;
56 class ImageBitmap;
57 class ImageData;
58 class UTF8StringOrCanvasGradientOrCanvasPattern;
59 class OwningUTF8StringOrCanvasGradientOrCanvasPattern;
60 class TextMetrics;
61 class CanvasGradient;
62 class CanvasPath;
63 class CanvasPattern;
65 extern const mozilla::gfx::Float SIGMA_MAX;
67 template <typename T>
68 class Optional;
70 struct CanvasBidiProcessor;
71 class CanvasDrawObserver;
72 class CanvasShutdownObserver;
74 class DOMMatrix;
75 class DOMMatrixReadOnly;
76 struct DOMMatrix2DInit;
78 /**
79 ** CanvasRenderingContext2D
80 **/
81 class CanvasRenderingContext2D : public nsICanvasRenderingContextInternal,
82 public nsWrapperCache {
83 protected:
84 virtual ~CanvasRenderingContext2D();
86 public:
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()) {
94 return nullptr;
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;
118 void Save();
119 void Restore();
121 void Reset() {
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);
219 void BeginPath();
220 void Fill(const CanvasWindingRule& aWinding);
221 void Fill(const CanvasPath& aPath, const CanvasWindingRule& aWinding);
222 void Stroke();
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,
233 nsIPrincipal&);
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&,
266 ErrorResult&);
267 already_AddRefed<ImageData> GetImageData(JSContext*, int32_t aSx, int32_t aSy,
268 int32_t aSw, int32_t aSh,
269 nsIPrincipal& aSubjectPrincipal,
270 ErrorResult&);
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,
274 ErrorResult&);
276 double LineWidth() { return CurrentState().lineWidth; }
278 void SetLineWidth(double aWidth) {
279 if (aWidth > 0.0) {
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) {
297 if (aMiter > 0.0) {
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() {
358 if (mPathPruned) {
359 mPathBuilder->LineTo(mPathBuilder->CurrentPoint());
360 mPathPruned = false;
364 void EnsureActivePath() {
365 if (mPathPruned && !mPathBuilder->IsActive()) {
366 mPathBuilder->MoveTo(mPathBuilder->CurrentPoint());
367 mPathPruned = false;
371 void ClosePath() {
372 if (!EnsureWritablePath()) {
373 return;
376 mPathBuilder->Close();
377 mPathPruned = false;
380 void MoveTo(double aX, double aY) {
381 if (!EnsureWritablePath()) {
382 return;
385 mozilla::gfx::Point pos(ToFloat(aX), ToFloat(aY));
386 if (!pos.IsFinite()) {
387 return;
390 EnsureCapped();
391 mPathBuilder->MoveTo(pos);
394 void LineTo(double aX, double aY) {
395 if (!EnsureWritablePath()) {
396 return;
399 LineTo(mozilla::gfx::Point(ToFloat(aX), ToFloat(aY)));
402 void QuadraticCurveTo(double aCpx, double aCpy, double aX, double aY) {
403 if (!EnsureWritablePath()) {
404 return;
407 mozilla::gfx::Point cp1(ToFloat(aCpx), ToFloat(aCpy));
408 mozilla::gfx::Point cp2(ToFloat(aX), ToFloat(aY));
409 if (!cp1.IsFinite() || !cp2.IsFinite()) {
410 return;
413 if (cp1 == mPathBuilder->CurrentPoint() && cp1 == cp2) {
414 mPathPruned = true;
415 return;
417 EnsureActivePath();
418 mPathBuilder->QuadraticBezierTo(cp1, cp2);
419 mPathPruned = false;
422 void BezierCurveTo(double aCp1x, double aCp1y, double aCp2x, double aCp2y,
423 double aX, double aY) {
424 if (!EnsureWritablePath()) {
425 return;
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);
436 void RoundRect(
437 double aX, double aY, double aW, double aH,
438 const UnrestrictedDoubleOrDOMPointInitOrUnrestrictedDoubleOrDOMPointInitSequence&
439 aRadii,
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
471 // functional.
472 void Demote();
474 nsresult Redraw();
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 {
522 Redraw(ToRect(aR));
523 return NS_OK;
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 {
545 STRING = 0,
546 PATTERN = 1,
547 GRADIENT = 2
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()) {
556 return;
558 if (mPathBuilder->CurrentPoint() == aPoint) {
559 mPathPruned = true;
560 return;
562 EnsureActivePath();
563 mPathBuilder->LineTo(aPoint);
564 mPathPruned = false;
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()) {
571 return;
574 if (aCP1 == mPathBuilder->CurrentPoint() && aCP1 == aCP2 && aCP1 == aCP3) {
575 mPathPruned = true;
576 return;
578 EnsureActivePath();
579 mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
580 mPathPruned = false;
583 virtual UniquePtr<uint8_t[]> GetImageBuffer(
584 int32_t* out_format, gfx::IntSize* out_imageSize) override;
586 void OnShutdown();
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; }
602 protected:
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,
617 JSObject** aRetval);
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
629 * set
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,
649 Style aWhichStyle);
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,
661 Style aWhichStyle);
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();
762 * Cf. 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
776 * rendering.
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;
821 // Member vars
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.
826 bool mZero;
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().
839 bool mOpaque;
841 // This is true when the next time our layer is retrieved we need to
842 // recreate it (i.e. our backing surface changed)
843 bool mResetLayer;
844 // This is needed for drawing in drawAsyncXULElement
845 bool mIPC;
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
854 // sErrorTarget.
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
863 // acceleration.
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
903 * space.
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
912 * occur correctly.
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
939 * drawing operation.
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);
967 EnsureTarget();
969 MOZ_ASSERT(CurrentState().filterSourceGraphicTainted == isWriteOnly);
970 return CurrentState().filter;
973 bool NeedToCalculateBounds() {
974 return NeedToDrawShadow() || NeedToApplyFilter();
977 // text
979 public:
980 gfxFontGroup* GetCurrentFontStyle();
982 protected:
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,
992 float aY,
993 const Optional<double>& aMaxWidth,
994 TextDrawOperation aOp,
995 ErrorResult& aError);
997 // A clip or a transform, recorded and restored in order.
998 struct ClipState {
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 {
1012 public:
1013 ContextState();
1014 ContextState(const ContextState& aOther);
1015 ~ContextState();
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;
1042 nsFont fontFont;
1044 EnumeratedArray<Style, RefPtr<CanvasGradient>, size_t(Style::MAX)>
1045 gradientStyles;
1046 EnumeratedArray<Style, RefPtr<CanvasPattern>, size_t(Style::MAX)>
1047 patternStyles;
1048 EnumeratedArray<Style, nscolor, size_t(Style::MAX)> colorStyles;
1050 nsCString font;
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
1095 // access to.
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) {}
1122 nsCString mFont;
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> {
1134 public:
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 {
1149 nsCString mKey;
1150 Maybe<nscolor> mColor;
1151 bool mWasCurrentColor = false;
1153 class ColorStyleCache
1154 : public MruCache<nsACString, ColorStyleCacheEntry, ColorStyleCache> {
1155 public:
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;
1173 // other helpers
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; }
1184 bool 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);
1198 } // namespace dom
1199 } // namespace mozilla
1201 #endif /* CanvasRenderingContext2D_h */