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 idunknown
push userunknown
push dateunknown
milestone2.0b2pre
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 *",