michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef _CANVASUTILS_H_ michael@0: #define _CANVASUTILS_H_ michael@0: michael@0: #include "mozilla/CheckedInt.h" michael@0: #include "mozilla/dom/ToJSValue.h" michael@0: #include "jsapi.h" michael@0: michael@0: class nsIPrincipal; michael@0: michael@0: namespace mozilla { michael@0: michael@0: namespace gfx { michael@0: class Matrix; michael@0: } michael@0: michael@0: namespace dom { michael@0: class HTMLCanvasElement; michael@0: } michael@0: michael@0: namespace CanvasUtils { michael@0: michael@0: michael@0: // Check that the rectangle [x,y,w,h] is a subrectangle of [0,0,realWidth,realHeight] michael@0: michael@0: inline bool CheckSaneSubrectSize(int32_t x, int32_t y, int32_t w, int32_t h, michael@0: int32_t realWidth, int32_t realHeight) { michael@0: CheckedInt32 checked_xmost = CheckedInt32(x) + w; michael@0: CheckedInt32 checked_ymost = CheckedInt32(y) + h; michael@0: michael@0: return w >= 0 && h >= 0 && x >= 0 && y >= 0 && michael@0: checked_xmost.isValid() && michael@0: checked_xmost.value() <= realWidth && michael@0: checked_ymost.isValid() && michael@0: checked_ymost.value() <= realHeight; michael@0: } michael@0: michael@0: // Flag aCanvasElement as write-only if drawing an image with aPrincipal michael@0: // onto it would make it such. michael@0: michael@0: void DoDrawImageSecurityCheck(dom::HTMLCanvasElement *aCanvasElement, michael@0: nsIPrincipal *aPrincipal, michael@0: bool forceWriteOnly, michael@0: bool CORSUsed); michael@0: michael@0: bool IsImageExtractionAllowed(nsIDocument *aDocument, JSContext *aCx); michael@0: michael@0: // Make a double out of |v|, treating undefined values as 0.0 (for michael@0: // the sake of sparse arrays). Return true iff coercion michael@0: // succeeded. michael@0: bool CoerceDouble(JS::Value v, double* d); michael@0: michael@0: /* Float validation stuff */ michael@0: #define VALIDATE(_f) if (!NS_finite(_f)) return false michael@0: michael@0: inline bool FloatValidate (double f1) { michael@0: VALIDATE(f1); michael@0: return true; michael@0: } michael@0: michael@0: inline bool FloatValidate (double f1, double f2) { michael@0: VALIDATE(f1); VALIDATE(f2); michael@0: return true; michael@0: } michael@0: michael@0: inline bool FloatValidate (double f1, double f2, double f3) { michael@0: VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); michael@0: return true; michael@0: } michael@0: michael@0: inline bool FloatValidate (double f1, double f2, double f3, double f4) { michael@0: VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); michael@0: return true; michael@0: } michael@0: michael@0: inline bool FloatValidate (double f1, double f2, double f3, double f4, double f5) { michael@0: VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); VALIDATE(f5); michael@0: return true; michael@0: } michael@0: michael@0: inline bool FloatValidate (double f1, double f2, double f3, double f4, double f5, double f6) { michael@0: VALIDATE(f1); VALIDATE(f2); VALIDATE(f3); VALIDATE(f4); VALIDATE(f5); VALIDATE(f6); michael@0: return true; michael@0: } michael@0: michael@0: #undef VALIDATE michael@0: michael@0: template michael@0: nsresult michael@0: JSValToDashArray(JSContext* cx, const JS::Value& val, michael@0: FallibleTArray& dashArray); michael@0: michael@0: template michael@0: JS::Value michael@0: DashArrayToJSVal(FallibleTArray& dashArray, michael@0: JSContext* cx, mozilla::ErrorResult& rv); michael@0: michael@0: template michael@0: nsresult michael@0: JSValToDashArray(JSContext* cx, const JS::Value& patternArray, michael@0: FallibleTArray& dashes) michael@0: { michael@0: // The cap is pretty arbitrary. 16k should be enough for michael@0: // anybody... michael@0: static const uint32_t MAX_NUM_DASHES = 1 << 14; michael@0: michael@0: if (!JSVAL_IS_PRIMITIVE(patternArray)) { michael@0: JS::Rooted obj(cx, JSVAL_TO_OBJECT(patternArray)); michael@0: uint32_t length; michael@0: if (!JS_GetArrayLength(cx, obj, &length)) { michael@0: // Not an array-like thing michael@0: return NS_ERROR_INVALID_ARG; michael@0: } else if (length > MAX_NUM_DASHES) { michael@0: // Too many dashes in the pattern michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: michael@0: bool haveNonzeroElement = false; michael@0: for (uint32_t i = 0; i < length; ++i) { michael@0: JS::Rooted elt(cx); michael@0: double d; michael@0: if (!JS_GetElement(cx, obj, i, &elt)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: if (!(CoerceDouble(elt, &d) && michael@0: FloatValidate(d) && michael@0: d >= 0.0)) { michael@0: // Pattern elements must be finite "numbers" >= 0. michael@0: return NS_ERROR_INVALID_ARG; michael@0: } else if (d > 0.0) { michael@0: haveNonzeroElement = true; michael@0: } michael@0: if (!dashes.AppendElement(d)) { michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: michael@0: if (dashes.Length() > 0 && !haveNonzeroElement) { michael@0: // An all-zero pattern makes no sense. michael@0: return NS_ERROR_ILLEGAL_VALUE; michael@0: } michael@0: } else if (!(JSVAL_IS_VOID(patternArray) || JSVAL_IS_NULL(patternArray))) { michael@0: // undefined and null mean "reset to no dash". Any other michael@0: // random garbage is a type error. michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: template michael@0: void michael@0: DashArrayToJSVal(FallibleTArray& dashes, michael@0: JSContext* cx, michael@0: JS::MutableHandle retval, michael@0: mozilla::ErrorResult& rv) michael@0: { michael@0: if (dashes.IsEmpty()) { michael@0: retval.setNull(); michael@0: return; michael@0: } michael@0: JS::Rooted val(cx); michael@0: if (!mozilla::dom::ToJSValue(cx, dashes, retval)) { michael@0: rv.Throw(NS_ERROR_OUT_OF_MEMORY); michael@0: } michael@0: } michael@0: michael@0: } michael@0: } michael@0: michael@0: #endif /* _CANVASUTILS_H_ */