1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef _CANVASUTILS_H_
7 #define _CANVASUTILS_H_
8 
9 #include "CanvasRenderingContextHelper.h"
10 #include "mozilla/CheckedInt.h"
11 #include "mozilla/dom/ToJSValue.h"
12 #include "jsapi.h"
13 #include "js/Array.h"  // JS::GetArrayLength
14 #include "mozilla/FloatingPoint.h"
15 
16 class nsIPrincipal;
17 
18 namespace mozilla {
19 
20 namespace dom {
21 class Document;
22 class HTMLCanvasElement;
23 }  // namespace dom
24 
25 namespace CanvasUtils {
26 
27 bool GetCanvasContextType(const nsAString& str,
28                           dom::CanvasContextType* const out_type);
29 
30 // Check that the rectangle [x,y,w,h] is a subrectangle of
31 // [0,0,realWidth,realHeight]
32 
CheckSaneSubrectSize(int32_t x,int32_t y,int32_t w,int32_t h,int32_t realWidth,int32_t realHeight)33 inline bool CheckSaneSubrectSize(int32_t x, int32_t y, int32_t w, int32_t h,
34                                  int32_t realWidth, int32_t realHeight) {
35   CheckedInt32 checked_xmost = CheckedInt32(x) + w;
36   CheckedInt32 checked_ymost = CheckedInt32(y) + h;
37 
38   return w >= 0 && h >= 0 && x >= 0 && y >= 0 && checked_xmost.isValid() &&
39          checked_xmost.value() <= realWidth && checked_ymost.isValid() &&
40          checked_ymost.value() <= realHeight;
41 }
42 
43 // Flag aCanvasElement as write-only if drawing an image with aPrincipal
44 // onto it would make it such.
45 
46 void DoDrawImageSecurityCheck(dom::HTMLCanvasElement* aCanvasElement,
47                               nsIPrincipal* aPrincipal, bool forceWriteOnly,
48                               bool CORSUsed);
49 
50 // Check if the context is chrome or has the permission to drawWindow
51 bool HasDrawWindowPrivilege(JSContext* aCx, JSObject* aObj);
52 
53 // Check site-specific permission and display prompt if appropriate.
54 bool IsImageExtractionAllowed(dom::Document* aDocument, JSContext* aCx,
55                               nsIPrincipal& aPrincipal);
56 
57 // Make a double out of |v|, treating undefined values as 0.0 (for
58 // the sake of sparse arrays).  Return true iff coercion
59 // succeeded.
60 bool CoerceDouble(const JS::Value& v, double* d);
61 
62 /* Float validation stuff */
63 #define VALIDATE(_f) \
64   if (!IsFinite(_f)) return false
65 
FloatValidate(double f1)66 inline bool FloatValidate(double f1) {
67   VALIDATE(f1);
68   return true;
69 }
70 
FloatValidate(double f1,double f2)71 inline bool FloatValidate(double f1, double f2) {
72   VALIDATE(f1);
73   VALIDATE(f2);
74   return true;
75 }
76 
FloatValidate(double f1,double f2,double f3)77 inline bool FloatValidate(double f1, double f2, double f3) {
78   VALIDATE(f1);
79   VALIDATE(f2);
80   VALIDATE(f3);
81   return true;
82 }
83 
FloatValidate(double f1,double f2,double f3,double f4)84 inline bool FloatValidate(double f1, double f2, double f3, double f4) {
85   VALIDATE(f1);
86   VALIDATE(f2);
87   VALIDATE(f3);
88   VALIDATE(f4);
89   return true;
90 }
91 
FloatValidate(double f1,double f2,double f3,double f4,double f5)92 inline bool FloatValidate(double f1, double f2, double f3, double f4,
93                           double f5) {
94   VALIDATE(f1);
95   VALIDATE(f2);
96   VALIDATE(f3);
97   VALIDATE(f4);
98   VALIDATE(f5);
99   return true;
100 }
101 
FloatValidate(double f1,double f2,double f3,double f4,double f5,double f6)102 inline bool FloatValidate(double f1, double f2, double f3, double f4, double f5,
103                           double f6) {
104   VALIDATE(f1);
105   VALIDATE(f2);
106   VALIDATE(f3);
107   VALIDATE(f4);
108   VALIDATE(f5);
109   VALIDATE(f6);
110   return true;
111 }
112 
113 #undef VALIDATE
114 
115 template <typename T>
JSValToDashArray(JSContext * cx,const JS::Value & patternArray,nsTArray<T> & dashes)116 nsresult JSValToDashArray(JSContext* cx, const JS::Value& patternArray,
117                           nsTArray<T>& dashes) {
118   // The cap is pretty arbitrary.  16k should be enough for
119   // anybody...
120   static const uint32_t MAX_NUM_DASHES = 1 << 14;
121 
122   if (!patternArray.isPrimitive()) {
123     JS::Rooted<JSObject*> obj(cx, patternArray.toObjectOrNull());
124     uint32_t length;
125     if (!JS::GetArrayLength(cx, obj, &length)) {
126       // Not an array-like thing
127       return NS_ERROR_INVALID_ARG;
128     } else if (length > MAX_NUM_DASHES) {
129       // Too many dashes in the pattern
130       return NS_ERROR_ILLEGAL_VALUE;
131     }
132 
133     bool haveNonzeroElement = false;
134     for (uint32_t i = 0; i < length; ++i) {
135       JS::Rooted<JS::Value> elt(cx);
136       double d;
137       if (!JS_GetElement(cx, obj, i, &elt)) {
138         return NS_ERROR_FAILURE;
139       }
140       if (!(CoerceDouble(elt, &d) && FloatValidate(d) && d >= 0.0)) {
141         // Pattern elements must be finite "numbers" >= 0.
142         return NS_ERROR_INVALID_ARG;
143       } else if (d > 0.0) {
144         haveNonzeroElement = true;
145       }
146       if (!dashes.AppendElement(d, mozilla::fallible)) {
147         return NS_ERROR_OUT_OF_MEMORY;
148       }
149     }
150 
151     if (dashes.Length() > 0 && !haveNonzeroElement) {
152       // An all-zero pattern makes no sense.
153       return NS_ERROR_ILLEGAL_VALUE;
154     }
155   } else if (!(patternArray.isUndefined() || patternArray.isNull())) {
156     // undefined and null mean "reset to no dash".  Any other
157     // random garbage is a type error.
158     return NS_ERROR_INVALID_ARG;
159   }
160 
161   return NS_OK;
162 }
163 
164 template <typename T>
DashArrayToJSVal(nsTArray<T> & dashes,JSContext * cx,JS::MutableHandle<JS::Value> retval,mozilla::ErrorResult & rv)165 void DashArrayToJSVal(nsTArray<T>& dashes, JSContext* cx,
166                       JS::MutableHandle<JS::Value> retval,
167                       mozilla::ErrorResult& rv) {
168   if (dashes.IsEmpty()) {
169     retval.setNull();
170     return;
171   }
172   JS::Rooted<JS::Value> val(cx);
173   if (!mozilla::dom::ToJSValue(cx, dashes, retval)) {
174     rv.Throw(NS_ERROR_OUT_OF_MEMORY);
175   }
176 }
177 
178 // returns true if write-only mode must used for this principal based on
179 // the incumbent global.
180 bool CheckWriteOnlySecurity(bool aCORSUsed, nsIPrincipal* aPrincipal,
181                             bool aHadCrossOriginRedirects);
182 
183 }  // namespace CanvasUtils
184 }  // namespace mozilla
185 
186 #endif /* _CANVASUTILS_H_ */
187