content/canvas/src/CanvasRenderingContext2D.h

branch
TOR_BUG_9701
changeset 11
deefc01c0e14
equal deleted inserted replaced
-1:000000000000 0:1216b88e057d
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/. */
4
5 #ifndef CanvasRenderingContext2D_h
6 #define CanvasRenderingContext2D_h
7
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"
28
29 class nsGlobalWindow;
30 class nsXULElement;
31
32 namespace mozilla {
33 namespace gfx {
34 class SourceSurface;
35 class SurfaceStream;
36 }
37
38 namespace dom {
39 class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
40 class ImageData;
41 class StringOrCanvasGradientOrCanvasPattern;
42 class OwningStringOrCanvasGradientOrCanvasPattern;
43 class TextMetrics;
44
45 extern const mozilla::gfx::Float SIGMA_MAX;
46
47 template<typename T> class Optional;
48
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)
55
56 nsCOMPtr<nsISupports> GetParentObject() { return mParent; }
57
58 JSObject* WrapObject(JSContext* aCx);
59
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);
68
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);
82
83 void LineTo(const gfx::Point& aPoint);
84 void BezierTo(const gfx::Point& aCP1,
85 const gfx::Point& aCP2,
86 const gfx::Point& aCP3);
87
88 mozilla::RefPtr<mozilla::gfx::Path> GetPath(const CanvasWindingRule& winding,
89 const mozilla::RefPtr<mozilla::gfx::DrawTarget>& mTarget) const;
90
91 explicit CanvasPath(nsISupports* aParent);
92 CanvasPath(nsISupports* aParent, RefPtr<gfx::PathBuilder> mPathBuilder);
93 virtual ~CanvasPath() {}
94
95 private:
96
97 nsCOMPtr<nsISupports> mParent;
98 static gfx::Float ToFloat(double aValue) { return gfx::Float(aValue); }
99
100 mutable RefPtr<gfx::Path> mPath;
101 mutable RefPtr<gfx::PathBuilder> mPathBuilder;
102
103 void EnsurePathBuilder() const;
104 };
105
106 struct CanvasBidiProcessor;
107 class CanvasRenderingContext2DUserData;
108
109 /**
110 ** CanvasRenderingContext2D
111 **/
112 class CanvasRenderingContext2D :
113 public nsICanvasRenderingContextInternal,
114 public nsWrapperCache
115 {
116 typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
117 HTMLImageOrCanvasOrVideoElement;
118
119 public:
120 CanvasRenderingContext2D();
121 virtual ~CanvasRenderingContext2D();
122
123 virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
124
125 HTMLCanvasElement* GetCanvas() const
126 {
127 // corresponds to changes to the old bindings made in bug 745025
128 return mCanvasElement->GetOriginalCanvas();
129 }
130
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);
140
141 double GlobalAlpha()
142 {
143 return CurrentState().globalAlpha;
144 }
145
146 // Useful for silencing cast warnings
147 static mozilla::gfx::Float ToFloat(double aValue) { return mozilla::gfx::Float(aValue); }
148
149 void SetGlobalAlpha(double globalAlpha)
150 {
151 if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
152 CurrentState().globalAlpha = ToFloat(globalAlpha);
153 }
154 }
155
156 void GetGlobalCompositeOperation(nsAString& op, mozilla::ErrorResult& error);
157 void SetGlobalCompositeOperation(const nsAString& op,
158 mozilla::ErrorResult& error);
159
160 void GetStrokeStyle(OwningStringOrCanvasGradientOrCanvasPattern& value)
161 {
162 GetStyleAsUnion(value, Style::STROKE);
163 }
164
165 void SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& value)
166 {
167 SetStyleFromUnion(value, Style::STROKE);
168 }
169
170 void GetFillStyle(OwningStringOrCanvasGradientOrCanvasPattern& value)
171 {
172 GetStyleAsUnion(value, Style::FILL);
173 }
174
175 void SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& value)
176 {
177 SetStyleFromUnion(value, Style::FILL);
178 }
179
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);
188
189 double ShadowOffsetX()
190 {
191 return CurrentState().shadowOffset.x;
192 }
193
194 void SetShadowOffsetX(double shadowOffsetX)
195 {
196 CurrentState().shadowOffset.x = ToFloat(shadowOffsetX);
197 }
198
199 double ShadowOffsetY()
200 {
201 return CurrentState().shadowOffset.y;
202 }
203
204 void SetShadowOffsetY(double shadowOffsetY)
205 {
206 CurrentState().shadowOffset.y = ToFloat(shadowOffsetY);
207 }
208
209 double ShadowBlur()
210 {
211 return CurrentState().shadowBlur;
212 }
213
214 void SetShadowBlur(double shadowBlur)
215 {
216 if (shadowBlur >= 0.0) {
217 CurrentState().shadowBlur = ToFloat(shadowBlur);
218 }
219 }
220
221 void GetShadowColor(nsAString& shadowColor)
222 {
223 StyleColorToString(CurrentState().shadowColor, shadowColor);
224 }
225
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);
254
255 void AddHitRegion(const HitRegionOptions& options, mozilla::ErrorResult& error);
256 void RemoveHitRegion(const nsAString& id);
257
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 }
263
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 }
270
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 }
277
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);
293
294 double LineWidth()
295 {
296 return CurrentState().lineWidth;
297 }
298
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);
309
310 double MiterLimit()
311 {
312 return CurrentState().miterLimit;
313 }
314
315 void SetMiterLimit(double miter)
316 {
317 if (miter > 0.0) {
318 CurrentState().miterLimit = ToFloat(miter);
319 }
320 }
321
322 void GetFont(nsAString& font)
323 {
324 font = GetFont();
325 }
326
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);
332
333 void ClosePath()
334 {
335 EnsureWritablePath();
336
337 if (mPathBuilder) {
338 mPathBuilder->Close();
339 } else {
340 mDSPathBuilder->Close();
341 }
342 }
343
344 void MoveTo(double x, double y)
345 {
346 EnsureWritablePath();
347
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 }
355
356 void LineTo(double x, double y)
357 {
358 EnsureWritablePath();
359
360 LineTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
361 }
362
363 void QuadraticCurveTo(double cpx, double cpy, double x, double y)
364 {
365 EnsureWritablePath();
366
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 }
378
379 void BezierCurveTo(double cp1x, double cp1y, double cp2x, double cp2y, double x, double y)
380 {
381 EnsureWritablePath();
382
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 }
387
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);
393
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);
412
413 void SetLineDash(const Sequence<double>& mSegments);
414 void GetLineDash(nsTArray<double>& mSegments) const;
415
416 void SetLineDashOffset(double mOffset);
417 double LineDashOffset() const;
418
419 double MozDashOffset()
420 {
421 return CurrentState().dashOffset;
422 }
423 void SetMozDashOffset(double mozDashOffset);
424
425 void GetMozTextStyle(nsAString& mozTextStyle)
426 {
427 GetFont(mozTextStyle);
428 }
429
430 void SetMozTextStyle(const nsAString& mozTextStyle,
431 mozilla::ErrorResult& error)
432 {
433 SetFont(mozTextStyle, error);
434 }
435
436 bool ImageSmoothingEnabled()
437 {
438 return CurrentState().imageSmoothingEnabled;
439 }
440
441 void SetImageSmoothingEnabled(bool imageSmoothingEnabled)
442 {
443 if (imageSmoothingEnabled != CurrentState().imageSmoothingEnabled) {
444 CurrentState().imageSmoothingEnabled = imageSmoothingEnabled;
445 }
446 }
447
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);
454
455 void Demote();
456
457 nsresult Redraw();
458
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;
466
467 NS_IMETHOD GetInputStream(const char* aMimeType,
468 const char16_t* aEncoderOptions,
469 nsIInputStream **aStream) MOZ_OVERRIDE;
470
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 }
479
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;
493
494 // this rect is in mTarget's current user space
495 void RedrawUser(const gfxRect &r);
496
497 // nsISupports interface + CC
498 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
499
500 NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(CanvasRenderingContext2D)
501
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)
507
508 MOZ_BEGIN_NESTED_ENUM_CLASS(Style, uint8_t)
509 STROKE = 0,
510 FILL,
511 MAX
512 MOZ_END_NESTED_ENUM_CLASS(Style)
513
514 nsINode* GetParentObject()
515 {
516 return mCanvasElement;
517 }
518
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 }
527
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 }
541
542 friend class CanvasRenderingContext2DUserData;
543
544 virtual void GetImageBuffer(uint8_t** aImageBuffer, int32_t* aFormat);
545
546 protected:
547 nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
548 uint32_t aWidth, uint32_t aHeight,
549 JSObject** aRetval);
550
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);
555
556 /**
557 * Internal method to complete initialisation, expects mTarget to have been set
558 */
559 nsresult Initialize(int32_t width, int32_t height);
560
561 nsresult InitializeWithTarget(mozilla::gfx::DrawTarget *surface,
562 int32_t width, int32_t height);
563
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;
569
570 /**
571 * Lookup table used to speed up GetImageData().
572 */
573 static uint8_t (*sUnpremultiplyTable)[256];
574
575 /**
576 * Lookup table used to speed up PutImageData().
577 */
578 static uint8_t (*sPremultiplyTable)[256];
579
580 static mozilla::gfx::DrawTarget* sErrorTarget;
581
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);
586
587 void SetStyleFromGradient(CanvasGradient& gradient, Style whichStyle)
588 {
589 CurrentState().SetGradientStyle(whichStyle, &gradient);
590 }
591
592 void SetStyleFromPattern(CanvasPattern& pattern, Style whichStyle)
593 {
594 CurrentState().SetPatternStyle(whichStyle, &pattern);
595 }
596
597 void GetStyleAsUnion(OwningStringOrCanvasGradientOrCanvasPattern& aValue,
598 Style aWhichStyle);
599
600 // Returns whether a color was successfully parsed.
601 bool ParseColor(const nsAString& aString, nscolor* aColor);
602
603 static void StyleColorToString(const nscolor& aColor, nsAString& aStr);
604
605 /**
606 * Creates the error target, if it doesn't exist
607 */
608 static void EnsureErrorTarget();
609
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();
616
617 // Ensures a path in UserSpace is available.
618 void EnsureUserSpacePath(const CanvasWindingRule& winding = CanvasWindingRule::Nonzero);
619
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();
625
626 // Report the fillRule has changed.
627 void FillRuleChanged();
628
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();
636
637 /*
638 * Disposes an old target and prepares to lazily create a new target.
639 */
640 void ClearTarget();
641
642 /**
643 * Check if the target is valid after calling EnsureTarget.
644 */
645 bool IsTargetValid() { return mTarget != sErrorTarget && mTarget != nullptr; }
646
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;
652
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);
657
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);
662
663 nsString& GetFont()
664 {
665 /* will initilize the value if not set, else does nothing */
666 GetCurrentFontStyle();
667
668 return CurrentState().font;
669 }
670
671 static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
672 static void DemoteOldestContextIfNecessary();
673
674 static void AddDemotableContext(CanvasRenderingContext2D* context);
675 static void RemoveDemotableContext(CanvasRenderingContext2D* context);
676
677 // Do not use GL
678 bool mForceSoftware;
679
680 // Member vars
681 int32_t mWidth, mHeight;
682
683 // This is true when the canvas is valid, but of zero size, this requires
684 // specific behavior on some operations.
685 bool mZero;
686
687 bool mOpaque;
688
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;
694
695 nsTArray<CanvasRenderingContext2DUserData*> mUserDatas;
696
697 // If mCanvasElement is not provided, then a docshell is
698 nsCOMPtr<nsIDocShell> mDocShell;
699
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;
704
705 RefPtr<gfx::SurfaceStream> mStream;
706
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;
718
719 // This is stored after GetThebesSurface has been called once to avoid
720 // excessive ThebesSurface initialization overhead.
721 nsRefPtr<gfxASurface> mThebesSurface;
722
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;
752
753 /**
754 * Number of times we've invalidated before calling redraw
755 */
756 uint32_t mInvalidateCount;
757 static const uint32_t kCanvasMaxInvalidateCount = 100;
758
759 /**
760 * State information for hit regions
761 */
762
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 }
773
774 nsRefPtr<Element> mElement;
775 };
776
777 #ifdef ACCESSIBILITY
778 static PLDHashOperator RemoveHitRegionProperty(RegionInfo* aEntry, void* aData);
779 #endif
780 nsTHashtable<RegionInfo> mHitRegionsOptions;
781
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();
789
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 }
795
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 }
802
803 return CurrentState().op;
804 }
805
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 }
818
819 // text
820
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)
831
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)
840
841 MOZ_BEGIN_NESTED_ENUM_CLASS(TextDrawOperation, uint8_t)
842 FILL,
843 STROKE,
844 MEASURE
845 MOZ_END_NESTED_ENUM_CLASS(TextDrawOperation)
846
847 protected:
848 gfxFontGroup *GetCurrentFontStyle();
849
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);
860
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 { }
877
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 { }
901
902 void SetColorStyle(Style whichStyle, nscolor color)
903 {
904 colorStyles[whichStyle] = color;
905 gradientStyles[whichStyle] = nullptr;
906 patternStyles[whichStyle] = nullptr;
907 }
908
909 void SetPatternStyle(Style whichStyle, CanvasPattern* pat)
910 {
911 gradientStyles[whichStyle] = nullptr;
912 patternStyles[whichStyle] = pat;
913 }
914
915 void SetGradientStyle(Style whichStyle, CanvasGradient* grad)
916 {
917 gradientStyles[whichStyle] = grad;
918 patternStyles[whichStyle] = nullptr;
919 }
920
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 }
928
929
930 std::vector<mozilla::RefPtr<mozilla::gfx::Path> > clipsPushed;
931
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;
936
937 nsString font;
938 TextAlign textAlign;
939 TextBaseline textBaseline;
940
941 nscolor shadowColor;
942
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;
951
952 mozilla::gfx::CompositionOp op;
953 mozilla::gfx::FillRule fillRule;
954 mozilla::gfx::CapStyle lineCap;
955 mozilla::gfx::JoinStyle lineJoin;
956
957 bool imageSmoothingEnabled;
958 };
959
960 nsAutoTArray<ContextState, 3> mStyleStack;
961
962 inline ContextState& CurrentState() {
963 return mStyleStack[mStyleStack.Length() - 1];
964 }
965
966 inline const ContextState& CurrentState() const {
967 return mStyleStack[mStyleStack.Length() - 1];
968 }
969
970 friend class CanvasGeneralPattern;
971 friend class AdjustedTarget;
972
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;
979
980 nsIPresShell *ps = GetPresShell();
981 nsPresContext *pc;
982
983 if (!ps) goto FINISH;
984 pc = ps->GetPresContext();
985 if (!pc) goto FINISH;
986 devPixel = pc->AppUnitsPerDevPixel();
987 cssPixel = pc->AppUnitsPerCSSPixel();
988
989 FINISH:
990 if (perDevPixel)
991 *perDevPixel = devPixel;
992 if (perCSSPixel)
993 *perCSSPixel = cssPixel;
994 }
995
996 friend struct CanvasBidiProcessor;
997 };
998
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)
1004
1005 }
1006 }
1007
1008 #endif /* CanvasRenderingContext2D_h */

mercurial