Merge m-i to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 04 Dec 2016 07:04:02 -0800
changeset 325250 12637ae351d64ecbf6b74cdbf26d7eb24ac0f659
parent 325243 ffe250d116edb093404b534883d9daba3792e15c (current diff)
parent 325249 96749829f50afb4e1fd86195b8ca2e6b269c1ba6 (diff)
child 325254 fef5e39a4c3a0b9c4d3fbe5bd098fc17bf7bbb27
child 325263 c7beb88235a105fdd854945688ded42e043da8d4
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersmerge
milestone53.0a1
Merge m-i to m-c, a=merge MozReview-Commit-ID: CO7PdhmLZCq
layout/base/nsLayoutUtils.cpp
--- a/accessible/ipc/DocAccessibleParent.cpp
+++ b/accessible/ipc/DocAccessibleParent.cpp
@@ -481,12 +481,43 @@ DocAccessibleParent::RecvCOMProxy(const 
   IAccessible* rawNative = nullptr;
   if (outerDoc) {
     outerDoc->GetNativeInterface((void**) &rawNative);
   }
 
   aParentCOMProxy->Set(IAccessibleHolder::COMPtrType(rawNative));
   return IPC_OK();
 }
+
+mozilla::ipc::IPCResult
+DocAccessibleParent::RecvGetWindowedPluginIAccessible(
+      const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy)
+{
+#if defined(MOZ_CONTENT_SANDBOX)
+  // We don't actually want the accessible object for aHwnd, but rather the
+  // one that belongs to its child (see HTMLWin32ObjectAccessible).
+  HWND childWnd = ::GetWindow(reinterpret_cast<HWND>(aHwnd), GW_CHILD);
+  if (!childWnd) {
+    return IPC_FAIL(this, "GetWindow failed");
+  }
+
+  IAccessible* rawAccPlugin = nullptr;
+  HRESULT hr = ::AccessibleObjectFromWindow(childWnd, OBJID_WINDOW,
+                                            IID_IAccessible,
+                                            (void**)&rawAccPlugin);
+  if (FAILED(hr)) {
+    // This might happen if the plugin doesn't handle WM_GETOBJECT properly.
+    // We should not consider that a failure.
+    return IPC_OK();
+  }
+
+  aPluginCOMProxy->Set(IAccessibleHolder::COMPtrType(rawAccPlugin));
+
+  return IPC_OK();
+#else
+  return IPC_FAIL(this, "Message unsupported in this build configuration");
+#endif
+}
+
 #endif // defined(XP_WIN)
 
 } // a11y
 } // mozilla
--- a/accessible/ipc/DocAccessibleParent.h
+++ b/accessible/ipc/DocAccessibleParent.h
@@ -141,16 +141,19 @@ public:
 
   size_t ChildDocCount() const { return mChildDocs.Length(); }
   const DocAccessibleParent* ChildDocAt(size_t aIdx) const
     { return mChildDocs[aIdx]; }
 
 #if defined(XP_WIN)
   virtual mozilla::ipc::IPCResult RecvCOMProxy(const IAccessibleHolder& aCOMProxy,
                                                IAccessibleHolder* aParentCOMProxy) override;
+
+  virtual mozilla::ipc::IPCResult RecvGetWindowedPluginIAccessible(
+      const WindowsHandle& aHwnd, IAccessibleHolder* aPluginCOMProxy) override;
 #endif
 
 private:
 
   class ProxyEntry : public PLDHashEntryHdr
   {
   public:
     explicit ProxyEntry(const void*) : mProxy(nullptr) {}
--- a/accessible/ipc/win/PDocAccessible.ipdl
+++ b/accessible/ipc/win/PDocAccessible.ipdl
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PFileDescriptorSet;
 include protocol PBrowser;
 
 using mozilla::a11y::IAccessibleHolder from "mozilla/a11y/COMPtrTypes.h";
+using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 
 namespace mozilla {
 namespace a11y {
 
 struct AccessibleData
 {
   uint64_t ID;
   int32_t MsaaID;
@@ -56,16 +57,19 @@ parent:
   async RoleChangedEvent(uint32_t aRole);
 
   /*
    * Tell the parent document to bind the existing document as a new child
    * document.
    */
   async BindChildDoc(PDocAccessible aChildDoc, uint64_t aID);
 
+  sync GetWindowedPluginIAccessible(WindowsHandle aHwnd)
+    returns (IAccessibleHolder aPluginCOMProxy);
+
   // For now we'll add the command to send the proxy here. This might move to
   // PDocAccessible constructor in PBrowser.
   sync COMProxy(IAccessibleHolder aDocCOMProxy)
     returns(IAccessibleHolder aParentCOMProxy);
 
 child:
   async __delete__();
 };
--- a/accessible/windows/msaa/EnumVariant.cpp
+++ b/accessible/windows/msaa/EnumVariant.cpp
@@ -27,23 +27,34 @@ ChildrenEnumVariant::Next(ULONG aCount, 
     return E_INVALIDARG;
 
   *aCountFetched = 0;
 
   if (mAnchorAcc->IsDefunct() || mAnchorAcc->GetChildAt(mCurIndex) != mCurAcc)
     return CO_E_OBJNOTCONNECTED;
 
   ULONG countFetched = 0;
-  for (; mCurAcc && countFetched < aCount; countFetched++) {
+  while (mCurAcc && countFetched < aCount) {
     VariantInit(aItems + countFetched);
-    aItems[countFetched].pdispVal = AccessibleWrap::NativeAccessible(mCurAcc);
+
+    IDispatch* accNative = AccessibleWrap::NativeAccessible(mCurAcc);
+
+    ++mCurIndex;
+    mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
+
+    // Don't output the accessible and count it as having been fetched unless
+    // it is non-null
+    MOZ_ASSERT(accNative);
+    if (!accNative) {
+      continue;
+    }
+
+    aItems[countFetched].pdispVal = accNative;
     aItems[countFetched].vt = VT_DISPATCH;
-
-    mCurIndex++;
-    mCurAcc = mAnchorAcc->GetChildAt(mCurIndex);
+    ++countFetched;
   }
 
   (*aCountFetched) = countFetched;
 
   return countFetched < aCount ? S_FALSE : S_OK;
 
   A11Y_TRYBLOCK_END
 }
--- a/accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp
+++ b/accessible/windows/msaa/HTMLWin32ObjectAccessible.cpp
@@ -57,29 +57,56 @@ HTMLWin32ObjectOwnerAccessible::Natively
 ////////////////////////////////////////////////////////////////////////////////
 
 HTMLWin32ObjectAccessible::HTMLWin32ObjectAccessible(void* aHwnd,
                                                      DocAccessible* aDoc) :
   DummyAccessible(aDoc)
 {
   mHwnd = aHwnd;
   if (mHwnd) {
+#if defined(MOZ_CONTENT_SANDBOX)
+    if (XRE_IsContentProcess()) {
+      DocAccessibleChild* ipcDoc = aDoc->IPCDoc();
+      MOZ_ASSERT(ipcDoc);
+      if (!ipcDoc) {
+        return;
+      }
+
+      IAccessibleHolder proxyHolder;
+      if (!ipcDoc->SendGetWindowedPluginIAccessible(
+              reinterpret_cast<uintptr_t>(mHwnd), &proxyHolder)) {
+        return;
+      }
+
+      mCOMProxy.reset(proxyHolder.Release());
+      return;
+    }
+#endif
+
     // The plugin is not windowless. In this situation we use 
     // use its inner child owned by the plugin so that we don't get
     // in an infinite loop, where the WM_GETOBJECT's get forwarded
     // back to us and create another HTMLWin32ObjectAccessible
     HWND childWnd = ::GetWindow((HWND)aHwnd, GW_CHILD);
     if (childWnd) {
       mHwnd = childWnd;
     }
   }
 }
 
 void
 HTMLWin32ObjectAccessible::GetNativeInterface(void** aNativeAccessible)
 {
+#if defined(MOZ_CONTENT_SANDBOX)
+  if (XRE_IsContentProcess()) {
+    RefPtr<IAccessible> addRefed = mCOMProxy.get();
+    addRefed.forget(aNativeAccessible);
+    return;
+  }
+#endif
+
   if (mHwnd) {
     ::AccessibleObjectFromWindow(static_cast<HWND>(mHwnd),
                                  OBJID_WINDOW, IID_IAccessible,
                                  aNativeAccessible);
   }
 }
 
--- a/accessible/windows/msaa/HTMLWin32ObjectAccessible.h
+++ b/accessible/windows/msaa/HTMLWin32ObjectAccessible.h
@@ -3,16 +3,20 @@
  * 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 mozilla_a11y_HTMLWin32ObjectAccessible_h_
 #define mozilla_a11y_HTMLWin32ObjectAccessible_h_
 
 #include "BaseAccessibles.h"
 
+#if defined(MOZ_CONTENT_SANDBOX)
+#include "mozilla/mscom/Ptr.h"
+#endif
+
 struct IAccessible;
 
 namespace mozilla {
 namespace a11y {
 
 class HTMLWin32ObjectOwnerAccessible : public AccessibleWrap
 {
 public:
@@ -50,14 +54,17 @@ class HTMLWin32ObjectAccessible : public
 public:
   HTMLWin32ObjectAccessible(void* aHwnd, DocAccessible* aDoc);
   virtual ~HTMLWin32ObjectAccessible() {}
 
   virtual void GetNativeInterface(void** aNativeAccessible) override;
 
 protected:
   void* mHwnd;
+#if defined(MOZ_CONTENT_SANDBOX)
+  mscom::ProxyUniquePtr<IAccessible> mCOMProxy;
+#endif
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif
--- a/image/MultipartImage.cpp
+++ b/image/MultipartImage.cpp
@@ -170,17 +170,19 @@ MultipartImage::BeginTransitionToPart(Im
   mNextPart->IncrementAnimationConsumers();
 }
 
 static Progress
 FilterProgress(Progress aProgress)
 {
   // Filter out onload blocking notifications, since we don't want to block
   // onload for multipart images.
-  return aProgress & ~(FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED);
+  // Filter out errors, since we don't want errors in one part to error out
+  // the whole stream.
+  return aProgress & ~(FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED | FLAG_HAS_ERROR);
 }
 
 void
 MultipartImage::FinishTransition()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mNextPart, "Should have a next part here");
 
--- a/image/ProgressTracker.cpp
+++ b/image/ProgressTracker.cpp
@@ -18,39 +18,44 @@
 #include "mozilla/Services.h"
 
 using mozilla::WeakPtr;
 
 namespace mozilla {
 namespace image {
 
 static void
-CheckProgressConsistency(Progress aOldProgress, Progress aNewProgress)
+CheckProgressConsistency(Progress aOldProgress, Progress aNewProgress, bool aIsMultipart)
 {
   // Check preconditions for every progress bit.
 
+  // Error's do not get propagated from the tracker for each image part to the
+  // tracker for the multipart image because we don't want one bad part to
+  // prevent the remaining parts from showing. So we need to consider whether
+  // this is a tracker for a multipart image for these assertions to work.
+
   if (aNewProgress & FLAG_SIZE_AVAILABLE) {
     // No preconditions.
   }
   if (aNewProgress & FLAG_DECODE_COMPLETE) {
     MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
-    MOZ_ASSERT(aNewProgress & (FLAG_FRAME_COMPLETE | FLAG_HAS_ERROR));
+    MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_FRAME_COMPLETE | FLAG_HAS_ERROR));
   }
   if (aNewProgress & FLAG_FRAME_COMPLETE) {
     MOZ_ASSERT(aNewProgress & FLAG_SIZE_AVAILABLE);
   }
   if (aNewProgress & FLAG_LOAD_COMPLETE) {
-    MOZ_ASSERT(aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
+    MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
   }
   if (aNewProgress & FLAG_ONLOAD_BLOCKED) {
     // No preconditions.
   }
   if (aNewProgress & FLAG_ONLOAD_UNBLOCKED) {
     MOZ_ASSERT(aNewProgress & FLAG_ONLOAD_BLOCKED);
-    MOZ_ASSERT(aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
+    MOZ_ASSERT(aIsMultipart || aNewProgress & (FLAG_SIZE_AVAILABLE | FLAG_HAS_ERROR));
   }
   if (aNewProgress & FLAG_IS_ANIMATED) {
     // No preconditions; like FLAG_HAS_TRANSPARENCY, we should normally never
     // discover this *after* FLAG_SIZE_AVAILABLE, but unfortunately some corrupt
     // GIFs may fool us.
   }
   if (aNewProgress & FLAG_HAS_TRANSPARENCY) {
     // XXX We'd like to assert that transparency is only set during metadata
@@ -370,17 +375,17 @@ ProgressTracker::SyncNotifyProgress(Prog
   MOZ_ASSERT(NS_IsMainThread(), "Use mObservers on main thread only");
 
   // Don't unblock onload if we're not blocked.
   Progress progress = Difference(aProgress);
   if (!((mProgress | progress) & FLAG_ONLOAD_BLOCKED)) {
     progress &= ~FLAG_ONLOAD_UNBLOCKED;
   }
 
-  CheckProgressConsistency(mProgress, mProgress | progress);
+  CheckProgressConsistency(mProgress, mProgress | progress, mIsMultipart);
 
   // XXX(seth): Hack to work around the fact that some observers have bugs and
   // need to get onload blocking notifications multiple times. We should fix
   // those observers and remove this.
   if ((aProgress & FLAG_DECODE_COMPLETE) &&
       (mProgress & FLAG_ONLOAD_BLOCKED) &&
       (mProgress & FLAG_ONLOAD_UNBLOCKED)) {
     progress |= FLAG_ONLOAD_BLOCKED | FLAG_ONLOAD_UNBLOCKED;
--- a/image/ProgressTracker.h
+++ b/image/ProgressTracker.h
@@ -113,16 +113,17 @@ public:
   MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ProgressTracker)
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ProgressTracker)
 
   ProgressTracker()
     : mImageMutex("ProgressTracker::mImage")
     , mImage(nullptr)
     , mObservers(new ObserverTable)
     , mProgress(NoProgress)
+    , mIsMultipart(false)
   { }
 
   bool HasImage() const { MutexAutoLock lock(mImageMutex); return mImage; }
   already_AddRefed<Image> GetImage() const
   {
     MutexAutoLock lock(mImageMutex);
     RefPtr<Image> image = mImage;
     return image.forget();
@@ -190,16 +191,19 @@ public:
   void AddObserver(IProgressObserver* aObserver);
   bool RemoveObserver(IProgressObserver* aObserver);
   uint32_t ObserverCount() const;
 
   // Resets our weak reference to our image. Image subclasses should call this
   // in their destructor.
   void ResetImage();
 
+  // Tell this progress tracker that it is for a multipart image.
+  void SetIsMultipart() { mIsMultipart = true; }
+
 private:
   friend class AsyncNotifyRunnable;
   friend class AsyncNotifyCurrentStateRunnable;
   friend class ImageFactory;
 
   ProgressTracker(const ProgressTracker& aOther) = delete;
 
   // Sets our weak reference to our image. Only ImageFactory should call this.
@@ -221,14 +225,17 @@ private:
   mutable Mutex mImageMutex;
   Image* mImage;
 
   // Hashtable of observers attached to the image. Each observer represents a
   // consumer using the image. Main thread only.
   CopyOnWrite<ObserverTable> mObservers;
 
   Progress mProgress;
+
+  // Whether this is a progress tracker for a multipart image.
+  bool mIsMultipart;
 };
 
 } // namespace image
 } // namespace mozilla
 
 #endif // mozilla_image_ProgressTracker_h
--- a/image/imgRequest.cpp
+++ b/image/imgRequest.cpp
@@ -958,16 +958,17 @@ PrepareForNewPart(nsIRequest* aRequest, 
     RefPtr<Image> partImage =
       ImageFactory::CreateImage(aRequest, progressTracker, result.mContentType,
                                 aURI, /* aIsMultipart = */ true,
                                 aInnerWindowId);
 
     if (result.mIsFirstPart) {
       // First part for a multipart channel. Create the MultipartImage wrapper.
       MOZ_ASSERT(aProgressTracker, "Shouldn't have given away tracker yet");
+      aProgressTracker->SetIsMultipart();
       result.mImage =
         ImageFactory::CreateMultipartImage(partImage, aProgressTracker);
     } else {
       // Transition to the new part.
       auto multipartImage = static_cast<MultipartImage*>(aExistingImage);
       multipartImage->BeginTransitionToPart(partImage);
 
       // Reset our cache entry size so it doesn't keep growing without bound.
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -5959,20 +5959,21 @@ nsLayoutUtils::GetLastLineBaseline(Writi
       nscoord kidBaseline;
       const nsSize& containerSize = line->mContainerSize;
       if (GetLastLineBaseline(aWM, kid, &kidBaseline)) {
         // Ignore relative positioning for baseline calculations
         *aResult = kidBaseline +
           kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
         return true;
       } else if (kid->GetType() == nsGkAtoms::scrollFrame) {
-        // Use the bottom of the scroll frame.
-        // XXX CSS2.1 really doesn't say what to do here.
-        *aResult = kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM) +
-                   kid->BSize(aWM);
+        // Defer to nsFrame::GetLogicalBaseline (which synthesizes a baseline
+        // from the margin-box).
+        kidBaseline = kid->GetLogicalBaseline(aWM);
+        *aResult = kidBaseline +
+          kid->GetLogicalNormalPosition(aWM, containerSize).B(aWM);
         return true;
       }
     } else {
       // XXX Is this the right test?  We have some bogus empty lines
       // floating around, but IsEmpty is perhaps too weak.
       if (line->BSize() != 0 || !line->IsEmpty()) {
         *aResult = line->BStart() + line->GetLogicalAscent();
         return true;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/inline/inline-block-baseline-ref.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html><head>
+<style>
+.inline-block { display: inline-block; }
+.test {
+  background-color: lightgrey;
+  overflow: hidden;
+}
+.border { border: solid blue;  border-width: 1px 3px 5px 7px; }
+.padding { padding: 10px; }
+.margin { margin: 1px 3px 5px 7px; }
+</style>
+
+</head><body>
+
+The boxes should align vertically:
+<div class="test inline-block margin border padding overflow"></div>
+
+<div class="test inline-block margin border padding overflow"></div>
+
+<br>
+
+The boxes should align vertically:
+<div class="test inline-block margin border padding overflow">X</div>
+
+<div class="test inline-block margin border padding overflow">X</div>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/inline/inline-block-baseline.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html><head>
+<style>
+.inline-block { display: inline-block; }
+.test {
+  background-color: lightgrey;
+  overflow: hidden;
+}
+.border { border: solid blue;  border-width: 1px 3px 5px 7px; }
+.padding { padding: 10px; }
+.margin { margin: 1px 3px 5px 7px; }
+</style>
+
+</head><body>
+
+The boxes should align vertically:
+<div class="inline-block">
+  <div>
+      <div class="test border padding margin overflow"></div>
+  </div>
+</div>
+
+<div class="test inline-block margin border padding overflow"></div>
+
+<br>
+
+The boxes should align vertically:
+<div class="inline-block">
+  <div>
+      <div class="test border padding margin overflow">X</div>
+  </div>
+</div>
+
+<div class="test inline-block margin border padding overflow">X</div>
+
+</body></html>
--- a/layout/reftests/inline/reftest.list
+++ b/layout/reftests/inline/reftest.list
@@ -1,7 +1,8 @@
 == zero-inline-block-margin-left.html zero-inline-block-margin-ref.html
 == zero-inline-block-margin-right.html zero-inline-block-margin-ref.html
 == zero-inline-block-margin-ref.html zero-inline-block-margin-ref2.html
 == inline-block-width.html zero-inline-block-margin-ref.html
 == inline-block-padding.html inline-block-width.html
 == inline-block-margin.html inline-block-width.html
 != inline-block-width.html inline-block-zero.html
+== inline-block-baseline.html inline-block-baseline-ref.html