merge with mc
authorDoug Turner <dougt@dougt.org>
Wed, 30 Jun 2010 10:50:45 -0700
changeset 46946 d1dc03b03aefd307243d25b26fe07af0a637cf86
parent 46945 9cfe0ace0e9588e4cfff87f978e88fe896d0a87d (current diff)
parent 46446 d5d4a04727a41b6fba56e2d5b978fe638ade3cb1 (diff)
child 46947 ff63836f5fca48374b0c4394845bf17d3846884c
push id14210
push userdougt@mozilla.com
push dateThu, 01 Jul 2010 06:28:42 +0000
treeherderautoland@3aff97777291 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone2.0b2pre
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
merge with mc
content/canvas/src/WebGLContext.h
modules/libpref/src/init/all.js
modules/plugin/test/mochitest/Makefile.in
toolkit/toolkit-makefiles.sh
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -249,18 +249,21 @@ window[chromehidden~="toolbar"] toolbar:
 #identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 ,
 #identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 {
   display: none;
 }
 
 /*  Full Screen UI */
 #fullscr-toggler {
   display: none;
-  min-height: 5px;
-  height: 5px;
+  min-height: 1px;
+  height: 1px;
+  background: black;
+  border-style: none;
+  -moz-appearance: none;
 }
 
 #navigator-toolbox[inFullscreen="true"] > #fullscr-toggler,
 #nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-icon {
   display: -moz-box;
 }
 
 #nav-bar[mode="text"] > #window-controls > toolbarbutton > .toolbarbutton-text {
--- a/browser/themes/winstripe/browser/browser-aero.css
+++ b/browser/themes/winstripe/browser/browser-aero.css
@@ -20,17 +20,17 @@
 
 @media all and (-moz-windows-compositor) {
   #main-window:not(:-moz-lwtheme) {
     -moz-appearance: -moz-win-glass;
     background: transparent;
   }
 
   /* the new titlebar requires this, or content will be clipped at the top of the screen. */
-  #main-window[sizemode="maximized"] {
+  #main-window[sizemode="maximized"][chromemargin^="0,"] {
     margin-top: 8px;
   }
 
   #main-window:not(:-moz-lwtheme)[inFullscreen="true"] {
     -moz-appearance: none;
     background-color: #556;
   }
 
--- a/client.mk
+++ b/client.mk
@@ -79,19 +79,21 @@ ifneq (1,$(words $(CWD)))
 endif
 
 ifeq "$(CWD)" "/"
 CWD   := /.
 endif
 
 ifndef TOPSRCDIR
 ifeq (,$(wildcard client.mk))
-$(error Must run from the client.mk directory, or specify TOPSRCDIR)
+TOPSRCDIR := $(patsubst %/,%,$(dir $(MAKEFILE_LIST)))
+MOZ_OBJDIR = .
+else
+TOPSRCDIR := $(CWD)
 endif
-TOPSRCDIR = $(CWD)
 endif
 
 # try to find autoconf 2.13 - discard errors from 'which'
 # MacOS X 10.4 sends "no autoconf*" errors to stdout, discard those via grep
 AUTOCONF ?= $(shell which autoconf-2.13 autoconf2.13 autoconf213 2>/dev/null | grep -v '^no autoconf' | head -1)
 
 ifeq (,$(strip $(AUTOCONF)))
 AUTOCONF=$(error Couldn't find autoconf 2.13)
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -1349,17 +1349,17 @@ else # COMPILER_DEPEND
 #
 # Generate dependencies on the fly
 #
 _MDDEPFILE = $(MDDEPDIR)/$(@F).pp
 
 define MAKE_DEPS_AUTO
 if test -d $(@D); then \
 	echo "Building deps for $<"; \
-	$(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \
+	$(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \
 fi
 endef
 
 MAKE_DEPS_AUTO_CC = $(MAKE_DEPS_AUTO)
 MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO)
 
 endif # COMPILER_DEPEND
 
--- a/content/canvas/src/CustomQS_WebGL.h
+++ b/content/canvas/src/CustomQS_WebGL.h
@@ -303,16 +303,17 @@ nsICanvasRenderingContextWebGL_ReadPixel
     return JS_TRUE;
 }
 
 
 /*
  * TexImage2D takes:
  *    TexImage2D(uint, int, uint, int, int, int, uint, uint, ArrayBufferView)\
  *    TexImage2D(uint, int, uint, uint, uint, nsIDOMElement)
+ *    TexImage2D(uint, int, uint, uint, uint, ImageData)
  */
 static JSBool
 nsICanvasRenderingContextWebGL_TexImage2D(JSContext *cx, uintN argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
@@ -355,16 +356,44 @@ nsICanvasRenderingContextWebGL_TexImage2
         GET_UINT32_ARG(argv4, 4);
 
         nsIDOMElement *elt;
         xpc_qsSelfRef eltRef;
         rv = xpc_qsUnwrapArg<nsIDOMElement>(cx, argv[5], &elt, &eltRef.ptr, &argv[5]);
         if (NS_FAILED(rv)) return JS_FALSE;
 
         rv = self->TexImage2D_dom(argv0, argv1, argv2, argv3, argv4, elt);
+
+        if (NS_FAILED(rv)) {
+            // failed to interprete argv[5] as a DOMElement, now try to interprete it as ImageData
+            JSObject *argv5 = JSVAL_TO_OBJECT(argv[5]);
+            jsval js_width, js_height, js_data;
+            JS_GetProperty(cx, argv5, "width", &js_width);
+            JS_GetProperty(cx, argv5, "height", &js_height);
+            JS_GetProperty(cx, argv5, "data", &js_data);
+            if (js_width  == JSVAL_VOID ||
+                js_height == JSVAL_VOID ||
+                js_data   == JSVAL_VOID)
+            {
+                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 5);
+                return JS_FALSE;
+            }
+            int32 int_width, int_height;
+            JSObject *obj_data = JSVAL_TO_OBJECT(js_data);
+            if (!JS_ValueToECMAInt32(cx, js_width, &int_width) ||
+                !JS_ValueToECMAInt32(cx, js_height, &int_height) ||
+                !js_IsTypedArray(obj_data))
+            {
+                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 5);
+                return JS_FALSE;
+            }
+            rv = self->TexImage2D_array(argv0, argv1, argv2,
+                                        int_width, int_height, 0,
+                                        argv3, argv4, js::TypedArray::fromJSObject(obj_data));
+        }
     } else if (argc > 8 && JSVAL_IS_OBJECT(argv[8])) {
         // implement the variants taking a buffer/array as argv[8]
         GET_UINT32_ARG(argv2, 2);
         GET_INT32_ARG(argv3, 3);
         GET_INT32_ARG(argv4, 4);
         GET_INT32_ARG(argv5, 5);
         GET_UINT32_ARG(argv6, 6);
         GET_UINT32_ARG(argv7, 7);
@@ -398,16 +427,17 @@ nsICanvasRenderingContextWebGL_TexImage2
 
     *vp = JSVAL_VOID;
     return JS_TRUE;
 }
 
 /* TexSubImage2D takes:
  *    TexSubImage2D(uint, int, int, int, int, int, uint, uint, ArrayBufferView)
  *    TexSubImage2D(uint, int, int, int, uint, uint, nsIDOMElement)
+ *    TexSubImage2D(uint, int, int, int, uint, uint, ImageData)
  */
 static JSBool
 nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *vp)
 {
     XPC_QS_ASSERT_CONTEXT_OK(cx);
     JSObject *obj = JS_THIS_OBJECT(cx, vp);
     if (!obj)
         return JS_FALSE;
@@ -437,16 +467,45 @@ nsICanvasRenderingContextWebGL_TexSubIma
         GET_UINT32_ARG(argv5, 5);
 
         nsIDOMElement *elt;
         xpc_qsSelfRef eltRef;
         rv = xpc_qsUnwrapArg<nsIDOMElement>(cx, argv[6], &elt, &eltRef.ptr, &argv[6]);
         if (NS_FAILED(rv)) return JS_FALSE;
 
         rv = self->TexSubImage2D_dom(argv0, argv1, argv2, argv3, argv4, argv5, elt);
+
+        if (NS_FAILED(rv)) {
+            // failed to interprete argv[6] as a DOMElement, now try to interprete it as ImageData
+            JSObject *argv6 = JSVAL_TO_OBJECT(argv[6]);
+            jsval js_width, js_height, js_data;
+            JS_GetProperty(cx, argv6, "width", &js_width);
+            JS_GetProperty(cx, argv6, "height", &js_height);
+            JS_GetProperty(cx, argv6, "data", &js_data);
+            if (js_width  == JSVAL_VOID ||
+                js_height == JSVAL_VOID ||
+                js_data   == JSVAL_VOID)
+            {
+                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
+                return JS_FALSE;
+            }
+            int32 int_width, int_height;
+            JSObject *obj_data = JSVAL_TO_OBJECT(js_data);
+            if (!JS_ValueToECMAInt32(cx, js_width, &int_width) ||
+                !JS_ValueToECMAInt32(cx, js_height, &int_height) ||
+                !js_IsTypedArray(obj_data))
+            {
+                xpc_qsThrowBadArg(cx, NS_ERROR_FAILURE, vp, 6);
+                return JS_FALSE;
+            }
+            rv = self->TexSubImage2D_array(argv0, argv1, argv2, argv3,
+                                           int_width, int_height,
+                                           argv4, argv5,
+                                           js::TypedArray::fromJSObject(obj_data));
+        }
     } else if (argc > 8 && JSVAL_IS_OBJECT(argv[8])) {
         // implement the variants taking a buffer/array as argv[8]
         GET_INT32_ARG(argv4, 4);
         GET_INT32_ARG(argv5, 5);
         GET_UINT32_ARG(argv6, 6);
         GET_UINT32_ARG(argv7, 7);
 
         JSObject *argv8 = JSVAL_TO_OBJECT(argv[8]);
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -293,16 +293,19 @@ public:
                     { return NS_ERROR_NOT_IMPLEMENTED; }
 
     nsresult SynthesizeGLError(WebGLenum err);
     nsresult SynthesizeGLError(WebGLenum err, const char *fmt, ...);
 
     nsresult ErrorInvalidEnum(const char *fmt = 0, ...);
     nsresult ErrorInvalidOperation(const char *fmt = 0, ...);
     nsresult ErrorInvalidValue(const char *fmt = 0, ...);
+    nsresult ErrorInvalidEnumInfo(const char *info) {
+        return ErrorInvalidEnum("%s: invalid enum value", info);
+    }
 
     already_AddRefed<CanvasLayer> GetCanvasLayer(LayerManager *manager);
     void MarkContextClean() { }
 
     // a number that increments every time we have an event that causes
     // all context resources to be lost.
     PRUint32 Generation() { return mGeneration; }
 protected:
@@ -319,20 +322,27 @@ protected:
     PRBool mInvalidated;
 
     WebGLuint mActiveTexture;
     WebGLenum mSynthesizedGLError;
 
     PRBool SafeToCreateCanvas3DContext(nsHTMLCanvasElement *canvasElement);
     PRBool InitAndValidateGL();
     PRBool ValidateBuffers(PRUint32 count);
-    static PRBool ValidateCapabilityEnum(WebGLenum cap);
-    static PRBool ValidateBlendEquationEnum(WebGLuint cap);
-    static PRBool ValidateBlendFuncDstEnum(WebGLuint mode);
-    static PRBool ValidateBlendFuncSrcEnum(WebGLuint mode);
+    PRBool ValidateCapabilityEnum(WebGLenum cap, const char *info);
+    PRBool ValidateBlendEquationEnum(WebGLuint cap, const char *info);
+    PRBool ValidateBlendFuncDstEnum(WebGLuint mode, const char *info);
+    PRBool ValidateBlendFuncSrcEnum(WebGLuint mode, const char *info);
+    PRBool ValidateTextureTargetEnum(WebGLenum target, const char *info);
+    PRBool ValidateComparisonEnum(WebGLenum target, const char *info);
+    PRBool ValidateStencilOpEnum(WebGLenum action, const char *info);
+    PRBool ValidateFaceEnum(WebGLenum target, const char *info);
+    PRBool ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
+                                      PRUint32 *texelSize, const char *info);
+
     void Invalidate();
 
     void MakeContextCurrent() { gl->MakeCurrent(); }
 
     // helpers
     nsresult TexImage2D_base(WebGLenum target, WebGLint level, WebGLenum internalformat,
                              WebGLsizei width, WebGLsizei height, WebGLint border,
                              WebGLenum format, WebGLenum type,
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -291,57 +291,55 @@ WebGLContext::BindTexture(WebGLenum targ
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_4(BlendColor, BlendColor, float, float, float, float)
 
 NS_IMETHODIMP WebGLContext::BlendEquation(WebGLenum mode)
 {
-    if (!ValidateBlendEquationEnum(mode))
-        return ErrorInvalidEnum("BlendEquation: invalid mode");
+    if (!ValidateBlendEquationEnum(mode, "blendEquation: mode"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendEquation(mode);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::BlendEquationSeparate(WebGLenum modeRGB, WebGLenum modeAlpha)
 {
-    if (!ValidateBlendEquationEnum(modeRGB)
-     || !ValidateBlendEquationEnum(modeAlpha))
-        return ErrorInvalidEnum("BlendEquationSeparate: invalid mode");
+    if (!ValidateBlendEquationEnum(modeRGB, "blendEquationSeparate: modeRGB") ||
+        !ValidateBlendEquationEnum(modeAlpha, "blendEquationSeparate: modeAlpha"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendEquationSeparate(modeRGB, modeAlpha);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::BlendFunc(WebGLenum sfactor, WebGLenum dfactor)
 {
-    if (!ValidateBlendFuncSrcEnum(sfactor))
-        return ErrorInvalidEnum("BlendFunc: invalid source factor");
-    if (!ValidateBlendFuncDstEnum(dfactor))
-        return ErrorInvalidEnum("BlendFunc: invalid destination factor");
+    if (!ValidateBlendFuncSrcEnum(sfactor, "blendFunc: sfactor") ||
+        !ValidateBlendFuncDstEnum(dfactor, "blendFunc: dfactor"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendFunc(sfactor, dfactor);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BlendFuncSeparate(WebGLenum srcRGB, WebGLenum dstRGB,
                                 WebGLenum srcAlpha, WebGLenum dstAlpha)
 {
-    if (!ValidateBlendFuncSrcEnum(srcRGB)
-     || !ValidateBlendFuncSrcEnum(srcAlpha))
-        return ErrorInvalidEnum("BlendFuncSeparate: invalid source factor");
-    if (!ValidateBlendFuncDstEnum(dstRGB)
-     || !ValidateBlendFuncDstEnum(dstAlpha))
-        return ErrorInvalidEnum("BlendFuncSeparate: invalid destination factor");
+    if (!ValidateBlendFuncSrcEnum(srcRGB, "blendFuncSeparate: srcRGB") ||
+        !ValidateBlendFuncSrcEnum(srcAlpha, "blendFuncSeparate: srcAlpha") ||
+        !ValidateBlendFuncDstEnum(dstRGB, "blendFuncSeparate: dstRGB") ||
+        !ValidateBlendFuncDstEnum(dstAlpha, "blendFuncSeparate: dstAlpha"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::BufferData(PRInt32 dummy)
@@ -799,17 +797,26 @@ WebGLContext::DetachShader(nsIWebGLProgr
 
     MakeContextCurrent();
 
     gl->fDetachShader(progname, shadername);
 
     return NS_OK;
 }
 
-GL_SAME_METHOD_1(DepthFunc, DepthFunc, WebGLenum)
+NS_IMETHODIMP
+WebGLContext::DepthFunc(WebGLenum func)
+{
+    if (!ValidateComparisonEnum(func, "depthFunc"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fDepthFunc(func);
+    return NS_OK;
+}
 
 GL_SAME_METHOD_1(DepthMask, DepthMask, WebGLboolean)
 
 #ifdef USE_GLES2
 GL_SAME_METHOD_2(DepthRangef, DepthRange, float, float)
 #else
 GL_SAME_METHOD_2(DepthRange, DepthRange, float, float)
 #endif
@@ -941,28 +948,28 @@ WebGLContext::DrawElements(WebGLenum mod
 
     Invalidate();
 
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Enable(WebGLenum cap)
 {
-    if (!ValidateCapabilityEnum(cap))
-        return ErrorInvalidEnum("Enable: invalid capability enum");
+    if (!ValidateCapabilityEnum(cap, "enable"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fEnable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP WebGLContext::Disable(WebGLenum cap)
 {
-    if (!ValidateCapabilityEnum(cap))
-        return ErrorInvalidEnum("Disable: invalid capability enum");
+    if (!ValidateCapabilityEnum(cap, "disable"))
+        return NS_OK;
 
     MakeContextCurrent();
     gl->fDisable(cap);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::EnableVertexAttribArray(WebGLuint index)
@@ -1057,19 +1064,31 @@ WebGLContext::FramebufferTexture2D(WebGL
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_0(Flush, Flush)
 
 GL_SAME_METHOD_0(Finish, Finish)
 
-GL_SAME_METHOD_1(FrontFace, FrontFace, WebGLenum)
-
-GL_SAME_METHOD_1(GenerateMipmap, GenerateMipmap, WebGLenum)
+NS_IMETHODIMP
+WebGLContext::FrontFace(WebGLenum mode)
+{
+    switch (mode) {
+        case LOCAL_GL_CW:
+        case LOCAL_GL_CCW:
+            break;
+        default:
+            return ErrorInvalidEnum("FrontFace: invalid mode");
+    }
+
+    MakeContextCurrent();
+    gl->fFrontFace(mode);
+    return NS_OK;
+}
 
 // returns an object: { size: ..., type: ..., name: ... }
 NS_IMETHODIMP
 WebGLContext::GetActiveAttrib(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
 {
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>(pobj, &progname))
         return ErrorInvalidOperation("GetActiveAttrib: invalid program");
@@ -1103,16 +1122,27 @@ WebGLContext::GetActiveAttrib(nsIWebGLPr
     retobj.DefineProperty("name", name, len);
 
     js.SetRetVal(retobj);
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
+WebGLContext::GenerateMipmap(WebGLenum target)
+{
+    if (!ValidateTextureTargetEnum(target, "generateMipmap"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fGenerateMipmap(target);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
 WebGLContext::GetActiveUniform(nsIWebGLProgram *pobj, PRUint32 index, nsIWebGLActiveInfo **retval)
 {
     WebGLuint progname;
     if (!GetGLName<WebGLProgram>(pobj, &progname))
         return ErrorInvalidOperation("GetActiveUniform: invalid program");
 
     NativeJSContext js;
     if (NS_FAILED(js.error))
@@ -1147,17 +1177,17 @@ WebGLContext::GetActiveUniform(nsIWebGLP
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::GetAttachedShaders(nsIWebGLProgram *pobj, nsIVariant **retval)
 {
     WebGLProgram *prog;
     if (!GetConcreteObject(pobj, &prog))
-        return ErrorInvalidOperation("GetActiveAttrib: invalid program");
+        return ErrorInvalidOperation("GetAttachedShaders: invalid program");
 
     nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
     NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
 
     MakeContextCurrent();
 
     if (prog->AttachedShaders().Length() == 0) {
         wrval->SetAsEmptyArray();
@@ -1241,57 +1271,77 @@ WebGLContext::GetParameter(PRUint32 pnam
         case LOCAL_GL_STENCIL_BACK_PASS_DEPTH_PASS:
         case LOCAL_GL_DEPTH_FUNC:
         case LOCAL_GL_BLEND_SRC_RGB:
         case LOCAL_GL_BLEND_SRC_ALPHA:
         case LOCAL_GL_BLEND_DST_RGB:
         case LOCAL_GL_BLEND_DST_ALPHA:
         case LOCAL_GL_BLEND_EQUATION_RGB:
         case LOCAL_GL_BLEND_EQUATION_ALPHA:
-        //case LOCAL_GL_UNPACK_ALIGNMENT: // not supported
-        //case LOCAL_GL_PACK_ALIGNMENT: // not supported
+        case LOCAL_GL_UNPACK_ALIGNMENT:
+        case LOCAL_GL_PACK_ALIGNMENT:
         case LOCAL_GL_GENERATE_MIPMAP_HINT:
         case LOCAL_GL_SUBPIXEL_BITS:
         case LOCAL_GL_MAX_TEXTURE_SIZE:
         case LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE:
-        case LOCAL_GL_MAX_ELEMENTS_INDICES:
-        case LOCAL_GL_MAX_ELEMENTS_VERTICES:
         case LOCAL_GL_SAMPLE_BUFFERS:
         case LOCAL_GL_SAMPLES:
-        //case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
-        //case LOCAL_GL_NUM_SHADER_BINARY_FORMATS:
         case LOCAL_GL_MAX_VERTEX_ATTRIBS:
-        case LOCAL_GL_MAX_VERTEX_UNIFORM_COMPONENTS:
-        case LOCAL_GL_MAX_VARYING_FLOATS:
         case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
-        //case LOCAL_GL_MAX_FRAGMENT_UNIFORM_VECTORS:  // not present in desktop OpenGL
-        //case LOCAL_GL_MAX_VARYING_VECTORS:           // not present in desktop OpenGL
         case LOCAL_GL_MAX_RENDERBUFFER_SIZE:
         case LOCAL_GL_RED_BITS:
         case LOCAL_GL_GREEN_BITS:
         case LOCAL_GL_BLUE_BITS:
         case LOCAL_GL_ALPHA_BITS:
         case LOCAL_GL_DEPTH_BITS:
         case LOCAL_GL_STENCIL_BITS:
-        case LOCAL_GL_PACK_ALIGNMENT:
-        //case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE:
-        //case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE:
+        case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT:
         {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             wrval->SetAsInt32(i);
         }
             break;
 
+        #define LOCAL_GL_MAX_VARYING_VECTORS 0x8dfc // not present in desktop OpenGL
+        // temporarily add those defs here, as they're missing from
+        //     gfx/thebes/public/GLDefs.h
+        // and from
+        //     gfx/layers/opengl/glDefs.h
+        // and I don't know in which of these 2 files they should go (probably we're going to
+        // kill one of them soon?)
+        #define LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS  0x9125
+        #define LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS   0x9122
+        case LOCAL_GL_MAX_VARYING_VECTORS:
+        {
+            #ifdef USE_GLES2
+                GLint i = 0;
+                gl->fGetIntegerv(pname, &i);
+                wrval->SetAsInt32(i);
+            #else
+                // since this pname is absent from desktop OpenGL, we have to implement it by hand.
+                // The formula below comes from the public_webgl list, "problematic GetParameter pnames" thread
+                GLint i = 0, j = 0;
+                gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_OUTPUT_COMPONENTS, &i);
+                gl->fGetIntegerv(LOCAL_GL_MAX_FRAGMENT_INPUT_COMPONENTS, &j);
+                wrval->SetAsInt32(PR_MIN(i,j)/4);
+            #endif
+        }
+            break;
+
         case LOCAL_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
             wrval->SetAsInt32(0);
             break;
+        case LOCAL_GL_COMPRESSED_TEXTURE_FORMATS:
+            wrval->SetAsVoid(); // the spec says we must return null
+            break;
 
 // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
 // javascript integer values. We just return them as doubles and javascript doesn't care.
         case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
         case LOCAL_GL_STENCIL_BACK_WRITEMASK:
         case LOCAL_GL_STENCIL_VALUE_MASK:
         case LOCAL_GL_STENCIL_WRITEMASK:
         {
@@ -1327,16 +1377,24 @@ WebGLContext::GetParameter(PRUint32 pnam
         case LOCAL_GL_DEPTH_WRITEMASK:
         {
             realGLboolean b = 0;
             gl->fGetBooleanv(pname, &b);
             wrval->SetAsBool(PRBool(b));
         }
             break;
 
+// bool, WebGL-specific
+        case UNPACK_FLIP_Y_WEBGL:
+            wrval->SetAsBool(mPixelStoreFlipY);
+            break;
+        case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+            wrval->SetAsBool(mPixelStorePremultiplyAlpha);
+            break;
+
         //
         // Complex values
         //
         case LOCAL_GL_DEPTH_RANGE: // 2 floats
         case LOCAL_GL_ALIASED_POINT_SIZE_RANGE: // 2 floats
         case LOCAL_GL_ALIASED_LINE_WIDTH_RANGE: // 2 floats
         {
             GLfloat fv[2] = { 0 };
@@ -1790,38 +1848,33 @@ WebGLContext::TexParameter()
 NS_IMETHODIMP
 WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **retval)
 {
     nsCOMPtr<nsIWritableVariant> wrval = do_CreateInstance("@mozilla.org/variant;1");
     NS_ENSURE_TRUE(wrval, NS_ERROR_FAILURE);
 
     MakeContextCurrent();
 
-    switch (target) {
-        case LOCAL_GL_TEXTURE_2D:
-        case LOCAL_GL_TEXTURE_CUBE_MAP:
-            break;
-        default:
-            return ErrorInvalidEnum("GetTexParameter: invalid target");
-    }
+    if (!ValidateTextureTargetEnum(target, "getTexParameter: target"))
+        return NS_OK;
 
     switch (pname) {
         case LOCAL_GL_TEXTURE_MIN_FILTER:
         case LOCAL_GL_TEXTURE_MAG_FILTER:
         case LOCAL_GL_TEXTURE_WRAP_S:
         case LOCAL_GL_TEXTURE_WRAP_T:
         {
             GLint i = 0;
             gl->fGetTexParameteriv(target, pname, &i);
             wrval->SetAsInt32(i);
         }
             break;
 
         default:
-            return ErrorInvalidEnum("GetTexParameter: invalid parameter");
+            return ErrorInvalidEnum("getTexParameter: invalid parameter");
     }
 
     *retval = wrval.forget().get();
 
     return NS_OK;
 }
 
 /* any getUniform(in WebGLProgram program, in WebGLUniformLocation location) raises(DOMException); */
@@ -2049,19 +2102,19 @@ WebGLContext::IsTexture(nsIWebGLTexture 
     *retval = CheckConversion<WebGLTexture>(tobj, 0, &isDeleted) && !isDeleted;
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 WebGLContext::IsEnabled(WebGLenum cap, WebGLboolean *retval)
 {
-    if(!ValidateCapabilityEnum(cap)) {
+    if (!ValidateCapabilityEnum(cap, "isEnabled")) {
         *retval = 0; // as per the OpenGL ES spec
-        return ErrorInvalidEnum("IsEnabled: invalid capability enum");
+        return NS_OK;
     }
 
     MakeContextCurrent();
     *retval = gl->fIsEnabled(cap);
     return NS_OK;
 }
 
 GL_SAME_METHOD_1(LineWidth, LineWidth, float)
@@ -2339,29 +2392,89 @@ WebGLContext::RenderbufferStorage(WebGLe
     MakeContextCurrent();
     gl->fRenderbufferStorage(target, internalformat, width, height);
 
     return NS_OK;
 }
 
 GL_SAME_METHOD_2(SampleCoverage, SampleCoverage, float, WebGLboolean)
 
-GL_SAME_METHOD_4(Scissor, Scissor, WebGLint, WebGLint, WebGLsizei, WebGLsizei)
-
-GL_SAME_METHOD_3(StencilFunc, StencilFunc, WebGLenum, WebGLint, WebGLuint)
-
-GL_SAME_METHOD_4(StencilFuncSeparate, StencilFuncSeparate, WebGLenum, WebGLenum, WebGLint, WebGLuint)
+NS_IMETHODIMP
+WebGLContext::Scissor(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
+{
+    if (width < 0 || height < 0)
+        return ErrorInvalidValue("Scissor: negative size");
+
+    MakeContextCurrent();
+    gl->fScissor(x, y, width, height);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::StencilFunc(WebGLenum func, WebGLint ref, WebGLuint mask)
+{
+    if (!ValidateComparisonEnum(func, "stencilFunc: func"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fStencilFunc(func, ref, mask);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::StencilFuncSeparate(WebGLenum face, WebGLenum func, WebGLint ref, WebGLuint mask)
+{
+    if (!ValidateFaceEnum(face, "stencilFuncSeparate: face") ||
+        !ValidateComparisonEnum(func, "stencilFuncSeparate: func"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fStencilFuncSeparate(face, func, ref, mask);
+    return NS_OK;
+}
 
 GL_SAME_METHOD_1(StencilMask, StencilMask, WebGLuint)
 
-GL_SAME_METHOD_2(StencilMaskSeparate, StencilMaskSeparate, WebGLenum, WebGLuint)
-
-GL_SAME_METHOD_3(StencilOp, StencilOp, WebGLenum, WebGLenum, WebGLenum)
-
-GL_SAME_METHOD_4(StencilOpSeparate, StencilOpSeparate, WebGLenum, WebGLenum, WebGLenum, WebGLenum)
+NS_IMETHODIMP
+WebGLContext::StencilMaskSeparate(WebGLenum face, WebGLuint mask)
+{
+    if (!ValidateFaceEnum(face, "stencilMaskSeparate: face"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fStencilMaskSeparate(face, mask);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::StencilOp(WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
+{
+    if (!ValidateStencilOpEnum(sfail, "stencilOp: sfail") ||
+        !ValidateStencilOpEnum(dpfail, "stencilOp: dpfail") ||
+        !ValidateStencilOpEnum(dppass, "stencilOp: dppass"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fStencilOp(sfail, dpfail, dppass);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+WebGLContext::StencilOpSeparate(WebGLenum face, WebGLenum sfail, WebGLenum dpfail, WebGLenum dppass)
+{
+    if (!ValidateFaceEnum(face, "stencilOpSeparate: face") ||
+        !ValidateStencilOpEnum(sfail, "stencilOpSeparate: sfail") ||
+        !ValidateStencilOpEnum(dpfail, "stencilOpSeparate: dpfail") ||
+        !ValidateStencilOpEnum(dppass, "stencilOpSeparate: dppass"))
+        return NS_OK;
+
+    MakeContextCurrent();
+    gl->fStencilOpSeparate(face, sfail, dpfail, dppass);
+    return NS_OK;
+}
 
 template<int format>
 inline void convert_pixel(PRUint8* dst, const PRUint8* src)
 {
     // since has_alpha is a compile time constant, any if(has_alpha) evaluates
     // at compile time, so has zero runtime cost.
     enum { has_alpha = format == gfxASurface::ImageFormatARGB32 };
 
@@ -2655,17 +2768,26 @@ WebGLContext::CreateRenderbuffer(nsIWebG
 
     WebGLRenderbuffer *globj = new WebGLRenderbuffer(this, name);
     NS_ADDREF(*retval = globj);
     mMapRenderbuffers.Put(name, globj);
 
     return NS_OK;
 }
 
-GL_SAME_METHOD_4(Viewport, Viewport, PRInt32, PRInt32, PRInt32, PRInt32)
+NS_IMETHODIMP
+WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height)
+{
+    if (width < 0 || height < 0)
+        return ErrorInvalidOperation("Viewport: negative size");
+
+    MakeContextCurrent();
+    gl->fViewport(x, y, width, height);
+    return NS_OK;
+}
 
 NS_IMETHODIMP
 WebGLContext::CompileShader(nsIWebGLShader *sobj)
 {
     WebGLuint shadername;
     if (!GetGLName<WebGLShader>(sobj, &shadername))
         return ErrorInvalidOperation("CompileShader: invalid shader");
 
@@ -2881,72 +3003,31 @@ WebGLContext::TexImage2D_base(WebGLenum 
     switch (internalformat) {
         case LOCAL_GL_RGB:
         case LOCAL_GL_RGBA:
         case LOCAL_GL_ALPHA:
         case LOCAL_GL_LUMINANCE:
         case LOCAL_GL_LUMINANCE_ALPHA:
             break;
         default:
-            return ErrorInvalidValue("TexImage2D: internal format not supported");
+            return ErrorInvalidEnum("TexImage2D: invalid internal format");
     }
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("TexImage2D: width and height must be >= 0");
 
     if (border != 0)
         return ErrorInvalidValue("TexImage2D: border must be 0");
 
-    // number of bytes per pixel
-    uint32 bufferPixelSize = 0;
-    switch (format) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_GREEN:
-        case LOCAL_GL_BLUE:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-            bufferPixelSize = 1;
-            break;
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            bufferPixelSize = 2;
-            break;
-        case LOCAL_GL_RGB:
-            bufferPixelSize = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            bufferPixelSize = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: pixel format not supported");
-    }
-
-    switch (type) {
-        case LOCAL_GL_BYTE:
-        case LOCAL_GL_UNSIGNED_BYTE:
-            break;
-        case LOCAL_GL_SHORT:
-        case LOCAL_GL_UNSIGNED_SHORT:
-            bufferPixelSize *= 2;
-            break;
-        case LOCAL_GL_INT:
-        case LOCAL_GL_UNSIGNED_INT:
-        case LOCAL_GL_FLOAT:
-            bufferPixelSize *= 4;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            bufferPixelSize *= 2;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: invalid type argument");
-    }
+    PRUint32 texelSize = 0;
+    if (!ValidateTexFormatAndType(format, type, &texelSize, "texImage2D"))
+        return NS_OK;
 
     // XXX overflow!
-    uint32 bytesNeeded = width * height * bufferPixelSize;
+    uint32 bytesNeeded = width * height * texelSize;
 
     if (byteLength && byteLength < bytesNeeded)
         return ErrorInvalidValue("TexImage2D: not enough data for operation (need %d, have %d)",
                                  bytesNeeded, byteLength);
 
     MakeContextCurrent();
 
     if (byteLength) {
@@ -3061,66 +3142,25 @@ WebGLContext::TexSubImage2D_base(WebGLen
     }
 
     if (level < 0)
         return ErrorInvalidValue("TexSubImage2D: level must be >= 0");
 
     if (width < 0 || height < 0)
         return ErrorInvalidValue("TexSubImage2D: width and height must be > 0!");
 
+    PRUint32 texelSize = 0;
+    if (!ValidateTexFormatAndType(format, type, &texelSize, "texSubImage2D"))
+        return NS_OK;
+
     if (width == 0 || height == 0)
         return NS_OK; // ES 2.0 says it has no effect, we better return right now
 
-    // number of bytes per pixel
-    uint32 bufferPixelSize = 0;
-    switch (format) {
-        case LOCAL_GL_RED:
-        case LOCAL_GL_GREEN:
-        case LOCAL_GL_BLUE:
-        case LOCAL_GL_ALPHA:
-        case LOCAL_GL_LUMINANCE:
-            bufferPixelSize = 1;
-            break;
-        case LOCAL_GL_LUMINANCE_ALPHA:
-            bufferPixelSize = 2;
-            break;
-        case LOCAL_GL_RGB:
-            bufferPixelSize = 3;
-            break;
-        case LOCAL_GL_RGBA:
-            bufferPixelSize = 4;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: pixel format not supported");
-    }
-
-    switch (type) {
-        case LOCAL_GL_BYTE:
-        case LOCAL_GL_UNSIGNED_BYTE:
-            break;
-        case LOCAL_GL_SHORT:
-        case LOCAL_GL_UNSIGNED_SHORT:
-            bufferPixelSize *= 2;
-            break;
-        case LOCAL_GL_INT:
-        case LOCAL_GL_UNSIGNED_INT:
-        case LOCAL_GL_FLOAT:
-            bufferPixelSize *= 4;
-            break;
-        case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
-        case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
-        case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-            bufferPixelSize *= 2;
-            break;
-        default:
-            return ErrorInvalidEnum("TexImage2D: invalid type argument");
-    }
-
     // XXX overflow!
-    uint32 bytesNeeded = width * height * bufferPixelSize;
+    uint32 bytesNeeded = width * height * texelSize;
     if (byteLength < bytesNeeded)
         return ErrorInvalidValue("TexSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, byteLength);
 
     MakeContextCurrent();
 
     gl->fTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
 
     return NS_OK;
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -120,47 +120,49 @@ WebGLContext::ValidateBuffers(PRUint32 c
             LogMessage("VBO too small for bound attrib index %d: need at least %d bytes, but have only %d", i, needed, vd.buf->ByteLength());
             return PR_FALSE;
         }
     }
 
     return PR_TRUE;
 }
 
-PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap)
+PRBool WebGLContext::ValidateCapabilityEnum(WebGLenum cap, const char *info)
 {
     switch (cap) {
         case LOCAL_GL_BLEND:
         case LOCAL_GL_CULL_FACE:
         case LOCAL_GL_DEPTH_TEST:
         case LOCAL_GL_DITHER:
         case LOCAL_GL_POLYGON_OFFSET_FILL:
         case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
         case LOCAL_GL_SAMPLE_COVERAGE:
         case LOCAL_GL_SCISSOR_TEST:
         case LOCAL_GL_STENCIL_TEST:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode)
+PRBool WebGLContext::ValidateBlendEquationEnum(WebGLenum mode, const char *info)
 {
     switch (mode) {
         case LOCAL_GL_FUNC_ADD:
         case LOCAL_GL_FUNC_SUBTRACT:
         case LOCAL_GL_FUNC_REVERSE_SUBTRACT:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor)
+PRBool WebGLContext::ValidateBlendFuncDstEnum(WebGLenum factor, const char *info)
 {
     switch (factor) {
         case LOCAL_GL_ZERO:
         case LOCAL_GL_ONE:
         case LOCAL_GL_SRC_COLOR:
         case LOCAL_GL_ONE_MINUS_SRC_COLOR:
         case LOCAL_GL_DST_COLOR:
         case LOCAL_GL_ONE_MINUS_DST_COLOR:
@@ -169,26 +171,140 @@ PRBool WebGLContext::ValidateBlendFuncDs
         case LOCAL_GL_DST_ALPHA:
         case LOCAL_GL_ONE_MINUS_DST_ALPHA:
         case LOCAL_GL_CONSTANT_COLOR:
         case LOCAL_GL_ONE_MINUS_CONSTANT_COLOR:
         case LOCAL_GL_CONSTANT_ALPHA:
         case LOCAL_GL_ONE_MINUS_CONSTANT_ALPHA:
             return PR_TRUE;
         default:
+            ErrorInvalidEnumInfo(info);
+            return PR_FALSE;
+    }
+}
+
+PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor, const char *info)
+{
+    if (factor == LOCAL_GL_SRC_ALPHA_SATURATE)
+        return PR_TRUE;
+    else
+        return ValidateBlendFuncDstEnum(factor, info);
+}
+
+PRBool WebGLContext::ValidateTextureTargetEnum(WebGLenum target, const char *info)
+{
+    switch (target) {
+        case LOCAL_GL_TEXTURE_2D:
+        case LOCAL_GL_TEXTURE_CUBE_MAP:
+            return PR_TRUE;
+        default:
+            ErrorInvalidEnumInfo(info);
+            return PR_FALSE;
+    }
+}
+
+PRBool WebGLContext::ValidateComparisonEnum(WebGLenum target, const char *info)
+{
+    switch (target) {
+        case LOCAL_GL_NEVER:
+        case LOCAL_GL_LESS:
+        case LOCAL_GL_LEQUAL:
+        case LOCAL_GL_GREATER:
+        case LOCAL_GL_GEQUAL:
+        case LOCAL_GL_EQUAL:
+        case LOCAL_GL_NOTEQUAL:
+        case LOCAL_GL_ALWAYS:
+            return PR_TRUE;
+        default:
+            ErrorInvalidEnumInfo(info);
+            return PR_FALSE;
+    }
+}
+
+PRBool WebGLContext::ValidateStencilOpEnum(WebGLenum action, const char *info)
+{
+    switch (action) {
+        case LOCAL_GL_KEEP:
+        case LOCAL_GL_ZERO:
+        case LOCAL_GL_REPLACE:
+        case LOCAL_GL_INCR:
+        case LOCAL_GL_INCR_WRAP:
+        case LOCAL_GL_DECR:
+        case LOCAL_GL_DECR_WRAP:
+        case LOCAL_GL_INVERT:
+            return PR_TRUE;
+        default:
+            ErrorInvalidEnumInfo(info);
             return PR_FALSE;
     }
 }
 
-PRBool WebGLContext::ValidateBlendFuncSrcEnum(WebGLenum factor)
+PRBool WebGLContext::ValidateFaceEnum(WebGLenum target, const char *info)
+{
+    switch (target) {
+        case LOCAL_GL_FRONT:
+        case LOCAL_GL_BACK:
+        case LOCAL_GL_FRONT_AND_BACK:
+            return PR_TRUE;
+        default:
+            ErrorInvalidEnumInfo(info);
+            return PR_FALSE;
+    }
+}
+
+PRBool WebGLContext::ValidateTexFormatAndType(WebGLenum format, WebGLenum type,
+                                                PRUint32 *texelSize, const char *info)
 {
-    if(factor == LOCAL_GL_SRC_ALPHA_SATURATE)
-        return PR_TRUE;
-    else
-        return ValidateBlendFuncDstEnum(factor);
+    if (type == LOCAL_GL_UNSIGNED_BYTE)
+    {
+        switch (format) {
+            case LOCAL_GL_RED:
+            case LOCAL_GL_GREEN:
+            case LOCAL_GL_BLUE:
+            case LOCAL_GL_ALPHA:
+            case LOCAL_GL_LUMINANCE:
+                *texelSize = 1;
+                return PR_TRUE;
+            case LOCAL_GL_LUMINANCE_ALPHA:
+                *texelSize = 2;
+                return PR_TRUE;
+            case LOCAL_GL_RGB:
+                *texelSize = 3;
+                return PR_TRUE;
+            case LOCAL_GL_RGBA:
+                *texelSize = 4;
+                return PR_TRUE;
+            default:
+                ErrorInvalidEnum("%s: invalid format", info);
+                return PR_FALSE;
+        }
+    } else {
+        switch (type) {
+            case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
+            case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
+                if (format == LOCAL_GL_RGBA) {
+                    *texelSize = 2;
+                    return PR_TRUE;
+                } else {
+                    ErrorInvalidOperation("%s: mutually incompatible format and type", info);
+                    return PR_FALSE;
+                }
+            case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
+                if (format == LOCAL_GL_RGB) {
+                    *texelSize = 2;
+                    return PR_TRUE;
+                } else {
+                    ErrorInvalidOperation("%s: mutually incompatible format and type", info);
+                    return PR_FALSE;
+                }
+            default:
+                ErrorInvalidEnum("%s: invalid type", info);
+                return PR_FALSE;
+        }
+    }
 }
 
 PRBool
 WebGLContext::InitAndValidateGL()
 {
     if (!gl) return PR_FALSE;
 
     mActiveTexture = 0;
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -722,17 +722,17 @@ nsXULDocument::SynchronizeBroadcastListe
         nsDelayedBroadcastUpdate delayedUpdate(aBroadcaster, aListener,
                                                aAttr);
         mDelayedBroadcasters.AppendElement(delayedUpdate);
         MaybeBroadcast();
         return;
     }
     nsCOMPtr<nsIContent> broadcaster = do_QueryInterface(aBroadcaster);
     nsCOMPtr<nsIContent> listener = do_QueryInterface(aListener);
-    PRBool notify = mInitialLayoutComplete || mHandlingDelayedBroadcasters;
+    PRBool notify = mDocumentLoaded || mHandlingDelayedBroadcasters;
 
     // We may be copying event handlers etc, so we must also copy
     // the script-type to the listener.
     listener->SetScriptTypeID(broadcaster->GetScriptTypeID());
 
     if (aAttr.EqualsLiteral("*")) {
         PRUint32 count = broadcaster->GetAttrCount();
         nsTArray<nsAttrNameInfo> attributes(count);
--- a/editor/idl/nsIEditorIMESupport.idl
+++ b/editor/idl/nsIEditorIMESupport.idl
@@ -34,49 +34,20 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 #include "domstubs.idl"
 
-%{C++
-class nsIPrivateTextRangeList;
-%}
-
-[ptr] native nsIPrivateTextRangeListPtr(nsIPrivateTextRangeList);
-
-
-[scriptable, uuid(5cb3f9c9-5ab9-40fd-8ee2-0d1c7abd20dd)]
+[scriptable, uuid(a64744c5-d3ff-46ba-b9b1-57f79ff7d97d)]
 
 interface nsIEditorIMESupport : nsISupports
 {
-
-
-  /**
-   * beginComposition() Handles the start of inline input composition.
-   */
-
-  [noscript] void beginComposition();
-
-  /**
-   * setCompositionString() Sets the inline input composition string.
-   * beginComposition must be called prior to this.
-   */
-
-  [noscript] void setCompositionString(in DOMString aCompositionString,
-                                       in nsIPrivateTextRangeListPtr aTextRange);
-
-  /**
-   * endComposition() Handles the end of inline input composition.
-   */
-
-  [noscript] void endComposition();
-
   /**
    * forceCompositionEnd() force the composition end
    */
 
   void forceCompositionEnd();
 
   /**
    * Get preferred IME status of current widget.
--- a/editor/libeditor/base/nsEditor.cpp
+++ b/editor/libeditor/base/nsEditor.cpp
@@ -1847,88 +1847,91 @@ nsEditor::StopPreservingSelection()
 {
   mRangeUpdater.DropSelectionState(mSavedSel);
   mSavedSel.MakeEmpty();
 }
 
 
 #ifdef XP_MAC
 #pragma mark -
-#pragma mark  nsIEditorIMESupport 
+#pragma mark  IME event handlers 
 #pragma mark -
 #endif
 
-//
-// The BeingComposition method is called from the Editor Composition event listeners.
-//
-NS_IMETHODIMP
-nsEditor::BeginComposition()
+nsresult
+nsEditor::BeginIMEComposition()
 {
-#ifdef DEBUG_tague
-  printf("nsEditor::StartComposition\n");
-#endif
   mInIMEMode = PR_TRUE;
-  if (mPhonetic)
+  if (mPhonetic) {
     mPhonetic->Truncate(0);
-
+  }
   return NS_OK;
 }
 
-NS_IMETHODIMP
-nsEditor::EndComposition(void)
+nsresult
+nsEditor::EndIMEComposition()
 {
   NS_ENSURE_TRUE(mInIMEMode, NS_OK); // nothing to do
-  
-  nsresult result = NS_OK;
+
+  nsresult rv = NS_OK;
 
   // commit the IME transaction..we can get at it via the transaction mgr.
   // Note that this means IME won't work without an undo stack!
-  if (mTxnMgr) 
-  {
+  if (mTxnMgr) {
     nsCOMPtr<nsITransaction> txn;
-    result = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));  
+    rv = mTxnMgr->PeekUndoStack(getter_AddRefs(txn));
+    NS_ASSERTION(NS_SUCCEEDED(rv), "PeekUndoStack() failed");
     nsCOMPtr<nsIAbsorbingTransaction> plcTxn = do_QueryInterface(txn);
-    if (plcTxn)
-    {
-      result = plcTxn->Commit();
+    if (plcTxn) {
+      rv = plcTxn->Commit();
+      NS_ASSERTION(NS_SUCCEEDED(rv),
+                   "nsIAbsorbingTransaction::Commit() failed");
     }
   }
 
   /* reset the data we need to construct a transaction */
-  mIMETextNode = do_QueryInterface(nsnull);
+  mIMETextNode = nsnull;
   mIMETextOffset = 0;
   mIMEBufferLength = 0;
   mInIMEMode = PR_FALSE;
   mIsIMEComposing = PR_FALSE;
 
   // notify editor observers of action
   NotifyEditorObservers();
 
-  return result;
+  return rv;
 }
 
-NS_IMETHODIMP
-nsEditor::SetCompositionString(const nsAString& aCompositionString,
-                               nsIPrivateTextRangeList* aTextRangeList)
-{
-  return NS_ERROR_NOT_IMPLEMENTED;
-}
+
+#ifdef XP_MAC
+#pragma mark -
+#pragma mark  nsIPhonetic
+#pragma mark -
+#endif
+
 
 NS_IMETHODIMP
 nsEditor::GetPhonetic(nsAString& aPhonetic)
 {
   if (mPhonetic)
     aPhonetic = *mPhonetic;
   else
     aPhonetic.Truncate(0);
 
   return NS_OK;
 }
 
 
+#ifdef XP_MAC
+#pragma mark -
+#pragma mark  nsIEditorIMESupport 
+#pragma mark -
+#endif
+
+
 static nsresult
 GetEditorContentWindow(nsIDOMElement *aRoot, nsIWidget **aResult)
 {
   NS_ENSURE_TRUE(aRoot && aResult, NS_ERROR_NULL_POINTER);
 
   *aResult = 0;
 
   nsCOMPtr<nsIContent> content = do_QueryInterface(aRoot);
--- a/editor/libeditor/base/nsEditor.h
+++ b/editor/libeditor/base/nsEditor.h
@@ -188,16 +188,22 @@ public:
 
   /* Method to replace certain CreateElementNS() calls. 
      Arguments:
       nsString& aTag          - tag you want
       nsIContent** aContent   - returned Content that was created with above namespace.
   */
   nsresult CreateHTMLContent(const nsAString& aTag, nsIContent** aContent);
 
+  // IME event handlers
+  virtual nsresult BeginIMEComposition();
+  virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
+                                        nsIPrivateTextRangeList *aTextRange)=0;
+  nsresult EndIMEComposition();
+
 protected:
   nsCString mContentMIMEType;       // MIME type of the doc we are editing.
 
   /** create a transaction for setting aAttribute to aValue on aElement
     */
   NS_IMETHOD CreateTxnForSetAttribute(nsIDOMElement *aElement, 
                                       const nsAString &  aAttribute, 
                                       const nsAString &  aValue,
--- a/editor/libeditor/base/nsEditorEventListener.cpp
+++ b/editor/libeditor/base/nsEditorEventListener.cpp
@@ -495,17 +495,17 @@ nsEditorEventListener::HandleText(nsIDOM
   textEvent->GetText(composedText);
   textRangeList = textEvent->GetInputRange();
 
   // if we are readonly or disabled, then do nothing.
   if (mEditor->IsReadonly() || mEditor->IsDisabled()) {
     return NS_OK;
   }
 
-  return mEditor->SetCompositionString(composedText, textRangeList);
+  return mEditor->UpdateIMEComposition(composedText, textRangeList);
 }
 
 /**
  * Drag event implementation
  */
 
 nsresult
 nsEditorEventListener::DragGesture(nsIDOMDragEvent* aDragEvent)
@@ -768,24 +768,24 @@ nsEditorEventListener::CanDrop(nsIDOMDra
 /**
  * nsIDOMCompositionListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleStartComposition(nsIDOMEvent* aCompositionEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-  return mEditor->BeginComposition();
+  return mEditor->BeginIMEComposition();
 }
 
 NS_IMETHODIMP
 nsEditorEventListener::HandleEndComposition(nsIDOMEvent* aCompositionEvent)
 {
   NS_ENSURE_TRUE(mEditor, NS_ERROR_NOT_AVAILABLE);
-  return mEditor->EndComposition();
+  return mEditor->EndIMEComposition();
 }
 
 /**
  * nsIDOMFocusListener implementation
  */
 
 NS_IMETHODIMP
 nsEditorEventListener::Focus(nsIDOMEvent* aEvent)
--- a/editor/libeditor/text/nsPlaintextEditor.cpp
+++ b/editor/libeditor/text/nsPlaintextEditor.cpp
@@ -919,36 +919,87 @@ NS_IMETHODIMP nsPlaintextEditor::InsertL
   {
     // post-process, always called if WillInsertBreak didn't return cancel==PR_TRUE
     res = mRules->DidDoAction(selection, &ruleInfo, res);
   }
 
   return res;
 }
 
-NS_IMETHODIMP
-nsPlaintextEditor::BeginComposition()
+nsresult
+nsPlaintextEditor::BeginIMEComposition()
 {
   NS_ENSURE_TRUE(!mInIMEMode, NS_OK);
 
-  if (IsPasswordEditor())  {
-    if (mRules) {
-      // Protect the edit rules object from dying
-      nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
+  if (IsPasswordEditor()) {
+    NS_ENSURE_TRUE(mRules, NS_ERROR_NULL_POINTER);
+    // Protect the edit rules object from dying
+    nsCOMPtr<nsIEditRules> kungFuDeathGrip(mRules);
+
+    nsTextEditRules *textEditRules =
+      static_cast<nsTextEditRules*>(mRules.get());
+    textEditRules->ResetIMETextPWBuf();
+  }
+
+  return nsEditor::BeginIMEComposition();
+}
+
+nsresult
+nsPlaintextEditor::UpdateIMEComposition(const nsAString& aCompositionString,
+                                        nsIPrivateTextRangeList* aTextRangeList)
+{
+  if (!aTextRangeList && !aCompositionString.IsEmpty()) {
+    NS_ERROR("aTextRangeList is null but the composition string is not null");
+    return NS_ERROR_NULL_POINTER;
+  }
+
+  nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
+  NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
+
+  nsCOMPtr<nsISelection> selection;
+  nsresult rv = GetSelection(getter_AddRefs(selection));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsRefPtr<nsCaret> caretP = ps->GetCaret();
 
-      nsIEditRules *p = mRules.get();
-      nsTextEditRules *textEditRules = static_cast<nsTextEditRules *>(p);
-      textEditRules->ResetIMETextPWBuf();
+  // We should return caret position if it is possible. Because this event
+  // dispatcher always expects to be returned the correct caret position.
+  // But in following cases, we don't need to process the composition string,
+  // so, we only need to return the caret position.
+
+  // aCompositionString.IsEmpty() && !mIMETextNode:
+  //   Workaround for Windows IME bug 23558: We get every IME event twice.
+  //   For escape keypress, this causes an empty string to be passed
+  //   twice, which freaks out the editor.
+
+  // aCompositionString.IsEmpty() && !aTextRangeList:
+  //   Some Chinese IMEs for Linux are always composition string and text range
+  //   list are empty when listing the Chinese characters. In this case,
+  //   we don't need to process composition string too. See bug 271815.
+
+  if (!aCompositionString.IsEmpty() || (mIMETextNode && aTextRangeList)) {
+    mIMETextRangeList = aTextRangeList;
+
+    SetIsIMEComposing(); // We set mIsIMEComposing properly.
+
+    rv = InsertText(aCompositionString);
+
+    mIMEBufferLength = aCompositionString.Length();
+
+    if (caretP) {
+      caretP->SetCaretDOMSelection(selection);
     }
-    else  {
-      return NS_ERROR_NULL_POINTER;
+
+    // second part of 23558 fix:
+    if (aCompositionString.IsEmpty()) {
+      mIMETextNode = nsnull;
     }
   }
 
-  return nsEditor::BeginComposition();
+  return rv;
 }
 
 NS_IMETHODIMP
 nsPlaintextEditor::GetDocumentIsEmpty(PRBool *aDocumentIsEmpty)
 {
   NS_ENSURE_TRUE(aDocumentIsEmpty, NS_ERROR_NULL_POINTER);
   
   NS_ENSURE_TRUE(mRules, NS_ERROR_NOT_INITIALIZED);
@@ -1614,78 +1665,16 @@ nsPlaintextEditor::GetEmbeddedObjects(ns
 {
   *aNodeList = 0;
   return NS_OK;
 }
 
 
 #ifdef XP_MAC
 #pragma mark -
-#pragma mark  nsIEditorIMESupport overrides 
-#pragma mark -
-#endif
-
-NS_IMETHODIMP
-nsPlaintextEditor::SetCompositionString(const nsAString& aCompositionString,
-                                        nsIPrivateTextRangeList* aTextRangeList)
-{
-  if (!aTextRangeList && !aCompositionString.IsEmpty())
-  {
-    NS_ERROR("aTextRangeList is null but the composition string is not null");
-    return NS_ERROR_NULL_POINTER;
-  }
-
-  nsCOMPtr<nsIPresShell> ps = do_QueryReferent(mPresShellWeak);
-  NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED);
-
-  nsCOMPtr<nsISelection> selection;
-  nsresult result = GetSelection(getter_AddRefs(selection));
-  NS_ENSURE_SUCCESS(result, result);
-
-  nsRefPtr<nsCaret> caretP = ps->GetCaret();
-
-  // We should return caret position if it is possible. Because this event
-  // dispatcher always expects to be returned the correct caret position.
-  // But in following cases, we don't need to process the composition string,
-  // so, we only need to return the caret position.
-
-  // aCompositionString.IsEmpty() && !mIMETextNode:
-  //   Workaround for Windows IME bug 23558: We get every IME event twice.
-  //   For escape keypress, this causes an empty string to be passed
-  //   twice, which freaks out the editor.
-
-  // aCompositionString.IsEmpty() && !aTextRangeList:
-  //   Some Chinese IMEs for Linux are always composition string and text range
-  //   list are empty when listing the Chinese characters. In this case,
-  //   we don't need to process composition string too. See bug 271815.
-
-  if (!aCompositionString.IsEmpty() || (mIMETextNode && aTextRangeList))
-  {
-    mIMETextRangeList = aTextRangeList;
-
-    SetIsIMEComposing(); // We set mIsIMEComposing properly.
-
-    result = InsertText(aCompositionString);
-
-    mIMEBufferLength = aCompositionString.Length();
-
-    if (caretP)
-      caretP->SetCaretDOMSelection(selection);
-
-    // second part of 23558 fix:
-    if (aCompositionString.IsEmpty())
-      mIMETextNode = nsnull;
-  }
-
-
-  return result;
-}
-
-#ifdef XP_MAC
-#pragma mark -
 #pragma mark  nsEditor overrides 
 #pragma mark -
 #endif
 
 
 /** All editor operations which alter the doc should be prefaced
  *  with a call to StartOperation, naming the action and direction */
 NS_IMETHODIMP
--- a/editor/libeditor/text/nsPlaintextEditor.h
+++ b/editor/libeditor/text/nsPlaintextEditor.h
@@ -82,22 +82,17 @@ public:
   virtual  ~nsPlaintextEditor();
 
   /* ------------ nsIPlaintextEditor methods -------------- */
   NS_DECL_NSIPLAINTEXTEDITOR
 
   /* ------------ nsIEditorMailSupport overrides -------------- */
   NS_DECL_NSIEDITORMAILSUPPORT
 
-  /* ------------ nsIEditorIMESupport overrides -------------- */
-  NS_IMETHOD SetCompositionString(const nsAString &aCompositionString,
-                                  nsIPrivateTextRangeList *aTextRange);
-
   /* ------------ Overrides of nsEditor interface methods -------------- */
-  NS_IMETHOD BeginComposition();
   NS_IMETHOD SetAttributeOrEquivalent(nsIDOMElement * aElement,
                                       const nsAString & aAttribute,
                                       const nsAString & aValue,
                                       PRBool aSuppressTransaction);
   NS_IMETHOD RemoveAttributeOrEquivalent(nsIDOMElement * aElement,
                                          const nsAString & aAttribute,
                                          PRBool aSuppressTransaction);
 
@@ -147,16 +142,20 @@ public:
 
   /** make the given selection span the entire document */
   NS_IMETHOD SelectEntireDocument(nsISelection *aSelection);
 
   virtual nsresult HandleKeyPressEvent(nsIDOMKeyEvent* aKeyEvent);
 
   virtual already_AddRefed<nsPIDOMEventTarget> GetPIDOMEventTarget();
 
+  virtual nsresult BeginIMEComposition();
+  virtual nsresult UpdateIMEComposition(const nsAString &aCompositionString,
+                                        nsIPrivateTextRangeList *aTextRange);
+
   /* ------------ Utility Routines, not part of public API -------------- */
   NS_IMETHOD TypedText(const nsAString& aString, PRInt32 aAction);
 
   /** Returns the absolute position of the end points of aSelection
    * in the document as a text stream.
    * Invariant: aStartOffset <= aEndOffset.
    */
   nsresult GetTextSelectionOffsets(nsISelection *aSelection,
new file mode 100644
--- /dev/null
+++ b/embedding/android/GeckoInputConnection.java
@@ -0,0 +1,174 @@
+/* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Wu <mwu@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+package org.mozilla.gecko;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.*;
+
+import android.os.*;
+import android.app.*;
+import android.text.*;
+import android.view.*;
+import android.view.inputmethod.*;
+import android.content.*;
+
+import android.util.*;
+
+public class GeckoInputConnection
+    extends BaseInputConnection
+{
+    public GeckoInputConnection (View targetView) {
+        super(targetView, true);
+        mQueryResult = new SynchronousQueue<String>();
+        mExtractedText.partialStartOffset = -1;
+        mExtractedText.partialEndOffset = -1;
+    }
+
+    @Override
+    public Editable getEditable() {
+        Log.i("GeckoAppJava", "getEditable");
+        return null;
+    }
+
+    @Override
+    public boolean beginBatchEdit() {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, null));
+        return true;
+    }
+    @Override
+    public boolean commitCompletion(CompletionInfo text) {
+        Log.i("GeckoAppJava", "Stub: commitCompletion");
+        return true;
+    }
+    @Override
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
+        endBatchEdit();
+        return true;
+    }
+    @Override
+    public boolean deleteSurroundingText(int leftLength, int rightLength) {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(leftLength, rightLength));
+        updateExtractedText();
+        return true;
+    }
+    @Override
+    public boolean endBatchEdit() {
+        updateExtractedText();
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, null));
+        return true;
+    }
+    @Override
+    public boolean finishComposingText() {
+        endBatchEdit();
+        return true;
+    }
+    @Override
+    public int getCursorCapsMode(int reqModes) {
+        return 0;
+    }
+    @Override
+    public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
+        mExtractToken = req.token;
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
+        try {
+            mExtractedText.text = mQueryResult.take();
+            mExtractedText.selectionStart = mSelectionStart;
+            mExtractedText.selectionEnd = mSelectionEnd;
+        } catch (InterruptedException e) {
+            Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
+        }
+        return mExtractedText;
+    }
+    @Override
+    public CharSequence getTextAfterCursor(int length, int flags) {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, length));
+        try {
+            String result = mQueryResult.take();
+            return result;
+        } catch (InterruptedException e) {
+            Log.i("GeckoAppJava", "getTextAfterCursor: Interrupted!");
+        }
+        return null;
+    }
+    @Override
+    public CharSequence getTextBeforeCursor(int length, int flags) {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, length));
+        try {
+            String result = mQueryResult.take();
+            return result;
+        } catch (InterruptedException e) {
+            Log.i("GeckoAppJava", "getTextBeforeCursor: Interrupted!");
+        }
+        return null;
+    }
+    @Override
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+        beginBatchEdit();
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
+        return true;
+    }
+    @Override
+    public boolean setSelection(int start, int end) {
+        Log.i("GeckoAppJava", "Stub: setSelection " + start + " " + end);
+        return true;
+    }
+
+    private void updateExtractedText() {
+        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
+        try {
+            mExtractedText.text = mQueryResult.take();
+            mExtractedText.selectionStart = mSelectionStart;
+            mExtractedText.selectionEnd = mSelectionEnd;
+        } catch (InterruptedException e) {
+            Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
+        }
+
+        InputMethodManager imm = (InputMethodManager)
+            GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.updateExtractedText(GeckoApp.surfaceView, mExtractToken, mExtractedText);
+    }
+
+    int mExtractToken;
+    final ExtractedText mExtractedText = new ExtractedText();
+
+    int mSelectionStart, mSelectionEnd;
+    SynchronousQueue<String> mQueryResult;
+}
--- a/embedding/android/GeckoSurfaceView.java
+++ b/embedding/android/GeckoSurfaceView.java
@@ -306,137 +306,8 @@ class GeckoSurfaceView
     // IME stuff
     GeckoInputConnection inputConnection;
     int mIMEState;
 
     // Software rendering
     ByteBuffer mSoftwareBuffer;
     Bitmap mSoftwareBitmap;
 }
-
-class GeckoInputConnection
-    extends BaseInputConnection
-{
-    public GeckoInputConnection (View targetView) {
-        super(targetView, true);
-        mQueryResult = new SynchronousQueue<String>();
-        mExtractedText.partialStartOffset = -1;
-        mExtractedText.partialEndOffset = -1;
-    }
-
-    @Override
-    public Editable getEditable() {
-        Log.i("GeckoAppJava", "getEditable");
-        return null;
-    }
-
-    @Override
-    public boolean beginBatchEdit() {
-        if (mComposing)
-            return true;
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, null));
-        mComposing = true;
-        return true;
-    }
-    @Override
-    public boolean commitCompletion(CompletionInfo text) {
-        Log.i("GeckoAppJava", "Stub: commitCompletion");
-        return true;
-    }
-    @Override
-    public boolean commitText(CharSequence text, int newCursorPosition) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
-        endBatchEdit();
-        return true;
-    }
-    @Override
-    public boolean deleteSurroundingText(int leftLength, int rightLength) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(leftLength, rightLength));
-        updateExtractedText();
-        return true;
-    }
-    @Override
-    public boolean endBatchEdit() {
-        updateExtractedText();
-        if (!mComposing)
-            return true;
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, null));
-        mComposing = false;
-        return true;
-    }
-    @Override
-    public boolean finishComposingText() {
-        endBatchEdit();
-        return true;
-    }
-    @Override
-    public int getCursorCapsMode(int reqModes) {
-        return 0;
-    }
-    @Override
-    public ExtractedText getExtractedText(ExtractedTextRequest req, int flags) {
-        mExtractToken = req.token;
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
-        try {
-            mExtractedText.text = mQueryResult.take();
-            mExtractedText.selectionStart = mSelectionStart;
-            mExtractedText.selectionEnd = mSelectionEnd;
-        } catch (InterruptedException e) {
-            Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
-        }
-        return mExtractedText;
-    }
-    @Override
-    public CharSequence getTextAfterCursor(int length, int flags) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, length));
-        try {
-            String result = mQueryResult.take();
-            return result;
-        } catch (InterruptedException e) {
-            Log.i("GeckoAppJava", "getTextAfterCursor: Interrupted!");
-        }
-        return null;
-    }
-    @Override
-    public CharSequence getTextBeforeCursor(int length, int flags) {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, length));
-        try {
-            String result = mQueryResult.take();
-            return result;
-        } catch (InterruptedException e) {
-            Log.i("GeckoAppJava", "getTextBeforeCursor: Interrupted!");
-        }
-        return null;
-    }
-    @Override
-    public boolean setComposingText(CharSequence text, int newCursorPosition) {
-        beginBatchEdit();
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(true, text.toString()));
-        return true;
-    }
-    @Override
-    public boolean setSelection(int start, int end) {
-        Log.i("GeckoAppJava", "Stub: setSelection " + start + " " + end);
-        return true;
-    }
-
-    private void updateExtractedText() {
-        GeckoAppShell.sendEventToGecko(new GeckoEvent(false, 0));
-        try {
-            mExtractedText.text = mQueryResult.take();
-            mExtractedText.selectionStart = mSelectionStart;
-            mExtractedText.selectionEnd = mSelectionEnd;
-        } catch (InterruptedException e) {
-            Log.i("GeckoAppJava", "getExtractedText: Interrupted!");
-        }
-
-        InputMethodManager imm = (InputMethodManager)
-            GeckoApp.surfaceView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-        imm.updateExtractedText(GeckoApp.surfaceView, mExtractToken, mExtractedText);
-    }
-
-    boolean mComposing;
-    int mExtractToken;
-    final ExtractedText mExtractedText = new ExtractedText();
-
-    int mSelectionStart, mSelectionEnd;
-    SynchronousQueue<String> mQueryResult;
-}
--- a/embedding/android/Makefile.in
+++ b/embedding/android/Makefile.in
@@ -43,16 +43,17 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/ipc/app/defs.mk
 
 JAVAFILES = \
   GeckoApp.java \
   GeckoAppShell.java \
   GeckoEvent.java \
   GeckoSurfaceView.java \
+  GeckoInputConnection.java \
   $(NULL)
 
 DEFINES += \
   -DMOZ_APP_DISPLAYNAME=$(MOZ_APP_DISPLAYNAME) \
   -DMOZ_APP_NAME=$(MOZ_APP_NAME) \
   -DMOZ_CHILD_PROCESS_NAME=$(MOZ_CHILD_PROCESS_NAME)
 
 GARBAGE += \
--- a/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
+++ b/gfx/cairo/cairo/src/cairo-d2d-surface.cpp
@@ -48,16 +48,19 @@ extern "C" {
 // Required for using placement new.
 #include <new>
 
 ID2D1Factory *D2DSurfFactory::mFactoryInstance = NULL;
 ID3D10Device1 *D3D10Factory::mDeviceInstance = NULL;
 
 #define CAIRO_INT_STATUS_SUCCESS (cairo_int_status_t)CAIRO_STATUS_SUCCESS
 
+// Contains our cache usage - perhaps this should be made threadsafe.
+static int cache_usage = 0;
+
 /**
  * Create a similar surface which will blend effectively to
  * another surface. For D2D, this will create another texture.
  * Within the types we use blending is always easy.
  *
  * \param surface Surface this needs to be similar to
  * \param content Content type of the new surface
  * \param width Width of the new surface
@@ -586,16 +589,23 @@ static RefPtr<ID2D1StrokeStyle>
 									      (FLOAT)style->dash_offset),
 						  dashes,
 						  style->num_dashes,
 						  &strokeStyle);
     delete [] dashes;
     return strokeStyle;
 }
 
+static int _d2d_compute_bitmap_mem_size(ID2D1Bitmap *bitmap)
+{
+    D2D1_SIZE_U size = bitmap->GetPixelSize();
+    int bytes_per_pixel = bitmap->GetPixelFormat().format == DXGI_FORMAT_A8_UNORM ? 1 : 4;
+    return size.width * size.height * bytes_per_pixel;
+}
+
 cairo_user_data_key_t bitmap_key_nonextend;
 cairo_user_data_key_t bitmap_key_extend;
 cairo_user_data_key_t bitmap_key_snapshot;
 
 struct cached_bitmap {
     /** The cached bitmap */
     RefPtr<ID2D1Bitmap> bitmap;
     /** The cached bitmap is dirty and needs its data refreshed */
@@ -607,32 +617,34 @@ struct cached_bitmap {
 /** 
  * This is called when user data on a surface is replaced or the surface is
  * destroyed.
  */
 static void _d2d_release_bitmap(void *bitmap)
 {
     cached_bitmap *existingBitmap = (cached_bitmap*)bitmap;
     if (!--existingBitmap->refs) {
+	cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
 	delete existingBitmap;
     }
 }
 
 /**
  * Via a little trick this is just used to determine when a surface has been
  * modified.
  */
 static void _d2d_snapshot_detached(cairo_surface_t *surface)
 {
     cached_bitmap *existingBitmap = (cached_bitmap*)cairo_surface_get_user_data(surface, &bitmap_key_snapshot);
     if (existingBitmap) {
 	existingBitmap->dirty = true;
     }
     if (!--existingBitmap->refs) {
-	delete existingBitmap;
+	cache_usage -= _d2d_compute_bitmap_mem_size(existingBitmap->bitmap);
+        delete existingBitmap;
     }
     cairo_surface_destroy(surface);
 }
 
 /**
  * This function will calculate the part of srcSurf which will possibly be used within
  * the boundaries of d2dsurf given the current transformation mat. This is used to
  * determine what the minimal part of a surface is that needs to be uploaded.
@@ -1072,16 +1084,17 @@ RefPtr<ID2D1Brush>
 			_cairo_null_surface_create(CAIRO_CONTENT_COLOR_ALPHA);
 		    cairo_surface_set_user_data(nullSurf,
 						&bitmap_key_snapshot,
 						cachebitmap,
 						NULL);
 		    _cairo_surface_attach_snapshot(surfacePattern->surface,
 						   nullSurf,
 						   _d2d_snapshot_detached);
+		    cache_usage += _d2d_compute_bitmap_mem_size(sourceBitmap);
 		}
 		if (pix_image) {
 		    pixman_image_unref(pix_image);
   		}
 	    }
 	} else {
 	    return NULL;
 	}
@@ -2549,9 +2562,15 @@ cairo_d2d_release_dc(cairo_surface_t *su
     
     RECT r;
     r.left = updated_rect->x;
     r.top = updated_rect->y;
     r.right = r.left + updated_rect->width;
     r.bottom = r.top + updated_rect->height;
 
     interopRT->ReleaseDC(&r);
-}
\ No newline at end of file
+}
+
+int
+cairo_d2d_get_image_surface_cache_usage()
+{
+  return _cairo_atomic_int_get(&cache_usage);
+}
--- a/gfx/cairo/cairo/src/cairo-win32.h
+++ b/gfx/cairo/cairo/src/cairo-win32.h
@@ -192,16 +192,22 @@ HDC cairo_d2d_get_dc(cairo_surface_t *su
 
 /**
  * Release the DC acquired through GetDC(). Optionally an update region may be specified
  *
  * \param updated_rect The area of the DC that was updated, if null the entire dc will
  * be updated.
  */
 void cairo_d2d_release_dc(cairo_surface_t *surcace, const cairo_rectangle_int_t *updated_rect);
+
+/**
+ * Get an estimate of the amount of (video) RAM which is currently in use by the D2D
+ * internal image surface cache.
+ */
+int cairo_d2d_get_image_surface_cache_usage();
 #endif
 
 CAIRO_END_DECLS
 
 #else  /* CAIRO_HAS_WIN32_SURFACE */
 # error Cairo was not compiled with support for the win32 backend
 #endif /* CAIRO_HAS_WIN32_SURFACE */
 
--- a/gfx/src/nsCoord.h
+++ b/gfx/src/nsCoord.h
@@ -51,17 +51,17 @@
  * Normally all coordinates are maintained in an app unit coordinate
  * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
  * an integer number of device pixels, such at the CSS DPI is as close to
  * 96dpi as possible.
  */
 
 // This controls whether we're using integers or floats for coordinates. We
 // want to eventually use floats. If you change this, you need to manually
-// change the definition of nscoord in gfx/idl/gfxidltypes.idl.
+// change the definition of nscoord in gfx/src/gfxidltypes.idl.
 //#define NS_COORD_IS_FLOAT
 
 inline float NS_IEEEPositiveInfinity() {
   union { PRUint32 mPRUint32; float mFloat; } pun;
   pun.mPRUint32 = 0x7F800000;
   return pun.mFloat;
 }
 inline PRBool NS_IEEEIsNan(float aF) {
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -70,16 +70,46 @@
 #include "gfxDWriteFonts.h"
 #include "gfxDWriteCommon.h"
 #include <dwrite.h>
 #endif
 #endif
 
 #ifdef CAIRO_HAS_D2D_SURFACE
 #include "gfxD2DSurface.h"
+
+#include "nsIMemoryReporter.h"
+#include "nsMemory.h"
+
+class D2DCacheReporter :
+    public nsIMemoryReporter
+{
+public:
+    D2DCacheReporter()
+    { }
+
+    NS_DECL_ISUPPORTS
+
+    NS_IMETHOD GetPath(char **memoryPath) {
+        *memoryPath = strdup("gfx/d2d/surfacecache");
+        return NS_OK;
+    }
+
+    NS_IMETHOD GetDescription(char **desc) {
+        *desc = strdup("Memory used by Direct2D internal surface cache.");
+        return NS_OK;
+    }
+
+    NS_IMETHOD GetMemoryUsed(PRInt64 *memoryUsed) {
+        *memoryUsed = cairo_d2d_get_image_surface_cache_usage();
+        return NS_OK;
+    }
+}; 
+
+NS_IMPL_ISUPPORTS1(D2DCacheReporter, nsIMemoryReporter)
 #endif
 
 #ifdef WINCE
 #include <shlwapi.h>
 
 #ifdef CAIRO_HAS_DDRAW_SURFACE
 #include "gfxDDrawSurface.h"
 #endif
@@ -133,16 +163,19 @@ gfxWindowsPlatform::gfxWindowsPlatform()
 #elif defined(WINCE)
     mRenderMode = RENDER_DDRAW_GL;
 #else
     mRenderMode = RENDER_GDI;
 #endif
 
     nsCOMPtr<nsIPrefBranch2> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
 
+#ifdef CAIRO_HAS_D2D_SURFACE
+    NS_RegisterMemoryReporter(new D2DCacheReporter());
+#endif
 #ifdef CAIRO_HAS_DWRITE_FONT
     nsresult rv;
     PRBool useDirectWrite = PR_FALSE;
 
     rv = pref->GetBoolPref(
         "gfx.font_rendering.directwrite.enabled", &useDirectWrite);
     if (NS_FAILED(rv)) {
         useDirectWrite = PR_FALSE;
--- a/intl/lwbrk/src/nsPangoBreaker.cpp
+++ b/intl/lwbrk/src/nsPangoBreaker.cpp
@@ -78,16 +78,16 @@ NS_GetComplexLineBreaks(const PRUnichar*
       PRBool err;
       PRUint32 ch = UTF8CharEnumerator::NextChar(&p, end, &err);
       ++attr;
 
       if (ch == 0 || err) {
         // pango_break (pango 1.16.2) only analyses text before the
         // first NUL (but sets one extra attr). Workaround loop to call
         // pango_break again to analyse after the NUL is done somewhere else
-        // (gfx/thebes/src/gfxPangoFonts.cpp: SetupClusterBoundaries()).
+        // (gfx/thebes/gfxPangoFonts.cpp: SetupClusterBoundaries()).
         // So, we do the same here for pango_get_log_attrs.
         break;
       }
     }
   }
 }
 
--- a/js/src/config/rules.mk
+++ b/js/src/config/rules.mk
@@ -1349,17 +1349,17 @@ else # COMPILER_DEPEND
 #
 # Generate dependencies on the fly
 #
 _MDDEPFILE = $(MDDEPDIR)/$(@F).pp
 
 define MAKE_DEPS_AUTO
 if test -d $(@D); then \
 	echo "Building deps for $<"; \
-	$(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \
+	$(MKDEPEND) -o'.$(OBJ_SUFFIX)' -f- $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) $(INCLUDES) $< 2>/dev/null | sed -e "s|^[^ ]*/||" > $(_MDDEPFILE) ; \
 fi
 endef
 
 MAKE_DEPS_AUTO_CC = $(MAKE_DEPS_AUTO)
 MAKE_DEPS_AUTO_CXX = $(MAKE_DEPS_AUTO)
 
 endif # COMPILER_DEPEND
 
--- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
+++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp
@@ -855,16 +855,17 @@ FindScrollParts(nsIFrame* aCurrFrame, ns
       }
     }
     // don't bother searching inside a scrollbar
     return;
   }
   
   nsIFrame* child = aCurrFrame->GetFirstChild(nsnull);
   while (child &&
+         !child->GetContent()->IsRootOfNativeAnonymousSubtree() &&
          (!aResult->mVScrollbar || !aResult->mHScrollbar ||
           !aResult->mColumnsScrollFrame)) {
     FindScrollParts(child, aResult);
     child = child->GetNextSibling();
   }
 }
 
 nsTreeBodyFrame::ScrollParts nsTreeBodyFrame::GetScrollParts()
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -165,17 +165,17 @@ pref("media.wave.enabled", true);
 #ifdef MOZ_WEBM
 pref("media.webm.enabled", true);
 #endif
 
 // Whether to autostart a media element with an |autoplay| attribute
 pref("media.autoplay.enabled", true);
 
 // 0 = Off, 1 = Full, 2 = Tagged Images Only. 
-// See eCMSMode in gfx/thebes/public/gfxPlatform.h
+// See eCMSMode in gfx/thebes/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
 pref("gfx.color_management.display_profile", "");
 pref("gfx.color_management.rendering_intent", 0);
 
 pref("gfx.downloadable_fonts.enabled", true);
 
 #ifdef XP_MACOSX
 pref("gfx.font_rendering.harfbuzz.level", 1);
--- a/modules/plugin/test/mochitest/Makefile.in
+++ b/modules/plugin/test/mochitest/Makefile.in
@@ -100,23 +100,29 @@ include $(topsrcdir)/config/rules.mk
 ifeq ($(OS_ARCH),WINNT)
 _MOCHITEST_FILES += \
   test_windowed_invalidate.html \
   $(NULL)
 endif
 
 _MOCHICHROME_FILES = \
   test_bug479979.xul \
-  test_crash_notify.xul \
-  test_crash_notify_no_report.xul \
   test_npruntime.xul   \
   test_privatemode.xul \
   test_wmode.xul \
   $(NULL)
 
+ifdef MOZ_CRASHREPORTER
+_MOCHICHROME_FILES += \
+  test_crash_notify.xul \
+  test_crash_notify_no_report.xul \
+  test_crash_submit.xul \
+  $(NULL)
+endif
+
 ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
 _MOCHICHROME_FILES += \
   test_convertpoint.xul \
   $(NULL)
 
 _MOCHITEST_FILES += \
   test_cocoa_window_focus.html \
   cocoa_window_focus.html \
copy from modules/plugin/test/mochitest/test_crash_notify_no_report.xul
copy to modules/plugin/test/mochitest/test_crash_submit.xul
--- a/modules/plugin/test/mochitest/test_crash_notify_no_report.xul
+++ b/modules/plugin/test/mochitest/test_crash_submit.xul
@@ -5,118 +5,119 @@
 <window title="Basic Plugin Tests"
   xmlns:html="http://www.w3.org/1999/xhtml"
   xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <title>Plugin Crash Notification Test</title>
   <script type="application/javascript" 
    src="chrome://mochikit/content/MochiKit/packed.js"></script>
   <script type="application/javascript"
           src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js" />
 <body xmlns="http://www.w3.org/1999/xhtml" onload="runTests()">
 <embed id="plugin1" type="application/x-test" width="200" height="200"></embed>
 </body>
 <script class="testbody" type="application/javascript">
 <![CDATA[
 SimpleTest.waitForExplicitFinish();
 
-var success = false;
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.import("resource://gre/modules/Services.jsm");
 
-var observerFired = false;
+var crashReporter =
+  Components.classes["@mozilla.org/toolkit/crash-reporter;1"]
+    .getService(Components.interfaces.nsICrashReporter);
+var oldServerURL = crashReporter.serverURL;
+
+const SERVER_URL = "http://example.com/browser/toolkit/crashreporter/test/browser/crashreport.sjs";
 
 var testObserver = {
   observe: function(subject, topic, data) {
-    observerFired = true;
-    ok(true, "Observer fired");
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-    is(topic, "plugin-crashed", "Checking correct topic");
-    is(data,  null, "Checking null data");
-    ok((subject instanceof Components.interfaces.nsIPropertyBag2), "got Propbag");
-    ok((subject instanceof Components.interfaces.nsIWritablePropertyBag2),
-"got writable Propbag");
+    if (data == "submitting") // not done yet
+      return;
+    is(data, "success", "report should have been submitted successfully");
+    is(topic, "crash-report-status", "Checking correct topic");
+    ok(subject instanceof Components.interfaces.nsIPropertyBag2,
+       "Subject should be a property bag");
+    ok(subject.hasKey("serverCrashID"), "Should have a server crash ID");
+    let crashid = subject.getPropertyAsAString("serverCrashID");
+
+    // Verify the data. The SJS script will return the data that was POSTed
+    let req = new XMLHttpRequest();
+    req.open("GET", SERVER_URL + "?id=" + crashid, false);
+    req.send(null);
+    is(req.status, 200, "Server response should be 200 OK");
+    let submitted = JSON.parse(req.responseText);
+    ok(!("Throttleable" in submitted), "Submit request should not be Throttleable");
+    is(submitted.ProcessType, "plugin", "Should specify ProcessType=plugin");
 
-    var id = subject.getPropertyAsAString("pluginDumpID");
-    isnot(id, "", "got a non-empty crash id");
-    let directoryService =
-      Components.classes["@mozilla.org/file/directory_service;1"].
-      getService(Components.interfaces.nsIProperties);
-    let pendingD = directoryService.get("UAppData",
-                                        Components.interfaces.nsIFile);
-    pendingD.append("Crash Reports");
-    pendingD.append("pending");
-    let dumpFile = pendingD.clone();    
-    dumpFile.append(id + ".dmp");
-    ok(dumpFile.exists(), "minidump exists");
-    let extraFile = pendingD.clone();
-    extraFile.append(id + ".extra");
-    ok(extraFile.exists(), "extra file exists");
-    // cleanup, to be nice
-    dumpFile.remove(false);
-    extraFile.remove(false);
+    // Cleanup
+    // First remove our fake submitted report
+    let file = Services.dirsvc.get("UAppData", Components.interfaces.nsILocalFile);
+    file.append("Crash Reports");
+    file.append("submitted");
+    file.append(crashid + ".txt");
+    file.remove(false);
+
+    // Next unregister our observer
+    var os = Components.classes["@mozilla.org/observer-service;1"].
+             getService(Components.interfaces.nsIObserverService);
+    os.removeObserver(testObserver, "crash-report-status");
+
+    // Then re-set MOZ_CRASHREPORTER_NO_REPORT
+    let env = Components.classes["@mozilla.org/process/environment;1"]
+                        .getService(Components.interfaces.nsIEnvironment);
+    env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
+
+    // Finally re-set crashreporter URL
+    crashReporter.serverURL = oldServerURL;
+    SimpleTest.finish();
   },
 
   QueryInterface: function(iid) {
-    netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
     if (iid.equals(Components.interfaces.nsIObserver) ||
         iid.equals(Components.interfaces.nsISupportsWeakReference) ||
         iid.equals(Components.interfaces.nsISupports))
       return this;
     throw Components.results.NS_NOINTERFACE;
   }
 };
 
 
 function onPluginCrashed(aEvent) {
   ok(true, "Plugin crashed notification received");
-  ok(observerFired, "Observer should have fired first");
   is(aEvent.type, "PluginCrashed", "event is correct type");
 
-  var pluginElement = document.getElementById("plugin1");
-  is (pluginElement, aEvent.target, "Plugin crashed event target is plugin element");
-
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
-  
-  ok(aEvent instanceof Components.interfaces.nsIDOMDataContainerEvent,
-     "plugin crashed event has the right interface");
-  var pluginName = aEvent.getData("pluginName");
-  is(pluginName, "Test Plug-in");
-  var didReport = aEvent.getData("submittedCrashReport");
-  // The app itself may or may not have decided to submit the report, so
-  // allow either true or false here.
-  ok((didReport == true || didReport == false), "event said crash report was submitted");
-
-  var os = Components.classes["@mozilla.org/observer-service;1"].
-           getService(Components.interfaces.nsIObserverService);
-  os.removeObserver(testObserver, "plugin-crashed");
-
-  // re-set MOZ_CRASHREPORTER_NO_REPORT
-  let env = Components.classes["@mozilla.org/process/environment;1"]
-                      .getService(Components.interfaces.nsIEnvironment);
-  env.set("MOZ_CRASHREPORTER_NO_REPORT", "1");
-  SimpleTest.finish();
+  let pleaseLink = document.getAnonymousElementByAttribute(
+                            aEvent.target, "class", "pleaseSubmitLink");
+  // try to submit this report
+  sendMouseEvent({type:'click'}, pleaseLink, window);
 }
 
 function runTests() {
-  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
   var prefs = Components.classes['@mozilla.org/preferences-service;1']
     .getService(Components.interfaces.nsIPrefBranch);
   if (!prefs.getBoolPref('dom.ipc.plugins.enabled')) {
     ok(true, "Skipping this test when IPC plugins are not enabled.");
     SimpleTest.finish();
     return;
   }
   // the test harness will have set MOZ_CRASHREPORTER_NO_REPORT,
   // ensure that we can change the setting and have our minidumps
   // wind up in Crash Reports/pending
   let env = Components.classes["@mozilla.org/process/environment;1"]
                       .getService(Components.interfaces.nsIEnvironment);
   env.set("MOZ_CRASHREPORTER_NO_REPORT", "");
 
+  // Override the crash reporter URL to send to our fake server
+  crashReporter.serverURL = NetUtil.newURI(SERVER_URL);
+
   var os = Components.classes["@mozilla.org/observer-service;1"].
            getService(Components.interfaces.nsIObserverService);
-  os.addObserver(testObserver, "plugin-crashed", true);
+  os.addObserver(testObserver, "crash-report-status", true);
   
   document.addEventListener("PluginCrashed", onPluginCrashed, false);
 
   var pluginElement = document.getElementById("plugin1");
   try {
     pluginElement.crash();
   } catch (e) {
   }
--- a/testing/mochitest/tests/SimpleTest/EventUtils.js
+++ b/testing/mochitest/tests/SimpleTest/EventUtils.js
@@ -3,32 +3,37 @@
  * Current methods:
  *  sendMouseEvent
  *  sendChar
  *  sendString
  *  sendKey
  */
 
 /**
- * Send a mouse event to the node with id aTarget. The "event" passed in to
- * aEvent is just a JavaScript object with the properties set that the real
- * mouse event object should have. This includes the type of the mouse event.
+ * Send a mouse event to the node aTarget (aTarget can be an id, or an
+ * actual node) . The "event" passed in to aEvent is just a JavaScript
+ * object with the properties set that the real mouse event object should
+ * have. This includes the type of the mouse event.
  * E.g. to send an click event to the node with id 'node' you might do this:
  *
  * sendMouseEvent({type:'click'}, 'node');
  */
 function sendMouseEvent(aEvent, aTarget, aWindow) {
   if (['click', 'mousedown', 'mouseup', 'mouseover', 'mouseout'].indexOf(aEvent.type) == -1) {
     throw new Error("sendMouseEvent doesn't know about event type '"+aEvent.type+"'");
   }
 
   if (!aWindow) {
     aWindow = window;
   }
 
+  if (!(aTarget instanceof Element)) {
+    aTarget = aWindow.document.getElementById(aTarget);
+  }
+
   // For events to trigger the UA's default actions they need to be "trusted"
   netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserWrite');
 
   var event = aWindow.document.createEvent('MouseEvent');
 
   var typeArg          = aEvent.type;
   var canBubbleArg     = true;
   var cancelableArg    = true;
@@ -47,17 +52,17 @@ function sendMouseEvent(aEvent, aTarget,
   var buttonArg        = aEvent.button        || 0;
   var relatedTargetArg = aEvent.relatedTarget || null;
 
   event.initMouseEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg,
                        screenXArg, screenYArg, clientXArg, clientYArg,
                        ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
                        buttonArg, relatedTargetArg);
 
-  aWindow.document.getElementById(aTarget).dispatchEvent(event);
+  aTarget.dispatchEvent(event);
 }
 
 /**
  * Send the char aChar to the node with id aTarget.  If aTarget is not
  * provided, use "target".  This method handles casing of chars (sends the
  * right charcode, and sends a shift key for uppercase chars).  No other
  * modifiers are handled at this point.
  *
--- a/toolkit/content/license.html
+++ b/toolkit/content/license.html
@@ -2299,18 +2299,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 
 
     <hr>
 
     <h1><a name="gfx-font-list"></a>gfxFontList License</h1>
 
     <p class="correctme">This license applies to the files 
-    <span class="path">gfx/thebes/src/gfxMacPlatformFontList.mm</span> and
-    <span class="path">gfx/thebes/src/gfxPlatformFontList.cpp</span>.
+    <span class="path">gfx/thebes/gfxMacPlatformFontList.mm</span> and
+    <span class="path">gfx/thebes/gfxPlatformFontList.cpp</span>.
     </p>
 
 <pre>
 Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
@@ -2616,17 +2616,17 @@ ON AN "AS IS" BASIS, AND THE COPYRIGHT H
 PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 </pre>
 
     <hr>
 
     <h1><a name="icu"></a>ICU License</h1>
 
     <p class="correctme">This license applies to some code in the
-    <span class="path">gfx/thebes/src/</span> directory.</p>
+    <span class="path">gfx/thebes</span> directory.</p>
 
 <pre>
 ICU License - ICU 1.8.1 and later
 
 COPYRIGHT AND PERMISSION NOTICE
 
 Copyright (c) 1995-2009 International Business Machines Corporation and
 others
--- a/toolkit/crashreporter/CrashSubmit.jsm
+++ b/toolkit/crashreporter/CrashSubmit.jsm
@@ -182,22 +182,23 @@ function writeSubmittedReport(crashID, v
      data += "\n" + strings.reporturl.replace("%s", viewURL);
 
   os.writeString(data);
   os.close();
   fstream.close();
 }
 
 // the Submitter class represents an individual submission.
-function Submitter(id, element, submitSuccess, submitError) {
+function Submitter(id, element, submitSuccess, submitError, noThrottle) {
   this.id = id;
   this.element = element;
   this.document = element.ownerDocument;
   this.successCallback = submitSuccess;
   this.errorCallback = submitError;
+  this.noThrottle = noThrottle;
 }
 
 Submitter.prototype = {
   submitSuccess: function Submitter_submitSuccess(ret)
   {
     if (!ret.CrashID) {
       this.notifyStatus(FAILED);
       this.cleanup();
@@ -245,18 +246,20 @@ Submitter.prototype = {
     }
     else {
       return false;
     }
     // add the other data
     for (let [name, value] in Iterator(reportData)) {
       addFormEntry(this.iframe.contentDocument, form, name, value);
     }
-    // tell the server not to throttle this, since it was manually submitted
-    addFormEntry(this.iframe.contentDocument, form, "Throttleable", "0");
+    if (this.noThrottle) {
+      // tell the server not to throttle this, since it was manually submitted
+      addFormEntry(this.iframe.contentDocument, form, "Throttleable", "0");
+    }
     // add the minidump
     this.iframe.contentDocument.getElementById('minidump').value
       = this.dump.path;
     this.iframe.docShell.QueryInterface(Ci.nsIWebProgress);
     this.iframe.docShell.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
     form.submit();
     return true;
   },
@@ -305,16 +308,19 @@ Submitter.prototype = {
   onStatusChange: function() {return 0;},
   onSecurityChange: function() {return 0;},
 
   notifyStatus: function Submitter_notify(status, ret)
   {
     let propBag = Cc["@mozilla.org/hash-property-bag;1"].
                   createInstance(Ci.nsIWritablePropertyBag2);
     propBag.setPropertyAsAString("minidumpID", this.id);
+    if (status == SUCCESS) {
+      propBag.setPropertyAsAString("serverCrashID", ret.CrashID);
+    }
 
     Services.obs.notifyObservers(propBag, "crash-report-status", status);
 
     switch (status) {
       case SUCCESS:
         if (this.successCallback)
           this.successCallback(this.id, ret);
         break;
@@ -379,24 +385,35 @@ let CrashSubmit = {
    *        A function that will be called if the report is submitted
    *        successfully with two parameters: the id that was passed
    *        to this function, and an object containing the key/value
    *        data returned from the server in its properties.
    * @param submitError
    *        A function that will be called with one parameter if the
    *        report fails to submit: the id that was passed to this
    *        function.
+   * @param noThrottle
+   *        If true, this crash report should be submitted with
+   *        an extra parameter of "Throttleable=0" indicating that
+   *        it should be processed right away. This should be set
+   *        when the report is being submitted and the user expects
+   *        to see the results immediately.
    *
    * @return true if the submission began successfully, or false if
    *         it failed for some reason. (If the dump file does not
    *         exist, for example.)
    */
-  submit: function CrashSubmit_submit(id, element, submitSuccess, submitError)
+  submit: function CrashSubmit_submit(id, element, submitSuccess, submitError,
+                                      noThrottle)
   {
-    let submitter = new Submitter(id, element, submitSuccess, submitError);
+    let submitter = new Submitter(id,
+                                  element,
+                                  submitSuccess,
+                                  submitError,
+                                  noThrottle);
     CrashSubmit._activeSubmissions.push(submitter);
     return submitter.submit();
   },
 
   // List of currently active submit objects
   _activeSubmissions: []
 };
 
--- a/toolkit/crashreporter/content/crashes.js
+++ b/toolkit/crashreporter/content/crashes.js
@@ -72,17 +72,17 @@ function submitError(dumpid) {
   let event = document.createEvent("Events");
   event.initEvent("CrashSubmitFailed", true, false);
   document.dispatchEvent(event);
 }
 
 function submitPendingReport(event) {
   var link = event.target;
   var id = link.firstChild.textContent;
-  if (CrashSubmit.submit(id, document.body, submitSuccess, submitError))
+  if (CrashSubmit.submit(id, document.body, submitSuccess, submitError, true))
     link.className = "submitting";
   event.preventDefault();
   return false;
 }
 
 function findInsertionPoint(reports, date) {
   if (reports.length == 0)
     return 0;
--- a/toolkit/toolkit-makefiles.sh
+++ b/toolkit/toolkit-makefiles.sh
@@ -117,26 +117,21 @@ MAKEFILES_xmlparser="
   parser/xml/Makefile
   parser/xml/public/Makefile
   parser/xml/src/Makefile
 "
 
 MAKEFILES_gfx="
   gfx/Makefile
   gfx/ycbcr/Makefile
-  gfx/idl/Makefile
   gfx/layers/Makefile
-  gfx/public/Makefile
   gfx/src/Makefile
-  gfx/src/psshared/Makefile
   gfx/src/thebes/Makefile
   gfx/tests/Makefile
   gfx/thebes/Makefile
-  gfx/thebes/public/Makefile
-  gfx/thebes/src/Makefile
   gfx/qcms/Makefile
 "
 
 MAKEFILES_htmlparser="
   parser/htmlparser/Makefile
   parser/htmlparser/public/Makefile
   parser/htmlparser/src/Makefile
   parser/htmlparser/tests/Makefile
new file mode 100644
--- /dev/null
+++ b/xpcom/ds/CheckedInt.h
@@ -0,0 +1,524 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Benoit Jacob <bjacob@mozilla.com>
+ *  Jeff Muizelaar <jmuizelaar@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_CheckedInt_h
+#define mozilla_CheckedInt_h
+
+#include "prtypes.h"
+
+#include <climits>
+
+namespace mozilla {
+
+namespace CheckedInt_internal {
+
+/* we don't want to use std::numeric_limits here because PRInt... types may not support it,
+ * depending on the platform, e.g. on certain platform they use nonstandard built-in types
+ */
+
+/*** Step 1: manually record information for all the types that we want to support
+ ***/
+
+struct unsupported_type {};
+
+template<typename T> struct integer_type_manually_recorded_info
+{
+    enum { is_supported = 0 };
+    typedef unsupported_type twice_bigger_type;
+};
+
+
+#define CHECKEDINT_REGISTER_SUPPORTED_TYPE(T,_twice_bigger_type)  \
+template<> struct integer_type_manually_recorded_info<T>       \
+{                                                              \
+    enum { is_supported = 1 };                                 \
+    typedef _twice_bigger_type twice_bigger_type;              \
+    static void TYPE_NOT_SUPPORTED_BY_CheckedInt() {}             \
+};
+
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt8,   PRInt16)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint8,  PRUint16)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt16,  PRInt32)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint16, PRUint32)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt32,  PRInt64)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint32, PRUint64)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRInt64,  unsupported_type)
+CHECKEDINT_REGISTER_SUPPORTED_TYPE(PRUint64, unsupported_type)
+
+
+/*** Step 2: record some info about a given integer type,
+ ***         including whether it is supported, whether a twice bigger integer type
+ ***         is supported, what that twice bigger type is, and some stuff as found
+ ***         in std::numeric_limits (which we don't use because PRInt.. types may
+ ***         not support it, if they are defined directly from compiler built-in types).
+ ***/
+
+template<typename T> struct is_unsupported_type { enum { answer = 0 }; };
+template<> struct is_unsupported_type<unsupported_type> { enum { answer = 1 }; };
+
+template<typename T> struct integer_traits
+{
+    typedef typename integer_type_manually_recorded_info<T>::twice_bigger_type twice_bigger_type;
+
+    enum {
+        is_supported = integer_type_manually_recorded_info<T>::is_supported,
+        twice_bigger_type_is_supported
+            = is_unsupported_type<
+                  typename integer_type_manually_recorded_info<T>::twice_bigger_type
+              >::answer ? 0 : 1,
+        size = sizeof(T),
+        position_of_sign_bit = CHAR_BIT * size - 1,
+        is_signed = (T(-1) > T(0)) ? 0 : 1
+    };
+
+    static T min()
+    {
+        // bitwise ops may return a larger type, that's why we cast explicitly to T
+        return is_signed ? T(T(1) << position_of_sign_bit) : T(0);
+    }
+
+    static T max()
+    {
+        return ~min();
+    }
+};
+
+/*** Step 3: Implement the actual validity checks --- ideas taken from IntegerLib, code different.
+ ***/
+
+// bitwise ops may return a larger type, so it's good to use these inline helpers guaranteeing that
+// the result is really of type T
+
+template<typename T> inline T has_sign_bit(T x)
+{
+    return x >> integer_traits<T>::position_of_sign_bit;
+}
+
+template<typename T> inline T binary_complement(T x)
+{
+    return ~x;
+}
+
+template<typename T, typename U,
+         bool is_T_signed = integer_traits<T>::is_signed,
+         bool is_U_signed = integer_traits<U>::is_signed>
+struct is_in_range_impl {};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, true, true>
+{
+    static T run(U x)
+    {
+        return (x <= integer_traits<T>::max()) &
+               (x >= integer_traits<T>::min());
+    }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, false, false>
+{
+    static T run(U x)
+    {
+        return x <= integer_traits<T>::max();
+    }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, true, false>
+{
+    static T run(U x)
+    {
+        if (sizeof(T) > sizeof(U))
+            return 1;
+        else
+            return x <= U(integer_traits<T>::max());
+    }
+};
+
+template<typename T, typename U>
+struct is_in_range_impl<T, U, false, true>
+{
+    static T run(U x)
+    {
+        if (sizeof(T) >= sizeof(U))
+            return x >= 0;
+        else
+            return x >= 0 && x <= U(integer_traits<T>::max());
+    }
+};
+
+template<typename T, typename U> inline T is_in_range(U x)
+{
+    return is_in_range_impl<T, U>::run(x);
+}
+
+template<typename T> inline T is_add_valid(T x, T y, T result)
+{
+    return integer_traits<T>::is_signed ?
+                        // addition is valid if the sign of x+y is equal to either that of x or that of y.
+                        // Beware! These bitwise operations can return a larger integer type, if T was a
+                        // small type like int8, so we explicitly cast to T.
+                        has_sign_bit(binary_complement(T((result^x) & (result^y))))
+                    :
+                        binary_complement(x) >= y;
+}
+
+template<typename T> inline T is_sub_valid(T x, T y, T result)
+{
+    return integer_traits<T>::is_signed ?
+                        // substraction is valid if either x and y have same sign, or x-y and x have same sign
+                        has_sign_bit(binary_complement(T((result^x) & (x^y))))
+                    :
+                        x >= y;
+}
+
+template<typename T,
+         bool is_signed =  integer_traits<T>::is_signed,
+         bool twice_bigger_type_is_supported = integer_traits<T>::twice_bigger_type_is_supported>
+struct is_mul_valid_impl {};
+
+template<typename T>
+struct is_mul_valid_impl<T, true, true>
+{
+    static T run(T x, T y)
+    {
+        typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
+        twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
+        return is_in_range<T>(product);
+    }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, false, true>
+{
+    static T run(T x, T y)
+    {
+        typedef typename integer_traits<T>::twice_bigger_type twice_bigger_type;
+        twice_bigger_type product = twice_bigger_type(x) * twice_bigger_type(y);
+        return is_in_range<T>(product);
+    }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, true, false>
+{
+    static T run(T x, T y)
+    {
+        const T max_value = integer_traits<T>::max();
+        const T min_value = integer_traits<T>::min();
+
+        if (x == 0 || y == 0) return true;
+
+        if (x > 0) {
+            if (y > 0)
+                return x <= max_value / y;
+            else
+                return y >= min_value / x;
+        } else {
+            if (y > 0)
+                return x >= min_value / y;
+            else
+                return y >= max_value / x;
+        }
+    }
+};
+
+template<typename T>
+struct is_mul_valid_impl<T, false, false>
+{
+    static T run(T x, T y)
+    {
+        const T max_value = integer_traits<T>::max();
+        if (x == 0 || y == 0) return true;
+        return x <= max_value / y;
+    }
+};
+
+template<typename T> inline T is_mul_valid(T x, T y, T /*result not used*/)
+{
+    return is_mul_valid_impl<T>::run(x, y);
+}
+
+template<typename T> inline T is_div_valid(T x, T y)
+{
+    return integer_traits<T>::is_signed ?
+                        // keep in mind that min/-1 is invalid because abs(min)>max
+                        y != 0 && (x != integer_traits<T>::min() || y != T(-1))
+                    :
+                        y != 0;
+}
+
+} // end namespace CheckedInt_internal
+
+
+/*** Step 4: Now define the CheckedInt class.
+ ***/
+
+/** \class CheckedInt
+  * \brief Integer wrapper class checking for integer overflow and other errors
+  * \param T the integer type to wrap. Can be any of PRInt8, PRUint8, PRInt16, PRUint16,
+  *          PRInt32, PRUint32, PRInt64, PRUint64.
+  *
+  * This class implements guarded integer arithmetic. Do a computation, then check that
+  * valid() returns true, you then have a guarantee that no problem, such as integer overflow,
+  * happened during this computation.
+  *
+  * The arithmetic operators in this class are guaranteed not to crash your app
+  * in case of a division by zero.
+  *
+  * For example, suppose that you want to implement a function that computes (x+y)/z,
+  * that doesn't crash if z==0, and that reports on error (divide by zero or integer overflow).
+  * You could code it as follows:
+    \code
+    PRBool compute_x_plus_y_over_z(PRInt32 x, PRInt32 y, PRInt32 z, PRInt32 *result)
+    {
+        CheckedInt<PRInt32> checked_result = (CheckedInt<PRInt32>(x) + y) / z;
+        *result = checked_result.value();
+        return checked_result.valid();
+    }
+    \endcode
+  *
+  * Implicit conversion from plain integers to checked integers is allowed. The plain integer
+  * is checked to be in range before being casted to the destination type. This means that the following
+  * lines all compile, and the resulting CheckedInts are correctly detected as valid or invalid:
+  * \code
+    CheckedInt<PRUint8> x(1);   // 1 is of type int, is found to be in range for PRUint8, x is valid
+    CheckedInt<PRUint8> x(-1);  // -1 is of type int, is found not to be in range for PRUint8, x is invalid
+    CheckedInt<PRInt8> x(-1);   // -1 is of type int, is found to be in range for PRInt8, x is valid
+    CheckedInt<PRInt8> x(PRInt16(1000)); // 1000 is of type PRInt16, is found not to be in range for PRInt8, x is invalid
+    CheckedInt<PRInt32> x(PRUint32(123456789)); // 3123456789 is of type PRUint32, is found not to be in range
+                                             // for PRInt32, x is invalid
+  * \endcode
+  * Implicit conversion from
+  * checked integers to plain integers is not allowed. As shown in the
+  * above example, to get the value of a checked integer as a normal integer, call value().
+  *
+  * Arithmetic operations between checked and plain integers is allowed; the result type
+  * is the type of the checked integer.
+  *
+  * Safe integers of different types cannot be used in the same arithmetic expression.
+  */
+template<typename T>
+class CheckedInt
+{
+protected:
+    T mValue;
+    T mIsValid; // stored as a T to limit the number of integer conversions when
+                // evaluating nested arithmetic expressions.
+
+    template<typename U>
+    CheckedInt(const U& value, PRBool isValid) : mValue(value), mIsValid(isValid)
+    {
+        CheckedInt_internal::integer_type_manually_recorded_info<T>
+            ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+    }
+
+public:
+    /** Constructs a checked integer with given \a value. The checked integer is initialized as valid or invalid
+      * depending on whether the \a value is in range.
+      *
+      * This constructor is not explicit. Instead, the type of its argument is a separate template parameter,
+      * ensuring that no conversion is performed before this constructor is actually called.
+      * As explained in the above documentation for class CheckedInt, this constructor checks that its argument is
+      * valid.
+      */
+    template<typename U>
+    CheckedInt(const U& value)
+        : mValue(value),
+          mIsValid(CheckedInt_internal::is_in_range<T>(value))
+    {
+        CheckedInt_internal::integer_type_manually_recorded_info<T>
+            ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+    }
+
+    /** Constructs a valid checked integer with uninitialized value */
+    CheckedInt() : mIsValid(1)
+    {
+        CheckedInt_internal::integer_type_manually_recorded_info<T>
+            ::TYPE_NOT_SUPPORTED_BY_CheckedInt();
+    }
+
+    /** \returns the actual value */
+    T value() const { return mValue; }
+
+    /** \returns PR_TRUE if the checked integer is valid, i.e. is not the result
+      * of an invalid operation or of an operation involving an invalid checked integer
+      */
+    PRBool valid() const { return mIsValid; }
+
+    /** \returns the sum. Checks for overflow. */
+    template<typename U> friend CheckedInt<U> operator +(const CheckedInt<U>& lhs, const CheckedInt<U>& rhs);
+    /** Adds. Checks for overflow. \returns self reference */
+    template<typename U> CheckedInt& operator +=(const U &rhs);
+    /** \returns the difference. Checks for overflow. */
+    template<typename U> friend CheckedInt<U> operator -(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+    /** Substracts. Checks for overflow. \returns self reference */
+    template<typename U> CheckedInt& operator -=(const U &rhs);
+    /** \returns the product. Checks for overflow. */
+    template<typename U> friend CheckedInt<U> operator *(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+    /** Multiplies. Checks for overflow. \returns self reference */
+    template<typename U> CheckedInt& operator *=(const U &rhs);
+    /** \returns the quotient. Checks for overflow and for divide-by-zero. */
+    template<typename U> friend CheckedInt<U> operator /(const CheckedInt<U>& lhs, const CheckedInt<U> &rhs);
+    /** Divides. Checks for overflow and for divide-by-zero. \returns self reference */
+    template<typename U> CheckedInt& operator /=(const U &rhs);
+
+    /** \returns the opposite value. Checks for overflow. */
+    CheckedInt operator -() const
+    {
+        T result = -value();
+        /* give the compiler a good chance to perform RVO */
+        return CheckedInt(result,
+                       mIsValid & CheckedInt_internal::is_sub_valid(T(0), value(), result));
+    }
+
+    /** \returns true if the left and right hand sides are valid and have the same value. */
+    PRBool operator ==(const CheckedInt& other) const
+    {
+        return PRBool(mIsValid & other.mIsValid & T(value() == other.value()));
+    }
+
+private:
+    /** operator!= is disabled. Indeed: (a!=b) should be the same as !(a==b) but that
+      * would mean that if a or b is invalid, (a!=b) is always true, which is very tricky.
+      */
+    template<typename U>
+    PRBool operator !=(const U& other) const { return !(*this == other); }
+};
+
+#define CHECKEDINT_BASIC_BINARY_OPERATOR(NAME, OP)               \
+template<typename T>                                          \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs) \
+{                                                             \
+    T x = lhs.value();                                        \
+    T y = rhs.value();                                        \
+    T result = x OP y;                                        \
+    T is_op_valid                                             \
+        = CheckedInt_internal::is_##NAME##_valid(x, y, result);  \
+    /* give the compiler a good chance to perform RVO */      \
+    return CheckedInt<T>(result,                                 \
+                      lhs.mIsValid &                          \
+                      rhs.mIsValid &                          \
+                      is_op_valid);                           \
+}
+
+CHECKEDINT_BASIC_BINARY_OPERATOR(add, +)
+CHECKEDINT_BASIC_BINARY_OPERATOR(sub, -)
+CHECKEDINT_BASIC_BINARY_OPERATOR(mul, *)
+
+// division can't be implemented by CHECKEDINT_BASIC_BINARY_OPERATOR
+// because if rhs == 0, we are not allowed to even try to compute the quotient.
+template<typename T>
+inline CheckedInt<T> operator /(const CheckedInt<T> &lhs, const CheckedInt<T> &rhs)
+{
+    T x = lhs.value();
+    T y = rhs.value();
+    T is_op_valid = CheckedInt_internal::is_div_valid(x, y);
+    T result = is_op_valid ? (x / y) : 0;
+    /* give the compiler a good chance to perform RVO */
+    return CheckedInt<T>(result,
+                      lhs.mIsValid &
+                      rhs.mIsValid &
+                      is_op_valid);
+}
+
+// implement cast_to_CheckedInt<T>(x), making sure that
+//  - it allows x to be either a CheckedInt<T> or any integer type that can be casted to T
+//  - if x is already a CheckedInt<T>, we just return a reference to it, instead of copying it (optimization)
+
+template<typename T, typename U>
+struct cast_to_CheckedInt_impl
+{
+    typedef CheckedInt<T> return_type;
+    static CheckedInt<T> run(const U& u) { return u; }
+};
+
+template<typename T>
+struct cast_to_CheckedInt_impl<T, CheckedInt<T> >
+{
+    typedef const CheckedInt<T>& return_type;
+    static const CheckedInt<T>& run(const CheckedInt<T>& u) { return u; }
+};
+
+template<typename T, typename U>
+inline typename cast_to_CheckedInt_impl<T, U>::return_type
+cast_to_CheckedInt(const U& u)
+{
+    return cast_to_CheckedInt_impl<T, U>::run(u);
+}
+
+#define CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(OP, COMPOUND_OP) \
+template<typename T>                                          \
+template<typename U>                                          \
+CheckedInt<T>& CheckedInt<T>::operator COMPOUND_OP(const U &rhs)    \
+{                                                             \
+    *this = *this OP cast_to_CheckedInt<T>(rhs);                 \
+    return *this;                                             \
+}                                                             \
+template<typename T, typename U>                              \
+inline CheckedInt<T> operator OP(const CheckedInt<T> &lhs, const U &rhs) \
+{                                                             \
+    return lhs OP cast_to_CheckedInt<T>(rhs);                    \
+}                                                             \
+template<typename T, typename U>                              \
+inline CheckedInt<T> operator OP(const U & lhs, const CheckedInt<T> &rhs) \
+{                                                             \
+    return cast_to_CheckedInt<T>(lhs) OP rhs;                    \
+}
+
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(+, +=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(*, *=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(-, -=)
+CHECKEDINT_CONVENIENCE_BINARY_OPERATORS(/, /=)
+
+template<typename T, typename U>
+inline PRBool operator ==(const CheckedInt<T> &lhs, const U &rhs)
+{
+    return lhs == cast_to_CheckedInt<T>(rhs);
+}
+
+template<typename T, typename U>
+inline PRBool operator ==(const U & lhs, const CheckedInt<T> &rhs)
+{
+    return cast_to_CheckedInt<T>(lhs) == rhs;
+}
+
+} // end namespace mozilla
+
+#endif /* mozilla_CheckedInt_h */
--- a/xpcom/ds/Makefile.in
+++ b/xpcom/ds/Makefile.in
@@ -109,16 +109,17 @@ EXPORTS		= \
 		nsSupportsArray.h \
 		nsSupportsPrimitives.h \
 		nsTime.h \
 		nsVariant.h \
 		nsStringEnumerator.h \
 		nsHashPropertyBag.h \
 		nsWhitespaceTokenizer.h \
 		nsCharSeparatedTokenizer.h \
+		CheckedInt.h \
 		$(NULL)			
 
 XPIDLSRCS	= \
 		nsIAtom.idl \
 		nsIAtomService.idl \
 		nsICollection.idl \
 		nsIEnumerator.idl \
 		nsIINIParser.idl \
--- a/xpcom/tests/Makefile.in
+++ b/xpcom/tests/Makefile.in
@@ -96,16 +96,17 @@ CPP_UNIT_TESTS = \
                  TestHashtables.cpp \
                  TestID.cpp \
                  TestObserverArray.cpp \
                  TestObserverService.cpp \
                  TestPipe.cpp \
                  TestRefPtr.cpp \
                  TestServMgr.cpp \
                  TestTextFormatter.cpp \
+                 TestCheckedInt.cpp \
                  $(NULL)
 
 ifndef MOZ_ENABLE_LIBXUL
 CPP_UNIT_TESTS += \
                   TestArray.cpp \
                   TestCRT.cpp \
                   TestDeque.cpp \
                   TestEncoding.cpp \
new file mode 100644
--- /dev/null
+++ b/xpcom/tests/TestCheckedInt.cpp
@@ -0,0 +1,455 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla code.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Benoit Jacob <bjacob@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+
+#include "CheckedInt.h"
+#include <iostream>
+
+namespace CheckedInt_test {
+
+using namespace mozilla::CheckedInt_internal;
+using mozilla::CheckedInt;
+
+int g_tests_passed = 0;
+int g_tests_failed = 0;
+
+void verify_impl_function(bool x, bool expected,
+                          const char* file, int line,
+                          int T_size, bool T_is_signed)
+{
+    if (x == expected) {
+        g_tests_passed++;
+    } else {
+        g_tests_failed++;
+        std::cerr << "Test failed at " << file << ":" << line;
+        std::cerr << " with T a ";
+        if(T_is_signed)
+            std::cerr << "signed";
+        else
+            std::cerr << "unsigned";
+        std::cerr << " " << CHAR_BIT*T_size << "-bit integer type" << std::endl;
+    }
+}
+
+#define VERIFY_IMPL(x, expected) \
+    verify_impl_function((x), (expected), __FILE__, __LINE__, sizeof(T), integer_traits<T>::is_signed)
+
+#define VERIFY(x)            VERIFY_IMPL(x, true)
+#define VERIFY_IS_FALSE(x)   VERIFY_IMPL(x, false)
+#define VERIFY_IS_VALID(x)   VERIFY_IMPL((x).valid(), PR_TRUE)
+#define VERIFY_IS_INVALID(x) VERIFY_IMPL((x).valid(), PR_FALSE)
+#define VERIFY_IS_VALID_IF(x,condition) VERIFY_IMPL((x).valid(), (condition))
+
+template<typename T, unsigned int size = sizeof(T)>
+struct test_twice_bigger_type
+{
+    static void run()
+    {
+        VERIFY(integer_traits<T>::twice_bigger_type_is_supported);
+        VERIFY(sizeof(typename integer_traits<T>::twice_bigger_type)
+                    == 2 * sizeof(T));
+        VERIFY(bool(integer_traits<
+                    typename integer_traits<T>::twice_bigger_type
+                >::is_signed) == bool(integer_traits<T>::is_signed));
+    }
+};
+
+template<typename T>
+struct test_twice_bigger_type<T, 8>
+{
+    static void run()
+    {
+        VERIFY_IS_FALSE(integer_traits<T>::twice_bigger_type_is_supported);
+    }
+};
+
+
+template<typename T>
+void test()
+{
+    static bool already_run = false;
+    if (already_run) {
+        g_tests_failed++;
+        std::cerr << "You already tested this type. Copy/paste typo??" << std::endl;
+        return;
+    }
+    already_run = true;
+
+    VERIFY(integer_traits<T>::is_supported);
+    VERIFY(integer_traits<T>::size == sizeof(T));
+    enum{ is_signed = integer_traits<T>::is_signed };
+    VERIFY(bool(is_signed) == !bool(T(-1) > T(0)));
+
+    test_twice_bigger_type<T>::run();
+
+    CheckedInt<T> max_value(integer_traits<T>::max());
+    CheckedInt<T> min_value(integer_traits<T>::min());
+
+    // check min() and max(), since they are custom implementations and a mistake there
+    // could potentially NOT be caught by any other tests... while making everything wrong!
+
+    T bit = 1;
+    for(unsigned int i = 0; i < sizeof(T) * CHAR_BIT - 1; i++)
+    {
+        VERIFY((min_value.value() & bit) == 0);
+        bit <<= 1;
+    }
+    VERIFY((min_value.value() & bit) == (is_signed ? bit : T(0)));
+    VERIFY(max_value.value() == T(~(min_value.value())));
+
+    CheckedInt<T> zero(0);
+    CheckedInt<T> one(1);
+    CheckedInt<T> two(2);
+    CheckedInt<T> three(3);
+    CheckedInt<T> four(4);
+
+    /* addition / substraction checks */
+
+    VERIFY_IS_VALID(zero+zero);
+    VERIFY(zero+zero == zero);
+    VERIFY_IS_FALSE(zero+zero == one); // check that == doesn't always return true
+    VERIFY_IS_VALID(zero+one);
+    VERIFY(zero+one == one);
+    VERIFY_IS_VALID(one+one);
+    VERIFY(one+one == two);
+
+    CheckedInt<T> max_value_minus_one = max_value - one;
+    CheckedInt<T> max_value_minus_two = max_value - two;
+    VERIFY_IS_VALID(max_value_minus_one);
+    VERIFY_IS_VALID(max_value_minus_two);
+    VERIFY_IS_VALID(max_value_minus_one + one);
+    VERIFY_IS_VALID(max_value_minus_two + one);
+    VERIFY_IS_VALID(max_value_minus_two + two);
+    VERIFY(max_value_minus_one + one == max_value);
+    VERIFY(max_value_minus_two + one == max_value_minus_one);
+    VERIFY(max_value_minus_two + two == max_value);
+
+    VERIFY_IS_VALID(max_value + zero);
+    VERIFY_IS_VALID(max_value - zero);
+    VERIFY_IS_INVALID(max_value + one);
+    VERIFY_IS_INVALID(max_value + two);
+    VERIFY_IS_INVALID(max_value + max_value_minus_one);
+    VERIFY_IS_INVALID(max_value + max_value);
+
+    CheckedInt<T> min_value_plus_one = min_value + one;
+    CheckedInt<T> min_value_plus_two = min_value + two;
+    VERIFY_IS_VALID(min_value_plus_one);
+    VERIFY_IS_VALID(min_value_plus_two);
+    VERIFY_IS_VALID(min_value_plus_one - one);
+    VERIFY_IS_VALID(min_value_plus_two - one);
+    VERIFY_IS_VALID(min_value_plus_two - two);
+    VERIFY(min_value_plus_one - one == min_value);
+    VERIFY(min_value_plus_two - one == min_value_plus_one);
+    VERIFY(min_value_plus_two - two == min_value);
+
+    CheckedInt<T> min_value_minus_one = min_value - one;
+    VERIFY_IS_VALID(min_value + zero);
+    VERIFY_IS_VALID(min_value - zero);
+    VERIFY_IS_INVALID(min_value - one);
+    VERIFY_IS_INVALID(min_value - two);
+    VERIFY_IS_INVALID(min_value - min_value_minus_one);
+    VERIFY_IS_VALID(min_value - min_value);
+
+    CheckedInt<T> max_value_over_two = max_value / two;
+    VERIFY_IS_VALID(max_value_over_two + max_value_over_two);
+    VERIFY_IS_VALID(max_value_over_two + one);
+    VERIFY((max_value_over_two + one) - one == max_value_over_two);
+    VERIFY_IS_VALID(max_value_over_two - max_value_over_two);
+    VERIFY(max_value_over_two - max_value_over_two == zero);
+
+    CheckedInt<T> min_value_over_two = min_value / two;
+    VERIFY_IS_VALID(min_value_over_two + min_value_over_two);
+    VERIFY_IS_VALID(min_value_over_two + one);
+    VERIFY((min_value_over_two + one) - one == min_value_over_two);
+    VERIFY_IS_VALID(min_value_over_two - min_value_over_two);
+    VERIFY(min_value_over_two - min_value_over_two == zero);
+
+    VERIFY_IS_INVALID(min_value - one);
+    VERIFY_IS_INVALID(min_value - two);
+
+    if (is_signed) {
+        VERIFY_IS_INVALID(min_value + min_value);
+        VERIFY_IS_INVALID(min_value_over_two + min_value_over_two + min_value_over_two);
+        VERIFY_IS_INVALID(zero - min_value + min_value);
+        VERIFY_IS_INVALID(one - min_value + min_value);
+    }
+
+    /* unary operator- checks */
+
+    CheckedInt<T> neg_one = -one;
+    CheckedInt<T> neg_two = -two;
+
+    if (is_signed) {
+        VERIFY_IS_VALID(-max_value);
+        VERIFY_IS_VALID(-max_value - one);
+        VERIFY_IS_VALID(neg_one);
+        VERIFY_IS_VALID(-max_value + neg_one);
+        VERIFY_IS_VALID(neg_one + one);
+        VERIFY(neg_one + one == zero);
+        VERIFY_IS_VALID(neg_two);
+        VERIFY_IS_VALID(neg_one + neg_one);
+        VERIFY(neg_one + neg_one == neg_two);
+    } else {
+        VERIFY_IS_INVALID(neg_one);
+    }
+
+    /* multiplication checks */
+
+    VERIFY_IS_VALID(zero*zero);
+    VERIFY(zero*zero == zero);
+    VERIFY_IS_VALID(zero*one);
+    VERIFY(zero*one == zero);
+    VERIFY_IS_VALID(one*zero);
+    VERIFY(one*zero == zero);
+    VERIFY_IS_VALID(one*one);
+    VERIFY(one*one == one);
+    VERIFY_IS_VALID(one*three);
+    VERIFY(one*three == three);
+    VERIFY_IS_VALID(two*two);
+    VERIFY(two*two == four);
+
+    VERIFY_IS_INVALID(max_value * max_value);
+    VERIFY_IS_INVALID(max_value_over_two * max_value);
+    VERIFY_IS_INVALID(max_value_over_two * max_value_over_two);
+
+    CheckedInt<T> max_value_approx_sqrt(T(T(1) << (CHAR_BIT*sizeof(T)/2)));
+
+    VERIFY_IS_VALID(max_value_approx_sqrt);
+    VERIFY_IS_VALID(max_value_approx_sqrt * two);
+    VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt);
+    VERIFY_IS_INVALID(max_value_approx_sqrt * max_value_approx_sqrt * max_value_approx_sqrt);
+
+    if (is_signed) {
+        VERIFY_IS_INVALID(min_value * min_value);
+        VERIFY_IS_INVALID(min_value_over_two * min_value);
+        VERIFY_IS_INVALID(min_value_over_two * min_value_over_two);
+
+        CheckedInt<T> min_value_approx_sqrt = -max_value_approx_sqrt;
+
+        VERIFY_IS_VALID(min_value_approx_sqrt);
+        VERIFY_IS_VALID(min_value_approx_sqrt * two);
+        VERIFY_IS_INVALID(min_value_approx_sqrt * max_value_approx_sqrt);
+        VERIFY_IS_INVALID(min_value_approx_sqrt * min_value_approx_sqrt);
+    }
+
+    // make sure to check all 4 paths in signed multiplication validity check.
+    // test positive * positive
+    VERIFY_IS_VALID(max_value * one);
+    VERIFY(max_value * one == max_value);
+    VERIFY_IS_INVALID(max_value * two);
+    VERIFY_IS_VALID(max_value_over_two * two);
+    VERIFY((max_value_over_two + max_value_over_two) == (max_value_over_two * two));
+
+    if (is_signed) {
+        // test positive * negative
+        VERIFY_IS_VALID(max_value * neg_one);
+        VERIFY_IS_VALID(-max_value);
+        VERIFY(max_value * neg_one == -max_value);
+        VERIFY_IS_VALID(one * min_value);
+        VERIFY_IS_INVALID(max_value * neg_two);
+        VERIFY_IS_VALID(max_value_over_two * neg_two);
+        VERIFY_IS_VALID(two * min_value_over_two);
+        VERIFY_IS_VALID((max_value_over_two + one) * neg_two);
+        VERIFY_IS_INVALID((max_value_over_two + two) * neg_two);
+        VERIFY_IS_INVALID(two * (min_value_over_two - one));
+
+        // test negative * positive
+        VERIFY_IS_VALID(min_value * one);
+        VERIFY_IS_VALID(min_value_plus_one * one);
+        VERIFY_IS_INVALID(min_value * two);
+        VERIFY_IS_VALID(min_value_over_two * two);
+        VERIFY(min_value_over_two * two == min_value);
+        VERIFY_IS_INVALID((min_value_over_two - one) * neg_two);
+        VERIFY_IS_INVALID(neg_two * max_value);
+        VERIFY_IS_VALID(min_value_over_two * two);
+        VERIFY(min_value_over_two * two == min_value);
+        VERIFY_IS_VALID(neg_two * max_value_over_two);
+        VERIFY_IS_INVALID((min_value_over_two - one) * two);
+        VERIFY_IS_VALID(neg_two * (max_value_over_two + one));
+        VERIFY_IS_INVALID(neg_two * (max_value_over_two + two));
+
+        // test negative * negative
+        VERIFY_IS_INVALID(min_value * neg_one);
+        VERIFY_IS_VALID(min_value_plus_one * neg_one);
+        VERIFY(min_value_plus_one * neg_one == max_value);
+        VERIFY_IS_INVALID(min_value * neg_two);
+        VERIFY_IS_INVALID(min_value_over_two * neg_two);
+        VERIFY_IS_INVALID(neg_one * min_value);
+        VERIFY_IS_VALID(neg_one * min_value_plus_one);
+        VERIFY(neg_one * min_value_plus_one == max_value);
+        VERIFY_IS_INVALID(neg_two * min_value);
+        VERIFY_IS_INVALID(neg_two * min_value_over_two);
+    }
+
+    /* division checks */
+
+    VERIFY_IS_VALID(one / one);
+    VERIFY(one / one == one);
+    VERIFY_IS_VALID(three / three);
+    VERIFY(three / three == one);
+    VERIFY_IS_VALID(four / two);
+    VERIFY(four / two == two);
+    VERIFY((four*three)/four == three);
+
+    // check that div by zero is invalid
+    VERIFY_IS_INVALID(zero / zero);
+    VERIFY_IS_INVALID(one / zero);
+    VERIFY_IS_INVALID(two / zero);
+    VERIFY_IS_INVALID(neg_one / zero);
+    VERIFY_IS_INVALID(max_value / zero);
+    VERIFY_IS_INVALID(min_value / zero);
+
+    if (is_signed) {
+        // check that min_value / -1 is invalid
+        VERIFY_IS_INVALID(min_value / neg_one);
+
+        // check that the test for div by -1 isn't banning other numerators than min_value
+        VERIFY_IS_VALID(one / neg_one);
+        VERIFY_IS_VALID(zero / neg_one);
+        VERIFY_IS_VALID(neg_one / neg_one);
+        VERIFY_IS_VALID(max_value / neg_one);
+    }
+
+    /* check that invalidity is correctly preserved by arithmetic ops */
+
+    CheckedInt<T> some_invalid = max_value + max_value;
+    VERIFY_IS_INVALID(some_invalid + zero);
+    VERIFY_IS_INVALID(some_invalid - zero);
+    VERIFY_IS_INVALID(zero + some_invalid);
+    VERIFY_IS_INVALID(zero - some_invalid);
+    VERIFY_IS_INVALID(-some_invalid);
+    VERIFY_IS_INVALID(some_invalid * zero);
+    VERIFY_IS_INVALID(some_invalid * one);
+    VERIFY_IS_INVALID(zero * some_invalid);
+    VERIFY_IS_INVALID(one * some_invalid);
+    VERIFY_IS_INVALID(some_invalid / zero);
+    VERIFY_IS_INVALID(some_invalid / one);
+    VERIFY_IS_INVALID(zero / some_invalid);
+    VERIFY_IS_INVALID(one / some_invalid);
+    VERIFY_IS_INVALID(some_invalid + some_invalid);
+    VERIFY_IS_INVALID(some_invalid - some_invalid);
+    VERIFY_IS_INVALID(some_invalid * some_invalid);
+    VERIFY_IS_INVALID(some_invalid / some_invalid);
+
+    /* check that mixing checked integers with plain integers in expressions is allowed */
+
+    VERIFY(one + T(2) == three);
+    VERIFY(2 + one == three);
+    {
+        CheckedInt<T> x = one;
+        x += 2;
+        VERIFY(x == three);
+    }
+    VERIFY(two - 1 == one);
+    VERIFY(2 - one == one);
+    {
+        CheckedInt<T> x = two;
+        x -= 1;
+        VERIFY(x == one);
+    }
+    VERIFY(one * 2 == two);
+    VERIFY(2 * one == two);
+    {
+        CheckedInt<T> x = one;
+        x *= 2;
+        VERIFY(x == two);
+    }
+    VERIFY(four / 2 == two);
+    VERIFY(4 / two == two);
+    {
+        CheckedInt<T> x = four;
+        x /= 2;
+        VERIFY(x == two);
+    }
+
+    VERIFY(one == 1);
+    VERIFY(1 == one);
+    VERIFY_IS_FALSE(two == 1);
+    VERIFY_IS_FALSE(1 == two);
+    VERIFY_IS_FALSE(some_invalid == 1);
+    VERIFY_IS_FALSE(1 == some_invalid);
+
+    /* Check that construction of CheckedInt from an integer value of a mismatched type is checked */
+
+    #define VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(U) \
+    { \
+        bool is_U_signed = integer_traits<U>::is_signed; \
+        VERIFY_IS_VALID(CheckedInt<T>(U(0))); \
+        VERIFY_IS_VALID(CheckedInt<T>(U(1))); \
+        VERIFY_IS_VALID(CheckedInt<T>(U(100))); \
+        if (is_U_signed) \
+            VERIFY_IS_VALID_IF(CheckedInt<T>(U(-1)), is_signed); \
+        if (sizeof(U) > sizeof(T)) \
+            VERIFY_IS_INVALID(CheckedInt<T>(U(integer_traits<T>::max())+1)); \
+        VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::max()), \
+            (sizeof(T) > sizeof(U) || ((sizeof(T) == sizeof(U)) && (is_U_signed || !is_signed)))); \
+        VERIFY_IS_VALID_IF(CheckedInt<T>(integer_traits<U>::min()), \
+            is_U_signed == false ? 1 : \
+            bool(is_signed) == false ? 0 : \
+            sizeof(T) >= sizeof(U)); \
+    }
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt8)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint8)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt16)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint16)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt32)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint32)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRInt64)
+    VERIFY_CONSTRUCTION_FROM_INTEGER_TYPE(PRUint64)
+}
+
+} // end namespace CheckedInt_test
+
+int main()
+{
+    CheckedInt_test::test<PRInt8>();
+    CheckedInt_test::test<PRUint8>();
+    CheckedInt_test::test<PRInt16>();
+    CheckedInt_test::test<PRUint16>();
+    CheckedInt_test::test<PRInt32>();
+    CheckedInt_test::test<PRUint32>();
+    CheckedInt_test::test<PRInt64>();
+    CheckedInt_test::test<PRUint64>();
+
+    std::cerr << CheckedInt_test::g_tests_failed << " tests failed, "
+              << CheckedInt_test::g_tests_passed << " tests passed out of "
+              << CheckedInt_test::g_tests_failed + CheckedInt_test::g_tests_passed
+              << " tests." << std::endl;
+
+    return CheckedInt_test::g_tests_failed > 0;
+}
--- a/xpcom/typelib/xpt/tools/xpt_dump.c
+++ b/xpcom/typelib/xpt/tools/xpt_dump.c
@@ -55,17 +55,17 @@ static void perror(const char* a) {}
 #endif
 
 #define BASE_INDENT 3
 
 static char *type_array[32] = 
             {"int8",        "int16",       "int32",       "int64",
              "uint8",       "uint16",      "uint32",      "uint64",
              "float",       "double",      "boolean",     "char",
-             "wchar_t",     "void",        "reserved",    "reserved",
+             "wchar_t",     "void",        "nsIID",       "reserved",
              "reserved",    "reserved",    "reserved",    "reserved",
              "reserved",    "reserved",    "reserved",    "reserved",
              "reserved",    "reserved",    "jsval",       "reserved",
              "reserved",    "reserved",    "reserved",    "reserved"};
 
 static char *ptype_array[32] = 
             {"int8 *",      "int16 *",     "int32 *",     "int64 *",
              "uint8 *",     "uint16 *",    "uint32 *",    "uint64 *",