Merge mozilla-central to fx-team
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 05 Oct 2016 17:08:10 +0200
changeset 421270 4f41a594f88d17e25bbfd362f2e45e6dc891bfc6
parent 421116 c4a811b0531e3bf4279a1e19a3e4451f2e416719 (current diff)
parent 421258 e8fa13708c070d1fadf488ed9d951464745b4e17 (diff)
child 421271 91864ad22b216e40710144ce911e483ad3804b88
child 421316 f86063e9cc87f2eaff236d9c504c9be19540b908
child 421318 6134abf8cabc3f6c5340b3935269f0dfba85c004
child 421328 f498eaacd18ef10345edc49d2a29e96f38916999
child 421330 499afba8bb16547c8502afcce25af93eda42c042
child 421402 1fc36f62f932fc23eaf073debccb5b86ba39b909
child 421650 7810eb62114436b2414c5820fe1366d6990c4139
push id31427
push userahunt@mozilla.com
push dateWed, 05 Oct 2016 16:24:51 +0000
milestone52.0a1
Merge mozilla-central to fx-team
build/moz.configure/ffi.configure
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/Axis.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DisplayPortCalculator.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DisplayPortMetrics.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DrawTimingQueue.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SimpleScaleGestureDetector.java
mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/SubdocumentScrollHelper.java
--- a/accessible/base/EventTree.cpp
+++ b/accessible/base/EventTree.cpp
@@ -389,16 +389,17 @@ void
 EventTree::Clear()
 {
   mFirst = nullptr;
   mNext = nullptr;
   mContainer = nullptr;
 
   uint32_t eventsCount = mDependentEvents.Length();
   for (uint32_t jdx = 0; jdx < eventsCount; jdx++) {
+    mDependentEvents[jdx]->mEventType = AccEvent::eDoNotEmit;
     AccHideEvent* ev = downcast_accEvent(mDependentEvents[jdx]);
     if (ev && ev->NeedsShutdown()) {
       ev->Document()->ShutdownChildrenInSubtree(ev->mAccessible);
     }
   }
   mDependentEvents.Clear();
 }
 
--- a/accessible/ipc/other/PDocAccessible.ipdl
+++ b/accessible/ipc/other/PDocAccessible.ipdl
@@ -38,17 +38,17 @@ struct Attribute
 };
 
 struct RelationTargets
 {
   uint32_t Type;
   uint64_t[] Targets;
 };
 
-prio(normal upto high) sync protocol PDocAccessible
+nested(upto inside_sync) sync protocol PDocAccessible
 {
   manager PBrowser;
 
 parent:
   async Shutdown();
 
   /*
    * Notify the parent process the document in the child process is firing an
@@ -69,193 +69,193 @@ parent:
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
 child:
   async __delete__();
 
   // Accessible
-  prio(high) sync State(uint64_t aID) returns(uint64_t states);
-  prio(high) sync NativeState(uint64_t aID) returns(uint64_t states);
-  prio(high) sync Name(uint64_t aID) returns(nsString name);
-  prio(high) sync Value(uint64_t aID) returns(nsString value);
-  prio(high) sync Help(uint64_t aID) returns(nsString help);
-  prio(high) sync Description(uint64_t aID) returns(nsString desc);
-  prio(high) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
-  prio(high) sync RelationByType(uint64_t aID, uint32_t aRelationType)
+  nested(inside_sync) sync State(uint64_t aID) returns(uint64_t states);
+  nested(inside_sync) sync NativeState(uint64_t aID) returns(uint64_t states);
+  nested(inside_sync) sync Name(uint64_t aID) returns(nsString name);
+  nested(inside_sync) sync Value(uint64_t aID) returns(nsString value);
+  nested(inside_sync) sync Help(uint64_t aID) returns(nsString help);
+  nested(inside_sync) sync Description(uint64_t aID) returns(nsString desc);
+  nested(inside_sync) sync Attributes(uint64_t aID) returns(Attribute[] attributes);
+  nested(inside_sync) sync RelationByType(uint64_t aID, uint32_t aRelationType)
     returns(uint64_t[] targets);
-  prio(high) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
-  prio(high) sync IsSearchbox(uint64_t aID) returns(bool retval);
-  prio(high) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
-  prio(high) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
-  prio(high) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel);
+  nested(inside_sync) sync Relations(uint64_t aID) returns(RelationTargets[] relations);
+  nested(inside_sync) sync IsSearchbox(uint64_t aID) returns(bool retval);
+  nested(inside_sync) sync LandmarkRole(uint64_t aID) returns(nsString landmark);
+  nested(inside_sync) sync ARIARoleAtom(uint64_t aID) returns(nsString role);
+  nested(inside_sync) sync GetLevelInternal(uint64_t aID) returns(int32_t aLevel);
   async ScrollTo(uint64_t aID, uint32_t aScrollType);
   async ScrollToPoint(uint64_t aID, uint32_t aScrollType, int32_t aX,
                       int32_t aY);
 
   // AccessibleText
 
   // TextSubstring is getText in IDL.
-  prio(high) sync CaretLineNumber(uint64_t aID) returns(int32_t aLineNumber);
-  prio(high) sync CaretOffset(uint64_t aID) returns(int32_t aOffset);
+  nested(inside_sync) sync CaretLineNumber(uint64_t aID) returns(int32_t aLineNumber);
+  nested(inside_sync) sync CaretOffset(uint64_t aID) returns(int32_t aOffset);
    async SetCaretOffset(uint64_t aID, int32_t aOffset);
-  prio(high) sync CharacterCount(uint64_t aID) returns(int32_t aCount);
-  prio(high) sync SelectionCount(uint64_t aID) returns(int32_t aCount);
-  prio(high) sync TextSubstring(uint64_t aID, int32_t aStartOffset, int32_t
-                                aEndOffset) returns(nsString aText, bool aValid);
-  prio(high) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+  nested(inside_sync) sync CharacterCount(uint64_t aID) returns(int32_t aCount);
+  nested(inside_sync) sync SelectionCount(uint64_t aID) returns(int32_t aCount);
+  nested(inside_sync) sync TextSubstring(uint64_t aID, int32_t aStartOffset, int32_t
+                                         aEndOffset) returns(nsString aText, bool aValid);
+  nested(inside_sync) sync GetTextAfterOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
     returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
-  prio(high) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+  nested(inside_sync) sync GetTextAtOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
     returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
 
-  prio(high) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
+  nested(inside_sync) sync GetTextBeforeOffset(uint64_t aID, int32_t aOffset, int32_t aBoundaryType)
     returns(nsString aText, int32_t aStartOffset, int32_t aEndOffset);
-  prio(high) sync CharAt(uint64_t aID, int32_t aOffset) returns(uint16_t aChar);
+  nested(inside_sync) sync CharAt(uint64_t aID, int32_t aOffset) returns(uint16_t aChar);
 
-  prio(high) sync TextAttributes(uint64_t aID, bool aIncludeDefAttrs, int32_t aOffset)
+  nested(inside_sync) sync TextAttributes(uint64_t aID, bool aIncludeDefAttrs, int32_t aOffset)
     returns(Attribute[] aAttributes, int32_t aStartOffset, int32_t aEndOffset);
-  prio(high) sync DefaultTextAttributes(uint64_t aID) returns(Attribute[] aAttributes);
+  nested(inside_sync) sync DefaultTextAttributes(uint64_t aID) returns(Attribute[] aAttributes);
 
-  prio(high) sync TextBounds(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
+  nested(inside_sync) sync TextBounds(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
                              uint32_t aCoordType)
     returns(nsIntRect aRetVal);
-  prio(high) sync CharBounds(uint64_t aID, int32_t aOffset, uint32_t aCoordType)
+  nested(inside_sync) sync CharBounds(uint64_t aID, int32_t aOffset, uint32_t aCoordType)
     returns(nsIntRect aRetVal);
 
-  prio(high) sync OffsetAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aCoordType)
+  nested(inside_sync) sync OffsetAtPoint(uint64_t aID, int32_t aX, int32_t aY, uint32_t aCoordType)
     returns(int32_t aRetVal);
 
-  prio(high) sync SelectionBoundsAt(uint64_t aID, int32_t aSelectionNum)
+  nested(inside_sync) sync SelectionBoundsAt(uint64_t aID, int32_t aSelectionNum)
     returns(bool aSucceeded, nsString aData, int32_t aStartOffset, int32_t aEndOffset);
-  prio(high) sync SetSelectionBoundsAt(uint64_t aID, int32_t aSelectionNum,
+  nested(inside_sync) sync SetSelectionBoundsAt(uint64_t aID, int32_t aSelectionNum,
                                        int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
-  prio(high) sync AddToSelection(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset)
+  nested(inside_sync) sync AddToSelection(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset)
     returns(bool aSucceeded);
-  prio(high) sync RemoveFromSelection(uint64_t aID, int32_t aSelectionNum)
+  nested(inside_sync) sync RemoveFromSelection(uint64_t aID, int32_t aSelectionNum)
     returns(bool aSucceeded);
 
   async ScrollSubstringTo(uint64_t aID, int32_t aStartOffset, int32_t aEndOffset,
                           uint32_t aScrollType);
   async ScrollSubstringToPoint(uint64_t aID,
                                int32_t aStartOffset,
                                int32_t aEndOffset,
                                uint32_t aCoordinateType,
                                int32_t aX, int32_t aY);
 
-  prio(high) sync Text(uint64_t aID) returns(nsString aText);
-  prio(high) sync ReplaceText(uint64_t aID, nsString aText);
-  prio(high) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
+  nested(inside_sync) sync Text(uint64_t aID) returns(nsString aText);
+  nested(inside_sync) sync ReplaceText(uint64_t aID, nsString aText);
+  nested(inside_sync) sync InsertText(uint64_t aID, nsString aText, int32_t aPosition)
     returns(bool aValid);
-  prio(high) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
+  nested(inside_sync) sync CopyText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
-  prio(high) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
+  nested(inside_sync) sync CutText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
-  prio(high) sync DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
+  nested(inside_sync) sync DeleteText(uint64_t aID, int32_t aStartPos, int32_t aEndPos)
     returns(bool aValid);
-  prio(high) sync PasteText(uint64_t aID, int32_t aPosition)
+  nested(inside_sync) sync PasteText(uint64_t aID, int32_t aPosition)
     returns(bool aValid);
 
-  prio(high) sync ImagePosition(uint64_t aID, uint32_t aCoordType) returns(IntPoint aRetVal);
-  prio(high) sync ImageSize(uint64_t aID) returns(IntSize aRetVal);
+  nested(inside_sync) sync ImagePosition(uint64_t aID, uint32_t aCoordType) returns(IntPoint aRetVal);
+  nested(inside_sync) sync ImageSize(uint64_t aID) returns(IntSize aRetVal);
 
-  prio(high) sync StartOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
-  prio(high) sync EndOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
-  prio(high) sync IsLinkValid(uint64_t aID) returns(bool aRetVal);
-  prio(high) sync AnchorCount(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
-  prio(high) sync AnchorURIAt(uint64_t aID, uint32_t aIndex) returns(nsCString aURI, bool aOk);
-  prio(high) sync AnchorAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfAnchor, bool aOk);
+  nested(inside_sync) sync StartOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
+  nested(inside_sync) sync EndOffset(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
+  nested(inside_sync) sync IsLinkValid(uint64_t aID) returns(bool aRetVal);
+  nested(inside_sync) sync AnchorCount(uint64_t aID) returns(uint32_t aRetVal, bool aOk);
+  nested(inside_sync) sync AnchorURIAt(uint64_t aID, uint32_t aIndex) returns(nsCString aURI, bool aOk);
+  nested(inside_sync) sync AnchorAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfAnchor, bool aOk);
 
-  prio(high) sync LinkCount(uint64_t aID) returns(uint32_t aCount);
-  prio(high) sync LinkAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfLink, bool aOk);
-  prio(high) sync LinkIndexOf(uint64_t aID, uint64_t aLinkID) returns(int32_t aIndex);
-  prio(high) sync LinkIndexAtOffset(uint64_t aID, uint32_t aOffset) returns(int32_t aIndex);
+  nested(inside_sync) sync LinkCount(uint64_t aID) returns(uint32_t aCount);
+  nested(inside_sync) sync LinkAt(uint64_t aID, uint32_t aIndex) returns(uint64_t aIDOfLink, bool aOk);
+  nested(inside_sync) sync LinkIndexOf(uint64_t aID, uint64_t aLinkID) returns(int32_t aIndex);
+  nested(inside_sync) sync LinkIndexAtOffset(uint64_t aID, uint32_t aOffset) returns(int32_t aIndex);
 
-  prio(high) sync TableOfACell(uint64_t aID) returns(uint64_t aTableID, bool aOk);
-  prio(high) sync ColIdx(uint64_t aID) returns(uint32_t aIndex);
-  prio(high) sync RowIdx(uint64_t aID) returns(uint32_t aIndex);
-  prio(high) sync ColExtent(uint64_t aID) returns(uint32_t aExtent);
-  prio(high) sync RowExtent(uint64_t aID) returns(uint32_t aExtent);
-  prio(high) sync ColHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
-  prio(high) sync RowHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
-  prio(high) sync IsCellSelected(uint64_t aID) returns(bool aSelected);
+  nested(inside_sync) sync TableOfACell(uint64_t aID) returns(uint64_t aTableID, bool aOk);
+  nested(inside_sync) sync ColIdx(uint64_t aID) returns(uint32_t aIndex);
+  nested(inside_sync) sync RowIdx(uint64_t aID) returns(uint32_t aIndex);
+  nested(inside_sync) sync ColExtent(uint64_t aID) returns(uint32_t aExtent);
+  nested(inside_sync) sync RowExtent(uint64_t aID) returns(uint32_t aExtent);
+  nested(inside_sync) sync ColHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
+  nested(inside_sync) sync RowHeaderCells(uint64_t aID) returns(uint64_t[] aCells);
+  nested(inside_sync) sync IsCellSelected(uint64_t aID) returns(bool aSelected);
 
-  prio(high) sync TableCaption(uint64_t aID) returns(uint64_t aCaptionID, bool aOk);
-  prio(high) sync TableSummary(uint64_t aID) returns(nsString aSummary);
-  prio(high) sync TableColumnCount(uint64_t aID) returns(uint32_t aColCount);
-  prio(high) sync TableRowCount(uint64_t aID) returns(uint32_t aRowCount);
-  prio(high) sync TableCellAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint64_t aCellID, bool aOk);
-  prio(high) sync TableCellIndexAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(int32_t aIndex);
-  prio(high) sync TableColumnIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aCol);
-  prio(high) sync TableRowIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow);
-  prio(high) sync TableRowAndColumnIndicesAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow, int32_t aCol);
-  prio(high) sync TableColumnExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
-  prio(high) sync TableRowExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
-  prio(high) sync TableColumnDescription(uint64_t aID, uint32_t aCol) returns(nsString aDescription);
-  prio(high) sync TableRowDescription(uint64_t aID, uint32_t aRow) returns(nsString aDescription);
-  prio(high) sync TableColumnSelected(uint64_t aID, uint32_t aCol) returns(bool aSelected);
-  prio(high) sync TableRowSelected(uint64_t aID, uint32_t aRow) returns(bool aSelected);
-  prio(high) sync TableCellSelected(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(bool aSelected);
-  prio(high) sync TableSelectedCellCount(uint64_t aID) returns(uint32_t aSelectedCells);
-  prio(high) sync TableSelectedColumnCount(uint64_t aID) returns(uint32_t aSelectedColumns);
-  prio(high) sync TableSelectedRowCount(uint64_t aID) returns(uint32_t aSelectedRows);
-  prio(high) sync TableSelectedCells(uint64_t aID) returns(uint64_t[] aCellIDs);
-  prio(high) sync TableSelectedCellIndices(uint64_t aID) returns(uint32_t[] aCellIndeces);
-  prio(high) sync TableSelectedColumnIndices(uint64_t aID) returns(uint32_t[] aColumnIndeces);
-  prio(high) sync TableSelectedRowIndices(uint64_t aID) returns(uint32_t[] aRowIndeces);
-  prio(high) sync TableSelectColumn(uint64_t aID, uint32_t aCol);
-  prio(high) sync TableSelectRow(uint64_t aID, uint32_t aRow);
-  prio(high) sync TableUnselectColumn(uint64_t aID, uint32_t aCol);
-  prio(high) sync TableUnselectRow(uint64_t aID, uint32_t aRow);
-  prio(high) sync TableIsProbablyForLayout(uint64_t aID) returns(bool aForLayout);
-  prio(high) sync AtkTableColumnHeader(uint64_t aID, int32_t aCol)
+  nested(inside_sync) sync TableCaption(uint64_t aID) returns(uint64_t aCaptionID, bool aOk);
+  nested(inside_sync) sync TableSummary(uint64_t aID) returns(nsString aSummary);
+  nested(inside_sync) sync TableColumnCount(uint64_t aID) returns(uint32_t aColCount);
+  nested(inside_sync) sync TableRowCount(uint64_t aID) returns(uint32_t aRowCount);
+  nested(inside_sync) sync TableCellAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint64_t aCellID, bool aOk);
+  nested(inside_sync) sync TableCellIndexAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(int32_t aIndex);
+  nested(inside_sync) sync TableColumnIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aCol);
+  nested(inside_sync) sync TableRowIndexAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow);
+  nested(inside_sync) sync TableRowAndColumnIndicesAt(uint64_t aID, uint32_t aCellIndex) returns(int32_t aRow, int32_t aCol);
+  nested(inside_sync) sync TableColumnExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
+  nested(inside_sync) sync TableRowExtentAt(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(uint32_t aExtent);
+  nested(inside_sync) sync TableColumnDescription(uint64_t aID, uint32_t aCol) returns(nsString aDescription);
+  nested(inside_sync) sync TableRowDescription(uint64_t aID, uint32_t aRow) returns(nsString aDescription);
+  nested(inside_sync) sync TableColumnSelected(uint64_t aID, uint32_t aCol) returns(bool aSelected);
+  nested(inside_sync) sync TableRowSelected(uint64_t aID, uint32_t aRow) returns(bool aSelected);
+  nested(inside_sync) sync TableCellSelected(uint64_t aID, uint32_t aRow, uint32_t aCol) returns(bool aSelected);
+  nested(inside_sync) sync TableSelectedCellCount(uint64_t aID) returns(uint32_t aSelectedCells);
+  nested(inside_sync) sync TableSelectedColumnCount(uint64_t aID) returns(uint32_t aSelectedColumns);
+  nested(inside_sync) sync TableSelectedRowCount(uint64_t aID) returns(uint32_t aSelectedRows);
+  nested(inside_sync) sync TableSelectedCells(uint64_t aID) returns(uint64_t[] aCellIDs);
+  nested(inside_sync) sync TableSelectedCellIndices(uint64_t aID) returns(uint32_t[] aCellIndeces);
+  nested(inside_sync) sync TableSelectedColumnIndices(uint64_t aID) returns(uint32_t[] aColumnIndeces);
+  nested(inside_sync) sync TableSelectedRowIndices(uint64_t aID) returns(uint32_t[] aRowIndeces);
+  nested(inside_sync) sync TableSelectColumn(uint64_t aID, uint32_t aCol);
+  nested(inside_sync) sync TableSelectRow(uint64_t aID, uint32_t aRow);
+  nested(inside_sync) sync TableUnselectColumn(uint64_t aID, uint32_t aCol);
+  nested(inside_sync) sync TableUnselectRow(uint64_t aID, uint32_t aRow);
+  nested(inside_sync) sync TableIsProbablyForLayout(uint64_t aID) returns(bool aForLayout);
+  nested(inside_sync) sync AtkTableColumnHeader(uint64_t aID, int32_t aCol)
     returns(uint64_t aHeaderID, bool aOk);
-  prio(high) sync AtkTableRowHeader(uint64_t aID, int32_t aRow)
+  nested(inside_sync) sync AtkTableRowHeader(uint64_t aID, int32_t aRow)
     returns(uint64_t aHeaderID, bool aOk);
 
-  prio(high) sync SelectedItems(uint64_t aID) returns(uint64_t[] aSelectedItemIDs);
-  prio(high) sync SelectedItemCount(uint64_t aID) returns(uint32_t aCount);
-  prio(high) sync GetSelectedItem(uint64_t aID, uint32_t aIndex) returns(uint64_t aSelected, bool aOk);
-  prio(high) sync IsItemSelected(uint64_t aID, uint32_t aIndex) returns(bool aSelected);
-  prio(high) sync AddItemToSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
-  prio(high) sync RemoveItemFromSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
-  prio(high) sync SelectAll(uint64_t aID) returns(bool aSuccess);
-  prio(high) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
+  nested(inside_sync) sync SelectedItems(uint64_t aID) returns(uint64_t[] aSelectedItemIDs);
+  nested(inside_sync) sync SelectedItemCount(uint64_t aID) returns(uint32_t aCount);
+  nested(inside_sync) sync GetSelectedItem(uint64_t aID, uint32_t aIndex) returns(uint64_t aSelected, bool aOk);
+  nested(inside_sync) sync IsItemSelected(uint64_t aID, uint32_t aIndex) returns(bool aSelected);
+  nested(inside_sync) sync AddItemToSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
+  nested(inside_sync) sync RemoveItemFromSelection(uint64_t aID, uint32_t aIndex) returns(bool aSuccess);
+  nested(inside_sync) sync SelectAll(uint64_t aID) returns(bool aSuccess);
+  nested(inside_sync) sync UnselectAll(uint64_t aID) returns(bool aSuccess);
 
   async TakeSelection(uint64_t aID);
   async SetSelected(uint64_t aID, bool aSelected);
 
-  prio(high) sync DoAction(uint64_t aID, uint8_t aIndex) returns(bool aSuccess);
-  prio(high) sync ActionCount(uint64_t aID) returns(uint8_t aCount);
-  prio(high) sync ActionDescriptionAt(uint64_t aID, uint8_t aIndex) returns(nsString aDescription);
-  prio(high) sync ActionNameAt(uint64_t aID, uint8_t aIndex) returns(nsString aName);
-  prio(high) sync AccessKey(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
-  prio(high) sync KeyboardShortcut(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
-  prio(high) sync AtkKeyBinding(uint64_t aID) returns(nsString aResult);
+  nested(inside_sync) sync DoAction(uint64_t aID, uint8_t aIndex) returns(bool aSuccess);
+  nested(inside_sync) sync ActionCount(uint64_t aID) returns(uint8_t aCount);
+  nested(inside_sync) sync ActionDescriptionAt(uint64_t aID, uint8_t aIndex) returns(nsString aDescription);
+  nested(inside_sync) sync ActionNameAt(uint64_t aID, uint8_t aIndex) returns(nsString aName);
+  nested(inside_sync) sync AccessKey(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
+  nested(inside_sync) sync KeyboardShortcut(uint64_t aID) returns(uint32_t aKey, uint32_t aModifierMask);
+  nested(inside_sync) sync AtkKeyBinding(uint64_t aID) returns(nsString aResult);
 
-  prio(high) sync CurValue(uint64_t aID) returns(double aValue);
-  prio(high) sync SetCurValue(uint64_t aID, double aValue) returns(bool aRetVal);
-  prio(high) sync MinValue(uint64_t aID) returns(double aValue);
-  prio(high) sync MaxValue(uint64_t aID) returns(double aValue);
-  prio(high) sync Step(uint64_t aID) returns(double aStep);
+  nested(inside_sync) sync CurValue(uint64_t aID) returns(double aValue);
+  nested(inside_sync) sync SetCurValue(uint64_t aID, double aValue) returns(bool aRetVal);
+  nested(inside_sync) sync MinValue(uint64_t aID) returns(double aValue);
+  nested(inside_sync) sync MaxValue(uint64_t aID) returns(double aValue);
+  nested(inside_sync) sync Step(uint64_t aID) returns(double aStep);
 
   async TakeFocus(uint64_t aID);
-  prio(high) sync FocusedChild(uint64_t aID)
+  nested(inside_sync) sync FocusedChild(uint64_t aID)
     returns(uint64_t aChild, bool aOk);
 
-  prio(high) sync Language(uint64_t aID) returns(nsString aLocale);
-  prio(high) sync DocType(uint64_t aID) returns(nsString aType);
-  prio(high) sync Title(uint64_t aID) returns(nsString aTitle);
-  prio(high) sync URL(uint64_t aID) returns(nsString aURL);
-  prio(high) sync MimeType(uint64_t aID) returns(nsString aMime);
-  prio(high) sync URLDocTypeMimeType(uint64_t aID) returns(nsString aURL, nsString aDocType, nsString aMimeType);
+  nested(inside_sync) sync Language(uint64_t aID) returns(nsString aLocale);
+  nested(inside_sync) sync DocType(uint64_t aID) returns(nsString aType);
+  nested(inside_sync) sync Title(uint64_t aID) returns(nsString aTitle);
+  nested(inside_sync) sync URL(uint64_t aID) returns(nsString aURL);
+  nested(inside_sync) sync MimeType(uint64_t aID) returns(nsString aMime);
+  nested(inside_sync) sync URLDocTypeMimeType(uint64_t aID) returns(nsString aURL, nsString aDocType, nsString aMimeType);
 
-  prio(high) sync AccessibleAtPoint(uint64_t aID, int32_t aX, int32_t aY, bool aNeedsScreenCoords, uint32_t aWhich)
+  nested(inside_sync) sync AccessibleAtPoint(uint64_t aID, int32_t aX, int32_t aY, bool aNeedsScreenCoords, uint32_t aWhich)
     returns(uint64_t aResult, bool aOk);
 
-  prio(high) sync Extents(uint64_t aID, bool aNeedsScreenCoords)
+  nested(inside_sync) sync Extents(uint64_t aID, bool aNeedsScreenCoords)
     returns(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight);
-  prio(high) sync DOMNodeID(uint64_t aID) returns(nsString aDOMNodeID);
+  nested(inside_sync) sync DOMNodeID(uint64_t aID) returns(nsString aDOMNodeID);
 };
 
 }
 }
--- a/accessible/tests/mochitest/events/test_coalescence.html
+++ b/accessible/tests/mochitest/events/test_coalescence.html
@@ -645,16 +645,52 @@
         getNode('t10_c2_moved').setAttribute('aria-owns', 't10_c3_moved');
       };
 
       this.getID = function test10_getID() {
         return "Move a node by aria-owns into a node moved by aria-owns to left within the tree";
       };
     }
 
+    /**
+     * Move a node by aria-owns from right to left in the tree, and then
+     * move its parent too by aria-owns. No hide event should be fired for
+     * original node.
+     */
+    function test11()
+    {
+      this.eventSeq = [
+        new invokerChecker(EVENT_HIDE, getNode('t11_c1_child')),
+        new invokerChecker(EVENT_SHOW, 't11_c2_child'),
+        new invokerChecker(EVENT_HIDE, getNode('t11_c2')),
+        new invokerChecker(EVENT_SHOW, 't11_c2'),
+        new invokerChecker(EVENT_REORDER, 't11'),
+        new unexpectedInvokerChecker(EVENT_HIDE, 't11_c2_child'),
+        new unexpectedInvokerChecker(EVENT_REORDER, 't11_c1'),
+        new unexpectedInvokerChecker(EVENT_REORDER, 't11_c2'),
+        new unexpectedInvokerChecker(EVENT_REORDER, 't11_c3')
+      ];
+
+      this.invoke = function test11_invoke()
+      {
+        // Remove a node from 't11_c1' container to give the event tree a
+        // desired structure (the 't11_c1' container node goes first in
+        // the event tree),
+        getNode('t11_c1_child').remove();
+        // then move 't11_c2_moved' from 't11_c2' to 't11_c1', and then move
+        // 't11_c2' to 't11_c3'.
+        getNode('t11_c1').setAttribute('aria-owns', 't11_c2_child');
+        getNode('t11_c3').setAttribute('aria-owns', 't11_c2');
+      };
+
+      this.getID = function test11_getID() {
+        return "Move a node by aria-owns to left within the tree";
+      };
+    }
+
     ////////////////////////////////////////////////////////////////////////////
     // Do tests.
 
     //gA11yEventDumpToConsole = true; // debug stuff
     //enableLogging("eventTree");
 
     var gQueue = null;
     function doTests()
@@ -681,16 +717,17 @@
       gQueue.push(new test3());
       gQueue.push(new test4());
       gQueue.push(new test5());
       gQueue.push(new test6());
       gQueue.push(new test7());
       gQueue.push(new test8());
       gQueue.push(new test9());
       gQueue.push(new test10());
+      gQueue.push(new test11());
 
       gQueue.invoke(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTests);
   </script>
 </head>
@@ -810,10 +847,16 @@
     <div id="t10_c2">
       <div id="t10_c2_child"></div>
       <div id="t10_c2_moved"></div>
     </div>
     <div id="t10_c3">
       <div id="t10_c3_moved"></div>
     </div>
   </div>
+
+  <div id="t11">
+    <div id="t11_c1"><div id="t11_c1_child"></div></div>
+    <div id="t11_c2"><div id="t11_c2_child"></div></div>
+    <div id="t11_c3"></div>
+  </div>
 </body>
 </html>
--- a/browser/modules/PermissionUI.jsm
+++ b/browser/modules/PermissionUI.jsm
@@ -128,18 +128,19 @@ this.PermissionPromptPrototype = {
     return undefined;
   },
 
   /**
    * These are the options that will be passed to the
    * PopupNotification when it is shown. See the documentation
    * for PopupNotification for more details.
    *
-   * Note that prompt()  will automatically set displayURI to
-   * be the URI of the requesting pricipal.
+   * Note that prompt() will automatically set displayURI to
+   * be the URI of the requesting pricipal, unless the displayURI is exactly
+   * set to false.
    */
   get popupOptions() {
     return {};
   },
 
   /**
    * PopupNotification requires a unique ID to open the notification.
    * You must return a unique ID string here, for which PopupNotification
@@ -324,17 +325,20 @@ this.PermissionPromptPrototype = {
       popupNotificationActions.push(action);
     }
 
     let mainAction = popupNotificationActions.length ?
                      popupNotificationActions[0] : null;
     let secondaryActions = popupNotificationActions.splice(1);
 
     let options = this.popupOptions;
-    options.displayURI = this.principal.URI;
+
+    if (!options.hasOwnProperty('displayURI') || options.displayURI) {
+      options.displayURI = this.principal.URI;
+    }
 
     this.onBeforeShow();
     chromeWin.PopupNotifications.show(this.browser,
                                       this.notificationID,
                                       this.message,
                                       this.anchorID,
                                       mainAction,
                                       secondaryActions,
--- a/browser/modules/test/browser_PermissionUI.js
+++ b/browser/modules/test/browser_PermissionUI.js
@@ -153,16 +153,65 @@ add_task(function* test_permission_promp
     let removePromise =
       BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
     notification.remove();
     yield removePromise;
   });
 });
 
 /**
+ * Tests that if the PermissionPrompt sets displayURI to false in popupOptions,
+ * then there is no URI shown on the popupnotification.
+ */
+add_task(function* test_permission_prompt_for_popupOptions() {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: "http://example.com/",
+  }, function*(browser) {
+    const kTestNotificationID = "test-notification";
+    const kTestMessage = "Test message";
+    let mainAction = {
+      label: "Main",
+      accessKey: "M",
+    };
+    let secondaryAction = {
+      label: "Secondary",
+      accessKey: "S",
+    };
+
+    let mockRequest = makeMockPermissionRequest(browser);
+    let TestPrompt = {
+      __proto__: PermissionUI.PermissionPromptForRequestPrototype,
+      request: mockRequest,
+      notificationID: kTestNotificationID,
+      message: kTestMessage,
+      promptActions: [mainAction, secondaryAction],
+      popupOptions: {
+        displayURI: false,
+      },
+    };
+
+    let shownPromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popupshown");
+    TestPrompt.prompt();
+    yield shownPromise;
+    let notification =
+      PopupNotifications.getNotification(kTestNotificationID, browser);
+
+    Assert.ok(!notification.options.displayURI,
+              "Should not show the URI of the requesting page");
+
+    let removePromise =
+      BrowserTestUtils.waitForEvent(PopupNotifications.panel, "popuphidden");
+    notification.remove();
+    yield removePromise;
+  });
+});
+
+/**
  * Tests that if the PermissionPrompt has the permissionKey
  * set that permissions can be set properly by the user. Also
  * ensures that callbacks for promptActions are properly fired.
  */
 add_task(function* test_with_permission_key() {
   yield BrowserTestUtils.withNewTab({
     gBrowser,
     url: "http://example.com",
--- a/build/autoconf/jemalloc.m4
+++ b/build/autoconf/jemalloc.m4
@@ -71,16 +71,25 @@ if test "$MOZ_BUILD_APP" != js -o -n "$J
     unset CONFIG_FILES
     if test -z "$MOZ_TLS"; then
       ac_configure_args="$ac_configure_args --disable-tls"
     fi
     EXTRA_CFLAGS="$CFLAGS"
     for var in AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS EXTRA_CFLAGS LDFLAGS; do
       ac_configure_args="$ac_configure_args $var='`eval echo \\${${var}}`'"
     done
+
+    # jemalloc's configure assumes that if you have CFLAGS set at all, you set
+    # all the flags necessary to configure jemalloc, which is not likely to be
+    # the case on Windows if someone is building Firefox with flags set in
+    # their mozconfig.
+    if test "$_MSC_VER"; then
+       ac_configure_args="$ac_configure_args CFLAGS="
+    fi
+
     # Force disable DSS support in jemalloc.
     ac_configure_args="$ac_configure_args ac_cv_func_sbrk=false"
 
     # Make Linux builds munmap freed chunks instead of recycling them.
     ac_configure_args="$ac_configure_args --enable-munmap"
 
     # Disable cache oblivious behavior that appears to have a performance
     # impact on Firefox.
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -798,21 +798,16 @@ def js_option(*args, **kwargs):
     @depends(opt.option, build_project)
     def js_option(value, build_project):
         if build_project != 'js':
             return value.format(opt.option)
 
     add_old_configure_arg(js_option)
 
 
-include('pkg.configure')
-# Make this assignment here rather than in pkg.configure to avoid
-# requiring this file in unit tests.
-add_old_configure_assignment('PKG_CONFIG', pkg_config)
-
 # Bug 1278542: This function is a workaround to resolve
 # |android_ndk_include|'s dependency on 'gonkdir.' The
 # actual implementation is located in b2g/moz.configure.
 # Remove this function as soon as 'android_ndk_include'
 # depends on 'target.'
 @dependable
 def gonkdir():
     return None
--- a/build/moz.configure/pkg.configure
+++ b/build/moz.configure/pkg.configure
@@ -1,15 +1,20 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-pkg_config = check_prog('PKG_CONFIG', ('pkg-config',), allow_missing=True)
+@depends('--enable-compile-environment')
+def pkg_config(compile_env):
+    if compile_env:
+        return ('pkg-config',)
+
+pkg_config = check_prog('PKG_CONFIG', pkg_config, allow_missing=True)
 
 @depends_if(pkg_config)
 @checking('for pkg-config version')
 @imports('subprocess')
 def pkg_config_version(pkg_config):
     return Version(check_cmd_output(pkg_config, '--version').rstrip())
 
 # Locates the given module using pkg-config.
@@ -26,28 +31,33 @@ def pkg_config_version(pkg_config):
 #   Returns `True` when the package description is fulfilled.
 @template
 def pkg_check_modules(var, package_desc, when=always,
                       allow_missing=False):
     if isinstance(package_desc, (tuple, list)):
         package_desc = ' '.join(package_desc)
     package_desc = dependable(package_desc)
 
-    @depends_when(pkg_config, pkg_config_version, when=when)
+    @depends(when, '--enable-compile-environment')
+    def when_and_compile_environment(when, compile_environment):
+        return when and compile_environment
+
+    @depends_when(pkg_config, pkg_config_version,
+                  when=when_and_compile_environment)
     def check_pkg_config(pkg_config, version):
         min_version = '0.9.0'
         if pkg_config is None:
             die("*** The pkg-config script could not be found. Make sure it is\n"
                 "*** in your path, or set the PKG_CONFIG environment variable\n"
                 "*** to the full path to pkg-config.")
         if version < min_version:
             die("*** Your version of pkg-config is too old. You need version %s or newer.",
                 min_version)
 
-    @depends_when(pkg_config, package_desc, when=when)
+    @depends_when(pkg_config, package_desc, when=when_and_compile_environment)
     @imports('subprocess')
     @imports('sys')
     @imports(_from='mozbuild.configure.util', _import='LineIO')
     def package(pkg_config, package_desc):
         # package_desc may start as a depends function, so we can't use
         # @checking here.
         log.info("checking for %s... " % package_desc)
         with log.queue_debug():
--- a/build/moz.configure/toolchain.configure
+++ b/build/moz.configure/toolchain.configure
@@ -877,10 +877,31 @@ add_old_configure_assignment('MOZ_DEBUG_
 @depends(c_compiler, target)
 def libcxx_inline_visibility(c_compiler, target):
     if c_compiler.type == 'clang' and target.os == 'Android':
         return ''
 
 set_define('_LIBCPP_INLINE_VISIBILITY', libcxx_inline_visibility)
 set_define('_LIBCPP_INLINE_VISIBILITY_EXCEPT_GCC49', libcxx_inline_visibility)
 
+@depends(c_compiler, target, check_build_environment)
+def visibility_flags(c_compiler, target, env):
+    if target.os != 'WINNT':
+        if target.kernel == 'Darwin':
+            return ('-fvisibility=hidden', '-fvisibility-inlines-hidden')
+        return ('-I%s/system_wrappers' % os.path.join(env.dist),
+                '-include',
+                '%s/config/gcc_hidden.h' % env.topsrcdir)
+
+@depends(target, visibility_flags)
+def wrap_system_includes(target, visibility_flags):
+    if visibility_flags and target.kernel != 'Darwin':
+        return True
+
+set_define('HAVE_VISIBILITY_HIDDEN_ATTRIBUTE',
+           depends(visibility_flags)(lambda v: bool(v) or None))
+set_define('HAVE_VISIBILITY_ATTRIBUTE',
+           depends(visibility_flags)(lambda v: bool(v) or None))
+set_config('WRAP_SYSTEM_INCLUDES', wrap_system_includes)
+set_config('VISIBILITY_FLAGS', visibility_flags)
+
 include('windows.configure')
 include('rust.configure')
--- a/devtools/client/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js
+++ b/devtools/client/webconsole/test/browser_bug664688_sandbox_update_after_navigation.js
@@ -74,24 +74,16 @@ add_task(function* () {
 
   // Navigation clears messages. Wait for that clear to happen before
   // continuing the test or it might destroy messages we wait later on (Bug
   // 1270234).
   let cleared = hud.jsterm.once("messages-cleared");
 
   gBrowser.goBack();
 
-  info("Waiting for page to navigate");
-  yield waitForSuccess({
-    name: "go back",
-    validator: function () {
-      return content.location.href == TEST_URI1;
-    },
-  });
-
   info("Waiting for messages to be cleared due to navigation");
   yield cleared;
 
   info("Messages cleared after navigation; checking location");
   hud.jsterm.execute("window.location.href");
 
   info("wait for window.location.href after goBack()");
   yield waitForMessages(msgForLocation1);
--- a/devtools/client/webide/test/test_import.html
+++ b/devtools/client/webide/test/test_import.html
@@ -24,18 +24,21 @@
           let packagedAppLocation = getTestFilePath("app");
 
           yield win.AppProjects.load();
           is(win.AppProjects.projects.length, 0, "IDB is empty");
 
           info("to call importPackagedApp(" + packagedAppLocation + ")");
           ok(!win.UI._busyPromise, "UI is not busy");
 
+          let onValidated = waitForUpdate(win, "project-validated");
+          let onDetails = waitForUpdate(win, "details");
           yield winProject.projectList.importPackagedApp(packagedAppLocation);
-          yield waitForUpdate(win, "project-validated");
+          yield onValidated;
+          yield onDetails;
 
           let project = win.AppManager.selectedProject;
           is(project.location, packagedAppLocation, "Location is valid");
           is(project.name, "A name (in app directory)", "name field has been updated");
           is(project.manifest.launch_path, "/index.html", "manifest found. launch_path valid.");
           is(project.manifest.description, "desc", "manifest found. description valid");
 
           yield nextTick();
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -291,17 +291,20 @@ KeyframeEffectReadOnly::UpdateProperties
 
   for (AnimationProperty& property : mProperties) {
     property.mWinsInCascade =
       winningInCascadeProperties.HasProperty(property.mProperty);
     property.mIsRunningOnCompositor =
       runningOnCompositorProperties.HasProperty(property.mProperty);
   }
 
-  CalculateCumulativeChangeHint(aStyleContext);
+  // FIXME (bug 1303235): Do this for Servo too
+  if (aStyleContext->PresContext()->StyleSet()->IsGecko()) {
+    CalculateCumulativeChangeHint(aStyleContext);
+  }
 
   MarkCascadeNeedsUpdate();
 
   RequestRestyle(EffectCompositor::RestyleType::Layer);
 }
 
 void
 KeyframeEffectReadOnly::ComposeStyle(RefPtr<AnimValuesStyleRule>& aStyleRule,
@@ -854,18 +857,23 @@ KeyframeEffectReadOnly::GetKeyframes(JSC
       // works with token stream values if we pass eCSSProperty_UNKNOWN as
       // the property.
       nsCSSPropertyID propertyForSerializing =
         nsCSSProps::IsShorthand(propertyValue.mProperty)
         ? eCSSProperty_UNKNOWN
         : propertyValue.mProperty;
 
       nsAutoString stringValue;
-      propertyValue.mValue.AppendToString(
-        propertyForSerializing, stringValue, nsCSSValue::eNormalized);
+      if (propertyValue.mServoDeclarationBlock) {
+        Servo_DeclarationBlock_SerializeOneValue(
+          propertyValue.mServoDeclarationBlock, &stringValue);
+      } else {
+        propertyValue.mValue.AppendToString(
+          propertyForSerializing, stringValue, nsCSSValue::eNormalized);
+      }
 
       JS::Rooted<JS::Value> value(aCx);
       if (!ToJSValue(aCx, stringValue, &value) ||
           !JS_DefineProperty(aCx, keyframeObject, name, value,
                              JSPROP_ENUMERATE)) {
         aRv.Throw(NS_ERROR_FAILURE);
         return;
       }
@@ -1265,16 +1273,23 @@ KeyframeEffectReadOnly::SetAnimation(Ani
 
 bool
 KeyframeEffectReadOnly::CanIgnoreIfNotVisible() const
 {
   if (!AnimationUtils::IsOffscreenThrottlingEnabled()) {
     return false;
   }
 
+  // FIXME (bug 1303235): We don't calculate mCumulativeChangeHint for
+  // the Servo backend yet
+  nsPresContext* presContext = GetPresContext();
+  if (!presContext || presContext->StyleSet()->IsServo()) {
+    return false;
+  }
+
   // FIXME: For further sophisticated optimization we need to check
   // change hint on the segment corresponding to computedTiming.progress.
   return NS_IsHintSubset(
     mCumulativeChangeHint, nsChangeHint_Hints_CanIgnoreIfNotVisible);
 }
 
 void
 KeyframeEffectReadOnly::MaybeUpdateFrameForCompositor()
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -15,16 +15,18 @@
 #include "nsWrapperCache.h"
 #include "mozilla/AnimationPerformanceWarning.h"
 #include "mozilla/AnimationTarget.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/ComputedTimingFunction.h"
 #include "mozilla/EffectCompositor.h"
 #include "mozilla/KeyframeEffectParams.h"
 #include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
+#include "mozilla/ServoBindingHelpers.h" // ServoDeclarationBlock and
+                                         // associated RefPtrTraits
 #include "mozilla/StyleAnimationValue.h"
 #include "mozilla/dom/AnimationEffectReadOnly.h"
 #include "mozilla/dom/Element.h"
 
 struct JSContext;
 class JSObject;
 class nsCSSPropertyIDSet;
 class nsIContent;
@@ -55,21 +57,30 @@ struct AnimationPropertyDetails;
  * A property-value pair specified on a keyframe.
  */
 struct PropertyValuePair
 {
   nsCSSPropertyID mProperty;
   // The specified value for the property. For shorthand properties or invalid
   // property values, we store the specified property value as a token stream
   // (string).
-  nsCSSValue    mValue;
+  nsCSSValue mValue;
+
+  // The specified value when using the Servo backend. However, even when
+  // using the Servo backend, we still fill in |mValue| in the case where we
+  // fail to parse the value since we use it to store the original string.
+  RefPtr<ServoDeclarationBlock> mServoDeclarationBlock;
 
   bool operator==(const PropertyValuePair& aOther) const {
     return mProperty == aOther.mProperty &&
-           mValue == aOther.mValue;
+           mValue == aOther.mValue &&
+           !mServoDeclarationBlock == !aOther.mServoDeclarationBlock &&
+           (!mServoDeclarationBlock ||
+            Servo_DeclarationBlock_Equals(mServoDeclarationBlock,
+                                          aOther.mServoDeclarationBlock));
   }
 };
 
 /**
  * A single keyframe.
  *
  * This is the canonical form in which keyframe effects are stored and
  * corresponds closely to the type of objects returned via the getKeyframes()
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -312,18 +312,22 @@ public:
 
 // ------------------------------------------------------------------
 //
 // Inlined helper methods
 //
 // ------------------------------------------------------------------
 
 inline bool
-IsInvalidValuePair(const PropertyValuePair& aPair)
+IsInvalidValuePair(const PropertyValuePair& aPair, StyleBackendType aBackend)
 {
+  if (aBackend == StyleBackendType::Servo) {
+    return !aPair.mServoDeclarationBlock;
+  }
+
   // There are three types of values we store as token streams:
   //
   // * Shorthand values (where we manually extract the token stream's string
   //   value) and pass that along to various parsing methods
   // * Longhand values with variable references
   // * Invalid values
   //
   // We can distinguish between the last two cases because for invalid values
@@ -584,51 +588,66 @@ KeyframeUtils::ApplyDistributeSpacing(ns
 /* static */ nsTArray<ComputedKeyframeValues>
 KeyframeUtils::GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
                                          dom::Element* aElement,
                                          nsStyleContext* aStyleContext)
 {
   MOZ_ASSERT(aStyleContext);
   MOZ_ASSERT(aElement);
 
+  StyleBackendType styleBackend = aElement->OwnerDoc()->GetStyleBackendType();
+
   const size_t len = aKeyframes.Length();
   nsTArray<ComputedKeyframeValues> result(len);
 
   for (const Keyframe& frame : aKeyframes) {
     nsCSSPropertyIDSet propertiesOnThisKeyframe;
     ComputedKeyframeValues* computedValues = result.AppendElement();
     for (const PropertyValuePair& pair :
            PropertyPriorityIterator(frame.mPropertyValues)) {
-      if (IsInvalidValuePair(pair)) {
+      MOZ_ASSERT(!pair.mServoDeclarationBlock ||
+                 styleBackend == StyleBackendType::Servo,
+                 "Animation values were parsed using Servo backend but target"
+                 " element is not using Servo backend?");
+
+      if (IsInvalidValuePair(pair, styleBackend)) {
         continue;
       }
 
       // Expand each value into the set of longhands and produce
       // a KeyframeValueEntry for each value.
       nsTArray<PropertyStyleAnimationValuePair> values;
 
-      // For shorthands, we store the string as a token stream so we need to
-      // extract that first.
-      if (nsCSSProps::IsShorthand(pair.mProperty)) {
-        nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
+      if (styleBackend == StyleBackendType::Servo) {
         if (!StyleAnimationValue::ComputeValues(pair.mProperty,
-              CSSEnabledState::eForAllContent, aElement, aStyleContext,
-              tokenStream->mTokenStream, /* aUseSVGMode */ false, values) ||
-            IsComputeValuesFailureKey(pair)) {
+              CSSEnabledState::eForAllContent, aStyleContext,
+              *pair.mServoDeclarationBlock, values)) {
           continue;
         }
       } else {
-        if (!StyleAnimationValue::ComputeValues(pair.mProperty,
-              CSSEnabledState::eForAllContent, aElement, aStyleContext,
-              pair.mValue, /* aUseSVGMode */ false, values)) {
-          continue;
+        // For shorthands, we store the string as a token stream so we need to
+        // extract that first.
+        if (nsCSSProps::IsShorthand(pair.mProperty)) {
+          nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
+          if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+                CSSEnabledState::eForAllContent, aElement, aStyleContext,
+                tokenStream->mTokenStream, /* aUseSVGMode */ false, values) ||
+              IsComputeValuesFailureKey(pair)) {
+            continue;
+          }
+        } else {
+          if (!StyleAnimationValue::ComputeValues(pair.mProperty,
+                CSSEnabledState::eForAllContent, aElement, aStyleContext,
+                pair.mValue, /* aUseSVGMode */ false, values)) {
+            continue;
+          }
+          MOZ_ASSERT(values.Length() == 1,
+                    "Longhand properties should produce a single"
+                    " StyleAnimationValue");
         }
-        MOZ_ASSERT(values.Length() == 1,
-                   "Longhand properties should produce a single"
-                   " StyleAnimationValue");
       }
 
       for (auto& value : values) {
         // If we already got a value for this property on the keyframe,
         // skip this one.
         if (propertiesOnThisKeyframe.HasProperty(value.mProperty)) {
           continue;
         }
@@ -964,16 +983,46 @@ AppendValueAsString(JSContext* aCx,
  * @param aDocument The document to use when parsing.
  * @return The constructed PropertyValuePair object.
  */
 static PropertyValuePair
 MakePropertyValuePair(nsCSSPropertyID aProperty, const nsAString& aStringValue,
                       nsCSSParser& aParser, nsIDocument* aDocument)
 {
   MOZ_ASSERT(aDocument);
+  PropertyValuePair result;
+
+  result.mProperty = aProperty;
+
+  if (aDocument->GetStyleBackendType() == StyleBackendType::Servo) {
+    nsCString name = nsCSSProps::GetStringValue(aProperty);
+
+    NS_ConvertUTF16toUTF8 value(aStringValue);
+    RefPtr<ThreadSafeURIHolder> base =
+      new ThreadSafeURIHolder(aDocument->GetDocumentURI());
+    RefPtr<ThreadSafeURIHolder> referrer =
+      new ThreadSafeURIHolder(aDocument->GetDocumentURI());
+    RefPtr<ThreadSafePrincipalHolder> principal =
+      new ThreadSafePrincipalHolder(aDocument->NodePrincipal());
+
+    nsCString baseString;
+    aDocument->GetDocumentURI()->GetSpec(baseString);
+
+    RefPtr<ServoDeclarationBlock> servoDeclarationBlock =
+      Servo_ParseProperty(
+        reinterpret_cast<const uint8_t*>(name.get()), name.Length(),
+        reinterpret_cast<const uint8_t*>(value.get()), value.Length(),
+        reinterpret_cast<const uint8_t*>(baseString.get()), baseString.Length(),
+        base, referrer, principal).Consume();
+
+    if (servoDeclarationBlock) {
+      result.mServoDeclarationBlock = servoDeclarationBlock.forget();
+      return result;
+    }
+  }
 
   nsCSSValue value;
   if (!nsCSSProps::IsShorthand(aProperty)) {
     aParser.ParseLonghandProperty(aProperty,
                                   aStringValue,
                                   aDocument->GetDocumentURI(),
                                   aDocument->GetDocumentURI(),
                                   aDocument->NodePrincipal(),
@@ -996,19 +1045,28 @@ MakePropertyValuePair(nsCSSPropertyID aP
 
     // By leaving mShorthandPropertyID as unknown, we ensure that when
     // we call nsCSSValue::AppendToString we get back the string stored
     // in mTokenStream.
     MOZ_ASSERT(tokenStream->mShorthandPropertyID == eCSSProperty_UNKNOWN,
                "The shorthand property of a token stream should be initialized"
                " to unknown");
     value.SetTokenStreamValue(tokenStream);
+  } else {
+    // If we succeeded in parsing with Gecko, but not Servo the animation is
+    // not going to work since, for the purposes of animation, we're going to
+    // ignore |mValue| when the backend is Servo.
+    NS_WARNING_ASSERTION(aDocument->GetStyleBackendType() !=
+                           StyleBackendType::Servo,
+                         "Gecko succeeded in parsing where Servo failed");
   }
 
-  return { aProperty, value };
+  result.mValue = value;
+
+  return result;
 }
 
 /**
  * Checks that the given keyframes are loosely ordered (each keyframe's
  * offset that is not null is greater than or equal to the previous
  * non-null offset) and that all values are within the range [0.0, 1.0].
  *
  * @return true if the keyframes' offsets are correctly ordered and
@@ -1339,42 +1397,52 @@ RequiresAdditiveAnimation(const nsTArray
     properties.AddProperty(aProperty);
     if (aOffset == 0.0) {
       propertiesWithFromValue.AddProperty(aProperty);
     } else if (aOffset == 1.0) {
       propertiesWithToValue.AddProperty(aProperty);
     }
   };
 
+  StyleBackendType styleBackend = aDocument->GetStyleBackendType();
+
   for (size_t i = 0, len = aKeyframes.Length(); i < len; i++) {
     const Keyframe& frame = aKeyframes[i];
 
     // We won't have called ApplySpacing when this is called so
     // we can't use frame.mComputedOffset. Instead we do a rough version
     // of that algorithm that substitutes null offsets with 0.0 for the first
     // frame, 1.0 for the last frame, and 0.5 for everything else.
     double computedOffset = i == len - 1
                             ? 1.0
                             : i == 0 ? 0.0 : 0.5;
     double offsetToUse = frame.mOffset
                          ? frame.mOffset.value()
                          : computedOffset;
 
     for (const PropertyValuePair& pair : frame.mPropertyValues) {
-      if (IsInvalidValuePair(pair)) {
+      if (IsInvalidValuePair(pair, styleBackend)) {
         continue;
       }
 
       if (nsCSSProps::IsShorthand(pair.mProperty)) {
-        nsCSSValueTokenStream* tokenStream = pair.mValue.GetTokenStreamValue();
-        nsCSSParser parser(aDocument->CSSLoader());
-        if (!parser.IsValueValidForProperty(pair.mProperty,
-                                            tokenStream->mTokenStream)) {
-          continue;
+        if (styleBackend == StyleBackendType::Gecko) {
+          nsCSSValueTokenStream* tokenStream =
+            pair.mValue.GetTokenStreamValue();
+          nsCSSParser parser(aDocument->CSSLoader());
+          if (!parser.IsValueValidForProperty(pair.mProperty,
+                                              tokenStream->mTokenStream)) {
+            continue;
+          }
         }
+        // For the Servo backend, invalid shorthand values are represented by
+        // a null mServoDeclarationBlock member which we skip above in
+        // IsInvalidValuePair.
+        MOZ_ASSERT(styleBackend != StyleBackendType::Servo ||
+                   pair.mServoDeclarationBlock);
         CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(
             prop, pair.mProperty, CSSEnabledState::eForAllContent) {
           addToPropertySets(*prop, offsetToUse);
         }
       } else {
         addToPropertySets(pair.mProperty, offsetToUse);
       }
     }
--- a/dom/base/nsAttrAndChildArray.cpp
+++ b/dom/base/nsAttrAndChildArray.cpp
@@ -479,17 +479,17 @@ nsAttrAndChildArray::RemoveAttrAt(uint32
   RefPtr<nsMappedAttributes> mapped =
     GetModifiableMapped(nullptr, nullptr, false);
 
   mapped->RemoveAttrAt(aPos - nonmapped, aValue);
 
   return MakeMappedUnique(mapped);
 }
 
-BorrowedAttrInfo
+mozilla::dom::BorrowedAttrInfo
 nsAttrAndChildArray::AttrInfoAt(uint32_t aPos) const
 {
   NS_ASSERTION(aPos < AttrCount(),
                "out-of-bounds access in nsAttrAndChildArray");
 
   uint32_t nonmapped = NonMappedAttrCount();
   if (aPos < nonmapped) {
     return BorrowedAttrInfo(&ATTRS(mImpl)[aPos].mName, &ATTRS(mImpl)[aPos].mValue);
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -886,17 +886,17 @@ nsDOMMutationObserver::HandleMutationsIn
     // after previous mutations are handled. But in case some
     // callback calls a sync API, which spins the eventloop, we need to still
     // process other mutations happening during that sync call.
     // This does *not* catch all cases, but should work for stuff running
     // in separate tabs.
     return;
   }
 
-  AutoSlowOperation aso;
+  mozilla::AutoSlowOperation aso;
 
   nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
 
   while (sScheduledMutationObservers) {
     AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
       sScheduledMutationObservers;
     sScheduledMutationObservers = nullptr;
     for (uint32_t i = 0; i < observers->Length(); ++i) {
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -3,16 +3,17 @@
 /* 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 "nsHostObjectProtocolHandler.h"
 
 #include "DOMMediaStream.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/Exceptions.h"
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/ipc/BlobChild.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/MediaSource.h"
 #include "mozilla/LoadInfo.h"
 #include "mozilla/ModuleUtils.h"
 #include "mozilla/Preferences.h"
@@ -124,43 +125,43 @@ void
 BroadcastBlobURLRegistration(const nsACString& aURI,
                              BlobImpl* aBlobImpl,
                              nsIPrincipal* aPrincipal)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aBlobImpl);
 
   if (XRE_IsParentProcess()) {
-    ContentParent::BroadcastBlobURLRegistration(aURI, aBlobImpl,
-                                                aPrincipal);
+    dom::ContentParent::BroadcastBlobURLRegistration(aURI, aBlobImpl,
+                                                     aPrincipal);
     return;
   }
 
-  ContentChild* cc = ContentChild::GetSingleton();
-  BlobChild* actor = cc->GetOrCreateActorForBlobImpl(aBlobImpl);
+  dom::ContentChild* cc = dom::ContentChild::GetSingleton();
+  dom::BlobChild* actor = cc->GetOrCreateActorForBlobImpl(aBlobImpl);
   if (NS_WARN_IF(!actor)) {
     return;
   }
 
   Unused << NS_WARN_IF(!cc->SendStoreAndBroadcastBlobURLRegistration(
     nsCString(aURI), actor, IPC::Principal(aPrincipal)));
 }
 
 void
 BroadcastBlobURLUnregistration(const nsACString& aURI, DataInfo* aInfo)
 {
   MOZ_ASSERT(aInfo);
   MOZ_ASSERT(NS_IsMainThread());
 
   if (XRE_IsParentProcess()) {
-    ContentParent::BroadcastBlobURLUnregistration(aURI);
+    dom::ContentParent::BroadcastBlobURLUnregistration(aURI);
     return;
   }
 
-  ContentChild* cc = ContentChild::GetSingleton();
+  dom::ContentChild* cc = dom::ContentChild::GetSingleton();
   Unused << NS_WARN_IF(!cc->SendUnstoreAndBroadcastBlobURLUnregistration(
     nsCString(aURI)));
 }
 
 class HostObjectURLsReporter final : public nsIMemoryReporter
 {
   ~HostObjectURLsReporter() {}
 
@@ -459,17 +460,17 @@ nsHostObjectProtocolHandler::AddDataEntr
   Init();
 
   nsresult rv = GenerateURIStringForBlobURL(aPrincipal, aUri);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = AddDataEntryInternal(aUri, aBlobImpl, aPrincipal);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  BroadcastBlobURLRegistration(aUri, aBlobImpl, aPrincipal);
+  mozilla::BroadcastBlobURLRegistration(aUri, aBlobImpl, aPrincipal);
   return NS_OK;
 }
 
 /* static */ nsresult
 nsHostObjectProtocolHandler::AddDataEntry(DOMMediaStream* aMediaStream,
                                           nsIPrincipal* aPrincipal,
                                           nsACString& aUri)
 {
@@ -504,42 +505,44 @@ nsHostObjectProtocolHandler::AddDataEntr
 nsHostObjectProtocolHandler::AddDataEntry(const nsACString& aURI,
                                           nsIPrincipal* aPrincipal,
                                           mozilla::dom::BlobImpl* aBlobImpl)
 {
   return AddDataEntryInternal(aURI, aBlobImpl, aPrincipal);
 }
 
 /* static */ bool
-nsHostObjectProtocolHandler::GetAllBlobURLEntries(nsTArray<BlobURLRegistrationData>& aRegistrations,
-                                                  ContentParent* aCP)
+nsHostObjectProtocolHandler::GetAllBlobURLEntries(
+  nsTArray<mozilla::dom::BlobURLRegistrationData>& aRegistrations,
+  mozilla::dom::ContentParent* aCP)
 {
   MOZ_ASSERT(aCP);
 
   if (!gDataTable) {
     return true;
   }
 
   for (auto iter = gDataTable->ConstIter(); !iter.Done(); iter.Next()) {
     DataInfo* info = iter.UserData();
     MOZ_ASSERT(info);
 
     if (info->mObjectType != DataInfo::eBlobImpl) {
       continue;
     }
 
     MOZ_ASSERT(info->mBlobImpl);
-    PBlobParent* blobParent = aCP->GetOrCreateActorForBlobImpl(info->mBlobImpl);
+    mozilla::dom::PBlobParent* blobParent =
+      aCP->GetOrCreateActorForBlobImpl(info->mBlobImpl);
     if (!blobParent) {
       return false;
     }
 
-    aRegistrations.AppendElement(
-      BlobURLRegistrationData(nsCString(iter.Key()), blobParent, nullptr,
-                              IPC::Principal(info->mPrincipal)));
+    aRegistrations.AppendElement(mozilla::dom::BlobURLRegistrationData(
+      nsCString(iter.Key()), blobParent, nullptr,
+      IPC::Principal(info->mPrincipal)));
   }
 
   return true;
 }
 
 void
 nsHostObjectProtocolHandler::RemoveDataEntry(const nsACString& aUri,
                                              bool aBroadcastToOtherProcesses)
@@ -549,17 +552,17 @@ nsHostObjectProtocolHandler::RemoveDataE
   }
 
   DataInfo* info = GetDataInfo(aUri);
   if (!info) {
     return;
   }
 
   if (aBroadcastToOtherProcesses && info->mObjectType == DataInfo::eBlobImpl) {
-    BroadcastBlobURLUnregistration(aUri, info);
+    mozilla::BroadcastBlobURLUnregistration(aUri, info);
   }
 
   gDataTable->Remove(aUri);
   if (gDataTable->Count() == 0) {
     delete gDataTable;
     gDataTable = nullptr;
   }
 }
--- a/dom/bindings/CallbackObject.h
+++ b/dom/bindings/CallbackObject.h
@@ -121,17 +121,17 @@ public:
 
   /*
    * If the callback is known to be non-gray, then this method can be
    * used instead of Callback() to avoid the overhead of
    * ExposeObjectToActiveJS().
    */
   JS::Handle<JSObject*> CallbackKnownNotGray() const
   {
-    MOZ_ASSERT(!JS::ObjectIsMarkedGray(mCallback.get()));
+    MOZ_ASSERT(!JS::ObjectIsMarkedGray(mCallback));
     return CallbackPreserveColor();
   }
 
   nsIGlobalObject* IncumbentGlobalOrNull() const
   {
     return mIncumbentGlobal;
   }
 
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -300,18 +300,18 @@ class IDLScope(IDLObject):
                 "identifier '%s'.\n%s\n%s"
                 % (identifier.name,
                    originalObject.location, newObject.location), [])
 
         # We do the merging of overloads here as opposed to in IDLInterface
         # because we need to merge overloads of NamedConstructors and we need to
         # detect conflicts in those across interfaces. See also the comment in
         # IDLInterface.addExtendedAttributes for "NamedConstructor".
-        if (originalObject.tag == IDLInterfaceMember.Tags.Method and
-           newObject.tag == IDLInterfaceMember.Tags.Method):
+        if (isinstance(originalObject, IDLMethod) and
+            isinstance(newObject, IDLMethod)):
             return originalObject.addOverload(newObject)
 
         # Default to throwing, derived classes can override.
         conflictdesc = "\n\t%s at %s\n\t%s at %s" % (originalObject,
                                                      originalObject.location,
                                                      newObject,
                                                      newObject.location)
 
new file mode 100644
--- /dev/null
+++ b/dom/bindings/parser/tests/test_identifier_conflict.py
@@ -0,0 +1,39 @@
+# Import the WebIDL module, so we can do isinstance checks and whatnot
+import WebIDL
+
+def WebIDLTest(parser, harness):
+    try:
+        parser.parse("""
+            enum Foo { "a" };
+            interface Foo;
+        """)
+        results = parser.finish()
+        harness.ok(False, "Should fail to parse")
+    except Exception, e:
+        harness.ok("Name collision" in e.message,
+                   "Should have name collision for interface")
+
+    parser = parser.reset()
+    try:
+        parser.parse("""
+            dictionary Foo { long x; };
+            enum Foo { "a" };
+        """)
+        results = parser.finish()
+        harness.ok(False, "Should fail to parse")
+    except Exception, e:
+        harness.ok("Name collision" in e.message,
+                   "Should have name collision for dictionary")
+
+    parser = parser.reset()
+    try:
+        parser.parse("""
+            enum Foo { "a" };
+            enum Foo { "b" };
+        """)
+        results = parser.finish()
+        harness.ok(False, "Should fail to parse")
+    except Exception, e:
+        harness.ok("Multiple unresolvable definitions" in e.message,
+                   "Should have name collision for dictionary")
+
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -7354,18 +7354,17 @@ HTMLInputElement::HasPatternMismatch() c
   nsIDocument* doc = OwnerDoc();
 
   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
 }
 
 bool
 HTMLInputElement::IsRangeOverflow() const
 {
-  // TODO: this is temporary until bug 888316 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
+  if (!DoesMinMaxApply()) {
     return false;
   }
 
   Decimal maximum = GetMaximum();
   if (maximum.isNaN()) {
     return false;
   }
 
@@ -7375,18 +7374,17 @@ HTMLInputElement::IsRangeOverflow() cons
   }
 
   return value > maximum;
 }
 
 bool
 HTMLInputElement::IsRangeUnderflow() const
 {
-  // TODO: this is temporary until bug 888316 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
+  if (!DoesMinMaxApply()) {
     return false;
   }
 
   Decimal minimum = GetMinimum();
   if (minimum.isNaN()) {
     return false;
   }
 
@@ -8381,18 +8379,17 @@ HTMLInputElement::UpdateHasRange()
 {
   /*
    * There is a range if min/max applies for the type and if the element
    * currently have a valid min or max.
    */
 
   mHasRange = false;
 
-  // TODO: this is temporary until bug 888316 is fixed.
-  if (!DoesMinMaxApply() || mType == NS_FORM_INPUT_WEEK) {
+  if (!DoesMinMaxApply()) {
     return;
   }
 
   Decimal minimum = GetMinimum();
   if (!minimum.isNaN()) {
     mHasRange = true;
     return;
   }
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1612,28 +1612,16 @@ nsresult HTMLMediaElement::LoadResource(
   nsCOMPtr<nsIDocShell> docShell = OwnerDoc()->GetDocShell();
   if (docShell && !docShell->GetAllowMedia()) {
     return NS_ERROR_FAILURE;
   }
 
   // Set the media element's CORS mode only when loading a resource
   mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
 
-  bool isBlob = false;
-  if (mMediaKeys &&
-      Preferences::GetBool("media.eme.mse-only", true) &&
-      // We only want mediaSource URLs, but they are BlobURL, so we have to
-      // check the schema and if they are not MediaStream or real Blob.
-      (NS_FAILED(mLoadingSrc->SchemeIs(BLOBURI_SCHEME, &isBlob)) ||
-       !isBlob ||
-       IsMediaStreamURI(mLoadingSrc) ||
-       IsBlobURI(mLoadingSrc))) {
-    return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
-  }
-
   HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
   if (other && other->mDecoder) {
     // Clone it.
     nsresult rv = InitializeDecoderAsClone(other->mDecoder);
     if (NS_SUCCEEDED(rv))
       return rv;
   }
 
--- a/dom/html/test/forms/test_max_attribute.html
+++ b/dom/html/test/forms/test_max_attribute.html
@@ -25,18 +25,17 @@ var data = [
   { type: 'search', apply: false },
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'datetime', apply: true, todo: true },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
-  // TODO: temporary set to false until bug 888316 is fixed.
-  { type: 'week', apply: false },
+  { type: 'week', apply: true },
   { type: 'time', apply: true },
   { type: 'datetime-local', apply: true, todo: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
@@ -67,17 +66,17 @@ function checkValidity(aElement, aValidi
   aValidity = aApply ? aValidity : true;
 
   is(aElement.validity.valid, aValidity,
      "element validity should be " + aValidity);
   is(aElement.validity.rangeOverflow, !aValidity,
      "element overflow status should be " + !aValidity);
   var overflowMsg =
         (aElement.type == "date" || aElement.type == "time" ||
-         aElement.type == "month") ?
+         aElement.type == "month" || aElement.type == "week") ?
         ("Please select a value that is no later than " + aElement.max + ".") :
         ("Please select a value that is no more than " + aElement.max + ".");
   is(aElement.validationMessage,
      aValidity ? "" : overflowMsg, "Checking range overflow validation message");
 
   is(aElement.matches(":valid"), aElement.willValidate && aValidity,
      (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
   is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
@@ -146,17 +145,17 @@ for (var test of data) {
       checkValidity(input, false, apply, apply);
       // Now make it something that won't cause an error below:
       input.max = '10';
       break;
     case 'month':
       input.max = '2016-12';
       break;
     case 'week':
-      // TODO: this is temporary until bug 888316 is fixed.
+      input.max = '2016-W39';
       break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   checkValidity(input, true, apply, apply);
 
   switch (input.type) {
@@ -378,18 +377,55 @@ for (var test of data) {
       input.value = '0049-12';
       checkValidity(input, true, apply, apply);
 
       input.max = '';
       checkValidity(input, true, apply, false);
 
       input.max = 'foo';
       checkValidity(input, true, apply, false);
+
+      break;
     case 'week':
-      // TODO: this is temporary until bug 888316 is fixed.
+      input.value = '2016-W01';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-W39';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2017-W01';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '2017-W01';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2017-W52';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-W01';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2100-W01';
+      checkValidity(input, false, apply, apply);
+
+      input.max = '0050-W01';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '0049-W52';
+      checkValidity(input, true, apply, apply);
+
+      input.max = '';
+      checkValidity(input, true, apply, false);
+
+      input.max = 'foo';
+      checkValidity(input, true, apply, false);
+
       break;
   }
 
   // Cleaning up,
   input.removeAttribute('max');
   input.value = '';
 }
 
--- a/dom/html/test/forms/test_min_attribute.html
+++ b/dom/html/test/forms/test_min_attribute.html
@@ -25,18 +25,17 @@ var data = [
   { type: 'search', apply: false },
   { type: 'tel', apply: false },
   { type: 'url', apply: false },
   { type: 'email', apply: false },
   { type: 'password', apply: false },
   { type: 'datetime', apply: true, todo: true },
   { type: 'date', apply: true },
   { type: 'month', apply: true },
-  // TODO: temporary set to false until bug 888316 is fixed.
-  { type: 'week', apply: false },
+  { type: 'week', apply: true },
   { type: 'time', apply: true },
   { type: 'datetime-local', apply: true, todo: true },
   { type: 'number', apply: true },
   { type: 'range', apply: true },
   { type: 'color', apply: false },
   { type: 'checkbox', apply: false },
   { type: 'radio', apply: false },
   { type: 'file', apply: false },
@@ -67,17 +66,17 @@ function checkValidity(aElement, aValidi
   aValidity = aApply ? aValidity : true;
 
   is(aElement.validity.valid, aValidity,
      "element validity should be " + aValidity);
   is(aElement.validity.rangeUnderflow, !aValidity,
      "element underflow status should be " + !aValidity);
   var underflowMsg =
         (aElement.type == "date" || aElement.type == "time" ||
-         aElement.type == "month") ?
+         aElement.type == "month" || aElement.type == "week") ?
         ("Please select a value that is no earlier than " + aElement.min + ".") :
         ("Please select a value that is no less than " + aElement.min + ".");
   is(aElement.validationMessage,
      aValidity ? "" : underflowMsg, "Checking range underflow validation message");
 
   is(aElement.matches(":valid"), aElement.willValidate && aValidity,
      (aElement.willValidate && aValidity) ? ":valid should apply" : "valid shouldn't apply");
   is(aElement.matches(":invalid"), aElement.willValidate && !aValidity,
@@ -142,17 +141,17 @@ for (var test of data) {
       // range is special, since setting min to 999 will make it invalid since
       // it's default maximum is 100, its value would be 999, and it would
       // suffer from overflow.
       break;
     case 'month':
       input.min = '2016-06';
       break;
     case 'week':
-      // TODO: this is temporary until bug 888316 is fixed.
+      input.min = "2016-W39";
       break;
     default:
       ok(false, 'please, add a case for this new type (' + input.type + ')');
   }
 
   // The element should still be valid and range should apply if it can.
   checkValidity(input, true, apply, apply);
 
@@ -376,17 +375,51 @@ for (var test of data) {
 
       input.min = '';
       checkValidity(input, true, apply, false);
 
       input.min = 'foo';
       checkValidity(input, true, apply, false);
       break;
     case 'week':
-      // TODO: this is temporary until bug 888316 is fixed.
+      input.value = '2016-W40';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-W39';
+      checkValidity(input, true, apply, apply);
+
+      input.value = 'foo';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2016-W38';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '2016-W01';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '2015-W53';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '1000-W01';
+      checkValidity(input, false, apply, apply);
+
+      input.value = '10000-01';
+      checkValidity(input, true, apply, apply);
+
+      input.min = '0010-W01';
+      checkValidity(input, true, apply, apply);
+
+      input.value = '0001-W01';
+      checkValidity(input, false, apply, apply);
+
+      input.min = '';
+      checkValidity(input, true, apply, false);
+
+      input.min = 'foo';
+      checkValidity(input, true, apply, false);
       break;
     default:
       ok(false, 'write tests for ' + input.type);
   }
 
   // Cleaning up,
   input.removeAttribute('min');
   input.value = '';
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -634,17 +634,17 @@ IDBTransaction::AbortInternal(nsresult a
   AssertIsOnOwningThread();
   MOZ_ASSERT(NS_FAILED(aAbortCode));
   MOZ_ASSERT(!IsCommittingOrDone());
 
   RefPtr<DOMError> error = aError;
 
   const bool isVersionChange = mMode == VERSION_CHANGE;
   const bool isInvalidated = mDatabase->IsInvalidated();
-  bool needToSendAbort = mReadyState == INITIAL && !isInvalidated;
+  bool needToSendAbort = mReadyState == INITIAL;
 
   mAbortCode = aAbortCode;
   mReadyState = DONE;
   mError = error.forget();
 
   if (isVersionChange) {
     // If a version change transaction is aborted, we must revert the world
     // back to its previous state unless we're being invalidated after the
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -106,17 +106,17 @@ struct ShowInfo
 };
 
 union OptionalShmem
 {
   void_t;
   Shmem;
 };
 
-prio(normal upto urgent) sync protocol PBrowser
+nested(upto inside_cpow) sync protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
     manages PDatePicker;
     manages PDocAccessible;
     manages PDocumentRenderer;
     manages PFilePicker;
@@ -199,145 +199,145 @@ parent:
     async DropLinks(nsString[] aLinks);
 
     async Event(RemoteDOMEvent aEvent);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
-    prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
-                               CpowEntry[] aCpows, Principal aPrincipal)
+    nested(inside_sync) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+                                        CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     /**
      * Notifies chrome that there is a focus change involving an editable
      * object (input, textarea, document, contentEditable. etc.)
      *
      *  contentCache Cache of content
      *  notification Whole data of the notification
      *  preference   Native widget preference for IME updates
      */
-    prio(urgent) sync NotifyIMEFocus(ContentCache contentCache,
-                                     IMENotification notification)
+    nested(inside_cpow) sync NotifyIMEFocus(ContentCache contentCache,
+                                            IMENotification notification)
       returns (nsIMEUpdatePreference preference);
 
     /**
      * Notifies chrome that there has been a change in text content
      * One call can encompass both a delete and an insert operation
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
      *  contentCache Cache of content
      *  notification Whole data of the notification
      */
-    prio(urgent) async NotifyIMETextChange(ContentCache contentCache,
-                                           IMENotification notification);
+    nested(inside_cpow) async NotifyIMETextChange(ContentCache contentCache,
+                                                  IMENotification notification);
 
     /**
      * Notifies chrome that there is a IME compostion rect updated
      *
      *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMECompositionUpdate(ContentCache contentCache,
-                                                  IMENotification notification);
+    nested(inside_cpow) async NotifyIMECompositionUpdate(ContentCache contentCache,
+                                                         IMENotification notification);
 
     /**
      * Notifies chrome that there has been a change in selection
      * Only called when NotifyIMEFocus returns PR_TRUE for mWantUpdates
      *
      *  contentCache Cache of content
      *  notification Whole data of the notification
      */
-    prio(urgent) async NotifyIMESelection(ContentCache contentCache,
-                                          IMENotification notification);
+    nested(inside_cpow) async NotifyIMESelection(ContentCache contentCache,
+                                                 IMENotification notification);
 
     /**
      * Notifies chrome of updating its content cache.
      * This is useful if content is modified but we don't need to notify IME.
      *
      *  contentCache Cache of content
      */
-    prio(urgent) async UpdateContentCache(ContentCache contentCache);
+    nested(inside_cpow) async UpdateContentCache(ContentCache contentCache);
 
     /**
      * Notifies IME of mouse button event on a character in focused editor.
      *
      * Returns true if the mouse button event is consumd by IME.
      */
-    prio(urgent) sync NotifyIMEMouseButtonEvent(IMENotification notification)
+    nested(inside_cpow) sync NotifyIMEMouseButtonEvent(IMENotification notification)
       returns (bool consumedByIME);
 
     /**
      * Notifies chrome to position change
      *
      *  contentCache Cache of content
      */
-    prio(urgent) async NotifyIMEPositionChange(ContentCache contentCache,
-                                               IMENotification notification);
+    nested(inside_cpow) async NotifyIMEPositionChange(ContentCache contentCache,
+                                                      IMENotification notification);
 
     /**
      * Requests chrome to commit or cancel composition of IME.
      *
      *  cancel                Set true if composition should be cancelled.
      *
      *  isCommitted           Returns true if the request causes composition
      *                        being committed synchronously.
      *  committedString       Returns committed string.  The may be non-empty
      *                        string even if cancel is true because IME may
      *                        try to restore selected string which was
      *                        replaced with the composition.
      */
-    prio(urgent) sync RequestIMEToCommitComposition(bool cancel)
+    nested(inside_cpow) sync RequestIMEToCommitComposition(bool cancel)
                         returns (bool isCommitted, nsString committedString);
 
     /**
      * OnEventNeedingAckHandled() is called after a child process dispatches a
      * composition event or a selection event which is sent from the parent
      * process.
      *
      * message      The message value of the handled event.
      */
-    prio(urgent) async OnEventNeedingAckHandled(EventMessage message);
+    nested(inside_cpow) async OnEventNeedingAckHandled(EventMessage message);
 
     /**
      * Tells chrome to start plugin IME.  If this results in a string getting
      * committed, the result is in aCommitted (otherwise aCommitted is empty).
      *
      * aKeyboardEvent     The event with which plugin IME is to be started
      * panelX and panelY  Location in screen coordinates of the IME input panel
      *                    (should be just under the plugin)
      * aCommitted         The string committed during IME -- otherwise empty
      */
-    prio(urgent) sync StartPluginIME(WidgetKeyboardEvent aKeyboardEvent,
-                                     int32_t panelX, int32_t panelY)
-                                     returns (nsString aCommitted);
+    nested(inside_cpow) sync StartPluginIME(WidgetKeyboardEvent aKeyboardEvent,
+                                            int32_t panelX, int32_t panelY)
+        returns (nsString aCommitted);
 
     /**
      * Tells chrome (and specifically the appropriate widget) whether or not
      * a plugin (inside the widget) has the keyboard focus.  Should be sent
      * when the keyboard focus changes too or from a plugin.
      *
      * aFocused  Whether or not a plugin is focused
      */
-    prio(urgent) async SetPluginFocused(bool aFocused);
+    nested(inside_cpow) async SetPluginFocused(bool aFocused);
 
     /**
      * Set IME candidate window by windowless plugin if plugin has focus.
      */
     async SetCandidateWindowForPlugin(CandidateWindowPosition aPosition);
 
     /**
      * Notifies the parent process of native key event data received in a
      * plugin process directly.
      *
      * aKeyEventData    The native key event data.  The actual type copied into
      *                  NativeEventData depending on the caller.  Please check
      *                  PluginInstanceChild.
      */
-    prio(urgent) async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
+    nested(inside_cpow) async OnWindowedPluginKeyEvent(NativeEventData aKeyEventData);
 
     /**
      *  When plugin event isn't consumed, call this
      */
     async DefaultProcOfPluginEvent(WidgetPluginEvent aEvent);
 
     /**
      * Request that the parent process move focus to the browser's frame. If
@@ -348,26 +348,26 @@ parent:
     /**
      * Indicate, based on the current state, that some commands are enabled and
      * some are disabled.
      */
     async EnableDisableCommands(nsString action,
                                 nsCString[] enabledCommands,
                                 nsCString[] disabledCommands);
 
-    prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled,
-                                                 int32_t IMEOpen);
+    nested(inside_cpow) sync GetInputContext() returns (int32_t IMEEnabled,
+                                                        int32_t IMEOpen);
 
-    prio(urgent) async SetInputContext(int32_t IMEEnabled,
-                                       int32_t IMEOpen,
-                                       nsString type,
-                                       nsString inputmode,
-                                       nsString actionHint,
-                                       int32_t cause,
-                                       int32_t focusChange);
+    nested(inside_cpow) async SetInputContext(int32_t IMEEnabled,
+                                              int32_t IMEOpen,
+                                              nsString type,
+                                              nsString inputmode,
+                                              nsString actionHint,
+                                              int32_t cause,
+                                              int32_t focusChange);
 
     sync IsParentWindowMainWidgetVisible() returns (bool visible);
 
     /**
      * Gets the DPI of the screen corresponding to this browser.
      */
     sync GetDPI() returns (float value);
 
@@ -574,19 +574,19 @@ parent:
     async ForcePaintNoOp(uint64_t aLayerObserverEpoch);
 
     /**
      * Sent by the child to the parent to inform it that an update to the
      * dimensions has been requested, likely through win.moveTo or resizeTo
      */
     async SetDimensions(uint32_t aFlags, int32_t aX, int32_t aY, int32_t aCx, int32_t aCy);
 
-    prio(high) sync DispatchWheelEvent(WidgetWheelEvent event);
-    prio(high) sync DispatchMouseEvent(WidgetMouseEvent event);
-    prio(high) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
+    nested(inside_sync) sync DispatchWheelEvent(WidgetWheelEvent event);
+    nested(inside_sync) sync DispatchMouseEvent(WidgetMouseEvent event);
+    nested(inside_sync) sync DispatchKeyboardEvent(WidgetKeyboardEvent event);
 
     async InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action,
                             OptionalShmem visualData,
                             uint32_t width, uint32_t height,
                             uint32_t stride, uint8_t format,
                             int32_t dragAreaX, int32_t dragAreaY);
 
     async AudioChannelActivityNotification(uint32_t aAudioChannel,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -372,17 +372,17 @@ union GetFilesResponseResult
 
 struct BlobURLRegistrationData
 {
     nsCString url;
     PBlob blob;
     Principal principal;
 };
 
-prio(normal upto urgent) sync protocol PContent
+nested(upto inside_cpow) sync protocol PContent
 {
     parent spawns PPluginModule;
 
     parent opens PProcessHangMonitor;
     parent opens PSharedBufferManager;
     parent opens PGMPService;
     child opens PBackground;
 
@@ -838,42 +838,42 @@ parent:
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
     async AccumulateMixedContentHSTS(URIParams uri, bool active, bool hasHSTSPriming);
 
     sync GetLookAndFeelCache()
         returns (LookAndFeelInt[] lookAndFeelIntCache);
 
-    prio(urgent) async PHal();
+    nested(inside_cpow) async PHal();
 
     async PHeapSnapshotTempFileHelper();
 
     async PIcc(uint32_t serviceId);
 
     async PMobileConnection(uint32_t clientId);
 
     async PNecko();
 
     async PPrinting();
 
     async PSendStream();
 
-    prio(high) sync PScreenManager()
+    nested(inside_sync) sync PScreenManager()
         returns (uint32_t numberOfScreens,
                  float systemDefaultScale,
                  bool success);
 
     async PCellBroadcast();
 
     async PSms();
 
     async PSpeechSynthesis();
 
-    prio(urgent) async PStorage();
+    nested(inside_cpow) async PStorage();
 
     async PTelephony();
 
     async PVoicemail();
 
     async PMedia();
 
     async PBluetooth();
@@ -903,18 +903,18 @@ parent:
 
     sync ReadDataStorageArray(nsString aFilename)
       returns (DataStorageItem[] retValue);
 
     sync SyncMessage(nsString aMessage, ClonedMessageData aData,
                      CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
-    prio(high) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
-                               CpowEntry[] aCpows, Principal aPrincipal)
+    nested(inside_sync) sync RpcMessage(nsString aMessage, ClonedMessageData aData,
+                                        CpowEntry[] aCpows, Principal aPrincipal)
       returns (StructuredCloneData[] retval);
 
     async ShowAlert(AlertNotificationType alert);
 
     async CloseAlert(nsString name, Principal principal);
 
     async DisableNotifications(Principal principal);
 
@@ -1052,20 +1052,20 @@ parent:
 
     sync OpenAnonymousTemporaryFile() returns (FileDescOrError aFD);
 
     /**
      * Keygen requires us to call it after a <keygen> element is parsed and
      * before one is submitted. This is urgent because an extension might use
      * a CPOW to synchronously submit a keygen element.
      */
-    prio(urgent) sync KeygenProcessValue(nsString oldValue,
-                                         nsString challenge,
-                                         nsString keytype,
-                                         nsString keyparams)
+    nested(inside_cpow) sync KeygenProcessValue(nsString oldValue,
+                                                nsString challenge,
+                                                nsString keytype,
+                                                nsString keyparams)
         returns (nsString newValue);
 
     /**
      * Called to provide the options for <keygen> elements.
      */
     sync KeygenProvideContent()
         returns (nsString aAttribute, nsString[] aContent);
 
--- a/dom/ipc/PContentBridge.ipdl
+++ b/dom/ipc/PContentBridge.ipdl
@@ -27,17 +27,17 @@ namespace dom {
 /*
  * PContentBridge allows us to represent a parent/child relationship between two
  * child processes.  When a child process wants to open its own child, it asks
  * the root process to create a new process and then bridge them.  The first
  * child will allocate the PContentBridgeParent, and the newly opened child will
  * allocate the PContentBridgeChild.  This protocol allows these processes to
  * share PBrowsers and send messages to each other.
  */
-prio(normal upto urgent) sync protocol PContentBridge
+nested(upto inside_cpow) sync protocol PContentBridge
 {
     bridges PContent, PContent;
 
     manages PBlob;
     manages PBrowser;
     manages PFileDescriptorSet;
     manages PJavaScript;
     manages PSendStream;
--- a/dom/ipc/PScreenManager.ipdl
+++ b/dom/ipc/PScreenManager.ipdl
@@ -20,42 +20,42 @@ struct ScreenDetails {
   nsIntRect rectDisplayPix;
   nsIntRect availRect;
   nsIntRect availRectDisplayPix;
   int32_t pixelDepth;
   int32_t colorDepth;
   double contentsScaleFactor;
 };
 
-prio(normal upto high) sync protocol PScreenManager
+nested(upto inside_sync) sync protocol PScreenManager
 {
   manager PContent;
 
 parent:
-    prio(high) sync Refresh()
+    nested(inside_sync) sync Refresh()
       returns (uint32_t numberOfScreens,
                float systemDefaultScale,
                bool success);
 
-    prio(high) sync ScreenRefresh(uint32_t aId)
+    nested(inside_sync) sync ScreenRefresh(uint32_t aId)
       returns (ScreenDetails screen,
                bool success);
 
-    prio(high) sync GetPrimaryScreen()
+    nested(inside_sync) sync GetPrimaryScreen()
       returns (ScreenDetails screen,
                bool success);
 
-    prio(high) sync ScreenForRect(int32_t aLeft,
-                       int32_t aTop,
-                       int32_t aWidth,
-                       int32_t aHeight)
+    nested(inside_sync) sync ScreenForRect(int32_t aLeft,
+                                           int32_t aTop,
+                                           int32_t aWidth,
+                                           int32_t aHeight)
       returns (ScreenDetails screen,
                bool success);
 
-    prio(high) sync ScreenForBrowser(TabId aTabId)
+    nested(inside_sync) sync ScreenForBrowser(TabId aTabId)
       returns (ScreenDetails screen,
                bool success);
 
 child:
     async __delete__();
 };
 
 } // namespace dom
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -216,16 +216,22 @@ public:
 
   virtual bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart)
   {
     return false;
   }
 
   virtual bool HandleEndOfStream() { return false; }
 
+  virtual RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget)
+  {
+    MOZ_ASSERT(false, "Can't seek in this state");
+    return nullptr;
+  }
+
 protected:
   using Master = MediaDecoderStateMachine;
   explicit StateObject(Master* aPtr) : mMaster(aPtr) {}
   TaskQueue* OwnerThread() const { return mMaster->mTaskQueue; }
   MediaResource* Resource() const { return mMaster->mResource; }
   MediaDecoderReaderWrapper* Reader() const { return mMaster->mReader; }
 
   // Note this function will delete the current state object.
@@ -371,16 +377,24 @@ public:
     return DECODER_STATE_WAIT_FOR_CDM;
   }
 
   bool HandleCDMProxyReady() override
   {
     SetState(DECODER_STATE_DECODING_FIRSTFRAME);
     return true;
   }
+
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    SLOG("Not Enough Data to seek at this stage, queuing seek");
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    mMaster->mQueuedSeek.mTarget = aTarget;
+    return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
+  }
 };
 
 class MediaDecoderStateMachine::DormantState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DormantState(Master* aPtr) : StateObject(aPtr) {}
 
@@ -402,53 +416,122 @@ public:
   bool HandleDormant(bool aDormant) override
   {
     if (!aDormant) {
       // Exit dormant state.
       SetState(DECODER_STATE_DECODING_METADATA);
     }
     return true;
   }
+
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    SLOG("Not Enough Data to seek at this stage, queuing seek");
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    mMaster->mQueuedSeek.mTarget = aTarget;
+    return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
+  }
 };
 
 class MediaDecoderStateMachine::DecodingFirstFrameState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DecodingFirstFrameState(Master* aPtr) : StateObject(aPtr) {}
 
   void Enter() override
   {
-    mMaster->DecodeFirstFrame();
+    // Handle pending seek.
+    if (mMaster->mQueuedSeek.Exists() &&
+        (mMaster->mSentFirstFrameLoadedEvent ||
+         Reader()->ForceZeroStartTime())) {
+      mMaster->InitiateSeek(Move(mMaster->mQueuedSeek));
+      return;
+    }
+
+    // Transition to DECODING if we've decoded first frames.
+    if (mMaster->mSentFirstFrameLoadedEvent) {
+      SetState(DECODER_STATE_DECODING);
+      return;
+    }
+
+    // Dispatch tasks to decode first frames.
+    mMaster->DispatchDecodeTasksIfNeeded();
   }
 
   State GetState() const override
   {
     return DECODER_STATE_DECODING_FIRSTFRAME;
   }
 
   bool HandleAudioDecoded(MediaData* aAudio) override
   {
     mMaster->Push(aAudio, MediaData::AUDIO_DATA);
-    mMaster->MaybeFinishDecodeFirstFrame();
+    MaybeFinishDecodeFirstFrame();
     return true;
   }
 
   bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
   {
     mMaster->Push(aVideo, MediaData::VIDEO_DATA);
-    mMaster->MaybeFinishDecodeFirstFrame();
+    MaybeFinishDecodeFirstFrame();
     return true;
   }
 
   bool HandleEndOfStream() override
   {
-    mMaster->MaybeFinishDecodeFirstFrame();
+    MaybeFinishDecodeFirstFrame();
     return true;
   }
+
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    // Should've transitioned to DECODING in Enter()
+    // if mSentFirstFrameLoadedEvent is true.
+    MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
+
+    if (!Reader()->ForceZeroStartTime()) {
+      SLOG("Not Enough Data to seek at this stage, queuing seek");
+      mMaster->mQueuedSeek.RejectIfExists(__func__);
+      mMaster->mQueuedSeek.mTarget = aTarget;
+      return mMaster->mQueuedSeek.mPromise.Ensure(__func__);
+    }
+
+    // Since ForceZeroStartTime() is true, we should've transitioned to SEEKING
+    // in Enter() if there is any queued seek.
+    MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
+
+    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = aTarget;
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    mMaster->InitiateSeek(Move(seekJob));
+    return p.forget();
+  }
+
+private:
+  // Notify FirstFrameLoaded if having decoded first frames and
+  // transition to SEEKING if there is any pending seek, or DECODING otherwise.
+  void MaybeFinishDecodeFirstFrame()
+  {
+    MOZ_ASSERT(!mMaster->mSentFirstFrameLoadedEvent);
+
+    if ((mMaster->IsAudioDecoding() && mMaster->AudioQueue().GetSize() == 0) ||
+        (mMaster->IsVideoDecoding() && mMaster->VideoQueue().GetSize() == 0)) {
+      return;
+    }
+
+    mMaster->FinishDecodeFirstFrame();
+
+    if (mMaster->mQueuedSeek.Exists()) {
+      mMaster->InitiateSeek(Move(mMaster->mQueuedSeek));
+    } else {
+      SetState(DECODER_STATE_DECODING);
+    }
+  }
 };
 
 class MediaDecoderStateMachine::DecodingState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit DecodingState(Master* aPtr) : StateObject(aPtr) {}
 
@@ -520,16 +603,27 @@ public:
   bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
   {
     mMaster->Push(aVideo, MediaData::VIDEO_DATA);
     mMaster->MaybeStopPrerolling();
     CheckSlowDecoding(aDecodeStart);
     return true;
   }
 
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = aTarget;
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    mMaster->InitiateSeek(Move(seekJob));
+    return p.forget();
+  }
+
 private:
   void CheckSlowDecoding(TimeStamp aDecodeStart)
   {
     // For non async readers, if the requested video sample was slow to
     // arrive, increase the amount of audio we buffer to ensure that we
     // don't run out of audio. This is unnecessary for async readers,
     // since they decode audio and video on different threads so they
     // are unlikely to run out of decoded audio.
@@ -568,17 +662,80 @@ private:
   // Time at which we started decoding.
   TimeStamp mDecodeStartTime;
 };
 
 class MediaDecoderStateMachine::SeekingState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
-  explicit SeekingState(Master* aPtr) : StateObject(aPtr) {}
+  explicit SeekingState(Master* aPtr, SeekJob aSeekJob)
+    : StateObject(aPtr), mSeekJob(Move(aSeekJob)) {}
+
+  void Enter() override
+  {
+    // Discard the existing seek task.
+    mMaster->DiscardSeekTaskIfExist();
+
+    mMaster->mSeekTaskRequest.DisconnectIfExists();
+
+    // SeekTask will register its callbacks to MediaDecoderReaderWrapper.
+    mMaster->CancelMediaDecoderReaderWrapperCallback();
+
+    // Create a new SeekTask instance for the incoming seek task.
+    if (mSeekJob.mTarget.IsAccurate() ||
+        mSeekJob.mTarget.IsFast()) {
+      mMaster->mSeekTask = new AccurateSeekTask(
+        mMaster->mDecoderID, OwnerThread(), Reader(), mSeekJob.mTarget,
+        mMaster->mInfo, mMaster->Duration(), mMaster->GetMediaTime());
+    } else if (mSeekJob.mTarget.IsNextFrame()) {
+      mMaster->mSeekTask = new NextFrameSeekTask(
+        mMaster->mDecoderID, OwnerThread(), Reader(), mSeekJob.mTarget,
+        mMaster->mInfo, mMaster->Duration(),mMaster->GetMediaTime(),
+        mMaster->AudioQueue(), mMaster->VideoQueue());
+    } else {
+      MOZ_DIAGNOSTIC_ASSERT(false, "Cannot handle this seek task.");
+    }
+
+    // Don't stop playback for a video-only seek since audio is playing.
+    if (!mSeekJob.mTarget.IsVideoOnly()) {
+      mMaster->StopPlayback();
+    }
+
+    // mSeekJob.mTarget.mTime might be different from
+    // mSeekTask->GetSeekTarget().mTime because the seek task might clamp the
+    // seek target to [0, duration]. We want to update the playback position to
+    // the clamped value.
+    mMaster->UpdatePlaybackPositionInternal(
+      mMaster->mSeekTask->GetSeekTarget().GetTime().ToMicroseconds());
+
+    if (mSeekJob.mTarget.mEventVisibility ==
+        MediaDecoderEventVisibility::Observable) {
+      mMaster->mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
+    }
+
+    // Reset our state machine and decoding pipeline before seeking.
+    if (mMaster->mSeekTask->NeedToResetMDSM()) {
+      if (mSeekJob.mTarget.IsVideoOnly()) {
+        mMaster->Reset(TrackInfo::kVideoTrack);
+      } else {
+        mMaster->Reset();
+      }
+    }
+
+    // Do the seek.
+    mMaster->mSeekTaskRequest.Begin(mMaster->mSeekTask->Seek(mMaster->Duration())
+      ->Then(OwnerThread(), __func__, mMaster,
+             &MediaDecoderStateMachine::OnSeekTaskResolved,
+             &MediaDecoderStateMachine::OnSeekTaskRejected));
+
+    MOZ_ASSERT(!mMaster->mQueuedSeek.Exists());
+    MOZ_ASSERT(!mMaster->mCurrentSeek.Exists());
+    mMaster->mCurrentSeek = Move(mSeekJob);
+  }
 
   State GetState() const override
   {
     return DECODER_STATE_SEEKING;
   }
 
   bool HandleDormant(bool aDormant) override
   {
@@ -606,16 +763,30 @@ public:
     return true;
   }
 
   bool HandleVideoDecoded(MediaData* aVideo, TimeStamp aDecodeStart) override
   {
     MOZ_ASSERT(false);
     return true;
   }
+
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = aTarget;
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    mMaster->InitiateSeek(Move(seekJob));
+    return p.forget();
+  }
+
+private:
+  SeekJob mSeekJob;
 };
 
 class MediaDecoderStateMachine::BufferingState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
   explicit BufferingState(Master* aPtr) : StateObject(aPtr) {}
 
@@ -707,16 +878,27 @@ public:
       SetState(DECODER_STATE_COMPLETED);
     } else {
       // Check if we can exit buffering.
       mMaster->ScheduleStateMachine();
     }
     return true;
   }
 
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = aTarget;
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    mMaster->InitiateSeek(Move(seekJob));
+    return p.forget();
+  }
+
 private:
   TimeStamp mBufferingStart;
 };
 
 class MediaDecoderStateMachine::CompletedState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
@@ -775,16 +957,27 @@ public:
     }
   }
 
   State GetState() const override
   {
     return DECODER_STATE_COMPLETED;
   }
 
+  RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override
+  {
+    mMaster->mQueuedSeek.RejectIfExists(__func__);
+    SLOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
+    SeekJob seekJob;
+    seekJob.mTarget = aTarget;
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    mMaster->InitiateSeek(Move(seekJob));
+    return p.forget();
+  }
+
 private:
   bool mSentPlaybackEndedEvent = false;
 };
 
 class MediaDecoderStateMachine::ShutdownState
   : public MediaDecoderStateMachine::StateObject
 {
 public:
@@ -1245,36 +1438,16 @@ MediaDecoderStateMachine::OnNotDecoded(M
   }
 
   MaybeStopPrerolling();
 
   mStateObj->HandleEndOfStream();
 }
 
 void
-MediaDecoderStateMachine::MaybeFinishDecodeFirstFrame()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(!mSentFirstFrameLoadedEvent);
-
-  if ((IsAudioDecoding() && AudioQueue().GetSize() == 0) ||
-      (IsVideoDecoding() && VideoQueue().GetSize() == 0)) {
-    return;
-  }
-
-  FinishDecodeFirstFrame();
-
-  if (mQueuedSeek.Exists()) {
-    InitiateSeek(Move(mQueuedSeek));
-  } else {
-    SetState(DECODER_STATE_DECODING);
-  }
-}
-
-void
 MediaDecoderStateMachine::OnVideoDecoded(MediaData* aVideo,
                                          TimeStamp aDecodeStartTime)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(aVideo);
 
   // Handle abnormal or negative timestamps.
   mDecodedVideoEndTime = std::max(mDecodedVideoEndTime, aVideo->GetEndTime());
@@ -1571,19 +1744,16 @@ MediaDecoderStateMachine::SetState(State
       mStateObj = MakeUnique<DormantState>(this);
       break;
     case DECODER_STATE_DECODING_FIRSTFRAME:
       mStateObj = MakeUnique<DecodingFirstFrameState>(this);
       break;
     case DECODER_STATE_DECODING:
       mStateObj = MakeUnique<DecodingState>(this);
       break;
-    case DECODER_STATE_SEEKING:
-      mStateObj = MakeUnique<SeekingState>(this);
-      break;
     case DECODER_STATE_BUFFERING:
       mStateObj = MakeUnique<BufferingState>(this);
       break;
     case DECODER_STATE_COMPLETED:
       mStateObj = MakeUnique<CompletedState>(this);
       break;
     case DECODER_STATE_SHUTDOWN:
       mStateObj = MakeUnique<ShutdownState>(this);
@@ -1725,39 +1895,16 @@ MediaDecoderStateMachine::Shutdown()
   // the queue to spin down.
   return mReader->Shutdown()
     ->Then(OwnerThread(), __func__, this,
            &MediaDecoderStateMachine::FinishShutdown,
            &MediaDecoderStateMachine::FinishShutdown)
     ->CompletionPromise();
 }
 
-void
-MediaDecoderStateMachine::DecodeFirstFrame()
-{
-  MOZ_ASSERT(OnTaskQueue());
-  MOZ_ASSERT(mState == DECODER_STATE_DECODING_FIRSTFRAME);
-
-  // Handle pending seek.
-  if (mQueuedSeek.Exists() &&
-      (mSentFirstFrameLoadedEvent || mReader->ForceZeroStartTime())) {
-    InitiateSeek(Move(mQueuedSeek));
-    return;
-  }
-
-  // Transition to DECODING if we've decoded first frames.
-  if (mSentFirstFrameLoadedEvent) {
-    SetState(DECODER_STATE_DECODING);
-    return;
-  }
-
-  // Dispatch tasks to decode first frames.
-  DispatchDecodeTasksIfNeeded();
-}
-
 void MediaDecoderStateMachine::PlayStateChanged()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
     mVideoDecodeSuspendTimer.Reset();
     return;
   }
@@ -1836,21 +1983,16 @@ void MediaDecoderStateMachine::Visibilit
   DECODER_LOG("VisibilityChanged: mIsVisible=%d, "
               "mVideoDecodeSuspended=%c, mIsReaderSuspended=%d",
               mIsVisible.Ref(), mVideoDecodeSuspended ? 'T' : 'F', mIsReaderSuspended.Ref());
 
   if (!HasVideo()) {
     return;
   }
 
-  // If not playing then there's nothing to do.
-  if (mPlayState != MediaDecoder::PLAY_STATE_PLAYING) {
-    return;
-  }
-
   // Start timer to trigger suspended decoding state when going invisible.
   if (!mIsVisible) {
     TimeStamp target = TimeStamp::Now() + SuspendBackgroundVideoDelay();
 
     RefPtr<MediaDecoderStateMachine> self = this;
     mVideoDecodeSuspendTimer.Ensure(target,
                                     [=]() { self->OnSuspendTimerResolved(); },
                                     [=]() { self->OnSuspendTimerRejected(); });
@@ -1890,20 +2032,21 @@ void MediaDecoderStateMachine::Visibilit
                                   ? SeekTarget::Type::Accurate
                                   : SeekTarget::Type::PrevSyncPoint;
 
     seekJob.mTarget = SeekTarget(GetMediaTime(),
                                  type,
                                  MediaDecoderEventVisibility::Suppressed,
                                  true /* aVideoOnly */);
 
-    InitiateSeek(Move(seekJob))
-      ->Then(AbstractThread::MainThread(), __func__,
-             [start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); },
-             [](){});
+    RefPtr<MediaDecoder::SeekPromise> p = seekJob.mPromise.Ensure(__func__);
+    p->Then(AbstractThread::MainThread(), __func__,
+            [start, info, hw](){ ReportRecoveryTelemetry(start, info, hw); },
+            [](){});
+    InitiateSeek(Move(seekJob));
   }
 }
 
 void MediaDecoderStateMachine::BufferedRangeUpdated()
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // While playing an unseekable stream of unknown duration, mObservedDuration
@@ -1944,34 +2087,17 @@ MediaDecoderStateMachine::Seek(SeekTarge
 
   if (aTarget.IsNextFrame() && !HasVideo()) {
     DECODER_WARN("Ignore a NextFrameSeekTask on a media file without video track.");
     return MediaDecoder::SeekPromise::CreateAndReject(/* aIgnored = */ true, __func__);
   }
 
   MOZ_ASSERT(mDuration.Ref().isSome(), "We should have got duration already");
 
-  // Can't seek until the start time is known.
-  bool hasStartTime = mSentFirstFrameLoadedEvent || mReader->ForceZeroStartTime();
-  // Can't seek when state is WAIT_FOR_CDM or DORMANT.
-  bool stateAllowed = mState >= DECODER_STATE_DECODING_FIRSTFRAME;
-
-  if (!stateAllowed || !hasStartTime) {
-    DECODER_LOG("Seek() Not Enough Data to continue at this stage, queuing seek");
-    mQueuedSeek.RejectIfExists(__func__);
-    mQueuedSeek.mTarget = aTarget;
-    return mQueuedSeek.mPromise.Ensure(__func__);
-  }
-  mQueuedSeek.RejectIfExists(__func__);
-
-  DECODER_LOG("Changed state to SEEKING (to %lld)", aTarget.GetTime().ToMicroseconds());
-
-  SeekJob seekJob;
-  seekJob.mTarget = aTarget;
-  return InitiateSeek(Move(seekJob));
+  return mStateObj->HandleSeek(aTarget);
 }
 
 RefPtr<MediaDecoder::SeekPromise>
 MediaDecoderStateMachine::InvokeSeek(SeekTarget aTarget)
 {
   return InvokeAsync(OwnerThread(), this, __func__,
                      &MediaDecoderStateMachine::Seek, aTarget);
 }
@@ -2042,79 +2168,27 @@ MediaDecoderStateMachine::DispatchDecode
   if (needIdle) {
     DECODER_LOG("Dispatching SetIdle() audioQueue=%lld videoQueue=%lld",
                 GetDecodedAudioDuration(),
                 VideoQueue().Duration());
     mReader->SetIdle();
   }
 }
 
-RefPtr<MediaDecoder::SeekPromise>
+void
 MediaDecoderStateMachine::InitiateSeek(SeekJob aSeekJob)
 {
   MOZ_ASSERT(OnTaskQueue());
 
-  SetState(DECODER_STATE_SEEKING);
-
-  // Discard the existing seek task.
-  DiscardSeekTaskIfExist();
-
-  mSeekTaskRequest.DisconnectIfExists();
-
-  // SeekTask will register its callbacks to MediaDecoderReaderWrapper.
-  CancelMediaDecoderReaderWrapperCallback();
-
-  // Create a new SeekTask instance for the incoming seek task.
-  if (aSeekJob.mTarget.IsAccurate() ||
-      aSeekJob.mTarget.IsFast()) {
-    mSeekTask = new AccurateSeekTask(mDecoderID, OwnerThread(),
-                                     mReader.get(), aSeekJob.mTarget,
-                                     mInfo, Duration(), GetMediaTime());
-  } else if (aSeekJob.mTarget.IsNextFrame()) {
-    mSeekTask = new NextFrameSeekTask(mDecoderID, OwnerThread(), mReader.get(),
-                                      aSeekJob.mTarget, mInfo, Duration(),
-                                      GetMediaTime(), AudioQueue(), VideoQueue());
-  } else {
-    MOZ_DIAGNOSTIC_ASSERT(false, "Cannot handle this seek task.");
-  }
-
-  // Don't stop playback for a video-only seek since audio is playing.
-  if (!aSeekJob.mTarget.IsVideoOnly()) {
-    StopPlayback();
-  }
-
-  // aSeekJob.mTarget.mTime might be different from
-  // mSeekTask->GetSeekTarget().mTime because the seek task might clamp the seek
-  // target to [0, duration]. We want to update the playback position to the
-  // clamped value.
-  UpdatePlaybackPositionInternal(mSeekTask->GetSeekTarget().GetTime().ToMicroseconds());
-
-  if (aSeekJob.mTarget.mEventVisibility == MediaDecoderEventVisibility::Observable) {
-    mOnPlaybackEvent.Notify(MediaEventType::SeekStarted);
-  }
-
-  // Reset our state machine and decoding pipeline before seeking.
-  if (mSeekTask->NeedToResetMDSM()) {
-    if (aSeekJob.mTarget.IsVideoOnly()) {
-      Reset(TrackInfo::kVideoTrack);
-    } else {
-      Reset();
-    }
-  }
-
-  // Do the seek.
-  mSeekTaskRequest.Begin(mSeekTask->Seek(Duration())
-    ->Then(OwnerThread(), __func__, this,
-           &MediaDecoderStateMachine::OnSeekTaskResolved,
-           &MediaDecoderStateMachine::OnSeekTaskRejected));
-
-  MOZ_ASSERT(!mQueuedSeek.Exists());
-  MOZ_ASSERT(!mCurrentSeek.Exists());
-  mCurrentSeek = Move(aSeekJob);
-  return mCurrentSeek.mPromise.Ensure(__func__);
+  // Note we can't call SetState(DECODER_STATE_SEEKING) which does nothing
+  // if we are already in the SEEKING state.
+  mStateObj->Exit();
+  mState = DECODER_STATE_SEEKING;
+  mStateObj = MakeUnique<SeekingState>(this, Move(aSeekJob));
+  mStateObj->Enter();
 }
 
 void
 MediaDecoderStateMachine::OnSeekTaskResolved(SeekTaskResolveValue aValue)
 {
   MOZ_ASSERT(OnTaskQueue());
   MOZ_ASSERT(mState == DECODER_STATE_SEEKING);
 
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -467,34 +467,31 @@ protected:
   // of media to begin or resume.
   // Must be called with the decode monitor held.
   void MaybeStartPlayback();
 
   // Check to see if we don't have enough data to play up to the next frame.
   // If we don't, switch to buffering mode.
   void MaybeStartBuffering();
 
-  // The entry action of DECODER_STATE_DECODING_FIRSTFRAME.
-  void DecodeFirstFrame();
-
   // Moves the decoder into the shutdown state, and dispatches an error
   // event to the media element. This begins shutting down the decoder.
   // The decoder monitor must be held. This is only called on the
   // decode thread.
   void DecodeError(const MediaResult& aError);
 
   // Dispatches a LoadedMetadataEvent.
   // This is threadsafe and can be called on any thread.
   // The decoder monitor must be held.
   void EnqueueLoadedMetadataEvent();
 
   void EnqueueFirstFrameLoadedEvent();
 
   // Clears any previous seeking state and initiates a new seek on the decoder.
-  RefPtr<MediaDecoder::SeekPromise> InitiateSeek(SeekJob aSeekJob);
+  void InitiateSeek(SeekJob aSeekJob);
 
   void DispatchAudioDecodeTaskIfNeeded();
   void DispatchVideoDecodeTaskIfNeeded();
 
   // Dispatch a task to decode audio if there is not.
   void EnsureAudioDecodeTaskQueued();
 
   // Dispatch a task to decode video if there is not.
@@ -528,20 +525,16 @@ protected:
   // decoded and playable. This is the sum of the number of usecs of audio which
   // is decoded and in the reader's audio queue, and the usecs of unplayed audio
   // which has been pushed to the audio hardware for playback. Note that after
   // calling this, the audio hardware may play some of the audio pushed to
   // hardware, so this can only be used as a upper bound. The decoder monitor
   // must be held when calling this. Called on the decode thread.
   int64_t GetDecodedAudioDuration();
 
-  // Notify FirstFrameLoaded if having decoded first frames and
-  // transition to SEEKING if there is any pending seek, or DECODING otherwise.
-  void MaybeFinishDecodeFirstFrame();
-
   void FinishDecodeFirstFrame();
 
   // Completes the seek operation, moves onto the next appropriate state.
   void SeekCompleted();
 
   // Queries our state to see whether the decode has finished for all streams.
   bool CheckIfDecodeComplete();
 
--- a/dom/media/mediasink/DecodedStream.cpp
+++ b/dom/media/mediasink/DecodedStream.cpp
@@ -56,23 +56,26 @@ public:
       nsCOMPtr<nsIRunnable> event =
         NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished);
       aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget());
     }
   }
 
   void DoNotifyFinished()
   {
+    MOZ_ASSERT(NS_IsMainThread());
     mFinishPromise.ResolveIfExists(true, __func__);
   }
 
   void Forget()
   {
-    MOZ_ASSERT(NS_IsMainThread());
-    mFinishPromise.ResolveIfExists(true, __func__);
+    AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction([this] () {
+      MOZ_ASSERT(NS_IsMainThread());
+      mFinishPromise.ResolveIfExists(true, __func__);
+    }));
     MutexAutoLock lock(mMutex);
     mStream = nullptr;
   }
 
   MediaEventSource<int64_t>& OnOutput()
   {
     return mOnOutput;
   }
@@ -118,16 +121,17 @@ UpdateStreamSuspended(MediaStream* aStre
 class DecodedStreamData {
 public:
   DecodedStreamData(OutputStreamManager* aOutputStreamManager,
                     PlaybackInfoInit&& aInit,
                     MozPromiseHolder<GenericPromise>&& aPromise);
   ~DecodedStreamData();
   void SetPlaying(bool aPlaying);
   MediaEventSource<int64_t>& OnOutput();
+  void Forget();
 
   /* The following group of fields are protected by the decoder's monitor
    * and can be read or written on any thread.
    */
   // Count of audio frames written to the stream
   int64_t mAudioFramesWritten;
   // mNextVideoTime is the end timestamp for the last packet sent to the stream.
   // Therefore video packets starting at or after this time need to be copied
@@ -183,17 +187,16 @@ DecodedStreamData::DecodedStreamData(Out
   if (aInit.mInfo.HasVideo()) {
     mStream->AddTrack(aInit.mInfo.mVideo.mTrackId, 0, new VideoSegment());
   }
 }
 
 DecodedStreamData::~DecodedStreamData()
 {
   mOutputStreamManager->Disconnect();
-  mListener->Forget();
   mStream->Destroy();
 }
 
 MediaEventSource<int64_t>&
 DecodedStreamData::OnOutput()
 {
   return mListener->OnOutput();
 }
@@ -202,16 +205,22 @@ void
 DecodedStreamData::SetPlaying(bool aPlaying)
 {
   if (mPlaying != aPlaying) {
     mPlaying = aPlaying;
     UpdateStreamSuspended(mStream, !mPlaying);
   }
 }
 
+void
+DecodedStreamData::Forget()
+{
+  mListener->Forget();
+}
+
 DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
                              MediaQueue<MediaData>& aAudioQueue,
                              MediaQueue<MediaData>& aVideoQueue,
                              OutputStreamManager* aOutputStreamManager,
                              const bool& aSameOrigin,
                              const PrincipalHandle& aPrincipalHandle)
   : mOwnerThread(aOwnerThread)
   , mOutputStreamManager(aOutputStreamManager)
@@ -358,16 +367,17 @@ DecodedStream::DestroyData(UniquePtr<Dec
 
   if (!aData) {
     return;
   }
 
   mOutputListener.Disconnect();
 
   DecodedStreamData* data = aData.release();
+  data->Forget();
   nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
     delete data;
   });
   AbstractThread::MainThread()->Dispatch(r.forget());
 }
 
 void
 DecodedStream::SetPlaying(bool aPlaying)
--- a/dom/media/mediasource/test/mediasource.js
+++ b/dom/media/mediasource/test/mediasource.js
@@ -14,17 +14,16 @@ function runWithMSE(testFunction) {
     });
 
     testFunction(ms, el);
   }
 
   addLoadEvent(function () {
     SpecialPowers.pushPrefEnv({"set": [
       [ "media.mediasource.enabled", true ],
-      [ "media.test.dumpDebugInfo", true ],
     ]},
                               bootstrapTest);
   });
 }
 
 function fetchWithXHR(uri, onLoadFunction) {
   var p = new Promise(function(resolve, reject) {
     var xhr = new XMLHttpRequest();
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -1540,19 +1540,16 @@ function Log(token, msg) {
 
 // Number of tests to run in parallel.
 var PARALLEL_TESTS = 2;
 
 // Prefs to set before running tests.  Use this to improve coverage of
 // conditions that might not otherwise be encountered on the test data.
 var gTestPrefs = [
   ['media.recorder.max_memory', 1024],
-  ["media.preload.default", 2], // default preload = metadata
-  ["media.preload.auto", 3], // auto preload = enough
-  ["media.test.dumpDebugInfo", true],
 ];
 
 // When true, we'll loop forever on whatever test we run. Use this to debug
 // intermittent test failures.
 const DEBUG_TEST_LOOP_FOREVER = false;
 
 // Manages a run of media tests. Runs them in chunks in order to limit
 // the number of media elements/threads running in parallel. This limits peak
@@ -1697,24 +1694,16 @@ function mediaTestCleanup(callback) {
     var A = document.getElementsByTagName("audio");
     for (i=0; i<A.length; i++) {
       removeNodeAndSource(A[i]);
       A[i] = null;
     }
     SpecialPowers.exactGC(callback);
 }
 
-function setMediaTestsPrefs(callback, extraPrefs) {
-  var prefs = gTestPrefs;
-  if (extraPrefs) {
-    prefs = prefs.concat(extraPrefs);
-  }
-  SpecialPowers.pushPrefEnv({"set": prefs}, callback);
-}
-
 // B2G emulator and Android 2.3 are condidered slow platforms
 function isSlowPlatform() {
   return SpecialPowers.Services.appinfo.name == "B2G" || getAndroidVersion() == 10;
 }
 
 // Could be undefined in a page opened by the parent test page
 // like file_access_controls.html.
 if ("SimpleTest" in window) {
--- a/dom/media/test/test_access_control.html
+++ b/dom/media/test/test_access_control.html
@@ -23,19 +23,17 @@ function run() {
   window.open("http://example.org:80/tests/dom/media/test/file_access_controls.html", "", "width=500,height=500");
 }
 
 function done() {
   mediaTestCleanup();
   SimpleTest.finish();
 }
 
-addLoadEvent(function() {
-  setMediaTestsPrefs(run);
-});
+addLoadEvent(run);
 SimpleTest.waitForExplicitFinish();
 
 
 window.addEventListener("message", receiveMessage, false);
 
 function receiveMessage(event)
 {
   if (event.origin !== "http://example.org") {
--- a/dom/media/test/test_streams_autoplay.html
+++ b/dom/media/test/test_streams_autoplay.html
@@ -32,15 +32,15 @@ if (media == null) {
     };
 
     v2.addEventListener('playing', function() {
       ok(true, "playback started");
       SimpleTest.finish();
     }, {once: true});
   }
 
-  setMediaTestsPrefs(startTest);
+  startTest();
 }
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/templates.js
+++ b/dom/media/tests/mochitest/templates.js
@@ -471,17 +471,17 @@ var commandsPeerConnectionOfferAnswer = 
         test.pcLocal.endOfTrickleSdp,
         Promise.reject("No SDP")
       ])
       .then(sdp => sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcLocal.label),
             () => info("pcLocal: Gathering is not complete yet, skipping post-gathering SDP check"));
     }
   },
   function PC_REMOTE_VERIFY_SDP_AFTER_END_OF_TRICKLE(test) {
-    if (test.pcRemote.endOfTrickelSdp) {
+    if (test.pcRemote.endOfTrickleSdp) {
       /* In case the endOfTrickleSdp promise is resolved already it will win the
        * race because it gets evaluated first. But if endOfTrickleSdp is still
        * pending the rejection will win the race. */
       return Promise.race([
         test.pcRemote.endOfTrickleSdp,
         Promise.reject("No SDP")
       ])
       .then(sdp => sdputils.checkSdpAfterEndOfTrickle(sdp, test.testOptions, test.pcRemote.label),
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -729,17 +729,16 @@ PluginModuleChromeParent::PluginModuleCh
                                                    uint32_t aPluginId,
                                                    int32_t aSandboxLevel,
                                                    bool aAllowAsyncInit)
     : PluginModuleParent(true, aAllowAsyncInit)
     , mSubprocess(new PluginProcessParent(aFilePath))
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
-    , mProtocolCallStackMutex("PluginModuleChromeParent::mProtocolCallStackMutex")
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
 #ifdef MOZ_CRASHREPORTER
     , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
     , mCrashReporter(nullptr)
@@ -1001,50 +1000,16 @@ GetProcessCpuUsage(const InfallibleTArra
 
   return true;
 }
 
 } // namespace
 
 #endif // #ifdef XP_WIN
 
-void
-PluginModuleChromeParent::OnEnteredCall()
-{
-    mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
-    MOZ_ASSERT(protocol);
-    mozilla::MutexAutoLock lock(mProtocolCallStackMutex);
-    mProtocolCallStack.AppendElement(protocol);
-}
-
-void
-PluginModuleChromeParent::OnExitedCall()
-{
-    mozilla::MutexAutoLock lock(mProtocolCallStackMutex);
-    MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
-    mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
-}
-
-void
-PluginModuleChromeParent::OnEnteredSyncSend()
-{
-    mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
-    MOZ_ASSERT(protocol);
-    mozilla::MutexAutoLock lock(mProtocolCallStackMutex);
-    mProtocolCallStack.AppendElement(protocol);
-}
-
-void
-PluginModuleChromeParent::OnExitedSyncSend()
-{
-    mozilla::MutexAutoLock lock(mProtocolCallStackMutex);
-    MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
-    mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
-}
-
 /**
  * This function converts the topmost routing id on the call stack (as recorded
  * by the MessageChannel) into a pointer to a IProtocol object.
  */
 mozilla::ipc::IProtocol*
 PluginModuleChromeParent::GetInvokingProtocol()
 {
     int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId();
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -487,21 +487,16 @@ class PluginModuleChromeParent
     void
     SetContentParent(dom::ContentParent* aContentParent);
 
     bool
     SendAssociatePluginId();
 
     void CachedSettingChanged();
 
-    void OnEnteredCall() override;
-    void OnExitedCall() override;
-    void OnEnteredSyncSend() override;
-    void OnExitedSyncSend() override;
-
 #ifdef  MOZ_ENABLE_PROFILER_SPS
     void GatherAsyncProfile();
     void GatheredAsyncProfile(nsIProfileSaveEvent* aSaveEvent);
     void StartProfiler(nsIProfilerStartParams* aParams);
     void StopProfiler();
 #endif
 
     virtual bool
@@ -587,18 +582,16 @@ private:
     enum HangAnnotationFlags
     {
         kInPluginCall = (1u << 0),
         kHangUIShown = (1u << 1),
         kHangUIContinued = (1u << 2),
         kHangUIDontShow = (1u << 3)
     };
     Atomic<uint32_t> mHangAnnotationFlags;
-    mozilla::Mutex mProtocolCallStackMutex;
-    InfallibleTArray<mozilla::ipc::IProtocol*> mProtocolCallStack;
 #ifdef XP_WIN
     InfallibleTArray<float> mPluginCpuUsageOnHang;
     PluginHangUIParent *mHangUIParent;
     bool mHangUIEnabled;
     bool mIsTimerReset;
 #ifdef MOZ_CRASHREPORTER
     /**
      * This mutex protects the crash reporter when the Plugin Hang UI event
--- a/dom/storage/PStorage.ipdl
+++ b/dom/storage/PStorage.ipdl
@@ -7,24 +7,24 @@
 include protocol PContent;
 
 namespace mozilla {
 namespace dom {
 
 /* This protocol bridges async access to the database thread running on the parent process
  * and caches running on the child process.
  */
-prio(normal upto urgent) sync protocol PStorage
+nested(upto inside_cpow) sync protocol PStorage
 {
   manager PContent;
 
 parent:
   async __delete__();
 
-  prio(urgent) sync Preload(nsCString originSuffix, nsCString originNoSuffix, uint32_t alreadyLoadedCount)
+  nested(inside_cpow) sync Preload(nsCString originSuffix, nsCString originNoSuffix, uint32_t alreadyLoadedCount)
     returns (nsString[] keys, nsString[] values, nsresult rv);
 
   async AsyncPreload(nsCString originSuffix, nsCString originNoSuffix, bool priority);
   async AsyncGetUsage(nsCString scope);
   async AsyncAddItem(nsCString originSuffix, nsCString originNoSuffix, nsString key, nsString value);
   async AsyncUpdateItem(nsCString originSuffix, nsCString originNoSuffix, nsString key, nsString value);
   async AsyncRemoveItem(nsCString originSuffix, nsCString originNoSuffix, nsString key);
   async AsyncClear(nsCString originSuffix, nsCString originNoSuffix);
--- a/dom/tests/mochitest/geolocation/geolocation_common.js
+++ b/dom/tests/mochitest/geolocation/geolocation_common.js
@@ -1,9 +1,10 @@
-var BASE_URL = "http://mochi.test:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs";
+var harness = SimpleTest.harnessParameters.testRoot == "chrome" ? "chrome" : "tests";
+var BASE_URL = "http://mochi.test:8888/" + harness + "/dom/tests/mochitest/geolocation/network_geolocation.sjs";
 
 function sleep(delay)
 {
     var start = Date.now();
     while (Date.now() < start + delay);
 }
 
 function force_prompt(allow, callback) {
--- a/dom/tests/mochitest/geolocation/test_handlerSpinsEventLoop.html
+++ b/dom/tests/mochitest/geolocation/test_handlerSpinsEventLoop.html
@@ -35,23 +35,30 @@ resume_geolocationProvider(function() {
 
 var successCallbackCalled = false;
 function successCallback(position) {
   successCallbackCalled = true;
   check_geolocation(position);
   while (!timeoutPassed) {
     SpecialPowers.spinEventLoop(window);
   }
-  ok(successCallbackCalled != errorCallbackCalled, "Ensure only one callback is called");
-  SimpleTest.finish();
+  info("TEST-INFO | successCallback called");
+  check();
 }
 
 var errorCallbackCalled = false;
 function errorCallback(error) {
   errorCallbackCalled = true;
+  info("TEST-INFO | errorCallback called");
+  check();
+}
+
+function check() {
+  ok(successCallbackCalled != errorCallbackCalled, "Ensure only one callback is called");
+  SimpleTest.finish();
 }
 
 var timeoutPassed = false;
 var timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
 function test1() {
   SpecialPowers.pushPrefEnv({"set": [["geo.wifi.timeToWaitBeforeSending", 10]]}, function() {
     navigator.geolocation.getCurrentPosition(successCallback, errorCallback, {timeout: 500});
     timer.initWithCallback(timer => {
--- a/dom/tests/moz.build
+++ b/dom/tests/moz.build
@@ -29,16 +29,17 @@ MOCHITEST_MANIFESTS += [
     'mochitest/webcomponents/mochitest.ini',
     'mochitest/whatwg/mochitest.ini',
 ]
 
 MOCHITEST_CHROME_MANIFESTS += [
     'mochitest/beacon/chrome.ini',
     'mochitest/chrome/chrome.ini',
     'mochitest/general/chrome.ini',
+    'mochitest/geolocation/chrome.ini',
     'mochitest/localstorage/chrome.ini',
     'mochitest/notification/chrome.ini',
     'mochitest/sessionstorage/chrome.ini',
     'mochitest/whatwg/chrome.ini',
 ]
 
 if CONFIG['MOZ_GAMEPAD']:
     MOCHITEST_MANIFESTS += [
--- a/gfx/layers/ipc/RemoteContentController.cpp
+++ b/gfx/layers/ipc/RemoteContentController.cpp
@@ -44,16 +44,31 @@ RemoteContentController::RequestContentR
   MOZ_ASSERT(IsRepaintThread());
 
   if (mCanSend) {
     Unused << SendRequestContentRepaint(aFrameMetrics);
   }
 }
 
 void
+RemoteContentController::HandleTapOnMainThread(TapType aTapType,
+                                               const LayoutDevicePoint& aPoint,
+                                               Modifiers aModifiers,
+                                               const ScrollableLayerGuid& aGuid,
+                                               uint64_t aInputBlockId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
+  if (tab) {
+    tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+  }
+}
+
+void
 RemoteContentController::HandleTap(TapType aTapType,
                                    const LayoutDevicePoint& aPoint,
                                    Modifiers aModifiers,
                                    const ScrollableLayerGuid& aGuid,
                                    uint64_t aInputBlockId)
 {
   APZThreadUtils::AssertOnControllerThread();
 
@@ -61,38 +76,30 @@ RemoteContentController::HandleTap(TapTy
     MOZ_ASSERT(MessageLoop::current() == mCompositorThread);
 
     // The raw pointer to APZCTreeManagerParent is ok here because we are on the
     // compositor thread.
     APZCTreeManagerParent* apzctmp =
         CompositorBridgeParent::GetApzcTreeManagerParentForRoot(aGuid.mLayersId);
     if (apzctmp) {
       Unused << apzctmp->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
-      return;
     }
+
+    return;
   }
 
-  // If we get here we're probably in the parent process, but we might be in
-  // the GPU process in some shutdown phase where the LayerTreeState or
-  // APZCTreeManagerParent structures are torn down. In that case we'll just get
-  // a null TabParent.
-  dom::TabParent* tab = dom::TabParent::GetTabParentFromLayersId(aGuid.mLayersId);
-  if (tab) {
-    // If we got a TabParent we're definitely in the parent process, and the
-    // message is going to a child process.
-    //
-    // On desktop, we're already on the main thread, so we can call TabParent::SendHandleTap directly.
-    // On Android, we're on the UI thread, so proxy the SendHandleTap call to the main thread.
-    MOZ_ASSERT(XRE_IsParentProcess());
-    if (NS_IsMainThread()) {
-      tab->SendHandleTap(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
-    } else {
-      NS_DispatchToMainThread(NewRunnableMethod<TapType, const LayoutDevicePoint&, Modifiers, const ScrollableLayerGuid&, uint64_t>
-        (tab, &dom::TabParent::SendHandleTap, aTapType, aPoint, aModifiers, aGuid, aInputBlockId));
-    }
+  MOZ_ASSERT(XRE_IsParentProcess());
+
+  if (NS_IsMainThread()) {
+    HandleTapOnMainThread(aTapType, aPoint, aModifiers, aGuid, aInputBlockId);
+  } else {
+    // We don't want to get the TabParent or call TabParent::SendHandleTap() from a non-main thread (this might happen
+    // on Android, where this is called from the Java UI thread)
+    NS_DispatchToMainThread(NewRunnableMethod<TapType, const LayoutDevicePoint&, Modifiers, const ScrollableLayerGuid&, uint64_t>
+        (this, &RemoteContentController::HandleTapOnMainThread, aTapType, aPoint, aModifiers, aGuid, aInputBlockId));
   }
 }
 
 void
 RemoteContentController::NotifyPinchGesture(PinchGestureInput::PinchGestureType aType,
                                             const ScrollableLayerGuid& aGuid,
                                             LayoutDeviceCoord aSpanChange,
                                             Modifiers aModifiers)
--- a/gfx/layers/ipc/RemoteContentController.h
+++ b/gfx/layers/ipc/RemoteContentController.h
@@ -81,16 +81,22 @@ public:
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   virtual void Destroy() override;
 
 private:
   MessageLoop* mCompositorThread;
   bool mCanSend;
 
+  void HandleTapOnMainThread(TapType aType,
+                             const LayoutDevicePoint& aPoint,
+                             Modifiers aModifiers,
+                             const ScrollableLayerGuid& aGuid,
+                             uint64_t aInputBlockId);
+
   // Mutex protecting members below accessed from multiple threads.
   mozilla::Mutex mMutex;
   nsRegion mTouchSensitiveRegion;
 };
 
 } // namespace layers
 
 } // namespace mozilla
--- a/gfx/thebes/gfxWindowsPlatform.cpp
+++ b/gfx/thebes/gfxWindowsPlatform.cpp
@@ -1991,18 +1991,16 @@ gfxWindowsPlatform::GetAcceleratedCompos
   }
 
   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && gfxPrefs::LayersPreferD3D9()) {
     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
   }
 
   if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
     aBackends.AppendElement(LayersBackend::LAYERS_D3D11);
-  } else {
-    NS_WARNING("Direct3D 11-accelerated layers are not supported on this system.");
   }
 
   if (gfxConfig::IsEnabled(Feature::D3D9_COMPOSITING) && !gfxPrefs::LayersPreferD3D9()) {
     aBackends.AppendElement(LayersBackend::LAYERS_D3D9);
   }
 }
 
 void
--- a/hal/sandbox/PHal.ipdl
+++ b/hal/sandbox/PHal.ipdl
@@ -91,17 +91,17 @@ struct SystemTimezoneChangeInformation {
   int32_t oldTimezoneOffsetMinutes;
   int32_t newTimezoneOffsetMinutes;
 };
 
 } // namespace hal
 
 namespace hal_sandbox {
 
-prio(normal upto urgent) sync protocol PHal {
+nested(upto inside_cpow) sync protocol PHal {
     manager PContent;
 
 child:
     async NotifyBatteryChange(BatteryInformation aBatteryInfo);
     async NotifyNetworkChange(NetworkInformation aNetworkInfo);
     async NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
     async NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
     async NotifySwitchChange(SwitchEvent aEvent);
@@ -151,17 +151,17 @@ parent:
                          uint64_t aProcessID);
     async EnableWakeLockNotifications();
     async DisableWakeLockNotifications();
     sync GetWakeLockInfo(nsString aTopic)
       returns (WakeLockInformation aWakeLockInfo);
 
     async EnableScreenConfigurationNotifications();
     async DisableScreenConfigurationNotifications();
-    prio(urgent) sync GetCurrentScreenConfiguration()
+    nested(inside_cpow) sync GetCurrentScreenConfiguration()
       returns (ScreenConfiguration aScreenConfiguration);
     sync LockScreenOrientation(ScreenOrientationInternal aOrientation)
       returns (bool allowed);
     async UnlockScreenOrientation();
  
     async EnableSwitchNotifications(SwitchDevice aDevice);
     async DisableSwitchNotifications(SwitchDevice aDevice);
     sync GetCurrentSwitchState(SwitchDevice aDevice)
--- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc
@@ -258,18 +258,17 @@ bool Channel::ChannelImpl::CreatePipe(co
 void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
   NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
 
   EnqueueHelloMessage();
 }
 
 bool Channel::ChannelImpl::EnqueueHelloMessage() {
   mozilla::UniquePtr<Message> msg(new Message(MSG_ROUTING_NONE,
-                                              HELLO_MESSAGE_TYPE,
-                                              IPC::Message::PRIORITY_NORMAL));
+                                              HELLO_MESSAGE_TYPE));
   if (!msg->WriteInt(base::GetCurrentProcId())) {
     Close();
     return false;
   }
 
   OutputQueuePush(msg.release());
   return true;
 }
@@ -495,18 +494,17 @@ bool Channel::ChannelImpl::ProcessIncomi
           // abort the connection
           return false;
         }
 
 #if defined(OS_MACOSX)
         // Send a message to the other side, indicating that we are now
         // responsible for closing the descriptor.
         Message *fdAck = new Message(MSG_ROUTING_NONE,
-                                     RECEIVED_FDS_MESSAGE_TYPE,
-                                     IPC::Message::PRIORITY_NORMAL);
+                                     RECEIVED_FDS_MESSAGE_TYPE);
         DCHECK(m.fd_cookie() != 0);
         fdAck->set_fd_cookie(m.fd_cookie());
         OutputQueuePush(fdAck);
 #endif
 
         m.file_descriptor_set()->SetDescriptors(
                                                 &fds[fds_i], m.header()->num_fds);
         fds_i += m.header()->num_fds;
--- a/ipc/chromium/src/chrome/common/ipc_channel_win.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.cc
@@ -223,18 +223,17 @@ bool Channel::ChannelImpl::CreatePipe(co
   }
 
   // Create the Hello message to be sent when Connect is called
   return EnqueueHelloMessage();
 }
 
 bool Channel::ChannelImpl::EnqueueHelloMessage() {
   mozilla::UniquePtr<Message> m = mozilla::MakeUnique<Message>(MSG_ROUTING_NONE,
-                                                               HELLO_MESSAGE_TYPE,
-                                                               IPC::Message::PRIORITY_NORMAL);
+                                                               HELLO_MESSAGE_TYPE);
 
   // If we're waiting for our shared secret from the other end's hello message
   // then don't give the game away by sending it in ours.
   int32_t secret = waiting_for_shared_secret_ ? 0 : shared_secret_;
 
   // Also, don't send if the value is zero (for IPC backwards compatability).
   if (!m->WriteInt(GetCurrentProcessId()) ||
       (secret && !m->WriteUInt32(secret)))
--- a/ipc/chromium/src/chrome/common/ipc_message.cc
+++ b/ipc/chromium/src/chrome/common/ipc_message.cc
@@ -40,23 +40,25 @@ Message::Message()
 #ifdef MOZ_TASK_TRACER
   header()->source_event_id = 0;
   header()->parent_task_id = 0;
   header()->source_event_type = SourceEventType::Unknown;
 #endif
   InitLoggingVariables();
 }
 
-Message::Message(int32_t routing_id, msgid_t type, PriorityValue priority,
+Message::Message(int32_t routing_id, msgid_t type, NestedLevel nestedLevel, PriorityValue priority,
                  MessageCompression compression, const char* const aName)
     : Pickle(sizeof(Header)) {
   MOZ_COUNT_CTOR(IPC::Message);
   header()->routing = routing_id;
   header()->type = type;
-  header()->flags = priority;
+  header()->flags = nestedLevel;
+  if (priority == HIGH_PRIORITY)
+    header()->flags |= PRIO_BIT;
   if (compression == COMPRESSION_ENABLED)
     header()->flags |= COMPRESS_BIT;
   else if (compression == COMPRESSION_ALL)
     header()->flags |= COMPRESSALL_BIT;
 #if defined(OS_POSIX)
   header()->num_fds = 0;
 #endif
   header()->interrupt_remote_stack_depth_guess = static_cast<uint32_t>(-1);
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -33,52 +33,74 @@ namespace IPC {
 class Channel;
 class Message;
 struct LogData;
 
 class Message : public Pickle {
  public:
   typedef uint32_t msgid_t;
 
+  enum NestedLevel {
+    NOT_NESTED = 1,
+    NESTED_INSIDE_SYNC = 2,
+    NESTED_INSIDE_CPOW = 3
+  };
+
   enum PriorityValue {
-    PRIORITY_NORMAL = 1,
-    PRIORITY_HIGH = 2,
-    PRIORITY_URGENT = 3
+    NORMAL_PRIORITY,
+    HIGH_PRIORITY,
   };
 
   enum MessageCompression {
     COMPRESSION_NONE,
     COMPRESSION_ENABLED,
     COMPRESSION_ALL
   };
 
   virtual ~Message();
 
   Message();
 
   // Initialize a message with a user-defined type, priority value, and
   // destination WebView ID.
-  Message(int32_t routing_id, msgid_t type, PriorityValue priority,
+  Message(int32_t routing_id,
+          msgid_t type,
+          NestedLevel nestedLevel = NOT_NESTED,
+          PriorityValue priority = NORMAL_PRIORITY,
           MessageCompression compression = COMPRESSION_NONE,
           const char* const name="???");
 
   Message(const char* data, int data_len);
 
   Message(const Message& other) = delete;
   Message(Message&& other);
   Message& operator=(const Message& other) = delete;
   Message& operator=(Message&& other);
 
-  PriorityValue priority() const {
-    return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
+  NestedLevel nested_level() const {
+    return static_cast<NestedLevel>(header()->flags & NESTED_MASK);
+  }
+
+  void set_nested_level(NestedLevel nestedLevel) {
+    DCHECK((nestedLevel & ~NESTED_MASK) == 0);
+    header()->flags = (header()->flags & ~NESTED_MASK) | nestedLevel;
   }
 
-  void set_priority(int prio) {
-    DCHECK((prio & ~PRIORITY_MASK) == 0);
-    header()->flags = (header()->flags & ~PRIORITY_MASK) | prio;
+  PriorityValue priority() const {
+    if (header()->flags & PRIO_BIT) {
+      return HIGH_PRIORITY;
+    }
+    return NORMAL_PRIORITY;
+  }
+
+  void set_priority(PriorityValue prio) {
+    header()->flags &= ~PRIO_BIT;
+    if (prio == HIGH_PRIORITY) {
+      header()->flags |= PRIO_BIT;
+    }
   }
 
   // True if this is a synchronous message.
   bool is_sync() const {
     return (header()->flags & SYNC_BIT) != 0;
   }
 
   // True if this is a synchronous message.
@@ -109,37 +131,16 @@ class Message : public Pickle {
   void set_reply_error() {
     header()->flags |= REPLY_ERROR_BIT;
   }
 
   bool is_reply_error() const {
     return (header()->flags & REPLY_ERROR_BIT) != 0;
   }
 
-  // Normally when a receiver gets a message and they're blocked on a
-  // synchronous message Send, they buffer a message.  Setting this flag causes
-  // the receiver to be unblocked and the message to be dispatched immediately.
-  void set_unblock(bool unblock) {
-    if (unblock) {
-      header()->flags |= UNBLOCK_BIT;
-    } else {
-      header()->flags &= ~UNBLOCK_BIT;
-    }
-  }
-
-  bool should_unblock() const {
-    return (header()->flags & UNBLOCK_BIT) != 0;
-  }
-
-  // Tells the receiver that the caller is pumping messages while waiting
-  // for the result.
-  bool is_caller_pumping_messages() const {
-    return (header()->flags & PUMPING_MSGS_BIT) != 0;
-  }
-
   msgid_t type() const {
     return header()->type;
   }
 
   int32_t routing_id() const {
     return header()->routing;
   }
 
@@ -264,26 +265,24 @@ class Message : public Pickle {
   }
 
 #if !defined(OS_MACOSX)
  protected:
 #endif
 
   // flags
   enum {
-    PRIORITY_MASK   = 0x0003,
-    SYNC_BIT        = 0x0004,
-    REPLY_BIT       = 0x0008,
-    REPLY_ERROR_BIT = 0x0010,
-    UNBLOCK_BIT     = 0x0020,
-    PUMPING_MSGS_BIT= 0x0040,
-    HAS_SENT_TIME_BIT = 0x0080,
-    INTERRUPT_BIT   = 0x0100,
-    COMPRESS_BIT    = 0x0200,
-    COMPRESSALL_BIT = 0x0400,
+    NESTED_MASK     = 0x0003,
+    PRIO_BIT        = 0x0004,
+    SYNC_BIT        = 0x0008,
+    REPLY_BIT       = 0x0010,
+    REPLY_ERROR_BIT = 0x0020,
+    INTERRUPT_BIT   = 0x0040,
+    COMPRESS_BIT    = 0x0080,
+    COMPRESSALL_BIT = 0x0100,
   };
 
   struct Header : Pickle::Header {
     int32_t routing;  // ID of the view that this message is destined for
     msgid_t type;   // specifies the user-defined message type
     uint32_t flags;   // specifies control flags for the message
 #if defined(OS_POSIX)
     uint32_t num_fds; // the number of descriptors included with this message
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -34,62 +34,67 @@ using mozilla::Move;
 static mozilla::LazyLogModule sLogModule("ipc");
 #define IPC_LOG(...) MOZ_LOG(sLogModule, LogLevel::Debug, (__VA_ARGS__))
 #endif
 
 /*
  * IPC design:
  *
  * There are three kinds of messages: async, sync, and intr. Sync and intr
- * messages are blocking. Only intr and high-priority sync messages can nest.
+ * messages are blocking.
  *
  * Terminology: To dispatch a message Foo is to run the RecvFoo code for
  * it. This is also called "handling" the message.
  *
- * Sync and async messages have priorities while intr messages always have
- * normal priority. The three possible priorities are normal, high, and urgent.
- * The intended uses of these priorities are:
- *   NORMAL - most messages.
- *   HIGH   - CPOW-related messages, which can go in either direction.
- *   URGENT - messages where we don't want to dispatch
- *            incoming CPOWs while waiting for the response.
- * Async messages cannot have HIGH priority.
+ * Sync and async messages can sometimes "nest" inside other sync messages
+ * (i.e., while waiting for the sync reply, we can dispatch the inner
+ * message). Intr messages cannot nest.  The three possible nesting levels are
+ * NOT_NESTED, NESTED_INSIDE_SYNC, and NESTED_INSIDE_CPOW.  The intended uses
+ * are:
+ *   NOT_NESTED - most messages.
+ *   NESTED_INSIDE_SYNC - CPOW-related messages, which are always sync
+ *                        and can go in either direction.
+ *   NESTED_INSIDE_CPOW - messages where we don't want to dispatch
+ *                        incoming CPOWs while waiting for the response.
+ * These nesting levels are ordered: NOT_NESTED, NESTED_INSIDE_SYNC,
+ * NESTED_INSIDE_CPOW.  Async messages cannot be NESTED_INSIDE_SYNC but they can
+ * be NESTED_INSIDE_CPOW.
  *
- * To avoid jank, the parent process is not allowed to send sync messages of
- * normal priority. When a process is waiting for a response to a sync message
+ * To avoid jank, the parent process is not allowed to send NOT_NESTED sync messages.
+ * When a process is waiting for a response to a sync message
  * M0, it will dispatch an incoming message M if:
- *   1. M has a higher priority than M0, or
- *   2. if M has the same priority as M0 and we're in the child, or
- *   3. if M has the same priority as M0 and it was sent by the other side
- *      while dispatching M0 (nesting).
- * The idea is that higher priority messages should take precendence, and we
- * also want to allow nesting. The purpose of rule 2 is to handle a race where
- * both processes send to each other simultaneously. In this case, we resolve
- * the race in favor of the parent (so the child dispatches first).
+ *   1. M has a higher nesting level than M0, or
+ *   2. if M has the same nesting level as M0 and we're in the child, or
+ *   3. if M has the same nesting level as M0 and it was sent by the other side
+ *      while dispatching M0.
+ * The idea is that messages with higher nesting should take precendence. The
+ * purpose of rule 2 is to handle a race where both processes send to each other
+ * simultaneously. In this case, we resolve the race in favor of the parent (so
+ * the child dispatches first).
  *
  * Messages satisfy the following properties:
  *   A. When waiting for a response to a sync message, we won't dispatch any
- *      messages of lower priority.
- *   B. Messages of the same priority will be dispatched roughly in the
+ *      messages of nesting level.
+ *   B. Messages of the same nesting level will be dispatched roughly in the
  *      order they were sent. The exception is when the parent and child send
  *      sync messages to each other simulataneously. In this case, the parent's
  *      message is dispatched first. While it is dispatched, the child may send
  *      further nested messages, and these messages may be dispatched before the
  *      child's original message. We can consider ordering to be preserved here
  *      because we pretend that the child's original message wasn't sent until
  *      after the parent's message is finished being dispatched.
  *
  * When waiting for a sync message reply, we dispatch an async message only if
- * it has URGENT priority. Normally URGENT async messages are sent only from the
- * child. However, the parent can send URGENT async messages when it is creating
- * a bridged protocol.
+ * it is NESTED_INSIDE_CPOW. Normally NESTED_INSIDE_CPOW async
+ * messages are sent only from the child. However, the parent can send
+ * NESTED_INSIDE_CPOW async messages when it is creating a bridged protocol.
  *
- * Intr messages are blocking but not prioritized. While waiting for an intr
- * response, all incoming messages are dispatched until a response is
- * received. Intr messages also can be nested. When two intr messages race with
+ * Intr messages are blocking and can nest, but they don't participate in the
+ * nesting levels. While waiting for an intr response, all incoming messages are
+ * dispatched until a response is received. When two intr messages race with
  * each other, a similar scheme is used to ensure that one side wins. The
  * winning side is chosen based on the message type.
  *
  * Intr messages differ from sync messages in that, while sending an intr
  * message, we may dispatch an async message. This causes some additional
  * complexity. One issue is that replies can be received out of order. It's also
  * more difficult to determine whether one message is nested inside
  * another. Consequently, intr handling uses mOutOfTurnReplies and
@@ -282,34 +287,34 @@ private:
 };
 
 class AutoEnterTransaction
 {
 public:
     explicit AutoEnterTransaction(MessageChannel *aChan,
                                   int32_t aMsgSeqno,
                                   int32_t aTransactionID,
-                                  int aPriority)
+                                  int aNestedLevel)
       : mChan(aChan),
         mActive(true),
         mOutgoing(true),
-        mPriority(aPriority),
+        mNestedLevel(aNestedLevel),
         mSeqno(aMsgSeqno),
         mTransaction(aTransactionID),
         mNext(mChan->mTransactionStack)
     {
         mChan->mMonitor->AssertCurrentThreadOwns();
         mChan->mTransactionStack = this;
     }
 
     explicit AutoEnterTransaction(MessageChannel *aChan, const IPC::Message &aMessage)
       : mChan(aChan),
         mActive(true),
         mOutgoing(false),
-        mPriority(aMessage.priority()),
+        mNestedLevel(aMessage.nested_level()),
         mSeqno(aMessage.seqno()),
         mTransaction(aMessage.transaction_id()),
         mNext(mChan->mTransactionStack)
     {
         mChan->mMonitor->AssertCurrentThreadOwns();
 
         if (!aMessage.is_sync()) {
             mActive = false;
@@ -324,21 +329,21 @@ public:
         if (mActive) {
             mChan->mTransactionStack = mNext;
         }
     }
 
     void Cancel() {
         AutoEnterTransaction *cur = mChan->mTransactionStack;
         MOZ_RELEASE_ASSERT(cur == this);
-        while (cur && cur->mPriority != IPC::Message::PRIORITY_NORMAL) {
+        while (cur && cur->mNestedLevel != IPC::Message::NOT_NESTED) {
             // Note that, in the following situation, we will cancel multiple
             // transactions:
-            // 1. Parent sends high prio message P1 to child.
-            // 2. Child sends high prio message C1 to child.
+            // 1. Parent sends NESTED_INSIDE_SYNC message P1 to child.
+            // 2. Child sends NESTED_INSIDE_SYNC message C1 to child.
             // 3. Child dispatches P1, parent blocks.
             // 4. Child cancels.
             // In this case, both P1 and C1 are cancelled. The parent will
             // remove C1 from its queue when it gets the cancellation message.
             MOZ_RELEASE_ASSERT(cur->mActive);
             cur->mActive = false;
             cur = cur->mNext;
         }
@@ -351,43 +356,43 @@ public:
     bool AwaitingSyncReply() const {
         MOZ_RELEASE_ASSERT(mActive);
         if (mOutgoing) {
             return true;
         }
         return mNext ? mNext->AwaitingSyncReply() : false;
     }
 
-    int AwaitingSyncReplyPriority() const {
+    int AwaitingSyncReplyNestedLevel() const {
         MOZ_RELEASE_ASSERT(mActive);
         if (mOutgoing) {
-            return mPriority;
+            return mNestedLevel;
         }
-        return mNext ? mNext->AwaitingSyncReplyPriority() : 0;
+        return mNext ? mNext->AwaitingSyncReplyNestedLevel() : 0;
     }
 
     bool DispatchingSyncMessage() const {
         MOZ_RELEASE_ASSERT(mActive);
         if (!mOutgoing) {
             return true;
         }
         return mNext ? mNext->DispatchingSyncMessage() : false;
     }
 
-    int DispatchingSyncMessagePriority() const {
+    int DispatchingSyncMessageNestedLevel() const {
         MOZ_RELEASE_ASSERT(mActive);
         if (!mOutgoing) {
-            return mPriority;
+            return mNestedLevel;
         }
-        return mNext ? mNext->DispatchingSyncMessagePriority() : 0;
+        return mNext ? mNext->DispatchingSyncMessageNestedLevel() : 0;
     }
 
-    int Priority() const {
+    int NestedLevel() const {
         MOZ_RELEASE_ASSERT(mActive);
-        return mPriority;
+        return mNestedLevel;
     }
 
     int32_t SequenceNumber() const {
         MOZ_RELEASE_ASSERT(mActive);
         return mSeqno;
     }
 
     int32_t TransactionID() const {
@@ -451,17 +456,17 @@ private:
     // or if it was for a message that doesn't require transactions (an async
     // message).
     bool mActive;
 
     // Is this stack frame for an outgoing message?
     bool mOutgoing;
 
     // Properties of the message being sent/received.
-    int mPriority;
+    int mNestedLevel;
     int32_t mSeqno;
     int32_t mTransaction;
 
     // Next item in mChan->mTransactionStack.
     AutoEnterTransaction *mNext;
 
     // Pointer the a reply received for this message, if one was received.
     nsAutoPtr<IPC::Message> mReply;
@@ -475,20 +480,20 @@ MessageChannel::MessageChannel(MessageLi
     mWorkerLoop(nullptr),
     mChannelErrorTask(nullptr),
     mWorkerLoopID(-1),
     mTimeoutMs(kNoTimeout),
     mInTimeoutSecondHalf(false),
     mNextSeqno(0),
     mLastSendError(SyncSendError::SendSuccess),
     mDispatchingAsyncMessage(false),
-    mDispatchingAsyncMessagePriority(0),
+    mDispatchingAsyncMessageNestedLevel(0),
     mTransactionStack(nullptr),
     mTimedOutMessageSeqno(0),
-    mTimedOutMessagePriority(0),
+    mTimedOutMessageNestedLevel(0),
 #if defined(MOZ_CRASHREPORTER) && defined(OS_WIN)
     mPending(AnnotateAllocator<Message>(*this)),
 #endif
     mRemoteStackDepthGuess(false),
     mSawInterruptOutMsg(false),
     mIsWaitingForIncoming(false),
     mAbortOnError(false),
     mNotifiedChannelDone(false),
@@ -538,55 +543,55 @@ MessageChannel::~MessageChannel()
 #endif
     Clear();
 }
 
 // This function returns the current transaction ID. Since the notion of a
 // "current transaction" can be hard to define when messages race with each
 // other and one gets canceled and the other doesn't, we require that this
 // function is only called when the current transaction is known to be for a
-// high priority message. In that case, we know for sure what the caller is
+// NESTED_INSIDE_SYNC message. In that case, we know for sure what the caller is
 // looking for.
 int32_t
-MessageChannel::CurrentHighPriorityTransaction() const
+MessageChannel::CurrentNestedInsideSyncTransaction() const
 {
     mMonitor->AssertCurrentThreadOwns();
     if (!mTransactionStack) {
         return 0;
     }
-    MOZ_RELEASE_ASSERT(mTransactionStack->Priority() == IPC::Message::PRIORITY_HIGH);
+    MOZ_RELEASE_ASSERT(mTransactionStack->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC);
     return mTransactionStack->TransactionID();
 }
 
 bool
 MessageChannel::AwaitingSyncReply() const
 {
     mMonitor->AssertCurrentThreadOwns();
     return mTransactionStack ? mTransactionStack->AwaitingSyncReply() : false;
 }
 
 int
-MessageChannel::AwaitingSyncReplyPriority() const
+MessageChannel::AwaitingSyncReplyNestedLevel() const
 {
     mMonitor->AssertCurrentThreadOwns();
-    return mTransactionStack ? mTransactionStack->AwaitingSyncReplyPriority() : 0;
+    return mTransactionStack ? mTransactionStack->AwaitingSyncReplyNestedLevel() : 0;
 }
 
 bool
 MessageChannel::DispatchingSyncMessage() const
 {
     mMonitor->AssertCurrentThreadOwns();
     return mTransactionStack ? mTransactionStack->DispatchingSyncMessage() : false;
 }
 
 int
-MessageChannel::DispatchingSyncMessagePriority() const
+MessageChannel::DispatchingSyncMessageNestedLevel() const
 {
     mMonitor->AssertCurrentThreadOwns();
-    return mTransactionStack ? mTransactionStack->DispatchingSyncMessagePriority() : 0;
+    return mTransactionStack ? mTransactionStack->DispatchingSyncMessageNestedLevel() : 0;
 }
 
 static void
 PrintErrorMessage(Side side, const char* channelName, const char* msg)
 {
     const char *from = (side == ChildSide)
                        ? "Child"
                        : ((side == ParentSide) ? "Parent" : "Unknown");
@@ -766,18 +771,17 @@ bool
 MessageChannel::Send(Message* aMsg)
 {
     if (aMsg->size() >= kMinTelemetryMessageSize) {
         Telemetry::Accumulate(Telemetry::IPC_MESSAGE_SIZE,
                               nsDependentCString(aMsg->name()), aMsg->size());
     }
 
     MOZ_RELEASE_ASSERT(!aMsg->is_sync());
-    // We never send an async high priority message.
-    MOZ_RELEASE_ASSERT(aMsg->priority() != IPC::Message::PRIORITY_HIGH);
+    MOZ_RELEASE_ASSERT(aMsg->nested_level() != IPC::Message::NESTED_INSIDE_SYNC);
 
     CxxStackFrame frame(*this, OUT_MESSAGE, aMsg);
 
     nsAutoPtr<Message> msg(aMsg);
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
     if (MSG_ROUTING_NONE == msg->routing_id()) {
         ReportMessageRouteError("MessageChannel::Send");
@@ -792,17 +796,17 @@ MessageChannel::Send(Message* aMsg)
     mLink->SendMessage(msg.forget());
     return true;
 }
 
 class CancelMessage : public IPC::Message
 {
 public:
     explicit CancelMessage(int transaction) :
-        IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE, PRIORITY_NORMAL)
+        IPC::Message(MSG_ROUTING_NONE, CANCEL_MESSAGE_TYPE)
     {
         set_transaction_id(transaction);
     }
     static bool Read(const Message* msg) {
         return true;
     }
     void Log(const std::string& aPrefix, FILE* aOutf) const {
         fputs("(special `Cancel' message)", aOutf);
@@ -833,51 +837,51 @@ MessageChannel::MaybeInterceptSpecialIOM
         }
     }
     return false;
 }
 
 bool
 MessageChannel::ShouldDeferMessage(const Message& aMsg)
 {
-    // Never defer messages that have the highest priority, even async
+    // Never defer messages that have the highest nested level, even async
     // ones. This is safe because only the child can send these messages, so
     // they can never nest.
-    if (aMsg.priority() == IPC::Message::PRIORITY_URGENT)
+    if (aMsg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW)
         return false;
 
-    // Unless they're urgent, we always defer async messages.
-    // Note that we never send an async high priority message.
+    // Unless they're NESTED_INSIDE_CPOW, we always defer async messages.
+    // Note that we never send an async NESTED_INSIDE_SYNC message.
     if (!aMsg.is_sync()) {
-        MOZ_RELEASE_ASSERT(aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
+        MOZ_RELEASE_ASSERT(aMsg.nested_level() == IPC::Message::NOT_NESTED);
         return true;
     }
 
-    int msgPrio = aMsg.priority();
-    int waitingPrio = AwaitingSyncReplyPriority();
+    int msgNestedLevel = aMsg.nested_level();
+    int waitingNestedLevel = AwaitingSyncReplyNestedLevel();
 
-    // Always defer if the priority of the incoming message is less than the
-    // priority of the message we're awaiting.
-    if (msgPrio < waitingPrio)
+    // Always defer if the nested level of the incoming message is less than the
+    // nested level of the message we're awaiting.
+    if (msgNestedLevel < waitingNestedLevel)
         return true;
 
-    // Never defer if the message has strictly greater priority.
-    if (msgPrio > waitingPrio)
+    // Never defer if the message has strictly greater nested level.
+    if (msgNestedLevel > waitingNestedLevel)
         return false;
 
-    // When both sides send sync messages of the same priority, we resolve the
+    // When both sides send sync messages of the same nested level, we resolve the
     // race by dispatching in the child and deferring the incoming message in
     // the parent. However, the parent still needs to dispatch nested sync
     // messages.
     //
     // Deferring in the parent only sort of breaks message ordering. When the
     // child's message comes in, we can pretend the child hasn't quite
     // finished sending it yet. Since the message is sync, we know that the
     // child hasn't moved on yet.
-    return mSide == ParentSide && aMsg.transaction_id() != CurrentHighPriorityTransaction();
+    return mSide == ParentSide && aMsg.transaction_id() != CurrentNestedInsideSyncTransaction();
 }
 
 // Predicate that is true for messages that should be consolidated if 'compress' is set.
 class MatchingKinds {
     typedef IPC::Message Message;
     Message::msgid_t mType;
     int32_t mRoutingId;
 public:
@@ -912,19 +916,19 @@ MessageChannel::OnMessageReceivedFromLin
         MOZ_RELEASE_ASSERT(AwaitingSyncReply());
         MOZ_RELEASE_ASSERT(!mTimedOutMessageSeqno);
 
         mTransactionStack->HandleReply(Move(aMsg));
         NotifyWorkerThread();
         return;
     }
 
-    // Prioritized messages cannot be compressed.
+    // Nested messages cannot be compressed.
     MOZ_RELEASE_ASSERT(aMsg.compress_type() == IPC::Message::COMPRESSION_NONE ||
-                       aMsg.priority() == IPC::Message::PRIORITY_NORMAL);
+                       aMsg.nested_level() == IPC::Message::NOT_NESTED);
 
     bool compress = false;
     if (aMsg.compress_type() == IPC::Message::COMPRESSION_ENABLED) {
         compress = (!mPending.empty() &&
                     mPending.back().type() == aMsg.type() &&
                     mPending.back().routing_id() == aMsg.routing_id());
         if (compress) {
             // This message type has compression enabled, and the back of the
@@ -964,17 +968,17 @@ MessageChannel::OnMessageReceivedFromLin
     IPC_LOG("Receive on link thread; seqno=%d, xid=%d, shouldWakeUp=%d",
             aMsg.seqno(), aMsg.transaction_id(), shouldWakeUp);
 
     // There are three cases we're concerned about, relating to the state of the
     // main thread:
     //
     // (1) We are waiting on a sync reply - main thread is blocked on the
     //     IPC monitor.
-    //   - If the message is high priority, we wake up the main thread to
+    //   - If the message is NESTED_INSIDE_SYNC, we wake up the main thread to
     //     deliver the message depending on ShouldDeferMessage. Otherwise, we
     //     leave it in the mPending queue, posting a task to the main event
     //     loop, where it will be processed once the synchronous reply has been
     //     received.
     //
     // (2) We are waiting on an Interrupt reply - main thread is blocked on the
     //     IPC monitor.
     //   - Always notify and wake up the main thread.
@@ -1016,38 +1020,38 @@ MessageChannel::PeekMessages(mozilla::fu
 }
 
 void
 MessageChannel::ProcessPendingRequests(AutoEnterTransaction& aTransaction)
 {
     IPC_LOG("ProcessPendingRequests for seqno=%d, xid=%d",
             aTransaction.SequenceNumber(), aTransaction.TransactionID());
 
-    // Loop until there aren't any more priority messages to process.
+    // Loop until there aren't any more nested messages to process.
     for (;;) {
         // If we canceled during ProcessPendingRequest, then we need to leave
         // immediately because the results of ShouldDeferMessage will be
         // operating with weird state (as if no Send is in progress). That could
-        // cause even normal priority sync messages to be processed (but not
-        // normal priority async messages), which would break message ordering.
+        // cause even NOT_NESTED sync messages to be processed (but not
+        // NOT_NESTED async messages), which would break message ordering.
         if (aTransaction.IsCanceled()) {
             return;
         }
 
         mozilla::Vector<Message> toProcess;
 
         for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
             Message &msg = *it;
 
             MOZ_RELEASE_ASSERT(!aTransaction.IsCanceled(),
                                "Calling ShouldDeferMessage when cancelled");
             bool defer = ShouldDeferMessage(msg);
 
             // Only log the interesting messages.
-            if (msg.is_sync() || msg.priority() == IPC::Message::PRIORITY_URGENT) {
+            if (msg.is_sync() || msg.nested_level() == IPC::Message::NESTED_INSIDE_CPOW) {
                 IPC_LOG("ShouldDeferMessage(seqno=%d) = %d", msg.seqno(), defer);
             }
 
             if (!defer) {
                 if (!toProcess.append(Move(msg)))
                     MOZ_CRASH();
                 it = mPending.erase(it);
                 continue;
@@ -1096,84 +1100,84 @@ MessageChannel::Send(Message* aMsg, Mess
         // and we haven't received a reply for it. Once the original timed-out
         // message receives a reply, we'll be able to send more sync messages
         // again.
         IPC_LOG("Send() failed due to previous timeout");
         mLastSendError = SyncSendError::PreviousTimeout;
         return false;
     }
 
-    if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_NORMAL &&
-        msg->priority() > IPC::Message::PRIORITY_NORMAL)
+    if (DispatchingSyncMessageNestedLevel() == IPC::Message::NOT_NESTED &&
+        msg->nested_level() > IPC::Message::NOT_NESTED)
     {
         // Don't allow sending CPOWs while we're dispatching a sync message.
         // If you want to do that, use sendRpcMessage instead.
-        IPC_LOG("Prio forbids send");
+        IPC_LOG("Nested level forbids send");
         mLastSendError = SyncSendError::SendingCPOWWhileDispatchingSync;
         return false;
     }
 
-    if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT ||
-        DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT)
+    if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
+        DispatchingAsyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW)
     {
         // Generally only the parent dispatches urgent messages. And the only
-        // sync messages it can send are high-priority. Mainly we want to ensure
+        // sync messages it can send are NESTED_INSIDE_SYNC. Mainly we want to ensure
         // here that we don't return false for non-CPOW messages.
-        MOZ_RELEASE_ASSERT(msg->priority() == IPC::Message::PRIORITY_HIGH);
+        MOZ_RELEASE_ASSERT(msg->nested_level() == IPC::Message::NESTED_INSIDE_SYNC);
         IPC_LOG("Sending while dispatching urgent message");
         mLastSendError = SyncSendError::SendingCPOWWhileDispatchingUrgent;
         return false;
     }
 
-    if (msg->priority() < DispatchingSyncMessagePriority() ||
-        msg->priority() < AwaitingSyncReplyPriority())
+    if (msg->nested_level() < DispatchingSyncMessageNestedLevel() ||
+        msg->nested_level() < AwaitingSyncReplyNestedLevel())
     {
         MOZ_RELEASE_ASSERT(DispatchingSyncMessage() || DispatchingAsyncMessage());
         IPC_LOG("Cancel from Send");
-        CancelMessage *cancel = new CancelMessage(CurrentHighPriorityTransaction());
-        CancelTransaction(CurrentHighPriorityTransaction());
+        CancelMessage *cancel = new CancelMessage(CurrentNestedInsideSyncTransaction());
+        CancelTransaction(CurrentNestedInsideSyncTransaction());
         mLink->SendMessage(cancel);
     }
 
     IPC_ASSERT(msg->is_sync(), "can only Send() sync messages here");
 
-    IPC_ASSERT(msg->priority() >= DispatchingSyncMessagePriority(),
-               "can't send sync message of a lesser priority than what's being dispatched");
-    IPC_ASSERT(AwaitingSyncReplyPriority() <= msg->priority(),
-               "nested sync message sends must be of increasing priority");
-    IPC_ASSERT(DispatchingSyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
+    IPC_ASSERT(msg->nested_level() >= DispatchingSyncMessageNestedLevel(),
+               "can't send sync message of a lesser nested level than what's being dispatched");
+    IPC_ASSERT(AwaitingSyncReplyNestedLevel() <= msg->nested_level(),
+               "nested sync message sends must be of increasing nested level");
+    IPC_ASSERT(DispatchingSyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
                "not allowed to send messages while dispatching urgent messages");
 
-    IPC_ASSERT(DispatchingAsyncMessagePriority() != IPC::Message::PRIORITY_URGENT,
+    IPC_ASSERT(DispatchingAsyncMessageNestedLevel() != IPC::Message::NESTED_INSIDE_CPOW,
                "not allowed to send messages while dispatching urgent messages");
 
     if (!Connected()) {
         ReportConnectionError("MessageChannel::SendAndWait", msg);
         mLastSendError = SyncSendError::NotConnectedBeforeSend;
         return false;
     }
 
     msg->set_seqno(NextSeqno());
 
     int32_t seqno = msg->seqno();
-    int prio = msg->priority();
+    int nestedLevel = msg->nested_level();
     msgid_t replyType = msg->type() + 1;
 
     AutoEnterTransaction *stackTop = mTransactionStack;
 
-    // If the most recent message on the stack is high priority, then our
+    // If the most recent message on the stack is NESTED_INSIDE_SYNC, then our
     // message should nest inside that and we use the same transaction
     // ID. Otherwise we need a new transaction ID (so we use the seqno of the
     // message we're sending).
-    bool nest = stackTop && stackTop->Priority() == IPC::Message::PRIORITY_HIGH;
+    bool nest = stackTop && stackTop->NestedLevel() == IPC::Message::NESTED_INSIDE_SYNC;
     int32_t transaction = nest ? stackTop->TransactionID() : seqno;
     msg->set_transaction_id(transaction);
 
     bool handleWindowsMessages = mListener->HandleWindowsMessages(*aMsg);
-    AutoEnterTransaction transact(this, seqno, transaction, prio);
+    AutoEnterTransaction transact(this, seqno, transaction, nestedLevel);
 
     IPC_LOG("Send seqno=%d, xid=%d", seqno, transaction);
 
     // msg will be destroyed soon, but name() is not owned by msg.
     const char* msgName = msg->name();
 
     mLink->SendMessage(msg.forget());
 
@@ -1222,17 +1226,17 @@ MessageChannel::Send(Message* aMsg, Mess
             // out message in these cases.
             if (transact.IsComplete()) {
                 break;
             }
 
             IPC_LOG("Timing out Send: xid=%d", transaction);
 
             mTimedOutMessageSeqno = seqno;
-            mTimedOutMessagePriority = prio;
+            mTimedOutMessageNestedLevel = nestedLevel;
             mLastSendError = SyncSendError::TimedOut;
             return false;
         }
 
         if (transact.IsCanceled()) {
             break;
         }
     }
@@ -1510,34 +1514,34 @@ MessageChannel::DequeueOne(Message *recv
     }
 
     if (!mDeferred.empty())
         MaybeUndeferIncall();
 
     // If we've timed out a message and we're awaiting the reply to the timed
     // out message, we have to be careful what messages we process. Here's what
     // can go wrong:
-    // 1. child sends a normal priority sync message S
-    // 2. parent sends a high priority sync message H at the same time
+    // 1. child sends a NOT_NESTED sync message S
+    // 2. parent sends a NESTED_INSIDE_SYNC sync message H at the same time
     // 3. parent times out H
-    // 4. child starts processing H and sends a high priority message H' nested
+    // 4. child starts processing H and sends a NESTED_INSIDE_SYNC message H' nested
     //    within the same transaction
     // 5. parent dispatches S and sends reply
     // 6. child asserts because it instead expected a reply to H'.
     //
     // To solve this, we refuse to process S in the parent until we get a reply
     // to H. More generally, let the timed out message be M. We don't process a
     // message unless the child would need the response to that message in order
-    // to process M. Those messages are the ones that have a higher priority
+    // to process M. Those messages are the ones that have a higher nested level
     // than M or that are part of the same transaction as M.
     if (mTimedOutMessageSeqno) {
         for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); it++) {
             Message &msg = *it;
-            if (msg.priority() > mTimedOutMessagePriority ||
-                (msg.priority() == mTimedOutMessagePriority
+            if (msg.nested_level() > mTimedOutMessageNestedLevel ||
+                (msg.nested_level() == mTimedOutMessageNestedLevel
                  && msg.transaction_id() == mTimedOutMessageSeqno))
             {
                 *recvd = Move(msg);
                 mPending.erase(it);
                 return true;
             }
         }
         return false;
@@ -1621,33 +1625,33 @@ MessageChannel::DispatchMessage(Message 
     }
 }
 
 void
 MessageChannel::DispatchSyncMessage(const Message& aMsg, Message*& aReply)
 {
     AssertWorkerThread();
 
-    int prio = aMsg.priority();
+    int nestedLevel = aMsg.nested_level();
 
-    MOZ_RELEASE_ASSERT(prio == IPC::Message::PRIORITY_NORMAL || NS_IsMainThread());
+    MOZ_RELEASE_ASSERT(nestedLevel == IPC::Message::NOT_NESTED || NS_IsMainThread());
 
     MessageChannel* dummy;
     MessageChannel*& blockingVar = mSide == ChildSide && NS_IsMainThread() ? gParentProcessBlocker : dummy;
 
     Result rv;
     {
         AutoSetValue<MessageChannel*> blocked(blockingVar, this);
         rv = mListener->OnMessageReceived(aMsg, aReply);
     }
 
     if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
         aReply = new Message();
         aReply->set_sync();
-        aReply->set_priority(aMsg.priority());
+        aReply->set_nested_level(aMsg.nested_level());
         aReply->set_reply();
         aReply->set_reply_error();
     }
     aReply->set_seqno(aMsg.seqno());
     aReply->set_transaction_id(aMsg.transaction_id());
 }
 
 void
@@ -1657,19 +1661,19 @@ MessageChannel::DispatchAsyncMessage(con
     MOZ_RELEASE_ASSERT(!aMsg.is_interrupt() && !aMsg.is_sync());
 
     if (aMsg.routing_id() == MSG_ROUTING_NONE) {
         NS_RUNTIMEABORT("unhandled special message!");
     }
 
     Result rv;
     {
-        int prio = aMsg.priority();
+        int nestedLevel = aMsg.nested_level();
         AutoSetValue<bool> async(mDispatchingAsyncMessage, true);
-        AutoSetValue<int> prioSet(mDispatchingAsyncMessagePriority, prio);
+        AutoSetValue<int> nestedLevelSet(mDispatchingAsyncMessageNestedLevel, nestedLevel);
         rv = mListener->OnMessageReceived(aMsg);
     }
     MaybeHandleError(rv, aMsg, "DispatchAsyncMessage");
 }
 
 void
 MessageChannel::DispatchInterruptMessage(Message&& aMsg, size_t stackDepth)
 {
@@ -1770,17 +1774,17 @@ MessageChannel::MaybeUndeferIncall()
     // maybe time to process this message
     Message call(Move(mDeferred.top()));
     mDeferred.pop();
 
     // fix up fudge factor we added to account for race
     IPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
     --mRemoteStackDepthGuess;
 
-    MOZ_RELEASE_ASSERT(call.priority() == IPC::Message::PRIORITY_NORMAL);
+    MOZ_RELEASE_ASSERT(call.nested_level() == IPC::Message::NOT_NESTED);
     mPending.push_back(Move(call));
 }
 
 void
 MessageChannel::FlushPendingInterruptQueue()
 {
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
@@ -2144,17 +2148,17 @@ MessageChannel::PostErrorNotifyTask()
     mWorkerLoop->PostTask(task.forget());
 }
 
 // Special async message.
 class GoodbyeMessage : public IPC::Message
 {
 public:
     GoodbyeMessage() :
-        IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE, PRIORITY_NORMAL)
+        IPC::Message(MSG_ROUTING_NONE, GOODBYE_MESSAGE_TYPE)
     {
     }
     static bool Read(const Message* msg) {
         return true;
     }
     void Log(const std::string& aPrefix, FILE* aOutf) const {
         fputs("(special `Goodbye' message)", aOutf);
     }
@@ -2333,17 +2337,17 @@ MessageChannel::GetTopmostMessageRouting
 
 void
 MessageChannel::EndTimeout()
 {
     mMonitor->AssertCurrentThreadOwns();
 
     IPC_LOG("Ending timeout of seqno=%d", mTimedOutMessageSeqno);
     mTimedOutMessageSeqno = 0;
-    mTimedOutMessagePriority = 0;
+    mTimedOutMessageNestedLevel = 0;
 
     for (size_t i = 0; i < mPending.size(); i++) {
         // There may be messages in the queue that we expected to process from
         // OnMaybeDequeueOne. But during the timeout, that function will skip
         // some messages. Now they're ready to be processed, so we enqueue more
         // tasks.
         RefPtr<DequeueTask> task = new DequeueTask(mDequeueOneTask);
         mWorkerLoop->PostTask(task.forget());
@@ -2370,17 +2374,17 @@ MessageChannel::CancelTransaction(int tr
     // An unusual case: We timed out a transaction which the other side then
     // cancelled. In this case we just leave the timedout state and try to
     // forget this ever happened.
     if (transaction == mTimedOutMessageSeqno) {
         IPC_LOG("Cancelled timed out message %d", mTimedOutMessageSeqno);
         EndTimeout();
 
         // Normally mCurrentTransaction == 0 here. But it can be non-zero if:
-        // 1. Parent sends hi prio message H.
+        // 1. Parent sends NESTED_INSIDE_SYNC message H.
         // 2. Parent times out H.
         // 3. Child dispatches H and sends nested message H' (same transaction).
         // 4. Parent dispatches H' and cancels.
         MOZ_RELEASE_ASSERT(!mTransactionStack || mTransactionStack->TransactionID() == transaction);
         if (mTransactionStack) {
             mTransactionStack->Cancel();
         }
     } else {
@@ -2390,18 +2394,18 @@ MessageChannel::CancelTransaction(int tr
 
     bool foundSync = false;
     for (MessageQueue::iterator it = mPending.begin(); it != mPending.end(); ) {
         Message &msg = *it;
 
         // If there was a race between the parent and the child, then we may
         // have a queued sync message. We want to drop this message from the
         // queue since if will get cancelled along with the transaction being
-        // cancelled. This happens if the message in the queue is high priority.
-        if (msg.is_sync() && msg.priority() != IPC::Message::PRIORITY_NORMAL) {
+        // cancelled. This happens if the message in the queue is NESTED_INSIDE_SYNC.
+        if (msg.is_sync() && msg.nested_level() != IPC::Message::NOT_NESTED) {
             MOZ_RELEASE_ASSERT(!foundSync);
             MOZ_RELEASE_ASSERT(msg.transaction_id() != transaction);
             IPC_LOG("Removing msg from queue seqno=%d xid=%d", msg.seqno(), msg.transaction_id());
             foundSync = true;
             it = mPending.erase(it);
             continue;
         }
 
@@ -2415,27 +2419,27 @@ MessageChannel::IsInTransaction() const
     MonitorAutoLock lock(*mMonitor);
     return !!mTransactionStack;
 }
 
 void
 MessageChannel::CancelCurrentTransaction()
 {
     MonitorAutoLock lock(*mMonitor);
-    if (DispatchingSyncMessagePriority() >= IPC::Message::PRIORITY_HIGH) {
-        if (DispatchingSyncMessagePriority() == IPC::Message::PRIORITY_URGENT ||
-            DispatchingAsyncMessagePriority() == IPC::Message::PRIORITY_URGENT)
+    if (DispatchingSyncMessageNestedLevel() >= IPC::Message::NESTED_INSIDE_SYNC) {
+        if (DispatchingSyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW ||
+            DispatchingAsyncMessageNestedLevel() == IPC::Message::NESTED_INSIDE_CPOW)
         {
             mListener->IntentionalCrash();
         }
 
-        IPC_LOG("Cancel requested: current xid=%d", CurrentHighPriorityTransaction());
+        IPC_LOG("Cancel requested: current xid=%d", CurrentNestedInsideSyncTransaction());
         MOZ_RELEASE_ASSERT(DispatchingSyncMessage());
-        CancelMessage *cancel = new CancelMessage(CurrentHighPriorityTransaction());
-        CancelTransaction(CurrentHighPriorityTransaction());
+        CancelMessage *cancel = new CancelMessage(CurrentNestedInsideSyncTransaction());
+        CancelTransaction(CurrentNestedInsideSyncTransaction());
         mLink->SendMessage(cancel);
     }
 }
 
 void
 CancelCPOWs()
 {
     if (gParentProcessBlocker) {
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -403,19 +403,19 @@ class MessageChannel : HasResultCodes
     friend class AutoEnterWaitForIncoming;
 
     // Returns true if we're dispatching an async message's callback.
     bool DispatchingAsyncMessage() const {
         AssertWorkerThread();
         return mDispatchingAsyncMessage;
     }
 
-    int DispatchingAsyncMessagePriority() const {
+    int DispatchingAsyncMessageNestedLevel() const {
         AssertWorkerThread();
-        return mDispatchingAsyncMessagePriority;
+        return mDispatchingAsyncMessageNestedLevel;
     }
 
     bool Connected() const;
 
   private:
     // Executed on the IO thread.
     void NotifyWorkerThread();
 
@@ -621,17 +621,17 @@ class MessageChannel : HasResultCodes
         }
       private:
         T& mVar;
         T mPrev;
         T mNew;
     };
 
     bool mDispatchingAsyncMessage;
-    int mDispatchingAsyncMessagePriority;
+    int mDispatchingAsyncMessageNestedLevel;
 
     // When we send an urgent request from the parent process, we could race
     // with an RPC message that was issued by the child beforehand. In this
     // case, if the parent were to wake up while waiting for the urgent reply,
     // and process the RPC, it could send an additional urgent message. The
     // child would wake up to process the urgent message (as it always will),
     // then send a reply, which could be received by the parent out-of-order
     // with respect to the first urgent reply.
@@ -644,39 +644,39 @@ class MessageChannel : HasResultCodes
     // transaction, the initiating transaction ID is used.
     //
     // To ensure IDs are unique, we use sequence numbers for transaction IDs,
     // which grow in opposite directions from child to parent.
 
     friend class AutoEnterTransaction;
     AutoEnterTransaction *mTransactionStack;
 
-    int32_t CurrentHighPriorityTransaction() const;
+    int32_t CurrentNestedInsideSyncTransaction() const;
 
     bool AwaitingSyncReply() const;
-    int AwaitingSyncReplyPriority() const;
+    int AwaitingSyncReplyNestedLevel() const;
 
     bool DispatchingSyncMessage() const;
-    int DispatchingSyncMessagePriority() const;
+    int DispatchingSyncMessageNestedLevel() const;
 
     // If a sync message times out, we store its sequence number here. Any
     // future sync messages will fail immediately. Once the reply for original
     // sync message is received, we allow sync messages again.
     //
     // When a message times out, nothing is done to inform the other side. The
     // other side will eventually dispatch the message and send a reply. Our
     // side is responsible for replying to all sync messages sent by the other
     // side when it dispatches the timed out message. The response is always an
     // error.
     //
     // A message is only timed out if it initiated a transaction. This avoids
     // hitting a lot of corner cases with message nesting that we don't really
     // care about.
     int32_t mTimedOutMessageSeqno;
-    int mTimedOutMessagePriority;
+    int mTimedOutMessageNestedLevel;
 
     // Queue of all incoming messages, except for replies to sync and urgent
     // messages, which are delivered directly to mRecvd, and any pending urgent
     // incall, which is stored in mPendingUrgentRequest.
     //
     // If both this side and the other side are functioning correctly, the queue
     // can only be in certain configurations.  Let
     //
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -78,20 +78,20 @@ IToplevelProtocol::~IToplevelProtocol()
 }
 
 class ChannelOpened : public IPC::Message
 {
 public:
   ChannelOpened(TransportDescriptor aDescriptor,
                 ProcessId aOtherProcess,
                 ProtocolId aProtocol,
-                PriorityValue aPriority = PRIORITY_NORMAL)
+                NestedLevel aNestedLevel = NOT_NESTED)
     : IPC::Message(MSG_ROUTING_CONTROL, // these only go to top-level actors
                    CHANNEL_OPENED_MESSAGE_TYPE,
-                   aPriority)
+                   aNestedLevel)
   {
     IPC::WriteParam(this, aDescriptor);
     IPC::WriteParam(this, aOtherProcess);
     IPC::WriteParam(this, static_cast<uint32_t>(aProtocol));
   }
 
   static bool Read(const IPC::Message& aMsg,
                    TransportDescriptor* aDescriptor,
@@ -123,26 +123,26 @@ Bridge(const PrivateIPDLInterface&,
   nsresult rv;
   if (NS_FAILED(rv = CreateTransport(aParentPid, &parentSide, &childSide))) {
     return rv;
   }
 
   if (!aParentChannel->Send(new ChannelOpened(parentSide,
                                               aChildPid,
                                               aProtocol,
-                                              IPC::Message::PRIORITY_URGENT))) {
+                                              IPC::Message::NESTED_INSIDE_CPOW))) {
     CloseDescriptor(parentSide);
     CloseDescriptor(childSide);
     return NS_ERROR_BRIDGE_OPEN_PARENT;
   }
 
   if (!aChildChannel->Send(new ChannelOpened(childSide,
                                             aParentPid,
                                             aChildProtocol,
-                                            IPC::Message::PRIORITY_URGENT))) {
+                                            IPC::Message::NESTED_INSIDE_CPOW))) {
     CloseDescriptor(parentSide);
     CloseDescriptor(childSide);
     return NS_ERROR_BRIDGE_OPEN_CHILD;
   }
 
   return NS_OK;
 }
 
--- a/ipc/glue/Shmem.cpp
+++ b/ipc/glue/Shmem.cpp
@@ -20,17 +20,17 @@ class ShmemCreated : public IPC::Message
 private:
   typedef Shmem::id_t id_t;
 
 public:
   ShmemCreated(int32_t routingId,
                id_t aIPDLId,
                size_t aSize,
                SharedMemory::SharedMemoryType aType) :
-    IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, PRIORITY_URGENT)
+    IPC::Message(routingId, SHMEM_CREATED_MESSAGE_TYPE, NESTED_INSIDE_CPOW)
   {
     IPC::WriteParam(this, aIPDLId);
     IPC::WriteParam(this, aSize);
     IPC::WriteParam(this, int32_t(aType));
   }
 
   static bool
   ReadInfo(const Message* msg, PickleIterator* iter,
@@ -55,17 +55,17 @@ public:
 class ShmemDestroyed : public IPC::Message
 {
 private:
   typedef Shmem::id_t id_t;
 
 public:
   ShmemDestroyed(int32_t routingId,
                  id_t aIPDLId) :
-    IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE, PRIORITY_NORMAL)
+    IPC::Message(routingId, SHMEM_DESTROYED_MESSAGE_TYPE)
   {
     IPC::WriteParam(this, aIPDLId);
   }
 };
 
 static SharedMemory*
 NewSegment(SharedMemory::SharedMemoryType aType)
 {
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -1,17 +1,20 @@
 # 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/.
 
 import sys
 
+NOT_NESTED = 1
+INSIDE_SYNC_NESTED = 2
+INSIDE_CPOW_NESTED = 3
+
 NORMAL_PRIORITY = 1
 HIGH_PRIORITY = 2
-URGENT_PRIORITY = 3
 
 class Visitor:
     def defaultVisit(self, node):
         raise Exception, "INTERNAL ERROR: no visitor for node type `%s'"% (
             node.__class__.__name__)
 
     def visitTranslationUnit(self, tu):
         for cxxInc in tu.cxxIncludes:
@@ -231,17 +234,17 @@ class Namespace(Node):
     def __init__(self, loc, namespace):
         Node.__init__(self, loc)
         self.name = namespace
 
 class Protocol(NamespacedNode):
     def __init__(self, loc):
         NamespacedNode.__init__(self, loc)
         self.sendSemantics = ASYNC
-        self.priority = NORMAL_PRIORITY
+        self.nested = NOT_NESTED
         self.spawnsStmts = [ ]
         self.bridgesStmts = [ ]
         self.opensStmts = [ ]
         self.managers = [ ]
         self.managesStmts = [ ]
         self.messageDecls = [ ]
         self.transitionStmts = [ ]
         self.startStates = [ ]
@@ -291,17 +294,18 @@ class ManagesStmt(Node):
         Node.__init__(self, loc)
         self.name = managedName
 
 class MessageDecl(Node):
     def __init__(self, loc):
         Node.__init__(self, loc)
         self.name = None
         self.sendSemantics = ASYNC
-        self.priority = NORMAL_PRIORITY
+        self.nested = NOT_NESTED
+        self.prio = NORMAL_PRIORITY
         self.direction = None
         self.inParams = [ ]
         self.outParams = [ ]
         self.compress = ''
         self.verify = ''
 
     def addInParams(self, inParamsList):
         self.inParams += inParamsList
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1680,27 +1680,29 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         ns.addstmts([ tfDecl, Whitespace.NL ])
         self.funcDefns.append(tfDefn)
 
         for md in p.messageDecls:
             decls = []
 
             mfDecl, mfDefn = _splitFuncDeclDefn(
                 _generateMessageConstructor(md.msgCtorFunc(), md.msgId(),
-                                            md.decl.type.priority,
+                                            md.decl.type.nested,
+                                            md.decl.type.prio,
                                             md.prettyMsgName(p.name+'::'),
                                             md.decl.type.compress))
             decls.append(mfDecl)
             self.funcDefns.append(mfDefn)
 
             if md.hasReply():
                 rfDecl, rfDefn = _splitFuncDeclDefn(
                     _generateMessageConstructor(
                         md.replyCtorFunc(), md.replyId(),
-                        md.decl.type.priority,
+                        md.decl.type.nested,
+                        md.decl.type.prio,
                         md.prettyReplyName(p.name+'::'),
                         md.decl.type.compress))
                 decls.append(rfDecl)
                 self.funcDefns.append(rfDefn)
 
             decls.append(Whitespace.NL)
             ns.addstmts(decls)
 
@@ -1921,44 +1923,52 @@ class _GenerateProtocolCode(ipdl.ast.Vis
                 StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
                 StmtReturn(ExprLiteral.FALSE),
             ])
 
         return transitionfunc
 
 ##--------------------------------------------------
 
-def _generateMessageConstructor(clsname, msgid, priority, prettyName, compress):
+def _generateMessageConstructor(clsname, msgid, nested, prio, prettyName, compress):
     routingId = ExprVar('routingId')
 
     func = FunctionDefn(FunctionDecl(
         clsname,
         params=[ Decl(Type('int32_t'), routingId.name) ],
         ret=Type('IPC::Message', ptr=1)))
 
     if compress == 'compress':
         compression = ExprVar('IPC::Message::COMPRESSION_ENABLED')
     elif compress:
         assert compress == 'compressall'
         compression = ExprVar('IPC::Message::COMPRESSION_ALL')
     else:
         compression = ExprVar('IPC::Message::COMPRESSION_NONE')
-    if priority == ipdl.ast.NORMAL_PRIORITY:
-        priorityEnum = 'IPC::Message::PRIORITY_NORMAL'
-    elif priority == ipdl.ast.HIGH_PRIORITY:
-        priorityEnum = 'IPC::Message::PRIORITY_HIGH'
+
+    if nested == ipdl.ast.NOT_NESTED:
+        nestedEnum = 'IPC::Message::NOT_NESTED'
+    elif nested == ipdl.ast.INSIDE_SYNC_NESTED:
+        nestedEnum = 'IPC::Message::NESTED_INSIDE_SYNC'
     else:
-        assert priority == ipdl.ast.URGENT_PRIORITY
-        priorityEnum = 'IPC::Message::PRIORITY_URGENT'
+        assert nested == ipdl.ast.INSIDE_CPOW_NESTED
+        nestedEnum = 'IPC::Message::NESTED_INSIDE_CPOW'
+
+    if prio == ipdl.ast.NORMAL_PRIORITY:
+        prioEnum = 'IPC::Message::NORMAL_PRIORITY'
+    else:
+        assert prio == ipdl.ast.HIGH_PRIORITY
+        prioEnum = 'IPC::Message::HIGH_PRIORITY'
 
     func.addstmt(
         StmtReturn(ExprNew(Type('IPC::Message'),
                            args=[ routingId,
                                   ExprVar(msgid),
-                                  ExprVar(priorityEnum),
+                                  ExprVar(nestedEnum),
+                                  ExprVar(prioEnum),
                                   compression,
                                   ExprLiteral.String(prettyName) ])))
 
     return func
 
 ##--------------------------------------------------
 
 class _ComputeTypeDeps(TypeVisitor):
@@ -3917,25 +3927,31 @@ class _GenerateProtocolActorCode(ipdl.as
             switchontype = StmtSwitch(pvar)
             for managee in p.managesStmts:
                 case = StmtBlock()
                 actorvar = ExprVar('actor')
                 manageeipdltype = managee.decl.type
                 manageecxxtype = _cxxBareType(ipdl.type.ActorType(manageeipdltype),
                                               self.side)
                 manageearray = p.managedVar(manageeipdltype, self.side)
+                containervar = ExprVar('container')
 
                 case.addstmts([
                     StmtDecl(Decl(manageecxxtype, actorvar.name),
                              ExprCast(listenervar, manageecxxtype, static=1)),
+                    # Use a temporary variable here so all the assertion expressions
+                    # in the _abortIfFalse call below are textually identical; the
+                    # linker can then merge the strings from the assertion macro(s).
+                    StmtDecl(Decl(Type('auto', ref=1), containervar.name),
+                             manageearray),
                     _abortIfFalse(
-                        _callHasManagedActor(manageearray, actorvar),
+                        _callHasManagedActor(containervar, actorvar),
                         "actor not managed by this!"),
                     Whitespace.NL,
-                    StmtExpr(_callRemoveManagedActor(manageearray, actorvar)),
+                    StmtExpr(_callRemoveManagedActor(containervar, actorvar)),
                     StmtExpr(ExprCall(_deallocMethod(manageeipdltype, self.side),
                                       args=[ actorvar ])),
                     StmtReturn()
                 ])
                 switchontype.addcase(CaseLabel(_protocolId(manageeipdltype).name),
                                      case)
             default = StmtBlock()
             default.addstmts([ _fatalError('unreached'), StmtReturn() ])
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -123,40 +123,38 @@ reserved = set((
         'child',
         'class',
         'compress',
         'compressall',
         '__delete__',
         'delete',                       # reserve 'delete' to prevent its use
         'from',
         'goto',
-        'high',
         'include',
         'intr',
         'manager',
         'manages',
         'namespace',
-        'normal',
+        'nested',
         'nullable',
         'opens',
         'or',
         'parent',
         'prio',
         'protocol',
         'recv',
         'returns',
         'send',
         'spawns',
         'start',
         'state',
         'struct',
         'sync',
         'union',
         'upto',
-        'urgent',
         'using',
         'verify'))
 tokens = [
     'COLONCOLON', 'ID', 'STRING',
 ] + [ r.upper() for r in reserved ]
 
 t_COLONCOLON = '::'
 
@@ -354,17 +352,17 @@ def p_ComponentTypes(p):
         p[1].append(p[2])
         p[0] = p[1]
 
 def p_ProtocolDefn(p):
     """ProtocolDefn : OptionalProtocolSendSemanticsQual PROTOCOL ID '{' ProtocolBody '}' ';'"""
     protocol = p[5]
     protocol.loc = locFromTok(p, 2)
     protocol.name = p[3]
-    protocol.priorityRange = p[1][0]
+    protocol.nestedRange = p[1][0]
     protocol.sendSemantics = p[1][1]
     p[0] = protocol
 
     if Parser.current.type == 'header':
         _error(protocol.loc, 'can\'t define a protocol in a header.  Do it in a protocol spec instead.')
 
 
 def p_ProtocolBody(p):
@@ -497,18 +495,19 @@ def p_MessageDirectionLabel(p):
     elif p[1] == 'both':
         Parser.current.direction = INOUT
     else:
         assert 0
 
 def p_MessageDecl(p):
     """MessageDecl : SendSemanticsQual MessageBody"""
     msg = p[2]
-    msg.priority = p[1][0]
-    msg.sendSemantics = p[1][1]
+    msg.nested = p[1][0]
+    msg.prio = p[1][1]
+    msg.sendSemantics = p[1][2]
 
     if Parser.current.direction is None:
         _error(msg.loc, 'missing message direction')
     msg.direction = Parser.current.direction
 
     p[0] = msg
 
 def p_MessageBody(p):
@@ -636,71 +635,92 @@ def p_StateList(p):
         p[0] = p[1]
 
 def p_State(p):
     """State : ID"""
     p[0] = State(locFromTok(p, 1), p[1])
 
 ##--------------------
 ## Minor stuff
+def p_Nested(p):
+    """Nested : ID"""
+    kinds = {'not': 1,
+             'inside_sync': 2,
+             'inside_cpow': 3}
+    if p[1] not in kinds:
+        _error(locFromTok(p, 1), "Expected not, inside_sync, or inside_cpow for nested()")
+
+    p[0] = { 'nested': kinds[p[1]] }
+
 def p_Priority(p):
-    """Priority : NORMAL
-                | HIGH
-                | URGENT"""
-    prios = {'normal': 1,
-             'high': 2,
-             'urgent': 3}
-    p[0] = prios[p[1]]
+    """Priority : ID"""
+    kinds = {'normal': 1,
+             'high': 2}
+    if p[1] not in kinds:
+        _error(locFromTok(p, 1), "Expected normal or high for prio()")
+
+    p[0] = { 'prio': kinds[p[1]] }
+
+def p_SendQualifier(p):
+    """SendQualifier : NESTED '(' Nested ')'
+                     | PRIO '(' Priority ')'"""
+    p[0] = p[3]
+
+def p_SendQualifierList(p):
+    """SendQualifierList : SendQualifier SendQualifierList
+                         | """
+    if len(p) > 1:
+        p[0] = p[1]
+        p[0].update(p[2])
+    else:
+        p[0] = {}
 
 def p_SendSemanticsQual(p):
-    """SendSemanticsQual : ASYNC
-                         | SYNC
-                         | PRIO '(' Priority ')' ASYNC
-                         | PRIO '(' Priority ')' SYNC
+    """SendSemanticsQual : SendQualifierList ASYNC
+                         | SendQualifierList SYNC
                          | INTR"""
-    if p[1] == 'prio':
-        mtype = p[5]
-        prio = p[3]
+    quals = {}
+    if len(p) == 3:
+        quals = p[1]
+        mtype = p[2]
     else:
-        mtype = p[1]
-        prio = NORMAL_PRIORITY
+        mtype = 'intr'
 
     if mtype == 'async': mtype = ASYNC
     elif mtype == 'sync': mtype = SYNC
     elif mtype == 'intr': mtype = INTR
     else: assert 0
 
-    p[0] = [ prio, mtype ]
+    p[0] = [ quals.get('nested', NOT_NESTED), quals.get('prio', NORMAL_PRIORITY), mtype ]
 
 def p_OptionalProtocolSendSemanticsQual(p):
     """OptionalProtocolSendSemanticsQual : ProtocolSendSemanticsQual
                                          | """
     if 2 == len(p): p[0] = p[1]
-    else:           p[0] = [ (NORMAL_PRIORITY, NORMAL_PRIORITY), ASYNC ]
+    else:           p[0] = [ (NOT_NESTED, NOT_NESTED), ASYNC ]
 
 def p_ProtocolSendSemanticsQual(p):
     """ProtocolSendSemanticsQual : ASYNC
                                  | SYNC
-                                 | PRIO '(' Priority UPTO Priority ')' ASYNC
-                                 | PRIO '(' Priority UPTO Priority ')' SYNC
-                                 | PRIO '(' Priority UPTO Priority ')' INTR
+                                 | NESTED '(' UPTO Nested ')' ASYNC
+                                 | NESTED '(' UPTO Nested ')' SYNC
                                  | INTR"""
-    if p[1] == 'prio':
-        mtype = p[7]
-        prio = (p[3], p[5])
+    if p[1] == 'nested':
+        mtype = p[6]
+        nested = (NOT_NESTED, p[4])
     else:
         mtype = p[1]
-        prio = (NORMAL_PRIORITY, NORMAL_PRIORITY)
+        nested = (NOT_NESTED, NOT_NESTED)
 
     if mtype == 'async': mtype = ASYNC
     elif mtype == 'sync': mtype = SYNC
     elif mtype == 'intr': mtype = INTR
     else: assert 0
 
-    p[0] = [ prio, mtype ]
+    p[0] = [ nested, mtype ]
 
 def p_ParamList(p):
     """ParamList : ParamList ',' Param
                  | Param
                  | """
     if 1 == len(p):
         p[0] = [ ]
     elif 2 == len(p):
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -4,17 +4,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import os, sys
 
 from ipdl.ast import CxxInclude, Decl, Loc, QualifiedId, State, StructDecl, TransitionStmt
 from ipdl.ast import TypeSpec, UnionDecl, UsingStmt, Visitor
 from ipdl.ast import ASYNC, SYNC, INTR
 from ipdl.ast import IN, OUT, INOUT, ANSWER, CALL, RECV, SEND
-from ipdl.ast import NORMAL_PRIORITY, HIGH_PRIORITY, URGENT_PRIORITY
+from ipdl.ast import NOT_NESTED, INSIDE_SYNC_NESTED, INSIDE_CPOW_NESTED
 import ipdl.builtin as builtin
 
 _DELETE_MSG = '__delete__'
 
 
 def _otherside(side):
     if side == 'parent':  return 'child'
     elif side == 'child': return 'parent'
@@ -212,24 +212,24 @@ class IPDLType(Type):
     def isAsync(self): return self.sendSemantics == ASYNC
     def isSync(self): return self.sendSemantics == SYNC
     def isInterrupt(self): return self.sendSemantics is INTR
 
     def hasReply(self):  return (self.isSync() or self.isInterrupt())
 
     @classmethod
     def convertsTo(cls, lesser, greater):
-        if (lesser.priorityRange[0] < greater.priorityRange[0] or
-            lesser.priorityRange[1] > greater.priorityRange[1]):
+        if (lesser.nestedRange[0] < greater.nestedRange[0] or
+            lesser.nestedRange[1] > greater.nestedRange[1]):
             return False
 
         # Protocols that use intr semantics are not allowed to use
-        # message priorities.
+        # message nesting.
         if (greater.isInterrupt() and
-            lesser.priorityRange != (NORMAL_PRIORITY, NORMAL_PRIORITY)):
+            lesser.nestedRange != (NOT_NESTED, NOT_NESTED)):
             return False
 
         if lesser.isAsync():
             return True
         elif lesser.isSync() and not greater.isAsync():
             return True
         elif greater.isInterrupt():
             return True
@@ -246,24 +246,25 @@ class StateType(IPDLType):
         self.start = start
     def isState(self): return True
     def name(self):
         return self.name
     def fullname(self):
         return self.name()
 
 class MessageType(IPDLType):
-    def __init__(self, priority, sendSemantics, direction,
+    def __init__(self, nested, prio, sendSemantics, direction,
                  ctor=False, dtor=False, cdtype=None, compress=False,
                  verify=False):
         assert not (ctor and dtor)
         assert not (ctor or dtor) or type is not None
 
-        self.priority = priority
-        self.priorityRange = (priority, priority)
+        self.nested = nested
+        self.prio = prio
+        self.nestedRange = (nested, nested)
         self.sendSemantics = sendSemantics
         self.direction = direction
         self.params = [ ]
         self.returns = [ ]
         self.ctor = ctor
         self.dtor = dtor
         self.cdtype = cdtype
         self.compress = compress
@@ -290,19 +291,19 @@ class Bridge:
     def __cmp__(self, o):
         return cmp(self.parent, o.parent) or cmp(self.child, o.child)
     def __eq__(self, o):
         return self.parent == o.parent and self.child == o.child
     def __hash__(self):
         return hash(self.parent) + hash(self.child)
 
 class ProtocolType(IPDLType):
-    def __init__(self, qname, priorityRange, sendSemantics, stateless=False):
+    def __init__(self, qname, nestedRange, sendSemantics, stateless=False):
         self.qname = qname
-        self.priorityRange = priorityRange
+        self.nestedRange = nestedRange
         self.sendSemantics = sendSemantics
         self.spawns = set()             # ProtocolType
         self.opens = set()              # ProtocolType
         self.managers = []           # ProtocolType
         self.manages = [ ]
         self.stateless = stateless
         self.hasDelete = False
         self.hasReentrantDelete = False
@@ -710,17 +711,17 @@ class GatherDecls(TcheckVisitor):
             # types?
             qname = p.qname()
             if 0 == len(qname.quals):
                 fullname = None
             else:
                 fullname = str(qname)
             p.decl = self.declare(
                 loc=p.loc,
-                type=ProtocolType(qname, p.priorityRange, p.sendSemantics,
+                type=ProtocolType(qname, p.nestedRange, p.sendSemantics,
                                   stateless=(0 == len(p.transitionStmts))),
                 shortname=p.name,
                 fullname=fullname)
 
             p.parentEndpointDecl = self.declare(
                 loc=p.loc,
                 type=EndpointType(QualifiedId(p.loc, 'Endpoint<' + fullname + 'Parent>', ['mozilla', 'ipc'])),
                 shortname='Endpoint<' + p.name + 'Parent>')
@@ -1120,17 +1121,17 @@ class GatherDecls(TcheckVisitor):
         if _DELETE_MSG == msgname:
             isdtor = True
             cdtype = self.currentProtocolDecl.type
 
 
         # enter message scope
         self.symtab.enterScope(md)
 
-        msgtype = MessageType(md.priority, md.sendSemantics, md.direction,
+        msgtype = MessageType(md.nested, md.prio, md.sendSemantics, md.direction,
                               ctor=isctor, dtor=isdtor, cdtype=cdtype,
                               compress=md.compress, verify=md.verify)
 
         # replace inparam Param nodes with proper Decls
         def paramToDecl(param):
             ptname = param.typespec.basename()
             ploc = param.typespec.loc
 
@@ -1494,32 +1495,32 @@ class CheckTypes(TcheckVisitor):
 
 
     def visitMessageDecl(self, md):
         mtype, mname = md.decl.type, md.decl.progname
         ptype, pname = md.protocolDecl.type, md.protocolDecl.shortname
 
         loc = md.decl.loc
 
-        if mtype.priority == HIGH_PRIORITY and not mtype.isSync():
+        if mtype.nested == INSIDE_SYNC_NESTED and not mtype.isSync():
             self.error(
                 loc,
-                "high priority messages must be sync (here, message `%s' in protocol `%s')",
+                "inside_sync nested messages must be sync (here, message `%s' in protocol `%s')",
                 mname, pname)
 
-        if mtype.priority == URGENT_PRIORITY and (mtype.isOut() or mtype.isInout()):
+        if mtype.nested == INSIDE_CPOW_NESTED and (mtype.isOut() or mtype.isInout()):
             self.error(
                 loc,
-                "urgent parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
+                "inside_cpow nested parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
                 mname, pname)
 
-        # We allow high priority sync messages to be sent from the
-        # parent. Normal and urgent sync messages can only come from
+        # We allow inside_sync messages that are themselves sync to be sent from the
+        # parent. Normal and inside_cpow nested messages that are sync can only come from
         # the child.
-        if mtype.isSync() and mtype.priority == NORMAL_PRIORITY and (mtype.isOut() or mtype.isInout()):
+        if mtype.isSync() and mtype.nested == NOT_NESTED and (mtype.isOut() or mtype.isInout()):
             self.error(
                 loc,
                 "sync parent-to-child messages are verboten (here, message `%s' in protocol `%s')",
                 mname, pname)
 
         if mtype.needsMoreJuiceThan(ptype):
             self.error(
                 loc,
--- a/ipc/ipdl/test/cxx/PTestCancel.ipdl
+++ b/ipc/ipdl/test/cxx/PTestCancel.ipdl
@@ -1,36 +1,36 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto high) sync protocol PTestCancel
+nested(upto inside_sync) sync protocol PTestCancel
 {
 // Test1
 child:
-    prio(high) sync Test1_1();
+    nested(inside_sync) sync Test1_1();
 parent:
     async Done1();
 
 // Test2
 child:
     async Start2();
-    prio(high) sync Test2_2();
+    nested(inside_sync) sync Test2_2();
 parent:
     sync Test2_1();
 
 // Test3
 child:
-    prio(high) sync Test3_1();
+    nested(inside_sync) sync Test3_1();
 parent:
     async Start3();
-    prio(high) sync Test3_2();
+    nested(inside_sync) sync Test3_2();
 
 parent:
     async Done();
 
 child:
-    prio(high) sync CheckChild() returns (uint32_t reply);
+    nested(inside_sync) sync CheckChild() returns (uint32_t reply);
 parent:
-    prio(high) sync CheckParent() returns (uint32_t reply);
+    nested(inside_sync) sync CheckParent() returns (uint32_t reply);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestDemon.ipdl
+++ b/ipc/ipdl/test/cxx/PTestDemon.ipdl
@@ -1,21 +1,21 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto urgent) sync protocol PTestDemon
+nested(upto inside_cpow) sync protocol PTestDemon
 {
 child:
     async Start();
 
 both:
     async AsyncMessage(int n);
-    prio(high) sync HiPrioSyncMessage();
+    nested(inside_sync) sync HiPrioSyncMessage();
 
 parent:
     sync SyncMessage(int n);
 
-    prio(urgent) async UrgentAsyncMessage(int n);
-    prio(urgent) sync UrgentSyncMessage(int n);
+    nested(inside_cpow) async UrgentAsyncMessage(int n);
+    nested(inside_cpow) sync UrgentSyncMessage(int n);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
+++ b/ipc/ipdl/test/cxx/PTestHighestPrio.ipdl
@@ -1,18 +1,18 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto urgent) sync protocol PTestHighestPrio
+nested(upto inside_cpow) sync protocol PTestHighestPrio
 {
 parent:
-  prio(urgent) async Msg1();
-  prio(high) sync Msg2();
-  prio(urgent) async Msg3();
-  prio(urgent) sync Msg4();
+  nested(inside_cpow) async Msg1();
+  nested(inside_sync) sync Msg2();
+  nested(inside_cpow) async Msg3();
+  nested(inside_cpow) sync Msg4();
 
 child:
   async Start();
-  prio(high) sync StartInner();
+  nested(inside_sync) sync StartInner();
 };
 
 }
 }
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/cxx/PTestPriority.ipdl
@@ -0,0 +1,14 @@
+namespace mozilla {
+namespace _ipdltest {
+
+sync protocol PTestPriority {
+parent:
+    prio(high) async Msg1();
+    prio(high) sync Msg2();
+
+child:
+    prio(high) async Msg3();
+};
+
+} // namespace _ipdltest
+} // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestRPC.ipdl
+++ b/ipc/ipdl/test/cxx/PTestRPC.ipdl
@@ -1,21 +1,21 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto high) sync protocol PTestRPC
+nested(upto inside_sync) sync protocol PTestRPC
 {
 parent:
-    prio(high) sync Test1_Start() returns (uint32_t result);
-    prio(high) sync Test1_InnerEvent() returns (uint32_t result);
+    nested(inside_sync) sync Test1_Start() returns (uint32_t result);
+    nested(inside_sync) sync Test1_InnerEvent() returns (uint32_t result);
     async Test2_Start();
-    prio(high) sync Test2_OutOfOrder();
+    nested(inside_sync) sync Test2_OutOfOrder();
 
 child:
     async Start();
-    prio(high) sync Test1_InnerQuery() returns (uint32_t result);
-    prio(high) sync Test1_NoReenter() returns (uint32_t result);
-    prio(high) sync Test2_FirstUrgent();
-    prio(high) sync Test2_SecondUrgent();
+    nested(inside_sync) sync Test1_InnerQuery() returns (uint32_t result);
+    nested(inside_sync) sync Test1_NoReenter() returns (uint32_t result);
+    nested(inside_sync) sync Test2_FirstUrgent();
+    nested(inside_sync) sync Test2_SecondUrgent();
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestUrgency.ipdl
+++ b/ipc/ipdl/test/cxx/PTestUrgency.ipdl
@@ -1,19 +1,19 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto high) sync protocol PTestUrgency
+nested(upto inside_cpow) sync protocol PTestUrgency
 {
 parent:
-    prio(high) sync Test1() returns (uint32_t result);
+    nested(inside_sync) sync Test1() returns (uint32_t result);
     async Test2();
     sync Test3() returns (uint32_t result);
     sync FinalTest_Begin();
 
 child:
     async Start();
-    prio(high) sync Reply1() returns (uint32_t result);
-    prio(high) sync Reply2() returns (uint32_t result);
+    nested(inside_sync) sync Reply1() returns (uint32_t result);
+    nested(inside_sync) sync Reply2() returns (uint32_t result);
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
+++ b/ipc/ipdl/test/cxx/PTestUrgentHangs.ipdl
@@ -1,28 +1,28 @@
 namespace mozilla {
 namespace _ipdltest {
 
-prio(normal upto urgent) sync protocol PTestUrgentHangs
+nested(upto inside_cpow) sync protocol PTestUrgentHangs
 {
 parent:
-    prio(high) sync Test1_2();
+    nested(inside_sync) sync Test1_2();
 
-    prio(high) sync TestInner();
-    prio(urgent) sync TestInnerUrgent();
+    nested(inside_sync) sync TestInner();
+    nested(inside_cpow) sync TestInnerUrgent();
 
 child:
-    prio(high) sync Test1_1();
-    prio(high) sync Test1_3();
+    nested(inside_sync) sync Test1_1();
+    nested(inside_sync) sync Test1_3();
 
-    prio(high) sync Test2();
+    nested(inside_sync) sync Test2();
 
-    prio(high) sync Test3();
+    nested(inside_sync) sync Test3();
 
     async Test4();
-    prio(high) sync Test4_1();
+    nested(inside_sync) sync Test4_1();
 
     async Test5();
-    prio(high) sync Test5_1();
+    nested(inside_sync) sync Test5_1();
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/moz.build
+++ b/ipc/ipdl/test/cxx/moz.build
@@ -102,16 +102,17 @@ IPDL_SOURCES += [
     'PTestManyChildAllocsSub.ipdl',
     'PTestMultiMgrs.ipdl',
     'PTestMultiMgrsBottom.ipdl',
     'PTestMultiMgrsLeft.ipdl',
     'PTestMultiMgrsRight.ipdl',
     'PTestNestedLoops.ipdl',
     'PTestOpens.ipdl',
     'PTestOpensOpened.ipdl',
+    'PTestPriority.ipdl',
     'PTestRaceDeadlock.ipdl',
     'PTestRaceDeferral.ipdl',
     'PTestRacyInterruptReplies.ipdl',
     'PTestRacyReentry.ipdl',
     'PTestRacyUndefer.ipdl',
     'PTestRPC.ipdl',
     'PTestSanity.ipdl',
     'PTestSelfManage.ipdl',
rename from build/moz.configure/ffi.configure
rename to js/ffi.configure
--- a/js/ipc/PJavaScript.ipdl
+++ b/js/ipc/PJavaScript.ipdl
@@ -10,48 +10,48 @@ include protocol PContentBridge;
 include DOMTypes;
 include JavaScriptTypes;
 
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace jsipc {
 
-prio(normal upto high) sync protocol PJavaScript
+nested(upto inside_sync) sync protocol PJavaScript
 {
     manager PContent or PContentBridge;
 
 both:
     // Sent when a CPOW has been finalized and table entries can be freed up.
     async DropObject(uint64_t objId);
 
     // These roughly map to the ProxyHandler hooks that CPOWs need.
-    prio(high) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
-    prio(high) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
-    prio(high) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
-    prio(high) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
-    prio(high) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs);
+    nested(inside_sync) sync PreventExtensions(uint64_t objId) returns (ReturnStatus rs);
+    nested(inside_sync) sync GetPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+    nested(inside_sync) sync GetOwnPropertyDescriptor(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, PPropertyDescriptor result);
+    nested(inside_sync) sync DefineProperty(uint64_t objId, JSIDVariant id, PPropertyDescriptor descriptor) returns (ReturnStatus rs);
+    nested(inside_sync) sync Delete(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs);
 
-    prio(high) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
-    prio(high) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
-    prio(high) sync Get(uint64_t objId, JSVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
-    prio(high) sync Set(uint64_t objId, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
+    nested(inside_sync) sync Has(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+    nested(inside_sync) sync HasOwn(uint64_t objId, JSIDVariant id) returns (ReturnStatus rs, bool has);
+    nested(inside_sync) sync Get(uint64_t objId, JSVariant receiver, JSIDVariant id) returns (ReturnStatus rs, JSVariant result);
+    nested(inside_sync) sync Set(uint64_t objId, JSIDVariant id, JSVariant value, JSVariant receiver) returns (ReturnStatus rs);
 
-    prio(high) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
-    prio(high) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
-    prio(high) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
-    prio(high) sync GetBuiltinClass(uint64_t objId) returns (ReturnStatus rs, uint32_t classValue);
-    prio(high) sync IsArray(uint64_t objId) returns (ReturnStatus rs, uint32_t ans);
-    prio(high) sync ClassName(uint64_t objId) returns (nsCString name);
-    prio(high) sync GetPrototype(uint64_t objId) returns (ReturnStatus rs, ObjectOrNullVariant result);
-    prio(high) sync GetPrototypeIfOrdinary(uint64_t objId) returns (ReturnStatus rs, bool isOrdinary, ObjectOrNullVariant result);
-    prio(high) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
+    nested(inside_sync) sync IsExtensible(uint64_t objId) returns (ReturnStatus rs, bool result);
+    nested(inside_sync) sync CallOrConstruct(uint64_t objId, JSParam[] argv, bool construct) returns (ReturnStatus rs, JSVariant result, JSParam[] outparams);
+    nested(inside_sync) sync HasInstance(uint64_t objId, JSVariant v) returns (ReturnStatus rs, bool has);
+    nested(inside_sync) sync GetBuiltinClass(uint64_t objId) returns (ReturnStatus rs, uint32_t classValue);
+    nested(inside_sync) sync IsArray(uint64_t objId) returns (ReturnStatus rs, uint32_t ans);
+    nested(inside_sync) sync ClassName(uint64_t objId) returns (nsCString name);
+    nested(inside_sync) sync GetPrototype(uint64_t objId) returns (ReturnStatus rs, ObjectOrNullVariant result);
+    nested(inside_sync) sync GetPrototypeIfOrdinary(uint64_t objId) returns (ReturnStatus rs, bool isOrdinary, ObjectOrNullVariant result);
+    nested(inside_sync) sync RegExpToShared(uint64_t objId) returns (ReturnStatus rs, nsString source, uint32_t flags);
 
-    prio(high) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
-    prio(high) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
-    prio(high) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
+    nested(inside_sync) sync GetPropertyKeys(uint64_t objId, uint32_t flags) returns (ReturnStatus rs, JSIDVariant[] ids);
+    nested(inside_sync) sync InstanceOf(uint64_t objId, JSIID iid) returns (ReturnStatus rs, bool instanceof);
+    nested(inside_sync) sync DOMInstanceOf(uint64_t objId, int prototypeID, int depth) returns (ReturnStatus rs, bool instanceof);
 
 parent:
     async __delete__();
 };
 
 }
 }
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -200,8 +200,39 @@ js_option('--enable-more-deterministic',
           help='Enable changes that make the shell more deterministic')
 
 @depends('--enable-more-deterministic')
 def more_deterministic(value):
     if value:
         return True
 
 set_define('JS_MORE_DETERMINISTIC', more_deterministic)
+
+
+# CTypes
+# =======================================================
+@depends(building_js, '--help')
+def ctypes_default(building_js, _):
+    return not building_js
+
+js_option('--enable-ctypes', help='Enable js-ctypes',
+          default=ctypes_default)
+
+build_ctypes = depends_if('--enable-ctypes')(lambda _: True)
+
+set_config('BUILD_CTYPES', build_ctypes)
+set_define('BUILD_CTYPES', build_ctypes)
+add_old_configure_assignment('BUILD_CTYPES', build_ctypes)
+
+@depends(build_ctypes, building_js)
+def js_has_ctypes(ctypes, js):
+    if ctypes and js:
+        return True
+
+set_config('JS_HAS_CTYPES', js_has_ctypes)
+set_define('JS_HAS_CTYPES', js_has_ctypes)
+add_old_configure_assignment('JS_HAS_CTYPES', js_has_ctypes)
+
+@depends('--enable-ctypes', '--enable-compile-environment', '--help')
+def ctypes_and_compile_environment(ctypes, compile_environment, _):
+    return ctypes and compile_environment
+
+include_when('ffi.configure', when=ctypes_and_compile_environment)
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -232,17 +232,17 @@ typedef enum JSWhyMagic
     JS_UNINITIALIZED_LEXICAL,
 
     /** for local use */
     JS_GENERIC_MAGIC,
 
     JS_WHY_MAGIC_COUNT
 } JSWhyMagic;
 
-#if defined(IS_LITTLE_ENDIAN)
+#if MOZ_LITTLE_ENDIAN
 # if defined(JS_NUNBOX32)
 typedef union jsval_layout
 {
     uint64_t asBits;
     struct {
         union {
             int32_t        i32;
             uint32_t       u32;
@@ -280,17 +280,17 @@ typedef union jsval_layout
         } payload;
     } s;
     double asDouble;
     void* asPtr;
     size_t asWord;
     uintptr_t asUIntPtr;
 } JSVAL_ALIGNMENT jsval_layout;
 # endif  /* JS_PUNBOX64 */
-#else   /* defined(IS_LITTLE_ENDIAN) */
+#else   /* MOZ_LITTLE_ENDIAN */
 # if defined(JS_NUNBOX32)
 typedef union jsval_layout
 {
     uint64_t asBits;
     struct {
         JSValueTag tag;
         union {
             int32_t        i32;
@@ -326,17 +326,17 @@ typedef union jsval_layout
         } payload;
     } s;
     double asDouble;
     void* asPtr;
     size_t asWord;
     uintptr_t asUIntPtr;
 } JSVAL_ALIGNMENT jsval_layout;
 # endif /* JS_PUNBOX64 */
-#endif  /* defined(IS_LITTLE_ENDIAN) */
+#endif  /* MOZ_LITTLE_ENDIAN */
 
 JS_STATIC_ASSERT(sizeof(jsval_layout) == 8);
 
 /*
  * For codesize purposes on some platforms, it's important that the
  * compiler know that JS::Values constructed from constant values can be
  * folded to constant bit patterns at compile time, rather than
  * constructed at runtime.  Doing this requires a fair amount of C++11
--- a/js/src/ds/MemoryProtectionExceptionHandler.cpp
+++ b/js/src/ds/MemoryProtectionExceptionHandler.cpp
@@ -6,17 +6,17 @@
 
 #include "ds/MemoryProtectionExceptionHandler.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 
 #if defined(XP_WIN)
 # include "jswin.h"
-#elif defined(XP_LINUX)
+#elif defined(XP_UNIX) && !defined(XP_DARWIN)
 # include <signal.h>
 # include <sys/types.h>
 # include <unistd.h>
 #elif defined(XP_DARWIN)
 # include <mach/mach.h>
 # include <unistd.h>
 #endif
 
@@ -205,17 +205,17 @@ MemoryProtectionExceptionHandler::uninst
 
         // Restore the previous exception handler.
         MOZ_ALWAYS_TRUE(RemoveVectoredExceptionHandler(sVectoredExceptionHandler));
 
         sExceptionHandlerInstalled = false;
     }
 }
 
-#elif defined(XP_LINUX)
+#elif defined(XP_UNIX) && !defined(XP_DARWIN)
 
 static struct sigaction sPrevSEGVHandler = {};
 
 /*
  * We can only handle one exception. To guard against races and reentrancy,
  * we set this value the first time we enter the exception handler and never
  * touch it again.
  */
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -2477,16 +2477,24 @@ js::TenuringTracer::traceObjectSlots(Nat
 
 void
 js::TenuringTracer::traceSlots(Value* vp, Value* end)
 {
     for (; vp != end; ++vp)
         traverse(vp);
 }
 
+#ifdef DEBUG
+static inline ptrdiff_t
+OffsetToChunkEnd(void* p)
+{
+    return ChunkLocationOffset - (uintptr_t(p) & gc::ChunkMask);
+}
+#endif
+
 size_t
 js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind dstKind)
 {
     size_t srcSize = Arena::thingSize(dstKind);
     size_t tenuredSize = srcSize;
 
     /*
      * Arrays do not necessarily have the same AllocKind between src and dst.
@@ -2496,16 +2504,17 @@ js::TenuringTracer::moveObjectToTenured(
      * For Arrays we're reducing tenuredSize to the smaller srcSize
      * because moveElementsToTenured() accounts for all Array elements,
      * even if they are inlined.
      */
     if (src->is<ArrayObject>())
         tenuredSize = srcSize = sizeof(NativeObject);
 
     // Copy the Cell contents.
+    MOZ_ASSERT(OffsetToChunkEnd(src) >= ptrdiff_t(srcSize));
     js_memcpy(dst, src, srcSize);
 
     // Move any hash code attached to the object.
     src->zone()->transferUniqueId(dst, src);
 
     // Move the slots and elements, if we need to.
     if (src->isNative()) {
         NativeObject* ndst = &dst->as<NativeObject>();
--- a/js/src/gc/Statistics.cpp
+++ b/js/src/gc/Statistics.cpp
@@ -193,20 +193,34 @@ static const PhaseInfo phases[] = {
 
 static ExtraPhaseInfo phaseExtra[PHASE_LIMIT] = { { 0, 0 } };
 
 // Mapping from all nodes with a multi-parented child to a Vector of all
 // multi-parented children and their descendants. (Single-parented children will
 // not show up in this list.)
 static mozilla::Vector<Phase, 0, SystemAllocPolicy> dagDescendants[Statistics::NumTimingArrays];
 
+// Preorder iterator over all phases in the expanded tree. Positions are
+// returned as <phase,dagSlot> pairs (dagSlot will be zero aka PHASE_DAG_NONE
+// for the top nodes with a single path from the parent, and 1 or more for
+// nodes in multiparented subtrees).
 struct AllPhaseIterator {
+    // If 'descendants' is empty, the current Phase position.
     int current;
+
+    // The depth of the current multiparented node that we are processing, or
+    // zero if we are pointing to the top portion of the tree.
     int baseLevel;
+
+    // When looking at multiparented descendants, the dag slot (index into
+    // PhaseTimeTables) containing the entries for the current parent.
     size_t activeSlot;
+
+    // When iterating over a multiparented subtree, the list of (remaining)
+    // subtree nodes.
     mozilla::Vector<Phase, 0, SystemAllocPolicy>::Range descendants;
 
     explicit AllPhaseIterator(const Statistics::PhaseTimeTable table)
       : current(0)
       , baseLevel(0)
       , activeSlot(PHASE_DAG_NONE)
       , descendants(dagDescendants[PHASE_DAG_NONE].all()) /* empty range */
     {
@@ -219,27 +233,33 @@ struct AllPhaseIterator {
         if (level)
             *level = phaseExtra[*phase].depth + baseLevel;
     }
 
     void advance() {
         MOZ_ASSERT(!done());
 
         if (!descendants.empty()) {
+            // Currently iterating over a multiparented subtree.
             descendants.popFront();
             if (!descendants.empty())
                 return;
 
+            // Just before leaving the last child, reset the iterator to look
+            // at "main" phases (in PHASE_DAG_NONE) instead of multiparented
+            // subtree phases.
             ++current;
             activeSlot = PHASE_DAG_NONE;
             baseLevel = 0;
             return;
         }
 
         if (phaseExtra[current].dagSlot != PHASE_DAG_NONE) {
+            // The current phase has a shared subtree. Load them up into
+            // 'descendants' and advance to the first child.
             activeSlot = phaseExtra[current].dagSlot;
             descendants = dagDescendants[activeSlot].all();
             MOZ_ASSERT(!descendants.empty());
             baseLevel += phaseExtra[current].depth + 1;
             return;
         }
 
         ++current;
@@ -303,29 +323,28 @@ Join(const FragmentVector& fragments, co
     return UniqueChars(joined);
 }
 
 static int64_t
 SumChildTimes(size_t phaseSlot, Phase phase, const Statistics::PhaseTimeTable phaseTimes)
 {
     // Sum the contributions from single-parented children.
     int64_t total = 0;
-    for (unsigned i = 0; i < PHASE_LIMIT; i++) {
+    size_t depth = phaseExtra[phase].depth;
+    for (unsigned i = phase + 1; i < PHASE_LIMIT && phaseExtra[i].depth > depth; i++) {
         if (phases[i].parent == phase)
             total += phaseTimes[phaseSlot][i];
     }
 
     // Sum the contributions from multi-parented children.
     size_t dagSlot = phaseExtra[phase].dagSlot;
     if (dagSlot != PHASE_DAG_NONE) {
-        for (size_t i = 0; i < mozilla::ArrayLength(dagChildEdges); i++) {
-            if (dagChildEdges[i].parent == phase) {
-                Phase child = dagChildEdges[i].child;
-                total += phaseTimes[dagSlot][child];
-            }
+        for (auto edge : dagChildEdges) {
+            if (edge.parent == phase)
+                total += phaseTimes[dagSlot][edge.child];
         }
     }
     return total;
 }
 
 UniqueChars
 Statistics::formatCompactSliceMessage() const
 {
@@ -882,16 +901,18 @@ Statistics::clearMaxGCPauseAccumulator()
 }
 
 int64_t
 Statistics::getMaxGCPauseSinceClear()
 {
     return maxPauseInInterval;
 }
 
+// Sum up the time for a phase, including instances of the phase with different
+// parents.
 static int64_t
 SumPhase(Phase phase, const Statistics::PhaseTimeTable times)
 {
     int64_t sum = 0;
     for (auto i : MakeRange(Statistics::NumTimingArrays))
         sum += times[i][phase];
     return sum;
 }
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -426,17 +426,17 @@ js::gc::GCRuntime::finishVerifier()
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 class CheckHeapTracer : public JS::CallbackTracer
 {
   public:
     explicit CheckHeapTracer(JSRuntime* rt);
     bool init();
-    bool check(AutoLockForExclusiveAccess& lock);
+    void check(AutoLockForExclusiveAccess& lock);
 
   private:
     void onChild(const JS::GCCellPtr& thing) override;
 
     struct WorkItem {
         WorkItem(JS::GCCellPtr thing, const char* name, int parentIndex)
           : thing(thing), name(name), parentIndex(parentIndex), processed(false)
         {}
@@ -507,17 +507,17 @@ CheckHeapTracer::onChild(const JS::GCCel
         return;
     }
 
     WorkItem item(thing, contextName(), parentIndex);
     if (!stack.append(item))
         oom = true;
 }
 
-bool
+void
 CheckHeapTracer::check(AutoLockForExclusiveAccess& lock)
 {
     // The analysis thinks that traceRuntime might GC by calling a GC callback.
     JS::AutoSuppressGCAnalysis nogc;
     if (!rt->isBeingDestroyed())
         rt->gc.traceRuntime(this, lock);
 
     while (!stack.empty()) {
@@ -527,29 +527,27 @@ CheckHeapTracer::check(AutoLockForExclus
         } else {
             parentIndex = stack.length() - 1;
             TraceChildren(this, item.thing);
             stack.back().processed = true;
         }
     }
 
     if (oom)
-        return false;
+        return;
 
     if (failures) {
         fprintf(stderr, "Heap check: %zu failure(s) out of %" PRIu32 " pointers checked\n",
                 failures, visited.count());
     }
     MOZ_RELEASE_ASSERT(failures == 0);
-
-    return true;
 }
 
 void
 js::gc::CheckHeapAfterGC(JSRuntime* rt)
 {
     AutoTraceSession session(rt, JS::HeapState::Tracing);
     CheckHeapTracer tracer(rt);
-    if (!tracer.init() || !tracer.check(session.lock))
-        fprintf(stderr, "OOM checking heap\n");
+    if (!tracer.init())
+        tracer.check(session.lock);
 }
 
 #endif /* JSGC_HASH_TABLE_CHECKS */
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -61,17 +61,17 @@ LIRGenerator::visitParameter(MParameter*
     else
         offset = 1 + param->index();
 
     LParameter* ins = new(alloc()) LParameter;
     defineBox(ins, param, LDefinition::FIXED);
 
     offset *= sizeof(Value);
 #if defined(JS_NUNBOX32)
-# if defined(IS_BIG_ENDIAN)
+# if MOZ_BIG_ENDIAN
     ins->getDef(0)->setOutput(LArgument(offset));
     ins->getDef(1)->setOutput(LArgument(offset + 4));
 # else
     ins->getDef(0)->setOutput(LArgument(offset + 4));
     ins->getDef(1)->setOutput(LArgument(offset));
 # endif
 #elif defined(JS_PUNBOX64)
     ins->getDef(0)->setOutput(LArgument(offset));
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -174,17 +174,17 @@ using mozilla::FloatingPoint;
 
 # define DEFINED_ON(...)                                \
     DEFINED_ON_MAP_ON_ARCHS((none, __VA_ARGS__))
 
 # define PER_ARCH DEFINED_ON(ALL_ARCH)
 # define PER_SHARED_ARCH DEFINED_ON(ALL_SHARED_ARCH)
 
 
-#ifdef IS_LITTLE_ENDIAN
+#if MOZ_LITTLE_ENDIAN
 #define IMM32_16ADJ(X) X << 16
 #else
 #define IMM32_16ADJ(X) X
 #endif
 
 namespace js {
 namespace jit {
 
--- a/js/src/js-config.h.in
+++ b/js/src/js-config.h.in
@@ -43,28 +43,16 @@
 #undef JS_GC_ZEAL
 
 /* Define to 1 if SpiderMonkey should use small chunks. */
 #undef JS_GC_SMALL_CHUNK_SIZE
 
 /* Define to 1 to perform extra assertions and heap poisoning. */
 #undef JS_CRASH_DIAGNOSTICS
 
-/* Define to 1 if the <endian.h> header is present and
-   useable.  See jscpucfg.h.  */
-#undef JS_HAVE_ENDIAN_H
-
-/* Define to 1 if the <machine/endian.h> header is present and
-   useable.  See jscpucfg.h.  */
-#undef JS_HAVE_MACHINE_ENDIAN_H
-
-/* Define to 1 if the <sys/isa_defs.h> header is present and
-   useable.  See jscpucfg.h.  */
-#undef JS_HAVE_SYS_ISA_DEFS_H
-
 /* Define to 1 if SpiderMonkey is in NUNBOX32 mode. */
 #undef JS_NUNBOX32
 
 /* Define to 1 if SpiderMonkey is in PUNBOX64 mode. */
 #undef JS_PUNBOX64
 
 /* MOZILLA JSAPI version number components */
 #undef MOZJS_MAJOR_VERSION
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -563,17 +563,17 @@ js::XDRAtom(XDRState<mode>* xdr, Mutable
     bool latin1 = lengthAndEncoding & 0x1;
 
     JSContext* cx = xdr->cx();
     JSAtom* atom;
     if (latin1) {
         const Latin1Char* chars = reinterpret_cast<const Latin1Char*>(xdr->buf.read(length));
         atom = AtomizeChars(cx, chars, length);
     } else {
-#if IS_LITTLE_ENDIAN
+#if MOZ_LITTLE_ENDIAN
         /* Directly access the little endian chars in the XDR buffer. */
         const char16_t* chars = reinterpret_cast<const char16_t*>(xdr->buf.read(length * sizeof(char16_t)));
         atom = AtomizeChars(cx, chars, length);
 #else
         /*
          * We must copy chars to a temporary buffer to convert between little and
          * big endian data.
          */
@@ -591,17 +591,17 @@ js::XDRAtom(XDRState<mode>* xdr, Mutable
             if (!chars)
                 return false;
         }
 
         JS_ALWAYS_TRUE(xdr->codeChars(chars, length));
         atom = AtomizeChars(cx, chars, length);
         if (chars != stackChars)
             js_free(chars);
-#endif /* !IS_LITTLE_ENDIAN */
+#endif /* !MOZ_LITTLE_ENDIAN */
     }
 
     if (!atom)
         return false;
     atomp.set(atom);
     return true;
 }
 
--- a/js/src/jscpucfg.h
+++ b/js/src/jscpucfg.h
@@ -2,129 +2,17 @@
  * vim: set ts=8 sts=4 et sw=4 tw=99:
  * 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/. */
 
 #ifndef jscpucfg_h
 #define jscpucfg_h
 
-#define JS_HAVE_LONG_LONG
-
-#if defined(_WIN64)
-
-# if defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)
-#  define IS_LITTLE_ENDIAN 1
-#  undef  IS_BIG_ENDIAN
-# else  /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
-#  error "CPU type is unknown"
-# endif /* !(defined(_M_X64) || defined(_M_AMD64) || defined(_AMD64_)) */
-
-#elif defined(_WIN32)
-
-# ifdef __WATCOMC__
-#  define HAVE_VA_LIST_AS_ARRAY 1
-# endif
-
-# define IS_LITTLE_ENDIAN 1
-# undef  IS_BIG_ENDIAN
-
-#elif defined(__APPLE__) || defined(__powerpc__) || defined(__ppc__)
-# if __LITTLE_ENDIAN__
-#  define IS_LITTLE_ENDIAN 1
-#  undef  IS_BIG_ENDIAN
-# elif __BIG_ENDIAN__
-#  undef  IS_LITTLE_ENDIAN
-#  define IS_BIG_ENDIAN 1
-# endif
-
-#elif defined(JS_HAVE_ENDIAN_H)
-# include <endian.h>
-
-/*
- * Historically, OSes providing <endian.h> only defined
- * __BYTE_ORDER to either __LITTLE_ENDIAN or __BIG_ENDIAN.
- * The Austin group decided to standardise <endian.h> in
- * POSIX around 2011, expecting it to provide a BYTE_ORDER
- * #define set to either LITTLE_ENDIAN or BIG_ENDIAN. We
- * should try to cope with both possibilities here.
- */
-
-# if defined(__BYTE_ORDER) || defined(BYTE_ORDER)
-#  if defined(__BYTE_ORDER)
-#   if __BYTE_ORDER == __LITTLE_ENDIAN
-#    define IS_LITTLE_ENDIAN 1
-#    undef  IS_BIG_ENDIAN
-#   elif __BYTE_ORDER == __BIG_ENDIAN
-#    undef  IS_LITTLE_ENDIAN
-#    define IS_BIG_ENDIAN 1
-#   endif
-#  endif
-#  if defined(BYTE_ORDER)
-#   if BYTE_ORDER == LITTLE_ENDIAN
-#    define IS_LITTLE_ENDIAN 1
-#    undef  IS_BIG_ENDIAN
-#   elif BYTE_ORDER == BIG_ENDIAN
-#    undef  IS_LITTLE_ENDIAN
-#    define IS_BIG_ENDIAN 1
-#   endif
-#  endif
-# else /* !defined(__BYTE_ORDER) */
-#  error "endian.h does not define __BYTE_ORDER nor BYTE_ORDER. Cannot determine endianness."
-# endif
-
-/* BSDs */
-#elif defined(JS_HAVE_MACHINE_ENDIAN_H)
-# include <sys/types.h>
-# include <machine/endian.h>
-
-# if defined(_BYTE_ORDER)
-#  if _BYTE_ORDER == _LITTLE_ENDIAN
-#   define IS_LITTLE_ENDIAN 1
-#   undef  IS_BIG_ENDIAN
-#  elif _BYTE_ORDER == _BIG_ENDIAN
-#   undef  IS_LITTLE_ENDIAN
-#   define IS_BIG_ENDIAN 1
-#  endif
-# else /* !defined(_BYTE_ORDER) */
-#  error "machine/endian.h does not define _BYTE_ORDER. Cannot determine endianness."
-# endif
-
-#elif defined(JS_HAVE_SYS_ISA_DEFS_H)
-# include <sys/isa_defs.h>
-
-# if defined(_BIG_ENDIAN)
-#  undef IS_LITTLE_ENDIAN
-#  define IS_BIG_ENDIAN 1
-# elif defined(_LITTLE_ENDIAN)
-#  define IS_LITTLE_ENDIAN 1
-#  undef IS_BIG_ENDIAN
-# else /* !defined(_LITTLE_ENDIAN) */
-#  error "sys/isa_defs.h does not define _BIG_ENDIAN or _LITTLE_ENDIAN. Cannot determine endianness."
-# endif
-# if !defined(JS_STACK_GROWTH_DIRECTION)
-#  if defined(_STACK_GROWS_UPWARD)
-#   define JS_STACK_GROWTH_DIRECTION (1)
-#  elif defined(_STACK_GROWS_DOWNWARD)
-#   define JS_STACK_GROWTH_DIRECTION (-1)
-#  endif
-# endif
-
-#elif defined(__sparc) || defined(__sparc__) || \
-      defined(_POWER) || defined(__hppa) || \
-      defined(_MIPSEB) || defined(_BIG_ENDIAN)
-/* IA64 running HP-UX will have _BIG_ENDIAN defined.
- * IA64 running Linux will have endian.h and be handled above.
- */
-# undef IS_LITTLE_ENDIAN
-# define IS_BIG_ENDIAN 1
-
-#else /* !defined(__sparc) && !defined(__sparc__) && ... */
-# error "Cannot determine endianness of your platform. Please add support to jscpucfg.h."
-#endif
+#include "mozilla/EndianUtils.h"
 
 #ifndef JS_STACK_GROWTH_DIRECTION
 # ifdef __hppa
 #  define JS_STACK_GROWTH_DIRECTION (1)
 # else
 #  define JS_STACK_GROWTH_DIRECTION (-1)
 # endif
 #endif
--- a/js/src/jsdtoa.cpp
+++ b/js/src/jsdtoa.cpp
@@ -11,17 +11,17 @@
 #include "jsdtoa.h"
 
 #include "jsprf.h"
 #include "jstypes.h"
 #include "jsutil.h"
 
 using namespace js;
 
-#ifdef IS_LITTLE_ENDIAN
+#if MOZ_LITTLE_ENDIAN
 #define IEEE_8087
 #else
 #define IEEE_MC68k
 #endif
 
 #ifndef Long
 #define Long int32_t
 #endif
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -994,64 +994,29 @@ AC_CACHE_VAL(ac_cv_type_ssize_t,
                  [ac_cv_type_ssize_t=false])])
 if test "$ac_cv_type_ssize_t" = true ; then
   AC_DEFINE(HAVE_SSIZE_T)
   AC_MSG_RESULT(yes)
 else
   AC_MSG_RESULT(no)
 fi
 
-MOZ_CHECK_HEADERS(endian.h)
-if test "$ac_cv_header_endian_h" = yes; then
-    AC_DEFINE(JS_HAVE_ENDIAN_H)
-fi
-
-MOZ_CHECK_HEADERS([machine/endian.h],[],[],[#include <sys/types.h>])
-if test "$ac_cv_header_machine_endian_h" = yes; then
-    AC_DEFINE(JS_HAVE_MACHINE_ENDIAN_H)
-fi
-
-MOZ_CHECK_HEADERS(sys/isa_defs.h)
-if test "$ac_cv_header_sys_isa_defs_h" = yes; then
-    AC_DEFINE(JS_HAVE_SYS_ISA_DEFS_H)
-fi
-
 AC_LANG_CPLUSPLUS
 
 MOZ_CXX11
 
-dnl Check for .hidden assembler directive and visibility attribute.
-dnl Borrowed from glibc configure.in
-dnl ===============================================================
-if test "$GNU_CC" -a "$OS_TARGET" != WINNT; then
-  AC_DEFINE(HAVE_VISIBILITY_HIDDEN_ATTRIBUTE)
-  AC_DEFINE(HAVE_VISIBILITY_ATTRIBUTE)
-  case "$OS_TARGET" in
-  Darwin)
-    VISIBILITY_FLAGS='-fvisibility=hidden -fvisibility-inlines-hidden'
-    ;;
-  *)
-    VISIBILITY_FLAGS="-I${DIST}/system_wrappers -include ${_topsrcdir}/config/gcc_hidden.h"
-    WRAP_SYSTEM_INCLUDES=1
-    ;;
-  esac
-fi         # GNU_CC
-
 case "${OS_TARGET}" in
 WINNT|Darwin|Android)
   ;;
 *)
   STL_FLAGS="-I${DIST}/stl_wrappers"
   WRAP_STL_INCLUDES=1
   ;;
 esac
 
-AC_SUBST(WRAP_SYSTEM_INCLUDES)
-AC_SUBST_LIST(VISIBILITY_FLAGS)
-
 dnl Checks for header files.
 dnl ========================================================
 AC_HEADER_DIRENT
 case "$target_os" in
 freebsd*)
 # for stuff like -lXshm
     CPPFLAGS="${CPPFLAGS} ${X_CFLAGS}"
     ;;
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -1779,17 +1779,17 @@ DataViewObject::getDataPointer(JSContext
 
     MOZ_ASSERT(offset < UINT32_MAX);
     return static_cast<uint8_t*>(obj->dataPointer()) + uint32_t(offset);
 }
 
 static inline bool
 needToSwapBytes(bool littleEndian)
 {
-#if IS_LITTLE_ENDIAN
+#if MOZ_LITTLE_ENDIAN
     return !littleEndian;
 #else
     return littleEndian;
 #endif
 }
 
 static inline uint8_t
 swapBytes(uint8_t x)
--- a/layout/base/RestyleManagerBase.cpp
+++ b/layout/base/RestyleManagerBase.cpp
@@ -673,26 +673,24 @@ FrameHasPositionedPlaceholderDescendants
         // they ignore their position style ... but they can't.
         NS_ASSERTION(!outOfFlow->IsSVGText(),
                      "SVG text frames can't be out of flow");
         if (aPositionMask & (1 << outOfFlow->StyleDisplay()->mPosition)) {
           return true;
         }
       }
       uint32_t positionMask = aPositionMask;
-      // Is it faster to check aPositionMask & (1 << NS_STYLE_POSITION_ABSOLUTE)
-      // before we check IsAbsPosContainingBlock?  Not clear....
-      if (f->IsAbsPosContainingBlock()) {
-        if (f->IsFixedPosContainingBlock()) {
-          continue;
-        }
-        // We don't care about absolutely positioned things inside f, because
-        // they will still use f as their containing block.
-        positionMask = (1 << NS_STYLE_POSITION_FIXED);
-      }
+      // NOTE:  It's tempting to check f->IsAbsPosContainingBlock() or
+      // f->IsFixedPosContainingBlock() here.  However, that would only
+      // be testing the *new* style of the frame, which might exclude
+      // descendants that currently have this frame as an abs-pos
+      // containing block.  Taking the codepath where we don't reframe
+      // could lead to an unsafe call to
+      // cont->MarkAsNotAbsoluteContainingBlock() before we've reframed
+      // the descendant and taken it off the absolute list.
       if (FrameHasPositionedPlaceholderDescendants(f, positionMask)) {
         return true;
       }
     }
   }
   return false;
 }
 
@@ -1130,17 +1128,27 @@ RestyleManagerBase::ProcessRestyledFrame
           // descendants).
           if (cont->IsAbsPosContainingBlock()) {
             if (!cont->IsAbsoluteContainer() &&
                 (cont->GetStateBits() & NS_FRAME_CAN_HAVE_ABSPOS_CHILDREN)) {
               cont->MarkAsAbsoluteContainingBlock();
             }
           } else {
             if (cont->IsAbsoluteContainer()) {
-              cont->MarkAsNotAbsoluteContainingBlock();
+              if (cont->HasAbsolutelyPositionedChildren()) {
+                // If |cont| still has absolutely positioned children,
+                // we can't call MarkAsNotAbsoluteContainingBlock.  This
+                // will remove a frame list that still has children in
+                // it that we need to keep track of.
+                // The optimization of removing it isn't particularly
+                // important, although it does mean we skip some tests.
+                NS_WARNING("skipping removal of absolute containing block");
+              } else {
+                cont->MarkAsNotAbsoluteContainingBlock();
+              }
             }
           }
         }
       }
     }
 
     if ((hint & nsChangeHint_AddOrRemoveTransform) && frame &&
         !(hint & nsChangeHint_ReconstructFrame)) {
new file mode 100644
--- /dev/null
+++ b/layout/base/crashtests/1299736-1.html
@@ -0,0 +1,15 @@
+<!DOCTYPE HTML>
+<title>Testcase, bug 1299736</title>
+
+<div id="A" style="transform: translateX(50px)">
+  <div id="B">
+    <div id="C" style="position: fixed">
+    </div>
+  </div>
+</div>
+
+<script>
+  document.getElementById("C").offsetLeft; // flush
+  document.getElementById("B").style.transform = "translateX(50px)";
+  document.getElementById("A").style.transform = "";
+</script>
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -473,8 +473,9 @@ load 1163583.html
 load 1234622-1.html
 load 1235467-1.html
 pref(dom.webcomponents.enabled,true) load 1261351.html
 load 1270797-1.html
 load 1278455-1.html
 load 1286889.html
 load 1297835.html
 load 1288608.html
+load 1299736-1.html
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -3556,26 +3556,17 @@ nsCSSFrameConstructor::FindHTMLData(Elem
     // <legend> is only special inside fieldset, we only check the frame tree
     // parent because the content tree parent may not be a <fieldset> due to
     // display:contents, Shadow DOM, or XBL. For floated or absolutely
     // positioned legends we want to construct by display type and
     // not do special legend stuff.
     return nullptr;
   }
 
-  if (aTag == nsGkAtoms::details || aTag == nsGkAtoms::summary) {
-    if (!HTMLDetailsElement::IsDetailsEnabled()) {
-      return nullptr;
-    }
-  }
-
-  if (aTag == nsGkAtoms::summary &&
-      (!aParentFrame || aParentFrame->GetType() != nsGkAtoms::detailsFrame)) {
-    // <summary> is special only if it is a direct child of <details>. If it
-    // isn't, construct it as a normal block frame instead of a summary frame.
+  if (aTag == nsGkAtoms::details && !HTMLDetailsElement::IsDetailsEnabled()) {
     return nullptr;
   }
 
   static const FrameConstructionDataByTag sHTMLData[] = {
     SIMPLE_TAG_CHAIN(img, nsCSSFrameConstructor::FindImgData),
     SIMPLE_TAG_CHAIN(mozgeneratedcontentimage,
                      nsCSSFrameConstructor::FindImgData),
     { &nsGkAtoms::br,
@@ -5900,20 +5891,33 @@ nsCSSFrameConstructor::AddFrameConstruct
     CreateGeneratedContentItem(aState, aParentFrame, aContent, styleContext,
                                CSSPseudoElementType::after, aItems);
     if (canHavePageBreak && display->mBreakAfter) {
       AddPageBreakItem(aContent, aStyleContext, aItems);
     }
     return;
   }
 
-  FrameConstructionItem* item =
-    aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
-                      pendingBinding, styleContext.forget(),
-                      aSuppressWhiteSpaceOptimizations, aAnonChildren);
+  FrameConstructionItem* item = nullptr;
+  if (details && details->IsDetailsEnabled() && details->Open()) {
+    auto* summary = HTMLSummaryElement::FromContentOrNull(aContent);
+    if (summary && summary->IsMainSummary()) {
+      // If details is open, the main summary needs to be rendered as if it is
+      // the first child, so add the item to the front of the item list.
+      item = aItems.PrependItem(data, aContent, aTag, aNameSpaceID,
+                                pendingBinding, styleContext.forget(),
+                                aSuppressWhiteSpaceOptimizations, aAnonChildren);
+    }
+  }
+
+  if (!item) {
+    item = aItems.AppendItem(data, aContent, aTag, aNameSpaceID,
+                             pendingBinding, styleContext.forget(),
+                             aSuppressWhiteSpaceOptimizations, aAnonChildren);
+  }
   item->mIsText = isText;
   item->mIsGeneratedContent = isGeneratedContent;
   item->mIsAnonymousContentCreatorContent =
     aFlags & ITEM_IS_ANONYMOUSCONTENTCREATOR_CONTENT;
   if (isGeneratedContent) {
     NS_ADDREF(item->mContent);
   }
   item->mIsRootPopupgroup =
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -857,16 +857,37 @@ private:
                                   aSuppressWhiteSpaceOptimizations,
                                   aAnonChildren);
       PR_APPEND_LINK(item, &mItems);
       ++mItemCount;
       ++mDesiredParentCounts[item->DesiredParentType()];
       return item;
     }
 
+    // Arguments are the same as AppendItem().
+    FrameConstructionItem* PrependItem(const FrameConstructionData* aFCData,
+                                       nsIContent* aContent,
+                                       nsIAtom* aTag,
+                                       int32_t aNameSpaceID,
+                                       PendingBinding* aPendingBinding,
+                                       already_AddRefed<nsStyleContext>&& aStyleContext,
+                                       bool aSuppressWhiteSpaceOptimizations,
+                                       nsTArray<nsIAnonymousContentCreator::ContentInfo>* aAnonChildren)
+    {
+      FrameConstructionItem* item =
+        new FrameConstructionItem(aFCData, aContent, aTag, aNameSpaceID,
+                                  aPendingBinding, aStyleContext,
+                                  aSuppressWhiteSpaceOptimizations,
+                                  aAnonChildren);
+      PR_INSERT_LINK(item, &mItems);
+      ++mItemCount;
+      ++mDesiredParentCounts[item->DesiredParentType()];
+      return item;
+    }
+
     void AppendUndisplayedItem(nsIContent* aContent,
                                nsStyleContext* aStyleContext) {
       mUndisplayedItems.AppendElement(UndisplayedItem(aContent, aStyleContext));
     }
 
     void InlineItemAdded() { ++mInlineCount; }
     void BlockItemAdded() { ++mBlockCount; }
     void LineParticipantItemAdded() { ++mLineParticipantCount; }
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -2134,19 +2134,22 @@ nsListControlFrame::KeyDown(nsIDOMEvent*
 #ifdef XP_MACOSX
   dropDownMenuOnUpDown = IsInDropDownMode() && !mComboboxFrame->IsDroppedDown();
   dropDownMenuOnSpace = !keyEvent->IsAlt() && !keyEvent->IsControl() &&
     !keyEvent->IsMeta();
 #else
   dropDownMenuOnUpDown = keyEvent->IsAlt();
   dropDownMenuOnSpace = IsInDropDownMode() && !mComboboxFrame->IsDroppedDown();
 #endif
+  bool withinIncrementalSearchTime =
+    keyEvent->mTime - gLastKeyTime <= INCREMENTAL_SEARCH_KEYPRESS_TIME;
   if ((dropDownMenuOnUpDown &&
        (keyEvent->mKeyCode == NS_VK_UP || keyEvent->mKeyCode == NS_VK_DOWN)) ||
-      (dropDownMenuOnSpace && keyEvent->mKeyCode == NS_VK_SPACE)) {
+      (dropDownMenuOnSpace && keyEvent->mKeyCode == NS_VK_SPACE &&
+       !withinIncrementalSearchTime)) {
     DropDownToggleKey(aKeyEvent);
     if (keyEvent->DefaultPrevented()) {
       return NS_OK;
     }
   }
   if (keyEvent->IsAlt()) {
     return NS_OK;
   }
--- a/layout/forms/test/mochitest.ini
+++ b/layout/forms/test/mochitest.ini
@@ -60,8 +60,9 @@ skip-if = (buildapp == 'b2g' && (toolkit
 [test_textarea_resize.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # b2g(resizing textarea not available in b2g) b2g-debug(resizing textarea not available in b2g) b2g-desktop(resizing textarea not available in b2g)
 [test_bug961363.html]
 skip-if = toolkit == 'android' # Bug 1021644 - Fails when pushed into a different chunk on Android
 [test_bug1111995.html]
 skip-if = buildapp == 'mulet' || buildapp == 'b2g'
 [test_select_vertical.html]
 skip-if = e10s || buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' # Bug 1170129 - vertical <select> popup not implemented for e10s # <select> elements don't use an in-page popup on B2G/Android
+[test_bug1305282.html]
new file mode 100644
--- /dev/null
+++ b/layout/forms/test/test_bug1305282.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=615697
+-->
+<head>
+  <title>Test for Bug 1305282</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1305282">Mozilla Bug 1305282</a>
+<p id="display"></p>
+<div id="content">
+  <select>
+    <option>f o o</option>
+    <option>b a r</option>
+    <option>b o o</option>
+  </select>
+</div>
+<pre id="test">
+<script type="application/javascript">
+
+/** Test for Bug 1305282 **/
+
+var select = document.getElementsByTagName('select')[0];
+
+select.addEventListener("change", function(aEvent) {
+  select.removeEventListener("change", arguments.callee, false);
+  is(select.selectedIndex, 1, "'b a r' option is selected");
+  SimpleTest.finish();
+}, false);
+
+select.addEventListener("focus", function() {
+  select.removeEventListener("focus", arguments.callee, false);
+  SimpleTest.executeSoon(function () {
+    synthesizeKey("VK_DOWN", {});
+    SimpleTest.executeSoon(function () {
+      synthesizeKey('b', {});
+      SimpleTest.executeSoon(function () {
+        synthesizeKey(' ', {});
+        SimpleTest.executeSoon(function () {
+          synthesizeKey("VK_RETURN", {});
+        });
+      });
+    });
+  });
+}, false);
+
+SimpleTest.waitForExplicitFinish();
+SimpleTest.waitForFocus(function() {
+  select.focus();
+});
+
+</script>
+</pre>
+</body>
+</html>
--- a/layout/generic/DetailsFrame.cpp
+++ b/layout/generic/DetailsFrame.cpp
@@ -41,59 +41,54 @@ nsIAtom*
 DetailsFrame::GetType() const
 {
   return nsGkAtoms::detailsFrame;
 }
 
 void
 DetailsFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList)
 {
+#ifdef DEBUG
   if (aListID == kPrincipalList) {
-    HTMLDetailsElement* details = HTMLDetailsElement::FromContent(GetContent());
-    bool isOpen = details->Open();
-
-    if (isOpen) {
-      // If details is open, the first summary needs to be rendered as if it is
-      // the first child.
-      for (nsIFrame* child : aChildList) {
-        HTMLSummaryElement* summary =
-          HTMLSummaryElement::FromContent(child->GetContent());
-
-        if (summary && summary->IsMainSummary()) {
-          // Take out the first summary frame and insert it to the beginning of
-          // the list.
-          aChildList.RemoveFrame(child);
-          aChildList.InsertFrame(nullptr, nullptr, child);
-          break;
-        }
-      }
-    }
-
-#ifdef DEBUG
-    for (nsIFrame* child : aChildList) {
-      HTMLSummaryElement* summary =
-        HTMLSummaryElement::FromContent(child->GetContent());
-
-      if (child == aChildList.FirstChild()) {
-        if (summary && summary->IsMainSummary()) {
-          break;
-        }
-      } else {
-        MOZ_ASSERT(!summary || !summary->IsMainSummary(),
-                   "Rest of the children are neither summary elements nor"
-                   "the main summary!");
-      }
-    }
+    CheckValidMainSummary(aChildList);
+  }
 #endif
 
-  }
-
   nsBlockFrame::SetInitialChildList(aListID, aChildList);
 }
 
+#ifdef DEBUG
+bool
+DetailsFrame::CheckValidMainSummary(const nsFrameList& aFrameList) const
+{
+  for (nsIFrame* child : aFrameList) {
+    HTMLSummaryElement* summary =
+      HTMLSummaryElement::FromContent(child->GetContent());
+
+    if (child == aFrameList.FirstChild()) {
+      if (summary && summary->IsMainSummary()) {
+        return true;
+      } else if (child->GetContent() == GetContent()) {
+        // The child frame's content is the same as our content, which means
+        // it's a kind of wrapper frame. Descend into its child list to find
+        // main summary.
+        if (CheckValidMainSummary(child->PrincipalChildList())) {
+          return true;
+        }
+      }
+    } else {
+      NS_ASSERTION(!summary || !summary->IsMainSummary(),
+                   "Rest of the children are either not summary element "
+                   "or are not the main summary!");
+    }
+  }
+  return false;
+}
+#endif
+
 void
 DetailsFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   nsContentUtils::DestroyAnonymousContent(&mDefaultSummary);
   nsBlockFrame::DestroyFrom(aDestructRoot);
 }
 
 nsresult
--- a/layout/generic/DetailsFrame.h
+++ b/layout/generic/DetailsFrame.h
@@ -33,16 +33,22 @@ public:
 
 #ifdef DEBUG_FRAME_DUMP
   nsresult GetFrameName(nsAString& aResult) const override
   {
     return MakeFrameName(NS_LITERAL_STRING("Details"), aResult);
   }
 #endif
 
+#ifdef DEBUG
+  // Check the frame of the main summary element is the first child in the frame
+  // list. Returns true if we found the main summary frame; false otherwise.
+  bool CheckValidMainSummary(const nsFrameList& aFrameList) const;
+#endif
+
   void SetInitialChildList(ChildListID aListID,
                            nsFrameList& aChildList) override;
 
   void DestroyFrom(nsIFrame* aDestructRoot) override;
 
   // nsIAnonymousContentCreator
   nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
 
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/1304441.html
@@ -0,0 +1,9 @@
+<details>
+<summary>
+<li>
+<style>
+summary{
+all:initial
+}
+:first-child::first-line
+{}
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -634,8 +634,9 @@ load 1278007.html
 load 1279814.html
 load large-border-radius-dashed.html
 load large-border-radius-dashed2.html
 load large-border-radius-dotted.html
 load large-border-radius-dotted2.html
 load 1297427-non-equal-centers.html
 load 1278461-1.html
 load 1278461-2.html
+load 1304441.html
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -4056,21 +4056,21 @@ nsGridContainerFrame::Tracks::Initialize
       // [align|justify]-self:[last-]baseline.
       auto selfAlignment = isOrthogonal ?
         child->StylePosition()->UsedJustifySelf(containerSC) :
         child->StylePosition()->UsedAlignSelf(containerSC);
       selfAlignment &= ~NS_STYLE_ALIGN_FLAG_BITS;
       if (selfAlignment == NS_STYLE_ALIGN_BASELINE) {
         state |= ItemState::eFirstBaseline | ItemState::eSelfBaseline;
         const GridArea& area = gridItem.mArea;
-        baselineTrack = isOrthogonal ? area.mCols.mStart : area.mRows.mStart;
+        baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
       } else if (selfAlignment == NS_STYLE_ALIGN_LAST_BASELINE) {
         state |= ItemState::eLastBaseline | ItemState::eSelfBaseline;
         const GridArea& area = gridItem.mArea;
-        baselineTrack = (isOrthogonal ? area.mCols.mEnd : area.mRows.mEnd) - 1;
+        baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
       }
 
       // [align|justify]-content:[last-]baseline.
       // https://drafts.csswg.org/css-align-3/#baseline-align-content
       // "[...] and its computed 'align-self' or 'justify-self' (whichever
       // affects its block axis) is 'stretch' or 'self-start' ('self-end').
       // For this purpose, the 'start', 'end', 'flex-start', and 'flex-end'
       // values of 'align-self' are treated as either 'self-start' or
@@ -4118,20 +4118,20 @@ nsGridContainerFrame::Tracks::Initialize
                            (alignContent == NS_STYLE_ALIGN_LAST_BASELINE);
               break;
           }
         }
         if (validCombo) {
           const GridArea& area = gridItem.mArea;
           if (alignContent == NS_STYLE_ALIGN_BASELINE) {
             state |= ItemState::eFirstBaseline | ItemState::eContentBaseline;
-            baselineTrack = isOrthogonal ? area.mCols.mStart : area.mRows.mStart;
+            baselineTrack = isInlineAxis ? area.mCols.mStart : area.mRows.mStart;
           } else if (alignContent == NS_STYLE_ALIGN_LAST_BASELINE) {
             state |= ItemState::eLastBaseline | ItemState::eContentBaseline;
-            baselineTrack = (isOrthogonal ? area.mCols.mEnd : area.mRows.mEnd) - 1;
+            baselineTrack = (isInlineAxis ? area.mCols.mEnd : area.mRows.mEnd) - 1;
           }
         }
       }
     }
 
     if (state & ItemState::eIsBaselineAligned) {
       // XXX available size issue
       LogicalSize avail(childWM, INFINITE_ISIZE_COORD, NS_UNCONSTRAINEDSIZE);
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/details-first-line-ref.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  div#details::first-line {
+    color: blue;
+  }
+  </style>
+  <body>
+    <div id="details">
+      <span>Summary
+        <div>Block in summary</div>
+      </span>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/details-first-line.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  summary {
+    display: inline; /* ::first-line appiles only to inline element. */
+  }
+
+  details::first-line {
+    color: blue;
+  }
+  </style>
+  <body>
+    <details>
+      <summary>Summary
+        <!-- Need ib-split so that the summary has multiple frames. -->
+        <div>Block in summary</div>
+      </summary>
+      <p>This is the details.</p>
+    </details>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-details-first-line-1.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  summary {
+    display: inline; /* ::first-line appiles only to inline element. */
+  }
+
+  details::first-line {
+    color: blue;
+  }
+  </style>
+  <body>
+    <details open>
+      <summary>Summary
+        <!-- Need ib-split so that the summary has multiple frames. -->
+        <div>Block in summary</div>
+      </summary>
+      <span>This is the details.</span>
+    </details>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-details-first-line-2.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  summary {
+    display: inline; /* ::first-line appiles only to inline element. */
+  }
+
+  details::first-line {
+    color: blue;
+  }
+  </style>
+  <body>
+    <details open>
+      <span>This is the details.</span>
+      <summary>Summary
+        <!-- Need ib-split so that the summary has multiple frames. -->
+        <div>Block in summary</div>
+      </summary>
+    </details>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-details-first-line-ref.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  div#details::first-line {
+    color: blue;
+  }
+  </style>
+  <body>
+    <div id="details">
+      <span>Summary
+        <div>Block in summary</div>
+      </span>
+      <span>This is the details.</span>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-summary-inline-style-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <body>
+    <div>
+      <span>Summary
+        <div>Block in summary</div>
+      </span>
+      <p>This is the details.</p>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-summary-inline-style.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  summary {
+    display: inline;
+  }
+  </style>
+  <body>
+    <details open>
+      <p>This is the details.</p>
+      <!-- Make summary the second element child so that layout will try to
+           render it as the first child. -->
+      <summary>Summary
+        <!-- Need ib-split so that the summary has multiple frames. -->
+        <div>Block in summary</div>
+      </summary>
+    </details>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-summary-table-cell-style-ref.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <body>
+    <div>
+      <span style="display: table-cell;">Summary
+        <div>Block in summary</div>
+      </span>
+      <p>This is the details.</p>
+    </div>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/details-summary/open-summary-table-cell-style.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<html>
+  <style>
+  summary {
+    display: table-cell;
+  }
+  </style>
+  <body>
+    <details open>
+      <p>This is the details.</p>
+      <!-- Make summary the second element child so that layout will try to
+           render it as the first child. -->
+      <summary>Summary
+        <div>Block in summary</div>
+      </summary>
+    </details>
+  </body>
+</html>
--- a/layout/reftests/details-summary/reftest.list
+++ b/layout/reftests/details-summary/reftest.list
@@ -6,16 +6,18 @@ pref(dom.details_element.enabled,false) 
 pref(dom.details_element.enabled,false) == no-summary.html disabled-no-summary-ref.html
 
 # Basic <summary> handling
 == multiple-summary.html single-summary.html
 == open-multiple-summary.html open-multiple-summary-ref.html
 == summary-not-first-child.html single-summary.html
 == open-summary-not-first-child.html open-single-summary.html
 == open-summary-block-style.html open-summary-block-style-ref.html
+== open-summary-inline-style.html open-summary-inline-style-ref.html
+== open-summary-table-cell-style.html open-summary-table-cell-style-ref.html
 == no-summary.html no-summary-ref.html
 == open-no-summary.html open-no-summary-ref.html
 == summary-not-in-details.html summary-not-in-details-ref.html
 == summary-not-direct-child.html summary-not-direct-child-ref.html
 == float-in-summary.html float-in-summary-ref.html
 
 # Add elements dynamically
 == dynamic-add-single-summary.html open-single-summary.html
@@ -65,16 +67,19 @@ pref(dom.details_element.enabled,false) 
 # Various properties on details or summary
 == details-display-inline.html details-display-inline-ref.html
 == details-percentage-height-children.html details-percentage-height-children-ref.html
 == details-absolute-children.html details-absolute-children-ref.html
 == details-three-columns.html details-three-columns-ref.html
 == details-writing-mode.html details-writing-mode-ref.html
 == details-in-ol.html details-in-ol-ref.html
 == summary-three-columns.html summary-three-columns-ref.html
+== details-first-line.html details-first-line-ref.html
+== open-details-first-line-1.html open-details-first-line-ref.html
+== open-details-first-line-2.html open-details-first-line-ref.html
 
 # Dispatch mouse click to summary
 == mouse-click-single-summary.html open-single-summary.html
 == mouse-click-twice-single-summary.html single-summary.html
 == mouse-click-open-single-summary.html single-summary.html
 == mouse-click-twice-open-single-summary.html open-single-summary.html
 == mouse-click-open-second-summary.html open-multiple-summary.html
 == mouse-click-overflow-hidden-details.html overflow-hidden-open-details.html
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -42,30 +42,53 @@ SERVO_BINDING_FUNC(Servo_StyleSet_Append
 SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void,
                    RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
                    RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet)
 SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
                    RawServoStyleSetBorrowedMut set, RawServoStyleSheetBorrowed sheet,
                    RawServoStyleSheetBorrowed reference)
 
+// Animations API
+SERVO_BINDING_FUNC(Servo_ParseProperty,
+                   ServoDeclarationBlockStrong,
+                   const uint8_t* property_bytes,
+                   uint32_t property_length,
+                   const uint8_t* value_bytes,
+                   uint32_t value_length,
+                   const uint8_t* base_bytes,
+                   uint32_t base_length,
+                   ThreadSafeURIHolder* base,
+                   ThreadSafeURIHolder* referrer,
+                   ThreadSafePrincipalHolder* principal)
+SERVO_BINDING_FUNC(Servo_RestyleWithAddedDeclaration,
+                   ServoComputedValuesStrong,
+                   ServoDeclarationBlockBorrowed declarations,
+                   ServoComputedValuesBorrowed previous_style)
+
 // Style attribute
 SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, ServoDeclarationBlockStrong,
                    const uint8_t* bytes, uint32_t length,
                    nsHTMLCSSStyleSheet* cache)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_AddRef, void,
                    ServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_Release, void,
                    ServoDeclarationBlockBorrowed declarations)
+SERVO_BINDING_FUNC(Servo_DeclarationBlock_Equals, bool,
+                   ServoDeclarationBlockBorrowed a,
+                   ServoDeclarationBlockBorrowed b)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCache, nsHTMLCSSStyleSheet*,
                    ServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetImmutable, void,
                    ServoDeclarationBlockBorrowed declarations)
 SERVO_BINDING_FUNC(Servo_DeclarationBlock_ClearCachePointer, void,
                    ServoDeclarationBlockBorrowed declarations)
+SERVO_BINDING_FUNC(Servo_DeclarationBlock_SerializeOneValue, void,
+                   ServoDeclarationBlockBorrowed declarations,
+                   nsString* buffer)
 
 // CSS supports()
 SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
                    const uint8_t* name, uint32_t name_length,
                    const uint8_t* value, uint32_t value_length)
 
 // Computed style data
 SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong,
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -615,16 +615,29 @@ Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* 
   // XXXbholley: We should be able to do this without converting, I just can't
   // find the right thing to call.
   nsDependentAtomString atomStr(aAtom);
   NS_ConvertUTF8toUTF16 inStr(nsDependentCSubstring(aString, aLength));
   return nsContentUtils::EqualsIgnoreASCIICase(atomStr, inStr);
 }
 
 void
+Gecko_Utf8SliceToString(nsString* aString,
+                        const uint8_t* aBuffer,
+                        size_t aBufferLen)
+{
+  MOZ_ASSERT(aString);
+  MOZ_ASSERT(aBuffer);
+
+  aString->Truncate();
+  AppendUTF8toUTF16(Substring(reinterpret_cast<const char*>(aBuffer),
+                              aBufferLen), *aString);
+}
+
+void
 Gecko_FontFamilyList_Clear(FontFamilyList* aList) {
   aList->Clear();
 }
 
 void
 Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName)
 {
   // Servo doesn't record whether the name was quoted or unquoted, so just
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -221,16 +221,21 @@ ServoDeclarationBlockBorrowedOrNull Geck
 // Atoms.
 nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
 void Gecko_AddRefAtom(nsIAtom* aAtom);
 void Gecko_ReleaseAtom(nsIAtom* aAtom);
 const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
 bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
 bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
 
+// Strings (temporary until bug 1294742)
+void Gecko_Utf8SliceToString(nsString* aString,
+                             const uint8_t* aBuffer,
+                             size_t aBufferLen);
+
 // Font style
 void Gecko_FontFamilyList_Clear(FontFamilyList* aList);
 void Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName);
 void Gecko_FontFamilyList_AppendGeneric(FontFamilyList* list, FontFamilyType familyType);
 void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src);
 
 // Counter style.
 void Gecko_SetListStyleType(nsStyleList* style_struct, uint32_t type);
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -22,16 +22,17 @@
 #include "nsStyleSet.h"
 #include "nsComputedDOMStyle.h"
 #include "nsCSSParser.h"
 #include "nsCSSPseudoElements.h"
 #include "mozilla/css/Declaration.h"
 #include "mozilla/dom/Element.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Likely.h"
+#include "mozilla/ServoBindings.h" // ServoDeclarationBlock
 #include "gfxMatrix.h"
 #include "gfxQuaternion.h"
 #include "nsIDocument.h"
 #include "nsIFrame.h"
 #include "gfx2DGlue.h"
 
 using namespace mozilla;
 using namespace mozilla::css;
@@ -3032,19 +3033,49 @@ BuildStyleRule(nsCSSPropertyID aProperty
   declaration->ValueAppended(aProperty);
   declaration->CompressFrom(&block);
 
   RefPtr<css::StyleRule> rule = new css::StyleRule(nullptr, declaration, 0, 0);
   return rule.forget();
 }
 
 static bool
+ComputeValuesFromStyleContext(
+  nsCSSPropertyID aProperty,
+  CSSEnabledState aEnabledState,
+  nsStyleContext* aStyleContext,
+  nsTArray<PropertyStyleAnimationValuePair>& aValues)
+{
+  // Extract computed value of our property (or all longhand components, if
+  // aProperty is a shorthand) from the temporary style context
+  if (nsCSSProps::IsShorthand(aProperty)) {
+    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty, aEnabledState) {
+      if (nsCSSProps::kAnimTypeTable[*p] == eStyleAnimType_None) {
+        // Skip non-animatable component longhands.
+        continue;
+      }
+      PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+      pair->mProperty = *p;
+      if (!StyleAnimationValue::ExtractComputedValue(*p, aStyleContext,
+                                                     pair->mValue)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
+  pair->mProperty = aProperty;
+  return StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
+                                                   pair->mValue);
+}
+
+static bool
 ComputeValuesFromStyleRule(nsCSSPropertyID aProperty,
                            CSSEnabledState aEnabledState,
-                           dom::Element* aTargetElement,
                            nsStyleContext* aStyleContext,
                            css::StyleRule* aStyleRule,
                            nsTArray<PropertyStyleAnimationValuePair>& aValues,
                            bool* aIsContextSensitive)
 {
   MOZ_ASSERT(aStyleContext);
   if (!nsCSSProps::IsEnabled(aProperty, aEnabledState)) {
     return false;
@@ -3095,38 +3126,18 @@ ComputeValuesFromStyleRule(nsCSSProperty
     declaration->SetImmutable();
     tmpStyleContext =
       styleSet->ResolveStyleByAddingRules(aStyleContext, ruleArray);
     if (!tmpStyleContext) {
       return false;
     }
   }
 
-  // Extract computed value of our property (or all longhand components, if
-  // aProperty is a shorthand) from the temporary style rule
-  if (nsCSSProps::IsShorthand(aProperty)) {
-    CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aProperty, aEnabledState) {
-      if (nsCSSProps::kAnimTypeTable[*p] == eStyleAnimType_None) {
-        // Skip non-animatable component longhands.
-        continue;
-      }
-      PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
-      pair->mProperty = *p;
-      if (!StyleAnimationValue::ExtractComputedValue(*p, tmpStyleContext,
-                                                     pair->mValue)) {
-        return false;
-      }
-    }
-    return true;
-  } else {
-    PropertyStyleAnimationValuePair* pair = aValues.AppendElement();
-    pair->mProperty = aProperty;
-    return StyleAnimationValue::ExtractComputedValue(aProperty, tmpStyleContext,
-                                                     pair->mValue);
-  }
+  return ComputeValuesFromStyleContext(aProperty, aEnabledState,
+                                       tmpStyleContext, aValues);
 }
 
 /* static */ bool
 StyleAnimationValue::ComputeValue(nsCSSPropertyID aProperty,
                                   dom::Element* aTargetElement,
                                   nsStyleContext* aStyleContext,
                                   const nsAString& aSpecifiedValue,
                                   bool aUseSVGMode,
@@ -3155,17 +3166,17 @@ StyleAnimationValue::ComputeValue(nsCSSP
       *aIsContextSensitive = false;
     }
     return true;
   }
 
   AutoTArray<PropertyStyleAnimationValuePair,1> values;
   bool ok = ComputeValuesFromStyleRule(aProperty,
                                        CSSEnabledState::eIgnoreEnabledState,
-                                       aTargetElement, aStyleContext, styleRule,
+                                       aStyleContext, styleRule,
                                        values, aIsContextSensitive);
   if (!ok) {
     return false;
   }
 
   MOZ_ASSERT(values.Length() == 1);
   MOZ_ASSERT(values[0].mProperty == aProperty);
 
@@ -3192,17 +3203,17 @@ ComputeValuesFromSpecifiedValue(
   // and Principal.
   RefPtr<css::StyleRule> styleRule =
     BuildStyleRule(aProperty, aTargetElement, aSpecifiedValue, aUseSVGMode);
   if (!styleRule) {
     return false;
   }
 
   aResult.Clear();
-  return ComputeValuesFromStyleRule(aProperty, aEnabledState, aTargetElement,
+  return ComputeValuesFromStyleRule(aProperty, aEnabledState,
                                     aStyleContext, styleRule, aResult,
                                     /* aIsContextSensitive */ nullptr);
 }
 
 /* static */ bool
 StyleAnimationValue::ComputeValues(
     nsCSSPropertyID aProperty,
     CSSEnabledState aEnabledState,
@@ -3229,16 +3240,55 @@ StyleAnimationValue::ComputeValues(
     nsTArray<PropertyStyleAnimationValuePair>& aResult)
 {
   return ComputeValuesFromSpecifiedValue(aProperty, aEnabledState,
                                          aTargetElement, aStyleContext,
                                          aSpecifiedValue, aUseSVGMode,
                                          aResult);
 }
 
+/* static */ bool
+StyleAnimationValue::ComputeValues(
+  nsCSSPropertyID aProperty,
+  CSSEnabledState aEnabledState,
+  nsStyleContext* aStyleContext,
+  const ServoDeclarationBlock& aDeclarations,
+  nsTArray<PropertyStyleAnimationValuePair>& aValues)
+{
+  MOZ_ASSERT(aStyleContext->PresContext()->StyleSet()->IsServo(),
+             "Should be using ServoStyleSet if we have a"
+             " ServoDeclarationBlock");
+
+  if (!nsCSSProps::IsEnabled(aProperty, aEnabledState)) {
+    return false;
+  }
+
+  RefPtr<ServoComputedValues> previousStyle =
+    aStyleContext->StyleSource().AsServoComputedValues();
+
+  // FIXME: Servo bindings don't yet represent const-ness so we just
+  // cast it away for now.
+  auto declarations = const_cast<ServoDeclarationBlock*>(&aDeclarations);
+  RefPtr<ServoComputedValues> computedValues =
+    Servo_RestyleWithAddedDeclaration(declarations, previousStyle).Consume();
+  if (!computedValues) {
+    return false;
+  }
+
+  RefPtr<nsStyleContext> tmpStyleContext =
+    NS_NewStyleContext(aStyleContext, aStyleContext->PresContext(),
+                       aStyleContext->GetPseudo(),
+                       aStyleContext->GetPseudoType(),
+                       computedValues.forget(),
+                       false /* skipFixup */);
+
+  return ComputeValuesFromStyleContext(aProperty, aEnabledState,
+                                       tmpStyleContext, aValues);
+}
+
 bool
 StyleAnimationValue::UncomputeValue(nsCSSPropertyID aProperty,
                                     const StyleAnimationValue& aComputedValue,
                                     nsCSSValue& aSpecifiedValue)
 {
   Unit unit = aComputedValue.GetUnit();
   switch (unit) {
     case eUnit_Normal:
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -15,16 +15,17 @@
 #include "nsCoord.h"
 #include "nsColor.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 
 class nsIFrame;
 class nsStyleContext;
 class gfx3DMatrix;
+struct ServoDeclarationBlock;
 
 namespace mozilla {
 
 namespace css {
 class StyleRule;
 } // namespace css
 
 namespace dom {
@@ -231,16 +232,27 @@ public:
                 mozilla::CSSEnabledState aEnabledState,
                 mozilla::dom::Element* aTargetElement,
                 nsStyleContext* aStyleContext,
                 const nsCSSValue& aSpecifiedValue,
                 bool aUseSVGMode,
                 nsTArray<PropertyStyleAnimationValuePair>& aResult);
 
   /**
+   * A variant of ComputeValues that takes a ServoDeclarationBlock as the
+   * specified value.
+   */
+  static MOZ_MUST_USE bool
+  ComputeValues(nsCSSPropertyID aProperty,
+                mozilla::CSSEnabledState aEnabledState,
+                nsStyleContext* aStyleContext,
+                const ServoDeclarationBlock& aDeclarations,
+                nsTArray<PropertyStyleAnimationValuePair>& aValues);
+
+  /**
    * Creates a specified value for the given computed value.
    *
    * The first two overloads fill in an nsCSSValue object; the third
    * produces a string.  For the overload that takes a const
    * StyleAnimationValue& reference, the nsCSSValue result may depend on
    * objects owned by the |aComputedValue| object, so users of that variant
    * must keep |aComputedValue| alive longer than |aSpecifiedValue|.
    * The overload that takes an rvalue StyleAnimationValue reference
--- a/mfbt/BufferList.h
+++ b/mfbt/BufferList.h
@@ -392,16 +392,17 @@ BufferList<AllocPolicy>::MoveFallible(bo
   BufferList<OtherAllocPolicy> result(0, 0, mStandardCapacity, aAP);
 
   IterImpl iter = Iter();
   while (!iter.Done()) {
     size_t toAdvance = iter.RemainingInSegment();
 
     if (!toAdvance || !result.mSegments.append(typename BufferList<OtherAllocPolicy>::Segment(iter.mData, toAdvance, toAdvance))) {
       *aSuccess = false;
+      result.mSegments.clear();
       return result;
     }
     iter.Advance(*this, toAdvance);
   }
 
   result.mSize = mSize;
   mSegments.clear();
   mSize = 0;
--- a/mobile/android/base/AppConstants.java.in
+++ b/mobile/android/base/AppConstants.java.in
@@ -46,21 +46,16 @@ public class AppConstants {
         /*
          * The SDK_INT >= N check can only pass if our MAX_SDK_VERSION is
          * _greater than or equal_ to that number, because otherwise we
          * won't be installed on the device.
          *
          * If MIN_SDK_VERSION is greater than or equal to the number, there
          * is no need to do the runtime check.
          */
-        public static final boolean feature10Plus = MIN_SDK_VERSION >= 10 || (MAX_SDK_VERSION >= 10 && Build.VERSION.SDK_INT >= 10);
-        public static final boolean feature11Plus = MIN_SDK_VERSION >= 11 || (MAX_SDK_VERSION >= 11 && Build.VERSION.SDK_INT >= 11);
-        public static final boolean feature12Plus = MIN_SDK_VERSION >= 12 || (MAX_SDK_VERSION >= 12 && Build.VERSION.SDK_INT >= 12);
-        public static final boolean feature14Plus = MIN_SDK_VERSION >= 14 || (MAX_SDK_VERSION >= 14 && Build.VERSION.SDK_INT >= 14);
-        public static final boolean feature15Plus = MIN_SDK_VERSION >= 15 || (MAX_SDK_VERSION >= 15 && Build.VERSION.SDK_INT >= 15);
         public static final boolean feature16Plus = MIN_SDK_VERSION >= 16 || (MAX_SDK_VERSION >= 16 && Build.VERSION.SDK_INT >= 16);
         public static final boolean feature17Plus = MIN_SDK_VERSION >= 17 || (MAX_SDK_VERSION >= 17 && Build.VERSION.SDK_INT >= 17);
         public static final boolean feature19Plus = MIN_SDK_VERSION >= 19 || (MAX_SDK_VERSION >= 19 && Build.VERSION.SDK_INT >= 19);
         public static final boolean feature20Plus = MIN_SDK_VERSION >= 20 || (MAX_SDK_VERSION >= 20 && Build.VERSION.SDK_INT >= 20);
         public static final boolean feature21Plus = MIN_SDK_VERSION >= 21 || (MAX_SDK_VERSION >= 21 && Build.VERSION.SDK_INT >= 21);
 
         /*
          * If our MIN_SDK_VERSION is 14 or higher, we must be an ICS device.
@@ -233,17 +228,17 @@ public class AppConstants {
 //#else
     false;
 //#endif
 
     // Android Beam is only supported on API14+, so we don't even bother building
     // it if this APK doesn't include API14 support.
     public static final boolean MOZ_ANDROID_BEAM =
 //#ifdef MOZ_ANDROID_BEAM
-    Versions.feature14Plus;
+    true;
 //#else
     false;
 //#endif
 
     // See this wiki page for more details about channel specific build defines:
     // https://wiki.mozilla.org/Platform/Channel-specific_build_defines
     public static final boolean RELEASE_BUILD =
 //#ifdef RELEASE_BUILD
@@ -280,17 +275,17 @@ public class AppConstants {
 //#ifdef MOZILLA_OFFICIAL
     true;
 //#else
     false;
 //#endif
 
     public static final boolean ANDROID_DOWNLOADS_INTEGRATION =
 //#ifdef MOZ_ANDROID_DOWNLOADS_INTEGRATION
-    AppConstants.Versions.feature12Plus;
+    true;
 //#else
     false;
 //#endif
 
     public static final boolean MOZ_LINKER_EXTRACT =
 //#ifdef MOZ_LINKER_EXTRACT
     true;
 //#else
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -510,17 +510,17 @@ public class BrowserApp extends GeckoApp
                     // Go forward on R1
                     Tabs.getInstance().getSelectedTab().doForward();
                     return true;
             }
         }
 
         // Check if this was a shortcut. Meta keys exists only on 11+.
         final Tab tab = Tabs.getInstance().getSelectedTab();
-        if (Versions.feature11Plus && tab != null && event.isCtrlPressed()) {
+        if (tab != null && event.isCtrlPressed()) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_LEFT_BRACKET:
                     tab.doBack();
                     return true;
 
                 case KeyEvent.KEYCODE_RIGHT_BRACKET:
                     tab.doForward();
                     return true;
@@ -744,17 +744,18 @@ public class BrowserApp extends GeckoApp
             "Favicon:CacheLoad",
             "Feedback:MaybeLater",
             "Menu:Add",
             "Menu:Remove",
             "Sanitize:ClearHistory",
             "Sanitize:ClearSyncedTabs",
             "Settings:Show",
             "Telemetry:Gather",
-            "Updater:Launch");
+            "Updater:Launch",
+            "Website:Metadata");
 
         final GeckoProfile profile = getProfile();
 
         // We want to upload the telemetry core ping as soon after startup as possible. It relies on the
         // Distribution being initialized. If you move this initialization, ensure it plays well with telemetry.
         final Distribution distribution = Distribution.init(getApplicationContext());
         distribution.addOnDistributionReadyCallback(
                 new DistributionStoreCallback(getApplicationContext(), profile.getName()));
@@ -1485,17 +1486,18 @@ public class BrowserApp extends GeckoApp
             "Favicon:CacheLoad",
             "Feedback:MaybeLater",
             "Menu:Add",
             "Menu:Remove",
             "Sanitize:ClearHistory",
             "Sanitize:ClearSyncedTabs",
             "Settings:Show",
             "Telemetry:Gather",
-            "Updater:Launch");
+            "Updater:Launch",
+            "Website:Metadata");
 
         if (AppConstants.MOZ_ANDROID_BEAM) {
             NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
             if (nfc != null) {
                 // null this out even though the docs say it's not needed,
                 // because the source code looks like it will only do this
                 // automatically on API 14+
                 nfc.setNdefPushMessageCallback(null, this);
@@ -1925,16 +1927,23 @@ public class BrowserApp extends GeckoApp
                     manager.enqueue(request);
 
                     Log.d(LOGTAG, "Enqueued download (Download Manager)");
                 } catch (RuntimeException e) {
                     Log.e(LOGTAG, "Download failed: " + e);
                 }
                 break;
 
+            case "Website:Metadata":
+                final NativeJSObject metadata = message.getObject("metadata");
+                final String location = message.getString("location");
+
+                // TODO: Store metadata (Bug 1301717)
+                break;
+
             default:
                 super.handleMessage(event, message, callback);
                 break;
         }
     }
 
     private void getFaviconFromCache(final EventCallback callback, final String url) {
         Icons.with(this)
@@ -2756,20 +2765,16 @@ public class BrowserApp extends GeckoApp
         super.onLocaleReady(locale);
 
         HomePanelsManager.getInstance().onLocaleReady(locale);
 
         if (mMenu != null) {
             mMenu.clear();
             onCreateOptionsMenu(mMenu);
         }
-
-        if (!Versions.feature14Plus) {
-            conditionallyNotifyEOL();
-        }
     }
 
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         Log.d(LOGTAG, "onActivityResult: " + requestCode + ", " + resultCode + ", " + data);
         switch (requestCode) {
             case ACTIVITY_REQUEST_PREFERENCES:
                 // We just returned from preferences. If our locale changed,
@@ -3175,22 +3180,18 @@ public class BrowserApp extends GeckoApp
     private void addAddonMenuItemToMenu(final Menu menu, final MenuItemInfo info) {
         info.added = true;
 
         final Menu destination;
         if (info.parent == 0) {
             destination = menu;
         } else if (info.parent == GECKO_TOOLS_MENU) {
             // The tools menu only exists in our -v11 resources.
-            if (Versions.feature11Plus) {
-                final MenuItem tools = menu.findItem(R.id.tools);
-                destination = tools != null ? tools.getSubMenu() : menu;
-            } else {
-                destination = menu;
-            }
+            final MenuItem tools = menu.findItem(R.id.tools);
+            destination = tools != null ? tools.getSubMenu() : menu;
         } else {
             final MenuItem parent = menu.findItem(info.parent);
             if (parent == null) {
                 return;
             }
 
             Menu parentMenu = findParentMenu(menu, parent);
 
@@ -3305,23 +3306,21 @@ public class BrowserApp extends GeckoApp
         // Add add-on menu items, if any exist.
         if (mAddonMenuItemsCache != null && !mAddonMenuItemsCache.isEmpty()) {
             for (MenuItemInfo item : mAddonMenuItemsCache) {
                 addAddonMenuItemToMenu(mMenu, item);
             }
         }
 
         // Action providers are available only ICS+.
-        if (Versions.feature14Plus) {
-            GeckoMenuItem share = (GeckoMenuItem) mMenu.findItem(R.id.share);
-
-            GeckoActionProvider provider = GeckoActionProvider.getForType(GeckoActionProvider.DEFAULT_MIME_TYPE, this);
-
-            share.setActionProvider(provider);
-        }
+        GeckoMenuItem share = (GeckoMenuItem) mMenu.findItem(R.id.share);
+
+        GeckoActionProvider provider = GeckoActionProvider.getForType(GeckoActionProvider.DEFAULT_MIME_TYPE, this);
+
+        share.setActionProvider(provider);
 
         return true;
     }
 
     @Override
     public void openOptionsMenu() {
         hideFirstrunPager(TelemetryContract.Method.MENU);
 
@@ -3440,20 +3439,17 @@ public class BrowserApp extends GeckoApp
             forward.setEnabled(false);
             share.setEnabled(false);
             saveAsPDF.setEnabled(false);
             print.setEnabled(false);
             findInPage.setEnabled(false);
 
             // NOTE: Use MenuUtils.safeSetEnabled because some actions might
             // be on the BrowserToolbar context menu.
-            if (Versions.feature11Plus) {
-                // There is no page menu prior to v11 resources.
-                MenuUtils.safeSetEnabled(aMenu, R.id.page, false);
-            }
+            MenuUtils.safeSetEnabled(aMenu, R.id.page, false);
             MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, false);
             MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, false);
             MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, false);
 
             return true;
         }
 
         // If tab data IS available we need to manually enable items as necessary. They may have
@@ -3464,20 +3460,18 @@ public class BrowserApp extends GeckoApp
         final boolean inGuestMode = GeckoProfile.get(this).inGuestMode();
 
         bookmark.setEnabled(true); // Might have been disabled above, ensure it's reenabled
         bookmark.setVisible(!inGuestMode);
         bookmark.setCheckable(true);
         bookmark.setChecked(tab.isBookmark());
         bookmark.setTitle(resolveBookmarkTitleID(tab.isBookmark()));
 
-        if (Versions.feature11Plus) {
-            // We don't use icons on GB builds so not resolving icons might conserve resources.
-            bookmark.setIcon(resolveBookmarkIconID(tab.isBookmark()));
-        }
+        // We don't use icons on GB builds so not resolving icons might conserve resources.
+        bookmark.setIcon(resolveBookmarkIconID(tab.isBookmark()));
 
         back.setEnabled(tab.canDoBack());
         forward.setEnabled(tab.canDoForward());
         desktopMode.setChecked(tab.getDesktopMode());
 
         View backButtonView = MenuItemCompat.getActionView(back);
 
         if (backButtonView != null) {
@@ -3521,73 +3515,68 @@ public class BrowserApp extends GeckoApp
         final boolean shareVisible = Restrictions.isAllowed(this, Restrictable.SHARE);
         share.setVisible(shareVisible);
         final boolean shareEnabled = StringUtils.isShareableUrl(url) && shareVisible;
         share.setEnabled(shareEnabled);
         MenuUtils.safeSetEnabled(aMenu, R.id.downloads, Restrictions.isAllowed(this, Restrictable.DOWNLOAD));
 
         // NOTE: Use MenuUtils.safeSetEnabled because some actions might
         // be on the BrowserToolbar context menu.
-        if (Versions.feature11Plus) {
-            MenuUtils.safeSetEnabled(aMenu, R.id.page, !isAboutHome(tab));
-        }
+        MenuUtils.safeSetEnabled(aMenu, R.id.page, !isAboutHome(tab));
         MenuUtils.safeSetEnabled(aMenu, R.id.subscribe, tab.hasFeeds());
         MenuUtils.safeSetEnabled(aMenu, R.id.add_search_engine, tab.hasOpenSearch());
         MenuUtils.safeSetEnabled(aMenu, R.id.add_to_launcher, !isAboutHome(tab));
 
-        // Action providers are available only ICS+.
-        if (Versions.feature14Plus) {
-            // This provider also applies to the quick share menu item.
-            final GeckoActionProvider provider = ((GeckoMenuItem) share).getGeckoActionProvider();
-            if (provider != null) {
-                Intent shareIntent = provider.getIntent();
-
-                // For efficiency, the provider's intent is only set once
-                if (shareIntent == null) {
-                    shareIntent = new Intent(Intent.ACTION_SEND);
-                    shareIntent.setType("text/plain");
-                    provider.setIntent(shareIntent);
-                }
-
-                // Replace the existing intent's extras
-                shareIntent.putExtra(Intent.EXTRA_TEXT, url);
-                shareIntent.putExtra(Intent.EXTRA_SUBJECT, tab.getDisplayTitle());
-                shareIntent.putExtra(Intent.EXTRA_TITLE, tab.getDisplayTitle());
-                shareIntent.putExtra(ShareDialog.INTENT_EXTRA_DEVICES_ONLY, true);
-
-                // Clear the existing thumbnail extras so we don't share an old thumbnail.
-                shareIntent.removeExtra("share_screenshot_uri");
-
-                // Include the thumbnail of the page being shared.
-                BitmapDrawable drawable = tab.getThumbnail();
-                if (drawable != null) {
-                    Bitmap thumbnail = drawable.getBitmap();
-
-                    // Kobo uses a custom intent extra for sharing thumbnails.
-                    if (Build.MANUFACTURER.equals("Kobo") && thumbnail != null) {
-                        File cacheDir = getExternalCacheDir();
-
-                        if (cacheDir != null) {
-                            File outFile = new File(cacheDir, "thumbnail.png");
-
+        // This provider also applies to the quick share menu item.
+        final GeckoActionProvider provider = ((GeckoMenuItem) share).getGeckoActionProvider();
+        if (provider != null) {
+            Intent shareIntent = provider.getIntent();
+
+            // For efficiency, the provider's intent is only set once
+            if (shareIntent == null) {
+                shareIntent = new Intent(Intent.ACTION_SEND);
+                shareIntent.setType("text/plain");
+                provider.setIntent(shareIntent);
+            }
+
+            // Replace the existing intent's extras
+            shareIntent.putExtra(Intent.EXTRA_TEXT, url);
+            shareIntent.putExtra(Intent.EXTRA_SUBJECT, tab.getDisplayTitle());
+            shareIntent.putExtra(Intent.EXTRA_TITLE, tab.getDisplayTitle());
+            shareIntent.putExtra(ShareDialog.INTENT_EXTRA_DEVICES_ONLY, true);
+
+            // Clear the existing thumbnail extras so we don't share an old thumbnail.
+            shareIntent.removeExtra("share_screenshot_uri");
+
+            // Include the thumbnail of the page being shared.
+            BitmapDrawable drawable = tab.getThumbnail();
+            if (drawable != null) {
+                Bitmap thumbnail = drawable.getBitmap();
+
+                // Kobo uses a custom intent extra for sharing thumbnails.
+                if (Build.MANUFACTURER.equals("Kobo") && thumbnail != null) {
+                    File cacheDir = getExternalCacheDir();
+
+                    if (cacheDir != null) {
+                        File outFile = new File(cacheDir, "thumbnail.png");
+
+                        try {
+                            final java.io.FileOutputStream out = new java.io.FileOutputStream(outFile);
                             try {
-                                final java.io.FileOutputStream out = new java.io.FileOutputStream(outFile);
+                                thumbnail.compress(Bitmap.CompressFormat.PNG, 90, out);
+                            } finally {
                                 try {
-                                    thumbnail.compress(Bitmap.CompressFormat.PNG, 90, out);
-                                } finally {
-                                    try {
-                                        out.close();
-                                    } catch (final IOException e) { /* Nothing to do here. */ }
-                                }
-                            } catch (FileNotFoundException e) {
-                                Log.e(LOGTAG, "File not found", e);
+                                    out.close();
+                                } catch (final IOException e) { /* Nothing to do here. */ }
                             }
-
-                            shareIntent.putExtra("share_screenshot_uri", Uri.parse(outFile.getPath()));
+                        } catch (FileNotFoundException e) {
+                            Log.e(LOGTAG, "File not found", e);
                         }
+
+                        shareIntent.putExtra("share_screenshot_uri", Uri.parse(outFile.getPath()));
                     }
                 }
             }
         }
 
         final boolean privateTabVisible = Restrictions.isAllowed(this, Restrictable.PRIVATE_BROWSING);
         MenuUtils.safeSetVisible(aMenu, R.id.new_private_tab, privateTabVisible);
 
@@ -3666,28 +3655,22 @@ public class BrowserApp extends GeckoApp
                 } else {
                     extra = "bookmark";
                 }
 
                 if (item.isChecked()) {
                     Telemetry.sendUIEvent(TelemetryContract.Event.UNSAVE, TelemetryContract.Method.MENU, extra);
                     tab.removeBookmark();
                     item.setTitle(resolveBookmarkTitleID(false));
-                    if (Versions.feature11Plus) {
-                        // We don't use icons on GB builds so not resolving icons might conserve resources.
-                        item.setIcon(resolveBookmarkIconID(false));
-                    }
+                    item.setIcon(resolveBookmarkIconID(false));
                 } else {
                     Telemetry.sendUIEvent(TelemetryContract.Event.SAVE, TelemetryContract.Method.MENU, extra);
                     tab.addBookmark();
                     item.setTitle(resolveBookmarkTitleID(true));
-                    if (Versions.feature11Plus) {
-                        // We don't use icons on GB builds so not resolving icons might conserve resources.
-                        item.setIcon(resolveBookmarkIconID(true));
-                    }
+                    item.setIcon(resolveBookmarkIconID(true));
                 }
             }
             return true;
         }
 
         if (itemId == R.id.share) {
             tab = Tabs.getInstance().getSelectedTab();
             if (tab != null) {
--- a/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DoorHangerPopup.java
@@ -318,22 +318,17 @@ public class DoorHangerPopup extends Anc
             firstDoorhanger.showTitle(tab.getFavicon(), baseDomain);
         }
 
         if (isShowing()) {
             show();
             return;
         }
 
-        // Make the popup focusable for accessibility. This gets done here
-        // so the node can be accessibility focused, but on pre-ICS devices this
-        // causes crashes, so it is done after the popup is shown.
-        if (Versions.feature14Plus) {
-            setFocusable(true);
-        }
+        setFocusable(true);
 
         show();
     }
 
     //Show all inter-DoorHanger dividers (ie. Dividers on all visible DoorHangers except the last one)
     private void showDividers() {
         int count = mContent.getChildCount();
         DoorHanger lastVisibleDoorHanger = null;
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -380,19 +380,17 @@ public abstract class GeckoApp
     @Override
     public void invalidateOptionsMenu() {
         if (mMenu == null) {
             return;
         }
 
         onPrepareOptionsMenu(mMenu);
 
-        if (Versions.feature11Plus) {
-            super.invalidateOptionsMenu();
-        }
+        super.invalidateOptionsMenu();
     }
 
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         mMenu = menu;
 
         MenuInflater inflater = getMenuInflater();
         inflater.inflate(R.menu.gecko_app_menu, mMenu);
@@ -847,32 +845,20 @@ public abstract class GeckoApp
                 }
 
                 final Button clearButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
                 clearButton.setEnabled(false);
 
                 dialog.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
-                        if (Versions.feature11Plus) {
-                            if (listView.getCheckedItemCount() == 0) {
-                                clearButton.setEnabled(false);
-                            } else {
-                                clearButton.setEnabled(true);
-                            }
+                        if (listView.getCheckedItemCount() == 0) {
+                            clearButton.setEnabled(false);
                         } else {
-                            final SparseBooleanArray items = listView.getCheckedItemPositions();
-                            for (int j = 0; j < items.size(); j++) {
-                                if (items.valueAt(j) == true) {
-                                    clearButton.setEnabled(true);
-                                    return;
-                                }
-                            }
-
-                            clearButton.setEnabled(false);
+                            clearButton.setEnabled(true);
                         }
                     }
                 });
             }
         });
     }
 
 
@@ -1885,19 +1871,17 @@ public abstract class GeckoApp
                     }
                 }
             }
         };
         mCameraOrientationEventListener.enable();
 
         // Try to make it fully transparent.
         if (mCameraView instanceof SurfaceView) {
-            if (Versions.feature11Plus) {
-                mCameraView.setAlpha(0.0f);
-            }
+            mCameraView.setAlpha(0.0f);
             ViewGroup mCameraLayout = (ViewGroup) findViewById(R.id.camera_layout);
             // Some phones (eg. nexus S) need at least a 8x16 preview size
             mCameraLayout.addView(mCameraView,
                                   new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
         }
     }
 
     @Override
@@ -2124,23 +2108,16 @@ public abstract class GeckoApp
 
         GeckoAppShell.setGeckoInterface(this);
 
         int newOrientation = getResources().getConfiguration().orientation;
         if (GeckoScreenOrientation.getInstance().update(newOrientation)) {
             refreshChrome();
         }
 
-        if (!Versions.feature14Plus) {
-            // Update accessibility settings in case it has been changed by the
-            // user. On API14+, this is handled in LayerView by registering an
-            // accessibility state change listener.
-            GeckoAccessibility.updateAccessibilitySettings(this);
-        }
-
         if (mAppStateListeners != null) {
             for (GeckoAppShell.AppStateListener listener : mAppStateListeners) {
                 listener.onResume();
             }
         }
 
         // We use two times: a pseudo-unique wall-clock time to identify the
         // current session across power cycles, and the elapsed realtime to
--- a/mobile/android/base/java/org/mozilla/gecko/IntentHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/IntentHelper.java
@@ -367,20 +367,16 @@ public final class IntentHelper implemen
         intent.setData(pruned);
 
         return intent;
     }
 
     // We create a separate method to better encapsulate the @TargetApi use.
     @TargetApi(15)
     private static void nullIntentSelector(final Intent intent) {
-        if (!AppConstants.Versions.feature15Plus) {
-            return;
-        }
-
         intent.setSelector(null);
     }
 
     /**
      * Return a <code>Uri</code> instance which is equivalent to <code>u</code>,
      * but with a guaranteed-lowercase scheme as if the API level 16 method
      * <code>u.normalizeScheme</code> had been called.
      *
--- a/mobile/android/base/java/org/mozilla/gecko/ScreenshotObserver.java
+++ b/mobile/android/base/java/org/mozilla/gecko/ScreenshotObserver.java
@@ -51,20 +51,16 @@ public class ScreenshotObserver {
                     MediaStore.Images.ImageColumns.TITLE
     };
 
     /**
      * Start ScreenshotObserver if this device is supported and all required runtime permissions
      * have been granted by the user. Calling this method will not prompt for permissions.
      */
     public void start() {
-        if (!Versions.feature14Plus) {
-            return;
-        }
-
         Permissions.from(context)
                    .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    .doNotPrompt()
                    .run(startObserverRunnable());
     }
 
     private Runnable startObserverRunnable() {
         return new Runnable() {
@@ -78,20 +74,16 @@ public class ScreenshotObserver {
                 } catch (Exception e) {
                     Log.e(LOGTAG, "Failure to start watching media: ", e);
                 }
             }
         };
     }
 
     public void stop() {
-        if (!Versions.feature14Plus) {
-            return;
-        }
-
         if (mediaObserver == null) {
             return;
         }
 
         try {
             context.getContentResolver().unregisterContentObserver(mediaObserver);
             mediaObserver = null;
         } catch (Exception e) {
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -861,18 +861,17 @@ public class Tabs implements GeckoEventL
 
             final boolean needsNewTab;
             final String applicationId = (intent == null) ? null :
                     intent.getStringExtra(Browser.EXTRA_APPLICATION_ID);
             if (applicationId == null) {
                 needsNewTab = (flags & LOADURL_NEW_TAB) != 0;
             } else {
                 // If you modify this code, be careful that intent != null.
-                final boolean extraCreateNewTab = (Versions.feature12Plus) ?
-                        intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false) : false;
+                final boolean extraCreateNewTab = intent.getBooleanExtra(Browser.EXTRA_CREATE_NEW_TAB, false);
                 final Tab applicationTab = getTabForApplicationId(applicationId);
                 if (applicationTab == null || extraCreateNewTab) {
                     needsNewTab = true;
                 } else {
                     needsNewTab = false;
                     delayLoad = false;
                     background = false;
 
--- a/mobile/android/base/java/org/mozilla/gecko/animation/PropertyAnimator.java
+++ b/mobile/android/base/java/org/mozilla/gecko/animation/PropertyAnimator.java
@@ -168,17 +168,17 @@ public class PropertyAnimator implements
                 return true;
             }
         };
 
         // Try to start animation after any on-going layout round
         // in the current view tree. OnPreDrawListener seems broken
         // on pre-Honeycomb devices, start animation immediatelly
         // in this case.
-        if (Versions.feature11Plus && treeObserver != null && treeObserver.isAlive()) {
+        if (treeObserver != null && treeObserver.isAlive()) {
             treeObserver.addOnPreDrawListener(preDrawListener);
         } else {
             mFramePoster.postFirstAnimationFrame();
         }
 
         if (mListeners != null) {
             for (PropertyAnimationListener listener : mListeners) {
                 listener.onPropertyAnimationStart();
--- a/mobile/android/base/java/org/mozilla/gecko/db/AbstractTransactionalProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/AbstractTransactionalProvider.java
@@ -90,17 +90,17 @@ public abstract class AbstractTransactio
     final ThreadLocal<Boolean> isInBatchOperation = new ThreadLocal<Boolean>();
 
     /**
      * Return true if OS version and database parallelism support indicates
      * that this provider should bundle writes into transactions.
      */
     @SuppressWarnings("static-method")
     protected boolean shouldUseTransactions() {
-        return Versions.feature11Plus;
+        return true;
     }
 
     private boolean isInBatch() {
         final Boolean isInBatch = isInBatchOperation.get();
         if (isInBatch == null) {
             return false;
         }
 
--- a/mobile/android/base/java/org/mozilla/gecko/db/DBUtils.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/DBUtils.java
@@ -404,31 +404,18 @@ public class DBUtils {
         // already bound.
         final SQLiteStatement statement = db.compileStatement(sql.toString());
         try {
             bindAllArgs(statement, bindArgs);
             if (!returnChangedRows) {
                 statement.execute();
                 return 0;
             }
-
-            if (AppConstants.Versions.feature11Plus) {
-                // This is a separate method so we can annotate it with @TargetApi.
-                return executeStatementReturningChangedRows(statement);
-            } else {
-                statement.execute();
-                final Cursor cursor = db.rawQuery("SELECT changes()", null);
-                try {
-                    cursor.moveToFirst();
-                    return cursor.getInt(0);
-                } finally {
-                    cursor.close();
-                }
-
-            }
+            // This is a separate method so we can annotate it with @TargetApi.
+            return executeStatementReturningChangedRows(statement);
         } finally {
             statement.close();
         }
     }
 
     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     private static int executeStatementReturningChangedRows(SQLiteStatement statement) {
         return statement.executeUpdateDelete();
--- a/mobile/android/base/java/org/mozilla/gecko/db/SQLiteBridgeContentProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/db/SQLiteBridgeContentProvider.java
@@ -93,20 +93,17 @@ public abstract class SQLiteBridgeConten
                 if (bridge != null) {
                     try {
                         bridge.close();
                     } catch (Exception ex) { }
                 }
             }
             mDatabasePerProfile = null;
         }
-
-        if (AppConstants.Versions.feature11Plus) {
-            super.shutdown();
-        }
+        super.shutdown();
     }
 
     @Override
     public void finalize() {
         shutdown();
     }
 
     /**
--- a/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/HomePager.java
@@ -208,17 +208,17 @@ public class HomePager extends ViewPager
         mRestoreData = restoreData;
 
         // Update the home banner message each time the HomePager is loaded.
         if (mHomeBanner != null) {
             mHomeBanner.update();
         }
 
         // Only animate on post-HC devices, when a non-null animator is given
-        final boolean shouldAnimate = Versions.feature11Plus && animator != null;
+        final boolean shouldAnimate = animator != null;
 
         final HomeAdapter adapter = new HomeAdapter(mContext, fm);
         adapter.setOnAddPanelListener(mAddPanelListener);
         adapter.setPanelStateChangeListener(mPanelStateChangeListener);
         adapter.setCanLoadHint(true);
         setAdapter(adapter);
 
         // Don't show the tabs strip until we have the
--- a/mobile/android/base/java/org/mozilla/gecko/lwt/LightweightTheme.java
+++ b/mobile/android/base/java/org/mozilla/gecko/lwt/LightweightTheme.java
@@ -352,23 +352,18 @@ public class LightweightTheme implements
 
         int offsetX = 0;
         int offsetY = 0;
 
         // Find if this view or any of its ancestors has been translated or scrolled.
         ViewParent parent;
         View curView = view;
         do {
-            if (Versions.feature11Plus) {
-                offsetX += (int) curView.getTranslationX() - curView.getScrollX();
-                offsetY += (int) curView.getTranslationY() - curView.getScrollY();
-            } else {
-                offsetX -= curView.getScrollX();
-                offsetY -= curView.getScrollY();
-            }
+            offsetX += (int) curView.getTranslationX() - curView.getScrollX();
+            offsetY += (int) curView.getTranslationY() - curView.getScrollY();
 
             parent = curView.getParent();
 
             if (parent instanceof View) {
                 curView = (View) parent;
             }
 
         } while (parent instanceof View);
--- a/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java
+++ b/mobile/android/base/java/org/mozilla/gecko/menu/GeckoMenuInflater.java
@@ -147,19 +147,17 @@ public class GeckoMenuInflater extends M
         }
 
         menuItem.setChecked(item.checked)
                 .setVisible(item.visible)
                 .setEnabled(item.enabled)
                 .setCheckable(item.checkable)
                 .setIcon(item.iconRes);
 
-        if (Versions.feature11Plus) {
-            menuItem.setShowAsAction(item.showAsAction);
-        }
+        menuItem.setShowAsAction(item.showAsAction);
 
         if (geckoItem != null) {
             // We don't need to allow presenter updates during inflation,
             // so we use the weak form of re-enabling changes.
             geckoItem.resumeDispatchingChanges();
         }
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/menu/MenuPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/menu/MenuPanel.java
@@ -24,15 +24,13 @@ public class MenuPanel extends LinearLay
         super(context, attrs);
 
         int width = (int) context.getResources().getDimension(R.dimen.menu_item_row_width);
         setLayoutParams(new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
     }
 
     @Override
     public boolean dispatchPopulateAccessibilityEvent (AccessibilityEvent event) {
-        if (Versions.feature14Plus) {
-            onPopulateAccessibilityEvent(event);
-        }
+        onPopulateAccessibilityEvent(event);
 
         return true;
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/overlays/ui/SendTabDeviceListArrayAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/overlays/ui/SendTabDeviceListArrayAdapter.java
@@ -66,23 +66,17 @@ public class SendTabDeviceListArrayAdapt
     public void updateRecordList() {
         if (currentState != State.LIST) {
             return;
         }
 
         clear();
 
         setNotifyOnChange(false);    // So we don't notify for each add.
-        if (AppConstants.Versions.feature11Plus) {
-             addAll(records);
-        } else {
-            for (RemoteClient record : records) {
-                add(record);
-            }
-        }
+        addAll(records);
 
         notifyDataSetChanged();
     }
 
     @Override
     public View getView(final int position, View convertView, ViewGroup parent) {
         final Context context = getContext();
 
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferenceFragment.java
@@ -161,17 +161,17 @@ public class GeckoPreferenceFragment ext
     private void updateTitle() {
         final String newTitle = getTitle();
         if (newTitle == null) {
             Log.d(LOGTAG, "No new title to show.");
             return;
         }
 
         final GeckoPreferences activity = (GeckoPreferences) getActivity();
-        if (Versions.feature11Plus && activity.isMultiPane()) {
+        if (activity.isMultiPane()) {
             // In a multi-pane activity, the title is "Settings", and the action
             // bar is along the top of the screen. We don't want to change those.
             activity.showBreadCrumbs(newTitle, newTitle);
             activity.switchToHeader(getHeader());
             return;
         }
 
         Log.v(LOGTAG, "Setting activity title to " + newTitle);
@@ -232,18 +232,17 @@ public class GeckoPreferenceFragment ext
             final String packageName = activity.getPackageName();
             resid = resources.getIdentifier(resourceName, "xml", packageName);
         }
 
         if (resid == 0) {
             // The resource was invalid. Use the default resource.
             Log.e(LOGTAG, "Failed to find resource: " + resourceName + ". Displaying default settings.");
 
-            boolean isMultiPane = Versions.feature11Plus &&
-                                  ((GeckoPreferences) activity).isMultiPane();
+            boolean isMultiPane = ((GeckoPreferences) activity).isMultiPane();
             resid = isMultiPane ? R.xml.preferences_general_tablet : R.xml.preferences;
         }
 
         return resid;
     }
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/GeckoPreferences.java
@@ -217,23 +217,21 @@ OnSharedPreferenceChangeListener
 
     private void finishChoosingTransition() {
         finish();
         if (NO_TRANSITIONS) {
             overridePendingTransition(0, 0);
         }
     }
     private void updateActionBarTitle(int title) {
-        if (Versions.feature14Plus) {
-            final String newTitle = getString(title);
-            if (newTitle != null) {
-                Log.v(LOGTAG, "Setting action bar title to " + newTitle);
+        final String newTitle = getString(title);
+        if (newTitle != null) {
+            Log.v(LOGTAG, "Setting action bar title to " + newTitle);
 
-                setTitle(newTitle);
-            }
+            setTitle(newTitle);
         }
     }
 
     /**
      * We only call this method for pre-HC versions of Android.
      */
     private void updateTitleForPrefsResource(int res) {
         // At present we only need to do this for non-leaf prefs views
@@ -336,30 +334,28 @@ OnSharedPreferenceChangeListener
         localeSwitchingIsEnabled = BrowserLocaleManager.getInstance().isEnabled();
 
         // For Android v11+ where we use Fragments (v11+ only due to bug 866352),
         // check that PreferenceActivity.EXTRA_SHOW_FRAGMENT has been set
         // (or set it) before super.onCreate() is called so Android can display
         // the correct Fragment resource.
         // Note: this seems to only be required for non-multipane devices, multipane
         // manages to automatically select the correct fragments.
-        if (Versions.feature11Plus) {
-            if (!getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
-                // Set up the default fragment if there is no explicit fragment to show.
-                setupTopLevelFragmentIntent();
-            }
+        if (!getIntent().hasExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT)) {
+            // Set up the default fragment if there is no explicit fragment to show.
+            setupTopLevelFragmentIntent();
         }
 
         // We must call this before setTitle to avoid crashes. Most devices don't seem to care
         // (we used to call onCreate later), however the ASUS TF300T (running 4.2) crashes
         // with an NPE in android.support.v7.app.AppCompatDelegateImplV7.ensureSubDecor(), and it's
         // likely other strange devices (other Asus devices, some Samsungs) could do the same.
         super.onCreate(savedInstanceState);
 
-        if (Versions.feature11Plus && onIsMultiPane()) {
+        if (onIsMultiPane()) {
             // So that Android doesn't put the fragment title (or nothing at
             // all) in the action bar.
             updateActionBarTitle(R.string.settings_title);
 
             if (Build.VERSION.SDK_INT < 13) {
                 // Affected by Bug 1015209 -- no detach/attach.
                 // If we try rejigging fragments, we'll crash, so don't
                 // enable locale switching at all.
@@ -516,21 +512,19 @@ OnSharedPreferenceChangeListener
             PrefsHelper.removeObserver(mPrefsRequest);
             mPrefsRequest = null;
         }
     }
 
     @Override
     public void onPause() {
         // Symmetric with onResume.
-        if (Versions.feature11Plus) {
-            if (isMultiPane()) {
-                SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
-                prefs.unregisterOnSharedPreferenceChangeListener(this);
-            }
+        if (isMultiPane()) {
+            SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
+            prefs.unregisterOnSharedPreferenceChangeListener(this);
         }
 
         super.onPause();
 
         if (getApplication() instanceof GeckoApplication) {
             ((GeckoApplication) getApplication()).onActivityPause(this);
         }
     }
@@ -538,24 +532,22 @@ OnSharedPreferenceChangeListener
     @Override
     public void onResume() {
         super.onResume();
 
         if (getApplication() instanceof GeckoApplication) {
             ((GeckoApplication) getApplication()).onActivityResume(this);
         }
 
-        if (Versions.feature11Plus) {
-            // Watch prefs, otherwise we don't reliably get told when they change.
-            // See documentation for onSharedPreferenceChange for more.
-            // Inexplicably only needed on tablet.
-            if (isMultiPane()) {
-                SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
-                prefs.registerOnSharedPreferenceChangeListener(this);
-            }
+        // Watch prefs, otherwise we don't reliably get told when they change.
+        // See documentation for onSharedPreferenceChange for more.
+        // Inexplicably only needed on tablet.
+        if (isMultiPane()) {
+            SharedPreferences prefs = GeckoSharedPrefs.forApp(this);
+            prefs.registerOnSharedPreferenceChangeListener(this);
         }
     }
 
     @Override
     public void startActivity(Intent intent) {
         // For settings, we want to be able to pass results up the chain
         // of preference screens so Settings can behave as a single unit.
         // Specifically, when we open a link, we want to back out of all
--- a/mobile/android/base/java/org/mozilla/gecko/preferences/SyncPreference.java
+++ b/mobile/android/base/java/org/mozilla/gecko/preferences/SyncPreference.java
@@ -47,42 +47,34 @@ class SyncPreference extends Preference 
 
     public void update(final AndroidFxAccount fxAccount) {
         if (fxAccount == null) {
             ThreadUtils.postToUiThread(new Runnable() {
                 @Override
                 public void run() {
                     setTitle(R.string.pref_sync);
                     setSummary(R.string.pref_sync_summary);
-                    if (AppConstants.Versions.feature11Plus) {
                         // Cancel any pending task.
                         Picasso.with(mContext).cancelRequest(profileAvatarTarget);
                         // Clear previously set icon.
                         setIcon(R.drawable.sync_avatar_default);
-                    }
-
                 }
             });
             return;
         }
 
         // Update title from account email.
         ThreadUtils.postToUiThread(new Runnable() {
             @Override
             public void run() {
                 setTitle(fxAccount.getEmail());
                 setSummary("");
             }
         });
 
-        // Updating icons from Java is not supported prior to API 11.
-        if (!AppConstants.Versions.feature11Plus) {
-            return;
-        }
-
         final ExtendedJSONObject profileJSON = fxAccount.getProfileJSON();
         if (profileJSON == null) {
             return;
         }
 
         // Avatar URI empty, return early.
         final String avatarURI = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_AVATAR);
         if (TextUtils.isEmpty(avatarURI)) {
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/IconGridInput.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/IconGridInput.java
@@ -80,17 +80,17 @@ public class IconGridInput extends Promp
             }
         }
 
         view.setNumColumns(Math.min(items.size(), maxColumns));
         view.setOnItemClickListener(this);
         // Despite what the docs say, setItemChecked was not moved into the AbsListView class until sometime between
         // Android 2.3.7 and Android 4.0.3. For other versions the item won't be visually highlighted, BUT we really only
         // mSelected will still be set so that we default to its behavior.
-        if (Versions.feature11Plus && mSelected > -1) {
+        if (mSelected > -1) {
             view.setItemChecked(mSelected, true);
         }
 
         mAdapter = new IconGridAdapter(context, -1, items);
         view.setAdapter(mAdapter);
         mView = view;
         return mView;
     }
--- a/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabqueue/TabQueueHelper.java
@@ -33,17 +33,17 @@ import org.json.JSONObject;
 
 import java.util.ArrayList;
 import java.util.List;
 
 public class TabQueueHelper {
     private static final String LOGTAG = "Gecko" + TabQueueHelper.class.getSimpleName();
 
     // Disable Tab Queue for API level 10 (GB) - Bug 1206055
-    public static final boolean TAB_QUEUE_ENABLED = AppConstants.Versions.feature11Plus;
+    public static final boolean TAB_QUEUE_ENABLED = true;
 
     public static final String FILE_NAME = "tab_queue_url_list.json";
     public static final String LOAD_URLS_ACTION = "TAB_QUEUE_LOAD_URLS_ACTION";
     public static final int TAB_QUEUE_NOTIFICATION_ID = R.id.tabQueueNotification;
 
     public static final String PREF_TAB_QUEUE_COUNT = "tab_queue_count";
     public static final String PREF_TAB_QUEUE_LAUNCHES = "tab_queue_launches";
     public static final String PREF_TAB_QUEUE_TIMES_PROMPT_SHOWN = "tab_queue_times_prompt_shown";
--- a/mobile/android/base/java/org/mozilla/gecko/tabs/TabsGridLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/tabs/TabsGridLayout.java
@@ -289,19 +289,17 @@ class TabsGridLayout extends GridView
                 for (int i = 0; i < displayCount; i++) {
                     final Tab tab = tabsAdapter.getItem(i);
                     final boolean checked = displayCount == 1 || i == selected;
                     final View tabView = getViewForTab(tab);
                     if (tabView != null) {
                         ((TabsLayoutItemView) tabView).setChecked(checked);
                     }
                     // setItemChecked doesn't exist until API 11, despite what the API docs say!
-                    if (AppConstants.Versions.feature11Plus) {
-                        setItemChecked(i, checked);
-                    }
+                    setItemChecked(i, checked);
                 }
             }
         });
     }
 
     private void refreshTabsData() {
         // Store a different copy of the tabs, so that we don't have to worry about
         // accidentally updating it on the wrong thread.
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/BrowserToolbar.java
@@ -186,19 +186,17 @@ public abstract class BrowserToolbar ext
         isSwitchingTabs = true;
 
         urlDisplayLayout = (ToolbarDisplayLayout) findViewById(R.id.display_layout);
         urlBarEntry = findViewById(R.id.url_bar_entry);
         urlEditLayout = (ToolbarEditLayout) findViewById(R.id.edit_layout);
 
         tabsButton = (ThemedImageButton) findViewById(R.id.tabs);
         tabsCounter = (TabCounter) findViewById(R.id.tabs_counter);
-        if (Versions.feature11Plus) {
-            tabsCounter.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
-        }
+        tabsCounter.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
 
         menuButton = (ThemedFrameLayout) findViewById(R.id.menu);
         menuIcon = (ThemedImageView) findViewById(R.id.menu_icon);
 
         // The focusOrder List should be filled by sub-classes.
         focusOrder = new ArrayList<View>();
 
         final Resources res = getResources();
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/CanvasDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/CanvasDelegate.java
@@ -43,30 +43,18 @@ class CanvasDelegate {
                                      Canvas.CLIP_TO_LAYER_SAVE_FLAG);
 
         // Do a default draw.
         mDrawManager.defaultDraw(canvas);
 
         if (path != null && !path.isEmpty()) {
             // ICS added double-buffering, which made it easier for drawing the Path directly over the DST.
             // In pre-ICS, drawPath() doesn't seem to use ARGB_8888 mode for performance, hence transparency is not preserved.
-            if (Versions.feature14Plus) {
-                mPaint.setXfermode(mMode);
-                canvas.drawPath(path, mPaint);
-            } else {
-                // Allocate a bitmap and draw the masking/clipping path.
-                Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-                (new Canvas(bitmap)).drawPath(path, mPaint);
-
-                mPaint.setXfermode(mMode);
-                canvas.drawBitmap(bitmap, 0, 0, mPaint);
-                bitmap.recycle();
-
-                mPaint.setXfermode(null);
-            }
+            mPaint.setXfermode(mMode);
+            canvas.drawPath(path, mPaint);
         }
 
         // Restore the canvas.
         canvas.restoreToCount(count);
     }
 
     void setShader(Shader shader) {
         mPaint.setShader(shader);
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/SiteIdentityPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/SiteIdentityPopup.java
@@ -223,21 +223,19 @@ public class SiteIdentityPopup extends A
                         final ClipboardManager manager = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
                         String password;
                         if (response.has("password")) {
                             // Click listener being called from List Dialog.
                             password = response.optString("password");
                         } else {
                             password = login.getString("password");
                         }
-                        if (AppConstants.Versions.feature11Plus) {
-                            manager.setPrimaryClip(ClipData.newPlainText("password", password));
-                        } else {
-                            manager.setText(password);
-                        }
+
+                        manager.setPrimaryClip(ClipData.newPlainText("password", password));
+
                         SnackbarBuilder.builder(activity)
                                 .message(R.string.doorhanger_login_select_toast_copy)
                                 .duration(Snackbar.LENGTH_SHORT)
                                 .buildAndShow();
                     }
                     dismiss();
                 } catch (JSONException e) {
                     Log.e(LOGTAG, "Error handling Select login button click", e);
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditText.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/ToolbarEditText.java
@@ -613,18 +613,17 @@ public class ToolbarEditText extends Cus
                 if (mDismissListener != null) {
                     mDismissListener.onDismiss();
                 }
 
                 return true;
             }
 
             if ((keyCode == KeyEvent.KEYCODE_DEL ||
-                (Versions.feature11Plus &&
-                 keyCode == KeyEvent.KEYCODE_FORWARD_DEL)) &&
+                (keyCode == KeyEvent.KEYCODE_FORWARD_DEL)) &&
                 removeAutocomplete(getText())) {
                 // Delete autocomplete text when backspacing or forward deleting.
                 return true;
             }
 
             return false;
         }
     }
--- a/mobile/android/base/java/org/mozilla/gecko/widget/DateTimePicker.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/DateTimePicker.java
@@ -96,92 +96,55 @@ public class DateTimePicker extends Fram
 
     public static enum PickersState { DATE, MONTH, WEEK, TIME, DATETIME };
 
     public class OnValueChangeListener implements NumberPicker.OnValueChangeListener {
         @Override
         public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
             updateInputState();
             mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
-            final boolean newBehavior = Versions.feature11Plus;
-            if (newBehavior) {
-                if (DEBUG) {
-                    Log.d(LOGTAG, "SDK version > 10, using new behavior");
-                }
+            if (DEBUG) {
+                Log.d(LOGTAG, "SDK version > 10, using new behavior");
+            }
 
-                // The native date picker widget on these SDKs increments
-                // the next field when one field reaches the maximum.
-                if (picker == mDaySpinner && mDayEnabled) {
-                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
-                    int old = mTempDate.get(Calendar.DAY_OF_MONTH);
-                    setTempDate(Calendar.DAY_OF_MONTH, old, newVal, 1, maxDayOfMonth);
-                } else if (picker == mMonthSpinner && mMonthEnabled) {
-                    int old = mTempDate.get(Calendar.MONTH);
-                    setTempDate(Calendar.MONTH, old, newVal, Calendar.JANUARY, Calendar.DECEMBER);
-                } else if (picker == mWeekSpinner) {
-                    int old = mTempDate.get(Calendar.WEEK_OF_YEAR);
-                    int maxWeekOfYear = mTempDate.getActualMaximum(Calendar.WEEK_OF_YEAR);
-                    setTempDate(Calendar.WEEK_OF_YEAR, old, newVal, 0, maxWeekOfYear);
-                } else if (picker == mYearSpinner && mYearEnabled) {
-                    int month = mTempDate.get(Calendar.MONTH);
-                    mTempDate.set(Calendar.YEAR, newVal);
-                    // Changing the year shouldn't change the month. (in case of non-leap year a Feb 29)
-                    // change the day instead;
-                    if (month != mTempDate.get(Calendar.MONTH)) {
-                        mTempDate.set(Calendar.MONTH, month);
-                        mTempDate.set(Calendar.DAY_OF_MONTH,
-                        mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                    }
-                } else if (picker == mHourSpinner && mHourEnabled) {
-                    if (mIs12HourMode) {
-                        setTempDate(Calendar.HOUR, oldVal, newVal, 1, 12);
-                    } else {
-                        setTempDate(Calendar.HOUR_OF_DAY, oldVal, newVal, 0, 23);
-                    }
-                } else if (picker == mMinuteSpinner && mMinuteEnabled) {
-                    setTempDate(Calendar.MINUTE, oldVal, newVal, 0, 59);
-                } else if (picker == mAMPMSpinner && mHourEnabled) {
-                    mTempDate.set(Calendar.AM_PM, newVal);
+            // The native date picker widget on these SDKs increments
+            // the next field when one field reaches the maximum.
+            if (picker == mDaySpinner && mDayEnabled) {
+                int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
+                int old = mTempDate.get(Calendar.DAY_OF_MONTH);
+                setTempDate(Calendar.DAY_OF_MONTH, old, newVal, 1, maxDayOfMonth);
+            } else if (picker == mMonthSpinner && mMonthEnabled) {
+                int old = mTempDate.get(Calendar.MONTH);
+                setTempDate(Calendar.MONTH, old, newVal, Calendar.JANUARY, Calendar.DECEMBER);
+            } else if (picker == mWeekSpinner) {
+                int old = mTempDate.get(Calendar.WEEK_OF_YEAR);
+                int maxWeekOfYear = mTempDate.getActualMaximum(Calendar.WEEK_OF_YEAR);
+                setTempDate(Calendar.WEEK_OF_YEAR, old, newVal, 0, maxWeekOfYear);
+            } else if (picker == mYearSpinner && mYearEnabled) {
+                int month = mTempDate.get(Calendar.MONTH);
+                mTempDate.set(Calendar.YEAR, newVal);
+                // Changing the year shouldn't change the month. (in case of non-leap year a Feb 29)
+                // change the day instead;
+                if (month != mTempDate.get(Calendar.MONTH)) {
+                    mTempDate.set(Calendar.MONTH, month);
+                    mTempDate.set(Calendar.DAY_OF_MONTH,
+                    mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
+                }
+            } else if (picker == mHourSpinner && mHourEnabled) {
+                if (mIs12HourMode) {
+                    setTempDate(Calendar.HOUR, oldVal, newVal, 1, 12);
                 } else {
-                    throw new IllegalArgumentException();
+                    setTempDate(Calendar.HOUR_OF_DAY, oldVal, newVal, 0, 23);
                 }
+            } else if (picker == mMinuteSpinner && mMinuteEnabled) {
+                setTempDate(Calendar.MINUTE, oldVal, newVal, 0, 59);
+            } else if (picker == mAMPMSpinner && mHourEnabled) {
+                mTempDate.set(Calendar.AM_PM, newVal);
             } else {
-                if (DEBUG) Log.d(LOGTAG, "Sdk version < 10, using old behavior");
-                if (picker == mDaySpinner && mDayEnabled) {
-                    mTempDate.set(Calendar.DAY_OF_MONTH, newVal);
-                } else if (picker == mMonthSpinner && mMonthEnabled) {
-                    mTempDate.set(Calendar.MONTH, newVal);
-                    if (mTempDate.get(Calendar.MONTH) == newVal + 1) {
-                        mTempDate.set(Calendar.MONTH, newVal);
-                        mTempDate.set(Calendar.DAY_OF_MONTH,
-                        mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                    }
-                } else if (picker == mWeekSpinner) {
-                    mTempDate.set(Calendar.WEEK_OF_YEAR, newVal);
-                } else if (picker == mYearSpinner && mYearEnabled) {
-                    int month = mTempDate.get(Calendar.MONTH);
-                    mTempDate.set(Calendar.YEAR, newVal);
-                    if (month != mTempDate.get(Calendar.MONTH)) {
-                        mTempDate.set(Calendar.MONTH, month);
-                        mTempDate.set(Calendar.DAY_OF_MONTH,
-                        mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                    }
-                } else if (picker == mHourSpinner && mHourEnabled) {
-                    if (mIs12HourMode) {
-                        mTempDate.set(Calendar.HOUR, newVal);
-                    } else {
-                        mTempDate.set(Calendar.HOUR_OF_DAY, newVal);
-                    }
-                } else if (picker == mMinuteSpinner && mMinuteEnabled) {
-                    mTempDate.set(Calendar.MINUTE, newVal);
-                } else if (picker == mAMPMSpinner && mHourEnabled) {
-                    mTempDate.set(Calendar.AM_PM, newVal);
-                } else {
-                    throw new IllegalArgumentException();
-                }
+                throw new IllegalArgumentException();
             }
             setDate(mTempDate);
             if (mDayEnabled) {
                 mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
             }
             if (mWeekEnabled) {
                 mWeekSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.WEEK_OF_YEAR));
             }
--- a/mobile/android/base/java/org/mozilla/gecko/widget/RoundedCornerLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/RoundedCornerLayout.java
@@ -36,17 +36,17 @@ public class RoundedCornerLayout extends
 
     public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         init(context);
     }
 
     private void init(Context context) {
         // Bug 1201081 - clipPath with hardware acceleration crashes on r11-18.
-        cannotClipPath = AppConstants.Versions.feature11Plus && !AppConstants.Versions.feature19Plus;
+        cannotClipPath = !AppConstants.Versions.feature19Plus;
 
         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
 
         cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
                 getResources().getDimensionPixelSize(R.dimen.doorhanger_rounded_corner_radius), metrics);
 
         setWillNotDraw(false);
     }
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -231,23 +231,19 @@ gvjar.sources += [geckoview_source_dir +
     'GeckoScreenOrientation.java',
     'GeckoSharedPrefs.java',
     'GeckoSmsManager.java',
     'GeckoThread.java',
     'GeckoView.java',
     'GeckoViewChrome.java',
     'GeckoViewContent.java',
     'GeckoViewFragment.java',
-    'gfx/Axis.java',
     'gfx/BitmapUtils.java',
     'gfx/BufferedImage.java',
     'gfx/BufferedImageGLInfo.java',
-    'gfx/DisplayPortCalculator.java',
-    'gfx/DisplayPortMetrics.java',
-    'gfx/DrawTimingQueue.java',
     'gfx/DynamicToolbarAnimator.java',
     'gfx/FloatSize.java',
     'gfx/FullScreenState.java',
     'gfx/GeckoLayerClient.java',
     'gfx/ImmutableViewportMetrics.java',
     'gfx/IntSize.java',
     'gfx/LayerRenderer.java',
     'gfx/LayerView.java',
@@ -256,19 +252,17 @@ gvjar.sources += [geckoview_source_dir +
     'gfx/OverscrollEdgeEffect.java',
     'gfx/PanningPerfAPI.java',
     'gfx/PanZoomController.java',
     'gfx/PanZoomTarget.java',
     'gfx/PointUtils.java',
     'gfx/ProgressiveUpdateData.java',
     'gfx/RectUtils.java',
     'gfx/RenderTask.java',
-    'gfx/SimpleScaleGestureDetector.java',
     'gfx/StackScroller.java',
-    'gfx/SubdocumentScrollHelper.java',
     'gfx/SurfaceTextureListener.java',
     'gfx/ViewTransform.java',
     'InputConnectionListener.java',
     'InputMethods.java',
     'NotificationListener.java',
     'NSSBridge.java',
     'permissions/PermissionBlock.java',
     'permissions/Permissions.java',
--- a/mobile/android/chrome/content/WebrtcUI.js
+++ b/mobile/android/chrome/content/WebrtcUI.js
@@ -161,17 +161,17 @@ var WebrtcUI = {
         let videoId = 0;
         if (inputs && inputs.videoSource != undefined)
           videoId = inputs.videoSource;
         if (videoDevices[videoId]) {
           allowedDevices.AppendElement(videoDevices[videoId]);
           let perms = Services.perms;
           // Although the lifetime is "session" it will be removed upon
           // use so it's more of a one-shot.
-          perms.add(aUri, "camera", perms.ALLOW_ACTION, perms.EXPIRE_SESSION);
+          perms.add(aUri, "MediaManagerVideo", perms.ALLOW_ACTION, perms.EXPIRE_SESSION);
         }
 
         Services.obs.notifyObservers(allowedDevices, "getUserMedia:response:allow", aCallID);
       },
       positive: true
     }];
   },
 
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -111,16 +111,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Notifications.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Snackbars", "resource://gre/modules/Snackbars.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions", "resource://gre/modules/RuntimePermissions.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this, "WebsiteMetadata", "resource://gre/modules/WebsiteMetadata.jsm");
+
 XPCOMUtils.defineLazyServiceGetter(this, "FontEnumerator",
   "@mozilla.org/gfx/fontenumerator;1",
   "nsIFontEnumerator");
 
 var lazilyLoadedBrowserScripts = [
   ["SelectHelper", "chrome://browser/content/SelectHelper.js"],
   ["InputWidgetHelper", "chrome://browser/content/InputWidgetHelper.js"],
   ["MasterPassword", "chrome://browser/content/MasterPassword.js"],
@@ -3925,16 +3927,21 @@ Tab.prototype = {
           this.browser.addEventListener("click", ErrorPageEventHandler, true);
           let listener = function() {
             this.browser.removeEventListener("click", ErrorPageEventHandler, true);
             this.browser.removeEventListener("pagehide", listener, true);
           }.bind(this);
 
           this.browser.addEventListener("pagehide", listener, true);
         }
+
+        if (AppConstants.NIGHTLY_BUILD || AppConstants.MOZ_ANDROID_ACTIVITY_STREAM) {
+          WebsiteMetadata.parseAsynchronously(this.browser.contentDocument);
+        }
+
         break;
       }
 
       case "DOMFormHasPassword": {
         LoginManagerContent.onDOMFormHasPassword(aEvent,
                                                  this.browser.contentWindow);
 
         // Send logins for this hostname to Java.
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -14,16 +14,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Messaging", "resource://gre/modules/Messaging.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "FormData", "resource://gre/modules/FormData.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition", "resource://gre/modules/ScrollPosition.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Log", "resource://gre/modules/AndroidLog.jsm", "AndroidLog");
 XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences", "resource://gre/modules/SharedPreferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Utils", "resource:///modules/sessionstore/Utils.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
                                    "@mozilla.org/network/serialization-helper;1",
                                    "nsISerializationHelper");
 
 function dump(a) {
   Services.console.logStringMessage(a);
 }
 
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAccessibility.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAccessibility.java
@@ -88,26 +88,22 @@ public class GeckoAccessibility {
         event.setChecked(message.optBoolean("checked"));
         event.setPassword(message.optBoolean("password"));
         event.setAddedCount(message.optInt("addedCount", -1));
         event.setRemovedCount(message.optInt("removedCount", -1));
         event.setFromIndex(message.optInt("fromIndex", -1));
         event.setItemCount(message.optInt("itemCount", -1));
         event.setCurrentItemIndex(message.optInt("currentItemIndex", -1));
         event.setBeforeText(message.optString("beforeText"));
-        if (Versions.feature14Plus) {
-            event.setToIndex(message.optInt("toIndex", -1));
-            event.setScrollable(message.optBoolean("scrollable"));
-            event.setScrollX(message.optInt("scrollX", -1));
-            event.setScrollY(message.optInt("scrollY", -1));
-        }
-        if (Versions.feature15Plus) {
-            event.setMaxScrollX(message.optInt("maxScrollX", -1));
-            event.setMaxScrollY(message.optInt("maxScrollY", -1));
-        }
+        event.setToIndex(message.optInt("toIndex", -1));
+        event.setScrollable(message.optBoolean("scrollable"));
+        event.setScrollX(message.optInt("scrollX", -1));
+        event.setScrollY(message.optInt("scrollY", -1));
+        event.setMaxScrollX(message.optInt("maxScrollX", -1));
+        event.setMaxScrollY(message.optInt("maxScrollY", -1));
     }
 
     private static void sendDirectAccessibilityEvent(int eventType, JSONObject message) {
         final Context context = GeckoAppShell.getApplicationContext();
         final AccessibilityEvent accEvent = AccessibilityEvent.obtain(eventType);
         accEvent.setClassName(GeckoAccessibility.class.getName());
         accEvent.setPackageName(context.getPackageName());
         populateEventFromJSON(accEvent, message);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java
@@ -819,31 +819,19 @@ public class GeckoAppShell
         if (geckoInterface == null) {
             return;
         }
         geckoInterface.createShortcut(aTitle, aURI);
     }
 
     @JNITarget
     static public int getPreferredIconSize() {
-        if (Versions.feature11Plus) {
-            ActivityManager am = (ActivityManager)
-                    getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
-            return am.getLauncherLargeIconSize();
-        } else {
-            switch (getDpi()) {
-                case DisplayMetrics.DENSITY_MEDIUM:
-                    return 48;
-                case DisplayMetrics.DENSITY_XHIGH:
-                    return 96;
-                case DisplayMetrics.DENSITY_HIGH:
-                default:
-                    return 72;
-            }
-        }
+        ActivityManager am = (ActivityManager)
+            getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
+        return am.getLauncherLargeIconSize();
     }
 
     @WrapForJNI(calledFrom = "gecko")
     private static String[] getHandlersForMimeType(String aMimeType, String aAction) {
         final GeckoInterface geckoInterface = getGeckoInterface();
         if (geckoInterface == null) {
             return new String[] {};
         }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoEditable.java
@@ -609,20 +609,18 @@ final class GeckoEditable extends JNIObj
                 tp.set(emptyTp);
                 for (CharacterStyle span : styleSpans) {
                     span.updateDrawState(tp);
                 }
                 int tpUnderlineColor = 0;
                 float tpUnderlineThickness = 0.0f;
 
                 // These TextPaint fields only exist on Android ICS+ and are not in the SDK.
-                if (Versions.feature14Plus) {
-                    tpUnderlineColor = (Integer)getField(tp, "underlineColor", 0);
-                    tpUnderlineThickness = (Float)getField(tp, "underlineThickness", 0.0f);
-                }
+                tpUnderlineColor = (Integer)getField(tp, "underlineColor", 0);
+                tpUnderlineThickness = (Float)getField(tp, "underlineThickness", 0.0f);
                 if (tpUnderlineColor != 0) {
                     rangeStyles |= IME_RANGE_UNDERLINE | IME_RANGE_LINECOLOR;
                     rangeLineColor = tpUnderlineColor;
                     // Approximately translate underline thickness to what Gecko understands
                     if (tpUnderlineThickness <= 0.5f) {
                         rangeLineStyle = IME_RANGE_LINE_DOTTED;
                     } else {
                         rangeLineStyle = IME_RANGE_LINE_SOLID;
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoInputConnection.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoInputConnection.java
@@ -989,20 +989,20 @@ class GeckoInputConnection
     @Override
     public void notifyIMEContext(int state, String typeHint, String modeHint, String actionHint) {
         // For some input type we will use a widget to display the ui, for those we must not
         // display the ime. We can display a widget for date and time types and, if the sdk version
         // is 11 or greater, for datetime/month/week as well.
         if (typeHint != null &&
             (typeHint.equalsIgnoreCase("date") ||
              typeHint.equalsIgnoreCase("time") ||
-             (Versions.feature11Plus && (typeHint.equalsIgnoreCase("datetime") ||
-                                         typeHint.equalsIgnoreCase("month") ||
-                                         typeHint.equalsIgnoreCase("week") ||
-                                         typeHint.equalsIgnoreCase("datetime-local"))))) {
+             typeHint.equalsIgnoreCase("datetime") ||
+             typeHint.equalsIgnoreCase("month") ||
+             typeHint.equalsIgnoreCase("week") ||
+             typeHint.equalsIgnoreCase("datetime-local"))) {
             state = IME_STATE_DISABLED;
         }
 
         // mIMEState and the mIME*Hint fields should only be changed by notifyIMEContext,
         // and not reset anywhere else. Usually, notifyIMEContext is called right after a
         // focus or blur, so resetting mIMEState during the focus or blur seems harmless.
         // However, this behavior is not guaranteed. Gecko may call notifyIMEContext
         // independent of focus change; that is, a focus change may not be accompanied by
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/Axis.java
+++ /dev/null
@@ -1,532 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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/. */
-
-package org.mozilla.gecko.gfx;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.PrefsHelper;
-import org.mozilla.gecko.util.FloatUtils;
-
-import android.os.SystemClock;
-import android.util.Log;
-import android.view.View;
-
-/**
- * This class represents the physics for one axis of movement (i.e. either
- * horizontal or vertical). It tracks the different properties of movement
- * like displacement, velocity, viewport dimensions, etc. pertaining to
- * a particular axis.
- */
-abstract class Axis {
-    private static final String LOGTAG = "GeckoAxis";
-
-    private static final String PREF_SCROLLING_FRICTION_SLOW = "ui.scrolling.friction_slow";
-    private static final String PREF_SCROLLING_FRICTION_FAST = "ui.scrolling.friction_fast";
-    private static final String PREF_SCROLLING_MAX_EVENT_ACCELERATION = "ui.scrolling.max_event_acceleration";
-    private static final String PREF_SCROLLING_OVERSCROLL_DECEL_RATE = "ui.scrolling.overscroll_decel_rate";
-    private static final String PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT = "ui.scrolling.overscroll_snap_limit";
-    private static final String PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE = "ui.scrolling.min_scrollable_distance";
-    private static final String PREF_FLING_ACCEL_INTERVAL = "ui.scrolling.fling_accel_interval";
-    private static final String PREF_FLING_ACCEL_BASE_MULTIPLIER = "ui.scrolling.fling_accel_base_multiplier";
-    private static final String PREF_FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER = "ui.scrolling.fling_accel_supplemental_multiplier";
-    private static final String PREF_FLING_CURVE_FUNCTION_X1 = "ui.scrolling.fling_curve_function_x1";
-    private static final String PREF_FLING_CURVE_FUNCTION_Y1 = "ui.scrolling.fling_curve_function_y1";
-    private static final String PREF_FLING_CURVE_FUNCTION_X2 = "ui.scrolling.fling_curve_function_x2";
-    private static final String PREF_FLING_CURVE_FUNCTION_Y2 = "ui.scrolling.fling_curve_function_y2";
-    private static final String PREF_FLING_CURVE_THRESHOLD_VELOCITY = "ui.scrolling.fling_curve_threshold_velocity";
-    private static final String PREF_FLING_CURVE_MAXIMUM_VELOCITY = "ui.scrolling.fling_curve_max_velocity";
-    private static final String PREF_FLING_CURVE_NEWTON_ITERATIONS = "ui.scrolling.fling_curve_newton_iterations";
-
-    // This fraction of velocity remains after every animation frame when the velocity is low.
-    private static float FRICTION_SLOW;
-    // This fraction of velocity remains after every animation frame when the velocity is high.
-    private static float FRICTION_FAST;
-    // Below this velocity (in pixels per frame), the friction starts increasing from FRICTION_FAST
-    // to FRICTION_SLOW.
-    private static float VELOCITY_THRESHOLD;
-    // The maximum velocity change factor between events, per ms, in %.
-    // Direction changes are excluded.
-    private static float MAX_EVENT_ACCELERATION;
-
-    // The rate of deceleration when the surface has overscrolled.
-    private static float OVERSCROLL_DECEL_RATE;
-    // The percentage of the surface which can be overscrolled before it must snap back.
-    private static float SNAP_LIMIT;
-
-    // The minimum amount of space that must be present for an axis to be considered scrollable,
-    // in pixels.
-    private static float MIN_SCROLLABLE_DISTANCE;
-
-    // The interval within which if two flings are done then scrolling effect is accelerated.
-    private static long FLING_ACCEL_INTERVAL;
-
-    // The multiplication constant of the base velocity in case of accelerated scrolling.
-    private static float FLING_ACCEL_BASE_MULTIPLIER;
-
-    // The multiplication constant of the supplemental velocity in case of accelerated scrolling.
-    private static float FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER;
-
-    // x co-ordinate of the second bezier control point
-    private static float FLING_CURVE_FUNCTION_X1;
-
-    // y co-ordinate of the second bezier control point
-    private static float FLING_CURVE_FUNCTION_Y1;
-
-    // x co-ordinate of the third bezier control point
-    private static float FLING_CURVE_FUNCTION_X2;
-
-    // y co-ordinate of the third bezier control point
-    private static float FLING_CURVE_FUNCTION_Y2;
-
-    // Minimum velocity for curve to be implemented i.e fling curving
-    private static float FLING_CURVE_THRESHOLD_VELOCITY;
-
-    // Maximum permitted velocity
-    private static float FLING_CURVE_MAXIMUM_VELOCITY;
-
-    // Number of iterations in the Newton-Raphson method
-    private static int FLING_CURVE_NEWTON_ITERATIONS;
-
-    private static float getFloatPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
-        Integer value = (prefs == null ? null : prefs.get(prefName));
-        return (value == null || value < 0 ? defaultValue : value) / 1000f;
-    }
-
-    private static int getIntPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
-        Integer value = (prefs == null ? null : prefs.get(prefName));
-        return (value == null || value < 0 ? defaultValue : value);
-    }
-
-    static void initPrefs() {
-        final String[] prefs = { PREF_SCROLLING_FRICTION_FAST,
-                                 PREF_SCROLLING_FRICTION_SLOW,
-                                 PREF_SCROLLING_MAX_EVENT_ACCELERATION,
-                                 PREF_SCROLLING_OVERSCROLL_DECEL_RATE,
-                                 PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT,
-                                 PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE,
-                                 PREF_FLING_ACCEL_INTERVAL,
-                                 PREF_FLING_ACCEL_BASE_MULTIPLIER,
-                                 PREF_FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER,
-                                 PREF_FLING_CURVE_FUNCTION_X1,
-                                 PREF_FLING_CURVE_FUNCTION_Y1,
-                                 PREF_FLING_CURVE_FUNCTION_X2,
-                                 PREF_FLING_CURVE_FUNCTION_Y2,
-                                 PREF_FLING_CURVE_THRESHOLD_VELOCITY,
-                                 PREF_FLING_CURVE_MAXIMUM_VELOCITY,
-                                 PREF_FLING_CURVE_NEWTON_ITERATIONS };
-
-        PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
-            Map<String, Integer> mPrefs = new HashMap<String, Integer>();
-
-            @Override public void prefValue(String name, int value) {
-                mPrefs.put(name, value);
-            }
-
-            @Override public void finish() {
-                setPrefs(mPrefs);
-            }
-        });
-    }
-
-    static final float MS_PER_FRAME = 1000.0f / 60.0f;
-    static final long NS_PER_FRAME = Math.round(1000000000f / 60f);
-    private static final float FRAMERATE_MULTIPLIER = (1000f / 60f) / MS_PER_FRAME;
-    private static final int FLING_VELOCITY_POINTS = 8;
-
-    //  The values we use for friction are based on a 16.6ms frame, adjust them to currentNsPerFrame:
-    static float getFrameAdjustedFriction(float baseFriction, long currentNsPerFrame) {
-        float framerateMultiplier = (float)currentNsPerFrame / NS_PER_FRAME;
-        return (float)Math.pow(Math.E, (Math.log(baseFriction) / framerateMultiplier));
-    }
-
-    static void setPrefs(Map<String, Integer> prefs) {
-        FRICTION_SLOW = getFloatPref(prefs, PREF_SCROLLING_FRICTION_SLOW, 850);
-        FRICTION_FAST = getFloatPref(prefs, PREF_SCROLLING_FRICTION_FAST, 970);
-        VELOCITY_THRESHOLD = 10 / FRAMERATE_MULTIPLIER;
-        MAX_EVENT_ACCELERATION = getFloatPref(prefs, PREF_SCROLLING_MAX_EVENT_ACCELERATION, GeckoAppShell.getDpi() > 300 ? 100 : 40);
-        OVERSCROLL_DECEL_RATE = getFloatPref(prefs, PREF_SCROLLING_OVERSCROLL_DECEL_RATE, 40);
-        SNAP_LIMIT = getFloatPref(prefs, PREF_SCROLLING_OVERSCROLL_SNAP_LIMIT, 300);
-        MIN_SCROLLABLE_DISTANCE = getFloatPref(prefs, PREF_SCROLLING_MIN_SCROLLABLE_DISTANCE, 500);
-        FLING_ACCEL_INTERVAL = getIntPref(prefs, PREF_FLING_ACCEL_INTERVAL, 500);
-        FLING_ACCEL_BASE_MULTIPLIER = getFloatPref(prefs, PREF_FLING_ACCEL_BASE_MULTIPLIER, 1000);
-        FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER = getFloatPref(prefs, PREF_FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER, 1000);
-        FLING_CURVE_FUNCTION_X1 = getFloatPref(prefs, PREF_FLING_CURVE_FUNCTION_X1, 410);
-        FLING_CURVE_FUNCTION_Y1 = getFloatPref(prefs, PREF_FLING_CURVE_FUNCTION_Y1, 0);
-        FLING_CURVE_FUNCTION_X2 = getFloatPref(prefs, PREF_FLING_CURVE_FUNCTION_X2, 800);
-        FLING_CURVE_FUNCTION_Y2 = getFloatPref(prefs, PREF_FLING_CURVE_FUNCTION_Y2, 1000);
-        FLING_CURVE_THRESHOLD_VELOCITY = getFloatPref(prefs, PREF_FLING_CURVE_THRESHOLD_VELOCITY, 30);
-        FLING_CURVE_MAXIMUM_VELOCITY = getFloatPref(prefs, PREF_FLING_CURVE_MAXIMUM_VELOCITY, 70);
-        FLING_CURVE_NEWTON_ITERATIONS = getIntPref(prefs, PREF_FLING_CURVE_NEWTON_ITERATIONS, 5);
-
-        Log.i(LOGTAG, "Prefs: " + FRICTION_SLOW + "," + FRICTION_FAST + "," + VELOCITY_THRESHOLD + ","
-                + MAX_EVENT_ACCELERATION + "," + OVERSCROLL_DECEL_RATE + "," + SNAP_LIMIT + "," + MIN_SCROLLABLE_DISTANCE);
-    }
-
-    static {
-        // set the scrolling parameters to default values on startup
-        setPrefs(null);
-    }
-
-    private enum FlingStates {
-        STOPPED,
-        PANNING,
-        FLINGING,
-    }
-
-    private enum Overscroll {
-        NONE,
-        MINUS,      // Overscrolled in the negative direction
-        PLUS,       // Overscrolled in the positive direction
-        BOTH,       // Overscrolled in both directions (page is zoomed to smaller than screen)
-    }
-
-    private final SubdocumentScrollHelper mSubscroller;
-
-    private int mOverscrollMode; /* Default to only overscrolling if we're allowed to scroll in a direction */
-    private float mFirstTouchPos;            /* Position of the first touch event on the current drag. */
-    private float mTouchPos;                 /* Position of the most recent touch event on the current drag. */
-    private float mLastTouchPos;             /* Position of the touch event before touchPos. */
-    private float mVelocity;                 /* Velocity in this direction; pixels per animation frame. */
-    private final float[] mRecentVelocities; /* Circular buffer of recent velocities since last touch start. */
-    private int mRecentVelocityCount;        /* Number of values put into mRecentVelocities (unbounded). */
-    private boolean mScrollingDisabled;      /* Whether movement on this axis is locked. */
-    private boolean mDisableSnap;            /* Whether overscroll snapping is disabled. */
-    private float mDisplacement;
-    private long mLastFlingTime;
-    private float mLastFlingVelocity;
-
-    private FlingStates mFlingState = FlingStates.STOPPED; /* The fling state we're in on this axis. */
-
-    protected abstract float getOrigin();
-    protected abstract float getViewportLength();
-    protected abstract float getPageStart();
-    protected abstract float getPageLength();
-    protected abstract float getVisibleEndOfLayerView();
-
-    Axis(SubdocumentScrollHelper subscroller) {
-        mSubscroller = subscroller;
-        mOverscrollMode = View.OVER_SCROLL_IF_CONTENT_SCROLLS;
-        mRecentVelocities = new float[FLING_VELOCITY_POINTS];
-    }
-
-    // Implementors can override these to show effects when the axis overscrolls
-    protected void overscrollFling(float velocity) { }
-    protected void overscrollPan(float displacement) { }
-
-    public void setOverScrollMode(int overscrollMode) {
-        mOverscrollMode = overscrollMode;
-    }
-
-    public int getOverScrollMode() {
-        return mOverscrollMode;
-    }
-
-    private float getViewportEnd() {
-        return getOrigin() + getViewportLength();
-    }
-
-    private float getPageEnd() {
-        return getPageStart() + getPageLength();
-    }
-
-    void startTouch(float pos) {
-        mVelocity = 0.0f;
-        mScrollingDisabled = false;
-        mFirstTouchPos = mTouchPos = mLastTouchPos = pos;
-        mRecentVelocityCount = 0;
-    }
-
-    float panDistance(float currentPos) {
-        return currentPos - mFirstTouchPos;
-    }
-
-    void setScrollingDisabled(boolean disabled) {
-        mScrollingDisabled = disabled;
-    }
-
-    void saveTouchPos() {
-        mLastTouchPos = mTouchPos;
-    }
-
-    // Calculates and return the slope of the curve at given parameter t
-    float getSlope(float t) {
-        float y1 = FLING_CURVE_FUNCTION_Y1;
-        float y2 = FLING_CURVE_FUNCTION_Y2;
-
-        return (3 * y1)
-             + t * (6 * y2 - 12 * y1)
-             + t * t * (9 * y1 - 9 * y2 + 3);
-    }
-
-    // Calculates and returns the value of the bezier curve with the given parameter t and control points p1 and p2
-    float cubicBezier(float p1, float p2, float t) {
-        return (3 * t * (1 - t) * (1 - t) * p1)
-             + (3 * t * t * (1 - t) * p2)
-             + (t * t * t);
-    }
-
-    // Responsible for mapping the physical velocity to a the velocity obtained after applying bezier curve (with control points (X1,Y1) and (X2,Y2))
-    float flingCurve(float By) {
-        int ni = FLING_CURVE_NEWTON_ITERATIONS;
-        float[] guess = new float[ni];
-        float y1 = FLING_CURVE_FUNCTION_Y1;
-        float y2 = FLING_CURVE_FUNCTION_Y2;
-        guess[0] = By;
-
-        for (int i = 1; i < ni; i++) {
-            guess[i] = guess[i - 1] - (cubicBezier(y1, y2, guess[i - 1]) - By) / getSlope(guess[i - 1]);
-        }
-        // guess[4] is the final approximate root the cubic equation.
-        float t = guess[4];
-
-        float x1 = FLING_CURVE_FUNCTION_X1;
-        float x2 = FLING_CURVE_FUNCTION_X2;
-        return cubicBezier(x1, x2, t);
-    }
-
-    void updateWithTouchAt(float pos, float timeDelta) {
-        float curveVelocityThreshold = FLING_CURVE_THRESHOLD_VELOCITY * GeckoAppShell.getDpi() * MS_PER_FRAME;
-        float maxVelocity = FLING_CURVE_MAXIMUM_VELOCITY * GeckoAppShell.getDpi() * MS_PER_FRAME;
-
-        float newVelocity = (mTouchPos - pos) / timeDelta * MS_PER_FRAME;
-
-        if (Math.abs(newVelocity) > curveVelocityThreshold && Math.abs(newVelocity) < maxVelocity) {
-            float sign = Math.signum(newVelocity);
-            newVelocity = newVelocity * sign;
-            float scale = maxVelocity - curveVelocityThreshold;
-            float functInp = (newVelocity - curveVelocityThreshold) / scale;
-            float functOut = flingCurve(functInp);
-            newVelocity = functOut * scale + curveVelocityThreshold;
-            newVelocity = newVelocity * sign;
-        }
-
-        mRecentVelocities[mRecentVelocityCount % FLING_VELOCITY_POINTS] = newVelocity;
-        mRecentVelocityCount++;
-
-        // If there's a direction change, or current velocity is very low,
-        // allow setting of the velocity outright. Otherwise, use the current
-        // velocity and a maximum change factor to set the new velocity.
-        boolean curVelocityIsLow = Math.abs(mVelocity) < 1.0f / FRAMERATE_MULTIPLIER;
-        boolean directionChange = (mVelocity > 0) != (newVelocity > 0);
-        if (curVelocityIsLow || (directionChange && !FloatUtils.fuzzyEquals(newVelocity, 0.0f))) {
-            mVelocity = newVelocity;
-        } else {
-            float maxChange = Math.abs(mVelocity * timeDelta * MAX_EVENT_ACCELERATION);
-            mVelocity = Math.min(mVelocity + maxChange, Math.max(mVelocity - maxChange, newVelocity));
-        }
-
-        mTouchPos = pos;
-    }
-
-    boolean overscrolled() {
-        return getOverscroll() != Overscroll.NONE;
-    }
-
-    private Overscroll getOverscroll() {
-        boolean minus = (getOrigin() < getPageStart());
-        boolean plus = (getViewportEnd() > getPageEnd());
-        if (minus && plus) {
-            return Overscroll.BOTH;
-        } else if (minus) {
-            return Overscroll.MINUS;
-        } else if (plus) {
-            return Overscroll.PLUS;
-        } else {
-            return Overscroll.NONE;
-        }
-    }
-
-    // Returns the amount that the page has been overscrolled. If the page hasn't been
-    // overscrolled on this axis, returns 0.
-    private float getExcess() {
-        switch (getOverscroll()) {
-        case MINUS:     return getPageStart() - getOrigin();
-        case PLUS:      return getViewportEnd() - getPageEnd();
-        case BOTH:      return (getViewportEnd() - getPageEnd()) + (getPageStart() - getOrigin());
-        default:        return 0.0f;
-        }
-    }
-
-    /*
-     * Returns true if the page is zoomed in to some degree along this axis such that scrolling is
-     * possible and this axis has not been scroll locked while panning. Otherwise, returns false.
-     */
-    boolean scrollable() {
-        // If we're scrolling a subdocument, ignore the viewport length restrictions (since those
-        // apply to the top-level document) and only take into account axis locking.
-        if (mSubscroller.scrolling()) {
-            return !mScrollingDisabled;
-        }
-
-        // if we are axis locked, return false
-        if (mScrollingDisabled) {
-            return false;
-        }
-
-        // there is scrollable space, and we're not disabled, or the document fits the viewport
-        // but we always allow overscroll anyway
-        return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE ||
-               getOverScrollMode() == View.OVER_SCROLL_ALWAYS;
-    }
-
-    /*
-     * Returns the resistance, as a multiplier, that should be taken into account when
-     * tracking or pinching.
-     */
-    float getEdgeResistance(boolean forPinching) {
-        float excess = getExcess();
-        if (excess > 0.0f && (getOverscroll() == Overscroll.BOTH || !forPinching)) {
-            // excess can be greater than viewport length, but the resistance
-            // must never drop below 0.0
-            return Math.max(0.0f, SNAP_LIMIT - excess / getViewportLength());
-        }
-        return 1.0f;
-    }
-
-    /* Returns the velocity. If the axis is locked, returns 0. */
-    float getRealVelocity() {
-        return scrollable() ? mVelocity : 0f;
-    }
-
-    void startPan() {
-        mFlingState = FlingStates.PANNING;
-    }
-
-    private float calculateFlingVelocity() {
-        int usablePoints = Math.min(mRecentVelocityCount, FLING_VELOCITY_POINTS);
-        if (usablePoints <= 1) {
-            return mVelocity;
-        }
-        float average = 0;
-        for (int i = 0; i < usablePoints; i++) {
-            average += mRecentVelocities[i];
-        }
-        return average / usablePoints;
-    }
-
-    float accelerate(float velocity, float lastFlingVelocity) {
-        return (FLING_ACCEL_BASE_MULTIPLIER * velocity + FLING_ACCEL_SUPPLEMENTAL_MULTIPLIER * lastFlingVelocity);
-    }
-
-    void startFling(boolean stopped) {
-        mDisableSnap = mSubscroller.scrolling();
-
-        if (stopped) {
-            mFlingState = FlingStates.STOPPED;
-        } else {
-            long now = SystemClock.uptimeMillis();
-            mVelocity = calculateFlingVelocity();
-
-            if ((now - mLastFlingTime < FLING_ACCEL_INTERVAL) && Math.signum(mVelocity) == Math.signum(mLastFlingVelocity)) {
-                mVelocity = accelerate(mVelocity, mLastFlingVelocity);
-            }
-            mFlingState = FlingStates.FLINGING;
-            mLastFlingVelocity = mVelocity;
-            mLastFlingTime = now;
-        }
-    }
-
-    /* Advances a fling animation by one step. */
-    boolean advanceFling(long realNsPerFrame) {
-        if (mFlingState != FlingStates.FLINGING) {
-            return false;
-        }
-        if (mSubscroller.scrolling() && !mSubscroller.lastScrollSucceeded()) {
-            // if the subdocument stopped scrolling, it's because it reached the end
-            // of the subdocument. we don't do overscroll on subdocuments, so there's
-            // no point in continuing this fling.
-            return false;
-        }
-
-        float excess = getExcess();
-        Overscroll overscroll = getOverscroll();
-        boolean decreasingOverscroll = false;
-        if ((overscroll == Overscroll.MINUS && mVelocity > 0) ||
-            (overscroll == Overscroll.PLUS && mVelocity < 0))
-        {
-            decreasingOverscroll = true;
-        }
-
-        if (mDisableSnap || FloatUtils.fuzzyEquals(excess, 0.0f) || decreasingOverscroll) {
-            // If we aren't overscrolled, just apply friction.
-            if (Math.abs(mVelocity) >= VELOCITY_THRESHOLD) {
-                mVelocity *= getFrameAdjustedFriction(FRICTION_FAST, realNsPerFrame);
-            } else {
-                float t = mVelocity / VELOCITY_THRESHOLD;
-                mVelocity *= FloatUtils.interpolate(getFrameAdjustedFriction(FRICTION_SLOW, realNsPerFrame),
-                                                    getFrameAdjustedFriction(FRICTION_FAST, realNsPerFrame), t);
-            }
-        } else {
-            // Otherwise, decrease the velocity linearly.
-            float elasticity = 1.0f - excess / (getViewportLength() * SNAP_LIMIT);
-            float overscrollDecelRate = getFrameAdjustedFriction(OVERSCROLL_DECEL_RATE, realNsPerFrame);
-            if (overscroll == Overscroll.MINUS) {
-                mVelocity = Math.min((mVelocity + overscrollDecelRate) * elasticity, 0.0f);
-            } else { // must be Overscroll.PLUS
-                mVelocity = Math.max((mVelocity - overscrollDecelRate) * elasticity, 0.0f);
-            }
-        }
-
-        return true;
-    }
-
-    void stopFling() {
-        mVelocity = 0.0f;
-        mFlingState = FlingStates.STOPPED;
-    }
-
-    // Performs displacement of the viewport position according to the current velocity.
-    void displace() {
-        // if this isn't scrollable just return
-        if (!scrollable())
-            return;
-
-        if (mFlingState == FlingStates.PANNING)
-            mDisplacement += (mLastTouchPos - mTouchPos) * getEdgeResistance(false);
-        else
-            mDisplacement += mVelocity * getEdgeResistance(false);
-
-        // if overscroll is disabled and we're trying to overscroll, reset the displacement
-        // to remove any excess. Using getExcess alone isn't enough here since it relies on
-        // getOverscroll which doesn't take into account any new displacment being applied.
-        // If we using a subscroller, we don't want to alter the scrolling being done
-        if (getOverScrollMode() == View.OVER_SCROLL_NEVER && !mSubscroller.scrolling()) {
-            float originalDisplacement = mDisplacement;
-
-            if (mDisplacement + getOrigin() < getPageStart()) {
-                mDisplacement = getPageStart() - getOrigin();
-            } else if (mDisplacement + getOrigin() + getVisibleEndOfLayerView() > getPageEnd()) {
-                mDisplacement = getPageEnd() - getOrigin() - getVisibleEndOfLayerView();
-            }
-
-            // Return the amount of overscroll so that the overscroll controller can draw it for us
-            if (originalDisplacement != mDisplacement) {
-                if (mFlingState == FlingStates.FLINGING) {
-                    overscrollFling(mVelocity / MS_PER_FRAME * 1000);
-                    stopFling();
-                } else if (mFlingState == FlingStates.PANNING) {
-                    overscrollPan(originalDisplacement - mDisplacement);
-                }
-            }
-        }
-    }
-
-    float resetDisplacement() {
-        float d = mDisplacement;
-        mDisplacement = 0.0f;
-        return d;
-    }
-
-    void setAutoscrollVelocity(float velocity) {
-        if (mFlingState != FlingStates.STOPPED) {
-            Log.e(LOGTAG, "Setting autoscroll velocity while in a fling is not allowed!");
-            return;
-        }
-        mVelocity = velocity;
-    }
-}
deleted file mode 100644
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/gfx/DisplayPortCalculator.java
+++ /dev/null
@@ -1,771 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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/. */
-
-package org.mozilla.gecko.gfx;
-
-import org.mozilla.gecko.GeckoAppShell;
-import org.mozilla.gecko.PrefsHelper;
-import org.mozilla.gecko.util.FloatUtils;
-
-import org.json.JSONArray;
-
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-
-final class DisplayPortCalculator {
-    private static final String LOGTAG = "GeckoDisplayPort";
-    private static final PointF ZERO_VELOCITY = new PointF(0, 0);
-
-    private static final String PREF_DISPLAYPORT_STRATEGY = "gfx.displayport.strategy";
-    private static final String PREF_DISPLAYPORT_FM_MULTIPLIER = "gfx.displayport.strategy_fm.multiplier";
-    private static final String PREF_DISPLAYPORT_FM_DANGER_X = "gfx.displayport.strategy_fm.danger_x";
-    private static final String PREF_DISPLAYPORT_FM_DANGER_Y = "gfx.displayport.strategy_fm.danger_y";
-    private static final String PREF_DISPLAYPORT_VB_MULTIPLIER = "gfx.displayport.strategy_vb.multiplier";
-    private static final String PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD = "gfx.displayport.strategy_vb.threshold";
-    private static final String PREF_DISPLAYPORT_VB_REVERSE_BUFFER = "gfx.displayport.strategy_vb.reverse_buffer";
-    private static final String PREF_DISPLAYPORT_VB_DANGER_X_BASE = "gfx.displayport.strategy_vb.danger_x_base";
-    private static final String PREF_DISPLAYPORT_VB_DANGER_Y_BASE = "gfx.displayport.strategy_vb.danger_y_base";
-    private static final String PREF_DISPLAYPORT_VB_DANGER_X_INCR = "gfx.displayport.strategy_vb.danger_x_incr";
-    private static final String PREF_DISPLAYPORT_VB_DANGER_Y_INCR = "gfx.displayport.strategy_vb.danger_y_incr";
-    private static final String PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD = "gfx.displayport.strategy_pb.threshold";
-
-    private static DisplayPortStrategy sStrategy = new VelocityBiasStrategy(null);
-
-    static DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
-        return sStrategy.calculate(metrics, (velocity == null ? ZERO_VELOCITY : velocity));
-    }
-
-    static boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
-        if (displayPort == null) {
-            return true;
-        }
-        return sStrategy.aboutToCheckerboard(metrics, (velocity == null ? ZERO_VELOCITY : velocity), displayPort);
-    }
-
-    static boolean drawTimeUpdate(long millis, int pixels) {
-        return sStrategy.drawTimeUpdate(millis, pixels);
-    }
-
-    static void resetPageState() {
-        sStrategy.resetPageState();
-    }
-
-    static void initPrefs() {
-        final String[] prefs = { PREF_DISPLAYPORT_STRATEGY,
-                                 PREF_DISPLAYPORT_FM_MULTIPLIER,
-                                 PREF_DISPLAYPORT_FM_DANGER_X,
-                                 PREF_DISPLAYPORT_FM_DANGER_Y,
-                                 PREF_DISPLAYPORT_VB_MULTIPLIER,
-                                 PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD,
-                                 PREF_DISPLAYPORT_VB_REVERSE_BUFFER,
-                                 PREF_DISPLAYPORT_VB_DANGER_X_BASE,
-                                 PREF_DISPLAYPORT_VB_DANGER_Y_BASE,
-                                 PREF_DISPLAYPORT_VB_DANGER_X_INCR,
-                                 PREF_DISPLAYPORT_VB_DANGER_Y_INCR,
-                                 PREF_DISPLAYPORT_PB_VELOCITY_THRESHOLD };
-
-        PrefsHelper.getPrefs(prefs, new PrefsHelper.PrefHandlerBase() {
-            private final Map<String, Integer> mValues = new HashMap<String, Integer>();
-
-            @Override public void prefValue(String pref, int value) {
-                mValues.put(pref, value);
-            }
-
-            @Override public void finish() {
-                setStrategy(mValues);
-            }
-        });
-    }
-
-    /**
-     * Set the active strategy to use.
-     * See the gfx.displayport.strategy pref in mobile/android/app/mobile.js to see the
-     * mapping between ints and strategies.
-     */
-    static boolean setStrategy(Map<String, Integer> prefs) {
-        Integer strategy = prefs.get(PREF_DISPLAYPORT_STRATEGY);
-        if (strategy == null) {
-            return false;
-        }
-
-        switch (strategy) {
-            case 0:
-                sStrategy = new FixedMarginStrategy(prefs);
-                break;
-            case 1:
-                sStrategy = new VelocityBiasStrategy(prefs);
-                break;
-            case 2:
-                sStrategy = new DynamicResolutionStrategy(prefs);
-                break;
-            case 3:
-                sStrategy = new NoMarginStrategy(prefs);
-                break;
-            case 4:
-                sStrategy = new PredictionBiasStrategy(prefs);
-                break;
-            default:
-                Log.e(LOGTAG, "Invalid strategy index specified");
-                return false;
-        }
-        Log.i(LOGTAG, "Set strategy " + sStrategy.toString());
-        return true;
-    }
-
-    private static float getFloatPref(Map<String, Integer> prefs, String prefName, int defaultValue) {
-        Integer value = (prefs == null ? null : prefs.get(prefName));
-        return (value == null || value < 0 ? defaultValue : value) / 1000f;
-    }
-
-    private static abstract class DisplayPortStrategy {
-        /** Calculates a displayport given a viewport and panning velocity. */
-        public abstract DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity);
-        /** Returns true if a checkerboard is about to be visible and we should not throttle drawing. */
-        public abstract boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort);
-        /** Notify the strategy of a new recorded draw time. Return false to turn off draw time recording. */
-        public boolean drawTimeUpdate(long millis, int pixels) { return false; }
-        /** Reset any page-specific state stored, as the page being displayed has changed. */
-        public void resetPageState() {}
-    }
-
-    /**
-     * Return the dimensions for a rect that has area (width*height) that does not exceed the page size in the
-     * given metrics object. The area in the returned FloatSize may be less than width*height if the page is
-     * small, but it will never be larger than width*height.
-     * Note that this process may change the relative aspect ratio of the given dimensions.
-     */
-    private static FloatSize reshapeForPage(float width, float height, ImmutableViewportMetrics metrics) {
-        // figure out how much of the desired buffer amount we can actually use on the horizontal axis
-        float usableWidth = Math.min(width, metrics.getPageWidth());
-        // if we reduced the buffer amount on the horizontal axis, we should take that saved memory and
-        // use it on the vertical axis
-        float extraUsableHeight = (float)Math.floor(((width - usableWidth) * height) / usableWidth);
-        float usableHeight = Math.min(height + extraUsableHeight, metrics.getPageHeight());
-        if (usableHeight < height && usableWidth == width) {
-            // and the reverse - if we shrunk the buffer on the vertical axis we can add it to the horizontal
-            float extraUsableWidth = (float)Math.floor(((height - usableHeight) * width) / usableHeight);
-            usableWidth = Math.min(width + extraUsableWidth, metrics.getPageWidth());
-        }
-        return new FloatSize(usableWidth, usableHeight);
-    }
-
-    /**
-     * Expand the given rect in all directions by a "danger zone". The size of the danger zone on an axis
-     * is the size of the view on that axis multiplied by the given multiplier. The expanded rect is then
-     * clamped to page bounds and returned.
-     */
-    private static RectF expandByDangerZone(RectF rect, float dangerZoneXMultiplier, float dangerZoneYMultiplier, ImmutableViewportMetrics metrics) {
-        // calculate the danger zone amounts in pixels
-        float dangerZoneX = metrics.getWidth() * dangerZoneXMultiplier;
-        float dangerZoneY = metrics.getHeight() * dangerZoneYMultiplier;
-        rect = RectUtils.expand(rect, dangerZoneX, dangerZoneY);
-        // clamp to page bounds
-        return clampToPageBounds(rect, metrics);
-    }
-
-    /**
-     * Calculate the display port by expanding the viewport by the specified
-     * margins, then clamping to the page size.
-     */
-    private static DisplayPortMetrics getPageClampedDisplayPortMetrics(RectF margins, float zoom, ImmutableViewportMetrics metrics) {
-        float left = metrics.viewportRectLeft - margins.left;
-        float top = metrics.viewportRectTop - margins.top;
-        float right = metrics.viewportRectRight() + margins.right;
-        float bottom = metrics.viewportRectBottom() + margins.bottom;
-        left = Math.max(metrics.pageRectLeft, left);
-        top = Math.max(metrics.pageRectTop, top);
-        right = Math.min(metrics.pageRectRight, right);
-        bottom = Math.min(metrics.pageRectBottom, bottom);
-
-        return new DisplayPortMetrics(left, top, right, bottom, zoom);
-    }
-
-    /**
-     * Adjust the given margins so if they are applied on the viewport in the metrics, the resulting rect
-     * does not exceed the page bounds. This code will maintain the total margin amount for a given axis;
-     * it assumes that margins.left + metrics.getWidth() + margins.right is less than or equal to
-     * metrics.getPageWidth(); and the same for the y axis.
-     */
-    private static RectF shiftMarginsForPageBounds(RectF margins, ImmutableViewportMetrics metrics) {
-        // check how much we're overflowing in each direction. note that at most one of leftOverflow
-        // and rightOverflow can be greater than zero, and at most one of topOverflow and bottomOverflow
-        // can be greater than zero, because of the assumption described in the method javadoc.
-        float leftOverflow = metrics.pageRectLeft - (metrics.viewportRectLeft - margins.left);
-        float rightOverflow = (metrics.viewportRectRight() + margins.right) - metrics.pageRectRight;
-        float topOverflow = metrics.pageRectTop - (metrics.viewportRectTop - margins.top);
-        float bottomOverflow = (metrics.viewportRectBottom() + margins.bottom) - metrics.pageRectBottom;
-
-        // if the margins overflow the page bounds, shift them to other side on the same axis
-        if (leftOverflow > 0) {
-            margins.left -= leftOverflow;
-            margins.right += leftOverflow;
-        } else if (rightOverflow > 0) {
-            margins.right -= rightOverflow;
-            margins.left += rightOverflow;
-        }
-        if (topOverflow > 0) {
-            margins.top -= topOverflow;
-            margins.bottom += topOverflow;
-        } else if (bottomOverflow > 0) {
-            margins.bottom -= bottomOverflow;
-            margins.top += bottomOverflow;
-        }
-        return margins;
-    }
-
-    /**
-     * Clamp the given rect to the page bounds and return it.
-     */
-    private static RectF clampToPageBounds(RectF rect, ImmutableViewportMetrics metrics) {
-        if (rect.top < metrics.pageRectTop) rect.top = metrics.pageRectTop;
-        if (rect.left < metrics.pageRectLeft) rect.left = metrics.pageRectLeft;
-        if (rect.right > metrics.pageRectRight) rect.right = metrics.pageRectRight;
-        if (rect.bottom > metrics.pageRectBottom) rect.bottom = metrics.pageRectBottom;
-        return rect;
-    }
-
-    /**
-     * This class implements the variation where we basically don't bother with a a display port.
-     */
-    private static class NoMarginStrategy extends DisplayPortStrategy {
-        NoMarginStrategy(Map<String, Integer> prefs) {
-            // no prefs in this strategy
-        }
-
-        @Override
-        public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
-            return new DisplayPortMetrics(metrics.viewportRectLeft,
-                    metrics.viewportRectTop,
-                    metrics.viewportRectRight(),
-                    metrics.viewportRectBottom(),
-                    metrics.zoomFactor);
-        }
-
-        @Override
-        public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
-            return true;
-        }
-
-        @Override
-        public String toString() {
-            return "NoMarginStrategy";
-        }
-    }
-
-    /**
-     * This class implements the variation where we use a fixed-size margin on the display port.
-     * The margin is always 300 pixels in all directions, except when we are (a) approaching a page
-     * boundary, and/or (b) if we are limited by the page size. In these cases we try to maintain
-     * the area of the display port by (a) shifting the buffer to the other side on the same axis,
-     * and/or (b) increasing the buffer on the other axis to compensate for the reduced buffer on
-     * one axis.
-     */
-    private static class FixedMarginStrategy extends DisplayPortStrategy {
-        // The length of each axis of the display port will be the corresponding view length
-        // multiplied by this factor.
-        private final float SIZE_MULTIPLIER;
-
-        // If the visible rect is within the danger zone (measured as a fraction of the view size
-        // from the edge of the displayport) we start redrawing to minimize checkerboarding.
-        private final float DANGER_ZONE_X_MULTIPLIER;
-        private final float DANGER_ZONE_Y_MULTIPLIER;
-
-        FixedMarginStrategy(Map<String, Integer> prefs) {
-            SIZE_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_MULTIPLIER, 2000);
-            DANGER_ZONE_X_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_DANGER_X, 100);
-            DANGER_ZONE_Y_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_FM_DANGER_Y, 200);
-        }
-
-        @Override
-        public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
-            float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
-            float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
-
-            // we need to avoid having a display port that is larger than the page, or we will end up
-            // painting things outside the page bounds (bug 729169). we simultaneously need to make
-            // the display port as large as possible so that we redraw less. reshape the display
-            // port dimensions to accomplish this.
-            FloatSize usableSize = reshapeForPage(displayPortWidth, displayPortHeight, metrics);
-            float horizontalBuffer = usableSize.width - metrics.getWidth();
-            float verticalBuffer = usableSize.height - metrics.getHeight();
-
-            // and now calculate the display port margins based on how much buffer we've decided to use and
-            // the page bounds, ensuring we use all of the available buffer amounts on one side or the other
-            // on any given axis. (i.e. if we're scrolled to the top of the page, the vertical buffer is
-            // entirely below the visible viewport, but if we're halfway down the page, the vertical buffer
-            // is split).
-            RectF margins = new RectF();
-            margins.left = horizontalBuffer / 2.0f;
-            margins.right = horizontalBuffer - margins.left;
-            margins.top = verticalBuffer / 2.0f;
-            margins.bottom = verticalBuffer - margins.top;
-            margins = shiftMarginsForPageBounds(margins, metrics);
-
-            return getPageClampedDisplayPortMetrics(margins, metrics.zoomFactor, metrics);
-        }
-
-        @Override
-        public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
-            // Increase the size of the viewport based on the danger zone multiplier (and clamp to page
-            // boundaries), and intersect it with the current displayport to determine whether we're
-            // close to checkerboarding.
-            RectF adjustedViewport = expandByDangerZone(metrics.getViewport(), DANGER_ZONE_X_MULTIPLIER, DANGER_ZONE_Y_MULTIPLIER, metrics);
-            return !displayPort.contains(adjustedViewport);
-        }
-
-        @Override
-        public String toString() {
-            return "FixedMarginStrategy mult=" + SIZE_MULTIPLIER + ", dangerX=" + DANGER_ZONE_X_MULTIPLIER + ", dangerY=" + DANGER_ZONE_Y_MULTIPLIER;
-        }
-    }
-
-    /**
-     * This class implements the variation with a small fixed-size margin with velocity bias.
-     * In this variation, the default margins are pretty small relative to the view size, but
-     * they are affected by the panning velocity. Specifically, if we are panning on one axis,
-     * we remove the margins on the other axis because we are likely axis-locked. Also once
-     * we are panning in one direction above a certain threshold velocity, we shift the buffer
-     * so that it is almost entirely in the direction of the pan, with a little bit in the
-     * reverse direction.
-     */
-    private static class VelocityBiasStrategy extends DisplayPortStrategy {
-        // The length of each axis of the display port will be the corresponding view length
-        // multiplied by this factor.
-        private final float SIZE_MULTIPLIER;
-        // The velocity above which we apply the velocity bias
-        private final float VELOCITY_THRESHOLD;
-        // How much of the buffer to keep in the reverse direction of the velocity
-        private final float REVERSE_BUFFER;
-        // If the visible rect is within the danger zone we start redrawing to minimize
-        // checkerboarding. the danger zone amount is a linear function of the form:
-        //    viewportsize * (base + velocity * incr)
-        // where base and incr are configurable values.
-        private final float DANGER_ZONE_BASE_X_MULTIPLIER;
-        private final float DANGER_ZONE_BASE_Y_MULTIPLIER;
-        private final float DANGER_ZONE_INCR_X_MULTIPLIER;
-        private final float DANGER_ZONE_INCR_Y_MULTIPLIER;
-
-        VelocityBiasStrategy(Map<String, Integer> prefs) {
-            SIZE_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_MULTIPLIER, 2000);
-            VELOCITY_THRESHOLD = GeckoAppShell.getDpi() * getFloatPref(prefs, PREF_DISPLAYPORT_VB_VELOCITY_THRESHOLD, 32);
-            REVERSE_BUFFER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_REVERSE_BUFFER, 200);
-            DANGER_ZONE_BASE_X_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_DANGER_X_BASE, 1000);
-            DANGER_ZONE_BASE_Y_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_DANGER_Y_BASE, 1000);
-            DANGER_ZONE_INCR_X_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_DANGER_X_INCR, 0);
-            DANGER_ZONE_INCR_Y_MULTIPLIER = getFloatPref(prefs, PREF_DISPLAYPORT_VB_DANGER_Y_INCR, 0);
-        }
-
-        /**
-         * Split the given amounts into margins based on the VELOCITY_THRESHOLD and REVERSE_BUFFER values.
-         * If the velocity is above the VELOCITY_THRESHOLD on an axis, split the amount into REVERSE_BUFFER
-         * and 1.0 - REVERSE_BUFFER fractions. The REVERSE_BUFFER fraction is set as the margin in the
-         * direction opposite to the velocity, and the remaining fraction is set as the margin in the direction
-         * of the velocity. If the velocity is lower than VELOCITY_THRESHOLD, split the amount evenly into the
-         * two margins on that axis.
-         */
-        private RectF velocityBiasedMargins(float xAmount, float yAmount, PointF velocity) {
-            RectF margins = new RectF();
-
-            if (velocity.x > VELOCITY_THRESHOLD) {
-                margins.left = xAmount * REVERSE_BUFFER;
-            } else if (velocity.x < -VELOCITY_THRESHOLD) {
-                margins.left = xAmount * (1.0f - REVERSE_BUFFER);
-            } else {
-                margins.left = xAmount / 2.0f;
-            }
-            margins.right = xAmount - margins.left;
-
-            if (velocity.y > VELOCITY_THRESHOLD) {
-                margins.top = yAmount * REVERSE_BUFFER;
-            } else if (velocity.y < -VELOCITY_THRESHOLD) {
-                margins.top = yAmount * (1.0f - REVERSE_BUFFER);
-            } else {
-                margins.top = yAmount / 2.0f;
-            }
-            margins.bottom = yAmount - margins.top;
-
-            return margins;
-        }
-
-        @Override
-        public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
-            float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
-            float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
-
-            // but if we're panning on one axis, set the margins for the other axis to zero since we are likely
-            // axis locked and won't be displaying that extra area.
-            if (Math.abs(velocity.x) > VELOCITY_THRESHOLD && FloatUtils.fuzzyEquals(velocity.y, 0)) {
-                displayPortHeight = metrics.getHeight();
-            } else if (Math.abs(velocity.y) > VELOCITY_THRESHOLD && FloatUtils.fuzzyEquals(velocity.x, 0)) {
-                displayPortWidth = metrics.getWidth();
-            }
-
-            // we need to avoid having a display port that is larger than the page, or we will end up
-            // painting things outside the page bounds (bug 729169).
-            displayPortWidth = Math.min(displayPortWidth, metrics.getPageWidth());
-            displayPortHeight = Math.min(displayPortHeight, metrics.getPageHeight());
-            float horizontalBuffer = displayPortWidth - metrics.getWidth();
-            float verticalBuffer = displayPortHeight - metrics.getHeight();
-
-            // split the buffer amounts into margins based on velocity, and shift it to
-            // take into account the page bounds
-            RectF margins = velocityBiasedMargins(horizontalBuffer, verticalBuffer, velocity);
-            margins = shiftMarginsForPageBounds(margins, metrics);
-
-            return getPageClampedDisplayPortMetrics(margins, metrics.zoomFactor, metrics);
-        }
-
-        @Override
-        public boolean aboutToCheckerboard(ImmutableViewportMetrics metrics, PointF velocity, DisplayPortMetrics displayPort) {
-            // calculate the danger zone amounts based on the prefs
-            float dangerZoneX = metrics.getWidth() * (DANGER_ZONE_BASE_X_MULTIPLIER + (velocity.x * DANGER_ZONE_INCR_X_MULTIPLIER));
-            float dangerZoneY = metrics.getHeight() * (DANGER_ZONE_BASE_Y_MULTIPLIER + (velocity.y * DANGER_ZONE_INCR_Y_MULTIPLIER));
-            // clamp it such that when added to the viewport, they don't exceed page size.
-            // this is a prerequisite to calling shiftMarginsForPageBounds as we do below.
-            dangerZoneX = Math.min(dangerZoneX, metrics.getPageWidth() - metrics.getWidth());
-            dangerZoneY = Math.min(dangerZoneY, metrics.getPageHeight() - metrics.getHeight());
-
-            // split the danger zone into margins based on velocity, and ensure it doesn't exceed
-            // page bounds.
-            RectF dangerMargins = velocityBiasedMargins(dangerZoneX, dangerZoneY, velocity);
-            dangerMargins = shiftMarginsForPageBounds(dangerMargins, metrics);
-
-            // we're about to checkerboard if the current viewport area + the danger zone margins
-            // fall out of the current displayport anywhere.
-            RectF adjustedViewport = new RectF(
-                    metrics.viewportRectLeft - dangerMargins.left,
-                    metrics.viewportRectTop - dangerMargins.top,
-                    metrics.viewportRectRight() + dangerMargins.right,
-                    metrics.viewportRectBottom() + dangerMargins.bottom);
-            return !displayPort.contains(adjustedViewport);
-        }
-
-        @Override
-        public String toString() {
-            return "VelocityBiasStrategy mult=" + SIZE_MULTIPLIER + ", threshold=" + VELOCITY_THRESHOLD + ", reverse=" + REVERSE_BUFFER
-                + ", dangerBaseX=" + DANGER_ZONE_BASE_X_MULTIPLIER + ", dangerBaseY=" + DANGER_ZONE_BASE_Y_MULTIPLIER
-                + ", dangerIncrX=" + DANGER_ZONE_INCR_Y_MULTIPLIER + ", dangerIncrY=" + DANGER_ZONE_INCR_Y_MULTIPLIER;
-        }
-    }
-
-    /**
-     * This class implements the variation where we draw more of the page at low resolution while panning.
-     * In this variation, as we pan faster, we increase the page area we are drawing, but reduce the draw
-     * resolution to compensate. This results in the same device-pixel area drawn; the compositor then
-     * scales this up to the viewport zoom level. This results in a large area of the page drawn but it
-     * looks blurry. The assumption is that drawing extra that we never display is better than checkerboarding,
-     * where we draw less but never even show it on the screen.
-     */
-    private static class DynamicResolutionStrategy extends DisplayPortStrategy {
-        // The length of each axis of the display port will be the corresponding view length
-        // multiplied by this factor.
-        private static final float SIZE_MULTIPLIER = 1.5f;
-
-        // The velocity above which we start zooming out the display port to keep up
-        // with the panning.
-        private static final float VELOCITY_EXPANSION_THRESHOLD = GeckoAppShell.getDpi() / 16f;
-
-        // How much we increase the display port based on velocity. Assuming no friction and
-        // splitting (see below), this should be be the number of frames (@60fps) between us
-        // calculating the display port and the draw of the *next* display port getting composited
-        // and displayed on the screen. This is because the timeline looks like this:
-        //      Java: pan pan pan pan pan pan ! pan pan pan pan pan pan !
-        //     Gecko:   \-> draw -> composite /   \-> draw -> composite /
-        // The display port calculated on the first "pan" gets composited to the screen at the
-        // first exclamation mark, and remains on the screen until the second exclamation mark.
-        // In order to avoid checkerboarding, that display port must be able to contain all of
-        // the panning until the second exclamation mark, which encompasses two entire draw/composite
-        // cycles.
-        // If we take into account friction, our velocity multiplier should be reduced as the
-        // amount of pan will decrease each time. If we take into account display port splitting,
-        // it should be increased as the splitting means some of the display port will be used to
-        // draw in the opposite direction of the velocity. For now I'm assuming these two cancel
-        // each other out.
-        private static final float VELOCITY_MULTIPLIER = 60.0f;
-
-        // The following constants adjust how biased the display port is in the direction of panning.
-        // When panning fast (above the FAST_THRESHOLD) we use the fast split factor to split the
-        // display port "buffer" area, otherwise we use the slow split factor. This is based on the
-        // assumption that if the user is panning fast, they are less likely to reverse directions
-        // and go backwards, so we should spend more of our display port buffer in the direction of
-        // panning.
-        private static final float VELOCITY_FAST_THRESHOLD = VELOCITY_EXPANSION_THRESHOLD * 2.0f;
-        private static final float FAST_SPLIT_FACTOR = 0.95f;
-        private static final float SLOW_SPLIT_FACTOR = 0.8f;
-
-        // The following constants are used for viewport prediction; we use them to estimate where
-        // the viewport will be soon and whether or not we should trigger a draw right now. "soon"
-        // in the previous sentence really refers to the amount of time it would take to draw and
-        // composite from the point at which we do the calculation, and that is not really a known
-        // quantity. The velocity multiplier is how much we multiply the velocity by; it has the
-        // same caveats as the VELOCITY_MULTIPLIER above except that it only needs to take into account
-        // one draw/composite cycle instead of two. The danger zone multiplier is a multiplier of the
-        // viewport size that we use as an extra "danger zone" around the viewport; if this danger
-        // zone falls outside the display port then we are approaching the point at which we will
-        // checkerboard, and hence should start drawing. Note that if DANGER_ZONE_MULTIPLIER is
-        // greater than (SIZE_MULTIPLIER - 1.0f), then at zero velocity we will always be in the
-        // danger zone, and thus will be constantly drawing.
-        private static final float PREDICTION_VELOCITY_MULTIPLIER = 30.0f;
-        private static final float DANGER_ZONE_MULTIPLIER = 0.20f; // must be less than (SIZE_MULTIPLIER - 1.0f)
-
-        DynamicResolutionStrategy(Map<String, Integer> prefs) {
-            // ignore prefs for now
-        }
-
-        @Override
-        public DisplayPortMetrics calculate(ImmutableViewportMetrics metrics, PointF velocity) {
-            float displayPortWidth = metrics.getWidth() * SIZE_MULTIPLIER;
-            float displayPortHeight = metrics.getHeight() * SIZE_MULTIPLIER;
-
-            // for resolution calculation purposes, we need to know what the adjusted display port dimensions
-            // would be if we had zero velocity, so calculate that here before we increase the display port
-            // based on velocity.
-            FloatSize reshapedSize = reshapeForPage(displayPortWidth, displayPortHeight, metrics);
-
-            // increase displayPortWidth and displayPortHeight based on the velocity, b