Merge m-i to m-c
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 19 Apr 2014 18:25:46 -0700
changeset 179768 53a6c96cea62c46160ce9ea80e0d9188fe5ed2df
parent 179767 3bf6a27f8f23584ee4cf77ead8f6f55a0983a482 (current diff)
parent 179753 83c8cecf82977f58aa38dbcf0764d4b208d31989 (diff)
child 179769 56fe9fa6abcdb5bd8db509aaff1dfc16d9fbe14a
child 179777 ea214ef03c3fc40f630fb16f333d05502692a6d5
child 179785 53a7716781454e6ba40ac94d010b4809d5c09d95
child 179827 ca3c2e681806d1fa36a57471326fc4e4d63cfb0b
push id272
push userpvanderbeken@mozilla.com
push dateMon, 05 May 2014 16:31:18 +0000
milestone31.0a1
Merge m-i to m-c
layout/reftests/backgrounds/background-size-bounding-box.html
layout/reftests/backgrounds/background-size-continuous.html
layout/reftests/backgrounds/background-size-cover-bounding-box.html
layout/reftests/backgrounds/background-size-cover-continuous.html
layout/reftests/backgrounds/background-size-cover-each-box.html
layout/reftests/backgrounds/background-size-each-box.html
layout/reftests/bugs/368020-4-ref.html
layout/reftests/bugs/368020-4.html
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -666,16 +666,19 @@ pref("plugins.hideMissingPluginsNotifica
 #ifdef RELEASE_BUILD
 // For now, plugins other than Java and Flash are enabled in beta/release
 // and click-to-activate in earlier channels.
 pref("plugin.default.state", 2);
 #else
 pref("plugin.default.state", 1);
 #endif
 
+// Plugins bundled in XPIs are enabled by default.
+pref("plugin.defaultXpi.state", 2);
+
 // Flash is enabled by default, and Java is click-to-activate by default on
 // all channels.
 pref("plugin.state.flash", 2);
 pref("plugin.state.java", 1);
 
 // display door hanger if flash not installed
 pref("plugins.notifyMissingFlash", true);
 
--- a/caps/idl/nsIScriptSecurityManager.idl
+++ b/caps/idl/nsIScriptSecurityManager.idl
@@ -6,17 +6,17 @@
 #include "nsISupports.idl"
 #include "nsIPrincipal.idl"
 #include "nsIXPCSecurityManager.idl"
 interface nsIURI;
 interface nsIChannel;
 interface nsIDocShell;
 interface nsIDomainPolicy;
 
-[scriptable, uuid(3b6e408b-e774-4612-89e8-3ef303564392)]
+[scriptable, uuid(4c087cc3-e0cc-4ec3-88df-8d68f3023b45)]
 interface nsIScriptSecurityManager : nsIXPCSecurityManager
 {
     /**
      * Check that the script currently running in context "cx" can load "uri".
      *
      * Will return error code NS_ERROR_DOM_BAD_URI if the load request
      * should be denied.
      *
@@ -146,21 +146,16 @@ interface nsIScriptSecurityManager : nsI
     /**
      * Legacy name for getNoAppCodebasePrincipal.
      *
      * @deprecated use getNoAppCodebasePrincipal instead.
      */
     [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri);
 
     /**
-     * Return the principal of the specified object in the specified context.
-     */
-    [implicit_jscontext] nsIPrincipal getObjectPrincipal(in jsval aObject);
-
-    /**
      * Returns true if the principal of the currently running script is the
      * system principal, false otherwise.
      */
     [noscript] boolean subjectPrincipalIsSystem();
 
     /**
      * Returns OK if aJSContext and target have the same "origin"
      * (scheme, host, and port).
--- a/caps/src/nsScriptSecurityManager.cpp
+++ b/caps/src/nsScriptSecurityManager.cpp
@@ -1113,28 +1113,16 @@ nsScriptSecurityManager::GetSubjectPrinc
     // The context should always be in a compartment, either one it has entered
     // or the one associated with its global.
     MOZ_ASSERT(!!compartment);
 
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
 
-NS_IMETHODIMP
-nsScriptSecurityManager::GetObjectPrincipal(JS::Handle<JS::Value> aObjectVal,
-                                            JSContext *aCx,
-                                            nsIPrincipal **result)
-{
-    NS_ENSURE_TRUE(aObjectVal.isObject(), NS_ERROR_FAILURE);
-    JS::RootedObject obj(aCx, &aObjectVal.toObject());
-    nsCOMPtr<nsIPrincipal> principal = doGetObjectPrincipal(obj);
-    principal.forget(result);
-    return NS_OK;
-}
-
 // static
 nsIPrincipal*
 nsScriptSecurityManager::doGetObjectPrincipal(JSObject *aObj)
 {
     JSCompartment *compartment = js::GetObjectCompartment(aObj);
     JSPrincipals *principals = JS_GetCompartmentPrincipals(compartment);
     return nsJSPrincipals::get(principals);
 }
--- a/content/base/src/nsInProcessTabChildGlobal.cpp
+++ b/content/base/src/nsInProcessTabChildGlobal.cpp
@@ -96,17 +96,17 @@ nsInProcessTabChildGlobal::DoSendAsyncMe
   NS_DispatchToCurrentThread(ev);
   return true;
 }
 
 nsInProcessTabChildGlobal::nsInProcessTabChildGlobal(nsIDocShell* aShell,
                                                      nsIContent* aOwner,
                                                      nsFrameMessageManager* aChrome)
 : mDocShell(aShell), mInitialized(false), mLoadingScript(false),
-  mDelayedDisconnect(false), mOwner(aOwner), mChromeMessageManager(aChrome)
+  mOwner(aOwner), mChromeMessageManager(aChrome)
 {
 
   // If owner corresponds to an <iframe mozbrowser> or <iframe mozapp>, we'll
   // have to tweak our PreHandleEvent implementation.
   nsCOMPtr<nsIMozBrowserFrame> browserFrame = do_QueryInterface(mOwner);
   if (browserFrame) {
     mIsBrowserOrAppFrame = browserFrame->GetReallyIsBrowserOrApp();
   }
@@ -229,23 +229,16 @@ nsInProcessTabChildGlobal::DelayedDiscon
   mChromeMessageManager = nullptr;
   if (mMessageManager) {
     static_cast<nsFrameMessageManager*>(mMessageManager.get())->Disconnect();
     mMessageManager = nullptr;
   }
   if (mListenerManager) {
     mListenerManager->Disconnect();
   }
-
-  if (!mLoadingScript) {
-    ReleaseWrapper(static_cast<EventTarget*>(this));
-    mGlobal = nullptr;
-  } else {
-    mDelayedDisconnect = true;
-  }
 }
 
 NS_IMETHODIMP_(nsIContent *)
 nsInProcessTabChildGlobal::GetOwnerContent()
 {
   return mOwner;
 }
 
@@ -326,13 +319,9 @@ nsInProcessTabChildGlobal::LoadFrameScri
   if (!mInitialized) {
     mInitialized = true;
     Init();
   }
   bool tmp = mLoadingScript;
   mLoadingScript = true;
   LoadFrameScriptInternal(aURL, aRunInGlobalScope);
   mLoadingScript = tmp;
-  if (!mLoadingScript && mDelayedDisconnect) {
-    mDelayedDisconnect = false;
-    Disconnect();
-  }
 }
--- a/content/base/src/nsInProcessTabChildGlobal.h
+++ b/content/base/src/nsInProcessTabChildGlobal.h
@@ -156,17 +156,16 @@ public:
   }
 protected:
   nsresult Init();
   nsresult InitTabChildGlobal();
   nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
   nsCOMPtr<nsIDocShell> mDocShell;
   bool mInitialized;
   bool mLoadingScript;
-  bool mDelayedDisconnect;
 
   // Is this the message manager for an in-process <iframe mozbrowser> or
   // <iframe mozapp>?  This affects where events get sent, so it affects
   // PreHandleEvent.
   bool mIsBrowserOrAppFrame;
 public:
   nsIContent* mOwner;
   nsFrameMessageManager* mChromeMessageManager;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -138,18 +138,19 @@ static const char *kPrefJavaMIME = "plug
 // 0.09 the file encoding is changed to UTF-8, bug 420285
 // 0.10 added plugin versions on appropriate platforms, bug 427743
 // 0.11 file name and full path fields now store expected values on all platforms, bug 488181
 // 0.12 force refresh due to quicktime pdf claim fix, bug 611197
 // 0.13 add architecture and list of invalid plugins, bug 616271
 // 0.14 force refresh due to locale comparison fix, bug 611296
 // 0.15 force refresh due to bug in reading Java plist MIME data, bug 638171
 // 0.16 version bump to avoid importing the plugin flags in newer versions
+// 0.17 added flag on whether plugin is loaded from an XPI
 // The current plugin registry version (and the maximum version we know how to read)
-static const char *kPluginRegistryVersion = "0.16";
+static const char *kPluginRegistryVersion = "0.17";
 // The minimum registry version we know how to read
 static const char *kMinimumRegistryVersion = "0.9";
 
 static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
 
 #define kPluginRegistryFilename NS_LITERAL_CSTRING("pluginreg.dat")
 
 #ifdef PLUGIN_LOGGING
@@ -1622,16 +1623,72 @@ int64_t GetPluginLastModifiedTime(const 
   }
 #else
   localfile->GetLastModifiedTime(&fileModTime);
 #endif
 
   return fileModTime;
 }
 
+bool
+GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
+                         const nsCOMPtr<nsISimpleEnumerator>& extensionDirs)
+{
+  if (!extensionDirs) {
+    return false;
+  }
+
+  bool hasMore;
+  while (NS_SUCCEEDED(extensionDirs->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> supports;
+    nsresult rv = extensionDirs->GetNext(getter_AddRefs(supports));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> extDir(do_QueryInterface(supports, &rv));
+    if (NS_FAILED(rv)) {
+      continue;
+    }
+
+    nsCOMPtr<nsIFile> dir;
+    if (NS_FAILED(extDir->Clone(getter_AddRefs(dir)))) {
+      continue;
+    }
+
+    bool contains;
+    if (NS_FAILED(dir->Contains(pluginFile, true, &contains)) || !contains) {
+      continue;
+    }
+
+    return true;
+  }
+
+  return false;
+}
+
+nsCOMPtr<nsISimpleEnumerator>
+GetExtensionDirectories()
+{
+  nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
+  if (!dirService) {
+    return nullptr;
+  }
+
+  nsCOMPtr<nsISimpleEnumerator> list;
+  nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
+                                NS_GET_IID(nsISimpleEnumerator),
+                                getter_AddRefs(list));
+  if (NS_FAILED(rv)) {
+    return nullptr;
+  }
+
+  return list;
+}
+
 struct CompareFilesByTime
 {
   bool
   LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
   {
     return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
   }
 
@@ -1685,27 +1742,33 @@ nsresult nsPluginHost::ScanPluginsDirect
 
     if (nsPluginsDir::IsPluginFile(dirEntry)) {
       pluginFiles.AppendElement(dirEntry);
     }
   }
 
   pluginFiles.Sort(CompareFilesByTime());
 
+  nsCOMPtr<nsISimpleEnumerator> extensionDirs = GetExtensionDirectories();
+  if (!extensionDirs) {
+    PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("Could not get extension directories."));
+  }
+
   bool warnOutdated = false;
 
   for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
     nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
 
     nsString utf16FilePath;
     rv = localfile->GetPath(utf16FilePath);
     if (NS_FAILED(rv))
       continue;
 
-    int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const int64_t fileModTime = GetPluginLastModifiedTime(localfile);
+    const bool fromExtension = GetPluginIsFromExtension(localfile, extensionDirs);
 
     // Look for it in our cache
     NS_ConvertUTF16toUTF8 filePath(utf16FilePath);
     nsRefPtr<nsPluginTag> pluginTag;
     RemoveCachedPluginsInfo(filePath.get(), getter_AddRefs(pluginTag));
 
     bool seenBefore = false;
 
@@ -1776,17 +1839,17 @@ nsresult nsPluginHost::ScanPluginsDirect
         }
         mInvalidPlugins = invalidTag;
 
         // Mark aPluginsChanged so pluginreg is rewritten
         *aPluginsChanged = true;
         continue;
       }
 
-      pluginTag = new nsPluginTag(&info, fileModTime);
+      pluginTag = new nsPluginTag(&info, fileModTime, fromExtension);
       pluginFile.FreePluginInfo(info);
       if (!pluginTag)
         return NS_ERROR_OUT_OF_MEMORY;
 
       pluginTag->mLibrary = library;
       uint32_t state = pluginTag->GetBlocklistState();
 
       // If the blocklist says it is risky and we have never seen this
@@ -2267,24 +2330,26 @@ nsPluginHost::WritePluginInfo()
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mFullPath.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mVersion.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
-    // lastModifiedTimeStamp|canUnload|tag->mFlags
-    PR_fprintf(fd, "%lld%c%d%c%lu%c%c\n",
+    // lastModifiedTimeStamp|canUnload|tag->mFlags|fromExtension
+    PR_fprintf(fd, "%lld%c%d%c%lu%c%d%c%c\n",
       tag->mLastModifiedTime,
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       false, // did store whether or not to unload in-process plugins
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       0, // legacy field for flags
       PLUGIN_REGISTRY_FIELD_DELIMITER,
+      tag->IsFromExtension(),
+      PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER);
 
     //description, name & mtypecount are on separate line
     PR_fprintf(fd, "%s%c%c\n%s%c%c\n%d\n",
       (tag->mDescription.get()),
       PLUGIN_REGISTRY_FIELD_DELIMITER,
       PLUGIN_REGISTRY_END_OF_LINE_MARKER,
       (tag->mName.get()),
@@ -2481,30 +2546,33 @@ nsPluginHost::ReadPluginInfo()
 
     // If this is a registry from a different architecture then don't attempt to read it
     if (PL_strcmp(archValues[1], arch.get())) {
       return rv;
     }
   }
 
   // Registry v0.13 and upwards includes the list of invalid plugins
-  bool hasInvalidPlugins = (version >= "0.13");
+  const bool hasInvalidPlugins = (version >= "0.13");
 
   // Registry v0.16 and upwards always have 0 for their plugin flags, prefs are used instead
   const bool hasValidFlags = (version < "0.16");
 
+  // Registry v0.17 and upwards store whether the plugin comes from an XPI.
+  const bool hasFromExtension = (version >= "0.17");
+
+#if defined(XP_MACOSX)
+  const bool hasFullPathInFileNameField = false;
+#else
+  const bool hasFullPathInFileNameField = (version < "0.11");
+#endif
+
   if (!ReadSectionHeader(reader, "PLUGINS"))
     return rv;
 
-#if defined(XP_MACOSX)
-  bool hasFullPathInFileNameField = false;
-#else
-  bool hasFullPathInFileNameField = (version < "0.11");
-#endif
-
   while (reader.NextLine()) {
     const char *filename;
     const char *fullpath;
     nsAutoCString derivedFileName;
 
     if (hasInvalidPlugins && *reader.LinePtr() == '[') {
       break;
     }
@@ -2540,23 +2608,28 @@ nsPluginHost::ReadPluginInfo()
     if (regHasVersion) {
       version = reader.LinePtr();
       if (!reader.NextLine())
         return rv;
     } else {
       version = "0";
     }
 
-    // lastModifiedTimeStamp|canUnload|tag.mFlag
-    if (reader.ParseLine(values, 3) != 3)
+    // lastModifiedTimeStamp|canUnload|tag.mFlag|fromExtension
+    const int count = hasFromExtension ? 4 : 3;
+    if (reader.ParseLine(values, count) != count)
       return rv;
 
     // If this is an old plugin registry mark this plugin tag to be refreshed
     int64_t lastmod = (vdiff == 0) ? nsCRT::atoll(values[0]) : -1;
     uint32_t tagflag = atoi(values[2]);
+    bool fromExtension = false;
+    if (hasFromExtension) {
+      fromExtension = atoi(values[3]);
+    }
     if (!reader.NextLine())
       return rv;
 
     char *description = reader.LinePtr();
     if (!reader.NextLine())
       return rv;
 
 #if MOZ_WIDGET_ANDROID
@@ -2617,17 +2690,17 @@ nsPluginHost::ReadPluginInfo()
     nsRefPtr<nsPluginTag> tag = new nsPluginTag(name,
       description,
       filename,
       fullpath,
       version,
       (const char* const*)mimetypes,
       (const char* const*)mimedescriptions,
       (const char* const*)extensions,
-      mimetypecount, lastmod, true);
+      mimetypecount, lastmod, fromExtension, true);
     if (heapalloced)
       delete [] heapalloced;
 
     // Import flags from registry into prefs for old registry versions
     if (hasValidFlags && !pluginStateImported) {
       tag->ImportFlagsToPrefs(tagflag);
     }
 
--- a/dom/plugins/base/nsPluginTags.cpp
+++ b/dom/plugins/base/nsPluginTags.cpp
@@ -25,16 +25,19 @@ using namespace mozilla;
 // These legacy flags are used in the plugin registry. The states are now
 // stored in prefs, but we still need to be able to import them.
 #define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
 // no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
 // no longer used                   0x0008    // reuse only if regenerating pluginreg.dat
 #define NS_PLUGIN_FLAG_CLICKTOPLAY  0x0020    // this is a click-to-play plugin
 
+static const char kPrefDefaultEnabledState[] = "plugin.default.state";
+static const char kPrefDefaultEnabledStateXpi[] = "plugin.defaultXpi.state";
+
 inline char* new_str(const char* str)
 {
   if (str == nullptr)
     return nullptr;
   
   char* result = new char[strlen(str) + 1];
   if (result != nullptr)
     return strcpy(result, str);
@@ -57,29 +60,32 @@ MakePrefNameForPlugin(const char* const 
 static nsCString
 GetStatePrefNameForPlugin(nsPluginTag* aTag)
 {
   return MakePrefNameForPlugin("state", aTag);
 }
 
 /* nsPluginTag */
 
-nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime)
+nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
+                         int64_t aLastModifiedTime,
+                         bool fromExtension)
   : mName(aPluginInfo->fName),
     mDescription(aPluginInfo->fDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aPluginInfo->fFileName),
     mFullPath(aPluginInfo->fFullPath),
     mVersion(aPluginInfo->fVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aPluginInfo->fMimeTypeArray,
            aPluginInfo->fMimeDescriptionArray,
            aPluginInfo->fExtensionArray,
            aPluginInfo->fVariantCount);
   EnsureMembersAreUTF8();
   FixupVersion();
 }
@@ -89,29 +95,31 @@ nsPluginTag::nsPluginTag(const char* aNa
                          const char* aFileName,
                          const char* aFullPath,
                          const char* aVersion,
                          const char* const* aMimeTypes,
                          const char* const* aMimeDescriptions,
                          const char* const* aExtensions,
                          int32_t aVariants,
                          int64_t aLastModifiedTime,
+                         bool fromExtension,
                          bool aArgsAreUTF8)
   : mName(aName),
     mDescription(aDescription),
     mLibrary(nullptr),
     mIsJavaPlugin(false),
     mIsFlashPlugin(false),
     mFileName(aFileName),
     mFullPath(aFullPath),
     mVersion(aVersion),
     mLastModifiedTime(aLastModifiedTime),
     mNiceFileName(),
     mCachedBlocklistState(nsIBlocklistService::STATE_NOT_BLOCKED),
-    mCachedBlocklistStateValid(false)
+    mCachedBlocklistStateValid(false),
+    mIsFromExtension(fromExtension)
 {
   InitMime(aMimeTypes, aMimeDescriptions, aExtensions,
            static_cast<uint32_t>(aVariants));
   if (!aArgsAreUTF8)
     EnsureMembersAreUTF8();
   FixupVersion();
 }
 
@@ -360,18 +368,20 @@ nsPluginTag::GetEnabledState(uint32_t *a
                                     &enabledState);
   if (NS_SUCCEEDED(rv) &&
       enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return rv;
   }
 
-  enabledState = Preferences::GetInt("plugin.default.state",
-                                     nsIPluginTag::STATE_ENABLED);
+  const char* const pref = mIsFromExtension ? kPrefDefaultEnabledStateXpi
+                                            : kPrefDefaultEnabledState;
+
+  enabledState = Preferences::GetInt(pref, nsIPluginTag::STATE_ENABLED);
   if (enabledState >= nsIPluginTag::STATE_DISABLED &&
       enabledState <= nsIPluginTag::STATE_ENABLED) {
     *aEnabledState = (uint32_t)enabledState;
     return NS_OK;
   }
 
   return NS_ERROR_UNEXPECTED;
 }
@@ -569,8 +579,13 @@ nsPluginTag::InvalidateBlocklistState()
 
 NS_IMETHODIMP
 nsPluginTag::GetLastModifiedTime(PRTime* aLastModifiedTime)
 {
   MOZ_ASSERT(aLastModifiedTime);
   *aLastModifiedTime = mLastModifiedTime;
   return NS_OK;
 }
+
+bool nsPluginTag::IsFromExtension() const
+{
+  return mIsFromExtension;
+}
--- a/dom/plugins/base/nsPluginTags.h
+++ b/dom/plugins/base/nsPluginTags.h
@@ -31,27 +31,30 @@ public:
   // These must match the STATE_* values in nsIPluginTag.idl
   enum PluginState {
     ePluginState_Disabled = 0,
     ePluginState_Clicktoplay = 1,
     ePluginState_Enabled = 2,
     ePluginState_MaxValue = 3,
   };
 
-  nsPluginTag(nsPluginInfo* aPluginInfo, int64_t aLastModifiedTime);
+  nsPluginTag(nsPluginInfo* aPluginInfo,
+              int64_t aLastModifiedTime,
+              bool fromExtension);
   nsPluginTag(const char* aName,
               const char* aDescription,
               const char* aFileName,
               const char* aFullPath,
               const char* aVersion,
               const char* const* aMimeTypes,
               const char* const* aMimeDescriptions,
               const char* const* aExtensions,
               int32_t aVariants,
               int64_t aLastModifiedTime,
+              bool fromExtension,
               bool aArgsAreUTF8 = false);
   virtual ~nsPluginTag();
 
   void TryUnloadPlugin(bool inShutdown);
 
   // plugin is enabled and not blocklisted
   bool IsActive();
 
@@ -64,16 +67,18 @@ public:
   void SetPluginState(PluginState state);
 
   // import legacy flags from plugin registry into the preferences
   void ImportFlagsToPrefs(uint32_t flag);
 
   bool HasSameNameAndMimes(const nsPluginTag *aPluginTag) const;
   nsCString GetNiceFileName();
 
+  bool IsFromExtension() const;
+
   nsRefPtr<nsPluginTag> mNext;
   nsCString     mName; // UTF-8
   nsCString     mDescription; // UTF-8
   nsTArray<nsCString> mMimeTypes; // UTF-8
   nsTArray<nsCString> mMimeDescriptions; // UTF-8
   nsTArray<nsCString> mExtensions; // UTF-8
   PRLibrary     *mLibrary;
   nsRefPtr<nsNPAPIPlugin> mPlugin;
@@ -87,16 +92,17 @@ public:
 
   uint32_t      GetBlocklistState();
   void          InvalidateBlocklistState();
 
 private:
   nsCString     mNiceFileName; // UTF-8
   uint16_t      mCachedBlocklistState;
   bool          mCachedBlocklistStateValid;
+  bool          mIsFromExtension;
 
   void InitMime(const char* const* aMimeTypes,
                 const char* const* aMimeDescriptions,
                 const char* const* aExtensions,
                 uint32_t aVariantCount);
   nsresult EnsureMembersAreUTF8();
   void FixupVersion();
 };
--- a/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
+++ b/dom/plugins/ipc/hangui/PluginHangUIChild.cpp
@@ -304,16 +304,17 @@ PluginHangUIChild::HangUIDlgProc(HWND aD
           break;
         default:
           break;
       }
       break;
     }
     case WM_DESTROY: {
       EnableWindow(mParentWindow, TRUE);
+      SetForegroundWindow(mParentWindow);
       break;
     }
     default:
       break;
   }
   return FALSE;
 }
 
--- a/dom/plugins/test/mochitest/chrome.ini
+++ b/dom/plugins/test/mochitest/chrome.ini
@@ -14,16 +14,19 @@ skip-if = toolkit != "cocoa"
 [test_crash_notify.xul]
 skip-if = !crashreporter
 [test_crash_notify_no_report.xul]
 skip-if = !crashreporter
 [test_crash_submit.xul]
 skip-if = !crashreporter
 [test_hang_submit.xul]
 skip-if = !crashreporter
+[test_hangui.xul]
+skip-if = (!crashreporter) || (os != "win")
+support-files = hangui_subpage.html hangui_common.js hangui_iface.js dialog_watcher.js
 [test_idle_hang.xul]
 skip-if = (!crashreporter) || (os != "win")
 [test_npruntime.xul]
 [test_plugin_tag_clicktoplay.html]
 [test_privatemode_perwindowpb.xul]
 [test_refresh_navigator_plugins.html]
 [test_xulbrowser_plugin_visibility.xul]
 skip-if = (toolkit == "cocoa") || (os == "win")
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/dialog_watcher.js
@@ -0,0 +1,172 @@
+const EVENT_OBJECT_SHOW = 0x8002;
+const EVENT_OBJECT_HIDE = 0x8003;
+const WINEVENT_OUTOFCONTEXT = 0;
+const WINEVENT_SKIPOWNPROCESS = 2;
+const QS_ALLINPUT = 0x04FF;
+const INFINITE = 0xFFFFFFFF;
+const WAIT_OBJECT_0 = 0;
+const WAIT_TIMEOUT = 258;
+const PM_NOREMOVE = 0;
+
+function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
+  this.titleText = titleText;
+  this.onDialogStart = onDialogStart;
+  this.onDialogEnd = onDialogEnd;
+}
+
+DialogWatcher.prototype.init = function() {
+  this.hwnd = undefined;
+  if (!this.user32) {
+    this.user32 = ctypes.open("user32.dll");
+  }
+  if (!this.findWindow) {
+    this.findWindow = user32.declare("FindWindowW",
+                                     ctypes.winapi_abi,
+                                     ctypes.uintptr_t,
+                                     ctypes.jschar.ptr,
+                                     ctypes.jschar.ptr);
+  }
+  if (!this.winEventProcType) {
+    this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
+                                                ctypes.void_t,
+                                                [ctypes.uintptr_t,
+                                                ctypes.uint32_t,
+                                                ctypes.uintptr_t,
+                                                ctypes.long,
+                                                ctypes.long,
+                                                ctypes.uint32_t,
+                                                ctypes.uint32_t]).ptr;
+  }
+  if (!this.setWinEventHook) {
+    this.setWinEventHook = user32.declare("SetWinEventHook",
+                                          ctypes.winapi_abi,
+                                          ctypes.uintptr_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uintptr_t,
+                                          this.winEventProcType,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t,
+                                          ctypes.uint32_t);
+  }
+  if (!this.unhookWinEvent) {
+    this.unhookWinEvent = user32.declare("UnhookWinEvent",
+                                         ctypes.winapi_abi,
+                                         ctypes.int,
+                                         ctypes.uintptr_t);
+  }
+  if (!this.pointType) {
+    this.pointType = ctypes.StructType("tagPOINT",
+                                       [ { "x": ctypes.long },
+                                         { "y": ctypes.long } ] );
+  }
+  if (!this.msgType) {
+    this.msgType = ctypes.StructType("tagMSG",
+                                     [ { "hwnd": ctypes.uintptr_t },
+                                       { "message": ctypes.uint32_t },
+                                       { "wParam": ctypes.uintptr_t },
+                                       { "lParam": ctypes.intptr_t },
+                                       { "time": ctypes.uint32_t },
+                                       { "pt": this.pointType } ] );
+  }
+  if (!this.peekMessage) {
+    this.peekMessage = user32.declare("PeekMessageW",
+                                      ctypes.winapi_abi,
+                                      ctypes.int,
+                                      this.msgType.ptr,
+                                      ctypes.uintptr_t,
+                                      ctypes.uint32_t,
+                                      ctypes.uint32_t,
+                                      ctypes.uint32_t);
+  }
+  if (!this.msgWaitForMultipleObjects) {
+    this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
+                                                    ctypes.winapi_abi,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uintptr_t.ptr,
+                                                    ctypes.int,
+                                                    ctypes.uint32_t,
+                                                    ctypes.uint32_t);
+  }
+  if (!this.getWindowTextW) {
+    this.getWindowTextW = user32.declare("GetWindowTextW",
+                                         ctypes.winapi_abi,
+                                         ctypes.int,
+                                         ctypes.uintptr_t,
+                                         ctypes.jschar.ptr,
+                                         ctypes.int);
+  }
+};
+
+DialogWatcher.prototype.getWindowText = function(hwnd) {
+  var bufType = ctypes.ArrayType(ctypes.jschar);
+  var buffer = new bufType(256);
+  
+  if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
+    return buffer.readString();
+  }
+};
+
+DialogWatcher.prototype.processWindowEvents = function(timeout) {
+  var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
+    var nhwnd = Number(hwnd)
+    if (event == EVENT_OBJECT_SHOW) {
+      if (nhwnd == self.hwnd) {
+        // We've already picked up this event via FindWindow
+        return;
+      }
+      var windowText = self.getWindowText(hwnd);
+      if (windowText == self.titleText && self.onDialogStart) {
+        self.hwnd = nhwnd;
+        self.onDialogStart(nhwnd);
+      }
+    } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
+      self.onDialogEnd();
+      self.hwnd = null;
+    }
+  };
+  var self = this;
+  var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
+                                                idChild, dwEventThread,
+                                                dwmsEventTime) {
+      onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
+                 dwmsEventTime);
+    } );
+  var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
+                                  0, callback, 0, 0,
+                                  WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
+  if (!hook) {
+    return;
+  }
+  // Check if the window is already showing
+  var hwnd = this.findWindow(null, this.titleText);
+  if (hwnd && hwnd > 0) {
+    this.hwnd = Number(hwnd);
+    if (this.onDialogStart) {
+      this.onDialogStart(this.hwnd);
+    }
+  }
+
+  if (!timeout) {
+    timeout = INFINITE;
+  }
+
+  var waitStatus = WAIT_OBJECT_0;
+  var expectingStart = this.onDialogStart && this.hwnd === undefined;
+  while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
+    waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
+                                                            INFINITE : timeout, 0);
+    if (waitStatus == WAIT_OBJECT_0) {
+      var msg = new this.msgType;
+      this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
+    } else if (waitStatus == WAIT_TIMEOUT) {
+      break;
+    }
+  }
+
+  this.unhookWinEvent(hook);
+  // Returns true if the hook was successful, something was found, and we never timed out
+  return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_common.js
@@ -0,0 +1,20 @@
+// Plugin Hang UI constants
+const HANGUIOP_NOTHING = 0;
+const HANGUIOP_CANCEL = 1;
+const HANGUIOP_COMMAND = 2;
+const IDC_CONTINUE = 1001;
+const IDC_STOP = 1002;
+const IDC_NOFUTURE = 1003;
+
+// Windows constants
+const WM_CLOSE = 0x0010;
+const WM_COMMAND = 0x0111;
+const BM_GETCHECK = 0x00F0;
+const BM_SETCHECK = 0x00F1;
+const BN_CLICKED = 0;
+const BST_CHECKED = 1;
+
+// Test-specific constants
+const EPSILON_MS = 1000;
+const STALL_DURATION = 2;
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_iface.js
@@ -0,0 +1,121 @@
+var user32;
+var sendMessage;
+var getDlgItem;
+var messageBox;
+var watcher;
+
+importScripts("hangui_common.js");
+importScripts("dialog_watcher.js");
+
+function initCTypes() {
+  if (!user32) {
+    user32 = ctypes.open("user32.dll");
+  }
+  if (!getDlgItem) {
+    getDlgItem = user32.declare("GetDlgItem",
+                                ctypes.winapi_abi,
+                                ctypes.uintptr_t,
+                                ctypes.uintptr_t,
+                                ctypes.int);
+  }
+  if (!sendMessage) {
+    sendMessage = user32.declare("SendMessageW",
+                                 ctypes.winapi_abi,
+                                 ctypes.intptr_t,
+                                 ctypes.uintptr_t,
+                                 ctypes.uint32_t,
+                                 ctypes.uintptr_t,
+                                 ctypes.intptr_t);
+  }
+  if (!messageBox) {
+    // Handy for debugging the test itself
+    messageBox = user32.declare("MessageBoxW",
+                                ctypes.winapi_abi,
+                                ctypes.int,
+                                ctypes.uintptr_t,
+                                ctypes.jschar.ptr,
+                                ctypes.jschar.ptr,
+                                ctypes.uint32_t);
+  }
+  if (!watcher) {
+    watcher = new DialogWatcher("Warning: Unresponsive plugin");
+  }
+}
+
+function postSuccess(params) {
+  self.postMessage({"status": true, "params": params});
+}
+
+function postFail(params, msg) {
+  self.postMessage({"status": false, "params": params, "msg": msg});
+}
+
+function onDialogStart(inparams, hwnd) {
+  var params = Object.create(inparams);
+  params.testName += " (Start)";
+  params.callback = null;
+  if (!params.expectToFind) {
+    postFail(params, "Dialog showed when we weren't expecting it to!");
+    return;
+  }
+  if (params.opCode == HANGUIOP_CANCEL) {
+    sendMessage(hwnd, WM_CLOSE, 0, 0);
+  } else if (params.opCode == HANGUIOP_COMMAND) {
+    if (params.check) {
+      var checkbox = getDlgItem(hwnd, IDC_NOFUTURE);
+      if (!checkbox) {
+        postFail(params, "Couldn't find checkbox");
+        return;
+      }
+      sendMessage(checkbox, BM_SETCHECK, BST_CHECKED, 0);
+      sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | IDC_NOFUTURE, checkbox);
+    }
+    var button = getDlgItem(hwnd, params.commandId);
+    if (!button) {
+      postFail(params,
+               "GetDlgItem failed to find button with ID " + params.commandId);
+      return;
+    }
+    sendMessage(hwnd, WM_COMMAND, (BN_CLICKED << 16) | params.commandId, button);
+  }
+  postSuccess(params);
+}
+
+function onDialogEnd(inparams) {
+  var params = Object.create(inparams);
+  params.testName += " (End)";
+  params.callback = inparams.callback;
+  postSuccess(params);
+}
+
+self.onmessage = function(event) {
+  initCTypes();
+  watcher.init();
+  var params = event.data;
+  var timeout = params.timeoutMs;
+  if (params.expectToFind) {
+    watcher.onDialogStart = function(hwnd) { onDialogStart(params, hwnd); };
+    if (params.expectToClose) {
+      watcher.onDialogEnd = function() { onDialogEnd(params); };
+    }
+  } else {
+    watcher.onDialogStart = null;
+    watcher.onDialogEnd = null;
+  }
+  var result = watcher.processWindowEvents(timeout);
+  if (result === null) {
+    postFail(params, "Hook failed");
+  } else if (!result) {
+    if (params.expectToFind) {
+      postFail(params, "The dialog didn't show but we were expecting it to");
+    } else {
+      postSuccess(params);
+    }
+  }
+}
+
+self.onerror = function(event) {
+  var msg = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+  postFail(null, msg);
+};
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/hangui_subpage.html
@@ -0,0 +1,4 @@
+<html>
+<body onload="window.parent.frameLoaded()">
+  <embed id="plugin1" type="application/x-test" width="400" height="400"></embed>
+
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/mochitest/test_hangui.xul
@@ -0,0 +1,263 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
+                 type="text/css"?>
+<window title="Basic Plugin Tests"
+  xmlns:html="http://www.w3.org/1999/xhtml"
+  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+  <title>Plugin Hang UI Test</title>
+  <script type="application/javascript"
+          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
+  <script type="application/javascript"
+          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
+  <script type="application/javascript"
+          src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hangui_common.js" />
+
+<body xmlns="http://www.w3.org/1999/xhtml">
+  <iframe id="iframe1" src="hangui_subpage.html" width="400" height="400"></iframe>
+</body>
+<script class="testbody" type="application/javascript">
+<![CDATA[
+SimpleTest.waitForExplicitFinish();
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+const hangUITimeoutPref = "dom.ipc.plugins.hangUITimeoutSecs";
+const hangUIMinDisplayPref = "dom.ipc.plugins.hangUIMinDisplaySecs";
+const timeoutPref = "dom.ipc.plugins.timeoutSecs";
+
+var worker = new ChromeWorker("hangui_iface.js");
+worker.onmessage = function(event) {
+  var result = event.data;
+  var params = result.params;
+  var output = params.testName;
+  if (result.msg) {
+    output += ": " + result.msg;
+  }
+  ok(result.status, output);
+  if (params.callback) {
+    var cb = eval(params.callback);
+    var timeout = setTimeout(function() { clearTimeout(timeout); cb(); }, 100);
+  }
+};
+worker.onerror = function(event) {
+  var output = "Error: " + event.message + " at " + event.filename + ":" + event.lineno;
+  ok(false, output);
+};
+
+var iframe;
+var p;
+var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+
+function hanguiOperation(testName, timeoutSec, expectFind, expectClose, opCode,
+                         commandId, check, cb) {
+  var timeoutMs = timeoutSec * 1000 + EPSILON_MS;
+  worker.postMessage({ "timeoutMs": timeoutMs, "expectToFind": expectFind,
+                       "expectToClose": expectClose, "opCode": opCode,
+                       "commandId": commandId, "check": check,
+                       "testName": testName, "callback": cb });
+}
+
+function hanguiExpect(testName, shouldBeShowing, shouldClose, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  if (!shouldBeShowing && !timeoutSec) {
+    timeoutSec = Services.prefs.getIntPref(timeoutPref);
+  }
+  hanguiOperation(testName, timeoutSec, shouldBeShowing, shouldClose, HANGUIOP_NOTHING, 0, false, cb);
+}
+
+function hanguiContinue(testName, check, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_CONTINUE, check, cb);
+}
+
+function hanguiStop(testName, check, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_COMMAND, IDC_STOP, check, cb);
+}
+
+function hanguiCancel(testName, cb) {
+  var timeoutSec = Services.prefs.getIntPref(hangUITimeoutPref);
+  hanguiOperation(testName, timeoutSec, true, true, HANGUIOP_CANCEL, 0, false, cb);
+}
+
+function finishTest() {
+  if (obsCount > 0) {
+    os.removeObserver(testObserver, "plugin-crashed");
+    --obsCount;
+  }
+  SpecialPowers.clearUserPref(hangUITimeoutPref);
+  SpecialPowers.clearUserPref(hangUIMinDisplayPref);
+  SpecialPowers.clearUserPref(timeoutPref);
+  SimpleTest.finish();
+}
+
+function runTests() {
+  if (!SimpleTest.testPluginIsOOP()) {
+    ok(true, "Skipping this test when test plugin is not OOP.");
+    SimpleTest.finish();
+  }
+
+  resetVars();
+
+  hanguiExpect("Prime ChromeWorker", false, false, "test1");
+}
+
+window.frameLoaded = runTests;
+
+var obsCount = 0;
+
+function onPluginCrashedHangUI(aEvent) {
+  ok(true, "Plugin crashed notification received");
+  is(aEvent.type, "PluginCrashed", "event is correct type");
+
+  is(p, aEvent.target, "Plugin crashed event target is plugin element");
+
+  ok(aEvent instanceof Components.interfaces.nsIDOMCustomEvent,
+     "plugin crashed event has the right interface");
+
+  var propBag = aEvent.detail.QueryInterface(Components.interfaces.nsIPropertyBag2);
+  var pluginDumpID = propBag.getPropertyAsAString("pluginDumpID");
+  isnot(pluginDumpID, "", "got a non-empty dump ID");
+  var pluginName = propBag.getPropertyAsAString("pluginName");
+  is(pluginName, "Test Plug-in", "got correct plugin name");
+  var pluginFilename = propBag.getPropertyAsAString("pluginFilename");
+  isnot(pluginFilename, "", "got a non-empty filename");
+  var didReport = propBag.getPropertyAsBool("submittedCrashReport");
+  // The app itself may or may not have decided to submit the report, so
+  // allow either true or false here.
+  ok((didReport == true || didReport == false), "event said crash report was submitted");
+  os.removeObserver(testObserver, "plugin-crashed");
+  --obsCount;
+}
+
+function resetVars() {
+  iframe = document.getElementById('iframe1');
+  p = iframe.contentDocument.getElementById("plugin1");
+  if (obsCount == 0) {
+    os.addObserver(testObserver, "plugin-crashed", true);
+    ++obsCount;
+  }
+  iframe.contentDocument.addEventListener("PluginCrashed",
+                                          onPluginCrashedHangUI,
+                                          false);
+}
+
+function test9b() {
+  hanguiExpect("test9b: Plugin Hang UI is not showing (checkbox)", false);
+  p.stall(STALL_DURATION);
+  hanguiExpect("test9b: Plugin Hang UI is still not showing (checkbox)", false, false, "finishTest");
+  p.stall(STALL_DURATION);
+}
+
+function test9a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 45);
+  hanguiContinue("test9a: Continue button works with checkbox", true, "test9b");
+  p.stall(STALL_DURATION);
+}
+
+function test9() {
+  window.frameLoaded = test9a;
+  iframe.contentWindow.location.reload();
+}
+
+function test8a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 4);
+  hanguiExpect("test8a: Plugin Hang UI is not showing (disabled due to hangUIMinDisplaySecs)", false, false, "test9");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test8a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test8() {
+  window.frameLoaded = test8a;
+  iframe.contentWindow.location.reload();
+}
+
+function test7a() {
+  resetVars();
+  SpecialPowers.setIntPref(hangUITimeoutPref, 0);
+  hanguiExpect("test7a: Plugin Hang UI is not showing (disabled)", false, false, "test8");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test7a: Exception thrown from hang() when plugin was terminated");
+}
+
+function test7() {
+  window.frameLoaded = test7a;
+  iframe.contentWindow.location.reload();
+}
+
+function test6() {
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 3);
+  hanguiExpect("test6: Plugin Hang UI is showing", true, true, "test7");
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test6: Exception thrown from hang() when plugin was terminated (child timeout)");
+}
+
+function test5a() {
+  resetVars();
+  hanguiCancel("test5a: Close button works", "test6");
+  p.stall(STALL_DURATION);
+}
+
+function test5() {
+  window.frameLoaded = test5a;
+  iframe.contentWindow.location.reload();
+}
+
+function test4() {
+  hanguiStop("test4: Stop button works", false, "test5");
+  // We'll get an exception here because the plugin was terminated
+  var exceptionThrown = false;
+  try {
+    p.hang();
+  } catch(e) {
+    exceptionThrown = true;
+  }
+  ok(exceptionThrown, "test4: Exception thrown from hang() when plugin was terminated");
+}
+
+function test3() {
+  hanguiContinue("test3: Continue button works", false, "test4");
+  p.stall(STALL_DURATION);
+}
+
+function test2() {
+  // This test is identical to test1 because there were some bugs where the 
+  // Hang UI would show on the first hang but not on subsequent hangs
+  hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
+  p.stall(STALL_DURATION);
+}
+
+function test1() {
+  SpecialPowers.setIntPref(hangUITimeoutPref, 1);
+  SpecialPowers.setIntPref(hangUIMinDisplayPref, 1);
+  SpecialPowers.setIntPref(timeoutPref, 45);
+  hanguiExpect("test1: Plugin Hang UI is showing", true, true, "test2");
+  p.stall(STALL_DURATION);
+}
+
+]]>
+</script>
+</window>
--- a/dom/plugins/test/moz.build
+++ b/dom/plugins/test/moz.build
@@ -1,14 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIRS += ['testplugin']
+DIRS += ['testplugin', 'testaddon']
 
 XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows'):
     MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini']
     MOCHITEST_CHROME_MANIFESTS += ['mochitest/chrome.ini']
 
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/Makefile.in
@@ -0,0 +1,23 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+include $(topsrcdir)/config/rules.mk
+
+ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
+plugin_file_name = Test.plugin
+addon_file_name = testaddon_$(TARGET_XPCOM_ABI).xpi
+else
+plugin_file_name = $(DLL_PREFIX)nptest$(DLL_SUFFIX)
+addon_file_name = testaddon.xpi
+endif
+
+# This is so hacky. Waiting on bug 988938.
+testdir = $(abspath $(DEPTH)/_tests/xpcshell/dom/plugins/test/unit/)
+addonpath = $(testdir)/$(addon_file_name)
+
+libs::
+	$(NSINSTALL) -D $(testdir)
+	rm -f $(addonpath)
+	cd $(srcdir) && zip -rD $(addonpath) install.rdf
+	cd $(DIST) && zip -rD $(addonpath) plugins/$(plugin_file_name)
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/install.rdf
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>test-plugin-from-xpi@tests.mozilla.org</em:id>
+    <em:version>1</em:version>
+    <em:name>Test plugin from XPI</em:name>
+    <em:description>This tests shipping a plugin through an extensions.</em:description>
+
+    <em:targetApplication>
+      <Description>
+        <em:id>toolkit@mozilla.org</em:id>
+        <em:minVersion>0</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <em:unpack>true</em:unpack>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/testaddon/moz.build
@@ -0,0 +1,5 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
--- a/dom/plugins/test/testplugin/nptest.cpp
+++ b/dom/plugins/test/testplugin/nptest.cpp
@@ -144,16 +144,17 @@ static bool getJavaCodebase(NPObject* np
 static bool checkObjectValue(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool enableFPExceptions(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool setCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getCookie(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getAuthInfo(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool asyncCallbackTest(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool checkGCRace(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool hangPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
+static bool stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool callOnDestroy(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool reinitWidget(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool crashPluginInNestedLoop(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool destroySharedGfxStuff(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool propertyAndMethod(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getTopLevelWindowActivationState(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
 static bool getTopLevelWindowActivationEventCount(NPObject* npobj, const NPVariant* args, uint32_t argCount, NPVariant* result);
@@ -208,16 +209,17 @@ static const NPUTF8* sPluginMethodIdenti
   "checkObjectValue",
   "enableFPExceptions",
   "setCookie",
   "getCookie",
   "getAuthInfo",
   "asyncCallbackTest",
   "checkGCRace",
   "hang",
+  "stall",
   "getClipboardText",
   "callOnDestroy",
   "reinitWidget",
   "crashInNestedLoop",
   "destroySharedGfxStuff",
   "propertyAndMethod",
   "getTopLevelWindowActivationState",
   "getTopLevelWindowActivationEventCount",
@@ -273,16 +275,17 @@ static const ScriptableFunction sPluginM
   checkObjectValue,
   enableFPExceptions,
   setCookie,
   getCookie,
   getAuthInfo,
   asyncCallbackTest,
   checkGCRace,
   hangPlugin,
+  stallPlugin,
   getClipboardText,
   callOnDestroy,
   reinitWidget,
   crashPluginInNestedLoop,
   destroySharedGfxStuff,
   propertyAndMethod,
   getTopLevelWindowActivationState,
   getTopLevelWindowActivationEventCount,
@@ -3350,16 +3353,34 @@ hangPlugin(NPObject* npobj, const NPVari
 
   // NB: returning true here means that we weren't terminated, and
   // thus the hang detection/handling didn't work correctly.  The
   // test harness will succeed in calling this function, and the
   // test will fail.
   return true;
 }
 
+bool
+stallPlugin(NPObject* npobj, const NPVariant* args, uint32_t argCount,
+           NPVariant* result)
+{
+  uint32_t stallTimeSeconds = 0;
+  if ((argCount == 1) && NPVARIANT_IS_INT32(args[0])) {
+    stallTimeSeconds = (uint32_t) NPVARIANT_TO_INT32(args[0]);
+  }
+
+#ifdef XP_WIN
+  Sleep(stallTimeSeconds * 1000U);
+#else
+  sleep(stallTimeSeconds);
+#endif
+
+  return true;
+}
+
 #if defined(MOZ_WIDGET_GTK)
 bool
 getClipboardText(NPObject* npobj, const NPVariant* args, uint32_t argCount,
                  NPVariant* result)
 {
   NPP npp = static_cast<TestNPObject*>(npobj)->npp;
   InstanceData* id = static_cast<InstanceData*>(npp->pdata);
   string sel = pluginGetClipboardText(id);
--- a/dom/plugins/test/unit/head_plugins.js
+++ b/dom/plugins/test/unit/head_plugins.js
@@ -1,20 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
-const Cc = Components.classes;
-const Ci = Components.interfaces;
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Promise.jsm");
 
 const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
 const gIsOSX = ("nsILocalFileMac" in Ci);
 const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
   ("@mozilla.org/gio-service;1" in Cc);
+const gDirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
 
 // Finds the test plugin library
 function get_test_plugin() {
   var pluginEnum = gDirSvc.get("APluginsDL", Ci.nsISimpleEnumerator);
   while (pluginEnum.hasMoreElements()) {
     let dir = pluginEnum.getNext().QueryInterface(Ci.nsILocalFile);
     let plugin = dir.clone();
     // OSX plugin
@@ -37,17 +39,17 @@ function get_test_plugin() {
       plugin.normalize();
       return plugin;
     }
   }
   return null;
 }
 
 // Finds the test nsIPluginTag
-function get_test_plugintag(aName) {
+function get_test_plugintag(aName="Test Plug-in") {
   const Cc = Components.classes;
   const Ci = Components.interfaces;
 
   var name = aName || "Test Plug-in";
   var host = Cc["@mozilla.org/plugin/host;1"].
              getService(Ci.nsIPluginHost);
   var tags = host.getPluginTags();
 
@@ -114,8 +116,84 @@ function get_test_plugin_no_symlink() {
     let plugin = dir.clone();
     plugin.append(get_platform_specific_plugin_name());
     if (plugin.exists()) {
       return plugin;
     }
   }
   return null;
 }
+
+let gGlobalScope = this;
+function loadAddonManager() {
+  let ns = {};
+  Cu.import("resource://gre/modules/Services.jsm", ns);
+  let head = "../../../../toolkit/mozapps/extensions/test/xpcshell/head_addons.js";
+  let file = do_get_file(head);
+  let uri = ns.Services.io.newFileURI(file);
+  ns.Services.scriptloader.loadSubScript(uri.spec, gGlobalScope);
+  createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
+  startupManager();
+}
+
+// Install addon and return a Promise<boolean> that is
+// resolve with true on success, false otherwise.
+function installAddon(relativePath) {
+  let deferred = Promise.defer();
+  let success = () => deferred.resolve(true);
+  let fail = () => deferred.resolve(false);
+  let listener = {
+    onDownloadCancelled: fail,
+    onDownloadFailed: fail,
+    onInstallCancelled: fail,
+    onInstallFailed: fail,
+    onInstallEnded: success,
+  };
+
+  let installCallback = install => {
+    install.addListener(listener);
+    install.install();
+  };
+
+  let file = do_get_file(relativePath, false);
+  AddonManager.getInstallForFile(file, installCallback,
+                                 "application/x-xpinstall");
+
+  return deferred.promise;
+}
+
+// Uninstall addon and return a Promise<boolean> that is
+// resolve with true on success, false otherwise.
+function uninstallAddon(id) {
+  let deferred = Promise.defer();
+
+  AddonManager.getAddonByID(id, addon => {
+    if (!addon) {
+      deferred.resolve(false);
+    }
+
+    let listener = {};
+    let handler = addon => {
+      if (addon.id !== id) {
+        return;
+      }
+
+      AddonManager.removeAddonListener(listener);
+      deferred.resolve(true);
+    };
+
+    listener.onUninstalled = handler;
+    listener.onDisabled = handler;
+
+    AddonManager.addAddonListener(listener);
+    addon.uninstall();
+  });
+
+  return deferred.promise;
+}
+
+// Returns a Promise<Addon> that is resolved with
+// the corresponding addon or rejected.
+function getAddonByID(id) {
+  let deferred = Promise.defer();
+  AddonManager.getAddonByID(id, addon => deferred.resolve(addon));
+  return deferred.promise;
+}
new file mode 100644
--- /dev/null
+++ b/dom/plugins/test/unit/test_plugin_default_state_xpi.js
@@ -0,0 +1,108 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Promise.jsm");
+
+const ADDON_ID = "test-plugin-from-xpi@tests.mozilla.org";
+const XRE_EXTENSIONS_DIR_LIST = "XREExtDL";
+const NS_APP_PLUGINS_DIR_LIST = "APluginsDL";
+
+const gPluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+const gXPCOMABI = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).XPCOMABI;
+let gProfileDir = null;
+
+function getAddonRoot(profileDir, id) {
+  let dir = profileDir.clone();
+  dir.append("extensions");
+  Assert.ok(dir.exists(), "Extensions dir should exist: " + dir.path);
+  dir.append(id);
+  return dir;
+}
+
+function getTestaddonFilename() {
+  let abiPart = "";
+  if (gIsOSX) {
+    abiPart = "_" + gXPCOMABI;
+  }
+  return "testaddon" + abiPart + ".xpi";
+}
+
+function run_test() {
+  loadAddonManager();
+  gProfileDir = do_get_profile();
+  do_register_cleanup(() => shutdownManager());
+  run_next_test();
+}
+
+add_task(function* test_state() {
+  // Remove test so we will have only one "Test Plug-in" registered.
+  // xpcshell tests have plugins in per-test profiles, so that's fine.
+  let file = get_test_plugin();
+  file.remove(true);
+
+  let success = yield installAddon(getTestaddonFilename());
+  Assert.ok(success, "Should have installed addon.");
+  let addonDir = getAddonRoot(gProfileDir, ADDON_ID);
+
+  let provider = {
+    classID: Components.ID("{0af6b2d7-a06c-49b7-babc-636d292b0dbb}"),
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
+                                           Ci.nsIDirectoryServiceProvider2]),
+
+    getFile: function (prop, persistant) {
+      throw Cr.NS_ERROR_FAILURE;
+    },
+
+    getFiles: function (prop) {
+      let result = [];
+
+      switch (prop) {
+      case XRE_EXTENSIONS_DIR_LIST:
+        result.push(addonDir);
+        break;
+      case NS_APP_PLUGINS_DIR_LIST:
+        let pluginDir = addonDir.clone();
+        pluginDir.append("plugins");
+        result.push(pluginDir);
+        break;
+      default:
+        throw Cr.NS_ERROR_FAILURE;
+      }
+
+      return {
+        QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
+        hasMoreElements: () => result.length > 0,
+        getNext: () => result.shift(),
+      };
+    },
+  };
+
+  let dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
+  dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
+
+  // We installed a non-restartless addon, need to restart the manager.
+  restartManager();
+  gPluginHost.reloadPlugins();
+
+  Assert.ok(addonDir.exists(), "Addon path should exist: " + addonDir.path);
+  Assert.ok(addonDir.isDirectory(), "Addon path should be a directory: " + addonDir.path);
+  let pluginDir = addonDir.clone();
+  pluginDir.append("plugins");
+  Assert.ok(pluginDir.exists(), "Addon plugins path should exist: " + pluginDir.path);
+  Assert.ok(pluginDir.isDirectory(), "Addon plugins path should be a directory: " + pluginDir.path);
+
+  let addon = yield getAddonByID(ADDON_ID);
+  Assert.ok(!addon.appDisabled, "Addon should not be appDisabled");
+  Assert.ok(addon.isActive, "Addon should be active");
+  Assert.ok(addon.isCompatible, "Addon should be compatible");
+  Assert.ok(!addon.userDisabled, "Addon should not be user disabled");
+
+  let testPlugin = get_test_plugintag();
+  Assert.notEqual(testPlugin, null, "Test plugin should have been found");
+  Assert.equal(testPlugin.enabledState, Ci.nsIPluginTag.STATE_ENABLED, "Test plugin from addon should have state enabled");
+
+  pluginDir.append(testPlugin.filename);
+  Assert.ok(pluginDir.exists(), "Plugin file should exist in addon directory: " + pluginDir.path);
+});
--- a/dom/plugins/test/unit/xpcshell.ini
+++ b/dom/plugins/test/unit/xpcshell.ini
@@ -12,8 +12,9 @@ fail-if = os == "android"
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_nice_plugin_name.js]
 # Bug 676953: test fails consistently on Android
 fail-if = os == "android"
 [test_persist_in_prefs.js]
 [test_bug854467.js]
 [test_plugin_default_state.js]
+[test_plugin_default_state_xpi.js]
--- a/gfx/thebes/gfxContext.h
+++ b/gfx/thebes/gfxContext.h
@@ -826,24 +826,22 @@ public:
   }
 
   void SetContext(gfxContext *aContext) {
     NS_ASSERTION(!mContext, "Not going to call Restore() on some context!!!");
     mContext = aContext;
     mContext->Save();    
   }
 
-  void Reset(gfxContext *aContext) {
-    // Do the equivalent of destroying and re-creating this object.
-    NS_PRECONDITION(aContext, "must provide a context");
-    if (mContext) {
-      mContext->Restore();
+  void EnsureSaved(gfxContext *aContext) {
+    MOZ_ASSERT(!mContext || mContext == aContext, "wrong context");
+    if (!mContext) {
+        mContext = aContext;
+        mContext->Save();
     }
-    mContext = aContext;
-    mContext->Save();
   }
 
 private:
   gfxContext *mContext;
 };
 
 /**
  * Sentry helper class for functions with multiple return points that need to
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -361,16 +361,17 @@ private:
 
         GROUP2_OP_SHL = 4,
         GROUP2_OP_SHR = 5,
         GROUP2_OP_SAR = 7,
 
         GROUP3_OP_TEST = 0,
         GROUP3_OP_NOT  = 2,
         GROUP3_OP_NEG  = 3,
+        GROUP3_OP_IMUL = 5,
         GROUP3_OP_DIV  = 6,
         GROUP3_OP_IDIV = 7,
 
         GROUP5_OP_INC   = 0,
         GROUP5_OP_DEC   = 1,
         GROUP5_OP_CALLN = 2,
         GROUP5_OP_JMPN  = 4,
         GROUP5_OP_PUSH  = 6,
@@ -1150,16 +1151,23 @@ public:
 #endif
 
     void imull_rr(RegisterID src, RegisterID dst)
     {
         spew("imull      %s, %s", nameIReg(4,src), nameIReg(4, dst));
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, src);
     }
 
+    void imull_r(RegisterID multiplier)
+    {
+        spew("imull      %s",
+             nameIReg(4, multiplier));
+        m_formatter.oneByteOp(OP_GROUP3_Ev, GROUP3_OP_IMUL, multiplier);
+    }
+
     void imull_mr(int offset, RegisterID base, RegisterID dst)
     {
         spew("imull      %s0x%x(%s), %s",
              PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(4,dst));
         m_formatter.twoByteOp(OP2_IMUL_GvEv, dst, base, offset);
     }
 
     void imull_i32r(RegisterID src, int32_t value, RegisterID dst)
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/testDivModWithIntMin.js
@@ -0,0 +1,19 @@
+var intMin = -2147483648;
+
+assertEq(intMin % (-2147483648), -0);
+assertEq(intMin % (-3), -2);
+assertEq(intMin % (-1), -0);
+assertEq(intMin % 1, -0);
+assertEq(intMin % 3, -2);
+assertEq(intMin % 10, -8);
+assertEq(intMin % 2147483647, -1);
+
+assertEq((-2147483648) % (-2147483648), -0);
+for (var i = -10; i <= 10; ++i)
+    assertEq(i % (-2147483648), i);
+assertEq(2147483647 % (-2147483648), 2147483647);
+
+assertEq((-2147483648) / (-2147483648), 1);
+assertEq(0 / (-2147483648), -0);
+assertEq((-2147483648) / (-1), 2147483648);
+assertEq((-0) / (-2147483648), 0);
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -153,17 +153,17 @@ MDefinition::valueHash() const
     for (size_t i = 0, e = numOperands(); i < e; i++) {
         uint32_t valueNumber = getOperand(i)->valueNumber();
         out = valueNumber + (out << 6) + (out << 16) - out;
     }
     return out;
 }
 
 bool
-MDefinition::congruentIfOperandsEqual(MDefinition *ins) const
+MDefinition::congruentIfOperandsEqual(const MDefinition *ins) const
 {
     if (op() != ins->op())
         return false;
 
     if (type() != ins->type())
         return false;
 
     if (isEffectful() || ins->isEffectful())
@@ -486,17 +486,17 @@ MConstant::MConstant(const js::Value &vp
 HashNumber
 MConstant::valueHash() const
 {
     // This disregards some state, since values are 64 bits. But for a hash,
     // it's completely acceptable.
     return (HashNumber)JSVAL_TO_IMPL(value_).asBits;
 }
 bool
-MConstant::congruentTo(MDefinition *ins) const
+MConstant::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isConstant())
         return false;
     return ins->toConstant()->value() == value();
 }
 
 void
 MConstant::printOpcode(FILE *fp) const
@@ -669,17 +669,17 @@ MParameter::printOpcode(FILE *fp) const
 
 HashNumber
 MParameter::valueHash() const
 {
     return index_; // Why not?
 }
 
 bool
-MParameter::congruentTo(MDefinition *ins) const
+MParameter::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isParameter())
         return false;
 
     return ins->toParameter()->index() == index_;
 }
 
 MCall *
@@ -755,25 +755,25 @@ MCallDOMNative::computeMovable()
     JS_ASSERT_IF(jitInfo->isMovable,
                  jitInfo->aliasSet() != JSJitInfo::AliasEverything);
 
     if (jitInfo->isMovable && !isEffectful())
         setMovable();
 }
 
 bool
-MCallDOMNative::congruentTo(MDefinition *ins) const
+MCallDOMNative::congruentTo(const MDefinition *ins) const
 {
     if (!isMovable())
         return false;
 
     if (!ins->isCall())
         return false;
 
-    MCall *call = ins->toCall();
+    const MCall *call = ins->toCall();
 
     if (!call->isCallDOMNative())
         return false;
 
     if (getSingleTarget() != call->getSingleTarget())
         return false;
 
     if (isConstructing() != call->isConstructing())
@@ -976,17 +976,17 @@ MPhi::foldsTo(TempAllocator &alloc, bool
 {
     if (MDefinition *def = operandIfRedundant())
         return def;
 
     return this;
 }
 
 bool
-MPhi::congruentTo(MDefinition *ins) const
+MPhi::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isPhi())
         return false;
     // Since we do not know which predecessor we are merging from, we must
     // assume that phi instructions in different blocks are not equal.
     // (Bug 674656)
     if (ins->block()->id() != block()->id())
         return false;
@@ -2712,69 +2712,69 @@ MNewArray::shouldUseVM() const
     // when mir hints it needs to get allocated immediately,
     // but only when data doesn't fit the available array slots.
     bool allocating = isAllocating() && count() > arraySlots;
 
     return templateObject()->hasSingletonType() || allocating;
 }
 
 bool
-MLoadFixedSlot::mightAlias(MDefinition *store)
+MLoadFixedSlot::mightAlias(const MDefinition *store) const
 {
     if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
         return false;
     return true;
 }
 
 bool
-MAsmJSLoadHeap::mightAlias(MDefinition *def)
+MAsmJSLoadHeap::mightAlias(const MDefinition *def) const
 {
     if (def->isAsmJSStoreHeap()) {
-        MAsmJSStoreHeap *store = def->toAsmJSStoreHeap();
+        const MAsmJSStoreHeap *store = def->toAsmJSStoreHeap();
         if (store->viewType() != viewType())
             return true;
         if (!ptr()->isConstant() || !store->ptr()->isConstant())
             return true;
-        MConstant *otherPtr = store->ptr()->toConstant();
+        const MConstant *otherPtr = store->ptr()->toConstant();
         return ptr()->toConstant()->value() == otherPtr->value();
     }
     return true;
 }
 
 bool
-MAsmJSLoadHeap::congruentTo(MDefinition *ins) const
+MAsmJSLoadHeap::congruentTo(const MDefinition *ins) const
 {
     if (!ins->isAsmJSLoadHeap())
         return false;
-    MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
+    const MAsmJSLoadHeap *load = ins->toAsmJSLoadHeap();
     return load->viewType() == viewType() && congruentIfOperandsEqual(load);
 }
 
 bool
-MAsmJSLoadGlobalVar::mightAlias(MDefinition *def)
+MAsmJSLoadGlobalVar::mightAlias(const MDefinition *def) const
 {
     if (def->isAsmJSStoreGlobalVar()) {
-        MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
+        const MAsmJSStoreGlobalVar *store = def->toAsmJSStoreGlobalVar();
         return store->globalDataOffset() == globalDataOffset_;
     }
     return true;
 }
 
 bool
-MAsmJSLoadGlobalVar::congruentTo(MDefinition *ins) const
+MAsmJSLoadGlobalVar::congruentTo(const MDefinition *ins) const
 {
     if (ins->isAsmJSLoadGlobalVar()) {
-        MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
+        const MAsmJSLoadGlobalVar *load = ins->toAsmJSLoadGlobalVar();
         return globalDataOffset_ == load->globalDataOffset_;
     }
     return false;
 }
 
 bool
-MLoadSlot::mightAlias(MDefinition *store)
+MLoadSlot::mightAlias(const MDefinition *store) const
 {
     if (store->isStoreSlot() && store->toStoreSlot()->slot() != slot())
         return false;
     return true;
 }
 
 void
 InlinePropertyTable::trimTo(ObjectVector &targets, BoolVector &choiceSet)
@@ -2875,26 +2875,26 @@ MGetElementCache::allowDoubleResult() co
 
 size_t
 MStoreTypedArrayElementStatic::length() const
 {
     return typedArray_->byteLength();
 }
 
 bool
-MGetPropertyPolymorphic::mightAlias(MDefinition *store)
+MGetPropertyPolymorphic::mightAlias(const MDefinition *store) const
 {
     // Allow hoisting this instruction if the store does not write to a
     // slot read by this instruction.
 
     if (!store->isStoreFixedSlot() && !store->isStoreSlot())
         return true;
 
     for (size_t i = 0; i < numShapes(); i++) {
-        Shape *shape = this->shape(i);
+        const Shape *shape = this->shape(i);
         if (shape->slot() < shape->numFixedSlots()) {
             // Fixed slot.
             uint32_t slot = shape->slot();
             if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot)
                 continue;
             if (store->isStoreSlot())
                 continue;
         } else {
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -371,20 +371,20 @@ class MDefinition : public MNode
         return range_;
     }
     void setRange(Range *range) {
         JS_ASSERT(type() != MIRType_None);
         range_ = range;
     }
 
     virtual HashNumber valueHash() const;
-    virtual bool congruentTo(MDefinition *ins) const {
+    virtual bool congruentTo(const MDefinition *ins) const {
         return false;
     }
-    bool congruentIfOperandsEqual(MDefinition *ins) const;
+    bool congruentIfOperandsEqual(const MDefinition *ins) const;
     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     virtual void analyzeEdgeCasesForward();
     virtual void analyzeEdgeCasesBackward();
 
     virtual bool truncate();
     virtual bool isOperandTruncated(size_t index) const;
 
     // Compute an absolute or symbolic range for the value of this node.
@@ -579,17 +579,17 @@ class MDefinition : public MNode
     }
     virtual AliasSet getAliasSet() const {
         // Instructions are effectful by default.
         return AliasSet::Store(AliasSet::Any);
     }
     bool isEffectful() const {
         return getAliasSet().isStore();
     }
-    virtual bool mightAlias(MDefinition *store) {
+    virtual bool mightAlias(const MDefinition *store) const {
         // Return whether this load may depend on the specified store, given
         // that the alias sets intersect. This may be refined to exclude
         // possible aliasing in cases where alias set flags are too imprecise.
         JS_ASSERT(!isEffectful() && store->isEffectful());
         JS_ASSERT(getAliasSet().flags() & store->getAliasSet().flags());
         return true;
     }
 };
@@ -740,40 +740,40 @@ class MBinaryInstruction : public MAryIn
         return op() ^ lhs->valueNumber() ^ rhs->valueNumber();
     }
     void swapOperands() {
         MDefinition *temp = getOperand(0);
         replaceOperand(0, getOperand(1));
         replaceOperand(1, temp);
     }
 
-    bool binaryCongruentTo(MDefinition *ins) const
+    bool binaryCongruentTo(const MDefinition *ins) const
     {
         if (op() != ins->op())
             return false;
 
         if (type() != ins->type())
             return false;
 
         if (isEffectful() || ins->isEffectful())
             return false;
 
-        MDefinition *left = getOperand(0);
-        MDefinition *right = getOperand(1);
-        MDefinition *tmp;
+        const MDefinition *left = getOperand(0);
+        const MDefinition *right = getOperand(1);
+        const MDefinition *tmp;
 
         if (isCommutative() && left->valueNumber() > right->valueNumber()) {
             tmp = right;
             right = left;
             left = tmp;
         }
 
-        MBinaryInstruction *bi = static_cast<MBinaryInstruction *>(ins);
-        MDefinition *insLeft = bi->getOperand(0);
-        MDefinition *insRight = bi->getOperand(1);
+        const MBinaryInstruction *bi = static_cast<const MBinaryInstruction *>(ins);
+        const MDefinition *insLeft = bi->getOperand(0);
+        const MDefinition *insRight = bi->getOperand(1);
         if (isCommutative() && insLeft->valueNumber() > insRight->valueNumber()) {
             tmp = insRight;
             insRight = insLeft;
             insLeft = tmp;
         }
 
         return (left->valueNumber() == insLeft->valueNumber()) &&
                (right->valueNumber() == insRight->valueNumber());
@@ -918,17 +918,17 @@ class MConstant : public MNullaryInstruc
     const bool valueToBoolean() const {
         // A hack to avoid this wordy pattern everywhere in the JIT.
         return ToBoolean(HandleValue::fromMarkedLocation(&value_));
     }
 
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const;
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool updateForReplacement(MDefinition *def) {
         MConstant *c = def->toConstant();
         // During constant folding, we don't want to replace a float32
@@ -986,32 +986,32 @@ class MParameter : public MNullaryInstru
     static MParameter *New(TempAllocator &alloc, int32_t index, types::TemporaryTypeSet *types);
 
     int32_t index() const {
         return index_;
     }
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const;
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 };
 
 class MCallee : public MNullaryInstruction
 {
   public:
     MCallee()
     {
         setResultType(MIRType_Object);
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(Callee)
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     static MCallee *New(TempAllocator &alloc) {
         return new(alloc) MCallee();
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
@@ -1915,17 +1915,17 @@ class MCallDOMNative : public MCall
 
     friend MCall *MCall::New(TempAllocator &alloc, JSFunction *target, size_t maxArgc,
                              size_t numActualArgs, bool construct, bool isDOMCall);
 
     const JSJitInfo *getJitInfo() const;
   public:
     virtual AliasSet getAliasSet() const MOZ_OVERRIDE;
 
-    virtual bool congruentTo(MDefinition *ins) const MOZ_OVERRIDE;
+    virtual bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE;
 
     virtual bool isCallDOMNative() const MOZ_OVERRIDE {
         return true;
     }
 
     virtual void computeMovable() MOZ_OVERRIDE;
 };
 
@@ -2294,17 +2294,17 @@ class MCompare
 # ifdef DEBUG
     bool isConsistentFloat32Use(MUse *use) const {
         // Both sides of the compare can be Float32
         return compareType_ == Compare_Float32;
     }
 # endif
 
   protected:
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!binaryCongruentTo(ins))
             return false;
         return compareType() == ins->toCompare()->compareType() &&
                jsop() == ins->toCompare()->jsop();
     }
 };
 
 // Takes a typed value and returns an untyped value.
@@ -2330,17 +2330,17 @@ class MBox : public MUnaryInstruction
     static MBox *New(TempAllocator &alloc, MDefinition *ins)
     {
         // Cannot box a box.
         JS_ASSERT(ins->type() != MIRType_Value);
 
         return new(alloc) MBox(alloc, ins);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Note: the op may have been inverted during lowering (to put constants in a
@@ -2412,17 +2412,17 @@ class MUnbox : public MUnaryInstruction,
     BailoutKind bailoutKind() const {
         // If infallible, no bailout should be generated.
         JS_ASSERT(fallible());
         return bailoutKind_;
     }
     bool fallible() const {
         return mode() != Infallible;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isUnbox() || ins->toUnbox()->mode() != mode())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void printOpcode(FILE *fp) const;
@@ -2840,17 +2840,17 @@ class MToDouble
         return conversion_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isToDouble() || ins->toToDouble()->conversion() != conversion())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -2902,17 +2902,17 @@ class MToFloat32
         return conversion_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     virtual MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isToFloat32() || ins->toToFloat32()->conversion() != conversion())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
@@ -2935,17 +2935,17 @@ class MAsmJSUnsignedToDouble
 
   public:
     INSTRUCTION_HEADER(AsmJSUnsignedToDouble);
     static MAsmJSUnsignedToDouble *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MAsmJSUnsignedToDouble(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 // Converts a uint32 to a float32 (coming from asm.js).
@@ -2961,17 +2961,17 @@ class MAsmJSUnsignedToFloat32
 
   public:
     INSTRUCTION_HEADER(AsmJSUnsignedToFloat32);
     static MAsmJSUnsignedToFloat32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MAsmJSUnsignedToFloat32(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool canProduceFloat32() const { return true; }
 };
@@ -3019,17 +3019,17 @@ class MToInt32
     TypePolicy *typePolicy() {
         return this;
     }
 
     MacroAssembler::IntConversionInputKind conversion() const {
         return conversion_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
@@ -3055,17 +3055,17 @@ class MTruncateToInt32 : public MUnaryIn
         return new(alloc) MTruncateToInt32(def);
     }
     static MTruncateToInt32 *NewAsmJS(TempAllocator &alloc, MDefinition *def) {
         return new(alloc) MTruncateToInt32(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     void computeRange(TempAllocator &alloc);
     bool isOperandTruncated(size_t index) const;
@@ -3096,17 +3096,17 @@ class MToString : public MUnaryInstructi
     INSTRUCTION_HEADER(ToString)
     static MToString *New(TempAllocator &alloc, MDefinition *def)
     {
         return new(alloc) MToString(def);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         JS_ASSERT(!input()->mightBeType(MIRType_Object));
         return AliasSet::None();
     }
 };
 
@@ -3129,17 +3129,17 @@ class MBitNot
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     void infer();
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ == MIRType_None)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -3232,17 +3232,17 @@ class MBinaryBitwiseInstruction
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     MDefinition *foldUnnecessaryBitop();
     virtual MDefinition *foldIfZero(size_t operand) = 0;
     virtual MDefinition *foldIfNegOne(size_t operand) = 0;
     virtual MDefinition *foldIfEqual()  = 0;
     virtual void infer(BaselineInspector *inspector, jsbytecode *pc);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ >= MIRType_Object)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
 
@@ -3448,17 +3448,17 @@ class MBinaryArithInstruction
 
     void setInt32() {
         specialization_ = MIRType_Int32;
         setResultType(MIRType_Int32);
     }
 
     virtual void trySpecializeFloat32(TempAllocator &alloc);
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return binaryCongruentTo(ins);
     }
     AliasSet getAliasSet() const {
         if (specialization_ >= MIRType_Object)
             return AliasSet::Store(AliasSet::Any);
         return AliasSet::None();
     }
 
@@ -3499,17 +3499,17 @@ class MMinMax
     }
     MIRType specialization() const {
         return specialization_;
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMinMax())
             return false;
         if (isMax() != ins->toMinMax()->isMax())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
@@ -3546,17 +3546,17 @@ class MAbs
         return ins;
     }
     MDefinition *num() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     bool fallible() const;
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -3587,17 +3587,17 @@ class MSqrt
         return new(alloc) MSqrt(num, type);
     }
     MDefinition *num() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 
@@ -3630,17 +3630,17 @@ class MAtan2
     MDefinition *x() const {
         return getOperand(1);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool possiblyCalls() const {
@@ -3673,17 +3673,17 @@ class MHypot
     MDefinition *y() const {
         return getOperand(1);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 
     bool possiblyCalls() const {
@@ -3714,17 +3714,17 @@ class MPow
     }
 
     MDefinition *input() const {
         return lhs();
     }
     MDefinition *power() const {
         return rhs();
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     TypePolicy *typePolicy() {
         return this;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
@@ -3752,17 +3752,17 @@ class MPowHalf
         setMovable();
     }
 
   public:
     INSTRUCTION_HEADER(PowHalf)
     static MPowHalf *New(TempAllocator &alloc, MDefinition *input) {
         return new(alloc) MPowHalf(input);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     bool operandIsNeverNegativeInfinity() const {
         return operandIsNeverNegativeInfinity_;
     }
     bool operandIsNeverNegativeZero() const {
         return operandIsNeverNegativeZero_;
     }
@@ -3860,17 +3860,17 @@ class MMathFunction
         return function_;
     }
     const MathCache *cache() const {
         return cache_;
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMathFunction())
             return false;
         if (ins->toMathFunction()->function() != function())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
@@ -4016,21 +4016,21 @@ class MMul : public MBinaryArithInstruct
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
     void analyzeEdgeCasesForward();
     void analyzeEdgeCasesBackward();
 
     double getIdentity() {
         return 1;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isMul())
             return false;
 
-        MMul *mul = ins->toMul();
+        const MMul *mul = ins->toMul();
         if (canBeNegativeZero_ != mul->canBeNegativeZero())
             return false;
 
         if (mode_ != mul->mode())
             return false;
 
         return binaryCongruentTo(ins);
     }
@@ -4055,17 +4055,17 @@ class MMul : public MBinaryArithInstruct
     }
 
     bool isFloat32Commutative() const { return true; }
 
     void computeRange(TempAllocator &alloc);
     bool truncate();
     bool isOperandTruncated(size_t index) const;
 
-    Mode mode() { return mode_; }
+    Mode mode() const { return mode_; }
 };
 
 class MDiv : public MBinaryArithInstruction
 {
     bool canBeNegativeZero_;
     bool canBeNegativeOverflow_;
     bool canBeDivideByZero_;
     bool canBeNegativeDividend_;
@@ -4252,17 +4252,17 @@ class MConcat
     INSTRUCTION_HEADER(Concat)
     static MConcat *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MConcat(left, right);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MConcatPar
@@ -4291,17 +4291,17 @@ class MConcatPar
     }
     MDefinition *lhs() const {
         return getOperand(1);
     }
     MDefinition *rhs() const {
         return getOperand(2);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MCharCodeAt
@@ -4321,17 +4321,17 @@ class MCharCodeAt
     static MCharCodeAt *New(TempAllocator &alloc, MDefinition *str, MDefinition *index) {
         return new(alloc) MCharCodeAt(str, index);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     virtual AliasSet getAliasSet() const {
         // Strings are immutable, so there is no implicit dependency.
         return AliasSet::None();
     }
 
@@ -4459,17 +4459,17 @@ class MLoadArrowThis
         return new(alloc) MLoadArrowThis(callee);
     }
     MDefinition *callee() const {
         return getOperand(0);
     }
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // An arrow function's lexical |this| value is immutable.
         return AliasSet::None();
     }
 };
 
@@ -4565,17 +4565,17 @@ class MPhi MOZ_FINAL : public MDefinitio
     void addInput(MDefinition *ins);
 
     // Appends a new input to the input vector. May call realloc_().
     // Prefer reserveLength() and addInput() instead, where possible.
     bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     bool isIterator() const {
         return isIterator_;
     }
     void setIterator() {
         isIterator_ = true;
     }
 
@@ -5050,17 +5050,17 @@ class MStringReplace
 
   public:
     INSTRUCTION_HEADER(StringReplace);
 
     static MStringReplace *New(TempAllocator &alloc, MDefinition *string, MDefinition *pattern, MDefinition *replacement) {
         return new(alloc) MStringReplace(string, pattern, replacement);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 struct LambdaFunctionInfo
@@ -5249,17 +5249,17 @@ class MSlots
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Returns obj->elements.
@@ -5282,17 +5282,17 @@ class MElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // A constant value for some object's array elements or typed array elements.
@@ -5319,17 +5319,17 @@ class MConstantElements : public MNullar
     }
 
     void printOpcode(FILE *fp) const;
 
     HashNumber valueHash() const {
         return (HashNumber)(size_t) value_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return ins->isConstantElements() && ins->toConstantElements()->value() == value();
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
@@ -5350,17 +5350,17 @@ class MConvertElementsToDoubles
 
     static MConvertElementsToDoubles *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MConvertElementsToDoubles(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // This instruction can read and write to the elements' contents.
         // However, it is alright to hoist this from loops which explicitly
         // read or write to the elements: such reads and writes will use double
         // values and can be reordered freely wrt this conversion, except that
         // definite double loads must follow the conversion. The latter
@@ -5398,17 +5398,17 @@ class MMaybeToDoubleElement
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
     MDefinition *value() const {
         return getOperand(1);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Load the initialized length from an elements header.
@@ -5427,17 +5427,17 @@ class MInitializedLength
 
     static MInitializedLength *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MInitializedLength(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     void computeRange(TempAllocator &alloc);
 };
@@ -5486,17 +5486,17 @@ class MArrayLength
 
     static MArrayLength *New(TempAllocator &alloc, MDefinition *elements) {
         return new(alloc) MArrayLength(elements);
     }
 
     MDefinition *elements() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 
     void computeRange(TempAllocator &alloc);
 };
@@ -5549,17 +5549,17 @@ class MTypedArrayLength
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // The typed array |length| property is immutable, so there is no
         // implicit dependency.
         return AliasSet::None();
     }
 
@@ -5586,17 +5586,17 @@ class MTypedArrayElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Checks whether a typed object is neutered.
@@ -5620,17 +5620,17 @@ class MNeuterCheck
     static MNeuterCheck *New(TempAllocator &alloc, MDefinition *object) {
         return new(alloc) MNeuterCheck(object);
     }
 
     MDefinition *object() const {
         return getOperand(0);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
@@ -5657,17 +5657,17 @@ class MTypedObjectElements
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
     }
 };
 
 // Inlined version of the js::SetTypedObjectOffset() intrinsic.
@@ -5812,20 +5812,20 @@ class MBoundsCheck
         minimum_ = n;
     }
     int32_t maximum() const {
         return maximum_;
     }
     void setMaximum(int32_t n) {
         maximum_ = n;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isBoundsCheck())
             return false;
-        MBoundsCheck *other = ins->toBoundsCheck();
+        const MBoundsCheck *other = ins->toBoundsCheck();
         if (minimum() != other->minimum() || maximum() != other->maximum())
             return false;
         return congruentIfOperandsEqual(other);
     }
     virtual AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
@@ -5918,20 +5918,20 @@ class MLoadElement
         return needsHoleCheck_;
     }
     bool loadDoubles() const {
         return loadDoubles_;
     }
     bool fallible() const {
         return needsHoleCheck();
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadElement())
             return false;
-        MLoadElement *other = ins->toLoadElement();
+        const MLoadElement *other = ins->toLoadElement();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (loadDoubles() != other->loadDoubles())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
@@ -5981,20 +5981,20 @@ class MLoadElementHole
         return getOperand(2);
     }
     bool needsNegativeIntCheck() const {
         return needsNegativeIntCheck_;
     }
     bool needsHoleCheck() const {
         return needsHoleCheck_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadElementHole())
             return false;
-        MLoadElementHole *other = ins->toLoadElementHole();
+        const MLoadElementHole *other = ins->toLoadElementHole();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
@@ -6300,20 +6300,20 @@ class MLoadTypedArrayElement
     }
     MDefinition *index() const {
         return getOperand(1);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadTypedArrayElement())
             return false;
-        MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
+        const MLoadTypedArrayElement *other = ins->toLoadTypedArrayElement();
         if (arrayType_ != other->arrayType_)
             return false;
         return congruentIfOperandsEqual(other);
     }
 
     void printOpcode(FILE *fp) const;
 
     void computeRange(TempAllocator &alloc);
@@ -6361,20 +6361,20 @@ class MLoadTypedArrayElementHole
         return this;
     }
     MDefinition *object() const {
         return getOperand(0);
     }
     MDefinition *index() const {
         return getOperand(1);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadTypedArrayElementHole())
             return false;
-        MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole();
+        const MLoadTypedArrayElementHole *other = ins->toLoadTypedArrayElementHole();
         if (arrayType() != other->arrayType())
             return false;
         if (allowDouble() != other->allowDouble())
             return false;
         return congruentIfOperandsEqual(other);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::TypedArrayElement);
@@ -6679,17 +6679,17 @@ class MClampToUint8
         return new(alloc) MClampToUint8(input);
     }
 
     MDefinition *foldsTo(TempAllocator &alloc, bool useValueNumbers);
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     void computeRange(TempAllocator &alloc);
 };
 
@@ -6719,29 +6719,29 @@ class MLoadFixedSlot
     }
 
     MDefinition *object() const {
         return getOperand(0);
     }
     size_t slot() const {
         return slot_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadFixedSlot())
             return false;
         if (slot() != ins->toLoadFixedSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::FixedSlot);
     }
 
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 class MStoreFixedSlot
   : public MBinaryInstruction,
     public MixPolicy<SingleObjectPolicy, NoFloatPolicy<1> >
 {
     bool needsBarrier_;
     size_t slot_;
@@ -6933,17 +6933,17 @@ class MGetPropertyCache
     bool monitoredResult() const {
         return monitoredResult_;
     }
     CacheLocationList &location() {
         return location_;
     }
     TypePolicy *typePolicy() { return this; }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!idempotent_)
             return false;
         if (!ins->isGetPropertyCache())
             return false;
         if (name() != ins->toGetPropertyCache()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -6993,17 +6993,17 @@ class MGetPropertyPolymorphic
 
   public:
     INSTRUCTION_HEADER(GetPropertyPolymorphic)
 
     static MGetPropertyPolymorphic *New(TempAllocator &alloc, MDefinition *obj, PropertyName *name) {
         return new(alloc) MGetPropertyPolymorphic(alloc, obj, name);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGetPropertyPolymorphic())
             return false;
         if (name() != ins->toGetPropertyPolymorphic()->name())
             return false;
         return congruentIfOperandsEqual(ins);
     }
 
     TypePolicy *typePolicy() {
@@ -7026,17 +7026,17 @@ class MGetPropertyPolymorphic
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields | AliasSet::FixedSlot | AliasSet::DynamicSlot);
     }
 
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 // Emit code to store a value to an object's slots if its shape matches
 // one of the shapes observed by the baseline IC, else bails out.
 class MSetPropertyPolymorphic
   : public MBinaryInstruction,
     public SingleObjectPolicy
 {
@@ -7357,17 +7357,17 @@ class MGuardShape
         return getOperand(0);
     }
     const Shape *shape() const {
         return shape_;
     }
     BailoutKind bailoutKind() const {
         return bailoutKind_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardShape())
             return false;
         if (shape() != ins->toGuardShape()->shape())
             return false;
         if (bailoutKind() != ins->toGuardShape()->bailoutKind())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7409,17 +7409,17 @@ class MGuardObjectType
         return getOperand(0);
     }
     const types::TypeObject *typeObject() const {
         return typeObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardObjectType())
             return false;
         if (typeObject() != ins->toGuardObjectType()->typeObject())
             return false;
         if (bailOnEquality() != ins->toGuardObjectType()->bailOnEquality())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7461,17 +7461,17 @@ class MGuardObjectIdentity
         return getOperand(0);
     }
     JSObject *singleObject() const {
         return singleObject_;
     }
     bool bailOnEquality() const {
         return bailOnEquality_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardObjectIdentity())
             return false;
         if (singleObject() != ins->toGuardObjectIdentity()->singleObject())
             return false;
         if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
             return false;
         return congruentIfOperandsEqual(ins);
     }
@@ -7506,17 +7506,17 @@ class MGuardClass
         return this;
     }
     MDefinition *obj() const {
         return getOperand(0);
     }
     const Class *getClass() const {
         return class_;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isGuardClass())
             return false;
         if (getClass() != ins->toGuardClass()->getClass())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::ObjectFields);
@@ -7551,28 +7551,28 @@ class MLoadSlot
     }
     MDefinition *slots() const {
         return getOperand(0);
     }
     uint32_t slot() const {
         return slot_;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isLoadSlot())
             return false;
         if (slot() != ins->toLoadSlot()->slot())
             return false;
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         JS_ASSERT(slots()->type() == MIRType_Slots);
         return AliasSet::Load(AliasSet::DynamicSlot);
     }
-    bool mightAlias(MDefinition *store);
+    bool mightAlias(const MDefinition *store) const;
 };
 
 // Inline call to access a function's environment (scope chain).
 class MFunctionEnvironment
   : public MUnaryInstruction,
     public SingleObjectPolicy
 {
   public:
@@ -8292,17 +8292,17 @@ class MGetDOMProperty
     MDefinition *object() {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!isDomMovable())
             return false;
 
         if (!ins->isGetDOMProperty())
             return false;
 
         // Checking the jitinfo is the same as checking the constant function
         if (!(info() == ins->toGetDOMProperty()->info()))
@@ -8369,17 +8369,17 @@ class MStringLength
 
     TypePolicy *typePolicy() {
         return this;
     }
 
     MDefinition *string() const {
         return getOperand(0);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // The string |length| property is immutable, so there is no
         // implicit dependency.
         return AliasSet::None();
     }
 
@@ -8646,20 +8646,20 @@ class MInArray
     }
     bool needsNegativeIntCheck() const {
         return needsNegativeIntCheck_;
     }
     void collectRangeInfoPreTrunc();
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::Element);
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         if (!ins->isInArray())
             return false;
-        MInArray *other = ins->toInArray();
+        const MInArray *other = ins->toInArray();
         if (needsHoleCheck() != other->needsHoleCheck())
             return false;
         if (needsNegativeIntCheck() != other->needsNegativeIntCheck())
             return false;
         return congruentIfOperandsEqual(other);
     }
     TypePolicy *typePolicy() {
         return this;
@@ -8730,17 +8730,17 @@ class MArgumentsLength : public MNullary
 
   public:
     INSTRUCTION_HEADER(ArgumentsLength)
 
     static MArgumentsLength *New(TempAllocator &alloc) {
         return new(alloc) MArgumentsLength();
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // Arguments |length| cannot be mutated by Ion Code.
         return AliasSet::None();
    }
 
     void computeRange(TempAllocator &alloc);
@@ -8770,17 +8770,17 @@ class MGetFrameArgument
 
     MDefinition *index() const {
         return getOperand(0);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         // If the script doesn't have any JSOP_SETARG ops, then this instruction is never
         // aliased.
         if (scriptHasSetArg_)
             return AliasSet::Load(AliasSet::FrameArgument);
         return AliasSet::None();
@@ -8811,17 +8811,17 @@ class MSetFrameArgument
     uint32_t argno() const {
         return argno_;
     }
 
     MDefinition *value() const {
         return getOperand(0);
     }
 
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::Store(AliasSet::FrameArgument);
     }
     TypePolicy *typePolicy() {
         return this;
     }
@@ -8949,17 +8949,17 @@ class MGuardThreadExclusive
         return getOperand(0);
     }
     MDefinition *object() const {
         return getOperand(1);
     }
     BailoutKind bailoutKind() const {
         return Bailout_Normal;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     bool possiblyCalls() const {
         return true;
     }
@@ -8980,17 +8980,17 @@ class MFilterTypeSet
 
   public:
     INSTRUCTION_HEADER(FilterTypeSet)
 
     static MFilterTypeSet *New(TempAllocator &alloc, MDefinition *def, types::TemporaryTypeSet *types) {
         return new(alloc) MFilterTypeSet(def, types);
     }
 
-    bool congruentTo(MDefinition *def) const {
+    bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
@@ -9023,17 +9023,17 @@ class MTypeBarrier
     }
 
     void printOpcode(FILE *fp) const;
 
     TypePolicy *typePolicy() {
         return this;
     }
 
-    bool congruentTo(MDefinition *def) const {
+    bool congruentTo(const MDefinition *def) const {
         return false;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
     virtual bool neverHoist() const {
         return resultTypeSet()->empty();
     }
@@ -9554,17 +9554,17 @@ class MHaveSameClass
 
     static MHaveSameClass *New(TempAllocator &alloc, MDefinition *left, MDefinition *right) {
         return new(alloc) MHaveSameClass(left, right);
     }
 
     TypePolicy *typePolicy() {
         return this;
     }
-    bool congruentTo(MDefinition *ins) const {
+    bool congruentTo(const MDefinition *ins) const {
         return congruentIfOperandsEqual(ins);
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MHasClass
@@ -9684,21 +9684,21 @@ class MAsmJSLoadHeap : public MUnaryInst
     INSTRUCTION_HEADER(AsmJSLoadHeap);
 
     static MAsmJSLoadHeap *New(TempAllocator &alloc, ArrayBufferView::ViewType vt, MDefinition *ptr) {
         return new(alloc) MAsmJSLoadHeap(vt, ptr);
     }
 
     MDefinition *ptr() const { return getOperand(0); }
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
     AliasSet getAliasSet() const {
         return AliasSet::Load(AliasSet::AsmJSHeap);
     }
-    bool mightAlias(MDefinition *def);
+    bool mightAlias(const MDefinition *def) const;
 };
 
 class MAsmJSStoreHeap : public MBinaryInstruction, public MAsmJSHeapAccess
 {
     MAsmJSStoreHeap(ArrayBufferView::ViewType vt, MDefinition *ptr, MDefinition *v)
       : MBinaryInstruction(ptr, v) , MAsmJSHeapAccess(vt, false)
     {}
 
@@ -9738,23 +9738,23 @@ class MAsmJSLoadGlobalVar : public MNull
     static MAsmJSLoadGlobalVar *New(TempAllocator &alloc, MIRType type, unsigned globalDataOffset,
                                     bool isConstant)
     {
         return new(alloc) MAsmJSLoadGlobalVar(type, globalDataOffset, isConstant);
     }
 
     unsigned globalDataOffset() const { return globalDataOffset_; }
 
-    bool congruentTo(MDefinition *ins) const;
+    bool congruentTo(const MDefinition *ins) const;
 
     AliasSet getAliasSet() const {
         return isConstant_ ? AliasSet::None() : AliasSet::Load(AliasSet::AsmJSGlobalVar);
     }
 
-    bool mightAlias(MDefinition *def);
+    bool mightAlias(const MDefinition *def) const;
 };
 
 class MAsmJSStoreGlobalVar : public MUnaryInstruction
 {
     MAsmJSStoreGlobalVar(unsigned globalDataOffset, MDefinition *v)
       : MUnaryInstruction(v), globalDataOffset_(globalDataOffset)
     {}
 
--- a/js/src/jit/shared/Assembler-x86-shared.h
+++ b/js/src/jit/shared/Assembler-x86-shared.h
@@ -1057,22 +1057,28 @@ class AssemblerX86Shared
             break;
           case Operand::MEM_REG_DISP:
             masm.andl_mr(src.disp(), src.base(), dest.code());
             break;
           default:
             MOZ_ASSUME_UNREACHABLE("unexpected operand kind");
         }
     }
+    void imull(const Register &multiplier) {
+        masm.imull_r(multiplier.code());
+    }
     void imull(Imm32 imm, const Register &dest) {
         masm.imull_i32r(dest.code(), imm.value, dest.code());
     }
     void imull(const Register &src, const Register &dest) {
         masm.imull_rr(src.code(), dest.code());
     }
+    void imull(Imm32 imm, const Register &src, const Register &dest) {
+        masm.imull_i32r(src.code(), imm.value, dest.code());
+    }
     void imull(const Operand &src, const Register &dest) {
         switch (src.kind()) {
           case Operand::REG:
             masm.imull_rr(src.reg(), dest.code());
             break;
           case Operand::MEM_REG_DISP:
             masm.imull_mr(src.disp(), src.base(), dest.code());
             break;
--- a/js/src/jit/shared/CodeGenerator-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-shared.cpp
@@ -1002,16 +1002,84 @@ CodeGeneratorShared::addCacheLocations(c
         new (&runtimeData_[curIndex]) CacheLocation(iter->pc, iter->script);
         numLocations++;
     }
     JS_ASSERT(numLocations != 0);
     *numLocs = numLocations;
     return firstIndex;
 }
 
+ReciprocalMulConstants
+CodeGeneratorShared::computeDivisionConstants(int d) {
+    // In what follows, d is positive and is not a power of 2.
+    JS_ASSERT(d > 0 && (d & (d - 1)) != 0);
+
+    // Speeding up division by non power-of-2 constants is possible by
+    // calculating, during compilation, a value M such that high-order
+    // bits of M*n correspond to the result of the division. Formally,
+    // we compute values 0 <= M < 2^32 and 0 <= s < 31 such that
+    //         (M * n) >> (32 + s) = floor(n/d)    if n >= 0
+    //         (M * n) >> (32 + s) = ceil(n/d) - 1 if n < 0.
+    // The original presentation of this technique appears in Hacker's
+    // Delight, a book by Henry S. Warren, Jr.. A proof of correctness
+    // for our version follows.
+
+    // Define p = 32 + s, M = ceil(2^p/d), and assume that s satisfies
+    //                     M - 2^p/d <= 2^(s+1)/d.                 (1)
+    // (Observe that s = FloorLog32(d) satisfies this, because in this
+    // case d <= 2^(s+1) and so the RHS of (1) is at least one). Then,
+    //
+    // a) If s <= FloorLog32(d), then M <= 2^32 - 1.
+    // Proof: Indeed, M is monotone in s and, for s = FloorLog32(d),
+    // the inequalities 2^31 > d >= 2^s + 1 readily imply
+    //    2^p / d  = 2^p/(d - 1) * (d - 1)/d
+    //            <= 2^32 * (1 - 1/d) < 2 * (2^31 - 1) = 2^32 - 2.
+    // The claim follows by applying the ceiling function.
+    //
+    // b) For any 0 <= n < 2^31, floor(Mn/2^p) = floor(n/d).
+    // Proof: Put x = floor(Mn/2^p); it's the unique integer for which
+    //                    Mn/2^p - 1 < x <= Mn/2^p.                (2)
+    // Using M >= 2^p/d on the LHS and (1) on the RHS, we get
+    //           n/d - 1 < x <= n/d + n/(2^31 d) < n/d + 1/d.
+    // Since x is an integer, it's not in the interval (n/d, (n+1)/d),
+    // and so n/d - 1 < x <= n/d, which implies x = floor(n/d).
+    //
+    // c) For any -2^31 <= n < 0, floor(Mn/2^p) + 1 = ceil(n/d).
+    // Proof: The proof is similar. Equation (2) holds as above. Using
+    // M > 2^p/d (d isn't a power of 2) on the RHS and (1) on the LHS,
+    //                 n/d + n/(2^31 d) - 1 < x < n/d.
+    // Using n >= -2^31 and summing 1,
+    //                  n/d - 1/d < x + 1 < n/d + 1.
+    // Since x + 1 is an integer, this implies n/d <= x + 1 < n/d + 1.
+    // In other words, x + 1 = ceil(n/d).
+    //
+    // Condition (1) isn't necessary for the existence of M and s with
+    // the properties above. Hacker's Delight provides a slightly less
+    // restrictive condition when d >= 196611, at the cost of a 3-page
+    // proof of correctness.
+
+    // Note that, since d*M - 2^p = d - (2^p)%d, (1) can be written as
+    //                   2^(s+1) >= d - (2^p)%d.
+    // We now compute the least s with this property...
+
+    int32_t shift = 0;
+    while ((int64_t(1) << (shift+1)) + (int64_t(1) << (shift+32)) % d < d)
+        shift++;
+
+    // ...and the corresponding M. This may not fit in a signed 32-bit
+    // integer; we will compute (M - 2^32) * n + (2^32 * n) instead of
+    // M * n if this is the case (cf. item (a) above).
+    ReciprocalMulConstants rmc;
+    rmc.multiplier = int32_t((int64_t(1) << (shift+32))/d + 1);
+    rmc.shift_amount = shift;
+
+    return rmc;
+}
+
+
 #ifdef JS_TRACE_LOGGING
 
 bool
 CodeGeneratorShared::emitTracelogScript(bool isStart)
 {
     RegisterSet regs = RegisterSet::Volatile();
     Register logger = regs.takeGeneral();
     Register script = regs.takeGeneral();
--- a/js/src/jit/shared/CodeGenerator-shared.h
+++ b/js/src/jit/shared/CodeGenerator-shared.h
@@ -40,16 +40,21 @@ struct PatchableBackedgeInfo
     Label *loopHeader;
     Label *interruptCheck;
 
     PatchableBackedgeInfo(CodeOffsetJump backedge, Label *loopHeader, Label *interruptCheck)
       : backedge(backedge), loopHeader(loopHeader), interruptCheck(interruptCheck)
     {}
 };
 
+struct ReciprocalMulConstants {
+    int32_t multiplier;
+    int32_t shift_amount;
+};
+
 class CodeGeneratorShared : public LInstructionVisitor
 {
     js::Vector<OutOfLineCode *, 0, SystemAllocPolicy> outOfLineCode_;
     OutOfLineCode *oolIns;
 
     MacroAssembler &ensureMasm(MacroAssembler *masm);
     mozilla::Maybe<MacroAssembler> maybeMasm_;
 
@@ -397,16 +402,17 @@ class CodeGeneratorShared : public LInst
     inline OutOfLineCode *oolCallVM(const VMFunctionsModal &f, LInstruction *ins,
                                     const ArgSeq &args, const StoreOutputTo &out)
     {
         return oolCallVM(f[gen->info().executionMode()], ins, args, out);
     }
 
     bool addCache(LInstruction *lir, size_t cacheIndex);
     size_t addCacheLocations(const CacheLocationList &locs, size_t *numLocs);
+    ReciprocalMulConstants computeDivisionConstants(int d);
 
   protected:
     bool addOutOfLineCode(OutOfLineCode *code);
     bool hasOutOfLineCode() { return !outOfLineCode_.empty(); }
     bool generateOutOfLineCode();
 
     Label *labelForBackedgeWithImplicitCheck(MBasicBlock *mir);
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.cpp
@@ -17,16 +17,17 @@
 #include "jit/RangeAnalysis.h"
 #include "vm/TraceLogging.h"
 
 #include "jit/shared/CodeGenerator-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Abs;
 using mozilla::FloatingPoint;
 using mozilla::FloorLog2;
 using mozilla::NegativeInfinity;
 using mozilla::SpecificNaN;
 
 namespace js {
 namespace jit {
 
@@ -864,49 +865,142 @@ CodeGeneratorX86Shared::visitMulNegative
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitDivPowTwoI(LDivPowTwoI *ins)
 {
     Register lhs = ToRegister(ins->numerator());
     mozilla::DebugOnly<Register> output = ToRegister(ins->output());
+
     int32_t shift = ins->shift();
+    bool negativeDivisor = ins->negativeDivisor();
+    MDiv *mir = ins->mir();
 
     // We use defineReuseInput so these should always be the same, which is
     // convenient since all of our instructions here are two-address.
     JS_ASSERT(lhs == output);
 
+    if (!mir->isTruncated() && negativeDivisor) {
+        // 0 divided by a negative number must return a double.
+        masm.testl(lhs, lhs);
+        if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+            return false;
+    }
+
     if (shift != 0) {
-        MDiv *mir = ins->mir();
         if (!mir->isTruncated()) {
             // If the remainder is != 0, bailout since this must be a double.
             masm.testl(lhs, Imm32(UINT32_MAX >> (32 - shift)));
             if (!bailoutIf(Assembler::NonZero, ins->snapshot()))
                 return false;
         }
 
-        if (!mir->canBeNegativeDividend()) {
-            // Numerator is unsigned, so needs no adjusting. Do the shift.
-            masm.sarl(Imm32(shift), lhs);
-            return true;
-        }
-
         // Adjust the value so that shifting produces a correctly rounded result
         // when the numerator is negative. See 10-1 "Signed Division by a Known
         // Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
-        Register lhsCopy = ToRegister(ins->numeratorCopy());
-        JS_ASSERT(lhsCopy != lhs);
-        if (shift > 1)
-            masm.sarl(Imm32(31), lhs);
-        masm.shrl(Imm32(32 - shift), lhs);
-        masm.addl(lhsCopy, lhs);
+        if (mir->canBeNegativeDividend()) {
+            Register lhsCopy = ToRegister(ins->numeratorCopy());
+            JS_ASSERT(lhsCopy != lhs);
+            if (shift > 1)
+                masm.sarl(Imm32(31), lhs);
+            masm.shrl(Imm32(32 - shift), lhs);
+            masm.addl(lhsCopy, lhs);
+        }
+
+        masm.sarl(Imm32(shift), lhs);
+        if (negativeDivisor)
+            masm.negl(lhs);
+    } else if (shift == 0 && negativeDivisor) {
+        // INT32_MIN / -1 overflows.
+        masm.negl(lhs);
+        if (!mir->isTruncated() && !bailoutIf(Assembler::Overflow, ins->snapshot()))
+            return false;
+    }
+
+    return true;
+}
+
+bool
+CodeGeneratorX86Shared::visitDivOrModConstantI(LDivOrModConstantI *ins) {
+    Register lhs = ToRegister(ins->numerator());
+    Register output = ToRegister(ins->output());
+    int32_t d = ins->denominator();
+
+    // This emits the division answer into edx or the modulus answer into eax.
+    JS_ASSERT(output == eax || output == edx);
+    JS_ASSERT(lhs != eax && lhs != edx);
+
+    // The absolute value of the denominator isn't a power of 2 (see LDivPowTwoI
+    // and LModPowTwoI).
+    JS_ASSERT((Abs(d) & (Abs(d) - 1)) != 0);
+
+    // We will first divide by Abs(d), and negate the answer if d is negative.
+    // If desired, this can be avoided by generalizing computeDivisionConstants.
+    ReciprocalMulConstants rmc = computeDivisionConstants(Abs(d));
 
-        // Do the shift.
-        masm.sarl(Imm32(shift), lhs);
+    // As explained in the comments of computeDivisionConstants, we first compute
+    // X >> (32 + shift), where X is either (rmc.multiplier * n) if the multiplier
+    // is non-negative or (rmc.multiplier * n) + (2^32 * n) otherwise. This is the
+    // desired division result if n is non-negative, and is one less than the result
+    // otherwise.
+    masm.movl(lhs, eax);
+    masm.movl(Imm32(rmc.multiplier), edx);
+    masm.imull(edx);
+    if (rmc.multiplier < 0)
+        masm.addl(lhs, edx);
+    masm.sarl(Imm32(rmc.shift_amount), edx);
+
+    // We'll subtract -1 instead of adding 1, because (n < 0 ? -1 : 0) can be
+    // computed with just a sign-extending shift of 31 bits.
+    if (ins->canBeNegativeDividend()) {
+        masm.movl(lhs, eax);
+        masm.sarl(Imm32(31), eax);
+        masm.subl(eax, edx);
+    }
+
+    // After this, edx contains the correct division result.
+    if (d < 0)
+        masm.negl(edx);
+
+    if (output == eax) {
+        masm.imull(Imm32(-d), edx, eax);
+        masm.addl(lhs, eax);
+    }
+
+    if (!ins->mir()->isTruncated()) {
+        if (output == edx) {
+            // This is a division op. Multiply the obtained value by d to check if
+            // the correct answer is an integer. This cannot overflow, since |d| > 1.
+            masm.imull(Imm32(d), edx, eax);
+            masm.cmpl(lhs, eax);
+            if (!bailoutIf(Assembler::NotEqual, ins->snapshot()))
+                return false;
+
+            // If lhs is zero and the divisor is negative, the answer should have
+            // been -0.
+            if (d < 0) {
+                masm.testl(lhs, lhs);
+                if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+                    return false;
+            }
+        } else if (ins->canBeNegativeDividend()) {
+            // This is a mod op. If the computed value is zero and lhs
+            // is negative, the answer should have been -0.
+            Label done;
+
+            masm.cmpl(lhs, Imm32(0));
+            masm.j(Assembler::GreaterThanOrEqual, &done);
+
+            masm.testl(eax, eax);
+            if (!bailoutIf(Assembler::Zero, ins->snapshot()))
+                return false;
+
+            masm.bind(&done);
+        }
     }
 
     return true;
 }
 
 bool
 CodeGeneratorX86Shared::visitDivI(LDivI *ins)
 {
@@ -1007,29 +1101,37 @@ CodeGeneratorX86Shared::visitModPowTwoI(
     Label negative;
 
     if (ins->mir()->canBeNegativeDividend()) {
         // Switch based on sign of the lhs.
         // Positive numbers are just a bitmask
         masm.branchTest32(Assembler::Signed, lhs, lhs, &negative);
     }
 
-    masm.andl(Imm32((1 << shift) - 1), lhs);
+    masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
 
     if (ins->mir()->canBeNegativeDividend()) {
         Label done;
         masm.jump(&done);
 
         // Negative numbers need a negate, bitmask, negate
         masm.bind(&negative);
-        // visitModI has an overflow check here to catch INT_MIN % -1, but
-        // here the rhs is a power of 2, and cannot be -1, so the check is not generated.
+
+        // Unlike in the visitModI case, we are not computing the mod by means of a
+        // division. Therefore, the divisor = -1 case isn't problematic (the andl
+        // always returns 0, which is what we expect).
+        //
+        // The negl instruction overflows if lhs == INT32_MIN, but this is also not
+        // a problem: shift is at most 31, and so the andl also always returns 0.
         masm.negl(lhs);
-        masm.andl(Imm32((1 << shift) - 1), lhs);
+        masm.andl(Imm32((uint32_t(1) << shift) - 1), lhs);
         masm.negl(lhs);
+
+        // Since a%b has the same sign as b, and a is negative in this branch,
+        // an answer of 0 means the correct result is actually -0. Bail out.
         if (!ins->mir()->isTruncated() && !bailoutIf(Assembler::Zero, ins->snapshot()))
             return false;
         masm.bind(&done);
     }
     return true;
 
 }
 
--- a/js/src/jit/shared/CodeGenerator-x86-shared.h
+++ b/js/src/jit/shared/CodeGenerator-x86-shared.h
@@ -119,16 +119,17 @@ class CodeGeneratorX86Shared : public Co
     virtual bool visitSqrtD(LSqrtD *ins);
     virtual bool visitSqrtF(LSqrtF *ins);
     virtual bool visitPowHalfD(LPowHalfD *ins);
     virtual bool visitAddI(LAddI *ins);
     virtual bool visitSubI(LSubI *ins);
     virtual bool visitMulI(LMulI *ins);
     virtual bool visitDivI(LDivI *ins);
     virtual bool visitDivPowTwoI(LDivPowTwoI *ins);
+    virtual bool visitDivOrModConstantI(LDivOrModConstantI *ins);
     virtual bool visitModI(LModI *ins);
     virtual bool visitModPowTwoI(LModPowTwoI *ins);
     virtual bool visitBitNotI(LBitNotI *ins);
     virtual bool visitBitOpI(LBitOpI *ins);
     virtual bool visitShiftI(LShiftI *ins);
     virtual bool visitUrshD(LUrshD *ins);
     virtual bool visitTestIAndBranch(LTestIAndBranch *test);
     virtual bool visitTestDAndBranch(LTestDAndBranch *test);
--- a/js/src/jit/shared/LIR-x86-shared.h
+++ b/js/src/jit/shared/LIR-x86-shared.h
@@ -42,41 +42,76 @@ class LDivI : public LBinaryMath<1>
         return mir_->toDiv();
     }
 };
 
 // Signed division by a power-of-two constant.
 class LDivPowTwoI : public LBinaryMath<0>
 {
     const int32_t shift_;
+    const bool negativeDivisor_;
 
   public:
     LIR_HEADER(DivPowTwoI)
 
-    LDivPowTwoI(const LAllocation &lhs, const LAllocation &lhsCopy, int32_t shift)
-      : shift_(shift)
+    LDivPowTwoI(const LAllocation &lhs, const LAllocation &lhsCopy, int32_t shift, bool negativeDivisor)
+      : shift_(shift), negativeDivisor_(negativeDivisor)
     {
         setOperand(0, lhs);
         setOperand(1, lhsCopy);
     }
 
     const LAllocation *numerator() {
         return getOperand(0);
     }
     const LAllocation *numeratorCopy() {
         return getOperand(1);
     }
     int32_t shift() const {
         return shift_;
     }
+    bool negativeDivisor() const {
+        return negativeDivisor_;
+    }
     MDiv *mir() const {
         return mir_->toDiv();
     }
 };
 
+class LDivOrModConstantI : public LInstructionHelper<1, 1, 1>
+{
+    const int32_t denominator_;
+
+  public:
+    LIR_HEADER(DivOrModConstantI)
+
+    LDivOrModConstantI(const LAllocation &lhs, int32_t denominator, const LDefinition& temp)
+    : denominator_(denominator)
+    {
+        setOperand(0, lhs);
+        setTemp(0, temp);
+    }
+
+    const LAllocation *numerator() {
+        return getOperand(0);
+    }
+    int32_t denominator() const {
+        return denominator_;
+    }
+    MBinaryArithInstruction *mir() const {
+        JS_ASSERT(mir_->isDiv() || mir_->isMod());
+        return static_cast<MBinaryArithInstruction *>(mir_);
+    }
+    bool canBeNegativeDividend() const {
+        if (mir_->isMod())
+            return mir_->toMod()->canBeNegativeDividend();
+        return mir_->toDiv()->canBeNegativeDividend();
+    }
+};
+
 class LModI : public LBinaryMath<1>
 {
   public:
     LIR_HEADER(ModI)
 
     LModI(const LAllocation &lhs, const LAllocation &rhs, const LDefinition &temp) {
         setOperand(0, lhs);
         setOperand(1, rhs);
--- a/js/src/jit/shared/Lowering-x86-shared.cpp
+++ b/js/src/jit/shared/Lowering-x86-shared.cpp
@@ -10,16 +10,17 @@
 
 #include "jit/MIR.h"
 
 #include "jit/shared/Lowering-shared-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::Abs;
 using mozilla::FloorLog2;
 
 LTableSwitch *
 LIRGeneratorX86Shared::newLTableSwitch(const LAllocation &in, const LDefinition &inputCopy,
                                        MTableSwitch *tableswitch)
 {
     return new(alloc()) LTableSwitch(in, inputCopy, temp(), tableswitch);
 }
@@ -132,36 +133,39 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
     if (div->isUnsigned())
         return lowerUDiv(div);
 
     // Division instructions are slow. Division by constant denominators can be
     // rewritten to use other instructions.
     if (div->rhs()->isConstant()) {
         int32_t rhs = div->rhs()->toConstant()->value().toInt32();
 
-        // Check for division by a positive power of two, which is an easy and
-        // important case to optimize. Note that other optimizations are also
-        // possible; division by negative powers of two can be optimized in a
-        // similar manner as positive powers of two, and division by other
-        // constants can be optimized by a reciprocal multiplication technique.
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
+        // Division by powers of two can be done by shifting, and division by
+        // other numbers can be done by a reciprocal multiplication technique.
+        int32_t shift = FloorLog2(Abs(rhs));
+        if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
             LAllocation lhs = useRegisterAtStart(div->lhs());
             LDivPowTwoI *lir;
             if (!div->canBeNegativeDividend()) {
                 // Numerator is unsigned, so does not need adjusting.
-                lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift);
+                lir = new(alloc()) LDivPowTwoI(lhs, lhs, shift, rhs < 0);
             } else {
                 // Numerator is signed, and needs adjusting, and an extra
                 // lhs copy register is needed.
-                lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift);
+                lir = new(alloc()) LDivPowTwoI(lhs, useRegister(div->lhs()), shift, rhs < 0);
             }
             if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 return false;
             return defineReuseInput(lir, div, 0);
+        } else if (rhs != 0) {
+            LDivOrModConstantI *lir;
+            lir = new(alloc()) LDivOrModConstantI(useRegister(div->lhs()), rhs, tempFixed(eax));
+            if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return defineFixed(lir, div, LAllocation(AnyRegister(edx)));
         }
     }
 
     LDivI *lir = new(alloc()) LDivI(useRegister(div->lhs()), useRegister(div->rhs()),
                                     tempFixed(edx));
     if (div->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
     return defineFixed(lir, div, LAllocation(AnyRegister(eax)));
@@ -170,22 +174,28 @@ LIRGeneratorX86Shared::lowerDivI(MDiv *d
 bool
 LIRGeneratorX86Shared::lowerModI(MMod *mod)
 {
     if (mod->isUnsigned())
         return lowerUMod(mod);
 
     if (mod->rhs()->isConstant()) {
         int32_t rhs = mod->rhs()->toConstant()->value().toInt32();
-        int32_t shift = FloorLog2(rhs);
-        if (rhs > 0 && 1 << shift == rhs) {
+        int32_t shift = FloorLog2(Abs(rhs));
+        if (rhs != 0 && uint32_t(1) << shift == Abs(rhs)) {
             LModPowTwoI *lir = new(alloc()) LModPowTwoI(useRegisterAtStart(mod->lhs()), shift);
             if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
                 return false;
             return defineReuseInput(lir, mod, 0);
+        } else if (rhs != 0) {
+            LDivOrModConstantI *lir;
+            lir = new(alloc()) LDivOrModConstantI(useRegister(mod->lhs()), rhs, tempFixed(edx));
+            if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
+                return false;
+            return defineFixed(lir, mod, LAllocation(AnyRegister(eax)));
         }
     }
 
     LModI *lir = new(alloc()) LModI(useRegister(mod->lhs()),
                                     useRegister(mod->rhs()),
                                     tempFixed(eax));
     if (mod->fallible() && !assignSnapshot(lir, Bailout_BaselineInfo))
         return false;
--- a/js/src/jit/x64/LOpcodes-x64.h
+++ b/js/src/jit/x64/LOpcodes-x64.h
@@ -8,16 +8,17 @@
 #define jit_x64_LOpcodes_x64_h
 
 #define LIR_CPU_OPCODE_LIST(_)      \
     _(Box)                          \
     _(Unbox)                        \
     _(UnboxFloatingPoint)           \
     _(DivI)                         \
     _(DivPowTwoI)                   \
+    _(DivOrModConstantI)            \
     _(ModI)                         \
     _(ModPowTwoI)                   \
     _(PowHalfD)                     \
     _(AsmJSUInt32ToDouble)          \
     _(AsmJSUInt32ToFloat32)         \
     _(AsmJSLoadFuncPtr)             \
     _(UDivOrMod)
 
--- a/js/src/jit/x86/LOpcodes-x86.h
+++ b/js/src/jit/x86/LOpcodes-x86.h
@@ -9,16 +9,17 @@
 
 #define LIR_CPU_OPCODE_LIST(_)  \
     _(Unbox)                    \
     _(UnboxFloatingPoint)       \
     _(Box)                      \
     _(BoxFloatingPoint)         \
     _(DivI)                     \
     _(DivPowTwoI)               \
+    _(DivOrModConstantI)        \
     _(ModI)                     \
     _(ModPowTwoI)               \
     _(PowHalfD)                 \
     _(AsmJSUInt32ToDouble)      \
     _(AsmJSUInt32ToFloat32)     \
     _(AsmJSLoadFuncPtr)         \
     _(UDivOrMod)
 
--- a/js/xpconnect/idl/xpccomponents.idl
+++ b/js/xpconnect/idl/xpccomponents.idl
@@ -116,17 +116,17 @@ interface nsIXPCComponents_utils_Sandbox
 interface ScheduledGCCallback : nsISupports
 {
     void callback();
 };
 
 /**
 * interface of Components.utils
 */
-[scriptable, uuid(5e253a02-f91f-4fb3-9335-db0fca23f2e0)]
+[scriptable, uuid(45b80e00-fb0d-439e-b7bf-54f24af0c4a6)]
 interface nsIXPCComponents_Utils : nsISupports
 {
 
     /* reportError is designed to be called from JavaScript only.
      *
      * It will report a JS Error object to the JS console, and return. It
      * is meant for use in exception handler blocks which want to "eat"
      * an exception, but still want to report it to the console.
@@ -563,16 +563,23 @@ interface nsIXPCComponents_Utils : nsISu
      *
      * Hence the notion of the "WebIDL Caller". If the current Entry Script on
      * the Script Settings Stack represents the invocation of JS-implemented
      * WebIDL, this API returns the principal of the caller at the time
      * of invocation. Otherwise (i.e. outside of JS-implemented WebIDL), this
      * function throws. If it throws, you probably shouldn't be using it.
      */
     nsIPrincipal getWebIDLCallerPrincipal();
+
+    /*
+     * Gets the principal of a script object, after unwrapping any cross-
+     * compartment wrappers.
+     */
+    [implicit_jscontext]
+    nsIPrincipal getObjectPrincipal(in jsval obj);
 };
 
 /**
 * Interface for the 'Components' object.
 *
 * The first interface contains things that are available to non-chrome XBL code
 * that runs in a scope with an nsExpandedPrincipal. The second interface
 * includes members that are only exposed to chrome.
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3252,33 +3252,33 @@ nsXPCComponents_Utils::NukeSandbox(Handl
 NS_IMETHODIMP
 nsXPCComponents_Utils::BlockScriptForGlobal(HandleValue globalArg,
                                             JSContext *cx)
 {
     NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
     RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
                                             /* stopAtOuter = */ false));
     NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
-    if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) {
+    if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
         JS_ReportError(cx, "Script may not be disabled for system globals");
         return NS_ERROR_FAILURE;
     }
     Scriptability::Get(global).Block();
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsXPCComponents_Utils::UnblockScriptForGlobal(HandleValue globalArg,
                                               JSContext *cx)
 {
     NS_ENSURE_TRUE(globalArg.isObject(), NS_ERROR_INVALID_ARG);
     RootedObject global(cx, UncheckedUnwrap(&globalArg.toObject(),
                                             /* stopAtOuter = */ false));
     NS_ENSURE_TRUE(JS_IsGlobalObject(global), NS_ERROR_INVALID_ARG);
-    if (nsContentUtils::IsSystemPrincipal(GetObjectPrincipal(global))) {
+    if (nsContentUtils::IsSystemPrincipal(xpc::GetObjectPrincipal(global))) {
         JS_ReportError(cx, "Script may not be disabled for system globals");
         return NS_ERROR_FAILURE;
     }
     Scriptability::Get(global).Unblock();
     return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -3611,16 +3611,31 @@ nsXPCComponents_Utils::GetWebIDLCallerPr
     // and we throw.
     nsCOMPtr<nsIPrincipal> callerPrin = mozilla::dom::GetWebIDLCallerPrincipal();
     if (!callerPrin)
         return NS_ERROR_NOT_AVAILABLE;
     callerPrin.forget(aResult);
     return NS_OK;
 }
 
+NS_IMETHODIMP
+nsXPCComponents_Utils::GetObjectPrincipal(HandleValue val, JSContext *cx,
+                                          nsIPrincipal **result)
+{
+    if (!val.isObject())
+        return NS_ERROR_INVALID_ARG;
+    RootedObject obj(cx, &val.toObject());
+    obj = js::CheckedUnwrap(obj);
+    MOZ_ASSERT(obj);
+
+    nsCOMPtr<nsIPrincipal> prin = nsContentUtils::GetObjectPrincipal(obj);
+    prin.forget(result);
+    return NS_OK;
+}
+
 /***************************************************************************/
 /***************************************************************************/
 /***************************************************************************/
 
 
 nsXPCComponentsBase::nsXPCComponentsBase(XPCWrappedNativeScope* aScope)
     :   mScope(aScope)
 {
--- a/js/xpconnect/tests/unit/test_getObjectPrincipal.js
+++ b/js/xpconnect/tests/unit/test_getObjectPrincipal.js
@@ -1,6 +1,11 @@
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
 function run_test() {
-  var secMan = Components.classes["@mozilla.org/scriptsecuritymanager;1"].getService(
-    Components.interfaces.nsIScriptSecurityManager);
-
-  do_check_true(secMan.isSystemPrincipal(secMan.getObjectPrincipal({})));
+  var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager);
+  do_check_true(secMan.isSystemPrincipal(Cu.getObjectPrincipal({})));
+  var sb = new Cu.Sandbox('http://www.example.com');
+  Cu.evalInSandbox('var obj = { foo: 42 };', sb);
+  do_check_eq(Cu.getObjectPrincipal(sb.obj).origin, 'http://www.example.com');
 }
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -56,16 +56,29 @@
 using namespace mozilla;
 using namespace mozilla::css;
 using namespace mozilla::gfx;
 using mozilla::image::ImageOps;
 using mozilla::CSSSizeOrRatio;
 
 static int gFrameTreeLockCount = 0;
 
+static void
+ApplySkipSides(int aSkipSides, nsMargin* aMargin)
+{
+  if (aSkipSides & SIDE_BIT_LEFT)
+    aMargin->left = 0;
+  if (aSkipSides & SIDE_BIT_TOP)
+    aMargin->top = 0;
+  if (aSkipSides & SIDE_BIT_RIGHT)
+    aMargin->right = 0;
+  if (aSkipSides & SIDE_BIT_BOTTOM)
+    aMargin->bottom = 0;
+}
+
 // To avoid storing this data on nsInlineFrame (bloat) and to avoid
 // recalculating this for each frame in a continuation (perf), hold
 // a cache of various coordinate information that we need in order
 // to paint inline backgrounds.
 struct InlineBackgroundData
 {
   InlineBackgroundData()
       : mFrame(nullptr), mBlockFrame(nullptr)
@@ -76,39 +89,44 @@ struct InlineBackgroundData
   {
   }
 
   void Reset()
   {
     mBoundingBox.SetRect(0,0,0,0);
     mContinuationPoint = mLineContinuationPoint = mUnbrokenWidth = 0;
     mFrame = mBlockFrame = nullptr;
+    mLeftBorderData.Reset();
   }
 
+  /**
+   * Return a continuous rect for (an inline) aFrame relative to the
+   * continuation that draws the left-most part of the background.
+   * This is used when painting backgrounds.
+   */
   nsRect GetContinuousRect(nsIFrame* aFrame)
   {
+    MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::inlineFrame);
+
     SetFrame(aFrame);
 
     nscoord x;
     if (mBidiEnabled) {
       x = mLineContinuationPoint;
 
       // Scan continuations on the same line as aFrame and accumulate the widths
       // of frames that are to the left (if this is an LTR block) or right
       // (if it's RTL) of the current one.
       bool isRtlBlock = (mBlockFrame->StyleVisibility()->mDirection ==
                            NS_STYLE_DIRECTION_RTL);
       nscoord curOffset = aFrame->GetOffsetTo(mBlockFrame).x;
 
-      // No need to use our GetPrevContinuation/GetNextContinuation methods
-      // here, since ib-split siblings are certainly not on the same line.
-
-      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
       // If the continuation is fluid we know inlineFrame is not on the same line.
       // If it's not fluid, we need to test further to be sure.
+      nsIFrame* inlineFrame = aFrame->GetPrevContinuation();
       while (inlineFrame && !inlineFrame->GetNextInFlow() &&
              AreOnSameLine(aFrame, inlineFrame)) {
         nscoord frameXOffset = inlineFrame->GetOffsetTo(mBlockFrame).x;
         if(isRtlBlock == (frameXOffset >= curOffset)) {
           x += inlineFrame->GetSize().width;
         }
         inlineFrame = inlineFrame->GetPrevContinuation();
       }
@@ -135,16 +153,49 @@ struct InlineBackgroundData
     }
 
     // Assume background-origin: border and return a rect with offsets
     // relative to (0,0).  If we have a different background-origin,
     // then our rect should be deflated appropriately by our caller.
     return nsRect(-x, 0, mUnbrokenWidth, mFrame->GetSize().height);
   }
 
+  /**
+   * Return a continuous rect for (an inline) aFrame relative to the
+   * continuation that should draw the left-border.  This is used when painting
+   * borders and clipping backgrounds.  This may NOT be the same continuous rect
+   * as for drawing backgrounds; the continuation with the left-border might be
+   * somewhere in the middle of that rect (e.g. BIDI), in those cases we need
+   * the reverse background order starting at the left-border continuation.
+   */
+  nsRect GetBorderContinuousRect(nsIFrame* aFrame, nsRect aBorderArea)
+  {
+    // Calling GetContinuousRect(aFrame) here may lead to Reset/Init which
+    // resets our mLeftBorderData so we save it ...
+    LeftBorderData saved(mLeftBorderData);
+    nsRect joinedBorderArea = GetContinuousRect(aFrame);
+    if (!saved.mIsValid || saved.mFrame != mLeftBorderData.mFrame) {
+      if (aFrame == mLeftBorderData.mFrame) {
+        mLeftBorderData.SetX(joinedBorderArea.x);
+      } else if (mLeftBorderData.mFrame) {
+        mLeftBorderData.SetX(GetContinuousRect(mLeftBorderData.mFrame).x);
+      }
+    } else {
+      // ... and restore it when possible.
+      mLeftBorderData.mX = saved.mX;
+    }
+    if (joinedBorderArea.x > mLeftBorderData.mX) {
+      joinedBorderArea.x =
+        -(mUnbrokenWidth + joinedBorderArea.x - aBorderArea.width);
+    } else {
+      joinedBorderArea.x -= mLeftBorderData.mX;
+    }
+    return joinedBorderArea;
+  }
+
   nsRect GetBoundingRect(nsIFrame* aFrame)
   {
     SetFrame(aFrame);
 
     // Move the offsets relative to (0,0) which puts the bounding box into
     // our coordinate system rather than our parent's.  We do this by
     // moving it the back distance from us to the bounding box.
     // This also assumes background-origin: border, so our caller will
@@ -152,23 +203,32 @@ struct InlineBackgroundData
     nsRect boundingBox(mBoundingBox);
     nsPoint point = mFrame->GetPosition();
     boundingBox.MoveBy(-point.x, -point.y);
 
     return boundingBox;
   }
 
 protected:
-  nsIFrame*     mFrame;
-  nsBlockFrame* mBlockFrame;
-  nsRect        mBoundingBox;
-  nscoord       mContinuationPoint;
-  nscoord       mUnbrokenWidth;
-  nscoord       mLineContinuationPoint;
-  bool          mBidiEnabled;
+  struct LeftBorderData {
+    nsIFrame* mFrame;   // the continuation that may have a left-border
+    nscoord   mX;       // cached GetContinuousRect(mFrame).x
+    bool      mIsValid; // true if mX is valid
+    void Reset() { mFrame = nullptr; mIsValid = false; }
+    void SetX(nscoord aX) { mX = aX; mIsValid = true; }
+  };
+
+  nsIFrame*      mFrame;
+  nsBlockFrame*  mBlockFrame;
+  nsRect         mBoundingBox;
+  nscoord        mContinuationPoint;
+  nscoord        mUnbrokenWidth;
+  nscoord        mLineContinuationPoint;
+  LeftBorderData mLeftBorderData;
+  bool           mBidiEnabled;
 
   void SetFrame(nsIFrame* aFrame)
   {
     NS_PRECONDITION(aFrame, "Need a frame");
     NS_ASSERTION(gFrameTreeLockCount > 0,
                  "Can't call this when frame tree is not locked");
 
     if (aFrame == mFrame) {
@@ -231,48 +291,56 @@ protected:
         NS_ASSERTION(nextCont, "How did that happen?");
       }
     }
     return nextCont;
   }
 
   void Init(nsIFrame* aFrame)
   {
+    mLeftBorderData.Reset();
     mBidiEnabled = aFrame->PresContext()->BidiEnabled();
     if (mBidiEnabled) {
       // Find the containing block frame
       nsIFrame* frame = aFrame;
       do {
         frame = frame->GetParent();
         mBlockFrame = do_QueryFrame(frame);
       }
       while (frame && frame->IsFrameOfType(nsIFrame::eLineParticipant));
 
       NS_ASSERTION(mBlockFrame, "Cannot find containing block.");
     }
 
     // Start with the previous flow frame as our continuation point
     // is the total of the widths of the previous frames.
     nsIFrame* inlineFrame = GetPrevContinuation(aFrame);
-
     while (inlineFrame) {
+      if (!mLeftBorderData.mFrame &&
+          !(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
+        mLeftBorderData.mFrame = inlineFrame;
+      }
       nsRect rect = inlineFrame->GetRect();
       mContinuationPoint += rect.width;
       if (mBidiEnabled && !AreOnSameLine(aFrame, inlineFrame)) {
         mLineContinuationPoint += rect.width;
       }
       mUnbrokenWidth += rect.width;
       mBoundingBox.UnionRect(mBoundingBox, rect);
       inlineFrame = GetPrevContinuation(inlineFrame);
     }
 
     // Next add this frame and subsequent frames to the bounding box and
     // unbroken width.
     inlineFrame = aFrame;
     while (inlineFrame) {
+      if (!mLeftBorderData.mFrame &&
+          !(inlineFrame->GetSkipSides() & SIDE_BIT_LEFT)) {
+        mLeftBorderData.mFrame = inlineFrame;
+      }
       nsRect rect = inlineFrame->GetRect();
       mUnbrokenWidth += rect.width;
       mBoundingBox.UnionRect(mBoundingBox, rect);
       inlineFrame = GetNextContinuation(inlineFrame);
     }
 
     mFrame = aFrame;
   }
@@ -300,17 +368,18 @@ struct ColorStop {
 };
 
 /* Local functions */
 static void DrawBorderImage(nsPresContext* aPresContext,
                             nsRenderingContext& aRenderingContext,
                             nsIFrame* aForFrame,
                             const nsRect& aBorderArea,
                             const nsStyleBorder& aStyleBorder,
-                            const nsRect& aDirtyRect);
+                            const nsRect& aDirtyRect,
+                            int aSkipSides);
 
 static nscolor MakeBevelColor(mozilla::css::Side whichSide, uint8_t style,
                               nscolor aBackgroundColor,
                               nscolor aBorderColor);
 
 static InlineBackgroundData* gInlineBGData = nullptr;
 
 // Initialize any static variables used by nsCSSRendering.
@@ -366,16 +435,116 @@ MakeBevelColor(mozilla::css::Side whichS
   case NS_SIDE_LEFT:
   default:
     theColor = colors[0];
     break;
   }
   return theColor;
 }
 
+static bool
+GetRadii(nsIFrame* aForFrame, const nsStyleBorder& aBorder,
+         const nsRect& aOrigBorderArea, const nsRect& aBorderArea,
+         gfxCornerSizes* aBgRadii)
+{
+  nscoord radii[8];
+  bool haveRoundedCorners;
+  nsSize sz = aBorderArea.Size();
+  nsSize frameSize = aForFrame->GetSize();
+  if (&aBorder == aForFrame->StyleBorder() &&
+      frameSize == aOrigBorderArea.Size()) {
+    haveRoundedCorners = aForFrame->GetBorderRadii(sz, sz, 0, radii);
+   } else {
+    haveRoundedCorners =
+      nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius, frameSize, sz, 0, radii);
+  }
+  if (haveRoundedCorners) {
+    auto d2a = aForFrame->PresContext()->AppUnitsPerDevPixel();
+    nsCSSRendering::ComputePixelRadii(radii, d2a, aBgRadii);
+  }
+  return haveRoundedCorners;
+}
+
+static nsRect
+JoinBoxesForVerticalSlice(nsIFrame* aFrame, const nsRect& aBorderArea)
+{
+  // Inflate vertically as if our continuations were laid out vertically
+  // adjacent. Note that we don't touch the width.
+  nsRect borderArea = aBorderArea;
+  nscoord h = 0;
+  nsIFrame* f = aFrame->GetNextContinuation();
+  for (; f; f = f->GetNextContinuation()) {
+    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+               "anonymous ib-split block shouldn't have border/background");
+    h += f->GetRect().height;
+  }
+  borderArea.height += h;
+  h = 0;
+  f = aFrame->GetPrevContinuation();
+  for (; f; f = f->GetPrevContinuation()) {
+    MOZ_ASSERT(!(f->GetStateBits() & NS_FRAME_PART_OF_IBSPLIT),
+               "anonymous ib-split block shouldn't have border/background");
+    h += f->GetRect().height;
+  }
+  borderArea.y -= h;
+  borderArea.height += h;
+  return borderArea;
+}
+
+/**
+ * Inflate aBorderArea which is relative to aFrame's origin to calculate
+ * a hypothetical non-split frame area for all the continuations.
+ * See "Joining Boxes for 'slice'" in
+ * http://dev.w3.org/csswg/css-break/#break-decoration
+ */
+enum InlineBoxOrder { eForBorder, eForBackground };
+static nsRect
+JoinBoxesForSlice(nsIFrame* aFrame, const nsRect& aBorderArea,
+                  InlineBoxOrder aOrder)
+{
+  if (aFrame->GetType() == nsGkAtoms::inlineFrame) {
+    return (aOrder == eForBorder
+            ? gInlineBGData->GetBorderContinuousRect(aFrame, aBorderArea)
+            : gInlineBGData->GetContinuousRect(aFrame)) +
+      aBorderArea.TopLeft();
+  }
+  return JoinBoxesForVerticalSlice(aFrame, aBorderArea);
+}
+
+static bool
+IsBoxDecorationSlice(const nsStyleBorder& aStyleBorder)
+{
+  return aStyleBorder.mBoxDecorationBreak ==
+           NS_STYLE_BOX_DECORATION_BREAK_SLICE;
+}
+
+static nsRect
+BoxDecorationRectForBorder(nsIFrame* aFrame, const nsRect& aBorderArea,
+                           const nsStyleBorder* aStyleBorder = nullptr)
+{
+  if (!aStyleBorder) {
+    aStyleBorder = aFrame->StyleBorder();
+  }
+  return ::IsBoxDecorationSlice(*aStyleBorder)
+           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBorder)
+           : aBorderArea;
+}
+
+static nsRect
+BoxDecorationRectForBackground(nsIFrame* aFrame, const nsRect& aBorderArea,
+                               const nsStyleBorder* aStyleBorder = nullptr)
+{
+  if (!aStyleBorder) {
+    aStyleBorder = aFrame->StyleBorder();
+  }
+  return ::IsBoxDecorationSlice(*aStyleBorder)
+           ? ::JoinBoxesForSlice(aFrame, aBorderArea, eForBackground)
+           : aBorderArea;
+}
+
 //----------------------------------------------------------------------
 // Thebes Border Rendering Code Start
 
 /*
  * Compute the float-pixel radii that should be used for drawing
  * this border/outline, given the various input bits.
  */
 /* static */ void
@@ -444,136 +613,133 @@ nsCSSRendering::PaintBorderWithStyleBord
                                            nsRenderingContext& aRenderingContext,
                                            nsIFrame* aForFrame,
                                            const nsRect& aDirtyRect,
                                            const nsRect& aBorderArea,
                                            const nsStyleBorder& aStyleBorder,
                                            nsStyleContext* aStyleContext,
                                            int aSkipSides)
 {
-  nsMargin            border;
-  nscoord             twipsRadii[8];
-  nsCompatibility     compatMode = aPresContext->CompatibilityMode();
-
   SN("++ PaintBorder");
 
   // Check to see if we have an appearance defined.  If so, we let the theme
   // renderer draw the border.  DO not get the data from aForFrame, since the passed in style context
   // may be different!  Always use |aStyleContext|!
   const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme && theme->ThemeSupportsWidget(aPresContext, aForFrame, displayData->mAppearance))
       return; // Let the theme handle it.
   }
 
   if (aStyleBorder.IsBorderImageLoaded()) {
     DrawBorderImage(aPresContext, aRenderingContext, aForFrame,
-                    aBorderArea, aStyleBorder, aDirtyRect);
+                    aBorderArea, aStyleBorder, aDirtyRect, aSkipSides);
     return;
   }
 
   // Get our style context's color struct.
   const nsStyleColor* ourColor = aStyleContext->StyleColor();
 
-  // in NavQuirks mode we want to use the parent's context as a starting point
-  // for determining the background color
-  nsIFrame* bgFrame = nsCSSRendering::FindNonTransparentBackgroundFrame
-    (aForFrame, compatMode == eCompatibility_NavQuirks ? true : false);
+  // In NavQuirks mode we want to use the parent's context as a starting point
+  // for determining the background color.
+  bool quirks = aPresContext->CompatibilityMode() == eCompatibility_NavQuirks;
+  nsIFrame* bgFrame = FindNonTransparentBackgroundFrame(aForFrame, quirks);
   nsStyleContext* bgContext = bgFrame->StyleContext();
   nscolor bgColor =
     bgContext->GetVisitedDependentColor(eCSSProperty_background_color);
 
-  border = aStyleBorder.GetComputedBorder();
-  if ((0 == border.left) && (0 == border.right) &&
-      (0 == border.top) && (0 == border.bottom)) {
+  nsMargin border = aStyleBorder.GetComputedBorder();
+  if (0 == border.left && 0 == border.right &&
+      0 == border.top  && 0 == border.bottom) {
     // Empty border area
     return;
   }
 
-  nsSize frameSize = aForFrame->GetSize();
-  if (&aStyleBorder == aForFrame->StyleBorder() &&
-      frameSize == aBorderArea.Size()) {
-    aForFrame->GetBorderRadii(twipsRadii);
+  // Compute the outermost boundary of the area that might be painted.
+  // Same coordinate space as aBorderArea & aBGClipRect.
+  nsRect joinedBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+  gfxCornerSizes bgRadii;
+  ::GetRadii(aForFrame, aStyleBorder, aBorderArea, joinedBorderArea, &bgRadii);
+
+
+  SF(" joinedBorderArea: %d %d %d %d\n", joinedBorderArea.x, joinedBorderArea.y,
+     joinedBorderArea.width, joinedBorderArea.height);
+
+  // start drawing
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  ctx->Save();
+
+  if (::IsBoxDecorationSlice(aStyleBorder)) {
+    if (aSkipSides == 0) {
+      // No continuations most likely, or ::first-letter that wants all border-
+      // sides on the first continuation.
+      joinedBorderArea = aBorderArea;
+    } else if (joinedBorderArea.IsEqualEdges(aBorderArea)) {
+      // No need for a clip, just skip the sides we don't want.
+      ::ApplySkipSides(aSkipSides, &border);
+    } else {
+      // We're drawing borders around the joined continuation boxes so we need
+      // to clip that to the slice that we want for this frame.
+      aRenderingContext.IntersectClip(aBorderArea);
+    }
   } else {
-    nsIFrame::ComputeBorderRadii(aStyleBorder.mBorderRadius, frameSize,
-                                 aBorderArea.Size(), aSkipSides, twipsRadii);
+    MOZ_ASSERT(joinedBorderArea.IsEqualEdges(aBorderArea),
+               "Should use aBorderArea for box-decoration-break:clone");
+    MOZ_ASSERT(aForFrame->GetSkipSides() == 0,
+               "Should not skip sides for box-decoration-break:clone except "
+               "::first-letter/line continuations or other frame types that "
+               "don't have borders but those shouldn't reach this point.");
   }
 
-  // Turn off rendering for all of the zero sized sides
-  if (aSkipSides & SIDE_BIT_TOP) border.top = 0;
-  if (aSkipSides & SIDE_BIT_RIGHT) border.right = 0;
-  if (aSkipSides & SIDE_BIT_BOTTOM) border.bottom = 0;
-  if (aSkipSides & SIDE_BIT_LEFT) border.left = 0;
-
-  // get the inside and outside parts of the border
-  nsRect outerRect(aBorderArea);
-
-  SF(" outerRect: %d %d %d %d\n", outerRect.x, outerRect.y, outerRect.width, outerRect.height);
-
-  // we can assume that we're already clipped to aDirtyRect -- I think? (!?)
-
-  // Get our conversion values
+  // Convert to dev pixels.
   nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  // convert outer and inner rects
-  gfxRect oRect(nsLayoutUtils::RectToGfxRect(outerRect, twipsPerPixel));
-
-  // convert the border widths
+  gfxRect joinedBorderAreaPx =
+    nsLayoutUtils::RectToGfxRect(joinedBorderArea, twipsPerPixel);
   gfxFloat borderWidths[4] = { gfxFloat(border.top / twipsPerPixel),
                                gfxFloat(border.right / twipsPerPixel),
                                gfxFloat(border.bottom / twipsPerPixel),
                                gfxFloat(border.left / twipsPerPixel) };
 
-  // convert the radii
-  gfxCornerSizes borderRadii;
-  ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
-
   uint8_t borderStyles[4];
   nscolor borderColors[4];
   nsBorderColors *compositeColors[4];
 
   // pull out styles, colors, composite colors
   NS_FOR_CSS_SIDES (i) {
     bool foreground;
     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
     aStyleBorder.GetBorderColor(i, borderColors[i], foreground);
     aStyleBorder.GetCompositeColors(i, &compositeColors[i]);
 
     if (foreground)
       borderColors[i] = ourColor->mColor;
   }
 
   SF(" borderStyles: %d %d %d %d\n", borderStyles[0], borderStyles[1], borderStyles[2], borderStyles[3]);
-
-  // start drawing
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-
-  ctx->Save();
+  //SF ("bgRadii: %f %f %f %f\n", bgRadii[0], bgRadii[1], bgRadii[2], bgRadii[3]);
 
 #if 0
-  // this will draw a transparent red backround underneath the oRect area
+  // this will draw a transparent red backround underneath the border area
   ctx->Save();
-  ctx->Rectangle(oRect);
+  ctx->Rectangle(joinedBorderAreaPx);
   ctx->SetColor(gfxRGBA(1.0, 0.0, 0.0, 0.5));
   ctx->Fill();
   ctx->Restore();
 #endif
 
-  //SF ("borderRadii: %f %f %f %f\n", borderRadii[0], borderRadii[1], borderRadii[2], borderRadii[3]);
-
   nsCSSBorderRenderer br(twipsPerPixel,
                          ctx,
-                         oRect,
+                         joinedBorderAreaPx,
                          borderStyles,
                          borderWidths,
-                         borderRadii,
+                         bgRadii,
                          borderColors,
                          compositeColors,
-                         aSkipSides,
                          bgColor);
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -683,17 +849,17 @@ nsCSSRendering::PaintOutline(nsPresConte
 
   nsCSSBorderRenderer br(twipsPerPixel,
                          ctx,
                          oRect,
                          outlineStyles,
                          outlineWidths,
                          outlineRadii,
                          outlineColors,
-                         nullptr, 0,
+                         nullptr,
                          bgColor);
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -736,17 +902,17 @@ nsCSSRendering::PaintFocus(nsPresContext
   // and PaintOutline do.)
   nsCSSBorderRenderer br(oneDevPixel,
                          ctx,
                          focusRect,
                          focusStyles,
                          focusWidths,
                          focusRadii,
                          focusColors,
-                         nullptr, 0,
+                         nullptr,
                          NS_RGB(255, 0, 0));
   br.DrawBorders();
 
   ctx->Restore();
 
   SN();
 }
 
@@ -991,44 +1157,53 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
                                     const nsRect& aFrameArea,
                                     const nsRect& aDirtyRect,
                                     float aOpacity)
 {
   const nsStyleBorder* styleBorder = aForFrame->StyleBorder();
   nsCSSShadowArray* shadows = styleBorder->mBoxShadow;
   if (!shadows)
     return;
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
+
+  gfxContextAutoSaveRestore gfxStateRestorer;
   bool hasBorderRadius;
   bool nativeTheme; // mutually exclusive with hasBorderRadius
-  gfxCornerSizes borderRadii;
-
-  // Get any border radius, since box-shadow must also have rounded corners if the frame does
   const nsStyleDisplay* styleDisplay = aForFrame->StyleDisplay();
   nsITheme::Transparency transparency;
   if (aForFrame->IsThemed(styleDisplay, &transparency)) {
     // We don't respect border-radius for native-themed widgets
     hasBorderRadius = false;
     // For opaque (rectangular) theme widgets we can take the generic
     // border-box path with border-radius disabled.
     nativeTheme = transparency != nsITheme::eOpaque;
   } else {
     nativeTheme = false;
+    hasBorderRadius = true; // we'll update this below
+  }
+
+  nsRect frameRect = nativeTheme ?
+    aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() :
+    aFrameArea;
+  frameRect = ::BoxDecorationRectForBorder(aForFrame, frameRect);
+
+  // Get any border radius, since box-shadow must also have rounded corners if
+  // the frame does.
+  gfxCornerSizes borderRadii;
+  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
+  if (hasBorderRadius) {
     nscoord twipsRadii[8];
     NS_ASSERTION(aFrameArea.Size() == aForFrame->VisualBorderRectRelativeToSelf().Size(),
                  "unexpected size");
-    hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii);
+    nsSize sz = frameRect.Size();
+    hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
     if (hasBorderRadius) {
       ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
     }
   }
 
-  nsRect frameRect =
-    nativeTheme ? aForFrame->GetVisualOverflowRectRelativeToSelf() + aFrameArea.TopLeft() : aFrameArea;
   gfxRect frameGfxRect(nsLayoutUtils::RectToGfxRect(frameRect, twipsPerPixel));
   frameGfxRect.Round();
 
   // We don't show anything that intersects with the frame we're blurring on. So tell the
   // blurrer not to do unnecessary work there.
   gfxRect skipGfxRect = frameGfxRect;
   bool useSkipGfxRect = true;
   if (nativeTheme) {
@@ -1042,16 +1217,17 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       aForFrame->GetPaddingRect() - aForFrame->GetPosition() + aFrameArea.TopLeft();
     skipGfxRect = nsLayoutUtils::RectToGfxRect(paddingRect, twipsPerPixel);
   } else if (hasBorderRadius) {
     skipGfxRect.Deflate(gfxMargin(
         std::max(borderRadii[C_TL].height, borderRadii[C_TR].height), 0,
         std::max(borderRadii[C_BL].height, borderRadii[C_BR].height), 0));
   }
 
+  int skipSides = aForFrame->GetSkipSides();
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (shadowItem->mInset)
       continue;
 
     nsRect shadowRect = frameRect;
     shadowRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
     if (!nativeTheme) {
@@ -1122,28 +1298,58 @@ nsCSSRendering::PaintBoxShadowOuter(nsPr
       aPresContext->GetTheme()->DrawWidgetBackground(wrapperCtx, aForFrame,
           styleDisplay->mAppearance, aFrameArea, nativeRect);
 
       blurringArea.DoPaint();
       renderContext->Restore();
     } else {
       renderContext->Save();
       // Clip out the area of the actual frame so the shadow is not shown within
-      // the frame
+      // the frame.
       renderContext->NewPath();
       renderContext->Rectangle(shadowGfxRectPlusBlur);
       if (hasBorderRadius) {
         renderContext->RoundedRectangle(frameGfxRect, borderRadii);
       } else {
         renderContext->Rectangle(frameGfxRect);
       }
 
       renderContext->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
       renderContext->Clip();
 
+      // Clip the shadow so that we only get the part that applies to aForFrame.
+      nsRect fragmentClip = shadowRectPlusBlur;
+      if (skipSides) {
+        if (skipSides & SIDE_BIT_LEFT) {
+          nscoord xmost = fragmentClip.XMost();
+          fragmentClip.x = aFrameArea.x;
+          fragmentClip.width = xmost - fragmentClip.x;
+        }
+        if (skipSides & SIDE_BIT_RIGHT) {
+          nscoord xmost = fragmentClip.XMost();
+          nscoord overflow = xmost - aFrameArea.XMost();
+          if (overflow > 0) {
+            fragmentClip.width -= overflow;
+          }
+        }
+        if (skipSides & SIDE_BIT_TOP) {
+          nscoord ymost = fragmentClip.YMost();
+          fragmentClip.y = aFrameArea.y;
+          fragmentClip.height = ymost - fragmentClip.y;
+        }
+        if (skipSides & SIDE_BIT_BOTTOM) {
+          nscoord ymost = fragmentClip.YMost();
+          nscoord overflow = ymost - aFrameArea.YMost();
+          if (overflow > 0) {
+            fragmentClip.height -= overflow;
+          }
+        }
+      }
+      aRenderingContext.IntersectClip(fragmentClip);
+
       gfxCornerSizes clipRectRadii;
       if (hasBorderRadius) {
         gfxFloat spreadDistance = shadowItem->mSpread / twipsPerPixel;
 
         gfxFloat borderSizes[4];
 
         borderSizes[NS_SIDE_LEFT] = spreadDistance;
         borderSizes[NS_SIDE_TOP] = spreadDistance;
@@ -1183,28 +1389,30 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
       !nsContentUtils::IsChromeDoc(aForFrame->GetContent()->GetCurrentDoc())) {
     // There's no way of getting hold of a shape corresponding to a
     // "padding-box" for native-themed widgets, so just don't draw
     // inner box-shadows for them. But we allow chrome to paint inner
     // box shadows since chrome can be aware of the platform theme.
     return;
   }
 
+  NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
+               aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
+
+  nsRect frameRect = ::BoxDecorationRectForBorder(aForFrame, aFrameArea);
+  nsRect paddingRect = frameRect;
+  nsMargin border = aForFrame->GetUsedBorder();
+  paddingRect.Deflate(border);
+
   // Get any border radius, since box-shadow must also have rounded corners
   // if the frame does.
   nscoord twipsRadii[8];
-  NS_ASSERTION(aForFrame->GetType() == nsGkAtoms::fieldSetFrame ||
-               aFrameArea.Size() == aForFrame->GetSize(), "unexpected size");
-  bool hasBorderRadius = aForFrame->GetBorderRadii(twipsRadii);
-  nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
-
-  nsRect paddingRect = aFrameArea;
-  nsMargin border = aForFrame->GetUsedBorder();
-  aForFrame->ApplySkipSides(border);
-  paddingRect.Deflate(border);
+  nsSize sz = frameRect.Size();
+  bool hasBorderRadius = aForFrame->GetBorderRadii(sz, sz, 0, twipsRadii);
+  const nscoord twipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
 
   gfxCornerSizes innerRadii;
   if (hasBorderRadius) {
     gfxCornerSizes borderRadii;
 
     ComputePixelRadii(twipsRadii, twipsPerPixel, &borderRadii);
     gfxFloat borderSizes[4] = {
       gfxFloat(border.top / twipsPerPixel),
@@ -1216,23 +1424,19 @@ nsCSSRendering::PaintBoxShadowInner(nsPr
                                            &innerRadii);
   }
 
   for (uint32_t i = shadows->Length(); i > 0; --i) {
     nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
     if (!shadowItem->mInset)
       continue;
 
-    /*
-     * shadowRect: the frame's padding rect
-     * shadowPaintRect: the area to paint on the temp surface, larger than shadowRect
-     *                  so that blurs still happen properly near the edges
-     * shadowClipRect: the area on the temporary surface within shadowPaintRect
-     *                 that we will NOT paint in
-     */
+    // shadowPaintRect: the area to paint on the temp surface
+    // shadowClipRect: the area on the temporary surface within shadowPaintRect
+    //                 that we will NOT paint in
     nscoord blurRadius = shadowItem->mRadius;
     nsMargin blurMargin =
       nsContextBoxBlur::GetBlurRadiusMargin(blurRadius, twipsPerPixel);
     nsRect shadowPaintRect = paddingRect;
     shadowPaintRect.Inflate(blurMargin);
 
     nsRect shadowClipRect = paddingRect;
     shadowClipRect.MoveBy(shadowItem->mXOffset, shadowItem->mYOffset);
@@ -1501,16 +1705,17 @@ GetBackgroundClip(gfxContext *aCtx, uint
                   const gfxCornerSizes& aBGRadii, nscoord aAppUnitsPerPixel,
                   /* out */ BackgroundClipState* aClipState)
 {
   aClipState->mBGClipArea = aBorderArea;
   aClipState->mHasAdditionalBGClipArea = false;
   aClipState->mCustomClip = false;
   aClipState->mRadiiAreOuter = true;
   aClipState->mClippedRadii = aBGRadii;
+
   if (aForFrame->GetType() == nsGkAtoms::scrollFrame &&
         NS_STYLE_BG_ATTACHMENT_LOCAL == aBackgroundAttachment) {
     // As of this writing, this is still in discussion in the CSS Working Group
     // http://lists.w3.org/Archives/Public/www-style/2013Jul/0250.html
 
     // The rectangle for 'background-clip' scrolls with the content,
     // but the background is also clipped at a non-scrolling 'padding-box'
     // like the content. (See below.)
@@ -1599,25 +1804,23 @@ SetupBackgroundClip(BackgroundClipState&
 
   // If we have rounded corners, clip all subsequent drawing to the
   // rounded rectangle defined by bgArea and bgRadii (we don't know
   // whether the rounded corners intrude on the dirtyRect or not).
   // Do not do this if we have a caller-provided clip rect --
   // as above with bgArea, arguably a bug, but table painting seems
   // to depend on it.
 
-  if (aHaveRoundedCorners || aClipState.mHasAdditionalBGClipArea) {
-    aAutoSR->Reset(aCtx);
-  }
-
   if (aClipState.mHasAdditionalBGClipArea) {
     gfxRect bgAreaGfx = nsLayoutUtils::RectToGfxRect(
       aClipState.mAdditionalBGClipArea, aAppUnitsPerPixel);
     bgAreaGfx.Round();
     bgAreaGfx.Condition();
+
+    aAutoSR->EnsureSaved(aCtx);
     aCtx->NewPath();
     aCtx->Rectangle(bgAreaGfx, true);
     aCtx->Clip();
   }
 
   if (aHaveRoundedCorners) {
     gfxRect bgAreaGfx =
       nsLayoutUtils::RectToGfxRect(aClipState.mBGClipArea, aAppUnitsPerPixel);
@@ -1628,16 +1831,17 @@ SetupBackgroundClip(BackgroundClipState&
       // I think it's become possible to hit this since
       // http://hg.mozilla.org/mozilla-central/rev/50e934e4979b landed.
       NS_WARNING("converted background area should not be empty");
       // Make our caller not do anything.
       aClipState.mDirtyRectGfx.SizeTo(gfxSize(0.0, 0.0));
       return;
     }
 
+    aAutoSR->EnsureSaved(aCtx);
     aCtx->NewPath();
     aCtx->RoundedRectangle(bgAreaGfx, aClipState.mClippedRadii, aClipState.mRadiiAreOuter);
     aCtx->Clip();
   }
 }
 
 static void
 DrawBackgroundColor(BackgroundClipState& aClipState, gfxContext *aCtx,
@@ -2402,43 +2606,33 @@ nsCSSRendering::PaintBackgroundWithSC(ns
 
   // At this point, drawBackgroundImage and drawBackgroundColor are
   // true if and only if we are actually supposed to paint an image or
   // color into aDirtyRect, respectively.
   if (!drawBackgroundImage && !drawBackgroundColor)
     return;
 
   // Compute the outermost boundary of the area that might be painted.
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-
-  // Same coordinate space as aBorderArea & aBGClipRect
+  // Same coordinate space as aBorderArea & aBGClipRect.
+  nsRect paintBorderArea =
+    ::BoxDecorationRectForBackground(aForFrame, aBorderArea, &aBorder);
+  nsRect clipBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aBorder);
   gfxCornerSizes bgRadii;
-  bool haveRoundedCorners;
-  {
-    nscoord radii[8];
-    nsSize frameSize = aForFrame->GetSize();
-    if (&aBorder == aForFrame->StyleBorder() &&
-        frameSize == aBorderArea.Size()) {
-      haveRoundedCorners = aForFrame->GetBorderRadii(radii);
-    } else {
-      haveRoundedCorners = nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius,
-                                   frameSize, aBorderArea.Size(),
-                                   aForFrame->GetSkipSides(), radii);
-    }
-    if (haveRoundedCorners)
-      ComputePixelRadii(radii, appUnitsPerPixel, &bgRadii);
-  }
+  bool haveRoundedCorners =
+    ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The 'bgClipArea' (used only by the image tiling logic, far below)
   // is the caller-provided aBGClipRect if any, or else the area
   // determined by the value of 'background-clip' in
   // SetupCurrentBackgroundClip.  (Arguably it should be the
   // intersection, but that breaks the table painter -- in particular,
   // taking the intersection breaks reftests/bugs/403249-1[ab].)
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
   BackgroundClipState clipState;
   uint8_t currentBackgroundClip;
   bool isSolidBorder;
   if (aBGClipRect) {
     clipState.mBGClipArea = *aBGClipRect;
     clipState.mCustomClip = true;
     SetupDirtyRects(clipState.mBGClipArea, aDirtyRect, appUnitsPerPixel,
                     &clipState.mDirtyRect, &clipState.mDirtyRectGfx);
@@ -2458,25 +2652,27 @@ nsCSSRendering::PaintBackgroundWithSC(ns
       // If we have rounded corners, we need to inflate the background
       // drawing area a bit to avoid seams between the border and
       // background.
       currentBackgroundClip = haveRoundedCorners ?
         NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
     }
 
     GetBackgroundClip(ctx, currentBackgroundClip, bg->BottomLayer().mAttachment,
-                      aForFrame, aBorderArea,
+                      aForFrame, clipBorderArea,
                       aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
                       &clipState);
   }
 
   // If we might be using a background color, go ahead and set it now.
   if (drawBackgroundColor && !isCanvasFrame)
     ctx->SetColor(gfxRGBA(bgColor));
 
+  // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved(ctx)
+  // in the cases we need it.
   gfxContextAutoSaveRestore autoSR;
 
   // If there is no background image, draw a color.  (If there is
   // neither a background image nor a color, we wouldn't have gotten
   // this far.)
   if (!drawBackgroundImage) {
     if (!isCanvasFrame) {
       DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel);
@@ -2526,38 +2722,49 @@ nsCSSRendering::PaintBackgroundWithSC(ns
             NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
         }
         if (currentBackgroundClip != newBackgroundClip || !clipSet) {
           currentBackgroundClip = newBackgroundClip;
           // If clipSet is false that means this is the bottom layer and we
           // already called GetBackgroundClip above and it stored its results
           // in clipState.
           if (clipSet) {
+            autoSR = gfxContextAutoSaveRestore(); // reset the previous one
             GetBackgroundClip(ctx, currentBackgroundClip, layer.mAttachment, aForFrame,
-                              aBorderArea, aDirtyRect, haveRoundedCorners,
+                              clipBorderArea, aDirtyRect, haveRoundedCorners,
                               bgRadii, appUnitsPerPixel, &clipState);
           }
           SetupBackgroundClip(clipState, ctx, haveRoundedCorners,
                               appUnitsPerPixel, &autoSR);
           clipSet = true;
+          if (!clipBorderArea.IsEqualEdges(aBorderArea)) {
+            // We're drawing the background for the joined continuation boxes
+            // so we need to clip that to the slice that we want for this frame.
+            gfxRect clip =
+              nsLayoutUtils::RectToGfxRect(aBorderArea, appUnitsPerPixel);
+            autoSR.EnsureSaved(ctx);
+            ctx->NewPath();
+            ctx->SnappedRectangle(clip);
+            ctx->Clip();
+          }
         }
       }
       if ((aLayer < 0 || i == (uint32_t)startLayer) &&
           !clipState.mDirtyRectGfx.IsEmpty()) {
         nsBackgroundLayerState state = PrepareBackgroundLayer(aPresContext, aForFrame,
-            aFlags, aBorderArea, clipState.mBGClipArea, *bg, layer);
+            aFlags, paintBorderArea, clipState.mBGClipArea, layer);
         if (!state.mFillArea.IsEmpty()) {
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             NS_ASSERTION(ctx->CurrentOperator() == gfxContext::OPERATOR_OVER,
                          "It is assumed the initial operator is OPERATOR_OVER, when it is restored later");
             ctx->SetOperator(state.mCompositingOp);
           }
           state.mImageRenderer.DrawBackground(aPresContext, aRenderingContext,
                                               state.mDestArea, state.mFillArea,
-                                              state.mAnchor + aBorderArea.TopLeft(),
+                                              state.mAnchor + paintBorderArea.TopLeft(),
                                               clipState.mDirtyRect);
           if (state.mCompositingOp != gfxContext::OPERATOR_OVER) {
             ctx->SetOperator(gfxContext::OPERATOR_OVER);
           }
         }
       }
     }
   }
@@ -2602,60 +2809,48 @@ nsCSSRendering::PaintBackgroundColorWith
 
   NS_ASSERTION(drawBackgroundImage || drawBackgroundColor,
                "Should not be trying to paint a background if we don't have one");
   if (!drawBackgroundColor) {
     return;
   }
 
   // Compute the outermost boundary of the area that might be painted.
-  gfxContext *ctx = aRenderingContext.ThebesContext();
-  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
-
-  // Same coordinate space as aBorderArea
+  // Same coordinate space as aBorderArea.
+  nsRect clipBorderArea =
+    ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aBorder);
   gfxCornerSizes bgRadii;
-  bool haveRoundedCorners;
-  {
-    nscoord radii[8];
-    nsSize frameSize = aForFrame->GetSize();
-    if (&aBorder == aForFrame->StyleBorder() &&
-        frameSize == aBorderArea.Size()) {
-      haveRoundedCorners = aForFrame->GetBorderRadii(radii);
-    } else {
-      haveRoundedCorners = nsIFrame::ComputeBorderRadii(aBorder.mBorderRadius,
-                                   frameSize, aBorderArea.Size(),
-                                   aForFrame->GetSkipSides(), radii);
-    }
-    if (haveRoundedCorners)
-      ComputePixelRadii(radii, appUnitsPerPixel, &bgRadii);
-  }
+  bool haveRoundedCorners =
+    ::GetRadii(aForFrame, aBorder, aBorderArea, clipBorderArea, &bgRadii);
 
   // The background is rendered over the 'background-clip' area,
   // which is normally equal to the border area but may be reduced
   // to the padding area by CSS.  Also, if the border is solid, we
   // don't need to draw outside the padding area.  In either case,
   // if the borders are rounded, make sure we use the same inner
   // radii as the border code will.
   // The background-color is drawn based on the bottom
   // background-clip.
+  gfxContext* ctx = aRenderingContext.ThebesContext();
+  nscoord appUnitsPerPixel = aPresContext->AppUnitsPerDevPixel();
   const nsStyleBackground *bg = aBackgroundSC->StyleBackground();
   uint8_t currentBackgroundClip = bg->BottomLayer().mClip;
   bool isSolidBorder =
     (aFlags & PAINTBG_WILL_PAINT_BORDER) && IsOpaqueBorder(aBorder);
   if (isSolidBorder && currentBackgroundClip == NS_STYLE_BG_CLIP_BORDER) {
     // If we have rounded corners, we need to inflate the background
     // drawing area a bit to avoid seams between the border and
     // background.
     currentBackgroundClip = haveRoundedCorners ?
       NS_STYLE_BG_CLIP_MOZ_ALMOST_PADDING : NS_STYLE_BG_CLIP_PADDING;
   }
 
   BackgroundClipState clipState;
   GetBackgroundClip(ctx, currentBackgroundClip, bg->BottomLayer().mAttachment,
-                    aForFrame, aBorderArea,
+                    aForFrame, clipBorderArea,
                     aDirtyRect, haveRoundedCorners, bgRadii, appUnitsPerPixel,
                     &clipState);
 
   ctx->SetColor(gfxRGBA(bgColor));
 
   gfxContextAutoSaveRestore autoSR;
   DrawBackgroundColor(clipState, ctx, haveRoundedCorners, appUnitsPerPixel);
 }
@@ -2670,57 +2865,27 @@ IsTransformed(nsIFrame* aForFrame, nsIFr
   }
   return false;
 }
 
 nsRect
 nsCSSRendering::ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
                                                  nsIFrame* aForFrame,
                                                  const nsRect& aBorderArea,
-                                                 const nsStyleBackground& aBackground,
                                                  const nsStyleBackground::Layer& aLayer,
                                                  nsIFrame** aAttachedToFrame)
 {
   // Compute background origin area relative to aBorderArea now as we may need
   // it to compute the effective image size for a CSS gradient.
-  nsRect bgPositioningArea(0, 0, 0, 0);
+  nsRect bgPositioningArea;
 
   nsIAtom* frameType = aForFrame->GetType();
   nsIFrame* geometryFrame = aForFrame;
-  if (frameType == nsGkAtoms::inlineFrame) {
-    // XXXjwalden Strictly speaking this is not quite faithful to how
-    // background-break is supposed to interact with background-origin values,
-    // but it's a non-trivial amount of work to make it fully conformant, and
-    // until the specification is more finalized (and assuming background-break
-    // even makes the cut) it doesn't make sense to hammer out exact behavior.
-    switch (aBackground.mBackgroundInlinePolicy) {
-    case NS_STYLE_BG_INLINE_POLICY_EACH_BOX:
-      bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
-      break;
-    case NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX:
-      bgPositioningArea = gInlineBGData->GetBoundingRect(aForFrame);
-      break;
-    default:
-      NS_ERROR("Unknown background-inline-policy value!  "
-               "Please, teach me what to do.");
-    case NS_STYLE_BG_INLINE_POLICY_CONTINUOUS:
-      bgPositioningArea = gInlineBGData->GetContinuousRect(aForFrame);
-      break;
-    }
-  } else if (frameType == nsGkAtoms::canvasFrame) {
-    geometryFrame = aForFrame->GetFirstPrincipalChild();
-    // geometryFrame might be null if this canvas is a page created
-    // as an overflow container (e.g. the in-flow content has already
-    // finished and this page only displays the continuations of
-    // absolutely positioned content).
-    if (geometryFrame) {
-      bgPositioningArea = geometryFrame->GetRect();
-    }
-  } else if (frameType == nsGkAtoms::scrollFrame &&
-             NS_STYLE_BG_ATTACHMENT_LOCAL == aLayer.mAttachment) {
+  if (MOZ_UNLIKELY(frameType == nsGkAtoms::scrollFrame &&
+                   NS_STYLE_BG_ATTACHMENT_LOCAL == aLayer.mAttachment)) {
     nsIScrollableFrame* scrollableFrame = do_QueryFrame(aForFrame);
     bgPositioningArea = nsRect(
       scrollableFrame->GetScrolledFrame()->GetPosition()
         // For the dir=rtl case:
         + scrollableFrame->GetScrollRange().TopLeft(),
       scrollableFrame->GetScrolledRect().Size());
     // The ScrolledRect’s size does not include the borders or scrollbars,
     // reverse the handling of background-origin
@@ -2734,30 +2899,40 @@ nsCSSRendering::ComputeBackgroundPositio
       nsMargin padding = geometryFrame->GetUsedPadding();
       geometryFrame->ApplySkipSides(padding);
       bgPositioningArea.Deflate(padding);
       NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
                    "unknown background-origin value");
     }
     *aAttachedToFrame = aForFrame;
     return bgPositioningArea;
+  }
+
+  if (MOZ_UNLIKELY(frameType == nsGkAtoms::canvasFrame)) {
+    geometryFrame = aForFrame->GetFirstPrincipalChild();
+    // geometryFrame might be null if this canvas is a page created
+    // as an overflow container (e.g. the in-flow content has already
+    // finished and this page only displays the continuations of
+    // absolutely positioned content).
+    if (geometryFrame) {
+      bgPositioningArea = geometryFrame->GetRect();
+    }
   } else {
     bgPositioningArea = nsRect(nsPoint(0,0), aBorderArea.Size());
   }
 
   // Background images are tiled over the 'background-clip' area
   // but the origin of the tiling is based on the 'background-origin' area
   if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_BORDER && geometryFrame) {
     nsMargin border = geometryFrame->GetUsedBorder();
     if (aLayer.mOrigin != NS_STYLE_BG_ORIGIN_PADDING) {
       border += geometryFrame->GetUsedPadding();
       NS_ASSERTION(aLayer.mOrigin == NS_STYLE_BG_ORIGIN_CONTENT,
                    "unknown background-origin value");
     }
-    geometryFrame->ApplySkipSides(border);
     bgPositioningArea.Deflate(border);
   }
 
   nsIFrame* attachedToFrame = aForFrame;
   if (NS_STYLE_BG_ATTACHMENT_FIXED == aLayer.mAttachment) {
     // If it's a fixed background attachment, then the image is placed
     // relative to the viewport, which is the area of the root frame
     // in a screen context or the page content frame in a print context.
@@ -2831,32 +3006,31 @@ ComputeDrawnSizeForBackground(const CSSS
 }
 
 nsBackgroundLayerState
 nsCSSRendering::PrepareBackgroundLayer(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        uint32_t aFlags,
                                        const nsRect& aBorderArea,
                                        const nsRect& aBGClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer)
 {
   /*
-   * The background properties we need to keep in mind when drawing background
+   * The properties we need to keep in mind when drawing background
    * layers are:
    *
    *   background-image
    *   background-repeat
    *   background-attachment
    *   background-position
    *   background-clip
    *   background-origin
    *   background-size
-   *   background-break (-moz-background-inline-policy)
    *   background-blend-mode
+   *   box-decoration-break
    *
    * (background-color applies to the entire element and not to individual
    * layers, so it is irrelevant to this method.)
    *
    * These properties have the following dependencies upon each other when
    * determining rendering:
    *
    *   background-image
@@ -2869,32 +3043,31 @@ nsCSSRendering::PrepareBackgroundLayer(n
    *     depends upon background-size (for the image's scaled size) and
    *     background-break (for the background positioning area)
    *   background-clip
    *     no dependencies
    *   background-origin
    *     depends upon background-attachment (only in the case where that value
    *     is 'fixed')
    *   background-size
-   *     depends upon background-break (for the background positioning area for
-   *     resolving percentages), background-image (for the image's intrinsic
+   *     depends upon box-decoration-break (for the background positioning area
+   *     for resolving percentages), background-image (for the image's intrinsic
    *     size), background-repeat (if that value is 'round'), and
    *     background-origin (for the background painting area, when
    *     background-repeat is 'round')
-   *   background-break
-   *     depends upon background-origin (specifying how the boxes making up the
-   *     background positioning area are determined)
+   *   box-decoration-break
+   *     no dependencies
    *
    * As a result of only-if dependencies we don't strictly do a topological
    * sort of the above properties when processing, but it's pretty close to one:
    *
    *   background-clip (by caller)
    *   background-image
-   *   background-break, background-origin
-   *   background-attachment (postfix for background-{origin,break} if 'fixed')
+   *   box-decoration-break, background-origin
+   *   background-attachment (postfix for background-origin if 'fixed')
    *   background-size
    *   background-position
    *   background-repeat
    */
 
   uint32_t irFlags = 0;
   if (aFlags & nsCSSRendering::PAINTBG_SYNC_DECODE_IMAGES) {
     irFlags |= nsImageRenderer::FLAG_SYNC_DECODE_IMAGES;
@@ -2910,17 +3083,17 @@ nsCSSRendering::PrepareBackgroundLayer(n
   }
 
   // The frame to which the background is attached
   nsIFrame* attachedToFrame = aForFrame;
   // Compute background origin area relative to aBorderArea now as we may need
   // it to compute the effective image size for a CSS gradient.
   nsRect bgPositioningArea =
     ComputeBackgroundPositioningArea(aPresContext, aForFrame, aBorderArea,
-                                     aBackground, aLayer, &attachedToFrame);
+                                     aLayer, &attachedToFrame);
 
   // For background-attachment:fixed backgrounds, we'll limit the area
   // where the background can be drawn to the viewport.
   nsRect bgClipRect = aBGClipRect;
 
   // Compute the anchor point.
   //
   // relative to aBorderArea.TopLeft() (which is where the top-left
@@ -2980,23 +3153,23 @@ nsCSSRendering::PrepareBackgroundLayer(n
   return state;
 }
 
 nsRect
 nsCSSRendering::GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags)
 {
+  nsRect borderArea = ::BoxDecorationRectForBackground(aForFrame, aBorderArea);
   nsBackgroundLayerState state =
-      PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, aBorderArea,
-                             aClipRect, aBackground, aLayer);
+      PrepareBackgroundLayer(aPresContext, aForFrame, aFlags, borderArea,
+                             aClipRect, aLayer);
   return state.mFillArea;
 }
 
 /* static */ bool
 nsCSSRendering::IsBackgroundImageDecodedForStyleContextAndLayer(
   const nsStyleBackground *aBackground, uint32_t aLayer)
 {
   const nsStyleImage* image = &aBackground->mLayers[aLayer].mImage;
@@ -3024,17 +3197,18 @@ nsCSSRendering::AreAllBackgroundImagesDe
 }
 
 static void
 DrawBorderImage(nsPresContext*       aPresContext,
                 nsRenderingContext&  aRenderingContext,
                 nsIFrame*            aForFrame,
                 const nsRect&        aBorderArea,
                 const nsStyleBorder& aStyleBorder,
-                const nsRect&        aDirtyRect)
+                const nsRect&        aDirtyRect,
+                int                  aSkipSides)
 {
   NS_PRECONDITION(aStyleBorder.IsBorderImageLoaded(),
                   "drawing border image that isn't successfully loaded");
 
   if (aDirtyRect.IsEmpty())
     return;
 
   nsImageRenderer renderer(aForFrame, &aStyleBorder.mBorderImageSource, 0);
@@ -3046,20 +3220,49 @@ DrawBorderImage(nsPresContext*       aPr
   // different style, they'll potentially have the wrong size for the
   // border too.
   aForFrame->AssociateImage(aStyleBorder.mBorderImageSource, aPresContext);
 
   if (!renderer.PrepareImage()) {
     return;
   }
 
+  // NOTE: no Save() yet, we do that later by calling autoSR.EnsureSaved()
+  // in case we need it.
+  gfxContextAutoSaveRestore autoSR;
+
   // Determine the border image area, which by default corresponds to the
   // border box but can be modified by 'border-image-outset'.
-  nsRect borderImgArea(aBorderArea);
-  borderImgArea.Inflate(aStyleBorder.GetImageOutset());
+  // Note that 'border-radius' do not apply to 'border-image' borders per
+  // <http://dev.w3.org/csswg/css-backgrounds/#corner-clipping>.
+  nsRect borderImgArea;
+  nsMargin borderWidths(aStyleBorder.GetComputedBorder());
+  nsMargin imageOutset(aStyleBorder.GetImageOutset());
+  if (::IsBoxDecorationSlice(aStyleBorder) && aSkipSides != 0) {
+    borderImgArea =
+      ::BoxDecorationRectForBorder(aForFrame, aBorderArea, &aStyleBorder);
+    if (borderImgArea.IsEqualEdges(aBorderArea)) {
+      // No need for a clip, just skip the sides we don't want.
+      ::ApplySkipSides(aSkipSides, &borderWidths);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      borderImgArea.Inflate(imageOutset);
+    } else {
+      // We're drawing borders around the joined continuation boxes so we need
+      // to clip that to the slice that we want for this frame.
+      borderImgArea.Inflate(imageOutset);
+      ::ApplySkipSides(aSkipSides, &imageOutset);
+      nsRect clip = aBorderArea;
+      clip.Inflate(imageOutset);
+      autoSR.EnsureSaved(aRenderingContext.ThebesContext());
+      aRenderingContext.IntersectClip(clip);
+    }
+  } else {
+    borderImgArea = aBorderArea;
+    borderImgArea.Inflate(imageOutset);
+  }
 
   // Calculate the image size used to compute slice points.
   CSSSizeOrRatio intrinsicSize = renderer.ComputeIntrinsicSize();
   nsSize imageSize = nsImageRenderer::ComputeConcreteSize(CSSSizeOrRatio(),
                                                           intrinsicSize,
                                                           borderImgArea.Size());
   renderer.SetPreferredSize(intrinsicSize, imageSize);
 
@@ -3088,17 +3291,16 @@ DrawBorderImage(nsPresContext*       aPr
         break;
     }
     if (value < 0)
       value = 0;
     if (value > imgDimension)
       value = imgDimension;
     slice.Side(s) = value;
 
-    nsMargin borderWidths(aStyleBorder.GetComputedBorder());
     coord = aStyleBorder.mBorderImageWidth.Get(s);
     switch (coord.GetUnit()) {
       case eStyleUnit_Coord: // absolute dimension
         value = coord.GetCoordValue();
         break;
       case eStyleUnit_Percent:
         value = coord.GetPercentValue() * borderDimension;
         break;
@@ -4930,20 +5132,18 @@ nsContextBoxBlur::GetContext()
 
 /* static */ nsMargin
 nsContextBoxBlur::GetBlurRadiusMargin(nscoord aBlurRadius,
                                       int32_t aAppUnitsPerDevPixel)
 {
   gfxIntSize blurRadius = ComputeBlurRadius(aBlurRadius, aAppUnitsPerDevPixel);
 
   nsMargin result;
-  result.top    = blurRadius.height * aAppUnitsPerDevPixel;
-  result.right  = blurRadius.width  * aAppUnitsPerDevPixel;
-  result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
-  result.left   = blurRadius.width  * aAppUnitsPerDevPixel;
+  result.top = result.bottom = blurRadius.height * aAppUnitsPerDevPixel;
+  result.left = result.right = blurRadius.width  * aAppUnitsPerDevPixel;
   return result;
 }
 
 /* static */ void
 nsContextBoxBlur::BlurRectangle(gfxContext* aDestinationCtx,
                                 const nsRect& aRect,
                                 int32_t aAppUnitsPerDevPixel,
                                 gfxCornerSizes* aCornerRadii,
--- a/layout/base/nsCSSRendering.h
+++ b/layout/base/nsCSSRendering.h
@@ -451,27 +451,25 @@ struct nsCSSRendering {
                            nsIFrame* aFrame,
                            bool& aDrawBackgroundImage,
                            bool& aDrawBackgroundColor);
 
   static nsRect
   ComputeBackgroundPositioningArea(nsPresContext* aPresContext,
                                    nsIFrame* aForFrame,
                                    const nsRect& aBorderArea,
-                                   const nsStyleBackground& aBackground,
                                    const nsStyleBackground::Layer& aLayer,
                                    nsIFrame** aAttachedToFrame);
 
   static nsBackgroundLayerState
   PrepareBackgroundLayer(nsPresContext* aPresContext,
                          nsIFrame* aForFrame,
                          uint32_t aFlags,
                          const nsRect& aBorderArea,
                          const nsRect& aBGClipRect,
-                         const nsStyleBackground& aBackground,
                          const nsStyleBackground::Layer& aLayer);
 
   /**
    * Render the background for an element using css rendering rules
    * for backgrounds.
    */
   enum {
     /**
@@ -537,17 +535,16 @@ struct nsCSSRendering {
    * Returns the rectangle covered by the given background layer image, taking
    * into account background positioning, sizing, and repetition, but not
    * clipping.
    */
   static nsRect GetBackgroundLayerRect(nsPresContext* aPresContext,
                                        nsIFrame* aForFrame,
                                        const nsRect& aBorderArea,
                                        const nsRect& aClipRect,
-                                       const nsStyleBackground& aBackground,
                                        const nsStyleBackground::Layer& aLayer,
                                        uint32_t aFlags);
 
   /**
    * Checks if image in layer aLayer of aBackground is currently decoded.
    */
   static bool IsBackgroundImageDecodedForStyleContextAndLayer(
     const nsStyleBackground *aBackground, uint32_t aLayer);
--- a/layout/base/nsCSSRenderingBorders.cpp
+++ b/layout/base/nsCSSRenderingBorders.cpp
@@ -115,27 +115,25 @@ typedef enum {
 nsCSSBorderRenderer::nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
                                          gfxContext* aDestContext,
                                          gfxRect& aOuterRect,
                                          const uint8_t* aBorderStyles,
                                          const gfxFloat* aBorderWidths,
                                          gfxCornerSizes& aBorderRadii,
                                          const nscolor* aBorderColors,
                                          nsBorderColors* const* aCompositeColors,
-                                         int aSkipSides,
                                          nscolor aBackgroundColor)
   : mContext(aDestContext),
     mOuterRect(aOuterRect),
     mBorderStyles(aBorderStyles),
     mBorderWidths(aBorderWidths),
     mBorderRadii(aBorderRadii),
     mBorderColors(aBorderColors),
     mCompositeColors(aCompositeColors),
     mAUPP(aAppUnitsPerPixel),
-    mSkipSides(aSkipSides),
     mBackgroundColor(aBackgroundColor)
 {
   if (!mCompositeColors) {
     static nsBorderColors * const noColors[4] = { nullptr };
     mCompositeColors = &noColors[0];
   }
 
   mInnerRect = mOuterRect;
--- a/layout/base/nsCSSRenderingBorders.h
+++ b/layout/base/nsCSSRenderingBorders.h
@@ -74,17 +74,16 @@ struct nsCSSBorderRenderer {
   nsCSSBorderRenderer(int32_t aAppUnitsPerPixel,
                       gfxContext* aDestContext,
                       gfxRect& aOuterRect,
                       const uint8_t* aBorderStyles,
                       const gfxFloat* aBorderWidths,
                       gfxCornerSizes& aBorderRadii,
                       const nscolor* aBorderColors,
                       nsBorderColors* const* aCompositeColors,
-                      int aSkipSides,
                       nscolor aBackgroundColor);
 
   gfxCornerSizes mBorderCornerDimensions;
 
   // destination context
   gfxContext* mContext;
 
   // the rectangle of the outside and the inside of the border
@@ -100,18 +99,17 @@ struct nsCSSBorderRenderer {
 
   // colors
   const nscolor* mBorderColors;
   nsBorderColors* const* mCompositeColors;
 
   // core app units per pixel
   int32_t mAUPP;
 
-  // misc -- which sides to skip, the background color
-  int mSkipSides;
+  // the background color
   nscolor mBackgroundColor;
 
   // calculated values
   bool mOneUnitBorder;
   bool mNoBorderRadius;
   bool mAvoidStroke;
 
   // For all the sides in the bitmask, would they be rendered
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1929,24 +1929,18 @@ nsDisplayBackgroundImage::IsSingleFixedP
   uint32_t flags = aBuilder->GetBackgroundPaintFlags();
   nsRect borderArea = nsRect(ToReferenceFrame(), mFrame->GetSize());
   const nsStyleBackground::Layer &layer = mBackgroundStyle->mLayers[mLayer];
 
   if (layer.mAttachment != NS_STYLE_BG_ATTACHMENT_FIXED)
     return false;
 
   nsBackgroundLayerState state =
-    nsCSSRendering::PrepareBackgroundLayer(presContext,
-                                           mFrame,
-                                           flags,
-                                           borderArea,
-                                           aClipRect,
-                                           *mBackgroundStyle,
-                                           layer);
-
+    nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags,
+                                           borderArea, aClipRect, layer);
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
   if (!imageRenderer->IsRasterImage())
     return false;
 
   int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel();
   *aDestRect = nsLayoutUtils::RectToGfxRect(state.mFillArea, appUnitsPerDevPixel);
 
@@ -1969,24 +1963,18 @@ nsDisplayBackgroundImage::TryOptimizeToI
     return false;
   }
   nscoord radii[8];
   if (mFrame->GetBorderRadii(radii)) {
     return false;
   }
 
   nsBackgroundLayerState state =
-    nsCSSRendering::PrepareBackgroundLayer(presContext,
-                                           mFrame,
-                                           flags,
-                                           borderArea,
-                                           borderArea,
-                                           *mBackgroundStyle,
-                                           layer);
-
+    nsCSSRendering::PrepareBackgroundLayer(presContext, mFrame, flags,
+                                           borderArea, borderArea, layer);
   nsImageRenderer* imageRenderer = &state.mImageRenderer;
   // We only care about images here, not gradients.
   if (!imageRenderer->IsRasterImage())
     return false;
 
   nsRefPtr<ImageContainer> imageContainer = imageRenderer->GetContainer(aManager);
   // Image is not ready to be made into a layer yet
   if (!imageContainer)
@@ -2189,22 +2177,23 @@ nsDisplayBackgroundImage::GetOpaqueRegio
   *aSnap = false;
 
   if (!mBackgroundStyle)
     return result;
 
 
   *aSnap = true;
 
-  // For policies other than EACH_BOX, don't try to optimize here, since
+  // For NS_STYLE_BOX_DECORATION_BREAK_SLICE, don't try to optimize here, since
   // this could easily lead to O(N^2) behavior inside InlineBackgroundData,
   // which expects frames to be sent to it in content order, not reverse
   // content order which we'll produce here.
   // Of course, if there's only one frame in the flow, it doesn't matter.
-  if (mBackgroundStyle->mBackgroundInlinePolicy == NS_STYLE_BG_INLINE_POLICY_EACH_BOX ||
+  if (mFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_CLONE ||
       (!mFrame->GetPrevContinuation() && !mFrame->GetNextContinuation())) {
     const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
     if (layer.mImage.IsOpaque() && layer.mBlendMode == NS_STYLE_BLEND_NORMAL) {
       nsPresContext* presContext = mFrame->PresContext();
       result = GetInsideClipRegion(this, presContext, layer.mClip, mBounds, aSnap);
     }
   }
 
@@ -2242,17 +2231,17 @@ nsDisplayBackgroundImage::GetPositioning
 {
   if (!mBackgroundStyle) {
     return nsRect();
   }
   nsIFrame* attachedToFrame;
   return nsCSSRendering::ComputeBackgroundPositioningArea(
       mFrame->PresContext(), mFrame,
       nsRect(ToReferenceFrame(), mFrame->GetSize()),
-      *mBackgroundStyle, mBackgroundStyle->mLayers[mLayer],
+      mBackgroundStyle->mLayers[mLayer],
       &attachedToFrame) + ToReferenceFrame();
 }
 
 bool
 nsDisplayBackgroundImage::RenderingMightDependOnPositioningAreaSizeChange()
 {
   if (!mBackgroundStyle)
     return false;
@@ -2356,18 +2345,17 @@ nsDisplayBackgroundImage::GetBoundsInter
   nsRect borderBox = nsRect(ToReferenceFrame(), mFrame->GetSize());
   nsRect clipRect = borderBox;
   if (mFrame->GetType() == nsGkAtoms::canvasFrame) {
     nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
     clipRect = frame->CanvasArea() + ToReferenceFrame();
   }
   const nsStyleBackground::Layer& layer = mBackgroundStyle->mLayers[mLayer];
   return nsCSSRendering::GetBackgroundLayerRect(presContext, mFrame,
-                                                borderBox, clipRect,
-                                                *mBackgroundStyle, layer,
+                                                borderBox, clipRect, layer,
                                                 aBuilder->GetBackgroundPaintFlags());
 }
 
 uint32_t
 nsDisplayBackgroundImage::GetPerFrameKey()
 {
   return (mLayer << nsDisplayItem::TYPE_BITS) |
     nsDisplayItem::GetPerFrameKey();
@@ -2834,21 +2822,18 @@ nsDisplayBoxShadowOuter::Paint(nsDisplay
   nsPoint offset = ToReferenceFrame();
   nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
   nsPresContext* presContext = mFrame->PresContext();
   nsAutoTArray<nsRect,10> rects;
   ComputeDisjointRectangles(mVisibleRegion, &rects);
 
   PROFILER_LABEL("nsDisplayBoxShadowOuter", "Paint");
   for (uint32_t i = 0; i < rects.Length(); ++i) {
-    aCtx->PushState();
-    aCtx->IntersectClip(rects[i]);
     nsCSSRendering::PaintBoxShadowOuter(presContext, *aCtx, mFrame,
                                         borderRect, rects[i], mOpacity);
-    aCtx->PopState();
   }
 }
 
 nsRect
 nsDisplayBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) {
   *aSnap = false;
   return mBounds;
 }
--- a/layout/generic/crashtests/383089-1.html
+++ b/layout/generic/crashtests/383089-1.html
@@ -73,14 +73,14 @@ function foo()
 </style>
 
 </head><body onload="setTimeout(olo, 30);">
 
 <br style="overflow: visible;" id="br1">
 <br style="clear: none;" id="br2">
 <br style="height: auto; clear: both; width: auto;" id="br3">
 <br style="position: static;" id="br4">
-<br style="background: yellow none repeat scroll 0% 0%; background-clip: initial; background-origin: initial; -moz-background-inline-policy: initial; display: inline;" id="br5">
+<br style="background: yellow none repeat scroll 0% 0%; background-clip: initial; background-origin: initial; display: inline;" id="br5">
 <br style="width: 1px; visibility: visible;" id="br6">
 <br style="color: black; width: 2px; display: table-cell;" id="br7">
 <table border="1"><tbody><tr style="display: list-item;" id="tableRow"><td>x</td></tr></tbody></table>
 
 </body></html>
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -844,30 +844,52 @@ nsContainerFrame::DoInlineIntrinsicWidth
 
   // This goes at the beginning no matter how things are broken and how
   // messy the bidi situations are, since per CSS2.1 section 8.6
   // (implemented in bug 328168), the startSide border is always on the
   // first line.
   // This frame is a first-in-flow, but it might have a previous bidi
   // continuation, in which case that continuation should handle the startSide
   // border.
+  // For box-decoration-break:clone we setup clonePBM = startPBM + endPBM and
+  // add that to each line.  For box-decoration-break:slice clonePBM is zero.
+  nscoord clonePBM = 0; // PBM = PaddingBorderMargin
+  const bool sliceBreak =
+    styleBorder->mBoxDecorationBreak == NS_STYLE_BOX_DECORATION_BREAK_SLICE;
   if (!GetPrevContinuation()) {
-    aData->currentLine +=
+    nscoord startPBM =
       // clamp negative calc() to 0
       std::max(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
       styleBorder->GetComputedBorderWidth(startSide) +
       GetCoord(styleMargin->mMargin.Get(startSide), 0);
+    if (MOZ_LIKELY(sliceBreak)) {
+      aData->currentLine += startPBM;
+    } else {
+      clonePBM = startPBM;
+    }
+  }
+
+  nscoord endPBM =
+    // clamp negative calc() to 0
+    std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
+    styleBorder->GetComputedBorderWidth(endSide) +
+    GetCoord(styleMargin->mMargin.Get(endSide), 0);
+  if (MOZ_UNLIKELY(!sliceBreak)) {
+    clonePBM += endPBM;
   }
 
   const nsLineList_iterator* savedLine = aData->line;
   nsIFrame* const savedLineContainer = aData->lineContainer;
 
   nsContainerFrame *lastInFlow;
   for (nsContainerFrame *nif = this; nif;
        nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
+    if (aData->currentLine == 0) {
+      aData->currentLine = clonePBM;
+    }
     for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
          kid = kid->GetNextSibling()) {
       if (aType == nsLayoutUtils::MIN_WIDTH)
         kid->AddInlineMinWidth(aRenderingContext,
                                static_cast<InlineMinWidthData*>(aData));
       else
         kid->AddInlinePrefWidth(aRenderingContext,
                                 static_cast<InlinePrefWidthData*>(aData));
@@ -886,22 +908,18 @@ nsContainerFrame::DoInlineIntrinsicWidth
 
   // This goes at the end no matter how things are broken and how
   // messy the bidi situations are, since per CSS2.1 section 8.6
   // (implemented in bug 328168), the endSide border is always on the
   // last line.
   // We reached the last-in-flow, but it might have a next bidi
   // continuation, in which case that continuation should handle
   // the endSide border.
-  if (!lastInFlow->GetNextContinuation()) {
-    aData->currentLine +=
-      // clamp negative calc() to 0
-      std::max(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
-      styleBorder->GetComputedBorderWidth(endSide) +
-      GetCoord(styleMargin->mMargin.Get(endSide), 0);
+  if (MOZ_LIKELY(!lastInFlow->GetNextContinuation() && sliceBreak)) {
+    aData->currentLine += endPBM;
   }
 }
 
 /* virtual */ nsSize
 nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
                                   nsSize aCBSize, nscoord aAvailableWidth,
                                   nsSize aMargin, nsSize aBorder,
                                   nsSize aPadding, bool aShrinkWrap)
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -948,16 +948,21 @@ nsIFrame::GetUsedPadding() const
     NS_ASSERTION(hasPadding, "We should have padding here! (out of memory?)");
   }
   return padding;
 }
 
 int
 nsIFrame::GetSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   // Convert the logical skip sides to physical sides using the frame's
   // writing mode
   WritingMode writingMode = GetWritingMode();
   int logicalSkip = GetLogicalSkipSides(aReflowState);
   int skip = 0;
 
   if (logicalSkip & LOGICAL_SIDE_B_START) {
     if (writingMode.IsVertical()) {
@@ -1272,34 +1277,42 @@ nsIFrame::OutsetBorderRadii(nscoord aRad
     if (aRadii[hc1] > 0)
       aRadii[hc1] += offset;
     if (aRadii[hc2] > 0)
       aRadii[hc2] += offset;
   }
 }
 
 /* virtual */ bool
-nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
+nsIFrame::GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                         int aSkipSides, nscoord aRadii[8]) const
 {
   if (IsThemed()) {
     // When we're themed, the native theme code draws the border and
     // background, and therefore it doesn't make sense to tell other
     // code that's interested in border-radius that we have any radii.
     //
     // In an ideal world, we might have a way for the them to tell us an
     // border radius, but since we don't, we're better off assuming
     // zero.
     NS_FOR_CSS_HALF_CORNERS(corner) {
       aRadii[corner] = 0;
     }
     return false;
   }
-  nsSize size = GetSize();
-  return ComputeBorderRadii(StyleBorder()->mBorderRadius, size, size,
-                            GetSkipSides(), aRadii);
+  return ComputeBorderRadii(StyleBorder()->mBorderRadius,
+                            aFrameSize, aBorderArea,
+                            aSkipSides, aRadii);
+}
+
+bool
+nsIFrame::GetBorderRadii(nscoord aRadii[8]) const
+{
+  nsSize sz = GetSize();
+  return GetBorderRadii(sz, sz, GetSkipSides(), aRadii);
 }
 
 bool
 nsIFrame::GetPaddingBoxBorderRadii(nscoord aRadii[8]) const
 {
   if (!GetBorderRadii(aRadii))
     return false;
   InsetBorderRadii(aRadii, GetUsedBorder());
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -4361,20 +4361,25 @@ ReduceRadii(nscoord aXBorder, nscoord aY
  * Implement an override for nsIFrame::GetBorderRadii to ensure that
  * the clipping region for the border radius does not clip the scrollbars.
  *
  * In other words, we require that the border radius be reduced until the
  * inner border radius at the inner edge of the border is 0 wherever we
  * have scrollbars.
  */
 bool
-ScrollFrameHelper::GetBorderRadii(nscoord aRadii[8]) const
+ScrollFrameHelper::GetBorderRadii(const nsSize& aFrameSize,
+                                  const nsSize& aBorderArea,
+                                  int aSkipSides,
+                                  nscoord aRadii[8]) const
 {
-  if (!mOuter->nsContainerFrame::GetBorderRadii(aRadii))
+  if (!mOuter->nsContainerFrame::GetBorderRadii(aFrameSize, aBorderArea,
+                                                aSkipSides, aRadii)) {
     return false;
+  }
 
   // Since we can use GetActualScrollbarSizes (rather than
   // GetDesiredScrollbarSizes) since this doesn't affect reflow, we
   // probably should.
   nsMargin sb = GetActualScrollbarSizes();
   nsMargin border = mOuter->GetUsedBorder();
 
   if (sb.left > 0 || sb.top > 0) {
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -66,17 +66,18 @@ public:
                         const nsDisplayListSet& aLists);
 
   void AppendScrollPartsTo(nsDisplayListBuilder*   aBuilder,
                            const nsRect&           aDirtyRect,
                            const nsDisplayListSet& aLists,
                            bool&                   aCreateLayer,
                            bool                    aPositioned);
 
-  bool GetBorderRadii(nscoord aRadii[8]) const;
+  bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                      int aSkipSides, nscoord aRadii[8]) const;
 
   // nsIReflowCallback
   virtual bool ReflowFinished() MOZ_OVERRIDE;
   virtual void ReflowCallbackCanceled() MOZ_OVERRIDE;
 
   /**
    * @note This method might destroy the frame, pres shell and other objects.
    * Called when the 'curpos' attribute on one of the scrollbars changes.
@@ -466,18 +467,19 @@ public:
                                nsHTMLReflowMetrics* aMetrics,
                                bool aFirstPass);
   nsresult ReflowContents(ScrollReflowState* aState,
                           const nsHTMLReflowMetrics& aDesiredSize);
   void PlaceScrollArea(const ScrollReflowState& aState,
                        const nsPoint& aScrollPosition);
   nscoord GetIntrinsicVScrollbarWidth(nsRenderingContext *aRenderingContext);
 
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const MOZ_OVERRIDE {
-    return mHelper.GetBorderRadii(aRadii);
+  virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                              int aSkipSides, nscoord aRadii[8]) const MOZ_OVERRIDE {
+    return mHelper.GetBorderRadii(aFrameSize, aBorderArea, aSkipSides, aRadii);
   }
 
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext) MOZ_OVERRIDE;
   virtual nsresult GetPadding(nsMargin& aPadding) MOZ_OVERRIDE;
   virtual bool IsCollapsed() MOZ_OVERRIDE;
   
   virtual nsresult Reflow(nsPresContext*           aPresContext,
@@ -803,18 +805,19 @@ public:
   virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
 
   NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState) MOZ_OVERRIDE;
   virtual nsresult GetPadding(nsMargin& aPadding) MOZ_OVERRIDE;
 
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const MOZ_OVERRIDE {
-    return mHelper.GetBorderRadii(aRadii);
+  virtual bool GetBorderRadii(const nsSize& aFrameSize, const nsSize& aBorderArea,
+                              int aSkipSides, nscoord aRadii[8]) const MOZ_OVERRIDE {
+    return mHelper.GetBorderRadii(aFrameSize, aBorderArea, aSkipSides, aRadii);
   }
 
   nsresult Layout(nsBoxLayoutState& aState);
   void LayoutScrollArea(nsBoxLayoutState& aState, const nsPoint& aScrollPosition);
 
   static bool AddRemoveScrollbar(bool& aHasScrollbar, 
                                    nscoord& aXY, 
                                    nscoord& aSize, 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1037,22 +1037,26 @@ public:
    * radii into zero, and OutsetBorderRadii does not inflate zero radii.
    * Therefore, callers should always inset or outset directly from the
    * original value coming from style.
    */
   static void InsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
   static void OutsetBorderRadii(nscoord aRadii[8], const nsMargin &aOffsets);
 
   /**
-   * Fill in border radii for this frame.  Return whether any are
-   * nonzero.
-   *
+   * Fill in border radii for this frame.  Return whether any are nonzero.
    * Indices into aRadii are the NS_CORNER_* constants in nsStyleConsts.h
+   * aSkipSides is a union of SIDE_BIT_LEFT/RIGHT/TOP/BOTTOM bits that says
+   * which side(s) to skip.
    */
-  virtual bool GetBorderRadii(nscoord aRadii[8]) const;
+  virtual bool GetBorderRadii(const nsSize& aFrameSize,
+                              const nsSize& aBorderArea,
+                              int aSkipSides,
+                              nscoord aRadii[8]) const;
+  bool GetBorderRadii(nscoord aRadii[8]) const;
 
   bool GetPaddingBoxBorderRadii(nscoord aRadii[8]) const;
   bool GetContentBoxBorderRadii(nscoord aRadii[8]) const;
 
   /**
    * Get the position of the frame's baseline, relative to the top of
    * the frame (its top border edge).  Only valid when Reflow is not
    * needed.
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1777,16 +1777,20 @@ nsImageFrame::List(FILE* out, const char
   }
   fprintf_stderr(out, "%s\n", str.get());
 }
 #endif
 
 int
 nsImageFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
   int skip = 0;
   if (nullptr != GetPrevInFlow()) {
     skip |= LOGICAL_SIDE_B_START;
   }
   if (nullptr != GetNextInFlow()) {
     skip |= LOGICAL_SIDE_B_END;
   }
   return skip;
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -110,17 +110,21 @@ nsInlineFrame::IsSelfEmpty()
     border->GetComputedBorderWidth(NS_SIDE_RIGHT) != 0 ||
     !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetRight()) ||
     !IsMarginZero(margin->mMargin.GetRight());
   bool haveLeft =
     border->GetComputedBorderWidth(NS_SIDE_LEFT) != 0 ||
     !nsLayoutUtils::IsPaddingZero(padding->mPadding.GetLeft()) ||
     !IsMarginZero(margin->mMargin.GetLeft());
   if (haveLeft || haveRight) {
-    if (GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) {
+    // We skip this block and return false for box-decoration-break:clone since
+    // in that case all the continuations will have the border/padding/margin.
+    if ((GetStateBits() & NS_FRAME_PART_OF_IBSPLIT) &&
+        StyleBorder()->mBoxDecorationBreak ==
+          NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
       bool haveStart, haveEnd;
       if (NS_STYLE_DIRECTION_LTR == StyleVisibility()->mDirection) {
         haveStart = haveLeft;
         haveEnd = haveRight;
       } else {
         haveStart = haveRight;
         haveEnd = haveLeft;
       }
@@ -486,19 +490,25 @@ nsInlineFrame::ReflowFrames(nsPresContex
   nsresult rv = NS_OK;
   aStatus = NS_FRAME_COMPLETE;
 
   nsLineLayout* lineLayout = aReflowState.mLineLayout;
   bool inFirstLine = aReflowState.mLineLayout->GetInFirstLine();
   RestyleManager* restyleManager = aPresContext->RestyleManager();
   WritingMode wm = aReflowState.GetWritingMode();
   nscoord startEdge = 0;
+  const bool boxDecorationBreakClone =
+    MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                   NS_STYLE_BOX_DECORATION_BREAK_CLONE);
   // Don't offset by our start borderpadding if we have a prev continuation or
-  // if we're in a part of an {ib} split other than the first one.
-  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
+  // if we're in a part of an {ib} split other than the first one. For
+  // box-decoration-break:clone we always offset our start since all
+  // continuations have border/padding.
+  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
+      boxDecorationBreakClone) {
     startEdge = aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   }
   nscoord availableISize = aReflowState.AvailableISize();
   NS_ASSERTION(availableISize != NS_UNCONSTRAINEDSIZE,
                "should no longer use available widths");
   // Subtract off inline axis border+padding from availableISize
   availableISize -= startEdge;
   availableISize -= aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
@@ -649,31 +659,35 @@ nsInlineFrame::ReflowFrames(nsPresContex
   // that are empty we force to empty so that things like collapsed
   // whitespace in an inline element don't affect the line-height.
   aMetrics.ISize() = lineLayout->EndSpan(this);
 
   // Compute final width.
 
   // Make sure to not include our start border and padding if we have a prev
   // continuation or if we're in a part of an {ib} split other than the first
-  // one.
-  if (!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) {
+  // one.  For box-decoration-break:clone we always include our start border
+  // and padding since all continuations have them.
+  if ((!GetPrevContinuation() && !FrameIsNonFirstInIBSplit()) ||
+      boxDecorationBreakClone) {
     aMetrics.ISize() += aReflowState.ComputedLogicalBorderPadding().IStart(wm);
   }
 
   /*
    * We want to only apply the end border and padding if we're the last
    * continuation and either not in an {ib} split or the last part of it.  To
    * be the last continuation we have to be complete (so that we won't get a
    * next-in-flow) and have no non-fluid continuations on our continuation
-   * chain.
+   * chain.  For box-decoration-break:clone we always apply the end border and
+   * padding since all continuations have them.
    */
-  if (NS_FRAME_IS_COMPLETE(aStatus) &&
-      !LastInFlow()->GetNextContinuation() &&
-      !FrameIsNonLastInIBSplit()) {
+  if ((NS_FRAME_IS_COMPLETE(aStatus) &&
+       !LastInFlow()->GetNextContinuation() &&
+       !FrameIsNonLastInIBSplit()) ||
+      boxDecorationBreakClone) {
     aMetrics.Width() += aReflowState.ComputedLogicalBorderPadding().IEnd(wm);
   }
 
   nsRefPtr<nsFontMetrics> fm;
   float inflation = nsLayoutUtils::FontSizeInflationFor(this);
   nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm), inflation);
   aReflowState.rendContext->SetFont(fm);
 
@@ -867,16 +881,21 @@ nsInlineFrame::PushFrames(nsPresContext*
 }
 
 
 //////////////////////////////////////////////////////////////////////
 
 int
 nsInlineFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   int skip = 0;
   if (!IsFirst()) {
     nsInlineFrame* prev = (nsInlineFrame*) GetPrevContinuation();
     if ((GetStateBits() & NS_INLINE_FRAME_BIDI_VISUAL_STATE_IS_SET) ||
         (prev && (prev->mRect.height || prev->mRect.width))) {
       // Prev continuation is not empty therefore we don't render our start
       // border edge.
       skip |= LOGICAL_SIDE_I_START;
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -1071,19 +1071,22 @@ nsLineLayout::ApplyStartMargin(PerFrameD
   WritingMode frameWM = pfd->mFrame->GetWritingMode();
   WritingMode lineWM = mRootSpan->mWritingMode;
 
   // Only apply start-margin on the first-in flow for inline frames,
   // and make sure to not apply it to any inline other than the first
   // in an ib split.  Note that the ib sibling (block-in-inline
   // sibling) annotations only live on the first continuation, but we
   // don't want to apply the start margin for later continuations
-  // anyway.
-  if (pfd->mFrame->GetPrevContinuation() ||
-      pfd->mFrame->FrameIsNonFirstInIBSplit()) {
+  // anyway.  For box-decoration-break:clone we apply the start-margin
+  // on all continuations.
+  if ((pfd->mFrame->GetPrevContinuation() ||
+       pfd->mFrame->FrameIsNonFirstInIBSplit()) &&
+      aReflowState.mStyleBorder->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
     // Zero this out so that when we compute the max-element-width of
     // the frame we will properly avoid adding in the starting margin.
     pfd->mMargin.IStart(frameWM) = 0;
   }
   if ((pfd->mFrame->LastInFlow()->GetNextContinuation() ||
       pfd->mFrame->FrameIsNonLastInIBSplit())
     && !pfd->GetFlag(PFD_ISLETTERFRAME)) {
     pfd->mMargin.IEnd(frameWM) = 0;
@@ -1155,25 +1158,30 @@ nsLineLayout::CanPlaceFrame(PerFrameData
    * 1) The frame is not complete (in this case it will get a next-in-flow)
    * 2) The frame is complete but has a non-fluid continuation on its
    *    continuation chain.  Note that if it has a fluid continuation, that
    *    continuation will get destroyed later, so we don't want to drop the
    *    end-margin in that case.
    * 3) The frame is in an {ib} split and is not the last part.
    *
    * However, none of that applies if this is a letter frame (XXXbz why?)
+   *
+   * For box-decoration-break:clone we apply the end margin on all
+   * continuations (that are not letter frames).
    */
   if (pfd->mFrame->GetPrevContinuation() ||
       pfd->mFrame->FrameIsNonFirstInIBSplit()) {
     pfd->mMargin.IStart(frameWM) = 0;
   }
   if ((NS_FRAME_IS_NOT_COMPLETE(aStatus) ||
        pfd->mFrame->LastInFlow()->GetNextContinuation() ||
-       pfd->mFrame->FrameIsNonLastInIBSplit())
-      && !pfd->GetFlag(PFD_ISLETTERFRAME)) {
+       pfd->mFrame->FrameIsNonLastInIBSplit()) &&
+      !pfd->GetFlag(PFD_ISLETTERFRAME) &&
+      pfd->mFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_SLICE) {
     pfd->mMargin.IEnd(frameWM) = 0;
   }
   LogicalMargin usedMargins = pfd->mMargin.ConvertTo(lineWM, frameWM);
   nscoord startMargin = usedMargins.IStart(lineWM);
   nscoord endMargin = usedMargins.IEnd(lineWM);
 
   if (!(lineWM.IsBidiLTR() && frameWM.IsBidiLTR())) {
     pfd->mBounds.IStart(lineWM) += startMargin;
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -248,18 +248,22 @@ nsSplittableFrame::GetEffectiveComputedH
 
 int
 nsSplittableFrame::GetLogicalSkipSides(const nsHTMLReflowState* aReflowState) const
 {
   if (IS_TRUE_OVERFLOW_CONTAINER(this)) {
     return LOGICAL_SIDES_B_BOTH;
   }
 
+  if (MOZ_UNLIKELY(StyleBorder()->mBoxDecorationBreak ==
+                     NS_STYLE_BOX_DECORATION_BREAK_CLONE)) {
+    return 0;
+  }
+
   int skip = 0;
-
   if (GetPrevInFlow()) {
     skip |= LOGICAL_SIDE_B_START;
   }
 
   if (aReflowState) {
     // We're in the midst of reflow right now, so it's possible that we haven't
     // created a nif yet. If our content height is going to exceed our available
     // height, though, then we're going to need a next-in-flow, it just hasn't
deleted file mode 100644
--- a/layout/reftests/backgrounds/background-size-bounding-box.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>background-break: bounding-box</title>
-  <style type="text/css">
-@font-face
-{
-  font-family: Ahem;
-  src: url(../fonts/Ahem.ttf);
-}
-
-#outer
-{
-  border: 1px solid black;
-  width: 10em;
-}
-#ahem-lines
-{
-  font-family: Ahem;
-  font-size: 32px;
-  white-space: pre;
-  background-image: url(blue-8x20-green-8x20.png);
-  background-repeat: no-repeat;
-  -moz-background-inline-policy: bounding-box;
-}
-</style>
-</head>
-<body>
-<div id="outer">
-<span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
-      <!-- EOL -->
-      <!-- EOL -->
-      </span></div>
-</body>
-</html>
rename from layout/reftests/backgrounds/background-size-each-box.html
rename to layout/reftests/backgrounds/background-size-clone.html
--- a/layout/reftests/backgrounds/background-size-each-box.html
+++ b/layout/reftests/backgrounds/background-size-clone.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-break: each-box</title>
+  <title>box-decoration-break: clone</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -16,21 +16,21 @@
 }
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
-  -moz-background-inline-policy: each-box;
+  box-decoration-break: clone;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for clone --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
deleted file mode 100644
--- a/layout/reftests/backgrounds/background-size-cover-bounding-box.html
+++ /dev/null
@@ -1,37 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-  <title>background-size: cover; background-break: bounding-box</title>
-  <style type="text/css">
-@font-face
-{
-  font-family: Ahem;
-  src: url(../fonts/Ahem.ttf);
-}
-
-#outer
-{
-  border: 1px solid black;
-  width: 10em;
-}
-#ahem-lines
-{
-  font-family: Ahem;
-  font-size: 32px;
-  white-space: pre;
-  background-image: url(blue-8x20-green-8x20.png);
-  background-repeat: no-repeat;
-  background-size: cover;
-  -moz-background-inline-policy: bounding-box;
-}
-</style>
-</head>
-<body>
-<div id="outer">
-<span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
-      <!-- EOL -->
-      <!-- EOL -->
-      </span></div>
-</body>
-</html>
rename from layout/reftests/backgrounds/background-size-cover-each-box.html
rename to layout/reftests/backgrounds/background-size-cover-clone.html
--- a/layout/reftests/backgrounds/background-size-cover-each-box.html
+++ b/layout/reftests/backgrounds/background-size-cover-clone.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-size: cover; background-break: each-box</title>
+  <title>background-size: cover; box-decoration-break: clone</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -17,21 +17,21 @@
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
   background-size: cover;
-  -moz-background-inline-policy: each-box;
+  box-decoration-break: clone;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for clone --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
rename from layout/reftests/backgrounds/background-size-cover-continuous.html
rename to layout/reftests/backgrounds/background-size-cover-slice.html
--- a/layout/reftests/backgrounds/background-size-cover-continuous.html
+++ b/layout/reftests/backgrounds/background-size-cover-slice.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-size: cover; background-break: continuous</title>
+  <title>background-size: cover; box-decoration-break: slice</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -17,21 +17,21 @@
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
   background-size: cover;
-  -moz-background-inline-policy: continuous;
+  box-decoration-break: slice;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for slice --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
rename from layout/reftests/backgrounds/background-size-continuous.html
rename to layout/reftests/backgrounds/background-size-slice.html
--- a/layout/reftests/backgrounds/background-size-continuous.html
+++ b/layout/reftests/backgrounds/background-size-slice.html
@@ -1,12 +1,12 @@
 <!DOCTYPE html>
 <html>
 <head>
-  <title>background-break: continuous</title>
+  <title>box-decoration-break: slice</title>
   <style type="text/css">
 @font-face
 {
   font-family: Ahem;
   src: url(../fonts/Ahem.ttf);
 }
 
 #outer
@@ -16,21 +16,21 @@
 }
 #ahem-lines
 {
   font-family: Ahem;
   font-size: 32px;
   white-space: pre;
   background-image: url(blue-8x20-green-8x20.png);
   background-repeat: no-repeat;
-  -moz-background-inline-policy: continuous;
+  box-decoration-break: slice;
 }
 </style>
 </head>
 <body>
 <div id="outer">
 <span id="ahem-lines">      <!-- EOL -->
-        <!-- mix it up for each-box and bounding-box --><!-- EOL -->
+        <!-- mix it up for slice --><!-- EOL -->
       <!-- EOL -->
       <!-- EOL -->
       </span></div>
 </body>
 </html>
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -85,29 +85,25 @@ fails-if(smallScreen&&Android) != backgr
 == background-size-contain-clip-border.html background-size-contain-clip-border-ref.html
 == background-size-contain-position-fifty-fifty.html background-size-contain-position-fifty-fifty-ref.html
 == background-size-contain-clip-padding-origin-border.html background-size-contain-clip-padding-origin-border-ref.html
 == background-size-contain-clip-padding-origin-border-padding.html background-size-contain-clip-padding-origin-border-padding-ref.html
 
 skip-if(B2G) == background-layers-1a.html background-layers-1-ref.html # bug 773482
 == background-layers-1b.html background-layers-1-ref.html
 
-# -moz-background-inline-policy is touchy and hard to test due to stretching
-# artifacts and the difficulty of covering exact lines, and its CSS3 analog is
-# on the chopping block at the moment, so just make sure background-size results
-# in a different rendering when present.
-!= background-size-cover-continuous.html background-size-continuous.html
-!= background-size-cover-each-box.html background-size-each-box.html
-!= background-size-cover-bounding-box.html background-size-bounding-box.html
+# box-decoration-break's effect on backgrounds is touchy and hard to test due to stretching
+# artifacts and the difficulty of covering exact lines, so just make sure
+# background-size results in a different rendering when present.
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-slice.html
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-clone.html background-size-clone.html
 
 # ...and make sure each rendering with background-size is different from the
-# others
-!= background-size-cover-continuous.html background-size-cover-each-box.html
-!= background-size-cover-continuous.html background-size-cover-bounding-box.html
-!= background-size-cover-each-box.html background-size-cover-bounding-box.html
+# other
+pref(layout.css.box-decoration-break.enabled,true) != background-size-cover-slice.html background-size-cover-clone.html
 
 == background-size-monster-ch.html background-size-monster-ref.html
 == background-size-monster-cm.html background-size-monster-ref.html
 == background-size-monster-em.html background-size-monster-ref.html
 == background-size-monster-ex.html background-size-monster-ref.html
 == background-size-monster-inches.html background-size-monster-ref.html
 == background-size-monster-mm.html background-size-monster-ref.html
 == background-size-monster-pc.html background-size-monster-ref.html
--- a/layout/reftests/bugs/368020-3-ref.html
+++ b/layout/reftests/bugs/368020-3-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: continuous; background-inline-policy: continuous;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-origin: padding-box; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/368020-3.html
+++ b/layout/reftests/bugs/368020-3.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px; -moz-background-inline-policy: continuous; background-inline-policy: continuous;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-origin: content-box; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
deleted file mode 100644
--- a/layout/reftests/bugs/368020-4-ref.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<title>Testcase, bug 368020</title>
-</head>
-<body style="line-height: 3; width: 500px; height: 250px;">
-
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: bounding-box; background-inline-policy: bounding-box;">
-        blah<br>
-        blah<br>
-        blah
-    </span>
-
-</body>
-</html>
deleted file mode 100644
--- a/layout/reftests/bugs/368020-4.html
+++ /dev/null
@@ -1,15 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-<title>Testcase, bug 368020</title>
-</head>
-<body style="line-height: 3; width: 500px; height: 250px;">
-
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 2% 3% 2px; -moz-background-inline-policy: bounding-box; background-inline-policy: bounding-box;">
-        blah<br>
-        blah<br>
-        blah
-    </span>
-
-</body>
-</html>
--- a/layout/reftests/bugs/368020-5-ref.html
+++ b/layout/reftests/bugs/368020-5-ref.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-clip: border; background-origin: padding-box; background-origin: padding; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; -moz-background-inline-policy: each-box; background-inline-policy: each-box;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: border-box; background-origin: padding-box; margin: 7px 4px 2px 18px; border: 6px transparent solid; border-width: 2px 10px 15px 2px; box-decoration-break: clone;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/368020-5.html
+++ b/layout/reftests/bugs/368020-5.html
@@ -1,15 +1,15 @@
 <!DOCTYPE HTML>
 <html>
 <head>
 <title>Testcase, bug 368020</title>
 </head>
 <body style="line-height: 3; width: 500px; height: 250px;">
 
-    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-clip: padding; background-origin: content-box; background-origin: content; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 10px 15px 2px; -moz-background-inline-policy: each-box; background-inline-policy: each-box;">
+    <span style="background: url(repeatable-diagonal-gradient.png); background-clip: padding-box; background-origin: content-box; border: medium transparent solid; border-width: 7px 4px 2px 18px; padding: 2px 10px 15px 2px; box-decoration-break: clone;">
         blah<br>
         blah<br>
         blah
     </span>
 
 </body>
 </html>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -590,19 +590,18 @@ skip-if(B2G) == 367247-l-scroll.html 367
 == 367612-1b.html 367612-1-ref.html
 == 367612-1c.html 367612-1-ref.html
 == 367612-1d.html 367612-1-ref.html
 == 367612-1e.html 367612-1-ref.html
 == 367612-1f.html 367612-1-ref.html
 != 367612-1g.html 367612-1-ref.html
 skip-if(B2G) random-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == 368020-1.html 368020-1-ref.html
 == 368020-2.html 368020-2-ref.html
-fails == 368020-3.html 368020-3-ref.html # bug 368085
-fails == 368020-4.html 368020-4-ref.html # bug 368085
-== 368020-5.html 368020-5-ref.html
+== 368020-3.html 368020-3-ref.html
+pref(layout.css.box-decoration-break.enabled,true) == 368020-5.html 368020-5-ref.html
 == 368155-1.xhtml 368155-1-ref.xhtml
 asserts(4) == 368155-negative-margins-1.html 368155-negative-margins-1-ref.html # bug 387205 / bug 457397
 # we can't test this because there's antialiasing involved, and our comparison
 # is too exact
 # == 368247-1.html 368247-1-ref.html
 == 368247-2.html 368247-2-ref.html
 == 368504-1.html 368504-1-ref.html
 == 368504-2.html 368504-2-ref.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-1-ref.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+
+span {
+  line-height:4em;
+  font-family:monospace;
+  padding: 3px 5px 7px 11px;
+  background-color: #0F0;
+  margin: 13px 17px 19px 23px;
+  border-left:13px dashed pink;
+  border-top:7px dashed blue;
+  border-right:3px dashed black;
+  border-bottom:1px dashed blue;
+}
+.o0 {
+  border-radius: 17px;
+}
+.o10 {
+  border-radius: 17px;
+  margin-left:0;
+}
+.o10x {
+  border-radius: 17px;
+  padding-right:0;
+}
+.so0 {
+  border-radius: 0px;
+}
+.so10 {
+  border-radius: 0px;
+  margin-right:0;
+}
+.so10x {
+  border-radius: 0px;
+  padding-left:0;
+}
+</style>
+</head>
+<body style="margin:10px">
+
+<table border=1 cellpadding=10><tr>
+<td><span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+<br>
+
+<table border=1 cellpadding=10><tr>
+<td><span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-1.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-1-ref.html">
+  <meta charset="utf-8">
+<style>
+
+span {
+  box-decoration-break:clone;
+
+  line-height:4em;
+  font-family:monospace;
+  padding: 3px 5px 7px 11px;
+  background-color: #0F0;
+  margin: 13px 17px 19px 23px;
+  border-left:13px dashed pink;
+  border-top:7px dashed blue;
+  border-right:3px dashed black;
+  border-bottom:1px dashed blue;
+}
+.o0 {
+  border-radius: 17px;
+}
+.o10 {
+  border-radius: 17px;
+  margin-left:0;
+}
+.o10x {
+  border-radius: 17px;
+  padding-right:0;
+}
+.so0 {
+  border-radius: 0px;
+}
+.so10 {
+  border-radius: 0px;
+  margin-right:0;
+}
+.so10x {
+  border-radius: 0px;
+  padding-left:0;
+}
+</style>
+</head>
+<body style="margin:10px">
+
+<table border=1 cellpadding=10><tr>
+<td><span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+<td><span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span></td>
+</tr>
+</table>
+
+<br>
+
+<table border=1 cellpadding=10><tr>
+<td><span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+<td><span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+<td><span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br></td>
+</tr>
+</table>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image-ref.html
@@ -0,0 +1,135 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,.b.clone {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  border-image-outset: 7px 3px 5px 9px;
+}
+.b {
+  border: 5px solid transparent;
+  background: pink;
+}
+.b.clone {
+  background: pink;
+  height:28px;
+}
+.col3 .b.clone {
+  height:32px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+
+b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10 {position:absolute;}
+c1,c2,c3,c4,c5,c6,c7,c8,c9,c10 {position:absolute; overflow:hidden; z-index:1;}
+
+
+b1 { top:50px; left:20px; height:65px; width:41px; }
+c1 { top:0; left:0; height:88px; width:200px; }
+
+b2 { top:-38px; left:128px; height:66px; width:41px; }
+c2 { top:50px; left:0; height:61px; width:200px; }
+
+b3 { top:50px; left:240px; height:115px; width:41px; }
+c3 { top:0; left:0; height:92px; width:600px; }
+
+b4 { top:-42px; left:312px; height:115px; width:41px; }
+c4 { top:50px; left:0; height:42px; width:600px; }
+
+b5 { top:-84px; left:384px; height:116px; width:41px; }
+c5 { top:50px; left:0; height:100px; width:600px; }
+
+b6 { top:148px; left:20px; height:19px; z-index:1; }
+m6 { top:135px; left:56px; height:55px; width:100px; background:white; z-index:2; }
+
+b7 { top:30px; left:-36px; width:78px; height:19px; }
+c7 { top:170px; left:20px; height:300px; width:200px; }
+
+b8 { top:30px; left:77px; width:125px; height:19px; }
+m8 { top:15px; left:113px; width:125px; height:55px; background:white; }
+c8 { top:170px; left:20px; height:300px; width:600px; }
+
+b9 { top:30px; left:-36px; width:125px; height:19px; }
+c9 { top:222px; left:20px; height:300px; width:47px; }
+
+b10 { top:30px; left:-83px; width:125px; height:19px; }
+c10 { top:274px; left:20px; height:300px; width:156px; }
+
+  </style>
+</head>
+<body>
+<c1><b1></b1></c1>
+<c2><b2></b2></c2>
+<c3><b3></b3></c3>
+<c4><b4></b4></c4>
+<c5><b5></b5></c5>
+<b6><x></x><y></y><br></b6><m6></m6>
+<c7><b7><x></x><y></y></b7></c7>
+<c8><b8><x></x><y></y><y></y></b8><m8></m8></c8>
+<c9><b9><x></x><y></y><y></y></b9></c9>
+<c10><b10><x></x><y></y><y></y></b10></c10>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div><div class="b vbreak clone"></div><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone"><x></x></span><div class="h"></div><span class="b clone"><y></y></span>
+<span class="b clone m"><x></x></span><div class="h"></div><span class="b clone m"><y></y></span><div class="h"></div><span class="b clone m"><y></y></span>
+</pos4>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-border-image.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Testcase for border-image + box-decoration-break</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=988653">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-border-image-ref.html">
+  <meta charset="utf-8">
+  <style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+* { font-family: DejaVuSansMono; }
+
+html,body {
+  color:black; background-color:white; font-size:16px; padding:0; padding-left:10px; margin:0;
+}
+
+.b {
+  border: 5px solid red;
+  border-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD%2FgAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAoUlEQVR42u3bwQ0AIAgEwcOmtXttgScmsxWQCTyp3EysJo61IliwYMGCBUuwYMGCBQuWYMGCBQsWLMGCBQsWLFiCBQsWLFiwBAsWLFiwYAkWLFiwYMESLFiwYMGCpXaVka%2BsO8dmOUNYggULFixYsAQLFixYsGAJFixYsGDBEixYsGDBgiVYsGDBggVLsGDBggULlmDBggULFizBggUL1t89N%2FYEtBGStpoAAAAASUVORK5CYII%3D) 10 10 repeat;
+  background: pink;
+  border-image-outset: 7px 3px 5px 9px;
+}
+
+.columns {
+  -moz-columns: 2;
+  width: 200px;
+  height: 50px;
+  background: grey;
+  margin-right: 20px;
+  margin-bottom: 20px;
+  float:left;
+}
+.col3 {
+  -moz-columns: 3;
+}
+.vbreak { height:65px; width:41px; }
+.h { width:30px;height:30px; background:grey; }
+.m { margin-left:15px; }
+.col3 .vbreak { height:115px; }
+.clone { box-decoration-break:clone; }
+.slice { box-decoration-break:slice; }
+x { display:inline-block; width:31px; height:18px; line-height:1; }
+y { display:inline-block; width:47px; height:18px; line-height:1; }
+pos1 { position:absolute; top:50px; width:700px; }
+pos2 { position:absolute; top:150px; width:700px; }
+pos3 { position:absolute; top:380px; width:700px; }
+pos4 { position:absolute; top:510px; width:700px; }
+  </style>
+</head>
+<body>
+<pre>box-decoration-break:slice</pre>
+
+<pos1>
+<div class="columns"><div class="b vbreak slice"></div></div>
+<div class="columns col3"><div class="b vbreak slice"></div></div>
+</pos1>
+
+<pos2>
+<span class="b slice" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b slice m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+
+<pre>box-decoration-break:clone</pre>
+</pos2>
+
+<pos3>
+<div class="columns"><div class="b vbreak clone"></div></div>
+<div class="columns col3"><div class="b vbreak clone"></div></div>
+</pos3>
+
+<pos4>
+<span class="b clone" style="border-style:dashed;"><x></x><div class="h"></div><y></y></span>
+<span class="b clone m" style="border-style:dashed;"><x></x><div class="h"></div><y></y><div class="h"></div><y></y></span>
+</pos4>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-inset-box-shadow-1-ref.html
@@ -0,0 +1,132 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with inset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+span {  border:3px dashed pink; margin:0 1em; line-height:4em; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=10><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br></span><span class="p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=10><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br></span><span class="m p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+
+</body>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-inset-box-shadow-1.html
@@ -0,0 +1,134 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with inset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-with-inset-box-shadow-1-ref.html">
+  <meta charset="utf-8">
+<style>
+span {  border:3px dashed pink; margin:0 1em; line-height:4em; box-decoration-break:clone; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 0px 10px #00F;
+          box-shadow: inset 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 10px #00F;
+          box-shadow: inset 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 0px 0px 7px 0px #00F;
+          box-shadow: inset 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 0px 10px #00F;
+          box-shadow: inset 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 10px #00F;
+          box-shadow: inset 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: inset 15px 9px 7px 0px #00F;
+          box-shadow: inset 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=10><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=10><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-outset-box-shadow-1-ref.html
@@ -0,0 +1,131 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with outset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <meta charset="utf-8">
+<style>
+span { border:3px dashed pink; line-height:80px; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=50 ><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=50 ><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m o10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m p10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m so10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp0"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;b&nbsp;&nbsp;</b></span><br><span class="m sp10x"><b>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+</body>
+
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/box-decoration-break-with-outset-box-shadow-1.html
@@ -0,0 +1,133 @@
+<!DOCTYPE HTML>
+<!--
+     Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>CSS Test: Testing box-decoration-break:clone with outset box-shadow</title>
+  <link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=613659">
+  <link rel="help" href="http://dev.w3.org/csswg/css-break/#break-decoration">
+  <link rel="match" href="box-decoration-break-with-outset-box-shadow-1-ref.html">
+  <meta charset="utf-8">
+<style>
+span { border:3px dashed pink; line-height:80px; box-decoration-break:clone; }
+
+span {
+  font-family:monospace;
+  padding:1em 1em;
+  background-image: url(green-circle-alpha-32x32.png);
+}
+.o0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.o10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.o10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.p0 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.p10 {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.p10x {
+  border-radius: 12px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+.so0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 0px 10px #00F;
+          box-shadow: 0px 0px 0px 10px #00F;
+}
+.so10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 10px #00F;
+          box-shadow: 0px 0px 7px 10px #00F;
+}
+.so10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 0px 0px 7px 0px #00F;
+          box-shadow: 0px 0px 7px 0px #00F;
+}
+.sp0 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 0px 10px #00F;
+          box-shadow: 15px 9px 0px 10px #00F;
+}
+.sp10 {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 10px #00F;
+          box-shadow: 15px 9px 7px 10px #00F;
+}
+.sp10x {
+  border-radius: 0px;
+  -webkit-box-shadow: 15px 9px 7px 0px #00F;
+          box-shadow: 15px 9px 7px 0px #00F;
+}
+
+.m b { visibility:hidden; }
+.m { box-shadow:none; background:none; border-style:solid; border-radius:0; border-color:transparent; }
+.m.o0, .m.o10, .m.o10x, .m.p0, .m.p10, .m.p10x { border-bottom-color: black; }
+</style>
+</head>
+<body style="margin:49px 50px;">
+
+<div style="position:relative">
+<table border=1 cellpadding=50 ><tr><td>
+<span class="o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+
+<div style="position:absolute; top:0px;left:0;">
+<!-- mask out 1px of outer edge of the rounded borders at some places due to rounding errors -->
+<table border=1 cellpadding=50 ><tr><td>
+<span class="m o0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m o10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m p0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m p10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m so0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m so10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td><td>
+<span class="m sp0"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+<span class="m sp10x"><b>&nbsp;&nbsp;a&nbsp;&nbsp;<br>&nbsp;&nbsp;b&nbsp;&nbsp;<br>&nbsp;&nbsp;c&nbsp;&nbsp;</b></span><br>
+</td></tr>
+</table>
+</div>
+
+</div>
+</body>
+
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a007675a176123cab7291d684537dde8961ecec7
GIT binary patch
literal 396
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdzwj^(N7l!{JxM1({$v_d#0*}aI
z1_o|n5N2eUHAey{$X?><>&kwIla1GcWoG4q7eFD|%#er@=ltB<)VvY~5O6L^O)N=G
zQ7F$W$xv|j^bJVSOJxU&fADm142d}Wbh@EXvx0!De5T6w6S{BK=xp8Q{d%uWd#F`^
z!u042t)K<Qepgg_b|{|w=XK!ce10A7Kh+w~?RnG{7=sk#qNEqF>1nL{mnx;ilg=ai
zOm$ac&XaDN>gE#Oo7W=4rBAqryvvLDbdC9E$2H%U`7_VY6^JN)Zo4q;n)Ck87q4sN
zJwE<$;bwsownvTGtsLI#EO0NJW1V0;N36hsKW4M42g~|~6i){&4TV@C0dB62>wb+D
zKCC89d(KX3hzfAn8<QbnIETr{#mtNG_vr?G<=YeAd(87c$*k+qq;b+NZVFrAG;Uj;
feNQsKoi1coD}A1I>bY1VC{R3I{an^LB{Ts5V_A-C
new file mode 100644
--- /dev/null
+++ b/layout/reftests/css-break/reftest.list
@@ -0,0 +1,5 @@
+pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-1.html box-decoration-break-1-ref.html
+
+fuzzy(1,20) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-inset-box-shadow-1.html box-decoration-break-with-inset-box-shadow-1-ref.html
+fuzzy(16,460) pref(layout.css.box-decoration-break.enabled,true) == box-decoration-break-with-outset-box-shadow-1.html box-decoration-break-with-outset-box-shadow-1-ref.html
+random-if(!gtk2Widget) pref(layout.css.box-decoration-break.enabled,true) HTTP(..) == box-decoration-break-border-image.html box-decoration-break-border-image-ref.html
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -51,16 +51,19 @@ include bugs/reftest.list
 include canvas/reftest.list
 
 # css animations
 include css-animations/reftest.list
 
 # blending/
 include css-blending/reftest.list
 
+# Tests for the css-break spec
+include css-break/reftest.list
+
 # css calc() tests
 include css-calc/reftest.list
 
 # css character encoding tests
 include css-charset/reftest.list
 
 # css default pseudo class tests
 include css-default/reftest.list
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -183,17 +183,16 @@ CSS_KEY(bold-fraktur, bold_fraktur)
 CSS_KEY(bold-italic, bold_italic)
 CSS_KEY(bold-sans-serif, bold_sans_serif)
 CSS_KEY(bold-script, bold_script)
 CSS_KEY(bolder, bolder)
 CSS_KEY(border-box, border_box)
 CSS_KEY(both, both)
 CSS_KEY(bottom, bottom)
 CSS_KEY(bottom-outside, bottom_outside)
-CSS_KEY(bounding-box, bounding_box)
 CSS_KEY(break-all, break_all)
 CSS_KEY(break-word, break_word)
 CSS_KEY(brightness, brightness)
 CSS_KEY(button, button)
 CSS_KEY(buttonface, buttonface)
 CSS_KEY(buttonhighlight, buttonhighlight)
 CSS_KEY(buttonshadow, buttonshadow)
 CSS_KEY(buttontext, buttontext)
@@ -203,16 +202,17 @@ CSS_KEY(captiontext, captiontext)
 CSS_KEY(cell, cell)
 CSS_KEY(center, center)
 CSS_KEY(ch, ch)
 CSS_KEY(character-variant, character_variant)
 CSS_KEY(circle, circle)
 CSS_KEY(cjk-decimal, cjk_decimal)
 CSS_KEY(cjk-ideographic, cjk_ideographic)
 CSS_KEY(clip, clip)
+CSS_KEY(clone, clone)
 CSS_KEY(close-quote, close_quote)
 CSS_KEY(closest-corner, closest_corner)
 CSS_KEY(closest-side, closest_side)
 CSS_KEY(cm, cm)
 CSS_KEY(col-resize, col_resize)
 CSS_KEY(collapse, collapse)
 CSS_KEY(color, color)
 CSS_KEY(color-burn, color_burn)
@@ -252,17 +252,16 @@ CSS_KEY(digits, digits)
 CSS_KEY(disabled, disabled)
 CSS_KEY(disc, disc)
 CSS_KEY(discretionary-ligatures, discretionary_ligatures)
 CSS_KEY(dotted, dotted)
 CSS_KEY(double, double)
 CSS_KEY(double-struck, double_struck)
 CSS_KEY(drop-shadow, drop_shadow)
 CSS_KEY(e-resize, e_resize)
-CSS_KEY(each-box, each_box)
 CSS_KEY(ease, ease)
 CSS_KEY(ease-in, ease_in)
 CSS_KEY(ease-in-out, ease_in_out)
 CSS_KEY(ease-out, ease_out)
 CSS_KEY(element, element)
 CSS_KEY(elements, elements)
 CSS_KEY(ellipse, ellipse)
 CSS_KEY(ellipsis, ellipsis)
@@ -491,16 +490,17 @@ CSS_KEY(show, show)
 CSS_KEY(sideways, sideways)
 CSS_KEY(simp-chinese-formal, simp_chinese_formal)
 CSS_KEY(simp-chinese-informal, simp_chinese_informal)
 CSS_KEY(simplified, simplified)
 CSS_KEY(skew, skew)
 CSS_KEY(skewx, skewx)
 CSS_KEY(skewy, skewy)
 CSS_KEY(slashed-zero, slashed_zero)
+CSS_KEY(slice, slice)
 CSS_KEY(small, small)
 CSS_KEY(small-caps, small_caps)
 CSS_KEY(small-caption, small_caption)
 CSS_KEY(smaller, smaller)
 CSS_KEY(soft, soft)
 CSS_KEY(soft-light, soft_light)
 CSS_KEY(solid, solid)
 CSS_KEY(space-around, space_around)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -269,20 +269,16 @@
 // :first-letter are: font properties, 'text-decoration',
 // 'text-transform', 'letter-spacing', 'word-spacing' (when
 // appropriate), 'line-height', 'float', 'vertical-align' (only if
 // 'float' is 'none'), margin properties, padding properties, border
 // properties, 'color', and background properties.  We also allow
 // 'text-shadow' (see above) and 'box-shadow' (which is like the
 // border properties).
 
-// We include '-moz-background-inline-policy' (css3-background's
-// 'background-break') in both as a background property, although this
-// is somewhat questionable.
-
 CSS_PROP_DISPLAY(
     -moz-appearance,
     appearance,
     CSS_PROP_DOMPROP_PREFIXED(Appearance),
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
     kAppearanceKTable,
@@ -533,28 +529,16 @@ CSS_PROP_BACKGROUND(
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED |
         CSS_PROPERTY_START_IMAGE_LOADS,
     "",
     VARIANT_IMAGE, // used by list parsing
     nullptr,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
 CSS_PROP_BACKGROUND(
-    -moz-background-inline-policy,
-    _moz_background_inline_policy,
-    CSS_PROP_DOMPROP_PREFIXED(BackgroundInlinePolicy),
-    CSS_PROPERTY_PARSE_VALUE |
-        CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
-        CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
-    "",
-    VARIANT_HK,
-    kBackgroundInlinePolicyKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_None)
-CSS_PROP_BACKGROUND(
     background-blend-mode,
     background_blend_mode,
     BackgroundBlendMode,
     CSS_PROPERTY_PARSE_VALUE_LIST |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS,
     "layout.css.background-blend-mode.enabled",
@@ -1361,16 +1345,26 @@ CSS_PROP_POSITION(
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
     "",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     offsetof(nsStylePosition, mOffset),
     eStyleAnimType_Sides_Bottom)
 CSS_PROP_BORDER(
+    box-decoration-break,
+    box_decoration_break,
+    BoxDecorationBreak,
+    CSS_PROPERTY_PARSE_VALUE,
+    "layout.css.box-decoration-break.enabled",
+    VARIANT_HK,
+    kBoxDecorationBreakKTable,
+    CSS_PROP_NO_OFFSET,
+    eStyleAnimType_None)
+CSS_PROP_BORDER(
     box-shadow,
     box_shadow,
     BoxShadow,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
         // NOTE: some components must be nonnegative
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -671,23 +671,16 @@ const KTableValue nsCSSProps::kTransform
 
 const KTableValue nsCSSProps::kBackgroundAttachmentKTable[] = {
   eCSSKeyword_fixed, NS_STYLE_BG_ATTACHMENT_FIXED,
   eCSSKeyword_scroll, NS_STYLE_BG_ATTACHMENT_SCROLL,
   eCSSKeyword_local, NS_STYLE_BG_ATTACHMENT_LOCAL,
   eCSSKeyword_UNKNOWN,-1
 };
 
-const KTableValue nsCSSProps::kBackgroundInlinePolicyKTable[] = {
-  eCSSKeyword_each_box,     NS_STYLE_BG_INLINE_POLICY_EACH_BOX,
-  eCSSKeyword_continuous,   NS_STYLE_BG_INLINE_POLICY_CONTINUOUS,
-  eCSSKeyword_bounding_box, NS_STYLE_BG_INLINE_POLICY_BOUNDING_BOX,
-  eCSSKeyword_UNKNOWN,-1
-};
-
 static_assert(NS_STYLE_BG_CLIP_BORDER == NS_STYLE_BG_ORIGIN_BORDER &&
               NS_STYLE_BG_CLIP_PADDING == NS_STYLE_BG_ORIGIN_PADDING &&
               NS_STYLE_BG_CLIP_CONTENT == NS_STYLE_BG_ORIGIN_CONTENT,
               "bg-clip and bg-origin style constants must agree");
 const KTableValue nsCSSProps::kBackgroundOriginKTable[] = {
   eCSSKeyword_border_box, NS_STYLE_BG_ORIGIN_BORDER,
   eCSSKeyword_padding_box, NS_STYLE_BG_ORIGIN_PADDING,
   eCSSKeyword_content_box, NS_STYLE_BG_ORIGIN_CONTENT,
@@ -791,16 +784,22 @@ const KTableValue nsCSSProps::kBorderWid
 };
 
 const KTableValue nsCSSProps::kBoxPropSourceKTable[] = {
   eCSSKeyword_physical,     NS_BOXPROP_SOURCE_PHYSICAL,
   eCSSKeyword_logical,      NS_BOXPROP_SOURCE_LOGICAL,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const KTableValue nsCSSProps::kBoxDecorationBreakKTable[] = {
+  eCSSKeyword_slice, NS_STYLE_BOX_DECORATION_BREAK_SLICE,
+  eCSSKeyword_clone, NS_STYLE_BOX_DECORATION_BREAK_CLONE,
+  eCSSKeyword_UNKNOWN,-1
+};
+
 const KTableValue nsCSSProps::kBoxShadowTypeKTable[] = {
   eCSSKeyword_inset, NS_STYLE_BOX_SHADOW_INSET,
   eCSSKeyword_UNKNOWN,-1
 };
 
 const KTableValue nsCSSProps::kBoxSizingKTable[] = {
   eCSSKeyword_content_box,  NS_STYLE_BOX_SIZING_CONTENT,
   eCSSKeyword_border_box,   NS_STYLE_BOX_SIZING_BORDER,
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -501,30 +501,30 @@ public:
   static const KTableValue kAnimationIterationCountKTable[];
   static const KTableValue kAnimationPlayStateKTable[];
   static const KTableValue kAnimationTimingFunctionKTable[];
   static const KTableValue kAppearanceKTable[];
   static const KTableValue kAzimuthKTable[];
   static const KTableValue kBackfaceVisibilityKTable[];
   static const KTableValue kTransformStyleKTable[];
   static const KTableValue kBackgroundAttachmentKTable[];
-  static const KTableValue kBackgroundInlinePolicyKTable[];
   static const KTableValue kBackgroundOriginKTable[];
   static const KTableValue kBackgroundPositionKTable[];
   static const KTableValue kBackgroundRepeatKTable[];
   static const KTableValue kBackgroundRepeatPartKTable[];
   static const KTableValue kBackgroundSizeKTable[];
   static const KTableValue kBlendModeKTable[];
   static const KTableValue kBorderCollapseKTable[];
   static const KTableValue kBorderColorKTable[];
   static const KTableValue kBorderImageRepeatKTable[];
   static const KTableValue kBorderImageSliceKTable[];
   static const KTableValue kBorderStyleKTable[];
   static const KTableValue kBorderWidthKTable[];
   static const KTableValue kBoxAlignKTable[];
+  static const KTableValue kBoxDecorationBreakKTable[];
   static const KTableValue kBoxDirectionKTable[];
   static const KTableValue kBoxOrientKTable[];
   static const KTableValue kBoxPackKTable[];
   static const KTableValue kDominantBaselineKTable[];
   static const KTableValue kFillRuleKTable[];
   static const KTableValue kFilterFunctionKTable[];
   static const KTableValue kImageRenderingKTable[];
   static const KTableValue kShapeRenderingKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2069,26 +2069,16 @@ nsComputedDOMStyle::DoGetBackgroundImage
     const nsStyleImage& image = bg->mLayers[i].mImage;
     SetValueToStyleImage(image, val);
   }
 
   return valueList;
 }
 
 CSSValue*
-nsComputedDOMStyle::DoGetBackgroundInlinePolicy()
-{
-  nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
-  val->SetIdent(nsCSSProps::ValueToKeywordEnum(
-                  StyleBackground()->mBackgroundInlinePolicy,
-                  nsCSSProps::kBackgroundInlinePolicyKTable));
-  return val;
-}
-
-CSSValue*
 nsComputedDOMStyle::DoGetBackgroundBlendMode()
 {
   return GetBackgroundList(&nsStyleBackground::Layer::mBlendMode,
                            &nsStyleBackground::mBlendModeCount,
                            nsCSSProps::kBlendModeKTable);
 }
 
 CSSValue*
@@ -2976,16 +2966,26 @@ nsComputedDOMStyle::GetCSSShadowArray(ns
                                        nsCSSProps::kBoxShadowTypeKTable));
     }
   }
 
   return valueList;
 }
 
 CSSValue*
+nsComputedDOMStyle::DoGetBoxDecorationBreak()
+{
+  nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+  val->SetIdent(
+    nsCSSProps::ValueToKeywordEnum(StyleBorder()->mBoxDecorationBreak,
+                                   nsCSSProps::kBoxDecorationBreakKTable));
+  return val;
+}
+
+CSSValue*
 nsComputedDOMStyle::DoGetBoxShadow()
 {
   return GetCSSShadowArray(StyleBorder()->mBoxShadow,
                            StyleColor()->mColor,
                            true);
 }
 
 CSSValue*
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -217,16 +217,17 @@ private:
    * To avoid a name conflict with nsIDOM*CSS2Properties, these are all
    * DoGetXXX instead of GetXXX.
    */
 
   mozilla::dom::CSSValue* DoGetAppearance();
 
   /* Box properties */
   mozilla::dom::CSSValue* DoGetBoxAlign();
+  mozilla::dom::CSSValue* DoGetBoxDecorationBreak();
   mozilla::dom::CSSValue* DoGetBoxDirection();
   mozilla::dom::CSSValue* DoGetBoxFlex();
   mozilla::dom::CSSValue* DoGetBoxOrdinalGroup();
   mozilla::dom::CSSValue* DoGetBoxOrient();
   mozilla::dom::CSSValue* DoGetBoxPack();
   mozilla::dom::CSSValue* DoGetBoxSizing();
 
   mozilla::dom::CSSValue* DoGetWidth();
@@ -278,17 +279,16 @@ private:
 
   /* Background properties */
   mozilla::dom::CSSValue* DoGetBackgroundAttachment();
   mozilla::dom::CSSValue* DoGetBackgroundColor();
   mozilla::dom::CSSValue* DoGetBackgroundImage();
   mozilla::dom::CSSValue* DoGetBackgroundPosition();
   mozilla::dom::CSSValue* DoGetBackgroundRepeat();
   mozilla::dom::CSSValue* DoGetBackgroundClip();
-  mozilla::dom::CSSValue* DoGetBackgroundInlinePolicy();
   mozilla::dom::CSSValue* DoGetBackgroundBlendMode();
   mozilla::dom::CSSValue* DoGetBackgroundOrigin();
   mozilla::dom::CSSValue* DoGetBackgroundSize();
 
   /* Padding properties */
   mozilla::dom::CSSValue* DoGetPaddingTop();
   mozilla::dom::CSSValue* DoGetPaddingBottom();
   mozilla::dom::CSSValue* DoGetPaddingLeft();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -225,17 +225,16 @@ COMPUTED_STYLE_PROP(word_wrap,          
 COMPUTED_STYLE_PROP(writing_mode,                  WritingMode)
 COMPUTED_STYLE_PROP(z_index,                       ZIndex)
 
 /* ******************************* *\
  * Implementations of -moz- styles *
 \* ******************************* */
 
 COMPUTED_STYLE_PROP(appearance,                    Appearance)
-COMPUTED_STYLE_PROP(_moz_background_inline_policy, BackgroundInlinePolicy)
 COMPUTED_STYLE_PROP(binding,                       Binding)
 COMPUTED_STYLE_PROP(border_bottom_colors,          BorderBottomColors)
 COMPUTED_STYLE_PROP(border_left_colors,            BorderLeftColors)
 COMPUTED_STYLE_PROP(border_right_colors,           BorderRightColors)
 COMPUTED_STYLE_PROP(border_top_colors,             BorderTopColors)
 COMPUTED_STYLE_PROP(box_align,                     BoxAlign)
 COMPUTED_STYLE_PROP(box_direction,                 BoxDirection)
 COMPUTED_STYLE_PROP(box_flex,                      BoxFlex)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -6234,24 +6234,16 @@ nsRuleNode::ComputeBackgroundData(void* 
 
   // background-clip: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundClip(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mClip,
                     uint8_t(NS_STYLE_BG_CLIP_BORDER), parentBG->mClipCount,
                     bg->mClipCount, maxItemCount, rebuild, canStoreInRuleTree);
 
-  // background-inline-policy: enum, inherit, initial
-  SetDiscrete(*aRuleData->ValueForBackgroundInlinePolicy(),
-              bg->mBackgroundInlinePolicy,
-              canStoreInRuleTree,
-              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
-              parentBG->mBackgroundInlinePolicy,
-              NS_STYLE_BG_INLINE_POLICY_CONTINUOUS, 0, 0, 0, 0);
-
   // background-blend-mode: enum, inherit, initial [list]
   SetBackgroundList(aContext, *aRuleData->ValueForBackgroundBlendMode(),
                     bg->mLayers,
                     parentBG->mLayers, &nsStyleBackground::Layer::mBlendMode,
                     uint8_t(NS_STYLE_BLEND_NORMAL), parentBG->mBlendModeCount,
                     bg->mBlendModeCount, maxItemCount, rebuild,
                     canStoreInRuleTree);
 
@@ -6440,16 +6432,23 @@ nsRuleNode::ComputeBorderData(void* aSta
                               const nsRuleData* aRuleData,
                               nsStyleContext* aContext,
                               nsRuleNode* aHighestNode,
                               const RuleDetail aRuleDetail,
                               const bool aCanStoreInRuleTree)
 {
   COMPUTE_START_RESET(Border, (mPresContext), border, parentBorder)
 
+  // box-decoration-break: enum, inherit, initial
+  SetDiscrete(*aRuleData->ValueForBoxDecorationBreak(),
+              border->mBoxDecorationBreak, canStoreInRuleTree,
+              SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
+              parentBorder->mBoxDecorationBreak,
+              NS_STYLE_BOX_DECORATION_BREAK_SLICE, 0, 0, 0, 0);
+
   // box-shadow: none, list, inherit, initial
   const nsCSSValue* boxShadowValue = aRuleData->ValueForBoxShadow();
   switch (boxShadowValue->GetUnit()) {
   case eCSSUnit_Null:
     break;
 
   case eCSSUnit_Initial:
   case eCSSUnit_Unset:
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -112,16 +112,20 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_BOX_ALIGN_END         4
 
 // box-pack
 #define NS_STYLE_BOX_PACK_START        0
 #define NS_STYLE_BOX_PACK_CENTER       1
 #define NS_STYLE_BOX_PACK_END          2
 #define NS_STYLE_BOX_PACK_JUSTIFY      3
 
+// box-decoration-break
+#define NS_STYLE_BOX_DECORATION_BREAK_SLICE  0
+#define NS_STYLE_BOX_DECORATION_BREAK_CLONE  1
+
 // box-direction
 #define NS_STYLE_BOX_DIRECTION_NORMAL    0
 #define NS_STYLE_BOX_DIRECTION_REVERSE   1
 
 // box-orient
 #define NS_STYLE_BOX_ORIENT_HORIZONTAL 0
 #define NS_STYLE_BOX_ORIENT_VERTICAL   1
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -383,16 +383,17 @@ nsChangeHint nsStylePadding::CalcDiffere
 
 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
   : mBorderColors(nullptr),
     mBoxShadow(nullptr),
     mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
     mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
     mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
+    mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE),
     mComputedBorder(0, 0, 0, 0)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   NS_FOR_CSS_HALF_CORNERS (corner) {
     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
   }
 
@@ -434,16 +435,17 @@ nsStyleBorder::nsStyleBorder(const nsSty
     mBorderImageSource(aSrc.mBorderImageSource),
     mBorderImageSlice(aSrc.mBorderImageSlice),
     mBorderImageWidth(aSrc.mBorderImageWidth),
     mBorderImageOutset(aSrc.mBorderImageOutset),
     mBorderImageFill(aSrc.mBorderImageFill),
     mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
     mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
     mFloatEdge(aSrc.mFloatEdge),
+    mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
     mComputedBorder(aSrc.mComputedBorder),
     mBorder(aSrc.mBorder),
     mTwipsPerPixel(aSrc.mTwipsPerPixel)
 {
   MOZ_COUNT_CTOR(nsStyleBorder);
   if (aSrc.mBorderColors) {
     EnsureBorderColors();
     for (int32_t i = 0; i < 4; i++)
@@ -523,17 +525,18 @@ nsChangeHint nsStyleBorder::CalcDifferen
   // Note that differences in mBorder don't affect rendering (which should only
   // use mComputedBorder), so don't need to be tested for here.
   // XXXbz we should be able to return a more specific change hint for
   // at least GetComputedBorder() differences...
   if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
       GetComputedBorder() != aOther.GetComputedBorder() ||
       mFloatEdge != aOther.mFloatEdge ||
       mBorderImageOutset != aOther.mBorderImageOutset ||
-      (shadowDifference & nsChangeHint_NeedReflow))
+      (shadowDifference & nsChangeHint_NeedReflow) ||
+      mBoxDecorationBreak != aOther.mBoxDecorationBreak)
     return NS_STYLE_HINT_REFLOW;
 
   NS_FOR_CSS_SIDES(ix) {
     // See the explanation in nsChangeHint.h of
     // nsChangeHint_BorderStyleNoneChange .
     // Furthermore, even though we know *this* side is 0 width, just
     // assume a visual hint for some other change rather than bother
     // tracking this result through the rest of the function.
@@ -1963,17 +1966,16 @@ nsStyleBackground::nsStyleBackground()
   , mClipCount(1)
   , mOriginCount(1)
   , mRepeatCount(1)
   , mPositionCount(1)
   , mImageCount(1)
   , mSizeCount(1)
   , mBlendModeCount(1)
   , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
-  , mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
   Layer *onlyLayer = mLayers.AppendElement();
   NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
   onlyLayer->SetInitialValues();
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
@@ -1982,17 +1984,16 @@ nsStyleBackground::nsStyleBackground(con
   , mOriginCount(aSource.mOriginCount)
   , mRepeatCount(aSource.mRepeatCount)
   , mPositionCount(aSource.mPositionCount)
   , mImageCount(aSource.mImageCount)
   , mSizeCount(aSource.mSizeCount)
   , mBlendModeCount(aSource.mBlendModeCount)
   , mLayers(aSource.mLayers) // deep copy
   , mBackgroundColor(aSource.mBackgroundColor)
-  , mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
 {
   MOZ_COUNT_CTOR(nsStyleBackground);
   // If the deep copy of mLayers failed, truncate the counts.
   uint32_t count = mLayers.Length();
   if (count != aSource.mLayers.Length()) {
     NS_WARNING("truncating counts due to out-of-memory");
     mAttachmentCount = std::max(mAttachmentCount, count);
     mClipCount = std::max(mClipCount, count);
@@ -2040,19 +2041,17 @@ nsChangeHint nsStyleBackground::CalcDiff
       }
     } else {
       if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
         return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
       hasVisualDifference = true;
     }
   }
 
-  if (hasVisualDifference ||
-      mBackgroundColor != aOther.mBackgroundColor ||
-      mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy)
+  if (hasVisualDifference || mBackgroundColor != aOther.mBackgroundColor)
     return NS_STYLE_HINT_VISUAL;
 
   return NS_STYLE_HINT_NONE;
 }
 
 bool nsStyleBackground::HasFixedBackground() const
 {
   NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -534,21 +534,16 @@ struct nsStyleBackground {
     for (uint32_t var_ = (stylebg_) ? (stylebg_)->mImageCount : 1; var_-- != 0; )
   #define NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, stylebg_, start_, count_) \
     NS_ASSERTION((int32_t)(start_) >= 0 && (uint32_t)(start_) < ((stylebg_) ? (stylebg_)->mImageCount : 1), "Invalid layer start!"); \
     NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, "Invalid layer range!"); \
     for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); )
 
   nscolor mBackgroundColor;       // [reset]
 
-  // FIXME: This (now background-break in css3-background) should
-  // probably move into a different struct so that everything in
-  // nsStyleBackground is set by the background shorthand.
-  uint8_t mBackgroundInlinePolicy; // [reset] See nsStyleConsts.h
-
   // True if this background is completely transparent.
   bool IsTransparent() const;
 
   // We have to take slower codepaths for fixed background attachment,
   // but we don't want to do that when there's no image.
   // Not inline because it uses an nsCOMPtr<imgIRequest>
   // FIXME: Should be in nsStyleStructInlines.h.
   bool HasFixedBackground() const;
@@ -981,16 +976,17 @@ public:
   nsStyleSides   mBorderImageSlice;   // [reset] factor, percent
   nsStyleSides   mBorderImageWidth;   // [reset] length, factor, percent, auto
   nsStyleSides   mBorderImageOutset;  // [reset] length, factor
 
   uint8_t        mBorderImageFill;    // [reset]
   uint8_t        mBorderImageRepeatH; // [reset] see nsStyleConsts.h
   uint8_t        mBorderImageRepeatV; // [reset]
   uint8_t        mFloatEdge;          // [reset]
+  uint8_t        mBoxDecorationBreak; // [reset] see nsStyleConsts.h
 
 protected:
   // mComputedBorder holds the CSS2.1 computed border-width values.
   // In particular, these widths take into account the border-style
   // for the relevant side, and the values are rounded to the nearest
   // device pixel (which is not part of the definition of computed
   // values). The presence or absence of a border-image does not
   // affect border-width values.
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1,5395 +1,5398 @@
-/* -*- Mode: Java; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* vim: set shiftwidth=4 tabstop=4 autoindent cindent noexpandtab: */
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // True longhand properties.
 const CSS_TYPE_LONGHAND = 0;
 
 // True shorthand properties.
 const CSS_TYPE_TRUE_SHORTHAND = 1;
 
 // Properties that we handle as shorthands but were longhands either in
 // the current spec or earlier versions of the spec.
 const CSS_TYPE_SHORTHAND_AND_LONGHAND = 2;
 
 // Each property has the following fields:
-//	 domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties
-//	 inherited: Whether the property is inherited by default (stated as
-//	   yes or no in the property header in all CSS specs)
-//	 type: see above
-//	 alias_for: optional, indicates that the property is an alias for
-//	   some other property that is the preferred serialization.  (Type
-//	   must not be CSS_TYPE_LONGHAND.)
-//	 get_computed: if present, the property's computed value shows up on
-//	   another property, and this is a function used to get it
-//	 initial_values: Values whose computed value should be the same as the
-//	   computed value for the property's initial value.
-//	 other_values: Values whose computed value should be different from the
-//	   computed value for the property's initial value.
-//	 XXX Should have a third field for values whose computed value may or
-//	   may not be the same as for the property's initial value.
-//	 invalid_values: Things that are not values for the property and
-//	   should be rejected, but which are balanced and should not absorb
-//	   what follows
-//	 quirks_values: Values that should be accepted in quirks mode only,
-//	   mapped to the values they are equivalent to.
-//	 unbalanced_values: Things that are not values for the property and
-//	   should be rejected, and which also contain unbalanced constructs
-//	   that should absorb what follows
+//   domProp: The name of the relevant member of nsIDOM[NS]CSS2Properties
+//   inherited: Whether the property is inherited by default (stated as
+//     yes or no in the property header in all CSS specs)
+//   type: see above
+//   alias_for: optional, indicates that the property is an alias for
+//     some other property that is the preferred serialization.  (Type
+//     must not be CSS_TYPE_LONGHAND.)
+//   get_computed: if present, the property's computed value shows up on
+//     another property, and this is a function used to get it
+//   initial_values: Values whose computed value should be the same as the
+//     computed value for the property's initial value.
+//   other_values: Values whose computed value should be different from the
+//     computed value for the property's initial value.
+//   XXX Should have a third field for values whose computed value may or
+//     may not be the same as for the property's initial value.
+//   invalid_values: Things that are not values for the property and
+//     should be rejected, but which are balanced and should not absorb
+//     what follows
+//   quirks_values: Values that should be accepted in quirks mode only,
+//     mapped to the values they are equivalent to.
+//   unbalanced_values: Things that are not values for the property and
+//     should be rejected, and which also contain unbalanced constructs
+//     that should absorb what follows
 
 // Helper functions used to construct gCSSProperties.
 
 function initial_font_family_is_sans_serif()
 {
-	// The initial value of 'font-family' might be 'serif' or
-	// 'sans-serif'.
-	var div = document.createElement("div");
-	div.setAttribute("style", "font: initial");
-	return getComputedStyle(div, "").fontFamily == "sans-serif";
+  // The initial value of 'font-family' might be 'serif' or
+  // 'sans-serif'.
+  var div = document.createElement("div");
+  div.setAttribute("style", "font: initial");
+  return getComputedStyle(div, "").fontFamily == "sans-serif";
 }
 var gInitialFontFamilyIsSansSerif = initial_font_family_is_sans_serif();
 
 // shared by background-image and border-image-source
 var validGradientAndElementValues = [
-	"-moz-element(#a)",
-	"-moz-element(  #a  )",
-	"-moz-element(#a-1)",
-	"-moz-element(#a\\:1)",
-	/* gradient torture test */
-	"linear-gradient(red, blue)",
-	"linear-gradient(red, yellow, blue)",
-	"linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"linear-gradient(red, yellow, green, blue 50%)",
-	"linear-gradient(red -50%, yellow -25%, green, blue)",
-	"linear-gradient(red -99px, yellow, green, blue 120%)",
-	"linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-element(#a)",
+  "-moz-element(  #a  )",
+  "-moz-element(#a-1)",
+  "-moz-element(#a\\:1)",
+  /* gradient torture test */
+  "linear-gradient(red, blue)",
+  "linear-gradient(red, yellow, blue)",
+  "linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "linear-gradient(red, yellow, green, blue 50%)",
+  "linear-gradient(red -50%, yellow -25%, green, blue)",
+  "linear-gradient(red -99px, yellow, green, blue 120%)",
+  "linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"linear-gradient(to top, red, blue)",
-	"linear-gradient(to bottom, red, blue)",
-	"linear-gradient(to left, red, blue)",
-	"linear-gradient(to right, red, blue)",
-	"linear-gradient(to top left, red, blue)",
-	"linear-gradient(to top right, red, blue)",
-	"linear-gradient(to bottom left, red, blue)",
-	"linear-gradient(to bottom right, red, blue)",
-	"linear-gradient(to left top, red, blue)",
-	"linear-gradient(to left bottom, red, blue)",
-	"linear-gradient(to right top, red, blue)",
-	"linear-gradient(to right bottom, red, blue)",
+  "linear-gradient(to top, red, blue)",
+  "linear-gradient(to bottom, red, blue)",
+  "linear-gradient(to left, red, blue)",
+  "linear-gradient(to right, red, blue)",
+  "linear-gradient(to top left, red, blue)",
+  "linear-gradient(to top right, red, blue)",
+  "linear-gradient(to bottom left, red, blue)",
+  "linear-gradient(to bottom right, red, blue)",
+  "linear-gradient(to left top, red, blue)",
+  "linear-gradient(to left bottom, red, blue)",
+  "linear-gradient(to right top, red, blue)",
+  "linear-gradient(to right bottom, red, blue)",
 
-	"linear-gradient(-33deg, red, blue)",
-	"linear-gradient(30grad, red, blue)",
-	"linear-gradient(10deg, red, blue)",
-	"linear-gradient(1turn, red, blue)",
-	"linear-gradient(.414rad, red, blue)",
+  "linear-gradient(-33deg, red, blue)",
+  "linear-gradient(30grad, red, blue)",
+  "linear-gradient(10deg, red, blue)",
+  "linear-gradient(1turn, red, blue)",
+  "linear-gradient(.414rad, red, blue)",
 
-	"-moz-linear-gradient(red, blue)",
-	"-moz-linear-gradient(red, yellow, blue)",
-	"-moz-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-linear-gradient(red, yellow, green, blue 50%)",
-	"-moz-linear-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-linear-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-linear-gradient(red, blue)",
+  "-moz-linear-gradient(red, yellow, blue)",
+  "-moz-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-linear-gradient(red, yellow, green, blue 50%)",
+  "-moz-linear-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-linear-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-linear-gradient(to top, red, blue)",
-	"-moz-linear-gradient(to bottom, red, blue)",
-	"-moz-linear-gradient(to left, red, blue)",
-	"-moz-linear-gradient(to right, red, blue)",
-	"-moz-linear-gradient(to top left, red, blue)",
-	"-moz-linear-gradient(to top right, red, blue)",
-	"-moz-linear-gradient(to bottom left, red, blue)",
-	"-moz-linear-gradient(to bottom right, red, blue)",
-	"-moz-linear-gradient(to left top, red, blue)",
-	"-moz-linear-gradient(to left bottom, red, blue)",
-	"-moz-linear-gradient(to right top, red, blue)",
-	"-moz-linear-gradient(to right bottom, red, blue)",
+  "-moz-linear-gradient(to top, red, blue)",
+  "-moz-linear-gradient(to bottom, red, blue)",
+  "-moz-linear-gradient(to left, red, blue)",
+  "-moz-linear-gradient(to right, red, blue)",
+  "-moz-linear-gradient(to top left, red, blue)",
+  "-moz-linear-gradient(to top right, red, blue)",
+  "-moz-linear-gradient(to bottom left, red, blue)",
+  "-moz-linear-gradient(to bottom right, red, blue)",
+  "-moz-linear-gradient(to left top, red, blue)",
+  "-moz-linear-gradient(to left bottom, red, blue)",
+  "-moz-linear-gradient(to right top, red, blue)",
+  "-moz-linear-gradient(to right bottom, red, blue)",
 
-	"-moz-linear-gradient(top left, red, blue)",
-	"-moz-linear-gradient(0 0, red, blue)",
-	"-moz-linear-gradient(20% bottom, red, blue)",
-	"-moz-linear-gradient(center 20%, red, blue)",
-	"-moz-linear-gradient(left 35px, red, blue)",
-	"-moz-linear-gradient(10% 10em, red, blue)",
-	"-moz-linear-gradient(44px top, red, blue)",
+  "-moz-linear-gradient(top left, red, blue)",
+  "-moz-linear-gradient(0 0, red, blue)",
+  "-moz-linear-gradient(20% bottom, red, blue)",
+  "-moz-linear-gradient(center 20%, red, blue)",
+  "-moz-linear-gradient(left 35px, red, blue)",
+  "-moz-linear-gradient(10% 10em, red, blue)",
+  "-moz-linear-gradient(44px top, red, blue)",
 
-	"-moz-linear-gradient(top left 45deg, red, blue)",
-	"-moz-linear-gradient(20% bottom -300deg, red, blue)",
-	"-moz-linear-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-linear-gradient(left 35px 30grad, red, blue)",
-	"-moz-linear-gradient(left 35px 0.1turn, red, blue)",
-	"-moz-linear-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-linear-gradient(44px top -33deg, red, blue)",
+  "-moz-linear-gradient(top left 45deg, red, blue)",
+  "-moz-linear-gradient(20% bottom -300deg, red, blue)",
+  "-moz-linear-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-linear-gradient(left 35px 30grad, red, blue)",
+  "-moz-linear-gradient(left 35px 0.1turn, red, blue)",
+  "-moz-linear-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-linear-gradient(44px top -33deg, red, blue)",
 
-	"-moz-linear-gradient(-33deg, red, blue)",
-	"-moz-linear-gradient(30grad left 35px, red, blue)",
-	"-moz-linear-gradient(10deg 20px, red, blue)",
-	"-moz-linear-gradient(1turn 20px, red, blue)",
-	"-moz-linear-gradient(.414rad bottom, red, blue)",
+  "-moz-linear-gradient(-33deg, red, blue)",
+  "-moz-linear-gradient(30grad left 35px, red, blue)",
+  "-moz-linear-gradient(10deg 20px, red, blue)",
+  "-moz-linear-gradient(1turn 20px, red, blue)",
+  "-moz-linear-gradient(.414rad bottom, red, blue)",
 
-	"-moz-linear-gradient(blue calc(0px) ,green calc(25%) ,red calc(40px) ,blue calc(60px) , yellow  calc(100px))",
-	"-moz-linear-gradient(-33deg, blue calc(-25%) ,red 40px)",
-	"-moz-linear-gradient(10deg, blue calc(100px + -25%),red calc(40px))",
-	"-moz-linear-gradient(10deg, blue calc(-25px),red calc(100%))",
-	"-moz-linear-gradient(.414rad, blue calc(100px + -25px) ,green calc(100px + -25px) ,red calc(100px + -25%) ,blue calc(-25px) , yellow  calc(-25px))",
-	"-moz-linear-gradient(1turn, blue calc(-25%) ,green calc(25px) ,red calc(25%),blue calc(0px),white 50px, yellow  calc(-25px))",
+  "-moz-linear-gradient(blue calc(0px) ,green calc(25%) ,red calc(40px) ,blue calc(60px) , yellow  calc(100px))",
+  "-moz-linear-gradient(-33deg, blue calc(-25%) ,red 40px)",
+  "-moz-linear-gradient(10deg, blue calc(100px + -25%),red calc(40px))",
+  "-moz-linear-gradient(10deg, blue calc(-25px),red calc(100%))",
+  "-moz-linear-gradient(.414rad, blue calc(100px + -25px) ,green calc(100px + -25px) ,red calc(100px + -25%) ,blue calc(-25px) , yellow  calc(-25px))",
+  "-moz-linear-gradient(1turn, blue calc(-25%) ,green calc(25px) ,red calc(25%),blue calc(0px),white 50px, yellow  calc(-25px))",
 
-	"radial-gradient(red, blue)",
-	"radial-gradient(red, yellow, blue)",
-	"radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"radial-gradient(red, yellow, green, blue 50%)",
-	"radial-gradient(red -50%, yellow -25%, green, blue)",
-	"radial-gradient(red -99px, yellow, green, blue 120%)",
-	"radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "radial-gradient(red, blue)",
+  "radial-gradient(red, yellow, blue)",
+  "radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "radial-gradient(red, yellow, green, blue 50%)",
+  "radial-gradient(red -50%, yellow -25%, green, blue)",
+  "radial-gradient(red -99px, yellow, green, blue 120%)",
+  "radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
 
-	"radial-gradient(0 0, red, blue)",
-	"radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "radial-gradient(0 0, red, blue)",
+  "radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"radial-gradient(at top left, red, blue)",
-	"radial-gradient(at 20% bottom, red, blue)",
-	"radial-gradient(at center 20%, red, blue)",
-	"radial-gradient(at left 35px, red, blue)",
-	"radial-gradient(at 10% 10em, red, blue)",
-	"radial-gradient(at 44px top, red, blue)",
-	"radial-gradient(at 0 0, red, blue)",
+  "radial-gradient(at top left, red, blue)",
+  "radial-gradient(at 20% bottom, red, blue)",
+  "radial-gradient(at center 20%, red, blue)",
+  "radial-gradient(at left 35px, red, blue)",
+  "radial-gradient(at 10% 10em, red, blue)",
+  "radial-gradient(at 44px top, red, blue)",
+  "radial-gradient(at 0 0, red, blue)",
 
-	"radial-gradient(farthest-corner, red, blue)",
-	"radial-gradient(circle, red, blue)",
-	"radial-gradient(ellipse closest-corner, red, blue)",
-	"radial-gradient(closest-corner ellipse, red, blue)",
+  "radial-gradient(farthest-corner, red, blue)",
+  "radial-gradient(circle, red, blue)",
+  "radial-gradient(ellipse closest-corner, red, blue)",
+  "radial-gradient(closest-corner ellipse, red, blue)",
 
-	"radial-gradient(43px, red, blue)",
-	"radial-gradient(43px 43px, red, blue)",
-	"radial-gradient(50% 50%, red, blue)",
-	"radial-gradient(43px 50%, red, blue)",
-	"radial-gradient(50% 43px, red, blue)",
-	"radial-gradient(circle 43px, red, blue)",
-	"radial-gradient(43px circle, red, blue)",
-	"radial-gradient(ellipse 43px 43px, red, blue)",
-	"radial-gradient(ellipse 50% 50%, red, blue)",
-	"radial-gradient(ellipse 43px 50%, red, blue)",
-	"radial-gradient(ellipse 50% 43px, red, blue)",
-	"radial-gradient(50% 43px ellipse, red, blue)",
+  "radial-gradient(43px, red, blue)",
+  "radial-gradient(43px 43px, red, blue)",
+  "radial-gradient(50% 50%, red, blue)",
+  "radial-gradient(43px 50%, red, blue)",
+  "radial-gradient(50% 43px, red, blue)",
+  "radial-gradient(circle 43px, red, blue)",
+  "radial-gradient(43px circle, red, blue)",
+  "radial-gradient(ellipse 43px 43px, red, blue)",
+  "radial-gradient(ellipse 50% 50%, red, blue)",
+  "radial-gradient(ellipse 43px 50%, red, blue)",
+  "radial-gradient(ellipse 50% 43px, red, blue)",
+  "radial-gradient(50% 43px ellipse, red, blue)",
 
-	"radial-gradient(farthest-corner at top left, red, blue)",
-	"radial-gradient(ellipse closest-corner at 45px, red, blue)",
-	"radial-gradient(circle farthest-side at 45px, red, blue)",
-	"radial-gradient(closest-side ellipse at 50%, red, blue)",
-	"radial-gradient(farthest-corner circle at 4em, red, blue)",
+  "radial-gradient(farthest-corner at top left, red, blue)",
+  "radial-gradient(ellipse closest-corner at 45px, red, blue)",
+  "radial-gradient(circle farthest-side at 45px, red, blue)",
+  "radial-gradient(closest-side ellipse at 50%, red, blue)",
+  "radial-gradient(farthest-corner circle at 4em, red, blue)",
 
-	"radial-gradient(30% 40% at top left, red, blue)",
-	"radial-gradient(50px 60px at 15% 20%, red, blue)",
-	"radial-gradient(7em 8em at 45px, red, blue)",
+  "radial-gradient(30% 40% at top left, red, blue)",
+  "radial-gradient(50px 60px at 15% 20%, red, blue)",
+  "radial-gradient(7em 8em at 45px, red, blue)",
 
-	"-moz-radial-gradient(red, blue)",
-	"-moz-radial-gradient(red, yellow, blue)",
-	"-moz-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-radial-gradient(red, yellow, green, blue 50%)",
-	"-moz-radial-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-radial-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-radial-gradient(red, blue)",
+  "-moz-radial-gradient(red, yellow, blue)",
+  "-moz-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-radial-gradient(red, yellow, green, blue 50%)",
+  "-moz-radial-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-radial-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
 
-	"-moz-radial-gradient(top left, red, blue)",
-	"-moz-radial-gradient(20% bottom, red, blue)",
-	"-moz-radial-gradient(center 20%, red, blue)",
-	"-moz-radial-gradient(left 35px, red, blue)",
-	"-moz-radial-gradient(10% 10em, red, blue)",
-	"-moz-radial-gradient(44px top, red, blue)",
+  "-moz-radial-gradient(top left, red, blue)",
+  "-moz-radial-gradient(20% bottom, red, blue)",
+  "-moz-radial-gradient(center 20%, red, blue)",
+  "-moz-radial-gradient(left 35px, red, blue)",
+  "-moz-radial-gradient(10% 10em, red, blue)",
+  "-moz-radial-gradient(44px top, red, blue)",
 
-	"-moz-radial-gradient(top left 45deg, red, blue)",
-	"-moz-radial-gradient(0 0, red, blue)",
-	"-moz-radial-gradient(20% bottom -300deg, red, blue)",
-	"-moz-radial-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-radial-gradient(left 35px 30grad, red, blue)",
-	"-moz-radial-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-radial-gradient(44px top -33deg, red, blue)",
-	"-moz-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-radial-gradient(top left 45deg, red, blue)",
+  "-moz-radial-gradient(0 0, red, blue)",
+  "-moz-radial-gradient(20% bottom -300deg, red, blue)",
+  "-moz-radial-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-radial-gradient(left 35px 30grad, red, blue)",
+  "-moz-radial-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-radial-gradient(44px top -33deg, red, blue)",
+  "-moz-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-radial-gradient(-33deg, red, blue)",
-	"-moz-radial-gradient(30grad left 35px, red, blue)",
-	"-moz-radial-gradient(10deg 20px, red, blue)",
-	"-moz-radial-gradient(.414rad bottom, red, blue)",
+  "-moz-radial-gradient(-33deg, red, blue)",
+  "-moz-radial-gradient(30grad left 35px, red, blue)",
+  "-moz-radial-gradient(10deg 20px, red, blue)",
+  "-moz-radial-gradient(.414rad bottom, red, blue)",
 
-	"-moz-radial-gradient(cover, red, blue)",
-	"-moz-radial-gradient(circle, red, blue)",
-	"-moz-radial-gradient(ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(farthest-side circle, red, blue)",
+  "-moz-radial-gradient(cover, red, blue)",
+  "-moz-radial-gradient(circle, red, blue)",
+  "-moz-radial-gradient(ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(top left, cover, red, blue)",
-	"-moz-radial-gradient(15% 20%, circle, red, blue)",
-	"-moz-radial-gradient(45px, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(45px, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(top left, cover, red, blue)",
+  "-moz-radial-gradient(15% 20%, circle, red, blue)",
+  "-moz-radial-gradient(45px, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(45px, farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(99deg, cover, red, blue)",
-	"-moz-radial-gradient(-1.2345rad, circle, red, blue)",
-	"-moz-radial-gradient(399grad, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(399grad, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(99deg, cover, red, blue)",
+  "-moz-radial-gradient(-1.2345rad, circle, red, blue)",
+  "-moz-radial-gradient(399grad, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(399grad, farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(top left 99deg, cover, red, blue)",
-	"-moz-radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
-	"-moz-radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
-	"-moz-radial-gradient(45px 399grad, farthest-side circle, red, blue)",
+  "-moz-radial-gradient(top left 99deg, cover, red, blue)",
+  "-moz-radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
+  "-moz-radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
+  "-moz-radial-gradient(45px 399grad, farthest-side circle, red, blue)",
 
-	"-moz-repeating-linear-gradient(red, blue)",
-	"-moz-repeating-linear-gradient(red, yellow, blue)",
-	"-moz-repeating-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-repeating-linear-gradient(red, yellow, green, blue 50%)",
-	"-moz-repeating-linear-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-repeating-linear-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-repeating-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-repeating-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-repeating-linear-gradient(red, blue)",
+  "-moz-repeating-linear-gradient(red, yellow, blue)",
+  "-moz-repeating-linear-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-repeating-linear-gradient(red, yellow, green, blue 50%)",
+  "-moz-repeating-linear-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-repeating-linear-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-repeating-linear-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-repeating-linear-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"-moz-repeating-linear-gradient(to top, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to left, red, blue)",
-	"-moz-repeating-linear-gradient(to right, red, blue)",
-	"-moz-repeating-linear-gradient(to top left, red, blue)",
-	"-moz-repeating-linear-gradient(to top right, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom left, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom right, red, blue)",
-	"-moz-repeating-linear-gradient(to left top, red, blue)",
-	"-moz-repeating-linear-gradient(to left bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to right top, red, blue)",
-	"-moz-repeating-linear-gradient(to right bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to top, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to left, red, blue)",
+  "-moz-repeating-linear-gradient(to right, red, blue)",
+  "-moz-repeating-linear-gradient(to top left, red, blue)",
+  "-moz-repeating-linear-gradient(to top right, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom left, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom right, red, blue)",
+  "-moz-repeating-linear-gradient(to left top, red, blue)",
+  "-moz-repeating-linear-gradient(to left bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to right top, red, blue)",
+  "-moz-repeating-linear-gradient(to right bottom, red, blue)",
 
-	"-moz-repeating-linear-gradient(top left, red, blue)",
-	"-moz-repeating-linear-gradient(0 0, red, blue)",
-	"-moz-repeating-linear-gradient(20% bottom, red, blue)",
-	"-moz-repeating-linear-gradient(center 20%, red, blue)",
-	"-moz-repeating-linear-gradient(left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(10% 10em, red, blue)",
-	"-moz-repeating-linear-gradient(44px top, red, blue)",
+  "-moz-repeating-linear-gradient(top left, red, blue)",
+  "-moz-repeating-linear-gradient(0 0, red, blue)",
+  "-moz-repeating-linear-gradient(20% bottom, red, blue)",
+  "-moz-repeating-linear-gradient(center 20%, red, blue)",
+  "-moz-repeating-linear-gradient(left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(10% 10em, red, blue)",
+  "-moz-repeating-linear-gradient(44px top, red, blue)",
 
-	"-moz-repeating-linear-gradient(top left 45deg, red, blue)",
-	"-moz-repeating-linear-gradient(20% bottom -300deg, red, blue)",
-	"-moz-repeating-linear-gradient(center 20% 1.95929rad, red, blue)",
-	"-moz-repeating-linear-gradient(left 35px 30grad, red, blue)",
-	"-moz-repeating-linear-gradient(10% 10em 99999deg, red, blue)",
-	"-moz-repeating-linear-gradient(44px top -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(top left 45deg, red, blue)",
+  "-moz-repeating-linear-gradient(20% bottom -300deg, red, blue)",
+  "-moz-repeating-linear-gradient(center 20% 1.95929rad, red, blue)",
+  "-moz-repeating-linear-gradient(left 35px 30grad, red, blue)",
+  "-moz-repeating-linear-gradient(10% 10em 99999deg, red, blue)",
+  "-moz-repeating-linear-gradient(44px top -33deg, red, blue)",
 
-	"-moz-repeating-linear-gradient(-33deg, red, blue)",
-	"-moz-repeating-linear-gradient(30grad left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(10deg 20px, red, blue)",
-	"-moz-repeating-linear-gradient(.414rad bottom, red, blue)",
+  "-moz-repeating-linear-gradient(-33deg, red, blue)",
+  "-moz-repeating-linear-gradient(30grad left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(10deg 20px, red, blue)",
+  "-moz-repeating-linear-gradient(.414rad bottom, red, blue)",
 
-	"-moz-repeating-radial-gradient(red, blue)",
-	"-moz-repeating-radial-gradient(red, yellow, blue)",
-	"-moz-repeating-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
-	"-moz-repeating-radial-gradient(red, yellow, green, blue 50%)",
-	"-moz-repeating-radial-gradient(red -50%, yellow -25%, green, blue)",
-	"-moz-repeating-radial-gradient(red -99px, yellow, green, blue 120%)",
-	"-moz-repeating-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
-	"-moz-repeating-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
+  "-moz-repeating-radial-gradient(red, blue)",
+  "-moz-repeating-radial-gradient(red, yellow, blue)",
+  "-moz-repeating-radial-gradient(red 1px, yellow 20%, blue 24em, green)",
+  "-moz-repeating-radial-gradient(red, yellow, green, blue 50%)",
+  "-moz-repeating-radial-gradient(red -50%, yellow -25%, green, blue)",
+  "-moz-repeating-radial-gradient(red -99px, yellow, green, blue 120%)",
+  "-moz-repeating-radial-gradient(#ffff00, #ef3, rgba(10, 20, 30, 0.4))",
+  "-moz-repeating-radial-gradient(rgba(10, 20, 30, 0.4), #ffff00, #ef3)",
 
-	"repeating-radial-gradient(at top left, red, blue)",
-	"repeating-radial-gradient(at 0 0, red, blue)",
-	"repeating-radial-gradient(at 20% bottom, red, blue)",
-	"repeating-radial-gradient(at center 20%, red, blue)",
-	"repeating-radial-gradient(at left 35px, red, blue)",
-	"repeating-radial-gradient(at 10% 10em, red, blue)",
-	"repeating-radial-gradient(at 44px top, red, blue)",
+  "repeating-radial-gradient(at top left, red, blue)",
+  "repeating-radial-gradient(at 0 0, red, blue)",
+  "repeating-radial-gradient(at 20% bottom, red, blue)",
+  "repeating-radial-gradient(at center 20%, red, blue)",
+  "repeating-radial-gradient(at left 35px, red, blue)",
+  "repeating-radial-gradient(at 10% 10em, red, blue)",
+  "repeating-radial-gradient(at 44px top, red, blue)",
 
-	"-moz-repeating-radial-gradient(farthest-corner, red, blue)",
-	"-moz-repeating-radial-gradient(circle, red, blue)",
-	"-moz-repeating-radial-gradient(ellipse closest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(farthest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(circle, red, blue)",
+  "-moz-repeating-radial-gradient(ellipse closest-corner, red, blue)",
 
-	"repeating-radial-gradient(farthest-corner at top left, red, blue)",
-	"repeating-radial-gradient(closest-corner ellipse at 45px, red, blue)",
-	"repeating-radial-gradient(farthest-side circle at 45px, red, blue)",
-	"repeating-radial-gradient(ellipse closest-side at 50%, red, blue)",
-	"repeating-radial-gradient(circle farthest-corner at 4em, red, blue)",
+  "repeating-radial-gradient(farthest-corner at top left, red, blue)",
+  "repeating-radial-gradient(closest-corner ellipse at 45px, red, blue)",
+  "repeating-radial-gradient(farthest-side circle at 45px, red, blue)",
+  "repeating-radial-gradient(ellipse closest-side at 50%, red, blue)",
+  "repeating-radial-gradient(circle farthest-corner at 4em, red, blue)",
 
-	"repeating-radial-gradient(30% 40% at top left, red, blue)",
-	"repeating-radial-gradient(50px 60px at 15% 20%, red, blue)",
-	"repeating-radial-gradient(7em 8em at 45px, red, blue)",
+  "repeating-radial-gradient(30% 40% at top left, red, blue)",
+  "repeating-radial-gradient(50px 60px at 15% 20%, red, blue)",
+  "repeating-radial-gradient(7em 8em at 45px, red, blue)",
 
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 2, 10, 10, 2)",
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10%, 50%, 30%, 0%)",
-	"-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10, 50%, 30%, 0)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 2, 10, 10, 2)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10%, 50%, 30%, 0%)",
+  "-moz-image-rect(url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAKElEQVR42u3NQQ0AAAgEoNP+nTWFDzcoQE1udQQCgUAgEAgEAsGTYAGjxAE/G/Q2tQAAAABJRU5ErkJggg==), 10, 50%, 30%, 0)",
 
-	"-moz-radial-gradient(calc(25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(25%), red, blue)",
-	"-moz-radial-gradient(calc(25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(25px), red, blue)",
-	"-moz-radial-gradient(calc(-25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(-25%), red, blue)",
-	"-moz-radial-gradient(calc(-25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(-25px), red, blue)",
-	"-moz-radial-gradient(calc(100px + -25%) top, red, blue)",
-	"-moz-radial-gradient(left calc(100px + -25%), red, blue)",
-	"-moz-radial-gradient(calc(100px + -25px) top, red, blue)",
-	"-moz-radial-gradient(left calc(100px + -25px), red, blue)"
+  "-moz-radial-gradient(calc(25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(25%), red, blue)",
+  "-moz-radial-gradient(calc(25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(25px), red, blue)",
+  "-moz-radial-gradient(calc(-25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(-25%), red, blue)",
+  "-moz-radial-gradient(calc(-25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(-25px), red, blue)",
+  "-moz-radial-gradient(calc(100px + -25%) top, red, blue)",
+  "-moz-radial-gradient(left calc(100px + -25%), red, blue)",
+  "-moz-radial-gradient(calc(100px + -25px) top, red, blue)",
+  "-moz-radial-gradient(left calc(100px + -25px), red, blue)"
 ];
 var invalidGradientAndElementValues = [
-	"-moz-element(#a:1)",
-	"-moz-element(a#a)",
-	"-moz-element(#a a)",
-	"-moz-element(#a+a)",
-	"-moz-element(#a())",
-	/* no quirks mode colors */
-	"linear-gradient(red, ff00ff)",
-	/* no quirks mode colors */
-	"-moz-radial-gradient(10% bottom, ffffff, black) scroll no-repeat",
-	/* no quirks mode lengths */
-	"-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
-	"-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
-	"linear-gradient(red -99, yellow, green, blue 120%)",
-	/* Old syntax */
-	"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
-	"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-linear-gradient(10px, 20px, 30px, 40px, color-stop(0.5, #00ccff))",
-	"-moz-linear-gradient(20px 20px, from(blue), to(red))",
-	"-moz-linear-gradient(40px 40px, 10px 10px, from(blue) to(red) color-stop(10%, fuchsia))",
-	"-moz-linear-gradient(20px 20px 30px, 10px 10px, from(red), to(#ff0000))",
-	"-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-linear-gradient(left left, top top, from(blue))",
-	"-moz-linear-gradient(inherit, 10px 10px, from(blue))",
-	/* New syntax */
-	"-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
-	"-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
-	"-moz-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
-	"-moz-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
-	"-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-linear-gradient(left left, top top, blue 0)",
-	"-moz-linear-gradient(inherit, 10px 10px, blue 0)",
-	"-moz-linear-gradient(left left blue red)",
-	"-moz-linear-gradient(left left blue, red)",
-	"-moz-linear-gradient()",
-	"-moz-linear-gradient(cover, red, blue)",
-	"-moz-linear-gradient(auto, red, blue)",
-	"-moz-linear-gradient(22 top, red, blue)",
-	"-moz-linear-gradient(10% red blue)",
-	"-moz-linear-gradient(10%, red blue)",
-	"-moz-linear-gradient(10%,, red, blue)",
-	"-moz-linear-gradient(45px, center, red, blue)",
-	"-moz-linear-gradient(45px, center red, blue)",
-	"-moz-radial-gradient(contain, ellipse, red, blue)",
-	"-moz-radial-gradient(10deg contain, red, blue)",
-	"-moz-radial-gradient(10deg, contain,, red, blue)",
-	"-moz-radial-gradient(contain contain, red, blue)",
-	"-moz-radial-gradient(ellipse circle, red, blue)",
-	"-moz-radial-gradient(to top left, red, blue)",
-	"-moz-radial-gradient(center, 10%, red, blue)",
-	"-moz-radial-gradient(5rad, 20px, red, blue)",
-	"-moz-radial-gradient(40%, -100px -10%, red, blue)",
+  "-moz-element(#a:1)",
+  "-moz-element(a#a)",
+  "-moz-element(#a a)",
+  "-moz-element(#a+a)",
+  "-moz-element(#a())",
+  /* no quirks mode colors */
+  "linear-gradient(red, ff00ff)",
+  /* no quirks mode colors */
+  "-moz-radial-gradient(10% bottom, ffffff, black) scroll no-repeat",
+  /* no quirks mode lengths */
+  "-moz-linear-gradient(10 10px -45deg, red, blue) repeat",
+  "-moz-linear-gradient(10px 10 -45deg, red, blue) repeat",
+  "linear-gradient(red -99, yellow, green, blue 120%)",
+  /* Old syntax */
+  "-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, from(blue), to(red))",
+  "-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-linear-gradient(10px, 20px, 30px, 40px, color-stop(0.5, #00ccff))",
+  "-moz-linear-gradient(20px 20px, from(blue), to(red))",
+  "-moz-linear-gradient(40px 40px, 10px 10px, from(blue) to(red) color-stop(10%, fuchsia))",
+  "-moz-linear-gradient(20px 20px 30px, 10px 10px, from(red), to(#ff0000))",
+  "-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-linear-gradient(left left, top top, from(blue))",
+  "-moz-linear-gradient(inherit, 10px 10px, from(blue))",
+  /* New syntax */
+  "-moz-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
+  "-moz-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
+  "-moz-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
+  "-moz-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
+  "-moz-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-linear-gradient(left left, top top, blue 0)",
+  "-moz-linear-gradient(inherit, 10px 10px, blue 0)",
+  "-moz-linear-gradient(left left blue red)",
+  "-moz-linear-gradient(left left blue, red)",
+  "-moz-linear-gradient()",
+  "-moz-linear-gradient(cover, red, blue)",
+  "-moz-linear-gradient(auto, red, blue)",
+  "-moz-linear-gradient(22 top, red, blue)",
+  "-moz-linear-gradient(10% red blue)",
+  "-moz-linear-gradient(10%, red blue)",
+  "-moz-linear-gradient(10%,, red, blue)",
+  "-moz-linear-gradient(45px, center, red, blue)",
+  "-moz-linear-gradient(45px, center red, blue)",
+  "-moz-radial-gradient(contain, ellipse, red, blue)",
+  "-moz-radial-gradient(10deg contain, red, blue)",
+  "-moz-radial-gradient(10deg, contain,, red, blue)",
+  "-moz-radial-gradient(contain contain, red, blue)",
+  "-moz-radial-gradient(ellipse circle, red, blue)",
+  "-moz-radial-gradient(to top left, red, blue)",
+  "-moz-radial-gradient(center, 10%, red, blue)",
+  "-moz-radial-gradient(5rad, 20px, red, blue)",
+  "-moz-radial-gradient(40%, -100px -10%, red, blue)",
 
-	"-moz-radial-gradient(at top left to cover, red, blue)",
-	"-moz-radial-gradient(at 15% 20% circle, red, blue)",
+  "-moz-radial-gradient(at top left to cover, red, blue)",
+  "-moz-radial-gradient(at 15% 20% circle, red, blue)",
 
-	"-moz-radial-gradient(to cover, red, blue)",
-	"-moz-radial-gradient(to contain, red, blue)",
-	"-moz-radial-gradient(to closest-side circle, red, blue)",
-	"-moz-radial-gradient(to farthest-corner ellipse, red, blue)",
+  "-moz-radial-gradient(to cover, red, blue)",
+  "-moz-radial-gradient(to contain, red, blue)",
+  "-moz-radial-gradient(to closest-side circle, red, blue)",
+  "-moz-radial-gradient(to farthest-corner ellipse, red, blue)",
 
-	"-moz-radial-gradient(ellipse at 45px closest-corner, red, blue)",
-	"-moz-radial-gradient(circle at 45px farthest-side, red, blue)",
-	"-moz-radial-gradient(ellipse 45px, closest-side, red, blue)",
-	"-moz-radial-gradient(circle 45px, farthest-corner, red, blue)",
-	"-moz-radial-gradient(ellipse, ellipse closest-side, red, blue)",
-	"-moz-radial-gradient(circle, circle farthest-corner, red, blue)",
+  "-moz-radial-gradient(ellipse at 45px closest-corner, red, blue)",
+  "-moz-radial-gradient(circle at 45px farthest-side, red, blue)",
+  "-moz-radial-gradient(ellipse 45px, closest-side, red, blue)",
+  "-moz-radial-gradient(circle 45px, farthest-corner, red, blue)",
+  "-moz-radial-gradient(ellipse, ellipse closest-side, red, blue)",
+  "-moz-radial-gradient(circle, circle farthest-corner, red, blue)",
 
-	"-moz-radial-gradient(99deg to farthest-corner, red, blue)",
-	"-moz-radial-gradient(-1.2345rad circle, red, blue)",
-	"-moz-radial-gradient(ellipse 399grad to closest-corner, red, blue)",
-	"-moz-radial-gradient(circle 399grad to farthest-side, red, blue)",
+  "-moz-radial-gradient(99deg to farthest-corner, red, blue)",
+  "-moz-radial-gradient(-1.2345rad circle, red, blue)",
+  "-moz-radial-gradient(ellipse 399grad to closest-corner, red, blue)",
+  "-moz-radial-gradient(circle 399grad to farthest-side, red, blue)",
 
-	"-moz-radial-gradient(at top left 99deg, to farthest-corner, red, blue)",
-	"-moz-radial-gradient(circle at 15% 20% -1.2345rad, red, blue)",
-	"-moz-radial-gradient(to top left at 30% 40%, red, blue)",
-	"-moz-radial-gradient(ellipse at 45px 399grad, to closest-corner, red, blue)",
-	"-moz-radial-gradient(at 45px 399grad to farthest-side circle, red, blue)",
+  "-moz-radial-gradient(at top left 99deg, to farthest-corner, red, blue)",
+  "-moz-radial-gradient(circle at 15% 20% -1.2345rad, red, blue)",
+  "-moz-radial-gradient(to top left at 30% 40%, red, blue)",
+  "-moz-radial-gradient(ellipse at 45px 399grad, to closest-corner, red, blue)",
+  "-moz-radial-gradient(at 45px 399grad to farthest-side circle, red, blue)",
 
-	"-moz-radial-gradient(to 50%, red, blue)",
-	"-moz-radial-gradient(circle to 50%, red, blue)",
-	"-moz-radial-gradient(circle to 43px 43px, red, blue)",
-	"-moz-radial-gradient(circle to 50% 50%, red, blue)",
-	"-moz-radial-gradient(circle to 43px 50%, red, blue)",
-	"-moz-radial-gradient(circle to 50% 43px, red, blue)",
-	"-moz-radial-gradient(ellipse to 43px, red, blue)",
-	"-moz-radial-gradient(ellipse to 50%, red, blue)",
+  "-moz-radial-gradient(to 50%, red, blue)",
+  "-moz-radial-gradient(circle to 50%, red, blue)",
+  "-moz-radial-gradient(circle to 43px 43px, red, blue)",
+  "-moz-radial-gradient(circle to 50% 50%, red, blue)",
+  "-moz-radial-gradient(circle to 43px 50%, red, blue)",
+  "-moz-radial-gradient(circle to 50% 43px, red, blue)",
+  "-moz-radial-gradient(ellipse to 43px, red, blue)",
+  "-moz-radial-gradient(ellipse to 50%, red, blue)",
 
-	"-moz-linear-gradient(to 0 0, red, blue)",
-	"-moz-linear-gradient(to 20% bottom, red, blue)",
-	"-moz-linear-gradient(to center 20%, red, blue)",
-	"-moz-linear-gradient(to left 35px, red, blue)",
-	"-moz-linear-gradient(to 10% 10em, red, blue)",
-	"-moz-linear-gradient(to 44px top, red, blue)",
-	"-moz-linear-gradient(to top left 45deg, red, blue)",
-	"-moz-linear-gradient(to 20% bottom -300deg, red, blue)",
-	"-moz-linear-gradient(to center 20% 1.95929rad, red, blue)",
-	"-moz-linear-gradient(to left 35px 30grad, red, blue)",
-	"-moz-linear-gradient(to 10% 10em 99999deg, red, blue)",
-	"-moz-linear-gradient(to 44px top -33deg, red, blue)",
-	"-moz-linear-gradient(to -33deg, red, blue)",
-	"-moz-linear-gradient(to 30grad left 35px, red, blue)",
-	"-moz-linear-gradient(to 10deg 20px, red, blue)",
-	"-moz-linear-gradient(to .414rad bottom, red, blue)",
+  "-moz-linear-gradient(to 0 0, red, blue)",
+  "-moz-linear-gradient(to 20% bottom, red, blue)",
+  "-moz-linear-gradient(to center 20%, red, blue)",
+  "-moz-linear-gradient(to left 35px, red, blue)",
+  "-moz-linear-gradient(to 10% 10em, red, blue)",
+  "-moz-linear-gradient(to 44px top, red, blue)",
+  "-moz-linear-gradient(to top left 45deg, red, blue)",
+  "-moz-linear-gradient(to 20% bottom -300deg, red, blue)",
+  "-moz-linear-gradient(to center 20% 1.95929rad, red, blue)",
+  "-moz-linear-gradient(to left 35px 30grad, red, blue)",
+  "-moz-linear-gradient(to 10% 10em 99999deg, red, blue)",
+  "-moz-linear-gradient(to 44px top -33deg, red, blue)",
+  "-moz-linear-gradient(to -33deg, red, blue)",
+  "-moz-linear-gradient(to 30grad left 35px, red, blue)",
+  "-moz-linear-gradient(to 10deg 20px, red, blue)",
+  "-moz-linear-gradient(to .414rad bottom, red, blue)",
 
-	"-moz-linear-gradient(to top top, red, blue)",
-	"-moz-linear-gradient(to bottom bottom, red, blue)",
-	"-moz-linear-gradient(to left left, red, blue)",
-	"-moz-linear-gradient(to right right, red, blue)",
+  "-moz-linear-gradient(to top top, red, blue)",
+  "-moz-linear-gradient(to bottom bottom, red, blue)",
+  "-moz-linear-gradient(to left left, red, blue)",
+  "-moz-linear-gradient(to right right, red, blue)",
 
-	"-moz-repeating-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
-	"-moz-repeating-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
-	"-moz-repeating-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
-	"-moz-repeating-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
-	"-moz-repeating-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
-	"-moz-repeating-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
-	"-moz-repeating-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
-	"-moz-repeating-linear-gradient(left left, top top, blue 0)",
-	"-moz-repeating-linear-gradient(inherit, 10px 10px, blue 0)",
-	"-moz-repeating-linear-gradient(left left blue red)",
-	"-moz-repeating-linear-gradient()",
+  "-moz-repeating-linear-gradient(10px 10px, 20px, 30px 30px, 40px, blue 0, red 100%)",
+  "-moz-repeating-radial-gradient(20px 20px, 10px 10px, from(green), to(#ff00ff))",
+  "-moz-repeating-radial-gradient(10px 10px, 20%, 40px 40px, 10px, from(green), to(#ff00ff))",
+  "-moz-repeating-linear-gradient(10px, 20px, 30px, 40px, #00ccff 50%)",
+  "-moz-repeating-linear-gradient(40px 40px, 10px 10px, blue 0 fuchsia 10% red 100%)",
+  "-moz-repeating-linear-gradient(20px 20px 30px, 10px 10px, red 0, #ff0000 100%)",
+  "-moz-repeating-radial-gradient(left top, center, 20px 20px, 10px, from(blue), to(red))",
+  "-moz-repeating-linear-gradient(left left, top top, blue 0)",
+  "-moz-repeating-linear-gradient(inherit, 10px 10px, blue 0)",
+  "-moz-repeating-linear-gradient(left left blue red)",
+  "-moz-repeating-linear-gradient()",
 
-	"-moz-repeating-linear-gradient(to 0 0, red, blue)",
-	"-moz-repeating-linear-gradient(to 20% bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to center 20%, red, blue)",
-	"-moz-repeating-linear-gradient(to left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(to 10% 10em, red, blue)",
-	"-moz-repeating-linear-gradient(to 44px top, red, blue)",
-	"-moz-repeating-linear-gradient(to top left 45deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 20% bottom -300deg, red, blue)",
-	"-moz-repeating-linear-gradient(to center 20% 1.95929rad, red, blue)",
-	"-moz-repeating-linear-gradient(to left 35px 30grad, red, blue)",
-	"-moz-repeating-linear-gradient(to 10% 10em 99999deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 44px top -33deg, red, blue)",
-	"-moz-repeating-linear-gradient(to -33deg, red, blue)",
-	"-moz-repeating-linear-gradient(to 30grad left 35px, red, blue)",
-	"-moz-repeating-linear-gradient(to 10deg 20px, red, blue)",
-	"-moz-repeating-linear-gradient(to .414rad bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to 0 0, red, blue)",
+  "-moz-repeating-linear-gradient(to 20% bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to center 20%, red, blue)",
+  "-moz-repeating-linear-gradient(to left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(to 10% 10em, red, blue)",
+  "-moz-repeating-linear-gradient(to 44px top, red, blue)",
+  "-moz-repeating-linear-gradient(to top left 45deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 20% bottom -300deg, red, blue)",
+  "-moz-repeating-linear-gradient(to center 20% 1.95929rad, red, blue)",
+  "-moz-repeating-linear-gradient(to left 35px 30grad, red, blue)",
+  "-moz-repeating-linear-gradient(to 10% 10em 99999deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 44px top -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(to -33deg, red, blue)",
+  "-moz-repeating-linear-gradient(to 30grad left 35px, red, blue)",
+  "-moz-repeating-linear-gradient(to 10deg 20px, red, blue)",
+  "-moz-repeating-linear-gradient(to .414rad bottom, red, blue)",
 
-	"-moz-repeating-linear-gradient(to top top, red, blue)",
-	"-moz-repeating-linear-gradient(to bottom bottom, red, blue)",
-	"-moz-repeating-linear-gradient(to left left, red, blue)",
-	"-moz-repeating-linear-gradient(to right right, red, blue)",
+  "-moz-repeating-linear-gradient(to top top, red, blue)",
+  "-moz-repeating-linear-gradient(to bottom bottom, red, blue)",
+  "-moz-repeating-linear-gradient(to left left, red, blue)",
+  "-moz-repeating-linear-gradient(to right right, red, blue)",
 
-	"-moz-repeating-radial-gradient(to top left at 30% 40%, red, blue)",
-	"-moz-repeating-radial-gradient(ellipse at 45px closest-corner, red, blue)",
-	"-moz-repeating-radial-gradient(circle at 45px farthest-side, red, blue)",
+  "-moz-repeating-radial-gradient(to top left at 30% 40%, red, blue)",
+  "-moz-repeating-radial-gradient(ellipse at 45px closest-corner, red, blue)",
+  "-moz-repeating-radial-gradient(circle at 45px farthest-side, red, blue)",
 
-	"radial-gradient(circle 175px 20px, black, white)",
-	"radial-gradient(175px 20px circle, black, white)",
-	"radial-gradient(ellipse 175px, black, white)",
-	"radial-gradient(175px ellipse, black, white)",
-	"radial-gradient(50%, red, blue)",
-	"radial-gradient(circle 50%, red, blue)",
-	"radial-gradient(50% circle, red, blue)",
+  "radial-gradient(circle 175px 20px, black, white)",
+  "radial-gradient(175px 20px circle, black, white)",
+  "radial-gradient(ellipse 175px, black, white)",
+  "radial-gradient(175px ellipse, black, white)",
+  "radial-gradient(50%, red, blue)",
+  "radial-gradient(circle 50%, red, blue)",
+  "radial-gradient(50% circle, red, blue)",
 
-	/* Valid only when prefixed */
-	"linear-gradient(top left, red, blue)",
-	"linear-gradient(0 0, red, blue)",
-	"linear-gradient(20% bottom, red, blue)",
-	"linear-gradient(center 20%, red, blue)",
-	"linear-gradient(left 35px, red, blue)",
-	"linear-gradient(10% 10em, red, blue)",
-	"linear-gradient(44px top, red, blue)",
+  /* Valid only when prefixed */
+  "linear-gradient(top left, red, blue)",
+  "linear-gradient(0 0, red, blue)",
+  "linear-gradient(20% bottom, red, blue)",
+  "linear-gradient(center 20%, red, blue)",
+  "linear-gradient(left 35px, red, blue)",
+  "linear-gradient(10% 10em, red, blue)",
+  "linear-gradient(44px top, red, blue)",
 
-	"linear-gradient(top left 45deg, red, blue)",
-	"linear-gradient(20% bottom -300deg, red, blue)",
-	"linear-gradient(center 20% 1.95929rad, red, blue)",
-	"linear-gradient(left 35px 30grad, red, blue)",
-	"linear-gradient(left 35px 0.1turn, red, blue)",
-	"linear-gradient(10% 10em 99999deg, red, blue)",
-	"linear-gradient(44px top -33deg, red, blue)",
+  "linear-gradient(top left 45deg, red, blue)",
+  "linear-gradient(20% bottom -300deg, red, blue)",
+  "linear-gradient(center 20% 1.95929rad, red, blue)",
+  "linear-gradient(left 35px 30grad, red, blue)",
+  "linear-gradient(left 35px 0.1turn, red, blue)",
+  "linear-gradient(10% 10em 99999deg, red, blue)",
+  "linear-gradient(44px top -33deg, red, blue)",
 
-	"linear-gradient(30grad left 35px, red, blue)",
-	"linear-gradient(10deg 20px, red, blue)",
-	"linear-gradient(1turn 20px, red, blue)",
-	"linear-gradient(.414rad bottom, red, blue)",
+  "linear-gradient(30grad left 35px, red, blue)",
+  "linear-gradient(10deg 20px, red, blue)",
+  "linear-gradient(1turn 20px, red, blue)",
+  "linear-gradient(.414rad bottom, red, blue)",
 
-	"radial-gradient(top left 45deg, red, blue)",
-	"radial-gradient(20% bottom -300deg, red, blue)",
-	"radial-gradient(center 20% 1.95929rad, red, blue)",
-	"radial-gradient(left 35px 30grad, red, blue)",
-	"radial-gradient(10% 10em 99999deg, red, blue)",
-	"radial-gradient(44px top -33deg, red, blue)",
+  "radial-gradient(top left 45deg, red, blue)",
+  "radial-gradient(20% bottom -300deg, red, blue)",
+  "radial-gradient(center 20% 1.95929rad, red, blue)",
+  "radial-gradient(left 35px 30grad, red, blue)",
+  "radial-gradient(10% 10em 99999deg, red, blue)",
+  "radial-gradient(44px top -33deg, red, blue)",
 
-	"radial-gradient(-33deg, red, blue)",
-	"radial-gradient(30grad left 35px, red, blue)",
-	"radial-gradient(10deg 20px, red, blue)",
-	"radial-gradient(.414rad bottom, red, blue)",
+  "radial-gradient(-33deg, red, blue)",
+  "radial-gradient(30grad left 35px, red, blue)",
+  "radial-gradient(10deg 20px, red, blue)",
+  "radial-gradient(.414rad bottom, red, blue)",
 
-	"radial-gradient(cover, red, blue)",
-	"radial-gradient(ellipse contain, red, blue)",
-	"radial-gradient(cover circle, red, blue)",
+  "radial-gradient(cover, red, blue)",
+  "radial-gradient(ellipse contain, red, blue)",
+  "radial-gradient(cover circle, red, blue)",
 
-	"radial-gradient(top left, cover, red, blue)",
-	"radial-gradient(15% 20%, circle, red, blue)",
-	"radial-gradient(45px, ellipse closest-corner, red, blue)",
-	"radial-gradient(45px, farthest-side circle, red, blue)",
+  "radial-gradient(top left, cover, red, blue)",
+  "radial-gradient(15% 20%, circle, red, blue)",
+  "radial-gradient(45px, ellipse closest-corner, red, blue)",
+  "radial-gradient(45px, farthest-side circle, red, blue)",
 
-	"radial-gradient(99deg, cover, red, blue)",
-	"radial-gradient(-1.2345rad, circle, red, blue)",
-	"radial-gradient(399grad, ellipse closest-corner, red, blue)",
-	"radial-gradient(399grad, farthest-side circle, red, blue)",
+  "radial-gradient(99deg, cover, red, blue)",
+  "radial-gradient(-1.2345rad, circle, red, blue)",
+  "radial-gradient(399grad, ellipse closest-corner, red, blue)",
+  "radial-gradient(399grad, farthest-side circle, red, blue)",
 
-	"radial-gradient(top left 99deg, cover, red, blue)",
-	"radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
-	"radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
-	"radial-gradient(45px 399grad, farthest-side circle, red, blue)",
+  "radial-gradient(top left 99deg, cover, red, blue)",
+  "radial-gradient(15% 20% -1.2345rad, circle, red, blue)",
+  "radial-gradient(45px 399grad, ellipse closest-corner, red, blue)",
+  "radial-gradient(45px 399grad, farthest-side circle, red, blue)",
 
-	/* Valid only when unprefixed */
-	"-moz-radial-gradient(at top left, red, blue)",
-	"-moz-radial-gradient(at 20% bottom, red, blue)",
-	"-moz-radial-gradient(at center 20%, red, blue)",
-	"-moz-radial-gradient(at left 35px, red, blue)",
-	"-moz-radial-gradient(at 10% 10em, red, blue)",
-	"-moz-radial-gradient(at 44px top, red, blue)",
-	"-moz-radial-gradient(at 0 0, red, blue)",
+  /* Valid only when unprefixed */
+  "-moz-radial-gradient(at top left, red, blue)",
+  "-moz-radial-gradient(at 20% bottom, red, blue)",
+  "-moz-radial-gradient(at center 20%, red, blue)",
+  "-moz-radial-gradient(at left 35px, red, blue)",
+  "-moz-radial-gradient(at 10% 10em, red, blue)",
+  "-moz-radial-gradient(at 44px top, red, blue)",
+  "-moz-radial-gradient(at 0 0, red, blue)",
 
-	"-moz-radial-gradient(circle 43px, red, blue)",
-	"-moz-radial-gradient(ellipse 43px 43px, red, blue)",
-	"-moz-radial-gradient(ellipse 50% 50%, red, blue)",
-	"-moz-radial-gradient(ellipse 43px 50%, red, blue)",
-	"-moz-radial-gradient(ellipse 50% 43px, red, blue)",
+  "-moz-radial-gradient(circle 43px, red, blue)",
+  "-moz-radial-gradient(ellipse 43px 43px, red, blue)",
+  "-moz-radial-gradient(ellipse 50% 50%, red, blue)",
+  "-moz-radial-gradient(ellipse 43px 50%, red, blue)",
+  "-moz-radial-gradient(ellipse 50% 43px, red, blue)",
 
-	"-moz-radial-gradient(farthest-corner at top left, red, blue)",
-	"-moz-radial-gradient(ellipse closest-corner at 45px, red, blue)",
-	"-moz-radial-gradient(circle farthest-side at 45px, red, blue)",
-	"-moz-radial-gradient(closest-side ellipse at 50%, red, blue)",
-	"-moz-radial-gradient(farthest-corner circle at 4em, red, blue)",
+  "-moz-radial-gradient(farthest-corner at top left, red, blue)",
+  "-moz-radial-gradient(ellipse closest-corner at 45px, red, blue)",
+  "-moz-radial-gradient(circle farthest-side at 45px, red, blue)",
+  "-moz-radial-gradient(closest-side ellipse at 50%, red, blue)",
+  "-moz-radial-gradient(farthest-corner circle at 4em, red, blue)",
 
-	"-moz-radial-gradient(30% 40% at top left, red, blue)",
-	"-moz-radial-gradient(50px 60px at 15% 20%, red, blue)",
-	"-moz-radial-gradient(7em 8em at 45px, red, blue)"
+  "-moz-radial-gradient(30% 40% at top left, red, blue)",
+  "-moz-radial-gradient(50px 60px at 15% 20%, red, blue)",
+  "-moz-radial-gradient(7em 8em at 45px, red, blue)"
 ];
 var unbalancedGradientAndElementValues = [
-	"-moz-element(#a()",
+  "-moz-element(#a()",
 ];
 
 var gCSSProperties = {
-	"animation": {
-		domProp: "animation",
-		inherited: false,
-		type: CSS_TYPE_TRUE_SHORTHAND,
-		subproperties: [ "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-direction", "animation-fill-mode", "animation-iteration-count" ],
-		initial_values: [ "none none 0s 0s ease normal 1.0", "none", "0s", "ease", "normal", "1.0" ],
-		other_values: [ "bounce 1s linear 2s", "bounce 1s 2s linear", "bounce linear 1s 2s", "linear bounce 1s 2s", "linear 1s bounce 2s", "linear 1s 2s bounce", "1s bounce linear 2s", "1s bounce 2s linear", "1s 2s bounce linear", "1s linear bounce 2s", "1s linear 2s bounce", "1s 2s linear bounce", "bounce linear 1s", "bounce 1s linear", "linear bounce 1s", "linear 1s bounce", "1s bounce linear", "1s linear bounce", "1s 2s bounce", "1s bounce 2s", "bounce 1s 2s", "1s 2s linear", "1s linear 2s", "linear 1s 2s", "bounce 1s", "1s bounce", "linear 1s", "1s linear", "1s 2s", "2s 1s", "bounce", "linear", "1s", "height", "2s", "ease-in-out", "2s ease-in", "opacity linear", "ease-out 2s", "2s color, 1s bounce, 500ms height linear, 1s opacity 4s cubic-bezier(0.0, 0.1, 1.0, 1.0)", "1s \\32bounce linear 2s", "1s -bounce linear 2s", "1s -\\32bounce linear 2s", "1s \\32 0bounce linear 2s", "1s -\\32 0bounce linear 2s", "1s \\2bounce linear 2s", "1s -\\2bounce linear 2s", "2s, 1s bounce", "1s bounce, 2s", "2s all, 1s bounce", "1s bounce, 2s all", "1s bounce, 2s none", "2s none, 1s bounce", "2s bounce, 1s all", "2s all, 1s bounce" ],
-		invalid_values: [  "2s inherit", "inherit 2s", "2s bounce, 1s inherit", "2s inherit, 1s bounce", "2s initial", "2s all,, 1s bounce", "2s all, , 1s bounce" ]
-	},
-	"animation-delay": {
-		domProp: "animationDelay",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "0s", "0ms" ],
-		other_values: [ "1s", "250ms", "-100ms", "-1s", "1s, 250ms, 2.3s"],
-		invalid_values: [ "0", "0px" ]
-	},
-	"animation-direction": {
-		domProp: "animationDirection",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "normal" ],
-		other_values: [ "alternate", "normal, alternate", "alternate, normal", "normal, normal", "normal, normal, normal", "reverse", "alternate-reverse", "normal, reverse, alternate-reverse, alternate" ],
-		invalid_values: [ "normal normal", "inherit, normal", "reverse-alternate" ]
-	},
-	"animation-duration": {
-		domProp: "animationDuration",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "0s", "0ms" ],
-		other_values: [ "1s", "250ms", "1s, 250ms, 2.3s"],
-		invalid_values: [ "0", "0px", "-1ms", "-2s" ]
-	},
-	"animation-fill-mode": {
-		domProp: "animationFillMode",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "forwards", "backwards", "both", "none, none", "forwards, backwards", "forwards, none", "none, both" ],
-		invalid_values: [ "all"]
-	},
-	"animation-iteration-count": {
-		domProp: "animationIterationCount",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "1" ],
-		other_values: [ "infinite", "0", "0.5", "7.75", "-0.0", "1, 2, 3", "infinite, 2", "1, infinite" ],
-		// negatives forbidden per
-		// http://lists.w3.org/Archives/Public/www-style/2011Mar/0355.html
-		invalid_values: [ "none", "-1", "-0.5", "-1, infinite", "infinite, -3" ]
-	},
-	"animation-name": {
-		domProp: "animationName",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "all", "ball", "mall", "color", "bounce, bubble, opacity", "foobar", "auto", "\\32bounce", "-bounce", "-\\32bounce", "\\32 0bounce", "-\\32 0bounce", "\\2bounce", "-\\2bounce" ],
-		invalid_values: [ "bounce, initial", "initial, bounce", "bounce, inherit", "inherit, bounce" ]
-	},
-	"animation-play-state": {
-		domProp: "animationPlayState",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "running" ],
-		other_values: [ "paused", "running, running", "paused, running", "paused, paused", "running, paused", "paused, running, running, running, paused, running" ],
-		invalid_values: [ "0" ]
-	},
-	"animation-timing-function": {
-		domProp: "animationTimingFunction",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "ease", "cubic-bezier(0.25, 0.1, 0.25, 1.0)" ],
-		other_values: [ "linear", "ease-in", "ease-out", "ease-in-out", "linear, ease-in, cubic-bezier(0.1, 0.2, 0.8, 0.9)", "cubic-bezier(0.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.25, 1.5, 0.75, -0.5)", "step-start", "step-end", "steps(1)", "steps(2, start)", "steps(386)", "steps(3, end)" ],
-		invalid_values: [ "none", "auto", "cubic-bezier(0.25, 0.1, 0.25)", "cubic-bezier(0.25, 0.1, 0.25, 0.25, 1.0)", "cubic-bezier(-0.5, 0.5, 0.5, 0.5)", "cubic-bezier(1.5, 0.5, 0.5, 0.5)", "cubic-bezier(0.5, 0.5, -0.5, 0.5)", "cubic-bezier(0.5, 0.5, 1.5, 0.5)", "steps(2, step-end)", "steps(0)", "steps(-2)", "steps(0, step-end, 1)" ]
-	},
-	"-moz-appearance": {
-		domProp: "MozAppearance",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "radio", "menulist" ],
-		invalid_values: []
-	},
-	"-moz-background-inline-policy": {
-		domProp: "MozBackgroundInlinePolicy",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "continuous" ],
-		other_values: ["bounding-box", "each-box" ],
-		invalid_values: []
-	},
-	"-moz-binding": {
-		domProp: "MozBinding",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "url(foo.xml)" ],
-		invalid_values: []
-	},
-	"-moz-border-bottom-colors": {
-		domProp: "MozBorderBottomColors",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "red green", "red #fc3", "#ff00cc", "currentColor", "blue currentColor orange currentColor" ],
-		invalid_values: [ "red none", "red inherit", "red, green", "none red", "inherit red", "ff00cc" ]
-	},
-	"-moz-border-end": {
-		domProp: "MozBorderEnd",
-		inherited: false,
-		type: CSS_TYPE_TRUE_SHORTHAND,
-		subproperties: [ "-moz-border-end-color", "-moz-border-end-style", "-moz-border-end-width" ],
-		initial_values: [ "none", "medium", "currentColor", "thin", "none medium currentcolor" ],
-		other_values: [ "solid", "green", "medium solid", "green solid", "10px solid", "thick solid", "5px green none" ],
-		invalid_values: [ "5%", "5", "5 green none" ]
-	},
-	"-moz-border-end-color": {
-		domProp: "MozBorderEndColor",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		initial_values: [ "currentColor" ],
-		other_values: [ "green", "rgba(255,128,0,0.5)", "transparent" ],
-		invalid_values: [ "#0", "#00", "#0000", "#00000", "#0000000", "#00000000", "#000000000", "000000" ]
-	},
-	"-moz-border-end-style": {
-		domProp: "MozBorderEndStyle",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		/* XXX hidden is sometimes the same as initial */
-		initial_values: [ "none" ],
-		other_values: [ "solid", "dashed", "dotted", "double", "outset", "inset", "groove", "ridge" ],
-		invalid_values: []
-	},
-	"-moz-border-end-width": {
-		domProp: "MozBorderEndWidth",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		prerequisites: { "-moz-border-end-style": "solid" },
-		initial_values: [ "medium", "3px", "calc(4px - 1px)" ],
-		other_values: [ "thin", "thick", "1px", "2em",
-			"calc(2px)",
-			"calc(-2px)",
-			"calc(0em)",
-			"calc(0px)",
-			"calc(5em)",
-			"calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 5em)",
-		],
-		invalid_values: [ "5%", "5" ]
-	},
-	"border-image": {
-		domProp: "borderImage",
-		inherited: false,
-		type: CSS_TYPE_TRUE_SHORTHAND,
-		subproperties: [ "border-image-source", "border-image-slice", "border-image-width", "border-image-outset", "border-image-repeat" ],
-		initial_values: [ "none" ],
-		other_values: [ "url('border.png') 27 27 27 27",
-						"url('border.png') 27",
-						"stretch url('border.png')",
-						"url('border.png') 27 fill",
-						"url('border.png') 27 27 27 27 repeat",
-						"repeat url('border.png') 27 27 27 27",
-						"url('border.png') repeat 27 27 27 27",
-						"url('border.png') fill 27 27 27 27 repeat",
-						"url('border.png') 27 27 27 27 / 1em",
-						"27 27 27 27 / 1em url('border.png') ",
-						"url('border.png') 27 27 27 27 / 10 10 10 / 10 10 repeat",
-						"repeat 27 27 27 27 / 10 10 10 / 10 10 url('border.png')",
-						"url('border.png') 27 27 27 27 / / 10 10 1em",
-						"fill 27 27 27 27 / / 10 10 1em url('border.png')",
-						"url('border.png') 27 27 27 27 / 1em 1em 1em 1em repeat",
-						"url('border.png') 27 27 27 27 / 1em 1em 1em 1em stretch round" ],
-		invalid_values: [ "url('border.png') 27 27 27 27 27",
-						  "url('border.png') 27 27 27 27 / 1em 1em 1em 1em 1em",
-						  "url('border.png') 27 27 27 27 /",
-						  "url('border.png') fill",
-						  "url('border.png') fill repeat",
-						  "fill repeat",
-						  "url('border.png') fill / 1em",
-						  "url('border.png') / repeat",
-						  "url('border.png') 1 /",
-						  "url('border.png') 1 / /",
-						  "1 / url('border.png')",
-						  "url('border.png') / 1",
-						  "url('border.png') / / 1"]
-	},
-	"border-image-source": {
-		domProp: "borderImageSource",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [
-		"url('border.png')"
-		].concat(validGradientAndElementValues),
-		invalid_values: [
-			"url('border.png') url('border.png')",
-		].concat(invalidGradientAndElementValues),
-		unbalanced_values: [
-		].concat(unbalancedGradientAndElementValues)
-	},
-	"border-image-slice": {
-		domProp: "borderImageSlice",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "100%", "100% 100% 100% 100%" ],
-		other_values: [ "0%", "10", "10 100% 0 2", "0 0 0 0", "fill 10 10", "10 10 fill" ],
-		invalid_values: [ "-10%", "-10", "10 10 10 10 10", "10 10 10 10 -10", "10px", "-10px", "fill", "fill fill 10px", "10px fill fill" ]
-	},
-	"border-image-width": {
-		domProp: "borderImageWidth",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "1", "1 1 1 1" ],
-		other_values: [ "0", "0%", "0px", "auto auto auto auto", "10 10% auto 15px", "10px 10px 10px 10px", "10", "10 10", "10 10 10" ],
-		invalid_values: [ "-10", "-10px", "-10%", "10 10 10 10 10", "10 10 10 10 auto", "auto auto auto auto auto" ]
-	},
-	"border-image-outset": {
-		domProp: "borderImageOutset",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "0", "0 0 0 0" ],
-		other_values: [ "10px", "10", "10 10", "10 10 10", "10 10 10 10", "10px 10 10 10px" ],
-		invalid_values: [ "-10", "-10px", "-10%", "10%", "10 10 10 10 10" ]
-	},
-	"border-image-repeat": {
-		domProp: "borderImageRepeat",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "stretch", "stretch stretch" ],
-		other_values: [ "round", "repeat", "stretch round", "repeat round", "stretch repeat", "round round", "repeat repeat" ],
-		invalid_values: [ "none", "stretch stretch stretch", "0", "10", "0%", "0px" ]
-	},
-	"-moz-border-left-colors": {
-		domProp: "MozBorderLeftColors",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "red green", "red #fc3", "#ff00cc", "currentColor", "blue currentColor orange currentColor" ],
-		invalid_values: [ "red none", "red inherit", "red, green", "none red", "inherit red", "ff00cc" ]
-	},
-	"border-radius": {
-		domProp: "borderRadius",
-		inherited: false,
-		type: CSS_TYPE_TRUE_SHORTHAND,
-		prerequisites: { "width": "200px", "height": "100px", "display": "inline-block"},
-		subproperties: [ "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius" ],
-		initial_values: [ "0", "0px", "0%", "0px 0 0 0px", "calc(-2px)", "calc(-1%)", "calc(0px) calc(0pt) calc(0%) calc(0em)" ],
-		other_values: [ "3%", "1px", "2em", "3em 2px", "2pt 3% 4em", "2px 2px 2px 2px", // circular
-						"3% / 2%", "1px / 4px", "2em / 1em", "3em 2px / 2px 3em", "2pt 3% 4em / 4pt 1% 5em", "2px 2px 2px 2px / 4px 4px 4px 4px", "1pt / 2pt 3pt", "4pt 5pt / 3pt", // elliptical
-			"calc(2px)",
-			"calc(50%)",
-			"calc(3*25px)",
-			"calc(3*25px) 5px",
-			"5px calc(3*25px)",
-			"calc(20%) calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 50%)",
-			"2px 2px calc(2px + 1%) 2px",
-			"1px 2px 2px 2px / 2px 2px calc(2px + 1%) 2px",
-					  ],
-		invalid_values: [ "2px -2px", "inherit 2px", "inherit / 2px", "2px inherit", "2px / inherit", "2px 2px 2px 2px 2px", "1px / 2px 2px 2px 2px 2px", "2", "2 2", "2px 2px 2px 2px / 2px 2px 2 2px" ]
-	},
-	"border-bottom-left-radius": {
-		domProp: "borderBottomLeftRadius",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		prerequisites: { "width": "200px", "height": "100px", "display": "inline-block"},
-		initial_values: [ "0", "0px", "0%", "calc(-2px)", "calc(-1%)" ],
-		other_values: [ "3%", "1px", "2em", // circular
-						"3% 2%", "1px 4px", "2em 2pt", // elliptical
-			"calc(2px)",
-			"calc(50%)",
-			"calc(3*25px)",
-			"calc(3*25px) 5px",
-			"5px calc(3*25px)",
-			"calc(20%) calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 50%)",
-					  ],
-		invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
-	},
-	"border-bottom-right-radius": {
-		domProp: "borderBottomRightRadius",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		prerequisites: { "width": "200px", "height": "100px", "display": "inline-block"},
-		initial_values: [ "0", "0px", "0%", "calc(-2px)", "calc(-1%)" ],
-		other_values: [ "3%", "1px", "2em", // circular
-						"3% 2%", "1px 4px", "2em 2pt", // elliptical
-			"calc(2px)",
-			"calc(50%)",
-			"calc(3*25px)",
-			"calc(3*25px) 5px",
-			"5px calc(3*25px)",
-			"calc(20%) calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 50%)",
-					  ],
-		invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
-	},
-	"border-top-left-radius": {
-		domProp: "borderTopLeftRadius",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		prerequisites: { "width": "200px", "height": "100px", "display": "inline-block"},
-		initial_values: [ "0", "0px", "0%", "calc(-2px)", "calc(-1%)" ],
-		other_values: [ "3%", "1px", "2em", // circular
-						"3% 2%", "1px 4px", "2em 2pt", // elliptical
-			"calc(2px)",
-			"calc(50%)",
-			"calc(3*25px)",
-			"calc(3*25px) 5px",
-			"5px calc(3*25px)",
-			"calc(20%) calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 50%)",
-					  ],
-		invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
-	},
-	"border-top-right-radius": {
-		domProp: "borderTopRightRadius",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		prerequisites: { "width": "200px", "height": "100px", "display": "inline-block"},
-		initial_values: [ "0", "0px", "0%", "calc(-2px)", "calc(-1%)" ],
-		other_values: [ "3%", "1px", "2em", // circular
-						"3% 2%", "1px 4px", "2em 2pt", // elliptical
-			"calc(2px)",
-			"calc(50%)",
-			"calc(3*25px)",
-			"calc(3*25px) 5px",
-			"5px calc(3*25px)",
-			"calc(20%) calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 50%)",
-					  ],
-		invalid_values: [ "-1px", "4px -2px", "inherit 2px", "2px inherit", "2", "2px 2", "2 2px" ]
-	},
-	"-moz-border-right-colors": {
-		domProp: "MozBorderRightColors",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "red green", "red #fc3", "#ff00cc", "currentColor", "blue currentColor orange currentColor" ],
-		invalid_values: [ "red none", "red inherit", "red, green", "none red", "inherit red", "ff00cc" ]
-	},
-	"-moz-border-start": {
-		domProp: "MozBorderStart",
-		inherited: false,
-		type: CSS_TYPE_TRUE_SHORTHAND,
-		subproperties: [ "-moz-border-start-color", "-moz-border-start-style", "-moz-border-start-width" ],
-		initial_values: [ "none", "medium", "currentColor", "thin", "none medium currentcolor" ],
-		other_values: [ "solid", "green", "medium solid", "green solid", "10px solid", "thick solid", "5px green none" ],
-		invalid_values: [ "5%", "5", "5 green solid" ]
-	},
-	"-moz-border-start-color": {
-		domProp: "MozBorderStartColor",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		initial_values: [ "currentColor" ],
-		other_values: [ "green", "rgba(255,128,0,0.5)", "transparent" ],
-		invalid_values: [ "#0", "#00", "#0000", "#00000", "#0000000", "#00000000", "#000000000", "000000" ]
-	},
-	"-moz-border-start-style": {
-		domProp: "MozBorderStartStyle",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		/* XXX hidden is sometimes the same as initial */
-		initial_values: [ "none" ],
-		other_values: [ "solid", "dashed", "dotted", "double", "outset", "inset", "groove", "ridge" ],
-		invalid_values: []
-	},
-	"-moz-border-start-width": {
-		domProp: "MozBorderStartWidth",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		get_computed: logical_box_prop_get_computed,
-		prerequisites: { "-moz-border-start-style": "solid" },
-		initial_values: [ "medium", "3px", "calc(4px - 1px)" ],
-		other_values: [ "thin", "thick", "1px", "2em",
-			"calc(2px)",
-			"calc(-2px)",
-			"calc(0em)",
-			"calc(0px)",
-			"calc(5em)",
-			"calc(3*25px)",
-			"calc(25px*3)",
-			"calc(3*25px + 5em)",
-		],
-		invalid_values: [ "5%", "5" ]
-	},
-	"-moz-border-top-colors": {
-		domProp: "MozBorderTopColors",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "none" ],
-		other_values: [ "red green", "red #fc3", "#ff00cc", "currentColor", "blue currentColor orange currentColor" ],
-		invalid_values: [ "red none", "red inherit", "red, green", "none red", "inherit red", "ff00cc" ]
-	},
-	"-moz-box-align": {
-		domProp: "MozBoxAlign",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "stretch" ],
-		other_values: [ "start", "center", "baseline", "end" ],
-		invalid_values: []
-	},
-	"-moz-box-direction": {
-		domProp: "MozBoxDirection",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "normal" ],
-		other_values: [ "reverse" ],
-		invalid_values: []
-	},
-	"-moz-box-flex": {
-		domProp: "MozBoxFlex",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "0", "0.0", "-0.0" ],
-		other_values: [ "1", "100", "0.1" ],
-		invalid_values: [ "10px", "-1" ]
-	},
-	"-moz-box-ordinal-group": {
-		domProp: "MozBoxOrdinalGroup",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "1" ],
-		other_values: [ "2", "100", "0" ],
-		invalid_values: [ "1.0", "-1", "-1000" ]
-	},
-	"-moz-box-orient": {
-		domProp: "MozBoxOrient",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "horizontal", "inline-axis" ],
-		other_values: [ "vertical", "block-axis" ],
-		invalid_values: []
-	},
-	"-moz-box-pack": {
-		domProp: "MozBoxPack",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "start" ],
-		other_values: [ "center", "end", "justify" ],
-		invalid_values: []
-	},
-	"box-sizing": {
-		domProp: "boxSizing",
-		inherited: false,
-		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "content-box" ],
-		other_values: [ "border-box", "padding-box" ],
-		invalid_values: [ "margin-box", "content", "padding", "border", "margin" ]
-	},
-	"-moz-box-sizing": {
-		domProp: "MozBoxSizing",
-		inherited: false,
-		type: CSS_TYPE_SHORTHAND_AND_LONGHAND,
-		alias_for: "box-sizing",
-		subproperties: [ "box-sizing" ],
-		initial_values: [ "content-box" ],
-		other_values: [ "border-box", "padding-box" ],
-		invalid_values: [ "margin-box", "content", "padding", "border", "margin" ]