|
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 */ |