Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
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 "mozilla/Attributes.h"
9 #include <vector>
10 #include "nsIDOMCanvasRenderingContext2D.h"
11 #include "nsICanvasRenderingContextInternal.h"
12 #include "mozilla/RefPtr.h"
13 #include "nsColor.h"
14 #include "mozilla/dom/HTMLCanvasElement.h"
15 #include "mozilla/dom/HTMLVideoElement.h"
16 #include "CanvasUtils.h"
17 #include "gfxFont.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/dom/CanvasGradient.h"
20 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
21 #include "mozilla/dom/CanvasPattern.h"
22 #include "mozilla/gfx/Rect.h"
23 #include "mozilla/gfx/2D.h"
24 #include "gfx2DGlue.h"
25 #include "imgIEncoder.h"
26 #include "nsLayoutUtils.h"
27 #include "mozilla/EnumeratedArray.h"
29 class nsGlobalWindow;
30 class nsXULElement;
32 namespace mozilla {
33 namespace gfx {
34 class SourceSurface;
35 class SurfaceStream;
36 }
38 namespace dom {
39 class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
40 class ImageData;
41 class StringOrCanvasGradientOrCanvasPattern;
42 class OwningStringOrCanvasGradientOrCanvasPattern;
43 class TextMetrics;
45 extern const mozilla::gfx::Float SIGMA_MAX;
47 template<typename T> class Optional;
49 class CanvasPath MOZ_FINAL :
50 public nsWrapperCache
51 {
52 public:
53 NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(CanvasPath)
54 NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(CanvasPath)
56 nsCOMPtr<nsISupports> GetParentObject() { return mParent; }
58 JSObject* WrapObject(JSContext* aCx);
60 static already_AddRefed<CanvasPath> Constructor(const GlobalObject& aGlobal,
61 ErrorResult& rv);
62 static already_AddRefed<CanvasPath> Constructor(const GlobalObject& aGlobal,
63 CanvasPath& aCanvasPath,
64 ErrorResult& rv);
65 static already_AddRefed<CanvasPath> Constructor(const GlobalObject& aGlobal,
66 const nsAString& aPathString,
67 ErrorResult& rv);
69 void ClosePath();
70 void MoveTo(double x, double y);
71 void LineTo(double x, double y);
72 void QuadraticCurveTo(double cpx, double cpy, double x, double y);
73 void BezierCurveTo(double cp1x, double cp1y,
74 double cp2x, double cp2y,
75 double x, double y);
76 void ArcTo(double x1, double y1, double x2, double y2, double radius,
77 ErrorResult& error);
78 void Rect(double x, double y, double w, double h);
79 void Arc(double x, double y, double radius,
80 double startAngle, double endAngle, bool anticlockwise,
81 ErrorResult& error);
83 void LineTo(const gfx::Point& aPoint);
84 void BezierTo(const gfx::Point& aCP1,
85 const gfx::Point& aCP2,
86 const gfx::Point& aCP3);
88 mozilla::RefPtr<mozilla::gfx::Path> GetPath(const CanvasWindingRule& winding,
89 const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const;
91 explicit CanvasPath(nsISupports* aParent);
92 CanvasPath(nsISupports* aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
93 virtual ~CanvasPath() {}
95 private:
97 nsCOMPtr<nsISupports> mParent;
98 static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
100 mutable RefPtr<gfx::Path> mPath;
101 mutable RefPtr<gfx::PathBuilder> mPathBuilder;
103 void EnsurePathBuilder() const;
104 };
106 struct CanvasBidiProcessor;
107 class CanvasRenderingContext2DUserData;
109 /**
110 ** CanvasRenderingContext2D
111 **/
112 class CanvasRenderingContext2D :
113 public nsICanvasRenderingContextInternal,
114 public nsWrapperCache
115 {
116 typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
117 HTMLImageOrCanvasOrVideoElement;
119 public:
120 CanvasRenderingContext2D();
121 virtual ~CanvasRenderingContext2D();
123 virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
125 HTMLCanvasElement* GetCanvas() const
126 {
127 // corresponds to changes to the old bindings made in bug 745025
128 return mCanvasElement->GetOriginalCanvas();
129 }
131 void Save();
132 void Restore();
133 void Scale(double x, double y, mozilla::ErrorResult& error);
134 void Rotate(double angle, mozilla::ErrorResult& error);
135 void Translate(double x, double y, mozilla::ErrorResult& error);
136 void Transform(double m11, double m12, double m21, double m22, double dx,
137 double dy, mozilla::ErrorResult& error);
138 void SetTransform(double m11, double m12, double m21, double m22, double dx,
139 double dy, mozilla::ErrorResult& error);
141 double GlobalAlpha()
142 {
143 return CurrentState().globalAlpha;
144 }
146 // Useful for silencing cast warnings
147 static mozilla::gfx::Float ToFloat(double aValue) { return mozilla::gfx::Float(aValue); }
149 void SetGlobalAlpha(double globalAlpha)
150 {
151 if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
152 CurrentState().globalAlpha = ToFloat(globalAlpha);
153 }
154 }
156 void GetGlobalCompositeOperation(nsAString& op, mozilla::ErrorResult& error);
157 void SetGlobalCompositeOperation(const nsAString& op,
158 mozilla::ErrorResult& error);
160 void GetStrokeStyle(OwningStringOrCanvasGradientOrCanvasPattern& value)
161 {
162 GetStyleAsUnion(value, Style::STROKE);
163 }
165 void SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& value)
166 {
167 SetStyleFromUnion(value, Style::STROKE);
168 }
170 void GetFillStyle(OwningStringOrCanvasGradientOrCanvasPattern& value)
171 {
172 GetStyleAsUnion(value, Style::FILL);
173 }
175 void SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& value)
176 {
177 SetStyleFromUnion(value, Style::FILL);
178 }
180 already_AddRefed<CanvasGradient>
181 CreateLinearGradient(double x0, double y0, double x1, double y1);
182 already_AddRefed<CanvasGradient>
183 CreateRadialGradient(double x0, double y0, double r0, double x1, double y1,
184 double r1, ErrorResult& aError);
185 already_AddRefed<CanvasPattern>
186 CreatePattern(const HTMLImageOrCanvasOrVideoElement& element,
187 const nsAString& repeat, ErrorResult& error);
189 double ShadowOffsetX()
190 {
191 return CurrentState().shadowOffset.x;
192 }
194 void SetShadowOffsetX(double shadowOffsetX)
195 {
196 CurrentState().shadowOffset.x = ToFloat(shadowOffsetX);
197 }
199 double ShadowOffsetY()
200 {
201 return CurrentState().shadowOffset.y;
202 }
204 void SetShadowOffsetY(double shadowOffsetY)
205 {
206 CurrentState().shadowOffset.y = ToFloat(shadowOffsetY);
207 }
209 double ShadowBlur()
210 {
211 return CurrentState().shadowBlur;
212 }
214 void SetShadowBlur(double shadowBlur)
215 {
216 if (shadowBlur >= 0.0) {
217 CurrentState().shadowBlur = ToFloat(shadowBlur);
218 }
219 }
221 void GetShadowColor(nsAString& shadowColor)
222 {
223 StyleColorToString(CurrentState().shadowColor, shadowColor);
224 }
226 void SetShadowColor(const nsAString& shadowColor);
227 void ClearRect(double x, double y, double w, double h);
228 void FillRect(double x, double y, double w, double h);
229 void StrokeRect(double x, double y, double w, double h);
230 void BeginPath();
231 void Fill(const CanvasWindingRule& winding);
232 void Fill(const CanvasPath& path, const CanvasWindingRule& winding);
233 void Stroke();
234 void Stroke(const CanvasPath& path);
235 void DrawFocusIfNeeded(mozilla::dom::Element& element);
236 bool DrawCustomFocusRing(mozilla::dom::Element& element);
237 void Clip(const CanvasWindingRule& winding);
238 void Clip(const CanvasPath& path, const CanvasWindingRule& winding);
239 bool IsPointInPath(JSContext* cx, double x, double y,
240 const CanvasWindingRule& winding);
241 bool IsPointInPath(JSContext* cx, const CanvasPath& path, double x, double y,
242 const CanvasWindingRule& winding);
243 bool IsPointInStroke(JSContext* cx, double x, double y);
244 bool IsPointInStroke(JSContext* cx, const CanvasPath& path,
245 double x, double y);
246 void FillText(const nsAString& text, double x, double y,
247 const Optional<double>& maxWidth,
248 mozilla::ErrorResult& error);
249 void StrokeText(const nsAString& text, double x, double y,
250 const Optional<double>& maxWidth,
251 mozilla::ErrorResult& error);
252 TextMetrics*
253 MeasureText(const nsAString& rawText, mozilla::ErrorResult& error);
255 void AddHitRegion(const HitRegionOptions& options, mozilla::ErrorResult& error);
256 void RemoveHitRegion(const nsAString& id);
258 void DrawImage(const HTMLImageOrCanvasOrVideoElement& image,
259 double dx, double dy, mozilla::ErrorResult& error)
260 {
261 DrawImage(image, 0.0, 0.0, 0.0, 0.0, dx, dy, 0.0, 0.0, 0, error);
262 }
264 void DrawImage(const HTMLImageOrCanvasOrVideoElement& image,
265 double dx, double dy, double dw, double dh,
266 mozilla::ErrorResult& error)
267 {
268 DrawImage(image, 0.0, 0.0, 0.0, 0.0, dx, dy, dw, dh, 2, error);
269 }
271 void DrawImage(const HTMLImageOrCanvasOrVideoElement& image,
272 double sx, double sy, double sw, double sh, double dx,
273 double dy, double dw, double dh, mozilla::ErrorResult& error)
274 {
275 DrawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, 6, error);
276 }
278 already_AddRefed<ImageData>
279 CreateImageData(JSContext* cx, double sw, double sh,
280 mozilla::ErrorResult& error);
281 already_AddRefed<ImageData>
282 CreateImageData(JSContext* cx, ImageData& imagedata,
283 mozilla::ErrorResult& error);
284 already_AddRefed<ImageData>
285 GetImageData(JSContext* cx, double sx, double sy, double sw, double sh,
286 mozilla::ErrorResult& error);
287 void PutImageData(ImageData& imageData,
288 double dx, double dy, mozilla::ErrorResult& error);
289 void PutImageData(ImageData& imageData,
290 double dx, double dy, double dirtyX, double dirtyY,
291 double dirtyWidth, double dirtyHeight,
292 mozilla::ErrorResult& error);
294 double LineWidth()
295 {
296 return CurrentState().lineWidth;
297 }
299 void SetLineWidth(double width)
300 {
301 if (width > 0.0) {
302 CurrentState().lineWidth = ToFloat(width);
303 }
304 }
305 void GetLineCap(nsAString& linecap);
306 void SetLineCap(const nsAString& linecap);
307 void GetLineJoin(nsAString& linejoin, mozilla::ErrorResult& error);
308 void SetLineJoin(const nsAString& linejoin);
310 double MiterLimit()
311 {
312 return CurrentState().miterLimit;
313 }
315 void SetMiterLimit(double miter)
316 {
317 if (miter > 0.0) {
318 CurrentState().miterLimit = ToFloat(miter);
319 }
320 }
322 void GetFont(nsAString& font)
323 {
324 font = GetFont();
325 }
327 void SetFont(const nsAString& font, mozilla::ErrorResult& error);
328 void GetTextAlign(nsAString& textAlign);
329 void SetTextAlign(const nsAString& textAlign);
330 void GetTextBaseline(nsAString& textBaseline);
331 void SetTextBaseline(const nsAString& textBaseline);
333 void ClosePath()
334 {
335 EnsureWritablePath();
337 if (mPathBuilder) {
338 mPathBuilder->Close();
339 } else {
340 mDSPathBuilder->Close();
341 }
342 }
344 void MoveTo(double x, double y)
345 {
346 EnsureWritablePath();
348 if (mPathBuilder) {
349 mPathBuilder->MoveTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
350 } else {
351 mDSPathBuilder->MoveTo(mTarget->GetTransform() *
352 mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
353 }
354 }
356 void LineTo(double x, double y)
357 {
358 EnsureWritablePath();
360 LineTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
361 }
363 void QuadraticCurveTo(double cpx, double cpy, double x, double y)
364 {
365 EnsureWritablePath();
367 if (mPathBuilder) {
368 mPathBuilder->QuadraticBezierTo(mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
369 mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
370 } else {
371 mozilla::gfx::Matrix transform = mTarget->GetTransform();
372 mDSPathBuilder->QuadraticBezierTo(transform *
373 mozilla::gfx::Point(ToFloat(cpx), ToFloat(cpy)),
374 transform *
375 mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
376 }
377 }
379 void BezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y)
380 {
381 EnsureWritablePath();
383 BezierTo(mozilla::gfx::Point(ToFloat(cp1x), ToFloat(cp1y)),
384 mozilla::gfx::Point(ToFloat(cp2x), ToFloat(cp2y)),
385 mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
386 }
388 void ArcTo(double x1, double y1, double x2, double y2, double radius,
389 mozilla::ErrorResult& error);
390 void Rect(double x, double y, double w, double h);
391 void Arc(double x, double y, double radius, double startAngle,
392 double endAngle, bool anticlockwise, mozilla::ErrorResult& error);
394 void GetMozCurrentTransform(JSContext* cx,
395 JS::MutableHandle<JSObject*> result,
396 mozilla::ErrorResult& error) const;
397 void SetMozCurrentTransform(JSContext* cx,
398 JS::Handle<JSObject*> currentTransform,
399 mozilla::ErrorResult& error);
400 void GetMozCurrentTransformInverse(JSContext* cx,
401 JS::MutableHandle<JSObject*> result,
402 mozilla::ErrorResult& error) const;
403 void SetMozCurrentTransformInverse(JSContext* cx,
404 JS::Handle<JSObject*> currentTransform,
405 mozilla::ErrorResult& error);
406 void GetFillRule(nsAString& fillRule);
407 void SetFillRule(const nsAString& fillRule);
408 void GetMozDash(JSContext* cx, JS::MutableHandle<JS::Value> retval,
409 mozilla::ErrorResult& error);
410 void SetMozDash(JSContext* cx, const JS::Value& mozDash,
411 mozilla::ErrorResult& error);
413 void SetLineDash(const Sequence<double>& mSegments);
414 void GetLineDash(nsTArray<double>& mSegments) const;
416 void SetLineDashOffset(double mOffset);
417 double LineDashOffset() const;
419 double MozDashOffset()
420 {
421 return CurrentState().dashOffset;
422 }
423 void SetMozDashOffset(double mozDashOffset);
425 void GetMozTextStyle(nsAString& mozTextStyle)
426 {
427 GetFont(mozTextStyle);
428 }
430 void SetMozTextStyle(const nsAString& mozTextStyle,
431 mozilla::ErrorResult& error)
432 {
433 SetFont(mozTextStyle, error);
434 }
436 bool ImageSmoothingEnabled()
437 {
438 return CurrentState().imageSmoothingEnabled;
439 }
441 void SetImageSmoothingEnabled(bool imageSmoothingEnabled)
442 {
443 if (imageSmoothingEnabled != CurrentState().imageSmoothingEnabled) {
444 CurrentState().imageSmoothingEnabled = imageSmoothingEnabled;
445 }
446 }
448 void DrawWindow(nsGlobalWindow& window, double x, double y, double w, double h,
449 const nsAString& bgColor, uint32_t flags,
450 mozilla::ErrorResult& error);
451 void AsyncDrawXULElement(nsXULElement& elem, double x, double y, double w,
452 double h, const nsAString& bgColor, uint32_t flags,
453 mozilla::ErrorResult& error);
455 void Demote();
457 nsresult Redraw();
459 #ifdef DEBUG
460 virtual int32_t GetWidth() const MOZ_OVERRIDE;
461 virtual int32_t GetHeight() const MOZ_OVERRIDE;
462 #endif
463 // nsICanvasRenderingContextInternal
464 NS_IMETHOD SetDimensions(int32_t width, int32_t height) MOZ_OVERRIDE;
465 NS_IMETHOD InitializeWithSurface(nsIDocShell *shell, gfxASurface *surface, int32_t width, int32_t height) MOZ_OVERRIDE;
467 NS_IMETHOD GetInputStream(const char* aMimeType,
468 const char16_t* aEncoderOptions,
469 nsIInputStream **aStream) MOZ_OVERRIDE;
471 mozilla::TemporaryRef<mozilla::gfx::SourceSurface> GetSurfaceSnapshot(bool* aPremultAlpha = nullptr) MOZ_OVERRIDE
472 {
473 EnsureTarget();
474 if (aPremultAlpha) {
475 *aPremultAlpha = true;
476 }
477 return mTarget->Snapshot();
478 }
480 NS_IMETHOD SetIsOpaque(bool isOpaque) MOZ_OVERRIDE;
481 bool GetIsOpaque() MOZ_OVERRIDE { return mOpaque; }
482 NS_IMETHOD Reset() MOZ_OVERRIDE;
483 already_AddRefed<CanvasLayer> GetCanvasLayer(nsDisplayListBuilder* aBuilder,
484 CanvasLayer *aOldLayer,
485 LayerManager *aManager) MOZ_OVERRIDE;
486 virtual bool ShouldForceInactiveLayer(LayerManager *aManager) MOZ_OVERRIDE;
487 void MarkContextClean() MOZ_OVERRIDE;
488 NS_IMETHOD SetIsIPC(bool isIPC) MOZ_OVERRIDE;
489 // this rect is in canvas device space
490 void Redraw(const mozilla::gfx::Rect &r);
491 NS_IMETHOD Redraw(const gfxRect &r) MOZ_OVERRIDE { Redraw(ToRect(r)); return NS_OK; }
492 NS_IMETHOD SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions) MOZ_OVERRIDE;
494 // this rect is in mTarget's current user space
495 void RedrawUser(const gfxRect &r);
497 // nsISupports interface + CC
498 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
500 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CanvasRenderingContext2D)
502 MOZ_BEGIN_NESTED_ENUM_CLASS(CanvasMultiGetterType, uint8_t)
503 STRING = 0,
504 PATTERN = 1,
505 GRADIENT = 2
506 MOZ_END_NESTED_ENUM_CLASS(CanvasMultiGetterType)
508 MOZ_BEGIN_NESTED_ENUM_CLASS(Style, uint8_t)
509 STROKE = 0,
510 FILL,
511 MAX
512 MOZ_END_NESTED_ENUM_CLASS(Style)
514 nsINode* GetParentObject()
515 {
516 return mCanvasElement;
517 }
519 void LineTo(const mozilla::gfx::Point& aPoint)
520 {
521 if (mPathBuilder) {
522 mPathBuilder->LineTo(aPoint);
523 } else {
524 mDSPathBuilder->LineTo(mTarget->GetTransform() * aPoint);
525 }
526 }
528 void BezierTo(const mozilla::gfx::Point& aCP1,
529 const mozilla::gfx::Point& aCP2,
530 const mozilla::gfx::Point& aCP3)
531 {
532 if (mPathBuilder) {
533 mPathBuilder->BezierTo(aCP1, aCP2, aCP3);
534 } else {
535 mozilla::gfx::Matrix transform = mTarget->GetTransform();
536 mDSPathBuilder->BezierTo(transform * aCP1,
537 transform * aCP2,
538 transform * aCP3);
539 }
540 }
542 friend class CanvasRenderingContext2DUserData;
544 virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
546 protected:
547 nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
548 uint32_t aWidth, uint32_t aHeight,
549 JSObject** aRetval);
551 nsresult PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
552 dom::Uint8ClampedArray* aArray,
553 bool hasDirtyRect, int32_t dirtyX, int32_t dirtyY,
554 int32_t dirtyWidth, int32_t dirtyHeight);
556 /**
557 * Internal method to complete initialisation, expects mTarget to have been set
558 */
559 nsresult Initialize(int32_t width, int32_t height);
561 nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
562 int32_t width, int32_t height);
564 /**
565 * The number of living nsCanvasRenderingContexts. When this goes down to
566 * 0, we free the premultiply and unpremultiply tables, if they exist.
567 */
568 static uint32_t sNumLivingContexts;
570 /**
571 * Lookup table used to speed up GetImageData().
572 */
573 static uint8_t (*sUnpremultiplyTable)[256];
575 /**
576 * Lookup table used to speed up PutImageData().
577 */
578 static uint8_t (*sPremultiplyTable)[256];
580 static mozilla::gfx::DrawTarget* sErrorTarget;
582 // Some helpers. Doesn't modify a color on failure.
583 void SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value,
584 Style whichStyle);
585 void SetStyleFromString(const nsAString& str, Style whichStyle);
587 void SetStyleFromGradient(CanvasGradient& gradient, Style whichStyle)
588 {
589 CurrentState().SetGradientStyle(whichStyle, &gradient);
590 }
592 void SetStyleFromPattern(CanvasPattern& pattern, Style whichStyle)
593 {
594 CurrentState().SetPatternStyle(whichStyle, &pattern);
595 }
597 void GetStyleAsUnion(OwningStringOrCanvasGradientOrCanvasPattern& aValue,
598 Style aWhichStyle);
600 // Returns whether a color was successfully parsed.
601 bool ParseColor(const nsAString& aString, nscolor* aColor);
603 static void StyleColorToString(const nscolor& aColor, nsAString& aStr);
605 /**
606 * Creates the error target, if it doesn't exist
607 */
608 static void EnsureErrorTarget();
610 /* This function ensures there is a writable pathbuilder available, this
611 * pathbuilder may be working in user space or in device space or
612 * device space.
613 * After calling this function mPathTransformWillUpdate will be false
614 */
615 void EnsureWritablePath();
617 // Ensures a path in UserSpace is available.
618 void EnsureUserSpacePath(const CanvasWindingRule& winding = CanvasWindingRule::Nonzero);
620 /**
621 * Needs to be called before updating the transform. This makes a call to
622 * EnsureTarget() so you don't have to.
623 */
624 void TransformWillUpdate();
626 // Report the fillRule has changed.
627 void FillRuleChanged();
629 /**
630 * Create the backing surfacing, if it doesn't exist. If there is an error
631 * in creating the target then it will put sErrorTarget in place. If there
632 * is in turn an error in creating the sErrorTarget then they would both
633 * be null so IsTargetValid() would still return null.
634 */
635 void EnsureTarget();
637 /*
638 * Disposes an old target and prepares to lazily create a new target.
639 */
640 void ClearTarget();
642 /**
643 * Check if the target is valid after calling EnsureTarget.
644 */
645 bool IsTargetValid() { return mTarget != sErrorTarget && mTarget != nullptr; }
647 /**
648 * Returns the surface format this canvas should be allocated using. Takes
649 * into account mOpaque, platform requirements, etc.
650 */
651 mozilla::gfx::SurfaceFormat GetSurfaceFormat() const;
653 void DrawImage(const HTMLImageOrCanvasOrVideoElement &imgElt,
654 double sx, double sy, double sw, double sh,
655 double dx, double dy, double dw, double dh,
656 uint8_t optional_argc, mozilla::ErrorResult& error);
658 void DrawDirectlyToCanvas(const nsLayoutUtils::DirectDrawInfo& image,
659 mozilla::gfx::Rect* bounds, double dx, double dy,
660 double dw, double dh, double sx, double sy,
661 double sw, double sh, gfxIntSize imgSize);
663 nsString& GetFont()
664 {
665 /* will initilize the value if not set, else does nothing */
666 GetCurrentFontStyle();
668 return CurrentState().font;
669 }
671 static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
672 static void DemoteOldestContextIfNecessary();
674 static void AddDemotableContext(CanvasRenderingContext2D* context);
675 static void RemoveDemotableContext(CanvasRenderingContext2D* context);
677 // Do not use GL
678 bool mForceSoftware;
680 // Member vars
681 int32_t mWidth, mHeight;
683 // This is true when the canvas is valid, but of zero size, this requires
684 // specific behavior on some operations.
685 bool mZero;
687 bool mOpaque;
689 // This is true when the next time our layer is retrieved we need to
690 // recreate it (i.e. our backing surface changed)
691 bool mResetLayer;
692 // This is needed for drawing in drawAsyncXULElement
693 bool mIPC;
695 nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
697 // If mCanvasElement is not provided, then a docshell is
698 nsCOMPtr<nsIDocShell> mDocShell;
700 // This is created lazily so it is necessary to call EnsureTarget before
701 // accessing it. In the event of an error it will be equal to
702 // sErrorTarget.
703 mozilla::RefPtr<mozilla::gfx::DrawTarget> mTarget;
705 RefPtr<gfx::SurfaceStream> mStream;
707 /**
708 * Flag to avoid duplicate calls to InvalidateFrame. Set to true whenever
709 * Redraw is called, reset to false when Render is called.
710 */
711 bool mIsEntireFrameInvalid;
712 /**
713 * When this is set, the first call to Redraw(gfxRect) should set
714 * mIsEntireFrameInvalid since we expect it will be followed by
715 * many more Redraw calls.
716 */
717 bool mPredictManyRedrawCalls;
719 // This is stored after GetThebesSurface has been called once to avoid
720 // excessive ThebesSurface initialization overhead.
721 nsRefPtr<gfxASurface> mThebesSurface;
723 /**
724 * We also have a device space pathbuilder. The reason for this is as
725 * follows, when a path is being built, but the transform changes, we
726 * can no longer keep a single path in userspace, considering there's
727 * several 'user spaces' now. We therefore transform the current path
728 * into device space, and add all operations to this path in device
729 * space.
730 *
731 * When then finally executing a render, the Azure drawing API expects
732 * the path to be in userspace. We could then set an identity transform
733 * on the DrawTarget and do all drawing in device space. This is
734 * undesirable because it requires transforming patterns, gradients,
735 * clips, etc. into device space and it would not work for stroking.
736 * What we do instead is convert the path back to user space when it is
737 * drawn, and draw it with the current transform. This makes all drawing
738 * occur correctly.
739 *
740 * There's never both a device space path builder and a user space path
741 * builder present at the same time. There is also never a path and a
742 * path builder present at the same time. When writing proceeds on an
743 * existing path the Path is cleared and a new builder is created.
744 *
745 * mPath is always in user-space.
746 */
747 mozilla::RefPtr<mozilla::gfx::Path> mPath;
748 mozilla::RefPtr<mozilla::gfx::PathBuilder> mDSPathBuilder;
749 mozilla::RefPtr<mozilla::gfx::PathBuilder> mPathBuilder;
750 bool mPathTransformWillUpdate;
751 mozilla::gfx::Matrix mPathToDS;
753 /**
754 * Number of times we've invalidated before calling redraw
755 */
756 uint32_t mInvalidateCount;
757 static const uint32_t kCanvasMaxInvalidateCount = 100;
759 /**
760 * State information for hit regions
761 */
763 struct RegionInfo : public nsStringHashKey
764 {
765 RegionInfo(const nsAString& aKey) :
766 nsStringHashKey(&aKey)
767 {
768 }
769 RegionInfo(const nsAString *aKey) :
770 nsStringHashKey(aKey)
771 {
772 }
774 nsRefPtr<Element> mElement;
775 };
777 #ifdef ACCESSIBILITY
778 static PLDHashOperator RemoveHitRegionProperty(RegionInfo* aEntry, void* aData);
779 #endif
780 nsTHashtable<RegionInfo> mHitRegionsOptions;
782 /**
783 * Returns true if a shadow should be drawn along with a
784 * drawing operation.
785 */
786 bool NeedToDrawShadow()
787 {
788 const ContextState& state = CurrentState();
790 // The spec says we should not draw shadows if the operator is OVER.
791 // If it's over and the alpha value is zero, nothing needs to be drawn.
792 return NS_GET_A(state.shadowColor) != 0 &&
793 (state.shadowBlur != 0 || state.shadowOffset.x != 0 || state.shadowOffset.y != 0);
794 }
796 mozilla::gfx::CompositionOp UsedOperation()
797 {
798 if (NeedToDrawShadow()) {
799 // In this case the shadow rendering will use the operator.
800 return mozilla::gfx::CompositionOp::OP_OVER;
801 }
803 return CurrentState().op;
804 }
806 /**
807 * Gets the pres shell from either the canvas element or the doc shell
808 */
809 nsIPresShell *GetPresShell() {
810 if (mCanvasElement) {
811 return mCanvasElement->OwnerDoc()->GetShell();
812 }
813 if (mDocShell) {
814 return mDocShell->GetPresShell();
815 }
816 return nullptr;
817 }
819 // text
821 public: // These enums are public only to accomodate non-C++11 legacy path of
822 // MOZ_FINISH_NESTED_ENUM_CLASS. Can move back to protected as soon
823 // as that legacy path is dropped.
824 MOZ_BEGIN_NESTED_ENUM_CLASS(TextAlign, uint8_t)
825 START,
826 END,
827 LEFT,
828 RIGHT,
829 CENTER
830 MOZ_END_NESTED_ENUM_CLASS(TextAlign)
832 MOZ_BEGIN_NESTED_ENUM_CLASS(TextBaseline, uint8_t)
833 TOP,
834 HANGING,
835 MIDDLE,
836 ALPHABETIC,
837 IDEOGRAPHIC,
838 BOTTOM
839 MOZ_END_NESTED_ENUM_CLASS(TextBaseline)
841 MOZ_BEGIN_NESTED_ENUM_CLASS(TextDrawOperation, uint8_t)
842 FILL,
843 STROKE,
844 MEASURE
845 MOZ_END_NESTED_ENUM_CLASS(TextDrawOperation)
847 protected:
848 gfxFontGroup *GetCurrentFontStyle();
850 /*
851 * Implementation of the fillText, strokeText, and measure functions with
852 * the operation abstracted to a flag.
853 */
854 nsresult DrawOrMeasureText(const nsAString& text,
855 float x,
856 float y,
857 const Optional<double>& maxWidth,
858 TextDrawOperation op,
859 float* aWidth);
861 // state stack handling
862 class ContextState {
863 public:
864 ContextState() : textAlign(TextAlign::START),
865 textBaseline(TextBaseline::ALPHABETIC),
866 lineWidth(1.0f),
867 miterLimit(10.0f),
868 globalAlpha(1.0f),
869 shadowBlur(0.0),
870 dashOffset(0.0f),
871 op(mozilla::gfx::CompositionOp::OP_OVER),
872 fillRule(mozilla::gfx::FillRule::FILL_WINDING),
873 lineCap(mozilla::gfx::CapStyle::BUTT),
874 lineJoin(mozilla::gfx::JoinStyle::MITER_OR_BEVEL),
875 imageSmoothingEnabled(true)
876 { }
878 ContextState(const ContextState& other)
879 : fontGroup(other.fontGroup),
880 gradientStyles(other.gradientStyles),
881 patternStyles(other.patternStyles),
882 colorStyles(other.colorStyles),
883 font(other.font),
884 textAlign(other.textAlign),
885 textBaseline(other.textBaseline),
886 shadowColor(other.shadowColor),
887 transform(other.transform),
888 shadowOffset(other.shadowOffset),
889 lineWidth(other.lineWidth),
890 miterLimit(other.miterLimit),
891 globalAlpha(other.globalAlpha),
892 shadowBlur(other.shadowBlur),
893 dash(other.dash),
894 dashOffset(other.dashOffset),
895 op(other.op),
896 fillRule(other.fillRule),
897 lineCap(other.lineCap),
898 lineJoin(other.lineJoin),
899 imageSmoothingEnabled(other.imageSmoothingEnabled)
900 { }
902 void SetColorStyle(Style whichStyle, nscolor color)
903 {
904 colorStyles[whichStyle] = color;
905 gradientStyles[whichStyle] = nullptr;
906 patternStyles[whichStyle] = nullptr;
907 }
909 void SetPatternStyle(Style whichStyle, CanvasPattern* pat)
910 {
911 gradientStyles[whichStyle] = nullptr;
912 patternStyles[whichStyle] = pat;
913 }
915 void SetGradientStyle(Style whichStyle, CanvasGradient* grad)
916 {
917 gradientStyles[whichStyle] = grad;
918 patternStyles[whichStyle] = nullptr;
919 }
921 /**
922 * returns true iff the given style is a solid color.
923 */
924 bool StyleIsColor(Style whichStyle) const
925 {
926 return !(patternStyles[whichStyle] || gradientStyles[whichStyle]);
927 }
930 std::vector<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed;
932 nsRefPtr<gfxFontGroup> fontGroup;
933 EnumeratedArray<Style, Style::MAX, nsRefPtr<CanvasGradient>> gradientStyles;
934 EnumeratedArray<Style, Style::MAX, nsRefPtr<CanvasPattern>> patternStyles;
935 EnumeratedArray<Style, Style::MAX, nscolor> colorStyles;
937 nsString font;
938 TextAlign textAlign;
939 TextBaseline textBaseline;
941 nscolor shadowColor;
943 mozilla::gfx::Matrix transform;
944 mozilla::gfx::Point shadowOffset;
945 mozilla::gfx::Float lineWidth;
946 mozilla::gfx::Float miterLimit;
947 mozilla::gfx::Float globalAlpha;
948 mozilla::gfx::Float shadowBlur;
949 FallibleTArray<mozilla::gfx::Float> dash;
950 mozilla::gfx::Float dashOffset;
952 mozilla::gfx::CompositionOp op;
953 mozilla::gfx::FillRule fillRule;
954 mozilla::gfx::CapStyle lineCap;
955 mozilla::gfx::JoinStyle lineJoin;
957 bool imageSmoothingEnabled;
958 };
960 nsAutoTArray<ContextState, 3> mStyleStack;
962 inline ContextState& CurrentState() {
963 return mStyleStack[mStyleStack.Length() - 1];
964 }
966 inline const ContextState& CurrentState() const {
967 return mStyleStack[mStyleStack.Length() - 1];
968 }
970 friend class CanvasGeneralPattern;
971 friend class AdjustedTarget;
973 // other helpers
974 void GetAppUnitsValues(int32_t *perDevPixel, int32_t *perCSSPixel)
975 {
976 // If we don't have a canvas element, we just return something generic.
977 int32_t devPixel = 60;
978 int32_t cssPixel = 60;
980 nsIPresShell *ps = GetPresShell();
981 nsPresContext *pc;
983 if (!ps) goto FINISH;
984 pc = ps->GetPresContext();
985 if (!pc) goto FINISH;
986 devPixel = pc->AppUnitsPerDevPixel();
987 cssPixel = pc->AppUnitsPerCSSPixel();
989 FINISH:
990 if (perDevPixel)
991 *perDevPixel = devPixel;
992 if (perCSSPixel)
993 *perCSSPixel = cssPixel;
994 }
996 friend struct CanvasBidiProcessor;
997 };
999 MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::CanvasMultiGetterType)
1000 MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::Style)
1001 MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::TextAlign)
1002 MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::TextBaseline)
1003 MOZ_FINISH_NESTED_ENUM_CLASS(CanvasRenderingContext2D::TextDrawOperation)
1005 }
1006 }
1008 #endif /* CanvasRenderingContext2D_h */