Merge autoland to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Wed, 07 Sep 2016 17:26:48 -0700
changeset 354295 7c655e03eef77b961ad44f62aaa0221b7cc51a43
parent 354259 ab70808cd4b6c6ad9a57a9f71cfa495fcea0aecd (current diff)
parent 354294 99ee305777f4fc9d884736e289d150102bbb6310 (diff)
child 354362 3f6286f7ce480c890cfe5a97149dfc86bff797b7
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge autoland to central, a=merge
toolkit/components/places/UnifiedComplete.manifest
--- a/browser/components/extensions/schemas/history.json
+++ b/browser/components/extensions/schemas/history.json
@@ -86,29 +86,16 @@
             "type": "string",
             "description": "The visit ID of the referrer."
           },
           "transition": {
             "$ref": "TransitionType",
             "description": "The $(topic:transition-types)[transition type] for this visit from its referrer."
           }
         }
-      },
-      {
-        "id": "HistoryTime",
-        "description": "A time specified as a Date object, a number or string representing milliseconds since the epoch, or an ISO 8601 string",
-        "choices": [
-          {
-            "type": "string",
-            "pattern": "^[1-9]\\d*$"
-          },
-          {
-            "$ref": "extensionTypes.Date"
-          }
-        ]
       }
     ],
     "functions": [
       {
         "name": "search",
         "type": "function",
         "description": "Searches the history for the last visit time of each page matching the query.",
         "async": "callback",
@@ -117,22 +104,22 @@
             "name": "query",
             "type": "object",
             "properties": {
               "text": {
                 "type": "string",
                 "description": "A free-text query to the history service.  Leave empty to retrieve all pages."
               },
               "startTime": {
-                "$ref": "HistoryTime",
+                "$ref": "extensionTypes.Date",
                 "optional": true,
                 "description": "Limit results to those visited after this date. If not specified, this defaults to 24 hours in the past."
               },
               "endTime": {
-                "$ref": "HistoryTime",
+                "$ref": "extensionTypes.Date",
                 "optional": true,
                 "description": "Limit results to those visited before this date."
               },
               "maxResults": {
                 "type": "integer",
                 "optional": true,
                 "minimum": 1,
                 "description": "The maximum number of results to retrieve.  Defaults to 100."
@@ -205,17 +192,17 @@
                 "description": "The title of the page."
               },
               "transition": {
                 "$ref": "TransitionType",
                 "optional": true,
                 "description": "The $(topic:transition-types)[transition type] for this visit from its referrer."
               },
               "visitTime": {
-                "$ref": "HistoryTime",
+                "$ref": "extensionTypes.Date",
                 "optional": true,
                 "description": "The date when this visit occurred."
               }
             }
           },
           {
             "name": "callback",
             "type": "function",
@@ -254,21 +241,21 @@
         "description": "Removes all items within the specified date range from the history.  Pages will not be removed from the history unless all visits fall within the range.",
         "async": "callback",
         "parameters": [
           {
             "name": "range",
             "type": "object",
             "properties": {
               "startTime": {
-                "$ref": "HistoryTime",
+                "$ref": "extensionTypes.Date",
                 "description": "Items added to history after this date."
               },
               "endTime": {
-                "$ref": "HistoryTime",
+                "$ref": "extensionTypes.Date",
                 "description": "Items added to history before this date."
               }
             }
           },
           {
             "name": "callback",
             "type": "function",
             "parameters": []
--- a/browser/components/extensions/test/xpcshell/test_ext_history.js
+++ b/browser/components/extensions/test/xpcshell/test_ext_history.js
@@ -284,17 +284,16 @@ add_task(function* test_add_url() {
 
     browser.test.sendMessage("ready");
   }
 
   let addTestData = [
     [{}, "default"],
     [{visitTime: new Date()}, "with_date"],
     [{visitTime: Date.now()}, "with_ms_number"],
-    [{visitTime: Date.now().toString()}, "with_ms_string"],
     [{visitTime: new Date().toISOString()}, "with_iso_string"],
     [{transition: "typed"}, "valid_transition"],
   ];
 
   let failTestData = [
     [{transition: "generated"}, "an invalid transition", "|generated| is not a supported transition for history"],
     [{visitTime: Date.now() + 1000000}, "a future date", "cannot be a future date"],
     [{url: "about.config"}, "an invalid url", "about.config is not a valid URL"],
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -162,17 +162,17 @@ static const nsAttrValue::EnumTable kMoz
   { "normal",             (int16_t)AudioChannel::Normal },
   { "content",            (int16_t)AudioChannel::Content },
   { "notification",       (int16_t)AudioChannel::Notification },
   { "alarm",              (int16_t)AudioChannel::Alarm },
   { "telephony",          (int16_t)AudioChannel::Telephony },
   { "ringer",             (int16_t)AudioChannel::Ringer },
   { "publicnotification", (int16_t)AudioChannel::Publicnotification },
   { "system",             (int16_t)AudioChannel::System },
-  { nullptr }
+  { nullptr,              0 }
 };
 
 /* static */ void
 AudioChannelService::CreateServiceIfNeeded()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!gAudioChannelService) {
--- a/dom/base/CORSMode.h
+++ b/dom/base/CORSMode.h
@@ -4,17 +4,17 @@
  * 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/. */
 
 #ifndef CORSMode_h_
 #define CORSMode_h_
 
 namespace mozilla {
 
-enum CORSMode {
+enum CORSMode : uint8_t {
   /**
    * The default of not using CORS to validate cross-origin loads.
    */
   CORS_NONE,
 
   /**
    * Validate cross-site loads using CORS, but do not send any credentials
    * (cookies, HTTP auth logins, etc) along with the request.
--- a/dom/base/DirectionalityUtils.h
+++ b/dom/base/DirectionalityUtils.h
@@ -17,17 +17,17 @@ class nsTextNode;
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
 
 namespace mozilla {
 
-enum Directionality {
+enum Directionality : uint8_t {
   eDir_NotSet,
   eDir_RTL,
   eDir_LTR,
   eDir_Auto
 };
 
 /**
  * Set the directionality of an element according to the algorithm defined at
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -3264,17 +3264,17 @@ Element::Matches(const nsAString& aSelec
                                                  selectorList);
 }
 
 static const nsAttrValue::EnumTable kCORSAttributeTable[] = {
   // Order matters here
   // See ParseCORSValue
   { "anonymous",       CORS_ANONYMOUS       },
   { "use-credentials", CORS_USE_CREDENTIALS },
-  { 0 }
+  { nullptr,           0 }
 };
 
 /* static */ void
 Element::ParseCORSValue(const nsAString& aValue,
                         nsAttrValue& aResult)
 {
   DebugOnly<bool> success =
     aResult.ParseEnumValue(aValue, kCORSAttributeTable, false,
--- a/dom/base/nsAttrValue.h
+++ b/dom/base/nsAttrValue.h
@@ -7,28 +7,31 @@
 /*
  * A struct that represents the value (type and actual data) of an
  * attribute.
  */
 
 #ifndef nsAttrValue_h___
 #define nsAttrValue_h___
 
+#include <type_traits>
+
 #include "nscore.h"
 #include "nsStringGlue.h"
 #include "nsStringBuffer.h"
 #include "nsColor.h"
 #include "nsCaseTreatment.h"
 #include "nsMargin.h"
 #include "nsCOMPtr.h"
 #include "SVGAttrValueWrapper.h"
 #include "nsTArrayForwardDeclare.h"
 #include "nsIAtom.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/EnumTypeTraits.h"
 
 // Undefine LoadImage to prevent naming conflict with Windows.
 #undef LoadImage
 
 class nsAString;
 class nsIDocument;
 class nsStyledElement;
 struct MiscContainer;
@@ -256,20 +259,39 @@ public:
 
   /**
    * Structure for a mapping from int (enum) values to strings.  When you use
    * it you generally create an array of them.
    * Instantiate like this:
    * EnumTable myTable[] = {
    *   { "string1", 1 },
    *   { "string2", 2 },
-   *   { 0 }
+   *   { nullptr, 0 }
    * }
    */
   struct EnumTable {
+    // EnumTable can be initialized either with an int16_t value
+    // or a value of an enumeration type that can fit within an int16_t.
+
+    constexpr EnumTable(const char* aTag, int16_t aValue)
+      : tag(aTag)
+      , value(aValue)
+    {
+    }
+
+    template<typename T,
+             typename = typename std::enable_if<std::is_enum<T>::value>::type>
+    constexpr EnumTable(const char* aTag, T aValue)
+      : tag(aTag)
+      , value(static_cast<int16_t>(aValue))
+    {
+      static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
+                    "aValue must be an enum that fits within int16_t");
+    }
+
     /** The string the value maps to */
     const char* tag;
     /** The enum value that maps to this string */
     int16_t value;
   };
 
   /**
    * Parse into an enum value.
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -299,36 +299,36 @@ bool nsContentUtils::sFragmentParsingAct
 bool nsContentUtils::sDOMWindowDumpEnabled;
 #endif
 
 bool nsContentUtils::sDoNotTrackEnabled = false;
 
 mozilla::LazyLogModule nsContentUtils::sDOMDumpLog("Dump");
 
 // Subset of http://www.whatwg.org/specs/web-apps/current-work/#autofill-field-name
-enum AutocompleteFieldName
+enum AutocompleteFieldName : uint8_t
 {
   #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
     eAutocompleteFieldName_##name_,
   #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
     AUTOCOMPLETE_FIELD_NAME(name_, value_)
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_NAME
   #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
 };
 
-enum AutocompleteFieldHint
+enum AutocompleteFieldHint : uint8_t
 {
   #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
     eAutocompleteFieldHint_##name_,
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_HINT
 };
 
-enum AutocompleteFieldContactHint
+enum AutocompleteFieldContactHint : uint8_t
 {
   #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
     eAutocompleteFieldContactHint_##name_,
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
 };
 
 enum AutocompleteCategory
@@ -338,41 +338,41 @@ enum AutocompleteCategory
   #undef AUTOCOMPLETE_CATEGORY
 };
 
 static const nsAttrValue::EnumTable kAutocompleteFieldNameTable[] = {
   #define AUTOCOMPLETE_FIELD_NAME(name_, value_) \
     { value_, eAutocompleteFieldName_##name_ },
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_NAME
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kAutocompleteContactFieldNameTable[] = {
   #define AUTOCOMPLETE_CONTACT_FIELD_NAME(name_, value_) \
     { value_, eAutocompleteFieldName_##name_ },
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_CONTACT_FIELD_NAME
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kAutocompleteFieldHintTable[] = {
   #define AUTOCOMPLETE_FIELD_HINT(name_, value_) \
     { value_, eAutocompleteFieldHint_##name_ },
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_HINT
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kAutocompleteContactFieldHintTable[] = {
   #define AUTOCOMPLETE_FIELD_CONTACT_HINT(name_, value_) \
     { value_, eAutocompleteFieldContactHint_##name_ },
   #include "AutocompleteFieldList.h"
   #undef AUTOCOMPLETE_FIELD_CONTACT_HINT
-  { 0 }
+  { nullptr, 0 }
 };
 
 namespace {
 
 static NS_DEFINE_CID(kParserServiceCID, NS_PARSERSERVICE_CID);
 static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
 
 static PLDHashTable* sEventListenerManagersHash;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -12316,16 +12316,17 @@ class CGDictionary(CGThing):
         if memberInits:
             body += fill(
                 """
                 bool isNull = val.isNullOrUndefined();
                 // We only need these if !isNull, in which case we have |cx|.
                 Maybe<JS::Rooted<JSObject *> > object;
                 Maybe<JS::Rooted<JS::Value> > temp;
                 if (!isNull) {
+                  MOZ_ASSERT(cx);
                   object.emplace(cx, &val.toObject());
                   temp.emplace(cx);
                 }
                 $*{memberInits}
                 """,
                 memberInits="\n".join(memberInits))
 
         body += "return true;\n"
--- a/dom/html/HTMLBRElement.cpp
+++ b/dom/html/HTMLBRElement.cpp
@@ -25,21 +25,21 @@ HTMLBRElement::HTMLBRElement(already_Add
 
 HTMLBRElement::~HTMLBRElement()
 {
 }
 
 NS_IMPL_ELEMENT_CLONE(HTMLBRElement)
 
 static const nsAttrValue::EnumTable kClearTable[] = {
-  { "left", NS_STYLE_CLEAR_LEFT },
-  { "right", NS_STYLE_CLEAR_RIGHT },
-  { "all", NS_STYLE_CLEAR_BOTH },
-  { "both", NS_STYLE_CLEAR_BOTH },
-  { 0 }
+  { "left", StyleClear::Left },
+  { "right", StyleClear::Right },
+  { "all", StyleClear::Both },
+  { "both", StyleClear::Both },
+  { nullptr, 0 }
 };
 
 bool
 HTMLBRElement::ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult)
 {
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -42,17 +42,17 @@ NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER
 
 namespace mozilla {
 namespace dom {
 
 static const nsAttrValue::EnumTable kButtonTypeTable[] = {
   { "button", NS_FORM_BUTTON_BUTTON },
   { "reset", NS_FORM_BUTTON_RESET },
   { "submit", NS_FORM_BUTTON_SUBMIT },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Default type is 'submit'.
 static const nsAttrValue::EnumTable* kButtonDefaultType = &kButtonTypeTable[2];
 
 
 // Construction, destruction
 HTMLButtonElement::HTMLButtonElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
--- a/dom/html/HTMLFormElement.cpp
+++ b/dom/html/HTMLFormElement.cpp
@@ -82,17 +82,17 @@ namespace mozilla {
 namespace dom {
 
 static const uint8_t NS_FORM_AUTOCOMPLETE_ON  = 1;
 static const uint8_t NS_FORM_AUTOCOMPLETE_OFF = 0;
 
 static const nsAttrValue::EnumTable kFormAutocompleteTable[] = {
   { "on",  NS_FORM_AUTOCOMPLETE_ON },
   { "off", NS_FORM_AUTOCOMPLETE_OFF },
-  { 0 }
+  { nullptr, 0 }
 };
 // Default autocomplete value is 'on'.
 static const nsAttrValue::EnumTable* kFormDefaultAutocomplete = &kFormAutocompleteTable[0];
 
 bool HTMLFormElement::gFirstFormSubmitted = false;
 bool HTMLFormElement::gPasswordManagerInitialized = false;
 
 HTMLFormElement::HTMLFormElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
--- a/dom/html/HTMLFormSubmissionConstants.h
+++ b/dom/html/HTMLFormSubmissionConstants.h
@@ -7,25 +7,25 @@
 #ifndef mozilla_dom_HTMLFormSubmissionConstants_h
 #define mozilla_dom_HTMLFormSubmissionConstants_h
 
 #include "nsIForm.h"
 
 static const nsAttrValue::EnumTable kFormMethodTable[] = {
   { "get", NS_FORM_METHOD_GET },
   { "post", NS_FORM_METHOD_POST },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Default method is 'get'.
 static const nsAttrValue::EnumTable* kFormDefaultMethod = &kFormMethodTable[0];
 
 static const nsAttrValue::EnumTable kFormEnctypeTable[] = {
   { "multipart/form-data", NS_FORM_ENCTYPE_MULTIPART },
   { "application/x-www-form-urlencoded", NS_FORM_ENCTYPE_URLENCODED },
   { "text/plain", NS_FORM_ENCTYPE_TEXTPLAIN },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Default method is 'application/x-www-form-urlencoded'.
 static const nsAttrValue::EnumTable* kFormDefaultEnctype = &kFormEnctypeTable[1];
 
 #endif // mozilla_dom_HTMLFormSubmissionConstants_h
--- a/dom/html/HTMLHRElement.cpp
+++ b/dom/html/HTMLHRElement.cpp
@@ -38,17 +38,17 @@ HTMLHRElement::ParseAttribute(int32_t aN
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult)
 {
   static const nsAttrValue::EnumTable kAlignTable[] = {
     { "left", NS_STYLE_TEXT_ALIGN_LEFT },
     { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
     { "center", NS_STYLE_TEXT_ALIGN_CENTER },
-    { 0 }
+    { nullptr, 0 }
   };
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (aAttribute == nsGkAtoms::width) {
       return aResult.ParseSpecialIntValue(aValue);
     }
     if (aAttribute == nsGkAtoms::size) {
       return aResult.ParseIntWithBounds(aValue, 1, 1000);
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -173,17 +173,17 @@ static const nsAttrValue::EnumTable kInp
   { "range", NS_FORM_INPUT_RANGE },
   { "search", NS_FORM_INPUT_SEARCH },
   { "submit", NS_FORM_INPUT_SUBMIT },
   { "tel", NS_FORM_INPUT_TEL },
   { "text", NS_FORM_INPUT_TEXT },
   { "time", NS_FORM_INPUT_TIME },
   { "url", NS_FORM_INPUT_URL },
   { "week", NS_FORM_INPUT_WEEK },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Default type is 'text'.
 static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[17];
 
 static const uint8_t NS_INPUT_INPUTMODE_AUTO              = 0;
 static const uint8_t NS_INPUT_INPUTMODE_NUMERIC           = 1;
 static const uint8_t NS_INPUT_INPUTMODE_DIGIT             = 2;
@@ -195,17 +195,17 @@ static const uint8_t NS_INPUT_INPUTMODE_
 static const nsAttrValue::EnumTable kInputInputmodeTable[] = {
   { "auto", NS_INPUT_INPUTMODE_AUTO },
   { "numeric", NS_INPUT_INPUTMODE_NUMERIC },
   { "digit", NS_INPUT_INPUTMODE_DIGIT },
   { "uppercase", NS_INPUT_INPUTMODE_UPPERCASE },
   { "lowercase", NS_INPUT_INPUTMODE_LOWERCASE },
   { "titlecase", NS_INPUT_INPUTMODE_TITLECASE },
   { "autocapitalized", NS_INPUT_INPUTMODE_AUTOCAPITALIZED },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Default inputmode value is "auto".
 static const nsAttrValue::EnumTable* kInputDefaultInputmode = &kInputInputmodeTable[0];
 
 const Decimal HTMLInputElement::kStepScaleFactorDate = Decimal(86400000);
 const Decimal HTMLInputElement::kStepScaleFactorNumberRange = Decimal(1);
 const Decimal HTMLInputElement::kStepScaleFactorTime = Decimal(1000);
--- a/dom/html/HTMLLIElement.cpp
+++ b/dom/html/HTMLLIElement.cpp
@@ -31,27 +31,27 @@ NS_IMPL_STRING_ATTR(HTMLLIElement, Type,
 NS_IMPL_INT_ATTR(HTMLLIElement, Value, value)
 
 // values that are handled case-insensitively
 static const nsAttrValue::EnumTable kUnorderedListItemTypeTable[] = {
   { "disc", NS_STYLE_LIST_STYLE_DISC },
   { "circle", NS_STYLE_LIST_STYLE_CIRCLE },
   { "round", NS_STYLE_LIST_STYLE_CIRCLE },
   { "square", NS_STYLE_LIST_STYLE_SQUARE },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // values that are handled case-sensitively
 static const nsAttrValue::EnumTable kOrderedListItemTypeTable[] = {
   { "A", NS_STYLE_LIST_STYLE_UPPER_ALPHA },
   { "a", NS_STYLE_LIST_STYLE_LOWER_ALPHA },
   { "I", NS_STYLE_LIST_STYLE_UPPER_ROMAN },
   { "i", NS_STYLE_LIST_STYLE_LOWER_ROMAN },
   { "1", NS_STYLE_LIST_STYLE_DECIMAL },
-  { 0 }
+  { nullptr, 0 }
 };
 
 bool
 HTMLLIElement::ParseAttribute(int32_t aNamespaceID,
                               nsIAtom* aAttribute,
                               const nsAString& aValue,
                               nsAttrValue& aResult)
 {
--- a/dom/html/HTMLLegendElement.cpp
+++ b/dom/html/HTMLLegendElement.cpp
@@ -42,17 +42,17 @@ HTMLLegendElement::ParseAttribute(int32_
 {
   // this contains center, because IE4 does
   static const nsAttrValue::EnumTable kAlignTable[] = {
     { "left", NS_STYLE_TEXT_ALIGN_LEFT },
     { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
     { "center", NS_STYLE_TEXT_ALIGN_CENTER },
     { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
     { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
-    { 0 }
+    { nullptr, 0 }
   };
 
   if (aAttribute == nsGkAtoms::align && aNamespaceID == kNameSpaceID_None) {
     return aResult.ParseEnumValue(aValue, kAlignTable, false);
   }
 
   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
                                               aResult);
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -2539,33 +2539,28 @@ HTMLMediaElement::AddCaptureMediaTrackTo
        track.get(), destinationTrackID, inputTrack, port.get()));
 }
 
 already_AddRefed<DOMMediaStream>
 HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
                                         bool aCaptureAudio,
                                         MediaStreamGraph* aGraph)
 {
+  MOZ_RELEASE_ASSERT(aGraph);
+
   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
   if (!window) {
     return nullptr;
   }
 #ifdef MOZ_EME
   if (ContainsRestrictedContent()) {
     return nullptr;
   }
 #endif
 
-  if (!aGraph) {
-    MediaStreamGraph::GraphDriverType graphDriverType =
-      HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
-                 : MediaStreamGraph::SYSTEM_THREAD_DRIVER;
-    aGraph = MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
-  }
-
   if (!mOutputStreams.IsEmpty() &&
       aGraph != mOutputStreams[0].mStream->GetInputStream()->Graph()) {
     return nullptr;
   }
 
   OutputMediaStream* out = mOutputStreams.AppendElement();
   MediaStreamTrackSourceGetter* getter = new CaptureStreamTrackSourceGetter(this);
   out->mStream = DOMMediaStream::CreateTrackUnionStreamAsInput(window, aGraph, getter);
@@ -2650,43 +2645,58 @@ HTMLMediaElement::CaptureStreamInternal(
   RefPtr<DOMMediaStream> result = out->mStream;
   return result.forget();
 }
 
 already_AddRefed<DOMMediaStream>
 HTMLMediaElement::CaptureAudio(ErrorResult& aRv,
                                MediaStreamGraph* aGraph)
 {
-  RefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, aGraph);
+  MOZ_RELEASE_ASSERT(aGraph);
+
+  RefPtr<DOMMediaStream> stream =
+    CaptureStreamInternal(false, true, aGraph);
   if (!stream) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return stream.forget();
 }
 
 already_AddRefed<DOMMediaStream>
-HTMLMediaElement::MozCaptureStream(ErrorResult& aRv,
-                                   MediaStreamGraph* aGraph)
-{
-  RefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, aGraph);
+HTMLMediaElement::MozCaptureStream(ErrorResult& aRv)
+{
+  MediaStreamGraph::GraphDriverType graphDriverType =
+    HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
+               : MediaStreamGraph::SYSTEM_THREAD_DRIVER;
+  MediaStreamGraph* graph =
+    MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
+
+  RefPtr<DOMMediaStream> stream =
+    CaptureStreamInternal(false, false, graph);
   if (!stream) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return stream.forget();
 }
 
 already_AddRefed<DOMMediaStream>
-HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv,
-                                             MediaStreamGraph* aGraph)
-{
-  RefPtr<DOMMediaStream> stream = CaptureStreamInternal(true, aGraph);
+HTMLMediaElement::MozCaptureStreamUntilEnded(ErrorResult& aRv)
+{
+  MediaStreamGraph::GraphDriverType graphDriverType =
+    HasAudio() ? MediaStreamGraph::AUDIO_THREAD_DRIVER
+               : MediaStreamGraph::SYSTEM_THREAD_DRIVER;
+  MediaStreamGraph* graph =
+    MediaStreamGraph::GetInstance(graphDriverType, mAudioChannel);
+
+  RefPtr<DOMMediaStream> stream =
+    CaptureStreamInternal(true, false, graph);
   if (!stream) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   return stream.forget();
 }
 
@@ -3216,17 +3226,17 @@ bool HTMLMediaElement::ParseAttribute(in
                                       nsAttrValue& aResult)
 {
   // Mappings from 'preload' attribute strings to an enumeration.
   static const nsAttrValue::EnumTable kPreloadTable[] = {
     { "",         HTMLMediaElement::PRELOAD_ATTR_EMPTY },
     { "none",     HTMLMediaElement::PRELOAD_ATTR_NONE },
     { "metadata", HTMLMediaElement::PRELOAD_ATTR_METADATA },
     { "auto",     HTMLMediaElement::PRELOAD_ATTR_AUTO },
-    { 0 }
+    { nullptr,    0 }
   };
 
   if (aNamespaceID == kNameSpaceID_None) {
     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
       return true;
     }
     if (aAttribute == nsGkAtoms::crossorigin) {
       ParseCORSValue(aValue, aResult);
@@ -6569,17 +6579,18 @@ HTMLMediaElement::AudioCaptureStreamChan
     uint64_t id = window->WindowID();
     MediaStreamGraph* msg =
       MediaStreamGraph::GetInstance(MediaStreamGraph::AUDIO_THREAD_DRIVER,
                                     mAudioChannel);
 
     if (GetSrcMediaStream()) {
       mCaptureStreamPort = msg->ConnectToCaptureStream(id, GetSrcMediaStream());
     } else {
-      RefPtr<DOMMediaStream> stream = CaptureStreamInternal(false, msg);
+      RefPtr<DOMMediaStream> stream =
+        CaptureStreamInternal(false, false, msg);
       mCaptureStreamPort = msg->ConnectToCaptureStream(id, stream->GetPlaybackStream());
     }
   } else if (!mAudioCapturedByWindow && mCaptureStreamPort) {
     if (mDecoder) {
       ProcessedMediaStream* ps =
         mCaptureStreamPort->GetSource()->AsProcessedStream();
       MOZ_ASSERT(ps);
 
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -650,23 +650,21 @@ public:
   void CannotDecryptWaitingForKey();
 
   bool MozAutoplayEnabled() const
   {
     return mAutoplayEnabled;
   }
 
   already_AddRefed<DOMMediaStream> CaptureAudio(ErrorResult& aRv,
-                                                MediaStreamGraph* aGraph = nullptr);
+                                                MediaStreamGraph* aGraph);
 
-  already_AddRefed<DOMMediaStream> MozCaptureStream(ErrorResult& aRv,
-                                                    MediaStreamGraph* aGraph = nullptr);
+  already_AddRefed<DOMMediaStream> MozCaptureStream(ErrorResult& aRv);
 
-  already_AddRefed<DOMMediaStream> MozCaptureStreamUntilEnded(ErrorResult& aRv,
-                                                              MediaStreamGraph* aGraph = nullptr);
+  already_AddRefed<DOMMediaStream> MozCaptureStreamUntilEnded(ErrorResult& aRv);
 
   bool MozAudioCaptured() const
   {
     return mAudioCaptured;
   }
 
   void MozGetMetadata(JSContext* aCx, JS::MutableHandle<JSObject*> aResult,
                       ErrorResult& aRv);
@@ -892,17 +890,17 @@ protected:
    * The stream will never finish.
    *
    * When aCaptureAudio is true, we stop playout of audio and instead route it
    * to the DOMMediaStream. Volume and mute state will be applied to the audio
    * reaching the stream. No video tracks will be captured in this case.
    */
   already_AddRefed<DOMMediaStream> CaptureStreamInternal(bool aFinishWhenEnded,
                                                          bool aCaptureAudio,
-                                                         MediaStreamGraph* aGraph = nullptr);
+                                                         MediaStreamGraph* aGraph);
 
   /**
    * Initialize a decoder as a clone of an existing decoder in another
    * element.
    * mLoadingSrc must already be set.
    */
   nsresult InitializeDecoderAsClone(MediaDecoder* aOriginal);
 
@@ -1034,17 +1032,17 @@ protected:
   /**
    * Called when "xpcom-shutdown" event is received.
    */
   void NotifyShutdownEvent();
 
   /**
    * Possible values of the 'preload' attribute.
    */
-  enum PreloadAttrValue {
+  enum PreloadAttrValue : uint8_t {
     PRELOAD_ATTR_EMPTY,    // set to ""
     PRELOAD_ATTR_NONE,     // set to "none"
     PRELOAD_ATTR_METADATA, // set to "metadata"
     PRELOAD_ATTR_AUTO      // set to "auto"
   };
 
   /**
    * The preloading action to perform. These dictate how we react to the
--- a/dom/html/HTMLMenuElement.cpp
+++ b/dom/html/HTMLMenuElement.cpp
@@ -17,28 +17,28 @@
 
 #define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT(Menu)
 
 namespace mozilla {
 namespace dom {
 
-enum MenuType
+enum MenuType : uint8_t
 {
   MENU_TYPE_CONTEXT = 1,
   MENU_TYPE_TOOLBAR,
   MENU_TYPE_LIST
 };
 
 static const nsAttrValue::EnumTable kMenuTypeTable[] = {
   { "context", MENU_TYPE_CONTEXT },
   { "toolbar", MENU_TYPE_TOOLBAR },
   { "list", MENU_TYPE_LIST },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable* kMenuDefaultType =
   &kMenuTypeTable[2];
 
 enum SeparatorType
 {
   ST_TRUE_INIT = -1,
--- a/dom/html/HTMLMenuItemElement.cpp
+++ b/dom/html/HTMLMenuItemElement.cpp
@@ -19,28 +19,28 @@ namespace mozilla {
 namespace dom {
 
 // First bits are needed for the menuitem type.
 #define NS_CHECKED_IS_TOGGLED (1 << 2)
 #define NS_ORIGINAL_CHECKED_VALUE (1 << 3)
 #define NS_MENUITEM_TYPE(bits) ((bits) & ~( \
   NS_CHECKED_IS_TOGGLED | NS_ORIGINAL_CHECKED_VALUE))
 
-enum CmdType                                                                 
-{                                                                            
+enum CmdType : uint8_t
+{
   CMD_TYPE_MENUITEM = 1,
   CMD_TYPE_CHECKBOX,
   CMD_TYPE_RADIO
 };
 
 static const nsAttrValue::EnumTable kMenuItemTypeTable[] = {
   { "menuitem", CMD_TYPE_MENUITEM },
   { "checkbox", CMD_TYPE_CHECKBOX },
   { "radio", CMD_TYPE_RADIO },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable* kMenuItemDefaultType =
   &kMenuItemTypeTable[0];
 
 // A base class inherited by all radio visitors.
 class Visitor
 {
--- a/dom/html/HTMLSharedListElement.cpp
+++ b/dom/html/HTMLSharedListElement.cpp
@@ -50,26 +50,26 @@ nsAttrValue::EnumTable kListTypeTable[] 
   { "circle", NS_STYLE_LIST_STYLE_CIRCLE },
   { "round", NS_STYLE_LIST_STYLE_CIRCLE },
   { "square", NS_STYLE_LIST_STYLE_SQUARE },
   { "decimal", NS_STYLE_LIST_STYLE_DECIMAL },
   { "lower-roman", NS_STYLE_LIST_STYLE_LOWER_ROMAN },
   { "upper-roman", NS_STYLE_LIST_STYLE_UPPER_ROMAN },
   { "lower-alpha", NS_STYLE_LIST_STYLE_LOWER_ALPHA },
   { "upper-alpha", NS_STYLE_LIST_STYLE_UPPER_ALPHA },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kOldListTypeTable[] = {
   { "1", NS_STYLE_LIST_STYLE_DECIMAL },
   { "A", NS_STYLE_LIST_STYLE_UPPER_ALPHA },
   { "a", NS_STYLE_LIST_STYLE_LOWER_ALPHA },
   { "I", NS_STYLE_LIST_STYLE_UPPER_ROMAN },
   { "i", NS_STYLE_LIST_STYLE_LOWER_ROMAN },
-  { 0 }
+  { nullptr, 0 }
 };
 
 bool
 HTMLSharedListElement::ParseAttribute(int32_t aNamespaceID,
                                       nsIAtom* aAttribute,
                                       const nsAString& aValue,
                                       nsAttrValue& aResult)
 {
--- a/dom/html/HTMLTableCaptionElement.cpp
+++ b/dom/html/HTMLTableCaptionElement.cpp
@@ -27,17 +27,17 @@ HTMLTableCaptionElement::WrapNode(JSCont
 
 NS_IMPL_ELEMENT_CLONE(HTMLTableCaptionElement)
 
 static const nsAttrValue::EnumTable kCaptionAlignTable[] = {
   { "left",   NS_STYLE_CAPTION_SIDE_LEFT },
   { "right",  NS_STYLE_CAPTION_SIDE_RIGHT },
   { "top",    NS_STYLE_CAPTION_SIDE_TOP },
   { "bottom", NS_STYLE_CAPTION_SIDE_BOTTOM },
-  { 0 }
+  { nullptr,  0 }
 };
 
 bool
 HTMLTableCaptionElement::ParseAttribute(int32_t aNamespaceID,
                                         nsIAtom* aAttribute,
                                         const nsAString& aValue,
                                         nsAttrValue& aResult)
 {
--- a/dom/html/HTMLTableCellElement.cpp
+++ b/dom/html/HTMLTableCellElement.cpp
@@ -361,17 +361,17 @@ HTMLTableCellElement::GetAlign(DOMString
   }
 }
 
 static const nsAttrValue::EnumTable kCellScopeTable[] = {
   { "row",      NS_STYLE_CELL_SCOPE_ROW },
   { "col",      NS_STYLE_CELL_SCOPE_COL },
   { "rowgroup", NS_STYLE_CELL_SCOPE_ROWGROUP },
   { "colgroup", NS_STYLE_CELL_SCOPE_COLGROUP },
-  { 0 }
+  { nullptr,    0 }
 };
 
 void
 HTMLTableCellElement::GetScope(DOMString& aScope)
 {
   GetEnumAttr(nsGkAtoms::scope, nullptr, aScope);
 }
 
--- a/dom/html/HTMLTrackElement.cpp
+++ b/dom/html/HTMLTrackElement.cpp
@@ -62,17 +62,17 @@ namespace dom {
 
 // Map html attribute string values to TextTrackKind enums.
 static constexpr nsAttrValue::EnumTable kKindTable[] = {
   { "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
   { "captions", static_cast<int16_t>(TextTrackKind::Captions) },
   { "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
   { "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
   { "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
-  { 0 }
+  { nullptr, 0 }
 };
 
 // Invalid values are treated as "metadata" in ParseAttribute, but if no value
 // at all is specified, it's treated as "subtitles" in GetKind
 static constexpr const nsAttrValue::EnumTable* kKindTableInvalidValueDefault = &kKindTable[4];
 
 class WindowDestroyObserver final : public nsIObserver
 {
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -215,17 +215,17 @@ nsGenericHTMLElement::GetDataset(nsISupp
   *aDataset = Dataset().take();
   return NS_OK;
 }
 
 static const nsAttrValue::EnumTable kDirTable[] = {
   { "ltr", eDir_LTR },
   { "rtl", eDir_RTL },
   { "auto", eDir_Auto },
-  { 0 }
+  { nullptr, 0 }
 };
 
 void
 nsGenericHTMLElement::GetAccessKeyLabel(nsString& aLabel)
 {
   nsAutoString suffix;
   GetAccessKey(suffix);
   if (!suffix.IsEmpty()) {
@@ -1053,44 +1053,44 @@ nsGenericHTMLElement::GetPresContext(Pre
 }
 
 static const nsAttrValue::EnumTable kDivAlignTable[] = {
   { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
   { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kFrameborderTable[] = {
   { "yes", NS_STYLE_FRAME_YES },
   { "no", NS_STYLE_FRAME_NO },
   { "1", NS_STYLE_FRAME_1 },
   { "0", NS_STYLE_FRAME_0 },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kScrollingTable[] = {
   { "yes", NS_STYLE_FRAME_YES },
   { "no", NS_STYLE_FRAME_NO },
   { "on", NS_STYLE_FRAME_ON },
   { "off", NS_STYLE_FRAME_OFF },
   { "scroll", NS_STYLE_FRAME_SCROLL },
   { "noscroll", NS_STYLE_FRAME_NOSCROLL },
   { "auto", NS_STYLE_FRAME_AUTO },
-  { 0 }
+  { nullptr, 0 }
 };
 
 static const nsAttrValue::EnumTable kTableVAlignTable[] = {
   { "top",     NS_STYLE_VERTICAL_ALIGN_TOP },
   { "middle",  NS_STYLE_VERTICAL_ALIGN_MIDDLE },
   { "bottom",  NS_STYLE_VERTICAL_ALIGN_BOTTOM },
   { "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
-  { 0 }
+  { nullptr,   0 }
 };
 
 bool
 nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
                                       nsAttrValue& aResult)
 {
   static const nsAttrValue::EnumTable kAlignTable[] = {
     { "left",      NS_STYLE_TEXT_ALIGN_LEFT },
@@ -1102,31 +1102,31 @@ nsGenericHTMLElement::ParseAlignValue(co
 
     { "center",    NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
     { "baseline",  NS_STYLE_VERTICAL_ALIGN_BASELINE },
 
     { "texttop",   NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
     { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
     { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
     { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
-    { 0 }
+    { nullptr,     0 }
   };
 
   return aResult.ParseEnumValue(aString, kAlignTable, false);
 }
 
 //----------------------------------------
 
 static const nsAttrValue::EnumTable kTableHAlignTable[] = {
   { "left",   NS_STYLE_TEXT_ALIGN_LEFT },
   { "right",  NS_STYLE_TEXT_ALIGN_RIGHT },
   { "center", NS_STYLE_TEXT_ALIGN_CENTER },
   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
-  { 0 }
+  { nullptr,  0 }
 };
 
 bool
 nsGenericHTMLElement::ParseTableHAlignValue(const nsAString& aString,
                                             nsAttrValue& aResult)
 {
   return aResult.ParseEnumValue(aString, kTableHAlignTable, false);
 }
@@ -1137,17 +1137,17 @@ nsGenericHTMLElement::ParseTableHAlignVa
 static const nsAttrValue::EnumTable kTableCellHAlignTable[] = {
   { "left",   NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
   { "right",  NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
   { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "char",   NS_STYLE_TEXT_ALIGN_CHAR },
   { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
   { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
   { "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
-  { 0 }
+  { nullptr,  0 }
 };
 
 bool
 nsGenericHTMLElement::ParseTableCellHAlignValue(const nsAString& aString,
                                                 nsAttrValue& aResult)
 {
   return aResult.ParseEnumValue(aString, kTableCellHAlignTable, false);
 }
@@ -1185,22 +1185,22 @@ nsGenericHTMLElement::ParseImageAttribut
   return false;
 }
 
 bool
 nsGenericHTMLElement::ParseReferrerAttribute(const nsAString& aString,
                                              nsAttrValue& aResult)
 {
   static const nsAttrValue::EnumTable kReferrerTable[] = {
-    { net::kRPS_No_Referrer, net::RP_No_Referrer },
-    { net::kRPS_Origin, net::RP_Origin },
-    { net::kRPS_Origin_When_Cross_Origin, net::RP_Origin_When_Crossorigin },
-    { net::kRPS_No_Referrer_When_Downgrade, net::RP_No_Referrer_When_Downgrade },
-    { net::kRPS_Unsafe_URL, net::RP_Unsafe_URL },
-    { 0 }
+    { net::kRPS_No_Referrer, static_cast<int16_t>(net::RP_No_Referrer) },
+    { net::kRPS_Origin, static_cast<int16_t>(net::RP_Origin) },
+    { net::kRPS_Origin_When_Cross_Origin, static_cast<int16_t>(net::RP_Origin_When_Crossorigin) },
+    { net::kRPS_No_Referrer_When_Downgrade, static_cast<int16_t>(net::RP_No_Referrer_When_Downgrade) },
+    { net::kRPS_Unsafe_URL, static_cast<int16_t>(net::RP_Unsafe_URL) },
+    { nullptr, 0 }
   };
   return aResult.ParseEnumValue(aString, kReferrerTable, false);
 }
 
 bool
 nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
                                             nsAttrValue& aResult)
 {
--- a/dom/html/nsIFormControl.h
+++ b/dom/html/nsIFormControl.h
@@ -33,24 +33,24 @@ enum FormControlsTypes {
 
   // Elements with different types, the value is used as a mask.
   // When changing the order, adding or removing elements, be sure to update
   // the static_assert checks accordingly.
   NS_FORM_BUTTON_ELEMENT = 0x40, // 0b01000000
   NS_FORM_INPUT_ELEMENT  = 0x80  // 0b10000000
 };
 
-enum ButtonElementTypes {
+enum ButtonElementTypes : uint8_t {
   NS_FORM_BUTTON_BUTTON = NS_FORM_BUTTON_ELEMENT + 1,
   NS_FORM_BUTTON_RESET,
   NS_FORM_BUTTON_SUBMIT,
   eButtonElementTypesMax
 };
 
-enum InputElementTypes {
+enum InputElementTypes : uint8_t {
   NS_FORM_INPUT_BUTTON = NS_FORM_INPUT_ELEMENT + 1,
   NS_FORM_INPUT_CHECKBOX,
   NS_FORM_INPUT_COLOR,
   NS_FORM_INPUT_DATE,
   NS_FORM_INPUT_EMAIL,
   NS_FORM_INPUT_FILE,
   NS_FORM_INPUT_HIDDEN,
   NS_FORM_INPUT_RESET,
--- a/dom/ipc/TabContext.cpp
+++ b/dom/ipc/TabContext.cpp
@@ -297,18 +297,18 @@ MaybeInvalidTabContext::MaybeInvalidTabC
 {
   bool isMozBrowserElement = false;
   bool isPrerendered = false;
   uint32_t containingAppId = NO_APP_ID;
   DocShellOriginAttributes originAttributes;
   nsAutoCString originSuffix;
   nsAutoCString signedPkgOriginNoSuffix;
   nsAutoString presentationURL;
-  UIStateChangeType showAccelerators;
-  UIStateChangeType showFocusRings;
+  UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
+  UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
 
   switch(aParams.type()) {
     case IPCTabContext::TPopupIPCTabContext: {
       const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
 
       TabContext *context;
       if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
         context = TabParent::GetFrom(ipcContext.opener().get_PBrowserParent());
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -1001,17 +1001,17 @@ MediaRecorder::MediaRecorder(AudioNode& 
   // union stream in recorder session won't be able to copy data from the
   // stream of non-destination node. Create a pipe stream in this case.
   if (aSrcAudioNode.NumberOfOutputs() > 0) {
     AudioContext* ctx = aSrcAudioNode.Context();
     AudioNodeEngine* engine = new AudioNodeEngine(nullptr);
     AudioNodeStream::Flags flags =
       AudioNodeStream::EXTERNAL_OUTPUT |
       AudioNodeStream::NEED_MAIN_THREAD_FINISHED;
-    mPipeStream = AudioNodeStream::Create(ctx, engine, flags);
+    mPipeStream = AudioNodeStream::Create(ctx, engine, flags, ctx->Graph());
     AudioNodeStream* ns = aSrcAudioNode.GetStream();
     if (ns) {
       mInputPort =
         mPipeStream->AllocateInputPort(aSrcAudioNode.GetStream(),
                                        TRACK_ANY, TRACK_ANY,
                                        0, aSrcOutput);
     }
   }
--- a/dom/media/platforms/android/RemoteDataDecoder.cpp
+++ b/dom/media/platforms/android/RemoteDataDecoder.cpp
@@ -144,17 +144,17 @@ public:
       MOZ_ASSERT(ok);
 
       int32_t size;
       ok |= NS_SUCCEEDED(aInfo->Size(&size));
       MOZ_ASSERT(ok);
 
       NS_ENSURE_TRUE_VOID(ok);
 
-      if (size > 0) {
+      if (size > 0 && durationUs.value() > 0) {
         RefPtr<layers::Image> img =
           new SurfaceTextureImage(mDecoder->mSurfaceTexture.get(), mDecoder->mConfig.mDisplay,
                                   gl::OriginPos::BottomLeft);
 
         RefPtr<VideoData> v =
           VideoData::CreateFromImage(mDecoder->mConfig,
                                     offset,
                                     presentationTimeUs,
@@ -166,17 +166,16 @@ public:
                                                   mDecoder->mConfig.mDisplay.width,
                                                   mDecoder->mConfig.mDisplay.height));
 
         mDecoderCallback->Output(v);
       }
 
       if ((flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) != 0) {
         mDecoderCallback->DrainComplete();
-        return;
       }
     }
 
     friend class RemoteDataDecoder;
 
   private:
     RemoteVideoDecoder* mDecoder;
   };
@@ -218,16 +217,25 @@ public:
   }
 
   nsresult Flush() override
   {
     mInputDurations.Clear();
     return RemoteDataDecoder::Flush();
   }
 
+  nsresult Drain() override
+  {
+    nsresult res = RemoteDataDecoder::Drain();
+    NS_ENSURE_SUCCESS(res, res);
+
+    mInputDurations.Put(0);
+    return NS_OK;
+  }
+
   nsresult Input(MediaRawData* aSample) override
   {
     nsresult res = RemoteDataDecoder::Input(aSample);
     NS_ENSURE_SUCCESS(res, res);
 
     mInputDurations.Put(aSample->mDuration);
     return NS_OK;
   }
@@ -435,17 +443,17 @@ nsresult
 RemoteDataDecoder::Drain()
 {
   BufferInfo::LocalRef bufferInfo;
   nsresult rv = BufferInfo::New(&bufferInfo);
   NS_ENSURE_SUCCESS(rv, rv);
   bufferInfo->Set(0, 0, -1, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
 
   mJavaDecoder->Input(nullptr, bufferInfo);
-  return NS_ERROR_FAILURE;
+  return NS_OK;
 }
 
 nsresult
 RemoteDataDecoder::Shutdown()
 {
   LOG("");
   MOZ_ASSERT(mJavaDecoder && mJavaCallbacks);
 
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.cpp
@@ -86,16 +86,17 @@ WMFVideoMFTManager::WMFVideoMFTManager(
   , mVideoStride(0)
   , mImageSize(aConfig.mImage)
   , mImageContainer(aImageContainer)
   , mDXVAEnabled(aDXVAEnabled)
   , mLayersBackend(aLayersBackend)
   , mNullOutputCount(0)
   , mGotValidOutputAfterNullOutput(false)
   , mGotExcessiveNullOutput(false)
+  , mIsValid(true)
   // mVideoStride, mVideoWidth, mVideoHeight, mUseHwAccel are initialized in
   // Init().
 {
   MOZ_COUNT_CTOR(WMFVideoMFTManager);
 
   // Need additional checks/params to check vp8/vp9
   if (MP4Decoder::IsH264(aConfig.mMimeType)) {
     mStreamType = H264;
@@ -366,18 +367,42 @@ WMFVideoMFTManager::InitializeDXVA(bool 
     NS_DispatchToMainThread(event, NS_DISPATCH_SYNC);
   }
   mDXVA2Manager = event->mDXVA2Manager;
 
   return mDXVA2Manager != nullptr;
 }
 
 bool
+WMFVideoMFTManager::ValidateVideoInfo()
+{
+  // The WMF H.264 decoder is documented to have a minimum resolution
+  // 48x48 pixels. We've observed the decoder working for output smaller than
+  // that, but on some output it hangs in IMFTransform::ProcessOutput(), so
+  // we just reject streams which are less than the documented minimum.
+  // https://msdn.microsoft.com/en-us/library/windows/desktop/dd797815(v=vs.85).aspx
+  static const int32_t MIN_H264_FRAME_DIMENSION = 48;
+  if (mStreamType == H264 &&
+      (mVideoInfo.mImage.width < MIN_H264_FRAME_DIMENSION ||
+       mVideoInfo.mImage.height < MIN_H264_FRAME_DIMENSION)) {
+    LogToBrowserConsole(NS_LITERAL_STRING(
+      "Can't decode H.264 stream with width or height less than 48 pixels."));
+    mIsValid = false;
+  }
+
+  return mIsValid;
+}
+
+bool
 WMFVideoMFTManager::Init()
 {
+  if (!ValidateVideoInfo()) {
+    return false;
+  }
+
   bool success = InitInternal(/* aForceD3D9 = */ false);
 
   if (success && mDXVA2Manager) {
     // If we had some failures but eventually made it work,
     // make sure we preserve the messages.
     if (mDXVA2Manager->IsD3D11()) {
       mDXVAFailureReason.Append(NS_LITERAL_CSTRING("Using D3D11 API"));
     } else {
@@ -479,16 +504,20 @@ WMFVideoMFTManager::SetDecoderMediaTypes
   NS_ENSURE_TRUE(SUCCEEDED(hr), hr);
 
   return mDecoder->SetMediaTypes(inputType, outputType);
 }
 
 HRESULT
 WMFVideoMFTManager::Input(MediaRawData* aSample)
 {
+  if (!mIsValid) {
+    return E_FAIL;
+  }
+
   if (!mDecoder) {
     // This can happen during shutdown.
     return E_FAIL;
   }
 
   HRESULT hr = mDecoder->CreateInputSample(aSample->Data(),
                                            uint32_t(aSample->Size()),
                                            aSample->mTime,
@@ -901,11 +930,12 @@ WMFVideoMFTManager::IsHardwareAccelerate
 }
 
 void
 WMFVideoMFTManager::ConfigurationChanged(const TrackInfo& aConfig)
 {
   MOZ_ASSERT(aConfig.GetAsVideoInfo());
   mVideoInfo = *aConfig.GetAsVideoInfo();
   mImageSize = mVideoInfo.mImage;
+  ValidateVideoInfo();
 }
 
 } // namespace mozilla
--- a/dom/media/platforms/wmf/WMFVideoMFTManager.h
+++ b/dom/media/platforms/wmf/WMFVideoMFTManager.h
@@ -46,16 +46,18 @@ public:
   {
     nsCString failureReason;
     return IsHardwareAccelerated(failureReason)
       ? "wmf hardware video decoder" : "wmf software video decoder";
   }
 
 private:
 
+  bool ValidateVideoInfo();
+
   bool InitializeDXVA(bool aForceD3D9);
 
   bool InitInternal(bool aForceD3D9);
 
   HRESULT ConfigureVideoFrameGeometry();
 
   HRESULT CreateBasicVideoFrame(IMFSample* aSample,
                                 int64_t aStreamOffset,
@@ -96,13 +98,14 @@ private:
   StreamType mStreamType;
 
   const GUID& GetMFTGUID();
   const GUID& GetMediaSubtypeGUID();
 
   uint32_t mNullOutputCount;
   bool mGotValidOutputAfterNullOutput;
   bool mGotExcessiveNullOutput;
+  bool mIsValid;
 };
 
 } // namespace mozilla
 
 #endif // WMFVideoMFTManager_h_
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -528,16 +528,30 @@ var gErrorTests = [
   { name:"bug504843.ogv", type:"video/ogg" },
   { name:"bug501279.ogg", type:"audio/ogg" },
   { name:"bug580982.webm", type:"video/webm" },
   { name:"bug603918.webm", type:"video/webm" },
   { name:"bug604067.webm", type:"video/webm" },
   { name:"bogus.duh", type:"bogus/duh" }
 ];
 
+function IsWindowsVistaOrLater() {
+  var re = /Windows NT (\d+.\d)/;
+  var winver = manifestNavigator().userAgent.match(re);
+  return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
+}
+
+// Windows' H.264 decoder cannot handle H.264 streams with resolution
+// less than 48x48 pixels. We refuse to play and error on such streams.
+if (IsWindowsVistaOrLater() &&
+    manifestVideo().canPlayType('video/mp4; codecs="avc1.42E01E"')) {
+  gErrorTests = gErrorTests.concat({name: "red-46x48.mp4", type:"video/mp4"},
+                                   {name: "red-48x46.mp4", type:"video/mp4"});
+}
+
 // These are files that have nontrivial duration and are useful for seeking within.
 var gSeekTests = [
   { name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
   { name:"audio.wav", type:"audio/x-wav", duration:0.031247 },
   { name:"seek.ogv", type:"video/ogg", duration:3.966 },
   { name:"320x240.ogv", type:"video/ogg", duration:0.266 },
   { name:"seek.webm", type:"video/webm", duration:3.966 },
   { name:"sine.webm", type:"audio/webm", duration:4.001 },
@@ -557,22 +571,16 @@ var gFastSeekTests = [
   // Note: Not all keyframes in the file are actually referenced in the Cues in this file.
   { name:"seek.webm", type:"video/webm", keyframes:[0, 0.8, 1.6, 2.4, 3.2]},
   // Note: the sync points are the points on both the audio and video streams
   // before the keyframes. You can't just assume that the keyframes are the sync
   // points, as the audio required for that sync point may be before the keyframe.
   { name:"bug516323.indexed.ogv", type:"video/ogg", keyframes:[0, 0.46, 3.06] },
 ];
 
-function IsWindows8OrLater() {
-  var re = /Windows NT (\d.\d)/;
-  var winver = manifestNavigator().userAgent.match(re);
-  return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.2;
-}
-
 // These files are WebMs without cues. They're seekable within their buffered
 // ranges. If work renders WebMs fully seekable these files should be moved
 // into gSeekTests
 var gCuelessWebMTests = [
   { name:"no-cues.webm", type:"video/webm", duration:3.967 },
 ];
 
 // These are files that are non seekable, due to problems with the media,
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -486,16 +486,20 @@ support-files =
   r11025_s16_c1_trailing.wav^headers^
   r11025_u8_c1.wav
   r11025_u8_c1.wav^headers^
   r11025_u8_c1_trunc.wav
   r11025_u8_c1_trunc.wav^headers^
   r16000_u8_c1_list.wav
   r16000_u8_c1_list.wav^headers^
   reactivate_helper.html
+  red-46x48.mp4
+  red-46x48.mp4^headers^
+  red-48x46.mp4
+  red-48x46.mp4^headers^
   redirect.sjs
   referer.sjs
   region.vtt
   resolution-change.webm
   resolution-change.webm^headers^
   sample.3gp
   sample.3g2
   sample-fisbone-skeleton4.ogv
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0760cc1c165dc13a50cf0e8b85f75ac7efb5c6f7
GIT binary patch
literal 1548
zc$|GyL5mzk6t0<&U?3pEf<ZP=;(8EwX1jZ4C%Xd;ktH|>BVNowgtoe>db*jau9~Wv
z*_pklASwj$wm-m|;3)`ta1Vk9!9U=NpgAZ;qsc{t9GtxB+0D$ZCPi1juj+m8y?XCe
zH$n(!ZmJ8bBtmuMCCrG7X()9&L<l{R8O}lXk7UGw{Oa7<+3d?7uiifR^|1HF{`&X$
z@VUS4PNGg5H!xL(<FLJjP1I>^;me!b+ff*RqSpk%#<kb3zT9Zzm#*&slW_`)9i^v&
zXAVa}&}u|MxCxuNbGo~+vAet592bl$LCU5w{S6<bnL8<fqqHkjX}g$`l+ZZDhG%gL
zGoA`X2XWX9x&bC75mU?KVAARalQ3*y$>W?)upOm<E@N${U<&WVusCc6U<5BLiwS3m
z_ZWgjVo2HNaoE8$H%gKOOhfDp7oxC$wkBJQIskMi;{c98*q$nR9EIy)h%;hcqV1s2
zo-ubY)QQS6%U#@vu*(ftct=910m)&JEcUD@C|_&@xHMG^T1evjIf~M8BM6XSKNTZG
zrU_M269;PwC31!oCAa{hA)b>NBDsZPrHP&bE?67^CX8sGMVh1q@sU_zc$L>KFZ#Jl
z0V&PPq^~q+=bIW#2Yd>?<7hKDf{83je{{-APDd_o2e=CED{8pS!P?N|VYXgxXiQRr
zWeR2WS)~Q=AwRel*aN48?++gO)Z(Do0jPbLN|H(3*#=-8*Kr#c8d?U|11!Kb8NzMw
zy+!Z9eSVRD_#S#@_V3>}e~P|4|HCgghBv;xxAzwNp!Mq7+qYIfx&8Z{Z+||he{}Bi
zcMssY|0$IkgPD-yoS_rr%x~4KA^$8!?Ii2;`U-mNsKfI#q&@)rrW;f-&-~Y$kNx;K
z{~NanGpLqpoH+|}l?&?@7Ds+7+uFyH6$Aj5>~!u|s`>gi)uNFzVU9KagI#7`_aAVN
zluU5Xsdb@g8Gx0steh?%bB)b)s|+s6QW_UVM&KiS-?~(Q+_%oMCC>Z)pY@1R_{0O$
z1KE2d<Mg;Vo54E(uRAq{F3fJBi+zxv9bUVC?<wCCUoBLBa^;2n8akW*ap&f`x3aD(
z>v4?QQQ=qNwDjcu!?^;wy}7D>cd<v+65ls19Wm$I@rLA;^yAs((nGrp(ON90(J1Eq
ceg0FYyu(ZI7bnLBc!i9!%?^Ac%`gZb08m<M@&Et;
new file mode 100644
--- /dev/null
+++ b/dom/media/test/red-46x48.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d83de4027d11f07f6e76c02f797a540ab9f0eb1b
GIT binary patch
literal 1548
zc$|GyL5mzk6t0<&pb!vY!5}M?xE{ov+3ud%$?iZyWC_l}h!=AZp{=f}o-U@UtEReU
zc4jXshzdcx?GNxKc#t6I!955b1pk05g65zYjV6~Mc*x{c&u(URH7UCKeO2#!@6~&+
zx)DM+b5kQqtq`gsFJVSxOhaYbAwuY}%yJI8e-tAQ<k#oU&Sqczbou7NZ->1v_t$^G
zhtK_edlGfpxPhs*9Ea^KY@<$V3t!ya-j2cm6ul-8Hm<yO`Q=6%zjSp6n2b|U>}WHU
zJaae-f>t96!cExBoip8yjosbd=2$SUB`KQP_BVW#X6}>(jy6u{qU>TyQbOYpTb{)&
z%y=p_9mHWb=mwY+L{3W{2a{Gen1o>qD<0>3g3D0~=pr`d6infrSQdxP0F2;;m6&jr
zc#k1iB$gC?9)}%FbE_3ez%<0paw$a#Xlt^?r~^QUDh}WXgzf2q$5FT*hBzaoOH4Ts
z#xv#)h9=QjR&p0NBJ6St7T%H6dO&hmB#XUL3d$E70WNG6g9=5QKZhtBw~_z}_ER~s
zWSUT|3~{igP$FlED8K~}E%BVp62(g>R+^Y8V8P-DFk!^_EYc(u#7APn@+z-gF8aAk
z0cpdFq^}KV=bHvh2Yd>?<7hKDf{7A^KRV?Frz01)16&376}7y~!P?T~LAG9RX-ra!
zRSISGS)~H_kRMzN?19tL_XiJsYH`r)05m>KCCMc2Yy&7AH*p&a11*E=0T$qz4B<BT
z-lBKlKEKF6d=EW6yLb2c&(Zgf|M=^*;k9q>?7hW4XuZ1j_Knp~ZvJuWyI&6KAD#Q+
z-2=Gpe<`iUU?$Z#XXwN@^LsUG$UlowJIOk|zJwk*>hL@TsSg0Z=>}EIGynDGV?R31
z|HchqHml_tXRZXf%4O*m7Ds+7+uFy92?78sb~^V<)qMTiYSGA<w8t9%!7eke`VY8A
z3MRSd)Vk2L48Y1*RZf?WxyI(YRR$MjDUI_ZEAbKjw{)olxnH`HEpguW|E!0U!YAHD
zJ&?VJGER>RvzfO8uRAq{&d+Y33w@BE9bUQj`IEjUzFMgM#L5f%HFP%r^VaosZ&kXg
ztj95GM}=R7)6$ds59SK!_U5Yk?ZqC|OMKtBbi|x*#~X@Q(vN4COAqa`#2C4pMnlZ|
c`~0U)dxy`!Uz{8l;1x2?HaqZ*G{Ydg4<15mwg3PC
new file mode 100644
--- /dev/null
+++ b/dom/media/test/red-48x46.mp4^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/dom/media/webaudio/AnalyserNode.cpp
+++ b/dom/media/webaudio/AnalyserNode.cpp
@@ -108,17 +108,18 @@ AnalyserNode::AnalyserNode(AudioContext*
               ChannelInterpretation::Speakers)
   , mAnalysisBlock(2048)
   , mMinDecibels(-100.)
   , mMaxDecibels(-30.)
   , mSmoothingTimeConstant(.8)
 {
   mStream = AudioNodeStream::Create(aContext,
                                     new AnalyserNodeEngine(this),
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 
   // Enough chunks must be recorded to handle the case of fftSize being
   // increased to maximum immediately before getFloatTimeDomainData() is
   // called, for example.
   Unused << mChunks.SetLength(CHUNK_COUNT, fallible);
 
   AllocateBuffer();
 }
--- a/dom/media/webaudio/AudioBufferSourceNode.cpp
+++ b/dom/media/webaudio/AudioBufferSourceNode.cpp
@@ -597,17 +597,18 @@ AudioBufferSourceNode::AudioBufferSource
   // mOffset and mDuration are initialized in Start().
   , mPlaybackRate(new AudioParam(this, PLAYBACKRATE, 1.0f, "playbackRate"))
   , mDetune(new AudioParam(this, DETUNE, 0.0f, "detune"))
   , mLoop(false)
   , mStartCalled(false)
 {
   AudioBufferSourceNodeEngine* engine = new AudioBufferSourceNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NEED_MAIN_THREAD_FINISHED);
+                                    AudioNodeStream::NEED_MAIN_THREAD_FINISHED,
+                                    aContext->Graph());
   engine->SetSourceStream(mStream);
   mStream->AddMainThreadListener(this);
 }
 
 AudioBufferSourceNode::~AudioBufferSourceNode()
 {
 }
 
--- a/dom/media/webaudio/AudioNodeStream.cpp
+++ b/dom/media/webaudio/AudioNodeStream.cpp
@@ -66,30 +66,30 @@ AudioNodeStream::DestroyImpl()
   ProcessedMediaStream::DestroyImpl();
 }
 
 /* static */ already_AddRefed<AudioNodeStream>
 AudioNodeStream::Create(AudioContext* aCtx, AudioNodeEngine* aEngine,
                         Flags aFlags, MediaStreamGraph* aGraph)
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_RELEASE_ASSERT(aGraph);
 
   // MediaRecorders use an AudioNodeStream, but no AudioNode
   AudioNode* node = aEngine->NodeMainThread();
-  MediaStreamGraph* graph = aGraph ? aGraph : aCtx->Graph();
 
   RefPtr<AudioNodeStream> stream =
-    new AudioNodeStream(aEngine, aFlags, graph->GraphRate());
+    new AudioNodeStream(aEngine, aFlags, aGraph->GraphRate());
   stream->mSuspendedCount += aCtx->ShouldSuspendNewStream();
   if (node) {
     stream->SetChannelMixingParametersImpl(node->ChannelCount(),
                                            node->ChannelCountModeValue(),
                                            node->ChannelInterpretationValue());
   }
-  graph->AddStream(stream);
+  aGraph->AddStream(stream);
   return stream.forget();
 }
 
 size_t
 AudioNodeStream::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
 {
   size_t amount = 0;
 
--- a/dom/media/webaudio/AudioNodeStream.h
+++ b/dom/media/webaudio/AudioNodeStream.h
@@ -57,23 +57,22 @@ public:
     // Internal AudioNodeStreams can only pass their output to another
     // AudioNode, whereas external AudioNodeStreams can pass their output
     // to other ProcessedMediaStreams or hardware audio output.
     EXTERNAL_OUTPUT = 1U << 2,
   };
   /**
    * Create a stream that will process audio for an AudioNode.
    * Takes ownership of aEngine.
-   * If aGraph is non-null, use that as the MediaStreamGraph, otherwise use
-   * aCtx's graph. aGraph is only non-null when called for AudioDestinationNode
-   * since the context's graph hasn't been set up in that case.
+   * aGraph is required and equals the graph of aCtx in most cases. An exception
+   * is AudioDestinationNode where the context's graph hasn't been set up yet.
    */
   static already_AddRefed<AudioNodeStream>
   Create(AudioContext* aCtx, AudioNodeEngine* aEngine, Flags aKind,
-         MediaStreamGraph* aGraph = nullptr);
+         MediaStreamGraph* aGraph);
 
 protected:
   /**
    * Transfers ownership of aEngine to the new AudioNodeStream.
    */
   AudioNodeStream(AudioNodeEngine* aEngine,
                   Flags aFlags,
                   TrackRate aSampleRate);
--- a/dom/media/webaudio/AudioParam.cpp
+++ b/dom/media/webaudio/AudioParam.cpp
@@ -86,17 +86,18 @@ AudioParam::Stream()
 {
   if (mStream) {
     return mStream;
   }
 
   AudioNodeEngine* engine = new AudioNodeEngine(nullptr);
   RefPtr<AudioNodeStream> stream =
     AudioNodeStream::Create(mNode->Context(), engine,
-                            AudioNodeStream::NO_STREAM_FLAGS);
+                            AudioNodeStream::NO_STREAM_FLAGS,
+                            mNode->Context()->Graph());
 
   // Force the input to have only one channel, and make it down-mix using
   // the speaker rules if needed.
   stream->SetChannelMixingParametersImpl(1, ChannelCountMode::Explicit, ChannelInterpretation::Speakers);
   // Mark as an AudioParam helper stream
   stream->SetAudioParamHelperStream();
 
   mStream = stream.forget();
--- a/dom/media/webaudio/BiquadFilterNode.cpp
+++ b/dom/media/webaudio/BiquadFilterNode.cpp
@@ -254,17 +254,18 @@ BiquadFilterNode::BiquadFilterNode(Audio
                               350.f, "frequency"))
   , mDetune(new AudioParam(this, BiquadFilterNodeEngine::DETUNE, 0.f, "detune"))
   , mQ(new AudioParam(this, BiquadFilterNodeEngine::Q, 1.f, "Q"))
   , mGain(new AudioParam(this, BiquadFilterNodeEngine::GAIN, 0.f, "gain"))
 {
   uint64_t windowID = aContext->GetParentObject()->WindowID();
   BiquadFilterNodeEngine* engine = new BiquadFilterNodeEngine(this, aContext->Destination(), windowID);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 BiquadFilterNode::~BiquadFilterNode()
 {
 }
 
 size_t
 BiquadFilterNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/ChannelMergerNode.cpp
+++ b/dom/media/webaudio/ChannelMergerNode.cpp
@@ -66,17 +66,18 @@ ChannelMergerNode::ChannelMergerNode(Aud
   : AudioNode(aContext,
               1,
               ChannelCountMode::Explicit,
               ChannelInterpretation::Speakers)
   , mInputCount(aInputCount)
 {
   mStream = AudioNodeStream::Create(aContext,
                                     new ChannelMergerNodeEngine(this),
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 ChannelMergerNode::~ChannelMergerNode()
 {
 }
 
 JSObject*
 ChannelMergerNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/media/webaudio/ChannelSplitterNode.cpp
+++ b/dom/media/webaudio/ChannelSplitterNode.cpp
@@ -57,17 +57,18 @@ ChannelSplitterNode::ChannelSplitterNode
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mOutputCount(aOutputCount)
 {
   mStream = AudioNodeStream::Create(aContext,
                                     new ChannelSplitterNodeEngine(this),
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 ChannelSplitterNode::~ChannelSplitterNode()
 {
 }
 
 JSObject*
 ChannelSplitterNode::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
--- a/dom/media/webaudio/ConvolverNode.cpp
+++ b/dom/media/webaudio/ConvolverNode.cpp
@@ -195,17 +195,18 @@ ConvolverNode::ConvolverNode(AudioContex
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
   , mNormalize(true)
 {
   ConvolverNodeEngine* engine = new ConvolverNodeEngine(this, mNormalize);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 ConvolverNode::~ConvolverNode()
 {
 }
 
 size_t
 ConvolverNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/DelayNode.cpp
+++ b/dom/media/webaudio/DelayNode.cpp
@@ -197,17 +197,18 @@ DelayNode::DelayNode(AudioContext* aCont
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mDelay(new AudioParam(this, DelayNodeEngine::DELAY, 0.0f, "delayTime"))
 {
   DelayNodeEngine* engine =
     new DelayNodeEngine(this, aContext->Destination(),
                         aContext->SampleRate() * aMaxDelay);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 DelayNode::~DelayNode()
 {
 }
 
 size_t
 DelayNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/DynamicsCompressorNode.cpp
+++ b/dom/media/webaudio/DynamicsCompressorNode.cpp
@@ -196,17 +196,18 @@ DynamicsCompressorNode::DynamicsCompress
   , mReduction(0)
   , mAttack(new AudioParam(this, DynamicsCompressorNodeEngine::ATTACK,
                            0.003f, "attack"))
   , mRelease(new AudioParam(this, DynamicsCompressorNodeEngine::RELEASE,
                             0.25f, "release"))
 {
   DynamicsCompressorNodeEngine* engine = new DynamicsCompressorNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 DynamicsCompressorNode::~DynamicsCompressorNode()
 {
 }
 
 size_t
 DynamicsCompressorNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/GainNode.cpp
+++ b/dom/media/webaudio/GainNode.cpp
@@ -119,17 +119,18 @@ GainNode::GainNode(AudioContext* aContex
   : AudioNode(aContext,
               2,
               ChannelCountMode::Max,
               ChannelInterpretation::Speakers)
   , mGain(new AudioParam(this, GainNodeEngine::GAIN, 1.0f, "gain"))
 {
   GainNodeEngine* engine = new GainNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 GainNode::~GainNode()
 {
 }
 
 size_t
 GainNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/IIRFilterNode.cpp
+++ b/dom/media/webaudio/IIRFilterNode.cpp
@@ -159,17 +159,18 @@ IIRFilterNode::IIRFilterNode(AudioContex
   }
 
   // We check that this is exactly equal to one later in blink/IIRFilter.cpp
   elements[0] = 1.0;
 
   uint64_t windowID = aContext->GetParentObject()->WindowID();
   IIRFilterNodeEngine* engine = new IIRFilterNodeEngine(this, aContext->Destination(), mFeedforward, mFeedback, windowID);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 IIRFilterNode::~IIRFilterNode()
 {
 }
 
 size_t
 IIRFilterNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -44,17 +44,18 @@ MediaStreamAudioDestinationNode::MediaSt
                                MediaSegment::AUDIO, source,
                                MediaTrackConstraints());
   mDOMStream->AddTrackInternal(track);
 
   ProcessedMediaStream* outputStream = mDOMStream->GetInputStream()->AsProcessedStream();
   MOZ_ASSERT(!!outputStream);
   AudioNodeEngine* engine = new AudioNodeEngine(this);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::EXTERNAL_OUTPUT);
+                                    AudioNodeStream::EXTERNAL_OUTPUT,
+                                    aContext->Graph());
   mPort = outputStream->AllocateInputPort(mStream, AudioNodeStream::AUDIO_TRACK);
 }
 
 MediaStreamAudioDestinationNode::~MediaStreamAudioDestinationNode()
 {
 }
 
 size_t
--- a/dom/media/webaudio/OscillatorNode.cpp
+++ b/dom/media/webaudio/OscillatorNode.cpp
@@ -415,17 +415,18 @@ OscillatorNode::OscillatorNode(AudioCont
   , mType(OscillatorType::Sine)
   , mFrequency(new AudioParam(this, OscillatorNodeEngine::FREQUENCY,
                               440.0f, "frequency"))
   , mDetune(new AudioParam(this, OscillatorNodeEngine::DETUNE, 0.0f, "detune"))
   , mStartCalled(false)
 {
   OscillatorNodeEngine* engine = new OscillatorNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NEED_MAIN_THREAD_FINISHED);
+                                    AudioNodeStream::NEED_MAIN_THREAD_FINISHED,
+                                    aContext->Graph());
   engine->SetSourceStream(mStream);
   mStream->AddMainThreadListener(this);
 }
 
 OscillatorNode::~OscillatorNode()
 {
 }
 
--- a/dom/media/webaudio/PannerNode.cpp
+++ b/dom/media/webaudio/PannerNode.cpp
@@ -310,17 +310,18 @@ PannerNode::PannerNode(AudioContext* aCo
   , mMaxDistance(10000.)
   , mRolloffFactor(1.)
   , mConeInnerAngle(360.)
   , mConeOuterAngle(360.)
   , mConeOuterGain(0.)
 {
   mStream = AudioNodeStream::Create(aContext,
                                     new PannerNodeEngine(this, aContext->Destination()),
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
   // We should register once we have set up our stream and engine.
   Context()->Listener()->RegisterPannerNode(this);
 }
 
 PannerNode::~PannerNode()
 {
   if (Context()) {
     Context()->UnregisterPannerNode(this);
--- a/dom/media/webaudio/ScriptProcessorNode.cpp
+++ b/dom/media/webaudio/ScriptProcessorNode.cpp
@@ -499,17 +499,18 @@ ScriptProcessorNode::ScriptProcessorNode
 {
   MOZ_ASSERT(BufferSize() % WEBAUDIO_BLOCK_SIZE == 0, "Invalid buffer size");
   ScriptProcessorNodeEngine* engine =
     new ScriptProcessorNodeEngine(this,
                                   aContext->Destination(),
                                   BufferSize(),
                                   aNumberOfInputChannels);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 ScriptProcessorNode::~ScriptProcessorNode()
 {
 }
 
 size_t
 ScriptProcessorNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/StereoPannerNode.cpp
+++ b/dom/media/webaudio/StereoPannerNode.cpp
@@ -174,17 +174,18 @@ StereoPannerNode::StereoPannerNode(Audio
   : AudioNode(aContext,
               2,
               ChannelCountMode::Clamped_max,
               ChannelInterpretation::Speakers)
   , mPan(new AudioParam(this, StereoPannerNodeEngine::PAN, 0.f, "pan"))
 {
   StereoPannerNodeEngine* engine = new StereoPannerNodeEngine(this, aContext->Destination());
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 StereoPannerNode::~StereoPannerNode()
 {
 }
 
 size_t
 StereoPannerNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
--- a/dom/media/webaudio/WaveShaperNode.cpp
+++ b/dom/media/webaudio/WaveShaperNode.cpp
@@ -317,17 +317,18 @@ WaveShaperNode::WaveShaperNode(AudioCont
               ChannelInterpretation::Speakers)
   , mCurve(nullptr)
   , mType(OverSampleType::None)
 {
   mozilla::HoldJSObjects(this);
 
   WaveShaperNodeEngine* engine = new WaveShaperNodeEngine(this);
   mStream = AudioNodeStream::Create(aContext, engine,
-                                    AudioNodeStream::NO_STREAM_FLAGS);
+                                    AudioNodeStream::NO_STREAM_FLAGS,
+                                    aContext->Graph());
 }
 
 WaveShaperNode::~WaveShaperNode()
 {
   ClearCurve();
 }
 
 void
--- a/dom/security/nsCSPParser.cpp
+++ b/dom/security/nsCSPParser.cpp
@@ -186,73 +186,16 @@ nsCSPParser::resetCurChar(const nsAStrin
 // number sign ("#") character, or by the end of the URI.
 // http://tools.ietf.org/html/rfc3986#section-3.3
 bool
 nsCSPParser::atEndOfPath()
 {
   return (atEnd() || peek(QUESTIONMARK) || peek(NUMBER_SIGN));
 }
 
-void
-nsCSPParser::percentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr)
-{
-  outDecStr.Truncate();
-
-  // helper function that should not be visible outside this methods scope
-  struct local {
-    static inline char16_t convertHexDig(char16_t aHexDig) {
-      if (isNumberToken(aHexDig)) {
-        return aHexDig - '0';
-      }
-      if (aHexDig >= 'A' && aHexDig <= 'F') {
-        return aHexDig - 'A' + 10;
-      }
-      // must be a lower case character
-      // (aHexDig >= 'a' && aHexDig <= 'f')
-      return aHexDig - 'a' + 10;
-    }
-  };
-
-  const char16_t *cur, *end, *hexDig1, *hexDig2;
-  cur = aEncStr.BeginReading();
-  end = aEncStr.EndReading();
-
-  while (cur != end) {
-    // if it's not a percent sign then there is
-    // nothing to do for that character
-    if (*cur != PERCENT_SIGN) {
-      outDecStr.Append(*cur);
-      cur++;
-      continue;
-    }
-
-    // get the two hexDigs following the '%'-sign
-    hexDig1 = cur + 1;
-    hexDig2 = cur + 2;
-
-    // if there are no hexdigs after the '%' then
-    // there is nothing to do for us.
-    if (hexDig1 == end || hexDig2 == end ||
-        !isValidHexDig(*hexDig1) ||
-        !isValidHexDig(*hexDig2)) {
-      outDecStr.Append(PERCENT_SIGN);
-      cur++;
-      continue;
-    }
-
-    // decode "% hexDig1 hexDig2" into a character.
-    char16_t decChar = (local::convertHexDig(*hexDig1) << 4) +
-                       local::convertHexDig(*hexDig2);
-    outDecStr.Append(decChar);
-
-    // increment 'cur' to after the second hexDig
-    cur = ++hexDig2;
-  }
-}
-
 // unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
 bool
 nsCSPParser::atValidUnreservedChar()
 {
   return (peek(isCharacterToken) || peek(isNumberToken) ||
           peek(DASH) || peek(DOT) ||
           peek(UNDERLINE) || peek(TILDE));
 }
@@ -393,17 +336,17 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspH
   uint32_t charCounter = 0;
   nsString pctDecodedSubPath;
 
   while (!atEndOfPath()) {
     if (peek(SLASH)) {
       // before appendig any additional portion of a subpath we have to pct-decode
       // that portion of the subpath. atValidPathChar() already verified a correct
       // pct-encoding, now we can safely decode and append the decoded-sub path.
-      percentDecodeStr(mCurValue, pctDecodedSubPath);
+      CSP_PercentDecodeStr(mCurValue, pctDecodedSubPath);
       aCspHost->appendPath(pctDecodedSubPath);
       // Resetting current value since we are appending parts of the path
       // to aCspHost, e.g; "http://www.example.com/path1/path2" then the
       // first part is "/path1", second part "/path2"
       resetCurValue();
     }
     else if (!atValidPathChar()) {
       const char16_t* params[] = { mCurToken.get() };
@@ -422,17 +365,17 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspH
     advance();
     if (++charCounter > kSubHostPathCharacterCutoff) {
       return false;
     }
   }
   // before appendig any additional portion of a subpath we have to pct-decode
   // that portion of the subpath. atValidPathChar() already verified a correct
   // pct-encoding, now we can safely decode and append the decoded-sub path.
-  percentDecodeStr(mCurValue, pctDecodedSubPath);
+  CSP_PercentDecodeStr(mCurValue, pctDecodedSubPath);
   aCspHost->appendPath(pctDecodedSubPath);
   resetCurValue();
   return true;
 }
 
 bool
 nsCSPParser::path(nsCSPHostSrc* aCspHost)
 {
--- a/dom/security/nsCSPParser.h
+++ b/dom/security/nsCSPParser.h
@@ -139,18 +139,16 @@ class nsCSPParser {
     bool                port();
     bool                path(nsCSPHostSrc* aCspHost);
 
     bool subHost();                                         // helper function to parse subDomains
     bool atValidUnreservedChar();                           // helper function to parse unreserved
     bool atValidSubDelimChar();                             // helper function to parse sub-delims
     bool atValidPctEncodedChar();                           // helper function to parse pct-encoded
     bool subPath(nsCSPHostSrc* aCspHost);                   // helper function to parse paths
-    void percentDecodeStr(const nsAString& aEncStr,         // helper function to percent-decode
-                          nsAString& outDecStr);
 
     inline bool atEnd()
     {
       return mCurChar >= mEndChar;
     }
 
     inline bool accept(char16_t aSymbol)
     {
--- a/dom/security/nsCSPUtils.cpp
+++ b/dom/security/nsCSPUtils.cpp
@@ -26,16 +26,73 @@ GetCspUtilsLog()
   static mozilla::LazyLogModule gCspUtilsPRLog("CSPUtils");
   return gCspUtilsPRLog;
 }
 
 #define CSPUTILSLOG(args) MOZ_LOG(GetCspUtilsLog(), mozilla::LogLevel::Debug, args)
 #define CSPUTILSLOGENABLED() MOZ_LOG_TEST(GetCspUtilsLog(), mozilla::LogLevel::Debug)
 
 void
+CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr)
+{
+  outDecStr.Truncate();
+
+  // helper function that should not be visible outside this methods scope
+  struct local {
+    static inline char16_t convertHexDig(char16_t aHexDig) {
+      if (isNumberToken(aHexDig)) {
+        return aHexDig - '0';
+      }
+      if (aHexDig >= 'A' && aHexDig <= 'F') {
+        return aHexDig - 'A' + 10;
+      }
+      // must be a lower case character
+      // (aHexDig >= 'a' && aHexDig <= 'f')
+      return aHexDig - 'a' + 10;
+    }
+  };
+
+  const char16_t *cur, *end, *hexDig1, *hexDig2;
+  cur = aEncStr.BeginReading();
+  end = aEncStr.EndReading();
+
+  while (cur != end) {
+    // if it's not a percent sign then there is
+    // nothing to do for that character
+    if (*cur != PERCENT_SIGN) {
+      outDecStr.Append(*cur);
+      cur++;
+      continue;
+    }
+
+    // get the two hexDigs following the '%'-sign
+    hexDig1 = cur + 1;
+    hexDig2 = cur + 2;
+
+    // if there are no hexdigs after the '%' then
+    // there is nothing to do for us.
+    if (hexDig1 == end || hexDig2 == end ||
+        !isValidHexDig(*hexDig1) ||
+        !isValidHexDig(*hexDig2)) {
+      outDecStr.Append(PERCENT_SIGN);
+      cur++;
+      continue;
+    }
+
+    // decode "% hexDig1 hexDig2" into a character.
+    char16_t decChar = (local::convertHexDig(*hexDig1) << 4) +
+                       local::convertHexDig(*hexDig2);
+    outDecStr.Append(decChar);
+
+    // increment 'cur' to after the second hexDig
+    cur = ++hexDig2;
+  }
+}
+
+void
 CSP_GetLocalizedStr(const char16_t* aName,
                     const char16_t** aParams,
                     uint32_t aLength,
                     char16_t** outResult)
 {
   nsCOMPtr<nsIStringBundle> keyStringBundle;
   nsCOMPtr<nsIStringBundleService> stringBundleService =
     mozilla::services::GetStringBundleService();
@@ -562,30 +619,33 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
   }
 
   // Before we can check if the host matches, we have to
   // extract the host part from aUri.
   nsAutoCString uriHost;
   nsresult rv = aUri->GetHost(uriHost);
   NS_ENSURE_SUCCESS(rv, false);
 
+  nsString decodedUriHost;
+  CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriHost), decodedUriHost);
+
   // 4.5) host matching: Check if the allowed host starts with a wilcard.
   if (mHost.First() == '*') {
     NS_ASSERTION(mHost[1] == '.', "Second character needs to be '.' whenever host starts with '*'");
 
     // Eliminate leading "*", but keeping the FULL STOP (.) thereafter before checking
     // if the remaining characters match
     nsString wildCardHost = mHost;
     wildCardHost = Substring(wildCardHost, 1, wildCardHost.Length() - 1);
-    if (!StringEndsWith(NS_ConvertUTF8toUTF16(uriHost), wildCardHost)) {
+    if (!StringEndsWith(decodedUriHost, wildCardHost)) {
       return false;
     }
   }
   // 4.6) host matching: Check if hosts match.
-  else if (!mHost.Equals(NS_ConvertUTF8toUTF16(uriHost))) {
+  else if (!mHost.Equals(decodedUriHost)) {
     return false;
   }
 
   // Port matching: Check if the ports match.
   if (!permitsPort(mScheme, mPort, aUri)) {
     return false;
   }
 
@@ -599,28 +659,32 @@ nsCSPHostSrc::permits(nsIURI* aUri, cons
     nsCOMPtr<nsIURL> url = do_QueryInterface(aUri);
     if (!url) {
       NS_ASSERTION(false, "can't QI into nsIURI");
       return false;
     }
     nsAutoCString uriPath;
     rv = url->GetFilePath(uriPath);
     NS_ENSURE_SUCCESS(rv, false);
+
+    nsString decodedUriPath;
+    CSP_PercentDecodeStr(NS_ConvertUTF8toUTF16(uriPath), decodedUriPath);
+
     // check if the last character of mPath is '/'; if so
     // we just have to check loading resource is within
     // the allowed path.
     if (mPath.Last() == '/') {
-      if (!StringBeginsWith(NS_ConvertUTF8toUTF16(uriPath), mPath)) {
+      if (!StringBeginsWith(decodedUriPath, mPath)) {
         return false;
       }
     }
     // otherwise mPath whitelists a specific file, and we have to
     // check if the loading resource matches that whitelisted file.
     else {
-      if (!mPath.Equals(NS_ConvertUTF8toUTF16(uriPath))) {
+      if (!mPath.Equals(decodedUriPath)) {
         return false;
       }
     }
   }
 
   // At the end: scheme, host, port and path match -> allow the load.
   return true;
 }
--- a/dom/security/nsCSPUtils.h
+++ b/dom/security/nsCSPUtils.h
@@ -188,16 +188,18 @@ nsCSPHostSrc* CSP_CreateHostSrcFromURI(n
 bool CSP_IsValidDirective(const nsAString& aDir);
 bool CSP_IsDirective(const nsAString& aValue, CSPDirective aDir);
 bool CSP_IsKeyword(const nsAString& aValue, enum CSPKeyword aKey);
 bool CSP_IsQuotelessKeyword(const nsAString& aKey);
 CSPDirective CSP_ContentTypeToDirective(nsContentPolicyType aType);
 
 class nsCSPSrcVisitor;
 
+void CSP_PercentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr);
+
 /* =============== nsCSPSrc ================== */
 
 class nsCSPBaseSrc {
   public:
     nsCSPBaseSrc();
     virtual ~nsCSPBaseSrc();
 
     virtual bool permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected,
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_bug1229639.html
@@ -0,0 +1,7 @@
+<html>
+<head> <meta charset="utf-8"> </head>
+  <body>
+    <!-- this should be allowed -->
+    <script src="http://mochi.test:8888/tests/dom/security/test/csp/%24.js"> </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/file_bug1229639.html^headers^
@@ -0,0 +1,1 @@
+Content-Security-Policy: "default-src 'self'; script-src http://mochi.test:8888/tests/dom/security/test/csp/%24.js
\ No newline at end of file
--- a/dom/security/test/csp/mochitest.ini
+++ b/dom/security/test/csp/mochitest.ini
@@ -76,16 +76,18 @@ support-files =
   file_redirects_resource.sjs
   file_bug910139.sjs
   file_bug910139.xml
   file_bug910139.xsl
   file_bug909029_star.html
   file_bug909029_star.html^headers^
   file_bug909029_none.html
   file_bug909029_none.html^headers^
+  file_bug1229639.html
+  file_bug1229639.html^headers^
   file_policyuri_regression_from_multipolicy.html
   file_policyuri_regression_from_multipolicy.html^headers^
   file_policyuri_regression_from_multipolicy_policy
   file_shouldprocess.html
   file_nonce_source.html
   file_nonce_source.html^headers^
   file_bug941404.html
   file_bug941404_xhr.html
@@ -203,16 +205,17 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_inlinescript.html]
 [test_inlinestyle.html]
 [test_invalid_source_expression.html]
 [test_bug836922_npolicies.html]
 [test_bug886164.html]
 [test_redirects.html]
 [test_bug910139.html]
 [test_bug909029.html]
+[test_bug1229639.html]
 [test_policyuri_regression_from_multipolicy.html]
 [test_nonce_source.html]
 [test_bug941404.html]
 [test_form-action.html]
 skip-if = buildapp == 'b2g' # http-on-opening-request observers are not available in child processes
 [test_hash_source.html]
 skip-if = buildapp == 'b2g' # can't compute hashes in child process (bug 958702)
 [test_scheme_relative_sources.html]
new file mode 100644
--- /dev/null
+++ b/dom/security/test/csp/test_bug1229639.html
@@ -0,0 +1,51 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Bug 1229639 - Percent encoded CSP path matching.</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+
+<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
+<script class="testbody" type="text/javascript">
+
+// This is used to watch the blocked data bounce off CSP and allowed data
+// get sent out to the wire.
+function examiner() {
+  SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
+  SpecialPowers.addObserver(this, "specialpowers-http-notify-request", false);
+}
+
+examiner.prototype  = {
+  observe: function(subject, topic, data) {
+    if (data === 'http://mochi.test:8888/tests/dom/security/test/csp/%24.js') {
+      is(topic, "specialpowers-http-notify-request");
+      this.remove();
+      SimpleTest.finish();
+    }
+  },
+
+  // must eventually call this to remove the listener,
+  // or mochitests might get borked.
+  remove: function() {
+    SpecialPowers.removeObserver(this, "csp-on-violate-policy");
+    SpecialPowers.removeObserver(this, "specialpowers-http-notify-request");
+  }
+}
+
+window.examiner = new examiner();
+
+SimpleTest.waitForExplicitFinish();
+
+// save this for last so that our listeners are registered.
+// ... this loads the testbed of good and bad requests.
+document.getElementById('cspframe').src = 'file_bug1229639.html';
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/smil/nsSMILAnimationFunction.h
+++ b/dom/smil/nsSMILAnimationFunction.h
@@ -266,17 +266,17 @@ public:
       }
   };
 
 protected:
   // Typedefs
   typedef FallibleTArray<nsSMILValue> nsSMILValueArray;
 
   // Types
-  enum nsSMILCalcMode
+  enum nsSMILCalcMode : uint8_t
   {
     CALC_LINEAR,
     CALC_DISCRETE,
     CALC_PACED,
     CALC_SPLINE
   };
 
   // Used for sorting nsSMILAnimationFunctions
--- a/dom/smil/nsSMILTimedElement.h
+++ b/dom/smil/nsSMILTimedElement.h
@@ -573,25 +573,25 @@ protected:
   nsSMILTimeValue                 mSimpleDur;
 
   nsSMILRepeatCount               mRepeatCount;
   nsSMILTimeValue                 mRepeatDur;
 
   nsSMILTimeValue                 mMin;
   nsSMILTimeValue                 mMax;
 
-  enum nsSMILFillMode
+  enum nsSMILFillMode : uint8_t
   {
     FILL_REMOVE,
     FILL_FREEZE
   };
   nsSMILFillMode                  mFillMode;
   static nsAttrValue::EnumTable   sFillModeTable[];
 
-  enum nsSMILRestartMode
+  enum nsSMILRestartMode : uint8_t
   {
     RESTART_ALWAYS,
     RESTART_WHENNOTACTIVE,
     RESTART_NEVER
   };
   nsSMILRestartMode               mRestartMode;
   static nsAttrValue::EnumTable   sRestartModeTable[];
 
--- a/dom/xbl/nsXBLPrototypeHandler.cpp
+++ b/dom/xbl/nsXBLPrototypeHandler.cpp
@@ -732,16 +732,17 @@ nsXBLPrototypeHandler::ConstructPrototyp
                                           const char16_t* aGroup,
                                           const char16_t* aPreventDefault,
                                           const char16_t* aAllowUntrusted)
 {
   mType = 0;
 
   if (aKeyElement) {
     mType |= NS_HANDLER_TYPE_XUL;
+    MOZ_ASSERT(!mPrototypeBinding);
     nsCOMPtr<nsIWeakReference> weak = do_GetWeakReference(aKeyElement);
     if (!weak) {
       return;
     }
     weak.swap(mHandlerElement);
   }
   else {
     mType |= aCommand ? NS_HANDLER_TYPE_XBL_COMMAND : NS_HANDLER_TYPE_XBL_JS;
@@ -831,22 +832,24 @@ nsXBLPrototypeHandler::ConstructPrototyp
     if (mKeyMask == 0)
       mKeyMask = cAllModifiers;
     ToLowerCase(key);
 
     // We have a charcode.
     mMisc = 1;
     mDetail = key[0];
     const uint8_t GTK2Modifiers = cShift | cControl | cShiftMask | cControlMask;
-    if ((mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
+    if ((mType & NS_HANDLER_TYPE_XUL) &&
+        (mKeyMask & GTK2Modifiers) == GTK2Modifiers &&
         modifiers.First() != char16_t(',') &&
         (mDetail == 'u' || mDetail == 'U'))
       ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "GTK2Conflict2");
     const uint8_t WinModifiers = cControl | cAlt | cControlMask | cAltMask;
-    if ((mKeyMask & WinModifiers) == WinModifiers &&
+    if ((mType & NS_HANDLER_TYPE_XUL) &&
+        (mKeyMask & WinModifiers) == WinModifiers &&
         modifiers.First() != char16_t(',') &&
         (('A' <= mDetail && mDetail <= 'Z') ||
          ('a' <= mDetail && mDetail <= 'z')))
       ReportKeyConflict(key.get(), modifiers.get(), aKeyElement, "WinConflict2");
   }
   else {
     key.Assign(aKeyCode);
     if (mType & NS_HANDLER_TYPE_XUL)
@@ -880,17 +883,17 @@ void
 nsXBLPrototypeHandler::ReportKeyConflict(const char16_t* aKey, const char16_t* aModifiers, nsIContent* aKeyElement, const char *aMessageName)
 {
   nsCOMPtr<nsIDocument> doc;
   if (mPrototypeBinding) {
     nsXBLDocumentInfo* docInfo = mPrototypeBinding->XBLDocumentInfo();
     if (docInfo) {
       doc = docInfo->GetDocument();
     }
-  } else if (aKeyElement) {
+  } else {
     doc = aKeyElement->OwnerDoc();
   }
 
   nsAutoString id;
   aKeyElement->GetAttr(kNameSpaceID_None, nsGkAtoms::id, id);
   const char16_t* params[] = { aKey, aModifiers, id.get() };
   nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                   NS_LITERAL_CSTRING("XBL Prototype Handler"), doc,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3045,41 +3045,44 @@ nsLayoutUtils::TranslateViewToWidget(nsP
   nsPoint pt = (aPt +
   viewOffset).ApplyResolution(GetCurrentAPZResolutionScale(aPresContext->PresShell()));
   LayoutDeviceIntPoint relativeToViewWidget(aPresContext->AppUnitsToDevPixels(pt.x),
                                             aPresContext->AppUnitsToDevPixels(pt.y));
   return relativeToViewWidget + WidgetToWidgetOffset(viewWidget, aWidget);
 }
 
 // Combine aNewBreakType with aOrigBreakType, but limit the break types
-// to NS_STYLE_CLEAR_LEFT, RIGHT, BOTH.
-uint8_t
-nsLayoutUtils::CombineBreakType(uint8_t aOrigBreakType,
-                                uint8_t aNewBreakType)
-{
-  uint8_t breakType = aOrigBreakType;
+// to StyleClear::Left, Right, Both.
+StyleClear
+nsLayoutUtils::CombineBreakType(StyleClear aOrigBreakType,
+                                StyleClear aNewBreakType)
+{
+  StyleClear breakType = aOrigBreakType;
   switch(breakType) {
-  case NS_STYLE_CLEAR_LEFT:
-    if (NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
-        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
-      breakType = NS_STYLE_CLEAR_BOTH;
-    }
-    break;
-  case NS_STYLE_CLEAR_RIGHT:
-    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
-        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
-      breakType = NS_STYLE_CLEAR_BOTH;
-    }
-    break;
-  case NS_STYLE_CLEAR_NONE:
-    if (NS_STYLE_CLEAR_LEFT == aNewBreakType ||
-        NS_STYLE_CLEAR_RIGHT == aNewBreakType ||
-        NS_STYLE_CLEAR_BOTH == aNewBreakType) {
-      breakType = aNewBreakType;
-    }
+    case StyleClear::Left:
+      if (StyleClear::Right == aNewBreakType ||
+          StyleClear::Both == aNewBreakType) {
+        breakType = StyleClear::Both;
+      }
+      break;
+    case StyleClear::Right:
+      if (StyleClear::Left == aNewBreakType ||
+          StyleClear::Both == aNewBreakType) {
+        breakType = StyleClear::Both;
+      }
+      break;
+    case StyleClear::None_:
+      if (StyleClear::Left == aNewBreakType ||
+          StyleClear::Right == aNewBreakType ||
+          StyleClear::Both == aNewBreakType) {
+        breakType = aNewBreakType;
+      }
+      break;
+    default:
+      break;
   }
   return breakType;
 }
 
 #ifdef MOZ_DUMP_PAINTING
 #include <stdio.h>
 
 static bool gDumpEventList = false;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -689,18 +689,19 @@ public:
 
   /**
    * If this frame is a placeholder for a float, then return the float,
    * otherwise return nullptr.  aPlaceholder must be a placeholder frame.
    */
   static nsIFrame* GetFloatFromPlaceholder(nsIFrame* aPlaceholder);
 
   // Combine aNewBreakType with aOrigBreakType, but limit the break types
-  // to NS_STYLE_CLEAR_LEFT, RIGHT, LEFT_AND_RIGHT.
-  static uint8_t CombineBreakType(uint8_t aOrigBreakType, uint8_t aNewBreakType);
+  // to StyleClear::Left, Right, Both.
+  static mozilla::StyleClear CombineBreakType(mozilla::StyleClear aOrigBreakType,
+                                              mozilla::StyleClear aNewBreakType);
 
   /**
    * Get the coordinates of a given DOM mouse event, relative to a given
    * frame. Works only for DOM events generated by WidgetGUIEvents.
    * @param aDOMEvent the event
    * @param aFrame the frame to make coordinates relative to
    * @return the point, or (NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE) if
    * for some reason the coordinates for the mouse are not known (e.g.,
--- a/layout/generic/BlockReflowInput.cpp
+++ b/layout/generic/BlockReflowInput.cpp
@@ -39,17 +39,17 @@ BlockReflowInput::BlockReflowInput(const
     mPresContext(aPresContext),
     mReflowInput(aReflowInput),
     mContentArea(aReflowInput.GetWritingMode()),
     mPushedFloats(nullptr),
     mOverflowTracker(nullptr),
     mBorderPadding(mReflowInput.ComputedLogicalBorderPadding()),
     mPrevBEndMargin(),
     mLineNumber(0),
-    mFloatBreakType(NS_STYLE_CLEAR_NONE),
+    mFloatBreakType(StyleClear::None_),
     mConsumedBSize(aConsumedBSize)
 {
   if (!sFloatFragmentsInsideColumnPrefCached) {
     sFloatFragmentsInsideColumnPrefCached = true;
     Preferences::AddBoolVarCache(&sFloatFragmentsInsideColumnEnabled,
                                  "layout.float-fragments-inside-column.enabled");
   }
   mFlags.mFloatFragmentsInsideColumnEnabled = sFloatFragmentsInsideColumnEnabled;
@@ -727,17 +727,17 @@ BlockReflowInput::FlowAndPlaceFloat(nsIF
 
   // Enforce CSS2 9.5.1 rule [2], i.e., make sure that a float isn't
   // ``above'' another float that preceded it in the flow.
   mBCoord = std::max(mFloatManager->GetLowestFloatTop(), mBCoord);
 
   // See if the float should clear any preceding floats...
   // XXX We need to mark this float somehow so that it gets reflowed
   // when floats are inserted before it.
-  if (NS_STYLE_CLEAR_NONE != floatDisplay->mBreakType) {
+  if (StyleClear::None_ != floatDisplay->mBreakType) {
     // XXXldb Does this handle vertical margins correctly?
     mBCoord = ClearFloats(mBCoord, floatDisplay->PhysicalBreakType(wm));
   }
     // Get the band of available space
   nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(mBCoord);
   LogicalRect adjustedAvailableSpace =
     mBlock->AdjustFloatAvailableSpace(*this, floatAvailableSpace.mRect, aFloat);
 
@@ -1075,40 +1075,40 @@ BlockReflowInput::PlaceBelowCurrentLineF
       delete fc;
       aLine->SetHadFloatPushed();
     }
     fc = next;
   }
 }
 
 nscoord
-BlockReflowInput::ClearFloats(nscoord aBCoord, uint8_t aBreakType,
+BlockReflowInput::ClearFloats(nscoord aBCoord, StyleClear aBreakType,
                                 nsIFrame *aReplacedBlock,
                                 uint32_t aFlags)
 {
 #ifdef DEBUG
   if (nsBlockFrame::gNoisyReflow) {
     nsFrame::IndentBy(stdout, nsBlockFrame::gNoiseIndent);
     printf("clear floats: in: aBCoord=%d\n", aBCoord);
   }
 #endif
 
 #ifdef NOISY_FLOAT_CLEARING
-  printf("BlockReflowInput::ClearFloats: aBCoord=%d breakType=%d\n",
-         aBCoord, aBreakType);
+  printf("BlockReflowInput::ClearFloats: aBCoord=%d breakType=%s\n",
+         aBCoord, nsLineBox::BreakTypeToString(aBreakType));
   mFloatManager->List(stdout);
 #endif
 
   if (!mFloatManager->HasAnyFloats()) {
     return aBCoord;
   }
 
   nscoord newBCoord = aBCoord;
 
-  if (aBreakType != NS_STYLE_CLEAR_NONE) {
+  if (aBreakType != StyleClear::None_) {
     newBCoord = mFloatManager->ClearFloats(newBCoord, aBreakType, aFlags);
   }
 
   if (aReplacedBlock) {
     for (;;) {
       nsFlowAreaRect floatAvailableSpace = GetFloatAvailableSpace(newBCoord);
       if (ReplacedBlockFitsInAvailSpace(aReplacedBlock, floatAvailableSpace)) {
         break;
--- a/layout/generic/BlockReflowInput.h
+++ b/layout/generic/BlockReflowInput.h
@@ -144,17 +144,17 @@ public:
   bool FlowAndPlaceFloat(nsIFrame* aFloat);
 
   void PlaceBelowCurrentLineFloats(nsFloatCacheFreeList& aFloats,
                                    nsLineBox* aLine);
 
   // Returns the first coordinate >= aBCoord that clears the
   // floats indicated by aBreakType and has enough inline size between floats
   // (or no floats remaining) to accomodate aReplacedBlock.
-  nscoord ClearFloats(nscoord aBCoord, uint8_t aBreakType,
+  nscoord ClearFloats(nscoord aBCoord, mozilla::StyleClear aBreakType,
                       nsIFrame *aReplacedBlock = nullptr,
                       uint32_t aFlags = 0);
 
   // Advances to the next band, i.e., the next horizontal stripe in
   // which there is a different set of floats.
   // Return false if it did not advance, which only happens for
   // constrained heights (and means that we should get pushed to the
   // next column/page).
@@ -366,17 +366,17 @@ public:
   nsFloatCacheFreeList mBelowCurrentLineFloats;
 
   nscoord mMinLineHeight;
 
   int32_t mLineNumber;
 
   Flags mFlags;
 
-  uint8_t mFloatBreakType;
+  StyleClear mFloatBreakType;
 
   // The amount of computed block-direction size "consumed" by previous-in-flows.
   nscoord mConsumedBSize;
 
 private:
   bool CanPlaceFloat(nscoord aFloatISize,
                      const nsFlowAreaRect& aFloatAvailableSpace);
 
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -2009,24 +2009,25 @@ nsStyleDisplay::PhysicalFloats(mozilla::
     return aWM.IsBidiLTR() ? StyleFloat::Left : StyleFloat::Right;
   }
   if (mFloat == StyleFloat::InlineEnd) {
     return aWM.IsBidiLTR() ? StyleFloat::Right : StyleFloat::Left;
   }
   return mFloat;
 }
 
-inline uint8_t
+inline mozilla::StyleClear
 nsStyleDisplay::PhysicalBreakType(mozilla::WritingMode aWM) const
 {
-  if (mBreakType == NS_STYLE_CLEAR_INLINE_START) {
-    return aWM.IsBidiLTR() ? NS_STYLE_CLEAR_LEFT : NS_STYLE_CLEAR_RIGHT;
+  using StyleClear = mozilla::StyleClear;
+  if (mBreakType == StyleClear::InlineStart) {
+    return aWM.IsBidiLTR() ? StyleClear::Left : StyleClear::Right;
   }
-  if (mBreakType == NS_STYLE_CLEAR_INLINE_END) {
-    return aWM.IsBidiLTR() ? NS_STYLE_CLEAR_RIGHT : NS_STYLE_CLEAR_LEFT;
+  if (mBreakType == StyleClear::InlineEnd) {
+    return aWM.IsBidiLTR() ? StyleClear::Right : StyleClear::Left;
   }
   return mBreakType;
 }
 
 inline bool
 nsStyleMargin::HasBlockAxisAuto(mozilla::WritingMode aWM) const
 {
   return mMargin.HasBlockAxisAuto(aWM);
--- a/layout/generic/nsBRFrame.cpp
+++ b/layout/generic/nsBRFrame.cpp
@@ -139,19 +139,19 @@ BRFrame::Reflow(nsPresContext* aPresCont
       // XXX This also fixes bug 10036!
       // Warning: nsTextControlFrame::CalculateSizeStandard depends on
       // the following line, see bug 228752.
       // The code below in AddInlinePrefISize also adds 1 appunit to width
       finalSize.ISize(wm) = 1;
     }
 
     // Return our reflow status
-    uint32_t breakType = aReflowInput.mStyleDisplay->PhysicalBreakType(wm);
-    if (NS_STYLE_CLEAR_NONE == breakType) {
-      breakType = NS_STYLE_CLEAR_LINE;
+    StyleClear breakType = aReflowInput.mStyleDisplay->PhysicalBreakType(wm);
+    if (StyleClear::None_ == breakType) {
+      breakType = StyleClear::Line;
     }
 
     aStatus = NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
       NS_INLINE_MAKE_BREAK_TYPE(breakType);
     ll->SetLineEndsInBR(true);
   }
   else {
     aStatus = NS_FRAME_COMPLETE;
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1544,17 +1544,17 @@ nsBlockFrame::ComputeFinalSize(const Ref
         std::min(blockEndEdgeOfChildren + aState.mPrevBEndMargin.get(),
                aState.mReflowInput.AvailableBSize());
     }
   }
   if (aState.mFlags.mBlockNeedsFloatManager) {
     // Include the float manager's state to properly account for the
     // block-end margin of any floated elements; e.g., inside a table cell.
     nscoord floatHeight =
-      aState.ClearFloats(blockEndEdgeOfChildren, NS_STYLE_CLEAR_BOTH,
+      aState.ClearFloats(blockEndEdgeOfChildren, StyleClear::Both,
                          nullptr, nsFloatManager::DONT_CLEAR_PUSHED_FLOATS);
     blockEndEdgeOfChildren = std::max(blockEndEdgeOfChildren, floatHeight);
   }
 
   if (NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()
       && (GetParent()->GetType() != nsGkAtoms::columnSetFrame ||
           aReflowInput.mParentReflowInput->AvailableBSize() == NS_UNCONSTRAINEDSIZE)) {
     ComputeFinalBSize(aReflowInput, &aState.mReflowStatus,
@@ -1914,24 +1914,25 @@ nsBlockFrame::PrepareResizeReflow(BlockR
       if (!line->IsBlock()) {
         printf("PrepareResizeReflow thinks line %p is %simpacted by floats\n", 
                line.get(), line->IsImpactedByFloat() ? "" : "not ");
       }
 #endif
 #ifdef DEBUG
       if (gNoisyReflow && !line->IsDirty()) {
         IndentBy(stdout, gNoiseIndent + 1);
-        printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%d/%d xmost=%d\n",
+        printf("skipped: line=%p next=%p %s %s%s%s breakTypeBefore/After=%s/%s xmost=%d\n",
            static_cast<void*>(line.get()),
            static_cast<void*>((line.next() != end_lines() ? line.next().get() : nullptr)),
            line->IsBlock() ? "block" : "inline",
            line->HasBreakAfter() ? "has-break-after " : "",
            line->HasFloats() ? "has-floats " : "",
            line->IsImpactedByFloat() ? "impacted " : "",
-           line->GetBreakTypeBefore(), line->GetBreakTypeAfter(),
+           line->BreakTypeToString(line->GetBreakTypeBefore()),
+           line->BreakTypeToString(line->GetBreakTypeAfter()),
            line->IEnd());
       }
 #endif
     }
   }
   else {
     // Mark everything dirty
     for (line_iterator line = begin_lines(), line_end = end_lines();
@@ -2024,17 +2025,17 @@ nsBlockFrame::PropagateFloatDamage(Block
         aLine->MarkDirty();
       }
     }
   }
 }
 
 static bool LineHasClear(nsLineBox* aLine) {
   return aLine->IsBlock()
-    ? (aLine->GetBreakTypeBefore() ||
+    ? (aLine->GetBreakTypeBefore() != StyleClear::None_ ||
        (aLine->mFirstChild->GetStateBits() & NS_BLOCK_HAS_CLEAR_CHILDREN) ||
        !nsBlockFrame::BlockCanIntersectFloats(aLine->mFirstChild))
     : aLine->HasFloatBreakAfter();
 }
 
 
 /**
  * Reparent a whole list of floats from aOldParent to this block.  The
@@ -2075,17 +2076,17 @@ static void DumpLine(const BlockReflowIn
 #endif
 }
 
 void
 nsBlockFrame::ReflowDirtyLines(BlockReflowInput& aState)
 {
   bool keepGoing = true;
   bool repositionViews = false; // should we really need this?
-  bool foundAnyClears = aState.mFloatBreakType != NS_STYLE_CLEAR_NONE;
+  bool foundAnyClears = aState.mFloatBreakType != StyleClear::None_;
   bool willReflowAgain = false;
 
 #ifdef DEBUG
   if (gNoisyReflow) {
     IndentBy(stdout, gNoiseIndent);
     ListTag(stdout);
     printf(": reflowing dirty lines");
     printf(" computedISize=%d\n", aState.mReflowInput.ComputedISize());
@@ -2116,17 +2117,17 @@ nsBlockFrame::ReflowDirtyLines(BlockRefl
     // recompute the carried out margin before the line if we want to
     // reflow it or if its previous margin is dirty
   bool needToRecoverState = false;
     // Float continuations were reflowed in ReflowPushedFloats
   bool reflowedFloat = mFloats.NotEmpty() &&
     (mFloats.FirstChild()->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT);
   bool lastLineMovedUp = false;
   // We save up information about BR-clearance here
-  uint8_t inlineFloatBreakType = aState.mFloatBreakType;
+  StyleClear inlineFloatBreakType = aState.mFloatBreakType;
 
   line_iterator line = begin_lines(), line_end = end_lines();
 
   // Reflow the lines that are already ours
   for ( ; line != line_end; ++line, aState.AdvanceToNextLine()) {
     DumpLine(aState, line, deltaBCoord, 0);
 #ifdef DEBUG
     AutoNoisyIndenter indent2(gNoisyReflow);
@@ -2147,22 +2148,22 @@ nsBlockFrame::ReflowDirtyLines(BlockRefl
     if (line->IsBlock() &&
         !nsBlockFrame::BlockCanIntersectFloats(line->mFirstChild)) {
       replacedBlock = line->mFirstChild;
     }
 
     // We have to reflow the line if it's a block whose clearance
     // might have changed, so detect that.
     if (!line->IsDirty() &&
-        (line->GetBreakTypeBefore() != NS_STYLE_CLEAR_NONE ||
+        (line->GetBreakTypeBefore() != StyleClear::None_ ||
          replacedBlock)) {
       nscoord curBCoord = aState.mBCoord;
       // See where we would be after applying any clearance due to
       // BRs.
-      if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
+      if (inlineFloatBreakType != StyleClear::None_) {
         curBCoord = aState.ClearFloats(curBCoord, inlineFloatBreakType);
       }
 
       nscoord newBCoord =
         aState.ClearFloats(curBCoord, line->GetBreakTypeBefore(), replacedBlock);
 
       if (line->HasClearance()) {
         // Reflow the line if it might not have clearance anymore.
@@ -2178,24 +2179,24 @@ nsBlockFrame::ReflowDirtyLines(BlockRefl
         // Reflow the line if the line might have clearance now.
         if (curBCoord != newBCoord) {
           line->MarkDirty();
         }
       }
     }
 
     // We might have to reflow a line that is after a clearing BR.
-    if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
+    if (inlineFloatBreakType != StyleClear::None_) {
       aState.mBCoord = aState.ClearFloats(aState.mBCoord, inlineFloatBreakType);
       if (aState.mBCoord != line->BStart() + deltaBCoord) {
         // SlideLine is not going to put the line where the clearance
         // put it. Reflow the line to be sure.
         line->MarkDirty();
       }
-      inlineFloatBreakType = NS_STYLE_CLEAR_NONE;
+      inlineFloatBreakType = StyleClear::None_;
     }
 
     bool previousMarginWasDirty = line->IsPreviousMarginDirty();
     if (previousMarginWasDirty) {
       // If the previous margin is dirty, reflow the current line
       line->MarkDirty();
       line->ClearPreviousMarginDirty();
     } else if (line->BEnd() + deltaBCoord > aState.mBEndEdge) {
@@ -2438,17 +2439,17 @@ nsBlockFrame::ReflowDirtyLines(BlockRefl
       // sure whether we really want to mark all lines dirty after an
       // interrupt, but until we get better at propagating float damage we
       // really do need to do it this way; see comments inside MarkLineDirty.
       MarkLineDirtyForInterrupt(line);
     }
   }
 
   // Handle BR-clearance from the last line of the block
-  if (inlineFloatBreakType != NS_STYLE_CLEAR_NONE) {
+  if (inlineFloatBreakType != StyleClear::None_) {
     aState.mBCoord = aState.ClearFloats(aState.mBCoord, inlineFloatBreakType);
   }
 
   if (needToRecoverState) {
     // Is this expensive?
     aState.ReconstructMarginBefore(line);
 
     // Update aState.mPrevChild as if we had reflowed all of the frames in
@@ -3121,22 +3122,22 @@ nsBlockFrame::ReflowBlockFrame(BlockRefl
   if (!frame) {
     NS_ASSERTION(false, "program error - unexpected empty line"); 
     return; 
   }
 
   // Prepare the block reflow engine
   nsBlockReflowContext brc(aState.mPresContext, aState.mReflowInput);
 
-  uint8_t breakType = frame->StyleDisplay()->
+  StyleClear breakType = frame->StyleDisplay()->
     PhysicalBreakType(aState.mReflowInput.GetWritingMode());
-  if (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType) {
+  if (StyleClear::None_ != aState.mFloatBreakType) {
     breakType = nsLayoutUtils::CombineBreakType(breakType,
                                                 aState.mFloatBreakType);
-    aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
+    aState.mFloatBreakType = StyleClear::None_;
   }
 
   // Clear past floats before the block if the clear style is not none
   aLine->SetBreakTypeBefore(breakType);
 
   // See if we should apply the block-start margin. If the block frame being
   // reflowed is a continuation (non-null prev-in-flow) then we don't
   // apply its block-start margin because it's not significant unless it has
@@ -3149,17 +3150,17 @@ nsBlockFrame::ReflowBlockFrame(BlockRefl
     // The HasClearance setting is only valid if ShouldApplyBStartMargin
     // returned false (in which case the block-start margin-root set our
     // clearance flag). Otherwise clear it now. We'll set it later on
     // ourselves if necessary.
     aLine->ClearHasClearance();
   }
   bool treatWithClearance = aLine->HasClearance();
 
-  bool mightClearFloats = breakType != NS_STYLE_CLEAR_NONE;
+  bool mightClearFloats = breakType != StyleClear::None_;
   nsIFrame *replacedBlock = nullptr;
   if (!nsBlockFrame::BlockCanIntersectFloats(frame)) {
     mightClearFloats = true;
     replacedBlock = frame;
   }
 
   // If our block-start margin was counted as part of some parent's block-start
   // margin collapse, and we are being speculatively reflowed assuming this
@@ -3428,17 +3429,17 @@ nsBlockFrame::ReflowBlockFrame(BlockRefl
                                                 floatAvailableSpace)) {
         // Advance to the next band.
         nscoord newBCoord = aState.mBCoord;
         if (aState.AdvanceToNextBand(floatAvailableSpace.mRect, &newBCoord)) {
           advanced = true;
         }
         // ClearFloats might be able to advance us further once we're there.
         aState.mBCoord =
-          aState.ClearFloats(newBCoord, NS_STYLE_CLEAR_NONE, replacedBlock);
+          aState.ClearFloats(newBCoord, StyleClear::None_, replacedBlock);
         // Start over with a new available space rect at the new height.
         floatAvailableSpace =
           aState.GetFloatAvailableSpaceWithState(aState.mBCoord,
                                                  &floatManagerState);
       }
 
       LogicalRect oldAvailSpace(availSpace);
       aState.ComputeBlockAvailSpace(frame, floatAvailableSpace,
@@ -4049,17 +4050,17 @@ nsBlockFrame::DoReflowInlineFrames(Block
 }
 
 /**
  * Reflow an inline frame. The reflow status is mapped from the frames
  * reflow status to the lines reflow status (not to our reflow status).
  * The line reflow status is simple: true means keep placing frames
  * on the line; false means don't (the line is done). If the line
  * has some sort of breaking affect then aLine's break-type will be set
- * to something other than NS_STYLE_CLEAR_NONE.
+ * to something other than StyleClear::None_.
  */
 void
 nsBlockFrame::ReflowInlineFrame(BlockReflowInput& aState,
                                 nsLineLayout& aLineLayout,
                                 line_iterator aLine,
                                 nsIFrame* aFrame,
                                 LineReflowStatus* aLineReflowStatus)
 {
@@ -4106,28 +4107,27 @@ nsBlockFrame::ReflowInlineFrame(BlockRef
       see bug 22496
    */
 
   // Process the child frames reflow status. There are 5 cases:
   // complete, not-complete, break-before, break-after-complete,
   // break-after-not-complete. There are two situations: we are a
   // block or we are an inline. This makes a total of 10 cases
   // (fortunately, there is some overlap).
-  aLine->SetBreakTypeAfter(NS_STYLE_CLEAR_NONE);
-  if (NS_INLINE_IS_BREAK(frameReflowStatus) || 
-      (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType)) {
+  aLine->SetBreakTypeAfter(StyleClear::None_);
+  if (NS_INLINE_IS_BREAK(frameReflowStatus) ||
+      StyleClear::None_ != aState.mFloatBreakType) {
     // Always abort the line reflow (because a line break is the
     // minimal amount of break we do).
     *aLineReflowStatus = LINE_REFLOW_STOP;
 
     // XXX what should aLine's break-type be set to in all these cases?
-    uint8_t breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
-    NS_ASSERTION((NS_STYLE_CLEAR_NONE != breakType) || 
-                 (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType), "bad break type");
-    NS_ASSERTION(NS_STYLE_CLEAR_MAX >= breakType, "invalid break type");
+    StyleClear breakType = NS_INLINE_GET_BREAK_TYPE(frameReflowStatus);
+    MOZ_ASSERT(StyleClear::None_ != breakType ||
+               StyleClear::None_ != aState.mFloatBreakType, "bad break type");
 
     if (NS_INLINE_IS_BREAK_BEFORE(frameReflowStatus)) {
       // Break-before cases.
       if (aFrame == aLine->mFirstChild) {
         // If we break before the first frame on the line then we must
         // be trying to place content where there's no room (e.g. on a
         // line with wide floats). Inform the caller to reflow the
         // line after skipping past a float.
@@ -4142,28 +4142,28 @@ nsBlockFrame::ReflowInlineFrame(BlockRef
         // was pushed, then mark the line as having word wrapped. We need to
         // know that if we're shrink wrapping our width
         if (pushedFrame) {
           aLine->SetLineWrapped(true);
         }
       }
     }
     else {
-      // If a float split and its prev-in-flow was followed by a <BR>, then combine 
-      // the <BR>'s break type with the inline's break type (the inline will be the very 
+      // If a float split and its prev-in-flow was followed by a <BR>, then combine
+      // the <BR>'s break type with the inline's break type (the inline will be the very
       // next frame after the split float).
-      if (NS_STYLE_CLEAR_NONE != aState.mFloatBreakType) {
+      if (StyleClear::None_ != aState.mFloatBreakType) {
         breakType = nsLayoutUtils::CombineBreakType(breakType,
                                                     aState.mFloatBreakType);
-        aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
+        aState.mFloatBreakType = StyleClear::None_;
       }
       // Break-after cases
-      if (breakType == NS_STYLE_CLEAR_LINE) {
+      if (breakType == StyleClear::Line) {
         if (!aLineLayout.GetLineEndsInBR()) {
-          breakType = NS_STYLE_CLEAR_NONE;
+          breakType = StyleClear::None_;
         }
       }
       aLine->SetBreakTypeAfter(breakType);
       if (NS_FRAME_IS_COMPLETE(frameReflowStatus)) {
         // Split line, but after the frame just reflowed
         SplitLine(aState, aLineLayout, aLine, aFrame->GetNextSibling(), aLineReflowStatus);
 
         if (NS_INLINE_IS_BREAK_AFTER(frameReflowStatus) &&
@@ -6221,29 +6221,29 @@ nsBlockFrame::ReflowFloat(BlockReflowInp
                     nsDidReflowStatus::FINISHED);
 
 #ifdef NOISY_FLOAT
   printf("end ReflowFloat %p, sized to %d,%d\n",
          aFloat, metrics.Width(), metrics.Height());
 #endif
 }
 
-uint8_t
+StyleClear
 nsBlockFrame::FindTrailingClear()
 {
   // find the break type of the last line
   for (nsIFrame* b = this; b; b = b->GetPrevInFlow()) {
     nsBlockFrame* block = static_cast<nsBlockFrame*>(b);
     line_iterator endLine = block->end_lines();
     if (endLine != block->begin_lines()) {
       --endLine;
       return endLine->GetBreakTypeAfter();
     }
   }
-  return NS_STYLE_CLEAR_NONE;
+  return StyleClear::None_;
 }
 
 void
 nsBlockFrame::ReflowPushedFloats(BlockReflowInput& aState,
                                  nsOverflowAreas&    aOverflowAreas,
                                  nsReflowStatus&     aStatus)
 {
   // Pushed floats live at the start of our float list; see comment
@@ -6302,17 +6302,17 @@ nsBlockFrame::ReflowPushedFloats(BlockRe
       // We didn't push |f| so its next-sibling is next.
       next = f->GetNextSibling();
       prev = f;
     } // else: we did push |f| so |prev|'s new next-sibling is next.
     f = next;
   }
 
   // If there are continued floats, then we may need to continue BR clearance
-  if (0 != aState.ClearFloats(0, NS_STYLE_CLEAR_BOTH)) {
+  if (0 != aState.ClearFloats(0, StyleClear::Both)) {
     nsBlockFrame* prevBlock = static_cast<nsBlockFrame*>(GetPrevInFlow());
     if (prevBlock) {
       aState.mFloatBreakType = prevBlock->FindTrailingClear();
     }
   }
 }
 
 void
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -571,17 +571,17 @@ protected:
   /** Reflow pushed floats
    */
   void ReflowPushedFloats(BlockReflowInput& aState,
                           nsOverflowAreas&    aOverflowAreas,
                           nsReflowStatus&     aStatus);
 
   /** Find any trailing BR clear from the last line of the block (or its PIFs)
    */
-  uint8_t FindTrailingClear();
+  mozilla::StyleClear FindTrailingClear();
 
   /**
    * Remove a float from our float list.
    */
   void RemoveFloat(nsIFrame* aFloat);
   /**
    * Remove a float from the float cache for the line its placeholder is on.
    */
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -163,17 +163,17 @@ nsBlockReflowContext::ComputeCollapsedBS
           {
             LogicalSize availSpace =
               outerReflowInput->ComputedSize(kid->GetWritingMode());
             ReflowInput innerReflowInput(prescontext,
                                                *outerReflowInput, kid,
                                                availSpace);
             // Record that we're being optimistic by assuming the kid
             // has no clearance
-            if (kid->StyleDisplay()->mBreakType != NS_STYLE_CLEAR_NONE ||
+            if (kid->StyleDisplay()->mBreakType != StyleClear::None_ ||
                 !nsBlockFrame::BlockCanIntersectFloats(kid)) {
               *aMayNeedRetry = true;
             }
             if (ComputeCollapsedBStartMargin(innerReflowInput, aMargin,
                                              aClearanceFrame, aMayNeedRetry,
                                              &isEmpty)) {
               line->MarkDirty();
               dirtiedLine = true;
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -473,59 +473,59 @@ nsFloatManager::List(FILE* out) const
                    fi.LineLeft(), fi.BStart(), fi.ISize(), fi.BSize(),
                    fi.mLeftBEnd, fi.mRightBEnd);
   }
   return NS_OK;
 }
 #endif
 
 nscoord
-nsFloatManager::ClearFloats(nscoord aBCoord, uint8_t aBreakType,
+nsFloatManager::ClearFloats(nscoord aBCoord, StyleClear aBreakType,
                             uint32_t aFlags) const
 {
   if (!(aFlags & DONT_CLEAR_PUSHED_FLOATS) && ClearContinues(aBreakType)) {
     return nscoord_MAX;
   }
   if (!HasAnyFloats()) {
     return aBCoord;
   }
 
   nscoord blockEnd = aBCoord + mBlockStart;
 
   const FloatInfo &tail = mFloats[mFloats.Length() - 1];
   switch (aBreakType) {
-    case NS_STYLE_CLEAR_BOTH:
+    case StyleClear::Both:
       blockEnd = std::max(blockEnd, tail.mLeftBEnd);
       blockEnd = std::max(blockEnd, tail.mRightBEnd);
       break;
-    case NS_STYLE_CLEAR_LEFT:
+    case StyleClear::Left:
       blockEnd = std::max(blockEnd, tail.mLeftBEnd);
       break;
-    case NS_STYLE_CLEAR_RIGHT:
+    case StyleClear::Right:
       blockEnd = std::max(blockEnd, tail.mRightBEnd);
       break;
     default:
       // Do nothing
       break;
   }
 
   blockEnd -= mBlockStart;
 
   return blockEnd;
 }
 
 bool
-nsFloatManager::ClearContinues(uint8_t aBreakType) const
+nsFloatManager::ClearContinues(StyleClear aBreakType) const
 {
   return ((mPushedLeftFloatPastBreak || mSplitLeftFloatAcrossBreak) &&
-          (aBreakType == NS_STYLE_CLEAR_BOTH ||
-           aBreakType == NS_STYLE_CLEAR_LEFT)) ||
+          (aBreakType == StyleClear::Both ||
+           aBreakType == StyleClear::Left)) ||
          ((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
-          (aBreakType == NS_STYLE_CLEAR_BOTH ||
-           aBreakType == NS_STYLE_CLEAR_RIGHT));
+          (aBreakType == StyleClear::Both ||
+           aBreakType == StyleClear::Right));
 }
 
 /////////////////////////////////////////////////////////////////////////////
 // FloatInfo
 
 nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
                                      nscoord aLineLeft, nscoord aBStart,
                                      nscoord aISize, nscoord aBSize)
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -266,24 +266,24 @@ public:
    *
    * Both aBCoord and the result are relative to the current translation.
    */
   enum {
     // Tell ClearFloats not to push to nscoord_MAX when floats have been
     // pushed to the next page/column.
     DONT_CLEAR_PUSHED_FLOATS = (1<<0)
   };
-  nscoord ClearFloats(nscoord aBCoord, uint8_t aBreakType,
+  nscoord ClearFloats(nscoord aBCoord, mozilla::StyleClear aBreakType,
                       uint32_t aFlags = 0) const;
 
   /**
    * Checks if clear would pass into the floats' BFC's next-in-flow,
    * i.e. whether floats affecting this clear have continuations.
    */
-  bool ClearContinues(uint8_t aBreakType) const;
+  bool ClearContinues(mozilla::StyleClear aBreakType) const;
 
   void AssertStateMatches(SavedState *aState) const
   {
     NS_ASSERTION(aState->mLineLeft == mLineLeft &&
                  aState->mBlockStart == mBlockStart &&
                  aState->mPushedLeftFloatPastBreak ==
                    mPushedLeftFloatPastBreak &&
                  aState->mPushedRightFloatPastBreak ==
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -4498,29 +4498,29 @@ nsIFrame::InlinePrefISizeData::ForceBrea
             // preferred widths accumulated for floats that have not yet
             // been cleared past
             floats_cur_left = 0,
             floats_cur_right = 0;
 
     for (uint32_t i = 0, i_end = mFloats.Length(); i != i_end; ++i) {
       const FloatInfo& floatInfo = mFloats[i];
       const nsStyleDisplay* floatDisp = floatInfo.Frame()->StyleDisplay();
-      uint8_t breakType = floatDisp->PhysicalBreakType(mLineContainerWM);
-      if (breakType == NS_STYLE_CLEAR_LEFT ||
-          breakType == NS_STYLE_CLEAR_RIGHT ||
-          breakType == NS_STYLE_CLEAR_BOTH) {
+      StyleClear breakType = floatDisp->PhysicalBreakType(mLineContainerWM);
+      if (breakType == StyleClear::Left ||
+          breakType == StyleClear::Right ||
+          breakType == StyleClear::Both) {
         nscoord floats_cur = NSCoordSaturatingAdd(floats_cur_left,
                                                   floats_cur_right);
         if (floats_cur > floats_done) {
           floats_done = floats_cur;
         }
-        if (breakType != NS_STYLE_CLEAR_RIGHT) {
+        if (breakType != StyleClear::Right) {
           floats_cur_left = 0;
         }
-        if (breakType != NS_STYLE_CLEAR_LEFT) {
+        if (breakType != StyleClear::Left) {
           floats_cur_right = 0;
         }
       }
 
       StyleFloat floatStyle = floatDisp->PhysicalFloats(mLineContainerWM);
       nscoord& floats_cur =
         floatStyle == StyleFloat::Left ? floats_cur_left : floats_cur_right;
       nscoord floatWidth = floatInfo.Width();
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -280,35 +280,36 @@ typedef uint32_t nsReflowStatus;
   (0 != ((_status) & NS_INLINE_BREAK))
 
 #define NS_INLINE_IS_BREAK_AFTER(_status) \
   (0 != ((_status) & NS_INLINE_BREAK_AFTER))
 
 #define NS_INLINE_IS_BREAK_BEFORE(_status) \
   (NS_INLINE_BREAK == ((_status) & (NS_INLINE_BREAK|NS_INLINE_BREAK_AFTER)))
 
-#define NS_INLINE_GET_BREAK_TYPE(_status) (((_status) >> 12) & 0xF)
-
-#define NS_INLINE_MAKE_BREAK_TYPE(_type)  ((_type) << 12)
+#define NS_INLINE_GET_BREAK_TYPE(_status) \
+  (static_cast<StyleClear>(((_status) >> 12) & 0xF))
+
+#define NS_INLINE_MAKE_BREAK_TYPE(_type)  (static_cast<int>(_type) << 12)
 
 // Construct a line-break-before status. Note that there is no
 // completion status for a line-break before because we *know* that
 // the frame will be reflowed later and hence its current completion
 // status doesn't matter.
 #define NS_INLINE_LINE_BREAK_BEFORE()                                   \
   (NS_INLINE_BREAK | NS_INLINE_BREAK_BEFORE |                           \
-   NS_INLINE_MAKE_BREAK_TYPE(NS_STYLE_CLEAR_LINE))
+   NS_INLINE_MAKE_BREAK_TYPE(StyleClear::Line))
 
 // Take a completion status and add to it the desire to have a
 // line-break after. For this macro we do need the completion status
 // because the user of the status will need to know whether to
 // continue the frame or not.
 #define NS_INLINE_LINE_BREAK_AFTER(_completionStatus)                   \
   ((_completionStatus) | NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |      \
-   NS_INLINE_MAKE_BREAK_TYPE(NS_STYLE_CLEAR_LINE))
+   NS_INLINE_MAKE_BREAK_TYPE(StyleClear::Line))
 
 // A frame is "truncated" if the part of the frame before the first
 // possible break point was unable to fit in the available vertical
 // space.  Therefore, the entire frame should be moved to the next page.
 // A frame that begins at the top of the page must never be "truncated".
 // Doing so would likely cause an infinite loop.
 #define NS_FRAME_TRUNCATED  0x0010
 #define NS_FRAME_IS_TRUNCATED(status) \
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -43,23 +43,19 @@ nsLineBox::nsLineBox(nsIFrame* aFrame, i
   ++ctorCount;
   NS_ASSERTION(!aIsBlock || aCount == 1, "Blocks must have exactly one child");
   nsIFrame* f = aFrame;
   for (int32_t n = aCount; n > 0; f = f->GetNextSibling(), --n) {
     NS_ASSERTION(aIsBlock == f->IsBlockOutside(),
                  "wrong kind of child frame");
   }
 #endif
-
-  static_assert(NS_STYLE_CLEAR_MAX <= 15,
+  static_assert(static_cast<int>(StyleClear::Max) <= 15,
                 "FlagBits needs more bits to store the full range of "
                 "break type ('clear') values");
-#if NS_STYLE_CLEAR_NONE > 0
-  mFlags.mBreakType = NS_STYLE_CLEAR_NONE;
-#endif
   mChildCount = aCount;
   MarkDirty();
   mFlags.mBlock = aIsBlock;
 }
 
 nsLineBox::~nsLineBox()
 {
   MOZ_COUNT_DTOR(nsLineBox);
@@ -190,27 +186,29 @@ ListFloats(FILE* out, const char* aPrefi
     else {
       str += "\n###!!! NULL out-of-flow frame";
     }
     fprintf_stderr(out, "%s\n", str.get());
     fc = fc->Next();
   }
 }
 
-const char *
-BreakTypeToString(uint8_t aBreakType)
+const char*
+nsLineBox::BreakTypeToString(StyleClear aBreakType) const
 {
   switch (aBreakType) {
-  case NS_STYLE_CLEAR_NONE: return "nobr";
-  case NS_STYLE_CLEAR_LEFT: return "leftbr";
-  case NS_STYLE_CLEAR_RIGHT: return "rightbr";
-  case NS_STYLE_CLEAR_BOTH: return "leftbr+rightbr";
-  case NS_STYLE_CLEAR_LINE: return "linebr";
-  default:
-    break;
+    case StyleClear::None_: return "nobr";
+    case StyleClear::Left: return "leftbr";
+    case StyleClear::Right: return "rightbr";
+    case StyleClear::InlineStart: return "inlinestartbr";
+    case StyleClear::InlineEnd: return "inlineendbr";
+    case StyleClear::Both: return "leftbr+rightbr";
+    case StyleClear::Line: return "linebr";
+    default:
+      break;
   }
   return "unknown";
 }
 
 char*
 nsLineBox::StateToString(char* aBuf, int32_t aBufSize) const
 {
   snprintf(aBuf, aBufSize, "%s,%s,%s,%s,%s,before:%s,after:%s[0x%x]",
@@ -280,19 +278,17 @@ nsLineBox::List(FILE* out, const char* a
   }
 
   if (HasFloats()) {
     fprintf_stderr(out, "%s> floats <\n", aPrefix);
     ListFloats(out, pfx.get(), mInlineData->mFloats);
   }
   fprintf_stderr(out, "%s>\n", aPrefix);
 }
-#endif
 
-#ifdef DEBUG
 nsIFrame*
 nsLineBox::LastChild() const
 {
   nsIFrame* frame = mFirstChild;
   int32_t n = GetChildCount() - 1;
   while (--n >= 0) {
     frame = frame->GetNextSibling();
   }
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -138,17 +138,16 @@ public:
 protected:
   nsFloatCache* mTail;
 
   friend class nsFloatCacheList;
 };
 
 //----------------------------------------------------------------------
 
-#define LINE_MAX_BREAK_TYPE  ((1 << 4) - 1)
 #define LINE_MAX_CHILD_COUNT INT32_MAX
 
 /**
  * Function to create a line box and initialize it with a single frame.
  * The allocation is infallible.
  * If the frame was moved from another line then you're responsible
  * for notifying that line using NoteFrameRemoved().  Alternatively,
  * it's better to use the next function that does that for you in an
@@ -389,47 +388,48 @@ public:
       --mChildCount;
     }
   }
 
   // mBreakType value
   // Break information is applied *before* the line if the line is a block,
   // or *after* the line if the line is an inline. Confusing, I know, but
   // using different names should help.
+  using StyleClear = mozilla::StyleClear;
   bool HasBreakBefore() const {
-    return IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
+    return IsBlock() && StyleClear::None_ != BreakType();
   }
-  void SetBreakTypeBefore(uint8_t aBreakType) {
-    NS_ASSERTION(IsBlock(), "Only blocks have break-before");
-    NS_ASSERTION(aBreakType == NS_STYLE_CLEAR_NONE ||
-                 aBreakType == NS_STYLE_CLEAR_LEFT ||
-                 aBreakType == NS_STYLE_CLEAR_RIGHT ||
-                 aBreakType == NS_STYLE_CLEAR_BOTH,
-                 "Only float break types are allowed before a line");
-    mFlags.mBreakType = aBreakType;
+  void SetBreakTypeBefore(StyleClear aBreakType) {
+    MOZ_ASSERT(IsBlock(), "Only blocks have break-before");
+    MOZ_ASSERT(aBreakType == StyleClear::None_ ||
+               aBreakType == StyleClear::Left ||
+               aBreakType == StyleClear::Right ||
+               aBreakType == StyleClear::Both,
+               "Only float break types are allowed before a line");
+    mFlags.mBreakType = static_cast<int>(aBreakType);
   }
-  uint8_t GetBreakTypeBefore() const {
-    return IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
+  StyleClear GetBreakTypeBefore() const {
+    return IsBlock() ? BreakType() : StyleClear::None_;
   }
 
   bool HasBreakAfter() const {
-    return !IsBlock() && NS_STYLE_CLEAR_NONE != mFlags.mBreakType;
+    return !IsBlock() && StyleClear::None_ != BreakType();
   }
-  void SetBreakTypeAfter(uint8_t aBreakType) {
-    NS_ASSERTION(!IsBlock(), "Only inlines have break-after");
-    NS_ASSERTION(aBreakType <= LINE_MAX_BREAK_TYPE, "bad break type");
-    mFlags.mBreakType = aBreakType;
+  void SetBreakTypeAfter(StyleClear aBreakType) {
+    MOZ_ASSERT(!IsBlock(), "Only inlines have break-after");
+    mFlags.mBreakType = static_cast<int>(aBreakType);
   }
   bool HasFloatBreakAfter() const {
-    return !IsBlock() && (NS_STYLE_CLEAR_LEFT == mFlags.mBreakType ||
-                          NS_STYLE_CLEAR_RIGHT == mFlags.mBreakType ||
-                          NS_STYLE_CLEAR_BOTH == mFlags.mBreakType);
+    return !IsBlock() &&
+           (StyleClear::Left == BreakType() ||
+            StyleClear::Right == BreakType() ||
+            StyleClear::Both == BreakType());
   }
-  uint8_t GetBreakTypeAfter() const {
-    return !IsBlock() ? mFlags.mBreakType : NS_STYLE_CLEAR_NONE;
+  StyleClear GetBreakTypeAfter() const {
+    return !IsBlock() ? BreakType() : StyleClear::None_;
   }
 
   // mCarriedOutBEndMargin value
   nsCollapsingMargin GetCarriedOutBEndMargin() const;
   // Returns true if the margin changed
   bool SetCarriedOutBEndMargin(nsCollapsingMargin aValue);
 
   // mFloats
@@ -567,16 +567,17 @@ public:
   // list).
   static bool RFindLineContaining(nsIFrame* aFrame,
                                     const nsLineList_iterator& aBegin,
                                     nsLineList_iterator& aEnd,
                                     nsIFrame* aLastFrameBeforeEnd,
                                     int32_t* aFrameIndexInLine);
 
 #ifdef DEBUG_FRAME_DUMP
+  const char* BreakTypeToString(StyleClear aBreakType) const;
   char* StateToString(char* aBuf, int32_t aBufSize) const;
 
   void List(FILE* out, int32_t aIndent, uint32_t aFlags = 0) const;
   void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const;
   nsIFrame* LastChild() const;
 #endif
 
 private:
@@ -658,17 +659,19 @@ public:
   struct FlagBits {
     uint32_t mDirty : 1;
     uint32_t mPreviousMarginDirty : 1;
     uint32_t mHasClearance : 1;
     uint32_t mBlock : 1;
     uint32_t mImpactedByFloat : 1;
     uint32_t mLineWrapped: 1;
     uint32_t mInvalidateTextRuns : 1;
-    uint32_t mResizeReflowOptimizationDisabled: 1;  // default 0 = means that the opt potentially applies to this line. 1 = never skip reflowing this line for a resize reflow
+    // default 0 = means that the opt potentially applies to this line.
+    // 1 = never skip reflowing this line for a resize reflow
+    uint32_t mResizeReflowOptimizationDisabled: 1;
     uint32_t mEmptyCacheValid: 1;
     uint32_t mEmptyCacheState: 1;
     // mHasBullet indicates that this is an inline line whose block's
     // bullet is adjacent to this line and non-empty.
     uint32_t mHasBullet : 1;
     // Indicates that this line *may* have a placeholder for a float
     // that was pushed to a later column or page.
     uint32_t mHadFloatPushed : 1;
@@ -694,21 +697,27 @@ public:
   struct ExtraInlineData : public ExtraData {
     explicit ExtraInlineData(const nsRect& aBounds) : ExtraData(aBounds) {
     }
     nsFloatCacheList mFloats;
   };
 
 protected:
   nscoord mAscent;           // see |SetAscent| / |GetAscent|
+  static_assert(sizeof(FlagBits) <= sizeof(uint32_t),
+                "size of FlagBits should not be larger than size of uint32_t");
   union {
     uint32_t mAllFlags;
     FlagBits mFlags;
   };
 
+  StyleClear BreakType() const {
+    return static_cast<StyleClear>(mFlags.mBreakType);
+  };
+
   union {
     ExtraData* mData;
     ExtraBlockData* mBlockData;
     ExtraInlineData* mInlineData;
   };
 
   void Cleanup();
   void MaybeFreeData();
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -444,17 +444,17 @@ public:
   void SetNormalValue();
   void SetAutoValue();
   void SetNoneValue();
   void SetIntValue(int32_t aInt, Unit aUnit);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   void SetIntValue(T aInt, Unit aUnit)
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
                   "aValue must be an enum that fits within mValue.mInt");
     SetIntValue(static_cast<int32_t>(aInt), aUnit);
   }
   void SetCoordValue(nscoord aCoord);
   void SetPercentValue(float aPercent);
   void SetFloatValue(float aFloat);
   void SetColorValue(nscolor aColor);
   void SetCurrentColorValue();
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1053,23 +1053,23 @@ const KTableEntry nsCSSProps::kCaptionSi
   { eCSSKeyword_bottom,               NS_STYLE_CAPTION_SIDE_BOTTOM },
   { eCSSKeyword_left,                 NS_STYLE_CAPTION_SIDE_LEFT },
   { eCSSKeyword_top_outside,          NS_STYLE_CAPTION_SIDE_TOP_OUTSIDE },
   { eCSSKeyword_bottom_outside,       NS_STYLE_CAPTION_SIDE_BOTTOM_OUTSIDE },
   { eCSSKeyword_UNKNOWN,              -1 }
 };
 
 KTableEntry nsCSSProps::kClearKTable[] = {
-  { eCSSKeyword_none,         NS_STYLE_CLEAR_NONE },
-  { eCSSKeyword_left,         NS_STYLE_CLEAR_LEFT },
-  { eCSSKeyword_right,        NS_STYLE_CLEAR_RIGHT },
-  { eCSSKeyword_inline_start, NS_STYLE_CLEAR_INLINE_START },
-  { eCSSKeyword_inline_end,   NS_STYLE_CLEAR_INLINE_END },
-  { eCSSKeyword_both,         NS_STYLE_CLEAR_BOTH },
-  { eCSSKeyword_UNKNOWN,      -1 }
+  { eCSSKeyword_none, StyleClear::None_ },
+  { eCSSKeyword_left, StyleClear::Left },
+  { eCSSKeyword_right, StyleClear::Right },
+  { eCSSKeyword_inline_start, StyleClear::InlineStart },
+  { eCSSKeyword_inline_end, StyleClear::InlineEnd },
+  { eCSSKeyword_both, StyleClear::Both },
+  { eCSSKeyword_UNKNOWN, -1 }
 };
 
 // See also kContextPatternKTable for SVG paint-specific values
 const KTableEntry nsCSSProps::kColorKTable[] = {
   { eCSSKeyword_activeborder, LookAndFeel::eColorID_activeborder },
   { eCSSKeyword_activecaption, LookAndFeel::eColorID_activecaption },
   { eCSSKeyword_appworkspace, LookAndFeel::eColorID_appworkspace },
   { eCSSKeyword_background, LookAndFeel::eColorID_background },
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -14,16 +14,17 @@
 #include <limits>
 #include <type_traits>
 #include "nsString.h"
 #include "nsCSSPropertyID.h"
 #include "nsStyleStructFwd.h"
 #include "nsCSSKeywords.h"
 #include "mozilla/CSSEnabledState.h"
 #include "mozilla/UseCounter.h"
+#include "mozilla/EnumTypeTraits.h"
 
 // Length of the "--" prefix on custom names (such as custom property names,
 // and, in the future, custom media query names).
 #define CSS_CUSTOM_NAME_PREFIX_LENGTH 2
 
 // Flags for ParseVariant method
 #define VARIANT_KEYWORD         0x000001  // K
 #define VARIANT_LENGTH          0x000002  // L
@@ -322,34 +323,16 @@ enum nsStyleAnimType {
 
   // discrete values
   eStyleAnimType_Discrete,
 
   // property not animatable
   eStyleAnimType_None
 };
 
-namespace mozilla {
-
-// Type trait that determines whether the integral or enum type Type can fit
-// within the integral type Storage without loss.
-template<typename T, typename Storage>
-struct IsEnumFittingWithin
-  : IntegralConstant<
-      bool,
-      std::is_integral<Storage>::value &&
-      std::numeric_limits<typename std::underlying_type<T>::type>::min() >=
-        std::numeric_limits<Storage>::min() &&
-      std::numeric_limits<typename std::underlying_type<T>::type>::max() <=
-        std::numeric_limits<Storage>::max()
-    >
-{};
-
-} // namespace mozilla
-
 class nsCSSProps {
 public:
   typedef mozilla::CSSEnabledState EnabledState;
 
   struct KTableEntry
   {
     // KTableEntry objects can be initialized either with an int16_t value
     // or a value of an enumeration type that can fit within an int16_t.
@@ -361,17 +344,17 @@ public:
     }
 
     template<typename T,
              typename = typename std::enable_if<std::is_enum<T>::value>::type>
     KTableEntry(nsCSSKeyword aKeyword, T aValue)
       : mKeyword(aKeyword)
       , mValue(static_cast<int16_t>(aValue))
     {
-      static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+      static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                     "aValue must be an enum that fits within mValue");
     }
 
     nsCSSKeyword mKeyword;
     int16_t mValue;
   };
 
   static void AddRefTable(void);
@@ -447,29 +430,29 @@ public:
   // Return |eCSSKeyword_UNKNOWN| if not found.
   static nsCSSKeyword ValueToKeywordEnum(int32_t aValue,
                                          const KTableEntry aTable[]);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   static nsCSSKeyword ValueToKeywordEnum(T aValue,
                                          const KTableEntry aTable[])
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                   "aValue must be an enum that fits within KTableEntry::mValue");
     return ValueToKeywordEnum(static_cast<int16_t>(aValue), aTable);
   }
   // Ditto but as a string, return "" when not found.
   static const nsAFlatCString& ValueToKeyword(int32_t aValue,
                                               const KTableEntry aTable[]);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   static const nsAFlatCString& ValueToKeyword(T aValue,
                                               const KTableEntry aTable[])
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int16_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int16_t>::value,
                   "aValue must be an enum that fits within KTableEntry::mValue");
     return ValueToKeyword(static_cast<int16_t>(aValue), aTable);
   }
 
   static const nsStyleStructID kSIDTable[eCSSProperty_COUNT_no_shorthands];
   static const KTableEntry* const kKeywordTableTable[eCSSProperty_COUNT_no_shorthands];
   static const nsStyleAnimType kAnimTypeTable[eCSSProperty_COUNT_no_shorthands];
   static const ptrdiff_t
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -753,17 +753,17 @@ private:
   void DoReset();
 
 public:
   void SetIntValue(int32_t aValue, nsCSSUnit aUnit);
   template<typename T,
            typename = typename std::enable_if<std::is_enum<T>::value>::type>
   void SetIntValue(T aValue, nsCSSUnit aUnit)
   {
-    static_assert(mozilla::IsEnumFittingWithin<T, int32_t>::value,
+    static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
                   "aValue must be an enum that fits within mValue.mInt");
     SetIntValue(static_cast<int32_t>(aValue), aUnit);
   }
   void SetPercentValue(float aValue);
   void SetFloatValue(float aValue, nsCSSUnit aUnit);
   void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
   void SetColorValue(nscolor aValue);
   void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1337,16 +1337,17 @@ struct SetEnumValueHelper
   }
 
   DEFINE_ENUM_CLASS_SETTER(StyleBoxAlign, Stretch, End)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxDecorationBreak, Slice, Clone)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxDirection, Normal, Reverse)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxOrient, Horizontal, Vertical)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxPack, Start, Justify)
   DEFINE_ENUM_CLASS_SETTER(StyleBoxSizing, Content, Border)
+  DEFINE_ENUM_CLASS_SETTER(StyleClear, None_, Both)
   DEFINE_ENUM_CLASS_SETTER(StyleFillRule, Nonzero, Evenodd)
   DEFINE_ENUM_CLASS_SETTER(StyleFloat, None_, InlineEnd)
   DEFINE_ENUM_CLASS_SETTER(StyleFloatEdge, ContentBox, MarginBox)
   DEFINE_ENUM_CLASS_SETTER(StyleUserFocus, None_, SelectMenu)
   DEFINE_ENUM_CLASS_SETTER(StyleUserSelect, None_, MozText)
 #ifdef MOZ_XUL
   DEFINE_ENUM_CLASS_SETTER(StyleDisplay, None_, Popup)
 #else
@@ -6039,17 +6040,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
     // an aStartStruct for some other elements.
     conditions.SetUncacheable();
   }
 
   // clear: enum, inherit, initial
   SetValue(*aRuleData->ValueForClear(), display->mBreakType, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INITIAL,
            parentDisplay->mBreakType,
-           NS_STYLE_CLEAR_NONE);
+           StyleClear::None_);
 
   // temp fix for bug 24000
   // Map 'auto' and 'avoid' to false, and 'always', 'left', and
   // 'right' to true.
   // "A conforming user agent may interpret the values 'left' and
   // 'right' as 'always'." - CSS2.1, section 13.3.1
   const nsCSSValue* breakBeforeValue = aRuleData->ValueForPageBreakBefore();
   if (eCSSUnit_Enumerated == breakBeforeValue->GetUnit()) {
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -103,16 +103,30 @@ enum class StyleBoxSizing : uint8_t {
   Border
 };
 
 // box-shadow
 enum class StyleBoxShadowType : uint8_t {
   Inset,
 };
 
+// clear
+enum class StyleClear : uint8_t {
+  None_ = 0,
+  Left,
+  Right,
+  InlineStart,
+  InlineEnd,
+  Both,
+  // StyleClear::Line can be added to one of the other values in layout
+  // so it needs to use a bit value that none of the other values can have.
+  Line = 8,
+  Max = 13  // Max = (Both | Line)
+};
+
 // clip-path geometry box
 enum class StyleClipPathGeometryBox : uint8_t {
   NoBox,
   Content,
   Padding,
   Border,
   Margin,
   Fill,
@@ -398,28 +412,16 @@ enum class FillMode : uint32_t;
 #define NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH    0
 #define NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT     1
 #define NS_STYLE_BORDER_IMAGE_REPEAT_ROUND      2
 #define NS_STYLE_BORDER_IMAGE_REPEAT_SPACE      3
 
 #define NS_STYLE_BORDER_IMAGE_SLICE_NOFILL      0
 #define NS_STYLE_BORDER_IMAGE_SLICE_FILL        1
 
-// See nsStyleDisplay
-#define NS_STYLE_CLEAR_NONE                     0
-#define NS_STYLE_CLEAR_LEFT                     1
-#define NS_STYLE_CLEAR_RIGHT                    2
-#define NS_STYLE_CLEAR_INLINE_START             3
-#define NS_STYLE_CLEAR_INLINE_END               4
-#define NS_STYLE_CLEAR_BOTH                     5
-#define NS_STYLE_CLEAR_LINE                     8
-// @note NS_STYLE_CLEAR_LINE can be added to one of the other values in layout
-// so it needs to use a bit value that none of the other values can have.
-#define NS_STYLE_CLEAR_MAX (NS_STYLE_CLEAR_LINE | NS_STYLE_CLEAR_BOTH)
-
 // See nsStyleContent
 #define NS_STYLE_CONTENT_OPEN_QUOTE             0
 #define NS_STYLE_CONTENT_CLOSE_QUOTE            1
 #define NS_STYLE_CONTENT_NO_OPEN_QUOTE          2
 #define NS_STYLE_CONTENT_NO_CLOSE_QUOTE         3
 #define NS_STYLE_CONTENT_ALT_CONTENT            4
 
 // See nsStyleColor
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2983,17 +2983,17 @@ StyleAnimation::operator==(const StyleAn
 nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext)
   : mDisplay(StyleDisplay::Inline)
   , mOriginalDisplay(StyleDisplay::Inline)
   , mContain(NS_STYLE_CONTAIN_NONE)
   , mAppearance(NS_THEME_NONE)
   , mPosition(NS_STYLE_POSITION_STATIC)
   , mFloat(StyleFloat::None_)
   , mOriginalFloat(StyleFloat::None_)
-  , mBreakType(NS_STYLE_CLEAR_NONE)
+  , mBreakType(StyleClear::None_)
   , mBreakInside(NS_STYLE_PAGE_BREAK_AUTO)
   , mBreakBefore(false)
   , mBreakAfter(false)
   , mOverflowX(NS_STYLE_OVERFLOW_VISIBLE)
   , mOverflowY(NS_STYLE_OVERFLOW_VISIBLE)
   , mOverflowClipBox(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
   , mResize(NS_STYLE_RESIZE_NONE)
   , mOrient(NS_STYLE_ORIENT_INLINE)
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2835,17 +2835,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   uint8_t mAppearance;          // [reset]
   uint8_t mPosition;            // [reset] see nsStyleConsts.h
 
   // [reset] See StyleFloat in nsStyleConsts.h.
   mozilla::StyleFloat mFloat;
   // [reset] Save mFloat for position:absolute/fixed; otherwise equal to mFloat.
   mozilla::StyleFloat mOriginalFloat;
 
-  uint8_t mBreakType;           // [reset] see nsStyleConsts.h NS_STYLE_CLEAR_*
+  mozilla::StyleClear mBreakType;  // [reset]
   uint8_t mBreakInside;         // [reset] NS_STYLE_PAGE_BREAK_AUTO/AVOID
   bool mBreakBefore;    // [reset]
   bool mBreakAfter;     // [reset]
   uint8_t mOverflowX;           // [reset] see nsStyleConsts.h
   uint8_t mOverflowY;           // [reset] see nsStyleConsts.h
   uint8_t mOverflowClipBox;     // [reset] see nsStyleConsts.h
   uint8_t mResize;              // [reset] see nsStyleConsts.h
   uint8_t mOrient;              // [reset] see nsStyleConsts.h
@@ -3089,17 +3089,17 @@ private:
   inline bool HasFixedPosContainingBlockStyleInternal(
                 StyleContextLike* aStyleContext) const;
 
 public:
   // Return the 'float' and 'clear' properties, with inline-{start,end} values
   // resolved to {left,right} according to the given writing mode. These are
   // defined in WritingModes.h.
   inline mozilla::StyleFloat PhysicalFloats(mozilla::WritingMode aWM) const;
-  inline uint8_t PhysicalBreakType(mozilla::WritingMode aWM) const;
+  inline mozilla::StyleClear PhysicalBreakType(mozilla::WritingMode aWM) const;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable
 {
   explicit nsStyleTable(StyleStructContext aContext);
   nsStyleTable(const nsStyleTable& aOther);
   ~nsStyleTable();
 
new file mode 100644
--- /dev/null
+++ b/mfbt/EnumTypeTraits.h
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* Type traits for enums. */
+
+#ifndef mozilla_EnumTypeTraits_h
+#define mozilla_EnumTypeTraits_h
+
+#include <type_traits>
+
+namespace mozilla {
+
+namespace detail {
+
+template<size_t EnumSize, bool EnumSigned, size_t StorageSize, bool StorageSigned>
+struct EnumFitsWithinHelper;
+
+// Signed enum, signed storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, true>
+  : public std::integral_constant<bool, (EnumSize <= StorageSize)>
+{};
+
+// Signed enum, unsigned storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, true, StorageSize, false>
+  : public std::integral_constant<bool, false>
+{};
+
+// Unsigned enum, signed storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, true>
+  : public std::integral_constant<bool, (EnumSize * 2 <= StorageSize)>
+{};
+
+// Unsigned enum, unsigned storage.
+template<size_t EnumSize, size_t StorageSize>
+struct EnumFitsWithinHelper<EnumSize, false, StorageSize, false>
+  : public std::integral_constant<bool, (EnumSize <= StorageSize)>
+{};
+
+} // namespace detail
+
+/*
+ * Type trait that determines whether the enum type T can fit within the
+ * integral type Storage without data loss. This trait should be used with
+ * caution with an enum type whose underlying type has not been explicitly
+ * specified: for such enums, the C++ implementation is free to choose a type
+ * no smaller than int whose range encompasses all possible values of the enum.
+ * So for an enum with only small non-negative values, the underlying type may
+ * be either int or unsigned int, depending on the whims of the implementation.
+ */
+template<typename T, typename Storage>
+struct EnumTypeFitsWithin
+  : public detail::EnumFitsWithinHelper<
+      sizeof(T),
+      std::is_signed<typename std::underlying_type<T>::type>::value,
+      sizeof(Storage),
+      std::is_signed<Storage>::value
+    >
+{
+  static_assert(std::is_enum<T>::value, "must provide an enum type");
+  static_assert(std::is_integral<Storage>::value, "must provide an integral type");
+};
+
+} // namespace mozilla
+
+#endif /* mozilla_EnumTypeTraits_h */
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -34,16 +34,17 @@ EXPORTS.mozilla = [
     'DebugOnly.h',
     'decimal/Decimal.h',
     'double-conversion/double-conversion.h',
     'double-conversion/utils.h',
     'EndianUtils.h',
     'EnumeratedArray.h',
     'EnumeratedRange.h',
     'EnumSet.h',
+    'EnumTypeTraits.h',
     'FastBernoulliTrial.h',
     'FloatingPoint.h',
     'Function.h',
     'GuardObjects.h',
     'HashFunctions.h',
     'IndexSequence.h',
     'InitializerList.h',
     'IntegerPrintfMacros.h',
new file mode 100644
--- /dev/null
+++ b/mfbt/tests/TestEnumTypeTraits.cpp
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "mozilla/IntegerTypeTraits.h"
+#include "mozilla/EnumTypeTraits.h"
+
+using namespace mozilla;
+
+/* Feature check for EnumTypeFitsWithin. */
+
+#define MAKE_FIXED_EMUM_FOR_TYPE(IntType)                               \
+  enum FixedEnumFor_##IntType : IntType {                               \
+    A_##IntType,                                                        \
+    B_##IntType,                                                        \
+    C_##IntType,                                                        \
+  };
+
+template<typename EnumType, typename IntType>
+static void
+TestShouldFit()
+{
+  static_assert(EnumTypeFitsWithin<EnumType, IntType>::value,
+                "Should fit within exact/promoted integral type");
+}
+
+template<typename EnumType, typename IntType>
+static void
+TestShouldNotFit()
+{
+  static_assert(!EnumTypeFitsWithin<EnumType, IntType>::value,
+                "Should not fit within");
+}
+
+int
+main()
+{
+  // check for int8_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int8_t);
+  TestShouldFit<FixedEnumFor_int8_t, int8_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int8_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int8_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int8_t, uint64_t>();
+
+  // check for uint8_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint8_t);
+  TestShouldFit<FixedEnumFor_uint8_t, uint8_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint8_t, int8_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int16_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint8_t, int64_t>();
+
+  // check for int16_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int16_t);
+  TestShouldNotFit<FixedEnumFor_int16_t, int8_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int16_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int16_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int16_t, uint64_t>();
+
+  // check for uint16_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint16_t);
+  TestShouldNotFit<FixedEnumFor_uint16_t, uint8_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint16_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint16_t, int16_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint16_t, int64_t>();
+
+  // check for int32_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int32_t);
+  TestShouldNotFit<FixedEnumFor_int32_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, int16_t>();
+  TestShouldFit<FixedEnumFor_int32_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int32_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int32_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int32_t, uint64_t>();
+
+  // check for uint32_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint32_t);
+  TestShouldNotFit<FixedEnumFor_uint32_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, uint16_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint32_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_uint32_t, int32_t>();
+  TestShouldFit<FixedEnumFor_uint32_t, int64_t>();
+
+  // check for int64_t
+  MAKE_FIXED_EMUM_FOR_TYPE(int64_t);
+  TestShouldNotFit<FixedEnumFor_int64_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, int32_t>();
+  TestShouldFit<FixedEnumFor_int64_t, int64_t>();
+
+  TestShouldNotFit<FixedEnumFor_int64_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint32_t>();
+  TestShouldNotFit<FixedEnumFor_int64_t, uint64_t>();
+
+  // check for uint64_t
+  MAKE_FIXED_EMUM_FOR_TYPE(uint64_t);
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint8_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint16_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, uint32_t>();
+  TestShouldFit<FixedEnumFor_uint64_t, uint64_t>();
+
+  TestShouldNotFit<FixedEnumFor_uint64_t, int8_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int16_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int32_t>();
+  TestShouldNotFit<FixedEnumFor_uint64_t, int64_t>();
+
+  return 0;
+}
--- a/mfbt/tests/moz.build
+++ b/mfbt/tests/moz.build
@@ -12,16 +12,17 @@ CppUnitTests([
     'TestBufferList',
     'TestCasting',
     'TestCeilingFloor',
     'TestCheckedInt',
     'TestCountPopulation',
     'TestCountZeroes',
     'TestEndian',
     'TestEnumSet',
+    'TestEnumTypeTraits',
     'TestFastBernoulliTrial',
     'TestFloatingPoint',
     'TestFunction',
     'TestInitializerList',
     'TestIntegerPrintfMacros',
     'TestIntegerRange',
     'TestJSONWriter',
     'TestLinkedList',
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -2568,17 +2568,19 @@ public abstract class GeckoApp
     public void notifyWakeLockChanged(String topic, String state) {
         PowerManager.WakeLock wl = mWakeLocks.get(topic);
         if (state.equals("locked-foreground") && wl == null) {
             PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
 
             if (CPU.equals(topic)) {
               wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, topic);
             } else if (SCREEN.equals(topic)) {
-              wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, topic);
+              // ON_AFTER_RELEASE is set, the user activity timer will be reset when the
+              // WakeLock is released, causing the illumination to remain on a bit longer.
+              wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, topic);
             }
 
             if (wl != null) {
               wl.acquire();
               mWakeLocks.put(topic, wl);
             }
         } else if (!state.equals("locked-foreground") && wl != null) {
             wl.release();
--- a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java
@@ -63,16 +63,22 @@ public class LauncherActivity extends Ac
     }
 
     /**
      * Launch the browser activity.
      */
     private void dispatchNormalIntent() {
         Intent intent = new Intent(getIntent());
         intent.setClassName(getApplicationContext(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+
+        // Explicitly remove the new task and clear task flags (Our browser activity is a single
+        // task activity and we never want to start a second task here). See bug 1280112.
+        intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
         startActivity(intent);
     }
 
     private void dispatchCustomTabsIntent() {
         Intent intent = new Intent(getIntent());
         intent.setClassName(getApplicationContext(), CustomTabsActivity.class.getName());
         startActivity(intent);
     }
--- a/mobile/android/base/java/org/mozilla/gecko/media/Sample.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/Sample.java
@@ -34,17 +34,17 @@ public final class Sample implements Par
 
     public static Sample createDummyWithInfo(BufferInfo info) {
         BufferInfo dummyInfo = new BufferInfo();
         dummyInfo.set(0, 0, info.presentationTimeUs, info.flags);
         return new Sample(null, dummyInfo);
     }
 
     public boolean isDummy() {
-        return bytes == null && info.size == 0;
+        return !isEOS() && bytes == null && info.size == 0;
     }
 
     public boolean isEOS() {
         return (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
     }
 
     public static final Creator<Sample> CREATOR = new Creator<Sample>() {
         @Override
--- a/python/mozlint/mozlint/vcs.py
+++ b/python/mozlint/mozlint/vcs.py
@@ -18,17 +18,17 @@ class VCSFiles(object):
 
         # First check if we're in an hg repo, if not try git
         commands = (
             ['hg', 'root'],
             ['git', 'rev-parse', '--show-toplevel'],
         )
 
         for cmd in commands:
-            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+            proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
             output = proc.communicate()[0].strip()
 
             if proc.returncode == 0:
                 self._vcs = cmd[0]
                 self._root = output
                 return self._root
 
     @property
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -22,31 +22,41 @@ Cu.import("resource://services-sync/book
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/PlacesBackups.jsm");
 
 const ANNOS_TO_TRACK = [BookmarkAnnos.DESCRIPTION_ANNO, BookmarkAnnos.SIDEBAR_ANNO,
                         PlacesUtils.LMANNO_FEEDURI, PlacesUtils.LMANNO_SITEURI];
 
 const SERVICE_NOT_SUPPORTED = "Service not supported on this platform";
 const FOLDER_SORTINDEX = 1000000;
-const { SOURCE_SYNC } = Ci.nsINavBookmarksService;
+const {
+  SOURCE_SYNC,
+  SOURCE_IMPORT,
+  SOURCE_IMPORT_REPLACE,
+} = Ci.nsINavBookmarksService;
 
 // Maps Sync record property names to `PlacesSyncUtils` bookmark properties.
 const RECORD_PROPS_TO_BOOKMARK_PROPS = {
   title: "title",
   bmkUri: "url",
   tags: "tags",
   keyword: "keyword",
   description: "description",
   loadInSidebar: "loadInSidebar",
   queryId: "query",
   siteUri: "site",
   feedUri: "feed",
 };
 
+// The tracker ignores changes made by bookmark import and restore, and
+// changes made by Sync. We don't need to exclude `SOURCE_IMPORT`, but both
+// import and restore fire `bookmarks-restore-*` observer notifications, and
+// the tracker doesn't currently distinguish between the two.
+const IGNORED_SOURCES = [SOURCE_SYNC, SOURCE_IMPORT, SOURCE_IMPORT_REPLACE];
+
 this.PlacesItem = function PlacesItem(collection, id, type) {
   CryptoWrapper.call(this, collection, id);
   this.type = type || "item";
 }
 PlacesItem.prototype = {
   decrypt: function PlacesItem_decrypt(keyBundle) {
     // Do the normal CryptoWrapper decrypt, but change types before returning
     let clear = CryptoWrapper.prototype.decrypt.call(this, keyBundle);
@@ -372,19 +382,17 @@ BookmarksEngine.prototype = {
     this._store._childrenToOrder = {};
   },
 
   _processIncoming: function (newitems) {
     try {
       SyncEngine.prototype._processIncoming.call(this, newitems);
     } finally {
       // Reorder children.
-      this._tracker.ignoreAll = true;
       this._store._orderChildren();
-      this._tracker.ignoreAll = false;
       delete this._store._childrenToOrder;
     }
   },
 
   _syncFinish: function _syncFinish() {
     SyncEngine.prototype._syncFinish.call(this);
     this._tracker._ensureMobileQuery();
   },
@@ -900,16 +908,26 @@ function BookmarksTracker(name, engine) 
   this._batchSawScoreIncrement = false;
   Tracker.call(this, name, engine);
 
   Svc.Obs.add("places-shutdown", this);
 }
 BookmarksTracker.prototype = {
   __proto__: Tracker.prototype,
 
+  //`_ignore` checks the change source for each observer notification, so we
+  // don't want to let the engine ignore all changes during a sync.
+  get ignoreAll() {
+    return false;
+  },
+
+  // Define an empty setter so that the engine doesn't throw a `TypeError`
+  // setting a read-only property.
+  set ignoreAll(value) {},
+
   startTracking: function() {
     PlacesUtils.bookmarks.addObserver(this, true);
     Svc.Obs.add("bookmarks-restore-begin", this);
     Svc.Obs.add("bookmarks-restore-success", this);
     Svc.Obs.add("bookmarks-restore-failed", this);
   },
 
   stopTracking: function() {
@@ -920,30 +938,27 @@ BookmarksTracker.prototype = {
   },
 
   observe: function observe(subject, topic, data) {
     Tracker.prototype.observe.call(this, subject, topic, data);
 
     switch (topic) {
       case "bookmarks-restore-begin":
         this._log.debug("Ignoring changes from importing bookmarks.");
-        this.ignoreAll = true;
         break;
       case "bookmarks-restore-success":
         this._log.debug("Tracking all items on successful import.");
-        this.ignoreAll = false;
 
         this._log.debug("Restore succeeded: wiping server and other clients.");
         this.engine.service.resetClient([this.name]);
         this.engine.service.wipeServer([this.name]);
         this.engine.service.clientsEngine.sendCommand("wipeEngine", [this.name]);
         break;
       case "bookmarks-restore-failed":
         this._log.debug("Tracking all items on failed import.");
-        this.ignoreAll = false;
         break;
     }
   },
 
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsINavBookmarkObserver,
     Ci.nsINavBookmarkObserver_MOZILLA_1_9_1_ADDITIONS,
     Ci.nsISupportsWeakReference
@@ -973,21 +988,25 @@ BookmarksTracker.prototype = {
 
   /**
    * Determine if a change should be ignored.
    *
    * @param itemId
    *        Item under consideration to ignore
    * @param folder (optional)
    *        Folder of the item being changed
+   * @param guid
+   *        Places GUID of the item being changed
+   * @param source
+   *        A change source constant from `nsINavBookmarksService::SOURCE_*`.
    */
-  _ignore: function BMT__ignore(itemId, folder, guid) {
-    // Ignore unconditionally if the engine tells us to.
-    if (this.ignoreAll)
+  _ignore: function BMT__ignore(itemId, folder, guid, source) {
+    if (IGNORED_SOURCES.includes(source)) {
       return true;
+    }
 
     // Get the folder id if we weren't given one.
     if (folder == null) {
       try {
         folder = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
       } catch (ex) {
         this._log.debug("getFolderIdForItem(" + itemId +
                         ") threw; calling _ensureMobileQuery.");
@@ -1013,28 +1032,29 @@ BookmarksTracker.prototype = {
       return true;
     }
 
     return false;
   },
 
   onItemAdded: function BMT_onItemAdded(itemId, folder, index,
                                         itemType, uri, title, dateAdded,
-                                        guid, parentGuid) {
-    if (this._ignore(itemId, folder, guid))
+                                        guid, parentGuid, source) {
+    if (this._ignore(itemId, folder, guid, source)) {
       return;
+    }
 
     this._log.trace("onItemAdded: " + itemId);
     this._add(itemId, guid);
     this._add(folder, parentGuid);
   },
 
   onItemRemoved: function (itemId, parentId, index, type, uri,
-                           guid, parentGuid) {
-    if (this._ignore(itemId, parentId, guid)) {
+                           guid, parentGuid, source) {
+    if (this._ignore(itemId, parentId, guid, source)) {
       return;
     }
 
     this._log.trace("onItemRemoved: " + itemId);
     this._add(itemId, guid);
     this._add(parentId, parentGuid);
   },
 
@@ -1044,19 +1064,16 @@ BookmarksTracker.prototype = {
         id => PlacesUtils.annotations.getItemAnnotation(id, BookmarkAnnos.ORGANIZERQUERY_ANNO) == val
       );
 
     // Don't continue if the Library isn't ready
     let all = find(BookmarkAnnos.ALLBOOKMARKS_ANNO);
     if (all.length == 0)
       return;
 
-    // Disable handling of notifications while changing the mobile query
-    this.ignoreAll = true;
-
     let mobile = find(BookmarkAnnos.MOBILE_ANNO);
     let queryURI = Utils.makeURI("place:folder=" + BookmarkSpecialIds.mobile);
     let title = Str.sync.get("mobile.label");
 
     // Don't add OR remove the mobile bookmarks if there's nothing.
     if (PlacesUtils.bookmarks.getIdForItemAt(BookmarkSpecialIds.mobile, 0) == -1) {
       if (mobile.length != 0)
         PlacesUtils.bookmarks.removeItem(mobile[0], SOURCE_SYNC);
@@ -1068,52 +1085,49 @@ BookmarksTracker.prototype = {
                                   PlacesUtils.annotations.EXPIRE_NEVER, SOURCE_SYNC);
       PlacesUtils.annotations.setItemAnnotation(query, BookmarkAnnos.EXCLUDEBACKUP_ANNO, 1, 0,
                                   PlacesUtils.annotations.EXPIRE_NEVER, SOURCE_SYNC);
     }
     // Make sure the existing title is correct
     else if (PlacesUtils.bookmarks.getItemTitle(mobile[0]) != title) {
       PlacesUtils.bookmarks.setItemTitle(mobile[0], title, SOURCE_SYNC);
     }
-
-    this.ignoreAll = false;
   },
 
   // This method is oddly structured, but the idea is to return as quickly as
   // possible -- this handler gets called *every time* a bookmark changes, for
   // *each change*.
   onItemChanged: function BMT_onItemChanged(itemId, property, isAnno, value,
                                             lastModified, itemType, parentId,
-                                            guid, parentGuid) {
-    // Quicker checks first.
-    if (this.ignoreAll)
-      return;
-
+                                            guid, parentGuid, source) {
     if (isAnno && (ANNOS_TO_TRACK.indexOf(property) == -1))
       // Ignore annotations except for the ones that we sync.
       return;
 
     // Ignore favicon changes to avoid unnecessary churn.
     if (property == "favicon")
       return;
 
-    if (this._ignore(itemId, parentId, guid))
+    if (this._ignore(itemId, parentId, guid, source)) {
       return;
+    }
 
     this._log.trace("onItemChanged: " + itemId +
                     (", " + property + (isAnno? " (anno)" : "")) +
                     (value ? (" = \"" + value + "\"") : ""));
     this._add(itemId, guid);
   },
 
   onItemMoved: function BMT_onItemMoved(itemId, oldParent, oldIndex,
                                         newParent, newIndex, itemType,
-                                        guid, oldParentGuid, newParentGuid) {
-    if (this._ignore(itemId, newParent, guid))
+                                        guid, oldParentGuid, newParentGuid,
+                                        source) {
+    if (this._ignore(itemId, newParent, guid, source)) {
       return;
+    }
 
     this._log.trace("onItemMoved: " + itemId);
     this._add(oldParent, oldParentGuid);
     if (oldParent != newParent) {
       this._add(itemId, guid);
       this._add(newParent, newParentGuid);
     }
 
--- a/services/sync/modules/engines/prefs.js
+++ b/services/sync/modules/engines/prefs.js
@@ -105,51 +105,63 @@ PrefStore.prototype = {
       if (this._isSynced(pref)) {
         // Missing and default prefs get the null value.
         values[pref] = this._prefs.isSet(pref) ? this._prefs.get(pref, null) : null;
       }
     }
     return values;
   },
 
+  _updateLightWeightTheme (themeID) {
+    let themeObject = null;
+    if (themeID) {
+      themeObject = LightweightThemeManager.getUsedTheme(themeID);
+    }
+    LightweightThemeManager.currentTheme = themeObject;
+  },
+
   _setAllPrefs: function (values) {
     let selectedThemeIDPref = "lightweightThemes.selectedThemeID";
     let selectedThemeIDBefore = this._prefs.get(selectedThemeIDPref, null);
+    let selectedThemeIDAfter = selectedThemeIDBefore;
 
     // Update 'services.sync.prefs.sync.foo.pref' before 'foo.pref', otherwise
     // _isSynced returns false when 'foo.pref' doesn't exist (e.g., on a new device).
     let prefs = Object.keys(values).sort(a => -a.indexOf(PREF_SYNC_PREFS_PREFIX));
     for (let pref of prefs) {
       if (!this._isSynced(pref)) {
         continue;
       }
 
       let value = values[pref];
 
-      // Pref has gone missing. The best we can do is reset it.
-      if (value == null) {
-        this._prefs.reset(pref);
-        continue;
-      }
+      switch (pref) {
+        // Some special prefs we don't want to set directly.
+        case selectedThemeIDPref:
+          selectedThemeIDAfter = value;
+          break;
 
-      try {
-        this._prefs.set(pref, value);
-      } catch(ex) {
-        this._log.trace("Failed to set pref: " + pref + ": " + ex);
-      } 
+        // default is to just set the pref
+        default:
+          if (value == null) {
+            // Pref has gone missing. The best we can do is reset it.
+            this._prefs.reset(pref);
+          } else {
+            try {
+              this._prefs.set(pref, value);
+            } catch(ex) {
+              this._log.trace("Failed to set pref: " + pref + ": " + ex);
+            }
+          }
+      }
     }
 
     // Notify the lightweight theme manager if the selected theme has changed.
-    let selectedThemeIDAfter = this._prefs.get(selectedThemeIDPref, null);
     if (selectedThemeIDBefore != selectedThemeIDAfter) {
-      // The currentTheme getter will reflect the theme with the new
-      // selectedThemeID (if there is one).  Just reset it to itself
-      let currentTheme = LightweightThemeManager.currentTheme;
-      LightweightThemeManager.currentTheme = null;
-      LightweightThemeManager.currentTheme = currentTheme;
+      this._updateLightWeightTheme(selectedThemeIDAfter);
     }
   },
 
   getAllIDs: function () {
     /* We store all prefs in just one WBO, with just one GUID */
     let allprefs = {};
     allprefs[PREFS_GUID] = true;
     return allprefs;
--- a/services/sync/tests/unit/test_bookmark_engine.js
+++ b/services/sync/tests/unit/test_bookmark_engine.js
@@ -12,16 +12,113 @@ Cu.import("resource://services-sync/serv
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 initTestLogging("Trace");
 
 Service.engineManager.register(BookmarksEngine);
 
+add_task(function* test_change_during_sync() {
+  _("Ensure that we track changes made during a sync.");
+
+  let engine = new BookmarksEngine(Service);
+  let store  = engine._store;
+  let server = serverForFoo(engine);
+  new SyncTestingInfrastructure(server.server);
+
+  let collection = server.user("foo").collection("bookmarks");
+
+  Svc.Obs.notify("weave:engine:start-tracking");
+
+  try {
+    let folder1_id = PlacesUtils.bookmarks.createFolder(
+      PlacesUtils.bookmarks.toolbarFolder, "Folder 1", 0);
+    let folder1_guid = store.GUIDForId(folder1_id);
+    _(`Folder GUID: ${folder1_guid}`);
+
+    let bmk1_id = PlacesUtils.bookmarks.insertBookmark(
+      folder1_id, Utils.makeURI("http://getthunderbird.com/"),
+      PlacesUtils.bookmarks.DEFAULT_INDEX, "Get Thunderbird!");
+    let bmk1_guid = store.GUIDForId(bmk1_id);
+    _(`Thunderbird GUID: ${bmk1_guid}`);
+
+    // Sync is synchronous, so, to simulate a bookmark change made during a
+    // sync, we create a server record that adds a bookmark as a side effect.
+    let bmk2_guid = "get-firefox1";
+    let bmk3_id = -1;
+    {
+      let localRecord = new Bookmark("bookmarks", bmk2_guid);
+      localRecord.bmkUri        = "http://getfirefox.com/";
+      localRecord.description   = "Firefox is awesome.";
+      localRecord.title         = "Get Firefox!";
+      localRecord.tags          = ["firefox", "awesome", "browser"];
+      localRecord.keyword       = "awesome";
+      localRecord.loadInSidebar = false;
+      localRecord.parentName    = "Folder 1";
+      localRecord.parentid      = folder1_guid;
+
+      let remoteRecord = collection.insert(bmk2_guid, encryptPayload(localRecord.cleartext));
+      remoteRecord.get = function get() {
+        _("Inserting bookmark into local store");
+        bmk3_id = PlacesUtils.bookmarks.insertBookmark(
+          folder1_id, Utils.makeURI("https://mozilla.org/"),
+          PlacesUtils.bookmarks.DEFAULT_INDEX, "Mozilla");
+
+        return ServerWBO.prototype.get.apply(this, arguments);
+      };
+    }
+
+    {
+      let tree = yield PlacesUtils.promiseBookmarksTree(folder1_guid);
+      let childGuids = tree.children.map(child => child.guid);
+      deepEqual(childGuids, [bmk1_guid], "Folder should have 1 child before first sync");
+    }
+
+    _("Perform first sync");
+    yield sync_engine_and_validate_telem(engine, false);
+
+    let bmk2_id = store.idForGUID(bmk2_guid);
+    let bmk3_guid = store.GUIDForId(bmk3_id);
+    _(`Mozilla GUID: ${bmk3_guid}`);
+    {
+      equal(store.GUIDForId(bmk2_id), bmk2_guid,
+        "Remote bookmark should be applied during first sync");
+      ok(bmk3_id > -1,
+        "Bookmark created during first sync should exist locally");
+      ok(!collection.wbo(bmk3_guid),
+        "Bookmark created during first sync shouldn't be uploaded yet");
+
+      let tree = yield PlacesUtils.promiseBookmarksTree(folder1_guid);
+      let childGuids = tree.children.map(child => child.guid);
+      deepEqual(childGuids, [bmk1_guid, bmk3_guid, bmk2_guid],
+        "Folder should have 3 children after first sync");
+    }
+
+    _("Perform second sync");
+    yield sync_engine_and_validate_telem(engine, false);
+
+    {
+      ok(collection.wbo(bmk3_guid),
+        "Bookmark created during first sync should be uploaded during second sync");
+
+      let tree = yield PlacesUtils.promiseBookmarksTree(folder1_guid);
+      let childGuids = tree.children.map(child => child.guid);
+      deepEqual(childGuids, [bmk1_guid, bmk3_guid, bmk2_guid],
+        "Folder should have same children after second sync");
+    }
+  } finally {
+    store.wipe();
+    Svc.Prefs.resetBranch("");
+    Service.recordManager.clearCache();
+    yield new Promise(resolve => server.stop(resolve));
+    Svc.Obs.notify("weave:engine:stop-tracking");
+  }
+});
+
 add_task(function* bad_record_allIDs() {
   let server = new SyncServer();
   server.start();
   let syncTesting = new SyncTestingInfrastructure(server.server);
 
   _("Ensure that bad Places queries don't cause an error in getAllIDs.");
   let engine = new BookmarksEngine(Service);
   let store = engine._store;
--- a/services/sync/tests/unit/test_prefs_store.js
+++ b/services/sync/tests/unit/test_prefs_store.js
@@ -126,12 +126,43 @@ function run_test() {
     _("Only the current app's preferences are applied.");
     record = new PrefRec("prefs", "some-fake-app");
     record.value = {
       "testing.int": 98
     };
     store.update(record);
     do_check_eq(prefs.get("testing.int"), 42);
 
+    _("The light-weight theme preference is handled correctly.");
+    let lastThemeID = undefined;
+    let orig_updateLightWeightTheme = store._updateLightWeightTheme;
+    store._updateLightWeightTheme = function(themeID) {
+      lastThemeID = themeID;
+    }
+    try {
+      record = new PrefRec("prefs", PREFS_GUID);
+      record.value = {
+        "testing.int": 42,
+      };
+      store.update(record);
+      do_check_true(lastThemeID === undefined,
+                    "should not have tried to change the theme with an unrelated pref.");
+      Services.prefs.setCharPref("lightweightThemes.selectedThemeID", "foo");
+      record.value = {
+        "lightweightThemes.selectedThemeID": "foo",
+      };
+      store.update(record);
+      do_check_true(lastThemeID === undefined,
+                    "should not have tried to change the theme when the incoming pref matches current value.");
+
+      record.value = {
+        "lightweightThemes.selectedThemeID": "bar",
+      };
+      store.update(record);
+      do_check_eq(lastThemeID, "bar",
+                  "should have tried to change the theme when the incoming pref was different.");
+    } finally {
+      store._updateLightWeightTheme = orig_updateLightWeightTheme;
+    }
   } finally {
     prefs.resetBranch("");
   }
 }
--- a/testing/cppunittest.ini
+++ b/testing/cppunittest.ini
@@ -28,16 +28,17 @@ skip-if = os == 'b2g' || (os == 'android
 [TestCountZeroes]
 [TestDeadlockDetector]
 skip-if = os == 'b2g' || (os == 'android' && debug) # Bug 1054249
 [TestDeadlockDetectorScalability]
 [TestDllInterceptor]
 skip-if = os != 'win'
 [TestEndian]
 [TestEnumSet]
+[TestEnumTypeTraits]
 [TestFastBernoulliTrial]
 [TestFile]
 [TestFloatingPoint]
 [TestFunction]
 [TestGetURL]
 [TestHashtables]
 [TestID]
 [TestInitializerList]
deleted file mode 100644
--- a/toolkit/components/places/UnifiedComplete.manifest
+++ /dev/null
@@ -1,2 +0,0 @@
-component {f964a319-397a-4d21-8be6-5cdd1ee3e3ae} UnifiedComplete.js
-contract @mozilla.org/autocomplete/search;1?name=unifiedcomplete {f964a319-397a-4d21-8be6-5cdd1ee3e3ae}
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -3960,22 +3960,22 @@ nsNavHistoryFolderResultNode::OnItemMove
       NS_ENSURE_TRUE(bookmarks, NS_ERROR_OUT_OF_MEMORY);
       nsresult rv = bookmarks->GetBookmarkURI(aItemId, getter_AddRefs(itemURI));
       NS_ENSURE_SUCCESS(rv, rv);
       rv = bookmarks->GetItemTitle(aItemId, itemTitle);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (aOldParent == mTargetFolderItemId) {
       OnItemRemoved(aItemId, aOldParent, aOldIndex, aItemType, itemURI,
-                    aGUID, aOldParentGUID, nsINavBookmarksService::SOURCE_DEFAULT);
+                    aGUID, aOldParentGUID, aSource);
     }
     if (aNewParent == mTargetFolderItemId) {
       OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType, itemURI, itemTitle,
                   RoundedPRNow(), // This is a dummy dateAdded, not the real value.
-                  aGUID, aNewParentGUID, nsINavBookmarksService::SOURCE_DEFAULT);
+                  aGUID, aNewParentGUID, aSource);
     }
   }
   return NS_OK;
 }
 
 
 /**
  * Separator nodes do not hold any data.
--- a/toolkit/components/telemetry/nsITelemetry.idl
+++ b/toolkit/components/telemetry/nsITelemetry.idl
@@ -57,17 +57,16 @@ interface nsITelemetry : nsISupports
    * where data is consists of the following properties:
    *   min - Minimal bucket size
    *   max - Maximum bucket size
    *   histogram_type - HISTOGRAM_EXPONENTIAL, HISTOGRAM_LINEAR, HISTOGRAM_BOOLEAN
    *                    or HISTOGRAM_COUNT
    *   counts - array representing contents of the buckets in the histogram
    *   ranges -  an array with calculated bucket sizes
    *   sum - sum of the bucket contents
-   *   static - true for histograms defined in TelemetryHistograms.h, false for ones defined with newHistogram
    */
   [implicit_jscontext]
   readonly attribute jsval histogramSnapshots;
 
   /**
    * Get a snapshot of the internally duplicated subsession histograms.
    * @param clear Whether to clear out the subsession histograms after snapshotting.
    * @return An object as histogramSnapshots, except this contains the internally duplicated histograms for subsession telemetry.
--- a/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_bug1254766.html
@@ -291,14 +291,15 @@ function runTest() {
 SimpleTest.waitForExplicitFinish();
 
 // 'network.predictor.enabled' is disabled because if other testcase load
 // evil.js, evil.css ...etc resources, it may cause we load them from cache
 // directly and bypass classifier check
 SpecialPowers.pushPrefEnv({"set": [
   ["browser.safebrowsing.malware.enabled", true],
   ["network.predictor.enabled", false],
+  ["urlclassifier.gethash.timeout_ms", 30000],
 ]}, runTest);
 
 </script>
 </pre>
 </body>
 </html>
--- a/toolkit/components/url-classifier/tests/mochitest/test_gethash.html
+++ b/toolkit/components/url-classifier/tests/mochitest/test_gethash.html
@@ -143,14 +143,15 @@ function runTest() {
 SimpleTest.waitForExplicitFinish();
 
 // 'network.predictor.enabled' is disabled because if other testcase load
 // evil.js, evil.css ...etc resources, it may cause we load them from cache
 // directly and bypass classifier check
 SpecialPowers.pushPrefEnv({"set": [
   ["browser.safebrowsing.malware.enabled", true],
   ["network.predictor.enabled", false],
+  ["urlclassifier.gethash.timeout_ms", 30000],
 ]}, runTest);
 
 </script>
 </pre>
 </body>
 </html>