<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[210880] trunk/Websites/perf.webkit.org</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/210880">210880</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2017-01-18 13:22:39 -0800 (Wed, 18 Jan 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>Make calls to render() functions async
https://bugs.webkit.org/show_bug.cgi?id=167151

Reviewed by Andreas Kling.

Make calls to render() async by coalescing calls inside enqueueToRender(), which has been renamed from
updateRendering(). We now queue up all the components and wait until the next animation frame to invoke
render() on all those components.

This reduces render() calls in the summary page of our internal dashboard by 15x from ~9400 to ~600 by
eliminating pathological O(n^2) behavior between render() calls.

Consolidated TimeSeriesChart's enqueueRender into this newly added feature of ComponentBase along with
the support to call render() on a resize event. New implementation makes use of connectedCallback and
disconnectedCallback to avoid the work when the component is not in a document tree.

The rest of the patch concerns with renaming updateRendering to enqueueToRender and fixing a few minor bugs
that I encountered while working on this patch.

* browser-tests/component-base-tests.js: Added tests for ComponentBase.enqueueToRender().
* browser-tests/index.html:
(BrowserContext.prototype.importScripts): Renamed from importScript; Now supports loading multiple scripts.
(BrowserContext.prototype.importScript): Added.
(BrowserContext): Removed the unused createWithScripts.

* public/v3/components/analysis-results-viewer.js:
(AnalysisResultsViewer.prototype._expandBetween):
* public/v3/components/bar-graph-group.js:
(BarGraphGroup.prototype.updateGroupRendering):

* public/v3/components/base.js:
(ComponentBase): When the browser doesn't support custom elements and 
(ComponentBase.prototype.enqueueToRender): Renamed from updateRendering. Queues up the component to call
render() instead of immediately invoking it.
(ComponentBase.renderingTimerDidFire): Call render(). Since render() function often calls enqueueToRender
on child components, go ahead and invoke render() on any components enqueued during render() calls.
(ComponentBase._connectedComponentToRenderOnResize): Added.
(ComponentBase._disconnectedComponentToRenderOnResize): Added.
(ComponentBase.defineElement.elementClass.prototype.connectedCallback): Added. This is an optimization to
avoid the work when the component is not in the document; e.g. because the entire page component has been
detached from the document. The old implementation in TimeSeriesChart was not doing this.
(ComponentBase.defineElement.elementClass.prototype.disconnectedCallback): Added.
(ComponentBase): Replaced unused static variables with _componentsToRender and _componentsToRenderOnResize.

* public/v3/components/chart-pane-base.js:
(ChartPaneBase.prototype.fetchAnalysisTasks):
(ChartPaneBase.prototype.didUpdateAnnotations): Added. Addresses the bug that the annotation bars in the
charts shown an an analysis task doesn't update its color when the state is updated in the UI. 
(ChartPaneBase.prototype._mainSelectionDidZoom):
(ChartPaneBase.prototype._updateStatus):
(ChartPaneBase.prototype._requestOpeningCommitViewer):
(ChartPaneBase.prototype._keyup):
(ChartPaneBase.prototype.render):
* public/v3/components/commit-log-viewer.js:
* public/v3/components/customizable-test-group-form.js:
(CustomizableTestGroupForm):
(CustomizableTestGroupForm.prototype._customize):
* public/v3/components/editable-text.js:
(EditableText.prototype._didUpdate):
* public/v3/components/interactive-time-series-chart.js:
* public/v3/components/pane-selector.js:
(PaneSelector.prototype._selectedItem):
* public/v3/components/time-series-chart.js:
(TimeSeriesChart): Removed the logic to update upon resize. See _connectedComponentToRenderOnResize above.
(TimeSeriesChart.prototype.get enqueueToRenderOnResize): Added. Returns true.
(TimeSeriesChart.prototype.enqueueToRender): Deleted.
(TimeSeriesChart._renderEnqueuedCharts): Deleted.
(TimeSeriesChart): Call ComponentBase.defineElement to make this a proper component so that the logic in
connectedCallback to update upon resize event would work.
* public/v3/instrumentation.js:
(Instrumentation.dumpStatistics): Sort results by the key names.
* public/v3/models/time-series.js:
(TimeSeries.prototype.values): Added. This method was never ported to v3 in <a href="http://trac.webkit.org/projects/webkit/changeset/198462">r198462</a>, and broke the feature
to show moving averages, etc... on the charts page.
* public/v3/pages/analysis-category-page.js:
(AnalysisCategoryPage.prototype.open):
(AnalysisCategoryPage.prototype.updateFromSerializedState):
(AnalysisCategoryPage.prototype.filterDidChange):
(AnalysisCategoryPage.prototype.render):
* public/v3/pages/analysis-task-page.js:
(AnalysisTaskChartPane.prototype._updateStatus):
(AnalysisTaskPage.prototype.updateFromSerializedState):
(AnalysisTaskPage.prototype._didFetchTask):
(AnalysisTaskPage.prototype._didFetchRelatedAnalysisTasks):
(AnalysisTaskPage.prototype._didFetchMeasurement):
(AnalysisTaskPage.prototype._didFetchTestGroups):
(AnalysisTaskPage.prototype._showAllTestGroups):
(AnalysisTaskPage.prototype._didFetchAnalysisResults):
(AnalysisTaskPage.prototype.render):
(AnalysisTaskPage.prototype._renderTestGroupList.):
(AnalysisTaskPage.prototype._renderTestGroupList):
(AnalysisTaskPage.prototype._createTestGroupListItem):
(AnalysisTaskPage.prototype._showTestGroup):
(AnalysisTaskPage.prototype._didStartEditingTaskName):
(AnalysisTaskPage.prototype._updateTaskName):
(AnalysisTaskPage.prototype._updateTestGroupName):
(AnalysisTaskPage.prototype._hideCurrentTestGroup):
(AnalysisTaskPage.prototype._updateChangeType): Fixed the bug that we were never updating annotation bars
in the main chart by calling didUpdateAnnotations.
(AnalysisTaskPage.prototype._associateBug):
(AnalysisTaskPage.prototype._dissociateBug):
(AnalysisTaskPage.prototype._associateCommit):
(AnalysisTaskPage.prototype._dissociateCommit):
(AnalysisTaskPage.prototype._chartSelectionDidChange):
(AnalysisTaskPage.prototype._selectedRowInAnalysisResultsViewer):
* public/v3/pages/build-request-queue-page.js:
(BuildRequestQueuePage.prototype.open.):
(BuildRequestQueuePage.prototype.open):
* public/v3/pages/chart-pane.js:
(ChartPane.prototype.setOpenRepository):
(ChartPane.prototype._renderTrendLinePopover): Fixed a race condition. Insert a select element as needed
before trying to assign the current value on it.
(ChartPane.prototype._trendLineTypeDidChange):
(ChartPane.prototype._updateTrendLine):
* public/v3/pages/charts-page.js:
(ChartsPage.prototype.updateFromSerializedState):
(ChartsPage.prototype._updateDomainsFromSerializedState):
(ChartsPage.prototype.setNumberOfDaysFromToolbar):
(ChartsPage.prototype._didMutatePaneList):
(ChartsPage.prototype.render):
* public/v3/pages/charts-toolbar.js:
(ChartsToolbar.prototype.render):
* public/v3/pages/create-analysis-task-page.js:
(CreateAnalysisTaskPage.prototype.updateFromSerializedState):
* public/v3/pages/dashboard-page.js:
(DashboardPage.prototype.updateFromSerializedState):
(DashboardPage.prototype._fetchedData):
* public/v3/pages/heading.js:
(Heading.prototype.render):
* public/v3/pages/page-with-heading.js:
(PageWithHeading.prototype.render):
* public/v3/pages/page.js:
(Page.prototype.open):
* public/v3/pages/summary-page.js:
(SummaryPage.prototype.open):
(SummaryPage.prototype.this._renderQueue.push):
(SummaryPage):
(SummaryPage.prototype._renderCell):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesperfwebkitorgChangeLog">trunk/Websites/perf.webkit.org/ChangeLog</a></li>
<li><a href="#trunkWebsitesperfwebkitorgbrowsertestscomponentbasetestsjs">trunk/Websites/perf.webkit.org/browser-tests/component-base-tests.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgbrowsertestsindexhtml">trunk/Websites/perf.webkit.org/browser-tests/index.html</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentsanalysisresultsviewerjs">trunk/Websites/perf.webkit.org/public/v3/components/analysis-results-viewer.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentsbargraphgroupjs">trunk/Websites/perf.webkit.org/public/v3/components/bar-graph-group.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentsbasejs">trunk/Websites/perf.webkit.org/public/v3/components/base.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentschartpanebasejs">trunk/Websites/perf.webkit.org/public/v3/components/chart-pane-base.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentscommitlogviewerjs">trunk/Websites/perf.webkit.org/public/v3/components/commit-log-viewer.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentscustomizabletestgroupformjs">trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentseditabletextjs">trunk/Websites/perf.webkit.org/public/v3/components/editable-text.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentsinteractivetimeserieschartjs">trunk/Websites/perf.webkit.org/public/v3/components/interactive-time-series-chart.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentspaneselectorjs">trunk/Websites/perf.webkit.org/public/v3/components/pane-selector.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3componentstimeserieschartjs">trunk/Websites/perf.webkit.org/public/v3/components/time-series-chart.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3instrumentationjs">trunk/Websites/perf.webkit.org/public/v3/instrumentation.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3modelstimeseriesjs">trunk/Websites/perf.webkit.org/public/v3/models/time-series.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesanalysiscategorypagejs">trunk/Websites/perf.webkit.org/public/v3/pages/analysis-category-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesbuildrequestqueuepagejs">trunk/Websites/perf.webkit.org/public/v3/pages/build-request-queue-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pageschartpanejs">trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pageschartspagejs">trunk/Websites/perf.webkit.org/public/v3/pages/charts-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pageschartstoolbarjs">trunk/Websites/perf.webkit.org/public/v3/pages/charts-toolbar.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagescreateanalysistaskpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/create-analysis-task-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesdashboardpagejs">trunk/Websites/perf.webkit.org/public/v3/pages/dashboard-page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagesheadingjs">trunk/Websites/perf.webkit.org/public/v3/pages/heading.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagespagewithheadingjs">trunk/Websites/perf.webkit.org/public/v3/pages/page-with-heading.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagespagejs">trunk/Websites/perf.webkit.org/public/v3/pages/page.js</a></li>
<li><a href="#trunkWebsitesperfwebkitorgpublicv3pagessummarypagejs">trunk/Websites/perf.webkit.org/public/v3/pages/summary-page.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebsitesperfwebkitorgChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/ChangeLog (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/ChangeLog        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/ChangeLog        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -1,3 +1,144 @@
</span><ins>+2017-01-17  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Make calls to render() functions async
+        https://bugs.webkit.org/show_bug.cgi?id=167151
+
+        Reviewed by Andreas Kling.
+
+        Make calls to render() async by coalescing calls inside enqueueToRender(), which has been renamed from
+        updateRendering(). We now queue up all the components and wait until the next animation frame to invoke
+        render() on all those components.
+
+        This reduces render() calls in the summary page of our internal dashboard by 15x from ~9400 to ~600 by
+        eliminating pathological O(n^2) behavior between render() calls.
+
+        Consolidated TimeSeriesChart's enqueueRender into this newly added feature of ComponentBase along with
+        the support to call render() on a resize event. New implementation makes use of connectedCallback and
+        disconnectedCallback to avoid the work when the component is not in a document tree.
+
+        The rest of the patch concerns with renaming updateRendering to enqueueToRender and fixing a few minor bugs
+        that I encountered while working on this patch.
+
+        * browser-tests/component-base-tests.js: Added tests for ComponentBase.enqueueToRender().
+        * browser-tests/index.html:
+        (BrowserContext.prototype.importScripts): Renamed from importScript; Now supports loading multiple scripts.
+        (BrowserContext.prototype.importScript): Added.
+        (BrowserContext): Removed the unused createWithScripts.
+
+        * public/v3/components/analysis-results-viewer.js:
+        (AnalysisResultsViewer.prototype._expandBetween):
+        * public/v3/components/bar-graph-group.js:
+        (BarGraphGroup.prototype.updateGroupRendering):
+
+        * public/v3/components/base.js:
+        (ComponentBase): When the browser doesn't support custom elements and 
+        (ComponentBase.prototype.enqueueToRender): Renamed from updateRendering. Queues up the component to call
+        render() instead of immediately invoking it.
+        (ComponentBase.renderingTimerDidFire): Call render(). Since render() function often calls enqueueToRender
+        on child components, go ahead and invoke render() on any components enqueued during render() calls.
+        (ComponentBase._connectedComponentToRenderOnResize): Added.
+        (ComponentBase._disconnectedComponentToRenderOnResize): Added.
+        (ComponentBase.defineElement.elementClass.prototype.connectedCallback): Added. This is an optimization to
+        avoid the work when the component is not in the document; e.g. because the entire page component has been
+        detached from the document. The old implementation in TimeSeriesChart was not doing this.
+        (ComponentBase.defineElement.elementClass.prototype.disconnectedCallback): Added.
+        (ComponentBase): Replaced unused static variables with _componentsToRender and _componentsToRenderOnResize.
+
+        * public/v3/components/chart-pane-base.js:
+        (ChartPaneBase.prototype.fetchAnalysisTasks):
+        (ChartPaneBase.prototype.didUpdateAnnotations): Added. Addresses the bug that the annotation bars in the
+        charts shown an an analysis task doesn't update its color when the state is updated in the UI. 
+        (ChartPaneBase.prototype._mainSelectionDidZoom):
+        (ChartPaneBase.prototype._updateStatus):
+        (ChartPaneBase.prototype._requestOpeningCommitViewer):
+        (ChartPaneBase.prototype._keyup):
+        (ChartPaneBase.prototype.render):
+        * public/v3/components/commit-log-viewer.js:
+        * public/v3/components/customizable-test-group-form.js:
+        (CustomizableTestGroupForm):
+        (CustomizableTestGroupForm.prototype._customize):
+        * public/v3/components/editable-text.js:
+        (EditableText.prototype._didUpdate):
+        * public/v3/components/interactive-time-series-chart.js:
+        * public/v3/components/pane-selector.js:
+        (PaneSelector.prototype._selectedItem):
+        * public/v3/components/time-series-chart.js:
+        (TimeSeriesChart): Removed the logic to update upon resize. See _connectedComponentToRenderOnResize above.
+        (TimeSeriesChart.prototype.get enqueueToRenderOnResize): Added. Returns true.
+        (TimeSeriesChart.prototype.enqueueToRender): Deleted.
+        (TimeSeriesChart._renderEnqueuedCharts): Deleted.
+        (TimeSeriesChart): Call ComponentBase.defineElement to make this a proper component so that the logic in
+        connectedCallback to update upon resize event would work.
+        * public/v3/instrumentation.js:
+        (Instrumentation.dumpStatistics): Sort results by the key names.
+        * public/v3/models/time-series.js:
+        (TimeSeries.prototype.values): Added. This method was never ported to v3 in r198462, and broke the feature
+        to show moving averages, etc... on the charts page.
+        * public/v3/pages/analysis-category-page.js:
+        (AnalysisCategoryPage.prototype.open):
+        (AnalysisCategoryPage.prototype.updateFromSerializedState):
+        (AnalysisCategoryPage.prototype.filterDidChange):
+        (AnalysisCategoryPage.prototype.render):
+        * public/v3/pages/analysis-task-page.js:
+        (AnalysisTaskChartPane.prototype._updateStatus):
+        (AnalysisTaskPage.prototype.updateFromSerializedState):
+        (AnalysisTaskPage.prototype._didFetchTask):
+        (AnalysisTaskPage.prototype._didFetchRelatedAnalysisTasks):
+        (AnalysisTaskPage.prototype._didFetchMeasurement):
+        (AnalysisTaskPage.prototype._didFetchTestGroups):
+        (AnalysisTaskPage.prototype._showAllTestGroups):
+        (AnalysisTaskPage.prototype._didFetchAnalysisResults):
+        (AnalysisTaskPage.prototype.render):
+        (AnalysisTaskPage.prototype._renderTestGroupList.):
+        (AnalysisTaskPage.prototype._renderTestGroupList):
+        (AnalysisTaskPage.prototype._createTestGroupListItem):
+        (AnalysisTaskPage.prototype._showTestGroup):
+        (AnalysisTaskPage.prototype._didStartEditingTaskName):
+        (AnalysisTaskPage.prototype._updateTaskName):
+        (AnalysisTaskPage.prototype._updateTestGroupName):
+        (AnalysisTaskPage.prototype._hideCurrentTestGroup):
+        (AnalysisTaskPage.prototype._updateChangeType): Fixed the bug that we were never updating annotation bars
+        in the main chart by calling didUpdateAnnotations.
+        (AnalysisTaskPage.prototype._associateBug):
+        (AnalysisTaskPage.prototype._dissociateBug):
+        (AnalysisTaskPage.prototype._associateCommit):
+        (AnalysisTaskPage.prototype._dissociateCommit):
+        (AnalysisTaskPage.prototype._chartSelectionDidChange):
+        (AnalysisTaskPage.prototype._selectedRowInAnalysisResultsViewer):
+        * public/v3/pages/build-request-queue-page.js:
+        (BuildRequestQueuePage.prototype.open.):
+        (BuildRequestQueuePage.prototype.open):
+        * public/v3/pages/chart-pane.js:
+        (ChartPane.prototype.setOpenRepository):
+        (ChartPane.prototype._renderTrendLinePopover): Fixed a race condition. Insert a select element as needed
+        before trying to assign the current value on it.
+        (ChartPane.prototype._trendLineTypeDidChange):
+        (ChartPane.prototype._updateTrendLine):
+        * public/v3/pages/charts-page.js:
+        (ChartsPage.prototype.updateFromSerializedState):
+        (ChartsPage.prototype._updateDomainsFromSerializedState):
+        (ChartsPage.prototype.setNumberOfDaysFromToolbar):
+        (ChartsPage.prototype._didMutatePaneList):
+        (ChartsPage.prototype.render):
+        * public/v3/pages/charts-toolbar.js:
+        (ChartsToolbar.prototype.render):
+        * public/v3/pages/create-analysis-task-page.js:
+        (CreateAnalysisTaskPage.prototype.updateFromSerializedState):
+        * public/v3/pages/dashboard-page.js:
+        (DashboardPage.prototype.updateFromSerializedState):
+        (DashboardPage.prototype._fetchedData):
+        * public/v3/pages/heading.js:
+        (Heading.prototype.render):
+        * public/v3/pages/page-with-heading.js:
+        (PageWithHeading.prototype.render):
+        * public/v3/pages/page.js:
+        (Page.prototype.open):
+        * public/v3/pages/summary-page.js:
+        (SummaryPage.prototype.open):
+        (SummaryPage.prototype.this._renderQueue.push):
+        (SummaryPage):
+        (SummaryPage.prototype._renderCell):
+
</ins><span class="cx"> 2017-01-15  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Add the build fix for browsers that don't yet support custom elements SPI.
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgbrowsertestscomponentbasetestsjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/browser-tests/component-base-tests.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/browser-tests/component-base-tests.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/browser-tests/component-base-tests.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx">     function createTestToCheckExistenceOfShadowTree(callback, options = {htmlTemplate: false, cssTemplate: true})
</span><span class="cx">     {
</span><span class="cx">         const context = new BrowsingContext();
</span><del>-        return context.importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+        return context.importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">             class SomeComponent extends ComponentBase { }
</span><span class="cx">             if (options.htmlTemplate)
</span><span class="cx">                 SomeComponent.htmlTemplate = () =&gt; { return '&lt;div style=&quot;height: 10px;&quot;&gt;&lt;/div&gt;'; };
</span><span class="lines">@@ -20,13 +20,13 @@
</span><span class="cx"> 
</span><span class="cx">     describe('constructor', () =&gt; {
</span><span class="cx">         it('is a function', () =&gt; {
</span><del>-            return new BrowsingContext().importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return new BrowsingContext().importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 expect(ComponentBase).toBeA('function');
</span><span class="cx">             });
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         it('can be instantiated', () =&gt; {
</span><del>-            return new BrowsingContext().importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return new BrowsingContext().importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 let callCount = 0;
</span><span class="cx">                 class SomeComponent extends ComponentBase {
</span><span class="cx">                     constructor() {
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">     describe('element()', () =&gt; {
</span><span class="cx">         it('must return an element', () =&gt; {
</span><span class="cx">             const context = new BrowsingContext();
</span><del>-            return context.importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return context.importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 class SomeComponent extends ComponentBase { }
</span><span class="cx">                 let instance = new SomeComponent('some-component');
</span><span class="cx">                 expect(instance.element()).toBeA(context.global.HTMLElement);
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         it('must return an element whose component() matches the component', () =&gt; {
</span><del>-            return new BrowsingContext().importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return new BrowsingContext().importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 class SomeComponent extends ComponentBase { }
</span><span class="cx">                 let instance = new SomeComponent('some-component');
</span><span class="cx">                 expect(instance.element().component()).toBe(instance);
</span><span class="lines">@@ -89,6 +89,187 @@
</span><span class="cx">         });
</span><span class="cx">     });
</span><span class="cx"> 
</span><ins>+    describe('enqueueToRender()', () =&gt; {
+        it('must not immediately call render()', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                context.global.requestAnimationFrame = () =&gt; {}
+
+                let renderCallCount = 0;
+                const SomeComponent = class extends ComponentBase {
+                    render() { renderCallCount++; }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                (new SomeComponent).enqueueToRender();
+                expect(renderCallCount).toBe(0);
+
+                (new SomeComponent).enqueueToRender();
+                expect(renderCallCount).toBe(0);
+            });
+        });
+
+        it('must request an animation frame exactly once', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                let requestAnimationFrameCount = 0;
+                context.global.requestAnimationFrame = () =&gt; { requestAnimationFrameCount++; }
+
+                const SomeComponent = class extends ComponentBase { }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                expect(requestAnimationFrameCount).toBe(0);
+                let instance = new SomeComponent;
+                instance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+
+                instance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+
+                (new SomeComponent).enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+
+                const AnotherComponent = class extends ComponentBase { }
+                ComponentBase.defineElement('another-component', AnotherComponent);
+                (new AnotherComponent).enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+            });
+        });
+
+        it('must invoke render() when the callback to requestAnimationFrame is called', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                let callback = null;
+                context.global.requestAnimationFrame = (newCallback) =&gt; {
+                    expect(callback).toBe(null);
+                    expect(newCallback).toNotBe(null);
+                    callback = newCallback;
+                }
+
+                let renderCalls = [];
+                const SomeComponent = class extends ComponentBase {
+                    render() {
+                        renderCalls.push(this);
+                    }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                expect(renderCalls.length).toBe(0);
+                const instance = new SomeComponent;
+                instance.enqueueToRender();
+                instance.enqueueToRender();
+
+                const anotherInstance = new SomeComponent;
+                anotherInstance.enqueueToRender();
+                expect(renderCalls.length).toBe(0);
+
+                callback();
+
+                expect(renderCalls.length).toBe(2);
+                expect(renderCalls[0]).toBe(instance);
+                expect(renderCalls[1]).toBe(anotherInstance);
+            });
+        });
+
+        it('must immediately invoke render() on a component enqueued inside another render() call', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                let callback = null;
+                context.global.requestAnimationFrame = (newCallback) =&gt; {
+                    expect(callback).toBe(null);
+                    expect(newCallback).toNotBe(null);
+                    callback = newCallback;
+                }
+
+                let renderCalls = [];
+                let instanceToEnqueue = null;
+                const SomeComponent = class extends ComponentBase {
+                    render() {
+                        renderCalls.push(this);
+                        if (instanceToEnqueue)
+                            instanceToEnqueue.enqueueToRender();
+                        instanceToEnqueue = null;
+                    }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                expect(renderCalls.length).toBe(0);
+                const instance = new SomeComponent;
+                const anotherInstance = new SomeComponent;
+                instance.enqueueToRender();
+                instanceToEnqueue = anotherInstance;
+                callback();
+                callback = null;
+                expect(renderCalls.length).toBe(2);
+                expect(renderCalls[0]).toBe(instance);
+                expect(renderCalls[1]).toBe(anotherInstance);
+                renderCalls = [];
+
+                instance.enqueueToRender();
+                anotherInstance.enqueueToRender();
+                instanceToEnqueue = instance;
+                callback();
+                expect(renderCalls.length).toBe(3);
+                expect(renderCalls[0]).toBe(instance);
+                expect(renderCalls[1]).toBe(anotherInstance);
+                expect(renderCalls[2]).toBe(instance);
+            });
+        });
+
+        it('must request a new animation frame once it exited the callback from requestAnimationFrame', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                let requestAnimationFrameCount = 0;
+                let callback = null;
+                context.global.requestAnimationFrame = (newCallback) =&gt; {
+                    expect(callback).toBe(null);
+                    expect(newCallback).toNotBe(null);
+                    callback = newCallback;
+                    requestAnimationFrameCount++;
+                }
+
+                let renderCalls = [];
+                const SomeComponent = class extends ComponentBase {
+                    render() { renderCalls.push(this); }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                const instance = new SomeComponent;
+                const anotherInstance = new SomeComponent;
+                expect(requestAnimationFrameCount).toBe(0);
+
+                instance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+                anotherInstance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(1);
+
+                expect(renderCalls.length).toBe(0);
+                callback();
+                callback = null;
+                expect(renderCalls.length).toBe(2);
+                expect(renderCalls[0]).toBe(instance);
+                expect(renderCalls[1]).toBe(anotherInstance);
+                expect(requestAnimationFrameCount).toBe(1);
+
+                anotherInstance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(2);
+                instance.enqueueToRender();
+                expect(requestAnimationFrameCount).toBe(2);
+
+                expect(renderCalls.length).toBe(2);
+                callback();
+                callback = null;
+                expect(renderCalls.length).toBe(4);
+                expect(renderCalls[0]).toBe(instance);
+                expect(renderCalls[1]).toBe(anotherInstance);
+                expect(renderCalls[2]).toBe(anotherInstance);
+                expect(renderCalls[3]).toBe(instance);
+                expect(requestAnimationFrameCount).toBe(2);
+            });
+        });
+
+    });
+
</ins><span class="cx">     describe('render()', () =&gt; {
</span><span class="cx">         it('must create shadow tree', () =&gt; {
</span><span class="cx">             return createTestToCheckExistenceOfShadowTree((instance, hasShadowTree) =&gt; {
</span><span class="lines">@@ -123,7 +304,7 @@
</span><span class="cx"> 
</span><span class="cx">         it('must define a custom element with a class of an appropriate name', () =&gt; {
</span><span class="cx">             const context = new BrowsingContext();
</span><del>-            return context.importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return context.importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 class SomeComponent extends ComponentBase { }
</span><span class="cx">                 ComponentBase.defineElement('some-component', SomeComponent);
</span><span class="cx"> 
</span><span class="lines">@@ -135,7 +316,7 @@
</span><span class="cx"> 
</span><span class="cx">         it('must define a custom element that can be instantiated via document.createElement', () =&gt; {
</span><span class="cx">             const context = new BrowsingContext();
</span><del>-            return context.importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return context.importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 let instances = [];
</span><span class="cx">                 class SomeComponent extends ComponentBase {
</span><span class="cx">                     constructor() {
</span><span class="lines">@@ -158,7 +339,7 @@
</span><span class="cx"> 
</span><span class="cx">         it('must define a custom element that can be instantiated via new', () =&gt; {
</span><span class="cx">             const context = new BrowsingContext();
</span><del>-            return context.importScript('../public/v3/components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</del><ins>+            return context.importScript('components/base.js', 'ComponentBase').then((ComponentBase) =&gt; {
</ins><span class="cx">                 let instances = [];
</span><span class="cx">                 class SomeComponent extends ComponentBase {
</span><span class="cx">                     constructor() {
</span><span class="lines">@@ -179,6 +360,52 @@
</span><span class="cx">             });
</span><span class="cx">         });
</span><span class="cx"> 
</span><ins>+        it('must enqueue a connected component to render upon a resize event if enqueueToRenderOnResize is true', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                class SomeComponent extends ComponentBase {
+                    static get enqueueToRenderOnResize() { return true; }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                let requestAnimationFrameCount = 0;
+                let callback = null;
+                context.global.requestAnimationFrame = (newCallback) =&gt; {
+                    callback = newCallback;
+                    requestAnimationFrameCount++;
+                }
+
+                expect(requestAnimationFrameCount).toBe(0);
+                const instance = new SomeComponent;
+                context.global.dispatchEvent(new Event('resize'));
+                context.document.body.appendChild(instance.element());
+                context.global.dispatchEvent(new Event('resize'));
+                expect(requestAnimationFrameCount).toBe(1);
+            });
+        });
+
+        it('must not enqueue a disconnected component to render upon a resize event if enqueueToRenderOnResize is true', () =&gt; {
+            const context = new BrowsingContext();
+            return context.importScripts(['instrumentation.js', 'components/base.js'], 'ComponentBase').then((ComponentBase) =&gt; {
+                class SomeComponent extends ComponentBase {
+                    static get enqueueToRenderOnResize() { return true; }
+                }
+                ComponentBase.defineElement('some-component', SomeComponent);
+
+                let requestAnimationFrameCount = 0;
+                let callback = null;
+                context.global.requestAnimationFrame = (newCallback) =&gt; {
+                    callback = newCallback;
+                    requestAnimationFrameCount++;
+                }
+
+                const instance = new SomeComponent;
+                expect(requestAnimationFrameCount).toBe(0);
+                context.global.dispatchEvent(new Event('resize'));
+                expect(requestAnimationFrameCount).toBe(0);
+            });
+        });
+
</ins><span class="cx">     });
</span><span class="cx"> 
</span><span class="cx"> });
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgbrowsertestsindexhtml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/browser-tests/index.html (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/browser-tests/index.html        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/browser-tests/index.html        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -36,17 +36,20 @@
</span><span class="cx">         this.document = this._iframe.contentDocument;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    importScript(path, ...symbolList)
</del><ins>+    importScripts(pathList, ...symbolList)
</ins><span class="cx">     {
</span><span class="cx">         const doc = this._iframe.contentDocument;
</span><span class="cx">         const global = this._iframe.contentWindow;
</span><del>-        return new Promise((resolve, reject) =&gt; {
-            let script = doc.createElement('script');
-            script.addEventListener('load', resolve);
-            script.addEventListener('error', reject);
-            script.src = path;
-            doc.body.appendChild(script);
-        }).then(() =&gt; {
</del><ins>+
+        return Promise.all(pathList.map((path) =&gt; {
+            return new Promise((resolve, reject) =&gt; {
+                let script = doc.createElement('script');
+                script.addEventListener('load', resolve);
+                script.addEventListener('error', reject);
+                script.src = '../public/v3/' + path;
+                doc.body.appendChild(script);
+            });
+        })).then(() =&gt; {
</ins><span class="cx">             const script = doc.createElement('script');
</span><span class="cx">             script.textContent = `window.importedSymbols = [${symbolList.join(', ')}];`;
</span><span class="cx">             doc.body.appendChild(script);
</span><span class="lines">@@ -59,36 +62,16 @@
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    importScript(path, ...symbols)
+    {
+        return this.importScripts([path], ...symbols);
+    }
+
</ins><span class="cx">     static cleanup()
</span><span class="cx">     {
</span><span class="cx">         BrowsingContext._iframes.forEach((iframe) =&gt; { iframe.remove(); });
</span><span class="cx">         BrowsingContext._iframes = [];
</span><span class="cx">     }
</span><del>-
-    static createWithScripts(scriptList)
-    {
-        let iframe = document.createElement('iframe');
-        document.body.appendChild(iframe);
-        const doc = iframe.contentDocument;
-
-        let symbolList = [];
-        return Promise.all(scriptList.map((entry) =&gt; {
-            let [path, ...symbols] = entry;
-            symbolList = symbolList.concat(symbols);
-            return new Promise((resolve, reject) =&gt; {
-                let script = doc.createElement('script');
-                script.addEventListener('load', resolve);
-                script.addEventListener('error', reject);
-                script.src = path;
-                doc.body.appendChild(script);
-            });
-        })).then(() =&gt; {
-            const script = doc.createElement('script');
-            script.textContent = `var symbols = { ${symbolList.join(', ')} };`;
-            doc.body.appendChild(script);
-            return iframe.contentWindow;
-        });
-    }
</del><span class="cx"> }
</span><span class="cx"> BrowsingContext._iframes = [];
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentsanalysisresultsviewerjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/analysis-results-viewer.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/analysis-results-viewer.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/analysis-results-viewer.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -260,7 +260,7 @@
</span><span class="cx">         for (var i = indexBeforeStart + 1; i &lt; indexAfterEnd; i += increment)
</span><span class="cx">             this._expandedPoints.add(series.findPointByIndex(i));
</span><span class="cx">         this._shouldRenderTable = true;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static htmlTemplate()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentsbargraphgroupjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/bar-graph-group.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/bar-graph-group.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/bar-graph-group.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx">             var start = min - (range - diff) / 2;
</span><span class="cx"> 
</span><span class="cx">             entry.bar.update((value - start) / range, formattedValue);
</span><del>-            entry.bar.updateRendering();
</del><ins>+            entry.bar.enqueueToRender();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         Instrumentation.endMeasuringTime('BarGraphGroup', 'updateGroupRendering');
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentsbasejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/base.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/base.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/base.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -15,6 +15,9 @@
</span><span class="cx"> 
</span><span class="cx">         this._element = element;
</span><span class="cx">         this._shadow = null;
</span><ins>+
+        if (!window.customElements &amp;&amp; new.target.enqueueToRenderOnResize)
+            ComponentBase._connectedComponentToRenderOnResize(this);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     element() { return this._element; }
</span><span class="lines">@@ -26,13 +29,54 @@
</span><span class="cx"> 
</span><span class="cx">     render() { this._ensureShadowTree(); }
</span><span class="cx"> 
</span><del>-    updateRendering()
</del><ins>+    enqueueToRender()
</ins><span class="cx">     {
</span><span class="cx">         Instrumentation.startMeasuringTime('ComponentBase', 'updateRendering');
</span><del>-        this.render();
</del><ins>+
+        if (!ComponentBase._componentsToRender) {
+            ComponentBase._componentsToRender = new Set;
+            requestAnimationFrame(() =&gt; ComponentBase.renderingTimerDidFire());
+        }
+        ComponentBase._componentsToRender.add(this);
+
</ins><span class="cx">         Instrumentation.endMeasuringTime('ComponentBase', 'updateRendering');
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    static renderingTimerDidFire()
+    {
+        Instrumentation.startMeasuringTime('ComponentBase', 'renderingTimerDidFire');
+
+        do {
+            const currentSet = [...ComponentBase._componentsToRender];
+            ComponentBase._componentsToRender.clear();
+            for (let component of currentSet) {
+                Instrumentation.startMeasuringTime('ComponentBase', 'renderingTimerDidFire.render');
+                component.render();
+                Instrumentation.endMeasuringTime('ComponentBase', 'renderingTimerDidFire.render');
+            }
+        } while (ComponentBase._componentsToRender.size);
+        ComponentBase._componentsToRender = null;
+
+        Instrumentation.endMeasuringTime('ComponentBase', 'renderingTimerDidFire');
+    }
+
+    static _connectedComponentToRenderOnResize(component)
+    {
+        if (!ComponentBase._componentsToRenderOnResize) {
+            ComponentBase._componentsToRenderOnResize = new Set;
+            window.addEventListener('resize', () =&gt; {
+                for (let component of ComponentBase._componentsToRenderOnResize)
+                    component.enqueueToRender();
+            });
+        }
+        ComponentBase._componentsToRenderOnResize.add(component);
+    }
+
+    static _disconnectedComponentToRenderOnResize(component)
+    {
+        ComponentBase._componentsToRenderOnResize.delete(component);
+    }
+
</ins><span class="cx">     renderReplace(element, content) { ComponentBase.renderReplace(element, content); }
</span><span class="cx"> 
</span><span class="cx">     static renderReplace(element, content)
</span><span class="lines">@@ -94,6 +138,8 @@
</span><span class="cx">         ComponentBase._componentByName.set(name, elementInterface);
</span><span class="cx">         ComponentBase._componentByClass.set(elementInterface, name);
</span><span class="cx"> 
</span><ins>+        const enqueueToRenderOnResize = elementInterface.enqueueToRenderOnResize;
+
</ins><span class="cx">         if (!window.customElements)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="lines">@@ -111,6 +157,18 @@
</span><span class="cx">                 new elementInterface();
</span><span class="cx">                 currentlyConstructed.delete(elementInterface);
</span><span class="cx">             }
</span><ins>+
+            connectedCallback()
+            {
+                if (enqueueToRenderOnResize)
+                    ComponentBase._connectedComponentToRenderOnResize(this.component());
+            }
+
+            disconnectedCallback()
+            {
+                if (enqueueToRenderOnResize)
+                    ComponentBase._disconnectedComponentToRenderOnResize(this.component());
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         const nameDescriptor = Object.getOwnPropertyDescriptor(elementClass, 'name');
</span><span class="lines">@@ -193,7 +251,5 @@
</span><span class="cx"> ComponentBase._componentByName = new Map;
</span><span class="cx"> ComponentBase._componentByClass = new Map;
</span><span class="cx"> ComponentBase._currentlyConstructedByInterface = new Map;
</span><del>-
-ComponentBase.css = Symbol();
-ComponentBase.html = Symbol();
-ComponentBase.map = {};
</del><ins>+ComponentBase._componentsToRender = null;
+ComponentBase._componentsToRenderOnResize = null;
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentschartpanebasejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/chart-pane-base.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/chart-pane-base.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/chart-pane-base.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -96,10 +96,17 @@
</span><span class="cx">         AnalysisTask.fetchByPlatformAndMetric(this._platformId, this._metricId, noCache).then(function (tasks) {
</span><span class="cx">             self._tasksForAnnotations = tasks;
</span><span class="cx">             self._renderedAnnotations = false;
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    // FIXME: We should have a mechanism to get notified whenever the set of annotations change.
+    didUpdateAnnotations()
+    {
+        this._renderedAnnotations = false;
+        this.enqueueToRender();
+    }
+
</ins><span class="cx">     platformId() { return this._platformId; }
</span><span class="cx">     metricId() { return this._metricId; }
</span><span class="cx"> 
</span><span class="lines">@@ -132,7 +139,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._overviewChart.setSelection(selection, this);
</span><span class="cx">         this._mainChart.setSelection(null);
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _indicatorDidChange(indicatorID, isLocked)
</span><span class="lines">@@ -148,7 +155,7 @@
</span><span class="cx">     _updateStatus()
</span><span class="cx">     {
</span><span class="cx">         var range = this._mainChartStatus.updateRevisionList();
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         this._commitLogViewer.view(range.repository, range.from, range.to).then(updateRendering);
</span><span class="cx">         updateRendering();
</span><span class="cx">     }
</span><span class="lines">@@ -165,7 +172,7 @@
</span><span class="cx">     _requestOpeningCommitViewer(repository, from, to)
</span><span class="cx">     {
</span><span class="cx">         this._mainChartStatus.setCurrentRepository(repository);
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         this._commitLogViewer.view(repository, from, to).then(updateRendering);
</span><span class="cx">         updateRendering();
</span><span class="cx">     }
</span><span class="lines">@@ -191,7 +198,7 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         event.preventDefault();
</span><span class="cx">         event.stopPropagation();
</span><span class="lines">@@ -217,12 +224,12 @@
</span><span class="cx">         this._renderAnnotations();
</span><span class="cx"> 
</span><span class="cx">         if (this._mainChartStatus)
</span><del>-            this._mainChartStatus.updateRendering();
</del><ins>+            this._mainChartStatus.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         var body = this.content().querySelector('.chart-pane-body');
</span><span class="cx">         if (this._commitLogViewer &amp;&amp; this._commitLogViewer.currentRepository()) {
</span><span class="cx">             body.classList.add('has-second-sidebar');
</span><del>-            this._commitLogViewer.updateRendering();
</del><ins>+            this._commitLogViewer.enqueueToRender();
</ins><span class="cx">         } else
</span><span class="cx">             body.classList.remove('has-second-sidebar');
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentscommitlogviewerjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/commit-log-viewer.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/commit-log-viewer.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/commit-log-viewer.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (!to) {
</span><span class="cx">             this._fetchingPromise = null;
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">             return Promise.resolve(null);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx"> 
</span><span class="cx">         var self = this;
</span><span class="cx">         var spinnerTimer = setTimeout(function () {
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         }, 300);
</span><span class="cx"> 
</span><span class="cx">         this._fetchingPromise.then(function (commits) {
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentscustomizabletestgroupformjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/customizable-test-group-form.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -8,7 +8,7 @@
</span><span class="cx">         this._renderedRepositorylist = null;
</span><span class="cx">         this._customized = false;
</span><span class="cx">         this._nameControl = this.content().querySelector('.name');
</span><del>-        this._nameControl.oninput = () =&gt; { this.updateRendering(); }
</del><ins>+        this._nameControl.oninput = () =&gt; { this.enqueueToRender(); }
</ins><span class="cx">         this.content().querySelector('a').onclick = this._customize.bind(this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx">     {
</span><span class="cx">         event.preventDefault();
</span><span class="cx">         this._customized = true;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _computeRootSetMap()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentseditabletextjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/editable-text.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/editable-text.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/editable-text.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -73,7 +73,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._inEditingMode = false;
</span><span class="cx">         this._updatingPromise = null;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static htmlTemplate()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentsinteractivetimeserieschartjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/interactive-time-series-chart.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/interactive-time-series-chart.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/interactive-time-series-chart.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -481,3 +481,5 @@
</span><span class="cx">         Instrumentation.endMeasuringTime('InteractiveTimeSeriesChart', 'renderChartContent');
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+ComponentBase.defineElement('interactive-time-series-chart', InteractiveTimeSeriesChart);
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentspaneselectorjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/pane-selector.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/pane-selector.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/pane-selector.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -167,7 +167,7 @@
</span><span class="cx">             if (data instanceof Metric &amp;&amp; data.test().onlyContainsSingleMetric())
</span><span class="cx">                 this._currentPath.splice(this._currentPath.length - 2, 1);
</span><span class="cx">         }
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     setCallback(callback)
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3componentstimeserieschartjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/components/time-series-chart.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/components/time-series-chart.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/components/time-series-chart.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -2,7 +2,7 @@
</span><span class="cx"> class TimeSeriesChart extends ComponentBase {
</span><span class="cx">     constructor(sourceList, options)
</span><span class="cx">     {
</span><del>-        super('time-series-chart');
</del><ins>+        super();
</ins><span class="cx">         this.element().style.display = 'block';
</span><span class="cx">         this.element().style.position = 'relative';
</span><span class="cx">         this._canvas = null;
</span><span class="lines">@@ -22,12 +22,6 @@
</span><span class="cx">         this._contextScaleX = 1;
</span><span class="cx">         this._contextScaleY = 1;
</span><span class="cx">         this._rem = null;
</span><del>-
-        if (!TimeSeriesChart._chartList) {
-            TimeSeriesChart._chartList = [];
-            window.addEventListener('resize', TimeSeriesChart._updateAllCharts.bind(TimeSeriesChart));
-        }
-        TimeSeriesChart._chartList.push(this);
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _ensureCanvas()
</span><span class="lines">@@ -46,6 +40,7 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static cssTemplate() { return ''; }
</span><ins>+    static get enqueueToRenderOnResize() { return true; }
</ins><span class="cx"> 
</span><span class="cx">     _createCanvas()
</span><span class="cx">     {
</span><span class="lines">@@ -57,22 +52,6 @@
</span><span class="cx">         TimeSeriesChart._chartList.map(function (chart) { chart.render(); });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    enqueueToRender()
-    {
-        if (!TimeSeriesChart._chartQueue) {
-            TimeSeriesChart._chartQueue = new Set;
-            window.requestAnimationFrame(TimeSeriesChart._renderEnqueuedCharts.bind(TimeSeriesChart));
-        }
-        TimeSeriesChart._chartQueue.add(this);
-    }
-
-    static _renderEnqueuedCharts()
-    {
-        for (var chart of TimeSeriesChart._chartQueue)
-            chart.updateRendering();
-        TimeSeriesChart._chartQueue = null;
-    }
-
</del><span class="cx">     setDomain(startTime, endTime)
</span><span class="cx">     {
</span><span class="cx">         console.assert(startTime &lt; endTime, 'startTime must be before endTime');
</span><span class="lines">@@ -804,3 +783,5 @@
</span><span class="cx">         return gridValues;
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+ComponentBase.defineElement('time-series-chart', TimeSeriesChart);
</ins></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3instrumentationjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/instrumentation.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/instrumentation.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/instrumentation.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -37,13 +37,13 @@
</span><span class="cx">         if (!this._statistics)
</span><span class="cx">             return;
</span><span class="cx">         var maxKeyLength = 0;
</span><del>-        for (var key in this._statistics)
</del><ins>+        for (let key in this._statistics)
</ins><span class="cx">             maxKeyLength = Math.max(key.length, maxKeyLength);
</span><span class="cx"> 
</span><del>-        for (var key in this._statistics) {
-            var item = this._statistics[key];
-            var keySuffix = ' '.repeat(maxKeyLength - key.length);
-            var log = `${key}${keySuffix}: `;
</del><ins>+        for (let key of Object.keys(this._statistics).sort()) {
+            const item = this._statistics[key];
+            const keySuffix = ' '.repeat(maxKeyLength - key.length);
+            let log = `${key}${keySuffix}: `;
</ins><span class="cx">             log += ` mean = ${item.mean.toFixed(2)} ${item.unit}`;
</span><span class="cx">             if (item.unit == 'ms')
</span><span class="cx">                 log += ` total = ${item.value.toFixed(2)} ${item.unit}`;
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3modelstimeseriesjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/models/time-series.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/models/time-series.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/models/time-series.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -8,6 +8,7 @@
</span><span class="cx">         this._data = [];
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    values() { return this._data.map((point) =&gt; point.value); }
</ins><span class="cx">     length() { return this._data.length; }
</span><span class="cx"> 
</span><span class="cx">     append(item)
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesanalysiscategorypagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/analysis-category-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/analysis-category-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/analysis-category-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -23,10 +23,10 @@
</span><span class="cx">         var self = this;
</span><span class="cx">         AnalysisTask.fetchAll().then(function () {
</span><span class="cx">             self._fetched = true;
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         }, function (error) {
</span><span class="cx">             self._errorMessage = 'Failed to fetch the list of analysis tasks: ' + error;
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         });
</span><span class="cx">         super.open(state);
</span><span class="cx">     }
</span><span class="lines">@@ -59,12 +59,12 @@
</span><span class="cx">             this._categoryToolbar.setFilter(state.filter);
</span><span class="cx"> 
</span><span class="cx">         if (!isOpen)
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     filterDidChange(shouldUpdateState)
</span><span class="cx">     {
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">         if (shouldUpdateState)
</span><span class="cx">             this.scheduleUrlStateUpdate();
</span><span class="cx">     }
</span><span class="lines">@@ -74,7 +74,7 @@
</span><span class="cx">         Instrumentation.startMeasuringTime('AnalysisCategoryPage', 'render');
</span><span class="cx"> 
</span><span class="cx">         super.render();
</span><del>-        this._categoryToolbar.updateRendering();
</del><ins>+        this._categoryToolbar.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         if (this._errorMessage) {
</span><span class="cx">             console.assert(!this._fetched);
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesanalysistaskpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/analysis-task-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx">     _updateStatus()
</span><span class="cx">     {
</span><span class="cx">         super._updateStatus();
</span><del>-        this._page.updateRendering();
</del><ins>+        this._page.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     selectedPoints()
</span><span class="lines">@@ -101,7 +101,7 @@
</span><span class="cx">             var taskId = parseInt(state.remainingRoute);
</span><span class="cx">             AnalysisTask.fetchById(taskId).then(this._didFetchTask.bind(this), function (error) {
</span><span class="cx">                 self._errorMessage = `Failed to fetch the analysis task ${state.remainingRoute}: ${error}`;
</span><del>-                self.updateRendering();
</del><ins>+                self.enqueueToRender();
</ins><span class="cx">             });
</span><span class="cx">             this._fetchRelatedInfoForTaskId(taskId);
</span><span class="cx">         } else if (state.buildRequest) {
</span><span class="lines">@@ -110,7 +110,7 @@
</span><span class="cx">                 self._fetchRelatedInfoForTaskId(task.id());
</span><span class="cx">             }, function (error) {
</span><span class="cx">                 self._errorMessage = `Failed to fetch the analysis task for the build request ${buildRequestId}: ${error}`;
</span><del>-                self.updateRendering();
</del><ins>+                self.enqueueToRender();
</ins><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -146,7 +146,7 @@
</span><span class="cx">         this._chartPane.setOverviewDomain(domain[0], domain[1]);
</span><span class="cx">         this._chartPane.setMainDomain(domain[0], domain[1]);
</span><span class="cx"> 
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         return task;
</span><span class="cx">     }
</span><span class="lines">@@ -154,7 +154,7 @@
</span><span class="cx">     _didFetchRelatedAnalysisTasks(relatedTasks)
</span><span class="cx">     {
</span><span class="cx">         this._relatedTasks = relatedTasks;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _didFetchMeasurement()
</span><span class="lines">@@ -171,7 +171,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._startPoint = startPoint;
</span><span class="cx">         this._endPoint = endPoint;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _didFetchTestGroups(testGroups)
</span><span class="lines">@@ -179,7 +179,7 @@
</span><span class="cx">         this._testGroups = testGroups.sort(function (a, b) { return +a.createdAt() - b.createdAt(); });
</span><span class="cx">         this._didUpdateTestGroupHiddenState();
</span><span class="cx">         this._assignTestResultsIfPossible();
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _showAllTestGroups()
</span><span class="lines">@@ -186,7 +186,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._showHiddenTestGroups = true;
</span><span class="cx">         this._didUpdateTestGroupHiddenState();
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _didUpdateTestGroupHiddenState()
</span><span class="lines">@@ -206,7 +206,7 @@
</span><span class="cx">     {
</span><span class="cx">         this._analysisResults = results;
</span><span class="cx">         if (this._assignTestResultsIfPossible())
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _assignTestResultsIfPossible()
</span><span class="lines">@@ -233,7 +233,7 @@
</span><span class="cx"> 
</span><span class="cx">         this.content().querySelector('.error-message').textContent = this._errorMessage || '';
</span><span class="cx"> 
</span><del>-        this._chartPane.updateRendering();
</del><ins>+        this._chartPane.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         var element = ComponentBase.createElement;
</span><span class="cx">         var link = ComponentBase.createLink;
</span><span class="lines">@@ -264,18 +264,18 @@
</span><span class="cx">         } else
</span><span class="cx">             repositoryList = Repository.sortByNamePreferringOnesWithURL(Repository.all());
</span><span class="cx"> 
</span><del>-        this._bugList.updateRendering();
</del><ins>+        this._bugList.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         this._causeList.setKindList(repositoryList);
</span><del>-        this._causeList.updateRendering();
</del><ins>+        this._causeList.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         this._fixList.setKindList(repositoryList);
</span><del>-        this._fixList.updateRendering();
</del><ins>+        this._fixList.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         this.content().querySelector('.analysis-task-status').style.display = this._task ? null : 'none';
</span><span class="cx">         this.content().querySelector('.overview-chart').style.display = this._task ? null : 'none';
</span><span class="cx">         this.content().querySelector('.test-group-view').style.display = this._task &amp;&amp; this._testGroups &amp;&amp; this._testGroups.length ? null : 'none';
</span><del>-        this._taskNameLabel.updateRendering();
</del><ins>+        this._taskNameLabel.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         if (this._relatedTasks &amp;&amp; this._task) {
</span><span class="cx">             var router = this.router();
</span><span class="lines">@@ -296,7 +296,7 @@
</span><span class="cx">         var a = selectedRange['A'];
</span><span class="cx">         var b = selectedRange['B'];
</span><span class="cx">         this._newTestGroupFormForViewer.setRootSetMap(a &amp;&amp; b ? {'A': a.rootSet(), 'B': b.rootSet()} : null);
</span><del>-        this._newTestGroupFormForViewer.updateRendering();
</del><ins>+        this._newTestGroupFormForViewer.enqueueToRender();
</ins><span class="cx">         this._newTestGroupFormForViewer.element().style.display = this._triggerable ? null : 'none';
</span><span class="cx"> 
</span><span class="cx">         this._renderTestGroupList();
</span><span class="lines">@@ -308,13 +308,13 @@
</span><span class="cx">         var points = this._chartPane.selectedPoints();
</span><span class="cx">         this._newTestGroupFormForChart.setRootSetMap(points &amp;&amp; points.length &gt;= 2 ?
</span><span class="cx">                 {'A': points[0].rootSet(), 'B': points[points.length - 1].rootSet()} : null);
</span><del>-        this._newTestGroupFormForChart.updateRendering();
</del><ins>+        this._newTestGroupFormForChart.enqueueToRender();
</ins><span class="cx">         this._newTestGroupFormForChart.element().style.display = this._triggerable ? null : 'none';
</span><span class="cx"> 
</span><span class="cx">         this._analysisResultsViewer.setCurrentTestGroup(this._currentTestGroup);
</span><del>-        this._analysisResultsViewer.updateRendering();
</del><ins>+        this._analysisResultsViewer.enqueueToRender();
</ins><span class="cx"> 
</span><del>-        this._testGroupResultsTable.updateRendering();
</del><ins>+        this._testGroupResultsTable.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         Instrumentation.endMeasuringTime('AnalysisTaskPage', 'render');
</span><span class="cx">     }
</span><span class="lines">@@ -356,7 +356,7 @@
</span><span class="cx">             for (var testGroup of this._filteredTestGroups) {
</span><span class="cx">                 var label = this._testGroupLabelMap.get(testGroup);
</span><span class="cx">                 label.setText(testGroup.label());
</span><del>-                label.updateRendering();
</del><ins>+                label.enqueueToRender();
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -364,7 +364,7 @@
</span><span class="cx">     _createTestGroupListItem(group)
</span><span class="cx">     {
</span><span class="cx">         var text = new EditableText(group.label());
</span><del>-        text.setStartedEditingCallback(() =&gt; { return text.updateRendering(); });
</del><ins>+        text.setStartedEditingCallback(() =&gt; { return text.enqueueToRender(); });
</ins><span class="cx">         text.setUpdateCallback(this._updateTestGroupName.bind(this, group));
</span><span class="cx"> 
</span><span class="cx">         this._testGroupLabelMap.set(group, text);
</span><span class="lines">@@ -408,7 +408,7 @@
</span><span class="cx"> 
</span><span class="cx">             this._renderedCurrentTestGroup = this._currentTestGroup;
</span><span class="cx">         }
</span><del>-        this._retryForm.updateRendering();
</del><ins>+        this._retryForm.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _showTestGroup(testGroup)
</span><span class="lines">@@ -415,23 +415,23 @@
</span><span class="cx">     {
</span><span class="cx">         this._currentTestGroup = testGroup;        
</span><span class="cx">         this._testGroupResultsTable.setTestGroup(this._currentTestGroup);
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _didStartEditingTaskName()
</span><span class="cx">     {
</span><del>-        this._taskNameLabel.updateRendering();
</del><ins>+        this._taskNameLabel.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _updateTaskName()
</span><span class="cx">     {
</span><span class="cx">         console.assert(this._task);
</span><del>-        this._taskNameLabel.updateRendering();
</del><ins>+        this._taskNameLabel.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         return this._task.updateName(this._taskNameLabel.editedText()).then(() =&gt; {
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">         }, (error) =&gt; {
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">             alert('Failed to update the name: ' + error);
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="lines">@@ -439,12 +439,12 @@
</span><span class="cx">     _updateTestGroupName(testGroup)
</span><span class="cx">     {
</span><span class="cx">         var label = this._testGroupLabelMap.get(testGroup);
</span><del>-        label.updateRendering();
</del><ins>+        label.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         return testGroup.updateName(label.editedText()).then(() =&gt; {
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">         }, (error) =&gt; {
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">             alert('Failed to hide the test name: ' + error);
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="lines">@@ -454,10 +454,10 @@
</span><span class="cx">         console.assert(this._currentTestGroup);
</span><span class="cx">         return this._currentTestGroup.updateHiddenFlag(!this._currentTestGroup.isHidden()).then(() =&gt; {
</span><span class="cx">             this._didUpdateTestGroupHiddenState();
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">         }, function (error) {
</span><span class="cx">             this._mayHaveMutatedTestGroupHiddenState();
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">             alert('Failed to update the group: ' + error);
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="lines">@@ -471,7 +471,10 @@
</span><span class="cx">         if (newChangeType == 'unconfirmed')
</span><span class="cx">             newChangeType = null;
</span><span class="cx"> 
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; {
+            this._chartPane.didUpdateAnnotations();
+            this.enqueueToRender();
+        };
</ins><span class="cx">         return this._task.updateChangeType(newChangeType).then(updateRendering, (error) =&gt; {
</span><span class="cx">             updateRendering();
</span><span class="cx">             alert('Failed to update the status: ' + error);
</span><span class="lines">@@ -483,7 +486,7 @@
</span><span class="cx">         console.assert(tracker instanceof BugTracker);
</span><span class="cx">         bugNumber = parseInt(bugNumber);
</span><span class="cx"> 
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         return this._task.associateBug(tracker, bugNumber).then(updateRendering, (error) =&gt; {
</span><span class="cx">             updateRendering();
</span><span class="cx">             alert('Failed to associate the bug: ' + error);
</span><span class="lines">@@ -492,7 +495,7 @@
</span><span class="cx"> 
</span><span class="cx">     _dissociateBug(bug)
</span><span class="cx">     {
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         return this._task.dissociateBug(bug).then(updateRendering, (error) =&gt; {
</span><span class="cx">             updateRendering();
</span><span class="cx">             alert('Failed to dissociate the bug: ' + error);
</span><span class="lines">@@ -501,7 +504,7 @@
</span><span class="cx"> 
</span><span class="cx">     _associateCommit(kind, repository, revision)
</span><span class="cx">     {
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         return this._task.associateCommit(kind, repository, revision).then(updateRendering, (error) =&gt; {
</span><span class="cx">             updateRendering();
</span><span class="cx">             if (error == 'AmbiguousRevision')
</span><span class="lines">@@ -515,7 +518,7 @@
</span><span class="cx"> 
</span><span class="cx">     _dissociateCommit(commit)
</span><span class="cx">     {
</span><del>-        const updateRendering = () =&gt; { this.updateRendering(); };
</del><ins>+        const updateRendering = () =&gt; { this.enqueueToRender(); };
</ins><span class="cx">         return this._task.dissociateCommit(commit).then(updateRendering, (error) =&gt; {
</span><span class="cx">             updateRendering();
</span><span class="cx">             alert('Failed to dissociate the commit: ' + error);
</span><span class="lines">@@ -539,7 +542,7 @@
</span><span class="cx">     _chartSelectionDidChange()
</span><span class="cx">     {
</span><span class="cx">         this._selectionWasModifiedByUser = true;
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _createNewTestGroupFromChart(name, repetitionCount, rootSetMap)
</span><span class="lines">@@ -549,7 +552,7 @@
</span><span class="cx"> 
</span><span class="cx">     _selectedRowInAnalysisResultsViewer()
</span><span class="cx">     {
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _createNewTestGroupFromViewer(name, repetitionCount, rootSetMap)
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesbuildrequestqueuepagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/build-request-queue-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/build-request-queue-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/build-request-queue-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -18,16 +18,16 @@
</span><span class="cx"> 
</span><span class="cx">                 BuildRequest.fetchForTriggerable(entry.name).then(function (requests) {
</span><span class="cx">                     triggerable.buildRequests = requests;
</span><del>-                    self.updateRendering();
</del><ins>+                    self.enqueueToRender();
</ins><span class="cx">                 });
</span><span class="cx"> 
</span><span class="cx">                 return triggerable;
</span><span class="cx">             });
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         AnalysisTask.fetchAll().then(function () {
</span><del>-            self.updateRendering();
</del><ins>+            self.enqueueToRender();
</ins><span class="cx">         });
</span><span class="cx"> 
</span><span class="cx">         super.open(state);
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pageschartpanejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/chart-pane.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -6,7 +6,7 @@
</span><span class="cx">         if (!values.length)
</span><span class="cx">             return Promise.resolve(null);
</span><span class="cx"> 
</span><del>-        var averageValues = callback.call(null, values, parameters[0], parameters[1]);
</del><ins>+        var averageValues = callback.call(null, values, ...parameters);
</ins><span class="cx">         if (!averageValues)
</span><span class="cx">             return Promise.resolve(null);
</span><span class="cx"> 
</span><span class="lines">@@ -186,8 +186,8 @@
</span><span class="cx">     {
</span><span class="cx">         if (repository != this._commitLogViewer.currentRepository()) {
</span><span class="cx">             var range = this._mainChartStatus.setCurrentRepository(repository);
</span><del>-            this._commitLogViewer.view(repository, range.from, range.to).then(() =&gt; { this.updateRendering(); });
-            this.updateRendering();
</del><ins>+            this._commitLogViewer.view(repository, range.from, range.to).then(() =&gt; { this.enqueueToRender(); });
+            this.enqueueToRender();
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -402,15 +402,15 @@
</span><span class="cx">         var link = ComponentBase.createLink;
</span><span class="cx">         var self = this;
</span><span class="cx"> 
</span><del>-        if (this._trendLineType == null) {
-            this.renderReplace(this.content().querySelector('.trend-line-types'), [
</del><ins>+        const trendLineTypesContainer = this.content().querySelector('.trend-line-types');
+        if (!trendLineTypesContainer.querySelector('select')) {
+            this.renderReplace(trendLineTypesContainer, [
</ins><span class="cx">                 element('select', {onchange: this._trendLineTypeDidChange.bind(this)},
</span><del>-                    ChartTrendLineTypes.map(function (type) {
-                        return element('option', type == self._trendLineType ? {value: type.id, selected: true} : {value: type.id}, type.label);
-                    }))
</del><ins>+                    ChartTrendLineTypes.map((type) =&gt; { return element('option', {value: type.id}, type.label); }))
</ins><span class="cx">             ]);
</span><del>-        } else
-            this.content().querySelector('.trend-line-types select').value = this._trendLineType.id;
</del><ins>+        }
+        if (this._trendLineType)
+            trendLineTypesContainer.querySelector('select').value = this._trendLineType.id;
</ins><span class="cx"> 
</span><span class="cx">         if (this._renderedTrendLineOptions)
</span><span class="cx">             return;
</span><span class="lines">@@ -448,7 +448,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._updateTrendLine();
</span><span class="cx">         this._chartsPage.graphOptionsDidChange();
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _defaultParametersForTrendLine(type)
</span><span class="lines">@@ -493,7 +493,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (!currentTrendLineType.execute) {
</span><span class="cx">             this._mainChart.clearTrendLines();
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">         } else {
</span><span class="cx">             // Wait for all trendlines to be ready. Otherwise we might see FOC when the domain is expanded.
</span><span class="cx">             Promise.all(sourceList.map(function (source, sourceIndex) {
</span><span class="lines">@@ -502,7 +502,7 @@
</span><span class="cx">                         self._mainChart.setTrendLine(sourceIndex, trendlineSeries);
</span><span class="cx">                 });
</span><span class="cx">             })).then(function () {
</span><del>-                self.updateRendering();
</del><ins>+                self.enqueueToRender();
</ins><span class="cx">             });
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pageschartspagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/charts-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/charts-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/charts-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -79,7 +79,7 @@
</span><span class="cx">         if (newPaneList) {
</span><span class="cx">             this._paneList = newPaneList;
</span><span class="cx">             this._paneListChanged = true;
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         this._updateDomainsFromSerializedState(state);
</span><span class="lines">@@ -109,7 +109,7 @@
</span><span class="cx">             since = zoom[0] - (zoom[1] - zoom[0]) / 2;
</span><span class="cx"> 
</span><span class="cx">         this.toolbar().setStartTime(since);
</span><del>-        this.toolbar().updateRendering();
</del><ins>+        this.toolbar().enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         this._mainDomain = zoom || null;
</span><span class="cx"> 
</span><span class="lines">@@ -151,7 +151,7 @@
</span><span class="cx">     setNumberOfDaysFromToolbar(numberOfDays, shouldUpdateState)
</span><span class="cx">     {
</span><span class="cx">         this.toolbar().setNumberOfDays(numberOfDays, true);
</span><del>-        this.toolbar().updateRendering();
</del><ins>+        this.toolbar().enqueueToRender();
</ins><span class="cx">         this._updateOverviewDomain();
</span><span class="cx">         this._updateMainDomain();
</span><span class="cx">         if (shouldUpdateState)
</span><span class="lines">@@ -298,7 +298,7 @@
</span><span class="cx">             this._updateOverviewDomain();
</span><span class="cx">             this._updateMainDomain();
</span><span class="cx">         }
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">         this.scheduleUrlStateUpdate();
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -310,7 +310,7 @@
</span><span class="cx">             this.renderReplace(this.content().querySelector('.pane-list'), this._paneList);
</span><span class="cx"> 
</span><span class="cx">         for (var pane of this._paneList)
</span><del>-            pane.updateRendering();
</del><ins>+            pane.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         this._paneListChanged = false;
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pageschartstoolbarjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/charts-toolbar.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/charts-toolbar.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/charts-toolbar.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx">     render()
</span><span class="cx">     {
</span><span class="cx">         super.render();
</span><del>-        this._paneSelector.updateRendering();
</del><ins>+        this._paneSelector.enqueueToRender();
</ins><span class="cx">         this._labelSpan.textContent = this._numberOfDays;
</span><span class="cx">         this._setInputElementValue(this._numberOfDays);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagescreateanalysistaskpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/create-analysis-task-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/create-analysis-task-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/create-analysis-task-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._errorMessage = state.error;
</span><span class="cx">         if (!isOpen)
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     render()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesdashboardpagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/dashboard-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/dashboard-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/dashboard-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx">         this._needsTableConstruction = true;
</span><span class="cx">         if (!isOpen)
</span><del>-            this.updateRendering();
</del><ins>+            this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     open(state)
</span><span class="lines">@@ -114,7 +114,7 @@
</span><span class="cx"> 
</span><span class="cx">         if (this._needsStatusUpdate) {
</span><span class="cx">             for (var statusView of this._statusViews)
</span><del>-                statusView.updateRendering();
</del><ins>+                statusView.enqueueToRender();
</ins><span class="cx">             this._needsStatusUpdate = false;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -155,7 +155,7 @@
</span><span class="cx">             return;
</span><span class="cx"> 
</span><span class="cx">         this._needsStatusUpdate = true;
</span><del>-        setTimeout(() =&gt; { this.updateRendering(); }, 10);
</del><ins>+        setTimeout(() =&gt; { this.enqueueToRender(); }, 10);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static htmlTemplate()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagesheadingjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/heading.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/heading.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/heading.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -50,7 +50,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if (this._toolbar)
</span><del>-            this._toolbar.updateRendering();
</del><ins>+            this._toolbar.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         var currentPage = this._router.currentPage();
</span><span class="cx">         if (this._renderedCurrentPage == currentPage)
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagespagewithheadingjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/page-with-heading.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/page-with-heading.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/page-with-heading.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx">             document.body.insertBefore(this.heading().element(), document.body.firstChild);
</span><span class="cx"> 
</span><span class="cx">         super.render();
</span><del>-        this.heading().updateRendering();
</del><ins>+        this.heading().enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     static htmlTemplate()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagespagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -19,7 +19,7 @@
</span><span class="cx">         if (this._router)
</span><span class="cx">             this._router.pageDidOpen(this);
</span><span class="cx">         this.updateFromSerializedState(state, true);
</span><del>-        this.updateRendering();
</del><ins>+        this.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     render()
</span></span></pre></div>
<a id="trunkWebsitesperfwebkitorgpublicv3pagessummarypagejs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/perf.webkit.org/public/v3/pages/summary-page.js (210879 => 210880)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/perf.webkit.org/public/v3/pages/summary-page.js        2017-01-18 20:43:44 UTC (rev 210879)
+++ trunk/Websites/perf.webkit.org/public/v3/pages/summary-page.js        2017-01-18 21:22:39 UTC (rev 210880)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx">         var current = Date.now();
</span><span class="cx">         var timeRange = [current - 24 * 3600 * 1000, current];
</span><span class="cx">         for (var group of this._configGroups)
</span><del>-            group.fetchAndComputeSummary(timeRange).then(() =&gt; { this.updateRendering(); });
</del><ins>+            group.fetchAndComputeSummary(timeRange).then(() =&gt; { this.enqueueToRender(); });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     render()
</span><span class="lines">@@ -106,7 +106,7 @@
</span><span class="cx">         var ratioGraph = new RatioBarGraph();
</span><span class="cx"> 
</span><span class="cx">         if (configurationList.length == 0) {
</span><del>-            this._renderQueue.push(() =&gt; { ratioGraph.updateRendering(); });
</del><ins>+            this._renderQueue.push(() =&gt; { ratioGraph.enqueueToRender(); });
</ins><span class="cx">             return element('td', ratioGraph);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -121,7 +121,7 @@
</span><span class="cx"> 
</span><span class="cx">     _renderCell(cell, spinner, anchor, ratioGraph, configurationGroup)
</span><span class="cx">     {
</span><del>-        spinner.updateRendering();
</del><ins>+        spinner.enqueueToRender();
</ins><span class="cx"> 
</span><span class="cx">         if (configurationGroup.isFetching())
</span><span class="cx">             cell.classList.add('fetching');
</span><span class="lines">@@ -131,7 +131,7 @@
</span><span class="cx">         var warningText = this._warningTextForGroup(configurationGroup);
</span><span class="cx">         anchor.title = warningText || 'Open charts';
</span><span class="cx">         ratioGraph.update(configurationGroup.ratio(), configurationGroup.label(), !!warningText);
</span><del>-        ratioGraph.updateRendering();
</del><ins>+        ratioGraph.enqueueToRender();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _warningTextForGroup(configurationGroup)
</span></span></pre>
</div>
</div>

</body>
</html>