Merge inbound to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 04 May 2015 15:59:00 -0400
changeset 261171 102d0e9aa9e1629e2b448b45ac5224c2aef87ec7
parent 261136 642aa49f22cff497d834e0a4066d1473497ecfa4 (current diff)
parent 261170 995db217fd1b4a32daa4300195818bdafc78a64d (diff)
child 261172 2a3912c6b9986d35fbad13c601f6a81c965b0a70
child 261181 80bb01392379b611eabd46d5670b062d79986227
child 261222 b491b0ab6c2ebc5a16f76e81f34543762cd92cad
push id8007
push userraliiev@mozilla.com
push dateMon, 11 May 2015 19:23:16 +0000
treeherdermozilla-aurora@e2ce1aac996e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone40.0a1
Merge inbound to m-c. a=merge
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -2764,19 +2764,19 @@ Element::CheckHandleEventForLinksPrecond
 }
 
 nsresult
 Element::PreHandleEventForLinks(EventChainPreVisitor& aVisitor)
 {
   // Optimisation: return early if this event doesn't interest us.
   // IMPORTANT: this switch and the switch below it must be kept in sync!
   switch (aVisitor.mEvent->message) {
-  case NS_MOUSE_ENTER_SYNTH:
+  case NS_MOUSE_OVER:
   case NS_FOCUS_CONTENT:
-  case NS_MOUSE_EXIT_SYNTH:
+  case NS_MOUSE_OUT:
   case NS_BLUR_CONTENT:
     break;
   default:
     return NS_OK;
   }
 
   // Make sure we meet the preconditions before continuing
   nsCOMPtr<nsIURI> absURI;
@@ -2785,32 +2785,32 @@ Element::PreHandleEventForLinks(EventCha
   }
 
   nsresult rv = NS_OK;
 
   // We do the status bar updates in PreHandleEvent so that the status bar gets
   // updated even if the event is consumed before we have a chance to set it.
   switch (aVisitor.mEvent->message) {
   // Set the status bar similarly for mouseover and focus
-  case NS_MOUSE_ENTER_SYNTH:
+  case NS_MOUSE_OVER:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
     // FALL THROUGH
   case NS_FOCUS_CONTENT: {
     InternalFocusEvent* focusEvent = aVisitor.mEvent->AsFocusEvent();
     if (!focusEvent || !focusEvent->isRefocus) {
       nsAutoString target;
       GetLinkTarget(target);
       nsContentUtils::TriggerLink(this, aVisitor.mPresContext, absURI, target,
                                   false, true, true);
       // Make sure any ancestor links don't also TriggerLink
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
   }
-  case NS_MOUSE_EXIT_SYNTH:
+  case NS_MOUSE_OUT:
     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
     // FALL THROUGH
   case NS_BLUR_CONTENT:
     rv = LeaveLink(aVisitor.mPresContext);
     if (NS_SUCCEEDED(rv)) {
       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
     }
     break;
--- a/dom/base/FragmentOrElement.cpp
+++ b/dom/base/FragmentOrElement.cpp
@@ -671,18 +671,18 @@ nsIContent::PreHandleEvent(EventChainPre
 {
   //FIXME! Document how this event retargeting works, Bug 329124.
   aVisitor.mCanHandle = true;
   aVisitor.mMayHaveListenerManager = HasListenerManager();
 
   // Don't propagate mouseover and mouseout events when mouse is moving
   // inside chrome access only content.
   bool isAnonForEvents = IsRootOfChromeAccessOnlySubtree();
-  if ((aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH ||
-       aVisitor.mEvent->message == NS_MOUSE_EXIT_SYNTH ||
+  if ((aVisitor.mEvent->message == NS_MOUSE_OVER ||
+       aVisitor.mEvent->message == NS_MOUSE_OUT ||
        aVisitor.mEvent->message == NS_POINTER_OVER ||
        aVisitor.mEvent->message == NS_POINTER_OUT) &&
       // Check if we should stop event propagation when event has just been
       // dispatched or when we're about to propagate from
       // chrome access only subtree or if we are about to propagate out of
       // a shadow root to a shadow root host.
       ((this == aVisitor.mEvent->originalTarget &&
         !ChromeOnlyAccess()) || isAnonForEvents || GetShadowRoot())) {
@@ -733,17 +733,17 @@ nsIContent::PreHandleEvent(EventChainPre
               if (originalTarget) {
                 originalTarget->NodeInfo()->NameAtom()->ToString(ot);
               }
               NodeInfo()->NameAtom()->ToString(ct);
               relatedTarget->NodeInfo()->NameAtom()->ToString(rt);
               printf("Stopping %s propagation:"
                      "\n\toriginalTarget=%s \n\tcurrentTarget=%s %s"
                      "\n\trelatedTarget=%s %s \n%s",
-                     (aVisitor.mEvent->message == NS_MOUSE_ENTER_SYNTH)
+                     (aVisitor.mEvent->message == NS_MOUSE_OVER)
                        ? "mouseover" : "mouseout",
                      NS_ConvertUTF16toUTF8(ot).get(),
                      NS_ConvertUTF16toUTF8(ct).get(),
                      isAnonForEvents
                        ? "(is native anonymous)"
                        : (ChromeOnlyAccess()
                            ? "(is in native anonymous subtree)" : ""),
                      NS_ConvertUTF16toUTF8(rt).get(),
--- a/dom/base/nsContentUtils.cpp
+++ b/dom/base/nsContentUtils.cpp
@@ -7648,19 +7648,19 @@ nsContentUtils::SendMouseEvent(nsCOMPtr<
   bool contextMenuKey = false;
   if (aType.EqualsLiteral("mousedown"))
     msg = NS_MOUSE_BUTTON_DOWN;
   else if (aType.EqualsLiteral("mouseup"))
     msg = NS_MOUSE_BUTTON_UP;
   else if (aType.EqualsLiteral("mousemove"))
     msg = NS_MOUSE_MOVE;
   else if (aType.EqualsLiteral("mouseover"))
-    msg = NS_MOUSE_ENTER;
+    msg = NS_MOUSE_ENTER_WIDGET;
   else if (aType.EqualsLiteral("mouseout"))
-    msg = NS_MOUSE_EXIT;
+    msg = NS_MOUSE_EXIT_WIDGET;
   else if (aType.EqualsLiteral("contextmenu")) {
     msg = NS_CONTEXTMENU;
     contextMenuKey = (aButton == 0);
   } else if (aType.EqualsLiteral("MozMouseHittest"))
     msg = NS_MOUSE_MOZHITTEST;
   else
     return NS_ERROR_FAILURE;
 
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -140,16 +140,18 @@ NS_CreateJSTimeoutHandler(nsGlobalWindow
                           const mozilla::dom::Sequence<JS::Value>& aArguments,
                           mozilla::ErrorResult& aError);
 
 extern already_AddRefed<nsIScriptTimeoutHandler>
 NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
                           const nsAString& aExpression,
                           mozilla::ErrorResult& aError);
 
+extern const js::Class OuterWindowProxyClass;
+
 /*
  * Timeout struct that holds information about each script
  * timeout.  Holds a strong reference to an nsIScriptTimeoutHandler, which
  * abstracts the language specific cruft.
  */
 struct nsTimeout final
   : mozilla::LinkedListElement<nsTimeout>
 {
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -360,19 +360,26 @@ DOMCameraControlListener::OnTakePictureC
     RunCallback(nsDOMCameraControl* aDOMCameraControl) override
     {
       nsCOMPtr<nsIDOMBlob> picture =
         File::CreateMemoryFile(mDOMCameraControl.get(),
                                static_cast<void*>(mData),
                                static_cast<uint64_t>(mLength),
                                mMimeType);
       aDOMCameraControl->OnTakePictureComplete(picture);
+      mData = NULL;
     }
 
   protected:
+    virtual
+    ~Callback()
+    {
+        free(mData);
+    }
+
     uint8_t* mData;
     uint32_t mLength;
     nsString mMimeType;
   };
 
   NS_DispatchToMainThread(new Callback(mDOMCameraControl, aData, aLength, aMimeType));
 }
 
--- a/dom/events/DataTransfer.cpp
+++ b/dom/events/DataTransfer.cpp
@@ -89,17 +89,17 @@ DataTransfer::DataTransfer(nsISupports* 
   if (aEventType == NS_CUT ||
       aEventType == NS_COPY ||
       aEventType == NS_DRAGDROP_START ||
       aEventType == NS_DRAGDROP_GESTURE) {
     mReadOnly = false;
   } else if (mIsExternal) {
     if (aEventType == NS_PASTE) {
       CacheExternalClipboardFormats();
-    } else if (aEventType >= NS_DRAGDROP_EVENT_START && aEventType <= NS_DRAGDROP_LEAVE_SYNTH) {
+    } else if (aEventType >= NS_DRAGDROP_EVENT_START && aEventType <= NS_DRAGDROP_LEAVE) {
       CacheExternalDragFormats();
     }
   }
 }
 
 DataTransfer::DataTransfer(nsISupports* aParent,
                            uint32_t aEventType,
                            const uint32_t aEffectAllowed,
--- a/dom/events/EventNameList.h
+++ b/dom/events/EventNameList.h
@@ -186,21 +186,21 @@ EVENT(dragend,
       NS_DRAGDROP_END,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(dragenter,
       NS_DRAGDROP_ENTER,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(dragleave,
-      NS_DRAGDROP_LEAVE_SYNTH,
+      NS_DRAGDROP_LEAVE,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(dragover,
-      NS_DRAGDROP_OVER_SYNTH,
+      NS_DRAGDROP_OVER,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(dragstart,
       NS_DRAGDROP_START,
       EventNameType_HTMLXUL,
       eDragEventClass)
 EVENT(drop,
       NS_DRAGDROP_DROP,
@@ -278,21 +278,21 @@ EVENT(mouseleave,
       NS_MOUSELEAVE,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mousemove,
       NS_MOUSE_MOVE,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseout,
-      NS_MOUSE_EXIT_SYNTH,
+      NS_MOUSE_OUT,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseover,
-      NS_MOUSE_ENTER_SYNTH,
+      NS_MOUSE_OVER,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mouseup,
       NS_MOUSE_BUTTON_UP,
       EventNameType_All,
       eMouseEventClass)
 EVENT(mozfullscreenchange,
       NS_FULLSCREENCHANGE,
@@ -715,17 +715,17 @@ NON_IDL_EVENT(broadcast,
               NS_XUL_BROADCAST,
               EventNameType_XUL,
               eBasicEventClass)
 NON_IDL_EVENT(commandupdate,
               NS_XUL_COMMAND_UPDATE,
               EventNameType_XUL,
               eBasicEventClass)
 NON_IDL_EVENT(dragexit,
-              NS_DRAGDROP_EXIT_SYNTH,
+              NS_DRAGDROP_EXIT,
               EventNameType_XUL,
               eDragEventClass)
 NON_IDL_EVENT(dragdrop,
               NS_DRAGDROP_DRAGDROP,
               EventNameType_XUL,
               eDragEventClass)
 NON_IDL_EVENT(draggesture,
               NS_DRAGDROP_GESTURE,
--- a/dom/events/EventStateManager.cpp
+++ b/dom/events/EventStateManager.cpp
@@ -486,23 +486,23 @@ EventStateManager::PreHandleEvent(nsPres
                    !aTargetFrame->GetContent() ||
                    aTargetFrame->GetContent() == aTargetContent ||
                    aTargetFrame->GetContent()->GetParent() == aTargetContent,
                    "aTargetFrame should be related with aTargetContent");
 
   mCurrentTarget = aTargetFrame;
   mCurrentTargetContent = nullptr;
 
-  // Do not take account NS_MOUSE_ENTER/EXIT so that loading a page
+  // Do not take account NS_MOUSE_ENTER_WIDGET/EXIT_WIDGET so that loading a page
   // when user is not active doesn't change the state to active.
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   if (aEvent->mFlags.mIsTrusted &&
       ((mouseEvent && mouseEvent->IsReal() &&
-        mouseEvent->message != NS_MOUSE_ENTER &&
-        mouseEvent->message != NS_MOUSE_EXIT) ||
+        mouseEvent->message != NS_MOUSE_ENTER_WIDGET &&
+        mouseEvent->message != NS_MOUSE_EXIT_WIDGET) ||
        aEvent->mClass == eWheelEventClass ||
        aEvent->mClass == eKeyboardEventClass)) {
     if (gMouseOrKeyboardEventCounter == 0) {
       nsCOMPtr<nsIObserverService> obs =
         mozilla::services::GetObserverService();
       if (obs) {
         obs->NotifyObservers(nullptr, "user-interaction-active", nullptr);
         UpdateUserActivityTimer();
@@ -575,18 +575,18 @@ EventStateManager::PreHandleEvent(nsPres
         // then fall through...
       case WidgetMouseEvent::eRightButton:
       case WidgetMouseEvent::eMiddleButton:
         SetClickCount(aPresContext, mouseEvent, aStatus);
         break;
     }
     break;
   }
-  case NS_MOUSE_EXIT:
-    // If this is a remote frame, we receive NS_MOUSE_EXIT from the parent
+  case NS_MOUSE_EXIT_WIDGET:
+    // If this is a remote frame, we receive NS_MOUSE_EXIT_WIDGET from the parent
     // the mouse exits our content. Since the parent may update the cursor
     // while the mouse is outside our frame, and since PuppetWidget caches the
     // current cursor internally, re-entering our content (say from over a
     // window edge) wont update the cursor if the cached value and the current
     // cursor match. So when the mouse exits a remote frame, clear the cached
     // widget cursor so a proper update will occur when the mouse re-enters.
     if (XRE_GetProcessType() == GeckoProcessType_Content) {
       ClearCachedWidgetCursor(mCurrentTarget);
@@ -1176,19 +1176,19 @@ CrossProcessSafeEvent(const WidgetEvent&
   case eWheelEventClass:
     return true;
   case eMouseEventClass:
     switch (aEvent.message) {
     case NS_MOUSE_BUTTON_DOWN:
     case NS_MOUSE_BUTTON_UP:
     case NS_MOUSE_MOVE:
     case NS_CONTEXTMENU:
-    case NS_MOUSE_ENTER:
-    case NS_MOUSE_EXIT:
-    case NS_MOUSE_ENTER_SYNTH:
+    case NS_MOUSE_ENTER_WIDGET:
+    case NS_MOUSE_EXIT_WIDGET:
+    case NS_MOUSE_OVER:
       return true;
     default:
       return false;
     }
   case eTouchEventClass:
     switch (aEvent.message) {
     case NS_TOUCH_START:
     case NS_TOUCH_MOVE:
@@ -3320,17 +3320,17 @@ EventStateManager::PostHandleEvent(nsPre
 
   case NS_KEY_PRESS:
     {
       WidgetKeyboardEvent* keyEvent = aEvent->AsKeyboardEvent();
       PostHandleKeyboardEvent(keyEvent, *aStatus, dispatchedToContentProcess);
     }
     break;
 
-  case NS_MOUSE_ENTER:
+  case NS_MOUSE_ENTER_WIDGET:
     if (mCurrentTarget) {
       nsCOMPtr<nsIContent> targetContent;
       mCurrentTarget->GetContentForEvent(aEvent, getter_AddRefs(targetContent));
       SetContentState(targetContent, NS_EVENT_STATE_HOVER);
     }
     break;
 
 #ifdef XP_MACOSX
@@ -3742,18 +3742,18 @@ EventStateManager::DispatchMouseOrPointe
                                                nsIContent* aRelatedContent)
 {
   // http://dvcs.w3.org/hg/webevents/raw-file/default/mouse-lock.html#methods
   // "[When the mouse is locked on an element...e]vents that require the concept
   // of a mouse cursor must not be dispatched (for example: mouseover, mouseout).
   if (sIsPointerLocked &&
       (aMessage == NS_MOUSELEAVE ||
        aMessage == NS_MOUSEENTER ||
-       aMessage == NS_MOUSE_ENTER_SYNTH ||
-       aMessage == NS_MOUSE_EXIT_SYNTH)) {
+       aMessage == NS_MOUSE_OVER ||
+       aMessage == NS_MOUSE_OUT)) {
     mCurrentTargetContent = nullptr;
     nsCOMPtr<Element> pointerLockedElement =
       do_QueryReferent(EventStateManager::sPointerLockedElement);
     if (!pointerLockedElement) {
       NS_WARNING("Should have pointer locked element, but didn't.");
       return nullptr;
     }
     nsCOMPtr<nsIContent> content = do_QueryInterface(pointerLockedElement);
@@ -3788,32 +3788,32 @@ EventStateManager::DispatchMouseOrPointe
   if (mPresContext) {
     // Although the primary frame was checked in event callback, it may not be
     // the same object after event dispatch and handling, so refetch it.
     targetFrame = mPresContext->GetPrimaryFrameFor(aTargetContent);
 
     // If we are entering/leaving remote content, dispatch a mouse enter/exit
     // event to the remote frame.
     if (IsRemoteTarget(aTargetContent)) {
-      if (aMessage == NS_MOUSE_EXIT_SYNTH) {
+      if (aMessage == NS_MOUSE_OUT) {
         // For remote content, send a "top-level" widget mouse exit event.
         nsAutoPtr<WidgetMouseEvent> remoteEvent;
-        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_EXIT,
+        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_EXIT_WIDGET,
                                         aRelatedContent, remoteEvent);
         remoteEvent->exit = WidgetMouseEvent::eTopLevel;
 
         // mCurrentTarget is set to the new target, so we must reset it to the
         // old target and then dispatch a cross-process event. (mCurrentTarget
         // will be set back below.) HandleCrossProcessEvent will query for the
         // proper target via GetEventTarget which will return mCurrentTarget.
         mCurrentTarget = targetFrame;
         HandleCrossProcessEvent(remoteEvent, &status);
-      } else if (aMessage == NS_MOUSE_ENTER_SYNTH) {
+      } else if (aMessage == NS_MOUSE_OVER) {
         nsAutoPtr<WidgetMouseEvent> remoteEvent;
-        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_ENTER,
+        CreateMouseOrPointerWidgetEvent(aMouseEvent, NS_MOUSE_ENTER_WIDGET,
                                         aRelatedContent, remoteEvent);
         HandleCrossProcessEvent(remoteEvent, &status);
       }
     }
   }
 
   mCurrentTargetContent = nullptr;
   mCurrentTarget = previousTarget;
@@ -3928,17 +3928,17 @@ EventStateManager::NotifyMouseOut(Widget
   }
 
   EnterLeaveDispatcher leaveDispatcher(this, wrapper->mLastOverElement,
                                        aMovingInto, aMouseEvent,
                                        isPointer ? NS_POINTER_LEAVE :
                                                    NS_MOUSELEAVE);
 
   // Fire mouseout
-  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_EXIT_SYNTH,
+  DispatchMouseOrPointerEvent(aMouseEvent, isPointer ? NS_POINTER_OUT : NS_MOUSE_OUT,
                               wrapper->mLastOverElement, aMovingInto);
 
   wrapper->mLastOverFrame = nullptr;
   wrapper->mLastOverElement = nullptr;
 
   // Turn recursion protection back off
   wrapper->mFirstOutEventElement = nullptr;
 }
@@ -4001,17 +4001,17 @@ EventStateManager::NotifyMouseOver(Widge
   if (!isPointer) {
     SetContentState(aContent, NS_EVENT_STATE_HOVER);
   }
 
   if (dispatch) {
     // Fire mouseover
     wrapper->mLastOverFrame = 
       DispatchMouseOrPointerEvent(aMouseEvent,
-                                  isPointer ? NS_POINTER_OVER : NS_MOUSE_ENTER_SYNTH,
+                                  isPointer ? NS_POINTER_OVER : NS_MOUSE_OVER,
                                   aContent, lastOverElement);
     wrapper->mLastOverElement = aContent;
   } else {
     wrapper->mLastOverFrame = nullptr;
     wrapper->mLastOverElement = nullptr;
   }
 
   // Turn recursion protection back off
@@ -4159,17 +4159,17 @@ EventStateManager::GenerateMouseEnterExi
           helper->mLastOverElement = targetElement;
         }
         NotifyMouseOut(aMouseEvent, nullptr);
       }
     }
     break;
   case NS_POINTER_LEAVE:
   case NS_POINTER_CANCEL:
-  case NS_MOUSE_EXIT:
+  case NS_MOUSE_EXIT_WIDGET:
     {
       // This is actually the window mouse exit or pointer leave event. We're not moving
       // into any new element.
 
       OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
       if (helper->mLastOverFrame &&
           nsContentUtils::GetTopLevelWidget(aMouseEvent->widget) !=
           nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
@@ -4288,26 +4288,26 @@ EventStateManager::GenerateDragDropEnter
                                            getter_AddRefs(targetContent));
 
         if (sLastDragOverFrame) {
           //The frame has changed but the content may not have. Check before dispatching to content
           sLastDragOverFrame->GetContentForEvent(aDragEvent,
                                                  getter_AddRefs(lastContent));
 
           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
-                              aDragEvent, NS_DRAGDROP_EXIT_SYNTH,
+                              aDragEvent, NS_DRAGDROP_EXIT,
                               targetContent, lastContent, sLastDragOverFrame);
         }
 
         FireDragEnterOrExit(aPresContext, aDragEvent, NS_DRAGDROP_ENTER,
                             lastContent, targetContent, mCurrentTarget);
 
         if (sLastDragOverFrame) {
           FireDragEnterOrExit(sLastDragOverFrame->PresContext(),
-                              aDragEvent, NS_DRAGDROP_LEAVE_SYNTH,
+                              aDragEvent, NS_DRAGDROP_LEAVE,
                               targetContent, lastContent, sLastDragOverFrame);
         }
 
         sLastDragOverFrame = mCurrentTarget;
       }
     }
     break;
 
@@ -4316,20 +4316,20 @@ EventStateManager::GenerateDragDropEnter
       //This is actually the window mouse exit event.
       if (sLastDragOverFrame) {
         nsCOMPtr<nsIContent> lastContent;
         sLastDragOverFrame->GetContentForEvent(aDragEvent,
                                                getter_AddRefs(lastContent));
 
         nsRefPtr<nsPresContext> lastDragOverFramePresContext = sLastDragOverFrame->PresContext();
         FireDragEnterOrExit(lastDragOverFramePresContext,
-                            aDragEvent, NS_DRAGDROP_EXIT_SYNTH,
+                            aDragEvent, NS_DRAGDROP_EXIT,
                             nullptr, lastContent, sLastDragOverFrame);
         FireDragEnterOrExit(lastDragOverFramePresContext,
-                            aDragEvent, NS_DRAGDROP_LEAVE_SYNTH,
+                            aDragEvent, NS_DRAGDROP_LEAVE,
                             nullptr, lastContent, sLastDragOverFrame);
 
         sLastDragOverFrame = nullptr;
       }
     }
     break;
   }
 
@@ -4368,17 +4368,17 @@ EventStateManager::FireDragEnterOrExit(n
 
     // adjust the drag hover if the dragenter event was cancelled or this is a drag exit
     if (status == nsEventStatus_eConsumeNoDefault || aMsg == NS_DRAGDROP_EXIT)
       SetContentState((aMsg == NS_DRAGDROP_ENTER) ? aTargetContent : nullptr,
                       NS_EVENT_STATE_DRAGOVER);
 
     // collect any changes to moz cursor settings stored in the event's
     // data transfer.
-    if (aMsg == NS_DRAGDROP_LEAVE_SYNTH || aMsg == NS_DRAGDROP_EXIT_SYNTH ||
+    if (aMsg == NS_DRAGDROP_LEAVE || aMsg == NS_DRAGDROP_EXIT ||
         aMsg == NS_DRAGDROP_ENTER)
       UpdateDragDataTransfer(&event);
   }
 
   // Finally dispatch the event to the frame
   if (aTargetFrame)
     aTargetFrame->HandleEvent(aPresContext, &event, &status);
 }
--- a/dom/html/HTMLButtonElement.cpp
+++ b/dom/html/HTMLButtonElement.cpp
@@ -342,26 +342,26 @@ HTMLButtonElement::PostHandleEvent(Event
           if (aVisitor.mDOMEvent &&
               (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
                mouseEvent->button == WidgetMouseEvent::eRightButton)) {
             aVisitor.mDOMEvent->StopPropagation();
           }
         }
         break;
 
-      case NS_MOUSE_ENTER_SYNTH:
+      case NS_MOUSE_OVER:
         {
           aVisitor.mPresContext->EventStateManager()->
             SetContentState(this, NS_EVENT_STATE_HOVER);
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
         break;
 
         // XXX this doesn't seem to do anything yet
-      case NS_MOUSE_EXIT_SYNTH:
+      case NS_MOUSE_OUT:
         {
           aVisitor.mPresContext->EventStateManager()->
             SetContentState(nullptr, NS_EVENT_STATE_HOVER);
           aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
         }
         break;
 
       default:
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -3365,20 +3365,20 @@ HTMLInputElement::NeedToInitializeEditor
   // mousein/move/out, overflow/underflow, and DOM mutation events.
   if (!IsSingleLineTextControl(false) ||
       aVisitor.mEvent->mClass == eMutationEventClass) {
     return false;
   }
 
   switch (aVisitor.mEvent->message) {
   case NS_MOUSE_MOVE:
-  case NS_MOUSE_ENTER:
-  case NS_MOUSE_EXIT:
-  case NS_MOUSE_ENTER_SYNTH:
-  case NS_MOUSE_EXIT_SYNTH:
+  case NS_MOUSE_ENTER_WIDGET:
+  case NS_MOUSE_EXIT_WIDGET:
+  case NS_MOUSE_OVER:
+  case NS_MOUSE_OUT:
   case NS_SCROLLPORT_UNDERFLOW:
   case NS_SCROLLPORT_OVERFLOW:
     return false;
   default:
     return true;
   }
 }
 
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -1215,26 +1215,26 @@ bool TabParent::SendRealMouseEvent(Widge
     return false;
   }
   event.refPoint += GetChildProcessOffset();
 
   nsCOMPtr<nsIWidget> widget = GetWidget();
   if (widget) {
     // When we mouseenter the tab, the tab's cursor should become the current
     // cursor.  When we mouseexit, we stop.
-    if (event.message == NS_MOUSE_ENTER ||
-        event.message == NS_MOUSE_ENTER_SYNTH) {
+    if (event.message == NS_MOUSE_ENTER_WIDGET ||
+        event.message == NS_MOUSE_OVER) {
       mTabSetsCursor = true;
       if (mCursor != nsCursor(-1)) {
         widget->SetCursor(mCursor);
       }
-      // We don't actually want to forward NS_MOUSE_ENTER messages.
+      // We don't actually want to forward NS_MOUSE_ENTER_WIDGET messages.
       return true;
-    } else if (event.message == NS_MOUSE_EXIT ||
-               event.message == NS_MOUSE_EXIT_SYNTH) {
+    } else if (event.message == NS_MOUSE_EXIT_WIDGET ||
+               event.message == NS_MOUSE_OUT) {
       mTabSetsCursor = false;
     }
   }
 
   if (event.message == NS_MOUSE_MOVE) {
     return SendRealMouseMoveEvent(event);
   }
   return SendRealMouseButtonEvent(event);
--- a/dom/media/MediaRecorder.cpp
+++ b/dom/media/MediaRecorder.cpp
@@ -619,17 +619,20 @@ private:
       NS_WARNING("Failed to dispatch ExtractRunnable at beginning");
     }
   }
   // application should get blob and onstop event
   void DoSessionEndTask(nsresult rv)
   {
     MOZ_ASSERT(NS_IsMainThread());
     if (NS_FAILED(rv)) {
-      mRecorder->NotifyError(rv);
+      nsCOMPtr<nsIRunnable> runnable =
+        NS_NewRunnableMethodWithArg<nsresult>(mRecorder,
+                                              &MediaRecorder::NotifyError, rv);
+      NS_DispatchToMainThread(runnable);
     }
 
     CleanupStreams();
     if (NS_FAILED(NS_DispatchToMainThread(new EncoderErrorNotifierRunnable(this)))) {
       MOZ_ASSERT(false, "NS_DispatchToMainThread EncoderErrorNotifierRunnable failed");
     }
     if (NS_FAILED(NS_DispatchToMainThread(new PushBlobRunnable(this)))) {
       MOZ_ASSERT(false, "NS_DispatchToMainThread PushBlobRunnable failed");
--- a/dom/media/TimeUnits.h
+++ b/dom/media/TimeUnits.h
@@ -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/. */
 
 #ifndef TIME_UNITS_H
 #define TIME_UNITS_H
 
 #include "VideoUtils.h"
+#include "mozilla/CheckedInt.h"
 #include "mozilla/FloatingPoint.h"
 
 namespace mozilla {
 namespace media {
 
 struct Microseconds {
   Microseconds()
     : mValue(0)
@@ -50,13 +51,86 @@ struct Microseconds {
   }
   bool operator <= (const Microseconds& aOther) const {
     return mValue <= aOther.mValue;
   }
 
   int64_t mValue;
 };
 
+class TimeUnit final {
+public:
+  static TimeUnit FromSeconds(double aValue) {
+    MOZ_ASSERT(!IsNaN(aValue));
 
-}
-}
+    double val = aValue * USECS_PER_S;
+    if (val >= double(INT64_MAX)) {
+      return FromMicroseconds(INT64_MAX);
+    } else if (val <= double(INT64_MIN)) {
+      return FromMicroseconds(INT64_MIN);
+    } else {
+      return FromMicroseconds(int64_t(val));
+    }
+  }
+
+  static TimeUnit FromMicroseconds(int64_t aValue) {
+    return TimeUnit(aValue);
+  }
+
+  static TimeUnit FromMicroseconds(Microseconds aValue) {
+    return TimeUnit(aValue.mValue);
+  }
+
+  int64_t ToMicroseconds() const {
+    return mValue.value();
+  }
+
+  double ToSeconds() const {
+    return double(mValue.value()) / USECS_PER_S;
+  }
+
+  bool operator >= (const TimeUnit& aOther) const {
+    MOZ_ASSERT(IsValid() && aOther.IsValid());
+    return mValue.value() >= aOther.mValue.value();
+  }
+  bool operator > (const TimeUnit& aOther) const {
+    return !(*this <= aOther);
+  }
+  bool operator <= (const TimeUnit& aOther) const {
+    MOZ_ASSERT(IsValid() && aOther.IsValid());
+    return mValue.value() <= aOther.mValue.value();
+  }
+  bool operator < (const TimeUnit& aOther) const {
+    return !(*this >= aOther);
+  }
+  TimeUnit operator + (const TimeUnit& aOther) const {
+    return TimeUnit(mValue + aOther.mValue);
+  }
+  TimeUnit operator - (const TimeUnit& aOther) const {
+    return TimeUnit(mValue - aOther.mValue);
+  }
+
+  bool IsValid() const
+  {
+    return mValue.isValid();
+  }
+
+  explicit TimeUnit(const Microseconds& aMicroseconds)
+    : mValue(aMicroseconds.mValue)
+  {}
+
+  TimeUnit(const TimeUnit&) = default;
+
+  TimeUnit& operator = (const TimeUnit&) = default;
+
+private:
+  explicit TimeUnit(CheckedInt64 aMicroseconds)
+    : mValue(aMicroseconds)
+  {}
+
+  // Our internal representation is in microseconds.
+  CheckedInt64 mValue;
+};
+
+} // namespace media
+} // namespace mozilla
 
 #endif // TIME_UNITS_H
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -68,17 +68,17 @@ TrackTypeToStr(TrackInfo::TrackType aTra
   case TrackInfo::kVideoTrack:
     return "Video";
   default:
     return "Unknown";
   }
 }
 #endif
 
-uint8_t sTestExtraData[40] = { 0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03,
+uint8_t sTestExtraData[40] = { 0x01, 0x64, 0x00, 0x0a, 0xff, 0xe1, 0x00, 0x17, 0x67, 0x64, 0x00, 0x0a, 0xac, 0xd9, 0x44, 0x26, 0x84, 0x00, 0x00, 0x03,
                                0x00, 0x04, 0x00, 0x00, 0x03, 0x00, 0xc8, 0x3c, 0x48, 0x96, 0x58, 0x01, 0x00, 0x06, 0x68, 0xeb, 0xe3, 0xcb, 0x22, 0xc0 };
 
 /* static */ bool
 MP4Reader::IsVideoAccelerated(LayersBackend aBackend)
 {
   VideoInfo config;
   config.mMimeType = "video/avc";
   config.mId = 1;
@@ -328,20 +328,16 @@ public:
   }
 private:
   nsRefPtr<AbstractMediaDecoder> mDecoder;
   nsTArray<uint8_t> mInitData;
   nsString mInitDataType;
 };
 #endif // MOZ_EME
 
-bool MP4Reader::IsWaitingMediaResources() {
-  return mVideo.mDecoder && mVideo.mDecoder->IsWaitingMediaResources();
-}
-
 bool MP4Reader::IsWaitingOnCDMResource() {
 #ifdef MOZ_EME
   nsRefPtr<CDMProxy> proxy;
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     if (!mIsEncrypted) {
       // Not encrypted, no need to wait for CDMProxy.
       return false;
@@ -373,16 +369,17 @@ MP4Reader::ExtractCryptoInitData(nsTArra
   }
 }
 
 bool
 MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType)
 {
   return (aMimeType.EqualsLiteral("audio/mpeg") ||
           aMimeType.EqualsLiteral("audio/mp4a-latm") ||
+          aMimeType.EqualsLiteral("audio/amr-wb") ||
           aMimeType.EqualsLiteral("audio/3gpp")) &&
          mPlatform->SupportsMimeType(aMimeType);
 }
 
 bool
 MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
 {
   return (aMimeType.EqualsLiteral("video/mp4") ||
@@ -429,16 +426,18 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
 
     // Remember that we've initialized the demuxer, so that if we're decoding
     // an encrypted stream and we need to wait for a CDM to be set, we don't
     // need to reinit the demuxer.
     mDemuxerInitialized = true;
   } else if (mPlatform && !IsWaitingMediaResources()) {
     *aInfo = mInfo;
     *aTags = nullptr;
+    NS_ENSURE_TRUE(EnsureDecodersSetup(), NS_ERROR_FAILURE);
+    return NS_OK;
   }
 
   if (HasAudio()) {
     mInfo.mAudio = mDemuxer->AudioConfig();
     mAudio.mCallback = new DecoderCallback(this, TrackInfo::kAudioTrack);
   }
 
   if (HasVideo()) {
@@ -487,90 +486,72 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo
   }
 
   MonitorAutoLock mon(mDemuxerMonitor);
   UpdateIndex();
 
   return NS_OK;
 }
 
-bool MP4Reader::CheckIfDecoderSetup()
-{
-  if (!mDemuxerInitialized) {
-    return false;
-  }
-
-  if (HasAudio() && !mAudio.mDecoder) {
-    return false;
-  }
-
-  if (HasVideo() && !mVideo.mDecoder) {
-    return false;
-  }
-
-  return true;
-}
-
 bool
 MP4Reader::EnsureDecodersSetup()
 {
-  if (CheckIfDecoderSetup()) {
-    return true;
-  }
-
-  if (mIsEncrypted) {
-#ifdef MOZ_EME
-    // We have encrypted audio or video. We'll need a CDM to decrypt and
-    // possibly decode this. Wait until we've received a CDM from the
-    // JavaScript player app. Note: we still go through the motions here
-    // even if EME is disabled, so that if script tries and fails to create
-    // a CDM, we can detect that and notify chrome and show some UI explaining
-    // that we failed due to EME being disabled.
-    nsRefPtr<CDMProxy> proxy;
-    if (IsWaitingMediaResources()) {
-      return true;
-    }
-    MOZ_ASSERT(!IsWaitingMediaResources());
+  MOZ_ASSERT(mDemuxerInitialized);
 
-    {
-      ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
-      proxy = mDecoder->GetCDMProxy();
-    }
-    MOZ_ASSERT(proxy);
+  if (!mPlatform) {
+    if (mIsEncrypted) {
+#ifdef MOZ_EME
+      // We have encrypted audio or video. We'll need a CDM to decrypt and
+      // possibly decode this. Wait until we've received a CDM from the
+      // JavaScript player app. Note: we still go through the motions here
+      // even if EME is disabled, so that if script tries and fails to create
+      // a CDM, we can detect that and notify chrome and show some UI
+      // explaining that we failed due to EME being disabled.
+      nsRefPtr<CDMProxy> proxy;
+      if (IsWaitingMediaResources()) {
+        return true;
+      }
+      MOZ_ASSERT(!IsWaitingMediaResources());
 
-    mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
-                                                        HasAudio(),
-                                                        HasVideo());
-    NS_ENSURE_TRUE(mPlatform, false);
+      {
+        ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+        proxy = mDecoder->GetCDMProxy();
+      }
+      MOZ_ASSERT(proxy);
+
+      mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
+                                                          HasAudio(),
+                                                          HasVideo());
+      NS_ENSURE_TRUE(mPlatform, false);
 #else
-    // EME not supported.
-    return false;
+      // EME not supported.
+      return false;
 #endif
-  } else {
-    // mPlatform doesn't need to be recreated when resuming from dormant.
-    if (!mPlatform) {
+    } else {
       mPlatform = PlatformDecoderModule::Create();
       NS_ENSURE_TRUE(mPlatform, false);
     }
   }
 
-  if (HasAudio()) {
+  MOZ_ASSERT(mPlatform);
+
+  if (HasAudio() && !mAudio.mDecoder) {
     NS_ENSURE_TRUE(IsSupportedAudioMimeType(mDemuxer->AudioConfig().mMimeType),
                    false);
 
     mAudio.mDecoder =
       mPlatform->CreateDecoder(mDemuxer->AudioConfig(),
                                mAudio.mTaskQueue,
                                mAudio.mCallback);
     NS_ENSURE_TRUE(mAudio.mDecoder != nullptr, false);
     nsresult rv = mAudio.mDecoder->Init();
     NS_ENSURE_SUCCESS(rv, false);
   }
 
-  if (HasVideo()) {
+  if (HasVideo() && !mVideo.mDecoder) {
     NS_ENSURE_TRUE(IsSupportedVideoMimeType(mDemuxer->VideoConfig().mMimeType),
                    false);
 
     if (mSharedDecoderManager &&
         mPlatform->SupportsSharedDecoders(mDemuxer->VideoConfig())) {
       mVideo.mDecoder =
         mSharedDecoderManager->CreateVideoDecoder(mPlatform,
                                                   mDemuxer->VideoConfig(),
@@ -586,16 +567,18 @@ MP4Reader::EnsureDecodersSetup()
                                  mLayersBackendType,
                                  mDecoder->GetImageContainer());
     }
     NS_ENSURE_TRUE(mVideo.mDecoder != nullptr, false);
     nsresult rv = mVideo.mDecoder->Init();
     NS_ENSURE_SUCCESS(rv, false);
   }
 
+  NotifyResourcesStatusChanged();
+
   return true;
 }
 
 void
 MP4Reader::ReadUpdatedMetadata(MediaInfo* aInfo)
 {
   *aInfo = mInfo;
 }
--- a/dom/media/fmp4/MP4Reader.h
+++ b/dom/media/fmp4/MP4Reader.h
@@ -67,17 +67,16 @@ public:
 
   virtual int64_t GetEvictionOffset(double aTime) override;
   virtual void NotifyDataArrived(const char* aBuffer, uint32_t aLength, int64_t aOffset) override;
 
   virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) override;
 
   // For Media Resource Management
   virtual void SetIdle() override;
-  virtual bool IsWaitingMediaResources() override;
   virtual bool IsDormantNeeded() override;
   virtual void ReleaseMediaResources() override;
   virtual void SetSharedDecoderManager(SharedDecoderManager* aManager)
     override;
 
   virtual nsresult ResetDecode() override;
 
   virtual nsRefPtr<ShutdownPromise> Shutdown() override;
@@ -92,18 +91,16 @@ public:
 
 private:
 
   bool InitDemuxer();
   void ReturnOutput(MediaData* aData, TrackType aTrack);
 
   bool EnsureDecodersSetup();
 
-  bool CheckIfDecoderSetup();
-
   // Sends input to decoder for aTrack, and output to the state machine,
   // if necessary.
   void Update(TrackType aTrack);
 
   // Enqueues a task to call Update(aTrack) on the decoder task queue.
   // Lock for corresponding track must be held.
   void ScheduleUpdate(TrackType aTrack);
 
--- a/dom/media/fmp4/PlatformDecoderModule.h
+++ b/dom/media/fmp4/PlatformDecoderModule.h
@@ -240,20 +240,16 @@ public:
   // decoder. The platform decoder should clean up any resources it's using
   // and release memory etc. Shutdown() must block until the decoder has
   // completed shutdown. The reader calls Flush() before calling Shutdown().
   // The reader will delete the decoder once Shutdown() returns.
   // The MediaDataDecoderCallback *must* not be called after Shutdown() has
   // returned.
   virtual nsresult Shutdown() = 0;
 
-  // For Codec Resource Management
-  virtual bool IsWaitingMediaResources() {
-    return false;
-  };
   virtual bool IsHardwareAccelerated() const { return false; }
 
   // ConfigurationChanged will be called to inform the video or audio decoder
   // that the format of the next input sample is about to change.
   // If video decoder, aConfig will be a VideoInfo object.
   // If audio decoder, aConfig will be a AudioInfo object.
   virtual nsresult ConfigurationChanged(const TrackInfo& aConfig)
   {
--- a/dom/media/fmp4/SharedDecoderManager.cpp
+++ b/dom/media/fmp4/SharedDecoderManager.cpp
@@ -235,20 +235,14 @@ SharedDecoderProxy::Drain()
 nsresult
 SharedDecoderProxy::Shutdown()
 {
   mManager->SetIdle(this);
   return NS_OK;
 }
 
 bool
-SharedDecoderProxy::IsWaitingMediaResources()
-{
-  return mManager->mDecoder->IsWaitingMediaResources();
-}
-
-bool
 SharedDecoderProxy::IsHardwareAccelerated() const
 {
   return mManager->mDecoder->IsHardwareAccelerated();
 }
 
 }
--- a/dom/media/fmp4/SharedDecoderManager.h
+++ b/dom/media/fmp4/SharedDecoderManager.h
@@ -68,17 +68,16 @@ public:
                      MediaDataDecoderCallback* aCallback);
   virtual ~SharedDecoderProxy();
 
   virtual nsresult Init() override;
   virtual nsresult Input(MediaRawData* aSample) override;
   virtual nsresult Flush() override;
   virtual nsresult Drain() override;
   virtual nsresult Shutdown() override;
-  virtual bool IsWaitingMediaResources() override;
   virtual bool IsHardwareAccelerated() const override;
 
   friend class SharedDecoderManager;
 
 private:
   nsRefPtr<SharedDecoderManager> mManager;
   MediaDataDecoderCallback* mCallback;
 };
--- a/dom/media/fmp4/gonk/GonkDecoderModule.cpp
+++ b/dom/media/fmp4/gonk/GonkDecoderModule.cpp
@@ -61,13 +61,14 @@ GonkDecoderModule::DecoderNeedsConversio
   }
 }
 
 bool
 GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
     aMimeType.EqualsLiteral("audio/3gpp") ||
+    aMimeType.EqualsLiteral("audio/amr-wb") ||
     aMimeType.EqualsLiteral("video/mp4") ||
     aMimeType.EqualsLiteral("video/mp4v-es") ||
     aMimeType.EqualsLiteral("video/avc");
 }
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.cpp
@@ -21,104 +21,64 @@ PRLogModuleInfo* GetDemuxerLog();
 #define LOG(...)
 #endif
 
 using namespace android;
 
 namespace mozilla {
 
 GonkDecoderManager::GonkDecoderManager(MediaTaskQueue* aTaskQueue)
-  : mTaskQueue(aTaskQueue)
+  : mMonitor("GonkDecoderManager")
 {
 }
 
 nsresult
 GonkDecoderManager::Input(MediaRawData* aSample)
 {
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  // To maintain the order of the MP4Sample, it needs to send the queued samples
-  // to OMX first. And then the current input aSample.
-  // If it fails to input sample to OMX, it needs to add current into queue
-  // for next round.
-  uint32_t len = mQueueSample.Length();
-  status_t rv = OK;
-
-  for (uint32_t i = 0; i < len; i++) {
-    rv = SendSampleToOMX(mQueueSample.ElementAt(0));
-    if (rv != OK) {
-      break;
-    }
-    mQueueSample.RemoveElementAt(0);
-  }
-
-  // When EOS, aSample will be null and sends this empty MediaRawData to nofity
-  // OMX it reachs EOS.
+  ReentrantMonitorAutoEnter mon(mMonitor);
   nsRefPtr<MediaRawData> sample;
+
   if (!aSample) {
+    // It means EOS with empty sample.
     sample = new MediaRawData();
-  }
-
-  // If rv is OK, that means mQueueSample is empty, now try to queue current input
-  // aSample.
-  if (rv == OK) {
-    MOZ_ASSERT(!mQueueSample.Length());
-    MediaRawData* tmp;
-    if (aSample) {
-      tmp = aSample;
-      if (!PerformFormatSpecificProcess(aSample)) {
-        return NS_ERROR_FAILURE;
-      }
-    } else {
-      tmp = sample;
-    }
-    rv = SendSampleToOMX(tmp);
-    if (rv == OK) {
-      return NS_OK;
+  } else {
+    sample = aSample;
+    if (!PerformFormatSpecificProcess(sample)) {
+      return NS_ERROR_FAILURE;
     }
   }
 
-  // Current valid sample can't be sent into OMX, adding the clone one into queue
-  // for next round.
-  if (!sample) {
-      sample = aSample->Clone();
-      if (!sample) {
-        return NS_ERROR_OUT_OF_MEMORY;
-      }
-  }
   mQueueSample.AppendElement(sample);
 
-  // In most cases, EAGAIN or ETIMEOUT safe due to OMX can't process the
-  // filled buffer on time. It should be gone When requeuing sample next time.
-  if (rv == -EAGAIN || rv == -ETIMEDOUT) {
-    return NS_OK;
+  status_t rv;
+  while (mQueueSample.Length()) {
+    nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
+    {
+      ReentrantMonitorAutoExit mon_exit(mMonitor);
+      rv = SendSampleToOMX(data);
+    }
+    if (rv == OK) {
+      mQueueSample.RemoveElementAt(0);
+    } else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
+      // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
+      // buffer on time.
+      return NS_OK;
+    } else {
+      return NS_ERROR_UNEXPECTED;
+    }
   }
 
-  return NS_ERROR_UNEXPECTED;
+  return NS_OK;
 }
 
 nsresult
 GonkDecoderManager::Flush()
 {
-  class ClearQueueRunnable : public nsRunnable
-  {
-  public:
-    explicit ClearQueueRunnable(GonkDecoderManager* aManager)
-      : mManager(aManager) {}
-
-    NS_IMETHOD Run()
-    {
-      mManager->ClearQueuedSample();
-      return NS_OK;
-    }
-
-    GonkDecoderManager* mManager;
-  };
-
-  mTaskQueue->SyncDispatch(new ClearQueueRunnable(this));
+  ReentrantMonitorAutoEnter mon(mMonitor);
+  mQueueSample.Clear();
   return NS_OK;
 }
 
 GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
                                            FlushableMediaTaskQueue* aTaskQueue,
                                            MediaDataDecoderCallback* aCallback)
   : mTaskQueue(aTaskQueue)
   , mCallback(aCallback)
@@ -257,17 +217,9 @@ GonkMediaDataDecoder::ProcessDrain()
 
 nsresult
 GonkMediaDataDecoder::Drain()
 {
   mTaskQueue->Dispatch(NS_NewRunnableMethod(this, &GonkMediaDataDecoder::ProcessDrain));
   return NS_OK;
 }
 
-bool
-GonkMediaDataDecoder::IsWaitingMediaResources() {
-  if (!mDecoder.get()) {
-    return true;
-  }
-  return false;
-}
-
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -39,42 +39,38 @@ public:
   virtual nsresult Output(int64_t aStreamOffset,
                           nsRefPtr<MediaData>& aOutput) = 0;
 
   // Flush the queued sample.
   // It this function is overrided by subclass, this functino should be called
   // in the overrided function.
   virtual nsresult Flush();
 
-  // It should be called in MediaTash thread.
+  // It should be called in MediaTask thread.
   bool HasQueuedSample() {
-    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
+    ReentrantMonitorAutoEnter mon(mMonitor);
     return mQueueSample.Length();
   }
 
-  void ClearQueuedSample() {
-    MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-    mQueueSample.Clear();
-  }
-
 protected:
   // It performs special operation to MP4 sample, the real action is depended on
   // the codec type.
   virtual bool PerformFormatSpecificProcess(MediaRawData* aSample) { return true; }
 
   // It sends MP4Sample to OMX layer. It must be overrided by subclass.
   virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0;
 
+  // This monitor protects mQueueSample.
+  ReentrantMonitor mMonitor;
+
   // An queue with the MP4 samples which are waiting to be sent into OMX.
   // If an element is an empty MP4Sample, that menas EOS. There should not
   // any sample be queued after EOS.
   nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
 
-  RefPtr<MediaTaskQueue> mTaskQueue;
-
   nsRefPtr<MediaByteBuffer> mCodecSpecificData;
 
   nsAutoCString mMimeType;
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
@@ -93,18 +89,16 @@ public:
   virtual nsresult Input(MediaRawData* aSample);
 
   virtual nsresult Flush() override;
 
   virtual nsresult Drain() override;
 
   virtual nsresult Shutdown() override;
 
-  virtual bool IsWaitingMediaResources() override;
-
 private:
 
   // Called on the task queue. Inserts the sample into the decoder, and
   // extracts output if available, if aSample is null, it means there is
   // no data from source, it will notify the decoder EOS and flush all the
   // decoded frames.
   void ProcessDecode(MediaRawData* aSample);
 
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -45,16 +45,17 @@ namespace mozilla {
 
 GonkVideoDecoderManager::GonkVideoDecoderManager(
   MediaTaskQueue* aTaskQueue,
   mozilla::layers::ImageContainer* aImageContainer,
   const VideoInfo& aConfig)
   : GonkDecoderManager(aTaskQueue)
   , mImageContainer(aImageContainer)
   , mReaderCallback(nullptr)
+  , mLastDecodedTime(0)
   , mColorConverterBufferSize(0)
   , mNativeWindow(nullptr)
   , mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
 {
   MOZ_COUNT_CTOR(GonkVideoDecoderManager);
   mMimeType = aConfig.mMimeType;
   mVideoWidth  = aConfig.mDisplay.width;
   mVideoHeight = aConfig.mDisplay.height;
@@ -108,66 +109,19 @@ GonkVideoDecoderManager::Init(MediaDataD
   mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener);
   mDecoder->AskMediaCodecAndWait();
   uint32_t capability = MediaCodecProxy::kEmptyCapability;
   if (mDecoder->getCapability(&capability) == OK && (capability &
       MediaCodecProxy::kCanExposeGraphicBuffer)) {
     mNativeWindow = new GonkNativeWindow();
   }
 
-  mReaderCallback->NotifyResourcesStatusChanged();
-
   return mDecoder;
 }
 
-void
-GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  FrameTimeInfo timeInfo = {aPTS, aDuration};
-  mFrameTimeInfo.AppendElement(timeInfo);
-}
-
-nsresult
-GonkVideoDecoderManager::QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration)
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-
-  // Set default to 1 here.
-  // During seeking, frames could still in MediaCodec and the mFrameTimeInfo could
-  // be cleared before these frames are out from MediaCodec. This is ok because
-  // these frames are old frame before seeking.
-  aDuration = 1;
-  for (uint32_t i = 0; i < mFrameTimeInfo.Length(); i++) {
-    const FrameTimeInfo& entry = mFrameTimeInfo.ElementAt(i);
-    if (i == 0) {
-      if (entry.pts > aPTS) {
-        // Codec sent a frame with rollbacked PTS time. It could
-        // be codec's problem.
-        ReleaseVideoBuffer();
-        return NS_ERROR_NOT_AVAILABLE;
-      }
-    }
-
-    // Ideally, the first entry in mFrameTimeInfo should be the one we are looking
-    // for. However, MediaCodec could dropped frame and the first entry doesn't
-    // match current decoded frame's PTS.
-    if (entry.pts == aPTS) {
-      aDuration = entry.duration;
-      if (i > 0) {
-        LOG("Frame could be dropped by MediaCodec, %d dropped frames.", i);
-      }
-      mFrameTimeInfo.RemoveElementsAt(0, i+1);
-      break;
-    }
-  }
-  return NS_OK;
-}
-
 nsresult
 GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
 {
   *v = nullptr;
   nsRefPtr<VideoData> data;
   int64_t timeUs;
   int32_t keyFrame;
 
@@ -176,19 +130,22 @@ GonkVideoDecoderManager::CreateVideoData
     return NS_ERROR_UNEXPECTED;
   }
 
   if (!mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) {
     GVDM_LOG("Decoder did not return frame time");
     return NS_ERROR_UNEXPECTED;
   }
 
-  int64_t duration;
-  nsresult rv = QueueFrameTimeOut(timeUs, duration);
-  NS_ENSURE_SUCCESS(rv, rv);
+  if (mLastDecodedTime > timeUs) {
+    ReleaseVideoBuffer();
+    GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+  mLastDecodedTime = timeUs;
 
   if (mVideoBuffer->range_length() == 0) {
     // Some decoders may return spurious empty buffers that we just want to ignore
     // quoted from Android's AwesomePlayer.cpp
     ReleaseVideoBuffer();
     return NS_ERROR_NOT_AVAILABLE;
   }
 
@@ -219,17 +176,18 @@ GonkVideoDecoderManager::CreateVideoData
     GrallocTextureClientOGL* grallocClient = static_cast<GrallocTextureClientOGL*>(textureClient.get());
     grallocClient->SetMediaBuffer(mVideoBuffer);
     textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this);
 
     data = VideoData::Create(mInfo.mVideo,
                              mImageContainer,
                              aStreamOffset,
                              timeUs,
-                             duration,
+                             1, // No way to pass sample duration from muxer to
+                                // OMX codec, so we hardcode the duration here.
                              textureClient,
                              keyFrame,
                              -1,
                              picture);
   } else {
     if (!mVideoBuffer->data()) {
       GVDM_LOG("No data in Video Buffer!");
       return NS_ERROR_UNEXPECTED;
@@ -433,57 +391,27 @@ void GonkVideoDecoderManager::ReleaseVid
     mDecoder->ReleaseMediaBuffer(mVideoBuffer);
     mVideoBuffer = nullptr;
   }
 }
 
 status_t
 GonkVideoDecoderManager::SendSampleToOMX(MediaRawData* aSample)
 {
-  // An empty MediaRawData is going to notify EOS to decoder. It doesn't need
-  // to keep PTS and duration.
-  if (aSample->mData && aSample->mDuration && aSample->mTime) {
-    QueueFrameTimeIn(aSample->mTime, aSample->mDuration);
-  }
-
   return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData),
                          aSample->mSize,
                          aSample->mTime,
                          0);
 }
 
-void
-GonkVideoDecoderManager::ClearQueueFrameTime()
-{
-  MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
-  mFrameTimeInfo.Clear();
-}
-
 nsresult
 GonkVideoDecoderManager::Flush()
 {
   GonkDecoderManager::Flush();
-
-  class ClearFrameTimeRunnable : public nsRunnable
-  {
-  public:
-    explicit ClearFrameTimeRunnable(GonkVideoDecoderManager* aManager)
-      : mManager(aManager) {}
-
-    NS_IMETHOD Run()
-    {
-      mManager->ClearQueueFrameTime();
-      return NS_OK;
-    }
-
-    GonkVideoDecoderManager* mManager;
-  };
-
-  mTaskQueue->SyncDispatch(new ClearFrameTimeRunnable(this));
-
+  mLastDecodedTime = 0;
   status_t err = mDecoder->flush();
   if (err != OK) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
 void
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -103,43 +103,30 @@ private:
     VideoResourceListener() = delete;
     VideoResourceListener(const VideoResourceListener &rhs) = delete;
     const VideoResourceListener &operator=(const VideoResourceListener &rhs) = delete;
 
     GonkVideoDecoderManager *mManager;
   };
   friend class VideoResourceListener;
 
-  // FrameTimeInfo keeps the presentation time stamp (pts) and its duration.
-  // On MediaDecoderStateMachine, it needs pts and duration to display decoded
-  // frame correctly. But OMX can carry one field of time info (kKeyTime) so
-  // we use FrameTimeInfo to keep pts and duration.
-  struct FrameTimeInfo {
-    int64_t pts;       // presentation time stamp of this frame.
-    int64_t duration;  // the playback duration.
-  };
-
   bool SetVideoFormat();
 
   nsresult CreateVideoData(int64_t aStreamOffset, VideoData** aOutData);
   void ReleaseVideoBuffer();
   uint8_t* GetColorConverterBuffer(int32_t aWidth, int32_t aHeight);
 
   // For codec resource management
   void codecReserved();
   void codecCanceled();
   void onMessageReceived(const sp<AMessage> &aMessage);
 
   void ReleaseAllPendingVideoBuffers();
   void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer);
 
-  void QueueFrameTimeIn(int64_t aPTS, int64_t aDuration);
-  nsresult QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration);
-  void ClearQueueFrameTime();
-
   uint32_t mVideoWidth;
   uint32_t mVideoHeight;
   uint32_t mDisplayWidth;
   uint32_t mDisplayHeight;
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
 
   android::sp<MediaCodecProxy> mDecoder;
@@ -150,21 +137,17 @@ private:
   MediaDataDecoderCallback*  mReaderCallback;
   MediaInfo mInfo;
   android::sp<VideoResourceListener> mVideoListener;
   android::sp<MessageHandler> mHandler;
   android::sp<ALooper> mLooper;
   android::sp<ALooper> mManagerLooper;
   FrameInfo mFrameInfo;
 
-  // Array of FrameTimeInfo whose corresponding frames are sent to OMX.
-  // Ideally, it is a FIFO. Input() adds the entry to the end element and
-  // CreateVideoData() takes the first entry. However, there are exceptions
-  // due to MediaCodec error or seeking.
-  nsTArray<FrameTimeInfo> mFrameTimeInfo;
+  int64_t mLastDecodedTime;  // The last decoded frame presentation time.
 
   // color converter
   android::I420ColorConverterHelper mColorConverter;
   nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
   size_t mColorConverterBufferSize;
 
   android::sp<android::GonkNativeWindow> mNativeWindow;
   enum {
--- a/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
+++ b/dom/media/fmp4/wmf/WMFMediaDataDecoder.h
@@ -64,17 +64,16 @@ public:
   virtual nsresult Input(MediaRawData* aSample);
 
   virtual nsresult Flush() override;
 
   virtual nsresult Drain() override;
 
   virtual nsresult Shutdown() override;
 
-  virtual bool IsWaitingMediaResources() { return false; };
   virtual bool IsHardwareAccelerated() const override;
 
 private:
 
   void Decode();
   void EnsureDecodeTaskDispatched();
   void PurgeInputQueue();
 
--- a/dom/media/fmp4/wrappers/H264Converter.cpp
+++ b/dom/media/fmp4/wrappers/H264Converter.cpp
@@ -104,25 +104,16 @@ H264Converter::Shutdown()
     nsresult rv = mDecoder->Shutdown();
     mDecoder = nullptr;
     return rv;
   }
   return NS_OK;
 }
 
 bool
-H264Converter::IsWaitingMediaResources()
-{
-  if (mDecoder) {
-    return mDecoder->IsWaitingMediaResources();
-  }
-  return MediaDataDecoder::IsWaitingMediaResources();
-}
-
-bool
 H264Converter::IsHardwareAccelerated() const
 {
   if (mDecoder) {
     return mDecoder->IsHardwareAccelerated();
   }
   return MediaDataDecoder::IsHardwareAccelerated();
 }
 
--- a/dom/media/fmp4/wrappers/H264Converter.h
+++ b/dom/media/fmp4/wrappers/H264Converter.h
@@ -29,17 +29,16 @@ public:
                 MediaDataDecoderCallback* aCallback);
   virtual ~H264Converter();
 
   virtual nsresult Init() override;
   virtual nsresult Input(MediaRawData* aSample) override;
   virtual nsresult Flush() override;
   virtual nsresult Drain() override;
   virtual nsresult Shutdown() override;
-  virtual bool IsWaitingMediaResources() override;
   virtual bool IsHardwareAccelerated() const override;
 
   // Return true if mimetype is H.264.
   static bool IsH264(const TrackInfo& aConfig);
 
 private:
   // Will create the required MediaDataDecoder if need AVCC and we have a SPS NAL.
   // Returns NS_ERROR_FAILURE if error is permanent and can't be recovered and
--- a/dom/media/test/test_mediarecorder_getencodeddata.html
+++ b/dom/media/test/test_mediarecorder_getencodeddata.html
@@ -53,16 +53,15 @@ SpecialPowers.pushPrefEnv({"set": [["med
            'Event name is GenericError');
         onErrorFired = true;
       }
       mediaRecorder.start(0);
       is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
       is(mediaRecorder.stream, stream,
          'Media recorder stream = element stream at the start of recording');
       mediaRecorder.requestData();
-      mediaRecorder.stop();
     }, 100);
   }
 );
 </script>
 </pre>
 </body>
 </html>
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1754,19 +1754,19 @@ static NPCocoaEventType
 CocoaEventTypeForEvent(const WidgetGUIEvent& anEvent, nsIFrame* aObjectFrame)
 {
   const NPCocoaEvent* event = static_cast<const NPCocoaEvent*>(anEvent.mPluginEvent);
   if (event) {
     return event->type;
   }
 
   switch (anEvent.message) {
-    case NS_MOUSE_ENTER_SYNTH:
+    case NS_MOUSE_OVER:
       return NPCocoaEventMouseEntered;
-    case NS_MOUSE_EXIT_SYNTH:
+    case NS_MOUSE_OUT:
       return NPCocoaEventMouseExited;
     case NS_MOUSE_MOVE:
     {
       // We don't know via information on events from the widget code whether or not
       // we're dragging. The widget code just generates mouse move events from native
       // drag events. If anybody is capturing, this is a drag event.
       if (nsIPresShell::GetCapturingContent()) {
         return NPCocoaEventMouseDragged;
@@ -1798,18 +1798,18 @@ TranslateToNPCocoaEvent(WidgetGUIEvent* 
   NPCocoaEvent cocoaEvent;
   InitializeNPCocoaEvent(&cocoaEvent);
   cocoaEvent.type = CocoaEventTypeForEvent(*anEvent, aObjectFrame);
 
   if (anEvent->message == NS_MOUSE_MOVE ||
       anEvent->message == NS_MOUSE_BUTTON_DOWN ||
       anEvent->message == NS_MOUSE_BUTTON_UP ||
       anEvent->message == NS_MOUSE_SCROLL ||
-      anEvent->message == NS_MOUSE_ENTER_SYNTH ||
-      anEvent->message == NS_MOUSE_EXIT_SYNTH)
+      anEvent->message == NS_MOUSE_OVER ||
+      anEvent->message == NS_MOUSE_OUT)
   {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(anEvent, aObjectFrame) -
                  aObjectFrame->GetContentRectRelativeToSelf().TopLeft();
     nsPresContext* presContext = aObjectFrame->PresContext();
     // Plugin event coordinates need to be translated from device pixels
     // into "display pixels" in HiDPI modes.
     double scaleFactor = double(nsPresContext::AppUnitsPerCSSPixel())/
       aObjectFrame->PresContext()->DeviceContext()->AppUnitsPerDevPixelAtUnitFullZoom();
@@ -2054,18 +2054,18 @@ nsEventStatus nsPluginInstanceOwner::Pro
     if (pPluginEvent) {
       // Make event coordinates relative to our enclosing widget,
       // not the widget they were received on.
       // See use of NPEvent in widget/windows/nsWindow.cpp
       // for why this assert should be safe
       NS_ASSERTION(anEvent.message == NS_MOUSE_BUTTON_DOWN ||
                    anEvent.message == NS_MOUSE_BUTTON_UP ||
                    anEvent.message == NS_MOUSE_DOUBLECLICK ||
-                   anEvent.message == NS_MOUSE_ENTER_SYNTH ||
-                   anEvent.message == NS_MOUSE_EXIT_SYNTH ||
+                   anEvent.message == NS_MOUSE_OVER ||
+                   anEvent.message == NS_MOUSE_OUT ||
                    anEvent.message == NS_MOUSE_MOVE,
                    "Incorrect event type for coordinate translation");
       nsPoint pt =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(&anEvent, mPluginFrame) -
         mPluginFrame->GetContentRectRelativeToSelf().TopLeft();
       nsPresContext* presContext = mPluginFrame->PresContext();
       nsIntPoint ptPx(presContext->AppUnitsToDevPixels(pt.x),
                       presContext->AppUnitsToDevPixels(pt.y));
@@ -2140,21 +2140,21 @@ nsEventStatus nsPluginInstanceOwner::Pro
 #elif defined(MOZ_WIDGET_QT)
         Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
 #else
         Window root = None; // Could XQueryTree, but this is not important.
 #endif
 
         switch (anEvent.message)
           {
-          case NS_MOUSE_ENTER_SYNTH:
-          case NS_MOUSE_EXIT_SYNTH:
+          case NS_MOUSE_OVER:
+          case NS_MOUSE_OUT:
             {
               XCrossingEvent& event = pluginEvent.xcrossing;
-              event.type = anEvent.message == NS_MOUSE_ENTER_SYNTH ?
+              event.type = anEvent.message == NS_MOUSE_OVER ?
                 EnterNotify : LeaveNotify;
               event.root = root;
               event.time = anEvent.time;
               event.x = pluginPoint.x;
               event.y = pluginPoint.y;
               event.x_root = rootPoint.x;
               event.y_root = rootPoint.y;
               event.state = XInputEventState(mouseEvent);
--- a/dom/workers/test/serviceworkers/importscript.sjs
+++ b/dom/workers/test/serviceworkers/importscript.sjs
@@ -1,9 +1,11 @@
 function handleRequest(request, response) {
-  if (!getState('counter')) {
+  if (request.queryString == 'clearcounter') {
+    setState('counter', '');
+  } else if (!getState('counter')) {
     response.setHeader("Content-Type", "application/javascript", false);
     response.write("callByScript();");
     setState('counter', '1');
   } else {
     response.write("no cache no party!");
   }
 }
--- a/dom/workers/test/serviceworkers/periodic.sjs
+++ b/dom/workers/test/serviceworkers/periodic.sjs
@@ -1,9 +1,13 @@
 function handleRequest(request, response) {
+  if (request.queryString == 'clearcounter') {
+    setState('periodiccounter', '');
+    return;
+  }
   if (!getState('periodiccounter')) {
     setState('periodiccounter', '1');
   } else {
     // Make sure that we pass a string value to setState!
     setState('periodiccounter', "" + (parseInt(getState('periodiccounter')) + 1));
   }
   response.setHeader("Content-Type", "application/javascript", false);
   response.write(getScript());
--- a/dom/workers/test/serviceworkers/periodic/unregister.html
+++ b/dom/workers/test/serviceworkers/periodic/unregister.html
@@ -1,11 +1,13 @@
 <!DOCTYPE html>
 <script>
-  navigator.serviceWorker.getRegistration(".").then(function(registration) {
+  fetch("../periodic.sjs?clearcounter").then(function() {
+    return navigator.serviceWorker.getRegistration(".");
+  }).then(function(registration) {
     registration.unregister().then(function(success) {
       if (success) {
         parent.callback();
       } else {
         dump("Unregister failed\n");
       }
     }, function(e) {
       dump("Unregistering the SW failed with " + e + "\n");
--- a/dom/workers/test/serviceworkers/test_importscript.html
+++ b/dom/workers/test/serviceworkers/test_importscript.html
@@ -14,17 +14,19 @@
 <script class="testbody" type="text/javascript">
   function start() {
     return navigator.serviceWorker.register("importscript_worker.js",
                                             { scope: "./sw_clients/" })
       .then((swr) => registration = swr);
   }
 
   function unregister() {
-    return registration.unregister().then(function(result) {
+    return fetch("importscript.sjs?clearcounter").then(function() {
+      return registration.unregister();
+    }).then(function(result) {
       ok(result, "Unregister should return true.");
     }, function(e) {
       dump("Unregistering the SW failed with " + e + "\n");
     });
   }
 
   function testPostMessage(swr) {
     var p = new Promise(function(res, rej) {
--- a/editor/libeditor/nsEditorEventListener.cpp
+++ b/editor/libeditor/nsEditorEventListener.cpp
@@ -369,22 +369,22 @@ nsEditorEventListener::HandleEvent(nsIDO
   //       you don't need to check if the QI succeeded before each call.
   switch (internalEvent->message) {
     // dragenter
     case NS_DRAGDROP_ENTER: {
       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
       return DragEnter(dragEvent);
     }
     // dragover
-    case NS_DRAGDROP_OVER_SYNTH: {
+    case NS_DRAGDROP_OVER: {
       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
       return DragOver(dragEvent);
     }
     // dragexit
-    case NS_DRAGDROP_EXIT_SYNTH: {
+    case NS_DRAGDROP_EXIT: {
       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
       return DragExit(dragEvent);
     }
     // drop
     case NS_DRAGDROP_DROP: {
       nsCOMPtr<nsIDOMDragEvent> dragEvent = do_QueryInterface(aEvent);
       return Drop(dragEvent);
     }
--- a/gfx/layers/ipc/ShadowLayers.cpp
+++ b/gfx/layers/ipc/ShadowLayers.cpp
@@ -533,16 +533,23 @@ ShadowLayerForwarder::EndTransaction(Inf
 
   AutoTxnEnd _(mTxn);
 
   if (mTxn->Empty() && !mTxn->RotationChanged() && !mWindowOverlayChanged) {
     MOZ_LAYERS_LOG(("[LayersForwarder] 0-length cset (?) and no rotation event, skipping Update()"));
     return true;
   }
 
+  if (!mTxn->mPaints.empty()) {
+    // With some platforms, telling the drawing backend that there will be no more
+    // drawing for this frame helps with preventing command queues from spanning
+    // across multiple frames.
+    gfxPlatform::GetPlatform()->FlushContentDrawing();
+  }
+
   MOZ_LAYERS_LOG(("[LayersForwarder] destroying buffers..."));
 
   MOZ_LAYERS_LOG(("[LayersForwarder] building transaction..."));
 
   // We purposely add attribute-change ops to the final changeset
   // before we add paint ops.  This allows layers to record the
   // attribute changes before new pixels arrive, which can be useful
   // for setting up back/front buffers.
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -625,16 +625,17 @@ public:
      */
     virtual bool SupportsApzWheelInput() const {
       return false;
     }
     virtual bool SupportsApzTouchInput() const {
       return false;
     }
 
+    virtual void FlushContentDrawing() {}
 protected:
     gfxPlatform();
     virtual ~gfxPlatform();
 
     void AppendCJKPrefLangs(eFontPrefLang aPrefLangs[], uint32_t &aLen,
                             eFontPrefLang aCharLang, eFontPrefLang aPageLang);
 
     /**
--- a/gfx/thebes/gfxPlatformGtk.cpp
+++ b/gfx/thebes/gfxPlatformGtk.cpp
@@ -25,16 +25,17 @@
 #include <gtk/gtk.h>
 
 #include "gfxImageSurface.h"
 #ifdef MOZ_X11
 #include <gdk/gdkx.h>
 #include "gfxXlibSurface.h"
 #include "cairo-xlib.h"
 #include "mozilla/Preferences.h"
+#include "mozilla/X11Util.h"
 
 /* Undefine the Status from Xlib since it will conflict with system headers on OSX */
 #if defined(__APPLE__) && defined(Status)
 #undef Status
 #endif
 
 #endif /* MOZ_X11 */
 
@@ -76,16 +77,24 @@ gfxPlatformGtk::gfxPlatformGtk()
 gfxPlatformGtk::~gfxPlatformGtk()
 {
     gfxFontconfigUtils::Shutdown();
     sFontconfigUtils = nullptr;
 
     gfxPangoFontGroup::Shutdown();
 }
 
+void
+gfxPlatformGtk::FlushContentDrawing()
+{
+    if (UseXRender()) {
+        XFlush(DefaultXDisplay());
+    }
+}
+
 already_AddRefed<gfxASurface>
 gfxPlatformGtk::CreateOffscreenSurface(const IntSize& size,
                                        gfxContentType contentType)
 {
     nsRefPtr<gfxASurface> newSurface;
     bool needsClear = true;
     gfxImageFormat imageFormat = OptimalFormatForContent(contentType);
 #ifdef MOZ_X11
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -70,16 +70,21 @@ public:
 
     /**
      * Check whether format is supported on a platform or not (if unclear,
      * returns true).
      */
     virtual bool IsFontFormatSupported(nsIURI *aFontURI,
                                          uint32_t aFormatFlags) override;
 
+    /**
+     * Calls XFlush if xrender is enabled.
+     */
+    virtual void FlushContentDrawing() override;
+
 #if (MOZ_WIDGET_GTK == 2)
     static void SetGdkDrawable(cairo_surface_t *target,
                                GdkDrawable *drawable);
     static GdkDrawable *GetGdkDrawable(cairo_surface_t *target);
 #endif
 
     static int32_t GetDPI();
     static double  GetDPIScale();
--- a/intl/strres/nsStringBundle.cpp
+++ b/intl/strres/nsStringBundle.cpp
@@ -64,16 +64,25 @@ nsStringBundle::LoadProperties()
 
   nsresult rv;
 
   // do it synchronously
   nsCOMPtr<nsIURI> uri;
   rv = NS_NewURI(getter_AddRefs(uri), mPropertiesURL);
   if (NS_FAILED(rv)) return rv;
 
+  // whitelist check for local schemes
+  nsCString scheme;
+  uri->GetScheme(scheme);
+  if (!scheme.EqualsLiteral("chrome") && !scheme.EqualsLiteral("jar") &&
+      !scheme.EqualsLiteral("resource") && !scheme.EqualsLiteral("file") &&
+      !scheme.EqualsLiteral("data")) {
+    return NS_ERROR_ABORT;
+  }
+
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      nsContentUtils::GetSystemPrincipal(),
                      nsILoadInfo::SEC_NORMAL,
                      nsIContentPolicy::TYPE_OTHER);
 
   if (NS_FAILED(rv)) return rv;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/lazyLink-bug1150783.js
@@ -0,0 +1,34 @@
+var path = '';
+
+// trigger off-main-thread compilation
+for (var i = 0; i < 11; i++)
+  path.substr(-1);
+
+// maybe link to the the result of the off-main-thread compilation.
+function load(unsigned) {
+  if (unsigned)
+    path.substr(-1);
+}
+
+(function(global, env) {
+  'use asm';
+  var load = env.load;
+  function _main() {
+    var $l1 = 0, $l2 = 0, $l3 = 0;
+    do {
+      load();
+      $l1 = $l1 + 1 | 0;
+    } while (($l1 | 0) != 10);
+    load(1);
+    load(1);
+    do {
+      load();
+      $l2 = $l2 + 1 | 0;
+    } while (($l2 | 0) != 1024);
+    while (($l3 | 0) < 10000) {
+      load(1);
+      $l3 = $l3 + 1 | 0;
+    }
+  }
+  return _main;
+})({}, { 'load':load })();
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/self-test/getBacktrace-bug1138195.js
@@ -0,0 +1,8 @@
+
+function f(x) {
+    for (var i = 0; i < 40; ++i) {
+	var stack = getBacktrace({args: true});
+	(function() { g = x;});
+    }
+}
+f(1);
--- a/js/src/jit/BytecodeAnalysis.cpp
+++ b/js/src/jit/BytecodeAnalysis.cpp
@@ -40,16 +40,19 @@ struct CatchFinallyRange
 };
 
 bool
 BytecodeAnalysis::init(TempAllocator& alloc, GSNCache& gsn)
 {
     if (!infos_.growByUninitialized(script_->length()))
         return false;
 
+    // We need a scope chain if any of the bindings are aliased.
+    usesScopeChain_ = script_->hasAnyAliasedBindings();
+
     jsbytecode* end = script_->codeEnd();
 
     // Clear all BytecodeInfo.
     mozilla::PodZero(infos_.begin(), infos_.length());
     infos_[0].init(/*stackDepth=*/0);
 
     Vector<CatchFinallyRange, 0, JitAllocPolicy> catchFinallyRanges(alloc);
 
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -431,20 +431,42 @@ FinishAllOffThreadCompilations(JSCompart
         IonBuilder* builder = finished[i];
         if (builder->compartment == CompileCompartment::get(comp)) {
             FinishOffThreadBuilder(nullptr, builder);
             HelperThreadState().remove(finished, &i);
         }
     }
 }
 
+class AutoLazyLinkExitFrame
+{
+    JitActivation* jitActivation_;
+    MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
+
+  public:
+    explicit AutoLazyLinkExitFrame(JitActivation* jitActivation
+                                   MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
+      : jitActivation_(jitActivation)
+    {
+        MOZ_GUARD_OBJECT_NOTIFIER_INIT;
+        MOZ_ASSERT(!jitActivation_->isLazyLinkExitFrame(),
+                   "Cannot stack multiple lazy-link frames.");
+        jitActivation_->setLazyLinkExitFrame(true);
+    }
+
+    ~AutoLazyLinkExitFrame() {
+        jitActivation_->setLazyLinkExitFrame(false);
+    }
+};
+
 uint8_t*
 jit::LazyLinkTopActivation(JSContext* cx)
 {
     JitActivationIterator iter(cx->runtime());
+    AutoLazyLinkExitFrame lazyLinkExitFrame(iter->asJit());
 
     // First frame should be an exit frame.
     JitFrameIterator it(iter);
     LazyLinkExitFrameLayout* ll = it.exitFrame()->as<LazyLinkExitFrameLayout>();
     JSScript* calleeScript = ScriptFromCalleeToken(ll->jsFrame()->calleeToken());
 
     // Get the pending builder from the Ion frame.
     IonBuilder* builder = calleeScript->ionScript()->pendingBuilder();
@@ -2494,21 +2516,22 @@ InvalidateActivation(FreeOp* fop, const 
 #ifdef CHECK_OSIPOINT_REGISTERS
     if (js_JitOptions.checkOsiPointRegisters)
         activations->asJit()->setCheckRegs(false);
 #endif
 
     size_t frameno = 1;
 
     for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
-        MOZ_ASSERT_IF(frameno == 1, it.type() == JitFrame_Exit || it.type() == JitFrame_Bailout);
+        MOZ_ASSERT_IF(frameno == 1, it.isExitFrame() || it.type() == JitFrame_Bailout);
 
 #ifdef DEBUG
         switch (it.type()) {
           case JitFrame_Exit:
+          case JitFrame_LazyLink:
             JitSpew(JitSpew_IonInvalidate, "#%d exit frame @ %p", frameno, it.fp());
             break;
           case JitFrame_BaselineJS:
           case JitFrame_IonJS:
           case JitFrame_Bailout:
           {
             MOZ_ASSERT(it.isScripted());
             const char* type = "Unknown";
--- a/js/src/jit/IonCaches.cpp
+++ b/js/src/jit/IonCaches.cpp
@@ -471,17 +471,18 @@ void
 IonCache::initializeAddCacheState(LInstruction* ins, AddCacheState* addState)
 {
 }
 
 static void*
 GetReturnAddressToIonCode(JSContext* cx)
 {
     JitFrameIterator iter(cx);
-    MOZ_ASSERT(iter.type() == JitFrame_Exit);
+    MOZ_ASSERT(iter.type() == JitFrame_Exit,
+               "An exit frame is expected as update functions are called with a VMFunction.");
 
     void* returnAddr = iter.returnAddress();
 #ifdef DEBUG
     ++iter;
     MOZ_ASSERT(iter.isIonJS());
 #endif
     return returnAddr;
 }
--- a/js/src/jit/JitFrameIterator-inl.h
+++ b/js/src/jit/JitFrameIterator-inl.h
@@ -35,17 +35,17 @@ JitFrameIterator::baselineFrame() const
     MOZ_ASSERT(isBaselineJS());
     return (BaselineFrame*)(fp() - BaselineFrame::FramePointerOffset - BaselineFrame::Size());
 }
 
 template <typename T>
 bool
 JitFrameIterator::isExitFrameLayout() const
 {
-    if (type_ != JitFrame_Exit || isFakeExitFrame())
+    if (!isExitFrame() || isFakeExitFrame())
         return false;
     return exitFrame()->is<T>();
 }
 
 } // namespace jit
 } // namespace js
 
 #endif /* jit_JitFrameIterator_inl_h */
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -60,17 +60,24 @@ enum FrameType
     // From within C++, an exit frame is always the last frame in any
     // JitActivation.
     JitFrame_Exit,
 
     // A bailout frame is a special IonJS jit frame after a bailout, and before
     // the reconstruction of the BaselineJS frame. From within C++, a bailout
     // frame is always the last frame in a JitActivation iff the bailout frame
     // information is recorded on the JitActivation.
-    JitFrame_Bailout
+    JitFrame_Bailout,
+
+    // A lazy link frame is a special exit frame where a IonJS frame is reused
+    // for linking the newly compiled code.  A special frame is needed to
+    // work-around the fact that we can make stack patterns which are similar to
+    // unwound frames. As opposed to unwound frames, we still have to mark all
+    // the arguments of the original IonJS frame.
+    JitFrame_LazyLink
 };
 
 enum ReadFrameArgsBehavior {
     // Only read formals (i.e. [0 ... callee()->nargs]
     ReadFrame_Formals,
 
     // Only read overflown args (i.e. [callee()->nargs ... numActuals()]
     ReadFrame_Overflown,
@@ -137,16 +144,19 @@ class JitFrameIterator
 
     inline ExitFrameLayout* exitFrame() const;
 
     // Returns whether the JS frame has been invalidated and, if so,
     // places the invalidated Ion script in |ionScript|.
     bool checkInvalidation(IonScript** ionScript) const;
     bool checkInvalidation() const;
 
+    bool isExitFrame() const {
+        return type_ == JitFrame_Exit || type_ == JitFrame_LazyLink;
+    }
     bool isScripted() const {
         return type_ == JitFrame_BaselineJS || type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
     }
     bool isBaselineJS() const {
         return type_ == JitFrame_BaselineJS;
     }
     bool isIonScripted() const {
         return type_ == JitFrame_IonJS || type_ == JitFrame_Bailout;
@@ -193,17 +203,17 @@ class JitFrameIterator
     // Previous frame information extracted from the current frame.
     inline size_t prevFrameLocalSize() const;
     inline FrameType prevType() const;
     uint8_t* prevFp() const;
 
     // Returns the stack space used by the current frame, in bytes. This does
     // not include the size of its fixed header.
     size_t frameSize() const {
-        MOZ_ASSERT(type_ != JitFrame_Exit);
+        MOZ_ASSERT(!isExitFrame());
         return frameSize_;
     }
 
     // Functions used to iterate on frames. When prevType is JitFrame_Entry,
     // the current frame is the last frame.
     inline bool done() const {
         return type_ == JitFrame_Entry;
     }
--- a/js/src/jit/JitFrames-inl.h
+++ b/js/src/jit/JitFrames-inl.h
@@ -46,30 +46,32 @@ JitFrameIterator::prevType() const
 {
     CommonFrameLayout* current = (CommonFrameLayout*) current_;
     return current->prevType();
 }
 
 inline bool
 JitFrameIterator::isFakeExitFrame() const
 {
+    if (type() == JitFrame_LazyLink)
+        return false;
     bool res = (prevType() == JitFrame_Unwound_Rectifier ||
                 prevType() == JitFrame_Unwound_IonJS ||
                 prevType() == JitFrame_Unwound_BaselineJS ||
                 prevType() == JitFrame_Unwound_BaselineStub ||
                 prevType() == JitFrame_Unwound_IonAccessorIC ||
                 (prevType() == JitFrame_Entry && type() == JitFrame_Exit));
     MOZ_ASSERT_IF(res, type() == JitFrame_Exit || type() == JitFrame_BaselineJS);
     return res;
 }
 
 inline ExitFrameLayout*
 JitFrameIterator::exitFrame() const
 {
-    MOZ_ASSERT(type() == JitFrame_Exit);
+    MOZ_ASSERT(isExitFrame());
     MOZ_ASSERT(!isFakeExitFrame());
     return (ExitFrameLayout*) fp();
 }
 
 inline BaselineFrame*
 GetTopBaselineFrame(JSContext* cx)
 {
     JitFrameIterator iter(cx);
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -112,31 +112,37 @@ JitFrameIterator::JitFrameIterator(JSCon
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
     activation_(cx->runtime()->activation()->asJit())
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
         frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
+    } else if (activation_->isLazyLinkExitFrame()) {
+        type_ = JitFrame_LazyLink;
+        MOZ_ASSERT(isExitFrameLayout<LazyLinkExitFrameLayout>());
     }
 }
 
 JitFrameIterator::JitFrameIterator(const ActivationIterator& activations)
   : current_(activations.jitTop()),
     type_(JitFrame_Exit),
     returnAddressToFp_(nullptr),
     frameSize_(0),
     cachedSafepointIndex_(nullptr),
     activation_(activations->asJit())
 {
     if (activation_->bailoutData()) {
         current_ = activation_->bailoutData()->fp();
         frameSize_ = activation_->bailoutData()->topFrameSize();
         type_ = JitFrame_Bailout;
+    } else if (activation_->isLazyLinkExitFrame()) {
+        type_ = JitFrame_LazyLink;
+        MOZ_ASSERT(isExitFrameLayout<LazyLinkExitFrameLayout>());
     }
 }
 
 bool
 JitFrameIterator::checkInvalidation() const
 {
     IonScript* dummy;
     return checkInvalidation(&dummy);
@@ -259,16 +265,17 @@ SizeOfFramePrefix(FrameType type)
       case JitFrame_BaselineStub:
       case JitFrame_Unwound_BaselineStub:
         return BaselineStubFrameLayout::Size();
       case JitFrame_Rectifier:
         return RectifierFrameLayout::Size();
       case JitFrame_Unwound_Rectifier:
         return IonUnwoundRectifierFrameLayout::Size();
       case JitFrame_Exit:
+      case JitFrame_LazyLink:
         return ExitFrameLayout::Size();
       case JitFrame_IonAccessorIC:
       case JitFrame_Unwound_IonAccessorIC:
         return IonAccessorICFrameLayout::Size();
     }
 
     MOZ_CRASH("unknown frame type");
 }
@@ -952,16 +959,17 @@ EnsureExitFrame(CommonFrameLayout* frame
         return;
 
       case JitFrame_IonAccessorIC:
         frame->changePrevType(JitFrame_Unwound_IonAccessorIC);
         return;
 
       case JitFrame_Exit:
       case JitFrame_Bailout:
+      case JitFrame_LazyLink:
         // Fall-through to MOZ_CRASH below.
         break;
     }
 
     MOZ_CRASH("Unexpected frame type");
 }
 
 CalleeToken
@@ -1490,16 +1498,17 @@ MarkJitActivation(JSTracer* trc, const J
 #endif
 
     activation->markRematerializedFrames(trc);
     activation->markIonRecovery(trc);
 
     for (JitFrameIterator frames(activations); !frames.done(); ++frames) {
         switch (frames.type()) {
           case JitFrame_Exit:
+          case JitFrame_LazyLink:
             MarkJitExitFrame(trc, frames);
             break;
           case JitFrame_BaselineJS:
             frames.baselineFrame()->trace(trc, frames);
             break;
           case JitFrame_BaselineStub:
             MarkBaselineStubFrame(trc, frames);
             break;
@@ -1564,17 +1573,17 @@ GetPcScript(JSContext* cx, JSScript** sc
     JitSpew(JitSpew_IonSnapshots, "Recover PC & Script from the last frame.");
 
     // Recover the return address so that we can look it up in the
     // PcScriptCache, as script/pc computation is expensive.
     JSRuntime* rt = cx->runtime();
     JitActivationIterator iter(rt);
     JitFrameIterator it(iter);
     uint8_t* retAddr;
-    if (it.type() == JitFrame_Exit) {
+    if (it.isExitFrame()) {
         ++it;
 
         // Skip rectifier frames.
         if (it.isRectifierMaybeUnwound()) {
             ++it;
             MOZ_ASSERT(it.isBaselineStub() || it.isBaselineJS() || it.isIonJS());
         }
 
@@ -2766,16 +2775,17 @@ JitFrameIterator::dump() const
         fprintf(stderr, " Ion scripted accessor IC\n");
         fprintf(stderr, "  Frame size: %u\n", unsigned(current()->prevFrameLocalSize()));
         break;
       case JitFrame_Unwound_IonJS:
       case JitFrame_Unwound_BaselineJS:
         fprintf(stderr, "Warning! Unwound JS frames are not observable.\n");
         break;
       case JitFrame_Exit:
+      case JitFrame_LazyLink:
         break;
     };
     fputc('\n', stderr);
 }
 
 #ifdef DEBUG
 bool
 JitFrameIterator::verifyReturnAddressUsingNativeToBytecodeMap()
@@ -3214,17 +3224,17 @@ AssertJitStackInvariants(JSContext* cx)
                     + sizeof(Value) * (frames.callee()->nargs() + 1 /* |this| argument */ )
                     + sizeof(JitFrameLayout);
                 MOZ_RELEASE_ASSERT(frameSize >= expectedFrameSize,
                   "The frame is large enough to hold all arguments");
                 MOZ_RELEASE_ASSERT(expectedFrameSize + JitStackAlignment > frameSize,
                   "The frame size is optimal");
             }
 
-            if (frames.type() == JitFrame_Exit) {
+            if (frames.isExitFrame()) {
                 // For the moment, we do not keep the JitStackAlignment
                 // alignment for exit frames.
                 frameSize -= ExitFrameLayout::Size();
             }
 
             if (frames.isIonJS()) {
                 // Ideally, we should not have such requirement, but keep the
                 // alignment-delta as part of the Safepoint such that we can pad
--- a/js/src/jit/RangeAnalysis.cpp
+++ b/js/src/jit/RangeAnalysis.cpp
@@ -1890,16 +1890,26 @@ RangeAnalysis::analyzeLoop(MBasicBlock* 
             ins->block()->discard(ins);
         }
     }
 
     UnmarkLoopBlocks(graph_, header);
     return true;
 }
 
+// Unbox beta nodes in order to hoist instruction properly, and not be limited
+// by the beta nodes which are added after each branch.
+static inline MDefinition*
+DefinitionOrBetaInputDefinition(MDefinition* ins)
+{
+    while (ins->isBeta())
+        ins = ins->toBeta()->input();
+    return ins;
+}
+
 LoopIterationBound*
 RangeAnalysis::analyzeLoopIterationCount(MBasicBlock* header,
                                          MTest* test, BranchDirection direction)
 {
     SimpleLinearSum lhs(nullptr, 0);
     MDefinition* rhs;
     bool lessEqual;
     if (!ExtractLinearInequality(test, direction, &lhs, &rhs, &lessEqual))
@@ -1935,19 +1945,18 @@ RangeAnalysis::analyzeLoopIterationCount
     // the first executed iteration, and not a value written which could
     // replace the second operand below during the middle of execution.
     MDefinition* lhsInitial = lhs.term->toPhi()->getLoopPredecessorOperand();
     if (lhsInitial->block()->isMarked())
         return nullptr;
 
     // The second operand of the phi should be a value written by an add/sub
     // in every loop iteration, i.e. in a block which dominates the backedge.
-    MDefinition* lhsWrite = lhs.term->toPhi()->getLoopBackedgeOperand();
-    if (lhsWrite->isBeta())
-        lhsWrite = lhsWrite->getOperand(0);
+    MDefinition* lhsWrite =
+        DefinitionOrBetaInputDefinition(lhs.term->toPhi()->getLoopBackedgeOperand());
     if (!lhsWrite->isAdd() && !lhsWrite->isSub())
         return nullptr;
     if (!lhsWrite->block()->isMarked())
         return nullptr;
     MBasicBlock* bb = header->backedge();
     for (; bb != lhsWrite->block() && bb != header; bb = bb->immediateDominator()) {}
     if (bb != lhsWrite->block())
         return nullptr;
@@ -2102,17 +2111,18 @@ SymbolicBoundIsValid(MBasicBlock* header
         bb = bb->immediateDominator();
     return bb == bound->loop->test->block();
 }
 
 bool
 RangeAnalysis::tryHoistBoundsCheck(MBasicBlock* header, MBoundsCheck* ins)
 {
     // The bounds check's length must be loop invariant.
-    if (ins->length()->block()->isMarked())
+    MDefinition *length = DefinitionOrBetaInputDefinition(ins->length());
+    if (length->block()->isMarked())
         return false;
 
     // The bounds check's index should not be loop invariant (else we would
     // already have hoisted it during LICM).
     SimpleLinearSum index = ExtractLinearSum(ins->index());
     if (!index.term || !index.term->block()->isMarked())
         return false;
 
@@ -2160,17 +2170,17 @@ RangeAnalysis::tryHoistBoundsCheck(MBasi
     if (!SafeAdd(upper->sum.constant(), upperConstant, &upperConstant))
         return false;
 
     MBoundsCheckLower* lowerCheck = MBoundsCheckLower::New(alloc(), lowerTerm);
     lowerCheck->setMinimum(lowerConstant);
     lowerCheck->computeRange(alloc());
     lowerCheck->collectRangeInfoPreTrunc();
 
-    MBoundsCheck* upperCheck = MBoundsCheck::New(alloc(), upperTerm, ins->length());
+    MBoundsCheck* upperCheck = MBoundsCheck::New(alloc(), upperTerm, length);
     upperCheck->setMinimum(upperConstant);
     upperCheck->setMaximum(upperConstant);
     upperCheck->computeRange(alloc());
     upperCheck->collectRangeInfoPreTrunc();
 
     // Hoist the loop invariant upper and lower bounds checks.
     preLoop->insertBefore(preLoop->lastIns(), lowerCheck);
     preLoop->insertBefore(preLoop->lastIns(), upperCheck);
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1386,16 +1386,17 @@ AbstractFramePtr::hasPushedSPSFrame() co
         return asInterpreterFrame()->hasPushedSPSFrame();
     MOZ_ASSERT(isBaselineFrame());
     return false;
 }
 
 jit::JitActivation::JitActivation(JSContext* cx, bool active)
   : Activation(cx, Jit),
     active_(active),
+    isLazyLinkExitFrame_(false),
     rematerializedFrames_(nullptr),
     ionRecovery_(cx),
     bailoutData_(nullptr),
     lastProfilingFrame_(nullptr),
     lastProfilingCallSite_(nullptr)
 {
     if (active) {
         prevJitTop_ = cx->runtime()->jitTop;
--- a/js/src/vm/Stack.h
+++ b/js/src/vm/Stack.h
@@ -1281,16 +1281,25 @@ class BailoutFrameInfo;
 // A JitActivation is used for frames running in Baseline or Ion.
 class JitActivation : public Activation
 {
     uint8_t* prevJitTop_;
     JitActivation* prevJitActivation_;
     JSContext* prevJitJSContext_;
     bool active_;
 
+    // The lazy link stub reuse the frame pushed for calling a function as an
+    // exit frame. In a few cases, such as after calls from asm.js, we might
+    // have an entry frame followed by an exit frame. This pattern can be
+    // assimilated as a fake exit frame (unwound frame), in which case we skip
+    // marking during a GC. To ensure that we do mark the stack as expected we
+    // have to keep a flag set by the LazyLink VM function to safely mark the
+    // stack if a GC happens during the link phase.
+    bool isLazyLinkExitFrame_;
+
     // Rematerialized Ion frames which has info copied out of snapshots. Maps
     // frame pointers (i.e. jitTop) to a vector of rematerializations of all
     // inline frames associated with that frame.
     //
     // This table is lazily initialized by calling getRematerializedFrame.
     typedef Vector<RematerializedFrame*> RematerializedFrameVector;
     typedef HashMap<uint8_t*, RematerializedFrameVector> RematerializedFrameTable;
     RematerializedFrameTable* rematerializedFrames_;
@@ -1412,16 +1421,24 @@ class JitActivation : public Activation
     const BailoutFrameInfo* bailoutData() const { return bailoutData_; }
 
     // Register the bailout data when it is constructed.
     void setBailoutData(BailoutFrameInfo* bailoutData);
 
     // Unregister the bailout data when the frame is reconstructed.
     void cleanBailoutData();
 
+    // Return the bailout information if it is registered.
+    bool isLazyLinkExitFrame() const { return isLazyLinkExitFrame_; }
+
+    // Register the bailout data when it is constructed.
+    void setLazyLinkExitFrame(bool isExitFrame) {
+        isLazyLinkExitFrame_ = isExitFrame;
+    }
+
     static size_t offsetOfLastProfilingFrame() {
         return offsetof(JitActivation, lastProfilingFrame_);
     }
     void* lastProfilingFrame() {
         return lastProfilingFrame_;
     }
     void setLastProfilingFrame(void* ptr) {
         lastProfilingFrame_ = ptr;
--- a/js/xpconnect/tests/unit/test_interposition.js
+++ b/js/xpconnect/tests/unit/test_interposition.js
@@ -58,18 +58,20 @@ let TestInterposition = {
     return null;
   }
 };
 
 function run_test()
 {
   Cu.setAddonInterposition(ADDONID, TestInterposition);
 
+  Cu.importGlobalProperties(["XMLHttpRequest"]);
+
   let sandbox = Cu.Sandbox(this, {addonId: ADDONID});
-  sandbox.outerObj = {};
+  sandbox.outerObj = new XMLHttpRequest();
 
   expectAccess("abcxyz", () => {
     Cu.evalInSandbox("outerObj.abcxyz = 12;", sandbox);
   });
 
   expectAccess("utils", () => {
     Cu.evalInSandbox("Components.utils;", sandbox);
   });
--- a/js/xpconnect/wrappers/AddonWrapper.cpp
+++ b/js/xpconnect/wrappers/AddonWrapper.cpp
@@ -6,28 +6,41 @@
 
 #include "AddonWrapper.h"
 #include "WrapperFactory.h"
 #include "XrayWrapper.h"
 #include "jsapi.h"
 #include "jsfriendapi.h"
 #include "nsIAddonInterposition.h"
 #include "xpcprivate.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "nsGlobalWindow.h"
 
 #include "nsID.h"
 
 using namespace js;
 using namespace JS;
 
 namespace xpc {
 
 bool
 Interpose(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id,
           MutableHandle<JSPropertyDescriptor> descriptor)
 {
+    // We only want to do interpostion on DOM instances and
+    // wrapped natives.
+    RootedObject unwrapped(cx, UncheckedUnwrap(target));
+    const js::Class* clasp = js::GetObjectClass(unwrapped);
+    if (!mozilla::dom::IsDOMClass(clasp) &&
+        !IS_WN_CLASS(clasp) &&
+        !IS_PROTO_CLASS(clasp) &&
+        clasp != &OuterWindowProxyClass) {
+        return true;
+    }
+
     XPCWrappedNativeScope* scope = ObjectScope(CurrentGlobalOrNull(cx));
     MOZ_ASSERT(scope->HasInterposition());
 
     nsCOMPtr<nsIAddonInterposition> interp = scope->GetInterposition();
     JSAddonId* addonId = AddonIdOfObject(target);
     RootedValue addonIdValue(cx, StringValue(StringOfAddonId(addonId)));
     RootedValue prop(cx, IdToValue(id));
     RootedValue targetValue(cx, ObjectValue(*target));
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -3015,29 +3015,34 @@ void ContainerState::FinishPaintedLayerD
       data->mVerticalPanRegion.GetBounds(),
       mContainerReferenceFrame,
       containingPaintedLayerData->mReferenceFrame,
       &containingPaintedLayerData->mVerticalPanRegion,
       &containingPaintedLayerData->mDispatchToContentHitRegion);
 
   } else {
     EventRegions regions;
-    regions.mHitRegion = ScaleRegionToOutsidePixels(data->mHitRegion);
-    regions.mNoActionRegion = ScaleRegionToOutsidePixels(data->mNoActionRegion);
-    regions.mHorizontalPanRegion = ScaleRegionToOutsidePixels(data->mHorizontalPanRegion);
-    regions.mVerticalPanRegion = ScaleRegionToOutsidePixels(data->mVerticalPanRegion);
+    regions.mHitRegion =
+      data->mHitRegion.ToOutsidePixels(mAppUnitsPerDevPixel);
+    regions.mNoActionRegion =
+      data->mNoActionRegion.ToOutsidePixels(mAppUnitsPerDevPixel);
+    regions.mHorizontalPanRegion =
+      data->mHorizontalPanRegion.ToOutsidePixels(mAppUnitsPerDevPixel);
+    regions.mVerticalPanRegion =
+      data->mVerticalPanRegion.ToOutsidePixels(mAppUnitsPerDevPixel);
 
     // Points whose hit-region status we're not sure about need to be dispatched
     // to the content thread. If a point is in both maybeHitRegion and hitRegion
     // then it's not a "maybe" any more, and doesn't go into the dispatch-to-
     // content region.
-    nsIntRegion maybeHitRegion = ScaleRegionToOutsidePixels(data->mMaybeHitRegion);
+    nsIntRegion maybeHitRegion =
+      data->mMaybeHitRegion.ToOutsidePixels(mAppUnitsPerDevPixel);
     regions.mDispatchToContentHitRegion.Sub(maybeHitRegion, regions.mHitRegion);
     regions.mDispatchToContentHitRegion.OrWith(
-        ScaleRegionToOutsidePixels(data->mDispatchToContentHitRegion));
+        data->mDispatchToContentHitRegion.ToOutsidePixels(mAppUnitsPerDevPixel));
     regions.mHitRegion.OrWith(maybeHitRegion);
 
     Matrix mat = layer->GetBaseTransform().As2D();
     mat.Invert();
     regions.ApplyTranslationAndScale(mat._31, mat._32, mat._11, mat._22);
 
     layer->SetEventRegions(regions);
   }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7585,17 +7585,17 @@ nsLayoutUtils::GetContentViewerSize(nsPr
 
   nsIntRect bounds;
   cv->GetBounds(bounds);
   aOutSize = LayoutDeviceIntRect::FromUntyped(bounds).Size();
   return true;
 }
 
 /* static */ nsSize
-nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame)
+nsLayoutUtils::CalculateCompositionSizeForFrame(nsIFrame* aFrame, bool aSubtractScrollbars)
 {
   // If we have a scrollable frame, restrict the composition bounds to its
   // scroll port. The scroll port excludes the frame borders and the scroll
   // bars, which we don't want to be part of the composition bounds.
   nsIScrollableFrame* scrollableFrame = aFrame->GetScrollTargetFrame();
   nsSize size = scrollableFrame ? scrollableFrame->GetScrollPortRect().Size() : aFrame->GetSize();
 
   nsPresContext* presContext = aFrame->PresContext();
@@ -7641,17 +7641,17 @@ nsLayoutUtils::CalculateCompositionSizeF
 #endif
       } else {
         LayoutDeviceIntSize contentSize;
         if (nsLayoutUtils::GetContentViewerSize(presContext, contentSize)) {
           size = LayoutDevicePixel::ToAppUnits(contentSize, auPerDevPixel);
         }
       }
 
-      if (scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
+      if (aSubtractScrollbars && scrollableFrame && !LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) {
         nsMargin margins = scrollableFrame->GetActualScrollbarSizes();
         size.width -= margins.LeftRight();
         size.height -= margins.TopBottom();
       }
     }
   }
 
   return size;
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2460,17 +2460,17 @@ public:
   * defintion of composition size (or bounds).
   * Note that for the root content document's root scroll frame (RCD-RSF),
   * the returned size does not change as the document's resolution changes,
   * but for all other frames it does. This means that callers that pass in
   * a frame that may or may not be the RCD-RSF (which is most callers),
   * are likely to need special-case handling of the RCD-RSF.
   */
   static nsSize
-  CalculateCompositionSizeForFrame(nsIFrame* aFrame);
+  CalculateCompositionSizeForFrame(nsIFrame* aFrame, bool aSubtractScrollbars = true);
 
  /**
   * Calculate the composition size for the root scroll frame of the root
   * content document.
   * @param aFrame A frame in the root content document (or a descendant of it).
   * @param aIsRootContentDocRootScrollFrame Whether aFrame is already the root
   *          scroll frame of the root content document. In this case we just
   *          use aFrame's own composition size.
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6513,17 +6513,17 @@ nsIPresShell::GetPointerInfo(uint32_t aP
   }
   return false;
 }
 
 void
 PresShell::UpdateActivePointerState(WidgetGUIEvent* aEvent)
 {
   switch (aEvent->message) {
-  case NS_MOUSE_ENTER:
+  case NS_MOUSE_ENTER_WIDGET:
     // In this case we have to know information about available mouse pointers
     if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
       gActivePointersIds->Put(mouseEvent->pointerId,
                               new PointerInfo(false, mouseEvent->inputSource, true));
     }
     break;
   case NS_POINTER_DOWN:
     // In this case we switch pointer to active state
@@ -6538,17 +6538,17 @@ PresShell::UpdateActivePointerState(Widg
       if(pointerEvent->inputSource != nsIDOMMouseEvent::MOZ_SOURCE_TOUCH) {
         gActivePointersIds->Put(pointerEvent->pointerId,
                                 new PointerInfo(false, pointerEvent->inputSource, pointerEvent->isPrimary));
       } else {
         gActivePointersIds->Remove(pointerEvent->pointerId);
       }
     }
     break;
-  case NS_MOUSE_EXIT:
+  case NS_MOUSE_EXIT_WIDGET:
     // In this case we have to remove information about disappeared mouse pointers
     if (WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent()) {
       gActivePointersIds->Remove(mouseEvent->pointerId);
     }
     break;
   }
 }
 
@@ -6734,38 +6734,38 @@ PresShell::RecordMouseLocation(WidgetGUI
     if (rootPresShell) {
       rootPresShell->RecordMouseLocation(aEvent);
     }
     return;
   }
 
   if ((aEvent->message == NS_MOUSE_MOVE &&
        aEvent->AsMouseEvent()->reason == WidgetMouseEvent::eReal) ||
-      aEvent->message == NS_MOUSE_ENTER ||
+      aEvent->message == NS_MOUSE_ENTER_WIDGET ||
       aEvent->message == NS_MOUSE_BUTTON_DOWN ||
       aEvent->message == NS_MOUSE_BUTTON_UP) {
     nsIFrame* rootFrame = GetRootFrame();
     if (!rootFrame) {
       nsView* rootView = mViewManager->GetRootView();
       mMouseLocation = nsLayoutUtils::TranslateWidgetToView(mPresContext,
         aEvent->widget, aEvent->refPoint, rootView);
     } else {
       mMouseLocation =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, rootFrame);
     }
 #ifdef DEBUG_MOUSE_LOCATION
-    if (aEvent->message == NS_MOUSE_ENTER)
+    if (aEvent->message == NS_MOUSE_ENTER_WIDGET)
       printf("[ps=%p]got mouse enter for %p\n",
              this, aEvent->widget);
     printf("[ps=%p]setting mouse location to (%d,%d)\n",
            this, mMouseLocation.x, mMouseLocation.y);
 #endif
-    if (aEvent->message == NS_MOUSE_ENTER)
+    if (aEvent->message == NS_MOUSE_ENTER_WIDGET)
       SynthesizeMouseMove(false);
-  } else if (aEvent->message == NS_MOUSE_EXIT) {
+  } else if (aEvent->message == NS_MOUSE_EXIT_WIDGET) {
     // Although we only care about the mouse moving into an area for which this
     // pres shell doesn't receive mouse move events, we don't check which widget
     // the mouse exit was for since this seems to vary by platform.  Hopefully
     // this won't matter at all since we'll get the mouse move or enter after
     // the mouse exit when the mouse moves from one of our widgets into another.
     mMouseLocation = nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
 #ifdef DEBUG_MOUSE_LOCATION
     printf("[ps=%p]got mouse exit for %p\n",
@@ -7453,17 +7453,17 @@ PresShell::HandleEvent(nsIFrame* aFrame,
 
     // all touch events except for touchstart use a captured target
     if (aEvent->mClass == eTouchEventClass &&
         aEvent->message != NS_TOUCH_START) {
       captureRetarget = true;
     }
 
     WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
-    bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT) &&
+    bool isWindowLevelMouseExit = (aEvent->message == NS_MOUSE_EXIT_WIDGET) &&
       (mouseEvent && mouseEvent->exit == WidgetMouseEvent::eTopLevel);
 
     // Get the frame at the event point. However, don't do this if we're
     // capturing and retargeting the event because the captured frame will
     // be used instead below. Also keep using the root frame if we're dealing
     // with a window-level mouse exit event since we want to start sending
     // mouse out events at the root EventStateManager.
     if (!captureRetarget && !isWindowLevelMouseExit) {
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -857,18 +857,18 @@ nsListControlFrame::HandleEvent(nsPresCo
                           "NS_MOUSE_LEFT_BUTTON_UP",
                           "NS_MOUSE_LEFT_BUTTON_DOWN",
                           "<NA>","<NA>","<NA>","<NA>","<NA>","<NA>","<NA>",
                           "NS_MOUSE_MIDDLE_BUTTON_UP",
                           "NS_MOUSE_MIDDLE_BUTTON_DOWN",
                           "<NA>","<NA>","<NA>","<NA>","<NA>","<NA>","<NA>","<NA>",
                           "NS_MOUSE_RIGHT_BUTTON_UP",
                           "NS_MOUSE_RIGHT_BUTTON_DOWN",
-                          "NS_MOUSE_ENTER_SYNTH",
-                          "NS_MOUSE_EXIT_SYNTH",
+                          "NS_MOUSE_OVER",
+                          "NS_MOUSE_OUT",
                           "NS_MOUSE_LEFT_DOUBLECLICK",
                           "NS_MOUSE_MIDDLE_DOUBLECLICK",
                           "NS_MOUSE_RIGHT_DOUBLECLICK",
                           "NS_MOUSE_LEFT_CLICK",
                           "NS_MOUSE_MIDDLE_CLICK",
                           "NS_MOUSE_RIGHT_CLICK"};
   int inx = aEvent->message-NS_MOUSE_MESSAGE_START;
   if (inx >= 0 && inx <= (NS_MOUSE_RIGHT_CLICK-NS_MOUSE_MESSAGE_START)) {
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -1273,16 +1273,23 @@ public:
     CHECK_WRITING_MODE(aMargin.GetWritingMode());
     return LogicalMargin(GetWritingMode(),
                          BStart() + aMargin.BStart(),
                          IEnd() + aMargin.IEnd(),
                          BEnd() + aMargin.BEnd(),
                          IStart() + aMargin.IStart());
   }
 
+  LogicalMargin operator+=(const LogicalMargin& aMargin)
+  {
+    CHECK_WRITING_MODE(aMargin.GetWritingMode());
+    mMargin += aMargin.mMargin;
+    return *this;
+  }
+
   LogicalMargin operator-(const LogicalMargin& aMargin) const {
     CHECK_WRITING_MODE(aMargin.GetWritingMode());
     return LogicalMargin(GetWritingMode(),
                          BStart() - aMargin.BStart(),
                          IEnd() - aMargin.IEnd(),
                          BEnd() - aMargin.BEnd(),
                          IStart() - aMargin.IStart());
   }
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -347,20 +347,26 @@ nsHTMLScrollFrame::TryLayout(ScrollReflo
   desiredInsideBorderSize.width = vScrollbarDesiredWidth +
     std::max(aKidMetrics->Width(), hScrollbarMinWidth);
   desiredInsideBorderSize.height = hScrollbarDesiredHeight +
     std::max(aKidMetrics->Height(), vScrollbarMinHeight);
   aState->mInsideBorderSize =
     ComputeInsideBorderSize(aState, desiredInsideBorderSize);
   nsSize scrollPortSize = nsSize(std::max(0, aState->mInsideBorderSize.width - vScrollbarDesiredWidth),
                                  std::max(0, aState->mInsideBorderSize.height - hScrollbarDesiredHeight));
+
   nsSize visualScrollPortSize = scrollPortSize;
   nsIPresShell* presShell = PresContext()->PresShell();
   if (mHelper.mIsRoot && presShell->IsScrollPositionClampingScrollPortSizeSet()) {
-    visualScrollPortSize = presShell->GetScrollPositionClampingScrollPortSize();
+    nsSize compositionSize = nsLayoutUtils::CalculateCompositionSizeForFrame(this, false);
+    float resolution = presShell->GetResolution();
+    compositionSize.width /= resolution;
+    compositionSize.height /= resolution;
+    visualScrollPortSize = nsSize(std::max(0, compositionSize.width - vScrollbarDesiredWidth),
+                                  std::max(0, compositionSize.height - hScrollbarDesiredHeight));
   }
 
   if (!aForce) {
     nsRect scrolledRect =
       mHelper.GetScrolledRectInternal(aState->mContentsOverflowAreas.ScrollableOverflow(),
                                      scrollPortSize);
     nscoord oneDevPixel = aState->mBoxState.PresContext()->DevPixelsToAppUnits(1);
 
--- a/layout/generic/nsPluginFrame.cpp
+++ b/layout/generic/nsPluginFrame.cpp
@@ -1778,17 +1778,17 @@ nsPluginFrame::HandleEvent(nsPresContext
 
 #ifdef XP_WIN
   rv = nsPluginFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus);
   return rv;
 #endif
 
 #ifdef XP_MACOSX
   // we want to process some native mouse events in the cocoa event model
-  if ((anEvent->message == NS_MOUSE_ENTER ||
+  if ((anEvent->message == NS_MOUSE_ENTER_WIDGET ||
        anEvent->message == NS_WHEEL_WHEEL) &&
       mInstanceOwner->GetEventModel() == NPEventModelCocoa) {
     *anEventStatus = mInstanceOwner->ProcessEvent(*anEvent);
     // Due to plugin code reentering Gecko, this frame may be dead at this
     // point.
     return rv;
   }
 
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -1234,23 +1234,22 @@ nsMathMLmtdFrame::ProcessBorders(nsTable
                                  nsDisplayListBuilder* aBuilder,
                                  const nsDisplayListSet& aLists)
 {
   aLists.BorderBackground()->AppendNewToTop(new (aBuilder)
                                             nsDisplaymtdBorder(aBuilder, this));
   return NS_OK;
 }
 
-nsMargin*
-nsMathMLmtdFrame::GetBorderWidth(nsMargin& aBorder) const
+LogicalMargin
+nsMathMLmtdFrame::GetBorderWidth(WritingMode aWM) const
 {
   nsStyleBorder styleBorder = *StyleBorder();
   ApplyBorderToStyle(this, styleBorder);
-  aBorder = styleBorder.GetComputedBorder();
-  return &aBorder;
+  return LogicalMargin(aWM, styleBorder.GetComputedBorder());
 }
 
 nsMargin
 nsMathMLmtdFrame::GetBorderOverflow()
 {
   nsStyleBorder styleBorder = *StyleBorder();
   ApplyBorderToStyle(this, styleBorder);
   nsMargin overflow = ComputeBorderOverflow(this, styleBorder);
--- a/layout/mathml/nsMathMLmtableFrame.h
+++ b/layout/mathml/nsMathMLmtableFrame.h
@@ -259,17 +259,17 @@ public:
 
   virtual int32_t GetRowSpan() override;
   virtual int32_t GetColSpan() override;
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsTableCellFrame::IsFrameOfType(aFlags & ~(nsIFrame::eMathML));
   }
 
-  virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const override;
+  virtual LogicalMargin GetBorderWidth(WritingMode aWM) const override;
 
   virtual nsMargin GetBorderOverflow() override;
 
 protected:
   nsMathMLmtdFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame)
     : nsTableCellFrame(aContext, aTableFrame) {}
   virtual ~nsMathMLmtdFrame();
 }; // class nsMathMLmtdFrame
--- a/layout/tables/celldata.h
+++ b/layout/tables/celldata.h
@@ -160,29 +160,29 @@ enum BCBorderOwner
 };
 
 typedef uint16_t BCPixelSize;
 
 // These are the max sizes that are stored. If they are exceeded, then the max is stored and
 // the actual value is computed when needed.
 #define MAX_BORDER_WIDTH nscoord((1u << (sizeof(BCPixelSize) * 8)) - 1)
 
-static inline nscoord
-BC_BORDER_TOP_HALF_COORD(int32_t p2t, uint16_t px)    { return (px - px / 2) * p2t; }
-static inline nscoord
-BC_BORDER_RIGHT_HALF_COORD(int32_t p2t, uint16_t px)  { return (     px / 2) * p2t; }
-static inline nscoord
-BC_BORDER_BOTTOM_HALF_COORD(int32_t p2t, uint16_t px) { return (     px / 2) * p2t; }
+// The half of border on inline/block-axis start side
+static inline BCPixelSize
+BC_BORDER_START_HALF(BCPixelSize px) { return px - px / 2; }
+// The half of border on inline/block-axis end side
+static inline BCPixelSize
+BC_BORDER_END_HALF(BCPixelSize px) { return px / 2; }
+
 static inline nscoord
-BC_BORDER_LEFT_HALF_COORD(int32_t p2t, uint16_t px)   { return (px - px / 2) * p2t; }
-
-#define BC_BORDER_TOP_HALF(px)    ((px) - (px) / 2)
-#define BC_BORDER_RIGHT_HALF(px)  ((px) / 2)
-#define BC_BORDER_BOTTOM_HALF(px) ((px) / 2)
-#define BC_BORDER_LEFT_HALF(px)   ((px) - (px) / 2)
+BC_BORDER_START_HALF_COORD(int32_t p2t, BCPixelSize px)
+  { return BC_BORDER_START_HALF(px) * p2t; }
+static inline nscoord
+BC_BORDER_END_HALF_COORD(int32_t p2t, BCPixelSize px)
+  { return BC_BORDER_END_HALF(px) * p2t; }
 
 // BCData stores the top and left border info and the corner connecting the two.
 class BCData
 {
 public:
   BCData();
 
   ~BCData();
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -791,19 +791,18 @@ nsTableCellFrame::GetPrefISize(nsRenderi
 nsTableCellFrame::IntrinsicISizeOffsets(nsRenderingContext* aRenderingContext)
 {
   IntrinsicISizeOffsetData result =
     nsContainerFrame::IntrinsicISizeOffsets(aRenderingContext);
 
   result.hMargin = 0;
   result.hPctMargin = 0;
 
-  nsMargin border;
-  GetBorderWidth(border);
-  result.hBorder = border.LeftRight();
+  WritingMode wm = GetWritingMode();
+  result.hBorder = GetBorderWidth(wm).IStartEnd(wm);
 
   return result;
 }
 
 #ifdef DEBUG
 #define PROBABLY_TOO_LARGE 1000000
 static
 void DebugCheckChildSize(nsIFrame*            aChild,
@@ -870,37 +869,36 @@ nsTableCellFrame::Reflow(nsPresContext* 
   }
 
   // see if a special height reflow needs to occur due to having a pct height
   nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState);
 
   aStatus = NS_FRAME_COMPLETE;
   nsSize availSize(aReflowState.AvailableWidth(), aReflowState.AvailableHeight());
 
-  nsMargin borderPadding = aReflowState.ComputedPhysicalPadding();
-  nsMargin border;
-  GetBorderWidth(border);
+  WritingMode wm = aReflowState.GetWritingMode();
+  LogicalMargin borderPadding = aReflowState.ComputedLogicalPadding();
+  LogicalMargin border = GetBorderWidth(wm);
   borderPadding += border;
 
-  nscoord topInset    = borderPadding.top;
-  nscoord rightInset  = borderPadding.right;
-  nscoord bottomInset = borderPadding.bottom;
-  nscoord leftInset   = borderPadding.left;
+  nscoord topInset = borderPadding.Top(wm);
+  nscoord rightInset = borderPadding.Right(wm);
+  nscoord bottomInset = borderPadding.Bottom(wm);
+  nscoord leftInset = borderPadding.Left(wm);
 
   // reduce available space by insets, if we're in a constrained situation
   availSize.width -= leftInset + rightInset;
   if (NS_UNCONSTRAINEDSIZE != availSize.height)
     availSize.height -= topInset + bottomInset;
 
   // Try to reflow the child into the available space. It might not
   // fit or might need continuing.
   if (availSize.height < 0)
     availSize.height = 1;
 
-  WritingMode wm = aReflowState.GetWritingMode();
   nsHTMLReflowMetrics kidSize(wm, aDesiredSize.mFlags);
   kidSize.ClearSize();
   SetPriorAvailWidth(aReflowState.AvailableWidth());
   nsIFrame* firstKid = mFrames.FirstChild();
   NS_ASSERTION(firstKid, "Frame construction error, a table cell always has an inner cell frame");
   nsTableFrame* tableFrame = GetTableFrame();
 
   if (aReflowState.mFlags.mSpecialHeightReflow) {
@@ -1075,21 +1073,20 @@ NS_NewTableCellFrame(nsIPresShell*   aPr
   if (aTableFrame->IsBorderCollapse())
     return new (aPresShell) nsBCTableCellFrame(aContext, aTableFrame);
   else
     return new (aPresShell) nsTableCellFrame(aContext, aTableFrame);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
 
-nsMargin*
-nsTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
+LogicalMargin
+nsTableCellFrame::GetBorderWidth(WritingMode aWM) const
 {
-  aBorder = StyleBorder()->GetComputedBorder();
-  return &aBorder;
+  return LogicalMargin(aWM, StyleBorder()->GetComputedBorder());
 }
 
 nsIAtom*
 nsTableCellFrame::GetType() const
 {
   return nsGkAtoms::tableCellFrame;
 }
 
@@ -1102,35 +1099,34 @@ nsTableCellFrame::GetFrameName(nsAString
 #endif
 
 // nsBCTableCellFrame
 
 nsBCTableCellFrame::nsBCTableCellFrame(nsStyleContext* aContext,
                                        nsTableFrame* aTableFrame)
   : nsTableCellFrame(aContext, aTableFrame)
 {
-  mTopBorder = mRightBorder = mBottomBorder = mLeftBorder = 0;
+  mBStartBorder = mIEndBorder = mBEndBorder = mIStartBorder = 0;
 }
 
 nsBCTableCellFrame::~nsBCTableCellFrame()
 {
 }
 
 nsIAtom*
 nsBCTableCellFrame::GetType() const
 {
   return nsGkAtoms::bcTableCellFrame;
 }
 
 /* virtual */ nsMargin
 nsBCTableCellFrame::GetUsedBorder() const
 {
-  nsMargin result;
-  GetBorderWidth(result);
-  return result;
+  WritingMode wm = GetWritingMode();
+  return GetBorderWidth(wm).GetPhysicalMargin(wm);
 }
 
 /* virtual */ bool
 nsBCTableCellFrame::GetBorderRadii(const nsSize& aFrameSize,
                                    const nsSize& aBorderArea,
                                    Sides aSkipSides,
                                    nscoord aRadii[8]) const
 {
@@ -1143,84 +1139,84 @@ nsBCTableCellFrame::GetBorderRadii(const
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsBCTableCellFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("BCTableCell"), aResult);
 }
 #endif
 
-nsMargin*
-nsBCTableCellFrame::GetBorderWidth(nsMargin&  aBorder) const
+LogicalMargin
+nsBCTableCellFrame::GetBorderWidth(WritingMode aWM) const
 {
-  int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.top    = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips, mTopBorder);
-  aBorder.right  = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips, mRightBorder);
-  aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mBottomBorder);
-  aBorder.left   = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mLeftBorder);
-  return &aBorder;
+  int32_t pixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
+  return LogicalMargin(aWM,
+                       BC_BORDER_END_HALF_COORD(pixelsToTwips, mBStartBorder),
+                       BC_BORDER_START_HALF_COORD(pixelsToTwips, mIEndBorder),
+                       BC_BORDER_START_HALF_COORD(pixelsToTwips, mBEndBorder),
+                       BC_BORDER_END_HALF_COORD(pixelsToTwips, mIStartBorder));
 }
 
 BCPixelSize
-nsBCTableCellFrame::GetBorderWidth(mozilla::css::Side aSide) const
+nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide) const
 {
   switch(aSide) {
-  case NS_SIDE_TOP:
-    return BC_BORDER_BOTTOM_HALF(mTopBorder);
-  case NS_SIDE_RIGHT:
-    return BC_BORDER_LEFT_HALF(mRightBorder);
-  case NS_SIDE_BOTTOM:
-    return BC_BORDER_TOP_HALF(mBottomBorder);
+  case eLogicalSideBStart:
+    return BC_BORDER_END_HALF(mBStartBorder);
+  case eLogicalSideIEnd:
+    return BC_BORDER_START_HALF(mIEndBorder);
+  case eLogicalSideBEnd:
+    return BC_BORDER_START_HALF(mBEndBorder);
   default:
-    return BC_BORDER_RIGHT_HALF(mLeftBorder);
+    return BC_BORDER_END_HALF(mIStartBorder);
   }
 }
 
 void
-nsBCTableCellFrame::SetBorderWidth(mozilla::css::Side aSide,
-                                   BCPixelSize aValue)
+nsBCTableCellFrame::SetBorderWidth(LogicalSide aSide, BCPixelSize aValue)
 {
   switch(aSide) {
-  case NS_SIDE_TOP:
-    mTopBorder = aValue;
+  case eLogicalSideBStart:
+    mBStartBorder = aValue;
     break;
-  case NS_SIDE_RIGHT:
-    mRightBorder = aValue;
+  case eLogicalSideIEnd:
+    mIEndBorder = aValue;
     break;
-  case NS_SIDE_BOTTOM:
-    mBottomBorder = aValue;
+  case eLogicalSideBEnd:
+    mBEndBorder = aValue;
     break;
   default:
-    mLeftBorder = aValue;
+    mIStartBorder = aValue;
   }
 }
 
 /* virtual */ nsMargin
 nsBCTableCellFrame::GetBorderOverflow()
 {
-  nsMargin halfBorder;
+  WritingMode wm = GetWritingMode();
   int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
-  halfBorder.top = BC_BORDER_TOP_HALF_COORD(p2t, mTopBorder);
-  halfBorder.right = BC_BORDER_RIGHT_HALF_COORD(p2t, mRightBorder);
-  halfBorder.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, mBottomBorder);
-  halfBorder.left = BC_BORDER_LEFT_HALF_COORD(p2t, mLeftBorder);
-  return halfBorder;
+  LogicalMargin halfBorder(wm,
+                           BC_BORDER_START_HALF_COORD(p2t, mBStartBorder),
+                           BC_BORDER_END_HALF_COORD(p2t, mIEndBorder),
+                           BC_BORDER_END_HALF_COORD(p2t, mBEndBorder),
+                           BC_BORDER_START_HALF_COORD(p2t, mIStartBorder));
+  return halfBorder.GetPhysicalMargin(wm);
 }
 
 
 DrawResult
 nsBCTableCellFrame::PaintBackground(nsRenderingContext& aRenderingContext,
                                     const nsRect&        aDirtyRect,
                                     nsPoint              aPt,
                                     uint32_t             aFlags)
 {
   // make border-width reflect the half of the border-collapse
   // assigned border that's inside the cell
-  nsMargin borderWidth;
-  GetBorderWidth(borderWidth);
+  WritingMode wm = GetWritingMode();
+  nsMargin borderWidth = GetBorderWidth(wm).GetPhysicalMargin(wm);
 
   nsStyleBorder myBorder(*StyleBorder());
 
   NS_FOR_CSS_SIDES(side) {
     myBorder.SetBorderWidth(side, borderWidth.Side(side));
   }
 
   nsRect rect(aPt, GetSize());
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -12,16 +12,17 @@
 #include "nscore.h"
 #include "nsContainerFrame.h"
 #include "nsStyleContext.h"
 #include "nsIPercentHeightObserver.h"
 #include "nsGkAtoms.h"
 #include "nsLayoutUtils.h"
 #include "nsTArray.h"
 #include "nsTableRowFrame.h"
+#include "mozilla/WritingModes.h"
 
 /**
  * nsTableCellFrame
  * data structure to maintain information about a single table cell's frame
  *
  * NOTE:  frames are not ref counted.  We expose addref and release here
  * so we can change that decsion in the future.  Users of nsITableCellLayout
  * should refcount correctly as if this object is being ref counted, though
@@ -30,16 +31,21 @@
  * @author  sclark
  */
 class nsTableCellFrame : public nsContainerFrame,
                          public nsITableCellLayout,
                          public nsIPercentHeightObserver
 {
   typedef mozilla::image::DrawResult DrawResult;
 
+protected:
+  typedef mozilla::WritingMode WritingMode;
+  typedef mozilla::LogicalSide LogicalSide;
+  typedef mozilla::LogicalMargin LogicalMargin;
+
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTableCellFrame)
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
   // default constructor supplied by the compiler
 
   nsTableCellFrame(nsStyleContext* aContext, nsTableFrame* aTableFrame);
@@ -210,17 +216,17 @@ public:
   bool GetContentEmpty();
   void SetContentEmpty(bool aContentEmpty);
 
   bool HasPctOverHeight();
   void SetHasPctOverHeight(bool aValue);
 
   nsTableCellFrame* GetNextCell() const;
 
-  virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const;
+  virtual LogicalMargin GetBorderWidth(WritingMode aWM) const;
 
   virtual DrawResult PaintBackground(nsRenderingContext& aRenderingContext,
                                      const nsRect&        aDirtyRect,
                                      nsPoint              aPt,
                                      uint32_t             aFlags);
 
   void DecorateForSelection(nsRenderingContext& aRenderingContext,
                             nsPoint              aPt);
@@ -316,38 +322,38 @@ public:
 
   virtual nsMargin GetUsedBorder() const override;
   virtual bool GetBorderRadii(const nsSize& aFrameSize,
                               const nsSize& aBorderArea,
                               Sides aSkipSides,
                               nscoord aRadii[8]) const override;
 
   // Get the *inner half of the border only*, in twips.
-  virtual nsMargin* GetBorderWidth(nsMargin& aBorder) const override;
+  virtual LogicalMargin GetBorderWidth(WritingMode aWM) const override;
 
   // Get the *inner half of the border only*, in pixels.
-  BCPixelSize GetBorderWidth(mozilla::css::Side aSide) const;
+  BCPixelSize GetBorderWidth(LogicalSide aSide) const;
 
   // Set the full (both halves) width of the border
-  void SetBorderWidth(mozilla::css::Side aSide, BCPixelSize aPixelValue);
+  void SetBorderWidth(LogicalSide aSide, BCPixelSize aPixelValue);
 
   virtual nsMargin GetBorderOverflow() override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override;
 #endif
 
   virtual DrawResult PaintBackground(nsRenderingContext& aRenderingContext,
                                      const nsRect&        aDirtyRect,
                                      nsPoint              aPt,
                                      uint32_t             aFlags) override;
 
 private:
 
   // These are the entire width of the border (the cell edge contains only
   // the inner half, per the macros in nsTablePainter.h).
-  BCPixelSize mTopBorder;
-  BCPixelSize mRightBorder;
-  BCPixelSize mBottomBorder;
-  BCPixelSize mLeftBorder;
+  BCPixelSize mBStartBorder;
+  BCPixelSize mIEndBorder;
+  BCPixelSize mBEndBorder;
+  BCPixelSize mIStartBorder;
 };
 
 #endif
--- a/layout/tables/nsTableColFrame.cpp
+++ b/layout/tables/nsTableColFrame.cpp
@@ -8,16 +8,18 @@
 #include "nsContainerFrame.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsPresContext.h"
 #include "nsGkAtoms.h"
 #include "nsCSSRendering.h"
 #include "nsIContent.h"
 
+using namespace mozilla;
+
 #define COL_TYPE_BITS                 (NS_FRAME_STATE_BIT(28) | \
                                        NS_FRAME_STATE_BIT(29) | \
                                        NS_FRAME_STATE_BIT(30) | \
                                        NS_FRAME_STATE_BIT(31))
 #define COL_TYPE_OFFSET               28
 
 using namespace mozilla;
 
@@ -64,28 +66,28 @@ nsTableColFrame::DidSetStyleContext(nsSt
   nsTableFrame* tableFrame = GetTableFrame();
   if (tableFrame->IsBorderCollapse() &&
       tableFrame->BCRecalcNeeded(aOldStyleContext, StyleContext())) {
     TableArea damageArea(GetColIndex(), 0, 1, tableFrame->GetRowCount());
     tableFrame->AddBCDamageArea(damageArea);
   }
 }
 
-void nsTableColFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
+void nsTableColFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
                                                  BCPixelSize aPixelValue)
 {
   switch (aForSide) {
-    case NS_SIDE_TOP:
-      mTopContBorderWidth = aPixelValue;
+    case eLogicalSideBStart:
+      mBStartContBorderWidth = aPixelValue;
       return;
-    case NS_SIDE_RIGHT:
-      mRightContBorderWidth = aPixelValue;
+    case eLogicalSideIEnd:
+      mIEndContBorderWidth = aPixelValue;
       return;
-    case NS_SIDE_BOTTOM:
-      mBottomContBorderWidth = aPixelValue;
+    case eLogicalSideBEnd:
+      mBEndContBorderWidth = aPixelValue;
       return;
     default:
       NS_ERROR("invalid side arg");
   }
 }
 
 void
 nsTableColFrame::Reflow(nsPresContext*          aPresContext,
--- a/layout/tables/nsTableColFrame.h
+++ b/layout/tables/nsTableColFrame.h
@@ -83,35 +83,35 @@ public:
     { return GetTableFrame()->GetWritingMode(); }
 
   /** return the number of the columns the col represents.  always >= 1 */
   int32_t GetSpan();
 
   /** convenience method, calls into cellmap */
   int32_t Count() const;
 
-  nscoord GetLeftBorderWidth();
-  void    SetLeftBorderWidth(BCPixelSize aWidth);
-  nscoord GetRightBorderWidth();
-  void    SetRightBorderWidth(BCPixelSize aWidth);
+  nscoord GetIStartBorderWidth() const { return mIStartBorderWidth; }
+  nscoord GetIEndBorderWidth() const { return mIEndBorderWidth; }
+  void SetIStartBorderWidth(BCPixelSize aWidth) { mIStartBorderWidth = aWidth; }
+  void SetIEndBorderWidth(BCPixelSize aWidth) { mIEndBorderWidth = aWidth; }
 
   /**
    * Gets inner border widths before collapsing with cell borders
    * Caller must get left border from previous column or from table
    * GetContinuousBCBorderWidth will not overwrite aBorder.left
    * see nsTablePainter about continuous borders
    *
    * @return outer right border width (left inner for next column)
    */
   nscoord GetContinuousBCBorderWidth(nsMargin& aBorder);
   /**
    * Set full border widths before collapsing with cell borders
-   * @param aForSide - side to set; only valid for top, right, and bottom
+   * @param aForSide - side to set; only valid for bstart, iend, and bend
    */
-  void SetContinuousBCBorderWidth(uint8_t     aForSide,
+  void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
                                   BCPixelSize aPixelValue);
 #ifdef DEBUG
   void Dump(int32_t aIndent);
 #endif
 
   /**
    * Restore the default values of the intrinsic widths, so that we can
    * re-accumulate intrinsic widths from the cells in the column.
@@ -300,62 +300,45 @@ protected:
   nscoord mFinalISize;
 
   // the index of the column with respect to the whole table (starting at 0)
   // it should never be smaller then the start column index of the parent
   // colgroup
   uint32_t mColIndex;
 
   // border width in pixels of the inner half of the border only
-  BCPixelSize mLeftBorderWidth;
-  BCPixelSize mRightBorderWidth;
-  BCPixelSize mTopContBorderWidth;
-  BCPixelSize mRightContBorderWidth;
-  BCPixelSize mBottomContBorderWidth;
+  BCPixelSize mIStartBorderWidth;
+  BCPixelSize mIEndBorderWidth;
+  BCPixelSize mBStartContBorderWidth;
+  BCPixelSize mIEndContBorderWidth;
+  BCPixelSize mBEndContBorderWidth;
 
   bool mHasSpecifiedCoord;
 };
 
 inline int32_t nsTableColFrame::GetColIndex() const
 {
   return mColIndex;
 }
 
 inline void nsTableColFrame::SetColIndex (int32_t aColIndex)
 {
   mColIndex = aColIndex;
 }
 
-inline nscoord nsTableColFrame::GetLeftBorderWidth()
-{
-  return mLeftBorderWidth;
-}
-
-inline void nsTableColFrame::SetLeftBorderWidth(BCPixelSize aWidth)
-{
-  mLeftBorderWidth = aWidth;
-}
-
-inline nscoord nsTableColFrame::GetRightBorderWidth()
-{
-  return mRightBorderWidth;
-}
-
-inline void nsTableColFrame::SetRightBorderWidth(BCPixelSize aWidth)
-{
-  mRightBorderWidth = aWidth;
-}
-
 inline nscoord
 nsTableColFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips,
-                                            mTopContBorderWidth);
-  aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips,
-                                            mRightContBorderWidth);
-  aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips,
-                                            mBottomContBorderWidth);
-  return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mRightContBorderWidth);
+  mozilla::WritingMode wm = GetWritingMode();
+  mozilla::LogicalMargin border(wm, aBorder);
+  border.BStart(wm) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+                                               mBStartContBorderWidth);
+  border.IEnd(wm) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                               mIEndContBorderWidth);
+  border.BEnd(wm) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                               mBEndContBorderWidth);
+  aBorder = border.GetPhysicalMargin(wm);
+  return BC_BORDER_END_HALF_COORD(aPixelsToTwips, mIEndContBorderWidth);
 }
 
 #endif
 
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -432,20 +432,20 @@ void nsTableColGroupFrame::SetContinuous
 }
 
 void nsTableColGroupFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
   nsTableColFrame* col = GetTableFrame()->
     GetColFrame(mStartColIndex + mColCount - 1);
   col->GetContinuousBCBorderWidth(aBorder);
-  aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips,
-                                            mTopContBorderWidth);
-  aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips,
-                                            mBottomContBorderWidth);
+  aBorder.top = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+                                         mTopContBorderWidth);
+  aBorder.bottom = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                              mBottomContBorderWidth);
 }
 
 /* ----- global methods ----- */
 
 nsTableColGroupFrame*
 NS_NewTableColGroupFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
 {
   return new (aPresShell) nsTableColGroupFrame(aContext);
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 sw=2 et tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Likely.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/IntegerRange.h"
+#include "mozilla/WritingModes.h"
 
 #include "nsCOMPtr.h"
 #include "nsTableFrame.h"
 #include "nsRenderingContext.h"
 #include "nsStyleContext.h"
 #include "nsStyleConsts.h"
 #include "nsIContent.h"
 #include "nsCellMap.h"
@@ -2596,38 +2597,38 @@ nsTableFrame::GetOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
   BCPropertyData* propData = GetBCProperty();
   if (propData) {
-    border.top    = BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
-    border.right  = BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightBorderWidth);
-    border.bottom = BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
-    border.left   = BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftBorderWidth);
+    border.top = BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth);
+    border.right = BC_BORDER_END_HALF_COORD(p2t, propData->mRightBorderWidth);
+    border.bottom = BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth);
+    border.left = BC_BORDER_START_HALF_COORD(p2t, propData->mLeftBorderWidth);
   }
   return border;
 }
 
 nsMargin
 nsTableFrame::GetIncludedOuterBCBorder() const
 {
   if (NeedToCalcBCBorders())
     const_cast<nsTableFrame*>(this)->CalcBCBorders();
 
   nsMargin border(0, 0, 0, 0);
   int32_t p2t = nsPresContext::AppUnitsPerCSSPixel();
   BCPropertyData* propData = GetBCProperty();
   if (propData) {
-    border.top += BC_BORDER_TOP_HALF_COORD(p2t, propData->mTopBorderWidth);
-    border.right += BC_BORDER_RIGHT_HALF_COORD(p2t, propData->mRightCellBorderWidth);
-    border.bottom += BC_BORDER_BOTTOM_HALF_COORD(p2t, propData->mBottomBorderWidth);
-    border.left += BC_BORDER_LEFT_HALF_COORD(p2t, propData->mLeftCellBorderWidth);
+    border.top += BC_BORDER_START_HALF_COORD(p2t, propData->mTopBorderWidth);
+    border.right += BC_BORDER_END_HALF_COORD(p2t, propData->mRightCellBorderWidth);
+    border.bottom += BC_BORDER_END_HALF_COORD(p2t, propData->mBottomBorderWidth);
+    border.left += BC_BORDER_START_HALF_COORD(p2t, propData->mLeftCellBorderWidth);
   }
   return border;
 }
 
 nsMargin
 nsTableFrame::GetExcludedOuterBCBorder() const
 {
   return GetOuterBCBorder() - GetIncludedOuterBCBorder();
@@ -2666,17 +2667,20 @@ nsTableFrame::InitChildReflowState(nsHTM
 {
   nsMargin collapseBorder;
   nsMargin padding(0,0,0,0);
   nsMargin* pCollapseBorder = nullptr;
   nsPresContext* presContext = PresContext();
   if (IsBorderCollapse()) {
     nsTableRowGroupFrame* rgFrame =
        static_cast<nsTableRowGroupFrame*>(aReflowState.frame);
-    pCollapseBorder = rgFrame->GetBCBorderWidth(collapseBorder);
+    WritingMode wm = GetWritingMode();
+    LogicalMargin border = rgFrame->GetBCBorderWidth(wm);
+    collapseBorder = border.GetPhysicalMargin(wm);
+    pCollapseBorder = &collapseBorder;
   }
   aReflowState.Init(presContext, -1, -1, pCollapseBorder, &padding);
 
   NS_ASSERTION(!mBits.mResizedColumns ||
                !aReflowState.parentReflowState->mFlags.mSpecialHeightReflow,
                "should not resize columns on special height reflow");
   if (mBits.mResizedColumns) {
     aReflowState.SetHResize(true);
@@ -4120,143 +4124,128 @@ struct BCMapCellInfo
                BCMapCellIterator* aIter,
                nsCellMap*         aCellMap = nullptr);
   // The BCMapCellInfo has functions to set the continous
   // border widths (see nsTablePainter.cpp for a description of the continous
   // borders concept). The widths are computed inside these functions based on
   // the current position inside the table and the cached frames that correspond
   // to this position. The widths are stored in member variables of the internal
   // table frames.
-  void SetTableTopLeftContBCBorder();
-  void SetRowGroupLeftContBCBorder();
-  void SetRowGroupRightContBCBorder();
-  void SetRowGroupBottomContBCBorder();
-  void SetRowLeftContBCBorder();
-  void SetRowRightContBCBorder();
-  void SetColumnTopRightContBCBorder();
-  void SetColumnBottomContBCBorder();
-  void SetColGroupBottomContBCBorder();
-  void SetInnerRowGroupBottomContBCBorder(const nsIFrame* aNextRowGroup,
-                                          nsTableRowFrame* aNextRow);
+  void SetTableBStartIStartContBCBorder();
+  void SetRowGroupIStartContBCBorder();
+  void SetRowGroupIEndContBCBorder();
+  void SetRowGroupBEndContBCBorder();
+  void SetRowIStartContBCBorder();
+  void SetRowIEndContBCBorder();
+  void SetColumnBStartIEndContBCBorder();
+  void SetColumnBEndContBCBorder();
+  void SetColGroupBEndContBCBorder();
+  void SetInnerRowGroupBEndContBCBorder(const nsIFrame* aNextRowGroup,
+                                        nsTableRowFrame* aNextRow);
 
   // functions to set the border widths on the table related frames, where the
   // knowledge about the current position in the table is used.
-  void SetTableTopBorderWidth(BCPixelSize aWidth);
-  void SetTableLeftBorderWidth(int32_t aRowY, BCPixelSize aWidth);
-  void SetTableRightBorderWidth(int32_t aRowY, BCPixelSize aWidth);
-  void SetTableBottomBorderWidth(BCPixelSize aWidth);
-  void SetLeftBorderWidths(BCPixelSize aWidth);
-  void SetRightBorderWidths(BCPixelSize aWidth);
-  void SetTopBorderWidths(BCPixelSize aWidth);
-  void SetBottomBorderWidths(BCPixelSize aWidth);
+  void SetTableBStartBorderWidth(BCPixelSize aWidth);
+  void SetTableIStartBorderWidth(int32_t aRowY, BCPixelSize aWidth);
+  void SetTableIEndBorderWidth(int32_t aRowY, BCPixelSize aWidth);
+  void SetTableBEndBorderWidth(BCPixelSize aWidth);
+  void SetIStartBorderWidths(BCPixelSize aWidth);
+  void SetIEndBorderWidths(BCPixelSize aWidth);
+  void SetBStartBorderWidths(BCPixelSize aWidth);
+  void SetBEndBorderWidths(BCPixelSize aWidth);
 
   // functions to compute the borders; they depend on the
   // knowledge about the current position in the table. The edge functions
   // should be called if a table edge is involved, otherwise the internal
   // functions should be called.
-  BCCellBorder GetTopEdgeBorder();
-  BCCellBorder GetBottomEdgeBorder();
-  BCCellBorder GetLeftEdgeBorder();
-  BCCellBorder GetRightEdgeBorder();
-  BCCellBorder GetRightInternalBorder();
-  BCCellBorder GetLeftInternalBorder();
-  BCCellBorder GetTopInternalBorder();
-  BCCellBorder GetBottomInternalBorder();
+  BCCellBorder GetBStartEdgeBorder();
+  BCCellBorder GetBEndEdgeBorder();
+  BCCellBorder GetIStartEdgeBorder();
+  BCCellBorder GetIEndEdgeBorder();
+  BCCellBorder GetIEndInternalBorder();
+  BCCellBorder GetIStartInternalBorder();
+  BCCellBorder GetBStartInternalBorder();
+  BCCellBorder GetBEndInternalBorder();
 
   // functions to set the interal position information
   void SetColumn(int32_t aColX);
   // Increment the row as we loop over the rows of a rowspan
   void IncrementRow(bool aResetToTopRowOfCell = false);
 
   // Helper functions to get extent of the cell
   int32_t GetCellEndRowIndex() const;
   int32_t GetCellEndColIndex() const;
 
   // storage of table information
   nsTableFrame*         mTableFrame;
   int32_t               mNumTableRows;
   int32_t               mNumTableCols;
   BCPropertyData*       mTableBCData;
-
-  // storage of table ltr information, the border collapse code swaps the sides
-  // to account for rtl tables, this is done through mStartSide and mEndSide
-  bool                  mTableIsLTR;
-  mozilla::css::Side    mStartSide;
-  mozilla::css::Side    mEndSide;
+  WritingMode           mTableWM;
 
   // a cell can only belong to one rowgroup
   nsTableRowGroupFrame* mRowGroup;
 
   // a cell with a rowspan has a top and a bottom row, and rows in between
-  nsTableRowFrame*      mTopRow;
-  nsTableRowFrame*      mBottomRow;
+  nsTableRowFrame*      mStartRow;
+  nsTableRowFrame*      mEndRow;
   nsTableRowFrame*      mCurrentRowFrame;
 
   // a cell with a colspan has a left and right column and columns in between
   // they can belong to different colgroups
   nsTableColGroupFrame* mColGroup;
   nsTableColGroupFrame* mCurrentColGroupFrame;
 
-  nsTableColFrame*      mLeftCol;
-  nsTableColFrame*      mRightCol;
+  nsTableColFrame*      mStartCol;
+  nsTableColFrame*      mEndCol;
   nsTableColFrame*      mCurrentColFrame;
 
   // cell information
   BCCellData*           mCellData;
   nsBCTableCellFrame*   mCell;
 
   int32_t               mRowIndex;
   int32_t               mRowSpan;
   int32_t               mColIndex;
   int32_t               mColSpan;
 
   // flags to describe the position of the cell with respect to the row- and
-  // colgroups, for instance mRgAtTop documents that the top cell border hits
+  // colgroups, for instance mRgAtStart documents that the top cell border hits
   // a rowgroup border
-  bool                  mRgAtTop;
-  bool                  mRgAtBottom;
-  bool                  mCgAtLeft;
-  bool                  mCgAtRight;
+  bool                  mRgAtStart;
+  bool                  mRgAtEnd;
+  bool                  mCgAtStart;
+  bool                  mCgAtEnd;
 
 };
 
 
 BCMapCellInfo::BCMapCellInfo(nsTableFrame* aTableFrame)
-{
-  mTableFrame = aTableFrame;
-  mTableIsLTR =
-    aTableFrame->StyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR;
-  if (mTableIsLTR) {
-    mStartSide = NS_SIDE_LEFT;
-    mEndSide = NS_SIDE_RIGHT;
-  }
-  else {
-    mStartSide = NS_SIDE_RIGHT;
-    mEndSide = NS_SIDE_LEFT;
-  }
-  mNumTableRows = mTableFrame->GetRowCount();
-  mNumTableCols = mTableFrame->GetColCount();
-  mTableBCData = static_cast<BCPropertyData*>
-    (mTableFrame->Properties().Get(TableBCProperty()));
-
+  : mTableFrame(aTableFrame)
+  , mNumTableRows(aTableFrame->GetRowCount())
+  , mNumTableCols(aTableFrame->GetColCount())
+  , mTableBCData(static_cast<BCPropertyData*>(
+      mTableFrame->Properties().Get(TableBCProperty())))
+  , mTableWM(aTableFrame->StyleContext())
+{
   ResetCellInfo();
 }
 
 void BCMapCellInfo::ResetCellInfo()
 {
   mCellData  = nullptr;
   mRowGroup  = nullptr;
-  mTopRow    = nullptr;
-  mBottomRow = nullptr;
+  mStartRow  = nullptr;
+  mEndRow    = nullptr;
   mColGroup  = nullptr;
-  mLeftCol   = nullptr;
-  mRightCol  = nullptr;
+  mStartCol  = nullptr;
+  mEndCol    = nullptr;
   mCell      = nullptr;
   mRowIndex  = mRowSpan = mColIndex = mColSpan = 0;
-  mRgAtTop = mRgAtBottom = mCgAtLeft = mCgAtRight = false;
+  mRgAtStart = mRgAtEnd = mCgAtStart = mCgAtEnd = false;
 }
 
 inline int32_t BCMapCellInfo::GetCellEndRowIndex() const
 {
   return mRowIndex + mRowSpan - 1;
 }
 
 inline int32_t BCMapCellInfo::GetCellEndColIndex() const
@@ -4349,90 +4338,90 @@ BCMapCellInfo::SetInfo(nsTableRowFrame* 
   // fill the cell information
   mCellData = aCellData;
   mColIndex = aColIndex;
 
   // initialize the row information if it was not previously set for cells in
   // this row
   mRowIndex = 0;
   if (aNewRow) {
-    mTopRow = aNewRow;
+    mStartRow = aNewRow;
     mRowIndex = aNewRow->GetRowIndex();
   }
 
   // fill cell frame info and row information
   mCell      = nullptr;
   mRowSpan   = 1;
   mColSpan   = 1;
   if (aCellData) {
     mCell = static_cast<nsBCTableCellFrame*>(aCellData->GetCellFrame());
     if (mCell) {
-      if (!mTopRow) {
-        mTopRow = static_cast<nsTableRowFrame*>(mCell->GetParent());
-        if (!mTopRow) ABORT0();
-        mRowIndex = mTopRow->GetRowIndex();
+      if (!mStartRow) {
+        mStartRow = mCell->GetTableRowFrame();
+        if (!mStartRow) ABORT0();
+        mRowIndex = mStartRow->GetRowIndex();
       }
       mColSpan = mTableFrame->GetEffectiveColSpan(*mCell, aCellMap);
       mRowSpan = mTableFrame->GetEffectiveRowSpan(*mCell, aCellMap);
     }
   }
 
-  if (!mTopRow) {
-    mTopRow = aIter->GetCurrentRow();
+  if (!mStartRow) {
+    mStartRow = aIter->GetCurrentRow();
   }
   if (1 == mRowSpan) {
-    mBottomRow = mTopRow;
+    mEndRow = mStartRow;
   }
   else {
-    mBottomRow = mTopRow->GetNextRow();
-    if (mBottomRow) {
-      for (int32_t spanY = 2; mBottomRow && (spanY < mRowSpan); spanY++) {
-        mBottomRow = mBottomRow->GetNextRow();
+    mEndRow = mStartRow->GetNextRow();
+    if (mEndRow) {
+      for (int32_t span = 2; mEndRow && span < mRowSpan; span++) {
+        mEndRow = mEndRow->GetNextRow();
       }
-      NS_ASSERTION(mBottomRow, "spanned row not found");
+      NS_ASSERTION(mEndRow, "spanned row not found");
     }
     else {
       NS_ASSERTION(false, "error in cell map");
       mRowSpan = 1;
-      mBottomRow = mTopRow;
+      mEndRow = mStartRow;
     }
   }
   // row group frame info
   // try to reuse the rgStart and rgEnd from the iterator as calls to
   // GetRowCount() are computationally expensive and should be avoided if
   // possible
   uint32_t rgStart  = aIter->mRowGroupStart;
   uint32_t rgEnd    = aIter->mRowGroupEnd;
-  mRowGroup = static_cast<nsTableRowGroupFrame*>(mTopRow->GetParent());
+  mRowGroup = mStartRow->GetTableRowGroupFrame();
   if (mRowGroup != aIter->GetCurrentRowGroup()) {
     rgStart = mRowGroup->GetStartRowIndex();
     rgEnd   = rgStart + mRowGroup->GetRowCount() - 1;
   }
-  uint32_t rowIndex = mTopRow->GetRowIndex();
-  mRgAtTop    = (rgStart == rowIndex);
-  mRgAtBottom = (rgEnd == rowIndex + mRowSpan - 1);
+  uint32_t rowIndex = mStartRow->GetRowIndex();
+  mRgAtStart = rgStart == rowIndex;
+  mRgAtEnd = rgEnd == rowIndex + mRowSpan - 1;
 
    // col frame info
-  mLeftCol = mTableFrame->GetColFrame(aColIndex);
-  if (!mLeftCol) ABORT0();
-
-  mRightCol = mLeftCol;
+  mStartCol = mTableFrame->GetColFrame(aColIndex);
+  if (!mStartCol) ABORT0();
+
+  mEndCol = mStartCol;
   if (mColSpan > 1) {
     nsTableColFrame* colFrame = mTableFrame->GetColFrame(aColIndex +
                                                          mColSpan -1);
     if (!colFrame) ABORT0();
-    mRightCol = colFrame;
+    mEndCol = colFrame;
   }
 
   // col group frame info
-  mColGroup = static_cast<nsTableColGroupFrame*>(mLeftCol->GetParent());
+  mColGroup = mStartCol->GetTableColGroupFrame();
   int32_t cgStart = mColGroup->GetStartColumnIndex();
   int32_t cgEnd = std::max(0, cgStart + mColGroup->GetColCount() - 1);
-  mCgAtLeft  = (cgStart == aColIndex);
-  mCgAtRight = (cgEnd == aColIndex + mColSpan - 1);
+  mCgAtStart = cgStart == aColIndex;
+  mCgAtEnd = cgEnd == aColIndex + mColSpan - 1;
 }
 
 bool
 BCMapCellIterator::SetNewRow(nsTableRowFrame* aRow)
 {
   mAtEnd   = true;
   mPrevRow = mRow;
   if (aRow) {
@@ -4668,111 +4657,79 @@ static uint8_t styleToPriority[13] = { 0
                                        1,  // NS_STYLE_BORDER_STYLE_INSET
                                        3,  // NS_STYLE_BORDER_STYLE_OUTSET
                                        9 };// NS_STYLE_BORDER_STYLE_HIDDEN
 // priority rules follow CSS 2.1 spec
 // 'hidden', 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove',
 // and the lowest: 'inset'. none is even weaker
 #define CELL_CORNER true
 
-/** return the border style, border color for a given frame and side
+/** return the border style, border color and optionally the width in
+  * pixel for a given frame and side
   * @param aFrame           - query the info for this frame
+  * @param aTableWM         - the writing-mode of the frame
   * @param aSide            - the side of the frame
   * @param aStyle           - the border style
   * @param aColor           - the border color
-  * @param aTableIsLTR      - table direction is LTR
+  * @param aWidth           - the border width in px.
+  * @param aWidth           - the border width in px
   */
 static void
-GetColorAndStyle(const nsIFrame*  aFrame,
-                 mozilla::css::Side aSide,
-                 uint8_t&         aStyle,
-                 nscolor&         aColor,
-                 bool             aTableIsLTR)
+GetColorAndStyle(const nsIFrame* aFrame,
+                 WritingMode aTableWM,
+                 LogicalSide aSide,
+                 uint8_t* aStyle,
+                 nscolor* aColor,
+                 BCPixelSize* aWidth = nullptr)
 {
   NS_PRECONDITION(aFrame, "null frame");
+  NS_PRECONDITION(aStyle && aColor, "null argument");
   // initialize out arg
-  aColor = 0;
+  *aColor = 0;
+  if (aWidth) {
+    *aWidth = 0;
+  }
+
   const nsStyleBorder* styleData = aFrame->StyleBorder();
-  if(!aTableIsLTR) { // revert the directions
-    if (NS_SIDE_RIGHT == aSide) {
-      aSide = NS_SIDE_LEFT;
-    }
-    else if (NS_SIDE_LEFT == aSide) {
-      aSide = NS_SIDE_RIGHT;
-    }
-  }
-  aStyle = styleData->GetBorderStyle(aSide);
-
-  if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) ||
-      (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
+  mozilla::Side physicalSide = aTableWM.PhysicalSide(aSide);
+  *aStyle = styleData->GetBorderStyle(physicalSide);
+
+  if ((NS_STYLE_BORDER_STYLE_NONE == *aStyle) ||
+      (NS_STYLE_BORDER_STYLE_HIDDEN == *aStyle)) {
     return;
   }
-  aColor = aFrame->StyleContext()->GetVisitedDependentColor(
-             nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color)[aSide]);
+  *aColor = aFrame->StyleContext()->GetVisitedDependentColor(
+    nsCSSProps::SubpropertyEntryFor(eCSSProperty_border_color)[physicalSide]);
+
+  if (aWidth) {
+    nscoord width = styleData->GetComputedBorderWidth(physicalSide);
+    *aWidth = nsPresContext::AppUnitsToIntCSSPixels(width);
+  }
 }
 
 /** coerce the paint style as required by CSS2.1
   * @param aFrame           - query the info for this frame
-  * @param aSide            - the side of the frame
-  * @param aStyle           - the border style
-  * @param aColor           - the border color
-  * @param aTableIsLTR      - table direction is LTR
-  */
-static void
-GetPaintStyleInfo(const nsIFrame*  aFrame,
-                  mozilla::css::Side aSide,
-                  uint8_t&         aStyle,
-                  nscolor&         aColor,
-                  bool             aTableIsLTR)
-{
-  GetColorAndStyle(aFrame, aSide, aStyle, aColor, aTableIsLTR);
-  if (NS_STYLE_BORDER_STYLE_INSET    == aStyle) {
-    aStyle = NS_STYLE_BORDER_STYLE_RIDGE;
-  }
-  else if (NS_STYLE_BORDER_STYLE_OUTSET    == aStyle) {
-    aStyle = NS_STYLE_BORDER_STYLE_GROOVE;
-  }
-}
-
-/** return the border style, border color and the width in pixel for a given
-  * frame and side
-  * @param aFrame           - query the info for this frame
+  * @param aTableWM         - the writing mode of the frame
   * @param aSide            - the side of the frame
   * @param aStyle           - the border style
   * @param aColor           - the border color
-  * @param aTableIsLTR      - table direction is LTR
-  * @param aWidth           - the border width in px.
-  * @param aTwipsToPixels   - conversion factor from twips to pixel
   */
 static void
-GetColorAndStyle(const nsIFrame*  aFrame,
-                 mozilla::css::Side aSide,
-                 uint8_t&         aStyle,
-                 nscolor&         aColor,
-                 bool             aTableIsLTR,
-                 BCPixelSize&     aWidth)
-{
-  GetColorAndStyle(aFrame, aSide, aStyle, aColor, aTableIsLTR);
-  if ((NS_STYLE_BORDER_STYLE_NONE == aStyle) ||
-      (NS_STYLE_BORDER_STYLE_HIDDEN == aStyle)) {
-    aWidth = 0;
-    return;
-  }
-  const nsStyleBorder* styleData = aFrame->StyleBorder();
-  nscoord width;
-  if(!aTableIsLTR) { // revert the directions
-    if (NS_SIDE_RIGHT == aSide) {
-      aSide = NS_SIDE_LEFT;
-    }
-    else if (NS_SIDE_LEFT == aSide) {
-      aSide = NS_SIDE_RIGHT;
-    }
-  }
-  width = styleData->GetComputedBorderWidth(aSide);
-  aWidth = nsPresContext::AppUnitsToIntCSSPixels(width);
+GetPaintStyleInfo(const nsIFrame* aFrame,
+                  WritingMode aTableWM,
+                  LogicalSide aSide,
+                  uint8_t* aStyle,
+                  nscolor* aColor)
+{
+  GetColorAndStyle(aFrame, aTableWM, aSide, aStyle, aColor);
+  if (NS_STYLE_BORDER_STYLE_INSET == *aStyle) {
+    *aStyle = NS_STYLE_BORDER_STYLE_RIDGE;
+  } else if (NS_STYLE_BORDER_STYLE_OUTSET == *aStyle) {
+    *aStyle = NS_STYLE_BORDER_STYLE_GROOVE;
+  }
 }
 
 class nsDelayedCalcBCBorders : public nsRunnable {
 public:
   explicit nsDelayedCalcBCBorders(nsIFrame* aFrame) :
     mFrame(aFrame) {}
 
   NS_IMETHOD Run() override {
@@ -4870,88 +4827,93 @@ CompareBorders(bool                aIsCo
   * adjacent frames are taken into account the ownership of a single border
   * segment is defined. The return value is the dominating border
   * The cellmap stores only top and left borders for each cellmap position.
   * If the cell border is owned by the cell that is left of the border
   * it will be an adjacent owner aka eAjaCellOwner. See celldata.h for the other
   * scenarios with a adjacent owner.
   * @param xxxFrame         - the frame for style information, might be zero if
   *                           it should not be considered
+  * @param aTableWM         - the writing mode of the frame
   * @param aSide            - side of the frames that should be considered
   * @param aAja             - the border comparison takes place from the point of
   *                           a frame that is adjacent to the cellmap entry, for
   *                           when a cell owns its lower border it will be the
   *                           adjacent owner as in the cellmap only top and left
   *                           borders are stored.
-  * @param aTwipsToPixels   - conversion factor as borders need to be drawn pixel
-  *                           aligned.
   */
 static BCCellBorder
 CompareBorders(const nsIFrame*  aTableFrame,
                const nsIFrame*  aColGroupFrame,
                const nsIFrame*  aColFrame,
                const nsIFrame*  aRowGroupFrame,
                const nsIFrame*  aRowFrame,
                const nsIFrame*  aCellFrame,
-               bool             aTableIsLTR,
-               mozilla::css::Side aSide,
+               WritingMode aTableWM,
+               LogicalSide aSide,
                bool             aAja)
 {
   BCCellBorder border, tempBorder;
-  bool horizontal = (NS_SIDE_TOP == aSide) || (NS_SIDE_BOTTOM == aSide);
+  bool inlineAxis = IsBlock(aSide);
 
   // start with the table as dominant if present
   if (aTableFrame) {
-    GetColorAndStyle(aTableFrame, aSide, border.style, border.color, aTableIsLTR, border.width);
+    GetColorAndStyle(aTableFrame, aTableWM, aSide,
+                     &border.style, &border.color, &border.width);
     border.owner = eTableOwner;
     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
       return border;
     }
   }
   // see if the colgroup is dominant
   if (aColGroupFrame) {
-    GetColorAndStyle(aColGroupFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
-    tempBorder.owner = (aAja && !horizontal) ? eAjaColGroupOwner : eColGroupOwner;
+    GetColorAndStyle(aColGroupFrame, aTableWM, aSide,
+                     &tempBorder.style, &tempBorder.color, &tempBorder.width);
+    tempBorder.owner = aAja && !inlineAxis ? eAjaColGroupOwner : eColGroupOwner;
     // pass here and below false for aSecondIsHorizontal as it is only used for corner calculations.
     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
       return border;
     }
   }
   // see if the col is dominant
   if (aColFrame) {
-    GetColorAndStyle(aColFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
-    tempBorder.owner = (aAja && !horizontal) ? eAjaColOwner : eColOwner;
+    GetColorAndStyle(aColFrame, aTableWM, aSide,
+                     &tempBorder.style, &tempBorder.color, &tempBorder.width);
+    tempBorder.owner = aAja && !inlineAxis ? eAjaColOwner : eColOwner;
     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
       return border;
     }
   }
   // see if the rowgroup is dominant
   if (aRowGroupFrame) {
-    GetColorAndStyle(aRowGroupFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
-    tempBorder.owner = (aAja && horizontal) ? eAjaRowGroupOwner : eRowGroupOwner;
+    GetColorAndStyle(aRowGroupFrame, aTableWM, aSide,
+                     &tempBorder.style, &tempBorder.color, &tempBorder.width);
+    tempBorder.owner = aAja && inlineAxis ? eAjaRowGroupOwner : eRowGroupOwner;
     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
       return border;
     }
   }
   // see if the row is dominant
   if (aRowFrame) {
-    GetColorAndStyle(aRowFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
-    tempBorder.owner = (aAja && horizontal) ? eAjaRowOwner : eRowOwner;
+    GetColorAndStyle(aRowFrame, aTableWM, aSide,
+                     &tempBorder.style, &tempBorder.color, &tempBorder.width);
+    tempBorder.owner = aAja && inlineAxis ? eAjaRowOwner : eRowOwner;
     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
     if (NS_STYLE_BORDER_STYLE_HIDDEN == border.style) {
       return border;
     }
   }
   // see if the cell is dominant
   if (aCellFrame) {
-    GetColorAndStyle(aCellFrame, aSide, tempBorder.style, tempBorder.color, aTableIsLTR, tempBorder.width);
-    tempBorder.owner = (aAja) ? eAjaCellOwner : eCellOwner;
+    GetColorAndStyle(aCellFrame, aTableWM, aSide,
+                     &tempBorder.style, &tempBorder.color, &tempBorder.width);
+    tempBorder.owner = aAja ? eAjaCellOwner : eCellOwner;
     border = CompareBorders(!CELL_CORNER, border, tempBorder, false);
   }
   return border;
 }
 
 static bool
 Perpendicular(mozilla::css::Side aSide1,
               mozilla::css::Side aSide2)
@@ -5303,274 +5265,280 @@ nsTableFrame::ExpandBCDamageArea(TableAr
   }
 }
 
 
 #define ADJACENT    true
 #define HORIZONTAL  true
 
 void
-BCMapCellInfo::SetTableTopLeftContBCBorder()
+BCMapCellInfo::SetTableBStartIStartContBCBorder()
 {
   BCCellBorder currentBorder;
   //calculate continuous top first row & rowgroup border: special case
   //because it must include the table in the collapse
-  if (mTopRow) {
+  if (mStartRow) {
     currentBorder = CompareBorders(mTableFrame, nullptr, nullptr, mRowGroup,
-                                   mTopRow, nullptr, mTableIsLTR,
-                                   NS_SIDE_TOP, !ADJACENT);
-    mTopRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
-  }
-  if (mCgAtRight && mColGroup) {
+                                   mStartRow, nullptr, mTableWM,
+                                   eLogicalSideBStart, !ADJACENT);
+    mStartRow->SetContinuousBCBorderWidth(eLogicalSideBStart,
+                                          currentBorder.width);
+  }
+  if (mCgAtEnd && mColGroup) {
     //calculate continuous top colgroup border once per colgroup
     currentBorder = CompareBorders(mTableFrame, mColGroup, nullptr, mRowGroup,
-                                   mTopRow, nullptr, mTableIsLTR,
-                                   NS_SIDE_TOP, !ADJACENT);
-    mColGroup->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
+                                   mStartRow, nullptr, mTableWM,
+                                   eLogicalSideBStart, !ADJACENT);
+    mColGroup->SetContinuousBCBorderWidth(eLogicalSideBStart,
+                                          currentBorder.width);
   }
   if (0 == mColIndex) {
-    currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, nullptr,
-                                   nullptr, nullptr, mTableIsLTR, NS_SIDE_LEFT,
-                                   !ADJACENT);
+    currentBorder = CompareBorders(mTableFrame, mColGroup, mStartCol, nullptr,
+                                   nullptr, nullptr, mTableWM,
+                                   eLogicalSideIStart, !ADJACENT);
     mTableFrame->SetContinuousLeftBCBorderWidth(currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetRowGroupLeftContBCBorder()
+BCMapCellInfo::SetRowGroupIStartContBCBorder()
 {
   BCCellBorder currentBorder;
   //get row group continuous borders
-  if (mRgAtBottom && mRowGroup) { //once per row group, so check for bottom
-     currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
-                                    nullptr, nullptr, mTableIsLTR, NS_SIDE_LEFT,
-                                    !ADJACENT);
-     mRowGroup->SetContinuousBCBorderWidth(mStartSide, currentBorder.width);
+  if (mRgAtEnd && mRowGroup) { //once per row group, so check for bottom
+     currentBorder = CompareBorders(mTableFrame, mColGroup, mStartCol,
+                                    mRowGroup, nullptr, nullptr, mTableWM,
+                                    eLogicalSideIStart, !ADJACENT);
+     mRowGroup->SetContinuousBCBorderWidth(eLogicalSideIStart,
+                                           currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetRowGroupRightContBCBorder()
+BCMapCellInfo::SetRowGroupIEndContBCBorder()
 {
   BCCellBorder currentBorder;
   //get row group continuous borders
-  if (mRgAtBottom && mRowGroup) { //once per mRowGroup, so check for bottom
-    currentBorder = CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
-                                   nullptr, nullptr, mTableIsLTR, NS_SIDE_RIGHT,
+  if (mRgAtEnd && mRowGroup) { //once per mRowGroup, so check for bottom
+    currentBorder = CompareBorders(mTableFrame, mColGroup, mEndCol, mRowGroup,
+                                   nullptr, nullptr, mTableWM, eLogicalSideIEnd,
                                    ADJACENT);
-    mRowGroup->SetContinuousBCBorderWidth(mEndSide, currentBorder.width);
+    mRowGroup->SetContinuousBCBorderWidth(eLogicalSideIEnd,
+                                          currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetColumnTopRightContBCBorder()
+BCMapCellInfo::SetColumnBStartIEndContBCBorder()
 {
   BCCellBorder currentBorder;
   //calculate column continuous borders
   //we only need to do this once, so we'll do it only on the first row
   currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
-                                 mCurrentColFrame, mRowGroup, mTopRow, nullptr,
-                                 mTableIsLTR, NS_SIDE_TOP, !ADJACENT);
-  ((nsTableColFrame*) mCurrentColFrame)->SetContinuousBCBorderWidth(NS_SIDE_TOP,
-                                                           currentBorder.width);
+                                 mCurrentColFrame, mRowGroup, mStartRow,
+                                 nullptr, mTableWM, eLogicalSideBStart,
+                                 !ADJACENT);
+  ((nsTableColFrame*) mCurrentColFrame)->
+    SetContinuousBCBorderWidth(eLogicalSideBStart, currentBorder.width);
   if (mNumTableCols == GetCellEndColIndex() + 1) {
     currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
                                    mCurrentColFrame, nullptr, nullptr, nullptr,
-                                   mTableIsLTR, NS_SIDE_RIGHT, !ADJACENT);
+                                   mTableWM, eLogicalSideIEnd, !ADJACENT);
   }
   else {
     currentBorder = CompareBorders(nullptr, mCurrentColGroupFrame,
                                    mCurrentColFrame, nullptr,nullptr, nullptr,
-                                   mTableIsLTR, NS_SIDE_RIGHT, !ADJACENT);
-  }
-  mCurrentColFrame->SetContinuousBCBorderWidth(NS_SIDE_RIGHT,
+                                   mTableWM, eLogicalSideIEnd, !ADJACENT);
+  }
+  mCurrentColFrame->SetContinuousBCBorderWidth(eLogicalSideIEnd,
                                                currentBorder.width);
 }
 
 void
-BCMapCellInfo::SetColumnBottomContBCBorder()
+BCMapCellInfo::SetColumnBEndContBCBorder()
 {
   BCCellBorder currentBorder;
   //get col continuous border
   currentBorder = CompareBorders(mTableFrame, mCurrentColGroupFrame,
-                                 mCurrentColFrame, mRowGroup, mBottomRow,
-                                 nullptr, mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
-  mCurrentColFrame->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM,
+                                 mCurrentColFrame, mRowGroup, mEndRow,
+                                 nullptr, mTableWM, eLogicalSideBEnd, ADJACENT);
+  mCurrentColFrame->SetContinuousBCBorderWidth(eLogicalSideBEnd,
                                                currentBorder.width);
 }
 
 void
-BCMapCellInfo::SetColGroupBottomContBCBorder()
+BCMapCellInfo::SetColGroupBEndContBCBorder()
 {
   BCCellBorder currentBorder;
   if (mColGroup) {
     currentBorder = CompareBorders(mTableFrame, mColGroup, nullptr, mRowGroup,
-                                   mBottomRow, nullptr, mTableIsLTR,
-                                   NS_SIDE_BOTTOM, ADJACENT);
+                                   mEndRow, nullptr, mTableWM,
+                                   eLogicalSideBEnd, ADJACENT);
     mColGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetRowGroupBottomContBCBorder()
+BCMapCellInfo::SetRowGroupBEndContBCBorder()
 {
   BCCellBorder currentBorder;
   if (mRowGroup) {
     currentBorder = CompareBorders(mTableFrame, nullptr, nullptr, mRowGroup,
-                                   mBottomRow, nullptr, mTableIsLTR,
-                                   NS_SIDE_BOTTOM, ADJACENT);
+                                   mEndRow, nullptr, mTableWM,
+                                   eLogicalSideBEnd, ADJACENT);
     mRowGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetInnerRowGroupBottomContBCBorder(const nsIFrame* aNextRowGroup,
-                                                  nsTableRowFrame* aNextRow)
+BCMapCellInfo::SetInnerRowGroupBEndContBCBorder(const nsIFrame* aNextRowGroup,
+                                                nsTableRowFrame* aNextRow)
 {
   BCCellBorder currentBorder, adjacentBorder;
 
-  const nsIFrame* rowgroup = (mRgAtBottom) ? mRowGroup : nullptr;
-  currentBorder = CompareBorders(nullptr, nullptr, nullptr, rowgroup, mBottomRow,
-                                 nullptr, mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
+  const nsIFrame* rowgroup = mRgAtEnd ? mRowGroup : nullptr;
+  currentBorder = CompareBorders(nullptr, nullptr, nullptr, rowgroup, mEndRow,
+                                 nullptr, mTableWM, eLogicalSideBEnd, ADJACENT);
 
   adjacentBorder = CompareBorders(nullptr, nullptr, nullptr, aNextRowGroup,
-                                  aNextRow, nullptr, mTableIsLTR, NS_SIDE_TOP,
+                                  aNextRow, nullptr, mTableWM, eLogicalSideBStart,
                                   !ADJACENT);
   currentBorder = CompareBorders(false, currentBorder, adjacentBorder,
                                  HORIZONTAL);
   if (aNextRow) {
-    aNextRow->SetContinuousBCBorderWidth(NS_SIDE_TOP, currentBorder.width);
-  }
-  if (mRgAtBottom && mRowGroup) {
+    aNextRow->SetContinuousBCBorderWidth(eLogicalSideBStart,
+                                         currentBorder.width);
+  }
+  if (mRgAtEnd && mRowGroup) {
     mRowGroup->SetContinuousBCBorderWidth(NS_SIDE_BOTTOM, currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetRowLeftContBCBorder()
+BCMapCellInfo::SetRowIStartContBCBorder()
 {
   //get row continuous borders
   if (mCurrentRowFrame) {
     BCCellBorder currentBorder;
-    currentBorder = CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
-                                   mCurrentRowFrame, nullptr, mTableIsLTR,
-                                   NS_SIDE_LEFT, !ADJACENT);
-    mCurrentRowFrame->SetContinuousBCBorderWidth(mStartSide,
+    currentBorder = CompareBorders(mTableFrame, mColGroup, mStartCol,
+                                   mRowGroup, mCurrentRowFrame, nullptr,
+                                   mTableWM, eLogicalSideIStart, !ADJACENT);
+    mCurrentRowFrame->SetContinuousBCBorderWidth(eLogicalSideIStart,
                                                  currentBorder.width);
   }
 }
 
 void
-BCMapCellInfo::SetRowRightContBCBorder()
+BCMapCellInfo::SetRowIEndContBCBorder()
 {
   if (mCurrentRowFrame) {
     BCCellBorder currentBorder;
-    currentBorder = CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
-                                   mCurrentRowFrame, nullptr, mTableIsLTR,
-                                   NS_SIDE_RIGHT, ADJACENT);
-    mCurrentRowFrame->SetContinuousBCBorderWidth(mEndSide,
+    currentBorder = CompareBorders(mTableFrame, mColGroup, mEndCol, mRowGroup,
+                                   mCurrentRowFrame, nullptr, mTableWM,
+                                   eLogicalSideIEnd, ADJACENT);
+    mCurrentRowFrame->SetContinuousBCBorderWidth(eLogicalSideIEnd,
                                                  currentBorder.width);
   }
 }
 void
-BCMapCellInfo::SetTableTopBorderWidth(BCPixelSize aWidth)
+BCMapCellInfo::SetTableBStartBorderWidth(BCPixelSize aWidth)
 {
   mTableBCData->mTopBorderWidth = std::max(mTableBCData->mTopBorderWidth, aWidth);
 }
 
 void
-BCMapCellInfo::SetTableLeftBorderWidth(int32_t aRowY, BCPixelSize aWidth)
+BCMapCellInfo::SetTableIStartBorderWidth(int32_t aRowY, BCPixelSize aWidth)
 {
   // update the left/right first cell border
   if (aRowY == 0) {
-    if (mTableIsLTR) {
+    if (mTableWM.IsBidiLTR()) {
       mTableBCData->mLeftCellBorderWidth = aWidth;
     }
     else {
       mTableBCData->mRightCellBorderWidth = aWidth;
     }
   }
   mTableBCData->mLeftBorderWidth = std::max(mTableBCData->mLeftBorderWidth,
                                           aWidth);
 }
 
 void
-BCMapCellInfo::SetTableRightBorderWidth(int32_t aRowY, BCPixelSize aWidth)
+BCMapCellInfo::SetTableIEndBorderWidth(int32_t aRowY, BCPixelSize aWidth)
 {
   // update the left/right first cell border
   if (aRowY == 0) {
-    if (mTableIsLTR) {
+    if (mTableWM.IsBidiLTR()) {
       mTableBCData->mRightCellBorderWidth = aWidth;
     }
     else {
       mTableBCData->mLeftCellBorderWidth = aWidth;
     }
   }
   mTableBCData->mRightBorderWidth = std::max(mTableBCData->mRightBorderWidth,
                                            aWidth);
 }
 
 void
-BCMapCellInfo::SetRightBorderWidths(BCPixelSize aWidth)
+BCMapCellInfo::SetIEndBorderWidths(BCPixelSize aWidth)
 {
    // update the borders of the cells and cols affected
   if (mCell) {
-    mCell->SetBorderWidth(mEndSide, std::max(aWidth,
-                          mCell->GetBorderWidth(mEndSide)));
-  }
-  if (mRightCol) {
-    BCPixelSize half = BC_BORDER_LEFT_HALF(aWidth);
-    mRightCol->SetRightBorderWidth(std::max(nscoord(half),
-                                   mRightCol->GetRightBorderWidth()));
+    mCell->SetBorderWidth(eLogicalSideIEnd, std::max(aWidth,
+                          mCell->GetBorderWidth(eLogicalSideIEnd)));
+  }
+  if (mEndCol) {
+    BCPixelSize half = BC_BORDER_START_HALF(aWidth);
+    mEndCol->SetIEndBorderWidth(
+      std::max(nscoord(half), mEndCol->GetIEndBorderWidth()));
   }
 }
 
 void
-BCMapCellInfo::SetBottomBorderWidths(BCPixelSize aWidth)
+BCMapCellInfo::SetBEndBorderWidths(BCPixelSize aWidth)
 {
   // update the borders of the affected cells and rows
   if (mCell) {
-    mCell->SetBorderWidth(NS_SIDE_BOTTOM, std::max(aWidth,
-                          mCell->GetBorderWidth(NS_SIDE_BOTTOM)));
-  }
-  if (mBottomRow) {
-    BCPixelSize half = BC_BORDER_TOP_HALF(aWidth);
-    mBottomRow->SetBottomBCBorderWidth(std::max(nscoord(half),
-                                       mBottomRow->GetBottomBCBorderWidth()));
+    mCell->SetBorderWidth(eLogicalSideBEnd, std::max(aWidth,
+                          mCell->GetBorderWidth(eLogicalSideBEnd)));
+  }
+  if (mEndRow) {
+    BCPixelSize half = BC_BORDER_START_HALF(aWidth);
+    mEndRow->SetBEndBCBorderWidth(
+      std::max(nscoord(half), mEndRow->GetBEndBCBorderWidth()));
   }
 }
 void
-BCMapCellInfo::SetTopBorderWidths(BCPixelSize aWidth)
+BCMapCellInfo::SetBStartBorderWidths(BCPixelSize aWidth)
 {
  if (mCell) {
-     mCell->SetBorderWidth(NS_SIDE_TOP, std::max(aWidth,
-                           mCell->GetBorderWidth(NS_SIDE_TOP)));
-  }
-  if (mTopRow) {
-    BCPixelSize half = BC_BORDER_BOTTOM_HALF(aWidth);
-    mTopRow->SetTopBCBorderWidth(std::max(nscoord(half),
-                                        mTopRow->GetTopBCBorderWidth()));
+     mCell->SetBorderWidth(eLogicalSideBStart, std::max(aWidth,
+                           mCell->GetBorderWidth(eLogicalSideBStart)));
+  }
+  if (mStartRow) {
+    BCPixelSize half = BC_BORDER_END_HALF(aWidth);
+    mStartRow->SetBStartBCBorderWidth(
+      std::max(nscoord(half), mStartRow->GetBStartBCBorderWidth()));
   }
 }
 void
-BCMapCellInfo::SetLeftBorderWidths(BCPixelSize aWidth)
+BCMapCellInfo::SetIStartBorderWidths(BCPixelSize aWidth)
 {
   if (mCell) {
-    mCell->SetBorderWidth(mStartSide, std::max(aWidth,
-                          mCell->GetBorderWidth(mStartSide)));
-  }
-  if (mLeftCol) {
-    BCPixelSize half = BC_BORDER_RIGHT_HALF(aWidth);
-    mLeftCol->SetLeftBorderWidth(std::max(nscoord(half),
-                                        mLeftCol->GetLeftBorderWidth()));
+    mCell->SetBorderWidth(eLogicalSideIStart, std::max(aWidth,
+                          mCell->GetBorderWidth(eLogicalSideIStart)));
+  }
+  if (mStartCol) {
+    BCPixelSize half = BC_BORDER_END_HALF(aWidth);
+    mStartCol->SetIStartBorderWidth(
+      std::max(nscoord(half), mStartCol->GetIStartBorderWidth()));
   }
 }
 
 void
-BCMapCellInfo::SetTableBottomBorderWidth(BCPixelSize aWidth)
+BCMapCellInfo::SetTableBEndBorderWidth(BCPixelSize aWidth)
 {
   mTableBCData->mBottomBorderWidth = std::max(mTableBCData->mBottomBorderWidth,
                                             aWidth);
 }
 
 void
 BCMapCellInfo::SetColumn(int32_t aColX)
 {
@@ -5583,79 +5551,79 @@ BCMapCellInfo::SetColumn(int32_t aColX)
   if (!mCurrentColGroupFrame) {
     NS_ERROR("null mCurrentColGroupFrame");
   }
 }
 
 void
 BCMapCellInfo::IncrementRow(bool aResetToTopRowOfCell)
 {
-  mCurrentRowFrame = (aResetToTopRowOfCell) ? mTopRow :
-                                                mCurrentRowFrame->GetNextRow();
+  mCurrentRowFrame =
+    aResetToTopRowOfCell ? mStartRow : mCurrentRowFrame->GetNextRow();
 }
 
 BCCellBorder
-BCMapCellInfo::GetTopEdgeBorder()
+BCMapCellInfo::GetBStartEdgeBorder()
 {
   return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
-                        mRowGroup, mTopRow, mCell, mTableIsLTR, NS_SIDE_TOP,
-                        !ADJACENT);
+                        mRowGroup, mStartRow, mCell, mTableWM,
+                        eLogicalSideBStart, !ADJACENT);
 }
 
 BCCellBorder
-BCMapCellInfo::GetBottomEdgeBorder()
+BCMapCellInfo::GetBEndEdgeBorder()
 {
   return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
-                        mRowGroup, mBottomRow, mCell, mTableIsLTR,
-                        NS_SIDE_BOTTOM, ADJACENT);
+                        mRowGroup, mEndRow, mCell, mTableWM,
+                        eLogicalSideBEnd, ADJACENT);
 }
 BCCellBorder
-BCMapCellInfo::GetLeftEdgeBorder()
-{
-  return CompareBorders(mTableFrame, mColGroup, mLeftCol, mRowGroup,
-                        mCurrentRowFrame, mCell, mTableIsLTR, NS_SIDE_LEFT,
+BCMapCellInfo::GetIStartEdgeBorder()
+{
+  return CompareBorders(mTableFrame, mColGroup, mStartCol, mRowGroup,
+                        mCurrentRowFrame, mCell, mTableWM, eLogicalSideIStart,
                         !ADJACENT);
 }
 BCCellBorder
-BCMapCellInfo::GetRightEdgeBorder()
-{
-  return CompareBorders(mTableFrame, mColGroup, mRightCol, mRowGroup,
-                        mCurrentRowFrame, mCell, mTableIsLTR, NS_SIDE_RIGHT,
+BCMapCellInfo::GetIEndEdgeBorder()
+{
+  return CompareBorders(mTableFrame, mColGroup, mEndCol, mRowGroup,
+                        mCurrentRowFrame, mCell, mTableWM, eLogicalSideIEnd,
                         ADJACENT);
 }
 BCCellBorder
-BCMapCellInfo::GetRightInternalBorder()
-{
-  const nsIFrame* cg = (mCgAtRight) ? mColGroup : nullptr;
-  return CompareBorders(nullptr, cg, mRightCol, nullptr, nullptr, mCell,
-                        mTableIsLTR, NS_SIDE_RIGHT, ADJACENT);
+BCMapCellInfo::GetIEndInternalBorder()
+{
+  const nsIFrame* cg = mCgAtEnd ? mColGroup : nullptr;
+  return CompareBorders(nullptr, cg, mEndCol, nullptr, nullptr, mCell,
+                        mTableWM, eLogicalSideIEnd, ADJACENT);
 }
 
 BCCellBorder
-BCMapCellInfo::GetLeftInternalBorder()
-{
-  const nsIFrame* cg = (mCgAtLeft) ? mColGroup : nullptr;
-  return CompareBorders(nullptr, cg, mLeftCol, nullptr, nullptr, mCell,
-                        mTableIsLTR, NS_SIDE_LEFT, !ADJACENT);
+BCMapCellInfo::GetIStartInternalBorder()
+{
+  const nsIFrame* cg = mCgAtStart ? mColGroup : nullptr;
+  return CompareBorders(nullptr, cg, mStartCol, nullptr, nullptr, mCell,
+                        mTableWM, eLogicalSideIStart, !ADJACENT);
 }
 
 BCCellBorder
-BCMapCellInfo::GetBottomInternalBorder()
-{
-  const nsIFrame* rg = (mRgAtBottom) ? mRowGroup : nullptr;
-  return CompareBorders(nullptr, nullptr, nullptr, rg, mBottomRow, mCell,
-                        mTableIsLTR, NS_SIDE_BOTTOM, ADJACENT);
+BCMapCellInfo::GetBEndInternalBorder()
+{
+  const nsIFrame* rg = mRgAtEnd ? mRowGroup : nullptr;
+  return CompareBorders(nullptr, nullptr, nullptr, rg, mEndRow, mCell,
+                        mTableWM, eLogicalSideBEnd, ADJACENT);
 }
 
 BCCellBorder
-BCMapCellInfo::GetTopInternalBorder()
-{
-  const nsIFrame* rg = (mRgAtTop) ? mRowGroup : nullptr;
-  return CompareBorders(nullptr, nullptr, nullptr, rg, mTopRow, mCell,
-                        mTableIsLTR, NS_SIDE_TOP, !ADJACENT);
+BCMapCellInfo::GetBStartInternalBorder()
+{
+  const nsIFrame* rg = mRgAtStart ? mRowGroup : nullptr;
+  return CompareBorders(nullptr, nullptr, nullptr, rg, mStartRow, mCell,
+                        mTableWM, eLogicalSideBStart, !ADJACENT);
 }
 
 /* Here is the order for storing border edges in the cell map as a cell is processed. There are
    n=colspan top and bottom border edges per cell and n=rowspan left and right border edges per cell.
 
    1) On the top edge of the table, store the top edge. Never store the top edge otherwise, since
       a bottom edge from a cell above will take care of it.
    2) On the left edge of the table, store the left edge. Never store the left edge othewise, since
@@ -5771,17 +5739,17 @@ nsTableFrame::CalcBCBorders()
     if (0 == info.mRowIndex) {
       if (!tableBorderReset[NS_SIDE_TOP]) {
         propData->mTopBorderWidth = 0;
         tableBorderReset[NS_SIDE_TOP] = true;
       }
       for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex();
            colX++) {
         info.SetColumn(colX);
-        currentBorder = info.GetTopEdgeBorder();
+        currentBorder = info.GetBStartEdgeBorder();
         // update/store the top left & top right corners of the seg
         BCCornerInfo& tlCorner = topCorners[colX]; // top left
         if (0 == colX) {
           // we are on right hand side of the corner
           tlCorner.Set(NS_SIDE_RIGHT, currentBorder);
         }
         else {
           tlCorner.Update(NS_SIDE_RIGHT, currentBorder);
@@ -5793,21 +5761,21 @@ nsTableFrame::CalcBCBorders()
         topCorners[colX + 1].Set(NS_SIDE_LEFT, currentBorder); // top right
         // update lastTopBorder and see if a new segment starts
         startSeg = SetHorBorder(currentBorder, tlCorner, lastTopBorder);
         // store the border segment in the cell map
         tableCellMap->SetBCBorderEdge(NS_SIDE_TOP, *iter.mCellMap, 0, 0, colX,
                                       1, currentBorder.owner,
                                       currentBorder.width, startSeg);
 
-        info.SetTableTopBorderWidth(currentBorder.width);
-        info.SetTopBorderWidths(currentBorder.width);
-        info.SetColumnTopRightContBCBorder();
+        info.SetTableBStartBorderWidth(currentBorder.width);
+        info.SetBStartBorderWidths(currentBorder.width);
+        info.SetColumnBStartIEndContBCBorder();
       }
-      info.SetTableTopLeftContBCBorder();
+      info.SetTableBStartIStartContBCBorder();
     }
     else {
       // see if the top border needs to be the start of a segment due to a
       // vertical border owning the corner
       if (info.mColIndex > 0) {
         BCData& data = info.mCellData->mData;
         if (!data.IsTopStart()) {
           mozilla::css::Side cornerSide;
@@ -5827,53 +5795,53 @@ nsTableFrame::CalcBCBorders()
       if (!tableBorderReset[NS_SIDE_LEFT]) {
         propData->mLeftBorderWidth = 0;
         tableBorderReset[NS_SIDE_LEFT] = true;
       }
       info.mCurrentRowFrame = nullptr;
       for (int32_t rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
            rowY++) {
         info.IncrementRow(rowY == info.mRowIndex);
-        currentBorder = info.GetLeftEdgeBorder();
+        currentBorder = info.GetIStartEdgeBorder();
         BCCornerInfo& tlCorner = (0 == rowY) ? topCorners[0] : bottomCorners[0];
         tlCorner.Update(NS_SIDE_BOTTOM, currentBorder);
         tableCellMap->SetBCBorderCorner(eTopLeft, *iter.mCellMap,
                                         iter.mRowGroupStart, rowY, 0,
                                         mozilla::css::Side(tlCorner.ownerSide),
                                         tlCorner.subWidth,
                                         tlCorner.bevel);
         bottomCorners[0].Set(NS_SIDE_TOP, currentBorder); // bottom left
 
         // update lastVerBordersBorder and see if a new segment starts
         startSeg = SetBorder(currentBorder, lastVerBorders[0]);
         // store the border segment in the cell map
         tableCellMap->SetBCBorderEdge(NS_SIDE_LEFT, *iter.mCellMap,
                                       iter.mRowGroupStart, rowY, info.mColIndex,
                                       1, currentBorder.owner,
                                       currentBorder.width, startSeg);
-        info.SetTableLeftBorderWidth(rowY , currentBorder.width);
-        info.SetLeftBorderWidths(currentBorder.width);
-        info.SetRowLeftContBCBorder();
+        info.SetTableIStartBorderWidth(rowY , currentBorder.width);
+        info.SetIStartBorderWidths(currentBorder.width);
+        info.SetRowIStartContBCBorder();
       }
-      info.SetRowGroupLeftContBCBorder();
+      info.SetRowGroupIStartContBCBorder();
     }
 
     // find the dominant border considering the cell's right border, adjacent
     // cells and the table, row group, row
     if (info.mNumTableCols == info.GetCellEndColIndex() + 1) {
       // touches right edge of table
       if (!tableBorderReset[NS_SIDE_RIGHT]) {
         propData->mRightBorderWidth = 0;
         tableBorderReset[NS_SIDE_RIGHT] = true;
       }
       info.mCurrentRowFrame = nullptr;
       for (int32_t rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
            rowY++) {
         info.IncrementRow(rowY == info.mRowIndex);
-        currentBorder = info.GetRightEdgeBorder();
+        currentBorder = info.GetIEndEdgeBorder();
         // update/store the top right & bottom right corners
         BCCornerInfo& trCorner = (0 == rowY) ?
                                  topCorners[info.GetCellEndColIndex() + 1] :
                                  bottomCorners[info.GetCellEndColIndex() + 1];
         trCorner.Update(NS_SIDE_BOTTOM, currentBorder);   // top right
         tableCellMap->SetBCBorderCorner(eTopRight, *iter.mCellMap,
                                         iter.mRowGroupStart, rowY,
                                         info.GetCellEndColIndex(),
@@ -5892,30 +5860,30 @@ nsTableFrame::CalcBCBorders()
         startSeg = SetBorder(currentBorder,
                              lastVerBorders[info.GetCellEndColIndex() + 1]);
         // store the border segment in the cell map and update cellBorders
         tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *iter.mCellMap,
                                       iter.mRowGroupStart, rowY,
                                       info.GetCellEndColIndex(), 1,
                                       currentBorder.owner, currentBorder.width,
                                       startSeg);
-        info.SetTableRightBorderWidth(rowY, currentBorder.width);
-        info.SetRightBorderWidths(currentBorder.width);
-        info.SetRowRightContBCBorder();
+        info.SetTableIEndBorderWidth(rowY, currentBorder.width);
+        info.SetIEndBorderWidths(currentBorder.width);
+        info.SetRowIEndContBCBorder();
       }
-      info.SetRowGroupRightContBCBorder();
+      info.SetRowGroupIEndContBCBorder();
     }
     else {
       int32_t segLength = 0;
       BCMapCellInfo priorAjaInfo(this);
       for (int32_t rowY = info.mRowIndex; rowY <= info.GetCellEndRowIndex();
            rowY += segLength) {
         iter.PeekRight(info, rowY, ajaInfo);
-        currentBorder  = info.GetRightInternalBorder();
-        adjacentBorder = ajaInfo.GetLeftInternalBorder();
+        currentBorder = info.GetIEndInternalBorder();
+        adjacentBorder = ajaInfo.GetIStartInternalBorder();
         currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
                                         adjacentBorder, !HORIZONTAL);
 
         segLength = std::max(1, ajaInfo.mRowIndex + ajaInfo.mRowSpan - rowY);
         segLength = std::min(segLength, info.mRowIndex + info.mRowSpan - rowY);
 
         // update lastVerBorders and see if a new segment starts
         startSeg = SetBorder(currentBorder,
@@ -5923,31 +5891,31 @@ nsTableFrame::CalcBCBorders()
         // store the border segment in the cell map and update cellBorders
         if (info.GetCellEndColIndex() < damageArea.EndCol() &&
             rowY >= damageArea.StartRow() && rowY < damageArea.EndRow()) {
           tableCellMap->SetBCBorderEdge(NS_SIDE_RIGHT, *iter.mCellMap,
                                         iter.mRowGroupStart, rowY,
                                         info.GetCellEndColIndex(), segLength,
                                         currentBorder.owner,
                                         currentBorder.width, startSeg);
-          info.SetRightBorderWidths(currentBorder.width);
-          ajaInfo.SetLeftBorderWidths(currentBorder.width);
+          info.SetIEndBorderWidths(currentBorder.width);
+          ajaInfo.SetIStartBorderWidths(currentBorder.width);
         }
         // update the top right corner
         bool hitsSpanOnRight = (rowY > ajaInfo.mRowIndex) &&
                                   (rowY < ajaInfo.mRowIndex + ajaInfo.mRowSpan);
         BCCornerInfo* trCorner = ((0 == rowY) || hitsSpanOnRight) ?
                                  &topCorners[info.GetCellEndColIndex() + 1] :
                                  &bottomCorners[info.GetCellEndColIndex() + 1];
         trCorner->Update(NS_SIDE_BOTTOM, currentBorder);
         // if this is not the first time through,
         // consider the segment to the right
         if (rowY != info.mRowIndex) {
-          currentBorder  = priorAjaInfo.GetBottomInternalBorder();
-          adjacentBorder = ajaInfo.GetTopInternalBorder();
+          currentBorder = priorAjaInfo.GetBEndInternalBorder();
+          adjacentBorder = ajaInfo.GetBStartInternalBorder();
           currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
                                           adjacentBorder, HORIZONTAL);
           trCorner->Update(NS_SIDE_RIGHT, currentBorder);
         }
         // store the top right corner in the cell map
         if (info.GetCellEndColIndex() < damageArea.EndCol() &&
             rowY >= damageArea.StartRow()) {
           if (0 != rowY) {
@@ -5988,17 +5956,17 @@ nsTableFrame::CalcBCBorders()
       // touches bottom edge of table
       if (!tableBorderReset[NS_SIDE_BOTTOM]) {
         propData->mBottomBorderWidth = 0;
         tableBorderReset[NS_SIDE_BOTTOM] = true;
       }
       for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex();
            colX++) {
         info.SetColumn(colX);
-        currentBorder = info.GetBottomEdgeBorder();
+        currentBorder = info.GetBEndEdgeBorder();
         // update/store the bottom left & bottom right corners
         BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
         blCorner.Update(NS_SIDE_RIGHT, currentBorder);
         tableCellMap->SetBCBorderCorner(eBottomLeft, *iter.mCellMap,
                                         iter.mRowGroupStart,
                                         info.GetCellEndRowIndex(),
                                         colX,
                                         mozilla::css::Side(blCorner.ownerSide),
@@ -6029,30 +5997,30 @@ nsTableFrame::CalcBCBorders()
                                       info.GetCellEndRowIndex(),
                                       colX, 1, currentBorder.owner,
                                       currentBorder.width, startSeg);
         // update lastBottomBorders
         lastBottomBorder.rowIndex = info.GetCellEndRowIndex() + 1;
         lastBottomBorder.rowSpan = info.mRowSpan;
         lastBottomBorders[colX] = lastBottomBorder;
 
-        info.SetBottomBorderWidths(currentBorder.width);
-        info.SetTableBottomBorderWidth(currentBorder.width);
-        info.SetColumnBottomContBCBorder();
+        info.SetBEndBorderWidths(currentBorder.width);
+        info.SetTableBEndBorderWidth(currentBorder.width);
+        info.SetColumnBEndContBCBorder();
       }
-      info.SetRowGroupBottomContBCBorder();
-      info.SetColGroupBottomContBCBorder();
+      info.SetRowGroupBEndContBCBorder();
+      info.SetColGroupBEndContBCBorder();
     }
     else {
       int32_t segLength = 0;
       for (int32_t colX = info.mColIndex; colX <= info.GetCellEndColIndex();
            colX += segLength) {
         iter.PeekBottom(info, colX, ajaInfo);
-        currentBorder  = info.GetBottomInternalBorder();
-        adjacentBorder = ajaInfo.GetTopInternalBorder();
+        currentBorder = info.GetBEndInternalBorder();
+        adjacentBorder = ajaInfo.GetBStartInternalBorder();
         currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
                                         adjacentBorder, HORIZONTAL);
         segLength = std::max(1, ajaInfo.mColIndex + ajaInfo.mColSpan - colX);
         segLength = std::min(segLength, info.mColIndex + info.mColSpan - colX);
 
         // update, store the bottom left corner
         BCCornerInfo& blCorner = bottomCorners[colX]; // bottom left
         bool hitsSpanBelow = (colX > ajaInfo.mColIndex) &&
@@ -6115,32 +6083,32 @@ nsTableFrame::CalcBCBorders()
         // store the border segment the cell map and update cellBorders
         if (info.GetCellEndRowIndex() < damageArea.EndRow() &&
             colX >= damageArea.StartCol() && colX < damageArea.EndCol()) {
           tableCellMap->SetBCBorderEdge(NS_SIDE_BOTTOM, *iter.mCellMap,
                                         iter.mRowGroupStart,
                                         info.GetCellEndRowIndex(),
                                         colX, segLength, currentBorder.owner,
                                         currentBorder.width, startSeg);
-          info.SetBottomBorderWidths(currentBorder.width);
-          ajaInfo.SetTopBorderWidths(currentBorder.width);
+          info.SetBEndBorderWidths(currentBorder.width);
+          ajaInfo.SetBStartBorderWidths(currentBorder.width);
         }
         // update bottom right corner
         BCCornerInfo& brCorner = bottomCorners[colX + segLength];
         brCorner.Update(NS_SIDE_LEFT, currentBorder);
       }
       if (!gotRowBorder && 1 == info.mRowSpan &&
-          (ajaInfo.mTopRow || info.mRgAtBottom)) {
+          (ajaInfo.mStartRow || info.mRgAtEnd)) {
         //get continuous row/row group border
         //we need to check the row group's bottom border if this is
         //the last row in the row group, but only a cell with rowspan=1
         //will know whether *this* row is at the bottom
-        const nsIFrame* nextRowGroup = (ajaInfo.mRgAtTop) ? ajaInfo.mRowGroup :
-                                                             nullptr;
-        info.SetInnerRowGroupBottomContBCBorder(nextRowGroup, ajaInfo.mTopRow);
+        const nsIFrame* nextRowGroup =
+          ajaInfo.mRgAtStart ? ajaInfo.mRowGroup : nullptr;
+        info.SetInnerRowGroupBEndContBCBorder(nextRowGroup, ajaInfo.mStartRow);
         gotRowBorder = true;
       }
     }
 
     // see if the cell to the right had a rowspan and its lower left border
     // needs be joined with this one's bottom
     // if  there is a cell to the right and the cell to right was a rowspan
     if ((info.mNumTableCols != info.GetCellEndColIndex() + 1) &&
@@ -6292,17 +6260,17 @@ public:
   void ResetVerInfo();
   void StoreColumnWidth(int32_t aIndex);
   bool VerticalSegmentOwnsCorner();
 
   nsTableFrame*         mTable;
   nsTableFrame*         mTableFirstInFlow;
   nsTableCellMap*       mTableCellMap;
   nsCellMap*            mCellMap;
-  bool                  mTableIsLTR;
+  WritingMode           mTableWM;
   int32_t               mColInc;            // +1 for ltr -1 for rtl
   const nsStyleBackground* mTableBgColor;
   nsTableFrame::RowGroupArray mRowGroups;
 
   nsTableRowGroupFrame* mPrevRg;
   nsTableRowGroupFrame* mRg;
   bool                  mIsRepeatedHeader;
   bool                  mIsRepeatedFooter;
@@ -6391,35 +6359,34 @@ private:
   bool SetNewRowGroup();
   void   SetNewData(int32_t aRowIndex, int32_t aColIndex);
 
 };
 
 
 
 BCPaintBorderIterator::BCPaintBorderIterator(nsTableFrame* aTable)
-{
-  mTable      = aTable;
+  : mTable(aTable)
+  , mTableFirstInFlow(static_cast<nsTableFrame*>(aTable->FirstInFlow()))
+  , mTableCellMap(aTable->GetCellMap())
+  , mTableWM(aTable->StyleContext())
+{
   mVerInfo    = nullptr;
   nsMargin childAreaOffset = mTable->GetChildAreaOffset(nullptr);
-  mTableFirstInFlow    = static_cast<nsTableFrame*>(mTable->FirstInFlow());
-  mTableCellMap        = mTable->GetCellMap();
   // y position of first row in damage area
   mInitialOffsetY = mTable->GetPrevInFlow() ? 0 : childAreaOffset.top;
   mNumTableRows  = mTable->GetRowCount();
   mNumTableCols  = mTable->GetColCount();
 
   // Get the ordered row groups
   mTable->OrderRowGroups(mRowGroups);
   // initialize to a non existing index
   mRepeatedHeaderRowIndex = -99;
 
-  mTableIsLTR = mTable->StyleVisibility()->mDirection ==
-                   NS_STYLE_DIRECTION_LTR;
-  mColInc = (mTableIsLTR) ? 1 : -1;
+  mColInc = mTableWM.IsBidiLTR() ? 1 : -1;
 
   nsIFrame* bgFrame =
     nsCSSRendering::FindNonTransparentBackgroundFrame(aTable);
   mTableBgColor = bgFrame->StyleBackground();
 }
 
 bool
 BCPaintBorderIterator::SetDamageArea(const nsRect& aDirtyRect)
@@ -6430,33 +6397,34 @@ BCPaintBorderIterator::SetDamageArea(con
   bool done = false;
   bool haveIntersect = false;
   // find startRowIndex, endRowIndex
   nscoord rowY = mInitialOffsetY;
   for (uint32_t rgX = 0; rgX < mRowGroups.Length() && !done; rgX++) {
     nsTableRowGroupFrame* rgFrame = mRowGroups[rgX];
     for (nsTableRowFrame* rowFrame = rgFrame->GetFirstRow(); rowFrame;
          rowFrame = rowFrame->GetNextRow()) {
-      // conservatively estimate the half border widths outside the row
-      nscoord topBorderHalf    = (mTable->GetPrevInFlow()) ? 0 :
-       nsPresContext::CSSPixelsToAppUnits(rowFrame->GetTopBCBorderWidth() + 1);
-      nscoord bottomBorderHalf = (mTable->GetNextInFlow()) ? 0 :
-        nsPresContext::CSSPixelsToAppUnits(rowFrame->GetBottomBCBorderWidth() + 1);
       // get the row rect relative to the table rather than the row group
       nsSize rowSize = rowFrame->GetSize();
       if (haveIntersect) {
-        if (aDirtyRect.YMost() >= (rowY - topBorderHalf)) {
+        // conservatively estimate the half border widths outside the row
+        nscoord borderHalf = mTable->GetPrevInFlow() ? 0 : nsPresContext::
+          CSSPixelsToAppUnits(rowFrame->GetBStartBCBorderWidth() + 1);
+        if (aDirtyRect.YMost() >= rowY - borderHalf) {
           nsTableRowFrame* fifRow =
             static_cast<nsTableRowFrame*>(rowFrame->FirstInFlow());
           endRowIndex = fifRow->GetRowIndex();
         }
         else done = true;
       }
       else {
-        if ((rowY + rowSize.height + bottomBorderHalf) >= aDirtyRect.y) {
+        // conservatively estimate the half border widths outside the row
+        nscoord borderHalf = mTable->GetNextInFlow() ? 0 : nsPresContext::
+          CSSPixelsToAppUnits(rowFrame->GetBEndBCBorderWidth() + 1);
+        if (rowY + rowSize.height + borderHalf >= aDirtyRect.y) {
           mStartRg  = rgFrame;
           mStartRow = rowFrame;
           nsTableRowFrame* fifRow =
             static_cast<nsTableRowFrame*>(rowFrame->FirstInFlow());
           startRowIndex = endRowIndex = fifRow->GetRowIndex();
           haveIntersect = true;
         }
         else {
@@ -6477,17 +6445,17 @@ BCPaintBorderIterator::SetDamageArea(con
     return false;
   // find startColIndex, endColIndex, startColX
   haveIntersect = false;
   if (0 == mNumTableCols)
     return false;
   int32_t leftCol, rightCol; // columns are in the range [leftCol, rightCol)
 
   nsMargin childAreaOffset = mTable->GetChildAreaOffset(nullptr);
-  if (mTableIsLTR) {
+  if (mTableWM.IsBidiLTR()) {
     mInitialOffsetX = childAreaOffset.left; // x position of first col in
                                             // damage area
     leftCol = 0;
     rightCol = mNumTableCols;
   } else {
     // x position of first col in damage area
     mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right;
     leftCol = mNumTableCols-1;
@@ -6497,38 +6465,38 @@ BCPaintBorderIterator::SetDamageArea(con
   int32_t colX;
   for (colX = leftCol; colX != rightCol; colX += mColInc) {
     nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(colX);
     if (!colFrame) ABORT1(false);
     // get the col rect relative to the table rather than the col group
     nsSize size = colFrame->GetSize();
     if (haveIntersect) {
       // conservatively estimate the left half border width outside the col
-      nscoord leftBorderHalf =
-        nsPresContext::CSSPixelsToAppUnits(colFrame->GetLeftBorderWidth() + 1);
-      if (aDirtyRect.XMost() >= (x - leftBorderHalf)) {
+      nscoord istartBorderHalf = nsPresContext::
+        CSSPixelsToAppUnits(colFrame->GetIStartBorderWidth() + 1);
+      if (aDirtyRect.XMost() >= x - istartBorderHalf) {
         endColIndex = colX;
       }
       else break;
     }
     else {
       // conservatively estimate the right half border width outside the col
-      nscoord rightBorderHalf =
-        nsPresContext::CSSPixelsToAppUnits(colFrame->GetRightBorderWidth() + 1);
-      if ((x + size.width + rightBorderHalf) >= aDirtyRect.x) {
+      nscoord iendBorderHalf = nsPresContext::
+        CSSPixelsToAppUnits(colFrame->GetIEndBorderWidth() + 1);
+      if (x + size.width + iendBorderHalf >= aDirtyRect.x) {
         startColIndex = endColIndex = colX;
         haveIntersect = true;
       }
       else {
         mInitialOffsetX += mColInc * size.width;
       }
     }
     x += size.width;
   }
-  if (!mTableIsLTR) {
+  if (!mTableWM.IsBidiLTR()) {
     uint32_t temp;
     mInitialOffsetX = mTable->GetRect().width - childAreaOffset.right;
     temp = startColIndex; startColIndex = endColIndex; endColIndex = temp;
     for (uint32_t column = 0; column < startColIndex; column++) {
       nsTableColFrame* colFrame = mTableFirstInFlow->GetColFrame(column);
       if (!colFrame) ABORT1(false);
       nsSize size = colFrame->GetSize();
       mInitialOffsetX += mColInc * size.width;
@@ -6953,45 +6921,45 @@ BCVerticalSeg::GetBottomCorner(BCPaintBo
  *                        at the start
  */
 void
 BCVerticalSeg::Paint(BCPaintBorderIterator& aIter,
                      nsRenderingContext&   aRenderingContext,
                      BCPixelSize            aHorSegHeight)
 {
   // get the border style, color and paint the segment
-  mozilla::css::Side side = (aIter.IsDamageAreaRightMost()) ? NS_SIDE_RIGHT :
-                                                    NS_SIDE_LEFT;
+  LogicalSide side =
+    aIter.IsDamageAreaRightMost() ? eLogicalSideIEnd : eLogicalSideIStart;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nsTableColFrame* col           = mCol; if (!col) ABORT0();
   nsTableCellFrame* cell         = mFirstCell; // ???
   nsIFrame* owner = nullptr;
   uint8_t style = NS_STYLE_BORDER_STYLE_SOLID;
   nscolor color = 0xFFFFFFFF;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
   int32_t appUnitsPerDevPixel = col->PresContext()->AppUnitsPerDevPixel();
 
   switch (mOwner) {
     case eTableOwner:
       owner = aIter.mTable;
       break;
     case eAjaColGroupOwner:
-      side = NS_SIDE_RIGHT;
+      side = eLogicalSideIEnd;
       if (!aIter.IsTableRightMost() && (relColIndex > 0)) {
         col = aIter.mVerInfo[relColIndex - 1].mCol;
       } // and fall through
     case eColGroupOwner:
       if (col) {
         owner = col->GetParent();
       }
       break;
     case eAjaColOwner:
-      side = NS_SIDE_RIGHT;
+      side = eLogicalSideIEnd;
       if (!aIter.IsTableRightMost() && (relColIndex > 0)) {
         col = aIter.mVerInfo[relColIndex - 1].mCol;
       } // and fall through
     case eColOwner:
       owner = col;
       break;
     case eAjaRowGroupOwner:
       NS_ERROR("a neighboring rowgroup can never own a vertical border");
@@ -7004,36 +6972,38 @@ BCVerticalSeg::Paint(BCPaintBorderIterat
     case eAjaRowOwner:
       NS_ASSERTION(false, "program error"); // and fall through
     case eRowOwner:
       NS_ASSERTION(aIter.IsTableLeftMost() || aIter.IsTableRightMost(),
                    "row can own border only at table edge");
       owner = mFirstRow;
       break;
     case eAjaCellOwner:
-      side = NS_SIDE_RIGHT;
+      side = eLogicalSideIEnd;
       cell = mAjaCell; // and fall through
     case eCellOwner:
       owner = cell;
       break;
   }
   if (owner) {
-    ::GetPaintStyleInfo(owner, side, style, color, aIter.mTableIsLTR);
+    ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &style, &color);
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   nsRect segRect(mOffsetX - nsPresContext::CSSPixelsToAppUnits(largeHalf),
                  mOffsetY,
                  nsPresContext::CSSPixelsToAppUnits(mWidth), mLength);
   nscoord bottomBevelOffset = (mIsBottomBevel) ?
                   nsPresContext::CSSPixelsToAppUnits(mBottomHorSegHeight) : 0;
-  mozilla::css::Side bottomBevelSide = ((aHorSegHeight > 0) ^ !aIter.mTableIsLTR) ?
-                            NS_SIDE_RIGHT : NS_SIDE_LEFT;
-  mozilla::css::Side topBevelSide = ((mTopBevelSide == NS_SIDE_RIGHT) ^ !aIter.mTableIsLTR)?
-                         NS_SIDE_RIGHT : NS_SIDE_LEFT;
+  mozilla::css::Side bottomBevelSide =
+    (aHorSegHeight > 0) ^ !aIter.mTableWM.IsBidiLTR() ?
+    NS_SIDE_RIGHT : NS_SIDE_LEFT;
+  mozilla::css::Side topBevelSide =
+    (mTopBevelSide == NS_SIDE_RIGHT) ^ !aIter.mTableWM.IsBidiLTR() ?
+    NS_SIDE_RIGHT : NS_SIDE_LEFT;
   nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color,
                                          aIter.mTableBgColor, segRect,
                                          appUnitsPerDevPixel,
                                          nsPresContext::AppUnitsPerCSSPixel(),
                                          topBevelSide, mTopBevelOffset,
                                          bottomBevelSide, bottomBevelOffset);
 }
 
@@ -7084,21 +7054,21 @@ BCHorizontalSeg::Start(BCPaintBorderIter
                                                        bevel) : 0;
 
   bool    leftBevel = (aHorSegHeight > 0) ? bevel : false;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nscoord maxVerSegWidth = std::max(aIter.mVerInfo[relColIndex].mWidth,
                                   aBottomVerSegWidth);
   nscoord offset = CalcHorCornerOffset(cornerOwnerSide, cornerSubWidth,
                                        maxVerSegWidth, true, leftBevel,
-                                       aIter.mTableIsLTR);
+                                       aIter.mTableWM.IsBidiLTR());
   mLeftBevelOffset = (leftBevel && (aHorSegHeight > 0)) ? maxVerSegWidth : 0;
   // XXX this assumes that only corners where 2 segments join can be beveled
   mLeftBevelSide   = (aBottomVerSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
-  if (aIter.mTableIsLTR) {
+  if (aIter.mTableWM.IsBidiLTR()) {
     mOffsetX += offset;
   }
   else {
     mOffsetX -= offset;
   }
   mLength          = -offset;
   mWidth           = aHorSegHeight;
   mFirstCell       = aIter.mCell;
@@ -7122,35 +7092,35 @@ BCHorizontalSeg::GetRightCorner(BCPaintB
   if (aIter.mBCData) {
     cornerSubWidth = aIter.mBCData->GetCorner(ownerSide, bevel);
   }
 
   mIsRightBevel = (mWidth > 0) ? bevel : 0;
   int32_t relColIndex = aIter.GetRelativeColIndex();
   nscoord verWidth = std::max(aIter.mVerInfo[relColIndex].mWidth, aLeftSegWidth);
   mEndOffset = CalcHorCornerOffset(ownerSide, cornerSubWidth, verWidth,
-                                   false, mIsRightBevel, aIter.mTableIsLTR);
+                                   false, mIsRightBevel, aIter.mTableWM.IsBidiLTR());
   mLength += mEndOffset;
   mRightBevelOffset = (mIsRightBevel) ?
                        nsPresContext::CSSPixelsToAppUnits(verWidth) : 0;
   mRightBevelSide = (aLeftSegWidth > 0) ? NS_SIDE_BOTTOM : NS_SIDE_TOP;
 }
 
 /**
  * Paint the horizontal segment
  * @param aIter         - iterator containing the structural information
  * @param aRenderingContext - the rendering context
  */
 void
 BCHorizontalSeg::Paint(BCPaintBorderIterator& aIter,
                        nsRenderingContext&   aRenderingContext)
 {
   // get the border style, color and paint the segment
-  mozilla::css::Side side = (aIter.IsDamageAreaBottomMost()) ? NS_SIDE_BOTTOM :
-                                                     NS_SIDE_TOP;
+  LogicalSide side =
+    aIter.IsDamageAreaBottomMost() ? eLogicalSideBEnd : eLogicalSideBStart;
   nsIFrame* rg   = aIter.mRg;  if (!rg) ABORT0();
   nsIFrame* row  = aIter.mRow; if (!row) ABORT0();
   nsIFrame* cell = mFirstCell;
   nsIFrame* col;
   nsIFrame* owner = nullptr;
 
   // All the tables frames have the same presContext, so we just use any one
   // that exists here:
@@ -7178,49 +7148,49 @@ BCHorizontalSeg::Paint(BCPaintBorderIter
       NS_ERROR("neighboring column can never own a horizontal border");
       // and fall through
     case eColOwner:
       NS_ASSERTION(aIter.IsTableTopMost() || aIter.IsTableBottomMost(),
                    "col can own border only at the table edge");
       owner = aIter.mTableFirstInFlow->GetColFrame(aIter.mColIndex - 1);
       break;
     case eAjaRowGroupOwner:
-      side = NS_SIDE_BOTTOM;
+      side = eLogicalSideBEnd;
       rg = (aIter.IsTableBottomMost()) ? aIter.mRg : aIter.mPrevRg;
       // and fall through
     case eRowGroupOwner:
       owner = rg;
       break;
     case eAjaRowOwner:
-      side = NS_SIDE_BOTTOM;
+      side = eLogicalSideBEnd;
       row = (aIter.IsTableBottomMost()) ? aIter.mRow : aIter.mPrevRow;
       // and fall through
       case eRowOwner:
       owner = row;
       break;
     case eAjaCellOwner:
-      side = NS_SIDE_BOTTOM;
+      side = eLogicalSideBEnd;
       // if this is null due to the damage area origin-y > 0, then the border
       // won't show up anyway
       cell = mAjaCell;
       // and fall through
     case eCellOwner:
       owner = cell;
       break;
   }
   if (owner) {
-    ::GetPaintStyleInfo(owner, side, style, color, aIter.mTableIsLTR);
+    ::GetPaintStyleInfo(owner, aIter.mTableWM, side, &style, &color);
   }
   BCPixelSize smallHalf, largeHalf;
   DivideBCBorderSize(mWidth, smallHalf, largeHalf);
   nsRect segRect(mOffsetX,
                  mOffsetY - nsPresContext::CSSPixelsToAppUnits(largeHalf),
                  mLength,
                  nsPresContext::CSSPixelsToAppUnits(mWidth));
-  if (aIter.mTableIsLTR) {
+  if (aIter.mTableWM.IsBidiLTR()) {
     nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color,
                                            aIter.mTableBgColor, segRect,
                                            appUnitsPerDevPixel,
                                            nsPresContext::AppUnitsPerCSSPixel(),
                                            mLeftBevelSide,
                                            nsPresContext::CSSPixelsToAppUnits(mLeftBevelOffset),
                                            mRightBevelSide, mRightBevelOffset);
   }
--- a/layout/tables/nsTableFrame.h
+++ b/layout/tables/nsTableFrame.h
@@ -981,17 +981,17 @@ inline void nsTableFrame::SetNeedToCalcB
 {
   mBits.mNeedToCalcBCBorders = (unsigned)aValue;
 }
 
 inline nscoord
 nsTableFrame::GetContinuousLeftBCBorderWidth() const
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  return BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips, mBits.mLeftContBCBorder);
+  return BC_BORDER_END_HALF_COORD(aPixelsToTwips, mBits.mLeftContBCBorder);
 }
 
 inline void nsTableFrame::SetContinuousLeftBCBorderWidth(nscoord aValue)
 {
   mBits.mLeftContBCBorder = (unsigned) aValue;
 }
 
 class nsTableIterator
--- a/layout/tables/nsTablePainter.cpp
+++ b/layout/tables/nsTablePainter.cpp
@@ -7,16 +7,17 @@
 #include "nsTableRowGroupFrame.h"
 #include "nsTableRowFrame.h"
 #include "nsTableColGroupFrame.h"
 #include "nsTableColFrame.h"
 #include "nsTableCellFrame.h"
 #include "nsTablePainter.h"
 #include "nsCSSRendering.h"
 #include "nsDisplayList.h"
+#include "mozilla/WritingModes.h"
 
 /* ~*~ Table Background Painting ~*~
 
    Mozilla's Table Background painting follows CSS2.1:17.5.1
    That section does not, however, describe the effect of
    borders on background image positioning. What we do is:
 
      - in separate borders, the borders are passed in so that
@@ -90,16 +91,17 @@
    Elements with stacking contexts set up their own painter to finish the
    painting process, since they were skipped. They call the appropriate
    sub-part of the loop (e.g. PaintRow) which will paint the frame and
    descendants.
 
    XXX views are going
  */
 
+using namespace mozilla;
 using namespace mozilla::image;
 
 TableBackgroundPainter::TableBackgroundData::TableBackgroundData()
   : mFrame(nullptr)
   , mVisible(false)
   , mUsesSynthBorder(false)
 {
 }
@@ -484,17 +486,19 @@ TableBackgroundPainter::PaintRow(nsTable
   /* Load row data */
   if (aPassThrough) {
     aRowBGData.MakeInvisible();
   } else {
     if (mIsBorderCollapse && aRowBGData.ShouldSetBCBorder()) {
       nsMargin border;
       nsTableRowFrame* nextRow = aFrame->GetNextRow();
       if (nextRow) { //outer top below us is inner bottom for us
-        border.bottom = nextRow->GetOuterTopContBCBorderWidth();
+        WritingMode wm = nextRow->GetWritingMode();
+        border.Side(wm.PhysicalSide(eLogicalSideBEnd)) =
+          nextRow->GetOuterBStartContBCBorderWidth();
       }
       else { //acquire rg's bottom border
         nsTableRowGroupFrame* rowGroup = static_cast<nsTableRowGroupFrame*>(aFrame->GetParent());
         rowGroup->GetContinuousBCBorderWidth(border);
       }
       //get the rest of the borders; will overwrite all but bottom
       aFrame->GetContinuousBCBorderWidth(border);
 
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -70,17 +70,19 @@ nsTableRowFrame::InitChildReflowState(ns
                                       nsTableCellReflowState& aReflowState)
 {
   nsMargin collapseBorder;
   nsMargin* pCollapseBorder = nullptr;
   if (aBorderCollapse) {
     // we only reflow cells, so don't need to check frame type
     nsBCTableCellFrame* bcCellFrame = (nsBCTableCellFrame*)aReflowState.frame;
     if (bcCellFrame) {
-      pCollapseBorder = bcCellFrame->GetBorderWidth(collapseBorder);
+      WritingMode wm = GetWritingMode();
+      collapseBorder = bcCellFrame->GetBorderWidth(wm).GetPhysicalMargin(wm);
+      pCollapseBorder = &collapseBorder;
     }
   }
   aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder);
   aReflowState.FixUp(aAvailSize);
 }
 
 void
 nsTableRowFrame::SetFixedHeight(nscoord aValue)
@@ -1368,28 +1370,28 @@ nsTableRowFrame::SetUnpaginatedHeight(ns
 
 nscoord
 nsTableRowFrame::GetUnpaginatedHeight(nsPresContext* aPresContext)
 {
   FrameProperties props = FirstInFlow()->Properties();
   return NS_PTR_TO_INT32(props.Get(RowUnpaginatedHeightProperty()));
 }
 
-void nsTableRowFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
+void nsTableRowFrame::SetContinuousBCBorderWidth(LogicalSide aForSide,
                                                  BCPixelSize aPixelValue)
 {
   switch (aForSide) {
-    case NS_SIDE_RIGHT:
-      mRightContBorderWidth = aPixelValue;
+    case eLogicalSideIEnd:
+      mIEndContBorderWidth = aPixelValue;
       return;
-    case NS_SIDE_TOP:
-      mTopContBorderWidth = aPixelValue;
+    case eLogicalSideBStart:
+      mBStartContBorderWidth = aPixelValue;
       return;
-    case NS_SIDE_LEFT:
-      mLeftContBorderWidth = aPixelValue;
+    case eLogicalSideIStart:
+      mIStartContBorderWidth = aPixelValue;
       return;
     default:
       NS_ERROR("invalid NS_SIDE arg");
   }
 }
 #ifdef ACCESSIBILITY
 a11y::AccType
 nsTableRowFrame::AccessibleType()
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -206,38 +206,38 @@ public:
 
   nsTableRowFrame* GetNextRow() const;
 
   bool    HasUnpaginatedHeight();
   void    SetHasUnpaginatedHeight(bool aValue);
   nscoord GetUnpaginatedHeight(nsPresContext* aPresContext);
   void    SetUnpaginatedHeight(nsPresContext* aPresContext, nscoord aValue);
 
-  nscoord GetTopBCBorderWidth();
-  void    SetTopBCBorderWidth(BCPixelSize aWidth);
-  nscoord GetBottomBCBorderWidth();
-  void    SetBottomBCBorderWidth(BCPixelSize aWidth);
-  nsMargin* GetBCBorderWidth(nsMargin& aBorder);
+  nscoord GetBStartBCBorderWidth() const { return mBStartBorderWidth; }
+  nscoord GetBEndBCBorderWidth() const { return mBEndBorderWidth; }
+  void SetBStartBCBorderWidth(BCPixelSize aWidth) { mBStartBorderWidth = aWidth; }
+  void SetBEndBCBorderWidth(BCPixelSize aWidth) { mBEndBorderWidth = aWidth; }
+  mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM);
                              
   /**
    * Gets inner border widths before collapsing with cell borders
-   * Caller must get bottom border from next row or from table
-   * GetContinuousBCBorderWidth will not overwrite aBorder.bottom
+   * Caller must get block-end border from next row or from table
+   * GetContinuousBCBorderWidth will not overwrite that border
    * see nsTablePainter about continuous borders
    */
   void GetContinuousBCBorderWidth(nsMargin& aBorder);
   /**
-   * @returns outer top bc border == prev row's bottom inner
+   * @returns outer block-start bc border == prev row's block-end inner
    */
-  nscoord GetOuterTopContBCBorderWidth();
+  nscoord GetOuterBStartContBCBorderWidth();
   /**
    * Sets full border widths before collapsing with cell borders
-   * @param aForSide - side to set; only accepts right, left, and top
+   * @param aForSide - side to set; only accepts iend, istart, and bstart
    */
-  void SetContinuousBCBorderWidth(uint8_t     aForSide,
+  void SetContinuousBCBorderWidth(mozilla::LogicalSide aForSide,
                                   BCPixelSize aPixelValue);
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
     return nsContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eTablePart));
   }
 
   virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) override;
@@ -295,21 +295,21 @@ private:
   nscoord mStyleFixedHeight;
 
   // max-ascent and max-descent amongst all cells that have 'vertical-align: baseline'
   nscoord mMaxCellAscent;  // does include cells with rowspan > 1
   nscoord mMaxCellDescent; // does *not* include cells with rowspan > 1
 
   // border widths in pixels in the collapsing border model of the *inner*
   // half of the border only
-  BCPixelSize mTopBorderWidth;
-  BCPixelSize mBottomBorderWidth;
-  BCPixelSize mRightContBorderWidth;
-  BCPixelSize mTopContBorderWidth;
-  BCPixelSize mLeftContBorderWidth;
+  BCPixelSize mBStartBorderWidth;
+  BCPixelSize mBEndBorderWidth;
+  BCPixelSize mIEndContBorderWidth;
+  BCPixelSize mBStartContBorderWidth;
+  BCPixelSize mIStartContBorderWidth;
 
   /**
    * Sets the NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT bit to indicate whether
    * this row has any cells that have non-auto-height.  (Row-spanning
    * cells are ignored.)
    */
   void InitHasCellWithStyleHeight(nsTableFrame* aTableFrame);
 
@@ -396,57 +396,38 @@ inline void nsTableRowFrame::SetHasUnpag
 {
   if (aValue) {
     mState |= NS_TABLE_ROW_HAS_UNPAGINATED_HEIGHT;
   } else {
     mState &= ~NS_TABLE_ROW_HAS_UNPAGINATED_HEIGHT;
   }
 }
 
-inline nscoord nsTableRowFrame::GetTopBCBorderWidth()
-{
-  return mTopBorderWidth;
-}
-
-inline void nsTableRowFrame::SetTopBCBorderWidth(BCPixelSize aWidth)
-{
-  mTopBorderWidth = aWidth;
-}
-
-inline nscoord nsTableRowFrame::GetBottomBCBorderWidth()
+inline mozilla::LogicalMargin
+nsTableRowFrame::GetBCBorderWidth(mozilla::WritingMode aWM)
 {
-  return mBottomBorderWidth;
-}
-
-inline void nsTableRowFrame::SetBottomBCBorderWidth(BCPixelSize aWidth)
-{
-  mBottomBorderWidth = aWidth;
-}
-
-inline nsMargin* nsTableRowFrame::GetBCBorderWidth(nsMargin& aBorder)
-{
-  aBorder.left = aBorder.right = 0;
-
-  aBorder.top    = nsPresContext::CSSPixelsToAppUnits(mTopBorderWidth);
-  aBorder.bottom = nsPresContext::CSSPixelsToAppUnits(mBottomBorderWidth);
-
-  return &aBorder;
+  return mozilla::LogicalMargin(
+    aWM, nsPresContext::CSSPixelsToAppUnits(mBStartBorderWidth), 0,
+    nsPresContext::CSSPixelsToAppUnits(mBEndBorderWidth), 0);
 }
 
 inline void
 nsTableRowFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips,
-                                            mLeftContBorderWidth);
-  aBorder.top = BC_BORDER_BOTTOM_HALF_COORD(aPixelsToTwips,
-                                            mTopContBorderWidth);
-  aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips,
-                                            mRightContBorderWidth);
+  mozilla::WritingMode wm = GetWritingMode();
+  mozilla::LogicalMargin border(wm, aBorder);
+  border.IEnd(wm) = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                               mIStartContBorderWidth);
+  border.BStart(wm) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+                                               mBStartContBorderWidth);
+  border.IStart(wm) = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+                                               mIEndContBorderWidth);
+  aBorder = border.GetPhysicalMargin(wm);
 }
 
-inline nscoord nsTableRowFrame::GetOuterTopContBCBorderWidth()
+inline nscoord nsTableRowFrame::GetOuterBStartContBCBorderWidth()
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  return BC_BORDER_TOP_HALF_COORD(aPixelsToTwips, mTopContBorderWidth);
+  return BC_BORDER_START_HALF_COORD(aPixelsToTwips, mBStartContBorderWidth);
 }
 
 #endif
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -291,17 +291,20 @@ nsTableRowGroupFrame::InitChildReflowSta
                                            nsHTMLReflowState& aReflowState)
 {
   nsMargin collapseBorder;
   nsMargin padding(0,0,0,0);
   nsMargin* pCollapseBorder = nullptr;
   if (aBorderCollapse) {
     nsTableRowFrame *rowFrame = do_QueryFrame(aReflowState.frame);
     if (rowFrame) {
-      pCollapseBorder = rowFrame->GetBCBorderWidth(collapseBorder);
+      WritingMode wm = GetWritingMode();
+      LogicalMargin border = rowFrame->GetBCBorderWidth(wm);
+      collapseBorder = border.GetPhysicalMargin(wm);
+      pCollapseBorder = &collapseBorder;
     }
   }
   aReflowState.Init(&aPresContext, -1, -1, pCollapseBorder, &padding);
 }
 
 static void
 CacheRowHeightsForPrinting(nsPresContext*   aPresContext,
                            nsTableRowFrame* aFirstRow)
@@ -1595,35 +1598,35 @@ NS_IMPL_FRAMEARENA_HELPERS(nsTableRowGro
 #ifdef DEBUG_FRAME_DUMP
 nsresult
 nsTableRowGroupFrame::GetFrameName(nsAString& aResult) const
 {
   return MakeFrameName(NS_LITERAL_STRING("TableRowGroup"), aResult);
 }
 #endif
 
-nsMargin*
-nsTableRowGroupFrame::GetBCBorderWidth(nsMargin& aBorder)
+LogicalMargin
+nsTableRowGroupFrame::GetBCBorderWidth(WritingMode aWM)
 {
-  aBorder.left = aBorder.right = aBorder.top = aBorder.bottom = 0;
-
+  LogicalMargin border(aWM);
   nsTableRowFrame* firstRowFrame = nullptr;
   nsTableRowFrame* lastRowFrame = nullptr;
   for (nsTableRowFrame* rowFrame = GetFirstRow(); rowFrame; rowFrame = rowFrame->GetNextRow()) {
     if (!firstRowFrame) {
       firstRowFrame = rowFrame;
     }
     lastRowFrame = rowFrame;
   }
   if (firstRowFrame) {
-    aBorder.top    = nsPresContext::CSSPixelsToAppUnits(firstRowFrame->GetTopBCBorderWidth());
-    aBorder.bottom = nsPresContext::CSSPixelsToAppUnits(lastRowFrame->GetBottomBCBorderWidth());
+    border.BStart(aWM) = nsPresContext::
+      CSSPixelsToAppUnits(firstRowFrame->GetBStartBCBorderWidth());
+    border.BEnd(aWM) = nsPresContext::
+      CSSPixelsToAppUnits(lastRowFrame->GetBEndBCBorderWidth());
   }
-
-  return &aBorder;
+  return border;
 }
 
 void nsTableRowGroupFrame::SetContinuousBCBorderWidth(uint8_t     aForSide,
                                                       BCPixelSize aPixelValue)
 {
   switch (aForSide) {
     case NS_SIDE_RIGHT:
       mRightContBorderWidth = aPixelValue;
--- a/layout/tables/nsTableRowGroupFrame.h
+++ b/layout/tables/nsTableRowGroupFrame.h
@@ -8,16 +8,17 @@
 #include "mozilla/Attributes.h"
 #include "nscore.h"
 #include "nsContainerFrame.h"
 #include "nsIAtom.h"
 #include "nsILineIterator.h"
 #include "nsTablePainter.h"
 #include "nsTArray.h"
 #include "nsTableFrame.h"
+#include "mozilla/WritingModes.h"
 
 class nsTableRowFrame;
 
 struct nsRowGroupReflowState {
   const nsHTMLReflowState& reflowState;  // Our reflow state
 
   nsTableFrame* tableFrame;
 
@@ -156,17 +157,17 @@ public:
                               nsTableRowGroupFrame* aHeaderFooterFrame);
 
 
   /**
    * Get the total height of all the row rects
    */
   nscoord GetHeightBasis(const nsHTMLReflowState& aReflowState);
 
-  nsMargin* GetBCBorderWidth(nsMargin& aBorder);
+  mozilla::LogicalMargin GetBCBorderWidth(mozilla::WritingMode aWM);
 
   /**
    * Gets inner border widths before collapsing with cell borders
    * Caller must get top border from previous row group or from table
    * GetContinuousBCBorderWidth will not overwrite aBorder.top
    * see nsTablePainter about continuous borders
    */
   void GetContinuousBCBorderWidth(nsMargin& aBorder);
@@ -445,17 +446,17 @@ inline void nsTableRowGroupFrame::SetHas
     mState &= ~NS_ROWGROUP_HAS_STYLE_HEIGHT;
   }
 }
 
 inline void
 nsTableRowGroupFrame::GetContinuousBCBorderWidth(nsMargin& aBorder)
 {
   int32_t aPixelsToTwips = nsPresContext::AppUnitsPerCSSPixel();
-  aBorder.right = BC_BORDER_LEFT_HALF_COORD(aPixelsToTwips,
-                                            mRightContBorderWidth);
-  aBorder.bottom = BC_BORDER_TOP_HALF_COORD(aPixelsToTwips,
-                                            mBottomContBorderWidth);
-  aBorder.left = BC_BORDER_RIGHT_HALF_COORD(aPixelsToTwips,
-                                            mLeftContBorderWidth);
+  aBorder.right = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                             mRightContBorderWidth);
+  aBorder.bottom = BC_BORDER_START_HALF_COORD(aPixelsToTwips,
+                                              mBottomContBorderWidth);
+  aBorder.left = BC_BORDER_END_HALF_COORD(aPixelsToTwips,
+                                          mLeftContBorderWidth);
   return;
 }
 #endif
--- a/layout/xul/nsMenuFrame.cpp
+++ b/layout/xul/nsMenuFrame.cpp
@@ -457,17 +457,17 @@ nsMenuFrame::HandleEvent(nsPresContext* 
   }
   else if (aEvent->message == NS_MOUSE_BUTTON_UP &&
            aEvent->AsMouseEvent()->button == WidgetMouseEvent::eLeftButton &&
            !IsMenu() && !IsDisabled()) {
     // Execute the execute event handler.
     *aEventStatus = nsEventStatus_eConsumeNoDefault;
     Execute(aEvent);
   }
-  else if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
+  else if (aEvent->message == NS_MOUSE_OUT) {
     // Kill our timer if one is active.
     if (mOpenTimer) {
       mOpenTimer->Cancel();
       mOpenTimer = nullptr;
     }
 
     // Deactivate the menu.
     if (menuParent) {
--- a/layout/xul/nsScrollBoxFrame.cpp
+++ b/layout/xul/nsScrollBoxFrame.cpp
@@ -83,26 +83,26 @@ nsAutoRepeatBoxFrame::HandleEvent(nsPres
     return NS_OK;
   }
 
   switch(aEvent->message)
   {
     // repeat mode may be "hover" for repeating while the mouse is hovering
     // over the element, otherwise repetition is done while the element is
     // active (pressed).
-    case NS_MOUSE_ENTER:
-    case NS_MOUSE_ENTER_SYNTH:
+    case NS_MOUSE_ENTER_WIDGET:
+    case NS_MOUSE_OVER:
       if (IsActivatedOnHover()) {
         StartRepeat();
         mTrustedEvent = aEvent->mFlags.mIsTrusted;
       }
       break;
 
-    case NS_MOUSE_EXIT:
-    case NS_MOUSE_EXIT_SYNTH:
+    case NS_MOUSE_EXIT_WIDGET:
+    case NS_MOUSE_OUT:
       // always stop on mouse exit
       StopRepeat();
       // Not really necessary but do this to be safe
       mTrustedEvent = false;
       break;
 
     case NS_MOUSE_CLICK: {
       WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
--- a/layout/xul/nsScrollbarButtonFrame.cpp
+++ b/layout/xul/nsScrollbarButtonFrame.cpp
@@ -58,17 +58,17 @@ nsScrollbarButtonFrame::HandleEvent(nsPr
       // if we didn't handle the press ourselves, pass it on to the superclass
       if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) {
         return NS_OK;
       }
       break;
     case NS_MOUSE_BUTTON_UP:
       HandleRelease(aPresContext, aEvent, aEventStatus);
       break;
-    case NS_MOUSE_EXIT_SYNTH:
+    case NS_MOUSE_OUT:
       mCursorOnThis = false;
       break;
     case NS_MOUSE_MOVE: {
       nsPoint cursor =
         nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
       nsRect frameRect(nsPoint(0, 0), GetSize());
       mCursorOnThis = frameRect.Contains(cursor);
       break;
--- a/layout/xul/nsSliderFrame.cpp
+++ b/layout/xul/nsSliderFrame.cpp
@@ -602,20 +602,20 @@ nsSliderFrame::HandleEvent(nsPresContext
       HandleRelease(aPresContext, aEvent, aEventStatus);
     }
 
     return NS_OK;
   }
 #endif
 
   // XXX hack until handle release is actually called in nsframe.
-//  if (aEvent->message == NS_MOUSE_EXIT_SYNTH || aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP || aEvent->message == NS_MOUSE_LEFT_BUTTON_UP)
+//  if (aEvent->message == NS_MOUSE_OUT || aEvent->message == NS_MOUSE_RIGHT_BUTTON_UP || aEvent->message == NS_MOUSE_LEFT_BUTTON_UP)
   //   HandleRelease(aPresContext, aEvent, aEventStatus);
 
-  if (aEvent->message == NS_MOUSE_EXIT_SYNTH && mChange)
+  if (aEvent->message == NS_MOUSE_OUT && mChange)
      HandleRelease(aPresContext, aEvent, aEventStatus);
 
   return nsFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
 }
 
 // Helper function to collect the "scroll to click" metric. Beware of
 // caching this, users expect to be able to change the system preference
 // and see the browser change its behavior immediately.
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2559,31 +2559,31 @@ static uint32_t GetDropEffect(WidgetGUIE
   return action;
 }
 
 nsresult
 nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext,
                              WidgetGUIEvent* aEvent,
                              nsEventStatus* aEventStatus)
 {
-  if (aEvent->message == NS_MOUSE_ENTER_SYNTH || aEvent->message == NS_MOUSE_MOVE) {
+  if (aEvent->message == NS_MOUSE_OVER || aEvent->message == NS_MOUSE_MOVE) {
     nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
     int32_t xTwips = pt.x - mInnerBox.x;
     int32_t yTwips = pt.y - mInnerBox.y;
     int32_t newrow = GetRowAt(xTwips, yTwips);
     if (mMouseOverRow != newrow) {
       // redraw the old and the new row
       if (mMouseOverRow != -1)
         InvalidateRow(mMouseOverRow);
       mMouseOverRow = newrow;
       if (mMouseOverRow != -1)
         InvalidateRow(mMouseOverRow);
     }
   }
-  else if (aEvent->message == NS_MOUSE_EXIT_SYNTH) {
+  else if (aEvent->message == NS_MOUSE_OUT) {
     if (mMouseOverRow != -1) {
       InvalidateRow(mMouseOverRow);
       mMouseOverRow = -1;
     }
   }
   else if (aEvent->message == NS_DRAGDROP_ENTER) {
     if (!mSlots)
       mSlots = new Slots();
--- a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
@@ -1,14 +1,14 @@
 # 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/.
 
-SSL_ERROR_EXPORT_ONLY_SERVER=Unable to communicate securely.  Peer does not support high-grade encryption.
-SSL_ERROR_US_ONLY_SERVER=Unable to communicate securely.  Peer requires high-grade encryption which is not supported.
+SSL_ERROR_EXPORT_ONLY_SERVER=Unable to communicate securely. Peer does not support high-grade encryption.
+SSL_ERROR_US_ONLY_SERVER=Unable to communicate securely. Peer requires high-grade encryption which is not supported.
 SSL_ERROR_NO_CYPHER_OVERLAP=Cannot communicate securely with peer: no common encryption algorithm(s).
 SSL_ERROR_NO_CERTIFICATE=Unable to find the certificate or key necessary for authentication.
 SSL_ERROR_BAD_CERTIFICATE=Unable to communicate securely with peer: peers's certificate was rejected.
 SSL_ERROR_UNUSED_5=Unrecognized SSL error code.
 SSL_ERROR_BAD_CLIENT=The server has encountered bad data from the client.
 SSL_ERROR_BAD_SERVER=The client has encountered bad data from the server.
 SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE=Unsupported certificate type.
 SSL_ERROR_UNSUPPORTED_VERSION=Peer using unsupported version of security protocol.
@@ -145,32 +145,32 @@ SEC_ERROR_INVALID_AVA=security library: 
 SEC_ERROR_INVALID_TIME=Improperly formatted time string.
 SEC_ERROR_BAD_DER=security library: improperly formatted DER-encoded message.
 SEC_ERROR_BAD_SIGNATURE=Peer's certificate has an invalid signature.
 SEC_ERROR_EXPIRED_CERTIFICATE=Peer's Certificate has expired.
 SEC_ERROR_REVOKED_CERTIFICATE=Peer's Certificate has been revoked.
 SEC_ERROR_UNKNOWN_ISSUER=Peer's Certificate issuer is not recognized.
 SEC_ERROR_BAD_KEY=Peer's public key is invalid.
 SEC_ERROR_BAD_PASSWORD=The security password entered is incorrect.
-SEC_ERROR_RETRY_PASSWORD=New password entered incorrectly.  Please try again.
+SEC_ERROR_RETRY_PASSWORD=New password entered incorrectly. Please try again.
 SEC_ERROR_NO_NODELOCK=security library: no nodelock.
 SEC_ERROR_BAD_DATABASE=security library: bad database.
 SEC_ERROR_NO_MEMORY=security library: memory allocation failure.
 SEC_ERROR_UNTRUSTED_ISSUER=Peer's certificate issuer has been marked as not trusted by the user.
 SEC_ERROR_UNTRUSTED_CERT=Peer's certificate has been marked as not trusted by the user.
 SEC_ERROR_DUPLICATE_CERT=Certificate already exists in your database.
 SEC_ERROR_DUPLICATE_CERT_NAME=Downloaded certificate's name duplicates one already in your database.
 SEC_ERROR_ADDING_CERT=Error adding certificate to database.
 SEC_ERROR_FILING_KEY=Error refiling the key for this certificate.
 SEC_ERROR_NO_KEY=The private key for this certificate cannot be found in key database
 SEC_ERROR_CERT_VALID=This certificate is valid.
 SEC_ERROR_CERT_NOT_VALID=This certificate is not valid.
 SEC_ERROR_CERT_NO_RESPONSE=Cert Library: No Response
-SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE=The certificate issuer's certificate has expired.  Check your system date and time.
-SEC_ERROR_CRL_EXPIRED=The CRL for the certificate's issuer has expired.  Update it or check your system date and time.
+SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE=The certificate issuer's certificate has expired. Check your system date and time.
+SEC_ERROR_CRL_EXPIRED=The CRL for the certificate's issuer has expired. Update it or check your system date and time.
 SEC_ERROR_CRL_BAD_SIGNATURE=The CRL for the certificate's issuer has an invalid signature.
 SEC_ERROR_CRL_INVALID=New CRL has an invalid format.
 SEC_ERROR_EXTENSION_VALUE_INVALID=Certificate extension value is invalid.
 SEC_ERROR_EXTENSION_NOT_FOUND=Certificate extension not found.
 SEC_ERROR_CA_CERT_INVALID=Issuer certificate is invalid.
 SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID=Certificate path length constraint is invalid.
 SEC_ERROR_CERT_USAGES_INVALID=Certificate usages field is invalid.
 SEC_INTERNAL_ONLY=**Internal ONLY module**
@@ -179,17 +179,17 @@ SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION=Cer
 SEC_ERROR_OLD_CRL=New CRL is not later than the current one.
 SEC_ERROR_NO_EMAIL_CERT=Not encrypted or signed: you do not yet have an email certificate.
 SEC_ERROR_NO_RECIPIENT_CERTS_QUERY=Not encrypted: you do not have certificates for each of the recipients.
 SEC_ERROR_NOT_A_RECIPIENT=Cannot decrypt: you are not a recipient, or matching certificate and private key not found.
 SEC_ERROR_PKCS7_KEYALG_MISMATCH=Cannot decrypt: key encryption algorithm does not match your certificate.
 SEC_ERROR_PKCS7_BAD_SIGNATURE=Signature verification failed: no signer found, too many signers found, or improper or corrupted data.
 SEC_ERROR_UNSUPPORTED_KEYALG=Unsupported or unknown key algorithm.
 SEC_ERROR_DECRYPTION_DISALLOWED=Cannot decrypt: encrypted using a disallowed algorithm or key size.
-XP_SEC_FORTEZZA_BAD_CARD=Fortezza card has not been properly initialized.  Please remove it and return it to your issuer.
+XP_SEC_FORTEZZA_BAD_CARD=Fortezza card has not been properly initialized. Please remove it and return it to your issuer.
 XP_SEC_FORTEZZA_NO_CARD=No Fortezza cards Found
 XP_SEC_FORTEZZA_NONE_SELECTED=No Fortezza card selected
 XP_SEC_FORTEZZA_MORE_INFO=Please select a personality to get more info on
 XP_SEC_FORTEZZA_PERSON_NOT_FOUND=Personality not found
 XP_SEC_FORTEZZA_NO_MORE_INFO=No more information on that Personality
 XP_SEC_FORTEZZA_BAD_PIN=Invalid Pin
 XP_SEC_FORTEZZA_PERSON_ERROR=Couldn't initialize Fortezza personalities.
 SEC_ERROR_NO_KRL=No KRL for this site's certificate has been found.
@@ -207,50 +207,50 @@ SEC_ERROR_KEY_NICKNAME_COLLISION=A key w
 SEC_ERROR_SAFE_NOT_CREATED=error while creating safe object
 SEC_ERROR_BAGGAGE_NOT_CREATED=error while creating baggage object
 XP_JAVA_REMOVE_PRINCIPAL_ERROR=Couldn't remove the principal
 XP_JAVA_DELETE_PRIVILEGE_ERROR=Couldn't delete the privilege
 XP_JAVA_CERT_NOT_EXISTS_ERROR=This principal doesn't have a certificate
 SEC_ERROR_BAD_EXPORT_ALGORITHM=Required algorithm is not allowed.
 SEC_ERROR_EXPORTING_CERTIFICATES=Error attempting to export certificates.
 SEC_ERROR_IMPORTING_CERTIFICATES=Error attempting to import certificates.
-SEC_ERROR_PKCS12_DECODING_PFX=Unable to import.  Decoding error.  File not valid.
-SEC_ERROR_PKCS12_INVALID_MAC=Unable to import.  Invalid MAC.  Incorrect password or corrupt file.
-SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM=Unable to import.  MAC algorithm not supported.
-SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE=Unable to import.  Only password integrity and privacy modes supported.
-SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE=Unable to import.  File structure is corrupt.
-SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM=Unable to import.  Encryption algorithm not supported.
-SEC_ERROR_PKCS12_UNSUPPORTED_VERSION=Unable to import.  File version not supported.
-SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT=Unable to import.  Incorrect privacy password.
-SEC_ERROR_PKCS12_CERT_COLLISION=Unable to import.  Same nickname already exists in database.
+SEC_ERROR_PKCS12_DECODING_PFX=Unable to import. Decoding error. File not valid.
+SEC_ERROR_PKCS12_INVALID_MAC=Unable to import. Invalid MAC. Incorrect password or corrupt file.
+SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM=Unable to import. MAC algorithm not supported.
+SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE=Unable to import. Only password integrity and privacy modes supported.
+SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE=Unable to import. File structure is corrupt.
+SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM=Unable to import. Encryption algorithm not supported.
+SEC_ERROR_PKCS12_UNSUPPORTED_VERSION=Unable to import. File version not supported.
+SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT=Unable to import. Incorrect privacy password.
+SEC_ERROR_PKCS12_CERT_COLLISION=Unable to import. Same nickname already exists in database.
 SEC_ERROR_USER_CANCELLED=The user pressed cancel.
 SEC_ERROR_PKCS12_DUPLICATE_DATA=Not imported, already in database.
 SEC_ERROR_MESSAGE_SEND_ABORTED=Message not sent.
 SEC_ERROR_INADEQUATE_KEY_USAGE=Certificate key usage inadequate for attempted operation.
 SEC_ERROR_INADEQUATE_CERT_TYPE=Certificate type not approved for application.
 SEC_ERROR_CERT_ADDR_MISMATCH=Address in signing certificate does not match address in message headers.
-SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY=Unable to import.  Error attempting to import private key.
-SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN=Unable to import.  Error attempting to import certificate chain.
-SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME=Unable to export.  Unable to locate certificate or key by nickname.
-SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY=Unable to export.  Private Key could not be located and exported.
-SEC_ERROR_PKCS12_UNABLE_TO_WRITE=Unable to export.  Unable to write the export file.
-SEC_ERROR_PKCS12_UNABLE_TO_READ=Unable to import.  Unable to read the import file.
-SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED=Unable to export.  Key database corrupt or deleted.
+SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY=Unable to import. Error attempting to import private key.
+SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN=Unable to import. Error attempting to import certificate chain.
+SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME=Unable to export. Unable to locate certificate or key by nickname.
+SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY=Unable to export. Private Key could not be located and exported.
+SEC_ERROR_PKCS12_UNABLE_TO_WRITE=Unable to export. Unable to write the export file.
+SEC_ERROR_PKCS12_UNABLE_TO_READ=Unable to import. Unable to read the import file.
+SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED=Unable to export. Key database corrupt or deleted.
 SEC_ERROR_KEYGEN_FAIL=Unable to generate public/private key pair.
-SEC_ERROR_INVALID_PASSWORD=Password entered is invalid.  Please pick a different one.
-SEC_ERROR_RETRY_OLD_PASSWORD=Old password entered incorrectly.  Please try again.
+SEC_ERROR_INVALID_PASSWORD=Password entered is invalid. Please pick a different one.
+SEC_ERROR_RETRY_OLD_PASSWORD=Old password entered incorrectly. Please try again.
 SEC_ERROR_BAD_NICKNAME=Certificate nickname already in use.
 SEC_ERROR_NOT_FORTEZZA_ISSUER=Peer FORTEZZA chain has a non-FORTEZZA Certificate.
 SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY=A sensitive key cannot be moved to the slot where it is needed.
 SEC_ERROR_JS_INVALID_MODULE_NAME=Invalid module name.
 SEC_ERROR_JS_INVALID_DLL=Invalid module path/filename
 SEC_ERROR_JS_ADD_MOD_FAILURE=Unable to add module
 SEC_ERROR_JS_DEL_MOD_FAILURE=Unable to delete module
 SEC_ERROR_OLD_KRL=New KRL is not later than the current one.
-SEC_ERROR_CKL_CONFLICT=New CKL has different issuer than current CKL.  Delete current CKL.
+SEC_ERROR_CKL_CONFLICT=New CKL has different issuer than current CKL. Delete current CKL.
 SEC_ERROR_CERT_NOT_IN_NAME_SPACE=The Certifying Authority for this certificate is not permitted to issue a certificate with this name.
 SEC_ERROR_KRL_NOT_YET_VALID=The key revocation list for this certificate is not yet valid.
 SEC_ERROR_CRL_NOT_YET_VALID=The certificate revocation list for this certificate is not yet valid.
 SEC_ERROR_UNKNOWN_CERT=The requested certificate could not be found.
 SEC_ERROR_UNKNOWN_SIGNER=The signer's certificate could not be found.
 SEC_ERROR_CERT_BAD_ACCESS_LOCATION=The location for the certificate status server has invalid format.
 SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE=The OCSP response cannot be fully decoded; it is of an unknown type.
 SEC_ERROR_OCSP_BAD_HTTP_RESPONSE=The OCSP server returned unexpected/invalid HTTP data.
@@ -297,17 +297,17 @@ SEC_ERROR_INVALID_POLICY_MAPPING=Policy 
 SEC_ERROR_POLICY_VALIDATION_FAILED=Cert chain fails policy validation
 SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE=Unknown location type in cert AIA extension
 SEC_ERROR_BAD_HTTP_RESPONSE=Server returned bad HTTP response
 SEC_ERROR_BAD_LDAP_RESPONSE=Server returned bad LDAP response
 SEC_ERROR_FAILED_TO_ENCODE_DATA=Failed to encode data with ASN1 encoder
 SEC_ERROR_BAD_INFO_ACCESS_LOCATION=Bad information access location in cert extension
 SEC_ERROR_LIBPKIX_INTERNAL=Libpkix internal error occurred during cert validation.
 SEC_ERROR_PKCS11_GENERAL_ERROR=A PKCS #11 module returned CKR_GENERAL_ERROR, indicating that an unrecoverable error has occurred.
-SEC_ERROR_PKCS11_FUNCTION_FAILED=A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed.  Trying the same operation again might succeed.
+SEC_ERROR_PKCS11_FUNCTION_FAILED=A PKCS #11 module returned CKR_FUNCTION_FAILED, indicating that the requested function could not be performed. Trying the same operation again might succeed.
 SEC_ERROR_PKCS11_DEVICE_ERROR=A PKCS #11 module returned CKR_DEVICE_ERROR, indicating that a problem has occurred with the token or slot.
 SEC_ERROR_BAD_INFO_ACCESS_METHOD=Unknown information access method in certificate extension.
 SEC_ERROR_CRL_IMPORT_FAILED=Error attempting to import a CRL.
 SEC_ERROR_EXPIRED_PASSWORD=The password expired.
 SEC_ERROR_LOCKED_PASSWORD=The password is locked.
 SEC_ERROR_UNKNOWN_PKCS11_ERROR=Unknown PKCS #11 error.
 SEC_ERROR_BAD_CRL_DP_URL=Invalid or unsupported URL in CRL distribution point name.
 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED=The certificate was signed using a signature algorithm that is disabled because it is not secure.
--- a/testing/marionette/driver.js
+++ b/testing/marionette/driver.js
@@ -1136,37 +1136,34 @@ GeckoDriver.prototype.executeWithCallbac
       chromeAsyncError(e, "execute_async_script", filename, line, script);
     }
   }.bind(this));
 
   resp.value = that.curBrowser.elementManager.wrapValue(res);
 };
 
 /**
- * Navigate to to given URL.
+ * Navigate to given URL.
  *
- * This will follow redirects issued by the server.  When the method
- * returns is based on the page load strategy that the user has
- * selected.
+ * Navigates the current browsing context to the given URL and waits for
+ * the document to load or the session's page timeout duration to elapse
+ * before returning.
  *
- * Documents that contain a META tag with the "http-equiv" attribute
- * set to "refresh" will return if the timeout is greater than 1
- * second and the other criteria for determining whether a page is
- * loaded are met.  When the refresh period is 1 second or less and
- * the page load strategy is "normal" or "conservative", it will
- * wait for the page to complete loading before returning.
+ * The command will return with a failure if there is an error loading
+ * the document or the URL is blocked.  This can occur if it fails to
+ * reach host, the URL is malformed, or if there is a certificate issue
+ * to name some examples.
  *
- * If any modal dialog box, such as those opened on
- * window.onbeforeunload or window.alert, is opened at any point in
- * the page load, it will return immediately.
+ * The document is considered successfully loaded when the
+ * DOMContentLoaded event on the frame element associated with the
+ * current window triggers and document.readyState is "complete".
  *
- * If a 401 response is seen by the browser, it will return
- * immediately.  That is, if BASIC, DIGEST, NTLM or similar
- * authentication is required, the page load is assumed to be
- * complete.  This does not include FORM-based authentication.
+ * In chrome context it will change the current window's location to
+ * the supplied URL and wait until document.readyState equals "complete"
+ * or the page timeout duration has elapsed.
  *
  * @param {string} url
  *     URL to navigate to.
  */
 GeckoDriver.prototype.get = function(cmd, resp) {
   let url = cmd.parameters.url;
 
   switch (this.context) {
--- a/testing/marionette/driver/marionette_driver/marionette.py
+++ b/testing/marionette/driver/marionette_driver/marionette.py
@@ -1177,45 +1177,39 @@ class Marionette(object):
 
         This command only makes sense in a chrome context. You might use this
         method to distinguish a browser window from an editor window.
         '''
         response = self._send_message('getWindowType', 'value')
         return response
 
     def navigate(self, url):
-        """Navigate to to given URL.
+        """Navigate to given `url`.
 
-        This will follow redirects issued by the server.  When the
-        method returns is based on the page load strategy that the
-        user has selected.
+        Navigates the current top-level browsing context's content
+        frame to the given URL and waits for the document to load or
+        the session's page timeout duration to elapse before returning.
 
-        Documents that contain a META tag with the "http-equiv"
-        attribute set to "refresh" will return if the timeout is
-        greater than 1 second and the other criteria for determining
-        whether a page is loaded are met.  When the refresh period is
-        1 second or less and the page load strategy is "normal" or
-        "conservative", it will wait for the page to complete loading
-        before returning.
+        The command will return with a failure if there is an error
+        loading the document or the URL is blocked.  This can occur if
+        it fails to reach the host, the URL is malformed, the page is
+        restricted (about:* pages), or if there is a certificate issue
+        to name some examples.
 
-        If any modal dialog box, such as those opened on
-        window.onbeforeunload or window.alert, is opened at any point
-        in the page load, it will return immediately.
+        The document is considered successfully loaded when the
+        `DOMContentLoaded` event on the frame element associated with the
+        `window` triggers and `document.readState` is "complete".
 
-        If a 401 response is seen by the browser, it will return
-        immediately.  That is, if BASIC, DIGEST, NTLM or similar
-        authentication is required, the page load is assumed to be
-        complete.  This does not include FORM-based authentication.
+        In chrome context it will change the current `window`'s location
+        to the supplied URL and wait until `document.readState` equals
+        "complete" or the page timeout duration has elapsed.
 
-        :param url: The url to navigate to.
-
+        :param url: The URL to navigate to.
         """
-
-        response = self._send_message("get", "ok", url=url)
-        return response
+        return self._send_message("get", "ok", url=url)
 
     def timeouts(self, timeout_type, ms):
         """An interface for managing timeout behaviour of a Marionette instance.
 
         Setting timeouts specifies the type and amount of time the Marionette instance should wait during requests.
 
         There are three types of timeouts that can be set: implicit, script and page load.
 
--- a/testing/marionette/listener.js
+++ b/testing/marionette/listener.js
@@ -1204,19 +1204,19 @@ function pollForReadyState(msg, start, c
       sendError(new TimeoutError("Error loading page, timed out (checkLoad)"), command_id);
     }
   }
   checkLoad();
 }
 
 /**
  * Navigate to the given URL.  The operation will be performed on the
- * current browser context, and handles the case where we navigate
- * within an iframe.  All other navigation is handled by the server
- * (in chrome space).
+ * current browsing context, which means it handles the case where we
+ * navigate within an iframe.  All other navigation is handled by the
+ * driver (in chrome space).
  */
 function get(msg) {
   let start = new Date().getTime();
 
   // Prevent DOMContentLoaded events from frames from invoking this
   // code, unless the event is coming from the frame associated with
   // the current window (i.e. someone has used switch_to_frame).
   onDOMContentLoaded = function onDOMContentLoaded(event) {
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -352,17 +352,17 @@
     "expires_in_version": "default",
     "kind": "boolean",
     "description": "Geolocation on OS X is either MLS or CoreLocation"
   },
   "JS_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT": {
     "expires_in_version": "never",
     "kind": "enumerated",
     "n_values": 10,
-    "description": "Use of SpiderMonkey's deprecated language extensions in web content: ForEach=0, DestructuringForIn=1, LegacyGenerator=2, ExpressionClosure=3, LetBlock=4, LetExpression=5, NoSuchMethod=6, FlagsArgument=7"
+    "description": "Use of SpiderMonkey's deprecated language extensions in web content: ForEach=0, DestructuringForIn=1, LegacyGenerator=2, ExpressionClosure=3, LetBlock=4, LetExpression=5, NoSuchMethod=6, FlagsArgument=7, RegExpSourceProp=8"
   },
   "TELEMETRY_PING": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "3000",
     "n_buckets": 10,
     "extended_statistics_ok": true,
     "description": "Time taken to submit telemetry info (ms)"
--- a/view/nsViewManager.cpp
+++ b/view/nsViewManager.cpp
@@ -728,18 +728,18 @@ nsViewManager::DispatchEvent(WidgetGUIEv
 
   WidgetMouseEvent* mouseEvent = aEvent->AsMouseEvent();
   if ((mouseEvent &&
        // Ignore mouse events that we synthesize.
        mouseEvent->reason == WidgetMouseEvent::eReal &&
        // Ignore mouse exit and enter (we'll get moves if the user
        // is really moving the mouse) since we get them when we
        // create and destroy widgets.
-       mouseEvent->message != NS_MOUSE_EXIT &&
-       mouseEvent->message != NS_MOUSE_ENTER) ||
+       mouseEvent->message != NS_MOUSE_EXIT_WIDGET &&
+       mouseEvent->message != NS_MOUSE_ENTER_WIDGET) ||
       aEvent->HasKeyEventMessage() ||
       aEvent->HasIMEEventMessage() ||
       aEvent->message == NS_PLUGIN_INPUT_EVENT) {
     gLastUserEventTime = PR_IntervalToMicroseconds(PR_IntervalNow());
   }
 
   // Find the view whose coordinates system we're in.
   nsView* view = aView;
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -66,23 +66,23 @@
 #define NS_MOZ_USER_ACTIVE               (NS_WINDOW_START + 68)
 
 #define NS_LANGUAGECHANGE                (NS_WINDOW_START + 70)
 
 #define NS_MOUSE_MESSAGE_START          300
 #define NS_MOUSE_MOVE                   (NS_MOUSE_MESSAGE_START)
 #define NS_MOUSE_BUTTON_UP              (NS_MOUSE_MESSAGE_START + 1)
 #define NS_MOUSE_BUTTON_DOWN            (NS_MOUSE_MESSAGE_START + 2)
-#define NS_MOUSE_ENTER                  (NS_MOUSE_MESSAGE_START + 22)
-#define NS_MOUSE_EXIT                   (NS_MOUSE_MESSAGE_START + 23)
+#define NS_MOUSE_ENTER_WIDGET           (NS_MOUSE_MESSAGE_START + 22)
+#define NS_MOUSE_EXIT_WIDGET            (NS_MOUSE_MESSAGE_START + 23)
 #define NS_MOUSE_DOUBLECLICK            (NS_MOUSE_MESSAGE_START + 24)
 #define NS_MOUSE_CLICK                  (NS_MOUSE_MESSAGE_START + 27)
 #define NS_MOUSE_ACTIVATE               (NS_MOUSE_MESSAGE_START + 30)
-#define NS_MOUSE_ENTER_SYNTH            (NS_MOUSE_MESSAGE_START + 31)
-#define NS_MOUSE_EXIT_SYNTH             (NS_MOUSE_MESSAGE_START + 32)
+#define NS_MOUSE_OVER                   (NS_MOUSE_MESSAGE_START + 31)
+#define NS_MOUSE_OUT                    (NS_MOUSE_MESSAGE_START + 32)
 #define NS_MOUSE_MOZHITTEST             (NS_MOUSE_MESSAGE_START + 33)
 #define NS_MOUSEENTER                   (NS_MOUSE_MESSAGE_START + 34)
 #define NS_MOUSELEAVE                   (NS_MOUSE_MESSAGE_START + 35)
 #define NS_MOUSE_MOZLONGTAP             (NS_MOUSE_MESSAGE_START + 36)
 
 // Pointer spec events
 #define NS_POINTER_EVENT_START          4400
 #define NS_POINTER_MOVE                 (NS_POINTER_EVENT_START)
@@ -127,19 +127,17 @@
 #define NS_DRAGDROP_OVER                (NS_DRAGDROP_EVENT_START + 1)
 #define NS_DRAGDROP_EXIT                (NS_DRAGDROP_EVENT_START + 2)
 #define NS_DRAGDROP_DRAGDROP            (NS_DRAGDROP_EVENT_START + 3)
 #define NS_DRAGDROP_GESTURE             (NS_DRAGDROP_EVENT_START + 4)
 #define NS_DRAGDROP_DRAG                (NS_DRAGDROP_EVENT_START + 5)
 #define NS_DRAGDROP_END                 (NS_DRAGDROP_EVENT_START + 6)
 #define NS_DRAGDROP_START               (NS_DRAGDROP_EVENT_START + 7)
 #define NS_DRAGDROP_DROP                (NS_DRAGDROP_EVENT_START + 8)
-#define NS_DRAGDROP_OVER_SYNTH          (NS_DRAGDROP_EVENT_START + 1)
-#define NS_DRAGDROP_EXIT_SYNTH          (NS_DRAGDROP_EVENT_START + 2)
-#define NS_DRAGDROP_LEAVE_SYNTH         (NS_DRAGDROP_EVENT_START + 9)
+#define NS_DRAGDROP_LEAVE               (NS_DRAGDROP_EVENT_START + 9)
 
 // Events for popups
 #define NS_XUL_EVENT_START            1500
 #define NS_XUL_POPUP_SHOWING          (NS_XUL_EVENT_START)
 #define NS_XUL_POPUP_SHOWN            (NS_XUL_EVENT_START+1)
 #define NS_XUL_POPUP_HIDING           (NS_XUL_EVENT_START+2)
 #define NS_XUL_POPUP_HIDDEN           (NS_XUL_EVENT_START+3)
 // NS_XUL_COMMAND used to be here     (NS_XUL_EVENT_START+4)
--- a/widget/InputData.cpp
+++ b/widget/InputData.cpp
@@ -190,17 +190,17 @@ MultiTouchInput::MultiTouchInput(const W
     break;
   case NS_MOUSE_BUTTON_UP:
     mType = MULTITOUCH_END;
     break;
   // The mouse pointer has been interrupted in an implementation-specific
   // manner, such as a synchronous event or action cancelling the touch, or a
   // touch point leaving the document window and going into a non-document
   // area capable of handling user interactions.
-  case NS_MOUSE_EXIT:
+  case NS_MOUSE_EXIT_WIDGET:
     mType = MULTITOUCH_CANCEL;
     break;
   default:
     NS_WARNING("Did not assign a type to a MultiTouchInput");
     break;
   }
 
   mTouches.AppendElement(SingleTouchData(0,
--- a/widget/MouseEvents.h
+++ b/widget/MouseEvents.h
@@ -317,18 +317,18 @@ public:
   virtual WidgetDragEvent* AsDragEvent() override { return this; }
 
   WidgetDragEvent(bool aIsTrusted, uint32_t aMessage, nsIWidget* aWidget)
     : WidgetMouseEvent(aIsTrusted, aMessage, aWidget, eDragEventClass, eReal)
     , userCancelled(false)
     , mDefaultPreventedOnContent(false)
   {
     mFlags.mCancelable =
-      (aMessage != NS_DRAGDROP_EXIT_SYNTH &&
-       aMessage != NS_DRAGDROP_LEAVE_SYNTH &&
+      (aMessage != NS_DRAGDROP_EXIT &&
+       aMessage != NS_DRAGDROP_LEAVE &&
        aMessage != NS_DRAGDROP_END);
   }
 
   virtual WidgetEvent* Duplicate() const override
   {
     MOZ_ASSERT(mClass == eDragEventClass,
                "Duplicate() must be overridden by sub class");
     // Not copying widget, it is a weak reference.
--- a/widget/WidgetEventImpl.cpp
+++ b/widget/WidgetEventImpl.cpp
@@ -77,21 +77,21 @@ WidgetEvent::IsNativeEventDelivererForPl
 bool
 WidgetEvent::HasMouseEventMessage() const
 {
   switch (message) {
     case NS_MOUSE_BUTTON_DOWN:
     case NS_MOUSE_BUTTON_UP:
     case NS_MOUSE_CLICK:
     case NS_MOUSE_DOUBLECLICK:
-    case NS_MOUSE_ENTER:
-    case NS_MOUSE_EXIT:
+    case NS_MOUSE_ENTER_WIDGET:
+    case NS_MOUSE_EXIT_WIDGET:
     case NS_MOUSE_ACTIVATE:
-    case NS_MOUSE_ENTER_SYNTH:
-    case NS_MOUSE_EXIT_SYNTH:
+    case NS_MOUSE_OVER:
+    case NS_MOUSE_OUT:
     case NS_MOUSE_MOZHITTEST:
     case NS_MOUSE_MOVE:
       return true;
     default:
       return false;
   }
 }
 
@@ -103,17 +103,17 @@ WidgetEvent::HasDragEventMessage() const
     case NS_DRAGDROP_OVER:
     case NS_DRAGDROP_EXIT:
     case NS_DRAGDROP_DRAGDROP:
     case NS_DRAGDROP_GESTURE:
     case NS_DRAGDROP_DRAG:
     case NS_DRAGDROP_END:
     case NS_DRAGDROP_START:
     case NS_DRAGDROP_DROP:
-    case NS_DRAGDROP_LEAVE_SYNTH:
+    case NS_DRAGDROP_LEAVE:
       return true;
     default:
       return false;
   }
 }
 
 bool
 WidgetEvent::HasKeyEventMessage() const
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -829,20 +829,20 @@ AndroidGeckoEvent::MakeMouseEvent(nsIWid
 {
     uint32_t msg = NS_EVENT_NULL;
     if (Points().Length() > 0) {
         switch (Action()) {
             case AndroidMotionEvent::ACTION_HOVER_MOVE:
                 msg = NS_MOUSE_MOVE;
                 break;
             case AndroidMotionEvent::ACTION_HOVER_ENTER:
-                msg = NS_MOUSE_ENTER;
+                msg = NS_MOUSE_ENTER_WIDGET;
                 break;
             case AndroidMotionEvent::ACTION_HOVER_EXIT:
-                msg = NS_MOUSE_EXIT;
+                msg = NS_MOUSE_EXIT_WIDGET;
                 break;
             default:
                 break;
         }
     }
 
     WidgetMouseEvent event(true, msg, widget,
                            WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -377,18 +377,18 @@ nsWindow::Show(bool aState)
         return NS_OK;
 
     mIsVisible = aState;
 
     if (IsTopLevel()) {
         // XXX should we bring this to the front when it's shown,
         // if it's a toplevel widget?
 
-        // XXX we should synthesize a NS_MOUSE_EXIT (for old top
-        // window)/NS_MOUSE_ENTER (for new top window) since we need
+        // XXX we should synthesize a NS_MOUSE_EXIT_WIDGET (for old top
+        // window)/NS_MOUSE_ENTER_WIDGET (for new top window) since we need
         // to pretend that the top window always has focus.  Not sure
         // if Show() is the right place to do this, though.
 
         if (aState) {
             // It just became visible, so send a resize update if necessary
             // and bring it to the front.
             Resize(0, 0, gAndroidBounds.width, gAndroidBounds.height, false);
             BringToFront();
--- a/widget/cocoa/nsChildView.mm
+++ b/widget/cocoa/nsChildView.mm
@@ -4544,17 +4544,17 @@ NSEvent* gLastDragMouseDownEvent = nil;
                              type:(WidgetMouseEvent::exitType)aType
 {
   if (!mGeckoChild)
     return;
 
   NSPoint windowEventLocation = nsCocoaUtils::EventLocationForWindow(aEvent, [self window]);
   NSPoint localEventLocation = [self convertPoint:windowEventLocation fromView:nil];
 
-  uint32_t msg = aEnter ? NS_MOUSE_ENTER : NS_MOUSE_EXIT;
+  uint32_t msg = aEnter ? NS_MOUSE_ENTER_WIDGET : NS_MOUSE_EXIT_WIDGET;
   WidgetMouseEvent event(true, msg, mGeckoChild, WidgetMouseEvent::eReal);
   event.refPoint = LayoutDeviceIntPoint::FromUntyped(
     mGeckoChild->CocoaPointsToDevPixels(localEventLocation));
 
   event.exit = aType;
 
   nsEventStatus status; // ignored
   mGeckoChild->DispatchEvent(&event, status);
--- a/widget/gtk/gtk3drawing.c
+++ b/widget/gtk/gtk3drawing.c
@@ -60,16 +60,17 @@ static GtkWidget* gToolbarSeparatorWidge
 static GtkWidget* gMenuSeparatorWidget;
 static GtkWidget* gHPanedWidget;
 static GtkWidget* gVPanedWidget;
 static GtkWidget* gScrolledWindowWidget;
 
 static style_prop_t style_prop_func;
 static gboolean have_arrow_scaling;
 static gboolean checkbox_check_state;
+static gboolean notebook_has_tab_gap;
 static gboolean is_initialized;
 
 #define ARROW_UP      0
 #define ARROW_DOWN    G_PI
 #define ARROW_RIGHT   G_PI_2
 #define ARROW_LEFT    (G_PI+G_PI_2)
 
 #if !GTK_CHECK_VERSION(3,14,0)
@@ -720,16 +721,24 @@ moz_gtk_init()
     have_arrow_scaling = (gtk_major_version > 2 ||
                           (gtk_major_version == 2 && gtk_minor_version >= 12));
     if (gtk_major_version > 3 ||
        (gtk_major_version == 3 && gtk_minor_version >= 14))
         checkbox_check_state = GTK_STATE_FLAG_CHECKED;
     else
         checkbox_check_state = GTK_STATE_FLAG_ACTIVE;
 
+    if(!gtk_check_version(3, 12, 0)) {
+        ensure_tab_widget();
+        gtk_widget_style_get(gTabWidget, "has-tab-gap", &notebook_has_tab_gap, NULL);
+    }
+    else {
+        notebook_has_tab_gap = TRUE;
+    }
+
     /* Add style property to GtkEntry.
      * Adding the style property to the normal GtkEntry class means that it
      * will work without issues inside GtkComboBox and for Spinbuttons. */
     entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
 
     return MOZ_GTK_SUCCESS;
 }
 
@@ -2007,16 +2016,19 @@ moz_gtk_progress_chunk_paint(cairo_t *cr
 
 gint
 moz_gtk_get_tab_thickness(void)
 {
     GtkBorder border;
     GtkStyleContext * style;
 
     ensure_tab_widget();
+    if (!notebook_has_tab_gap)
+      return 0; /* tabs do not overdraw the tabpanel border with "no gap" style */
+
     style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK);
     gtk_style_context_get_border(style, 0, &border);
 
     if (border.top < 2)
         return 2; /* some themes don't set ythickness correctly */
 
     return border.top;
@@ -2052,170 +2064,182 @@ moz_gtk_tab_paint(cairo_t *cr, GdkRectan
     GdkRectangle tabRect;
     GdkRectangle focusRect;
     GdkRectangle backRect;
     int initial_gap = 0;
 
     ensure_tab_widget();
     gtk_widget_set_direction(gTabWidget, direction);
 
-    style = gtk_widget_get_style_context(gTabWidget);    
+    style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_save(style);
     moz_gtk_tab_prepare_style_context(style, flags);
 
     tabRect = *rect;
 
     if (flags & MOZ_GTK_TAB_FIRST) {
         gtk_widget_style_get (gTabWidget, "initial-gap", &initial_gap, NULL);
         tabRect.width -= initial_gap;
 
         if (direction != GTK_TEXT_DIR_RTL) {
             tabRect.x += initial_gap;
         }
     }
 
     focusRect = backRect = tabRect;
 
-    if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
-        /* Only draw the tab */
-        gtk_render_extension(style, cr,
-                             tabRect.x, tabRect.y, tabRect.width, tabRect.height,
-                            (flags & MOZ_GTK_TAB_BOTTOM) ?
-                                GTK_POS_TOP : GTK_POS_BOTTOM );
-    } else {
-        /* Draw the tab and the gap
-         * We want the gap to be positioned exactly on the tabpanel top
-         * border; since tabbox.css may set a negative margin so that the tab
-         * frame rect already overlaps the tabpanel frame rect, we need to take
-         * that into account when drawing. To that effect, nsNativeThemeGTK
-         * passes us this negative margin (bmargin in the graphic below) in the
-         * lowest bits of |flags|.  We use it to set gap_voffset, the distance
-         * between the top of the gap and the bottom of the tab (resp. the
-         * bottom of the gap and the top of the tab when we draw a bottom tab),
-         * while ensuring that the gap always touches the border of the tab,
-         * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
-         * with big negative or positive margins.
-         * Here is a graphical explanation in the case of top tabs:
-         *             ___________________________
-         *            /                           \
-         *           |            T A B            |
-         * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
-         *           :    ^       bmargin          :  ^
-         *           :    | (-negative margin,     :  |
-         *  bottom   :    v  passed in flags)      :  |       gap_height
-         *    of  -> :.............................:  |    (the size of the
-         * the tab   .       part of the gap       .  |  tabpanel top border)
-         *           .      outside of the tab     .  v
-         * ----------------------------------------------
-         *
-         * To draw the gap, we use gtk_paint_box_gap(), see comment in
-         * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
-         * which should suffice to ensure that the only visible border is the
-         * pierced one.  If the tab is in the middle, we make the box_gap begin
-         * a bit to the left of the tab and end a bit to the right, adjusting
-         * the gap position so it still is under the tab, because we want the
-         * rendering of a gap in the middle of a tabpanel.  This is the role of
-         * the gints gap_{l,r}_offset. On the contrary, if the tab is the
-         * first, we align the start border of the box_gap with the start
-         * border of the tab (left if LTR, right if RTL), by setting the
-         * appropriate offset to 0.*/
-        gint gap_loffset, gap_roffset, gap_voffset, gap_height;
-
-        /* Get height needed by the gap */
-        gap_height = moz_gtk_get_tab_thickness();
-
-        /* Extract gap_voffset from the first bits of flags */
-        gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
-        if (gap_voffset > gap_height)
-            gap_voffset = gap_height;
-
-        /* Set gap_{l,r}_offset to appropriate values */
-        gap_loffset = gap_roffset = 20; /* should be enough */
-        if (flags & MOZ_GTK_TAB_FIRST) {
-            if (direction == GTK_TEXT_DIR_RTL)
-                gap_roffset = initial_gap;
-            else
-                gap_loffset = initial_gap;
+    if (notebook_has_tab_gap) {
+        if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
+            /* Only draw the tab */
+            gtk_render_extension(style, cr,
+                                 tabRect.x, tabRect.y, tabRect.width, tabRect.height,
+                                (flags & MOZ_GTK_TAB_BOTTOM) ?
+                                    GTK_POS_TOP : GTK_POS_BOTTOM );
+        } else {
+            /* Draw the tab and the gap
+             * We want the gap to be positioned exactly on the tabpanel top
+             * border; since tabbox.css may set a negative margin so that the tab
+             * frame rect already overlaps the tabpanel frame rect, we need to take
+             * that into account when drawing. To that effect, nsNativeThemeGTK
+             * passes us this negative margin (bmargin in the graphic below) in the
+             * lowest bits of |flags|.  We use it to set gap_voffset, the distance
+             * between the top of the gap and the bottom of the tab (resp. the
+             * bottom of the gap and the top of the tab when we draw a bottom tab),
+             * while ensuring that the gap always touches the border of the tab,
+             * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
+             * with big negative or positive margins.
+             * Here is a graphical explanation in the case of top tabs:
+             *             ___________________________
+             *            /                           \
+             *           |            T A B            |
+             * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
+             *           :    ^       bmargin          :  ^
+             *           :    | (-negative margin,     :  |
+             *  bottom   :    v  passed in flags)      :  |       gap_height
+             *    of  -> :.............................:  |    (the size of the
+             * the tab   .       part of the gap       .  |  tabpanel top border)
+             *           .      outside of the tab     .  v
+             * ----------------------------------------------
+             *
+             * To draw the gap, we use gtk_paint_box_gap(), see comment in
+             * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
+             * which should suffice to ensure that the only visible border is the
+             * pierced one.  If the tab is in the middle, we make the box_gap begin
+             * a bit to the left of the tab and end a bit to the right, adjusting
+             * the gap position so it still is under the tab, because we want the
+             * rendering of a gap in the middle of a tabpanel.  This is the role of
+             * the gints gap_{l,r}_offset. On the contrary, if the tab is the
+             * first, we align the start border of the box_gap with the start
+             * border of the tab (left if LTR, right if RTL), by setting the
+             * appropriate offset to 0.*/
+            gint gap_loffset, gap_roffset, gap_voffset, gap_height;
+
+            /* Get height needed by the gap */
+            gap_height = moz_gtk_get_tab_thickness();
+
+            /* Extract gap_voffset from the first bits of flags */
+            gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
+            if (gap_voffset > gap_height)
+                gap_voffset = gap_height;
+
+            /* Set gap_{l,r}_offset to appropriate values */
+            gap_loffset = gap_roffset = 20; /* should be enough */
+            if (flags & MOZ_GTK_TAB_FIRST) {
+                if (direction == GTK_TEXT_DIR_RTL)
+                    gap_roffset = initial_gap;
+                else
+                    gap_loffset = initial_gap;
+            }
+
+            if (flags & MOZ_GTK_TAB_BOTTOM) {
+                /* Draw the tab on bottom */
+                focusRect.y += gap_voffset;
+                focusRect.height -= gap_voffset;
+
+                gtk_render_extension(style, cr,
+                                     tabRect.x, tabRect.y + gap_voffset, tabRect.width,
+                                     tabRect.height - gap_voffset, GTK_POS_TOP);
+
+                gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
+
+                backRect.y += (gap_voffset - gap_height);
+                backRect.height = gap_height;
+
+                /* Draw the gap; erase with background color before painting in
+                 * case theme does not */
+                gtk_render_background(style, cr, backRect.x, backRect.y,
+                                     backRect.width, backRect.height);
+                cairo_save(cr);
+                cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
+                cairo_clip(cr);
+
+                gtk_render_frame_gap(style, cr,
+                                     tabRect.x - gap_loffset,
+                                     tabRect.y + gap_voffset - 3 * gap_height,
+                                     tabRect.width + gap_loffset + gap_roffset,
+                                     3 * gap_height, GTK_POS_BOTTOM,
+                                     gap_loffset, gap_loffset + tabRect.width);
+                cairo_restore(cr);
+            } else {
+                /* Draw the tab on top */
+                focusRect.height -= gap_voffset;
+                gtk_render_extension(style, cr,
+                                     tabRect.x, tabRect.y, tabRect.width,
+                                     tabRect.height - gap_voffset, GTK_POS_BOTTOM);
+
+                gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
+
+                backRect.y += (tabRect.height - gap_voffset);
+                backRect.height = gap_height;
+
+                /* Draw the gap; erase with background color before painting in
+                 * case theme does not */
+                gtk_render_background(style, cr, backRect.x, backRect.y,
+                                      backRect.width, backRect.height);
+
+                cairo_save(cr);
+                cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
+                cairo_clip(cr);
+
+                gtk_render_frame_gap(style, cr,
+                                     tabRect.x - gap_loffset,
+                                     tabRect.y + tabRect.height - gap_voffset,
+                                     tabRect.width + gap_loffset + gap_roffset,
+                                     3 * gap_height, GTK_POS_TOP,
+                                     gap_loffset, gap_loffset + tabRect.width);
+                cairo_restore(cr);
+            }
         }
-
-        if (flags & MOZ_GTK_TAB_BOTTOM) {
-            /* Draw the tab on bottom */
-            focusRect.y += gap_voffset;
-            focusRect.height -= gap_voffset;
-
-            gtk_render_extension(style, cr,
-                                 tabRect.x, tabRect.y + gap_voffset, tabRect.width,
-                                 tabRect.height - gap_voffset, GTK_POS_TOP);
-
-            gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
-
-            backRect.y += (gap_voffset - gap_height);
-            backRect.height = gap_height;
-
-            /* Draw the gap; erase with background color before painting in
-             * case theme does not */
-            gtk_render_background(style, cr, backRect.x, backRect.y,
-                                 backRect.width, backRect.height);
-            cairo_save(cr);
-            cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
-            cairo_clip(cr);
-
-            gtk_render_frame_gap(style, cr,
-                                 tabRect.x - gap_loffset,
-                                 tabRect.y + gap_voffset - 3 * gap_height,
-                                 tabRect.width + gap_loffset + gap_roffset,
-                                 3 * gap_height, GTK_POS_BOTTOM,
-                                 gap_loffset, gap_loffset + tabRect.width);
-            cairo_restore(cr);
-        } else {
-            /* Draw the tab on top */
-            focusRect.height -= gap_voffset;
-            gtk_render_extension(style, cr,
-                                 tabRect.x, tabRect.y, tabRect.width,
-                                 tabRect.height - gap_voffset, GTK_POS_BOTTOM);
-
-            gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
-
-            backRect.y += (tabRect.height - gap_voffset);
-            backRect.height = gap_height;
-
-            /* Draw the gap; erase with background color before painting in
-             * case theme does not */
-            gtk_render_background(style, cr, backRect.x, backRect.y,
-                                  backRect.width, backRect.height);
-
-            cairo_save(cr);
-            cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
-            cairo_clip(cr);
-
-            gtk_render_frame_gap(style, cr,
-                                 tabRect.x - gap_loffset,
-                                 tabRect.y + tabRect.height - gap_voffset,
-                                 tabRect.width + gap_loffset + gap_roffset,
-                                 3 * gap_height, GTK_POS_TOP,
-                                 gap_loffset, gap_loffset + tabRect.width);
-            cairo_restore(cr);
-        }
+    } else {
+        gtk_render_background(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
+        gtk_render_frame(style, cr, tabRect.x, tabRect.y, tabRect.width, tabRect.height);
     }
 
+    gtk_style_context_restore(style);
+
     if (state->focused) {
       /* Paint the focus ring */
-      GtkBorder border;
-      gtk_style_context_get_border(style, GetStateFlagsFromGtkWidgetState(state), &border);
-
-      focusRect.x += border.left;
-      focusRect.width -= (border.left + border.right);
-      focusRect.y += border.top;
-      focusRect.height -= (border.top + border.bottom);
+      GtkBorder padding;
+
+      gtk_style_context_save(style);
+      moz_gtk_tab_prepare_style_context(style, flags);
+
+      gtk_style_context_get_padding(style, GetStateFlagsFromGtkWidgetState(state), &padding);
+
+      focusRect.x += padding.left;
+      focusRect.width -= (padding.left + padding.right);
+      focusRect.y += padding.top;
+      focusRect.height -= (padding.top + padding.bottom);
 
       gtk_render_focus(style, cr,
                       focusRect.x, focusRect.y, focusRect.width, focusRect.height);
+
+      gtk_style_context_restore(style);
     }
 
-    gtk_style_context_restore(style);
 
     return MOZ_GTK_SUCCESS;
 }
 
 /* tab area*/
 static gint
 moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
                         GtkTextDirection direction)
@@ -2826,41 +2850,30 @@ moz_gtk_get_tab_border(gint* left, gint*
     int tab_curvature;
 
     ensure_tab_widget();
 
     style = gtk_widget_get_style_context(gTabWidget);
     gtk_style_context_save(style);
     moz_gtk_tab_prepare_style_context(style, flags);
 
-    // TODO add_style_border() should be replaced
-    // with focus-line-width and focus-padding
-    // see Bug 877605
     *left = *top = *right = *bottom = 0;
-    moz_gtk_add_style_border(style, left, top, right, bottom);
     moz_gtk_add_style_padding(style, left, top, right, bottom);
 
     gtk_widget_style_get (gTabWidget, "tab-curvature", &tab_curvature, NULL);
     *left += tab_curvature;
     *right += tab_curvature;
 
     if (flags & MOZ_GTK_TAB_FIRST) {
       int initial_gap;
       gtk_widget_style_get (gTabWidget, "initial-gap", &initial_gap, NULL);
       if (direction == GTK_TEXT_DIR_RTL)
-      	*right += initial_gap;
+        *right += initial_gap;
       else
-      	*left += initial_gap;
-    }
-
-    // Top tabs have no bottom border, bottom tabs have no top border
-    if (flags & MOZ_GTK_TAB_BOTTOM) {
-      *top = 0;
-    } else {
-      *bottom = 0;
+        *left += initial_gap;
     }
 
     gtk_style_context_restore(style);
 
     return MOZ_GTK_SUCCESS;
 }
 
 gint
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -760,16 +760,18 @@ nsNativeThemeGTK::GetExtraSizeForWidget(
       break;
     }
   case NS_THEME_TAB :
     {
       if (!IsSelectedTab(aFrame))
         return false;
 
       gint gap_height = moz_gtk_get_tab_thickness();
+      if (!gap_height)
+        return false;
 
       int32_t extra = gap_height - GetTabMarginPixels(aFrame);
       if (extra <= 0)
         return false;
 
       if (IsBottomTab(aFrame)) {
         aExtra->top = extra;
       } else {
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -2537,17 +2537,17 @@ nsWindow::OnEnterNotifyEvent(GdkEventCro
 
     // Check before is_parent_ungrab_enter() as the button state may have
     // changed while a non-Gecko ancestor window had a pointer grab.
     DispatchMissedButtonReleases(aEvent);
 
     if (is_parent_ungrab_enter(aEvent))
         return;
 
-    WidgetMouseEvent event(true, NS_MOUSE_ENTER, this, WidgetMouseEvent::eReal);
+    WidgetMouseEvent event(true, NS_MOUSE_ENTER_WIDGET, this, WidgetMouseEvent::eReal);
 
     event.refPoint.x = nscoord(aEvent->x);
     event.refPoint.y = nscoord(aEvent->y);
 
     event.time = aEvent->time;
 
     LOG(("OnEnterNotify: %p\n", (void *)this));
 
@@ -2578,17 +2578,17 @@ nsWindow::OnLeaveNotifyEvent(GdkEventCro
     // that window.
     //
     // XXXkt However, we will miss toplevel exits when the pointer directly
     // leaves a foreign (plugin) child window without passing over a visible
     // portion of a Gecko window.
     if (aEvent->subwindow != nullptr)
         return;
 
-    WidgetMouseEvent event(true, NS_MOUSE_EXIT, this, WidgetMouseEvent::eReal);
+    WidgetMouseEvent event(true, NS_MOUSE_EXIT_WIDGET, this, WidgetMouseEvent::eReal);
 
     event.refPoint.x = nscoord(aEvent->x);
     event.refPoint.y = nscoord(aEvent->y);
 
     event.time = aEvent->time;
 
     event.exit = is_top_level_mouse_exit(mGdkWindow, aEvent)
         ? WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild;
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -1933,18 +1933,18 @@ case _value: eventName.AssignLiteral(_na
     _ASSIGN_eventName(NS_FORM_CHANGE,"NS_FORM_CHANGE");
     _ASSIGN_eventName(NS_FORM_RESET,"NS_FORM_RESET");
     _ASSIGN_eventName(NS_FORM_SUBMIT,"NS_FORM_SUBMIT");
     _ASSIGN_eventName(NS_IMAGE_ABORT,"NS_IMAGE_ABORT");
     _ASSIGN_eventName(NS_LOAD_ERROR,"NS_LOAD_ERROR");
     _ASSIGN_eventName(NS_KEY_DOWN,"NS_KEY_DOWN");
     _ASSIGN_eventName(NS_KEY_PRESS,"NS_KEY_PRESS");
     _ASSIGN_eventName(NS_KEY_UP,"NS_KEY_UP");
-    _ASSIGN_eventName(NS_MOUSE_ENTER,"NS_MOUSE_ENTER");
-    _ASSIGN_eventName(NS_MOUSE_EXIT,"NS_MOUSE_EXIT");
+    _ASSIGN_eventName(NS_MOUSE_ENTER_WIDGET,"NS_MOUSE_ENTER_WIDGET");
+    _ASSIGN_eventName(NS_MOUSE_EXIT_WIDGET,"NS_MOUSE_EXIT_WIDGET");
     _ASSIGN_eventName(NS_MOUSE_BUTTON_DOWN,"NS_MOUSE_BUTTON_DOWN");
     _ASSIGN_eventName(NS_MOUSE_BUTTON_UP,"NS_MOUSE_BUTTON_UP");
     _ASSIGN_eventName(NS_MOUSE_CLICK,"NS_MOUSE_CLICK");
     _ASSIGN_eventName(NS_MOUSE_DOUBLECLICK,"NS_MOUSE_DBLCLICK");
     _ASSIGN_eventName(NS_MOUSE_MOVE,"NS_MOUSE_MOVE");
     _ASSIGN_eventName(NS_LOAD,"NS_LOAD");
     _ASSIGN_eventName(NS_POPSTATE,"NS_POPSTATE");
     _ASSIGN_eventName(NS_BEFORE_SCRIPT_EXECUTE,"NS_BEFORE_SCRIPT_EXECUTE");
@@ -2094,18 +2094,18 @@ nsBaseWidget::debug_DumpEvent(FILE *    
                               int32_t               aWindowID)
 {
   if (aGuiEvent->message == NS_MOUSE_MOVE)
   {
     if (!debug_GetCachedBoolPref("nglayout.debug.motion_event_dumping"))
       return;
   }
 
-  if (aGuiEvent->message == NS_MOUSE_ENTER ||
-      aGuiEvent->message == NS_MOUSE_EXIT)
+  if (aGuiEvent->message == NS_MOUSE_ENTER_WIDGET ||
+      aGuiEvent->message == NS_MOUSE_EXIT_WIDGET)
   {
     if (!debug_GetCachedBoolPref("nglayout.debug.crossing_event_dumping"))
       return;
   }
 
   if (!debug_GetCachedBoolPref("nglayout.debug.event_dumping"))
     return;
 
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -3775,31 +3775,31 @@ bool nsWindow::DispatchMouseEvent(uint32
   if (NS_MOUSE_MOVE != aEventType
       // Since it is unclear whether a user will use the digitizer,
       // Postpone initialization until first PEN message will be found.
       && nsIDOMMouseEvent::MOZ_SOURCE_PEN == aInputSource
       // Messages should be only at topLevel window.
       && nsWindowType::eWindowType_toplevel == mWindowType
       // Currently this scheme is used only when pointer events is enabled.
       && gfxPrefs::PointerEventsEnabled()
-      // NS_MOUSE_EXIT is received, when InkCollector has been already initialized.
-      && NS_MOUSE_EXIT != aEventType) {
+      // NS_MOUSE_EXIT_WIDGET is received, when InkCollector has been already initialized.
+      && NS_MOUSE_EXIT_WIDGET != aEventType) {
     InkCollector::sInkCollector->SetTarget(mWnd);
   }
 
   switch (aEventType) {
     case NS_MOUSE_BUTTON_DOWN:
       CaptureMouse(true);
       break;
 
-    // NS_MOUSE_MOVE and NS_MOUSE_EXIT are here because we need to make sure capture flag
+    // NS_MOUSE_MOVE and NS_MOUSE_EXIT_WIDGET are here because we need to make sure capture flag
     // isn't left on after a drag where we wouldn't see a button up message (see bug 324131).
     case NS_MOUSE_BUTTON_UP:
     case NS_MOUSE_MOVE:
-    case NS_MOUSE_EXIT:
+    case NS_MOUSE_EXIT_WIDGET:
       if (!(wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)) && sIsInMouseCapture)
         CaptureMouse(false);
       break;
 
     default:
       break;
 
   } // switch
@@ -3882,17 +3882,17 @@ bool nsWindow::DispatchMouseEvent(uint32
       sLastClickCount = 1;
     }
     // Set last Click time on MouseDown only
     sLastMouseDownTime = curMsgTime;
   }
   else if (aEventType == NS_MOUSE_MOVE && !insideMovementThreshold) {
     sLastClickCount = 0;
   }
-  else if (aEventType == NS_MOUSE_EXIT) {
+  else if (aEventType == NS_MOUSE_EXIT_WIDGET) {
     event.exit = IsTopLevelMouseExit(mWnd) ?
                    WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild;
   }
   event.clickCount = sLastClickCount;
 
 #ifdef NS_DEBUG_XX
   PR_LOG(gWindowsLog, PR_LOG_ALWAYS,
          ("Msg Time: %d Click Count: %d\n", curMsgTime, event.clickCount));
@@ -3945,17 +3945,17 @@ bool nsWindow::DispatchMouseEvent(uint32
           break;
         default:
           break;
       }
       break;
     case NS_MOUSE_MOVE:
       pluginEvent.event = WM_MOUSEMOVE;
       break;
-    case NS_MOUSE_EXIT:
+    case NS_MOUSE_EXIT_WIDGET:
       pluginEvent.event = WM_MOUSELEAVE;
       break;
     default:
       pluginEvent.event = WM_NULL;
       break;
   }
 
   pluginEvent.wParam = wParam;     // plugins NEED raw OS event flags!
@@ -3975,30 +3975,30 @@ bool nsWindow::DispatchMouseEvent(uint32
       GetBounds(rect);
       rect.x = 0;
       rect.y = 0;
 
       if (rect.Contains(LayoutDeviceIntPoint::ToUntyped(event.refPoint))) {
         if (sCurrentWindow == nullptr || sCurrentWindow != this) {
           if ((nullptr != sCurrentWindow) && (!sCurrentWindow->mInDtor)) {
             LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
-            sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false, 
+            sCurrentWindow->DispatchMouseEvent(NS_MOUSE_EXIT_WIDGET, wParam, pos, false, 
                                                WidgetMouseEvent::eLeftButton,
                                                aInputSource);
           }
           sCurrentWindow = this;
           if (!mInDtor) {
             LPARAM pos = sCurrentWindow->lParamToClient(lParamToScreen(lParam));
-            sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER, wParam, pos, false,
+            sCurrentWindow->DispatchMouseEvent(NS_MOUSE_ENTER_WIDGET, wParam, pos, false,
                                                WidgetMouseEvent::eLeftButton,
                                                aInputSource);
           }
         }
       }
-    } else if (aEventType == NS_MOUSE_EXIT) {
+    } else if (aEventType == NS_MOUSE_EXIT_WIDGET) {
       if (sCurrentWindow == this) {
         sCurrentWindow = nullptr;
       }
     }
 
     result = ConvertStatus(DispatchInputEvent(&event));
 
     if (nsToolkit::gMouseTrailer)
@@ -4859,17 +4859,17 @@ nsWindow::ProcessMessage(UINT msg, WPARA
       if (userMovedMouse) {
         DispatchPendingEvents();
       }
     }
     break;
 
     case WM_NCMOUSEMOVE:
       // If we receive a mouse move event on non-client chrome, make sure and
-      // send an NS_MOUSE_EXIT event as well.
+      // send an NS_MOUSE_EXIT_WIDGET event as well.
       if (mMousePresent && !sIsInMouseCapture)
         SendMessage(mWnd, WM_MOUSELEAVE, 0, 0);
     break;
 
     case WM_LBUTTONDOWN:
     {
       result = DispatchMouseEvent(NS_MOUSE_BUTTON_DOWN, wParam, lParam,
                                   false, WidgetMouseEvent::eLeftButton,
@@ -4896,25 +4896,25 @@ nsWindow::ProcessMessage(UINT msg, WPARA
       // We need to check mouse button states and put them in for
       // wParam.
       WPARAM mouseState = (GetKeyState(VK_LBUTTON) ? MK_LBUTTON : 0)
         | (GetKeyState(VK_MBUTTON) ? MK_MBUTTON : 0)
         | (GetKeyState(VK_RBUTTON) ? MK_RBUTTON : 0);
       // Synthesize an event position because we don't get one from
       // WM_MOUSELEAVE.
       LPARAM pos = lParamToClient(::GetMessagePos());
-      DispatchMouseEvent(NS_MOUSE_EXIT, mouseState, pos, false,
+      DispatchMouseEvent(NS_MOUSE_EXIT_WIDGET, mouseState, pos, false,
                          WidgetMouseEvent::eLeftButton, MOUSE_INPUT_SOURCE());
     }
     break;
 
     case MOZ_WM_PEN_LEAVES_HOVER_OF_DIGITIZER:
     {
       LPARAM pos = lParamToClient(::GetMessagePos());
-      DispatchMouseEvent(NS_MOUSE_EXIT, wParam, pos, false,
+      DispatchMouseEvent(NS_MOUSE_EXIT_WIDGET, wParam, pos, false,
                          WidgetMouseEvent::eLeftButton,
                          nsIDOMMouseEvent::MOZ_SOURCE_PEN);
     }
     break;
 
     case WM_CONTEXTMENU:
     {
       // if the context menu is brought up from the keyboard, |lParam|