Merge mozilla-central and mozilla-inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Sat, 27 Aug 2011 10:40:12 +0200
changeset 75981 6c8a909977d32284bbddd60a45e1780e824b5d7c
parent 75951 906413a7ae6b6894e0f5f67cceaebe84008c940f (current diff)
parent 75980 bbb80094e71ac267a31142e902f57568f63caa87 (diff)
child 76002 0ac24f429e24d7f46731e9698d3f889bda63e2cb
child 76003 61f9ec712a1c9e6244248bb67a004036778781e9
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone9.0a1
Merge mozilla-central and mozilla-inbound
content/base/public/nsINode.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/test/test_bug557628.html
content/xul/document/public/nsIXULPrototypeCache.h
mobile/themes/core/honeycomb/images/check-30.png
mobile/themes/core/honeycomb/images/check-selected-30.png
mobile/themes/core/honeycomb/images/check-unselected-30.png
modules/libpr0n/test/crashtests/crashtests.list
testing/mochitest/redirect.js
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -10,16 +10,17 @@ builtin(include, build/autoconf/nss.m4)d
 builtin(include, build/autoconf/pkg.m4)dnl
 builtin(include, build/autoconf/freetype2.m4)dnl
 builtin(include, build/autoconf/codeset.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/mozheader.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
+builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
 
 # Read the user's .mozconfig script.  We can't do this in
 # configure.in: autoconf puts the argument parsing code above anything
 # expanded from configure.in, and we need to get the configure options
 # from .mozconfig in place before that argument parsing code.
 MOZ_READ_MOZCONFIG(.)
--- a/browser/base/content/aboutHome.css
+++ b/browser/base/content/aboutHome.css
@@ -95,17 +95,21 @@ a:hover {
   max-width: 1830px;
   margin: 0 auto;
 }
 
 @media all and (max-height: 700px) {
   #searchContainer { height: 20% }
 }
 
-@media all and (max-height: 450px) {
+@media all and (max-height: 500px) {
+  #searchContainer { height: 25% }
+}
+
+@media all and (max-height: 370px) {
   #searchContainer { height: 30% }
 }
 
 #searchLogoContainer {
   display: table-cell;
   width: 30%;
   text-align: end;
   line-height: 32px;
@@ -274,20 +278,20 @@ body[dir=rtl] #searchSubmit:active {
   content: url("chrome://browser/content/aboutHome-snippet2.png");
 }
 
 #sessionRestoreContainer {
   padding-top: 1.5%;
   text-align: center;
 }
 
-@media all and (max-height: 370px) {
+@media all and (max-height: 500px) {
   #sessionRestoreContainer {
     position: relative;
-    top: -5px;
+    top: -15px;
     padding-top: 0;
   }
 }
 
 #restorePreviousSession {
   padding: 10px;
   border: 0;
   border-radius: 4px;
@@ -355,8 +359,14 @@ body[dir=rtl] #restorePreviousSession::b
 #bottomSection {
   position: absolute;
   color: rgb(150,150,150);
   font-size: .8em;
   width: 100%;
   text-align: center;
   bottom: 2%;
 }
+
+@media all and (max-height: 370px) {
+  #bottomSection {
+    visibility: hidden;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/build/autoconf/gcc-pr49911.m4
@@ -0,0 +1,67 @@
+dnl Check if the compiler is gcc and has PR49911. If so
+dnl disable vrp.
+
+AC_DEFUN([MOZ_GCC_PR49911],
+[
+if test "$GNU_CC"; then
+
+AC_MSG_CHECKING(for gcc PR49911)
+ac_have_gcc_pr49911="no"
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+
+_SAVE_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-O2"
+AC_TRY_RUN([
+extern "C" void abort(void);
+typedef enum {
+eax,         ecx,         edx,         ebx,         esp,         ebp,
+esi,         edi     }
+RegisterID;
+union StateRemat {
+  RegisterID reg_;
+  int offset_;
+};
+static StateRemat FromRegister(RegisterID reg) {
+  StateRemat sr;
+  sr.reg_ = reg;
+  return sr;
+}
+static StateRemat FromAddress3(int address) {
+  StateRemat sr;
+  sr.offset_ = address;
+  if (address < 46 &&    address >= 0) {
+    abort();
+  }
+  return sr;
+}
+struct FrameState {
+  StateRemat dataRematInfo2(bool y, int z) {
+    if (y)         return FromRegister(RegisterID(1));
+    return FromAddress3(z);
+  }
+};
+FrameState frame;
+StateRemat x;
+__attribute__((noinline)) void jsop_setelem(bool y, int z) {
+  x = frame.dataRematInfo2(y, z);
+}
+int main(void) {
+  jsop_setelem(0, 47);
+}
+], true,
+   ac_have_gcc_pr49911="yes",
+   true)
+CXXFLAGS="$_SAVE_CXXFLAGS"
+
+AC_LANG_RESTORE
+
+if test "$ac_have_gcc_pr49911" == "yes"; then
+   AC_MSG_RESULT(yes)
+   CFLAGS="$CFLAGS -fno-tree-vrp"
+   CXXFLAGS="$CXXFLAGS -fno-tree-vrp"
+else
+   AC_MSG_RESULT(no)
+fi
+fi
+])
--- a/build/mobile/devicemanagerADB.py
+++ b/build/mobile/devicemanagerADB.py
@@ -8,16 +8,17 @@ class DeviceManagerADB(DeviceManager):
 
   def __init__(self, host = None, port = 20701, retrylimit = 5, packageName = None):
     self.host = host
     self.port = port
     self.retrylimit = retrylimit
     self.retries = 0
     self._sock = None
     self.useRunAs = False
+    self.packageName = None
     if packageName == None:
       if os.getenv('USER'):
         packageName = 'org.mozilla.fennec_' + os.getenv('USER')
       else:
         packageName = 'org.mozilla.fennec_'
     self.Init(packageName)
 
   def Init(self, packageName):
--- a/chrome/src/nsChromeProtocolHandler.cpp
+++ b/chrome/src/nsChromeProtocolHandler.cpp
@@ -64,24 +64,16 @@
 #include "nsIServiceManager.h"
 #include "nsIStandardURL.h"
 #include "nsIStreamListener.h"
 #include "nsNetUtil.h"
 #include "nsXPIDLString.h"
 #include "nsString.h"
 #include "prlog.h"
 
-#ifdef MOZ_XUL
-#include "nsIXULPrototypeCache.h"
-#endif
-
-//----------------------------------------------------------------------
-
-static NS_DEFINE_CID(kXULPrototypeCacheCID,      NS_XULPROTOTYPECACHE_CID);
-
 ////////////////////////////////////////////////////////////////////////////////
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsChromeProtocolHandler,
                               nsIProtocolHandler,
                               nsISupportsWeakReference)
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsIProtocolHandler methods:
--- a/configure.in
+++ b/configure.in
@@ -2112,18 +2112,16 @@ case "$target" in
     AC_TRY_LINK(,[return 0;],
                 ac_cv_have_framework_exceptionhandling="yes",
                 ac_cv_have_framework_exceptionhandling="no")
     AC_MSG_RESULT([$ac_cv_have_framework_exceptionhandling])
     if test "$ac_cv_have_framework_exceptionhandling" = "yes"; then
       MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling";
     fi
     LDFLAGS=$_SAVE_LDFLAGS
-    # Debug builds should always have frame pointers
-    MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
 
     if test "x$lto_is_enabled" = "xyes"; then
         echo "Skipping -dead_strip because lto is enabled."
     dnl DTrace and -dead_strip don't interact well. See bug 403132.
     dnl ===================================================================
     elif test "x$enable_dtrace" = "xyes"; then
         echo "Skipping -dead_strip because DTrace is enabled. See bug 403132."
     else
@@ -2260,18 +2258,16 @@ ia64*-hpux*)
 
     MOZ_GFX_OPTIMIZE_MOBILE=1
     # If we're building with --enable-profiling, we need a frame pointer.
     if test -z "$MOZ_PROFILING"; then
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer"
     else
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer"
     fi
-    # Debug builds should always have frame pointers
-    MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
     ;;
 
 *-*linux*)
     # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler.
     # Similarly for GNU_CXX and INTEL_CXX.
     if test "$INTEL_CC" -o "$INTEL_CXX"; then
         # -Os has been broken on Intel's C/C++ compilers for quite a
         # while; Intel recommends against using it.
@@ -2287,18 +2283,17 @@ ia64*-hpux*)
         # If we're building with --enable-profiling, we need a frame pointer.
         if test -z "$MOZ_PROFILING"; then
             MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer"
         else
             MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer"
         fi
         MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS"
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS"
-        # Debug builds should always have frame pointers
-        MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
+        MOZ_DEBUG_FLAGS="-g"
     fi
 
     TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
 
     MOZ_MEMORY=1
 
     case "${target_cpu}" in
     alpha*)
@@ -2381,18 +2376,17 @@ ia64*-hpux*)
         _DEFINES_CXXFLAGS='-FI $(DEPTH)/dist/include/mozilla-config.h -DMOZILLA_CLIENT'
         CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -wd4800" # disable warning "forcing value to bool"
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib"
-        # Debug builds should always have frame pointers
-        MOZ_DEBUG_FLAGS='-Zi -Oy-'
+        MOZ_DEBUG_FLAGS='-Zi'
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer.
         if test -z "$MOZ_PROFILING"; then
             MOZ_OPTIMIZE_FLAGS='-O1'
         else
             MOZ_OPTIMIZE_FLAGS='-O1 -Oy-'
         fi
@@ -3238,16 +3232,18 @@ fi         # GNU_CC
 # visibility hidden flag for Sun Studio on Solaris
 if test "$SOLARIS_SUNPRO_CC"; then
 VISIBILITY_FLAGS='-xldscope=hidden'
 fi         # Sun Studio on Solaris
 
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
+MOZ_GCC_PR49911
+
 dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
 dnl ========================================================
 if test "$GNU_CC"; then
   CFLAGS_save="${CFLAGS}"
   CFLAGS="${CFLAGS} -Werror"
   AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute,
                  ac_cv_force_align_arg_pointer,
                  [AC_TRY_COMPILE([__attribute__ ((__force_align_arg_pointer__)) void test() {}],
--- a/content/base/public/nsContentCID.h
+++ b/content/base/public/nsContentCID.h
@@ -181,20 +181,16 @@
 // {1abdcc96-1dd2-11b2-b520-f8f59cdd67bc}
 #define NS_XULTREEBUILDER_CID \
 { 0x1abdcc96, 0x1dd2, 0x11b2, { 0xb5, 0x20, 0xf8, 0xf5, 0x9c, 0xdd, 0x67, 0xbc } }
 
 // {541AFCB2-A9A3-11d2-8EC5-00805F29F370}
 #define NS_XULDOCUMENT_CID \
 { 0x541afcb2, 0xa9a3, 0x11d2, { 0x8e, 0xc5, 0x0, 0x80, 0x5f, 0x29, 0xf3, 0x70 } }
 
-// {3A0A0FC1-8349-11d3-BE47-00104BDE6048}
-#define NS_XULPROTOTYPECACHE_CID \
-{ 0x3a0a0fc1, 0x8349, 0x11d3, { 0xbe, 0x47, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } }
-
 // {a6cf9126-15b3-11d2-932e-00805f8add32}
 #define NS_RANGEUTILS_CID \
 { 0xa6cf9126, 0x15b3, 0x11d2, {0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32 } }
 
 #define NS_SVGDOCUMENT_CID                        \
 { /* b7f44954-1dd1-11b2-8c2e-c2feab4186bc */      \
   0xb7f44954, 0x11d1, 0x11b2,                     \
   {0x8c, 0x2e, 0xc2, 0xfe, 0xab, 0x41, 0x86, 0xbc}}
--- a/content/base/public/nsINode.h
+++ b/content/base/public/nsINode.h
@@ -928,52 +928,16 @@ public:
 
   /**
    * Implementation is in nsIDocument.h, because it needs to cast from
    * nsIDocument* to nsINode*.
    */
   nsIDocument* GetOwnerDocument() const;
 
   /**
-   * Iterator that can be used to easily iterate over the children.  This has
-   * the same restrictions on its use as GetChildArray does.
-   */
-  class ChildIterator {
-  public:
-    ChildIterator(const nsINode* aNode) { Init(aNode); }
-    ChildIterator(const nsINode* aNode, PRUint32 aOffset) {
-      Init(aNode);
-      Advance(aOffset);
-    }
-    ~ChildIterator() {
-      NS_ASSERTION(!mGuard.Mutated(0), "Unexpected mutations happened");
-    }
-
-    PRBool IsDone() const { return mCur == mEnd; }
-    operator nsIContent*() const { return *mCur; }
-    void Next() { NS_PRECONDITION(mCur != mEnd, "Check IsDone"); ++mCur; }
-    void Advance(PRUint32 aOffset) {
-      NS_ASSERTION(mCur + aOffset <= mEnd, "Unexpected offset");
-      mCur += aOffset;
-    }
-  private:
-    void Init(const nsINode* aNode) {
-      NS_PRECONDITION(aNode, "Must have node here!");
-      PRUint32 childCount;
-      mCur = aNode->GetChildArray(&childCount);
-      mEnd = mCur + childCount;
-    }
-#ifdef DEBUG
-    nsMutationGuard mGuard;
-#endif
-    nsIContent* const * mCur;
-    nsIContent* const * mEnd;
-  };
-
-  /**
    * The default script type (language) ID for this node.
    * All nodes must support fetching the default script language.
    */
   virtual PRUint32 GetScriptTypeID() const
   { return nsIProgrammingLanguage::JAVASCRIPT; }
 
   /**
    * Not all nodes support setting a new default language.
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -728,18 +728,20 @@ nsGenericHTMLElement::FireMutationEvents
   // Fire mutation events. Optimize for the case when there are no listeners
   PRInt32 newChildCount = aDest->GetChildCount();
   if (newChildCount && nsContentUtils::
         HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
     nsAutoTArray<nsCOMPtr<nsIContent>, 50> childNodes;
     NS_ASSERTION(newChildCount - aOldChildCount >= 0,
                  "What, some unexpected dom mutation has happened?");
     childNodes.SetCapacity(newChildCount - aOldChildCount);
-    for (nsINode::ChildIterator iter(aDest); !iter.IsDone(); iter.Next()) {
-      childNodes.AppendElement(iter);
+    for (nsIContent* child = aDest->GetFirstChild();
+         child;
+         child = child->GetNextSibling()) {
+      childNodes.AppendElement(child);
     }
     nsGenericElement::FireNodeInserted(aDoc, aDest, childNodes);
   }
 }
 
 nsresult
 nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
 {
--- a/content/html/content/src/nsHTMLCanvasElement.cpp
+++ b/content/html/content/src/nsHTMLCanvasElement.cpp
@@ -223,16 +223,19 @@ nsHTMLCanvasElement::ExtractData(const n
 {
   // note that if we don't have a current context, the spec says we're
   // supposed to just return transparent black pixels of the canvas
   // dimensions.
   nsRefPtr<gfxImageSurface> emptyCanvas;
   nsIntSize size = GetWidthHeight();
   if (!mCurrentContext) {
     emptyCanvas = new gfxImageSurface(gfxIntSize(size.width, size.height), gfxASurface::ImageFormatARGB32);
+    if (emptyCanvas->CairoStatus()) {
+      return NS_ERROR_INVALID_ARG;
+    }
   }
 
   nsresult rv;
 
   // get image bytes
   nsCOMPtr<nsIInputStream> imgStream;
   NS_ConvertUTF16toUTF8 encoderType(aType);
 
--- a/content/html/content/test/Makefile.in
+++ b/content/html/content/test/Makefile.in
@@ -208,17 +208,16 @@ include $(topsrcdir)/config/rules.mk
 		test_bug588683-2.html \
 		test_bug588683-3.html \
 		test_bug588683-4.html \
 		test_bug590353-1.html \
 		test_bug590353-2.html \
 		test_bug593689.html \
 		test_bug561636.html \
 		test_bug590363.html \
-		test_bug557628.html \
 		test_bug592802.html \
 		test_bug595429.html \
 		test_bug595447.html \
 		test_bug595449.html \
 		test_bug557087-1.html \
 		test_bug557087-2.html \
 		test_bug557087-3.html \
 		test_bug557087-4.html \
--- a/content/html/content/test/forms/test_form_attributes_reflection.html
+++ b/content/html/content/test/forms/test_form_attributes_reflection.html
@@ -10,28 +10,78 @@
 <p id="display"></p>
 <div id="content" style="display: none">
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for HTMLFormElement attributes reflection **/
 
-// TODO: acceptCharset
-// TODO: action
-// TODO: autocomplete
-// TODO: enctype
-// TODO: encoding
-// TODO: method
-// TODO: name
+// .acceptCharset
+reflectString({
+  element: document.createElement("form"),
+  attribute: { idl: "acceptCharset", content: "accept-charset" },
+  otherValues: [ "ISO-8859-1", "UTF-8" ],
+});
+
+// TODO: action (URL)
+
+// .autocomplete
+reflectLimitedEnumerated({
+  element: document.createElement("form"),
+  attribute: "autocomplete",
+  validValues: [ "on", "off" ],
+  invalidValues: [ "", "foo", "tulip", "default" ],
+  defaultValue: "on",
+});
+
+// .enctype
+reflectLimitedEnumerated({
+  element: document.createElement("form"),
+  attribute: "enctype",
+  validValues: [ "application/x-www-form-urlencoded", "multipart/form-data",
+                 "text/plain" ],
+  invalidValues: [ "", "foo", "tulip", "multipart/foo" ],
+  defaultValue: "application/x-www-form-urlencoded"
+});
+
+// .encoding
+reflectLimitedEnumerated({
+  element: document.createElement("form"),
+  attribute: { idl: "encoding", content: "enctype" },
+  validValues: [ "application/x-www-form-urlencoded", "multipart/form-data",
+                 "text/plain" ],
+  invalidValues: [ "", "foo", "tulip", "multipart/foo" ],
+  defaultValue: "application/x-www-form-urlencoded"
+});
+
+// .method
+reflectLimitedEnumerated({
+  element: document.createElement("form"),
+  attribute: "method",
+  validValues: [ "get", "post" ],
+  invalidValues: [ "", "foo", "tulip" ],
+  defaultValue: "get"
+});
+
+// .name
+reflectString({
+  element: document.createElement("form"),
+  attribute: "name",
+});
 
 // .noValidate
 reflectBoolean({
   element: document.createElement("form"),
   attribute: "noValidate",
 });
 
-// TODO: target
+// .target
+reflectString({
+  element: document.createElement("form"),
+  attribute: "target",
+  otherValues: [ "_blank", "_self", "_parent", "_top" ],
+});
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/html/content/test/reflect.js
+++ b/content/html/content/test/reflect.js
@@ -232,118 +232,123 @@ function reflectUnsignedInt(aParameters)
 
 /**
  * Checks that a given attribute is correctly reflected as limited to known
  * values enumerated attribute.
  *
  * @param aParameters    Object    object containing the parameters, which are:
  *  - element            Element   node to test on
  *  - attribute          String    name of the attribute
+ *     OR
+ *    attribute          Object    object containing two attributes, 'content' and 'idl'
  *  - validValues        Array     valid values we support
  *  - invalidValues      Array     invalid values
  *  - defaultValue       String    [optional] default value when no valid value is set
  *  - unsupportedValues  Array     [optional] valid values we do not support
  */
 function reflectLimitedEnumerated(aParameters)
 {
   var element = aParameters.element;
-  var attr = aParameters.attribute;
+  var contentAttr = typeof aParameters.attribute === "string"
+                      ? aParameters.attribute : aParameters.attribute.content;
+  var idlAttr = typeof aParameters.attribute === "string"
+                  ? aParameters.attribute : aParameters.attribute.idl;
   var validValues = aParameters.validValues;
   var invalidValues = aParameters.invalidValues;
   var defaultValue = aParameters.defaultValue !== undefined
-    ? aParameters.defaultValue : "";
+                       ? aParameters.defaultValue : "";
   var unsupportedValues = aParameters.unsupportedValues !== undefined
-    ? aParameters.unsupportedValues : [];
+                            ? aParameters.unsupportedValues : [];
 
-  ok(attr in element, attr + " should be an IDL attribute of this element");
-  is(typeof element[attr], "string", attr + " IDL attribute should be a string");
+  ok(idlAttr in element, idlAttr + " should be an IDL attribute of this element");
+  is(typeof element[idlAttr], "string", idlAttr + " IDL attribute should be a string");
 
   // Explicitly check the default value.
-  element.removeAttribute(attr);
-  is(element[attr], defaultValue,
+  element.removeAttribute(contentAttr);
+  is(element[idlAttr], defaultValue,
      "When no attribute is set, the value should be the default value.");
 
   // Check valid values.
   validValues.forEach(function (v) {
-    element.setAttribute(attr, v);
-    is(element[attr], v,
-       v + " should be accepted as a valid value for " + attr);
-    is(element.getAttribute(attr), v,
+    element.setAttribute(contentAttr, v);
+    is(element[idlAttr], v,
+       v + " should be accepted as a valid value for " + idlAttr);
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should return the value it has been set to.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element.setAttribute(attr, v.toUpperCase());
-    is(element[attr], v,
+    element.setAttribute(contentAttr, v.toUpperCase());
+    is(element[idlAttr], v,
        "Enumerated attributes should be case-insensitive.");
-    is(element.getAttribute(attr), v.toUpperCase(),
+    is(element.getAttribute(contentAttr), v.toUpperCase(),
        "Content attribute should not be lower-cased.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element[attr] = v;
-    is(element[attr], v,
-       v + " should be accepted as a valid value for " + attr);
-    is(element.getAttribute(attr), v,
+    element[idlAttr] = v;
+    is(element[idlAttr], v,
+       v + " should be accepted as a valid value for " + idlAttr);
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should return the value it has been set to.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element[attr] = v.toUpperCase();
-    is(element[attr], v,
+    element[idlAttr] = v.toUpperCase();
+    is(element[idlAttr], v,
        "Enumerated attributes should be case-insensitive.");
-    is(element.getAttribute(attr), v.toUpperCase(),
+    is(element.getAttribute(contentAttr), v.toUpperCase(),
        "Content attribute should not be lower-cased.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
   });
 
   // Check invalid values.
   invalidValues.forEach(function (v) {
-    element.setAttribute(attr, v);
-    is(element[attr], defaultValue,
+    element.setAttribute(contentAttr, v);
+    is(element[idlAttr], defaultValue,
        "When the content attribute is set to an invalid value, the default value should be returned.");
-    is(element.getAttribute(attr), v,
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should not have been changed.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element[attr] = v;
-    is(element[attr], defaultValue,
+    element[idlAttr] = v;
+    is(element[idlAttr], defaultValue,
        "When the value is set to an invalid value, the default value should be returned.");
-    is(element.getAttribute(attr), v,
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should not have been changed.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
   });
 
   // Check valid values we currently do not support.
   // Basically, it's like the checks for the valid values but with some todo's.
   unsupportedValues.forEach(function (v) {
-    element.setAttribute(attr, v);
-    todo_is(element[attr], v,
-            v + " should be accepted as a valid value for " + attr);
-    is(element.getAttribute(attr), v,
+    element.setAttribute(contentAttr, v);
+    todo_is(element[idlAttr], v,
+            v + " should be accepted as a valid value for " + idlAttr);
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should return the value it has been set to.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element.setAttribute(attr, v.toUpperCase());
-    todo_is(element[attr], v,
+    element.setAttribute(contentAttr, v.toUpperCase());
+    todo_is(element[idlAttr], v,
             "Enumerated attributes should be case-insensitive.");
-    is(element.getAttribute(attr), v.toUpperCase(),
+    is(element.getAttribute(contentAttr), v.toUpperCase(),
        "Content attribute should not be lower-cased.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element[attr] = v;
-    todo_is(element[attr], v,
-            v + " should be accepted as a valid value for " + attr);
-    is(element.getAttribute(attr), v,
+    element[idlAttr] = v;
+    todo_is(element[idlAttr], v,
+            v + " should be accepted as a valid value for " + idlAttr);
+    is(element.getAttribute(contentAttr), v,
        "Content attribute should return the value it has been set to.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
 
-    element[attr] = v.toUpperCase();
-    todo_is(element[attr], v,
+    element[idlAttr] = v.toUpperCase();
+    todo_is(element[idlAttr], v,
             "Enumerated attributes should be case-insensitive.");
-    is(element.getAttribute(attr), v.toUpperCase(),
+    is(element.getAttribute(contentAttr), v.toUpperCase(),
        "Content attribute should not be lower-cased.");
-    element.removeAttribute(attr);
+    element.removeAttribute(contentAttr);
   });
 }
 
 /**
  * Checks that a given attribute is correctly reflected as a boolean.
  *
  * @param aParameters    Object    object containing the parameters, which are:
  *  - element            Element   node to test on
deleted file mode 100644
--- a/content/html/content/test/test_bug557628.html
+++ /dev/null
@@ -1,71 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=557628
--->
-<head>
-  <title>Test for Bug 557628</title>
-  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=557628">Mozilla Bug 557628</a>
-<p id="display"></p>
-<pre id="test">
-<script type="application/javascript">
-
-/** Test for Bug 557628 **/
-
-var formAutocompleteTestData = [
-  // Default value.
-  [ "on" ],
-  // Valid values.
-  [ "on", "off" ],
-  // Invalid values.
-  [ "", " ", "foo", "default" ]
-];
-
-function checkAttribute(element, name, data)
-{
-  is(element.getAttribute(name), undefined,
-     "By default " + name + " content attribute should be undefined");
-  is(element[name], data[0][0],
-     "By default " + name + " IDL attribute should be equal to " +
-     data[0][0]);
-
-  // Valid values.
-  for (i in data[1]) {
-    element.setAttribute(name, data[1][i]);
-    is(element.getAttribute(name), data[1][i],
-       "getAttribute should return the content attribute");
-    is(element[name], data[1][i], "When getting, " + name + " IDL attribute " +
-       "should be equal to the content attribute if the value is known");
-  }
-
-  // Invalid values.
-  for (i in data[2]) {
-    element.setAttribute(name, data[2][i]);
-    is(element.getAttribute(name), data[2][i],
-       "getAttribute should return the content attribute");
-    is(element[name], data[0][0], "When getting, " + name + " IDL attribute " +
-       "should return the default value if the content attribute value isn't known");
-  }
-
-  // TODO values.
-  for (i in data[3]) {
-    element.setAttribute(name, data[3][i]);
-    is(element.getAttribute(name), data[3][i],
-       "getAttribute should return the content attribute");
-    todo_is(element[name], data[3][i], "When getting, " + name + " IDL attribute " +
-       "should be equal to the content attribute if the value is known");
-  }
-}
-
-var form = document.createElement('form');
-
-checkAttribute(form, 'autocomplete', formAutocompleteTestData);
-
-</script>
-</pre>
-</body>
-</html>
--- a/content/html/content/test/test_bug585508.html
+++ b/content/html/content/test/test_bug585508.html
@@ -56,20 +56,17 @@ function checkAttribute(form, attrName, 
     form.setAttribute(attrName, data[2][i]);
     is(form.getAttribute(attrName), data[2][i],
        "getAttribute should return the content attribute");
     is(form[idlName], data[0][0], "When getting, " + idlName + " IDL attribute " +
        "should return the default value if the content attribute value isn't known");
   }
 }
 
-var form = document.createElement('form');
 var button = document.createElement('button');
 
-checkAttribute(form, 'enctype', 'enctype', enctypeTestData);
-checkAttribute(form, 'method', 'method', methodTestData);
 checkAttribute(button, 'formenctype', 'formEnctype', enctypeTestData);
 checkAttribute(button, 'formmethod', 'formMethod', methodTestData);
 
 </script>
 </pre>
 </body>
 </html>
--- a/content/xul/document/public/Makefile.in
+++ b/content/xul/document/public/Makefile.in
@@ -52,14 +52,13 @@ XPIDLSRCS	= \
 
 ifdef MOZ_XUL
 XPIDLSRCS += \
 		nsIXULOverlayProvider.idl \
 		$(NULL)
 
 EXPORTS		= \
 		nsIXULDocument.h \
-		nsIXULPrototypeCache.h \
 		$(NULL)
 endif
 
 include $(topsrcdir)/config/rules.mk
 
deleted file mode 100644
--- a/content/xul/document/public/nsIXULPrototypeCache.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* ***** 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 Communicator client code.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Ben Goodger <ben@netscape.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of 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 nsIXULPrototypeCache_h__
-#define nsIXULPrototypeCache_h__
-
-#include "nsISupports.h"
-class nsIURI;
-
-// {3A0A0FC1-8349-11d3-BE47-00104BDE6048}
-#define NS_XULPROTOTYPECACHE_CID \
-{ 0x3a0a0fc1, 0x8349, 0x11d3, { 0xbe, 0x47, 0x0, 0x10, 0x4b, 0xde, 0x60, 0x48 } }
-
-// {f8bee3d7-4be8-46ae-92c2-60c25d5cd647}
-#define NS_IXULPROTOTYPECACHE_IID \
-{ 0xf8bee3d7, 0x4be8, 0x46ae, \
-  { 0x92, 0xc2, 0x60, 0xc2, 0x5d, 0x5c, 0xd6, 0x47 } }
-
-/**
- * This interface lets code from outside gklayout access the prototype cache.
- */
-class nsIXULPrototypeCache : public nsISupports
-{
-public:
-    NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXULPROTOTYPECACHE_IID)
-
-    /**
-     * Whether the XUL document at the specified URI is in the cache.
-     */
-    virtual PRBool IsCached(nsIURI* aURI) = 0;
-
-    /**
-     * Stop the caching process abruptly, removing the cache file.
-     */
-    virtual void AbortCaching() = 0;
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(nsIXULPrototypeCache, NS_IXULPROTOTYPECACHE_IID)
-
-nsresult
-NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult);
-
-
-const char XUL_FASTLOAD_FILE_BASENAME[] = "XUL";
-
-// Increase the subtractor when changing version, say when changing the
-// (opaque to XPCOM FastLoad code) format of XUL-specific XDR serializations.
-// See also JSXDR_BYTECODE_VERSION in jsxdrapi.h, which tracks incompatible JS
-// bytecode version changes.
-#define XUL_FASTLOAD_FILE_VERSION       (0xfeedbeef - 25)
-
-#define XUL_SERIALIZATION_BUFFER_SIZE   (64 * 1024)
-#define XUL_DESERIALIZATION_BUFFER_SIZE (8 * 1024)
-
-
-#endif // nsIXULPrototypeCache_h__
--- a/content/xul/document/src/nsXULDocument.h
+++ b/content/xul/document/src/nsXULDocument.h
@@ -55,17 +55,16 @@
 #include "nsIURI.h"
 #include "nsIXULDocument.h"
 #include "nsScriptLoader.h"
 #include "nsIStreamListener.h"
 #include "nsICSSLoaderObserver.h"
 
 class nsIRDFResource;
 class nsIRDFService;
-class nsIXULPrototypeCache;
 class nsPIWindowRoot;
 #if 0 // XXXbe save me, scc (need NSCAP_FORWARD_DECL(nsXULPrototypeScript))
 class nsIObjectInputStream;
 class nsIObjectOutputStream;
 class nsIXULPrototypeScript;
 #else
 #include "nsIObjectInputStream.h"
 #include "nsIObjectOutputStream.h"
--- a/content/xul/document/src/nsXULPrototypeCache.cpp
+++ b/content/xul/document/src/nsXULPrototypeCache.cpp
@@ -64,18 +64,16 @@
 
 #include "mozilla/Preferences.h"
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::scache;
 
-static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
-
 static PRBool gDisableXULCache = PR_FALSE; // enabled by default
 static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
 static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache";
 static const char kXULCachePrefix[] = "xulcache";
 
 //----------------------------------------------------------------------
 
 static int
@@ -104,75 +102,47 @@ nsXULPrototypeCache::nsXULPrototypeCache
 
 
 nsXULPrototypeCache::~nsXULPrototypeCache()
 {
     FlushScripts();
 }
 
 
-NS_IMPL_THREADSAFE_ISUPPORTS2(nsXULPrototypeCache,
-                              nsIXULPrototypeCache,
-                              nsIObserver)
-
-
-nsresult
-NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
-{
-    NS_PRECONDITION(! aOuter, "no aggregation");
-    if (aOuter)
-        return NS_ERROR_NO_AGGREGATION;
-
-    nsRefPtr<nsXULPrototypeCache> result = new nsXULPrototypeCache();
-    if (! result)
-        return NS_ERROR_OUT_OF_MEMORY;
-
-    if (!(result->mPrototypeTable.Init() &&
-          result->mStyleSheetTable.Init() &&
-          result->mScriptTable.Init() &&
-          result->mXBLDocTable.Init())) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    if (!(result->mCacheURITable.Init() &&
-          result->mInputStreamTable.Init() &&
-          result->mOutputStreamTable.Init())) {
-        return NS_ERROR_OUT_OF_MEMORY;
-    }
-
-    // XXX Ignore return values.
-    gDisableXULCache =
-        Preferences::GetBool(kDisableXULCachePref, gDisableXULCache);
-    Preferences::RegisterCallback(DisableXULCacheChangedCallback,
-                                  kDisableXULCachePref);
-
-    nsresult rv = result->QueryInterface(aIID, aResult);
-
-    nsCOMPtr<nsIObserverService> obsSvc =
-        mozilla::services::GetObserverService();
-    if (obsSvc && NS_SUCCEEDED(rv)) {
-        nsXULPrototypeCache *p = result;
-        obsSvc->AddObserver(p, "chrome-flush-skin-caches", PR_FALSE);
-        obsSvc->AddObserver(p, "chrome-flush-caches", PR_FALSE);
-        obsSvc->AddObserver(p, "startupcache-invalidate", PR_FALSE);
-    }
-
-    return rv;
-}
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsXULPrototypeCache, nsIObserver)
 
 /* static */ nsXULPrototypeCache*
 nsXULPrototypeCache::GetInstance()
 {
-    // Theoretically this can return nsnull and callers should handle that.
     if (!sInstance) {
-        nsIXULPrototypeCache* cache;
+        NS_ADDREF(sInstance = new nsXULPrototypeCache());
+
+        sInstance->mPrototypeTable.Init();
+        sInstance->mStyleSheetTable.Init();
+        sInstance->mScriptTable.Init();
+        sInstance->mXBLDocTable.Init();
+
+        sInstance->mCacheURITable.Init();
+        sInstance->mInputStreamTable.Init();
+        sInstance->mOutputStreamTable.Init();
 
-        CallGetService(kXULPrototypeCacheCID, &cache);
+        gDisableXULCache =
+            Preferences::GetBool(kDisableXULCachePref, gDisableXULCache);
+        Preferences::RegisterCallback(DisableXULCacheChangedCallback,
+                                      kDisableXULCachePref);
 
-        sInstance = static_cast<nsXULPrototypeCache*>(cache);
+        nsCOMPtr<nsIObserverService> obsSvc =
+            mozilla::services::GetObserverService();
+        if (obsSvc) {
+            nsXULPrototypeCache *p = sInstance;
+            obsSvc->AddObserver(p, "chrome-flush-skin-caches", PR_FALSE);
+            obsSvc->AddObserver(p, "chrome-flush-caches", PR_FALSE);
+            obsSvc->AddObserver(p, "startupcache-invalidate", PR_FALSE);
+        }
+		
     }
     return sInstance;
 }
 
 /* static */ StartupCache*
 nsXULPrototypeCache::GetStartupCache()
 {
     return gStartupCache;
@@ -582,19 +552,17 @@ static int
 CachePrefChangedCallback(const char* aPref, void* aClosure)
 {
     PRBool wasEnabled = !gDisableXULDiskCache;
     gDisableXULDiskCache =
         Preferences::GetBool(kDisableXULCachePref,
                              gDisableXULDiskCache);
 
     if (wasEnabled && gDisableXULDiskCache) {
-        static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
-        nsCOMPtr<nsIXULPrototypeCache> cache =
-            do_GetService(kXULPrototypeCacheCID);
+        nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
 
         if (cache)
             cache->AbortCaching();
     }
     return 0;
 }
 
 nsresult
--- a/content/xul/document/src/nsXULPrototypeCache.h
+++ b/content/xul/document/src/nsXULPrototypeCache.h
@@ -41,17 +41,16 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef nsXULPrototypeCache_h__
 #define nsXULPrototypeCache_h__
 
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
 #include "nsXBLDocumentInfo.h"
-#include "nsIXULPrototypeCache.h"
 #include "nsDataHashtable.h"
 #include "nsInterfaceHashtable.h"
 #include "nsRefPtrHashtable.h"
 #include "nsURIHashKey.h"
 #include "nsXULPrototypeDocument.h"
 #include "nsIInputStream.h"
 #include "nsIStorageStream.h"
 #include "mozilla/scache/StartupCache.h"
@@ -69,29 +68,27 @@ struct CacheScriptEntry
 /**
  * The XUL prototype cache can be used to store and retrieve shared data for
  * XUL documents, style sheets, XBL, and scripts.
  *
  * The cache has two levels:
  *  1. In-memory hashtables
  *  2. The on-disk cache file.
  */
-class nsXULPrototypeCache : public nsIXULPrototypeCache,
-                                   nsIObserver
+class nsXULPrototypeCache : public nsIObserver
 {
 public:
     // nsISupports
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
 
-    // nsIXULPrototypeCache
-    virtual PRBool IsCached(nsIURI* aURI) {
+    PRBool IsCached(nsIURI* aURI) {
         return GetPrototype(aURI) != nsnull;
     }
-    virtual void AbortCaching();
+    void AbortCaching();
 
 
     /**
      * Whether the prototype cache is enabled.
      */
     PRBool IsEnabled();
 
     /**
--- a/content/xul/templates/src/nsXULContentUtils.cpp
+++ b/content/xul/templates/src/nsXULContentUtils.cpp
@@ -66,17 +66,16 @@
 #include "nsIDOMXULCommandDispatcher.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIRDFNode.h"
 #include "nsINameSpaceManager.h"
 #include "nsIRDFService.h"
 #include "nsIServiceManager.h"
 #include "nsIURL.h"
 #include "nsXULContentUtils.h"
-#include "nsIXULPrototypeCache.h"
 #include "nsLayoutCID.h"
 #include "nsNetUtil.h"
 #include "nsRDFCID.h"
 #include "nsString.h"
 #include "nsXPIDLString.h"
 #include "nsGkAtoms.h"
 #include "prlog.h"
 #include "prtime.h"
--- a/content/xul/templates/src/nsXULTemplateBuilder.cpp
+++ b/content/xul/templates/src/nsXULTemplateBuilder.cpp
@@ -2122,19 +2122,20 @@ nsXULTemplateBuilder::CompileExtendedQue
     return NS_OK;
 }
 
 already_AddRefed<nsIAtom>
 nsXULTemplateBuilder::DetermineMemberVariable(nsIContent* aElement)
 {
     // recursively iterate over the children looking for an element
     // with uri="?..."
-    for (nsINode::ChildIterator iter(aElement); !iter.IsDone(); iter.Next()) {
+    for (nsIContent* child = aElement->GetFirstChild();
+         child;
+         child = child->GetNextSibling()) {
         nsAutoString uri;
-        nsIContent *child = iter;
         child->GetAttr(kNameSpaceID_None, nsGkAtoms::uri, uri);
         if (!uri.IsEmpty() && uri[0] == PRUnichar('?')) {
             return NS_NewAtom(uri);
         }
 
         nsCOMPtr<nsIAtom> result = DetermineMemberVariable(child);
         if (result) {
             return result.forget();
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -46,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[builtinclass, scriptable, uuid(286466f1-4246-4574-afdb-2f8a03ad7cc8)]
+[builtinclass, scriptable, uuid(519ae4fa-0fee-4aaa-bcb9-34b503236801)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -686,17 +686,20 @@ interface nsIDOMCSS2Properties : nsISupp
 
            attribute DOMString        MozPerspective;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozPerspectiveOrigin;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozBackfaceVisibility;
-                                        // raises(DOMException) on setting 
+                                        // raises(DOMException) on setting
+
+           attribute DOMString        MozTransformStyle;
+                                        // raises(DOMException) on setting
 
            attribute DOMString        MozWindowShadow;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundSize;
                                         // raises(DOMException) on setting
 
            attribute DOMString        MozTextBlink;
--- a/dom/src/geolocation/nsGeolocation.cpp
+++ b/dom/src/geolocation/nsGeolocation.cpp
@@ -144,17 +144,17 @@ private:
 class RequestSendLocationEvent : public nsRunnable
 {
 public:
   // a bit funky.  if locator is passed, that means this
   // event should remove the request from it.  If we ever
   // have to do more, then we can change this around.
   RequestSendLocationEvent(nsIDOMGeoPosition* aPosition,
                            nsGeolocationRequest* aRequest,
-                           nsGeolocation* aLocator = nsnull)
+                           nsGeolocation* aLocator)
     : mPosition(aPosition),
       mRequest(aRequest),
       mLocator(aLocator)
   {
   }
 
   NS_IMETHOD Run() {
     mRequest->SendLocation(mPosition);
@@ -384,17 +384,19 @@ nsGeolocationRequest::Allow()
   }
 
   if (lastPosition && maximumAge > 0 &&
       ( PRTime(PR_Now() / PR_USEC_PER_MSEC) - maximumAge <=
         PRTime(cachedPositionTime) )) {
     // okay, we can return a cached position
     mAllowed = PR_TRUE;
     
-    nsCOMPtr<nsIRunnable> ev = new RequestSendLocationEvent(lastPosition, this, mLocator);
+     nsCOMPtr<nsIRunnable> ev =
+         new RequestSendLocationEvent(lastPosition, this,
+                                      mIsWatchPositionRequest ? nsnull : mLocator);
     NS_DispatchToMainThread(ev);
   }
 
   SetTimeoutTimer();
 
   mAllowed = PR_TRUE;
   return NS_OK;
 }
@@ -457,17 +459,19 @@ nsGeolocationRequest::SendLocation(nsIDO
 
   if (mIsWatchPositionRequest)
     SetTimeoutTimer();
 }
 
 void
 nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
 {
-  nsCOMPtr<nsIRunnable> ev  = new RequestSendLocationEvent(aPosition, this);
+  nsCOMPtr<nsIRunnable> ev  =
+      new RequestSendLocationEvent(aPosition, this,
+                                   mIsWatchPositionRequest ? nsnull : mLocator);
   NS_DispatchToMainThread(ev);
 }
 
 void
 nsGeolocationRequest::Shutdown()
 {
   if (mTimeoutTimer) {
     mTimeoutTimer->Cancel();
--- a/gfx/2d/BasePoint3D.h
+++ b/gfx/2d/BasePoint3D.h
@@ -55,16 +55,26 @@ struct BasePoint3D {
   BasePoint3D(T aX, T aY, T aZ) : x(aX), y(aY), z(aZ) {}
 
   void MoveTo(T aX, T aY, T aZ) { x = aX; y = aY; z = aZ; }
   void MoveBy(T aDx, T aDy, T aDz) { x += aDx; y += aDy; z += aDz; }
 
   // Note that '=' isn't defined so we'll get the
   // compiler generated default assignment operator
 
+  T& operator[](int aIndex) {
+    NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index");
+    return *((&x)+aIndex);
+  }
+
+  const T& operator[](int aIndex) const {
+    NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 2, "Invalid array index");
+    return *((&x)+aIndex);
+  }
+
   bool operator==(const Sub& aPoint) const {
     return x == aPoint.x && y == aPoint.y && z == aPoint.z;
   }
   bool operator!=(const Sub& aPoint) const {
     return x != aPoint.x || y != aPoint.y || z != aPoint.z;
   }
 
   Sub operator+(const Sub& aPoint) const {
new file mode 100644
--- /dev/null
+++ b/gfx/2d/BasePoint4D.h
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** 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 Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@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_BASEPOINT4D_H_
+#define MOZILLA_BASEPOINT4D_H_
+
+namespace mozilla {
+namespace gfx {
+
+/**
+ * Do not use this class directly. Subclass it, pass that subclass as the
+ * Sub parameter, and only use that subclass. This allows methods to safely
+ * cast 'this' to 'Sub*'.
+ */
+template <class T, class Sub>
+struct BasePoint4D {
+  T x, y, z, w;
+
+  // Constructors
+  BasePoint4D() : x(0), y(0), z(0), w(0) {}
+  BasePoint4D(T aX, T aY, T aZ, T aW) : x(aX), y(aY), z(aZ), w(aW) {}
+
+  void MoveTo(T aX, T aY, T aZ, T aW) { x = aX; y = aY; z = aZ; w = aW; }
+  void MoveBy(T aDx, T aDy, T aDz, T aDw) { x += aDx; y += aDy; z += aDz; w += aDw; }
+
+  // Note that '=' isn't defined so we'll get the
+  // compiler generated default assignment operator
+
+  bool operator==(const Sub& aPoint) const {
+    return x == aPoint.x && y == aPoint.y && 
+           z == aPoint.z && w == aPoint.w;
+  }
+  bool operator!=(const Sub& aPoint) const {
+    return x != aPoint.x || y != aPoint.y || 
+           z != aPoint.z || w != aPoint.w;
+  }
+
+  Sub operator+(const Sub& aPoint) const {
+    return Sub(x + aPoint.x, y + aPoint.y, z + aPoint.z, w + aPoint.w);
+  }
+  Sub operator-(const Sub& aPoint) const {
+    return Sub(x - aPoint.x, y - aPoint.y, z - aPoint.z, w - aPoint.w);
+  }
+  Sub& operator+=(const Sub& aPoint) {
+    x += aPoint.x;
+    y += aPoint.y;
+    z += aPoint.z;
+    w += aPoint.w;
+    return *static_cast<Sub*>(this);
+  }
+  Sub& operator-=(const Sub& aPoint) {
+    x -= aPoint.x;
+    y -= aPoint.y;
+    z -= aPoint.z;
+    w -= aPoint.w;
+    return *static_cast<Sub*>(this);
+  }
+
+  Sub operator*(T aScale) const {
+    return Sub(x * aScale, y * aScale, z * aScale, w * aScale);
+  }
+  Sub operator/(T aScale) const {
+    return Sub(x / aScale, y / aScale, z / aScale, w / aScale);
+  }
+
+  Sub& operator*=(T aScale) {
+    x *= aScale;
+    y *= aScale;
+    z *= aScale;
+    w *= aScale;
+    return *static_cast<Sub*>(this);
+  }
+
+  Sub& operator/=(T aScale) {
+    x /= aScale;
+    y /= aScale;
+    z /= aScale;
+    w /= aScale;
+    return *static_cast<Sub*>(this);
+  }
+
+  Sub operator-() const {
+    return Sub(-x, -y, -z, -w);
+  }
+
+  T& operator[](int aIndex) {
+    NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index");
+    return *((&x)+aIndex);
+  }
+
+  const T& operator[](int aIndex) const {
+    NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid array index");
+    return *((&x)+aIndex);
+  }
+
+  T DotProduct(const Sub& aPoint) const {
+    return x * aPoint.x + y * aPoint.y + z * aPoint.z + w * aPoint.w;
+  }
+
+  // Ignores the 4th component!
+  Sub CrossProduct(const Sub& aPoint) const {
+      return Sub(y * aPoint.z - aPoint.y * z,
+          z * aPoint.x - aPoint.z * x,
+          x * aPoint.y - aPoint.x * y, 
+          0);
+  }
+
+  T Length() const {
+    return sqrt(x*x + y*y + z*z + w*w);
+  }
+
+  void Normalize() {
+    *this /= Length();
+  }
+};
+
+}
+}
+
+#endif /* MOZILLA_BASEPOINT4D_H_ */
--- a/gfx/2d/Makefile.in
+++ b/gfx/2d/Makefile.in
@@ -46,17 +46,18 @@ MODULE		= gfx2d
 LIBRARY_NAME	= gfx2d
 LIBXUL_LIBRARY	= 1
 EXPORT_LIBRARY	= 1
 
 EXPORTS_NAMESPACES = mozilla/gfx
 EXPORTS_mozilla/gfx	= \
         2D.h \
         BasePoint.h \
-	BasePoint3D.h \
+        BasePoint3D.h \
+        BasePoint4D.h \
         BaseMargin.h \
         BaseRect.h \
         BaseSize.h \
         Point.h \
         Matrix.h \
         Rect.h \
         Types.h \
 	$(NULL)
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -164,16 +164,19 @@ missing-cairo-clip-init.diff: Missing ca
 
 fix-cairo-win32-print-gdi-error.diff: Don't use fwprintf with char* format.  Flush stderr so that all error messages appears before exit.
 
 pixman-image-transform.patch: Reset the transform on pixman images when using them as destinations.
 
 fix-cairo-surface-wrapper-flush-build-warning.patch: Ensures that _cairo_surface_wrapper_flush always returns a status, to silence the build warning
 
 fixup-unbounded.patch: Hack to work around bad assumption.
+
+quartz-get-image-performance: Make cairo_quartz_get_image faster in the failure case by not flushing unless we are going to succeed.
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
+++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
@@ -1909,30 +1909,30 @@ static cairo_int_status_t
     unsigned char *imageData;
     cairo_image_surface_t *isurf;
 
     if (IS_EMPTY(surface)) {
 	*image_out = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
 	return CAIRO_STATUS_SUCCESS;
     }
 
-    CGContextFlush(surface->cgContext);
-
     if (surface->imageSurfaceEquiv) {
+	CGContextFlush(surface->cgContext);
 	*image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
 	return CAIRO_STATUS_SUCCESS;
     }
 
     if (_cairo_quartz_is_cgcontext_bitmap_context(surface->cgContext)) {
 	unsigned int stride;
 	unsigned int bitinfo;
 	unsigned int bpc, bpp;
 	CGColorSpaceRef colorspace;
 	unsigned int color_comps;
 
+	CGContextFlush(surface->cgContext);
 	imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
 
 #ifdef USE_10_3_WORKAROUNDS
 	bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
 #else
 	bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
 #endif
 	stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/quartz-get-image-performance.patch
@@ -0,0 +1,43 @@
+# HG changeset patch
+# User Matt Woodrow <mwoodrow@mozilla.com>
+# Date 1314162877 -43200
+# Node ID 87458c4670dcd16be5a5715d741ee2ca4cf18d0f
+# Parent  95eb700a64591cda694c284a9f8ad08c11e3dd97
+Bug 675837 - Only flush Quartz surfaces on the success paths during cairo_quartz_get_image. r=roc
+
+diff --git a/gfx/cairo/cairo/src/cairo-quartz-surface.c b/gfx/cairo/cairo/src/cairo-quartz-surface.c
+--- a/gfx/cairo/cairo/src/cairo-quartz-surface.c
++++ b/gfx/cairo/cairo/src/cairo-quartz-surface.c
+@@ -1909,30 +1909,30 @@ _cairo_quartz_get_image (cairo_quartz_su
+     unsigned char *imageData;
+     cairo_image_surface_t *isurf;
+ 
+     if (IS_EMPTY(surface)) {
+ 	*image_out = (cairo_image_surface_t*) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0);
+ 	return CAIRO_STATUS_SUCCESS;
+     }
+ 
+-    CGContextFlush(surface->cgContext);
+-
+     if (surface->imageSurfaceEquiv) {
++	CGContextFlush(surface->cgContext);
+ 	*image_out = (cairo_image_surface_t*) cairo_surface_reference(surface->imageSurfaceEquiv);
+ 	return CAIRO_STATUS_SUCCESS;
+     }
+ 
+     if (_cairo_quartz_is_cgcontext_bitmap_context(surface->cgContext)) {
+ 	unsigned int stride;
+ 	unsigned int bitinfo;
+ 	unsigned int bpc, bpp;
+ 	CGColorSpaceRef colorspace;
+ 	unsigned int color_comps;
+ 
++	CGContextFlush(surface->cgContext);
+ 	imageData = (unsigned char *) CGBitmapContextGetData(surface->cgContext);
+ 
+ #ifdef USE_10_3_WORKAROUNDS
+ 	bitinfo = CGBitmapContextGetAlphaInfo (surface->cgContext);
+ #else
+ 	bitinfo = CGBitmapContextGetBitmapInfo (surface->cgContext);
+ #endif
+ 	stride = CGBitmapContextGetBytesPerRow (surface->cgContext);
--- a/gfx/layers/basic/BasicLayers.cpp
+++ b/gfx/layers/basic/BasicLayers.cpp
@@ -58,16 +58,17 @@
 #include "ThebesLayerBuffer.h"
 #include "nsIWidget.h"
 #include "ReadbackProcessor.h"
 #ifdef MOZ_X11
 #include "gfxXlibSurface.h"
 #endif
 
 #include "GLContext.h"
+#include "pixman.h"
 
 namespace mozilla {
 namespace layers {
 
 class BasicContainerLayer;
 class ShadowableLayer;
 
 /**
@@ -232,18 +233,27 @@ public:
     ContainerRemoveChild(aChild, this);
   }
 
   virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
   {
     // We push groups for container layers if we need to, which always
     // are aligned in device space, so it doesn't really matter how we snap
     // containers.
+    gfxMatrix residual;
     gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
-    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
+
+    if (!idealTransform.CanDraw2D()) {
+      mEffectiveTransform = idealTransform;
+      ComputeEffectiveTransformsForChildren(gfx3DMatrix());
+      mUseIntermediateSurface = PR_TRUE;
+      return;
+    }
+
+    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
     // We always pass the ideal matrix down to our children, so there is no
     // need to apply any compensation using the residual from SnapTransform.
     ComputeEffectiveTransformsForChildren(idealTransform);
 
     /* If we have a single child, it can just inherit our opacity,
      * otherwise we need a PushGroup and we need to mark ourselves as using
      * an intermediate surface so our children don't inherit our opacity
      * via GetEffectiveOpacity.
@@ -283,30 +293,30 @@ BasicContainerLayer::~BasicContainerLaye
 
   MOZ_COUNT_DTOR(BasicContainerLayer);
 }
 
 PRBool
 BasicContainerLayer::ChildrenPartitionVisibleRegion(const nsIntRect& aInRect)
 {
   gfxMatrix transform;
-  if (!GetEffectiveTransform().Is2D(&transform) ||
+  if (!GetEffectiveTransform().CanDraw2D(&transform) ||
       transform.HasNonIntegerTranslation())
     return PR_FALSE;
 
   nsIntPoint offset(PRInt32(transform.x0), PRInt32(transform.y0));
   nsIntRect rect = aInRect.Intersect(GetEffectiveVisibleRegion().GetBounds() + offset);
   nsIntRegion covered;
 
   for (Layer* l = mFirstChild; l; l = l->GetNextSibling()) {
     if (ToData(l)->IsHidden())
       continue;
 
     gfxMatrix childTransform;
-    if (!l->GetEffectiveTransform().Is2D(&childTransform) ||
+    if (!l->GetEffectiveTransform().CanDraw2D(&childTransform) ||
         childTransform.HasNonIntegerTranslation() ||
         l->GetEffectiveOpacity() != 1.0)
       return PR_FALSE;
     nsIntRegion childRegion = l->GetEffectiveVisibleRegion();
     childRegion.MoveBy(PRInt32(childTransform.x0), PRInt32(childTransform.y0));
     childRegion.And(childRegion, rect);
     if (l->GetClipRect()) {
       childRegion.And(childRegion, *l->GetClipRect() + offset);
@@ -699,17 +709,17 @@ BasicThebesLayer::PaintThebes(gfxContext
       aContext->Restore();
     }
     return;
   }
 
   {
     PRUint32 flags = 0;
     gfxMatrix transform;
-    if (!GetEffectiveTransform().Is2D(&transform) ||
+    if (!GetEffectiveTransform().CanDraw2D(&transform) ||
         transform.HasNonIntegerTranslation() ||
         MustRetainContent() /*<=> has shadow layer*/) {
       flags |= ThebesLayerBuffer::PAINT_WILL_RESAMPLE;
     }
     Buffer::PaintState state =
       mBuffer.BeginPaint(this, contentType, flags);
     mValidRegion.Sub(mValidRegion, state.mRegionToInvalidate);
 
@@ -1350,16 +1360,28 @@ BasicLayerManager::PopGroupToSourceWithC
     aTarget->IdentityMatrix();
     aTarget->SetSource(current);
     mCachedSurfaceInUse = PR_FALSE;
   } else {
     aTarget->PopGroupToSource();
   }
 }
 
+already_AddRefed<gfxASurface>
+BasicLayerManager::PopGroupToSurface(gfxContext *aTarget, gfxContext *aPushed)
+{
+  if (!aTarget)
+    return nsnull;
+  nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
+  NS_ASSERTION(!mCachedSurface.IsSurface(current), "Should never be popping cached surface here!");
+  nsRefPtr<gfxPattern> pat = aTarget->PopGroup();
+  current = pat->GetSurface();
+  return current.forget();
+}
+
 void
 BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
 {
 #ifdef MOZ_LAYERS_HAVE_LOG
   MOZ_LAYERS_LOG(("[----- BeginTransaction"));
   Log();
 #endif
 
@@ -1415,17 +1437,17 @@ MarkLayersHidden(Layer* aLayer, const ns
   {
     const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
     if (clipRect) {
       nsIntRect cr = *clipRect;
       // clipRect is in the container's coordinate system. Get it into the
       // global coordinate system.
       if (aLayer->GetParent()) {
         gfxMatrix tr;
-        if (aLayer->GetParent()->GetEffectiveTransform().Is2D(&tr)) {
+        if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
           // Clip rect is applied after aLayer's transform, i.e., in the coordinate
           // system of aLayer's parent.
           TransformIntRect(cr, tr, ToInsideIntRect);
         } else {
           cr.SetRect(0, 0, 0, 0);
         }
       }
       newClipRect.IntersectRect(newClipRect, cr);
@@ -1433,17 +1455,17 @@ MarkLayersHidden(Layer* aLayer, const ns
   }
 
   BasicImplData* data = ToData(aLayer);
   data->SetOperator(gfxContext::OPERATOR_OVER);
   data->SetClipToVisibleRegion(PR_FALSE);
 
   if (!aLayer->AsContainerLayer()) {
     gfxMatrix transform;
-    if (!aLayer->GetEffectiveTransform().Is2D(&transform)) {
+    if (!aLayer->GetEffectiveTransform().CanDraw2D(&transform)) {
       data->SetHidden(PR_FALSE);
       return;
     }
 
     nsIntRegion region = aLayer->GetEffectiveVisibleRegion();
     nsIntRect r = region.GetBounds();
     TransformIntRect(r, transform, ToOutsideIntRect);
     r.IntersectRect(r, aDirtyRect);
@@ -1494,17 +1516,17 @@ ApplyDoubleBuffering(Layer* aLayer, cons
   {
     const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
     if (clipRect) {
       nsIntRect cr = *clipRect;
       // clipRect is in the container's coordinate system. Get it into the
       // global coordinate system.
       if (aLayer->GetParent()) {
         gfxMatrix tr;
-        if (aLayer->GetParent()->GetEffectiveTransform().Is2D(&tr)) {
+        if (aLayer->GetParent()->GetEffectiveTransform().CanDraw2D(&tr)) {
           NS_ASSERTION(!tr.HasNonIntegerTranslation(),
                        "Parent can only have an integer translation");
           cr += nsIntPoint(PRInt32(tr.x0), PRInt32(tr.y0));
         } else {
           NS_ERROR("Parent can only have an integer translation");
         }
       }
       newVisibleRect.IntersectRect(newVisibleRect, cr);
@@ -1635,16 +1657,153 @@ void
 BasicLayerManager::SetRoot(Layer* aLayer)
 {
   NS_ASSERTION(aLayer, "Root can't be null");
   NS_ASSERTION(aLayer->Manager() == this, "Wrong manager");
   NS_ASSERTION(InConstruction(), "Only allowed in construction phase");
   mRoot = aLayer;
 }
 
+static pixman_transform
+Matrix3DToPixman(const gfx3DMatrix& aMatrix)
+{
+  pixman_f_transform transform;
+
+  transform.m[0][0] = aMatrix._11;
+  transform.m[0][1] = aMatrix._21;
+  transform.m[0][2] = aMatrix._41;
+  transform.m[1][0] = aMatrix._12;
+  transform.m[1][1] = aMatrix._22;
+  transform.m[1][2] = aMatrix._42;
+  transform.m[2][0] = aMatrix._14;
+  transform.m[2][1] = aMatrix._24;
+  transform.m[2][2] = aMatrix._44;
+
+  pixman_transform result;
+  pixman_transform_from_pixman_f_transform(&result, &transform);
+
+  return result;
+}
+
+static void
+PixmanTransform(const gfxImageSurface *aDest, 
+                const gfxImageSurface *aSrc, 
+                const gfx3DMatrix& aTransform, 
+                gfxPoint aDestOffset)
+{
+  gfxIntSize destSize = aDest->GetSize();
+  pixman_image_t* dest = pixman_image_create_bits(aDest->Format() == gfxASurface::ImageFormatARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+                                                  destSize.width,
+                                                  destSize.height,
+                                                  (uint32_t*)aDest->Data(),
+                                                  aDest->Stride());
+
+  gfxIntSize srcSize = aSrc->GetSize();
+  pixman_image_t* src = pixman_image_create_bits(aSrc->Format() == gfxASurface::ImageFormatARGB32 ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8,
+                                                 srcSize.width,
+                                                 srcSize.height,
+                                                 (uint32_t*)aSrc->Data(),
+                                                 aSrc->Stride());
+
+  NS_ABORT_IF_FALSE(src && dest, "Failed to create pixman images?");
+
+  pixman_transform pixTransform = Matrix3DToPixman(aTransform);
+  pixman_transform pixTransformInverted;
+
+  // If the transform is singular then nothing would be drawn anyway, return here
+  if (!pixman_transform_invert(&pixTransformInverted, &pixTransform)) {
+    return;
+  }
+  pixman_image_set_transform(src, &pixTransformInverted);
+
+  pixman_image_composite32(PIXMAN_OP_SRC,
+                           src,
+                           nsnull,
+                           dest,
+                           aDestOffset.x,
+                           aDestOffset.y,
+                           0,
+                           0,
+                           0,
+                           0,
+                           destSize.width,
+                           destSize.height);
+
+  pixman_image_unref(dest);
+  pixman_image_unref(src);
+}
+
+/**
+ * Transform a surface using a gfx3DMatrix and blit to the destination if
+ * it is efficient to do so.
+ *
+ * @param aSource       Source surface.
+ * @param aDest         Desintation context.
+ * @param aBounds       Area represented by aSource.
+ * @param aTransform    Transformation matrix.
+ * @param aDrawOffset   Location to draw returned surface on aDest.
+ * @param aDontBlit     Never draw to aDest if this is true.
+ * @return              Transformed surface, or nsnull if it has been drawn to aDest.
+ */
+static already_AddRefed<gfxASurface> 
+Transform3D(gfxASurface* aSource, gfxContext* aDest, 
+            const gfxRect& aBounds, const gfx3DMatrix& aTransform, 
+            gfxPoint& aDrawOffset, PRBool aDontBlit)
+{
+  nsRefPtr<gfxImageSurface> sourceImage = aSource->GetAsImageSurface();
+  if (!sourceImage) {
+    sourceImage = new gfxImageSurface(gfxIntSize(aBounds.width, aBounds.height), gfxASurface::FormatFromContent(aSource->GetContentType()));
+    nsRefPtr<gfxContext> ctx = new gfxContext(sourceImage);
+
+    aSource->SetDeviceOffset(gfxPoint(0, 0));
+    ctx->SetSource(aSource);
+    ctx->SetOperator(gfxContext::OPERATOR_SOURCE);
+    ctx->Paint();
+  }
+
+  // Find the transformed rectangle of our layer.
+  gfxRect offsetRect = aTransform.TransformBounds(aBounds);
+
+  // Intersect the transformed layer with the destination rectangle.
+  // This is in device space since we have an identity transform set on aTarget.
+  gfxRect destRect = aDest->GetClipExtents();
+  destRect.IntersectRect(destRect, offsetRect);
+
+  // Create a surface the size of the transformed object.
+  nsRefPtr<gfxASurface> dest = aDest->CurrentSurface();
+  nsRefPtr<gfxImageSurface> destImage = dest->GetAsImageSurface();
+  destImage = nsnull;
+  gfxPoint offset;
+  PRBool blitComplete;
+  if (!destImage || aDontBlit || !aDest->ClipContainsRect(destRect)) {
+    destImage = new gfxImageSurface(gfxIntSize(destRect.width, destRect.height),
+                                    gfxASurface::ImageFormatARGB32);
+    offset = destRect.TopLeft();
+    blitComplete = PR_FALSE;
+  } else {
+    offset = -dest->GetDeviceOffset();
+    blitComplete = PR_TRUE;
+  }
+
+  // Include a translation to the correct origin.
+  gfx3DMatrix translation = gfx3DMatrix::Translation(aBounds.x, aBounds.y, 0);
+
+  // Transform the content and offset it such that the content begins at the origin.
+  PixmanTransform(destImage, sourceImage, translation * aTransform, offset);
+
+  if (blitComplete) {
+    return nsnull;
+  }
+
+  // If we haven't actually drawn to aDest then return our temporary image so that
+  // the caller can do this.
+  aDrawOffset = destRect.TopLeft();
+  return destImage.forget(); 
+}
+
 void
 BasicLayerManager::PaintLayer(gfxContext* aTarget,
                               Layer* aLayer,
                               DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               ReadbackProcessor* aReadback)
 {
   const nsIntRect* clipRect = aLayer->GetEffectiveClipRect();
@@ -1671,22 +1830,26 @@ BasicLayerManager::PaintLayer(gfxContext
       aTarget->Rectangle(gfxRect(clipRect->x, clipRect->y, clipRect->width, clipRect->height), PR_TRUE);
       aTarget->Clip();
     }
   } else {
     savedMatrix = aTarget->CurrentMatrix();
   }
 
   gfxMatrix transform;
-  // XXX we need to add some kind of 3D transform support, possibly
-  // using pixman?
-  NS_ASSERTION(effectiveTransform.Is2D(),
-               "Only 2D transforms supported currently");
-  effectiveTransform.Is2D(&transform);
-  aTarget->SetMatrix(transform);
+  // Will return an identity matrix for 3d transforms, and is handled separately below.
+  PRBool is2D = effectiveTransform.CanDraw2D(&transform);
+  NS_ABORT_IF_FALSE(is2D || needsGroup || !aLayer->GetFirstChild(), "Must PushGroup for 3d transforms!");
+  if (is2D) {
+    aTarget->SetMatrix(transform);
+  } else {
+    aTarget->SetMatrix(gfxMatrix());
+    // Save so we can restore clipping after PushGroupForLayer changes it.
+    aTarget->Save();
+  }
 
   const nsIntRegion& visibleRegion = aLayer->GetEffectiveVisibleRegion();
   // If needsGroup is true, we'll clip to the visible region after we've popped the group
   if (needsClipToVisibleRegion && !needsGroup) {
     gfxUtils::ClipToRegion(aTarget, visibleRegion);
     // Don't need to clip to visible region again
     needsClipToVisibleRegion = PR_FALSE;
   }
@@ -1736,27 +1899,47 @@ BasicLayerManager::PaintLayer(gfxContext
     for (; child; child = child->GetNextSibling()) {
       PaintLayer(groupTarget, child, aCallback, aCallbackData, &readback);
       if (mTransactionIncomplete)
         break;
     }
   }
 
   if (needsGroup) {
-    PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
+    PRBool blitComplete = PR_FALSE;
+    if (is2D) {
+      PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
+    } else {
+      nsRefPtr<gfxASurface> sourceSurface = PopGroupToSurface(aTarget, groupTarget);
+      aTarget->Restore();
+      NS_ABORT_IF_FALSE(sourceSurface, "PopGroup should always return a surface pattern");
+      gfxRect bounds = visibleRegion.GetBounds();
+
+      gfxPoint offset;
+      PRBool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete || 
+                        aLayer->GetEffectiveOpacity() != 1.0f;
+      nsRefPtr<gfxASurface> result = 
+        Transform3D(sourceSurface, aTarget, bounds,
+                    effectiveTransform, offset, dontBlit);
+
+      blitComplete = !result;
+      if (result) {
+        aTarget->SetSource(result, offset);
+      }
+    }
     // If we're doing our own double-buffering, we need to avoid drawing
     // the results of an incomplete transaction to the destination surface ---
     // that could cause flicker. Double-buffering is implemented using a
     // temporary surface for one or more container layers, so we need to stop
     // those temporary surfaces from being composited to aTarget.
     // ApplyDoubleBuffering guarantees that this container layer can't
     // intersect any other leaf layers, so if the transaction is not yet marked
     // incomplete, the contents of this container layer are the final contents
     // for the window.
-    if (!mTransactionIncomplete) {
+    if (!mTransactionIncomplete && !blitComplete) {
       if (needsClipToVisibleRegion) {
         gfxUtils::ClipToRegion(aTarget, aLayer->GetEffectiveVisibleRegion());
       }
       AutoSetOperator setOperator(aTarget, container->GetOperator());
       aTarget->Paint(aLayer->GetEffectiveOpacity());
     }
   }
 
@@ -2672,18 +2855,27 @@ public:
   virtual void RemoveChild(Layer* aChild)
   { ContainerRemoveChild(aChild, this); }
 
   virtual void ComputeEffectiveTransforms(const gfx3DMatrix& aTransformToSurface)
   {
     // We push groups for container layers if we need to, which always
     // are aligned in device space, so it doesn't really matter how we snap
     // containers.
+    gfxMatrix residual;
     gfx3DMatrix idealTransform = GetLocalTransform()*aTransformToSurface;
-    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), nsnull);
+
+    if (!idealTransform.CanDraw2D()) {
+      mEffectiveTransform = idealTransform;
+      ComputeEffectiveTransformsForChildren(gfx3DMatrix());
+      mUseIntermediateSurface = PR_TRUE;
+      return;
+    }
+
+    mEffectiveTransform = SnapTransform(idealTransform, gfxRect(0, 0, 0, 0), &residual);
     // We always pass the ideal matrix down to our children, so there is no
     // need to apply any compensation using the residual from SnapTransform.
     ComputeEffectiveTransformsForChildren(idealTransform);
 
     /* If we have a single child, it can just inherit our opacity,
      * otherwise we need a PushGroup and we need to mark ourselves as using
      * an intermediate surface so our children don't inherit our opacity
      * via GetEffectiveOpacity.
--- a/gfx/layers/basic/BasicLayers.h
+++ b/gfx/layers/basic/BasicLayers.h
@@ -166,16 +166,17 @@ public:
   void SetTransactionIncomplete() { mTransactionIncomplete = true; }
 
   already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
                                                  const nsIntRegion& aRegion,
                                                  PRBool* aNeedsClipToVisibleRegion);
   already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
                                                           gfxASurface::gfxContentType aContent);
   void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
+  already_AddRefed<gfxASurface> PopGroupToSurface(gfxContext *aTarget, gfxContext *aPushed);
 
   virtual PRBool IsCompositingCheap() { return PR_FALSE; }
   virtual bool HasShadowManagerInternal() const { return false; }
   bool HasShadowManager() const { return HasShadowManagerInternal(); }
 
 protected:
 #ifdef DEBUG
   enum TransactionPhase {
--- a/gfx/thebes/GLContextProviderEGL.cpp
+++ b/gfx/thebes/GLContextProviderEGL.cpp
@@ -777,23 +777,24 @@ public:
     }
 
     PRBool MakeCurrentImpl(PRBool aForce = PR_FALSE) {
         PRBool succeeded = PR_TRUE;
 
         // Assume that EGL has the same problem as WGL does,
         // where MakeCurrent with an already-current context is
         // still expensive.
-        if (!mSurface || aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
 #ifndef MOZ_WIDGET_QT
-            if (!mSurface) {
-                EGLConfig config = CreateConfig();
-                mSurface = CreateSurfaceForWindow(NULL, config);
-            }
+        if (!mSurface) {
+            EGLConfig config = CreateConfig();
+            mSurface = CreateSurfaceForWindow(NULL, config);
+            aForce = PR_TRUE;
+        }
 #endif
+        if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
             succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
                                                  mSurface, mSurface,
                                                  mContext);
             NS_ASSERTION(succeeded, "Failed to make GL context current!");
         }
 
         return succeeded;
     }
--- a/gfx/thebes/Makefile.in
+++ b/gfx/thebes/Makefile.in
@@ -28,16 +28,18 @@ EXPORTS	= \
 	gfxFontTest.h \
 	gfxImageSurface.h \
 	gfxMatrix.h \
 	gfxPath.h \
 	gfxPattern.h \
 	gfxPlatform.h \
 	gfxPoint.h \
 	gfxPoint3D.h \
+	gfxPointH3D.h \
+	gfxQuaternion.h \
 	gfxRect.h \
 	gfxSkipChars.h \
 	gfxTeeSurface.h \
 	gfxTypes.h \
 	gfxTextRunCache.h \
 	gfxTextRunWordCache.h \
 	gfxUnicodeProperties.h \
 	gfxUtils.h \
--- a/gfx/thebes/gfx3DMatrix.cpp
+++ b/gfx/thebes/gfx3DMatrix.cpp
@@ -49,16 +49,20 @@ gfx3DMatrix::gfx3DMatrix(void)
   _21 = _23 = _24 = 0.0f;
   _31 = _32 = _34 = 0.0f;
   _41 = _42 = _43 = 0.0f;
 }
 
 gfx3DMatrix
 gfx3DMatrix::operator*(const gfx3DMatrix &aMatrix) const
 {
+  if (Is2D() && aMatrix.Is2D()) {
+    return Multiply2D(aMatrix);
+  }
+
   gfx3DMatrix matrix;
 
   matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21 + _13 * aMatrix._31 + _14 * aMatrix._41;
   matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21 + _23 * aMatrix._31 + _24 * aMatrix._41;
   matrix._31 = _31 * aMatrix._11 + _32 * aMatrix._21 + _33 * aMatrix._31 + _34 * aMatrix._41;
   matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + _43 * aMatrix._31 + _44 * aMatrix._41;
   matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22 + _13 * aMatrix._32 + _14 * aMatrix._42;
   matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22 + _23 * aMatrix._32 + _24 * aMatrix._42;
@@ -77,16 +81,31 @@ gfx3DMatrix::operator*(const gfx3DMatrix
 }
 
 gfx3DMatrix&
 gfx3DMatrix::operator*=(const gfx3DMatrix &aMatrix)
 {
   return *this = *this * aMatrix;
 }
 
+gfx3DMatrix
+gfx3DMatrix::Multiply2D(const gfx3DMatrix &aMatrix) const
+{
+  gfx3DMatrix matrix;
+
+  matrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
+  matrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
+  matrix._41 = _41 * aMatrix._11 + _42 * aMatrix._21 + aMatrix._41;
+  matrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
+  matrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
+  matrix._42 = _41 * aMatrix._12 + _42 * aMatrix._22 + aMatrix._42;
+
+  return matrix;
+}
+
 bool
 gfx3DMatrix::operator==(const gfx3DMatrix& o) const
 {
   // XXX would be nice to memcmp here, but that breaks IEEE 754 semantics
   return _11 == o._11 && _12 == o._12 && _13 == o._13 && _14 == o._14 &&
          _21 == o._21 && _22 == o._22 && _23 == o._23 && _24 == o._24 &&
          _31 == o._31 && _32 == o._32 && _33 == o._33 && _34 == o._34 &&
          _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44;
@@ -131,16 +150,68 @@ PRBool
 gfx3DMatrix::IsIdentity() const
 {
   return _11 == 1.0f && _12 == 0.0f && _13 == 0.0f && _14 == 0.0f &&
          _21 == 0.0f && _22 == 1.0f && _23 == 0.0f && _24 == 0.0f &&
          _31 == 0.0f && _32 == 0.0f && _33 == 1.0f && _34 == 0.0f &&
          _41 == 0.0f && _42 == 0.0f && _43 == 0.0f && _44 == 1.0f;
 }
 
+void
+gfx3DMatrix::Translate(const gfxPoint3D& aPoint)
+{
+    _41 += aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31;
+    _42 += aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32;
+    _43 += aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33;
+    _44 += aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34;
+}
+
+void
+gfx3DMatrix::TranslatePost(const gfxPoint3D& aPoint)
+{
+    _11 += _14 * aPoint.x;
+    _21 += _24 * aPoint.x;
+    _31 += _34 * aPoint.x;
+    _41 += _44 * aPoint.x;
+    _12 += _14 * aPoint.y;
+    _22 += _24 * aPoint.y;
+    _32 += _34 * aPoint.y;
+    _42 += _44 * aPoint.y;
+    _13 += _14 * aPoint.z;
+    _23 += _24 * aPoint.z;
+    _33 += _34 * aPoint.z;
+    _43 += _44 * aPoint.z;
+}
+
+void
+gfx3DMatrix::SkewXY(float aSkew)
+{
+    (*this)[1] += (*this)[0] * aSkew;
+}
+
+void 
+gfx3DMatrix::SkewXZ(float aSkew)
+{
+    (*this)[2] += (*this)[0] * aSkew;
+}
+
+void
+gfx3DMatrix::SkewYZ(float aSkew)
+{
+    (*this)[2] += (*this)[1] * aSkew;
+}
+
+void
+gfx3DMatrix::Scale(float aX, float aY, float aZ)
+{
+    (*this)[0] *= aX;
+    (*this)[1] *= aY;
+    (*this)[2] *= aZ;
+}
+
 gfx3DMatrix
 gfx3DMatrix::Translation(float aX, float aY, float aZ)
 {
   gfx3DMatrix matrix;
 
   matrix._41 = aX;
   matrix._42 = aY;
   matrix._43 = aZ;
@@ -154,26 +225,26 @@ gfx3DMatrix::Translation(const gfxPoint3
 
   matrix._41 = aPoint.x;
   matrix._42 = aPoint.y;
   matrix._43 = aPoint.z;
   return matrix;
 }
 
 gfx3DMatrix
-gfx3DMatrix::Scale(float aFactor)
+gfx3DMatrix::ScalingMatrix(float aFactor)
 {
   gfx3DMatrix matrix;
 
   matrix._11 = matrix._22 = matrix._33 = aFactor;
   return matrix;
 }
 
 gfx3DMatrix
-gfx3DMatrix::Scale(float aX, float aY, float aZ)
+gfx3DMatrix::ScalingMatrix(float aX, float aY, float aZ)
 {
   gfx3DMatrix matrix;
 
   matrix._11 = aX;
   matrix._22 = aY;
   matrix._33 = aZ;
 
   return matrix;
@@ -203,83 +274,158 @@ gfx3DMatrix::Determinant() const
        - _13 * _22 * _31 * _44
        + _12 * _23 * _31 * _44
        + _13 * _21 * _32 * _44
        - _11 * _23 * _32 * _44
        - _12 * _21 * _33 * _44
        + _11 * _22 * _33 * _44;
 }
 
+gfxFloat
+gfx3DMatrix::Determinant3x3() const
+{
+    return _11 * (_22 * _33 - _23 * _32) +
+           _12 * (_23 * _31 - _33 * _21) +
+           _13 * (_21 * _32 - _22 * _31);
+}
+
+gfx3DMatrix
+gfx3DMatrix::Inverse3x3() const
+{
+    gfxFloat det = Determinant3x3();
+    if (det == 0.0) {
+        return *this;
+    }
+
+    gfxFloat detInv = 1/det;
+    gfx3DMatrix temp;
+
+    temp._11 = (_22 * _33 - _23 * _32) * detInv;
+    temp._12 = (_13 * _32 - _12 * _33) * detInv;
+    temp._13 = (_12 * _23 - _13 * _22) * detInv;
+    temp._21 = (_23 * _31 - _33 * _21) * detInv;
+    temp._22 = (_11 * _33 - _13 * _31) * detInv;
+    temp._23 = (_13 * _21 - _11 * _23) * detInv;
+    temp._31 = (_21 * _32 - _22 * _31) * detInv;
+    temp._32 = (_31 * _12 - _11 * _32) * detInv;
+    temp._33 = (_11 * _22 - _12 * _21) * detInv;
+    return temp;
+}
+
 PRBool
 gfx3DMatrix::IsSingular() const
 {
   return Determinant() == 0.0;
 }
 
-gfx3DMatrix&
-gfx3DMatrix::Invert()
+gfx3DMatrix
+gfx3DMatrix::Inverse() const
 {
+  if (TransposedVector(3) == gfxPointH3D(0, 0, 0, 1)) {
+    /** 
+     * When the matrix contains no perspective, the inverse
+     * is the same as the 3x3 inverse of the rotation components
+     * multiplied by the inverse of the translation components.
+     * Doing these steps separately is faster and more numerically
+     * stable.
+     *
+     * Inverse of the translation matrix is just negating
+     * the values.
+     */
+    gfx3DMatrix matrix3 = Inverse3x3();
+    matrix3.Translate(gfxPoint3D(-_41, -_42, -_43));
+    return matrix3;
+ }
+
   gfxFloat det = Determinant();
   if (det == 0.0) {
     return *this;
   }
 
-  gfx3DMatrix temp = *this;
+  gfx3DMatrix temp;
 
-  _11 = temp._23*temp._34*temp._42 - temp._24*temp._33*temp._42 
-      + temp._24*temp._32*temp._43 - temp._22*temp._34*temp._43 
-      - temp._23*temp._32*temp._44 + temp._22*temp._33*temp._44;
-  _12 = temp._14*temp._33*temp._42 - temp._13*temp._34*temp._42 
-      - temp._14*temp._32*temp._43 + temp._12*temp._34*temp._43 
-      + temp._13*temp._32*temp._44 - temp._12*temp._33*temp._44;
-  _13 = temp._13*temp._24*temp._42 - temp._14*temp._23*temp._42 
-      + temp._14*temp._22*temp._43 - temp._12*temp._24*temp._43 
-      - temp._13*temp._22*temp._44 + temp._12*temp._23*temp._44;
-  _14 = temp._14*temp._23*temp._32 - temp._13*temp._24*temp._32 
-      - temp._14*temp._22*temp._33 + temp._12*temp._24*temp._33 
-      + temp._13*temp._22*temp._34 - temp._12*temp._23*temp._34;
-  _21 = temp._24*temp._33*temp._41 - temp._23*temp._34*temp._41 
-      - temp._24*temp._31*temp._43 + temp._21*temp._34*temp._43 
-      + temp._23*temp._31*temp._44 - temp._21*temp._33*temp._44;
-  _22 = temp._13*temp._34*temp._41 - temp._14*temp._33*temp._41 
-      + temp._14*temp._31*temp._43 - temp._11*temp._34*temp._43 
-      - temp._13*temp._31*temp._44 + temp._11*temp._33*temp._44;
-  _23 = temp._14*temp._23*temp._41 - temp._13*temp._24*temp._41 
-      - temp._14*temp._21*temp._43 + temp._11*temp._24*temp._43 
-      + temp._13*temp._21*temp._44 - temp._11*temp._23*temp._44;
-  _24 = temp._13*temp._24*temp._31 - temp._14*temp._23*temp._31 
-      + temp._14*temp._21*temp._33 - temp._11*temp._24*temp._33 
-      - temp._13*temp._21*temp._34 + temp._11*temp._23*temp._34;
-  _31 = temp._22*temp._34*temp._41 - temp._24*temp._32*temp._41 
-      + temp._24*temp._31*temp._42 - temp._21*temp._34*temp._42 
-      - temp._22*temp._31*temp._44 + temp._21*temp._32*temp._44;
-  _32 = temp._14*temp._32*temp._41 - temp._12*temp._34*temp._41 
-      - temp._14*temp._31*temp._42 + temp._11*temp._34*temp._42 
-      + temp._12*temp._31*temp._44 - temp._11*temp._32*temp._44;
-  _33 = temp._12*temp._24*temp._41 - temp._14*temp._22*temp._41 
-      + temp._14*temp._21*temp._42 - temp._11*temp._24*temp._42 
-      - temp._12*temp._21*temp._44 + temp._11*temp._22*temp._44;
-  _34 = temp._14*temp._22*temp._31 - temp._12*temp._24*temp._31 
-      - temp._14*temp._21*temp._32 + temp._11*temp._24*temp._32 
-      + temp._12*temp._21*temp._34 - temp._11*temp._22*temp._34;
-  _41 = temp._23*temp._32*temp._41 - temp._22*temp._33*temp._41 
-      - temp._23*temp._31*temp._42 + temp._21*temp._33*temp._42 
-      + temp._22*temp._31*temp._43 - temp._21*temp._32*temp._43;
-  _42 = temp._12*temp._33*temp._41 - temp._13*temp._32*temp._41 
-      + temp._13*temp._31*temp._42 - temp._11*temp._33*temp._42 
-      - temp._12*temp._31*temp._43 + temp._11*temp._32*temp._43;
-  _43 = temp._13*temp._22*temp._41 - temp._12*temp._23*temp._41 
-      - temp._13*temp._21*temp._42 + temp._11*temp._23*temp._42 
-      + temp._12*temp._21*temp._43 - temp._11*temp._22*temp._43;
-  _44 = temp._12*temp._23*temp._31 - temp._13*temp._22*temp._31 
-      + temp._13*temp._21*temp._32 - temp._11*temp._23*temp._32 
-      - temp._12*temp._21*temp._33 + temp._11*temp._22*temp._33;
+  temp._11 = _23*_34*_42 - _24*_33*_42 + 
+             _24*_32*_43 - _22*_34*_43 - 
+             _23*_32*_44 + _22*_33*_44;
+  temp._12 = _14*_33*_42 - _13*_34*_42 -
+             _14*_32*_43 + _12*_34*_43 +
+             _13*_32*_44 - _12*_33*_44;
+  temp._13 = _13*_24*_42 - _14*_23*_42 +
+             _14*_22*_43 - _12*_24*_43 -
+             _13*_22*_44 + _12*_23*_44;
+  temp._14 = _14*_23*_32 - _13*_24*_32 -
+             _14*_22*_33 + _12*_24*_33 +
+             _13*_22*_34 - _12*_23*_34;
+  temp._21 = _24*_33*_41 - _23*_34*_41 -
+             _24*_31*_43 + _21*_34*_43 +
+             _23*_31*_44 - _21*_33*_44;
+  temp._22 = _13*_34*_41 - _14*_33*_41 +
+             _14*_31*_43 - _11*_34*_43 -
+             _13*_31*_44 + _11*_33*_44;
+  temp._23 = _14*_23*_41 - _13*_24*_41 -
+             _14*_21*_43 + _11*_24*_43 +
+             _13*_21*_44 - _11*_23*_44;
+  temp._24 = _13*_24*_31 - _14*_23*_31 +
+             _14*_21*_33 - _11*_24*_33 -
+             _13*_21*_34 + _11*_23*_34;
+  temp._31 = _22*_34*_41 - _24*_32*_41 +
+             _24*_31*_42 - _21*_34*_42 -
+             _22*_31*_44 + _21*_32*_44;
+  temp._32 = _14*_32*_41 - _12*_34*_41 -
+             _14*_31*_42 + _11*_34*_42 +
+             _12*_31*_44 - _11*_32*_44;
+  temp._33 = _12*_24*_41 - _14*_22*_41 +
+             _14*_21*_42 - _11*_24*_42 -
+             _12*_21*_44 + _11*_22*_44;
+  temp._34 = _14*_22*_31 - _12*_24*_31 -
+             _14*_21*_32 + _11*_24*_32 +
+             _12*_21*_34 - _11*_22*_34;
+  temp._41 = _23*_32*_41 - _22*_33*_41 -
+             _23*_31*_42 + _21*_33*_42 +
+             _22*_31*_43 - _21*_32*_43;
+  temp._42 = _12*_33*_41 - _13*_32*_41 +
+             _13*_31*_42 - _11*_33*_42 -
+             _12*_31*_43 + _11*_32*_43;
+  temp._43 = _13*_22*_41 - _12*_23*_41 -
+             _13*_21*_42 + _11*_23*_42 +
+             _12*_21*_43 - _11*_22*_43;
+  temp._44 = _12*_23*_31 - _13*_22*_31 +
+             _13*_21*_32 - _11*_23*_32 -
+             _12*_21*_33 + _11*_22*_33;
 
-  *this /= det;
-  return *this;
+  temp /= det;
+  return temp;
+}
+
+gfx3DMatrix&
+gfx3DMatrix::Normalize()
+{
+    for (int i = 0; i < 4; i++) {
+        for (int j = 0; j < 4; j++) {
+            (*this)[i][j] /= (*this)[3][3];
+       }
+    }
+    return *this;
+}
+
+gfx3DMatrix&
+gfx3DMatrix::Transpose()
+{
+    *this = Transposed();
+    return *this;
+}
+
+gfx3DMatrix
+gfx3DMatrix::Transposed() const
+{
+    gfx3DMatrix temp;
+    for (int i = 0; i < 4; i++) {
+        temp[i] = TransposedVector(i);
+    }
+    return temp;
 }
 
 gfxPoint
 gfx3DMatrix::Transform(const gfxPoint& point) const
 {
   gfxPoint3D vec3d(point.x, point.y, 0);
   vec3d = Transform3D(vec3d);
   return gfxPoint(vec3d.x, vec3d.y);
@@ -295,16 +441,38 @@ gfx3DMatrix::Transform3D(const gfxPoint3
 
   x /= w;
   y /= w;
   z /= w;
 
   return gfxPoint3D(x, y, z);
 }
 
+gfxPointH3D
+gfx3DMatrix::Transform4D(const gfxPointH3D& aPoint) const
+{
+    gfxFloat x = aPoint.x * _11 + aPoint.y * _21 + aPoint.z * _31 + aPoint.w * _41;
+    gfxFloat y = aPoint.x * _12 + aPoint.y * _22 + aPoint.z * _32 + aPoint.w * _42;
+    gfxFloat z = aPoint.x * _13 + aPoint.y * _23 + aPoint.z * _33 + aPoint.w * _43;
+    gfxFloat w = aPoint.x * _14 + aPoint.y * _24 + aPoint.z * _34 + aPoint.w * _44;
+
+    return gfxPointH3D(x, y, z, w);
+}
+
+gfxPointH3D
+gfx3DMatrix::TransposeTransform4D(const gfxPointH3D& aPoint) const
+{
+    gfxFloat x = aPoint.x * _11 + aPoint.y * _12 + aPoint.z * _13 + aPoint.w * _14;
+    gfxFloat y = aPoint.x * _21 + aPoint.y * _22 + aPoint.z * _23 + aPoint.w * _24;
+    gfxFloat z = aPoint.x * _31 + aPoint.y * _32 + aPoint.z * _33 + aPoint.w * _34;
+    gfxFloat w = aPoint.x * _41 + aPoint.y * _42 + aPoint.z * _43 + aPoint.w * _44;
+
+    return gfxPointH3D(x, y, z, w);
+}
+
 gfxRect
 gfx3DMatrix::TransformBounds(const gfxRect& rect) const
 {
   gfxPoint points[4];
 
   points[0] = Transform(rect.TopLeft());
   points[1] = Transform(gfxPoint(rect.X() + rect.Width(), rect.Y()));
   points[2] = Transform(gfxPoint(rect.X(), rect.Y() + rect.Height()));
@@ -323,24 +491,51 @@ gfx3DMatrix::TransformBounds(const gfxRe
     min_y = min(points[i].y, min_y);
     max_y = max(points[i].y, max_y);
   }
 
   return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y);
 }
 
 PRBool
-gfx3DMatrix::Is2D(gfxMatrix* aMatrix) const
+gfx3DMatrix::Is2D() const
 {
   if (_13 != 0.0f || _14 != 0.0f ||
       _23 != 0.0f || _24 != 0.0f ||
       _31 != 0.0f || _32 != 0.0f || _33 != 1.0f || _34 != 0.0f ||
       _43 != 0.0f || _44 != 1.0f) {
     return PR_FALSE;
   }
+  return PR_TRUE;
+}
+
+PRBool
+gfx3DMatrix::Is2D(gfxMatrix* aMatrix) const
+{
+  if (!Is2D()) {
+    return PR_FALSE;
+  }
+  if (aMatrix) {
+    aMatrix->xx = _11;
+    aMatrix->yx = _12;
+    aMatrix->xy = _21;
+    aMatrix->yy = _22;
+    aMatrix->x0 = _41;
+    aMatrix->y0 = _42;
+  }
+  return PR_TRUE;
+}
+
+PRBool
+gfx3DMatrix::CanDraw2D(gfxMatrix* aMatrix) const
+{
+  if (_14 != 0.0f || _24 != 0.0f ||
+      _34 != 0.0f || _44 != 1.0f) {
+    return PR_FALSE;
+  }
   if (aMatrix) {
     aMatrix->xx = _11;
     aMatrix->yx = _12;
     aMatrix->xy = _21;
     aMatrix->yy = _22;
     aMatrix->x0 = _41;
     aMatrix->y0 = _42;
   }
--- a/gfx/thebes/gfx3DMatrix.h
+++ b/gfx/thebes/gfx3DMatrix.h
@@ -36,16 +36,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_3DMATRIX_H
 #define GFX_3DMATRIX_H
 
 #include <gfxTypes.h>
 #include <gfxPoint3D.h>
+#include <gfxPointH3D.h>
 #include <gfxMatrix.h>
 
 /**
  * This class represents a 3D transformation. The matrix is laid
  * out as follows:
  *
  * _11 _12 _13 _14
  * _21 _22 _23 _24
@@ -67,16 +68,27 @@ public:
   gfx3DMatrix(void);
 
   /**
    * Matrix multiplication.
    */
   gfx3DMatrix operator*(const gfx3DMatrix &aMatrix) const;
   gfx3DMatrix& operator*=(const gfx3DMatrix &aMatrix);
 
+  gfxPointH3D& operator[](int aIndex)
+  {
+      NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
+      return *reinterpret_cast<gfxPointH3D*>((&_11)+4*aIndex);
+  }
+  const gfxPointH3D& operator[](int aIndex) const
+  {
+      NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
+      return *reinterpret_cast<const gfxPointH3D*>((&_11)+4*aIndex);
+  }
+
   /**
    * Return true if this matrix and |aMatrix| are the same matrix.
    */
   bool operator==(const gfx3DMatrix& aMatrix) const;
   
   /**
    * Divide all values in the matrix by a scalar value
    */
@@ -89,56 +101,109 @@ public:
    */
   static gfx3DMatrix From2D(const gfxMatrix &aMatrix);
 
   /**
    * Returns true if the matrix is isomorphic to a 2D affine transformation
    * (i.e. as obtained by From2D). If it is, optionally returns the 2D
    * matrix in aMatrix.
    */
-  PRBool Is2D(gfxMatrix* aMatrix = nsnull) const;
+  PRBool Is2D(gfxMatrix* aMatrix) const;
+  PRBool Is2D() const;
+
+  /**
+   * Returns true if the matrix can be reduced to a 2D affine transformation
+   * (i.e. as obtained by From2D). If it is, optionally returns the 2D
+   * matrix in aMatrix. This should only be used on matrices required for
+   * rendering, not for intermediate calculations.
+   *
+   * Since drawing is to a 2d plane, any 3d transform without perspective
+   * can be reduced by dropping the z row and column.
+   */
+  PRBool CanDraw2D(gfxMatrix* aMatrix = nsnull) const;
 
   /**
    * Returns true if the matrix is the identity matrix. The most important
    * property we require is that gfx3DMatrix().IsIdentity() returns true.
    */
   PRBool IsIdentity() const;
 
   /**
+   * Add a translation by aPoint to the matrix.
+   * This is functionally equivalent to:
+   * gfx3DMatrix::Translation(aPoint) * matrix
+   */
+  void Translate(const gfxPoint3D& aPoint);
+
+  /**
+   * Add a translation by aPoint after the matrix.
+   * This is functionally equivalent to:
+   * matrix *gfx3DMatrix::Translation(aPoint)
+   */
+  void TranslatePost(const gfxPoint3D& aPoint);
+
+  void SkewXY(float aSkew);
+  void SkewXZ(float aSkew);
+  void SkewYZ(float aSkew);
+
+  void Scale(float aX, float aY, float aZ);
+
+  /**
    * Transforms a point according to this matrix.
    */
   gfxPoint Transform(const gfxPoint& point) const;
 
   /**
    * Transforms a rectangle according to this matrix
    */
   gfxRect TransformBounds(const gfxRect& rect) const;
 
   /** 
    * Transforms a 3D vector according to this matrix.
    */
   gfxPoint3D Transform3D(const gfxPoint3D& point) const;
+  gfxPointH3D Transform4D(const gfxPointH3D& aPoint) const;
+  gfxPointH3D TransposeTransform4D(const gfxPointH3D& aPoint) const;
 
   gfxPoint ProjectPoint(const gfxPoint& aPoint) const;
   gfxRect ProjectRectBounds(const gfxRect& aRect) const;
 
 
   /**
    * Inverts this matrix, if possible. Otherwise, the matrix is left
    * unchanged.
    */
-  gfx3DMatrix& Invert();
+  gfx3DMatrix Inverse() const;
 
-  inline gfx3DMatrix Inverse() const
+  gfx3DMatrix& Invert()
+  {
+      *this = Inverse();
+      return *this;
+  }
+
+  gfx3DMatrix& Normalize();
+
+  gfxPointH3D TransposedVector(int aIndex) const
   {
-    gfx3DMatrix temp = *this;
-    temp.Invert();
-    return temp;
+      NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
+      return gfxPointH3D(*((&_11)+aIndex), *((&_21)+aIndex), *((&_31)+aIndex), *((&_41)+aIndex));
   }
 
+  void SetTransposedVector(int aIndex, gfxPointH3D &aVector)
+  {
+      NS_ABORT_IF_FALSE(aIndex >= 0 && aIndex <= 3, "Invalid matrix array index");
+      *((&_11)+aIndex) = aVector.x;
+      *((&_21)+aIndex) = aVector.y;
+      *((&_31)+aIndex) = aVector.z;
+      *((&_41)+aIndex) = aVector.w;
+  }
+
+  gfx3DMatrix& Transpose();
+  gfx3DMatrix Transposed() const;
+
   /**
    * Returns a unit vector that is perpendicular to the plane formed
    * by transform the screen plane (z=0) by this matrix.
    */
   gfxPoint3D GetNormalVector() const;
 
   /**
    * Check if matrix is singular (no inverse exists).
@@ -155,26 +220,31 @@ public:
   static gfx3DMatrix Translation(float aX, float aY, float aZ);
   static gfx3DMatrix Translation(const gfxPoint3D& aPoint);
 
   /**
    * Create a scale matrix. Scales uniformly along all axes.
    *
    * \param aScale Scale factor
    */
-  static gfx3DMatrix Scale(float aFactor);
+  static gfx3DMatrix ScalingMatrix(float aFactor);
 
   /**
    * Create a scale matrix.
    */
-  static gfx3DMatrix Scale(float aX, float aY, float aZ);
+  static gfx3DMatrix ScalingMatrix(float aX, float aY, float aZ);
+
+  gfxFloat Determinant() const;
 
 private:
 
-  gfxFloat Determinant() const;
+  gfxFloat Determinant3x3() const;
+  gfx3DMatrix Inverse3x3() const;
+
+  gfx3DMatrix Multiply2D(const gfx3DMatrix &aMatrix) const;
 
 public:
 
   /** Matrix elements */
   float _11, _12, _13, _14;
   float _21, _22, _23, _24;
   float _31, _32, _33, _34;
   float _41, _42, _43, _44;
--- a/gfx/thebes/gfxContext.cpp
+++ b/gfx/thebes/gfxContext.cpp
@@ -691,16 +691,39 @@ gfxContext::UpdateSurfaceClip()
 gfxRect
 gfxContext::GetClipExtents()
 {
     double xmin, ymin, xmax, ymax;
     cairo_clip_extents(mCairo, &xmin, &ymin, &xmax, &ymax);
     return gfxRect(xmin, ymin, xmax - xmin, ymax - ymin);
 }
 
+PRBool
+gfxContext::ClipContainsRect(const gfxRect& aRect)
+{
+    cairo_rectangle_list_t *clip =
+        cairo_copy_clip_rectangle_list(mCairo);
+
+    PRBool result = PR_FALSE;
+
+    if (clip->status == CAIRO_STATUS_SUCCESS) {
+        for (int i = 0; i < clip->num_rectangles; i++) {
+            gfxRect rect(clip->rectangles[i].x, clip->rectangles[i].y,
+                         clip->rectangles[i].width, clip->rectangles[i].height);
+            if (rect.Contains(aRect)) {
+                result = PR_TRUE;
+                break;
+            }
+        }
+    }
+
+   cairo_rectangle_list_destroy(clip);
+   return result;
+}
+
 // rendering sources
 
 void
 gfxContext::SetColor(const gfxRGBA& c)
 {
     if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
 
         gfxRGBA cms;
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -601,16 +601,23 @@ public:
 
     /**
      * This will return the current bounds of the clip region in user
      * space.
      */
     gfxRect GetClipExtents();
 
     /**
+     * Returns true if the given rectangle is fully contained in the current clip. 
+     * This is conservative; it may return false even when the given rectangle is 
+     * fully contained by the current clip.
+     */
+    PRBool ClipContainsRect(const gfxRect& aRect);
+
+    /**
      * Groups
      */
     void PushGroup(gfxASurface::gfxContentType content = gfxASurface::CONTENT_COLOR);
     /**
      * Like PushGroup, but if the current surface is CONTENT_COLOR and
      * content is CONTENT_COLOR_ALPHA, makes the pushed surface CONTENT_COLOR
      * instead and copies the contents of the current surface to the pushed
      * surface. This is good for pushing opacity groups, since blending the
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxPointH3D.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * ***** 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 Oracle Corporation code.
+ *
+ * The Initial Developer of the Original Code is Oracle Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2005
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@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 GFX_POINTH3D_H
+#define GFX_POINTH3D_H
+
+#include "mozilla/gfx/BasePoint4D.h"
+#include "gfxTypes.h"
+
+struct THEBES_API gfxPointH3D : public mozilla::gfx::BasePoint4D<float, gfxPointH3D> {
+    typedef mozilla::gfx::BasePoint4D<float, gfxPointH3D> Super;
+
+    gfxPointH3D() : Super() {}
+    gfxPointH3D(float aX, float aY, float aZ, float aW) : Super(aX, aY, aZ, aW) {}
+};
+
+#endif /* GFX_POINTH3D_H */ 
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/gfxQuaternion.h
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** 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 Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Matt Woodrow <mwoodrow@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 GFX_QUATERNION_H
+#define GFX_QUATERNION_H
+
+#include "mozilla/gfx/BasePoint4D.h"
+#include "gfx3DMatrix.h"
+
+struct THEBES_API gfxQuaternion : public mozilla::gfx::BasePoint4D<gfxFloat, gfxQuaternion> {
+    typedef mozilla::gfx::BasePoint4D<gfxFloat, gfxQuaternion> Super;
+
+    gfxQuaternion() : Super() {}
+    gfxQuaternion(gfxFloat aX, gfxFloat aY, gfxFloat aZ, gfxFloat aW) : Super(aX, aY, aZ, aW) {}
+
+    gfxQuaternion(const gfx3DMatrix& aMatrix) {
+        w = 0.5 * sqrt(NS_MAX(1 + aMatrix[0][0] + aMatrix[1][1] + aMatrix[2][2], 0.0f));
+        x = 0.5 * sqrt(NS_MAX(1 + aMatrix[0][0] - aMatrix[1][1] - aMatrix[2][2], 0.0f));
+        y = 0.5 * sqrt(NS_MAX(1 - aMatrix[0][0] + aMatrix[1][1] - aMatrix[2][2], 0.0f));
+        z = 0.5 * sqrt(NS_MAX(1 - aMatrix[0][0] - aMatrix[1][1] + aMatrix[2][2], 0.0f));
+
+        if(aMatrix[2][1] > aMatrix[1][2])
+            x = -x;
+        if(aMatrix[0][2] > aMatrix[2][0])
+            y = -y;
+        if(aMatrix[1][0] > aMatrix[0][1])
+            z = -z;
+    }
+
+    gfxQuaternion Slerp(const gfxQuaternion &aOther, gfxFloat aCoeff) {
+        gfxFloat dot = NS_CLAMP(DotProduct(aOther), -1.0, 1.0);
+        if (dot == 1.0) {
+            return *this;
+        }
+
+        gfxFloat theta = acos(dot);
+        gfxFloat rsintheta = 1/sqrt(1 - dot*dot);
+        gfxFloat w = sin(aCoeff*theta)*rsintheta;
+
+        gfxQuaternion left = *this;
+        gfxQuaternion right = aOther;
+
+        left *= cos(aCoeff*theta) - dot*w;
+        right *= w;
+
+        return left + right;
+    }
+
+    gfx3DMatrix ToMatrix() {
+        gfx3DMatrix temp;
+
+        temp[0][0] = 1 - 2 * (y * y + z * z);
+        temp[0][1] = 2 * (x * y + w * z);
+        temp[0][2] = 2 * (x * z - w * y);
+        temp[1][0] = 2 * (x * y - w * z);
+        temp[1][1] = 1 - 2 * (x * x + z * z);
+        temp[1][2] = 2 * (y * z + w * x);
+        temp[2][0] = 2 * (x * z + w * y);
+        temp[2][1] = 2 * (y * z - w * x);
+        temp[2][2] = 1 - 2 * (x * x + y * y);
+
+        return temp;
+    }
+
+};
+
+#endif /* GFX_QUATERNION_H */
\ No newline at end of file
--- a/js/src/aclocal.m4
+++ b/js/src/aclocal.m4
@@ -5,10 +5,11 @@ dnl
 
 builtin(include, build/autoconf/pkg.m4)dnl
 builtin(include, build/autoconf/nspr.m4)dnl
 builtin(include, build/autoconf/altoptions.m4)dnl
 builtin(include, build/autoconf/moznbytetype.m4)dnl
 builtin(include, build/autoconf/mozprog.m4)dnl
 builtin(include, build/autoconf/acwinpaths.m4)dnl
 builtin(include, build/autoconf/lto.m4)dnl
+builtin(include, build/autoconf/gcc-pr49911.m4)dnl
 
 MOZ_PROG_CHECKMSYS()
new file mode 100644
--- /dev/null
+++ b/js/src/build/autoconf/gcc-pr49911.m4
@@ -0,0 +1,67 @@
+dnl Check if the compiler is gcc and has PR49911. If so
+dnl disable vrp.
+
+AC_DEFUN([MOZ_GCC_PR49911],
+[
+if test "$GNU_CC"; then
+
+AC_MSG_CHECKING(for gcc PR49911)
+ac_have_gcc_pr49911="no"
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+
+_SAVE_CXXFLAGS=$CXXFLAGS
+CXXFLAGS="-O2"
+AC_TRY_RUN([
+extern "C" void abort(void);
+typedef enum {
+eax,         ecx,         edx,         ebx,         esp,         ebp,
+esi,         edi     }
+RegisterID;
+union StateRemat {
+  RegisterID reg_;
+  int offset_;
+};
+static StateRemat FromRegister(RegisterID reg) {
+  StateRemat sr;
+  sr.reg_ = reg;
+  return sr;
+}
+static StateRemat FromAddress3(int address) {
+  StateRemat sr;
+  sr.offset_ = address;
+  if (address < 46 &&    address >= 0) {
+    abort();
+  }
+  return sr;
+}
+struct FrameState {
+  StateRemat dataRematInfo2(bool y, int z) {
+    if (y)         return FromRegister(RegisterID(1));
+    return FromAddress3(z);
+  }
+};
+FrameState frame;
+StateRemat x;
+__attribute__((noinline)) void jsop_setelem(bool y, int z) {
+  x = frame.dataRematInfo2(y, z);
+}
+int main(void) {
+  jsop_setelem(0, 47);
+}
+], true,
+   ac_have_gcc_pr49911="yes",
+   true)
+CXXFLAGS="$_SAVE_CXXFLAGS"
+
+AC_LANG_RESTORE
+
+if test "$ac_have_gcc_pr49911" == "yes"; then
+   AC_MSG_RESULT(yes)
+   CFLAGS="$CFLAGS -fno-tree-vrp"
+   CXXFLAGS="$CXXFLAGS -fno-tree-vrp"
+else
+   AC_MSG_RESULT(no)
+fi
+fi
+])
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -2019,18 +2019,16 @@ case "$target" in
     AC_TRY_LINK(,[return 0;],
                 ac_cv_have_framework_exceptionhandling="yes",
                 ac_cv_have_framework_exceptionhandling="no")
     AC_MSG_RESULT([$ac_cv_have_framework_exceptionhandling])
     if test  "$ac_cv_have_framework_exceptionhandling" = "yes"; then
       MOZ_DEBUG_LDFLAGS="$MOZ_DEBUG_LDFLAGS -framework ExceptionHandling";
     fi
     LDFLAGS=$_SAVE_LDFLAGS
-    # Debug builds should always have frame pointers
-    MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
 
     if test "x$lto_is_enabled" = "xyes"; then
         echo "Skipping -dead_strip because lto is enabled."
     dnl DTrace and -dead_strip don't interact well. See bug 403132.
     dnl ===================================================================
     elif test "x$enable_dtrace" = "xyes"; then
         echo "Skipping -dead_strip because DTrace is enabled. See bug 403132."
     else
@@ -2169,18 +2167,16 @@ ia64*-hpux*)
     # If we're building with --enable-profiling, we need a frame pointer.
     if test -z "$MOZ_PROFILING"; then
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fomit-frame-pointer"
     else
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks -fno-reorder-functions -fno-omit-frame-pointer"
     fi
     # The Maemo builders don't know about this flag
     MOZ_ARM_VFP_FLAGS="-mfpu=vfp"
-    # Debug builds should always have frame pointers
-    MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
     ;;
 
 *-*linux*)
     # Note: both GNU_CC and INTEL_CC are set when using Intel's C compiler.
     # Similarly for GNU_CXX and INTEL_CXX.
     if test "$INTEL_CC" -o "$INTEL_CXX"; then
         # -Os has been broken on Intel's C/C++ compilers for quite a
         # while; Intel recommends against using it.
@@ -2196,18 +2192,17 @@ ia64*-hpux*)
         # If we're building with --enable-profiling, we need a frame pointer.
         if test -z "$MOZ_PROFILING"; then
             MOZ_FRAMEPTR_FLAGS="-fomit-frame-pointer"
         else
             MOZ_FRAMEPTR_FLAGS="-fno-omit-frame-pointer"
         fi
         MOZ_PGO_OPTIMIZE_FLAGS="-O3 $MOZ_FRAMEPTR_FLAGS"
         MOZ_OPTIMIZE_FLAGS="-Os -freorder-blocks $MOZ_OPTIMIZE_SIZE_TWEAK $MOZ_FRAMEPTR_FLAGS"
-        # Debug builds should always have frame pointers
-        MOZ_DEBUG_FLAGS="-g -fno-omit-frame-pointer"
+        MOZ_DEBUG_FLAGS="-g"
     fi
 
     TARGET_NSPR_MDCPUCFG='\"md/_linux.cfg\"'
 
     case "${target_cpu}" in
     alpha*)
     	CFLAGS="$CFLAGS -mieee"
     	CXXFLAGS="$CXXFLAGS -mieee"
@@ -2313,18 +2308,17 @@ ia64*-hpux*)
         CFLAGS="$CFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         CXXFLAGS="$CXXFLAGS -W3 -Gy -Fd\$(COMPILE_PDBFILE)"
         # MSVC warnings C4244 and C4800 are ubiquitous, useless, and annoying.
         CXXFLAGS="$CXXFLAGS -wd4244 -wd4800"
         # make 'foo == bar;' error out
         CFLAGS="$CFLAGS -we4553"
         CXXFLAGS="$CXXFLAGS -we4553"
         LIBS="$LIBS kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib"
-        # Debug builds should always have frame pointers
-        MOZ_DEBUG_FLAGS='-Zi -Oy-'
+        MOZ_DEBUG_FLAGS='-Zi'
         MOZ_DEBUG_LDFLAGS='-DEBUG -DEBUGTYPE:CV'
         WARNINGS_AS_ERRORS='-WX'
         # If we're building with --enable-profiling, we need -Oy-, which forces a frame pointer.
         if test -z "$MOZ_PROFILING"; then
             MOZ_OPTIMIZE_FLAGS='-O1'
         else
             MOZ_OPTIMIZE_FLAGS='-O1 -Oy-'
         fi
@@ -3227,16 +3221,18 @@ fi         # GNU_CC
 # visibility hidden flag for Sun Studio on Solaris
 if test "$SOLARIS_SUNPRO_CC"; then
 VISIBILITY_FLAGS='-xldscope=hidden'
 fi         # Sun Studio on Solaris
 
 AC_SUBST(WRAP_SYSTEM_INCLUDES)
 AC_SUBST(VISIBILITY_FLAGS)
 
+MOZ_GCC_PR49911
+
 dnl Check for __force_align_arg_pointer__ for SSE2 on gcc
 dnl ========================================================
 if test "$GNU_CC"; then
   CFLAGS_save="${CFLAGS}"
   CFLAGS="${CFLAGS} -Werror"
   AC_CACHE_CHECK(for __force_align_arg_pointer__ attribute,
                  ac_cv_force_align_arg_pointer,
                  [AC_TRY_COMPILE([__attribute__ ((__force_align_arg_pointer__)) void test() {}],
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -1407,17 +1407,17 @@ ContainerState::ProcessDisplayItems(cons
         continue;
       }
 
       // If it's not a ContainerLayer, we need to apply the scale transform
       // ourselves.
       if (!ownLayer->AsContainerLayer()) {
         // The layer's current transform is applied first, then the result is scaled.
         gfx3DMatrix transform = ownLayer->GetTransform()*
-            gfx3DMatrix::Scale(mParameters.mXScale, mParameters.mYScale, 1.0f);
+            gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f);
         ownLayer->SetTransform(transform);
       }
 
       ownLayer->SetIsFixedPosition(!nsLayoutUtils::ScrolledByViewportScrolling(
                                       activeScrolledRoot, mBuilder));
 
       // Update that layer's clip and visible rects.
       NS_ASSERTION(ownLayer->Manager() == mManager, "Wrong manager");
@@ -1672,17 +1672,17 @@ ContainerState::Finish(PRUint32* aTextCo
 static FrameLayerBuilder::ContainerParameters
 ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
                            nsIFrame* aContainerFrame,
                            const gfx3DMatrix* aTransform,
                            const FrameLayerBuilder::ContainerParameters& aIncomingScale,
                            ContainerLayer* aLayer)
 {
   gfx3DMatrix transform =
-    gfx3DMatrix::Scale(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
+    gfx3DMatrix::ScalingMatrix(aIncomingScale.mXScale, aIncomingScale.mYScale, 1.0);
   if (aTransform) {
     // aTransform is applied first, then the scale is applied to the result
     transform = (*aTransform)*transform;
   }
 
   gfxMatrix transform2d;
   gfxSize scale;
   // Only fiddle with scale factors for the retaining layer manager, since
@@ -1711,17 +1711,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
     if (fabs(scale.width) < 1e-8 || fabs(scale.height) < 1e-8) {
       scale.width = scale.height = 1.0;
     }
   } else {
     scale = gfxSize(1.0, 1.0);
   }
 
   // Apply the inverse of our resolution-scale before the rest of our transform
-  transform = gfx3DMatrix::Scale(1.0/scale.width, 1.0/scale.height, 1.0)*transform;
+  transform = gfx3DMatrix::ScalingMatrix(1.0/scale.width, 1.0/scale.height, 1.0)*transform;
   aLayer->SetTransform(transform);
 
   FrameLayerBuilder::ContainerParameters
     result(scale.width, scale.height, aIncomingScale);
   if (aTransform) {
     result.mInTransformedSubtree = true;
     if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
       result.mInActiveTransformedSubtree = true;
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -595,18 +595,18 @@ void nsDisplayList::PaintForFrame(nsDisp
     (presShell->GetXResolution(), presShell->GetYResolution());
   nsRefPtr<ContainerLayer> root = aBuilder->LayerBuilder()->
     BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nsnull, *this,
                            containerParameters, nsnull);
   if (!root)
     return;
   // Root is being scaled up by the X/Y resolution. Scale it back down.
   gfx3DMatrix rootTransform = root->GetTransform()*
-    gfx3DMatrix::Scale(1.0f/containerParameters.mXScale,
-                       1.0f/containerParameters.mYScale, 1.0f);
+    gfx3DMatrix::ScalingMatrix(1.0f/containerParameters.mXScale,
+                               1.0f/containerParameters.mYScale, 1.0f);
   root->SetTransform(rootTransform);
 
   ViewID id = presContext->IsRootContentDocument() ? FrameMetrics::ROOT_SCROLL_ID
                                                    : FrameMetrics::NULL_SCROLL_ID;
 
   nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame();
   nsRect displayport;
   bool usingDisplayport = false;
@@ -757,25 +757,43 @@ static PRBool IsContentLEQ(nsDisplayItem
   // These GetUnderlyingFrame calls return non-null because we're only used
   // in sorting
   return nsLayoutUtils::CompareTreePosition(
       aItem1->GetUnderlyingFrame()->GetContent(),
       aItem2->GetUnderlyingFrame()->GetContent(),
       static_cast<nsIContent*>(aClosure)) <= 0;
 }
 
+static PRBool IsZPositionLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
+                             void* aClosure) {
+  if (!aItem1->GetUnderlyingFrame()->Preserves3D() ||
+      !aItem1->GetUnderlyingFrame()->Preserves3D()) {
+    return IsContentLEQ(aItem1, aItem2, aClosure);
+  }
+
+  nsIFrame* ancestor;
+  gfx3DMatrix matrix1 = aItem1->GetUnderlyingFrame()->GetTransformMatrix(&ancestor);
+  gfx3DMatrix matrix2 = aItem2->GetUnderlyingFrame()->GetTransformMatrix(&ancestor);
+
+  if (matrix1._43 == matrix2._43) {
+    return IsContentLEQ(aItem1, aItem2, aClosure);
+  }
+
+  return matrix1._43 < matrix2._43;
+}
+
 static PRBool IsZOrderLEQ(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
                           void* aClosure) {
   // These GetUnderlyingFrame calls return non-null because we're only used
   // in sorting.  Note that we can't just take the difference of the two
   // z-indices here, because that might overflow a 32-bit int.
   PRInt32 index1 = nsLayoutUtils::GetZIndex(aItem1->GetUnderlyingFrame());
   PRInt32 index2 = nsLayoutUtils::GetZIndex(aItem2->GetUnderlyingFrame());
   if (index1 == index2)
-    return IsContentLEQ(aItem1, aItem2, aClosure);
+    return IsZPositionLEQ(aItem1, aItem2, aClosure);
   return index1 < index2;
 }
 
 void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) {
   // See if there's anything to do
   PRBool anyAnonymousItems = PR_FALSE;
   nsDisplayItem* i;
   for (i = GetBottom(); i != nsnull; i = i->GetAbove()) {
@@ -812,16 +830,21 @@ void nsDisplayList::SortByZOrder(nsDispl
   Sort(aBuilder, IsZOrderLEQ, aCommonAncestor);
 }
 
 void nsDisplayList::SortByContentOrder(nsDisplayListBuilder* aBuilder,
                                        nsIContent* aCommonAncestor) {
   Sort(aBuilder, IsContentLEQ, aCommonAncestor);
 }
 
+void nsDisplayList::SortByZPosition(nsDisplayListBuilder* aBuilder,
+                                    nsIContent* aCommonAncestor) {
+  Sort(aBuilder, IsZPositionLEQ, aCommonAncestor);
+}
+
 void nsDisplayList::Sort(nsDisplayListBuilder* aBuilder,
                          SortLEQ aCmp, void* aClosure) {
   ExplodeAnonymousChildLists(aBuilder);
   ::Sort(this, Count(), aCmp, aClosure);
 }
 
 PRBool nsDisplayItem::RecomputeVisibility(nsDisplayListBuilder* aBuilder,
                                           nsRegion* aVisibleRegion) {
@@ -2414,21 +2437,31 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigi
 /* Wraps up the -moz-transform matrix in a change-of-basis matrix pair that
  * translates from local coordinate space to transform coordinate space, then
  * hands it back.
  */
 gfx3DMatrix
 nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
                                                 const nsPoint &aOrigin,
                                                 float aFactor,
-                                                const nsRect* aBoundsOverride)
+                                                const nsRect* aBoundsOverride,
+                                                nsIFrame** aOutAncestor)
 {
   NS_PRECONDITION(aFrame, "Cannot get transform matrix for a null frame!");
-  NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
-                  "Cannot get transform matrix if frame isn't transformed!");
+
+  if (aOutAncestor) {
+      *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
+  }
+
+  /* Preserve-3d can cause frames without a transform to get an nsDisplayTransform created, we should
+   * use our parent's transform here.
+   */
+  if (!aFrame->GetStyleDisplay()->HasTransform()) {
+    return GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(), aFactor, nsnull, aOutAncestor);
+  }
 
   /* Account for the -moz-transform-origin property by translating the
    * coordinate space to the new origin.
    */
   gfxPoint3D toMozOrigin = GetDeltaToMozTransformOrigin(aFrame, aFactor, aBoundsOverride);
   gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aFactor, aBoundsOverride);
   gfxPoint3D newOrigin = gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aFactor),
                                     NSAppUnitsToFloatPixels(aOrigin.y, aFactor),
@@ -2438,35 +2471,53 @@ nsDisplayTransform::GetResultingTransfor
    * bounds of the frame.
    */
   const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
   nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
                    nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
 
   /* Get the matrix, then change its basis to factor in the origin. */
   PRBool dummy;
-  gfx3DMatrix result =
-    nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
-                                           aFrame->GetStyleContext(),
-                                           aFrame->PresContext(),
-                                           dummy, bounds, aFactor);
+  gfx3DMatrix result;
+  /* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
+  if (disp->mSpecifiedTransform) {
+    result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
+                                                    aFrame->GetStyleContext(),
+                                                    aFrame->PresContext(),
+                                                    dummy, bounds, aFactor);
+  } else {
+     NS_ASSERTION(aFrame->Preserves3DChildren(),
+                  "If we don't have a transform, then we must be at least preserving transforms of our children");
+  }
 
   const nsStyleDisplay* parentDisp = nsnull;
   if (aFrame->GetParent()) {
     parentDisp = aFrame->GetParent()->GetStyleDisplay();
   }
   if (nsLayoutUtils::Are3DTransformsEnabled() &&
       parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
       parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
     gfx3DMatrix perspective;
     perspective._34 =
       -1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(),
                                      aFactor);
     result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin, perspective);
   }
+
+  if (aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {
+      // Include the transform set on our parent
+      NS_ASSERTION(aFrame->GetParent() &&
+                   aFrame->GetParent()->IsTransformed() &&
+                   aFrame->GetParent()->Preserves3DChildren(),
+                   "Preserve3D mismatch!");
+      gfx3DMatrix parent = GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(),
+                                                       aFactor, nsnull, aOutAncestor);
+      return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
+  }
+
   return nsLayoutUtils::ChangeMatrixBasis
     (newOrigin + toMozOrigin, result);
 }
 
 const gfx3DMatrix&
 nsDisplayTransform::GetTransform(float aFactor)
 {
   if (mTransform.IsIdentity() || mCachedFactor != aFactor) {
@@ -2734,51 +2785,44 @@ nsDisplayTransform::TryMerge(nsDisplayLi
  *         rectangle.
  */
 nsRect nsDisplayTransform::TransformRect(const nsRect &aUntransformedBounds,
                                          const nsIFrame* aFrame,
                                          const nsPoint &aOrigin,
                                          const nsRect* aBoundsOverride)
 {
   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
-  NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
-                  "Cannot transform a rectangle if there's no transformation!");
 
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   return nsLayoutUtils::MatrixTransformRect
     (aUntransformedBounds,
      GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
      factor);
 }
 
 nsRect nsDisplayTransform::TransformRectOut(const nsRect &aUntransformedBounds,
                                             const nsIFrame* aFrame,
                                             const nsPoint &aOrigin,
                                             const nsRect* aBoundsOverride)
 {
   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
-  NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
-                  "Cannot transform a rectangle if there's no transformation!");
 
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   return nsLayoutUtils::MatrixTransformRectOut
     (aUntransformedBounds,
      GetResultingTransformMatrix(aFrame, aOrigin, factor, aBoundsOverride),
      factor);
 }
 
 PRBool nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
                                            const nsIFrame* aFrame,
                                            const nsPoint &aOrigin,
                                            nsRect* aOutRect)
 {
   NS_PRECONDITION(aFrame, "Can't take the transform based on a null frame!");
-  NS_PRECONDITION(aFrame->GetStyleDisplay()->HasTransform(),
-                  "Cannot transform a rectangle if there's no transformation!");
-
 
   /* Grab the matrix.  If the transform is degenerate, just hand back the
    * empty rect.
    */
   float factor = nsPresContext::AppUnitsPerCSSPixel();
   gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nsnull);
   if (matrix.IsSingular())
     return PR_FALSE;
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1004,16 +1004,18 @@ public:
    * GetUnderlyingFrame() on each item. z-index is ignored.
    * @param aCommonAncestor a common ancestor of all the content elements
    * associated with the display items, for speeding up tree order
    * checks, or nsnull if not known; it's only a hint, if it is not an
    * ancestor of some elements, then we lose performance but not correctness
    */
   void SortByContentOrder(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
 
+  void SortByZPosition(nsDisplayListBuilder* aBuilder, nsIContent* aCommonAncestor);
+
   /**
    * Generic stable sort. Take care, because some of the items might be nsDisplayLists
    * themselves.
    * aCmp(item1, item2) should return true if item1 <= item2. We sort the items
    * into increasing order.
    */
   typedef PRBool (* SortLEQ)(nsDisplayItem* aItem1, nsDisplayItem* aItem2,
                              void* aClosure);
@@ -2075,16 +2077,23 @@ public:
    */
   nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
                      nsDisplayList *aList) :
     nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aList)
   {
     MOZ_COUNT_CTOR(nsDisplayTransform);
   }
 
+  nsDisplayTransform(nsDisplayListBuilder* aBuilder, nsIFrame *aFrame,
+                     nsDisplayItem *aItem) :
+  nsDisplayItem(aBuilder, aFrame), mStoredList(aBuilder, aFrame, aItem)
+  {
+    MOZ_COUNT_CTOR(nsDisplayTransform);
+  }
+
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTransform()
   {
     MOZ_COUNT_DTOR(nsDisplayTransform);
   }
 #endif
 
   NS_DISPLAY_DECL_NAME("nsDisplayTransform", TYPE_TRANSFORM);
@@ -2179,21 +2188,22 @@ public:
    *        computation will use the value of GetFrameBoundsForTransform(aFrame)
    *        for the frame's bounding rectangle. Otherwise, it will use the
    *        value of aBoundsOverride.  This is mostly for internal use and in
    *        most cases you will not need to specify a value.
    */
   static gfx3DMatrix GetResultingTransformMatrix(const nsIFrame* aFrame,
                                                  const nsPoint& aOrigin,
                                                  float aFactor,
-                                                 const nsRect* aBoundsOverride = nsnull);
+                                                 const nsRect* aBoundsOverride = nsnull,
+                                                 nsIFrame** aOutAncestor = nsnull);
 
 private:
   nsDisplayWrapList mStoredList;
-  gfx3DMatrix mTransform;
+  gfx3DMatrix mTransform;
   float mCachedFactor;
 };
 
 /**
  * This class adds basic support for limiting the rendering to the part inside
  * the specified edges.  It's a base class for the display item classes that
  * does the actual work.  The two members, mLeftEdge and mRightEdge, are
  * relative to the edges of the frame's scrollable overflow rectangle and is
--- a/layout/base/nsLayoutDebugger.cpp
+++ b/layout/base/nsLayoutDebugger.cpp
@@ -174,23 +174,23 @@ PrintDisplayListTo(nsDisplayListBuilder*
       }
       default:
         break;
     }
     nscolor color;
     nsRect vis = i->GetVisibleRect();
     nsDisplayList* list = i->GetList();
     nsRegion opaque;
+    if (i->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
+        nsDisplayTransform* t = static_cast<nsDisplayTransform*>(i);
+        list = t->GetStoredList()->GetList();
+    }
     if (!list || list->DidComputeVisibility()) {
       opaque = i->GetOpaqueRegion(aBuilder);
     }
-    if (i->GetType() == nsDisplayItem::TYPE_TRANSFORM) {
-      nsDisplayTransform* t = static_cast<nsDisplayTransform*>(i);
-      list = t->GetStoredList()->GetList();
-    }
     fprintf(aOutput, "%s %p(%s) (%d,%d,%d,%d)(%d,%d,%d,%d)%s%s",
             i->Name(), (void*)f, NS_ConvertUTF16toUTF8(fName).get(),
             rect.x, rect.y, rect.width, rect.height,
             vis.x, vis.y, vis.width, vis.height,
             opaque.IsEmpty() ? "" : " opaque",
             i->IsUniform(aBuilder, &color) ? " uniform" : "");
     if (f) {
       PRUint32 key = i->GetPerFrameKey();
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1003,24 +1003,25 @@ nsLayoutUtils::GetPopupFrameForEventCoor
 #endif
   return nsnull;
 }
 
 gfx3DMatrix
 nsLayoutUtils::ChangeMatrixBasis(const gfxPoint3D &aOrigin,
                                  const gfx3DMatrix &aMatrix)
 {
-  /* These are translation matrices from world-to-origin of relative frame and
-   * vice-versa.
-   */
-  gfx3DMatrix worldToOrigin = gfx3DMatrix::Translation(-aOrigin);
-  gfx3DMatrix originToWorld = gfx3DMatrix::Translation(aOrigin);
-
-  /* Multiply all three to get the transform! */
-  return worldToOrigin * aMatrix * originToWorld;
+  gfx3DMatrix result = aMatrix;
+
+  /* Translate to the origin before aMatrix */
+  result.Translate(-aOrigin);
+
+  /* Translate back into position after aMatrix */
+  result.TranslatePost(aOrigin);
+
+  return result; 
 }
 
 /**
  * Given a gfxFloat, constrains its value to be between nscoord_MIN and nscoord_MAX.
  *
  * @param aVal The value to constrain (in/out)
  */
 static void ConstrainToCoordValues(gfxFloat &aVal)
--- a/layout/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -857,16 +857,19 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_COLOR_INTERPOLATION_AUTO           0
 #define NS_STYLE_COLOR_INTERPOLATION_SRGB           1
 #define NS_STYLE_COLOR_INTERPOLATION_LINEARRGB      2
 
 // 3d Transforms - Backface visibility
 #define NS_STYLE_BACKFACE_VISIBILITY_VISIBLE        1
 #define NS_STYLE_BACKFACE_VISIBILITY_HIDDEN         0
 
+#define NS_STYLE_TRANSFORM_STYLE_FLAT               0
+#define NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D        1
+
 /*****************************************************************************
  * Constants for media features.                                             *
  *****************************************************************************/
 
 // orientation
 #define NS_STYLE_ORIENTATION_PORTRAIT           0
 #define NS_STYLE_ORIENTATION_LANDSCAPE          1
 
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -255,17 +255,16 @@ static NS_DEFINE_CID(kWindowCommandTable
 
 #include "inDeepTreeWalker.h"
 #include "inFlasher.h"
 #include "inCSSValueSearch.h"
 #include "inDOMUtils.h"
 
 #ifdef MOZ_XUL
 #include "nsIXULDocument.h"
-#include "nsIXULPrototypeCache.h"
 #include "nsIXULSortService.h"
 
 nsresult
 NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 
 nsresult
 NS_NewXULTreeBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult);
 #endif
@@ -534,17 +533,16 @@ MAKE_CTOR(CreateSanitizingHTMLSerializer
 MAKE_CTOR(CreateXBLService,               nsIXBLService,               NS_NewXBLService)
 MAKE_CTOR(CreateContentPolicy,            nsIContentPolicy,            NS_NewContentPolicy)
 #ifdef MOZ_XUL
 MAKE_CTOR(CreateXULSortService,           nsIXULSortService,           NS_NewXULSortService)
 // NS_NewXULContentBuilder
 // NS_NewXULTreeBuilder
 MAKE_CTOR(CreateXULDocument,              nsIXULDocument,              NS_NewXULDocument)
 // NS_NewXULControllers
-// NS_NewXULPrototypeCache
 MAKE_CTOR(CreateXULPopupManager,      nsISupports,      NS_NewXULPopupManager)
 #endif
 #ifdef MOZ_XTF
 MAKE_CTOR(CreateXTFService,               nsIXTFService,               NS_NewXTFService)
 MAKE_CTOR(CreateXMLContentBuilder,        nsIXMLContentBuilder,        NS_NewXMLContentBuilder)
 #endif
 MAKE_CTOR(CreateContentDLF,               nsIDocumentLoaderFactory,    NS_NewContentDocumentLoaderFactory)
 MAKE_CTOR(CreateEventListenerService,     nsIEventListenerService,     NS_NewEventListenerService)
@@ -759,17 +757,17 @@ NS_DEFINE_NAMED_CID(NS_CONTENTITERATOR_C
 NS_DEFINE_NAMED_CID(NS_PRECONTENTITERATOR_CID);
 NS_DEFINE_NAMED_CID(NS_SUBTREEITERATOR_CID);
 NS_DEFINE_NAMED_CID(NS_HTMLIMAGEELEMENT_CID);
 NS_DEFINE_NAMED_CID(NS_HTMLOPTIONELEMENT_CID);
 #ifdef MOZ_MEDIA
 NS_DEFINE_NAMED_CID(NS_HTMLAUDIOELEMENT_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2D_CID);
-NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2DTHEBES_CID);
+NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2DTHEBES_CID);
 NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXT2DAZURE_CID);
 NS_DEFINE_NAMED_CID(NS_CANVASRENDERINGCONTEXTWEBGL_CID);
 NS_DEFINE_NAMED_CID(NS_TEXT_ENCODER_CID);
 NS_DEFINE_NAMED_CID(NS_HTMLCOPY_TEXT_ENCODER_CID);
 NS_DEFINE_NAMED_CID(NS_XMLCONTENTSERIALIZER_CID);
 NS_DEFINE_NAMED_CID(NS_XHTMLCONTENTSERIALIZER_CID);
 NS_DEFINE_NAMED_CID(NS_HTMLCONTENTSERIALIZER_CID);
 NS_DEFINE_NAMED_CID(NS_PLAINTEXTSERIALIZER_CID);
@@ -780,17 +778,16 @@ NS_DEFINE_NAMED_CID(NS_DATADOCUMENTCONTE
 NS_DEFINE_NAMED_CID(NS_NODATAPROTOCOLCONTENTPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_XULCONTROLLERS_CID);
 #ifdef MOZ_XUL
 NS_DEFINE_NAMED_CID(NS_XULSORTSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_XULTEMPLATEBUILDER_CID);
 NS_DEFINE_NAMED_CID(NS_XULTREEBUILDER_CID);
 NS_DEFINE_NAMED_CID(NS_XULPOPUPMANAGER_CID);
 NS_DEFINE_NAMED_CID(NS_XULDOCUMENT_CID);
-NS_DEFINE_NAMED_CID(NS_XULPROTOTYPECACHE_CID);
 #endif
 #ifdef MOZ_XTF
 NS_DEFINE_NAMED_CID(NS_XTFSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_XMLCONTENTBUILDER_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_CONTENT_DOCUMENT_LOADER_FACTORY_CID);
 NS_DEFINE_NAMED_CID(NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 NS_DEFINE_NAMED_CID(NS_BASE_DOM_EXCEPTION_CID);
@@ -915,17 +912,16 @@ static const mozilla::Module::CIDEntry k
   { &kNS_NODATAPROTOCOLCONTENTPOLICY_CID, false, NULL, nsNoDataProtocolContentPolicyConstructor },
   { &kNS_XULCONTROLLERS_CID, false, NULL, NS_NewXULControllers },
 #ifdef MOZ_XUL
   { &kNS_XULSORTSERVICE_CID, false, NULL, CreateXULSortService },
   { &kNS_XULTEMPLATEBUILDER_CID, false, NULL, NS_NewXULContentBuilder },
   { &kNS_XULTREEBUILDER_CID, false, NULL, NS_NewXULTreeBuilder },
   { &kNS_XULPOPUPMANAGER_CID, false, NULL, CreateXULPopupManager },
   { &kNS_XULDOCUMENT_CID, false, NULL, CreateXULDocument },
-  { &kNS_XULPROTOTYPECACHE_CID, false, NULL, NS_NewXULPrototypeCache },
 #endif
 #ifdef MOZ_XTF
   { &kNS_XTFSERVICE_CID, false, NULL, CreateXTFService },
   { &kNS_XMLCONTENTBUILDER_CID, false, NULL, CreateXMLContentBuilder },
 #endif
   { &kNS_CONTENT_DOCUMENT_LOADER_FACTORY_CID, false, NULL, CreateContentDLF },
   { &kNS_DOM_SCRIPT_OBJECT_FACTORY_CID, false, NULL, nsDOMScriptObjectFactoryConstructor },
   { &kNS_BASE_DOM_EXCEPTION_CID, false, NULL, nsBaseDOMExceptionConstructor },
@@ -1051,17 +1047,16 @@ static const mozilla::Module::ContractID
   { NS_NODATAPROTOCOLCONTENTPOLICY_CONTRACTID, &kNS_NODATAPROTOCOLCONTENTPOLICY_CID },
   { "@mozilla.org/xul/xul-controllers;1", &kNS_XULCONTROLLERS_CID },
 #ifdef MOZ_XUL
   { "@mozilla.org/xul/xul-sort-service;1", &kNS_XULSORTSERVICE_CID },
   { "@mozilla.org/xul/xul-template-builder;1", &kNS_XULTEMPLATEBUILDER_CID },
   { "@mozilla.org/xul/xul-tree-builder;1", &kNS_XULTREEBUILDER_CID },
   { "@mozilla.org/xul/xul-popup-manager;1", &kNS_XULPOPUPMANAGER_CID },
   { "@mozilla.org/xul/xul-document;1", &kNS_XULDOCUMENT_CID },
-  { "@mozilla.org/xul/xul-prototype-cache;1", &kNS_XULPROTOTYPECACHE_CID },
 #endif
 #ifdef MOZ_XTF
   { NS_XTFSERVICE_CONTRACTID, &kNS_XTFSERVICE_CID },
   { NS_XMLCONTENTBUILDER_CONTRACTID, &kNS_XMLCONTENTBUILDER_CID },
 #endif
   { CONTENT_DLF_CONTRACTID, &kNS_CONTENT_DOCUMENT_LOADER_FACTORY_CID },
   { NS_JSPROTOCOLHANDLER_CONTRACTID, &kNS_JSPROTOCOLHANDLER_CID },
   { NS_WINDOWCONTROLLER_CONTRACTID, &kNS_WINDOWCONTROLLER_CID },
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -249,16 +249,26 @@ nsFrame::RootFrameList(nsPresContext* aP
     nsIFrame* frame = shell->FrameManager()->GetRootFrame();
     if(frame) {
       frame->List(out, aIndent);
     }
   }
 }
 #endif
 
+static PRBool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
+                                    const nsIFrame* aFrame,
+                                    const nsStyleDisplay* aDisp, 
+                                    nsRect* aRect);
+
+static PRBool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
+                                  const nsStyleDisplay* aDisp, 
+                                  const nsIFrame* aFrame,
+                                  nsRect* aRect);
+
 void
 NS_MergeReflowStatusInto(nsReflowStatus* aPrimary, nsReflowStatus aSecondary)
 {
   *aPrimary |= aSecondary &
     (NS_FRAME_NOT_COMPLETE | NS_FRAME_OVERFLOW_INCOMPLETE |
      NS_FRAME_TRUNCATED | NS_FRAME_REFLOW_NEXTINFLOW);
   if (*aPrimary & NS_FRAME_NOT_COMPLETE) {
     *aPrimary &= ~NS_FRAME_OVERFLOW_INCOMPLETE;
@@ -757,16 +767,35 @@ nsIFrame::GetPaddingRect() const
 
 PRBool
 nsIFrame::IsTransformed() const
 {
   return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
     GetStyleDisplay()->HasTransform();
 }
 
+PRBool
+nsIFrame::Preserves3DChildren() const
+{
+  return GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D && IsTransformed();
+}
+
+PRBool
+nsIFrame::Preserves3D() const
+{
+  if (!GetParent() || !GetParent()->Preserves3DChildren() || !IsTransformed()) {
+    return PR_FALSE;
+  }
+
+  nsRect temp;
+  return (!ApplyOverflowClipping(nsnull, this, GetStyleDisplay(), &temp) &&
+          !ApplyAbsPosClipping(nsnull, GetStyleDisplay(), this, &temp) &&
+          !nsSVGIntegrationUtils::UsingEffectsForFrame(this));
+}
+
 nsRect
 nsIFrame::GetContentRectRelativeToSelf() const
 {
   nsMargin bp(GetUsedBorderAndPadding());
   ApplySkipSides(bp);
   nsRect r(0, 0, mRect.width, mRect.height);
   r.Deflate(bp);
   return r;
@@ -1200,17 +1229,17 @@ nsFrame::DisplayBorderBackgroundOutline(
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return DisplayOutlineUnconditional(aBuilder, aLists);
 }
 
 PRBool
 nsIFrame::GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
-                            const nsSize& aSize)
+                            const nsSize& aSize) const
 {
   NS_PRECONDITION(aRect, "Must have aRect out parameter");
 
   if (!aDisp->IsAbsolutelyPositioned() ||
       !(aDisp->mClipFlags & NS_STYLE_CLIP_RECT))
     return PR_FALSE;
 
   *aRect = aDisp->mClip;
@@ -1219,30 +1248,32 @@ nsIFrame::GetAbsPosClipRect(const nsStyl
   }
   if (NS_STYLE_CLIP_BOTTOM_AUTO & aDisp->mClipFlags) {
     aRect->height = aSize.height - aRect->y;
   }
   return PR_TRUE;
 }
 
 static PRBool ApplyAbsPosClipping(nsDisplayListBuilder* aBuilder,
-                                  const nsStyleDisplay* aDisp, nsIFrame* aFrame,
+                                  const nsStyleDisplay* aDisp, const nsIFrame* aFrame,
                                   nsRect* aRect) {
   if (!aFrame->GetAbsPosClipRect(aDisp, aRect, aFrame->GetSize()))
     return PR_FALSE;
 
-  *aRect += aBuilder->ToReferenceFrame(aFrame);
+  if (aBuilder) {
+    *aRect += aBuilder->ToReferenceFrame(aFrame);
+  }
   return PR_TRUE;
 }
 
 /**
  * Returns PR_TRUE if aFrame is overflow:hidden and we should interpret
  * that as -moz-hidden-unscrollable.
  */
-static inline PRBool ApplyOverflowHiddenClipping(nsIFrame* aFrame,
+static inline PRBool ApplyOverflowHiddenClipping(const nsIFrame* aFrame,
                                                  const nsStyleDisplay* aDisp)
 {
   if (aDisp->mOverflowX != NS_STYLE_OVERFLOW_HIDDEN)
     return PR_FALSE;
     
   nsIAtom* type = aFrame->GetType();
   // REVIEW: these are the frame types that call IsTableClip and set up
   // clipping. Actually there were also table rows and the inner table frame
@@ -1251,17 +1282,17 @@ static inline PRBool ApplyOverflowHidden
   // but we should actually clip at tableFrame (as per discussion with Hixie and
   // bz).
   return type == nsGkAtoms::tableFrame ||
        type == nsGkAtoms::tableCellFrame ||
        type == nsGkAtoms::bcTableCellFrame;
 }
 
 static PRBool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
-                                    nsIFrame* aFrame,
+                                    const nsIFrame* aFrame,
                                     const nsStyleDisplay* aDisp, nsRect* aRect) {
   // REVIEW: from nsContainerFrame.cpp SyncFrameViewGeometryDependentProperties,
   // except that that function used the border-edge for
   // -moz-hidden-unscrollable which I don't think is correct... Also I've
   // changed -moz-hidden-unscrollable to apply to any kind of frame.
 
   // Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
   // frames, and any non-visible value for blocks in a paginated context).
@@ -1271,18 +1302,20 @@ static PRBool ApplyOverflowClipping(nsDi
     PRBool clip = aDisp->mOverflowX == NS_STYLE_OVERFLOW_CLIP;
     if (!clip)
       return PR_FALSE;
     // We allow -moz-hidden-unscrollable to apply to any kind of frame. This
     // is required by comboboxes which make their display text (an inline frame)
     // have clipping.
   }
   
-  *aRect = aFrame->GetPaddingRect() - aFrame->GetPosition() +
-    aBuilder->ToReferenceFrame(aFrame);
+  *aRect = aFrame->GetPaddingRect() - aFrame->GetPosition();
+  if (aBuilder) {
+    *aRect += aBuilder->ToReferenceFrame(aFrame);
+  }
   return PR_TRUE;
 }
 
 class nsOverflowClipWrapper : public nsDisplayWrapper
 {
 public:
   /**
    * Create a wrapper to apply overflow clipping for aContainer.
@@ -1422,16 +1455,59 @@ DisplayDebugBorders(nsDisplayListBuilder
       aFrame->PresContext()->PresShell()->GetDrawEventTargetFrame() == aFrame) {
     aLists.Outlines()->AppendNewToTop(new (aBuilder)
         nsDisplayGeneric(aBuilder, aFrame, PaintEventTargetBorder, "EventTargetBorder",
                          nsDisplayItem::TYPE_EVENT_TARGET_BORDER));
   }
 }
 #endif
 
+static nsresult
+WrapPreserve3DList(nsIFrame *aFrame, nsDisplayListBuilder *aBuilder, nsDisplayList *aList)
+{
+  nsresult rv = NS_OK;
+  nsDisplayList newList;
+  while (nsDisplayItem *item = aList->RemoveBottom()) {
+    if (item->GetUnderlyingFrame() && item->GetUnderlyingFrame()->GetParent()->Preserves3DChildren()) {
+      switch (item->GetType()) {
+        case nsDisplayItem::TYPE_TRANSFORM: {
+          // The child transform frame should always preserve 3d. In the cases where preserve-3d is disabled
+          // such as clipping, this would be wrapped in a clip display object, and we wouldn't reach this point.
+          NS_ASSERTION(item->GetUnderlyingFrame()->Preserves3D(), "Child transform frame must preserve 3d!");
+          break;
+        }
+        case nsDisplayItem::TYPE_WRAP_LIST: {
+          nsDisplayWrapList *list = static_cast<nsDisplayWrapList*>(item);
+          rv = WrapPreserve3DList(aFrame, aBuilder, list->GetList());
+          break;
+        }
+        case nsDisplayItem::TYPE_OPACITY: {
+          nsDisplayOpacity *opacity = static_cast<nsDisplayOpacity*>(item);
+          rv = WrapPreserve3DList(aFrame, aBuilder, opacity->GetList());
+          break;
+        }
+        default: {
+          item = new (aBuilder) nsDisplayTransform(aBuilder, item->GetUnderlyingFrame(), item);
+          break;
+        }
+      } 
+    } else {
+      item = new (aBuilder) nsDisplayTransform(aBuilder, item->GetUnderlyingFrame(), item);
+    }
+ 
+    if (NS_FAILED(rv) || !item)
+      return rv;
+
+    newList.AppendToTop(item);
+  }
+
+  aList->AppendToTop(&newList);
+  return NS_OK;
+}
+
 nsresult
 nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
                                              const nsRect&         aDirtyRect,
                                              nsDisplayList*        aList) {
   if (GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE)
     return NS_OK;
 
   // Replaced elements have their visibility handled here, because
@@ -1452,17 +1528,17 @@ nsIFrame::BuildDisplayListForStackingCon
 
   PRBool inTransform = aBuilder->IsInTransform();
   /* If we're being transformed, we need to invert the matrix transform so that we don't 
    * grab points in the wrong coordinate system!
    */
   if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
       disp->HasTransform()) {
     /* If we have a complex transform, just grab the entire overflow rect instead. */
-    if (!nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
+    if (Preserves3DChildren() || !nsDisplayTransform::UntransformRect(dirtyRect, this, nsPoint(0, 0), &dirtyRect)) {
       dirtyRect = GetVisualOverflowRectRelativeToSelf();
     }
     inTransform = PR_TRUE;
   }
 
   if (applyAbsPosClipping) {
     dirtyRect.IntersectRect(dirtyRect,
                             absPosClip - aBuilder->ToReferenceFrame(this));
@@ -1573,25 +1649,46 @@ nsIFrame::BuildDisplayListForStackingCon
    */
   if (disp->mOpacity < 1.0f && !resultList.IsEmpty()) {
     rv = resultList.AppendNewToTop(
         new (aBuilder) nsDisplayOpacity(aBuilder, this, &resultList));
     if (NS_FAILED(rv))
       return rv;
   }
 
-  /* If we're going to apply a transformation, wrap everything in an
-   * nsDisplayTransform. If there's nothing in the list, don't add anything.
+  /* If we're going to apply a transformation and don't have preserve-3d set, wrap 
+   * everything in an nsDisplayTransform. If there's nothing in the list, don't add 
+   * anything.
+   *
+   * For the preserve-3d case we want to individually wrap every child in the list with
+   * a separate nsDisplayTransform instead. When the child is already an nsDisplayTransform,
+   * we can skip this step, as the computed transform will already include our own.
+   *
+   * We also traverse into sublists created by nsDisplayWrapList or nsDisplayOpacity, so that
+   * we find all the correct children.
    */
   if ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
       disp->HasTransform() && !resultList.IsEmpty()) {
-    rv = resultList.AppendNewToTop(
+    if (Preserves3DChildren()) {
+      rv = WrapPreserve3DList(this, aBuilder, &resultList);
+      if (NS_FAILED(rv))
+        return rv;
+
+      if (resultList.Count() > 1) {
+        rv = resultList.AppendNewToTop(
+          new (aBuilder) nsDisplayWrapList(aBuilder, this, &resultList));
+        if (NS_FAILED(rv))
+          return rv;
+      }
+    } else {
+      rv = resultList.AppendNewToTop(
         new (aBuilder) nsDisplayTransform(aBuilder, this, &resultList));
-    if (NS_FAILED(rv))
-      return rv;
+      if (NS_FAILED(rv))
+        return rv;
+    }
   }
 
   aList->AppendToTop(&resultList);
   return rv;
 }
 
 nsresult
 nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder*   aBuilder,
@@ -4151,18 +4248,35 @@ nsIFrame::InvalidateInternalAfterResize(
    * There's one more problem, though, and that's that we don't know what
    * coordinate space this rectangle is in.  Sometimes it's in the local
    * coordinate space for the frame, and sometimes its in the transformed
    * coordinate space.  If we get it wrong, we'll display incorrectly.  Until I
    * find a better fix for this problem, we'll invalidate the union of the two
    * rectangles (original rectangle and transformed rectangle).  At least one of
    * these will be correct.
    *
+   * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d
+   * children. The computed transform on these children is relative to the root
+   * transform object in the hierarchy, not necessarily their direct ancestor.
+   * In this case we transform by the child's transform, and mark the rectangle
+   * as being transformed until it is passed up to the root of the hierarchy.
+   *
    * See bug #452496 for more details.
    */
+
+  // Check the transformed flags and remove it
+  PRBool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED);
+  if (!Preserves3D()) {
+    // We only want to remove the flag if we aren't preserving 3d. Otherwise
+    // the rect will already have been transformed into the root preserve-3d
+    // frame coordinate space, and we should continue passing it up without
+    // further transforms.
+    aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED;
+  }
+
   if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) &&
       !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) {
     // XXX for now I'm going to assume this is in the local coordinate space
     // This only matters for frames with transforms and retained layers,
     // which can't happen right now since transforms trigger fallback
     // rendering and the display items that trigger layers are nested inside
     // the nsDisplayTransform
     // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of
@@ -4170,20 +4284,28 @@ nsIFrame::InvalidateInternalAfterResize(
     FrameLayerBuilder::InvalidateThebesLayerContents(this,
         aDamageRect + nsPoint(aX, aY));
     // Don't need to invalidate any more Thebes layers
     aFlags |= INVALIDATE_NO_THEBES_LAYERS;
     if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) {
       return;
     }
   }
-  if (IsTransformed()) {
+  if (IsTransformed() && !rectIsTransformed) {
     nsRect newDamageRect;
     newDamageRect.UnionRect(nsDisplayTransform::TransformRectOut
                             (aDamageRect, this, nsPoint(-aX, -aY)), aDamageRect);
+
+    // If we are preserving 3d, then our computed transform includes that of any
+    // ancestor frames that also preserve 3d. Mark the rectangle as already being
+    // transformed into the parent's coordinate space.
+    if (Preserves3D()) {
+      aFlags |= INVALIDATE_ALREADY_TRANSFORMED;
+    }
+
     GetParent()->
       InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this,
                          aFlags);
   }
   else 
     GetParent()->
       InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags);
 }
@@ -4207,44 +4329,41 @@ nsIFrame::InvalidateInternal(const nsRec
   InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags);
 }
 
 gfx3DMatrix
 nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
 {
   NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
 
-  /* If we're transformed, the matrix will be relative to our
-   * cross-doc parent frame.
-   */
-  *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
-
   /* If we're transformed, we want to hand back the combination
    * transform/translate matrix that will apply our current transform, then
    * shift us to our parent.
    */
   if (IsTransformed()) {
     /* Compute the delta to the parent, which we need because we are converting
      * coordinates to our parent.
      */
-    NS_ASSERTION(*aOutAncestor, "Cannot transform the viewport frame!");
-    nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
+    NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this), "Cannot transform the viewport frame!");
     PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
 
     gfx3DMatrix result =
       nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
-                                                      scaleFactor);
+                                                      scaleFactor, nsnull, aOutAncestor);
+    nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
     /* Combine the raw transform with a translation to our parent. */
     result *= gfx3DMatrix::Translation
       (NSAppUnitsToFloatPixels(delta.x, scaleFactor),
        NSAppUnitsToFloatPixels(delta.y, scaleFactor),
        0.0f);
     return result;
   }
   
+  *aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
+  
   /* Otherwise, we're not transformed.  In that case, we'll walk up the frame
    * tree until we either hit the root frame or something that may be
    * transformed.  We'll then change coordinates into that frame, since we're
    * guaranteed that nothing in-between can be transformed.  First, however,
    * we have to check to see if we have a parent.  If not, we'll set the
    * outparam to null (indicating that there's nothing left) and will hand back
    * the identity matrix.
    */
@@ -6261,19 +6380,23 @@ nsIFrame::FinishAndStoreOverflow(nsOverf
     Properties().Set(nsIFrame::PreTransformBBoxProperty(),
                      new nsRect(aOverflowAreas.VisualOverflow()));
     /* Since our size might not actually have been computed yet, we need to make sure that we use the
      * correct dimensions by overriding the stored bounding rectangle with the value the caller has
      * ensured us we'll use.
      */
     nsRect newBounds(nsPoint(0, 0), aNewSize);
     // Transform affects both overflow areas.
-    NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
-      nsRect& o = aOverflowAreas.Overflow(otype);
-      o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
+    if (!Preserves3DChildren()) {
+      NS_FOR_FRAME_OVERFLOW_TYPES(otype) {
+        nsRect& o = aOverflowAreas.Overflow(otype);
+       o = nsDisplayTransform::TransformRect(o, this, nsPoint(0, 0), &newBounds);
+      }
+    } else {
+      ComputePreserve3DChildrenOverflow(aOverflowAreas, newBounds);
     }
   }
 
   PRBool visualOverflowChanged =
     !GetVisualOverflowRect().IsEqualInterior(aOverflowAreas.VisualOverflow());
 
   if (aOverflowAreas != nsOverflowAreas(bounds, bounds)) {
     SetOverflowAreas(aOverflowAreas);
@@ -6321,16 +6444,47 @@ nsIFrame::FinishAndStoreOverflow(nsOverf
       // that we didn't reach here.
       InvalidateLayer(aOverflowAreas.VisualOverflow(),
                       nsDisplayItem::TYPE_TRANSFORM);
     }
   }
 }
 
 void
+nsIFrame::ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds)
+{
+  // When we are preserving 3d we need to iterate over all children separately.
+  // If the child also preserves 3d then their overflow will already been in our
+  // coordinate space, otherwise we need to transform.
+  nsRect childVisual;
+  nsRect childScrollable;
+  nsIFrame::ChildListIterator lists(this);
+  for (; !lists.IsDone(); lists.Next()) {
+    nsFrameList::Enumerator childFrames(lists.CurrentList());
+    for (; !childFrames.AtEnd(); childFrames.Next()) {
+      nsIFrame* child = childFrames.get();
+      if (child->Preserves3D()) {
+        childVisual = childVisual.Union(child->GetVisualOverflowRect());
+        childScrollable = childScrollable.Union(child->GetScrollableOverflowRect());
+      } else {
+        childVisual = 
+          childVisual.Union(nsDisplayTransform::TransformRect(child->GetVisualOverflowRect(), 
+                            this, nsPoint(0,0), &aBounds));
+        childScrollable = 
+          childScrollable.Union(nsDisplayTransform::TransformRect(child->GetScrollableOverflowRect(), 
+                                this, nsPoint(0,0), &aBounds));
+      }
+    }
+  }
+
+  aOverflowAreas.Overflow(eVisualOverflow) = childVisual;
+  aOverflowAreas.Overflow(eScrollableOverflow) = childScrollable;
+}
+
+void
 nsFrame::ConsiderChildOverflow(nsOverflowAreas& aOverflowAreas,
                                nsIFrame* aChildFrame)
 {
   const nsStyleDisplay* disp = GetStyleDisplay();
   // check here also for hidden as table frames (table, tr and td) currently 
   // don't wrap their content into a scrollable frame if overflow is specified
   // FIXME: Why do we check this here rather than in
   // FinishAndStoreOverflow (where we check NS_STYLE_OVERFLOW_CLIP)?
--- a/layout/generic/nsFrame.h
+++ b/layout/generic/nsFrame.h
@@ -572,17 +572,17 @@ public:
   // frame.
   // If aScrollLock is true, don't break outside scrollframes when looking for a
   // containing block frame.
   static PRInt32 GetLineNumber(nsIFrame *aFrame,
                                PRBool aLockScroll,
                                nsIFrame** aContainingBlock = nsnull);
 
   // test whether aFrame should apply paginated overflow clipping.
-  static PRBool ApplyPaginatedOverflowClipping(nsIFrame* aFrame)
+  static PRBool ApplyPaginatedOverflowClipping(const nsIFrame* aFrame)
   {
     // If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
     // set, then we want to clip our overflow.
     return
       aFrame->PresContext()->IsPaginated() &&
       aFrame->GetType() == nsGkAtoms::blockFrame &&
       (aFrame->GetStateBits() & NS_BLOCK_CLIP_PAGINATED_OVERFLOW) != 0;
   }
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1200,16 +1200,31 @@ public:
 
   /**
    * Returns whether this frame has a transform matrix applied to it.  This is true
    * if we have the -moz-transform property or if we're an SVGForeignObjectFrame.
    */
   virtual PRBool IsTransformed() const;
 
   /**
+   * Returns whether this frame will attempt to preserve the 3d transforms of its
+   * children. This is a direct indicator of -moz-transform-style: preserve-3d.
+   */
+  PRBool Preserves3DChildren() const;
+
+  /**
+   * Returns whether this frame has a parent that Preserves3DChildren() and
+   * can respect this. Returns false if the frame is clipped.
+   */
+  PRBool Preserves3D() const;
+
+  // Calculate the overflow size of all child frames, taking preserve-3d into account
+  void ComputePreserve3DChildrenOverflow(nsOverflowAreas& aOverflowAreas, const nsRect& aBounds);
+
+  /**
    * Event handling of GUI events.
    *
    * @param   aEvent event structure describing the type of event and rge widget
    *            where the event originated
    *          The |point| member of this is in the coordinate system of the
    *          view returned by GetOffsetFromView.
    * @param   aEventStatus a return value indicating whether the event was handled
    *            and whether default processing should be done
@@ -2111,17 +2126,18 @@ public:
     INVALIDATE_CROSS_DOC = 0x02,
     INVALIDATE_REASON_SCROLL_BLIT = 0x04,
     INVALIDATE_REASON_SCROLL_REPAINT = 0x08,
     INVALIDATE_REASON_MASK = INVALIDATE_REASON_SCROLL_BLIT |
                              INVALIDATE_REASON_SCROLL_REPAINT,
     INVALIDATE_NO_THEBES_LAYERS = 0x10,
     INVALIDATE_ONLY_THEBES_LAYERS = 0x20,
     INVALIDATE_EXCLUDE_CURRENT_PAINT = 0x40,
-    INVALIDATE_NO_UPDATE_LAYER_TREE = 0x80
+    INVALIDATE_NO_UPDATE_LAYER_TREE = 0x80,
+    INVALIDATE_ALREADY_TRANSFORMED = 0x100
   };
   virtual void InvalidateInternal(const nsRect& aDamageRect,
                                   nscoord aOffsetX, nscoord aOffsetY,
                                   nsIFrame* aForChild, PRUint32 aFlags);
 
   /**
    * Helper function that funnels an InvalidateInternal request up to the
    * parent.  This function is used so that if MOZ_SVG is not defined, we still
@@ -2498,17 +2514,17 @@ NS_PTR_TO_INT32(frame->Properties().Get(
 
   /**
    * Returns PR_TRUE if the frame is absolutely positioned and has a clip
    * rect set via the 'clip' property. If true, then we also set aRect
    * to the computed clip rect coordinates relative to this frame's origin.
    * aRect must not be null!
    */
   PRBool GetAbsPosClipRect(const nsStyleDisplay* aDisp, nsRect* aRect,
-                           const nsSize& aSize);
+                           const nsSize& aSize) const;
 
   /**
    * Check if this frame is focusable and in the current tab order.
    * Tabbable is indicated by a nonnegative tabindex & is a subset of focusable.
    * For example, only the selected radio button in a group is in the 
    * tab order, unless the radio group has no selection in which case
    * all of the visible, non-disabled radio buttons in the group are 
    * in the tab order. On the other hand, all of the visible, non-disabled 
--- a/layout/generic/test/test_bug632379.xul
+++ b/layout/generic/test/test_bug632379.xul
@@ -71,17 +71,17 @@ https://bugzilla.mozilla.org/show_bug.cg
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
           </menupopup>
         </menu>
         <menu label="menu5" accesskey="5" id="menu5">
-	  <menupopup onpopupshown="snapshot(this)">
+          <menupopup onpopupshown="snapshot(this)">
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
             <menuitem label="item"/>
@@ -171,33 +171,34 @@ https://bugzilla.mozilla.org/show_bug.cg
 var pos = new Array(2);
 var count=0;
 
 function snapshot(elem)
 {
     pos[count] = elem.getBoundingClientRect().top;
     ++count;
     if (count <= 1) {
-	// close the submenu and open the bottom submenu
-	synthesizeKey("VK_LEFT", {});
-	synthesizeKey("9", {});
+        ok(true, "trying to open the second submenu");
+        // close the submenu and open the bottom submenu
+        synthesizeKey("VK_LEFT", {});
+        synthesizeKey("9", {});
     } else {
-	is(pos[1], pos[0], "Popup should open in the same place when the menu is scrolled");
-
-	SimpleTest.finish();
+        is(pos[1], pos[0], "Popup should open in the same place when the menu is scrolled");
+        SimpleTest.finish();
     }
 }
 
 function doTest() {
     // open the top-level menu
     $("mainMenu").open = true;
 }
 
 function openSubmenu()
 {
+    ok(true, "openSubMenu() called");
     // open a submenu in the middle
     synthesizeKey("5", {});
 }
 
 SimpleTest.waitForExplicitFinish();
 addLoadEvent(doTest);
 
 ]]></script>
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -90,17 +90,17 @@ struct ViewTransform {
     : mTranslation(aTranslation)
     , mXScale(aXScale)
     , mYScale(aYScale)
   {}
 
   operator gfx3DMatrix() const
   {
     return
-      gfx3DMatrix::Scale(mXScale, mYScale, 1) *
+      gfx3DMatrix::ScalingMatrix(mXScale, mYScale, 1) *
       gfx3DMatrix::Translation(mTranslation.x, mTranslation.y, 0);
   }
 
   nsIntPoint mTranslation;
   float mXScale;
   float mYScale;
 };
 
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -268,16 +268,17 @@ CSS_KEY(ex, ex)
 CSS_KEY(expanded, expanded)
 CSS_KEY(extra-condensed, extra_condensed)
 CSS_KEY(extra-expanded, extra_expanded)
 CSS_KEY(ew-resize, ew_resize)
 CSS_KEY(farthest-side, farthest_side)
 CSS_KEY(farthest-corner, farthest_corner)
 CSS_KEY(fill, fill)
 CSS_KEY(fixed, fixed)
+CSS_KEY(flat, flat)
 CSS_KEY(forwards, forwards)
 CSS_KEY(georgian, georgian)
 CSS_KEY(grad, grad)
 CSS_KEY(graytext, graytext)
 CSS_KEY(groove, groove)
 CSS_KEY(hebrew, hebrew)
 CSS_KEY(help, help)
 CSS_KEY(hidden, hidden)
@@ -369,16 +370,17 @@ CSS_KEY(paused, paused)
 CSS_KEY(pc, pc)
 CSS_KEY(perspective, perspective)
 CSS_KEY(physical, physical)
 CSS_KEY(pointer, pointer)
 CSS_KEY(portrait, portrait)
 CSS_KEY(pre, pre)
 CSS_KEY(pre-wrap, pre_wrap)
 CSS_KEY(pre-line, pre_line)
+CSS_KEY(preserve-3d, preserve_3d)
 CSS_KEY(progress, progress)
 CSS_KEY(progressive, progressive)
 CSS_KEY(pt, pt)
 CSS_KEY(px, px)
 CSS_KEY(rad, rad)
 CSS_KEY(read-only, read_only)
 CSS_KEY(read-write, read_write)
 CSS_KEY(relative, relative)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2279,16 +2279,25 @@ CSS_PROP_DISPLAY(
     perspective,
     CSS_PROP_DOMPROP_PREFIXED(Perspective),
     CSS_PROPERTY_PARSE_VALUE,
     VARIANT_NONE | VARIANT_INHERIT | VARIANT_LENGTH,
     nsnull,
     offsetof(nsStyleDisplay, mChildPerspective),
     eStyleAnimType_Coord)
 CSS_PROP_DISPLAY(
+    -moz-transform-style,
+    transform_style,
+    CSS_PROP_DOMPROP_PREFIXED(TransformStyle),
+    CSS_PROPERTY_PARSE_VALUE,
+    VARIANT_HK,
+    kTransformStyleKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_DISPLAY(
     -moz-backface-visibility,
     backface_visibility,
     CSS_PROP_DOMPROP_PREFIXED(BackfaceVisibility),
     CSS_PROPERTY_PARSE_VALUE,
     VARIANT_HK,
     kBackfaceVisibilityKTable,
     offsetof(nsStyleDisplay, mBackfaceVisibility),
     eStyleAnimType_None)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -581,16 +581,21 @@ const PRInt32 nsCSSProps::kAppearanceKTa
   eCSSKeyword_UNKNOWN,-1
 };
 
 const PRInt32 nsCSSProps::kBackfaceVisibilityKTable[] = {
   eCSSKeyword_visible, NS_STYLE_BACKFACE_VISIBILITY_VISIBLE,
   eCSSKeyword_hidden, NS_STYLE_BACKFACE_VISIBILITY_HIDDEN
 };
 
+const PRInt32 nsCSSProps::kTransformStyleKTable[] = {
+  eCSSKeyword_flat, NS_STYLE_TRANSFORM_STYLE_FLAT,
+  eCSSKeyword_preserve_3d, NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D
+};
+
 const PRInt32 nsCSSProps::kBackgroundAttachmentKTable[] = {
   eCSSKeyword_fixed, NS_STYLE_BG_ATTACHMENT_FIXED,
   eCSSKeyword_scroll, NS_STYLE_BG_ATTACHMENT_SCROLL,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const PRInt32 nsCSSProps::kBackgroundInlinePolicyKTable[] = {
   eCSSKeyword_each_box,     NS_STYLE_BG_INLINE_POLICY_EACH_BOX,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -329,16 +329,17 @@ public:
   static const PRInt32 kAnimationDirectionKTable[];
   static const PRInt32 kAnimationFillModeKTable[];
   static const PRInt32 kAnimationIterationCountKTable[];
   static const PRInt32 kAnimationPlayStateKTable[];
   static const PRInt32 kAnimationTimingFunctionKTable[];
   static const PRInt32 kAppearanceKTable[];
   static const PRInt32 kAzimuthKTable[];
   static const PRInt32 kBackfaceVisibilityKTable[];
+  static const PRInt32 kTransformStyleKTable[];
   static const PRInt32 kBackgroundAttachmentKTable[];
   static const PRInt32 kBackgroundInlinePolicyKTable[];
   static const PRInt32 kBackgroundOriginKTable[];
   static const PRInt32 kBackgroundPositionKTable[];
   static const PRInt32 kBackgroundRepeatKTable[];
   static const PRInt32 kBackgroundSizeKTable[];
   static const PRInt32 kBorderCollapseKTable[];
   static const PRInt32 kBorderColorKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -996,16 +996,26 @@ nsComputedDOMStyle::DoGetMozBackfaceVisi
 {
     nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue();
     val->SetIdent(
         nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mBackfaceVisibility,
                                        nsCSSProps::kBackfaceVisibilityKTable));
     return val;
 }
 
+nsIDOMCSSValue*
+nsComputedDOMStyle::DoGetMozTransformStyle()
+{
+    nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+    val->SetIdent(
+        nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mTransformStyle,
+                                       nsCSSProps::kTransformStyleKTable));
+    return val;
+}
+
 /* If the property is "none", hand back "none" wrapped in a value.
  * Otherwise, compute the aggregate transform matrix and hands it back in a
  * "matrix" wrapper.
  */
 nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetMozTransform()
 {
   /* First, get the display data.  We'll need it. */
@@ -4479,16 +4489,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(stack_sizing,                  StackSizing),
     COMPUTED_STYLE_MAP_ENTRY(_moz_tab_size,                 MozTabSize),
     COMPUTED_STYLE_MAP_ENTRY(text_blink,                    MozTextBlink),
     COMPUTED_STYLE_MAP_ENTRY(text_decoration_color,         MozTextDecorationColor),
     COMPUTED_STYLE_MAP_ENTRY(text_decoration_line,          MozTextDecorationLine),
     COMPUTED_STYLE_MAP_ENTRY(text_decoration_style,         MozTextDecorationStyle),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_transform,         MozTransform),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_transform_origin,  MozTransformOrigin),
+    COMPUTED_STYLE_MAP_ENTRY(transform_style,               MozTransformStyle),
     COMPUTED_STYLE_MAP_ENTRY(transition_delay,              TransitionDelay),
     COMPUTED_STYLE_MAP_ENTRY(transition_duration,           TransitionDuration),
     COMPUTED_STYLE_MAP_ENTRY(transition_property,           TransitionProperty),
     COMPUTED_STYLE_MAP_ENTRY(transition_timing_function,    TransitionTimingFunction),
     COMPUTED_STYLE_MAP_ENTRY(user_focus,                    UserFocus),
     COMPUTED_STYLE_MAP_ENTRY(user_input,                    UserInput),
     COMPUTED_STYLE_MAP_ENTRY(user_modify,                   UserModify),
     COMPUTED_STYLE_MAP_ENTRY(user_select,                   UserSelect),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -345,16 +345,17 @@ private:
   nsIDOMCSSValue* DoGetResize();
   nsIDOMCSSValue* DoGetPageBreakAfter();
   nsIDOMCSSValue* DoGetPageBreakBefore();
   nsIDOMCSSValue* DoGetMozTransform();
   nsIDOMCSSValue* DoGetMozTransformOrigin();
   nsIDOMCSSValue* DoGetMozPerspective();
   nsIDOMCSSValue* DoGetMozBackfaceVisibility();
   nsIDOMCSSValue* DoGetMozPerspectiveOrigin();
+  nsIDOMCSSValue* DoGetMozTransformStyle();
   nsIDOMCSSValue* DoGetOrient();
 
   /* User interface properties */
   nsIDOMCSSValue* DoGetCursor();
   nsIDOMCSSValue* DoGetForceBrokenImageIcon();
   nsIDOMCSSValue* DoGetIMEMode();
   nsIDOMCSSValue* DoGetUserFocus();
   nsIDOMCSSValue* DoGetUserInput();
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -4596,16 +4596,22 @@ nsRuleNode::ComputeDisplayData(void* aSt
            SETCOORD_LAH | SETCOORD_INITIAL_ZERO | SETCOORD_NONE,
            aContext, mPresContext, canStoreInRuleTree);
 
   SetDiscrete(*aRuleData->ValueForBackfaceVisibility(),
               display->mBackfaceVisibility, canStoreInRuleTree,
               SETDSC_ENUMERATED, parentDisplay->mBackfaceVisibility,
               NS_STYLE_BACKFACE_VISIBILITY_VISIBLE, 0, 0, 0, 0);
 
+  // transform-style: enum, inherit, initial
+  SetDiscrete(*aRuleData->ValueForTransformStyle(),
+              display->mTransformStyle, canStoreInRuleTree,
+              SETDSC_ENUMERATED, parentDisplay->mTransformStyle,
+              NS_STYLE_TRANSFORM_STYLE_FLAT, 0, 0, 0, 0);
+
   // orient: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForOrient(),
               display->mOrient, canStoreInRuleTree,
               SETDSC_ENUMERATED, parentDisplay->mOrient,
               NS_STYLE_ORIENT_HORIZONTAL, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(Display, display)
 }
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2093,16 +2093,17 @@ nsStyleDisplay::nsStyleDisplay()
   mSpecifiedTransform = nsnull;
   mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
   mTransformOrigin[1].SetPercentValue(0.5f);
   mTransformOrigin[2].SetCoordValue(0);
   mPerspectiveOrigin[0].SetPercentValue(0.5f);
   mPerspectiveOrigin[1].SetPercentValue(0.5f);
   mChildPerspective.SetCoordValue(0);
   mBackfaceVisibility = NS_STYLE_BACKFACE_VISIBILITY_VISIBLE;
+  mTransformStyle = NS_STYLE_TRANSFORM_STYLE_FLAT;
   mOrient = NS_STYLE_ORIENT_HORIZONTAL;
 
   mTransitions.AppendElement();
   NS_ABORT_IF_FALSE(mTransitions.Length() == 1,
                     "appending within auto buffer should never fail");
   mTransitions[0].SetInitialValues();
   mTransitionTimingFunctionCount = 1;
   mTransitionDurationCount = 1;
@@ -2163,16 +2164,17 @@ nsStyleDisplay::nsStyleDisplay(const nsS
   /* Copy over transform origin. */
   mTransformOrigin[0] = aSource.mTransformOrigin[0];
   mTransformOrigin[1] = aSource.mTransformOrigin[1];
   mTransformOrigin[2] = aSource.mTransformOrigin[2];
   mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
   mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
   mChildPerspective = aSource.mChildPerspective;
   mBackfaceVisibility = aSource.mBackfaceVisibility;
+  mTransformStyle = aSource.mTransformStyle;
 }
 
 nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
 {
   nsChangeHint hint = nsChangeHint(0);
 
   if (!EqualURIs(mBinding, aOther.mBinding)
       || mPosition != aOther.mPosition
@@ -2238,16 +2240,20 @@ nsChangeHint nsStyleDisplay::CalcDiffere
       }
 
     if (mChildPerspective != aOther.mChildPerspective)
       NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
                                          nsChangeHint_RepaintFrame));
 
     if (mBackfaceVisibility != aOther.mBackfaceVisibility)
       NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
+
+    if (mTransformStyle != aOther.mTransformStyle)
+      NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame,
+                                         nsChangeHint_RepaintFrame));
   }
 
   // Note:  Our current behavior for handling changes to the
   // transition-duration, transition-delay, and transition-timing-function
   // properties is to do nothing.  In other words, the transition
   // property that matters is what it is when the transition begins, and
   // we don't stop a transition later because the transition property
   // changed.
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1526,16 +1526,17 @@ struct nsStyleDisplay {
   // specified, or null to indicate there is no transform.  (inherit or
   // initial are replaced by an actual list of transform functions, or
   // null, as appropriate.) (owned by the style rule)
   const nsCSSValueList *mSpecifiedTransform; // [reset]
   nsStyleCoord mTransformOrigin[3]; // [reset] percent, coord, calc, 3rd param is coord, calc only
   nsStyleCoord mChildPerspective; // [reset] coord
   nsStyleCoord mPerspectiveOrigin[2]; // [reset] percent, coord, calc
   PRUint8 mBackfaceVisibility;
+  PRUint8 mTransformStyle;
 
   nsAutoTArray<nsTransition, 1> mTransitions; // [reset]
   // The number of elements in mTransitions that are not from repeating
   // a list due to another property being longer.
   PRUint32 mTransitionTimingFunctionCount,
            mTransitionDurationCount,
            mTransitionDelayCount,
            mTransitionPropertyCount;
@@ -1609,17 +1610,17 @@ struct nsStyleDisplay {
   PRBool IsTableClip() const {
     return mOverflowX == NS_STYLE_OVERFLOW_CLIP ||
            (mOverflowX == NS_STYLE_OVERFLOW_HIDDEN &&
             mOverflowY == NS_STYLE_OVERFLOW_HIDDEN);
   }
 
   /* Returns whether the element has the -moz-transform property. */
   PRBool HasTransform() const {
-    return mSpecifiedTransform != nsnull;
+    return mSpecifiedTransform != nsnull || mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D;
   }
 };
 
 struct nsStyleTable {
   nsStyleTable(void);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable(void);
 
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1015,16 +1015,24 @@ var gCSSProperties = {
     "-moz-backface-visibility": {
         domProp: "MozBackfaceVisibility",
         inherited: false,
         type: CSS_TYPE_LONGHAND,
         initial_values: [ "visible" ],
         other_values: [ "hidden" ],
         invalid_values: [ "collapse" ]
     },
+	"-moz-transform-style": {
+		domProp: "MozTransformStyle",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "flat" ],
+		other_values: [ "preserve-3d" ],
+		invalid_values: []
+	},
 	"-moz-user-focus": {
 		domProp: "MozUserFocus",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		initial_values: [ "none" ],
 		other_values: [ "normal", "ignore", "select-all", "select-before", "select-after", "select-same", "select-menu" ],
 		invalid_values: []
 	},
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -380,16 +380,19 @@ pref("geo.enabled", true);
 
 // content sink control -- controls responsiveness during page load
 // see https://bugzilla.mozilla.org/show_bug.cgi?id=481566#c9
 pref("content.sink.enable_perf_mode",  2); // 0 - switch, 1 - interactive, 2 - perf
 pref("content.sink.pending_event_mode", 0);
 pref("content.sink.perf_deflect_count", 1000000);
 pref("content.sink.perf_parse_time", 50000000);
 
+// Disable methodjit in chrome to save memory
+pref("javascript.options.methodjit.chrome",  false);
+
 pref("javascript.options.mem.high_water_mark", 32);
 
 // Disable the JS engine's gc on memory pressure, since we do one in the mobile
 // browser (bug 669346).
 pref("javascript.options.gc_on_memory_pressure", false);
 
 pref("dom.max_chrome_script_run_time", 0); // disable slow script dialog for chrome
 pref("dom.max_script_run_time", 20);
--- a/mobile/chrome/content/ContextCommands.js
+++ b/mobile/chrome/content/ContextCommands.js
@@ -17,17 +17,17 @@ var ContextCommands = {
 #endif
 
   paste: function cc_paste() {
     let target = ContextHelper.popupState.target;
     if (target.localName == "browser") {
       let x = ContextHelper.popupState.x;
       let y = ContextHelper.popupState.y;
       let json = {x: x, y: y, command: "paste" };
-      messageManager.sendAsyncMessage("Browser:ContextCommand", json);
+      target.messageManager.sendAsyncMessage("Browser:ContextCommand", json);
     } else {
       target.editor.paste(Ci.nsIClipboard.kGlobalClipboard);
       target.focus();
     }
   },
 
   pasteAndGo: function cc_pasteAndGo() {
     let target = ContextHelper.popupState.target;
@@ -37,17 +37,17 @@ var ContextCommands = {
   },
 
   selectAll: function cc_selectAll() {
     let target = ContextHelper.popupState.target;
     if (target.localName == "browser") {
       let x = ContextHelper.popupState.x;
       let y = ContextHelper.popupState.y;
       let json = {x: x, y: y, command: "select-all" };
-      messageManager.sendAsyncMessage("Browser:ContextCommand", json);
+      target.messageManager.sendAsyncMessage("Browser:ContextCommand", json);
     } else {
       target.editor.selectAll();
       target.focus();
     }
   },
 
   openInNewTab: function cc_openInNewTab() {
     Browser.addTab(ContextHelper.popupState.linkURL, false, Browser.selectedTab);
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -1014,20 +1014,16 @@ ContextHandler.registerType("callto", fu
 ContextHandler.registerType("link-openable", function(aState, aElement) {
   return Util.isOpenableScheme(aState.linkProtocol);
 });
 
 ContextHandler.registerType("link-shareable", function(aState, aElement) {
   return Util.isShareableScheme(aState.linkProtocol);
 });
 
-ContextHandler.registerType("input-text", function(aState, aElement) {
-    return (aElement instanceof Ci.nsIDOMHTMLInputElement && aElement.mozIsTextField(false)) || aElement instanceof Ci.nsIDOMHTMLTextAreaElement;
-});
-
 ["image", "video"].forEach(function(aType) {
   ContextHandler.registerType(aType+"-shareable", function(aState, aElement) {
     if (aState.types.indexOf(aType) == -1)
       return false;
 
     let protocol = ContextHandler._getProtocol(ContextHandler._getURI(aState.mediaURL));
     return Util.isShareableScheme(protocol);
   });
--- a/mobile/chrome/tests/Makefile.in
+++ b/mobile/chrome/tests/Makefile.in
@@ -80,16 +80,18 @@ include $(topsrcdir)/config/rules.mk
   browser_scroll.html \
   browser_scrollbar.js \
   browser_select.html \
   browser_select.js \
   browser_sessionstore.js \
   browser_tabs.js \
   browser_tapping.js \
   browser_tap_content.html \
+  browser_tapping_edit.js \
+  browser_tap_contentedit.html \
   browser_test.js \
   browser_vkb.js \
   $(warning browser_viewport.js disabled due to failures) \
   browser_viewport.sjs \
   browser_scrollbar.sjs \
   browser_title.sjs \
   browser_thumbnails.js \
   browser_install.xml \
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/tests/browser_tap_contentedit.html
@@ -0,0 +1,14 @@
+<html style="border: 1px solid red">
+<title>Browser Tap Page w/ Editboxes</title>
+<body>
+
+  <div style="margin-bottom:20px">
+    <input id="plain-edit" type="text" value="Some text"/>
+  </div>
+
+  <div style="margin-bottom:20px">
+    <input id="url-edit" type="url" value="http://foo.bar"/>
+  </div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/mobile/chrome/tests/browser_tapping_edit.js
@@ -0,0 +1,246 @@
+/*
+ * Testing the context menus on editboxes:
+ *   plain and url
+ */
+
+let testURL = chromeRoot + "browser_tap_contentedit.html";
+
+let gTests = [];
+let gCurrentTest = null;
+let gCurrentTab;
+
+const kDoubleClickIntervalPlus = kDoubleClickInterval + 100;
+
+let gEvents = [];
+function dumpEvents(aEvent) {
+  if (aEvent.target != gCurrentTab.browser.parentNode)
+    return;
+
+  gEvents.push(aEvent.type);
+}
+
+function clearEvents() {
+  gEvents = [];
+}
+
+function checkEvents(aEvents) {
+  if (aEvents.length != gEvents.length) {
+    info("---- event check: failed length (" + aEvents.length + " != " + gEvents.length + ")\n");
+    info("---- expected: [" + aEvents.join(",") + "] actual: [" + gEvents.join(",") + "]\n");
+    return false;
+  }
+
+  for (let i=0; i<aEvents.length; i++) {
+    if (aEvents[i] != gEvents[i]) {
+      info("---- event check: failed match (" + aEvents[i] + " != " + gEvents[i] + "\n");
+      return false;
+    }
+  }
+  return true;
+}
+
+let gContextTypes = "";
+function clearContextTypes() {
+  gContextTypes = [];
+
+  if (ContextHelper.popupState)
+    ContextHelper.hide();
+}
+
+function checkContextTypes(aTypes) {
+  if (aTypes.length != gContextTypes.length) {
+    info("---- type check: failed length (" + aTypes.length + " != " + gContextTypes.length + ")\n");
+    info("---- expected: [" + aTypes.join(",") + "] actual: [" + gContextTypes.join(",") + "]\n");
+    return false;
+  }
+
+  for (let i=0; i<aTypes.length; i++) {
+    if (gContextTypes.indexOf(aTypes[i]) == -1) {
+      info("---- type check: failed match (" + aTypes[i] + ")\n");
+      info("---- expected: [" + aTypes.join(",") + "] actual: [" + gContextTypes.join(",") + "]\n");
+      return false;
+    }
+  }
+  return true;
+}
+
+function waitForContextMenu(aCallback, aNextTest) {
+  clearContextTypes();
+
+  let browser = gCurrentTab.browser;
+  browser.messageManager.addMessageListener("Browser:ContextMenu", function(aMessage) {
+    browser.messageManager.removeMessageListener(aMessage.name, arguments.callee);
+    aMessage.json.types.forEach(function(aType) {
+      gContextTypes.push(aType);
+    });
+    setTimeout(function() {
+      aCallback(aMessage.json);
+      clearContextTypes();
+      aNextTest();
+    }, 0);
+  });
+}
+
+function test() {
+  // The "runNextTest" approach is async, so we need to call "waitForExplicitFinish()"
+  // We call "finish()" when the tests are finished
+  waitForExplicitFinish();
+
+  // Add new tab
+  gCurrentTab = Browser.addTab(testURL, true);
+  ok(gCurrentTab, "Tab Opened");
+
+  let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+  clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+
+  SelectionHelper.enabled = false;
+
+  window.addEventListener("TapSingle", dumpEvents, true);
+  window.addEventListener("TapDouble", dumpEvents, true);
+  window.addEventListener("TapLong", dumpEvents, true);
+
+  // Wait for the tab to load, then do the tests
+  messageManager.addMessageListener("Browser:FirstPaint", function() {
+  if (gCurrentTab.browser.currentURI.spec == testURL) {
+    messageManager.removeMessageListener("Browser:FirstPaint", arguments.callee);
+    // Hack the allowZoom getter since we want to observe events
+    // for testing purpose even if it is a local tab
+    gCurrentTab.__defineGetter__("allowZoom", function() {
+      return true;
+    });
+
+    // Using setTimeout(..., 0) here result into a duplicate mousedown/mouseup
+    // sequence that makes the double tap test fails (add some dump in input.js
+    // to see that...)
+    runNextTest();
+  }});
+}
+
+//------------------------------------------------------------------------------
+// Iterating tests by shifting test out one by one as runNextTest is called.
+function runNextTest() {
+  // Run the next test until all tests completed
+  if (gTests.length > 0) {
+    gCurrentTest = gTests.shift();
+    info(gCurrentTest.desc);
+    gCurrentTest.run();
+  }
+  else {
+    let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+
+    window.removeEventListener("TapSingle", dumpEvents, true);
+    window.removeEventListener("TapDouble", dumpEvents, true);
+    window.removeEventListener("TapLong", dumpEvents, true);
+
+    SelectionHelper.enabled = true;
+    Browser.closeTab(gCurrentTab);
+
+    finish();
+  }
+}
+
+//------------------------------------------------------------------------------
+gTests.push({
+  desc: "Test empty plain textbox",
+
+  run: function() {
+    waitForContextMenu(function(aJSON) {
+      ok(checkContextTypes(["input-text"]), "Editbox with no text, no selection and no clipboard");
+    }, runNextTest);
+
+    let browser = gCurrentTab.browser;
+    let plainEdit = browser.contentDocument.getElementById("plain-edit");
+    plainEdit.readOnly = false;
+    plainEdit.value = "";
+
+    // Try very hard to keep "paste" from if the clipboard has data
+    let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+    plainEdit.readOnly = true;
+    
+    let event = content.document.createEvent("PopupEvents");
+    event.initEvent("contextmenu", true, true);
+    plainEdit.dispatchEvent(event);
+  }
+});
+
+//------------------------------------------------------------------------------
+gTests.push({
+  desc: "Test plain textbox with text fully selected",
+
+  run: function() {
+    waitForContextMenu(function(aJSON) {
+      ok(checkContextTypes(["input-text", "copy"]), "Editbox with text and full selection, but no clipboard");
+    }, runNextTest);
+
+    let browser = gCurrentTab.browser;
+    let plainEdit = browser.contentDocument.getElementById("plain-edit");
+    plainEdit.readOnly = false;
+    plainEdit.value = "Every time we fix a bug, Stuart call's the President";
+    let plainEdit = plainEdit.QueryInterface(Ci.nsIDOMNSEditableElement);
+    plainEdit.editor.selectAll();
+
+    // Try very hard to keep "paste" from if the clipboard has data
+    let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+    plainEdit.readOnly = true;
+    
+    let event = content.document.createEvent("PopupEvents");
+    event.initEvent("contextmenu", true, true);
+    plainEdit.dispatchEvent(event);
+  }
+});
+
+//------------------------------------------------------------------------------
+gTests.push({
+  desc: "Test plain textbox with text no selection",
+
+  run: function() {
+    waitForContextMenu(function(aJSON) {
+      ok(checkContextTypes(["input-text", "copy-all", "select-all"]), "Editbox with text, but no selection and no clipboard");
+    }, runNextTest);
+
+    let browser = gCurrentTab.browser;
+    let plainEdit = browser.contentDocument.getElementById("plain-edit");
+    plainEdit.readOnly = false;
+    plainEdit.value = "Every time we fix a bug, Stuart call's the President";
+    plainEdit.selectionStart = 0;
+    plainEdit.selectionEnd = 0;
+
+    // Try very hard to keep "paste" from if the clipboard has data
+    let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
+    clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
+    plainEdit.readOnly = true;
+    
+    let event = content.document.createEvent("PopupEvents");
+    event.initEvent("contextmenu", true, true);
+    plainEdit.dispatchEvent(event);
+  }
+});
+
+//------------------------------------------------------------------------------
+gTests.push({
+  desc: "Test plain textbox with text no selection and text on clipboard",
+
+  run: function() {
+    waitForContextMenu(function(aJSON) {
+      ok(checkContextTypes(["input-text", "copy-all", "select-all", "paste"]), "Editbox with text and clipboard, but no selection");
+    }, runNextTest);
+
+    let browser = gCurrentTab.browser;
+    let plainEdit = browser.contentDocument.getElementById("plain-edit");
+    plainEdit.readOnly = false;
+    plainEdit.value = "Every time we fix a bug, Stuart call's the President";
+    plainEdit.selectionStart = 0;
+    plainEdit.selectionEnd = 0;
+
+    // Put some data on the clipboard to get "paste" to be active
+    let clipboard = Cc["@mozilla.org/widget/clipboardhelper;1"].getService(Ci.nsIClipboardHelper);
+    clipboard.copyString("We are testing Firefox");
+    
+    let event = content.document.createEvent("PopupEvents");
+    event.initEvent("contextmenu", true, true);
+    plainEdit.dispatchEvent(event);
+  }
+});
--- a/mobile/themes/core/gingerbread/forms.css
+++ b/mobile/themes/core/gingerbread/forms.css
@@ -200,16 +200,20 @@
   -moz-user-focus: ignore;
   -moz-user-select: none;
 }
 
 #select-container[multiple="true"] button {
   display: -moz-box;
 }
 
+#select-popup > hbox {
+  background-color: @color_background_default@;
+}
+
 #select-commands {
   background: transparent;
   border-top: @border_width_tiny@ solid rgb(205,205,205);
   padding: 0;
   -moz-user-focus: ignore;
 }
 
 /* listcell elements doesn't have flex="1" so we need to force it */
deleted file mode 100644
index 82cf8f415fa7e89918c521e474c6729e66ecf95a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index a29f65655ef5292621f3eb8094e9836c8fee1a0d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2fa34331d93149a113646952e9095e3a338f7b1f
GIT binary patch
literal 1305
zc$@(l1?KvRP)<h;3K|Lk000e1NJLTq001rk001rs1^@s6SGg-U0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$yGcYrRCwC#T1{vZK@^_dObbF=DHsK<
z)e1_f2ZiR+f+r6>h=M3yER>@3642_sG|{_gAqR^hg&tH|L~jK>6rlyl!61}U5B;GQ
znnYt$f7)%5b>9AU@;bBGCMGuElqH+V?94aczWLs~H&t|9C*g2dCtQI#z9@>~)WJR9
zj{gn+j@yaq`Tp%TxIg^-;NYO*V--5?5E|JR|D6ZM4~pC4-$f+g{$v<1A@J<v<Yb6)
z11Y!@JW~;95&L*h*<0iLlZ`ES`$mN-1A!lOGas3W;R)mZMC0)N@Fd{ADV`~_pBAzQ
z3tNZt{A5(oO!s2J3t1&qSPaHR5>yR^%4BP=m#Si%R~z~-*-j)9zNMuly1cwx1K*pP
znzovon=^jDKkEh_@KU^5D+zjPYHHu~^mHQw-e3VwcXV{5Iy*am%fQ<>seL2cPm~k%
z#Kgp*SS;4k|MKK8LqHx~d*7E%r$Mh*F?dWYt+Z|Pprg^~soUenBVRW^69683-ZcF1
zN;GIS6@t%`L($%%GN6w|zH194omnxi6uXDI+1c5{Gcz-F>+9=^Y=NqH?@%ew{fub<
z`ZJp#S$&J-^o();U0WnKMh=Xy_O+>0$|u|RsG_ZFB|v}UK!ce;f%}cz8hP52>|rLN
zH8wV8MN*i@c)7G(#`G@+8d%PEDwMpqzCYO7+Pc!#*7l>mzFr#OP`rICw@rW3<{8sT
z#;#_*X`(ow$GZ;(1A)L?S6A1nND_HxNq4K?UY&+`AuckeP0#>XxBh&jrXXlM0V<2@
zN^u$@(B?u+GV|DSScXq8Op78Y&z{q((}1>Er&E@B<hX?h#i#6^X<PlMTioaN+LN1e
z24lhJM;xcIv9XbWPZrGj^B3YaXq#;SJ=X2_40?yl_YyOLBLIg0j=_BGi;Tgz0V2cf
zwST-N^5F7^Tk&|j4%#m)EF8W2>cmiLhvb=dT`XuGqo@5iI0A48H<@GLr3^p-Fhx_y
zomVYG;q$Tk&_49;>;Sa;!6wH`o?@uS?#x3LzEM%y0T*xt;1HhleC)aKcx@z;(}?xP
z8JniZ19cmCdwRf_D1go|(8L67n@A~4V{%nd-UJtL1mF<BF@S@hYOQIjx-nbB6u@+n
z+MID2OcTzz=qA&pfX0rJdU*&2uoPnzzK?ZBgI7lrku2GAv^bk%?pj}S*md$HVACp?
zNAaMsWILu(NLAdxXAE6t&s&*1+p*ZDM3vf-n3icdEo3Hzz+V}SM}Tc-o!E?*s2;MA
z%^rvDc7uh%k6YkvmD$$mzsIyNJyFcAPz2tvc}uTNk61p?4)9`jg&6$n-dNwIXJ3Zl
z{!Q<ZzChs2{NDz>BjzkNx59&OXlT$r-CMp0_2<qNj@FA^oWg8vDa^z6mhBi*Uh^ZR
zEYQ5gSxNzbaJ9F$Z<aIBnU`j+h7_|1U)7|Uaj>I`BIs&JeyZgPl>aC8Wpe0cgS96o
z5ekKLi)}@8z$(*sx6@*`^HO{sT13Cw=bXHa;}c_<9J!qc<9s9^ofnchFJ^)hLb@on
z6P+FxVi9{|5sR{Pi0oV+_o?82LMU`REdt^eaLf7=c|@<<4)`a8KLQK@7a*znkZj<Z
P00000NkvXXu0mjf^1phG
deleted file mode 100644
index 054c7373b405de8da050c35d8b817ed4dd29c31d..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..add20cb42c95c01e48fc327e59b06f03e2d28370
GIT binary patch
literal 530
zc$@(e0`2{YP)<h;3K|Lk000e1NJLTq001rk001rs1^@s6SGg-U0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUzv`IukRCwCdT3L3(APh8$F4B`4j^>l(
zC{D>MeUphGZof4A5H=&kXhSLId2X$>v)84Rt(WneYb?F5muMW<jXBuQ>v@d#;C=Re
zFSkD48@vcVI_t+8H^%l~#(2*$hvyx~Q5{ZKm>}j##0eyV565FG=FDydZ|<l4Y*_Ts
zJ|Vg~=0tSJu@>9dkB3^_CLfAvabEb1pRX-pskPpbNgiFlLh+eIXD*#qQz9DW#Z;ie
zLTjvFGjkh-(@00kz{OX_AtO{q?K6v*o#RqaLCb3@P+`Bx6s_hj;n`Io3+Rgh%1%5(
zSr;notjiF-a@JF;Llq7)GF%DcXe|9oRG(I>DByeQtEfO`;M`Q8!b~+4h`fbv{BWa!
zb60a~Lj#oE$wKB@6h$jw-4!%Ss8v)1lAS?|o`e;gEQ{VOGF!|y1B9GcFhVlkq3rVn
zr)*3?6^15X$@siLMK#KI&LFqe?pO5aN}yNyQO4>Os78oz)RD84_!UAwrM*`~&ko9S
zLUlMYwoybK#iY><d`jv@#LjZ~D+WD7x1P|SZGPoX0V~UkdHDapW2UNWt>q!W01=y|
U^g|7r>i_@%07*qoM6N<$g4b^DfdBvi
--- a/mobile/themes/core/jar.mn
+++ b/mobile/themes/core/jar.mn
@@ -303,18 +303,16 @@ chrome.jar:
   skin/honeycomb/images/arrowrightdark-16.png         (honeycomb/images/arrowrightdark-16.png)
   skin/honeycomb/images/arrowupdark-16.png            (honeycomb/images/arrowupdark-16.png)
   skin/honeycomb/images/arrowdowndark-16.png          (honeycomb/images/arrowdowndark-16.png)
   skin/honeycomb/images/popup-bg-hdpi.png             (honeycomb/images/popup-bg-hdpi.png)
   skin/honeycomb/images/popup-selected-item-hdpi.png  (honeycomb/images/popup-selected-item-hdpi.png)
   skin/honeycomb/images/arrowbox-up.png               (honeycomb/images/arrowbox-up.png)
   skin/honeycomb/images/arrowbox-down.png             (honeycomb/images/arrowbox-down.png)
   skin/honeycomb/images/arrowbox-horiz.png            (honeycomb/images/arrowbox-horiz.png)
-  skin/honeycomb/images/check-selected-30.png         (honeycomb/images/check-selected-30.png)
-  skin/honeycomb/images/check-unselected-30.png       (honeycomb/images/check-unselected-30.png)
   skin/honeycomb/images/dropmarker-hdpi.png           (honeycomb/images/dropmarker-hdpi.png)
   skin/honeycomb/images/ratings-18.png                (images/ratings-18.png)
   skin/honeycomb/images/favicon-default-32.png        (honeycomb/images/favicon-default-32.png)
   skin/honeycomb/images/endcap-default-bg.png         (honeycomb/images/endcap-default-bg.png)
   skin/honeycomb/images/endcap-active-bg.png          (honeycomb/images/endcap-active-bg.png)
   skin/honeycomb/images/endcap-ev-default-bg.png      (honeycomb/images/endcap-ev-default-bg.png)
   skin/honeycomb/images/endcap-ev-active-bg.png       (honeycomb/images/endcap-ev-active-bg.png)
   skin/honeycomb/images/endcap-ssl-default-bg.png     (honeycomb/images/endcap-ssl-default-bg.png)
@@ -360,17 +358,18 @@ chrome.jar:
   skin/honeycomb/images/identity-default-hdpi.png     (honeycomb/images/identity-default-hdpi.png)
   skin/honeycomb/images/identity-ssl-hdpi.png         (honeycomb/images/identity-ssl-hdpi.png)
   skin/honeycomb/images/identity-ev-hdpi.png          (honeycomb/images/identity-ev-hdpi.png)
   skin/honeycomb/images/unlocked-hdpi.png             (honeycomb/images/unlocked-hdpi.png)
   skin/honeycomb/images/locked-hdpi.png               (honeycomb/images/locked-hdpi.png)
   skin/honeycomb/images/close-default-hdpi.png        (honeycomb/images/close-default-hdpi.png)
   skin/honeycomb/images/close-active-hdpi.png         (honeycomb/images/close-active-hdpi.png)
   skin/honeycomb/images/close-inactive-tab-hdpi.png   (honeycomb/images/close-inactive-tab-hdpi.png)
-  skin/honeycomb/images/check-30.png                  (honeycomb/images/check-30.png)
+  skin/honeycomb/images/check-selected-hdpi.png       (honeycomb/images/check-selected-hdpi.png)
+  skin/honeycomb/images/check-unselected-hdpi.png     (honeycomb/images/check-unselected-hdpi.png)
   skin/honeycomb/images/search-glass-30.png           (honeycomb/images/search-glass-30.png)
   skin/honeycomb/images/search-clear-30.png           (honeycomb/images/search-clear-30.png)
   skin/honeycomb/images/section-expanded-16.png       (images/section-expanded-16.png)
   skin/honeycomb/images/section-collapsed-16.png      (images/section-collapsed-16.png)
   skin/honeycomb/images/task-switch-hdpi.png          (honeycomb/images/task-switch-hdpi.png)
   skin/honeycomb/images/task-close-hdpi.png           (honeycomb/images/task-close-hdpi.png)
   skin/honeycomb/images/task-back-hdpi.png            (honeycomb/images/task-back-hdpi.png)
   skin/honeycomb/images/task-back-rtl-hdpi.png        (honeycomb/images/task-back-rtl-hdpi.png)
--- a/modules/libpr0n/encoders/jpeg/nsJPEGEncoder.cpp
+++ b/modules/libpr0n/encoders/jpeg/nsJPEGEncoder.cpp
@@ -83,16 +83,18 @@ nsJPEGEncoder::~nsJPEGEncoder()
 NS_IMETHODIMP nsJPEGEncoder::InitFromData(const PRUint8* aData,
                                           PRUint32 aLength, // (unused, req'd by JS)
                                           PRUint32 aWidth,
                                           PRUint32 aHeight,
                                           PRUint32 aStride,
                                           PRUint32 aInputFormat,
                                           const nsAString& aOutputOptions)
 {
+  NS_ENSURE_ARG(aData);
+
   // validate input format
   if (aInputFormat != INPUT_FORMAT_RGB &&
       aInputFormat != INPUT_FORMAT_RGBA &&
       aInputFormat != INPUT_FORMAT_HOSTARGB)
     return NS_ERROR_INVALID_ARG;
 
   // Stride is the padded width of each row, so it better be longer (I'm afraid
   // people will not understand what stride means, so check it well)
--- a/modules/libpr0n/encoders/png/nsPNGEncoder.cpp
+++ b/modules/libpr0n/encoders/png/nsPNGEncoder.cpp
@@ -84,16 +84,17 @@ NS_IMETHODIMP nsPNGEncoder::InitFromData
                                          PRUint32 aLength, // (unused,
                                                            // req'd by JS)
                                          PRUint32 aWidth,
                                          PRUint32 aHeight,
                                          PRUint32 aStride,
                                          PRUint32 aInputFormat,
                                          const nsAString& aOutputOptions)
 {
+  NS_ENSURE_ARG(aData);
   nsresult rv;
 
   rv = StartImageEncode(aWidth, aHeight, aInputFormat, aOutputOptions);
   if (!NS_SUCCEEDED(rv))
     return rv;
 
   rv = AddImageFrame(aData, aLength, aWidth, aHeight, aStride,
                      aInputFormat, aOutputOptions);
new file mode 100644
--- /dev/null
+++ b/modules/libpr0n/test/crashtests/681190.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<body>
+<canvas id="crashtest" width="50000" height="50000" />
+<script>
+  document.getElementById("crashtest").mozGetAsFile("foo.png", "image/png");
+  document.getElementById("crashtest").mozGetAsFile("foo.jpeg", "image/jpeg");
+</script>
+</body>
+</html>
--- a/modules/libpr0n/test/crashtests/crashtests.list
+++ b/modules/libpr0n/test/crashtests/crashtests.list
@@ -17,8 +17,10 @@ load invalid-icc-profile.jpg
 # maximum (256) width and height icons that we currently (due to bug 668068)
 # interpret as 0-width and 0-height.
 load 256-width.ico
 load 256-height.ico
 
 # A 3-frame animated GIF with an inordinate delay between the second and third
 # frame.
 HTTP load delayedframe.sjs
+
+load 681190.html
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -2399,16 +2399,19 @@ WebSocketChannel::OnStopRequest(nsIReque
 // nsIInputStreamCallback
 
 NS_IMETHODIMP
 WebSocketChannel::OnInputStreamReady(nsIAsyncInputStream *aStream)
 {
   LOG(("WebSocketChannel::OnInputStreamReady() %p\n", this));
   NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "not socket thread");
 
+  if (!mSocketIn) // did we we clean up the socket after scheduling InputReady?
+    return NS_OK;
+  
   nsRefPtr<nsIStreamListener>    deleteProtector1(mInflateReader);
   nsRefPtr<nsIStringInputStream> deleteProtector2(mInflateStream);
 
   // this is after the  http upgrade - so we are speaking websockets
   char  buffer[2048];
   PRUint32 count;
   nsresult rv;
 
--- a/testing/xpcshell/remotexpcshelltests.py
+++ b/testing/xpcshell/remotexpcshelltests.py
@@ -190,17 +190,19 @@ class XPCShellRemote(xpcshell.XPCShellTe
             cmd[index] = part
           index = index + 1
 
         xpcshell = self.remoteJoin(self.remoteBinDir, "xpcshell")
 
         shellArgs = "cd "+self.remoteHere
         shellArgs += "; LD_LIBRARY_PATH="+self.remoteBinDir
         shellArgs += "; export CACHE_PATH="+self.remoteBinDir
-        shellArgs += "; export GRE_HOME="+self.device.getAppRoot()
+        if (self.device.getAppRoot()):
+          # xpcshell still runs without GRE_HOME; it may not be necessary
+          shellArgs += "; export GRE_HOME="+self.device.getAppRoot()
         shellArgs += "; export XPCSHELL_TEST_PROFILE_DIR="+self.profileDir
         shellArgs += "; "+xpcshell+" "
         shellArgs += " ".join(cmd[1:])
 
         if self.verbose:
           self.log.info(shellArgs)
 
         # If the adb version of devicemanager is used and the arguments passed
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -962,17 +962,16 @@ function buildJarURI(aJarfile, aPath) {
 function flushJarCache(aJarFile) {
   Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null);
   Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIChromeFrameMessageManager)
     .sendAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
 }
 
 function flushStartupCache() {
   // Init this, so it will get the notification.
-  Cc["@mozilla.org/xul/xul-prototype-cache;1"].getService(Ci.nsISupports);
   Services.obs.notifyObservers(null, "startupcache-invalidate", null);
 }
 
 /**
  * Creates and returns a new unique temporary file. The caller should delete
  * the file when it is no longer needed.
  *
  * @return an nsIFile that points to a randomly named, initially empty file in
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1681,38 +1681,44 @@ ProfileLockedDialog(nsILocalFile* aProfi
 
     if (!killMessage || !killTitle)
       return NS_ERROR_FAILURE;
 
     nsCOMPtr<nsIPromptService> ps
       (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
     NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
 
-    PRUint32 flags = nsIPromptService::BUTTON_TITLE_OK * nsIPromptService::BUTTON_POS_0;
-
     if (aUnlocker) {
-      flags =
-        nsIPromptService::BUTTON_TITLE_CANCEL * nsIPromptService::BUTTON_POS_0 +
-        nsIPromptService::BUTTON_TITLE_IS_STRING * nsIPromptService::BUTTON_POS_1 +
+      const PRUint32 flags =
+        (nsIPromptService::BUTTON_TITLE_CANCEL * 
+         nsIPromptService::BUTTON_POS_0) +
+        (nsIPromptService::BUTTON_TITLE_IS_STRING * 
+         nsIPromptService::BUTTON_POS_1) +
         nsIPromptService::BUTTON_POS_1_DEFAULT;
-    }
-
-    PRInt32 button;
-    // The actual value is irrelevant but we shouldn't be handing out
-    // malformed JSBools to XPConnect.
-    PRBool checkState = PR_FALSE;
-    rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
-                       killTitle, nsnull, nsnull, nsnull, &checkState, &button);
-    NS_ENSURE_SUCCESS_LOG(rv, rv);
-
-    if (button == 1 && aUnlocker) {
-      rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
-      if (NS_FAILED(rv)) return rv;
-
-      return NS_LockProfilePath(aProfileDir, aProfileLocalDir, nsnull, aResult);
+
+      PRInt32 button;
+      // The actual value is irrelevant but we shouldn't be handing out
+      // malformed JSBools to XPConnect.
+      PRBool checkState = PR_FALSE;
+      rv = ps->ConfirmEx(nsnull, killTitle, killMessage, flags,
+                         killTitle, nsnull, nsnull, nsnull, 
+                         &checkState, &button);
+      NS_ENSURE_SUCCESS_LOG(rv, rv);
+
+      if (button == 1) {
+        rv = aUnlocker->Unlock(nsIProfileUnlocker::FORCE_QUIT);
+        if (NS_FAILED(rv)) 
+          return rv;
+
+        return NS_LockProfilePath(aProfileDir, aProfileLocalDir, 
+                                  nsnull, aResult);
+      }
+    } else {
+      rv = ps->Alert(nsnull, killTitle, killMessage);
+      NS_ENSURE_SUCCESS_LOG(rv, rv);
     }
 
     return NS_ERROR_ABORT;
   }
 }
 
 static nsresult
 ProfileMissingDialog(nsINativeAppSupport* aNative)
--- a/xpcom/string/public/nsAlgorithm.h
+++ b/xpcom/string/public/nsAlgorithm.h
@@ -66,16 +66,17 @@ NS_ROUNDUP( const T& a, const T& b )
 template <class T>
 inline
 const T&
 NS_MIN( const T& a, const T& b )
   {
     return b < a ? b : a;
   }
 
+// Must return b when a == b in case a is -0
 template <class T>
 inline
 const T&
 NS_MAX( const T& a, const T& b )
   {
     return a > b ? a : b;
   }