Bug 1454053 - re-record tp6 pages for raptor (wip) draft
authorRob Wood <rwood@mozilla.com>
Wed, 18 Jul 2018 13:40:50 -0400
changeset 821496 d6be8f5e6668b171045e220e12521268d496a054
parent 821495 62fd708ed9d936568e54d21b890dfd9e19703cd0
push id117114
push userrwood@mozilla.com
push dateMon, 23 Jul 2018 13:42:31 +0000
bugs1454053
milestone63.0a1
Bug 1454053 - re-record tp6 pages for raptor (wip) MozReview-Commit-ID: JdSmYZkMPpn
dom/html/nsGenericHTMLElement.cpp
layout/base/PresShell.cpp
layout/base/PresShell.h
layout/base/nsIPresShell.h
testing/raptor/raptor/manifest.py
testing/raptor/raptor/playback/mitmproxy-pagesets-raptor-tp6.manifest
testing/raptor/raptor/playback/mitmproxy-playback-set.manifest
testing/raptor/raptor/playback/mitmproxy.py
testing/raptor/raptor/tests/raptor-tp6.ini
testing/raptor/test/test_playback.py
testing/talos/talos/tests/perf-reftest/perf_reftest.manifest
testing/talos/talos/tests/perf-reftest/util.js
testing/web-platform/meta/MANIFEST.json
--- a/dom/html/nsGenericHTMLElement.cpp
+++ b/dom/html/nsGenericHTMLElement.cpp
@@ -2896,31 +2896,85 @@ nsGenericHTMLElement::NewURIFromString(c
     NS_RELEASE(*aURI);
     return NS_ERROR_DOM_INVALID_STATE_ERR;
   }
 
   return NS_OK;
 }
 
 static bool
-IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
+IsOrHasAncestorWithDisplayNone(Element* aElement)
 {
   return !aElement->HasServoData() || Servo_Element_IsDisplayNone(aElement);
 }
 
 void
 nsGenericHTMLElement::GetInnerText(mozilla::dom::DOMString& aValue,
                                    mozilla::ErrorResult& aError)
 {
-  if (!GetPrimaryFrame(FlushType::Layout)) {
-    nsIPresShell* presShell = nsContentUtils::GetPresShellForContent(this);
+  // innerText depends on layout. For example, white space processing is
+  // something that happens during reflow and which must be reflected by
+  // innerText.  So for:
+  //
+  //   <div style="white-space:normal"> A     B C </div>
+  //
+  // innerText should give "A B C".
+  //
+  // The approach taken here to avoid the expense of reflow is to flush style
+  // and then see whether it's necessary to flush layout afterwards. Flushing
+  // layout can be skipped if we can detect that the element or its descendants
+  // are not dirty.
+
+  // Obtain the composed doc to handle elements in Shadow DOM.
+  nsIDocument* doc = GetComposedDoc();
+  if (doc) {
+    doc->FlushPendingNotifications(FlushType::Style);
+  }
+
+  // Elements with `display: content` will not have a frame. To handle Shadow
+  // DOM, walk the flattened tree looking for parent frame.
+  nsIFrame* frame = GetPrimaryFrame();
+  if (IsDisplayContents()) {
+    for (Element* parent = GetFlattenedTreeParentElement();
+         parent;
+         parent = parent->GetFlattenedTreeParentElement())
+    {
+      frame = parent->GetPrimaryFrame();
+      if (frame) {
+        break;
+      }
+    }
+  }
+
+  // Check for dirty reflow roots in the subtree from targetFrame; this requires
+  // a reflow flush.
+  nsIPresShell* presShell = nsContentUtils::GetPresShellForContent(this);
+  bool dirty = presShell && presShell->FrameIsAncestorOfDirtyRoot(frame);
+
+  // The way we do that is by checking whether the element has either of the two
+  // dirty bits (NS_FRAME_IS_DIRTY or NS_FRAME_HAS_DIRTY_DESCENDANTS) or if any
+  // ancestor has NS_FRAME_IS_DIRTY.  We need to check for NS_FRAME_IS_DIRTY on
+  // ancestors since that is something that implies NS_FRAME_IS_DIRTY on all
+  // descendants.
+  dirty |= frame && frame->HasAnyStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
+  while (!dirty && frame) {
+    dirty |= frame->HasAnyStateBits(NS_FRAME_IS_DIRTY);
+    frame = frame->GetInFlowParent();
+  }
+
+  // Flush layout if we determined a reflow is required.
+  if (dirty && doc) {
+    doc->FlushPendingNotifications(FlushType::Layout);
+  }
+
+  if (!GetPrimaryFrame()) {
     // NOTE(emilio): We need to check the presshell is initialized in order to
     // ensure the document is styled.
     if (!presShell || !presShell->DidInitialize() ||
-        IsOrHasAncestorWithDisplayNone(this, presShell)) {
+        IsOrHasAncestorWithDisplayNone(this)) {
       GetTextContentInternal(aValue, aError);
       return;
     }
   }
 
   nsRange::GetInnerTextNoFlush(aValue, aError, this);
 }
 
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -4558,16 +4558,36 @@ PresShell::ContentRemoved(nsIContent* aC
 
 void
 PresShell::NotifyCounterStylesAreDirty()
 {
   nsAutoCauseReflowNotifier reflowNotifier(this);
   mFrameConstructor->NotifyCounterStylesAreDirty();
 }
 
+bool
+PresShell::FrameIsAncestorOfDirtyRoot(nsIFrame* aFrame) {
+  MOZ_ASSERT(aFrame);
+
+  // Look for a path from any dirty roots to aFrame, following GetParent().
+  // This check mirrors what FrameNeedsReflow() would have done if the reflow
+  // root didn't get in the way.
+  for (nsIFrame* dirtyFrame : mDirtyRoots) {
+    while (dirtyFrame) {
+      if (dirtyFrame == aFrame) {
+        return true;
+      }
+
+      dirtyFrame = dirtyFrame->GetParent();
+    }
+  }
+
+  return false;
+}
+
 void
 PresShell::ReconstructFrames()
 {
   MOZ_ASSERT(!mFrameConstructor->GetRootFrame() || mDidInitialize,
              "Must not have root frame before initial reflow");
   if (!mDidInitialize || mIsDestroying) {
     // Nothing to do here
     return;
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -174,16 +174,18 @@ public:
                                  nsIContent* aOverrideClickTarget = nullptr)
                                  override;
   nsIFrame* GetEventTargetFrame() override;
   already_AddRefed<nsIContent>
     GetEventTargetContent(WidgetEvent* aEvent) override;
 
   void NotifyCounterStylesAreDirty() override;
 
+  bool FrameIsAncestorOfDirtyRoot(nsIFrame* aFrame) override;
+
   void ReconstructFrames(void) override;
   void Freeze() override;
   void Thaw() override;
   void FireOrClearDelayedEvents(bool aFireEvents) override;
 
   nsresult RenderDocument(const nsRect& aRect,
                           uint32_t aFlags,
                           nscolor aBackgroundColor,
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -499,16 +499,21 @@ public:
    */
   virtual void FrameNeedsToContinueReflow(nsIFrame *aFrame) = 0;
 
   virtual void CancelAllPendingReflows() = 0;
 
   virtual void NotifyCounterStylesAreDirty() = 0;
 
   /**
+   * Deterimine if aFrame is an ancestor of any dirty roots.
+   */
+  virtual bool FrameIsAncestorOfDirtyRoot(nsIFrame* aFrame) = 0;
+
+  /**
    * Destroy the frames for aElement, and reconstruct them asynchronously if
    * needed.
    *
    * Note that this may destroy frames for an ancestor instead.
    */
   void DestroyFramesForAndRestyle(mozilla::dom::Element* aElement);
 
   /**
--- a/testing/raptor/raptor/manifest.py
+++ b/testing/raptor/raptor/manifest.py
@@ -13,18 +13,17 @@ from utils import transform_platform
 here = os.path.abspath(os.path.dirname(__file__))
 raptor_ini = os.path.join(here, 'raptor.ini')
 tests_dir = os.path.join(here, 'tests')
 LOG = get_proxy_logger(component="raptor-manifest")
 
 required_settings = ['apps', 'type', 'page_cycles', 'test_url', 'measure',
                      'unit', 'lower_is_better', 'alert_threshold']
 
-playback_settings = ['playback_binary_manifest', 'playback_binary_zip_mac',
-                     'playback_pageset_manifest', 'playback_pageset_zip_mac',
+playback_settings = ['playback_binary_manifest', 'playback_pageset_manifest',
                      'playback_recordings', 'python3_win_manifest']
 
 
 def filter_app(tests, values):
     for test in tests:
         if values["app"] in test['apps']:
             yield test
 
rename from testing/raptor/raptor/playback/mitmproxy-playback-set.manifest
rename to testing/raptor/raptor/playback/mitmproxy-pagesets-raptor-tp6.manifest
--- a/testing/raptor/raptor/playback/mitmproxy-playback-set.manifest
+++ b/testing/raptor/raptor/playback/mitmproxy-pagesets-raptor-tp6.manifest
@@ -1,9 +1,9 @@
 [
     {
-        "filename": "mitmproxy-recording-set-win10.zip",
-        "size": 9189938,
-        "digest": "e904917ed6bf1cef7201284385dc603a283e8e22f992876f17edcf0f1f20db95b609f0d8c7f593b4a0a6c20957dcb6a4d502c562ed74fb6cf4bc255c2f691f32",
+        "filename": "mitmproxy-recordings-raptor-tp6.zip",
+        "size": 8767174,
+        "digest": "3343f54b6c727a2061534872888da4e3aa647e81903c675dc318c717ed0c93f6ce4e2b98c66eb4128376cf8507590531283c95f3951259607edaaae28944d9a5",
         "algorithm": "sha512",
         "unpack": true
     }
 ]
\ No newline at end of file
--- a/testing/raptor/raptor/playback/mitmproxy.py
+++ b/testing/raptor/raptor/playback/mitmproxy.py
@@ -144,17 +144,17 @@ class Mitmproxy(Playback, Python3Virtual
             LOG.info("python3 path is: %s" % self.py3_path)
         else:
             # on osx and linux we use pre-built binaries
             LOG.info("downloading mitmproxy binary")
             _manifest = os.path.join(here, self.config['playback_binary_manifest'])
             transformed_manifest = transform_platform(_manifest, self.config['platform'])
             self._tooltool_fetch(transformed_manifest)
 
-        # we use one pageset for all platforms (pageset was recorded on win10)
+        # we use one pageset for all platforms
         LOG.info("downloading mitmproxy pageset")
         _manifest = os.path.join(here, self.config['playback_pageset_manifest'])
         transformed_manifest = transform_platform(_manifest, self.config['platform'])
         self._tooltool_fetch(transformed_manifest)
         return
 
     def fetch_python3(self):
         """Mitmproxy on windows needs Python 3.x"""
--- a/testing/raptor/raptor/tests/raptor-tp6.ini
+++ b/testing/raptor/raptor/tests/raptor-tp6.ini
@@ -3,66 +3,70 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 # raptor tp6
 
 [DEFAULT]
 type =  pageload
 playback = mitmproxy
 playback_binary_manifest = mitmproxy-rel-bin-{platform}.manifest
-playback_binary_zip_mac = mitmproxy-2.0.2-{platform}.tar.gz
 python3_win_manifest = python3{x64}.manifest
-playback_pageset_manifest = mitmproxy-playback-set.manifest
-playback_pageset_zip_mac = mitmproxy-recording-set-win10.zip
+playback_pageset_manifest = mitmproxy-recordings-raptor-tp6.manifest
 page_cycles = 25
 unit = ms
 lower_is_better = true
 alert_threshold = 2.0
 
 [raptor-firefox-tp6-amazon]
 apps = firefox
 test_url = https://www.amazon.com/s/url=search-alias%3Daps&field-keywords=laptop
-playback_recordings = mitmproxy-recording-amazon.mp
-measure = fnbpaint
+playback_recordings = amazon.mp
+measure = fnbpaint, hero
+hero = hero1
 
 [raptor-firefox-tp6-facebook]
 apps = firefox
 test_url = https://www.facebook.com
-playback_recordings = mitmproxy-recording-facebook.mp
-measure = fnbpaint
+playback_recordings = facebook.mp
+measure = fnbpaint, hero
+hero = hero1
 
 [raptor-firefox-tp6-google]
 apps = firefox
 test_url = https://www.google.com/#hl=en&q=barack+obama
-playback_recordings = mitmproxy-recording-google.mp
+playback_recordings = google-search.mp
 measure = fnbpaint, hero
-hero = hero
+hero = hero1
 
 [raptor-firefox-tp6-youtube]
 apps = firefox
 test_url = https://www.youtube.com
-playback_recordings = mitmproxy-recording-youtube.mp
-measure = fnbpaint
+playback_recordings = youtube.mp
+measure = fnbpaint, hero
+hero = hero1
 
 [raptor-chrome-tp6-amazon]
 apps = chrome
 test_url = https://www.amazon.com/s/url=search-alias%3Daps&field-keywords=laptop
-playback_recordings = mitmproxy-recording-amazon.mp
-measure = fcp
+playback_recordings = amazon.mp
+measure = fcp, hero
+hero = hero1
 
 [raptor-chrome-tp6-facebook]
 apps = chrome
 test_url = https://www.facebook.com
-playback_recordings = mitmproxy-recording-facebook.mp
-measure = fcp
+playback_recordings = facebook.mp
+measure = fcp, hero
+hero = hero1
 
 [raptor-chrome-tp6-google]
 apps = chrome
 test_url = https://www.google.com/#hl=en&q=barack+obama
-playback_recordings = mitmproxy-recording-google.mp
+playback_recordings = google-search.mp
 measure = fcp, hero
-hero = hero
+hero = hero1
 
 [raptor-chrome-tp6-youtube]
 apps = chrome
 test_url = https://www.youtube.com
-playback_recordings = mitmproxy-recording-youtube.mp
-measure = fcp
+playback_recordings = youtube.mp
+measure = fcp, hero
+hero = hero1
--- a/testing/raptor/test/test_playback.py
+++ b/testing/raptor/test/test_playback.py
@@ -18,19 +18,17 @@ def test_get_playback(get_binary):
     config['platform'] = mozinfo.os
     if 'win' in config['platform']:
         # this test is not yet supported on windows
         assert True
         return
     config['obj_path'] = os.path.dirname(get_binary('firefox'))
     config['playback_tool'] = 'mitmproxy'
     config['playback_binary_manifest'] = 'mitmproxy-rel-bin-osx.manifest'
-    config['playback_binary_zip_mac'] = 'mitmproxy-2.0.2-osx.tar.gz'
     config['playback_pageset_manifest'] = 'mitmproxy-playback-set.manifest'
-    config['playback_pageset_zip_mac'] = 'mitmproxy-recording-set-win10.zip'
     config['playback_recordings'] = 'mitmproxy-recording-amazon.mp'
     config['binary'] = get_binary('firefox')
     playback = get_playback(config)
     assert isinstance(playback, Mitmproxy)
     playback.stop()
 
 
 def test_get_unsupported_playback():
--- a/testing/talos/talos/tests/perf-reftest/perf_reftest.manifest
+++ b/testing/talos/talos/tests/perf-reftest/perf_reftest.manifest
@@ -15,8 +15,10 @@
 & http://localhost/tests/perf-reftest/dep-check-1.html, http://localhost/tests/perf-reftest/dep-check-1-ref.html
 & http://localhost/tests/perf-reftest/slow-selector-1.html, http://localhost/tests/perf-reftest/slow-selector-1-ref.html
 & http://localhost/tests/perf-reftest/slow-selector-2.html, http://localhost/tests/perf-reftest/slow-selector-2-ref.html
 & http://localhost/tests/perf-reftest/style-attr-1.html, http://localhost/tests/perf-reftest/style-attr-1-ref.html
 & http://localhost/tests/perf-reftest/stop-cascade-1.html, http://localhost/tests/perf-reftest/stop-cascade-ref.html
 & http://localhost/tests/perf-reftest/stop-cascade-2.html, http://localhost/tests/perf-reftest/stop-cascade-ref.html
 
 & http://localhost/tests/perf-reftest/bidi-resolution-1.html, http://localhost/tests/perf-reftest/bidi-resolution-1-ref.html
+
+& http://localhost/tests/perf-reftest/innertext-1.html, http://localhost/tests/perf-reftest/innertext-1-ref.html
\ No newline at end of file
--- a/testing/talos/talos/tests/perf-reftest/util.js
+++ b/testing/talos/talos/tests/perf-reftest/util.js
@@ -29,16 +29,37 @@ function build_dom(n, elemName, options)
 function build_rule(selector, selectorRepeat, declaration, ruleRepeat) {
   ruleRepeat = ruleRepeat || 1;
   var s = document.createElement("style");
   var rule = Array(selectorRepeat).fill(selector).join(", ") + declaration;
   s.textContent = Array(ruleRepeat).fill(rule).join("\n\n");
   return s;
 }
 
+function build_table(rows, cols, text) {
+  rows = rows || 1;
+  cols = cols || 1;
+  text = text || "";
+  var tbody = document.createElement("tbody");
+  for (j = 0; j < rows; j++) {
+    var row = document.createElement("tr");
+    for (i = 0; i < cols; i++) {
+      var col = document.createElement("td");
+      if (text) {
+        col.textContent = build_text(TEST_WORDS);
+      }
+      row.appendChild(col);
+    }
+    tbody.appendChild(row);
+  }
+  var table = document.createElement("table");
+  table.append(tbody);
+  return table;
+}
+
 function build_text(word, wordRepeat, paraRepeat) {
   wordRepeat = wordRepeat || 1;
   paraRepeat = paraRepeat || 1;
   let para = Array(wordRepeat).fill(word).join(" ");
   return Array(paraRepeat).fill(para).join("\n");
 }
 
 function flush_style(element) {
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -342491,16 +342491,22 @@
     ]
    ],
    "html/dom/elements/global-attributes/the-translate-attribute-012.html": [
     [
      "/html/dom/elements/global-attributes/the-translate-attribute-012.html",
      {}
     ]
    ],
+   "html/dom/elements/the-innertext-idl-attribute/dynamic-getter.html": [
+    [
+     "/html/dom/elements/the-innertext-idl-attribute/dynamic-getter.html",
+     {}
+    ]
+   ],
    "html/dom/elements/the-innertext-idl-attribute/getter.html": [
     [
      "/html/dom/elements/the-innertext-idl-attribute/getter.html",
      {}
     ]
    ],
    "html/dom/elements/the-innertext-idl-attribute/multiple-text-nodes.window.js": [
     [
@@ -576686,16 +576692,20 @@
   "html/dom/elements/requirements-relating-to-bidirectional-algorithm-formatting-characters/reference/dir-isolation-009b-ref.html": [
    "355953f8ebb44f79bfe3cad728bcaaa3ec04e4bb",
    "support"
   ],
   "html/dom/elements/the-innertext-idl-attribute/META.yml": [
    "45472ac8906e7b383d80ab0b92ecddd6b900f726",
    "support"
   ],
+  "html/dom/elements/the-innertext-idl-attribute/dynamic-getter.html": [
+   "12b095d1076d9081266dd3c4437c96c287838cb4",
+   "testharness"
+  ],
   "html/dom/elements/the-innertext-idl-attribute/getter-tests.js": [
    "0ffc6d2bf3011a376f85b45090c63de07ac023d5",
    "support"
   ],
   "html/dom/elements/the-innertext-idl-attribute/getter.html": [
    "bfcd91955e1645278f7825d472bcce03dbc8f773",
    "testharness"
   ],