Reland "Updates performance timeline for long tasks"

This reverts commit 84d733f34b732ce42a0a2d70ab2cb273e0f86dc7.

Reason for revert: Relanding to fix layout test

Original change's description:
> Revert "Updates performance timeline for long tasks"
> 
> This reverts commit e19afdbb2fb24f4123dc7b8b62f38d359ff2d916.
> 
> Reason for revert: it breaks a flamechart layout test: https://test-results.appspot.com/data/layout_results/DevTools_Linux/556/webkit_layout_tests%20%28with%20patch%29/layout-test-results/results.html
> 
> Original change's description:
> > Updates performance timeline for long tasks
> > 
> > This CL updates the performance timeline to a) mark any task longer than
> > 50ms as a "long task" (which is in line with TBT and RAIL guidelines),
> > and denotes long-running, top level, main thread tasks with a candy
> > stripe visual marker.
> > 
> > Bug: 1054447
> > Change-Id: I14a708db64f2c5afedf72fe49ad2c69e251c4891
> > Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2067058
> > Commit-Queue: Paul Lewis <[email protected]>
> > Reviewed-by: Tim van der Lippe <[email protected]>
> 
> [email protected],[email protected]
> 
> Change-Id: Ie00ad35072147e84166b1448b07f2a92d777b741
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: 1054447
> Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2067063
> Reviewed-by: Tim van der Lippe <[email protected]>
> Commit-Queue: Tim van der Lippe <[email protected]>

[email protected],[email protected]

Change-Id: I34f10e06e915cc91765b9adfaa4aade2da7428e7
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1054447
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2067064
Commit-Queue: Paul Lewis <[email protected]>
Reviewed-by: Paul Lewis <[email protected]>
diff --git a/front_end/perf_ui/FlameChart.js b/front_end/perf_ui/FlameChart.js
index a7ec82b..bb0b383 100644
--- a/front_end/perf_ui/FlameChart.js
+++ b/front_end/perf_ui/FlameChart.js
@@ -87,6 +87,9 @@
 
     this._dataProvider = dataProvider;
 
+    this._candyStripeCanvas = /** @type {!HTMLCanvasElement} */ (document.createElement('canvas'));
+    this._createCandyStripePattern();
+
     this._viewportElement = this._chartViewport.viewportElement;
     if (this._useWebGL) {
       this._canvasGL = /** @type {!HTMLCanvasElement} */ (this._viewportElement.createChild('canvas', 'fill'));
@@ -227,6 +230,25 @@
     this.dispatchEventToListeners(Events.EntryHighlighted, -1);
   }
 
+  _createCandyStripePattern() {
+    // Set the candy stripe pattern to 17px so it repeats well.
+    const size = 17;
+    this._candyStripeCanvas.width = size;
+    this._candyStripeCanvas.height = size;
+
+    const ctx = this._candyStripeCanvas.getContext('2d');
+
+    // Rotate the stripe by 45deg to the right.
+    ctx.translate(size * 0.5, size * 0.5);
+    ctx.rotate(Math.PI * 0.25);
+    ctx.translate(-size * 0.5, -size * 0.5);
+
+    ctx.fillStyle = 'rgba(255, 0, 0, 0.4)';
+    for (let x = -size; x < size * 2; x += 3) {
+      ctx.fillRect(x, -size, 1, size * 3);
+    }
+  }
+
   _resetCanvas() {
     const ratio = window.devicePixelRatio;
     const width = Math.round(this._offsetWidth * ratio);
@@ -981,6 +1003,8 @@
     const defaultFont = '11px ' + Host.Platform.fontFamily();
     context.font = defaultFont;
 
+    const candyStripePattern = context.createPattern(this._candyStripeCanvas, 'repeat');
+
     const entryTotalTimes = timelineData.entryTotalTimes;
     const entryStartTimes = timelineData.entryStartTimes;
     const entryLevels = timelineData.entryLevels;
@@ -994,7 +1018,24 @@
     const minVisibleBarLevel = Math.max(this._visibleLevelOffsets.upperBound(top) - 1, 0);
     this._markerPositions.clear();
 
-    /** @type {!Map<string, !Array<number>>} */
+    let mainThreadTopLevel = -1;
+
+    // Find the main thread so that we can mark tasks longer than 50ms.
+    if ('groups' in timelineData && Array.isArray(timelineData.groups)) {
+      const mainThread = timelineData.groups.find(v => {
+        if (!v._track) {
+          return false;
+        }
+
+        return v._track.name === 'CrRendererMain';
+      });
+
+      if (mainThread) {
+        mainThreadTopLevel = mainThread.startLevel;
+      }
+    }
+
+    /** @type {!Map<string, {indexes: !Array<number>, showLongDurations: boolean}>} */
     const colorBuckets = new Map();
     for (let level = minVisibleBarLevel; level < this._dataProvider.maxStackDepth(); ++level) {
       if (this._levelToOffset(level) > top + height) {
@@ -1041,10 +1082,10 @@
         const color = this._entryColorsCache[entryIndex];
         let bucket = colorBuckets.get(color);
         if (!bucket) {
-          bucket = [];
+          bucket = {indexes: [], showLongDurations: level === mainThreadTopLevel};
           colorBuckets.set(color, bucket);
         }
-        bucket.push(entryIndex);
+        bucket.indexes.push(entryIndex);
       }
     }
 
@@ -1060,7 +1101,7 @@
       });
       context.restore();
 
-      for (const [color, indexes] of colorBuckets) {
+      for (const [color, {indexes, showLongDurations}] of colorBuckets) {
         context.beginPath();
         for (let i = 0; i < indexes.length; ++i) {
           const entryIndex = indexes[i];
@@ -1079,6 +1120,37 @@
         }
         context.fillStyle = color;
         context.fill();
+
+        // Draw long task regions.
+        context.beginPath();
+        for (let i = 0; i < indexes.length; ++i) {
+          const entryIndex = indexes[i];
+          const duration = entryTotalTimes[entryIndex];
+
+          if (!showLongDurations) {
+            continue;
+          }
+
+          if (isNaN(duration)) {
+            continue;
+          }
+
+          if (duration < 50) {
+            continue;
+          }
+
+          const entryStartTime = entryStartTimes[entryIndex];
+          const barX = this._timeToPositionClipped(entryStartTime + 50);
+          const barLevel = entryLevels[entryIndex];
+          const barHeight = this._levelHeight(barLevel);
+          const barY = this._levelToOffset(barLevel);
+          const barRight = this._timeToPositionClipped(entryStartTime + duration);
+          const barWidth = Math.max(barRight - barX, 1);
+          context.rect(barX, barY, barWidth - 0.4, barHeight - 1);
+        }
+
+        context.fillStyle = candyStripePattern;
+        context.fill();
       }
     }
 
diff --git a/front_end/timeline_model/TimelineModel.js b/front_end/timeline_model/TimelineModel.js
index 934278d..1ecca48 100644
--- a/front_end/timeline_model/TimelineModel.js
+++ b/front_end/timeline_model/TimelineModel.js
@@ -1486,7 +1486,7 @@
 };
 
 TimelineModelImpl.Thresholds = {
-  LongTask: 200,
+  LongTask: 50,
   Handler: 150,
   RecurringHandler: 50,
   ForcedLayout: 30,