Bug 961289 - Expose client- and compositor-side APZ test data from nsIDOMWindowUtils. r=ehsan,kats,bholley
authorBotond Ballo <botond@mozilla.com>
Fri, 09 May 2014 17:16:03 -0400
changeset 202521 e6eef0510bb10fbb37c5ba3168ba6e95e66ed0a0
parent 202520 043b5bcd7bc1f419332b6ba35c5181c1149369cd
child 202522 1779847c002c38653e048da5ac414f3824561682
push id3741
push userasasaki@mozilla.com
push dateMon, 21 Jul 2014 20:25:18 +0000
treeherdermozilla-beta@4d6f46f5af68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehsan, kats, bholley
bugs961289
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 961289 - Expose client- and compositor-side APZ test data from nsIDOMWindowUtils. r=ehsan,kats,bholley
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
dom/webidl/APZTestData.webidl
dom/webidl/moz.build
gfx/layers/apz/testutil/APZTestData.cpp
gfx/layers/apz/testutil/APZTestData.h
gfx/layers/client/ClientLayerManager.cpp
gfx/layers/client/ClientLayerManager.h
gfx/layers/moz.build
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -17,16 +17,17 @@
 #include "nsIDocument.h"
 #include "nsFocusManager.h"
 #include "nsFrameManager.h"
 #include "nsRefreshDriver.h"
 #include "mozilla/dom/Touch.h"
 #include "nsIObjectLoadingContent.h"
 #include "nsFrame.h"
 #include "mozilla/layers/ShadowLayers.h"
+#include "ClientLayerManager.h"
 
 #include "nsIScrollableFrame.h"
 
 #include "nsContentUtils.h"
 
 #include "nsIFrame.h"
 #include "nsIWidget.h"
 #include "nsCharsetSource.h"
@@ -3962,16 +3963,60 @@ nsDOMWindowUtils::GetOMTAOrComputedStyle
   rv = element->GetCurrentDoc()->GetWindow()->
     GetComputedStyle(aElement, aProperty, getter_AddRefs(style));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return style->GetPropertyValue(aProperty, aResult);
 }
 
 NS_IMETHODIMP
+nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext,
+                                        JS::MutableHandleValue aOutContentTestData)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  if (nsIWidget* widget = GetWidget()) {
+    nsRefPtr<LayerManager> lm = widget->GetLayerManager();
+    if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
+      ClientLayerManager* clm = static_cast<ClientLayerManager*>(lm.get());
+      if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext,
+                                           JS::MutableHandleValue aOutCompositorTestData)
+{
+  if (!nsContentUtils::IsCallerChrome()) {
+    return NS_ERROR_DOM_SECURITY_ERR;
+  }
+
+  if (nsIWidget* widget = GetWidget()) {
+    nsRefPtr<LayerManager> lm = widget->GetLayerManager();
+    if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
+      ClientLayerManager* clm = static_cast<ClientLayerManager*>(lm.get());
+      APZTestData compositorSideData;
+      clm->GetCompositorSideAPZTestData(&compositorSideData);
+      if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) {
+        return NS_ERROR_FAILURE;
+      }
+    }
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsDOMWindowUtils::GetAudioMuted(bool* aMuted)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_STATE(window);
 
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -43,17 +43,17 @@ interface nsIDOMFile;
 interface nsIFile;
 interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsICompositionStringSynthesizer;
 interface nsITranslationNodeList;
 
-[scriptable, uuid(8489681a-7407-457e-b889-53d1ae999b30)]
+[scriptable, uuid(a1d75ae1-d3fc-40cb-97d5-8c81846632f4)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1670,16 +1670,23 @@ interface nsIDOMWindowUtils : nsISupport
     * Returns the value of a given property.  If the property is animated off
     * the main thread, this function will fetch the correct value from the
     * compositor.
     */
    AString getOMTAOrComputedStyle(in nsIDOMElement aElement,
                                   in AString aProperty);
 
    /**
+    * Get the content- and compositor-side APZ test data instances.
+    * The return values are of type APZTestData (see APZTestData.webidl).
+    */
+   [implicit_jscontext] jsval getContentAPZTestData();
+   [implicit_jscontext] jsval getCompositorAPZTestData();
+
+   /**
     * With this it's possible to mute all the MediaElements in this window.
     * We have audioMuted and audioVolume to preserve the volume across
     * mute/umute.
     */
    attribute boolean audioMuted;
 
     /**
      * range: greater or equal to 0. The real volume level is affected by the
new file mode 100644
--- /dev/null
+++ b/dom/webidl/APZTestData.webidl
@@ -0,0 +1,37 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/*
+ * This file declares data structures used to communicate data logged by
+ * various components for the purpose of APZ testing (see bug 961289 and 
+ * gfx/layers/apz/test/APZTestData.h) to JS test code.
+ */
+
+// A single key-value pair in the data.
+dictionary ScrollFrameDataEntry {
+  DOMString key;
+  DOMString value;
+};
+
+// All the key-value pairs associated with a given scrollable frame.
+// The scrollable frame is identified by a scroll id.
+dictionary ScrollFrameData {
+  unsigned long long scrollId;
+  sequence<ScrollFrameDataEntry> entries;
+};
+
+// All the scrollable frames associated with a given paint or repaint request.
+// The paint or repaint request is identified by a sequence number.
+dictionary APZBucket {
+  unsigned long sequenceNumber;
+  sequence<ScrollFrameData> scrollFrames;
+};
+
+// All the paints and repaint requests. This is the top-level data structure.
+dictionary APZTestData {
+  sequence<APZBucket> paints;
+  sequence<APZBucket> repaintRequests;
+};
\ No newline at end of file
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -17,16 +17,17 @@ PREPROCESSED_WEBIDL_FILES = [
 WEBIDL_FILES = [
     'AbstractWorker.webidl',
     'ActivityRequestHandler.webidl',
     'AnalyserNode.webidl',
     'AnimationEvent.webidl',
     'AnimationTimeline.webidl',
     'AppInfo.webidl',
     'AppNotificationServiceOptions.webidl',
+    'APZTestData.webidl',
     'ArchiveReader.webidl',
     'ArchiveRequest.webidl',
     'Attr.webidl',
     'AudioBuffer.webidl',
     'AudioBufferSourceNode.webidl',
     'AudioChannel.webidl',
     'AudioContext.webidl',
     'AudioDestinationNode.webidl',
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/testutil/APZTestData.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "APZTestData.h"
+#include "mozilla/dom/APZTestDataBinding.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace layers {
+
+struct APZTestDataToJSConverter {
+  template <typename Key, typename Value, typename KeyValuePair>
+  static void ConvertMap(const std::map<Key, Value>& aFrom,
+                               dom::Sequence<KeyValuePair>& aOutTo,
+                               void (*aElementConverter)(const Key&, const Value&, KeyValuePair&)) {
+    for (auto it = aFrom.begin(); it != aFrom.end(); ++it) {
+      aOutTo.AppendElement();
+      aElementConverter(it->first, it->second, aOutTo.LastElement());
+    }
+  }
+
+  static void ConvertAPZTestData(const APZTestData& aFrom,
+                                 dom::APZTestData& aOutTo) {
+    ConvertMap(aFrom.mPaints, aOutTo.mPaints.Construct(), ConvertBucket);
+    ConvertMap(aFrom.mRepaintRequests, aOutTo.mRepaintRequests.Construct(), ConvertBucket);
+  }
+
+  static void ConvertBucket(const SequenceNumber& aKey,
+                            const APZTestData::Bucket& aValue,
+                            dom::APZBucket& aOutKeyValuePair) {
+    aOutKeyValuePair.mSequenceNumber.Construct() = aKey;
+    ConvertMap(aValue, aOutKeyValuePair.mScrollFrames.Construct(), ConvertScrollFrameData);
+  }
+
+  static void ConvertScrollFrameData(const APZTestData::ViewID& aKey,
+                                     const APZTestData::ScrollFrameData& aValue,
+                                     dom::ScrollFrameData& aOutKeyValuePair) {
+    aOutKeyValuePair.mScrollId.Construct() = aKey;
+    ConvertMap(aValue, aOutKeyValuePair.mEntries.Construct(), ConvertEntry);
+  }
+
+  static void ConvertEntry(const std::string& aKey,
+                           const std::string& aValue,
+                           dom::ScrollFrameDataEntry& aOutKeyValuePair) {
+    ConvertString(aKey, aOutKeyValuePair.mKey.Construct());
+    ConvertString(aValue, aOutKeyValuePair.mValue.Construct());
+  }
+
+  static void ConvertString(const std::string& aFrom, nsString& aOutTo) {
+    aOutTo = NS_ConvertUTF8toUTF16(aFrom.c_str(), aFrom.size());
+  }
+};
+
+bool
+APZTestData::ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext) const
+{
+  dom::APZTestData result;
+  APZTestDataToJSConverter::ConvertAPZTestData(*this, result);
+  return dom::ToJSValue(aContext, result, aOutValue);
+}
+
+}
+}
--- a/gfx/layers/apz/testutil/APZTestData.h
+++ b/gfx/layers/apz/testutil/APZTestData.h
@@ -9,16 +9,17 @@
 #include <map>
 
 #include "FrameMetrics.h"
 #include "nsDebug.h"             // for NS_WARNING
 #include "mozilla/Assertions.h"  // for MOZ_ASSERT
 #include "mozilla/DebugOnly.h"   // for DebugOnly
 #include "mozilla/ToString.h"    // for ToString
 #include "ipc/IPCMessageUtils.h"
+#include "js/TypeDecls.h"
 
 namespace mozilla {
 namespace layers {
 
 typedef uint32_t SequenceNumber;
 
 /**
  * This structure is used to store information logged by various gecko
@@ -33,16 +34,17 @@ typedef uint32_t SequenceNumber;
  */
 // TODO(botond):
 //  - Improve warnings/asserts.
 //  - Add ability to associate a repaint request triggered during a layers update
 //    with the sequence number of the paint that caused the layers update.
 class APZTestData {
   typedef FrameMetrics::ViewID ViewID;
   friend struct IPC::ParamTraits<APZTestData>;
+  friend class APZTestDataToJSConverter;
 public:
   void StartNewPaint(SequenceNumber aSequenceNumber) {
     auto insertResult = mPaints.insert(DataStore::value_type(aSequenceNumber, Bucket()));
     if (!insertResult.second) {
       // TODO(botond): Change this to MOZ_ASSERT once we get rid of
       // APZCTreeManager::UpdatePanZoomControllerTree() calls for repeat
       // transactions.
       NS_WARNING("Already have a paint with this sequence number");
@@ -62,16 +64,19 @@ public:
   }
   void LogTestDataForRepaintRequest(SequenceNumber aSequenceNumber,
                                     ViewID aScrollId,
                                     const std::string& aKey,
                                     const std::string& aValue) {
     LogTestDataImpl(mRepaintRequests, aSequenceNumber, aScrollId, aKey, aValue);
   }
 
+  // Convert this object to a JS representation.
+  bool ToJS(JS::MutableHandleValue aOutValue, JSContext* aContext) const;
+
   // Use dummy derived structures wrapping the tyepdefs to work around a type
   // name length limit in MSVC.
   typedef std::map<std::string, std::string> ScrollFrameDataBase;
   struct ScrollFrameData : ScrollFrameDataBase {};
   typedef std::map<ViewID, ScrollFrameData> BucketBase;
   struct Bucket : BucketBase {};
   typedef std::map<SequenceNumber, Bucket> DataStoreBase;
   struct DataStore : DataStoreBase {};
--- a/gfx/layers/client/ClientLayerManager.cpp
+++ b/gfx/layers/client/ClientLayerManager.cpp
@@ -294,16 +294,26 @@ ClientLayerManager::DidComposite()
     listener->DidCompositeWindow();
   }
   listener = mWidget->GetAttachedWidgetListener();
   if (listener) {
     listener->DidCompositeWindow();
   }
 }
 
+void
+ClientLayerManager::GetCompositorSideAPZTestData(APZTestData* aData) const
+{
+  if (mForwarder->HasShadowManager()) {
+    if (!mForwarder->GetShadowManager()->SendGetAPZTestData(aData)) {
+      NS_WARNING("Call to PLayerTransactionChild::SendGetAPZTestData() failed");
+    }
+  }
+}
+
 bool
 ClientLayerManager::RequestOverfill(mozilla::dom::OverfillCallback* aCallback)
 {
   MOZ_ASSERT(aCallback != nullptr);
   MOZ_ASSERT(HasShadowManager(), "Request Overfill only supported on b2g for now");
 
   if (HasShadowManager()) {
     CompositorChild* child = GetRemoteRenderer();
--- a/gfx/layers/client/ClientLayerManager.h
+++ b/gfx/layers/client/ClientLayerManager.h
@@ -193,16 +193,25 @@ public:
   void LogTestDataForRepaintRequest(SequenceNumber aSequenceNumber,
                                     FrameMetrics::ViewID aScrollId,
                                     const std::string& aKey,
                                     const std::string& aValue)
   {
     mApzTestData.LogTestDataForRepaintRequest(aSequenceNumber, aScrollId, aKey, aValue);
   }
 
+  // Get the content-side APZ test data for reading. For writing, use the
+  // LogTestData...() functions.
+  const APZTestData& GetAPZTestData() const {
+    return mApzTestData;
+  }
+
+  // Get a copy of the compositor-side APZ test data for our layers ID.
+  void GetCompositorSideAPZTestData(APZTestData* aData) const;
+
 protected:
   enum TransactionPhase {
     PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD
   };
   TransactionPhase mPhase;
 
 private:
   /**
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -224,16 +224,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         ]
 
 UNIFIED_SOURCES += [
     'apz/src/APZCTreeManager.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/Axis.cpp',
     'apz/src/GestureEventListener.cpp',
     'apz/src/TaskThrottler.cpp',
+    'apz/testutil/APZTestData.cpp',
     'apz/util/ActiveElementManager.cpp',
     'apz/util/APZCCallbackHelper.cpp',
     'basic/BasicCanvasLayer.cpp',
     'basic/BasicColorLayer.cpp',
     'basic/BasicCompositor.cpp',
     'basic/BasicContainerLayer.cpp',
     'basic/BasicImages.cpp',
     'basic/BasicLayerManager.cpp',