Bug 865998: Implement WebIDL union return values r=bz
authorDavid Zbarsky <dzbarsky@gmail.com>
Fri, 26 Jul 2013 11:25:54 -0700
changeset 140193 889041639eb9
parent 140192 e7045ef73a3d
child 140194 9bdc850e67f6
push id25016
push userryanvm@gmail.com
push date2013-07-27 02:25 +0000
treeherdermozilla-central@fb48c7d58b8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs865998
milestone25.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 865998: Implement WebIDL union return values r=bz
browser/devtools/webconsole/test/Makefile.in
browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js
browser/devtools/webconsole/test/test-bug-595934-canvas.html
browser/devtools/webconsole/test/test-bug-595934-canvas.js
content/canvas/src/CanvasGradient.h
content/canvas/src/CanvasPattern.h
content/canvas/src/CanvasRenderingContext2D.cpp
content/canvas/src/CanvasRenderingContext2D.h
content/html/content/src/HTMLCanvasElement.cpp
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
dom/bindings/parser/WebIDL.py
dom/bindings/test/TestBindingHeader.h
dom/bindings/test/TestCodeGen.webidl
dom/bindings/test/TestExampleGen.webidl
dom/bindings/test/TestJSImplGen.webidl
dom/src/events/Makefile.in
dom/webidl/CanvasRenderingContext2D.webidl
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -181,18 +181,16 @@ MOCHITEST_BROWSER_FILES += \
 	test-bug-595934-css-loader.css \
 	test-bug-595934-css-loader.css^headers^ \
 	test-bug-595934-imagemap.html \
 	test-bug-595934-html.html \
 	test-bug-595934-malformedxml.xhtml \
 	test-bug-595934-svg.xhtml \
 	test-bug-595934-workers.html \
 	test-bug-595934-workers.js \
-	test-bug-595934-canvas.html \
-	test-bug-595934-canvas.js \
 	test-bug-595934-css-parser.html \
 	test-bug-595934-css-parser.css \
 	test-bug-595934-canvas-css.html \
 	test-bug-595934-canvas-css.js \
 	test-bug-595934-malformedxml-external.html \
 	test-bug-595934-malformedxml-external.xml \
 	test-bug-595934-empty-getelementbyid.html \
 	test-bug-595934-empty-getelementbyid.js \
--- a/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_bug_595934_message_categories.js
@@ -41,41 +41,36 @@ const TESTS = [
     matchString: "no element found",
   },
   { // #5
     file: "test-bug-595934-svg.xhtml",
     category: "SVG",
     matchString: "fooBarSVG",
   },
   { // #6
-    file: "test-bug-595934-canvas.html",
-    category: "Canvas",
-    matchString: "strokeStyle",
-  },
-  { // #7
     file: "test-bug-595934-css-parser.html",
     category: "CSS Parser",
     matchString: "foobarCssParser",
   },
-  { // #8
+  { // #7
     file: "test-bug-595934-malformedxml-external.html",
     category: "malformed-xml",
     matchString: "</html>",
   },
-  { // #9
+  { // #8
     file: "test-bug-595934-empty-getelementbyid.html",
     category: "DOM",
     matchString: "getElementById",
   },
-  { // #10
+  { // #9
     file: "test-bug-595934-canvas-css.html",
     category: "CSS Parser",
     matchString: "foobarCanvasCssParser",
   },
-  { // #11
+  { // #10
     file: "test-bug-595934-image.html",
     category: "Image",
     matchString: "corrupt",
   },
 ];
 
 let pos = -1;
 
deleted file mode 100644
--- a/browser/devtools/webconsole/test/test-bug-595934-canvas.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <title>Web Console test for bug 595934 - category: Canvas</title>
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-    <script type="text/javascript"
-      src="test-bug-595934-canvas.js"></script>
-  </head>
-  <body>
-    <p>Web Console test for bug 595934 - category "Canvas".</p>
-    <p><canvas width="200" height="200">Canvas support is required!</canvas></p>
-  </body>
-</html>
deleted file mode 100644
--- a/browser/devtools/webconsole/test/test-bug-595934-canvas.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/
- */
-
-window.addEventListener("DOMContentLoaded", function() {
-  var canvas = document.querySelector("canvas");
-  var context = canvas.getContext("2d");
-  context.strokeStyle = document;
-}, false);
-
--- a/content/canvas/src/CanvasGradient.h
+++ b/content/canvas/src/CanvasGradient.h
@@ -8,27 +8,23 @@
 #include "mozilla/Attributes.h"
 #include "nsTArray.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/gfx/2D.h"
 #include "nsWrapperCache.h"
 
-#define NS_CANVASGRADIENTAZURE_PRIVATE_IID \
-    {0x28425a6a, 0x90e0, 0x4d42, {0x9c, 0x75, 0xff, 0x60, 0x09, 0xb3, 0x10, 0xa8}}
-
 namespace mozilla {
 namespace dom {
 
 class CanvasGradient : public nsISupports,
                        public nsWrapperCache
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASGRADIENTAZURE_PRIVATE_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CanvasGradient)
 
   enum Type
   {
     LINEAR = 0,
     RADIAL
   };
--- a/content/canvas/src/CanvasPattern.h
+++ b/content/canvas/src/CanvasPattern.h
@@ -7,32 +7,29 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/RefPtr.h"
 #include "nsISupports.h"
 #include "nsWrapperCache.h"
 
-#define NS_CANVASPATTERNAZURE_PRIVATE_IID \
-    {0xc9bacc25, 0x28da, 0x421e, {0x9a, 0x4b, 0xbb, 0xd6, 0x93, 0x05, 0x12, 0xbc}}
 class nsIPrincipal;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
 
 class CanvasPattern MOZ_FINAL : public nsISupports,
                                 public nsWrapperCache
 {
 public:
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_CANVASPATTERNAZURE_PRIVATE_IID)
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CanvasPattern)
 
   enum RepeatMode
   {
     REPEAT,
     REPEATX,
     REPEATY,
--- a/content/canvas/src/CanvasRenderingContext2D.cpp
+++ b/content/canvas/src/CanvasRenderingContext2D.cpp
@@ -87,20 +87,21 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsCCUncollectableMarker.h"
 #include "nsWrapperCacheInlines.h"
 #include "nsJSUtils.h"
 #include "XPCQuickStubs.h"
 #include "mozilla/dom/BindingUtils.h"
+#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/HTMLImageElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
-#include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/TextMetrics.h"
+#include "mozilla/dom/UnionTypes.h"
 
 #ifdef USE_SKIA_GPU
 #undef free // apparently defined by some windows header, clashing with a free()
             // method in SkTypes.h
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "GLContextSkia.h"
 #include "SurfaceTypes.h"
@@ -395,39 +396,33 @@ CanvasGradient::AddColorStop(float offse
   GradientStop newStop;
 
   newStop.offset = offset;
   newStop.color = Color::FromABGR(color);
 
   mRawStops.AppendElement(newStop);
 }
 
-NS_DEFINE_STATIC_IID_ACCESSOR(CanvasGradient, NS_CANVASGRADIENTAZURE_PRIVATE_IID)
-
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasGradient)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasGradient)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasGradient, mContext)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasGradient)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(mozilla::dom::CanvasGradient)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-NS_DEFINE_STATIC_IID_ACCESSOR(CanvasPattern, NS_CANVASPATTERNAZURE_PRIVATE_IID)
-
 NS_IMPL_CYCLE_COLLECTING_ADDREF(CanvasPattern)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(CanvasPattern)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(CanvasPattern, mContext)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CanvasPattern)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(mozilla::dom::CanvasPattern)
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 class CanvasRenderingContext2DUserData : public LayerUserData {
 public:
     CanvasRenderingContext2DUserData(CanvasRenderingContext2D *aContext)
     : mContext(aContext)
   {
@@ -643,62 +638,42 @@ CanvasRenderingContext2D::Reset()
   // Since the target changes the backing texture will change, and this will
   // no longer be valid.
   mIsEntireFrameInvalid = false;
   mPredictManyRedrawCalls = false;
 
   return NS_OK;
 }
 
-static void
-WarnAboutUnexpectedStyle(HTMLCanvasElement* canvasElement)
-{
-  nsContentUtils::ReportToConsole(
-    nsIScriptError::warningFlag,
-    "Canvas",
-    canvasElement ? canvasElement->OwnerDoc() : nullptr,
-    nsContentUtils::eDOM_PROPERTIES,
-    "UnexpectedCanvasVariantStyle");
-}
-
 void
 CanvasRenderingContext2D::SetStyleFromString(const nsAString& str,
                                              Style whichStyle)
 {
   MOZ_ASSERT(!str.IsVoid());
 
   nscolor color;
   if (!ParseColor(str, &color)) {
     return;
   }
 
   CurrentState().SetColorStyle(whichStyle, color);
 }
 
-nsISupports*
-CanvasRenderingContext2D::GetStyleAsStringOrInterface(nsAString& aStr,
-                                                      CanvasMultiGetterType& aType,
-                                                      Style aWhichStyle)
+void
+CanvasRenderingContext2D::GetStyleAsUnion(StringOrCanvasGradientOrCanvasPatternReturnValue& aValue,
+                                          Style aWhichStyle)
 {
   const ContextState &state = CurrentState();
-  nsISupports* supports;
   if (state.patternStyles[aWhichStyle]) {
-    aStr.SetIsVoid(true);
-    supports = state.patternStyles[aWhichStyle];
-    aType = CMG_STYLE_PATTERN;
+    aValue.SetAsCanvasPattern() = state.patternStyles[aWhichStyle];
   } else if (state.gradientStyles[aWhichStyle]) {
-    aStr.SetIsVoid(true);
-    supports = state.gradientStyles[aWhichStyle];
-    aType = CMG_STYLE_GRADIENT;
+    aValue.SetAsCanvasGradient() = state.gradientStyles[aWhichStyle];
   } else {
-    StyleColorToString(state.colorStyles[aWhichStyle], aStr);
-    supports = nullptr;
-    aType = CMG_STYLE_STRING;
+    StyleColorToString(state.colorStyles[aWhichStyle], aValue.SetAsString());
   }
-  return supports;
 }
 
 // static
 void
 CanvasRenderingContext2D::StyleColorToString(const nscolor& aColor, nsAString& aStr)
 {
   // We can't reuse the normal CSS color stringification code,
   // because the spec calls for a different algorithm for canvas.
@@ -1344,102 +1319,35 @@ CanvasRenderingContext2D::GetMozCurrentT
   return MatrixToJSObject(cx, ctm, error);
 }
 
 //
 // colors
 //
 
 void
-CanvasRenderingContext2D::SetStyleFromJSValue(JSContext* cx,
-                                              JS::Handle<JS::Value> value,
-                                              Style whichStyle)
+CanvasRenderingContext2D::SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value,
+                                            Style whichStyle)
 {
-  if (value.isString()) {
-    nsDependentJSString strokeStyle;
-    if (strokeStyle.init(cx, value.toString())) {
-      SetStyleFromString(strokeStyle, whichStyle);
-    }
+  if (value.IsString()) {
+    SetStyleFromString(value.GetAsString(), whichStyle);
     return;
   }
 
-  if (value.isObject()) {
-    nsCOMPtr<nsISupports> holder;
-
-    CanvasGradient* gradient;
-    JS::Rooted<JS::Value> rootedVal(cx, value);
-    nsresult rv = xpc_qsUnwrapArg<CanvasGradient>(cx, value, &gradient,
-                                                  static_cast<nsISupports**>(getter_AddRefs(holder)),
-                                                  rootedVal.address());
-    if (NS_SUCCEEDED(rv)) {
-      SetStyleFromGradient(gradient, whichStyle);
-      return;
-    }
-
-    CanvasPattern* pattern;
-    rv = xpc_qsUnwrapArg<CanvasPattern>(cx, value, &pattern,
-                                        static_cast<nsISupports**>(getter_AddRefs(holder)),
-                                        rootedVal.address());
-    if (NS_SUCCEEDED(rv)) {
-      SetStyleFromPattern(pattern, whichStyle);
-      return;
-    }
+  if (value.IsCanvasGradient()) {
+    SetStyleFromGradient(value.GetAsCanvasGradient(), whichStyle);
+    return;
   }
 
-  WarnAboutUnexpectedStyle(mCanvasElement);
-}
-
-static JS::Value
-WrapStyle(JSContext* cx, JSObject* objArg,
-          CanvasRenderingContext2D::CanvasMultiGetterType type,
-          nsAString& str, nsISupports* supports, ErrorResult& error)
-{
-  JS::Rooted<JS::Value> v(cx);
-  bool ok;
-  switch (type) {
-    case CanvasRenderingContext2D::CMG_STYLE_STRING:
-    {
-      ok = xpc::StringToJsval(cx, str, v.address());
-      break;
-    }
-    case CanvasRenderingContext2D::CMG_STYLE_PATTERN:
-    case CanvasRenderingContext2D::CMG_STYLE_GRADIENT:
-    {
-      JS::Rooted<JSObject*> obj(cx, objArg);
-      ok = dom::WrapObject(cx, obj, supports, &v);
-      break;
-    }
-    default:
-      MOZ_CRASH("unexpected CanvasMultiGetterType");
+  if (value.IsCanvasPattern()) {
+    SetStyleFromPattern(value.GetAsCanvasPattern(), whichStyle);
+    return;
   }
-  if (!ok) {
-    error.Throw(NS_ERROR_FAILURE);
-  }
-  return v;
-}
-
-
-JS::Value
-CanvasRenderingContext2D::GetStrokeStyle(JSContext* cx,
-                                         ErrorResult& error)
-{
-  nsString str;
-  CanvasMultiGetterType t;
-  nsISupports* supports = GetStyleAsStringOrInterface(str, t, STYLE_STROKE);
-  return WrapStyle(cx, GetWrapper(), t, str, supports, error);
-}
-
-JS::Value
-CanvasRenderingContext2D::GetFillStyle(JSContext* cx,
-                                       ErrorResult& error)
-{
-  nsString str;
-  CanvasMultiGetterType t;
-  nsISupports* supports = GetStyleAsStringOrInterface(str, t, STYLE_FILL);
-  return WrapStyle(cx, GetWrapper(), t, str, supports, error);
+
+  MOZ_ASSUME_UNREACHABLE("Invalid union value");
 }
 
 void
 CanvasRenderingContext2D::SetFillRule(const nsAString& aString)
 {
   FillRule rule;
 
   if (aString.EqualsLiteral("evenodd"))
--- a/content/canvas/src/CanvasRenderingContext2D.h
+++ b/content/canvas/src/CanvasRenderingContext2D.h
@@ -12,47 +12,49 @@
 #include "mozilla/RefPtr.h"
 #include "nsColor.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "CanvasUtils.h"
 #include "gfxFont.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/ImageData.h"
-#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/dom/CanvasGradient.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/dom/CanvasPattern.h"
 #include "mozilla/gfx/Rect.h"
 
 class nsXULElement;
 
 namespace mozilla {
 namespace gfx {
 class SourceSurface;
 }
 
 namespace dom {
+class HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement;
+class StringOrCanvasGradientOrCanvasPattern;
+class StringOrCanvasGradientOrCanvasPatternReturnValue;
 class TextMetrics;
 
 extern const mozilla::gfx::Float SIGMA_MAX;
 
 template<typename T> class Optional;
 
 struct CanvasBidiProcessor;
 class CanvasRenderingContext2DUserData;
 
 /**
  ** CanvasRenderingContext2D
  **/
 class CanvasRenderingContext2D :
   public nsICanvasRenderingContextInternal,
   public nsWrapperCache
 {
-typedef mozilla::dom::HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
+typedef HTMLImageElementOrHTMLCanvasElementOrHTMLVideoElement
   HTMLImageOrCanvasOrVideoElement;
 
 public:
   CanvasRenderingContext2D();
   virtual ~CanvasRenderingContext2D();
 
   virtual JSObject* WrapObject(JSContext *cx,
                                JS::Handle<JSObject*> scope) MOZ_OVERRIDE;
@@ -86,28 +88,35 @@ public:
     if (globalAlpha >= 0.0 && globalAlpha <= 1.0) {
       CurrentState().globalAlpha = ToFloat(globalAlpha);
     }
   }
 
   void GetGlobalCompositeOperation(nsAString& op, mozilla::ErrorResult& error);
   void SetGlobalCompositeOperation(const nsAString& op,
                                    mozilla::ErrorResult& error);
-  JS::Value GetStrokeStyle(JSContext* cx, mozilla::ErrorResult& error);
 
-  void SetStrokeStyle(JSContext* cx, JS::Handle<JS::Value> value)
+  void GetStrokeStyle(StringOrCanvasGradientOrCanvasPatternReturnValue& value)
   {
-    SetStyleFromJSValue(cx, value, STYLE_STROKE);
+    GetStyleAsUnion(value, STYLE_STROKE);
   }
 
-  JS::Value GetFillStyle(JSContext* cx, mozilla::ErrorResult& error);
+  void SetStrokeStyle(const StringOrCanvasGradientOrCanvasPattern& value)
+  {
+    SetStyleFromUnion(value, STYLE_STROKE);
+  }
 
-  void SetFillStyle(JSContext* cx, JS::Handle<JS::Value> value)
+  void GetFillStyle(StringOrCanvasGradientOrCanvasPatternReturnValue& value)
   {
-    SetStyleFromJSValue(cx, value, STYLE_FILL);
+    GetStyleAsUnion(value, STYLE_FILL);
+  }
+
+  void SetFillStyle(const StringOrCanvasGradientOrCanvasPattern& value)
+  {
+    SetStyleFromUnion(value, STYLE_FILL);
   }
 
   already_AddRefed<CanvasGradient>
     CreateLinearGradient(double x0, double y0, double x1, double y1);
   already_AddRefed<CanvasGradient>
     CreateRadialGradient(double x0, double y0, double r0, double x1, double y1,
                          double r1, ErrorResult& aError);
   already_AddRefed<CanvasPattern>
@@ -157,20 +166,20 @@ public:
   void StrokeRect(double x, double y, double w, double h);
   void BeginPath();
   void Fill(const CanvasWindingRule& winding);
   void Stroke();
   void Clip(const CanvasWindingRule& winding);
   bool IsPointInPath(double x, double y, const CanvasWindingRule& winding);
   bool IsPointInStroke(double x, double y);
   void FillText(const nsAString& text, double x, double y,
-                const mozilla::dom::Optional<double>& maxWidth,
+                const Optional<double>& maxWidth,
                 mozilla::ErrorResult& error);
   void StrokeText(const nsAString& text, double x, double y,
-                  const mozilla::dom::Optional<double>& maxWidth,
+                  const Optional<double>& maxWidth,
                   mozilla::ErrorResult& error);
   TextMetrics*
     MeasureText(const nsAString& rawText, mozilla::ErrorResult& error);
 
   void DrawImage(const HTMLImageOrCanvasOrVideoElement& image,
                  double dx, double dy, mozilla::ErrorResult& error)
   {
     DrawImage(image, 0.0, 0.0, 0.0, 0.0, dx, dy, 0.0, 0.0, 0, error);
@@ -185,28 +194,28 @@ public:
 
   void DrawImage(const HTMLImageOrCanvasOrVideoElement& image,
                  double sx, double sy, double sw, double sh, double dx,
                  double dy, double dw, double dh, mozilla::ErrorResult& error)
   {
     DrawImage(image, sx, sy, sw, sh, dx, dy, dw, dh, 6, error);
   }
 
-  already_AddRefed<mozilla::dom::ImageData>
+  already_AddRefed<ImageData>
     CreateImageData(JSContext* cx, double sw, double sh,
                     mozilla::ErrorResult& error);
-  already_AddRefed<mozilla::dom::ImageData>
-    CreateImageData(JSContext* cx, mozilla::dom::ImageData& imagedata,
+  already_AddRefed<ImageData>
+    CreateImageData(JSContext* cx, ImageData& imagedata,
                     mozilla::ErrorResult& error);
-  already_AddRefed<mozilla::dom::ImageData>
+  already_AddRefed<ImageData>
     GetImageData(JSContext* cx, double sx, double sy, double sw, double sh,
                  mozilla::ErrorResult& error);
-  void PutImageData(mozilla::dom::ImageData& imageData,
+  void PutImageData(ImageData& imageData,
                     double dx, double dy, mozilla::ErrorResult& error);
-  void PutImageData(mozilla::dom::ImageData& imageData,
+  void PutImageData(ImageData& imageData,
                     double dx, double dy, double dirtyX, double dirtyY,
                     double dirtyWidth, double dirtyHeight,
                     mozilla::ErrorResult& error);
 
   double LineWidth()
   {
     return CurrentState().lineWidth;
   }
@@ -266,17 +275,17 @@ public:
       mDSPathBuilder->MoveTo(mTarget->GetTransform() *
                              mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
     }
   }
 
   void LineTo(double x, double y)
   {
     EnsureWritablePath();
-    
+
     LineTo(mozilla::gfx::Point(ToFloat(x), ToFloat(y)));
   }
 
   void QuadraticCurveTo(double cpx, double cpy, double x, double y)
   {
     EnsureWritablePath();
 
     if (mPathBuilder) {
@@ -469,31 +478,32 @@ protected:
   /**
     * Lookup table used to speed up PutImageData().
     */
   static uint8_t (*sPremultiplyTable)[256];
 
   static mozilla::gfx::DrawTarget* sErrorTarget;
 
   // Some helpers.  Doesn't modify a color on failure.
-  void SetStyleFromJSValue(JSContext* cx, JS::Handle<JS::Value> value,
-                           Style whichStyle);
+  void SetStyleFromUnion(const StringOrCanvasGradientOrCanvasPattern& value,
+                         Style whichStyle);
   void SetStyleFromString(const nsAString& str, Style whichStyle);
 
-  void SetStyleFromGradient(CanvasGradient *gradient, Style whichStyle)
+  void SetStyleFromGradient(CanvasGradient& gradient, Style whichStyle)
   {
-    CurrentState().SetGradientStyle(whichStyle, gradient);
+    CurrentState().SetGradientStyle(whichStyle, &gradient);
   }
 
-  void SetStyleFromPattern(CanvasPattern *pattern, Style whichStyle)
+  void SetStyleFromPattern(CanvasPattern& pattern, Style whichStyle)
   {
-    CurrentState().SetPatternStyle(whichStyle, pattern);
+    CurrentState().SetPatternStyle(whichStyle, &pattern);
   }
 
-  nsISupports* GetStyleAsStringOrInterface(nsAString& aStr, CanvasMultiGetterType& aType, Style aWhichStyle);
+  void GetStyleAsUnion(StringOrCanvasGradientOrCanvasPatternReturnValue& aValue,
+                       Style aWhichStyle);
 
   // Returns whether a color was successfully parsed.
   bool ParseColor(const nsAString& aString, nscolor* aColor);
 
   static void StyleColorToString(const nscolor& aColor, nsAString& aStr);
 
   /**
    * Creates the error target, if it doesn't exist
@@ -711,17 +721,17 @@ protected:
 
   /*
     * Implementation of the fillText, strokeText, and measure functions with
     * the operation abstracted to a flag.
     */
   nsresult DrawOrMeasureText(const nsAString& text,
                              float x,
                              float y,
-                             const mozilla::dom::Optional<double>& maxWidth,
+                             const Optional<double>& maxWidth,
                              TextDrawOperation op,
                              float* aWidth);
 
   // state stack handling
   class ContextState {
   public:
     ContextState() : textAlign(TEXT_ALIGN_START),
                      textBaseline(TEXT_BASELINE_ALPHABETIC),
--- a/content/html/content/src/HTMLCanvasElement.cpp
+++ b/content/html/content/src/HTMLCanvasElement.cpp
@@ -8,16 +8,17 @@
 #include "BasicLayers.h"
 #include "imgIEncoder.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "mozilla/Base64.h"
 #include "mozilla/CheckedInt.h"
 #include "mozilla/dom/CanvasRenderingContext2D.h"
 #include "mozilla/dom/HTMLCanvasElementBinding.h"
+#include "mozilla/dom/UnionTypes.h"
 #include "mozilla/gfx/Rect.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "nsAsyncDOMEvent.h"
 #include "nsAttrValueInlines.h"
 #include "nsContentUtils.h"
 #include "nsDisplayList.h"
 #include "nsDOMFile.h"
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -154,18 +154,17 @@ DOMInterfaces = {
 
 'CameraManager': {
     'nativeType': 'nsDOMCameraManager',
     'headerFile': 'DOMCameraManager.h'
 },
 
 'CanvasRenderingContext2D': {
     'implicitJSContext': [
-        'createImageData', 'getImageData', 'strokeStyle',
-        'fillStyle', 'mozDash'
+        'createImageData', 'getImageData', 'mozDash'
     ],
     'resultNotAddRefed': [ 'canvas', 'measureText' ],
     'binaryNames': {
         'mozImageSmoothingEnabled': 'imageSmoothingEnabled',
         'mozFillRule': 'fillRule'
     }
 },
 
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -4,16 +4,17 @@
 
 # Common codegen classes.
 
 import operator
 import os
 import re
 import string
 import math
+import itertools
 
 from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType
 from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor
 
 AUTOGENERATED_WARNING_COMMENT = \
     "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
 ADDPROPERTY_HOOK_NAME = '_addProperty'
 FINALIZE_HOOK_NAME = '_finalize'
@@ -730,32 +731,37 @@ def UnionTypes(descriptors, dictionaries
     """
 
     # Now find all the things we'll need as arguments and return values because
     # we need to wrap or unwrap them.
     headers = set()
     implheaders = set(["UnionTypes.h"])
     declarations = set()
     unionStructs = dict()
+    unionReturnValues = dict()
 
     def addInfoForType(t, descriptor=None, dictionary=None):
         """
         Add info for the given type.  descriptor and dictionary, if passed, are
         used to figure out what to do with interface types.
         """
         assert not descriptor or not dictionary
         t = t.unroll()
         if not t.isUnion():
             return
         name = str(t)
         if not name in unionStructs:
             providers = getRelevantProviders(descriptor, dictionary,
                                              config)
             # FIXME: Unions are broken in workers.  See bug 809899.
             unionStructs[name] = CGUnionStruct(t, providers[0])
+            # Unions cannot contain JSObject*.
+            if not any(member.isObject() or member.isSpiderMonkeyInterface() for member in t.flatMemberTypes):
+                unionReturnValues[name] = CGUnionReturnValueStruct(t, providers[0])
+
             for f in t.flatMemberTypes:
                 f = f.unroll()
                 if f.isInterface():
                     if f.isSpiderMonkeyInterface():
                         headers.add("jsfriendapi.h")
                         headers.add("mozilla/dom/TypedArray.h")
                     else:
                         for p in providers:
@@ -767,17 +773,18 @@ def UnionTypes(descriptors, dictionaries
                             implheaders.add(typeDesc.headerFile)
                 elif f.isDictionary():
                     declarations.add((f.inner.identifier.name, True))
                     implheaders.add(CGHeaders.getDeclarationFilename(f.inner))
 
     callForEachType(descriptors, dictionaries, callbacks, addInfoForType)
 
     return (headers, implheaders, declarations,
-            CGList(SortedDictValues(unionStructs), "\n"))
+            CGList(itertools.chain(SortedDictValues(unionStructs),
+                                   SortedDictValues(unionReturnValues)), "\n"))
 
 def UnionConversions(descriptors, dictionaries, callbacks, config):
     """
     Returns a CGThing to declare all union argument conversion helper structs.
     """
     # Now find all the things we'll need as arguments because we
     # need to unwrap them.
     headers = set()
@@ -2064,17 +2071,17 @@ def GetAccessCheck(descriptor, object):
 def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""):
     """
     properties is a PropertyArrays instance
     """
     failureReturn = "return"
     if len(failureReturnValue) > 0:
         failureReturn += " " + failureReturnValue
     failureReturn += ";"
-        
+
     defineUnforgeables = ("if (!DefineUnforgeableAttributes(aCx, " + obj + ", %s)) {\n"
                           "  " + failureReturn + "\n"
                           "}")
 
     unforgeableAttrs = properties.unforgeableAttrs
     unforgeables = []
     if unforgeableAttrs.hasNonChromeOnly():
         unforgeables.append(CGGeneric(defineUnforgeables %
@@ -2483,16 +2490,17 @@ def getJSToNativeConversionInfo(type, de
                                 treatUndefinedAs="Default",
                                 isEnforceRange=False,
                                 isClamp=False,
                                 isNullOrUndefined=False,
                                 exceptionCode=None,
                                 lenientFloatCode=None,
                                 allowTreatNonCallableAsNull=False,
                                 isCallbackReturnValue=False,
+                                isInUnionReturnValue=False,
                                 sourceDescription="value"):
     """
     Get a template for converting a JS value to a native object based on the
     given type and descriptor.  If failureCode is given, then we're actually
     testing whether we can convert the argument to the desired type.  That
     means that failures to convert due to the JS value being the wrong type of
     value need to use failureCode instead of throwing exceptions.  Failures to
     convert that are due to JS exceptions (from toString or valueOf methods) or
@@ -3031,23 +3039,26 @@ for (uint32_t i = 0; i < length; ++i) {
 
         # Allow null pointers for nullable types and old-binding classes, and
         # use an nsRefPtr or raw pointer for callback return values to make
         # them easier to return.
         argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or
                         isCallbackReturnValue)
 
         # Sequences and non-worker callbacks have to hold a strong ref to the
-        # thing being passed down.  Also, callback return values always end up
+        # thing being passed down.  Union return values must hold a strong ref
+        # because they may be returning an addrefed pointer.
+        # Also, callback return values always end up
         # addrefing anyway, so there is no point trying to avoid it here and it
         # makes other things simpler since we can assume the return value is a
         # strong ref.
         forceOwningType = ((descriptor.interface.isCallback() and
                             not descriptor.workers) or
                            isMember or
+                           isInUnionReturnValue or
                            isCallbackReturnValue)
 
         typeName = descriptor.nativeType
         typePtr = typeName + "*"
 
         # Compute a few things:
         #  - declType is the type we want to return as the first element of our
         #    tuple.
@@ -3254,16 +3265,18 @@ for (uint32_t i = 0; i < length; ++i) {
                 "  FakeDependentString str;\n"
                 "%s\n"
                 "  ${declName} = str;\n"
                 "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
                 declType=declType, dealWithOptional=isOptional)
 
         if isOptional:
             declType = "Optional<nsAString>"
+        elif isInUnionReturnValue:
+            declType = "nsString"
         else:
             declType = "NonNull<nsAString>"
 
         # No need to deal with optional here; we handled it already
         return JSToNativeConversionInfo(
             "%s\n"
             "${declName} = &${holderName};" %
             getConversionCode("${holderName}"),
@@ -4095,35 +4108,31 @@ if (!returnArray) {
             toValue = "JS::ObjectValue(*%s)"
             if type.isSpiderMonkeyInterface():
                 wrapType = "nonDOMObject"
             else:
                 wrapType = "object"
         # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
         return (setValue(toValue % result, wrapType), False)
 
-    if type.isUnion():
-        if type.nullable():
-            prefix = "%s->"
-        else:
-            prefix = "%s."
-        return (wrapAndSetPtr((prefix % result) +
-                              "ToJSVal(cx, ${obj}, ${jsvalHandle})"), False)
-
-    if not (type.isPrimitive() or type.isDictionary() or type.isDate()):
+    if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or type.isDate()):
         raise TypeError("Need to learn to wrap %s" % type)
 
     if type.nullable():
         (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
                                                          "%s.Value()" % result, successCode,
                                                          isCreator, exceptionCode)
         return ("if (%s.IsNull()) {\n" % result +
                 CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
                 "}\n" + recTemplate, recInfal)
 
+    if type.isUnion():
+        return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result),
+                False)
+
     if type.isDictionary():
         return (wrapAndSetPtr("%s.ToObject(cx, ${obj}, ${jsvalHandle})" % result),
                 False)
 
     if type.isDate():
         return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result),
                 False)
 
@@ -4317,17 +4326,20 @@ def getRetvalDeclarationForType(returnTy
             else:
                 result = CGTemplatedType("RootedDictionary", result)
             resultArgs = "cx"
         elif nullable:
             result = CGTemplatedType("Nullable", result)
             resultArgs = None
         return result, True, None, resultArgs
     if returnType.isUnion():
-        raise TypeError("Need to sort out ownership model for union retvals");
+        result = CGGeneric(returnType.unroll().name + "ReturnValue")
+        if returnType.nullable():
+            result = CGTemplatedType("Nullable", result)
+        return result, True, None, None
     if returnType.isDate():
         result = CGGeneric("Date")
         if returnType.nullable():
             result = CGTemplatedType("Nullable", result)
         return result, False, None, None
     raise TypeError("Don't know how to declare return value for %s" %
                     returnType)
 
@@ -4425,17 +4437,17 @@ class CGCallGenerator(CGThing):
             if not resultOutParam:
                 call = CGWrapper(call, pre="result = ")
 
         call = CGWrapper(call)
         self.cgRoot.append(call)
 
         if isFallible:
             self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
-            self.cgRoot.append(CGGeneric("rv.WouldReportJSException();"));
+            self.cgRoot.append(CGGeneric("rv.WouldReportJSException();"))
             self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
             self.cgRoot.append(CGIndenter(errorReport))
             self.cgRoot.append(CGGeneric("}"))
 
     def define(self):
         return self.cgRoot.define()
 
 class MethodNotCreatorError(Exception):
@@ -5834,17 +5846,17 @@ def getUnionAccessorSignatureType(type, 
     if not type.isPrimitive():
         raise TypeError("Need native type for argument type '%s'" % str(type))
 
     typeName = CGGeneric(builtinNames[type.tag()])
     if type.nullable():
         typeName = CGTemplatedType("Nullable", typeName, isReference=True)
     return typeName
 
-def getUnionTypeTemplateVars(unionType, type, descriptorProvider):
+def getUnionTypeTemplateVars(unionType, type, descriptorProvider, isReturnValue=False):
     # For dictionaries and sequences we need to pass None as the failureCode
     # for getJSToNativeConversionInfo.
     # Also, for dictionaries we would need to handle conversion of
     # null/undefined to the dictionary correctly.
     if type.isDictionary() or type.isSequence():
         raise TypeError("Can't handle dictionaries or sequences in unions")
 
     if type.isGeckoInterface():
@@ -5859,17 +5871,17 @@ def getUnionTypeTemplateVars(unionType, 
     tryNextCode = """tryNext = true;
 return true;"""
     if type.isGeckoInterface():
          tryNextCode = ("""if (mUnion.mType != mUnion.eUninitialized) {
   mUnion.Destroy%s();
 }""" % name) + tryNextCode
     conversionInfo = getJSToNativeConversionInfo(
         type, descriptorProvider, failureCode=tryNextCode,
-        isDefinitelyObject=True,
+        isDefinitelyObject=True, isInUnionReturnValue=isReturnValue,
         sourceDescription="member of %s" % unionType)
 
     # This is ugly, but UnionMember needs to call a constructor with no
     # arguments so the type can't be const.
     structType = conversionInfo.declType.define()
     if structType.startswith("const "):
         structType = structType[6:]
     externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
@@ -5953,17 +5965,17 @@ class CGUnionStruct(CGThing):
   }
   ${externalType} GetAs${name}() const
   {
     MOZ_ASSERT(Is${name}(), "Wrong type!");
     return const_cast<${structType}&>(mValue.m${name}.Value());
   }"""
         methods.extend(mapTemplate(methodTemplate, templateVars))
         # Now have to be careful: we do not want the SetAsObject() method!
-        setterTemplate = """ ${structType}& SetAs${name}()
+        setterTemplate = """  ${structType}& SetAs${name}()
   {
     mType = e${name};
     return mValue.m${name}.SetValue();
   }"""
         methods.extend(mapTemplate(setterTemplate,
                                    filter(lambda v: v["name"] != "Object",
                                           templateVars)))
         values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
@@ -6015,17 +6027,17 @@ private:
        })
 
     def define(self):
         templateVars = self.templateVars
         conversionsToJS = []
         if self.type.hasNullableType:
             conversionsToJS.append("    case eNull:\n"
                                    "    {\n"
-                                   "      rval.set(JS::NullValue());\n"
+                                   "      rval.setNull();\n"
                                    "      return true;\n"
                                    "    }")
         conversionsToJS.extend(
             map(self.getConversionToJS,
                 zip(templateVars, self.type.flatMemberTypes)))
 
         return string.Template("""bool
 ${structName}::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj,
@@ -6057,17 +6069,171 @@ private:
             val = "%s.get()->Obj()" % val
         wrapCode = wrapForType(
             type, self.descriptorProvider,
             {
                 "jsvalRef": "rval",
                 "jsvalHandle": "rval",
                 "obj": "scopeObj",
                 "result": val,
-                "objectCanBeNonNull": True
+                })
+        return CGIndenter(CGList([CGGeneric("case e%(name)s:" % templateVars),
+                                  CGWrapper(CGIndenter(CGGeneric(wrapCode)),
+                                            pre="{\n",
+                                            post="\n}")],
+                                 "\n"),
+                          4).define()
+
+class CGUnionReturnValueStruct(CGThing):
+    def __init__(self, type, descriptorProvider):
+        CGThing.__init__(self)
+        self.type = type.unroll()
+        self.descriptorProvider = descriptorProvider
+        self.templateVars = map(
+            lambda t: getUnionTypeTemplateVars(self.type, t,
+                                               self.descriptorProvider,
+                                               isReturnValue=True),
+            self.type.flatMemberTypes)
+
+    def declare(self):
+        templateVars = self.templateVars
+
+        enumValues = []
+        methods = []
+        if self.type.hasNullableType:
+            enumValues.append("eNull")
+            methods.append("""  bool IsNull() const
+  {
+    return mType == eNull;
+  }
+
+  bool SetNull()
+  {
+    mType = eNull;
+    return true;
+  }""")
+
+        enumValues.extend(mapTemplate("e${name}", templateVars))
+        methodTemplate = "  ${structType}& SetAs${name}();"
+        methods.extend(mapTemplate(methodTemplate, templateVars))
+        values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
+        return string.Template("""
+class ${structName}ReturnValue {
+public:
+  ${structName}ReturnValue() : mType(eUninitialized)
+  {
+  }
+  ~${structName}ReturnValue();
+
+${methods}
+
+  bool ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj,
+               JS::MutableHandle<JS::Value> rval) const;
+
+private:
+  enum Type {
+    eUninitialized,
+    ${enumValues}
+  };
+  union Value {
+    ${values}
+  };
+
+  Type mType;
+  Value mValue;
+};
+
+""").substitute(
+    {
+       "structName": self.type.__str__(),
+       "methods": "\n\n".join(methods),
+       "enumValues": ",\n    ".join(enumValues),
+       "values": "\n    ".join(values)
+       })
+
+    def define(self):
+        templateVars = self.templateVars
+        conversionsToJS = []
+        if self.type.hasNullableType:
+            conversionsToJS.append("    case eNull:\n"
+                                   "    {\n"
+                                   "      rval.setNull();\n"
+                                   "      return true;\n"
+                                   "    }")
+        conversionsToJS.extend(
+            map(self.getConversionToJS,
+                zip(templateVars, self.type.flatMemberTypes)))
+
+        toJSVal = string.Template("""
+
+bool
+${structName}ReturnValue::ToJSVal(JSContext* cx, JS::Handle<JSObject*> scopeObj, JS::MutableHandle<JS::Value> rval) const
+{
+  switch (mType) {
+${doConversionsToJS}
+
+    case eUninitialized:
+    {
+      break;
+    }
+  }
+  return false;
+}
+""").substitute({
+                "structName": str(self.type),
+                "doConversionsToJS": "\n\n".join(conversionsToJS)
+                })
+        templateVars = self.templateVars
+
+        methods = []
+        methodTemplate = """${structType}&
+%sReturnValue::SetAs${name}()
+{
+  mType = e${name};
+  return mValue.m${name}.SetValue();
+}""" % str(self.type)
+        methods.extend(mapTemplate(methodTemplate, templateVars))
+
+        callDestructors = []
+        if self.type.hasNullableType:
+            callDestructors.append("      case eNull:\n"
+                                   "        break;")
+        callDestructors.extend(mapTemplate("    case e${name}:\n"
+                                           "       mValue.m${name}.Destroy();\n"
+                                           "       mType = eUninitialized;\n"
+                                           "       break;", templateVars))
+        destructor = string.Template("""
+${structName}ReturnValue::~${structName}ReturnValue()
+{
+  switch (mType) {
+${callDestructors}
+    case eUninitialized:
+      break;
+  }
+}
+
+""").substitute(
+    {
+       "structName": self.type.__str__(),
+       "callDestructors": "\n".join(callDestructors),
+       })
+
+        return destructor + "\n\n".join(methods) + toJSVal
+
+    def getConversionToJS(self, arg):
+        (templateVars, type) = arg
+        assert not type.nullable() # flatMemberTypes never has nullable types
+        val = "mValue.m%(name)s.Value()" % templateVars
+        wrapCode = wrapForType(
+            type, self.descriptorProvider,
+            {
+                "jsvalRef": "rval",
+                "jsvalHandle": "rval",
+                "obj": "scopeObj",
+                "result": val,
                 })
         return CGIndenter(CGList([CGGeneric("case e%(name)s:" % templateVars),
                                   CGWrapper(CGIndenter(CGGeneric(wrapCode)),
                                             pre="{\n",
                                             post="\n}")],
                                  "\n"),
                           4).define()
 
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -2499,17 +2499,17 @@ class IDLAttribute(IDLInterfaceMember):
 
         if self.type.isDictionary():
             raise WebIDLError("An attribute cannot be of a dictionary type",
                               [self.location])
         if self.type.isSequence():
             raise WebIDLError("An attribute cannot be of a sequence type",
                               [self.location])
         if self.type.isUnion():
-            for f in self.type.flatMemberTypes:
+            for f in self.type.unroll().flatMemberTypes:
                 if f.isDictionary():
                     raise WebIDLError("An attribute cannot be of a union "
                                       "type if one of its member types (or "
                                       "one of its member types's member "
                                       "types, and so on) is a dictionary "
                                       "type", [self.location, f.location])
                 if f.isSequence():
                     raise WebIDLError("An attribute cannot be of a union "
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -502,16 +502,26 @@ public:
   //void PassUnionWithInterfaces(const TestInterfaceOrTestExternalInterface& arg);
   //void PassUnionWithInterfacesAndNullable(const TestInterfaceOrNullOrTestExternalInterface& arg);
   void PassUnionWithArrayBuffer(const ArrayBufferOrLong&);
   void PassUnionWithString(JSContext*, const StringOrObject&);
   //void PassUnionWithEnum(JSContext*, const TestEnumOrObject&);
   //void PassUnionWithCallback(JSContext*, const TestCallbackOrLong&);
   void PassUnionWithObject(JSContext*, const ObjectOrLong&);
 
+  void ReceiveUnion(const CanvasPatternOrCanvasGradientReturnValue&);
+  void ReceiveUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&);
+  void ReceiveNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
+  void GetWritableUnion(const CanvasPatternOrCanvasGradientReturnValue&);
+  void SetWritableUnion(const CanvasPatternOrCanvasGradient&);
+  void GetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradientReturnValue&);
+  void SetWritableUnionContainingNull(const CanvasPatternOrNullOrCanvasGradient&);
+  void GetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradientReturnValue>&);
+  void SetWritableNullableUnion(const Nullable<CanvasPatternOrCanvasGradient>&);
+
   // Date types
   void PassDate(Date);
   void PassNullableDate(const Nullable<Date>&);
   void PassOptionalDate(const Optional<Date>&);
   void PassOptionalNullableDate(const Optional<Nullable<Date> >&);
   void PassOptionalNullableDateWithDefaultValue(const Nullable<Date>&);
   void PassDateSequence(const Sequence<Date>&);
   void PassNullableDateSequence(const Sequence<Nullable<Date> >&);
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -447,16 +447,24 @@ interface TestInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((TestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //void passUnionWithCallback((TestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  (CanvasPattern or CanvasGradient) receiveUnion();
+  (CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
+  (CanvasPattern or CanvasGradient)? receiveNullableUnion();
+
+  attribute (CanvasPattern or CanvasGradient) writableUnion;
+  attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;
+  attribute (CanvasPattern or CanvasGradient)? writableNullableUnion;
+
   // Date types
   void passDate(Date arg);
   void passNullableDate(Date? arg);
   void passOptionalDate(optional Date arg);
   void passOptionalNullableDate(optional Date? arg);
   void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
   void passDateSequence(sequence<Date> arg);
   void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -343,16 +343,24 @@ interface TestExampleInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((TestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //  void passUnionWithCallback((TestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  //(CanvasPattern or CanvasGradient) receiveUnion();
+  //(CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
+  //(CanvasPattern or CanvasGradient)? receiveNullableUnion();
+
+  //attribute (CanvasPattern or CanvasGradient) writableUnion;
+  //attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;
+  //attribute (CanvasPattern or CanvasGradient)? writableNullableUnion;
+
   // Date types
   void passDate(Date arg);
   void passNullableDate(Date? arg);
   void passOptionalDate(optional Date arg);
   void passOptionalNullableDate(optional Date? arg);
   void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
   void passDateSequence(sequence<Date> arg);
   void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/bindings/test/TestJSImplGen.webidl
+++ b/dom/bindings/test/TestJSImplGen.webidl
@@ -367,16 +367,24 @@ interface TestJSImplInterface {
   void passUnionWithString((DOMString or object) arg);
   //void passUnionWithEnum((MyTestEnum or object) arg);
   // Trying to use a callback in a union won't include the test
   // headers, unfortunately, so won't compile.
   //  void passUnionWithCallback((MyTestCallback or long) arg);
   void passUnionWithObject((object or long) arg);
   //void passUnionWithDict((Dict or long) arg);
 
+  //(CanvasPattern or CanvasGradient) receiveUnion();
+  //(CanvasPattern? or CanvasGradient) receiveUnionContainingNull();
+  //(CanvasPattern or CanvasGradient)? receiveNullableUnion();
+
+  //attribute (CanvasPattern or CanvasGradient) writableUnion;
+  //attribute (CanvasPattern? or CanvasGradient) writableUnionContainingNull;
+  //attribute (CanvasPattern or CanvasGradient)? writableNullableUnion;
+
   // Date types
   void passDate(Date arg);
   void passNullableDate(Date? arg);
   void passOptionalDate(optional Date arg);
   void passOptionalNullableDate(optional Date? arg);
   void passOptionalNullableDateWithDefaultValue(optional Date? arg = null);
   void passDateSequence(sequence<Date> arg);
   void passNullableDateSequence(sequence<Date?> arg);
--- a/dom/src/events/Makefile.in
+++ b/dom/src/events/Makefile.in
@@ -12,9 +12,10 @@ FAIL_ON_WARNINGS := 1
 include $(DEPTH)/config/autoconf.mk
 
 MSVC_ENABLE_PGO := 1
 LIBXUL_LIBRARY	= 1
 
 include $(topsrcdir)/config/rules.mk
 
 INCLUDES	+= -I$(topsrcdir)/dom/base
+INCLUDES	+= -I$(topsrcdir)/content/base/src
 
--- a/dom/webidl/CanvasRenderingContext2D.webidl
+++ b/dom/webidl/CanvasRenderingContext2D.webidl
@@ -41,20 +41,18 @@ interface CanvasRenderingContext2D {
 // NOT IMPLEMENTED  void resetTransform();
 
   // compositing
            attribute unrestricted double globalAlpha; // (default 1.0)
            [Throws]
            attribute DOMString globalCompositeOperation; // (default source-over)
 
   // colors and styles (see also the CanvasDrawingStyles interface)
-           [GetterThrows]
-           attribute any strokeStyle; // (default black)
-           [GetterThrows]
-           attribute any fillStyle; // (default black)
+           attribute (DOMString or CanvasGradient or CanvasPattern) strokeStyle; // (default black)
+           attribute (DOMString or CanvasGradient or CanvasPattern) fillStyle; // (default black)
   [Creator]
   CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
   [Creator, Throws]
   CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
   [Creator, Throws]
   CanvasPattern createPattern((HTMLImageElement or HTMLCanvasElement or HTMLVideoElement) image, [TreatNullAs=EmptyString] DOMString repetition);
 
   // shadows