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