diff options
Diffstat (limited to 'chromium/third_party/catapult/tracing/tracing/ui')
285 files changed, 16205 insertions, 12223 deletions
diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html index 67ff160cea9..0d2cfecf43a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/alert_sub_view.html @@ -1,6 +1,6 @@ <!DOCTYPE html> <!-- -Copyright (c) 2015 The Chromium Authors. All rights reserved. +Copyright 2015 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> @@ -8,13 +8,13 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/model/event_set.html"> +<link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name="tr-ui-a-alert-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-alert-sub-view'> <template> <style> :host { @@ -24,138 +24,157 @@ found in the LICENSE file. #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"> </tr-ui-b-table> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.currentSelection_ = undefined; - this.$.table.tableColumns = [ - { - title: 'Label', - value: function(row) { return row.name; }, - width: '150px' - }, - { - title: 'Value', - width: '100%', - value: function(row) { return row.value; } - } - ]; - this.$.table.showHeader = false; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - this.currentSelection_ = selection; - this.updateContents_(); - }, - - getRowsForSingleAlert_: function(alert) { - var rows = []; - - // Arguments - for (var argName in alert.args) { - var argView = - document.createElement('tr-ui-a-generic-object-view'); - argView.object = alert.args[argName]; - rows.push({ name: argName, value: argView }); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-alert-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + ready: function() { + this.currentSelection_ = undefined; + this.$.table.tableColumns = [ + { + title: 'Label', + value: function(row) { return row.name; }, + width: '150px' + }, + { + title: 'Value', + width: '100%', + value: function(row) { return row.value; } } + ]; + this.$.table.showHeader = false; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + this.currentSelection_ = selection; + this.updateContents_(); + }, + + getRowsForSingleAlert_: function(alert) { + var rows = []; + + // Arguments + for (var argName in alert.args) { + var argView = + document.createElement('tr-ui-a-generic-object-view'); + argView.object = alert.args[argName]; + rows.push({ name: argName, value: argView }); + } - // Associated events - if (alert.associatedEvents.length) { - alert.associatedEvents.forEach(function(event, i) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return event; - }, event.title); - - var valueString = ''; - if (event instanceof tr.model.TimedEvent) - valueString = 'took ' + event.duration.toFixed(2) + 'ms'; - - rows.push({ - name: linkEl, - value: valueString - }); - }); - } + // Associated events + if (alert.associatedEvents.length) { + alert.associatedEvents.forEach(function(event, i) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent( + new tr.model.EventSet(event), event.title); - // Description - var descriptionEl = tr.ui.b.createDiv({ - textContent: alert.info.description, - maxWidth: '300px' - }); - rows.push({ - name: 'Description', - value: descriptionEl + var valueString = ''; + if (event instanceof tr.model.TimedEvent) + valueString = 'took ' + event.duration.toFixed(2) + 'ms'; + + rows.push({ + name: linkEl, + value: valueString + }); }); + } - // Additional Reading Links - if (alert.info.docLinks) { - alert.info.docLinks.forEach(function(linkObject) { - var linkEl = document.createElement('a'); - linkEl.target = '_blank'; - linkEl.href = linkObject.href; - linkEl.textContent = linkObject.textContent; - rows.push({ - name: linkObject.label, - value: linkEl - }); + // Description + var descriptionEl = tr.ui.b.createDiv({ + textContent: alert.info.description, + maxWidth: '300px' + }); + rows.push({ + name: 'Description', + value: descriptionEl + }); + + // Additional Reading Links + if (alert.info.docLinks) { + alert.info.docLinks.forEach(function(linkObject) { + var linkEl = document.createElement('a'); + linkEl.target = '_blank'; + linkEl.href = linkObject.href; + Polymer.dom(linkEl).textContent = Polymer.dom(linkObject).textContent; + rows.push({ + name: linkObject.label, + value: linkEl }); - } + }); + } + return rows; + }, + + getRowsForAlerts_: function(alerts) { + if (alerts.length === 1) { + var rows = [{ + name: 'Alert', + value: tr.b.getOnlyElement(alerts).title + }]; + var detailRows = this.getRowsForSingleAlert_(tr.b.getOnlyElement(alerts)); + rows.push.apply(rows, detailRows); return rows; - }, - - getRowsForAlerts_: function(alerts) { - if (alerts.length == 1) { - var rows = [{ + } else { + return alerts.map(function(alert) { + return { name: 'Alert', - value: tr.b.getOnlyElement(alerts).title - }]; - var detailRows = this.getRowsForSingleAlert_(alerts[0]); - rows.push.apply(rows, detailRows); - return rows; - } else { - return alerts.map(function(alert) { - return { - name: 'Alert', - value: alert.title, - isExpanded: alerts.size < 10, // This is somewhat arbitrary for now. - subRows: this.getRowsForSingleAlert_(alert) - }; - }, this); - } - }, - - updateContents_: function() { - if (this.currentSelection_ === undefined) { - this.$.table.rows = []; - this.$.table.rebuild(); - return; - } + value: alert.title, + isExpanded: alerts.size < 10, // This is somewhat arbitrary for now. + subRows: this.getRowsForSingleAlert_(alert) + }; + }, this); + } + }, - var alerts = this.currentSelection_; - this.$.table.tableRows = this.getRowsForAlerts_(alerts); + updateContents_: function() { + if (this.currentSelection_ === undefined) { + this.$.table.rows = []; this.$.table.rebuild(); - }, - - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - var result = new tr.model.EventSet(); - for (var event of this.currentSelection_) - result.addEventSet(event.associatedEvents); - return result; + return; } - }); - </script> -</polymer-element> + + var alerts = this.currentSelection_; + this.$.table.tableRows = this.getRowsForAlerts_(alerts); + this.$.table.rebuild(); + }, + + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + var result = new tr.model.EventSet(); + for (var event of this.currentSelection_) + result.addEventSet(event.associatedEvents); + return result; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-alert-sub-view', + tr.model.Alert, + { + multi: false, + title: 'Alert', + }); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-alert-sub-view', + tr.model.Alert, + { + multi: true, + title: 'Alerts', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html index 3619e4a9b40..a0fd79af567 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_link.html @@ -9,116 +9,137 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/brushing_state_controller.html"> -<polymer-element name="tr-ui-a-analysis-link" is="a" - on-click="{{onClicked_}}" - on-mouseenter="{{onMouseEnter_}}" - on-mouseleave="{{onMouseLeave_}}"> +<dom-module id='tr-ui-a-analysis-link'> <template> <style> :host { display: inline; - color: -webkit-link; cursor: pointer; - text-decoration: underline; cursor: pointer; + white-space: nowrap; + } + a { + text-decoration: underline; } </style> - <content></content> + <a href="{{href}}" on-click="onClicked_" on-mouseenter="onMouseEnter_" on-mouseleave="onMouseLeave_"><content></content></a> + </template> - <script> - 'use strict'; - Polymer({ - ready: function() { - this.selection_ = undefined; - }, - - attached: function() { - // Save an instance of the controller since it's going to be used in - // detached() where it can no longer be obtained. - this.controller_ = - tr.c.BrushingStateController.getControllerForElement(this); - }, - - detached: function() { - // Reset highlights. - this.clearHighlight_(); - this.controller_ = undefined; - }, - - /** - * @return {*|function():*} - */ - get selection() { - return this.selection_; - }, - - /** - * |selection| can be anything except a function, or else a function that - * can return anything. - * - * In the context of trace_viewer, |selection| is typically an EventSet, - * whose events will be highlighted by trace_viewer when this link is - * clicked or mouse-entered. - * - * If |selection| is not a function, then it will be dispatched to this - * link's embedder via a RequestSelectionChangeEvent when this link is - * clicked or mouse-entered. - * - * If |selection| is a function, then it will be called when this link is - * clicked or mouse-entered, and its result will be dispatched to this - * link's embedder via a RequestSelectionChangeEvent. - * - * @param {*|function():*} selection - */ - set selection(selection) { - this.selection_ = selection; - this.textContent = selection.userFriendlyName; - }, - - setSelectionAndContent: function(selection, opt_textContent) { - this.selection_ = selection; - if (opt_textContent) - this.textContent = opt_textContent; - }, - - /** - * If |selection| is a function, call it and return the result. - * Otherwise return |selection| directly. - * - * @return {*} - */ - getCurrentSelection_: function() { - // Gets the current selection, invoking the selection function if needed. - if (typeof this.selection_ === 'function') - return this.selection_(); - return this.selection_; - }, - - setHighlight_: function(opt_eventSet) { - if (this.controller_) - this.controller_.changeAnalysisLinkHoveredEvents(opt_eventSet); - }, - - clearHighlight_: function(opt_eventSet) { - this.setHighlight_(); - }, - - onClicked_: function() { - if (!this.selection_) - return; - - var event = new tr.model.RequestSelectionChangeEvent(); - event.selection = this.getCurrentSelection_(); - this.dispatchEvent(event); - }, - - onMouseEnter_: function() { - this.setHighlight_(this.getCurrentSelection_()); - }, - - onMouseLeave_: function() { - this.clearHighlight_(); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-analysis-link', + + properties: { + href: { + type: String } - }); - </script> -</polymer-element> + }, + + listeners: { + 'click': 'onClicked_', + 'mouseenter': 'onMouseEnter_', + 'mouseleave': 'onMouseLeave_' + }, + + ready: function() { + this.selection_ = undefined; + }, + + attached: function() { + // Save an instance of the controller since it's going to be used in + // detached() where it can no longer be obtained. + this.controller_ = + tr.c.BrushingStateController.getControllerForElement(this); + }, + + detached: function() { + // Reset highlights. + this.clearHighlight_(); + this.controller_ = undefined; + }, + + set color(c) { + this.style.color = c; + }, + + /** + * @return {*|function():*} + */ + get selection() { + return this.selection_; + }, + + /** + * |selection| can be anything except a function, or else a function that + * can return anything. + * + * In the context of trace_viewer, |selection| is typically an EventSet, + * whose events will be highlighted by trace_viewer when this link is + * clicked or mouse-entered. + * + * If |selection| is not a function, then it will be dispatched to this + * link's embedder via a RequestSelectionChangeEvent when this link is + * clicked or mouse-entered. + * + * If |selection| is a function, then it will be called when this link is + * clicked or mouse-entered, and its result will be dispatched to this + * link's embedder via a RequestSelectionChangeEvent. + * + * @param {*|function():*} selection + */ + set selection(selection) { + this.selection_ = selection; + Polymer.dom(this).textContent = selection.userFriendlyName; + }, + + setSelectionAndContent: function(selection, opt_textContent) { + this.selection_ = selection; + if (opt_textContent) + Polymer.dom(this).textContent = opt_textContent; + }, + + /** + * If |selection| is a function, call it and return the result. + * Otherwise return |selection| directly. + * + * @return {*} + */ + getCurrentSelection_: function() { + // Gets the current selection, invoking the selection function if needed. + if (typeof this.selection_ === 'function') + return this.selection_(); + return this.selection_; + }, + + setHighlight_: function(opt_eventSet) { + if (this.controller_) + this.controller_.changeAnalysisLinkHoveredEvents(opt_eventSet); + }, + + clearHighlight_: function(opt_eventSet) { + this.setHighlight_(); + }, + + onClicked_: function(clickEvent) { + if (!this.selection_) + return; + + clickEvent.stopPropagation(); + + var event = new tr.model.RequestSelectionChangeEvent(); + event.selection = this.getCurrentSelection_(); + this.dispatchEvent(event); + }, + + onMouseEnter_: function() { + this.setHighlight_(this.getCurrentSelection_()); + }, + + onMouseLeave_: function() { + this.clearHighlight_(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html index 203eed642df..66bae5772d4 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_sub_view.html @@ -1,21 +1,25 @@ <!DOCTYPE html> <!-- -Copyright (c) 2014 The Chromium Authors. All rights reserved. +Copyright 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <link rel="import" href="/tracing/base/base.html"> +<link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/model/event_set.html"> <!-- @fileoverview Polymer element for various analysis sub-views. --> -<polymer-element name="tr-ui-a-sub-view"> - <script> - 'use strict'; - Polymer({ +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + + var AnalysisSubView = { set tabLabel(label) { - return this.setAttribute('tab-label', label); + Polymer.dom(this).setAttribute('tab-label', label); }, get tabLabel() { @@ -41,6 +45,222 @@ found in the LICENSE file. get selection() { throw new Error('Not implemented!'); } - }); - </script> -</polymer-element> + }; + + // Basic registry. + var allTypeInfosByEventProto = new Map(); + var onlyRootTypeInfosByEventProto = undefined; + var eventProtoToRootTypeInfoMap = undefined; + + function AnalysisSubViewTypeInfo(eventConstructor, options) { + if (options.multi === undefined) + throw new Error('missing field: multi'); + if (options.title === undefined) + throw new Error('missing field: title'); + this.eventConstructor = eventConstructor; + + this.singleTagName = undefined; + this.singleTitle = undefined; + + this.multiTagName = undefined; + this.multiTitle = undefined; + + // This is computed by rebuildRootSubViewTypeInfos, so don't muck with it! + this.childrenTypeInfos_ = undefined; + }; + + AnalysisSubViewTypeInfo.prototype = { + get childrenTypeInfos() { + return this.childrenTypeInfos_; + }, + + resetchildrenTypeInfos: function() { + this.childrenTypeInfos_ = []; + } + }; + + AnalysisSubView.register = function(tagName, eventConstructor, options) { + var typeInfo = allTypeInfosByEventProto.get(eventConstructor.prototype); + if (typeInfo === undefined) { + typeInfo = new AnalysisSubViewTypeInfo(eventConstructor, options); + allTypeInfosByEventProto.set(typeInfo.eventConstructor.prototype, + typeInfo); + + onlyRootTypeInfosByEventProto = undefined; + } + + if (!options.multi) { + if (typeInfo.singleTagName !== undefined) + throw new Error('SingleTagName already set'); + typeInfo.singleTagName = tagName; + typeInfo.singleTitle = options.title; + } else { + if (typeInfo.multiTagName !== undefined) + throw new Error('MultiTagName already set'); + typeInfo.multiTagName = tagName; + typeInfo.multiTitle = options.title; + } + return typeInfo; + }; + + function rebuildRootSubViewTypeInfos() { + onlyRootTypeInfosByEventProto = new Map(); + allTypeInfosByEventProto.forEach(function(typeInfo) { + typeInfo.resetchildrenTypeInfos(); + }); + + // Find all root typeInfos. + allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) { + var eventPrototype = typeInfo.eventConstructor.prototype; + + var lastEventProto = eventPrototype; + var curEventProto = eventPrototype.__proto__; + while (true) { + if (!allTypeInfosByEventProto.has(curEventProto)) { + var rootTypeInfo = allTypeInfosByEventProto.get(lastEventProto); + var rootEventProto = lastEventProto; + + var isNew = onlyRootTypeInfosByEventProto.has(rootEventProto); + onlyRootTypeInfosByEventProto.set(rootEventProto, + rootTypeInfo); + break; + } + + lastEventProto = curEventProto; + curEventProto = curEventProto.__proto__; + } + }); + + // Build the childrenTypeInfos array. + allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) { + var eventPrototype = typeInfo.eventConstructor.prototype; + var parentEventProto = eventPrototype.__proto__; + var parentTypeInfo = allTypeInfosByEventProto.get(parentEventProto); + if (!parentTypeInfo) + return; + parentTypeInfo.childrenTypeInfos.push(typeInfo); + }); + + // Build the eventProto to rootTypeInfo map. + eventProtoToRootTypeInfoMap = new Map(); + allTypeInfosByEventProto.forEach(function(typeInfo, eventProto) { + var eventPrototype = typeInfo.eventConstructor.prototype; + + var curEventProto = eventPrototype; + while (true) { + if (onlyRootTypeInfosByEventProto.has(curEventProto)) { + var rootTypeInfo = onlyRootTypeInfosByEventProto.get( + curEventProto); + eventProtoToRootTypeInfoMap.set(eventPrototype, + rootTypeInfo); + break; + } + curEventProto = curEventProto.__proto__; + } + }); + } + + function findLowestTypeInfoForEvents(thisTypeInfo, events) { + if (events.length === 0) + return thisTypeInfo; + var event0 = tr.b.getFirstElement(events); + + var candidateSubTypeInfo; + for (var i = 0; i < thisTypeInfo.childrenTypeInfos.length; i++) { + var childTypeInfo = thisTypeInfo.childrenTypeInfos[i]; + if (event0 instanceof childTypeInfo.eventConstructor) { + candidateSubTypeInfo = childTypeInfo; + break; + } + } + if (!candidateSubTypeInfo) + return thisTypeInfo; + + // Validate that all the other events are instances of the candidate type. + var allMatch = true; + for (var event of events) { + if (event instanceof candidateSubTypeInfo.eventConstructor) + continue; + allMatch = false; + break; + } + + if (!allMatch) { + return thisTypeInfo; + } + + return findLowestTypeInfoForEvents(candidateSubTypeInfo, events); + } + + var primaryEventProtoToTypeInfoMap = new Map(); + function getRootTypeInfoForEvent(event) { + var curProto = event.__proto__; + var typeInfo = primaryEventProtoToTypeInfoMap.get(curProto); + if (typeInfo) + return typeInfo; + return getRootTypeInfoForEventSlow(event); + } + + function getRootTypeInfoForEventSlow(event) { + var typeInfo; + var curProto = event.__proto__; + while (true) { + if (curProto === Object.prototype) + throw new Error('No view registered for ' + event.toString()); + typeInfo = onlyRootTypeInfosByEventProto.get(curProto); + if (typeInfo) { + primaryEventProtoToTypeInfoMap.set(event.__proto__, typeInfo); + return typeInfo; + } + curProto = curProto.__proto__; + } + } + + AnalysisSubView.getEventsOrganizedByTypeInfo = function(selection) { + if (onlyRootTypeInfosByEventProto === undefined) + rebuildRootSubViewTypeInfos(); + + // Base grouping. + var eventsByRootTypeInfo = tr.b.groupIntoMap( + selection, + function(event) { + return getRootTypeInfoForEvent(event); + }, + this, tr.model.EventSet); + + // Now, try to lower the typeinfo to the most specific type that still + // encompasses the event group. + // + // For instance, if we have 3 ThreadSlices, and all three are V8 slices, + // then we can convert this to use the V8Slices's typeinfos. But, if one + // of those slices was not a V8Slice, then we must still use + // ThreadSlice. + // + // The reason for this is for the confusion that might arise from the + // alternative. Suppose you click on a set of mixed slices, we want to show + // you the most correct information, and let you navigate to . If we instead + // showed you a V8 slices tab, and a Slices tab, we present the user with an + // ambiguity: is the V8 slice also in the Slices tab? Or is it not? Better, + // we think, to just only ever show an event in one place at a time, and + // avoid the possible confusion. + var eventsByLowestTypeInfo = new Map(); + eventsByRootTypeInfo.forEach(function(events, typeInfo) { + var lowestTypeInfo = findLowestTypeInfoForEvents(typeInfo, events); + eventsByLowestTypeInfo.set(lowestTypeInfo, events); + }); + + return eventsByLowestTypeInfo; + }; + + return { + AnalysisSubView: AnalysisSubView, + AnalysisSubViewTypeInfo: AnalysisSubViewTypeInfo + }; +}); + +// Dummy element for testing +Polymer({ + is: 'tr-ui-a-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView] +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html index b5961acda7d..f5a8a387a08 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view.html @@ -12,7 +12,6 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/container_memory_dump_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/counter_sample_sub_view.html"> -<link rel="import" href="/tracing/ui/analysis/layout_tree_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_async_slice_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_cpu_slice_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_flow_event_sub_view.html"> @@ -46,14 +45,13 @@ found in the LICENSE file. href="/tracing/ui/analysis/single_thread_time_slice_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/single_user_expectation_sub_view.html"> -<link rel="import" href="/tracing/ui/base/polymer_utils.html"> <link rel="import" href="/tracing/ui/base/tab_view.html"> <!-- @fileoverview A component used to display an analysis of a selection, using custom elements specialized for different event types. --> -<polymer-element name="tr-ui-a-analysis-view"> +<dom-module id='tr-ui-a-analysis-view'> <template> <style> :host { @@ -67,192 +65,138 @@ using custom elements specialized for different event types. :host(.tall-mode) { height: 525px; } - - ::content > * { - flex: 1 0 auto; - } </style> <content></content> </template> - <script> - 'use strict'; - (function() { - var EventRegistry = tr.model.EventRegistry; - - Polymer({ - ready: function() { - this.tabView_ = document.createElement('tr-ui-a-tab-view'); - this.tabView_.style.flex = '1 1 auto'; - this.appendChild(this.tabView_); - this.brushingStateController_ = undefined; - this.onSelectedTabChange_ = this.onSelectedTabChange_.bind(this); - this.onSelectionChanged_ = this.onSelectionChanged_.bind(this); - - this.lastSeenSelection_ = new tr.model.EventSet(); - }, +</dom-module> +<script> +'use strict'; +(function() { + var EventRegistry = tr.model.EventRegistry; + + /** Returns the label that goes next to the list of tabs. */ + function getTabStripLabel(numEvents) { + if (numEvents === 0) + return 'Nothing selected. Tap stuff.'; + else if (numEvents === 1) + return '1 item selected.'; + return numEvents + ' items selected.'; + } + + function createSubView(subViewTypeInfo, selection) { + var tagName; + if (selection.length === 1) + tagName = subViewTypeInfo.singleTagName; + else + tagName = subViewTypeInfo.multiTagName; + + if (tagName === undefined) { + throw new Error('No view registered for ' + + subViewTypeInfo.eventConstructor.name); + } + var subView = document.createElement(tagName); + + var title; + if (selection.length === 1) + title = subViewTypeInfo.singleTitle; + else + title = subViewTypeInfo.multiTitle; + title += ' (' + selection.length + ')'; + subView.tabLabel = title; + + subView.selection = selection; + return subView; + } + + Polymer({ + is: 'tr-ui-a-analysis-view', + + ready: function() { + this.brushingStateController_ = undefined; + this.lastSelection_ = undefined; + this.tabView_ = document.createElement('tr-ui-b-tab-view'); + this.tabView_.addEventListener( + 'selected-tab-change', this.onSelectedSubViewChanged_.bind(this)); + + Polymer.dom(this).appendChild(this.tabView_); + }, + + set tallMode(value) { + Polymer.dom(this).classList.toggle('tall-mode', value); + }, + + get tallMode() { + return Polymer.dom(this).classList.contains('tall-mode'); + }, + + get tabView() { + return this.tabView_; + }, + + get brushingStateController() { + return this.brushingStateController_; + }, + + set brushingStateController(brushingStateController) { + if (this.brushingStateController_) { + this.brushingStateController_.removeEventListener( + 'change', this.onSelectionChanged_.bind(this)); + } - set tallMode(value) { - if (value) - this.classList.add('tall-mode'); - else - this.classList.remove('tall-mode'); - }, + this.brushingStateController_ = brushingStateController; + if (this.brushingStateController) { + this.brushingStateController_.addEventListener( + 'change', this.onSelectionChanged_.bind(this)); + } - get tallMode() { - return this.classList.contains('tall-mode'); - }, + // The new brushing controller may have a different selection than the + // last one, so we have to refresh the subview. + this.onSelectionChanged_(); + }, - get tabView() { - return this.tabView_; - }, + get selection() { + return this.brushingStateController_.selection; + }, - get brushingStateController() { - return this.brushingStateController_; - }, + onSelectionChanged_: function(e) { + if (this.lastSelection_ && this.selection.equals(this.lastSelection_)) + return; + this.lastSelection_ = this.selection; - set brushingStateController(brushingStateController) { - if (this.brushingStateController) { - this.brushingStateController_.removeEventListener( - 'change', this.onSelectionChanged_); - } - this.brushingStateController_ = brushingStateController; - if (this.brushingStateController) { - this.brushingStateController_.addEventListener( - 'change', this.onSelectionChanged_); - } - this.onSelectionChanged_(); - }, + this.tallMode = false; - get selection() { - return this.brushingStateController_.selection; - }, + this.tabView_.label = getTabStripLabel(this.selection.length); + var eventsByBaseTypeName = + this.selection.getEventsOrganizedByBaseType(true); - onSelectionChanged_: function(e) { - var selection = this.brushingStateController_.selection; + var ASV = tr.ui.analysis.AnalysisSubView; + var eventsByTagName = ASV.getEventsOrganizedByTypeInfo(this.selection); + var newSubViews = []; + eventsByTagName.forEach(function(events, typeInfo) { + newSubViews.push(createSubView(typeInfo, events)); + }); - var selectionHasSameValue = this.lastSeenSelection_.equals(selection); - this.lastSeenSelection_ = selection; - if (selectionHasSameValue) - return; + this.tabView_.resetSubViews(newSubViews); + }, - var lastSelectedTabTagName; - var lastSelectedTabTypeName; - if (this.tabView_.selectedTab) { - lastSelectedTabTagName = this.tabView_.selectedTab.tagName; - lastSelectedTabTypeName = this.tabView_.selectedTab._eventTypeName; - } + onSelectedSubViewChanged_: function() { + var selectedSubView = this.tabView_.selectedSubView; + if (!selectedSubView) { this.tallMode = false; - - var previouslySelectedTab = this.tabView_.selectedTab; - this.tabView_.removeEventListener( - 'selected-tab-change', this.onSelectedTabChange_); - - var previousSubViews = {}; - for (var i = 0; i < this.tabView_.children.length; i++) { - var previousSubView = this.tabView_.children[i]; - previousSubViews[previousSubView._eventTypeName] = previousSubView; - } - - this.tabView_.saveTabStates(); - this.tabView_.textContent = ''; - if (selection.length == 0) { - this.tabView_.tabStripHeadingText = 'Nothing selected. Tap stuff.'; - } else if (selection.length == 1) { - this.tabView_.tabStripHeadingText = '1 item selected: '; - } else { - this.tabView_.tabStripHeadingText = selection.length + - ' items selected: '; - } - - var eventsByBaseTypeName = selection.getEventsOrganizedByBaseType(true); - - var numBaseTypesToAnalyze = tr.b.dictionaryLength(eventsByBaseTypeName); - for (var eventTypeName in eventsByBaseTypeName) { - var subSelection = eventsByBaseTypeName[eventTypeName]; - var subView = this.createSubViewForSelection_( - eventTypeName, subSelection, previousSubViews[eventTypeName]); - // Store the eventTypeName for future tab restoration. - subView._eventTypeName = eventTypeName; - this.tabView_.appendChild(subView); - - subView.selection = subSelection; - } - - // Restore the tab type that was previously selected. First try by tag - // name. - var tab; - if (lastSelectedTabTagName) - tab = this.tabView_.querySelector(lastSelectedTabTagName); - - // If that fails, look for a tab with that typeName. - if (!tab && lastSelectedTabTypeName) { - var tab = tr.b.findFirstInArray( - this.tabView_.children, function(tab) { - return tab._eventTypeName === lastSelectedTabTypeName; - }); - } - // If all else fails, pick the first tab. - if (!tab) - tab = this.tabView_.firstChild; - - this.tabView_.selectedTab = tab; - this.onSelectedTabChange_(); - - this.tabView_.addEventListener( - 'selected-tab-change', this.onSelectedTabChange_); - }, - - createSubViewForSelection_: function(eventTypeName, subSelection, - previousSubView) { - // Find. - var eventTypeInfo = EventRegistry.getEventTypeInfoByTypeName( - eventTypeName); - var singleMode = subSelection.length == 1; - var tagName; - if (subSelection.length === 1) - tagName = eventTypeInfo.metadata.singleViewElementName; - else - tagName = eventTypeInfo.metadata.multiViewElementName; - - if (!tr.ui.b.getPolymerElementNamed(tagName)) - throw new Error('Element not registered: ' + tagName); - - // Create if necessary. - var subView; - if (previousSubView && - previousSubView.tagName === tagName.toUpperCase()) - subView = previousSubView; - else - subView = document.createElement(tagName); - - // Set label. - var camelLabel; - if (subSelection.length === 1) - camelLabel = EventRegistry.getUserFriendlySingularName(eventTypeName); - else - camelLabel = EventRegistry.getUserFriendlyPluralName(eventTypeName); - subView.tabLabel = camelLabel + ' (' + subSelection.length + ')'; - - return subView; - }, - - onSelectedTabChange_: function() { - var brushingStateController = this.brushingStateController_; - if (this.tabView_.selectedTab) { - var selectedTab = this.tabView_.selectedTab; - this.tallMode = selectedTab.requiresTallView; - if (brushingStateController) { - var rlth = selectedTab.relatedEventsToHighlight; - brushingStateController.changeAnalysisViewRelatedEvents(rlth); - } - } else { - this.tallMode = false; - if (brushingStateController) - brushingStateController.changeAnalysisViewRelatedEvents(undefined); - } + this.maybeChangeRelatedEvents_(undefined); + return; } - }); - })(); - </script> -</polymer-element> + + this.tallMode = selectedSubView.requiresTallView; + this.maybeChangeRelatedEvents_(selectedSubView.relatedEventsToHighlight); + }, + + /** Changes the highlighted related events if possible. */ + maybeChangeRelatedEvents_: function(events) { + if (this.brushingStateController) + this.brushingStateController.changeAnalysisViewRelatedEvents(events); + } + }); +})(); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html index 37776f819bd..7f88d256ab5 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/analysis_view_test.html @@ -74,7 +74,7 @@ tr.b.unittest.testSuite(function() { analysisView.brushingStateController = controller; function checkSelectedTab(expectedSelectedTab, expectedRelatedEvents) { - assert.strictEqual(tabView.selectedTab, expectedSelectedTab); + assert.strictEqual(tabView.selectedSubView, expectedSelectedTab); assertEventSet(controller.currentBrushingState.analysisViewRelatedEvents, expectedRelatedEvents); } @@ -99,7 +99,7 @@ tr.b.unittest.testSuite(function() { checkSelectedTab(sampleTab2, []); // 3. Tab selection: single thread slice tab. - tabView.selectedTab = singleThreadSliceTab2; + tabView.selectedSubView = singleThreadSliceTab2; checkSelectedTab(singleThreadSliceTab2, []); // 4. Event selection: one sample, two thread slices, and one @@ -111,8 +111,6 @@ tr.b.unittest.testSuite(function() { checkTab(sampleTab4, 'tr-ui-a-counter-sample-sub-view', [sample3]); - // Reuse tab (same event type and sub-view tag name). - assert.strictEqual(sampleTab4, sampleTab2); var singleRecordTab4 = tabView.tabs[2]; checkTab(singleRecordTab4, 'tr-ui-a-single-user-expectation-sub-view', @@ -125,7 +123,7 @@ tr.b.unittest.testSuite(function() { checkSelectedTab(multiThreadSliceTab4, []); // 5. Tab selection: single user expectation tab. - tabView.selectedTab = singleRecordTab4; + tabView.selectedSubView = singleRecordTab4; checkSelectedTab(singleRecordTab4, [sample1, slice1]); // 6. Event selection: one user expectation. @@ -136,8 +134,6 @@ tr.b.unittest.testSuite(function() { checkTab(singleRecordTab6, 'tr-ui-a-single-user-expectation-sub-view', [record2]); - // Reuse tab (same event type and sub-view tag name). - assert.strictEqual(singleRecordTab6, singleRecordTab4); // Remember selected tab. checkSelectedTab(singleRecordTab6, [sample2, sample3, slice1]); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html index d6a437e775a..ba55bd7739c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view.html @@ -6,27 +6,34 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> -<link rel="import" href="/tracing/model/container_memory_dump.html"> +<link rel="import" href="/tracing/base/unit.html"> +<link rel="import" href="/tracing/model/model.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_header_pane.html"> <link rel="import" href="/tracing/ui/analysis/stacked_pane_view.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-container-memory-dump-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-container-memory-dump-sub-view'> <template> + <style> + tr-ui-b-table { + font-size: 12px; + } + </style> <div id="content"></div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui.analysis', function() { - Polymer('tr-ui-a-container-memory-dump-sub-view', { + Polymer({ + is: 'tr-ui-a-container-memory-dump-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + set selection(selection) { if (selection === undefined) { this.currentSelection_ = undefined; @@ -67,7 +74,7 @@ tr.exportTo('tr.ui.analysis', function() { }, updateContents_: function() { - this.$.content.textContent = ''; + Polymer.dom(this.$.content).textContent = ''; if (this.dumpsByContainerName_ === undefined) return; @@ -87,7 +94,7 @@ tr.exportTo('tr.ui.analysis', function() { tr.b.dictionaryValues(this.dumpsByContainerName_)[0]; var dumpView = this.ownerDocument.createElement( 'tr-ui-a-stacked-pane-view'); - this.$.content.appendChild(dumpView); + Polymer.dom(this.$.content).appendChild(dumpView); dumpView.setPaneBuilder(function() { var headerPane = document.createElement( 'tr-ui-a-memory-dump-header-pane'); @@ -126,22 +133,23 @@ tr.exportTo('tr.ui.analysis', function() { singleDumpValue_: function(row) { var linkEl = ownerDocument.createElement('tr-ui-a-analysis-link'); linkEl.setSelectionAndContent(new tr.model.EventSet([row])); - linkEl.appendChild(tr.v.ui.createScalarSpan(row.start, { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: ownerDocument - })); + Polymer.dom(linkEl).appendChild(tr.v.ui.createScalarSpan( + row.start, { + unit: tr.b.Unit.byName.timeStampInMs, + ownerDocument: ownerDocument + })); return linkEl; }, groupedDumpValue_: function(row) { var linkEl = ownerDocument.createElement('tr-ui-a-analysis-link'); linkEl.setSelectionAndContent(new tr.model.EventSet(row.subRows)); - linkEl.appendChild(tr.ui.b.createSpan({ + Polymer.dom(linkEl).appendChild(tr.ui.b.createSpan({ ownerDocument: ownerDocument, textContent: row.subRows.length + ' memory dump' + (row.subRows.length === 1 ? '' : 's') + ' in ' })); - linkEl.appendChild(tr.ui.b.createSpan({ + Polymer.dom(linkEl).appendChild(tr.ui.b.createSpan({ ownerDocument: ownerDocument, textContent: row.containerName, bold: true @@ -156,10 +164,42 @@ tr.exportTo('tr.ui.analysis', function() { table.tableRows = rows; table.showHeader = false; table.rebuild(); - this.$.content.appendChild(table); + Polymer.dom(this.$.content).appendChild(table); } }); + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-container-memory-dump-sub-view', + tr.model.GlobalMemoryDump, + { + multi: false, + title: 'Global Memory Dump', + }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-container-memory-dump-sub-view', + tr.model.GlobalMemoryDump, + { + multi: true, + title: 'Global Memory Dumps', + }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-container-memory-dump-sub-view', + tr.model.ProcessMemoryDump, + { + multi: false, + title: 'Process Memory Dump', + }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-container-memory-dump-sub-view', + tr.model.ProcessMemoryDump, + { + multi: true, + title: 'Process Memory Dumps', + }); + return {}; }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html index 0619106cd1f..05004a84f99 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/container_memory_dump_sub_view_test.html @@ -27,7 +27,7 @@ tr.b.unittest.testSuite(function() { var viewEl = document.createElement( 'tr-ui-a-container-memory-dump-sub-view'); if (opt_parentElement) - opt_parentElement.appendChild(viewEl); + Polymer.dom(opt_parentElement).appendChild(viewEl); if (selection === undefined) { viewEl.selection = undefined; } else { @@ -281,7 +281,7 @@ tr.b.unittest.testSuite(function() { }, containerEl); // Destroy the first container memory view. - containerEl.textContent = ''; + Polymer.dom(containerEl).textContent = ''; // Create the second container memory view. createAndCheckContainerMemoryDumpView(this, @@ -321,11 +321,11 @@ tr.b.unittest.testSuite(function() { var rows = tableEl.tableRows; var col = tableEl.tableColumns[0]; - assert.equal(col.value(rows[0]).textContent, + assert.equal(Polymer.dom(col.value(rows[0])).textContent, '2 memory dumps in Process 1'); - assert.equal(col.value(rows[1]).textContent, + assert.equal(Polymer.dom(col.value(rows[1])).textContent, '3 memory dumps in Process 2'); - assert.equal(col.value(rows[2]).textContent, + assert.equal(Polymer.dom(col.value(rows[2])).textContent, '1 memory dump in Process 4'); // Check that the analysis link is associated with the right dumps. diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html index 40ae156078c..db03cdb4e30 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/counter_sample_sub_view.html @@ -9,18 +9,20 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/table.html"> -<polymer-element name='tr-ui-a-counter-sample-sub-view' - extends='tr-ui-a-sub-view'> +<dom-module id='tr-ui-a-counter-sample-sub-view'> <template> <style> :host { display: flex; flex-direction: column; } + tr-ui-b-table { + font-size: 12px; + } </style> <tr-ui-b-table id='table'></tr-ui-b-table> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -48,7 +50,10 @@ found in the LICENSE file. } ]; - Polymer('tr-ui-a-counter-sample-sub-view', { + Polymer({ + is: 'tr-ui-a-counter-sample-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + ready: function() { this.currentSelection_ = undefined; this.$.table.tableColumns = COUNTER_SAMPLE_TABLE_COLUMNS; @@ -116,5 +121,21 @@ found in the LICENSE file. }); } }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-counter-sample-sub-view', + tr.model.CounterSample, + { + multi: false, + title: 'Counter Sample', + }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-counter-sample-sub-view', + tr.model.CounterSample, + { + multi: true, + title: 'Counter Samples', + }); })(); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html index 87162a4e023..e86e76f8180 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/frame_power_usage_chart.html @@ -17,11 +17,11 @@ frame. This chart aims to help users understand the shape of the power consumption curve over the course of a frame or set of frames. --> -<polymer-element name="tr-ui-a-frame-power-usage-chart"> +<dom-module id='tr-ui-a-frame-power-usage-chart'> <template> <div id="content"></div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -32,7 +32,9 @@ var CHART_TITLE = 'Power (W) by ms since vertical sync'; // TODO(charliea): Find out how to make this specifiable via CSS. var CHART_WIDTH_FRACTION_OF_BODY = 0.5; -Polymer('tr-ui-a-frame-power-usage-chart', { +Polymer({ + is: 'tr-ui-a-frame-power-usage-chart', + ready: function() { this.chart_ = undefined; this.samples_ = new EventSet(); @@ -71,7 +73,7 @@ Polymer('tr-ui-a-frame-power-usage-chart', { return; this.chart_ = this.createChart_(data); - this.$.content.appendChild(this.chart_); + Polymer.dom(this.$.content).appendChild(this.chart_); }, createChart_: function(data) { @@ -86,8 +88,8 @@ Polymer('tr-ui-a-frame-power-usage-chart', { clearChart_: function() { var content = this.$.content; - while (content.firstChild) - content.removeChild(content.firstChild); + while (Polymer.dom(content).firstChild) + Polymer.dom(content).removeChild(Polymer.dom(content).firstChild); this.chart_ = undefined; }, @@ -123,7 +125,7 @@ Polymer('tr-ui-a-frame-power-usage-chart', { return; var point = { x: sample.start - lastVSyncTimestamp }; - point['f' + frameNumber] = sample.power; + point['f' + frameNumber] = sample.powerInW; points.push(point); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html index 521699ee129..14797a9aa38 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view.html @@ -16,8 +16,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/value/numeric.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<polymer-element name="tr-ui-a-generic-object-view" - is="HTMLUnknownElement"> +<dom-module id='tr-ui-a-generic-object-view'> <template> <style> :host { @@ -28,277 +27,285 @@ found in the LICENSE file. <div id="content"> </div> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +var URL_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; // eslint-disable-line max-len - function isTable(object) { - if (!(object instanceof Array) || - (object.length < 2)) return false; - for (var colName in object[0]) { - if (typeof colName !== 'string') return false; +function isTable(object) { + if (!(object instanceof Array) || + (object.length < 2)) return false; + for (var colName in object[0]) { + if (typeof colName !== 'string') return false; + } + for (var i = 0; i < object.length; ++i) { + if (!(object[i] instanceof Object)) return false; + for (var colName in object[i]) { + if (i && (object[0][colName] === undefined)) return false; + var cellType = typeof object[i][colName]; + if (cellType !== 'string' && cellType !== 'number') return false; } - for (var i = 0; i < object.length; ++i) { - if (!(object[i] instanceof Object)) return false; - for (var colName in object[i]) { - if (i && (object[0][colName] === undefined)) return false; - var cellType = typeof object[i][colName]; - if (cellType !== 'string' && cellType != 'number') return false; - } - if (i) { - for (var colName in object[0]) { - if (object[i][colName] === undefined) return false; - } + if (i) { + for (var colName in object[0]) { + if (object[i][colName] === undefined) return false; } } - return true; } + return true; +} + +Polymer({ + is: 'tr-ui-a-generic-object-view', + + ready: function() { + this.object_ = undefined; + }, + + get object() { + return this.object_; + }, + + set object(object) { + this.object_ = object; + this.updateContents_(); + }, + + updateContents_: function() { + Polymer.dom(this.$.content).textContent = ''; + this.appendElementsForType_('', this.object_, 0, 0, 5, ''); + }, + + appendElementsForType_: function( + label, object, indent, depth, maxDepth, suffix) { + if (depth > maxDepth) { + this.appendSimpleText_( + label, indent, '<recursion limit reached>', suffix); + return; + } - Polymer({ - ready: function() { - this.object_ = undefined; - }, - - get object() { - return this.object_; - }, - - set object(object) { - this.object_ = object; - this.updateContents_(); - }, - - updateContents_: function() { - this.$.content.textContent = ''; - this.appendElementsForType_('', this.object_, 0, 0, 5, ''); - }, - - appendElementsForType_: function( - label, object, indent, depth, maxDepth, suffix) { - if (depth > maxDepth) { - this.appendSimpleText_( - label, indent, '<recursion limit reached>', suffix); - return; - } - - if (object === undefined) { - this.appendSimpleText_(label, indent, 'undefined', suffix); - return; - } + if (object === undefined) { + this.appendSimpleText_(label, indent, 'undefined', suffix); + return; + } - if (object === null) { - this.appendSimpleText_(label, indent, 'null', suffix); - return; - } + if (object === null) { + this.appendSimpleText_(label, indent, 'null', suffix); + return; + } - if (!(object instanceof Object)) { - var type = typeof object; - if (type == 'string') { - var objectReplaced = false; - if ((object[0] == '{' && object[object.length - 1] == '}') || - (object[0] == '[' && object[object.length - 1] == ']')) { - try { - object = JSON.parse(object); - objectReplaced = true; - } catch (e) { - } - } - if (!objectReplaced) { - if (object.indexOf('\n') !== -1) { - var lines = object.split('\n'); - lines.forEach(function(line, i) { - var text, ioff, ll, ss; - if (i == 0) { - text = '"' + line; - ioff = 0; - ll = label; - ss = ''; - } else if (i < lines.length - 1) { - text = line; - ioff = 1; - ll = ''; - ss = ''; - } else { - text = line + '"'; - ioff = 1; - ll = ''; - ss = suffix; - } - - var el = this.appendSimpleText_( - ll, indent + ioff * label.length + ioff, text, ss); - el.style.whiteSpace = 'pre'; - return el; - }, this); - return; - } else { - this.appendSimpleText_( - label, indent, '"' + object + '"', suffix); - return; - } + if (!(object instanceof Object)) { + var type = typeof object; + if (type === 'string') { + var objectReplaced = false; + if ((object[0] === '{' && object[object.length - 1] === '}') || + (object[0] === '[' && object[object.length - 1] === ']')) { + try { + object = JSON.parse(object); + objectReplaced = true; + } catch (e) { } - else { - /* Fall through to the flow below */ + } + if (!objectReplaced) { + if (object.indexOf('\n') !== -1) { + var lines = object.split('\n'); + lines.forEach(function(line, i) { + var text, ioff, ll, ss; + if (i === 0) { + text = '"' + line; + ioff = 0; + ll = label; + ss = ''; + } else if (i < lines.length - 1) { + text = line; + ioff = 1; + ll = ''; + ss = ''; + } else { + text = line + '"'; + ioff = 1; + ll = ''; + ss = suffix; + } + + var el = this.appendSimpleText_( + ll, indent + ioff * label.length + ioff, text, ss); + el.style.whiteSpace = 'pre'; + return el; + }, this); + return; + } else if (object.match(URL_REGEX)) { + var link = document.createElement('a'); + link.href = object; + link.textContent = object; + this.appendElementWithLabel_(label, indent, link, suffix); + return; + } else { + this.appendSimpleText_( + label, indent, '"' + object + '"', suffix); + return; } - } else { - return this.appendSimpleText_(label, indent, object, suffix); } + else { + /* Fall through to the flow below */ + } + } else { + return this.appendSimpleText_(label, indent, object, suffix); } + } - if (object instanceof tr.model.ObjectSnapshot) { - var link = document.createElement('tr-ui-a-analysis-link'); - link.selection = new tr.model.EventSet(object); - this.appendElementWithLabel_(label, indent, link, suffix); - return; - } - - if (object instanceof tr.model.ObjectInstance) { - var link = document.createElement('tr-ui-a-analysis-link'); - link.selection = new tr.model.EventSet(object); - this.appendElementWithLabel_(label, indent, link, suffix); - return; - } + if (object instanceof tr.model.ObjectSnapshot) { + var link = document.createElement('tr-ui-a-analysis-link'); + link.selection = new tr.model.EventSet(object); + this.appendElementWithLabel_(label, indent, link, suffix); + return; + } - if (object instanceof tr.b.Rect) { - this.appendSimpleText_(label, indent, object.toString(), suffix); - return; - } + if (object instanceof tr.model.ObjectInstance) { + var link = document.createElement('tr-ui-a-analysis-link'); + link.selection = new tr.model.EventSet(object); + this.appendElementWithLabel_(label, indent, link, suffix); + return; + } - if (object instanceof tr.v.ScalarNumeric) { - var el = this.ownerDocument.createElement('tr-v-ui-scalar-span'); - el.value = object; - this.appendElementWithLabel_(label, indent, el, suffix); - return; - } + if (object instanceof tr.b.Rect) { + this.appendSimpleText_(label, indent, object.toString(), suffix); + return; + } - if (object instanceof Array) { - this.appendElementsForArray_( - label, object, indent, depth, maxDepth, suffix); - return; - } + if (object instanceof tr.v.ScalarNumeric) { + var el = this.ownerDocument.createElement('tr-v-ui-scalar-span'); + el.value = object; + this.appendElementWithLabel_(label, indent, el, suffix); + return; + } - this.appendElementsForObject_( + if (object instanceof Array) { + this.appendElementsForArray_( label, object, indent, depth, maxDepth, suffix); - }, + return; + } - appendElementsForArray_: function( - label, object, indent, depth, maxDepth, suffix) { - if (object.length == 0) { - this.appendSimpleText_(label, indent, '[]', suffix); - return; - } + this.appendElementsForObject_( + label, object, indent, depth, maxDepth, suffix); + }, - if (isTable(object)) { - var table = document.createElement('tr-ui-b-table'); - var columns = []; - tr.b.iterItems(object[0], function(colName) { - var allStrings = true; - var allNumbers = true; - for (var i = 0; i < object.length; ++i) { - if (typeof(object[i][colName]) !== 'string') - allStrings = false; - - if (typeof(object[i][colName]) !== 'number') - allNumbers = false; - - if (!allStrings && !allNumbers) - break; - } + appendElementsForArray_: function( + label, object, indent, depth, maxDepth, suffix) { + if (object.length === 0) { + this.appendSimpleText_(label, indent, '[]', suffix); + return; + } - var column = {title: colName}; - column.value = function(row) { - return row[colName]; - }; + if (isTable(object)) { + var table = document.createElement('tr-ui-b-table'); + var columns = []; + tr.b.iterItems(object[0], function(colName) { + var allStrings = true; + var allNumbers = true; + for (var i = 0; i < object.length; ++i) { + if (typeof(object[i][colName]) !== 'string') + allStrings = false; + + if (typeof(object[i][colName]) !== 'number') + allNumbers = false; + + if (!allStrings && !allNumbers) + break; + } - if (allStrings) { - column.cmp = function(x, y) { - return x[colName].localeCompare(y[colName]); - }; - } else if (allNumbers) { - column.cmp = function(x, y) { - return x[colName] - y[colName]; - }; - } - columns.push(column); - }); - table.tableColumns = columns; - table.tableRows = object; - this.appendElementWithLabel_(label, indent, table, suffix); - table.rebuild(); - return; - } + var column = {title: colName}; + column.value = function(row) { + return row[colName]; + }; - this.appendElementsForType_( - label + '[', - object[0], - indent, depth + 1, maxDepth, - object.length > 1 ? ',' : ']' + suffix); - for (var i = 1; i < object.length; i++) { - this.appendElementsForType_( - '', - object[i], - indent + label.length + 1, depth + 1, maxDepth, - i < object.length - 1 ? ',' : ']' + suffix); - } + if (allStrings) { + column.cmp = function(x, y) { + return x[colName].localeCompare(y[colName]); + }; + } else if (allNumbers) { + column.cmp = function(x, y) { + return x[colName] - y[colName]; + }; + } + columns.push(column); + }); + table.tableColumns = columns; + table.tableRows = object; + this.appendElementWithLabel_(label, indent, table, suffix); + table.rebuild(); return; - }, - - appendElementsForObject_: function( - label, object, indent, depth, maxDepth, suffix) { - var keys = tr.b.dictionaryKeys(object); - if (keys.length == 0) { - this.appendSimpleText_(label, indent, '{}', suffix); - return; - } + } + this.appendElementsForType_( + label + '[', + object[0], + indent, depth + 1, maxDepth, + object.length > 1 ? ',' : ']' + suffix); + for (var i = 1; i < object.length; i++) { this.appendElementsForType_( - label + '{' + keys[0] + ': ', - object[keys[0]], - indent, depth, maxDepth, - keys.length > 1 ? ',' : '}' + suffix); - for (var i = 1; i < keys.length; i++) { - this.appendElementsForType_( - keys[i] + ': ', - object[keys[i]], - indent + label.length + 1, depth + 1, maxDepth, - i < keys.length - 1 ? ',' : '}' + suffix); - } - }, - - appendElementWithLabel_: function(label, indent, dataElement, suffix) { - var row = document.createElement('div'); - - var indentSpan = document.createElement('span'); - indentSpan.style.whiteSpace = 'pre'; - for (var i = 0; i < indent; i++) - indentSpan.textContent += ' '; - row.appendChild(indentSpan); - - var labelSpan = document.createElement('span'); - labelSpan.textContent = label; - row.appendChild(labelSpan); - - row.appendChild(dataElement); - var suffixSpan = document.createElement('span'); - suffixSpan.textContent = suffix; - row.appendChild(suffixSpan); - - row.dataElement = dataElement; - this.$.content.appendChild(row); - }, + '', + object[i], + indent + label.length + 1, depth + 1, maxDepth, + i < object.length - 1 ? ',' : ']' + suffix); + } + return; + }, + + appendElementsForObject_: function( + label, object, indent, depth, maxDepth, suffix) { + var keys = tr.b.dictionaryKeys(object); + if (keys.length === 0) { + this.appendSimpleText_(label, indent, '{}', suffix); + return; + } - appendSimpleText_: function(label, indent, text, suffix) { - var el = this.ownerDocument.createElement('span'); - el.textContent = text; - this.appendElementWithLabel_(label, indent, el, suffix); - return el; + this.appendElementsForType_( + label + '{' + keys[0] + ': ', + object[keys[0]], + indent, depth, maxDepth, + keys.length > 1 ? ',' : '}' + suffix); + for (var i = 1; i < keys.length; i++) { + this.appendElementsForType_( + keys[i] + ': ', + object[keys[i]], + indent + label.length + 1, depth + 1, maxDepth, + i < keys.length - 1 ? ',' : '}' + suffix); } - }); - </script> -</polymer-element> + }, + + appendElementWithLabel_: function(label, indent, dataElement, suffix) { + var row = document.createElement('div'); + + var indentSpan = document.createElement('span'); + indentSpan.style.whiteSpace = 'pre'; + for (var i = 0; i < indent; i++) + Polymer.dom(indentSpan).textContent += ' '; + Polymer.dom(row).appendChild(indentSpan); + + var labelSpan = document.createElement('span'); + Polymer.dom(labelSpan).textContent = label; + Polymer.dom(row).appendChild(labelSpan); + + Polymer.dom(row).appendChild(dataElement); + var suffixSpan = document.createElement('span'); + Polymer.dom(suffixSpan).textContent = suffix; + Polymer.dom(row).appendChild(suffixSpan); + + row.dataElement = dataElement; + Polymer.dom(this.$.content).appendChild(row); + }, + + appendSimpleText_: function(label, indent, text, suffix) { + var el = this.ownerDocument.createElement('span'); + Polymer.dom(el).textContent = text; + this.appendElementWithLabel_(label, indent, el, suffix); + return el; + } +}); +</script> -<polymer-element name="tr-ui-a-generic-object-view-with-label" - is="HTMLUnknownElement"> +<dom-module id='tr-ui-a-generic-object-view-with-label'> <template> <style> :host { @@ -306,34 +313,35 @@ found in the LICENSE file. } </style> </template> - - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.labelEl_ = document.createElement('div'); - this.genericObjectView_ = - document.createElement('tr-ui-a-generic-object-view'); - this.shadowRoot.appendChild(this.labelEl_); - this.shadowRoot.appendChild(this.genericObjectView_); - }, - - get label() { - return this.labelEl_.textContent; - }, - - set label(label) { - this.labelEl_.textContent = label; - }, - - get object() { - return this.genericObjectView_.object; - }, - - set object(object) { - this.genericObjectView_.object = object; - } - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-generic-object-view-with-label', + + ready: function() { + this.labelEl_ = document.createElement('div'); + this.genericObjectView_ = + document.createElement('tr-ui-a-generic-object-view'); + Polymer.dom(this.root).appendChild(this.labelEl_); + Polymer.dom(this.root).appendChild(this.genericObjectView_); + }, + + get label() { + return Polymer.dom(this.labelEl_).textContent; + }, + + set label(label) { + Polymer.dom(this.labelEl_).textContent = label; + }, + + get object() { + return this.genericObjectView_.object; + }, + + set object(object) { + this.genericObjectView_.object = object; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html index 50997e18622..64b0e04a2fc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/generic_object_view_test.html @@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/object_instance.html"> <link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> <link rel="import" href="/tracing/ui/base/deep_utils.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -18,19 +18,19 @@ tr.b.unittest.testSuite(function() { test('undefinedValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = undefined; - assert.equal(view.$.content.textContent, 'undefined'); + assert.equal(Polymer.dom(view.$.content).textContent, 'undefined'); }); test('nullValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = null; - assert.equal(view.$.content.textContent, 'null'); + assert.equal(Polymer.dom(view.$.content).textContent, 'null'); }); test('stringValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = 'string value'; - assert.equal(view.$.content.textContent, '"string value"'); + assert.equal(Polymer.dom(view.$.content).textContent, '"string value"'); }); test('multiLineStringValue', function() { @@ -65,13 +65,13 @@ tr.b.unittest.testSuite(function() { test('booleanValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = false; - assert.equal(view.$.content.textContent, 'false'); + assert.equal(Polymer.dom(view.$.content).textContent, 'false'); }); test('numberValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = 3.14159; - assert.equal(view.$.content.textContent, '3.14159'); + assert.equal(Polymer.dom(view.$.content).textContent, '3.14159'); }); test('objectSnapshotValue', function() { @@ -179,14 +179,14 @@ tr.b.unittest.testSuite(function() { test('timeDurationValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = - new tr.v.ScalarNumeric(tr.v.Unit.byName.timeDurationInMs, 3); + new tr.v.ScalarNumeric(tr.b.Unit.byName.timeDurationInMs, 3); assert.isDefined(tr.b.findDeepElementMatching( view.$.content, 'tr-v-ui-scalar-span')); }); test('timeStampValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); - view.object = new tr.v.ScalarNumeric(tr.v.Unit.byName.timeStampInMs, 3); + view.object = new tr.v.ScalarNumeric(tr.b.Unit.byName.timeStampInMs, 3); assert.isDefined(tr.b.findDeepElementMatching( view.$.content, 'tr-v-ui-scalar-span')); }); @@ -194,13 +194,23 @@ tr.b.unittest.testSuite(function() { test('scalarValue', function() { var view = document.createElement('tr-ui-a-generic-object-view'); view.object = - new tr.v.ScalarNumeric(tr.v.Unit.byName.normalizedPercentage, .3); + new tr.v.ScalarNumeric(tr.b.Unit.byName.normalizedPercentage, .3); var m = tr.b.findDeepElementMatching( view.$.content, 'tr-v-ui-scalar-span'); assert.isDefined(m); assert.equal(m.value, .3); - assert.equal(m.unit, tr.v.Unit.byName.normalizedPercentage); + assert.equal(m.unit, tr.b.Unit.byName.normalizedPercentage); }); + test('httpLink', function() { + var view = document.createElement('tr-ui-a-generic-object-view'); + var url = 'https://google.com/chrome'; + view.object = {a: url}; + this.addHTMLOutput(view); + var a = tr.b.findDeepElementMatching(view.$.content, 'a'); + assert.isDefined(a); + assert.strictEqual(url, a.href); + assert.strictEqual(url, a.textContent); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html index df1d38264aa..e410eaca58d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane.html @@ -7,17 +7,16 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/range.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/memory_allocator_dump.html"> -<link rel="import" - href="/tracing/ui/analysis/memory_dump_heap_details_pane.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_pane.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/ui/analysis/stacked_pane.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/table.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-memory-dump-allocator-details-pane" - extends="tr-ui-a-stacked-pane"> + +<dom-module id='tr-ui-a-memory-dump-allocator-details-pane'> <template> <style> :host { @@ -54,6 +53,7 @@ found in the LICENSE file. display: none; /* Hide until memory allocator dumps are set. */ flex: 1 0 auto; align-self: stretch; + font-size: 12px; } </style> <div id="label">Component details</div> @@ -62,7 +62,7 @@ found in the LICENSE file. <tr-ui-b-table id="table"></tr-ui-b-table> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -210,7 +210,7 @@ tr.exportTo('tr.ui.analysis', function() { appendSizeIfDefined: function(size) { if (size !== undefined) - this.append(' (', tr.v.Unit.byName.sizeInBytes.format(size), ')'); + this.append(' (', tr.b.Unit.byName.sizeInBytes.format(size), ')'); }, appendSomeTimestampsQuantifier: function() { @@ -492,7 +492,10 @@ tr.exportTo('tr.ui.analysis', function() { } ]; - Polymer('tr-ui-a-memory-dump-allocator-details-pane', { + Polymer({ + is: 'tr-ui-a-memory-dump-allocator-details-pane', + behaviors: [tr.ui.analysis.StackedPane], + created: function() { this.memoryAllocatorDumps_ = undefined; this.heapDumps_ = undefined; @@ -518,7 +521,7 @@ tr.exportTo('tr.ui.analysis', function() { */ set memoryAllocatorDumps(memoryAllocatorDumps) { this.memoryAllocatorDumps_ = memoryAllocatorDumps; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get memoryAllocatorDumps() { @@ -530,19 +533,19 @@ tr.exportTo('tr.ui.analysis', function() { // (view) instead. set heapDumps(heapDumps) { this.heapDumps_ = heapDumps; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, set aggregationMode(aggregationMode) { this.aggregationMode_ = aggregationMode; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get aggregationMode() { return this.aggregationMode_; }, - rebuildPane_: function() { + onRebuild_: function() { if (this.memoryAllocatorDumps_ === undefined || this.memoryAllocatorDumps_.length === 0) { // Show the info text (hide the table). @@ -830,11 +833,16 @@ tr.exportTo('tr.ui.analysis', function() { var titleColumn = new AllocatorDumpNameColumn(); titleColumn.width = '200px'; - var numericColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'numericCells', this.aggregationMode_, NUMERIC_COLUMN_RULES); - var diagnosticColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'diagnosticCells', this.aggregationMode_, - DIAGNOSTIC_COLUMN_RULES); + var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'numericCells', + aggregationMode: this.aggregationMode_, + rules: NUMERIC_COLUMN_RULES + }); + var diagnosticColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'diagnosticCells', + aggregationMode: this.aggregationMode_, + rules: DIAGNOSTIC_COLUMN_RULES + }); var fieldColumns = numericColumns.concat(diagnosticColumns); tr.ui.analysis.MemoryColumn.spaceEqually(fieldColumns); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html index cc0f99ffc81..7c6a8ba4203 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_allocator_details_pane_test.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/core/test_utils.html"> <link rel="import" href="/tracing/model/heap_dump.html"> <link rel="import" href="/tracing/model/memory_allocator_dump.html"> @@ -16,7 +17,6 @@ found in the LICENSE file. href="/tracing/ui/analysis/memory_dump_sub_view_test_utils.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -25,9 +25,9 @@ tr.b.unittest.testSuite(function() { var MemoryAllocatorDump = tr.model.MemoryAllocatorDump; var ScalarNumeric = tr.v.ScalarNumeric; var unitlessNumber_smallerIsBetter = - tr.v.Unit.byName.unitlessNumber_smallerIsBetter; + tr.b.Unit.byName.unitlessNumber_smallerIsBetter; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var HeapDump = tr.model.HeapDump; var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode; var checkNumericFields = tr.ui.analysis.checkNumericFields; @@ -66,7 +66,8 @@ tr.b.unittest.testSuite(function() { } function newSuballocationDump(ownerDump, parentDump, name, size) { - var suballocationDump = addChildDump(parentDump, name, { size: size }); + var suballocationDump = addChildDump(parentDump, name, + {numerics: {size: size}}); if (ownerDump !== undefined) addOwnershipLink(ownerDump, suballocationDump); return suballocationDump; @@ -77,49 +78,51 @@ tr.b.unittest.testSuite(function() { var process = model.getOrCreateProcess(1); // First timestamp. - var gmd1 = addGlobalMemoryDump(model, -10); - var pmd1 = addProcessMemoryDump(gmd1, process, -11); + var gmd1 = addGlobalMemoryDump(model, {ts: -10}); + var pmd1 = addProcessMemoryDump(gmd1, process, {ts: -11}); pmd1.memoryAllocatorDumps = (function() { - var v8Dump = newAllocatorDump(pmd1, 'v8', { + var v8Dump = newAllocatorDump(pmd1, 'v8', {numerics: { size: 1073741824 /* 1 GiB */, inner_size: 2097152 /* 2 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204) - }); + }}); var v8HeapsDump = addChildDump(v8Dump, 'heaps', - { size: 805306368 /* 768 MiB */ }); + {numerics: {size: 805306368 /* 768 MiB */}}); addChildDump(v8HeapsDump, 'heap42', - { size: 804782080 /* 767.5 MiB */ }); + {numerics: {size: 804782080 /* 767.5 MiB */}}); var v8ObjectsDump = addChildDump(v8Dump, 'objects'); v8ObjectsDump.addDiagnostic('url', 'http://example.com'); - addChildDump(v8ObjectsDump, 'foo', { size: 1022976 /* 999 KiB */ }); - addChildDump(v8ObjectsDump, 'bar', { size: 1024000 /* 1000 KiB */ }); + addChildDump(v8ObjectsDump, 'foo', + {numerics: {size: 1022976 /* 999 KiB */}}); + addChildDump(v8ObjectsDump, 'bar', + {numerics: {size: 1024000 /* 1000 KiB */}}); var oilpanDump = newAllocatorDump(pmd1, 'oilpan', - { size: 125829120 /* 120 MiB */ }); + {numerics: {size: 125829120 /* 120 MiB */}}); newSuballocationDump( oilpanDump, v8Dump, '__99BEAD', 150994944 /* 144 MiB */); var oilpanSubDump = addChildDump(oilpanDump, 'animals'); var oilpanSubDump1 = addChildDump(oilpanSubDump, 'cow', - { size: 33554432 /* 32 MiB */ }); + {numerics: {size: 33554432 /* 32 MiB */}}); newSuballocationDump( oilpanSubDump1, v8Dump, '__42BEEF', 67108864 /* 64 MiB */); var oilpanSubDump2 = addChildDump(oilpanSubDump, 'chicken', - { size: 16777216 /* 16 MiB */ }); + {numerics: {size: 16777216 /* 16 MiB */}}); newSuballocationDump( oilpanSubDump2, v8Dump, '__68DEAD', 33554432 /* 32 MiB */); var skiaDump = newAllocatorDump(pmd1, 'skia', - { size: 8388608 /* 8 MiB */ }); + {numerics: {size: 8388608 /* 8 MiB */}}); var suballocationDump = newSuballocationDump( skiaDump, v8Dump, '__15FADE', 16777216 /* 16 MiB */); var ccDump = newAllocatorDump(pmd1, 'cc', - { size: 4194304 /* 4 MiB */ }); + {numerics: {size: 4194304 /* 4 MiB */}}); newSuballocationDump( ccDump, v8Dump, '__12FEED', 5242880 /* 5 MiB */).addDiagnostic( 'url', 'localhost:1234'); @@ -128,25 +131,27 @@ tr.b.unittest.testSuite(function() { })(); // Second timestamp. - var gmd2 = addGlobalMemoryDump(model, 10); - var pmd2 = addProcessMemoryDump(gmd2, process, 11); + var gmd2 = addGlobalMemoryDump(model, {ts: 10}); + var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 11}); pmd2.memoryAllocatorDumps = (function() { - var v8Dump = newAllocatorDump(pmd2, 'v8', { + var v8Dump = newAllocatorDump(pmd2, 'v8', {numerics: { size: 1073741824 /* 1 GiB */, inner_size: 2097152 /* 2 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204) - }); + }}); var v8ObjectsDump = addChildDump(v8Dump, 'objects'); v8ObjectsDump.addDiagnostic('url', 'http://sample.net'); - addChildDump(v8ObjectsDump, 'foo', { size: 1020928 /* 997 KiB */ }); - addChildDump(v8ObjectsDump, 'bar', { size: 1026048 /* 1002 KiB */ }); + addChildDump(v8ObjectsDump, 'foo', + {numerics: {size: 1020928 /* 997 KiB */}}); + addChildDump(v8ObjectsDump, 'bar', + {numerics: {size: 1026048 /* 1002 KiB */}}); newSuballocationDump( undefined, v8Dump, '__99BEAD', 268435456 /* 256 MiB */); var ccDump = newAllocatorDump(pmd2, 'cc', - { size: 7340032 /* 7 MiB */ }); + {numerics: {size: 7340032 /* 7 MiB */}}); newSuballocationDump( ccDump, v8Dump, '__13DEED', 11534336 /* 11 MiB */).addDiagnostic( 'url', 'localhost:5678'); @@ -209,8 +214,8 @@ tr.b.unittest.testSuite(function() { var process = model.getOrCreateProcess(1); for (var i = 0; i < count; i++) { var timestamp = 10 + i; - var gmd = addGlobalMemoryDump(model, timestamp); - pmds[i] = addProcessMemoryDump(gmd, process, timestamp); + var gmd = addGlobalMemoryDump(model, {ts: timestamp}); + pmds[i] = addProcessMemoryDump(gmd, process, {ts: timestamp}); } preFinalizeDumpsCallback(pmds); }); @@ -298,7 +303,7 @@ tr.b.unittest.testSuite(function() { var suballocationsSubRow = rootRow.subRows[2]; checkRow(columns, suballocationsSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'suballocations'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations'); assert.equal(formattedTitle.title, ''); }, size: [135266304], @@ -310,7 +315,7 @@ tr.b.unittest.testSuite(function() { var oilpanSuballocationSubRow = suballocationsSubRow.subRows[0]; checkRow(columns, oilpanSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'oilpan'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'oilpan'); assert.equal(formattedTitle.title, ''); }, size: [125829120], @@ -323,7 +328,7 @@ tr.b.unittest.testSuite(function() { oilpanSuballocationSubRow.subRows[0]; checkRow(columns, oilpanUnspecifiedSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, '<unspecified>'); + assert.equal(Polymer.dom(formattedTitle).textContent, '<unspecified>'); assert.equal(formattedTitle.title, 'v8/__99BEAD'); }, size: [75497472], @@ -334,7 +339,7 @@ tr.b.unittest.testSuite(function() { var oilpanAnimalsSuballocationSubRow = oilpanSuballocationSubRow.subRows[1]; checkRow(columns, oilpanAnimalsSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'animals'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'animals'); assert.equal(formattedTitle.title, ''); }, size: [50331648], @@ -347,7 +352,7 @@ tr.b.unittest.testSuite(function() { oilpanAnimalsSuballocationSubRow.subRows[0]; checkRow(columns, oilpanCowSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'cow'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'cow'); assert.equal(formattedTitle.title, 'v8/__42BEEF'); }, size: [33554432], @@ -358,7 +363,7 @@ tr.b.unittest.testSuite(function() { var skiaSuballocationSubRow = suballocationsSubRow.subRows[1]; checkRow(columns, skiaSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'skia'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'skia'); assert.equal(formattedTitle.title, 'v8/__15FADE'); }, size: [8388608], @@ -369,7 +374,7 @@ tr.b.unittest.testSuite(function() { var ccSuballocationSubRow = suballocationsSubRow.subRows[2]; checkRow(columns, ccSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'cc'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'cc'); assert.equal(formattedTitle.title, 'v8/__12FEED'); }, size: [1048576], @@ -440,7 +445,7 @@ tr.b.unittest.testSuite(function() { var suballocationsSubRow = rootRow.subRows[3]; checkRow(columns, suballocationsSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'suballocations'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations'); assert.equal(formattedTitle.title, ''); }, size: [135266304, 272629760], @@ -452,7 +457,7 @@ tr.b.unittest.testSuite(function() { var oilpanSuballocationSubRow = suballocationsSubRow.subRows[0]; checkRow(columns, oilpanSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'oilpan'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'oilpan'); assert.equal(formattedTitle.title, ''); }, size: [125829120, 268435456], @@ -465,7 +470,7 @@ tr.b.unittest.testSuite(function() { oilpanSuballocationSubRow.subRows[0]; checkRow(columns, oilpanUnspecifiedSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, '<unspecified>'); + assert.equal(Polymer.dom(formattedTitle).textContent, '<unspecified>'); assert.equal(formattedTitle.title, 'v8/__99BEAD'); }, size: [75497472, 268435456], @@ -476,7 +481,7 @@ tr.b.unittest.testSuite(function() { var oilpanAnimalsSuballocationSubRow = oilpanSuballocationSubRow.subRows[1]; checkRow(columns, oilpanAnimalsSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'animals'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'animals'); assert.equal(formattedTitle.title, ''); }, size: [50331648, undefined], @@ -489,7 +494,7 @@ tr.b.unittest.testSuite(function() { oilpanAnimalsSuballocationSubRow.subRows[0]; checkRow(columns, oilpanCowSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'cow'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'cow'); assert.equal(formattedTitle.title, 'v8/__42BEEF'); }, size: [33554432, undefined], @@ -500,7 +505,7 @@ tr.b.unittest.testSuite(function() { var skiaSuballocationSubRow = suballocationsSubRow.subRows[1]; checkRow(columns, skiaSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'skia'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'skia'); assert.equal(formattedTitle.title, 'v8/__15FADE'); }, size: [8388608, undefined], @@ -511,7 +516,7 @@ tr.b.unittest.testSuite(function() { var ccSuballocationSubRow = suballocationsSubRow.subRows[2]; checkRow(columns, ccSuballocationSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'cc'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'cc'); assert.equal(formattedTitle.title, 'v8/__12FEED, v8/__13DEED'); }, size: [1048576, 4194304], @@ -592,7 +597,7 @@ tr.b.unittest.testSuite(function() { var suballocationsSubRow = rootRow.subRows[3]; checkRow(columns, suballocationsSubRow, { title: function(formattedTitle) { - assert.equal(formattedTitle.textContent, 'suballocations'); + assert.equal(Polymer.dom(formattedTitle).textContent, 'suballocations'); assert.equal(formattedTitle.title, ''); }, size: [135266304, undefined, 272629760], @@ -648,7 +653,7 @@ tr.b.unittest.testSuite(function() { // Sub-allocation row. var row = c.formatTitle({title: 'Suballocation row', suballocation: true}); - assert.strictEqual(row.textContent, 'Suballocation row'); + assert.strictEqual(Polymer.dom(row).textContent, 'Suballocation row'); assert.strictEqual(row.style.fontStyle, 'italic'); }); @@ -696,10 +701,10 @@ tr.b.unittest.testSuite(function() { AggregationMode.DIFF); var pmds = buildProcessMemoryDumps(4 /* count */, function(pmds) { addRootDumps(pmds[0], ['v8'], function(v8Dump) { - addChildDump(v8Dump, 'heaps', { size: 64 }); + addChildDump(v8Dump, 'heaps', {numerics: {size: 64}}); }); addRootDumps(pmds[2], ['v8'], function(v8Dump) { - addChildDump(v8Dump, 'heaps', { size: 128 }); + addChildDump(v8Dump, 'heaps', {numerics: {size: 128}}); }); addRootDumps(pmds[3], ['v8'], function(v8Dump) {}); }); @@ -729,28 +734,28 @@ tr.b.unittest.testSuite(function() { AggregationMode.MAX); var pmds = buildProcessMemoryDumps(5 /* count */, function(pmds) { addRootDumps(pmds[0], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); addOwnershipLink(v8HeapsDump, oilpanObjectsDump); }); addRootDumps(pmds[1], ['v8'], function(v8Dump) { - addChildDump(v8Dump, 'heaps', { size: 32 }); + addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); // Missing oilpan/objects dump. }); addRootDumps(pmds[2], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); // Missing v8/heaps dump. }); addRootDumps(pmds[3], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - addChildDump(v8Dump, 'heaps', { size: 32 }); - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); // Missing ownership link. }); addRootDumps(pmds[4], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 2); }); }); @@ -835,44 +840,51 @@ tr.b.unittest.testSuite(function() { AggregationMode.DIFF); var pmds = buildProcessMemoryDumps(6 /* count */, function(pmds) { addRootDumps(pmds[0], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 }); - var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); + var v8QueuesDump = addChildDump(v8Dump, 'queues', + {numerics: {size: 8}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); addOwnershipLink(v8HeapsDump, oilpanObjectsDump); addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1); }); addRootDumps(pmds[1], ['v8'], function(v8Dump) {}); addRootDumps(pmds[2], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 }); - var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 }); - var v8PilesDump = addChildDump(v8Dump, 'piles', { size: 48 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); + var v8QueuesDump = addChildDump(v8Dump, 'queues', + {numerics: {size: 8}}); + var v8PilesDump = addChildDump(v8Dump, 'piles', {numerics: {size: 48}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 2); addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1); addOwnershipLink(v8PilesDump, oilpanObjectsDump); }); addRootDumps(pmds[3], ['v8', 'blink'], function(v8Dump, blinkDump) { - var blinkHandlesDump = addChildDump(blinkDump, 'handles', { size: 32 }); - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 64 }); - var blinkObjectsDump = addChildDump(blinkDump, 'objects', { size: 32 }); + var blinkHandlesDump = addChildDump(blinkDump, 'handles', + {numerics: {size: 32}}); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 64}}); + var blinkObjectsDump = addChildDump(blinkDump, 'objects', + {numerics: {size: 32}}); addOwnershipLink(blinkHandlesDump, v8HeapsDump, -273); addOwnershipLink(v8HeapsDump, blinkObjectsDump, 3); }); addRootDumps(pmds[4], ['v8', 'gpu'], function(v8Dump, gpuDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 64 }); - var gpuTile1Dump = addChildDump(gpuDump, 'tile1', { size: 100 }); - var gpuTile2Dump = addChildDump(gpuDump, 'tile2', { size: 99 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 64}}); + var gpuTile1Dump = addChildDump(gpuDump, 'tile1', + {numerics: {size: 100}}); + var gpuTile2Dump = addChildDump(gpuDump, 'tile2', + {numerics: {size: 99}}); addOwnershipLink(v8HeapsDump, gpuTile1Dump, 3); addOwnershipLink(gpuTile2Dump, gpuTile1Dump, -1); }); addRootDumps(pmds[5], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 32 }); - var v8QueuesDump = addChildDump(v8Dump, 'queues', { size: 8 }); - var v8PilesDump = addChildDump(v8Dump, 'piles', { size: 48 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', {numerics: {size: 32}}); + var v8QueuesDump = addChildDump(v8Dump, 'queues', + {numerics: {size: 8}}); + var v8PilesDump = addChildDump(v8Dump, 'piles', {numerics: {size: 48}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 64 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 64}}); addOwnershipLink(v8HeapsDump, oilpanObjectsDump, 1); addOwnershipLink(v8QueuesDump, oilpanObjectsDump, 1); addOwnershipLink(v8PilesDump, oilpanObjectsDump, 7); @@ -1023,54 +1035,71 @@ tr.b.unittest.testSuite(function() { var pmds = buildProcessMemoryDumps(7 /* count */, function(pmds) { addRootDumps(pmds[0], ['v8'], function(v8Dump) { // Single direct overlap (v8/objects -> v8/heaps). - var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1536 }); - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); + var v8ObjectsDump = addChildDump(v8Dump, 'objects', + {numerics: {size: 1536}}); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); addOwnershipLink(v8ObjectsDump, v8HeapsDump); }); // pmd[1] intentionally skipped. addRootDumps(pmds[2], ['v8'], function(v8Dump, oilpanDump) { // Single direct overlap with inconsistent owned dump size. - var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 3072 }); - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); + var v8ObjectsDump = addChildDump(v8Dump, 'objects', + {numerics: {size: 3072}}); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); addOwnershipLink(v8ObjectsDump, v8HeapsDump); }); addRootDumps(pmds[3], ['v8'], function(v8Dump) { // Single indirect overlap (v8/objects/X -> v8/heaps/42). - var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1536 }); - var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', { size: 512 }); - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); - var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', { size: 1024 }); + var v8ObjectsDump = addChildDump(v8Dump, 'objects', + {numerics: {size: 1536}}); + var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', + {numerics: {size: 512}}); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); + var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', + {numerics: {size: 1024}}); addOwnershipLink(v8ObjectsXDump, v8Heaps42Dump); }); addRootDumps(pmds[4], ['v8'], function(v8Dump) { // Multiple overlaps. - var v8ObjectsDump = addChildDump(v8Dump, 'objects', { size: 1024 }); - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); + var v8ObjectsDump = addChildDump(v8Dump, 'objects', + {numerics: {size: 1024}}); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); - var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', { size: 512 }); - var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', { size: 1280 }); + var v8ObjectsXDump = addChildDump(v8ObjectsDump, 'X', + {numerics: {size: 512}}); + var v8Heaps42Dump = addChildDump(v8HeapsDump, '42', + {numerics: {size: 1280}}); addOwnershipLink(v8ObjectsXDump, v8Heaps42Dump); - var v8ObjectsYDump = addChildDump(v8ObjectsDump, 'Y', { size: 128 }); - var v8Heaps90Dump = addChildDump(v8HeapsDump, '90', { size: 256 }); + var v8ObjectsYDump = addChildDump(v8ObjectsDump, 'Y', + {numerics: {size: 128}}); + var v8Heaps90Dump = addChildDump(v8HeapsDump, '90', + {numerics: {size: 256}}); addOwnershipLink(v8ObjectsYDump, v8Heaps90Dump); - var v8BlocksDump = addChildDump(v8Dump, 'blocks', { size: 768 }); + var v8BlocksDump = addChildDump(v8Dump, 'blocks', + {numerics: {size: 768}}); addOwnershipLink(v8BlocksDump, v8Heaps42Dump); }); addRootDumps(pmds[5], ['v8'], function(v8Dump) { // No overlaps, inconsistent parent size. - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); - addChildDump(v8HeapsDump, '42', { size: 1536 }); - addChildDump(v8HeapsDump, '90', { size: 615 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); + addChildDump(v8HeapsDump, '42', {numerics: {size: 1536}}); + addChildDump(v8HeapsDump, '90', {numerics: {size: 615}}); }); addRootDumps(pmds[6], ['v8', 'oilpan'], function(v8Dump, oilpanDump) { // No overlaps, inconsistent parent and owned dump size. - var v8HeapsDump = addChildDump(v8Dump, 'heaps', { size: 2048 }); - addChildDump(v8HeapsDump, '42', { size: 1536 }); - addChildDump(v8HeapsDump, '90', { size: 615 }); + var v8HeapsDump = addChildDump(v8Dump, 'heaps', + {numerics: {size: 2048}}); + addChildDump(v8HeapsDump, '42', {numerics: {size: 1536}}); + addChildDump(v8HeapsDump, '90', {numerics: {size: 615}}); var oilpanObjectsDump = - addChildDump(oilpanDump, 'objects', { size: 3072 }); + addChildDump(oilpanDump, 'objects', {numerics: {size: 3072}}); addOwnershipLink(oilpanObjectsDump, v8HeapsDump); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html index 7b9ea7ce06e..3033295062f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane.html @@ -5,14 +5,13 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_overview_pane.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/ui/analysis/stacked_pane.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-memory-dump-header-pane" - extends="tr-ui-a-stacked-pane"> +<dom-module id='tr-ui-a-memory-dump-header-pane'> <template> <style> :host { @@ -45,31 +44,33 @@ found in the LICENSE file. <!-- Aggregation mode selector (added in Polymer.ready()) --> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui.analysis', function() { + Polymer({ + is: 'tr-ui-a-memory-dump-header-pane', + behaviors: [tr.ui.analysis.StackedPane], - Polymer('tr-ui-a-memory-dump-header-pane', { created: function() { this.containerMemoryDumps_ = undefined; }, ready: function() { - this.$.aggregation_mode_container.appendChild(tr.ui.b.createSelector( - this, 'aggregationMode', 'memoryDumpHeaderPane.aggregationMode', - tr.ui.analysis.MemoryColumn.AggregationMode.DIFF, - [ - { - label: 'Diff', - value: tr.ui.analysis.MemoryColumn.AggregationMode.DIFF - }, - { - label: 'Max', - value: tr.ui.analysis.MemoryColumn.AggregationMode.MAX - } - ])); + Polymer.dom(this.$.aggregation_mode_container).appendChild( + tr.ui.b.createSelector(this, 'aggregationMode', + 'memoryDumpHeaderPane.aggregationMode', + tr.ui.analysis.MemoryColumn.AggregationMode.DIFF, [ + { + label: 'Diff', + value: tr.ui.analysis.MemoryColumn.AggregationMode.DIFF + }, + { + label: 'Max', + value: tr.ui.analysis.MemoryColumn.AggregationMode.MAX + } + ])); }, /** @@ -89,7 +90,7 @@ tr.exportTo('tr.ui.analysis', function() { */ set containerMemoryDumps(containerMemoryDumps) { this.containerMemoryDumps_ = containerMemoryDumps; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get containerMemoryDumps() { @@ -98,45 +99,46 @@ tr.exportTo('tr.ui.analysis', function() { set aggregationMode(aggregationMode) { this.aggregationMode_ = aggregationMode; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get aggregationMode() { return this.aggregationMode_; }, - rebuildPane_: function() { + onRebuild_: function() { this.updateLabel_(); this.updateAggregationModeSelector_(); this.changeChildPane_(); }, updateLabel_: function() { - this.$.label.textContent = ''; + Polymer.dom(this.$.label).textContent = ''; if (this.containerMemoryDumps_ === undefined || this.containerMemoryDumps_.length <= 0) { - this.$.label.textContent = 'No memory dumps selected'; + Polymer.dom(this.$.label).textContent = 'No memory dumps selected'; return; } var containerDumpCount = this.containerMemoryDumps_.length; var isMultiSelection = containerDumpCount > 1; - this.$.label.appendChild(document.createTextNode( + Polymer.dom(this.$.label).appendChild(document.createTextNode( 'Selected ' + containerDumpCount + ' memory dump' + (isMultiSelection ? 's' : '') + ' in ' + this.containerMemoryDumps_[0].containerName + ' at ')); // TODO(petrcermak): Use <tr-v-ui-scalar-span> once it can be displayed // inline. See https://github.com/catapult-project/catapult/issues/1371. - this.$.label.appendChild(document.createTextNode( - tr.v.Unit.byName.timeStampInMs.format( + Polymer.dom(this.$.label).appendChild(document.createTextNode( + tr.b.Unit.byName.timeStampInMs.format( this.containerMemoryDumps_[0].start))); if (isMultiSelection) { var ELLIPSIS = String.fromCharCode(8230); - this.$.label.appendChild(document.createTextNode(ELLIPSIS)); - this.$.label.appendChild(document.createTextNode( - tr.v.Unit.byName.timeStampInMs.format( + Polymer.dom(this.$.label).appendChild( + document.createTextNode(ELLIPSIS)); + Polymer.dom(this.$.label).appendChild(document.createTextNode( + tr.b.Unit.byName.timeStampInMs.format( this.containerMemoryDumps_[containerDumpCount - 1].start))); } }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html index f3e220605e8..8bdf26243af 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_header_pane_test.html @@ -35,7 +35,7 @@ tr.b.unittest.testSuite(function() { assert.equal(viewEl.aggregationMode, AggregationMode.DIFF); // Check the text in the label. - assert.equal(viewEl.$.label.textContent, expectedLabelText); + assert.equal(Polymer.dom(viewEl.$.label).textContent, expectedLabelText); // Check the visibility of aggregation mode selector. var aggregationModeContainerVisible = diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html new file mode 100644 index 00000000000..90f796799a5 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html @@ -0,0 +1,276 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/color_scheme.html"> +<link rel="import" href="/tracing/base/event.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> +<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html"> +<link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/tab_view.html"> +<link rel="import" href="/tracing/ui/base/table.html"> +<link rel="import" href="/tracing/value/ui/scalar_context_controller.html"> + +<dom-module id='tr-ui-a-memory-dump-heap-details-breakdown-view'> + <template> + <tr-ui-b-tab-view id="tabs"></tr-ui-b-tab-view> + </template> +</dom-module> + +<dom-module id='tr-ui-a-memory-dump-heap-details-breakdown-view-tab'> + <template> + <tr-v-ui-scalar-context-controller></tr-v-ui-scalar-context-controller> + <tr-ui-b-table id="table"></tr-ui-b-table> + </template> +</dom-module> + +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + + /** @constructor */ + function EmptyFillerColumn() {} + + EmptyFillerColumn.prototype = { + title: '', + + value: function() { + return ''; + }, + }; + + Polymer({ + is: 'tr-ui-a-memory-dump-heap-details-breakdown-view', + behaviors: [tr.ui.analysis.RebuildableBehavior], + + created: function() { + this.displayedNode_ = undefined; + this.dimensionToTab_ = new Map(); + }, + + ready: function() { + this.scheduleRebuild_(); + this.root.addEventListener('keydown', this.onKeyDown_.bind(this), true); + }, + + get displayedNode() { + return this.displayedNode_; + }, + + set displayedNode(node) { + this.displayedNode_ = node; + this.scheduleRebuild_(); + }, + + get aggregationMode() { + return this.aggregationMode_; + }, + + set aggregationMode(aggregationMode) { + this.aggregationMode_ = aggregationMode; + for (var tab of this.$.tabs.tabs) + tab.aggregationMode = aggregationMode; + }, + + onRebuild_: function() { + var previouslySelectedTab = this.$.tabs.selectedSubView; + var previouslySelectedTabFocused = false; + var previouslySelectedDimension = undefined; + if (previouslySelectedTab) { + previouslySelectedTabFocused = previouslySelectedTab.isFocused; + previouslySelectedDimension = previouslySelectedTab.dimension; + } + + for (var tab of this.$.tabs.tabs) { + tab.nodes = undefined; + } + this.$.tabs.clearSubViews(); + + if (this.displayedNode_ === undefined) { + this.$.tabs.label = 'No heap node provided.'; + return; + } + + for (var [dimension, children] of this.displayedNode_.childNodes) { + if (!this.dimensionToTab_.has(dimension)) { + this.dimensionToTab_.set(dimension, document.createElement( + 'tr-ui-a-memory-dump-heap-details-breakdown-view-tab')); + } + var tab = this.dimensionToTab_.get(dimension); + tab.aggregationMode = this.aggregationMode_; + tab.dimension = dimension; + tab.nodes = children; + this.$.tabs.addSubView(tab); + tab.rebuild(); + if (dimension === previouslySelectedDimension) { + this.$.tabs.selectedSubView = tab; + if (previouslySelectedTabFocused) + tab.focus(); + } + } + + if (this.$.tabs.tabs.length > 0) + this.$.tabs.label = 'Break selected node further by:'; + else + this.$.tabs.label = 'Selected node cannot be broken down any further.'; + }, + + onKeyDown_: function(keyEvent) { + if (!this.displayedNode_) + return; + + var keyHandled = false; + switch (keyEvent.keyCode) { + case 8: // Backspace. + if (!this.displayedNode_.parentNode) + break; + + // Enter the parent node upon pressing backspace. + var viewEvent = new tr.b.Event('enter-node'); + viewEvent.node = this.displayedNode_.parentNode; + this.dispatchEvent(viewEvent); + keyHandled = true; + break; + + case 37: // Left arrow. + case 39: // Right arrow. + var wasFocused = this.$.tabs.selectedSubView.isFocused; + keyHandled = keyEvent.keyCode === 37 ? + this.$.tabs.selectPreviousTabIfPossible() : + this.$.tabs.selectNextTabIfPossible(); + if (wasFocused && keyHandled) + this.$.tabs.selectedSubView.focus(); // Restore focus to new tab. + } + + if (!keyHandled) + return; + keyEvent.stopPropagation(); + keyEvent.preventDefault(); + } + }); + + Polymer({ + is: 'tr-ui-a-memory-dump-heap-details-breakdown-view-tab', + behaviors: [tr.ui.analysis.RebuildableBehavior], + + created: function() { + this.dimension_ = undefined; + this.nodes_ = undefined; + this.aggregationMode_ = undefined; + }, + + ready: function() { + this.$.table.addEventListener('step-into', function(tableEvent) { + var viewEvent = new tr.b.Event('enter-node'); + viewEvent.node = tableEvent.tableRow; + this.dispatchEvent(viewEvent); + }.bind(this)); + }, + + get dimension() { + return this.dimension_; + }, + + set dimension(dimension) { + this.dimension_ = dimension; + this.scheduleRebuild_(); + }, + + get nodes() { + return this.nodes_; + }, + + set nodes(nodes) { + this.nodes_ = nodes; + this.scheduleRebuild_(); + }, + + get dimensionLabel_() { + if (this.dimension_ === undefined) + return '(undefined)' + return this.dimension_.label; + }, + + get tabLabel() { + var nodeCount = 0; + if (this.nodes_) + nodeCount = this.nodes_.length; + return this.dimensionLabel_ + ' (' + nodeCount + ')'; + }, + + get tabIcon() { + if (this.dimension_ === undefined || + this.dimension_ === tr.ui.analysis.HeapDetailsRowDimension.ROOT) { + return undefined; + } + return { + text: this.dimension_.symbol, + style: 'color: ' + tr.b.ColorScheme.getColorForReservedNameAsString( + this.dimension_.color) + ';' + }; + }, + + get aggregationMode() { + return this.aggregationMode_; + }, + + set aggregationMode(aggregationMode) { + this.aggregationMode_ = aggregationMode; + this.scheduleRebuild_(); + }, + + focus: function() { + this.$.table.focus(); + }, + + blur: function() { + this.$.table.blur(); + }, + + get isFocused() { + return this.$.table.isFocused; + }, + + onRebuild_: function() { + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + this.$.table.emptyValue = 'Cannot break down by ' + + this.dimensionLabel_.toLowerCase() + ' any further.'; + var rows = this.nodes_ || []; + this.$.table.tableRows = rows; + this.$.table.tableColumns = this.createColumns_(rows); + if (this.$.table.sortColumnIndex === undefined) { + this.$.table.sortColumnIndex = 0; + this.$.table.sortDescending = false; + } + this.$.table.rebuild(); + }, + + createColumns_: function(rows) { + var titleColumn = new tr.ui.analysis.HeapDetailsTitleColumn( + this.dimensionLabel_); + titleColumn.width = '200px'; + + var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'cells', + aggregationMode: this.aggregationMode_, + rules: tr.ui.analysis.HEAP_DETAILS_COLUMN_RULES, + shouldSetContextGroup: true + }); + if (numericColumns.length === 0) { + numericColumns.push(new EmptyFillerColumn()); + } + tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns); + + var columns = [titleColumn].concat(numericColumns); + return columns; + } + }); + + return {}; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html index 05d4ad5d689..7b53e66ab5c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane.html @@ -8,16 +8,17 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/color_scheme.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/multi_dimensional_view.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_breakdown_view.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_path_view.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/ui/analysis/stacked_pane.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> -<link rel='import' href='/tracing/ui/base/info_bar.html'> -<link rel="import" href="/tracing/ui/base/table.html"> +<link rel="import" href="/tracing/ui/base/drag_handle.html"> +<link rel="import" href="/tracing/ui/base/info_bar.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-memory-dump-heap-details-pane" - extends="tr-ui-a-stacked-pane"> +<dom-module id='tr-ui-a-memory-dump-heap-details-pane'> <template> <style> :host { @@ -39,7 +40,7 @@ found in the LICENSE file. #label { flex: 1 1 auto; padding: 8px; - font-size: 15px; + font-size: 15px; font-weight: bold; } @@ -63,10 +64,24 @@ found in the LICENSE file. text-align: center; } - #table { + #split_view { display: none; /* Hide until memory allocator dumps are set. */ flex: 1 0 auto; align-self: stretch; + flex-direction: row; + } + + #path_view { + width: 50%; + } + + #breakdown_view { + flex: 1 1 auto; + width: 0; + } + + #path_view, #breakdown_view { + overflow-x: auto; /* Show scrollbar if necessary. */ } </style> <div id="header"> @@ -79,11 +94,19 @@ found in the LICENSE file. <div id="contents"> <tr-ui-b-info-bar id="info_bar" class="info-bar-hidden"> </tr-ui-b-info-bar> + <div id="info_text">No heap dump selected</div> - <tr-ui-b-table id="table"></tr-ui-b-table> + + <div id="split_view"> + <tr-ui-a-memory-dump-heap-details-path-view id="path_view"> + </tr-ui-a-memory-dump-heap-details-path-view> + <tr-ui-b-drag-handle id="drag_handle"></tr-ui-b-drag-handle> + <tr-ui-a-memory-dump-heap-details-breakdown-view id="breakdown_view"> + </tr-ui-a-memory-dump-heap-details-breakdown-view> + </div> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -91,144 +114,203 @@ tr.exportTo('tr.ui.analysis', function() { var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; - var unitlessNumber_smallerIsBetter = - tr.v.Unit.byName.unitlessNumber_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; + var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter; var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder; var TotalState = tr.b.MultiDimensionalViewNode.TotalState; - /** @{enum} */ - var RowDimension = { - ROOT: -1, - STACK_FRAME: 0, - OBJECT_TYPE: 1 - }; - - var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192); - var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9); - /** @{constructor} */ - function HeapDumpNodeTitleColumn(title) { - tr.ui.analysis.TitleColumn.call(this, title); + function HeapDumpTreeNode( + stackFrameNodes, dimension, title, heavyView, parentNode) { + this.dimension = dimension; + this.title = title; + this.parentNode = parentNode; + + this.heavyView_ = heavyView; + this.stackFrameNodes_ = stackFrameNodes; + this.lazyCells_ = undefined; + this.lazyChildNodes_ = undefined; } - HeapDumpNodeTitleColumn.prototype = { - __proto__: tr.ui.analysis.TitleColumn.prototype, - - formatTitle: function(row) { - var title = row.title; - var dimension = row.dimension; - switch (dimension) { - case RowDimension.ROOT: - return title; - - case RowDimension.STACK_FRAME: - case RowDimension.OBJECT_TYPE: - return this.formatSubRow_(title, dimension); - - default: - throw new Error('Invalid row dimension: ' + row.dimension); + HeapDumpTreeNode.prototype = { + get minDisplayedTotalState_() { + if (this.heavyView_) { + // Show lower-bound and exact values in heavy views. + return TotalState.LOWER_BOUND; + } else { + // Show only exact values in tree view. + return TotalState.EXACT; } }, - cmp: function(rowA, rowB) { - if (rowA.dimension !== rowB.dimension) - return rowA.dimension - rowB.dimension; - return tr.ui.analysis.TitleColumn.prototype.cmp.call(this, rowA, rowB); + get childNodes() { + if (!this.lazyChildNodes_) { + this.lazyChildNodes_ = new Map(); + this.addDimensionChildNodes_( + tr.ui.analysis.HeapDetailsRowDimension.STACK_FRAME, 0); + this.addDimensionChildNodes_( + tr.ui.analysis.HeapDetailsRowDimension.OBJECT_TYPE, 1); + this.releaseStackFrameNodesIfPossible_(); + } + return this.lazyChildNodes_; }, - formatSubRow_: function(title, dimension) { - var titleEl = document.createElement('span'); + get cells() { + if (!this.lazyCells_) { + this.addCells_(); + this.releaseStackFrameNodesIfPossible_(); + } + return this.lazyCells_; + }, - var symbolEl = document.createElement('span'); - var symbolColorName; - if (dimension === RowDimension.STACK_FRAME) { - symbolEl.textContent = LATIN_SMALL_LETTER_F_WITH_HOOK; - symbolEl.title = 'Stack frame'; - symbolColorName = 'heap_dump_stack_frame'; - } else { - symbolEl.textContent = CIRCLED_LATIN_CAPITAL_LETTER_T; - symbolEl.title = 'Object type'; - symbolColorName = 'heap_dump_object_type'; + releaseStackFrameNodesIfPossible_: function() { + if (this.lazyCells_ && this.lazyChildNodes_) { + // Don't unnecessarily hold a reference to the stack frame nodes when + // we don't need them anymore. + this.stackFrameNodes_ = undefined; } - symbolEl.style.color = - tr.b.ColorScheme.getColorForReservedNameAsString(symbolColorName); - symbolEl.style.paddingRight = '4px'; - symbolEl.style.cursor = 'help'; - symbolEl.style.weight = 'bold'; - titleEl.appendChild(symbolEl); + }, - titleEl.appendChild(document.createTextNode(title)); + addDimensionChildNodes_: function(dimension, dimensionIndex) { + // Child title -> Timestamp (list index) -> Child + // MultiDimensionalViewNode. + var dimensionChildTitleToStackFrameNodes = tr.b.invertArrayOfDicts( + this.stackFrameNodes_, + node => this.convertStackFrameNodeDimensionToChildDict_( + node, dimensionIndex)); + + // Child title (list index) -> Child HeapDumpTreeNode. + var dimensionChildNodes = []; + tr.b.iterItems(dimensionChildTitleToStackFrameNodes, + function(childTitle, childStackFrameNodes) { + dimensionChildNodes.push(new HeapDumpTreeNode(childStackFrameNodes, + dimension, childTitle, this.heavyView_, this)); + }, this); + this.lazyChildNodes_.set(dimension, dimensionChildNodes); + }, - return titleEl; - } - }; + convertStackFrameNodeDimensionToChildDict_: function( + stackFrameNode, dimensionIndex) { + var childDict = {}; + + var displayedChildrenTotalSize = 0; + var displayedChildrenTotalCount = 0; + var hasDisplayedChildren = false; + var allDisplayedChildrenHaveDisplayedCounts = true; + for (var child of stackFrameNode.children[dimensionIndex].values()) { + if (child.values[0].totalState < this.minDisplayedTotalState_) + continue; + if (child.values[1].totalState < this.minDisplayedTotalState_) + allDisplayedChildrenHaveDisplayedCounts = false; + childDict[child.title[dimensionIndex]] = child; + displayedChildrenTotalSize += child.values[0].total; + displayedChildrenTotalCount += child.values[1].total; + hasDisplayedChildren = true; + } - /** @constructor */ - function AllocationCountColumn(name, cellPath, aggregationMode) { - tr.ui.analysis.DetailsNumericMemoryColumn.call( - this, name, cellPath, aggregationMode); - } + var nodeTotalSize = stackFrameNode.values[0].total; + var nodeTotalCount = stackFrameNode.values[1].total; + + // Add '<other>' node if necessary in tree-view. + var hasUnclassifiedSizeOrCount = + displayedChildrenTotalSize < nodeTotalSize || + displayedChildrenTotalCount < nodeTotalCount; + if (!this.heavyView_ && hasUnclassifiedSizeOrCount && + hasDisplayedChildren) { + var otherTitle = stackFrameNode.title.slice(); + otherTitle[dimensionIndex] = '<other>'; + var otherNode = new tr.b.MultiDimensionalViewNode(otherTitle, 2); + childDict[otherTitle[dimensionIndex]] = otherNode; + + // '<other>' node size. + otherNode.values[0].total = nodeTotalSize - displayedChildrenTotalSize; + otherNode.values[0].totalState = this.minDisplayedTotalState_; + + // '<other>' node allocation count. + otherNode.values[1].total = + nodeTotalCount - displayedChildrenTotalCount; + // Don't show allocation count of the '<other>' node if there is a + // displayed child node that did NOT display allocation count. + otherNode.values[1].totalState = + allDisplayedChildrenHaveDisplayedCounts ? + this.minDisplayedTotalState_ : TotalState.NOT_PROVIDED; + } - AllocationCountColumn.prototype = { - __proto__: tr.ui.analysis.DetailsNumericMemoryColumn.prototype, + return childDict; + }, - getFormattingContext: function(unit) { - return { minimumFractionDigits: 0 }; + addCells_: function() { + // Transform a chronological list of heap stack frame tree nodes into a + // dictionary of cells (where each cell contains a chronological list + // of the values of its numeric). + this.lazyCells_ = tr.ui.analysis.createCells(this.stackFrameNodes_, + function(stackFrameNode) { + var size = stackFrameNode.values[0].total; + var numerics = { + 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size) + }; + var countValue = stackFrameNode.values[1]; + if (countValue.totalState >= this.minDisplayedTotalState_) { + var count = countValue.total; + numerics['Count'] = new ScalarNumeric( + count_smallerIsBetter, count); + numerics['Average size per allocation'] = new ScalarNumeric( + sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count); + } + return numerics; + }, this); } }; - var COLUMN_RULES = [ - { - condition: 'Size', - importance: 3, - columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn - }, - { - condition: 'Count', - importance: 2, - columnConstructor: AllocationCountColumn - }, - { - condition: 'Average size per allocation', - importance: 1, - columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn - }, - { - importance: 0, - columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn - } - ]; + Polymer({ + is: 'tr-ui-a-memory-dump-heap-details-pane', + behaviors: [tr.ui.analysis.StackedPane], - Polymer('tr-ui-a-memory-dump-heap-details-pane', { created: function() { this.heapDumps_ = undefined; - this.aggregationMode_ = undefined; this.viewMode_ = undefined; + this.aggregationMode_ = undefined; }, ready: function() { - this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; this.$.info_bar.message = 'Note: Values displayed in the heavy view ' + 'are lower bounds (except for the root).'; - this.$.view_mode_container.appendChild(tr.ui.b.createSelector( - this, 'viewMode', 'memoryDumpHeapDetailsPane.viewMode', - MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW, - [ - { - label: 'Top-down (Tree)', - value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW - }, - { - label: 'Top-down (Heavy)', - value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW - }, - { - label: 'Bottom-up (Heavy)', - value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW - } - ])); + Polymer.dom(this.$.view_mode_container).appendChild( + tr.ui.b.createSelector( + this, 'viewMode', 'memoryDumpHeapDetailsPane.viewMode', + MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW, + [ + { + label: 'Top-down (Tree)', + value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW + }, + { + label: 'Top-down (Heavy)', + value: + MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW + }, + { + label: 'Bottom-up (Heavy)', + value: + MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW + } + ])); + + this.$.drag_handle.target = this.$.path_view; + this.$.drag_handle.horizontal = false; + + // If the user selects a node in the path view, show its children in the + // breakdown view. + this.$.path_view.addEventListener('selected-node-changed', (function(e) { + this.$.breakdown_view.displayedNode = this.$.path_view.selectedNode; + }).bind(this)); + + // If the user double-clicks on a node in the breakdown view, select the + // node in the path view. + this.$.breakdown_view.addEventListener('enter-node', (function(e) { + this.$.path_view.selectedNode = e.node; + }).bind(this)); }, /** @@ -246,7 +328,7 @@ tr.exportTo('tr.ui.analysis', function() { */ set heapDumps(heapDumps) { this.heapDumps_ = heapDumps; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get heapDumps() { @@ -255,7 +337,8 @@ tr.exportTo('tr.ui.analysis', function() { set aggregationMode(aggregationMode) { this.aggregationMode_ = aggregationMode; - this.scheduleRebuildPane_(); + this.$.path_view.aggregationMode = aggregationMode; + this.$.breakdown_view.aggregationMode = aggregationMode; }, get aggregationMode() { @@ -264,7 +347,7 @@ tr.exportTo('tr.ui.analysis', function() { set viewMode(viewMode) { this.viewMode_ = viewMode; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get viewMode() { @@ -281,36 +364,44 @@ tr.exportTo('tr.ui.analysis', function() { } }, - rebuildPane_: function() { + onRebuild_: function() { if (this.heapDumps_ === undefined || this.heapDumps_.length === 0) { // Show the info text (hide the table and the view mode selector). this.$.info_text.style.display = 'block'; - this.$.table.style.display = 'none'; + this.$.split_view.style.display = 'none'; this.$.view_mode_container.style.display = 'none'; this.$.info_bar.visible = false; - - this.$.table.clear(); - this.$.table.rebuild(); + this.$.path_view.selectedNode = undefined; return; } // Show the table and the view mode selector (hide the info text). this.$.info_text.style.display = 'none'; - this.$.table.style.display = 'block'; + this.$.split_view.style.display = 'flex'; this.$.view_mode_container.style.display = 'block'; // Show the info bar if in heavy view mode. this.$.info_bar.visible = this.heavyView; + this.$.path_view.selectedNode = this.createHeapTree_(); + this.$.path_view.rebuild(); + this.$.breakdown_view.rebuild(); + }, + + createHeapTree_: function() { + var definedHeapDump = tr.b.findFirstInArray(this.heapDumps_); + if (definedHeapDump === undefined) + return undefined; + + // The title of the root node is the name of the allocator. + var rootRowTitle = definedHeapDump.allocatorName; + var stackFrameTrees = this.createStackFrameTrees_(this.heapDumps_); - var rows = this.createRows_(stackFrameTrees); - var columns = this.createColumns_(rows); - this.$.table.tableRows = rows; - this.$.table.tableColumns = columns; - this.$.table.rebuild(); - tr.ui.analysis.expandTableRowsRecursively(this.$.table); + return new HeapDumpTreeNode(stackFrameTrees, + tr.ui.analysis.HeapDetailsRowDimension.ROOT, rootRowTitle, + this.heavyView); }, createStackFrameTrees_: function(heapDumps) { @@ -339,150 +430,9 @@ tr.exportTo('tr.ui.analysis', function() { return builder.buildView(this.viewMode); }, this); - }, - - createRows_: function(stackFrameTrees) { - var definedHeapDump = tr.b.findFirstInArray(this.heapDumps); - if (definedHeapDump === undefined) - return []; - - // The title of the root row is the name of the allocator. - var rootRowTitle = definedHeapDump.allocatorName; - return [this.createHeapRowRecursively_( - stackFrameTrees, RowDimension.ROOT, rootRowTitle)]; - }, - - createHeapRowRecursively_: function(nodes, dimension, title) { - // Transform a chronological list of stack frame tree nodes into a - // dictionary of cells (where each cell contains a chronological list - // of the values of its numeric). - var cells = tr.ui.analysis.createCells(nodes, function(node) { - var size = node.values[0].total; - var row = { - 'Size': new ScalarNumeric(sizeInBytes_smallerIsBetter, size) - }; - var countValue = node.values[1]; - if (countValue.totalState >= this.minDisplayedTotalState_) { - var count = countValue.total; - row['Count'] = new ScalarNumeric(unitlessNumber_smallerIsBetter, - count); - row['Average size per allocation'] = new ScalarNumeric( - sizeInBytes_smallerIsBetter, count === 0 ? 0 : size / count); - } - return row; - }, this); - - var row = { - dimension: dimension, - title: title, - contexts: nodes, - cells: cells - }; - - // Recursively create sub-rows for children (if applicable). - var stackFrameSubRows = this.createHeapDimensionSubRowsRecursively_( - nodes, RowDimension.STACK_FRAME); - var objectTypeSubRows = this.createHeapDimensionSubRowsRecursively_( - nodes, RowDimension.OBJECT_TYPE); - var subRows = stackFrameSubRows.concat(objectTypeSubRows); - if (subRows.length > 0) - row.subRows = subRows; - - return row; - }, - - get minDisplayedTotalState_() { - if (this.heavyView) { - // Show lower-bound and exact values in heavy views. - return TotalState.LOWER_BOUND; - } else { - // Show only exact values in tree view. - return TotalState.EXACT; - } - }, - - createHeapDimensionSubRowsRecursively_: function(nodes, dimension) { - // Sub-row name (list index) -> Timestamp (list index) -> Child - // MultiDimensionalViewNode. - var dimensionGroupedChildNodes = tr.b.dictionaryValues( - tr.b.invertArrayOfDicts(nodes, function(node) { - var childDict = {}; - var displayedChildrenTotalSize = 0; - var displayedChildrenTotalCount = 0; - var hasDisplayedChildren = false; - var allDisplayedChildrenHaveDisplayedCounts = true; - for (var child of node.children[dimension].values()) { - if (child.values[0].totalState < this.minDisplayedTotalState_) - continue; - if (child.values[1].totalState < this.minDisplayedTotalState_) - allDisplayedChildrenHaveDisplayedCounts = false; - childDict[child.title[dimension]] = child; - displayedChildrenTotalSize += child.values[0].total; - displayedChildrenTotalCount += child.values[1].total; - hasDisplayedChildren = true; - } - - var nodeTotalSize = node.values[0].total; - var nodeTotalCount = node.values[1].total; - - // Add '<other>' node if necessary in tree-view. - var hasUnclassifiedSizeOrCount = - displayedChildrenTotalSize < nodeTotalSize || - displayedChildrenTotalCount < nodeTotalCount; - if (!this.heavyView && hasUnclassifiedSizeOrCount && - hasDisplayedChildren) { - var otherTitle = node.title.slice(); - otherTitle[dimension] = '<other>'; - childDict['<other>'] = { - title: otherTitle, - values: [ - { - self: 0, - total: nodeTotalSize - displayedChildrenTotalSize, - totalState: this.minDisplayedTotalState_ - }, - { - self: 0, - total: nodeTotalCount - displayedChildrenTotalCount, - // Don't show allocation count of the '<other>' node if - // there is a displayed child node that did NOT display - // allocation count. - totalState: allDisplayedChildrenHaveDisplayedCounts ? - this.minDisplayedTotalState_ : TotalState.NOT_PROVIDED - } - ], - children: [new Map(), new Map()] - }; - } - - return childDict; - }, this)); - - // Sub-row name (list index) -> Sub-row. - return dimensionGroupedChildNodes.map(function(subRowNodes) { - var subRowTitle = tr.b.findFirstInArray(subRowNodes).title[dimension]; - return this.createHeapRowRecursively_( - subRowNodes, dimension, subRowTitle); - }, this); - }, - - createColumns_: function(rows) { - var titleColumn = new HeapDumpNodeTitleColumn('Stack frame'); - titleColumn.width = '500px'; - - var numericColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'cells', this.aggregationMode_, COLUMN_RULES); - tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns); - - var columns = [titleColumn].concat(numericColumns); - return columns; } - }); + }); - return { - // Exported for testing. - RowDimension: RowDimension, - AllocationCountColumn: AllocationCountColumn - }; + return {}; }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html index 1d1425dfb88..3fdd677213c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_pane_test.html @@ -7,6 +7,7 @@ found in the LICENSE file. <link rel='import' href='/tracing/base/iteration_helpers.html'> <link rel='import' href='/tracing/base/multi_dimensional_view.html'> +<link rel='import' href='/tracing/base/unit.html'> <link rel='import' href='/tracing/core/test_utils.html'> <link rel='import' href='/tracing/model/heap_dump.html'> <link rel='import' href='/tracing/model/memory_dump_test_utils.html'> @@ -15,7 +16,6 @@ found in the LICENSE file. <link rel='import' href='/tracing/ui/analysis/memory_dump_sub_view_test_utils.html'> <link rel='import' href='/tracing/ui/analysis/memory_dump_sub_view_util.html'> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -26,13 +26,12 @@ tr.b.unittest.testSuite(function() { var TOP_DOWN_HEAVY_VIEW = ViewType.TOP_DOWN_HEAVY_VIEW; var BOTTOM_UP_HEAVY_VIEW = ViewType.BOTTOM_UP_HEAVY_VIEW; var HeapDump = tr.model.HeapDump; - var RowDimension = tr.ui.analysis.RowDimension; - var ROOT = RowDimension.ROOT; - var STACK_FRAME = RowDimension.STACK_FRAME; - var OBJECT_TYPE = RowDimension.OBJECT_TYPE; + var HeapDetailsRowDimension = tr.ui.analysis.HeapDetailsRowDimension; + var ROOT = HeapDetailsRowDimension.ROOT; + var STACK_FRAME = HeapDetailsRowDimension.STACK_FRAME; + var OBJECT_TYPE = HeapDetailsRowDimension.OBJECT_TYPE; var TitleColumn = tr.ui.analysis.TitleColumn; var NumericMemoryColumn = tr.ui.analysis.NumericMemoryColumn; - var AllocationCountColumn = tr.ui.analysis.AllocationCountColumn; var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode; var addGlobalMemoryDump = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump; var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump; @@ -40,8 +39,7 @@ tr.b.unittest.testSuite(function() { var checkNumericFields = tr.ui.analysis.checkNumericFields; var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields; var isElementDisplayed = tr.ui.analysis.isElementDisplayed; - var unitlessNumber_smallerIsBetter = - tr.v.Unit.byName.unitlessNumber_smallerIsBetter; + var count_smallerIsBetter = tr.b.Unit.byName.count_smallerIsBetter; function createHeapDumps(withCount) { var model = new tr.Model(); @@ -55,8 +53,8 @@ tr.b.unittest.testSuite(function() { } // First timestamp. - var gmd1 = addGlobalMemoryDump(model, -10); - var pmd1 = addProcessMemoryDump(gmd1, process, -11); + var gmd1 = addGlobalMemoryDump(model, {ts: -10}); + var pmd1 = addProcessMemoryDump(gmd1, process, {ts: -11}); var hd1 = new HeapDump(pmd1, 'partition_alloc'); addHeapEntry(hd1, undefined /* sum over all traces */, @@ -124,8 +122,8 @@ tr.b.unittest.testSuite(function() { undefined /* sum over all types */, 307200 /* 300 KiB */, 300); // Second timestamp. - var gmd2 = addGlobalMemoryDump(model, 10); - var pmd2 = addProcessMemoryDump(gmd2, process, 11); + var gmd2 = addGlobalMemoryDump(model, {ts: 10}); + var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 11}); var hd2 = new HeapDump(pmd2, 'partition_alloc'); addHeapEntry(hd2, undefined /* sum over all traces */, @@ -187,102 +185,103 @@ tr.b.unittest.testSuite(function() { displayExpectations.infoText); assert.strictEqual(isElementDisplayed(viewEl.$.info_bar), displayExpectations.infoBar); - assert.strictEqual(isElementDisplayed(viewEl.$.table), - displayExpectations.tableAndSelector); + assert.strictEqual(isElementDisplayed(viewEl.$.split_view), + displayExpectations.tableAndSplitView); assert.strictEqual(isElementDisplayed(viewEl.$.view_mode_container), - displayExpectations.tableAndSelector); + displayExpectations.tableAndSplitView); } var EXPECTED_COLUMNS_WITHOUT_COUNT = [ - { title: 'Stack frame', type: TitleColumn, noAggregation: true }, + { title: 'Current path', type: TitleColumn, noAggregation: true }, { title: 'Size', type: NumericMemoryColumn } ]; var EXPECTED_COLUMNS_WITH_COUNT = EXPECTED_COLUMNS_WITHOUT_COUNT.concat([ - { title: 'Count', type: AllocationCountColumn }, + { title: 'Count', type: NumericMemoryColumn }, { title: 'Average size per allocation', type: NumericMemoryColumn } ]); - function checkRow(columns, row, expectedDimension, expectedTitle, - expectedSizes, expectedCounts, expectedAverageSizes, - expectedDefinedValues) { - var formattedTitle = columns[0].formatTitle(row); - switch (expectedDimension) { - case ROOT: - assert.equal(formattedTitle, expectedTitle); - break; + var EXPECTED_CELLS = ['Size', 'Count', 'Average size per allocation']; - case STACK_FRAME: - case OBJECT_TYPE: - assert.lengthOf(formattedTitle.childNodes, 2); - assert.strictEqual(formattedTitle.childNodes[0].textContent, - expectedDimension === STACK_FRAME ? '\u0192' : '\u24C9'); - assert.strictEqual( - formattedTitle.childNodes[1].textContent, expectedTitle); - break; + function checkNode(node, expectedNodeStructure, expectedParentNode) { + assert.strictEqual(node.title, expectedNodeStructure.title); + assert.strictEqual(node.dimension, expectedNodeStructure.dimension); + assert.strictEqual(node.parentNode, expectedParentNode); - default: - throw new Error('Invalid expected dimension: ' + expectedDimension); - } + // Check that there AREN'T any cells that we are NOT expecting. + var cells = node.cells; + assert.includeMembers(EXPECTED_CELLS, Object.keys(cells)); - checkSizeNumericFields(row, columns[1], expectedSizes); - if (expectedCounts !== undefined) { - // Test sanity check. - assert.lengthOf(expectedCounts, expectedSizes.length); - assert.lengthOf(expectedAverageSizes, expectedSizes.length); + var sizeCell = cells['Size']; + var sizeFields = sizeCell ? sizeCell.fields : undefined; + checkSizeNumericFields(sizeFields, undefined, expectedNodeStructure.size); - checkNumericFields(row, columns[2], expectedCounts, - unitlessNumber_smallerIsBetter); - checkSizeNumericFields(row, columns[3], expectedAverageSizes); - } else { - // Test sanity check. - assert.lengthOf(columns, EXPECTED_COLUMNS_WITHOUT_COUNT.length); - assert.isUndefined(expectedAverageSizes); - } + var countCell = cells['Count']; + var countFields = countCell ? countCell.fields : undefined; + checkNumericFields(countFields, undefined, expectedNodeStructure.count, + count_smallerIsBetter); - var actualDefinedValues = new Array(row.contexts.length); - for (var i = 0; i < row.contexts.length; i++) - actualDefinedValues[i] = row.contexts[i] !== undefined; - assert.deepEqual(actualDefinedValues, expectedDefinedValues); - } + var averageSizeCell = cells['Average size per allocation']; + var averageSizeFields = averageSizeCell ? averageSizeCell.fields : + undefined; + checkSizeNumericFields(averageSizeFields, undefined, + expectedNodeStructure.averageSize); + + assert.strictEqual(node.childNodes.size, 2); - function checkRows(columns, rows, expectedStructure) { - if (expectedStructure === undefined) { - assert.isUndefined(rows); + // If |expectedNodeStructure.children| is undefined, check that there are + // no child nodes. + if (!expectedNodeStructure.children) { + assert.lengthOf(node.childNodes.get(STACK_FRAME), 0); + assert.lengthOf(node.childNodes.get(OBJECT_TYPE), 0); return; } - if (typeof expectedStructure === 'number') { - assert.lengthOf(rows, expectedStructure); + // If |expectedNodeStructure.children| is just a number, check total number + // of child nodes. + if (typeof expectedNodeStructure.children === 'number') { + assert.strictEqual(expectedNodeStructure.children, + node.childNodes.get(STACK_FRAME).length + + node.childNodes.get(OBJECT_TYPE).length); return; } - assert.lengthOf(rows, expectedStructure.length); + // Check child nodes wrt both dimensions. + checkNodes(node.childNodes.get(STACK_FRAME), + expectedNodeStructure.children.filter(c => c.dimension === STACK_FRAME), + node); + checkNodes(node.childNodes.get(OBJECT_TYPE), + expectedNodeStructure.children.filter(c => c.dimension === OBJECT_TYPE), + node); + } + + function checkNodes(nodes, expectedStructure, expectedParentNode) { + assert.lengthOf(nodes, expectedStructure.length); for (var i = 0; i < expectedStructure.length; i++) { - var row = rows[i]; - var expectedRowStructure = expectedStructure[i]; - checkRow(columns, row, expectedRowStructure.dimension, - expectedRowStructure.title, expectedRowStructure.size, - expectedRowStructure.count, expectedRowStructure.averageSize, - expectedRowStructure.defined); - checkRows(columns, row.subRows, expectedRowStructure.children); + checkNode(nodes[i], expectedStructure[i], expectedParentNode); } } - function checkTable(viewEl, expectedConfig, expectedStructure) { + function checkSplitView(viewEl, expectedConfig, expectedStructure) { checkDisplayedElements(viewEl, { infoText: false, - tableAndSelector: true, + tableAndSplitView: true, infoBar: !!expectedConfig.expectedInfoBarDisplayed }); - var table = viewEl.$.table; - var columns = table.tableColumns; - var rows = table.tableRows; + + // Both the split view and breakdown view should be displaying the same + // node. + var selectedNode = viewEl.$.path_view.selectedNode; + assert.strictEqual(viewEl.$.breakdown_view.displayedNode, selectedNode); + checkNodes([selectedNode], expectedStructure, + undefined /* expectedParentNode */); + + // TODO: Add proper tests for tr-ui-a-memory-dump-heap-details-path-view + // and tr-ui-a-memory-dump-heap-details-breakdown-view. var expectedColumns = expectedConfig.expectedCountColumns ? EXPECTED_COLUMNS_WITH_COUNT : EXPECTED_COLUMNS_WITHOUT_COUNT; - checkColumns(columns, expectedColumns, + checkColumns(viewEl.$.path_view.$.table.tableColumns, expectedColumns, expectedConfig.expectedAggregationMode); - checkRows(columns, rows, expectedStructure); } function changeView(viewEl, viewType) { @@ -290,97 +289,6 @@ tr.b.unittest.testSuite(function() { viewEl.rebuild(); } - /** - * Helper function for generating the expected structures of heap details - * pane tables. Given a table, this function generates its structure. - * - * This avoids the need to write such structures manually, which is very - * tedious. However, the correctness of the generated structures needs to be - * verified by the developer! Maximum line length must also be enforced - * manually. - */ - function printTable(test, viewEl) { - var generator = new tr.c.TestUtils.SourceGenerator(); - - function formatRows(rows) { - generator.formatMultiLineList(rows, function(row) { - generator.push('{'); - generator.indentBlock(2, true /* break line */, function() { - generator.push('dimension: '); - for (var dimensionTitle in RowDimension) { - if (row.dimension === RowDimension[dimensionTitle]) { - generator.push(dimensionTitle); - break; - } - } - generator.push(','); - generator.breakLine(); - - generator.push('title: \'', row.title, '\','); - generator.breakLine(); - - - var sizeFields = row.cells['Size'].fields; - generator.push('size: '); - generator.formatSingleLineList(sizeFields, function(field) { - generator.push( - field === undefined ? 'undefined' : String(field.value)); - }); - generator.push(','); - generator.breakLine(); - - if (row.cells['Count'] !== undefined) { - var countFields = row.cells['Count'].fields; - generator.push('count: '); - generator.formatSingleLineList(countFields, function(field) { - generator.push( - field === undefined ? 'undefined' : String(field.value)); - }); - generator.push(','); - generator.breakLine(); - - generator.push('averageSize: '); - generator.formatSingleLineList(row.cells['Average size'].fields, - function(field, index) { - if (field === undefined) { - generator.push('undefined'); - } else if (field.value === 0) { - generator.push('0'); - } else { - generator.push(String(sizeFields[index].value) + ' / ' + - String(countFields[index].value)); - } - }); - generator.push(','); - generator.breakLine(); - } - - generator.push('defined: '); - generator.formatSingleLineList(sizeFields, function(field) { - generator.push(String(field !== undefined)); - }); - - if (row.subRows && row.subRows.length > 0) { - generator.push(','); - generator.breakLine(); - generator.push('children: '); - formatRows(row.subRows); - } - }); - generator.breakLine(); - generator.push('}'); - }); - } - - generator.indentBlock(8, false /* don't break line */, - formatRows.bind(null, viewEl.$.table.tableRows)); - - tr.c.TestUtils.addSourceListing(test, generator.build()); - - throw new Error('This error is thrown to prevent accidentally ' + - 'checking in a test which calls this function.'); - } - test('instantiate_empty', function() { tr.ui.analysis.createAndCheckEmptyPanes(this, 'tr-ui-a-memory-dump-heap-details-pane', 'heapDumps', @@ -388,7 +296,7 @@ tr.b.unittest.testSuite(function() { // Check that the info text is shown. checkDisplayedElements(viewEl, { infoText: true, - tableAndSelector: false, + tableAndSplitView: false, infoBar: false }); }); @@ -405,7 +313,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); // Top-down tree view (default). - checkTable(viewEl, + checkSplitView(viewEl, { /* empty expectedConfig */ }, [ { @@ -417,7 +325,7 @@ tr.b.unittest.testSuite(function() { ]); changeView(viewEl, TOP_DOWN_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedInfoBarDisplayed: true }, [ { @@ -429,7 +337,7 @@ tr.b.unittest.testSuite(function() { ]); changeView(viewEl, BOTTOM_UP_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedInfoBarDisplayed: true }, [ { @@ -453,7 +361,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); // Top-down tree view (default). - checkTable(viewEl, + checkSplitView(viewEl, { /* empty expectedConfig */ }, [ { @@ -761,7 +669,7 @@ tr.b.unittest.testSuite(function() { ]); changeView(viewEl, BOTTOM_UP_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedInfoBarDisplayed: true }, [ { @@ -1541,7 +1449,7 @@ tr.b.unittest.testSuite(function() { ]); changeView(viewEl, TOP_DOWN_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedInfoBarDisplayed: true }, [ { dimension: ROOT, @@ -2331,7 +2239,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); changeView(viewEl, TOP_DOWN_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedAggregationMode: AggregationMode.DIFF, expectedInfoBarDisplayed: true, @@ -3567,7 +3475,7 @@ tr.b.unittest.testSuite(function() { ]); changeView(viewEl, TOP_DOWN_TREE_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedAggregationMode: AggregationMode.DIFF, expectedCountColumns: true @@ -4047,7 +3955,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); changeView(viewEl, TOP_DOWN_HEAVY_VIEW); - checkTable(viewEl, + checkSplitView(viewEl, { expectedAggregationMode: AggregationMode.MAX, expectedInfoBarDisplayed: true @@ -4075,7 +3983,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); // Top-down tree view (default). - checkTable(viewEl, + checkSplitView(viewEl, { expectedAggregationMode: AggregationMode.DIFF }, [ { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html new file mode 100644 index 00000000000..de5e473049b --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_path_view.html @@ -0,0 +1,149 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/color_scheme.html"> +<link rel="import" href="/tracing/base/event.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_heap_details_util.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> +<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html"> +<link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/table.html"> +<link rel="import" href="/tracing/value/ui/scalar_context_controller.html"> + +<dom-module id='tr-ui-a-memory-dump-heap-details-path-view'> + <template> + <style> + :host { + display: flex; + flex-direction: column; + } + </style> + <tr-v-ui-scalar-context-controller></tr-v-ui-scalar-context-controller> + <tr-ui-b-table id="table"></tr-ui-b-table> + </template> +</dom-module> +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + + var DOWNWARDS_ARROW_WITH_TIP_RIGHTWARDS = String.fromCharCode(0x21B3); + + function HeapDetailsPathColumn(title) { + tr.ui.analysis.HeapDetailsTitleColumn.call(this, title); + } + + HeapDetailsPathColumn.prototype = { + __proto__: tr.ui.analysis.HeapDetailsTitleColumn.prototype, + + formatTitle: function(row) { + var title = tr.ui.analysis.HeapDetailsTitleColumn.prototype. + formatTitle.call(this, row); + if (row.dimension === tr.ui.analysis.HeapDetailsRowDimension.ROOT) + return title; + + var arrowEl = document.createElement('span'); + Polymer.dom(arrowEl).textContent = DOWNWARDS_ARROW_WITH_TIP_RIGHTWARDS; + arrowEl.style.paddingRight = '2px'; + arrowEl.style.fontWeight = 'bold'; + arrowEl.style.color = tr.b.ColorScheme.getColorForReservedNameAsString( + 'heap_dump_child_node_arrow'); + + var rowEl = document.createElement('span'); + Polymer.dom(rowEl).appendChild(arrowEl); + Polymer.dom(rowEl).appendChild(tr.ui.b.asHTMLOrTextNode(title)); + return rowEl; + } + } + + Polymer({ + is: 'tr-ui-a-memory-dump-heap-details-path-view', + behaviors: [tr.ui.analysis.RebuildableBehavior], + + created: function() { + this.selectedNode_ = undefined; + this.aggregationMode_ = undefined; + }, + + ready: function() { + this.$.table.addEventListener('selection-changed', function(event) { + this.selectedNode_ = this.$.table.selectedTableRow; + this.didSelectedNodeChange_(); + }.bind(this)); + }, + + didSelectedNodeChange_: function() { + this.dispatchEvent(new tr.b.Event('selected-node-changed')); + }, + + get selectedNode() { + return this.selectedNode_; + }, + + set selectedNode(node) { + this.selectedNode_ = node; + this.didSelectedNodeChange_(); + this.scheduleRebuild_(); + }, + + get aggregationMode() { + return this.aggregationMode_; + }, + + set aggregationMode(aggregationMode) { + this.aggregationMode_ = aggregationMode; + this.scheduleRebuild_(); + }, + + onRebuild_: function() { + if (this.selectedNode_ === undefined) { + this.$.table.clear(); + return; + } + + if (this.$.table.tableRows.includes(this.selectedNode_)) { + this.$.table.selectedTableRow = this.selectedNode_; + return; + } + + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + this.$.table.userCanModifySortOrder = false; + var rows = this.createRows_(this.selectedNode_); + this.$.table.tableRows = rows; + this.$.table.tableColumns = this.createColumns_(rows); + this.$.table.selectedTableRow = rows[rows.length - 1]; + }, + + createRows_: function(node) { + var rows = []; + while (node) { + rows.push(node); + node = node.parentNode; + } + rows.reverse(); + return rows; + }, + + createColumns_: function(rows) { + var titleColumn = new HeapDetailsPathColumn('Current path'); + titleColumn.width = '200px'; + + var numericColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'cells', + aggregationMode: this.aggregationMode_, + rules: tr.ui.analysis.HEAP_DETAILS_COLUMN_RULES, + shouldSetContextGroup: true + }); + tr.ui.analysis.MemoryColumn.spaceEqually(numericColumns); + + return [titleColumn].concat(numericColumns); + } + }); + + return {}; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html new file mode 100644 index 00000000000..d0c33aca21a --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_heap_details_util.html @@ -0,0 +1,106 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/color_scheme.html"> +<link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> + +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + + var LATIN_SMALL_LETTER_F_WITH_HOOK = String.fromCharCode(0x0192); + var CIRCLED_LATIN_CAPITAL_LETTER_T = String.fromCharCode(0x24C9); + + /** @{enum} */ + var HeapDetailsRowDimension = { + ROOT: {}, + STACK_FRAME: { + label: 'Stack frame', + symbol: LATIN_SMALL_LETTER_F_WITH_HOOK, + color: 'heap_dump_stack_frame' + }, + OBJECT_TYPE: { + label: 'Object type', + symbol: CIRCLED_LATIN_CAPITAL_LETTER_T, + color: 'heap_dump_object_type' + } + }; + + /** @{constructor} */ + function HeapDetailsTitleColumn(title) { + tr.ui.analysis.TitleColumn.call(this, title); + } + + HeapDetailsTitleColumn.prototype = { + __proto__: tr.ui.analysis.TitleColumn.prototype, + + formatTitle: function(row) { + if (row.dimension === HeapDetailsRowDimension.ROOT) + return row.title; + + var symbolEl = document.createElement('span'); + Polymer.dom(symbolEl).textContent = row.dimension.symbol; + symbolEl.title = row.dimension.label; + symbolEl.style.color = tr.b.ColorScheme.getColorForReservedNameAsString( + row.dimension.color); + symbolEl.style.paddingRight = '4px'; + symbolEl.style.cursor = 'help'; + symbolEl.style.fontWeight = 'bold'; + + var titleEl = document.createElement('span'); + Polymer.dom(titleEl).appendChild(symbolEl); + Polymer.dom(titleEl).appendChild(document.createTextNode(row.title)); + + return titleEl; + } + }; + + /** @constructor */ + function AllocationCountColumn(name, cellPath, aggregationMode) { + tr.ui.analysis.DetailsNumericMemoryColumn.call( + this, name, cellPath, aggregationMode); + } + + AllocationCountColumn.prototype = { + __proto__: tr.ui.analysis.DetailsNumericMemoryColumn.prototype, + + getFormattingContext: function(unit) { + return { minimumFractionDigits: 0 }; + } + }; + + var HEAP_DETAILS_COLUMN_RULES = [ + { + condition: 'Size', + importance: 3, + columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn + }, + { + condition: 'Count', + importance: 2, + columnConstructor: AllocationCountColumn + }, + { + condition: 'Average size per allocation', + importance: 1, + columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn + }, + { + importance: 0, + columnConstructor: tr.ui.analysis.DetailsNumericMemoryColumn + } + ]; + + return { + HeapDetailsRowDimension: HeapDetailsRowDimension, + HeapDetailsTitleColumn: HeapDetailsTitleColumn, + AllocationCountColumn: AllocationCountColumn, + HEAP_DETAILS_COLUMN_RULES: HEAP_DETAILS_COLUMN_RULES + }; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html index 9f2152d1106..31118444e36 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane.html @@ -7,6 +7,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/color_scheme.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> +<link rel="import" href="/tracing/base/unit_scale.html"> <link rel="import" href="/tracing/model/memory_allocator_dump.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_allocator_details_pane.html"> @@ -19,11 +21,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/view_specific_brushing_state.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> -<link rel="import" href="/tracing/value/unit_scale.html"> -<polymer-element name="tr-ui-a-memory-dump-overview-pane" - extends="tr-ui-a-stacked-pane"> +<dom-module id='tr-ui-a-memory-dump-overview-pane'> <template> <style> :host { @@ -47,6 +46,7 @@ found in the LICENSE file. flex: 1 0 auto; align-self: stretch; font-size: 12px; + overflow: auto; } #info_text { @@ -60,6 +60,7 @@ found in the LICENSE file. display: none; /* Hide until memory dumps are set. */ flex: 1 0 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-view-specific-brushing-state id="state" @@ -71,7 +72,7 @@ found in the LICENSE file. <tr-ui-b-table id="table"></tr-ui-b-table> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -80,7 +81,7 @@ tr.exportTo('tr.ui.analysis', function() { var ColorScheme = tr.b.ColorScheme; var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var PLATFORM_SPECIFIC_TOTAL_NAME_SUFFIX = '_bytes'; @@ -150,7 +151,7 @@ tr.exportTo('tr.ui.analysis', function() { }, getFormattingContext: function(unit) { - return { unitPrefix: tr.v.UnitScale.Binary.MEBI }; + return { unitPrefix: tr.b.UnitScale.Binary.MEBI }; }, color: function(numerics, processMemoryDumps) { @@ -341,7 +342,7 @@ tr.exportTo('tr.ui.analysis', function() { }, getFormattingContext: function(unit) { - return { unitPrefix: tr.v.UnitScale.Binary.MEBI }; + return { unitPrefix: tr.b.UnitScale.Binary.MEBI }; }, addInfos: function(numerics, processMemoryDumps, infos) { @@ -455,7 +456,10 @@ tr.exportTo('tr.ui.analysis', function() { } ]; - Polymer('tr-ui-a-memory-dump-overview-pane', { + Polymer({ + is: 'tr-ui-a-memory-dump-overview-pane', + behaviors: [tr.ui.analysis.StackedPane], + created: function() { this.processMemoryDumps_ = undefined; this.aggregationMode_ = undefined; @@ -490,7 +494,7 @@ tr.exportTo('tr.ui.analysis', function() { */ set processMemoryDumps(processMemoryDumps) { this.processMemoryDumps_ = processMemoryDumps; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get processMemoryDumps() { @@ -499,7 +503,7 @@ tr.exportTo('tr.ui.analysis', function() { set aggregationMode(aggregationMode) { this.aggregationMode_ = aggregationMode; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get aggregationMode() { @@ -548,7 +552,7 @@ tr.exportTo('tr.ui.analysis', function() { return selectedColumn.getChildPaneBuilder(selectedTableRow.contexts); }, - rebuildPane_: function() { + onRebuild_: function() { if (this.processMemoryDumps_ === undefined || this.processMemoryDumps_.length === 0) { // Show the info text (hide the table). @@ -685,13 +689,17 @@ tr.exportTo('tr.ui.analysis', function() { var titleColumn = new ProcessNameColumn(); titleColumn.width = '200px'; - var usedMemorySizeColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'usedMemoryCells', this.aggregationMode_, - UsedMemoryColumn.RULES); + var usedMemorySizeColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'usedMemoryCells', + aggregationMode: this.aggregationMode_, + rules: UsedMemoryColumn.RULES + }); - var allocatorSizeColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'allocatorCells', this.aggregationMode_, - AllocatorColumn.RULES); + var allocatorSizeColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'allocatorCells', + aggregationMode: this.aggregationMode_, + rules: AllocatorColumn.RULES + }); var sizeColumns = usedMemorySizeColumns.concat(allocatorSizeColumns); tr.ui.analysis.MemoryColumn.spaceEqually(sizeColumns); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html index bb377bba241..f4bfbfb68f3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_overview_pane_test.html @@ -22,7 +22,7 @@ found in the LICENSE file. tr.b.unittest.testSuite(function() { var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var MemoryAllocatorDump = tr.model.MemoryAllocatorDump; var HeapDump = tr.model.HeapDump; var AggregationMode = tr.ui.analysis.MemoryColumn.AggregationMode; @@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() { return function(actualTitle) { assert.instanceOf(actualTitle, HTMLElement); assert.strictEqual(actualTitle.tagName, 'SPAN'); - assert.strictEqual(actualTitle.textContent, expectedTitle); + assert.strictEqual(Polymer.dom(actualTitle).textContent, expectedTitle); }; } @@ -115,7 +115,7 @@ tr.b.unittest.testSuite(function() { function checkSpanWithColor(span, expectedText, expectedColorReservedName) { assert.strictEqual(span.tagName, 'SPAN'); - assert.strictEqual(span.textContent, expectedText); + assert.strictEqual(Polymer.dom(span).textContent, expectedText); checkColor(span.style.color, expectedColorReservedName); } @@ -168,9 +168,9 @@ tr.b.unittest.testSuite(function() { var process = model.getOrCreateProcess(1); fieldAndDumpMask.forEach(function(mask, i) { var timestamp = 10 + i; - var gmd = addGlobalMemoryDump(model, timestamp); + var gmd = addGlobalMemoryDump(model, {ts: timestamp}); if (mask & DUMP) { - var pmd = addProcessMemoryDump(gmd, process, timestamp); + var pmd = addProcessMemoryDump(gmd, process, {ts: timestamp}); dumpCreatedCallback(pmd, mask); } }); @@ -372,8 +372,8 @@ tr.b.unittest.testSuite(function() { var viewEl = tr.ui.analysis.createTestPane('tr-ui-a-memory-dump-overview-pane'); var table = viewEl.$.table; - containerEl.textContent = ''; - containerEl.appendChild(viewEl); + Polymer.dom(containerEl).textContent = ''; + Polymer.dom(containerEl).appendChild(viewEl); var displayedProcessMemoryDumps = processMemoryDumps.map( function(memoryDumps) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html index 36235636c56..57c2dafc1c6 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_test_utils.html @@ -7,6 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/color.html"> <link rel="import" href="/tracing/base/color_scheme.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/core/test_utils.html"> <link rel="import" href="/tracing/model/global_memory_dump.html"> <link rel="import" href="/tracing/model/heap_dump.html"> @@ -14,7 +15,6 @@ found in the LICENSE file. <link rel="import" href="/tracing/model/process_memory_dump.html"> <link rel="import" href="/tracing/model/vm_region.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -31,9 +31,9 @@ tr.exportTo('tr.ui.analysis', function() { var VMRegionClassificationNode = tr.model.VMRegionClassificationNode; var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var unitlessNumber_smallerIsBetter = - tr.v.Unit.byName.unitlessNumber_smallerIsBetter; + tr.b.Unit.byName.unitlessNumber_smallerIsBetter; var HeapDump = tr.model.HeapDump; var addGlobalMemoryDump = tr.model.MemoryDumpTestUtils.addGlobalMemoryDump; var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump; @@ -50,11 +50,11 @@ tr.exportTo('tr.ui.analysis', function() { // ====================================================================== // First timestamp. // ====================================================================== - var gmd1 = addGlobalMemoryDump(model, 42); + var gmd1 = addGlobalMemoryDump(model, {ts: 42}); // Totals and VM regions. - var pmd1A = addProcessMemoryDump(gmd1, pA, 41); - pmd1A.totals = { residentBytes: 31457280 /* 30 MiB */ }; + var pmd1A = addProcessMemoryDump(gmd1, pA, {ts: 41}); + pmd1A.totals = {residentBytes: 31457280 /* 30 MiB */}; pmd1A.vmRegions = VMRegionClassificationNode.fromRegions([ VMRegion.fromDict({ startAddress: 1024, @@ -70,7 +70,7 @@ tr.exportTo('tr.ui.analysis', function() { ]); // Everything. - var pmd1B = addProcessMemoryDump(gmd1, pB, 42); + var pmd1B = addProcessMemoryDump(gmd1, pB, {ts: 42}); pmd1B.totals = { residentBytes: 20971520, /* 20 MiB */ peakResidentBytes: 41943040, /* 40 MiB */ @@ -105,27 +105,28 @@ tr.exportTo('tr.ui.analysis', function() { }) ]); pmd1B.memoryAllocatorDumps = [ - newAllocatorDump(pmd1B, 'malloc', { size: 3145728 /* 3 MiB */ }), - newAllocatorDump(pmd1B, 'v8', { size: 5242880 /* 5 MiB */ }), - newAllocatorDump(pmd1B, 'tracing', { + newAllocatorDump(pmd1B, 'malloc', + {numerics: {size: 3145728 /* 3 MiB */}}), + newAllocatorDump(pmd1B, 'v8', {numerics: {size: 5242880 /* 5 MiB */}}), + newAllocatorDump(pmd1B, 'tracing', {numerics: { size: 1048576 /* 1 MiB */, resident_size: 1572864 /* 1.5 MiB */ - }) + }}) ]; // Allocator dumps only. - var pmd1C = addProcessMemoryDump(gmd1, pC, 43); + var pmd1C = addProcessMemoryDump(gmd1, pC, {ts: 43}); pmd1C.memoryAllocatorDumps = (function() { - var oilpanDump = newAllocatorDump(pmd1C, 'oilpan', { + var oilpanDump = newAllocatorDump(pmd1C, 'oilpan', {numerics: { size: 3221225472 /* 3 GiB */, inner_size: 5242880 /* 5 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 2015) - }); - var v8Dump = newAllocatorDump(pmd1C, 'v8', { + }}); + var v8Dump = newAllocatorDump(pmd1C, 'v8', {numerics: { size: 1073741824 /* 1 GiB */, inner_size: 2097152 /* 2 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204) - }); + }}); addOwnershipLink(v8Dump, oilpanDump); @@ -146,11 +147,11 @@ tr.exportTo('tr.ui.analysis', function() { // ====================================================================== // Second timestamp. // ====================================================================== - var gmd2 = addGlobalMemoryDump(model, 68); + var gmd2 = addGlobalMemoryDump(model, {ts: 68}); // Everything. - var pmd2A = addProcessMemoryDump(gmd2, pA, 67); - pmd2A.totals = { residentBytes: 32505856 /* 31 MiB */ }; + var pmd2A = addProcessMemoryDump(gmd2, pA, {ts: 67}); + pmd2A.totals = {residentBytes: 32505856 /* 31 MiB */}; pmd2A.vmRegions = VMRegionClassificationNode.fromRegions([ VMRegion.fromDict({ startAddress: 1024, @@ -176,15 +177,17 @@ tr.exportTo('tr.ui.analysis', function() { }) ]); pmd2A.memoryAllocatorDumps = [ - newAllocatorDump(pmd2A, 'malloc', { size: 9437184 /* 9 MiB */ }), - newAllocatorDump(pmd2A, 'tracing', { + newAllocatorDump(pmd2A, 'malloc', {numerics: { + size: 9437184 /* 9 MiB */ + }}), + newAllocatorDump(pmd2A, 'tracing', {numerics: { size: 2097152 /* 2 MiB */, resident_size: 2621440 /* 2.5 MiB */ - }) + }}) ]; // Totals and allocator dumps only. - var pmd2B = addProcessMemoryDump(gmd2, pB, 69); + var pmd2B = addProcessMemoryDump(gmd2, pB, {ts: 69}); pmd2B.totals = { residentBytes: 19922944, /* 19 MiB */ peakResidentBytes: 41943040, /* 40 MiB */ @@ -194,19 +197,27 @@ tr.exportTo('tr.ui.analysis', function() { } }; pmd2B.memoryAllocatorDumps = [ - newAllocatorDump(pmd2B, 'malloc', { size: 2621440 /* 2.5 MiB */ }), - newAllocatorDump(pmd2B, 'v8', { size: 5242880 /* 5 MiB */ }), - newAllocatorDump(pmd2B, 'blink', { size: 7340032 /* 7 MiB */ }), - newAllocatorDump(pmd2B, 'oilpan', { size: 1 }), - newAllocatorDump(pmd2B, 'tracing', { + newAllocatorDump(pmd2B, 'malloc', {numerics: { + size: 2621440 /* 2.5 MiB */ + }}), + newAllocatorDump(pmd2B, 'v8', {numerics: { + size: 5242880 /* 5 MiB */ + }}), + newAllocatorDump(pmd2B, 'blink', {numerics: { + size: 7340032 /* 7 MiB */ + }}), + newAllocatorDump(pmd2B, 'oilpan', {numerics: {size: 1}}), + newAllocatorDump(pmd2B, 'tracing', {numerics: { size: 1572864 /* 1.5 MiB */, resident_size: 2097152 /* 2 MiB */ - }), - newAllocatorDump(pmd2B, 'gpu', { memtrack_pss: 524288 /* 512 KiB */ }) + }}), + newAllocatorDump(pmd2B, 'gpu', {numerics: { + memtrack_pss: 524288 /* 512 KiB */ + }}) ]; // Resettable peak total size only. - var pmd2D = addProcessMemoryDump(gmd2, pD, 71); + var pmd2D = addProcessMemoryDump(gmd2, pD, {ts: 71}); pmd2D.totals = { peakResidentBytes: 17825792, /* 17 MiB */ arePeakResidentBytesResettable: true @@ -215,10 +226,10 @@ tr.exportTo('tr.ui.analysis', function() { // ====================================================================== // Third timestamp. // ====================================================================== - var gmd3 = addGlobalMemoryDump(model, 100); + var gmd3 = addGlobalMemoryDump(model, {ts: 100}); // Everything. - var pmd3B = addProcessMemoryDump(gmd3, pB, 102); + var pmd3B = addProcessMemoryDump(gmd3, pB, {ts: 102}); pmd3B.totals = { residentBytes: 18874368, /* 18 MiB */ peakResidentBytes: 44040192, /* 42 MiB */ @@ -242,32 +253,38 @@ tr.exportTo('tr.ui.analysis', function() { }) ]); pmd3B.memoryAllocatorDumps = [ - newAllocatorDump(pmd3B, 'malloc', {size: 2883584 /* 2.75 MiB */ }), - newAllocatorDump(pmd3B, 'v8', { size: 5767168 /* 5.5 MiB */ }), - newAllocatorDump(pmd3B, 'blink', { size: 6291456 /* 7 MiB */ }), - newAllocatorDump(pmd3B, 'tracing', { + newAllocatorDump(pmd3B, 'malloc', {numerics: { + size: 2883584 /* 2.75 MiB */ + }}), + newAllocatorDump(pmd3B, 'v8', {numerics: { + size: 5767168 /* 5.5 MiB */ + }}), + newAllocatorDump(pmd3B, 'blink', {numerics: { + size: 6291456 /* 7 MiB */ + }}), + newAllocatorDump(pmd3B, 'tracing', {numerics: { size: 2097152 /* 2 MiB */, resident_size: 3145728 /* 3 MiB */ - }), - newAllocatorDump(pmd3C, 'gpu', { + }}), + newAllocatorDump(pmd3C, 'gpu', {numerics: { size: 1048576 /* 1 MiB */, memtrack_pss: 786432 /* 768 KiB */ - }) + }}) ]; // Allocator dumps only. - var pmd3C = addProcessMemoryDump(gmd3, pC, 100); + var pmd3C = addProcessMemoryDump(gmd3, pC, {ts: 100}); pmd3C.memoryAllocatorDumps = (function() { - var oilpanDump = newAllocatorDump(pmd3C, 'oilpan', { + var oilpanDump = newAllocatorDump(pmd3C, 'oilpan', {numerics: { size: 3221225472 /* 3 GiB */, inner_size: 5242880 /* 5 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 2015) - }); - var v8Dump = newAllocatorDump(pmd3C, 'v8', { + }}); + var v8Dump = newAllocatorDump(pmd3C, 'v8', {numerics: { size: 2147483648 /* 2 GiB */, inner_size: 2097152 /* 2 MiB */, objects_count: new ScalarNumeric(unitlessNumber_smallerIsBetter, 204) - }); + }}); addOwnershipLink(v8Dump, oilpanDump); @@ -291,7 +308,7 @@ tr.exportTo('tr.ui.analysis', function() { }; // Resettable peak total size only. - var pmd3D = addProcessMemoryDump(gmd3, pD, 99); + var pmd3D = addProcessMemoryDump(gmd3, pD, {ts: 99}); pmd3D.totals = { peakResidentBytes: 17825792, /* 17 MiB */ arePeakResidentBytesResettable: true diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html index 74a38e81cda..1dc7c2f5f26 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util.html @@ -103,12 +103,14 @@ tr.exportTo('tr.ui.analysis', function() { var prefixEl = tr.ui.b.createSpan({textContent: prefix}); // Enforce same width of '+++' and '---'. prefixEl.style.fontFamily = 'monospace'; - titleEl.appendChild(prefixEl); - titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(NO_BREAK_SPACE)); + Polymer.dom(titleEl).appendChild(prefixEl); + Polymer.dom(titleEl).appendChild( + tr.ui.b.asHTMLOrTextNode(NO_BREAK_SPACE)); } if (color !== undefined) titleEl.style.color = color; - titleEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedTitle)); + Polymer.dom(titleEl).appendChild( + tr.ui.b.asHTMLOrTextNode(formattedTitle)); return titleEl; }, @@ -133,6 +135,7 @@ tr.exportTo('tr.ui.analysis', function() { function MemoryColumn(name, cellPath, aggregationMode) { this.name = name; this.cellPath = cellPath; + this.shouldSetContextGroup = false; // See MemoryColumn.AggregationMode enum in this file. this.aggregationMode = aggregationMode; @@ -191,15 +194,26 @@ tr.exportTo('tr.ui.analysis', function() { * [least important, right in the resulting table] * * where columns will be sorted alphabetically within each group. + * + * @param {!Array.<!Object>} rows + * @param {!Object} config + * @param {string} config.cellKey + * @param {!MemoryColumn.AggregationMode=} config.aggregationMode + * @param {!Array.<!{ + * condition: (string|!RegExp)=, + * importance: number, + * columnConstructor: !function(new: MemoryColumn, ...)=, + * shouldSetContextGroup: boolean= + * }>} config.rules */ - MemoryColumn.fromRows = function(rows, cellKey, aggregationMode, rules) { + MemoryColumn.fromRows = function(rows, config) { // Recursively find the names of all cells of the rows (and their sub-rows). var cellNames = new Set(); function gatherCellNames(rows) { rows.forEach(function(row) { if (row === undefined) return; - var fieldCells = row[cellKey]; + var fieldCells = row[config.cellKey]; if (fieldCells !== undefined) { tr.b.iterItems(fieldCells, function(fieldName, fieldCell) { if (fieldCell === undefined || fieldCell.fields === undefined) @@ -218,10 +232,11 @@ tr.exportTo('tr.ui.analysis', function() { // their importance. var positions = []; cellNames.forEach(function(cellName) { - var cellPath = [cellKey, cellName]; - var matchingRule = MemoryColumn.findMatchingRule(cellName, rules); + var cellPath = [config.cellKey, cellName]; + var matchingRule = MemoryColumn.findMatchingRule(cellName, config.rules); var constructor = matchingRule.columnConstructor; - var column = new constructor(cellName, cellPath, aggregationMode); + var column = new constructor(cellName, cellPath, config.aggregationMode); + column.shouldSetContextGroup = !!config.shouldSetContextGroup; positions.push({ importance: matchingRule.importance, column: column @@ -331,7 +346,8 @@ tr.exportTo('tr.ui.analysis', function() { fieldEl.style.display = 'flex'; fieldEl.style.alignItems = 'center'; fieldEl.style.justifyContent = 'flex-end'; - fieldEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedFields)); + Polymer.dom(fieldEl).appendChild( + tr.ui.b.asHTMLOrTextNode(formattedFields)); // Add info icons with tooltips. infos.forEach(function(info) { @@ -339,11 +355,11 @@ tr.exportTo('tr.ui.analysis', function() { infoEl.style.paddingLeft = '4px'; infoEl.style.cursor = 'help'; infoEl.style.fontWeight = 'bold'; - infoEl.textContent = info.icon; + Polymer.dom(infoEl).textContent = info.icon; if (info.color !== undefined) infoEl.style.color = info.color; infoEl.title = info.message; - fieldEl.appendChild(infoEl); + Polymer.dom(fieldEl).appendChild(infoEl); }, this); // Set the color of the element. @@ -567,15 +583,15 @@ tr.exportTo('tr.ui.analysis', function() { if (firstString === undefined) { // String was added ("+NEW_VALUE" in red). var spanEl = tr.ui.b.createSpan({color: 'red'}); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode('+')); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode( + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode('+')); + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode( this.formatSingleField(lastString))); return spanEl; } else if (lastString === undefined) { // String was removed ("-OLD_VALUE" in green). var spanEl = tr.ui.b.createSpan({color: 'green'}); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode('-')); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode( + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode('-')); + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode( this.formatSingleField(firstString))); return spanEl; } else if (firstString === lastString) { @@ -584,11 +600,11 @@ tr.exportTo('tr.ui.analysis', function() { } else { // String changed ("OLD_VALUE -> NEW_VALUE" in orange). var spanEl = tr.ui.b.createSpan({color: 'DarkOrange'}); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode( + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode( this.formatSingleField(firstString))); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode( + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode( ' ' + RIGHTWARDS_ARROW + ' ')); - spanEl.appendChild(tr.ui.b.asHTMLOrTextNode( + Polymer.dom(spanEl).appendChild(tr.ui.b.asHTMLOrTextNode( this.formatSingleField(lastString))); return spanEl; } @@ -724,8 +740,14 @@ tr.exportTo('tr.ui.analysis', function() { formatSingleField: function(numeric) { var formattingContext = this.getFormattingContext(numeric.unit); - var config = formattingContext !== undefined ? - { context: formattingContext } : undefined; + var contextGroup = this.shouldSetContextGroup ? this.name : undefined; + var config = undefined; + if (formattingContext || contextGroup) { + config = { + context: formattingContext, + contextGroup: contextGroup + }; + } return tr.v.ui.createScalarSpan(numeric, config); }, @@ -866,8 +888,8 @@ tr.exportTo('tr.ui.analysis', function() { __proto__: NumericMemoryColumn.prototype, getFormattingContext: function(unit) { - if (unit.baseUnit === tr.v.Unit.byName.sizeInBytes) - return { unitPrefix: tr.v.UnitScale.Binary.KIBI }; + if (unit.baseUnit === tr.b.Unit.byName.sizeInBytes) + return { unitPrefix: tr.b.UnitScale.Binary.KIBI }; return undefined; } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html index 3a4350ec276..538a996d686 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_sub_view_util_test.html @@ -6,13 +6,13 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_test_utils.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() { tr.ui.analysis.aggregateTableRowCellsRecursively; var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var checkSizeNumericFields = tr.ui.analysis.checkSizeNumericFields; var checkNumericFields = tr.ui.analysis.checkNumericFields; var checkStringFields = tr.ui.analysis.checkStringFields; @@ -53,10 +53,10 @@ tr.b.unittest.testSuite(function() { var node = tr.ui.b.asHTMLOrTextNode(value); var spanEl = document.createElement('span'); - spanEl.appendChild(node); + Polymer.dom(spanEl).appendChild(node); test.addHTMLOutput(spanEl); - assert.strictEqual(node.textContent, expectedTextContent); + assert.strictEqual(Polymer.dom(node).textContent, expectedTextContent); if (opt_expectedColor === undefined) assert.notInstanceOf(node, HTMLElement); else @@ -118,8 +118,8 @@ tr.b.unittest.testSuite(function() { [512, 513]), 'mixed': new MemoryCell(['0.01', '0.10']), 'mixed2': new MemoryCell([ - new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 2.43e18), - new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 0.5433) + new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 2.43e18), + new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 0.5433) ]) } } @@ -129,38 +129,28 @@ tr.b.unittest.testSuite(function() { title: 'Row 2', fields: { 'cpu_temperature': undefined, - 'mixed': buildScalarCell(tr.v.Unit.byName.timeDurationInMs, + 'mixed': buildScalarCell(tr.b.Unit.byName.timeDurationInMs, [0.99, 0.999]) } } ]; } - function checkMemoryColumn(column, expectedName, expectedTitle, - expectedAggregationMode, testRow, expectedCell, expectedType) { - assert.strictEqual(column.name, expectedName); - if (typeof expectedTitle === 'function') - expectedTitle(column.title); - else - assert.strictEqual(column.title, expectedTitle); - assert.strictEqual(column.aggregationMode, expectedAggregationMode); - assert.strictEqual(column.cell(testRow), expectedCell); - assert.instanceOf(column, expectedType); - } - function checkCellValue( test, value, expectedText, expectedColor, opt_expectedInfos) { var expectedInfos = opt_expectedInfos || []; - assert.lengthOf(value.childNodes, 1 + expectedInfos.length); + assert.lengthOf(Polymer.dom(value).childNodes, 1 + expectedInfos.length); assert.strictEqual(value.style.color, expectedColor); if (typeof expectedText === 'string') - assert.strictEqual(value.childNodes[0].textContent, expectedText); + assert.strictEqual( + Polymer.dom(Polymer.dom(value).childNodes[0]).textContent, + expectedText); else - expectedText(value.childNodes[0]); + expectedText(Polymer.dom(value).childNodes[0]); for (var i = 0; i < expectedInfos.length; i++) { var expectedInfo = expectedInfos[i]; - var infoEl = value.childNodes[i + 1]; - assert.strictEqual(infoEl.textContent, expectedInfo.icon); + var infoEl = Polymer.dom(value).childNodes[i + 1]; + assert.strictEqual(Polymer.dom(infoEl).textContent, expectedInfo.icon); assert.strictEqual(infoEl.title, expectedInfo.message); assert.strictEqual(infoEl.style.color, expectedInfo.color || ''); } @@ -173,8 +163,8 @@ tr.b.unittest.testSuite(function() { assert.strictEqual(element.tagName, 'TR-V-UI-SCALAR-SPAN'); assert.strictEqual(element.value, expectedValue); assert.strictEqual(element.unit, opt_expectedIsDelta ? - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter : - tr.v.Unit.byName.sizeInBytes_smallerIsBetter); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter : + tr.b.Unit.byName.sizeInBytes_smallerIsBetter); assert.deepEqual(element.context, opt_expectedContext); }; } @@ -195,33 +185,33 @@ tr.b.unittest.testSuite(function() { var row = {title: 'added', contexts: [undefined, undefined, undefined, {}]}; assert.equal(column.formatTitle(row), 'added'); var value = column.value(row); - assert.equal(value.textContent, '+++\u00A0added'); + assert.equal(Polymer.dom(value).textContent, '+++\u00A0added'); assert.equal(value.style.color, 'red'); var row = {title: 'removed', contexts: [true, true, undefined, undefined]}; assert.equal(column.formatTitle(row), 'removed'); var value = column.value(row); - assert.equal(value.textContent, '---\u00A0removed'); + assert.equal(Polymer.dom(value).textContent, '---\u00A0removed'); assert.equal(value.style.color, 'green'); var row = {title: 'flaky', contexts: [true, undefined, true, true]}; assert.equal(column.formatTitle(row), 'flaky'); var value = column.value(row); - assert.equal(value.textContent, 'flaky'); + assert.equal(Polymer.dom(value).textContent, 'flaky'); assert.equal(value.style.color, 'purple'); var row = {title: 'added-flaky', contexts: [undefined, {}, undefined, true]}; assert.equal(column.formatTitle(row), 'added-flaky'); var value = column.value(row); - assert.equal(value.textContent, '+++\u00A0added-flaky'); + assert.equal(Polymer.dom(value).textContent, '+++\u00A0added-flaky'); assert.equal(value.style.color, 'purple'); var row = {title: 'removed-flaky', contexts: [true, undefined, {}, undefined]}; assert.equal(column.formatTitle(row), 'removed-flaky'); var value = column.value(row); - assert.equal(value.textContent, '---\u00A0removed-flaky'); + assert.equal(Polymer.dom(value).textContent, '---\u00A0removed-flaky'); assert.equal(value.style.color, 'purple'); }); @@ -283,27 +273,49 @@ tr.b.unittest.testSuite(function() { ]; var rows = buildTestRows(); - var columns = MemoryColumn.fromRows(rows, 'fields', AggregationMode.MAX, - rules); + var columns = MemoryColumn.fromRows(rows, { + cellKey: 'fields', + aggregationMode: AggregationMode.MAX, + rules: rules, + shouldSetContextGroup: true + }); assert.lengthOf(columns, 4); var pageSizeColumn = columns[0]; - checkMemoryColumn(pageSizeColumn, 'page_size', 'MockColumn0', - AggregationMode.MAX, {fields: {page_size: 'large'}}, 'large', - MockColumn0); + assert.strictEqual(pageSizeColumn.name, 'page_size'); + assert.strictEqual(pageSizeColumn.title, 'MockColumn0'); + assert.strictEqual(pageSizeColumn.aggregationMode, AggregationMode.MAX); + assert.strictEqual(pageSizeColumn.cell({fields: {page_size: 'large'}}), + 'large'); + assert.isTrue(pageSizeColumn.shouldSetContextGroup); + assert.instanceOf(pageSizeColumn, MockColumn0); var mixedColumn = columns[1]; - checkMemoryColumn(mixedColumn, 'mixed', 'MockColumn2', AggregationMode.MAX, - {fields: {mixed: 89}}, 89, MockColumn2); + assert.strictEqual(mixedColumn.name, 'mixed'); + assert.strictEqual(mixedColumn.title, 'MockColumn2'); + assert.strictEqual(mixedColumn.aggregationMode, AggregationMode.MAX); + assert.strictEqual(mixedColumn.cell({fields: {mixed: 89}}), 89); + assert.isTrue(mixedColumn.shouldSetContextGroup); + assert.instanceOf(mixedColumn, MockColumn2); var mixed2Column = columns[2]; - checkMemoryColumn(mixed2Column, 'mixed2', 'MockColumn2', - AggregationMode.MAX, {fields: {mixed2: 'invalid'}}, 'invalid', - MemoryColumn); + assert.strictEqual(mixed2Column.name, 'mixed2'); + assert.strictEqual(mixed2Column.title, 'MockColumn2'); + assert.strictEqual(mixed2Column.aggregationMode, AggregationMode.MAX); + assert.strictEqual(mixed2Column.cell({fields: {mixed2: 'invalid'}}), + 'invalid'); + assert.isTrue(mixed2Column.shouldSetContextGroup); + assert.instanceOf(mixed2Column, MockColumn2); var cpuTemperatureColumn = columns[3]; - checkMemoryColumn(cpuTemperatureColumn, 'cpu_temperature', 'MockColumn1', - AggregationMode.MAX, {fields: {cpu_temperature: 42}}, 42, MockColumn1); + assert.strictEqual(cpuTemperatureColumn.name, 'cpu_temperature'); + assert.strictEqual(cpuTemperatureColumn.title, 'MockColumn1'); + assert.strictEqual(cpuTemperatureColumn.aggregationMode, + AggregationMode.MAX); + assert.strictEqual( + cpuTemperatureColumn.cell({fields: {cpu_temperature: 42}}), 42); + assert.isTrue(cpuTemperatureColumn.shouldSetContextGroup); + assert.instanceOf(cpuTemperatureColumn, MockColumn1); }); test('checkMemoryColumn_spaceEqually', function() { @@ -365,8 +377,8 @@ tr.b.unittest.testSuite(function() { assert.isUndefined(c.fields({x: new MemoryCell(undefined)})); // Defined field(s) inside cell. - var field1 = new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 1013.25); - var field2 = new ScalarNumeric(tr.v.Unit.byName.powerInWatts, 1065); + var field1 = new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 1013.25); + var field2 = new ScalarNumeric(tr.b.Unit.byName.powerInWatts, 1065); var row1 = {x: new MemoryCell([field1])}; var row2 = {x: new MemoryCell([field1, field2])}; assert.deepEqual(c.fields(row1), [field1]); @@ -770,7 +782,7 @@ tr.b.unittest.testSuite(function() { // With custom formatting context. c.getFormattingContext = function(unit) { assert.strictEqual(unit, - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter); return { minimumFractionDigits: 2 }; }; checkCellValue(this, c.value(row), @@ -783,19 +795,24 @@ tr.b.unittest.testSuite(function() { var c = new NumericMemoryColumn('non_bytes_column', ['x'], undefined /* aggregation mode */); var value = c.formatSingleField(new ScalarNumeric( - tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 123)); - assert.equal(value.tagName, 'TR-V-UI-SCALAR-SPAN'); - assert.equal(value.value, 123); - assert.equal(value.unit, tr.v.Unit.byName.unitlessNumber_smallerIsBetter); + tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 123)); + assert.strictEqual(value.tagName, 'TR-V-UI-SCALAR-SPAN'); + assert.strictEqual(value.value, 123); + assert.strictEqual(value.unit, + tr.b.Unit.byName.unitlessNumber_smallerIsBetter); + assert.isUndefined(value.contextGroup); this.addHTMLOutput(value); var c = new NumericMemoryColumn('bytes_column', ['x'], undefined /* aggregation mode */); + c.shouldSetContextGroup = true; var value = c.formatSingleField(new ScalarNumeric( sizeInBytes_smallerIsBetter, 456)); - assert.equal(value.tagName, 'TR-V-UI-SCALAR-SPAN'); - assert.equal(value.value, 456); - assert.equal(value.unit, tr.v.Unit.byName.sizeInBytes_smallerIsBetter); + assert.strictEqual(value.tagName, 'TR-V-UI-SCALAR-SPAN'); + assert.strictEqual(value.value, 456); + assert.strictEqual(value.unit, + tr.b.Unit.byName.sizeInBytes_smallerIsBetter); + assert.strictEqual(value.contextGroup, 'bytes_column'); this.addHTMLOutput(value); }); @@ -804,26 +821,26 @@ tr.b.unittest.testSuite(function() { var c = new NumericMemoryColumn('non_bytes_column', ['x'], AggregationMode.DIFF); checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3], - tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 2); + tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 2); checkNumericMemoryColumnFieldFormat(this, c, [10, undefined], - tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, -10); + tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, -10); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0], - tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0); + tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0); checkNumericMemoryColumnFieldFormat( this, c, [2.71828, 2.71829] /* diff within epsilon */, - tr.v.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0); + tr.b.Unit.byName.unitlessNumberDelta_smallerIsBetter, 0); var c = new NumericMemoryColumn('bytes_column', ['x'], AggregationMode.DIFF); checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3], - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 2); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 2); checkNumericMemoryColumnFieldFormat(this, c, [10, undefined], - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, -10); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, -10); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0], - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0); checkNumericMemoryColumnFieldFormat( this, c, [1.41421, 1.41422] /* diff within epsilon */, - tr.v.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0); + tr.b.Unit.byName.sizeInBytesDelta_smallerIsBetter, 0); }); test('checkNumericMemoryColumn_formatMultipleFields_max', @@ -831,24 +848,24 @@ tr.b.unittest.testSuite(function() { var c = new NumericMemoryColumn('non_bytes_column', ['x'], AggregationMode.MAX); checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3], - tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 3); + tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 3); checkNumericMemoryColumnFieldFormat(this, c, [10, undefined], - tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 10); + tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 10); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0], - tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 60); + tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 60); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 10, 20, undefined], - tr.v.Unit.byName.unitlessNumber_smallerIsBetter, 20); + tr.b.Unit.byName.unitlessNumber_smallerIsBetter, 20); var c = new NumericMemoryColumn('bytes_column', ['x'], AggregationMode.MAX); checkNumericMemoryColumnFieldFormat(this, c, [1, 2, 3], - tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 3); + tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 3); checkNumericMemoryColumnFieldFormat(this, c, [10, undefined], - tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 10); + tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 10); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 60, 0], - tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 60); + tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 60); checkNumericMemoryColumnFieldFormat(this, c, [undefined, 10, 20, undefined], - tr.v.Unit.byName.sizeInBytes_smallerIsBetter, 20); + tr.b.Unit.byName.sizeInBytes_smallerIsBetter, 20); }); test('checkNumericMemoryColumn_cmp', function() { @@ -884,12 +901,12 @@ tr.b.unittest.testSuite(function() { assert.isBelow(c.compareSingleFields( new ScalarNumeric( - tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, 99), + tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, 99), new ScalarNumeric( - tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, 100)), 0); + tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, 100)), 0); assert.equal(c.compareSingleFields( - new ScalarNumeric(tr.v.Unit.byName.unitlessNumber, 0xEEE), - new ScalarNumeric(tr.v.Unit.byName.unitlessNumber, 0xEEE)), 0); + new ScalarNumeric(tr.b.Unit.byName.unitlessNumber, 0xEEE), + new ScalarNumeric(tr.b.Unit.byName.unitlessNumber, 0xEEE)), 0); assert.isAbove(c.compareSingleFields( new ScalarNumeric(sizeInBytes_smallerIsBetter, 10), new ScalarNumeric(sizeInBytes_smallerIsBetter, 2)), 0); @@ -905,9 +922,9 @@ tr.b.unittest.testSuite(function() { buildScalarCell(sizeInBytes_smallerIsBetter, [5, 7, 8] /* diff +3 */).fields), 0); assert.equal(c.compareMultipleFields( - buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [4, undefined] /* diff -4 */).fields, - buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [999, 995] /* diff -4 */).fields), 0); assert.isAbove(c.compareMultipleFields( buildScalarCell(sizeInBytes_smallerIsBetter, @@ -915,9 +932,9 @@ tr.b.unittest.testSuite(function() { buildScalarCell(sizeInBytes_smallerIsBetter, [11, 50, 12] /* diff +1 */).fields), 0); assert.equal(c.compareMultipleFields( - buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter, [17, undefined, 17] /* diff 0 */).fields, - buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter, [undefined, 100, undefined] /* diff 0 */).fields), 0); assert.equal(c.compareMultipleFields( buildScalarCell(sizeInBytes_smallerIsBetter, @@ -935,18 +952,18 @@ tr.b.unittest.testSuite(function() { [10, undefined, 12]).fields, buildScalarCell(sizeInBytes_smallerIsBetter, [11, 50, 12]).fields), 0); assert.equal(c.compareMultipleFields( - buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [999, undefined, -8888]).fields, - buildScalarCell(tr.v.Unit.byName.timeDurationInMs_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.timeDurationInMs_smallerIsBetter, [undefined, 999, undefined]).fields), 0); assert.isAbove(c.compareMultipleFields( buildScalarCell(sizeInBytes_smallerIsBetter, [10000, 10001, 10002]).fields, buildScalarCell(sizeInBytes_smallerIsBetter, [5, 7, 8]).fields), 0); assert.isBelow(c.compareMultipleFields( - buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter, [17, undefined, 17]).fields, - buildScalarCell(tr.v.Unit.byName.powerInWatts_smallerIsBetter, + buildScalarCell(tr.b.Unit.byName.powerInWatts_smallerIsBetter, [undefined, 100, undefined]).fields), 0); }); @@ -1132,7 +1149,7 @@ tr.b.unittest.testSuite(function() { var row = { // Intentionally no testCells. otherCells: { - a: buildScalarCell(tr.v.Unit.byName.unitlessNumber, + a: buildScalarCell(tr.b.Unit.byName.unitlessNumber, [5, undefined, undefined]) } }; @@ -1155,7 +1172,7 @@ tr.b.unittest.testSuite(function() { b: buildScalarCell(sizeInBytes_smallerIsBetter, [5]) }, otherCells: { - a: buildScalarCell(tr.v.Unit.byName.unitlessNumber, + a: buildScalarCell(tr.b.Unit.byName.unitlessNumber, [153, undefined, 257]), b: new MemoryCell(['field-should-not-propagate-upwards', '']) } @@ -1175,7 +1192,7 @@ tr.b.unittest.testSuite(function() { checkSizeNumericFields(row, ctc, undefined); checkNumericFields(row, coa, [5, undefined, 257], - tr.v.Unit.byName.unitlessNumber); + tr.b.Unit.byName.unitlessNumber); checkStringFields(row, cob, undefined); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html index c16df525127..fe7af81eb27 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane.html @@ -6,14 +6,13 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/memory_dump_sub_view_util.html"> <link rel="import" href="/tracing/ui/analysis/stacked_pane.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/numeric.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane" - extends="tr-ui-a-stacked-pane"> +<dom-module id='tr-ui-a-memory-dump-vm-regions-details-pane'> <template> <style> :host { @@ -50,6 +49,7 @@ found in the LICENSE file. display: none; /* Hide until memory dumps are set. */ flex: 1 0 auto; align-self: stretch; + font-size: 12px; } </style> <div id="label">Memory maps</div> @@ -58,7 +58,7 @@ found in the LICENSE file. <tr-ui-b-table id="table"></tr-ui-b-table> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -66,7 +66,7 @@ tr.exportTo('tr.ui.analysis', function() { var ScalarNumeric = tr.v.ScalarNumeric; var sizeInBytes_smallerIsBetter = - tr.v.Unit.byName.sizeInBytes_smallerIsBetter; + tr.b.Unit.byName.sizeInBytes_smallerIsBetter; var CONSTANT_COLUMN_RULES = [ { @@ -153,7 +153,10 @@ tr.exportTo('tr.ui.analysis', function() { }); } - Polymer('tr-ui-a-memory-dump-vm-regions-details-pane', { + Polymer({ + is: 'tr-ui-a-memory-dump-vm-regions-details-pane', + behaviors: [tr.ui.analysis.StackedPane], + created: function() { this.vmRegions_ = undefined; this.aggregationMode_ = undefined; @@ -187,7 +190,7 @@ tr.exportTo('tr.ui.analysis', function() { */ set vmRegions(vmRegions) { this.vmRegions_ = vmRegions; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get vmRegions() { @@ -196,14 +199,14 @@ tr.exportTo('tr.ui.analysis', function() { set aggregationMode(aggregationMode) { this.aggregationMode_ = aggregationMode; - this.scheduleRebuildPane_(); + this.scheduleRebuild_(); }, get aggregationMode() { return this.aggregationMode_; }, - rebuildPane_: function() { + onRebuild_: function() { if (this.vmRegions_ === undefined || this.vmRegions_.length === 0) { // Show the info text (hide the table). this.$.info_text.style.display = 'block'; @@ -362,10 +365,16 @@ tr.exportTo('tr.ui.analysis', function() { var titleColumn = new tr.ui.analysis.TitleColumn('Mapped file'); titleColumn.width = '200px'; - var constantColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'constantCells', undefined, CONSTANT_COLUMN_RULES); - var variableColumns = tr.ui.analysis.MemoryColumn.fromRows( - rows, 'variableCells', this.aggregationMode_, VARIABLE_COLUMN_RULES); + var constantColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'constantCells', + aggregationMode: undefined, + rules: CONSTANT_COLUMN_RULES + }); + var variableColumns = tr.ui.analysis.MemoryColumn.fromRows(rows, { + cellKey: 'variableCells', + aggregationMode: this.aggregationMode_, + rules: VARIABLE_COLUMN_RULES + }); var fieldColumns = constantColumns.concat(variableColumns); tr.ui.analysis.MemoryColumn.spaceEqually(fieldColumns); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html index 9c79c1b5753..abfd3b5c81e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/memory_dump_vm_regions_details_pane_test.html @@ -40,8 +40,8 @@ tr.b.unittest.testSuite(function() { var process = model.getOrCreateProcess(1); // First timestamp. - var gmd1 = addGlobalMemoryDump(model, 42, DETAILED); - var pmd1 = addProcessMemoryDump(gmd1, process, 42); + var gmd1 = addGlobalMemoryDump(model, {ts: 42, levelOfDetail: DETAILED}); + var pmd1 = addProcessMemoryDump(gmd1, process, {ts: 42}); pmd1.vmRegions = VMRegionClassificationNode.fromRegions([ VMRegion.fromDict({ mappedFile: '/lib/chrome.so', @@ -111,12 +111,13 @@ tr.b.unittest.testSuite(function() { // This is here so that we could test that tracing is discounted from the // 'Native heap' category. pmd1.memoryAllocatorDumps = [ - newAllocatorDump(pmd1, 'tracing', { size: 500, resident_size: 32 }) + newAllocatorDump(pmd1, 'tracing', + {numerics: {size: 500, resident_size: 32}}) ]; // Second timestamp. - var gmd2 = addGlobalMemoryDump(model, 42, DETAILED); - var pmd2 = addProcessMemoryDump(gmd2, process, 42); + var gmd2 = addGlobalMemoryDump(model, {ts: 42, levelOfDetail: DETAILED}); + var pmd2 = addProcessMemoryDump(gmd2, process, {ts: 42}); pmd2.vmRegions = VMRegionClassificationNode.fromRegions([ VMRegion.fromDict({ mappedFile: '/lib/chrome.so', diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html index f062aca2336..d97043e9ef3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_async_slice_sub_view.html @@ -10,8 +10,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/related_events.html"> -<polymer-element name="tr-ui-a-multi-async-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-async-slice-sub-view'> <template> <style> :host { @@ -33,40 +32,49 @@ found in the LICENSE file. </div> </div> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-multi-async-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - get selection() { - return this.$.content.selection; - }, + get selection() { + return this.$.content.selection; + }, - set selection(selection) { - this.$.content.selection = selection; - this.$.relatedEvents.setRelatedEvents(selection); - if (this.$.relatedEvents.hasRelatedEvents()) { - this.$.relatedEvents.style.display = ''; - } else { - this.$.relatedEvents.style.display = 'none'; - } - }, + set selection(selection) { + this.$.content.selection = selection; + this.$.relatedEvents.setRelatedEvents(selection); + if (this.$.relatedEvents.hasRelatedEvents()) { + this.$.relatedEvents.style.display = ''; + } else { + this.$.relatedEvents.style.display = 'none'; + } + }, - get relatedEventsToHighlight() { - if (!this.$.content.selection) - return undefined; - var selection = new tr.model.EventSet(); - this.$.content.selection.forEach(function(asyncEvent) { - if (!asyncEvent.associatedEvents) - return; - asyncEvent.associatedEvents.forEach(function(event) { - selection.push(event); - }); - }); - if (selection.length) - return selection; + get relatedEventsToHighlight() { + if (!this.$.content.selection) return undefined; - } - }); - </script> -</polymer-element> + var selection = new tr.model.EventSet(); + this.$.content.selection.forEach(function(asyncEvent) { + if (!asyncEvent.associatedEvents) + return; + asyncEvent.associatedEvents.forEach(function(event) { + selection.push(event); + }); + }); + if (selection.length) + return selection; + return undefined; + } +}); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-async-slice-sub-view', + tr.model.AsyncSlice, + { + multi: true, + title: 'Async Slices', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html index f4f5215a004..ee061a58271 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_cpu_slice_sub_view.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> -<polymer-element name="tr-ui-a-multi-cpu-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-cpu-slice-sub-view'> <template> <style> :host { @@ -21,22 +20,32 @@ found in the LICENSE file. </style> <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-multi-cpu-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - ready: function() { - this.$.content.eventsHaveSubRows = false; - }, + ready: function() { + this.$.content.eventsHaveSubRows = false; + }, - get selection() { - return this.$.content.selection; - }, + get selection() { + return this.$.content.selection; + }, - set selection(selection) { - this.$.content.setSelectionWithoutErrorChecks(selection); - } - }); - </script> -</polymer-element> + set selection(selection) { + this.$.content.setSelectionWithoutErrorChecks(selection); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-cpu-slice-sub-view', + tr.model.CpuSlice, + { + multi: true, + title: 'CPU Slices', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html deleted file mode 100644 index 101137cdcb6..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table.html +++ /dev/null @@ -1,333 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2013 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/base/base.html"> -<link rel="import" href="/tracing/base/iteration_helpers.html"> -<link rel="import" href="/tracing/model/event_set.html"> -<link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> -<link rel="import" href="/tracing/ui/analysis/multi_event_summary.html"> -<link rel="import" href="/tracing/ui/base/table.html"> -<link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> - -<polymer-element name='tr-ui-a-multi-event-details-table'> - <template> - <style> - :host { - display: flex; - flex-direction: column; - } - #table { - flex: 1 1 auto; - align-self: stretch; - } - - #titletable { - font-weight: bold; - } - - #title-info { - font-size: 12px; - } - </style> - <tr-ui-b-table id="titletable"> - </tr-ui-b-table> - <tr-ui-b-table id="table"> - </tr-ui-b-table> - </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.selection_ = undefined; - this.eventsHaveDuration_ = true; - this.eventsHaveSubRows_ = true; - }, - - ready: function() { - this.initTitleTable_(); - }, - - get eventsHaveDuration() { - return this.eventsHaveDuration_; - }, - - set eventsHaveDuration(eventsHaveDuration) { - this.eventsHaveDuration_ = eventsHaveDuration; - this.updateContents_(); - }, - - get eventsHaveSubRows() { - return this.eventsHaveSubRows_; - }, - - set eventsHaveSubRows(eventsHaveSubRows) { - this.eventsHaveSubRows_ = eventsHaveSubRows; - this.updateContents_(); - }, - - get selection() { - return this.selection_; - }, - - set selection(selection) { - this.selection_ = selection; - this.updateContents_(); - }, - - updateContents_: function() { - var selection = this.selection_; - - this.updateTitleTable_(); - - if (this.selection_ === undefined) { - this.$.table.tableRows = []; - this.$.table.tableFooterRows = []; - this.$.table.rebuild(); - return; - } - - var summary = new tr.ui.analysis.MultiEventSummary( - 'Totals', this.selection_); - this.updateColumns_(summary); - this.updateRows_(summary); - this.$.table.rebuild(); - }, - - initTitleTable_: function() { - var table = this.$.titletable; - - table.showHeader = false; - table.tableColumns = [ - { - title: 'Title', - value: function(row) { return row.title; }, - width: '350px' - }, - { - title: 'Value', - width: '100%', - value: function(row) { - return row.value; - } - } - ]; - }, - - getSelectionTitle_: function() { - if (!this.selection || !this.selection.length) - return '<No selection>'; - - var firstTitle = tr.b.getFirstElement(this.selection).title; - if (!tr.b.every(this.selection, (event) => event.title === firstTitle)) - return '<Different titles>'; - - return firstTitle; - }, - - updateTitleTable_: function() { - this.$.titletable.tableRows = [{ - title: 'Title', - value: this.getSelectionTitle_() - }]; - }, - - updateColumns_: function(summary) { - var hasCpuData; - if (summary.cpuDuration !== undefined) - hasCpuData = true; - if (summary.cpuSelfTime !== undefined) - hasCpuData = true; - - var colWidthPercentage; - if (hasCpuData) - colWidthPercentage = '20%'; - else - colWidthPercentage = '33.3333%'; - - var ownerDocument = this.ownerDocument; - var columns = []; - - columns.push({ - title: 'Start', - value: function(row) { - if (row.__proto__ === tr.ui.analysis.MultiEventSummary.prototype) { - return row.title; - } - - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return new tr.model.EventSet(row.event); - }); - linkEl.appendChild(tr.v.ui.createScalarSpan(row.start, { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: ownerDocument - })); - return linkEl; - }, - width: '350px', - cmp: function(rowA, rowB) { - return rowA.start - rowB.start; - } - }); - - if (this.eventsHaveDuration_) { - columns.push({ - title: 'Wall Duration (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.duration, { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: ownerDocument - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.duration - rowB.duration; - } - }); - } - - if (this.eventsHaveDuration_ && hasCpuData) { - columns.push({ - title: 'CPU Duration (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.cpuDuration, { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: ownerDocument - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.cpuDuration - rowB.cpuDuration; - } - }); - } - - if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) { - columns.push({ - title: 'Self time (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.selfTime, { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: ownerDocument - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.selfTime - rowB.selfTime; - } - }); - } - - if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) { - columns.push({ - title: 'CPU Self Time (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.cpuSelfTime, { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: ownerDocument - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.cpuSelfTime - rowB.cpuSelfTime; - } - }); - } - - var argKeys = tr.b.dictionaryKeys(summary.totalledArgs); - argKeys.sort(); - - var otherKeys = summary.untotallableArgs.slice(0); - otherKeys.sort(); - - argKeys.push.apply(argKeys, otherKeys); - var keysWithColumns = argKeys.slice(0, 4); - var keysInOtherColumn = argKeys.slice(4); - - keysWithColumns.forEach(function(argKey) { - - var hasTotal = summary.totalledArgs[argKey]; - var colDesc = { - title: 'Arg: ' + argKey, - value: function(row) { - if (row.__proto__ !== tr.ui.analysis.MultiEventSummary.prototype) { - var argView = - document.createElement('tr-ui-a-generic-object-view'); - argView.object = row.args[argKey]; - return argView; - } - if (hasTotal) - return row.totalledArgs[argKey]; - return ''; - }, - width: '<upated further down>' - }; - if (hasTotal) { - colDesc.cmp = function(rowA, rowB) { - return rowA.args[argKey] - rowB.args[argKey]; - }; - } - columns.push(colDesc); - }); - - if (keysInOtherColumn.length) { - columns.push({ - title: 'Other Args', - value: function(row) { - if (row.__proto__ === tr.ui.analysis.MultiEventSummary.prototype) - return ''; - var argView = - document.createElement('tr-ui-a-generic-object-view'); - var obj = {}; - for (var i = 0; i < keysInOtherColumn.length; i++) - obj[keysInOtherColumn[i]] = row.args[keysInOtherColumn[i]]; - argView.object = obj; - return argView; - }, - width: '<upated further down>' - }); - } - - var colWidthPercentage; - if (columns.length == 1) - colWidthPercentage = '100%'; - else - colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; - - for (var i = 1; i < columns.length; i++) - columns[i].width = colWidthPercentage; - - this.$.table.tableColumns = columns; - }, - - updateRows_: function(summary) { - this.$.table.sortColumnIndex = 0; - function Row(event) { - this.event = event; - } - Row.prototype = { - get start() { return this.event.start; }, - get duration() { return this.event.duration; }, - get cpuDuration() { return this.event.cpuDuration; }, - get selfTime() { return this.event.selfTime; }, - get cpuSelfTime() { return this.event.cpuSelfTime; }, - get args() { return this.event.args; } - }; - - this.$.table.tableRows = this.selection_.map(function(event) { - return new Row(event); - }); - this.$.table.footerRows = [summary]; - } - }); -</script> -</polymer-element> - - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html deleted file mode 100644 index 0bf2d13e081..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_details_table_test.html +++ /dev/null @@ -1,171 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2013 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/core/test_utils.html"> -<link rel="import" href="/tracing/model/event_set.html"> -<link rel="import" href="/tracing/model/model.html"> -<link rel="import" href="/tracing/ui/analysis/multi_event_details_table.html"> -<link rel="import" href="/tracing/ui/base/deep_utils.html"> - -<script> -'use strict'; - -tr.b.unittest.testSuite(function() { - var Model = tr.Model; - var Thread = tr.model.Thread; - var EventSet = tr.model.EventSet; - var newSliceEx = tr.c.TestUtils.newSliceEx; - - test('sortingOfFirstColumn', function() { - var model = new Model(); - var thread = model.getOrCreateProcess(1).getOrCreateThread(2); - var tsg = thread.sliceGroup; - var sA = tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2, - cpuStart: 1, cpuEnd: 1.75})); - var sB = tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3, - cpuStart: 0, cpuEnd: 3})); - var sC = tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5, - cpuStart: 3, cpuEnd: 3.75})); - tsg.createSubSlices(); - - var threadTrack = {}; - threadTrack.thread = thread; - - var selection = new EventSet(tsg.slices); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - - var table = viewEl.$.table; - var cmpResult = table.tableColumns[0].cmp(sA, sB); - assert.equal(cmpResult, 1); - }); - - test('withCpuTime', function() { - var model = new Model(); - var thread = model.getOrCreateProcess(1).getOrCreateThread(2); - var tsg = thread.sliceGroup; - tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3, - cpuStart: 0, cpuEnd: 3})); - tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2, - cpuStart: 1, cpuEnd: 1.75})); - tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5, - cpuStart: 3, cpuEnd: 3.75})); - tsg.createSubSlices(); - - var threadTrack = {}; - threadTrack.thread = thread; - - var selection = new EventSet(tsg.slices); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - }); - - test('withoutCpuTime', function() { - var model = new Model(); - var thread = model.getOrCreateProcess(1).getOrCreateThread(2); - var tsg = thread.sliceGroup; - tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3})); - tsg.pushSlice(newSliceEx({title: 'a', start: 1, end: 2})); - tsg.pushSlice(newSliceEx({title: 'a', start: 4, end: 5})); - tsg.createSubSlices(); - - var threadTrack = {}; - threadTrack.thread = thread; - - var selection = new EventSet(tsg.slices); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - }); - - - test('withFewerThanFourArgs', function() { - var model = new Model(); - var thread = model.getOrCreateProcess(1).getOrCreateThread(2); - var tsg = thread.sliceGroup; - tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3, - args: {value1: 3, value2: 'x', value3: 1}})); - tsg.pushSlice(newSliceEx({title: 'b', start: 1, end: 2, - args: {value1: 3.1, value2: 'y', value3: 2}})); - tsg.pushSlice(newSliceEx({title: 'b', start: 4, end: 5, - args: {value1: 3.2, value2: 'z', value3: 'x'}})); - tsg.createSubSlices(); - - var threadTrack = {}; - threadTrack.thread = thread; - - var selection = new EventSet(tsg.slices); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - }); - - test('withExtraArgs', function() { - var model = new Model(); - var thread = model.getOrCreateProcess(1).getOrCreateThread(2); - var tsg = thread.sliceGroup; - tsg.pushSlice(newSliceEx({title: 'a', start: 0, end: 3, - args: {value1: 3, value2: 'x', value3: 1, - value4: 4, value5: 5, value6: 6}})); - tsg.pushSlice(newSliceEx({title: 'b', start: 1, end: 2, - args: {value1: 3.1, value2: 'y', value3: 2, - value4: 4, value5: 5, value6: 6}})); - tsg.pushSlice(newSliceEx({title: 'b', start: 4, end: 5, - args: {value1: 3.2, value2: 'z', value3: 'x', - value4: 4, value5: 'whoops', value6: 6}})); - tsg.createSubSlices(); - - var threadTrack = {}; - threadTrack.thread = thread; - - var selection = new EventSet(tsg.slices); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - }); - - test('noDuration', function() { - var model = new Model(); - - var fe1 = new tr.model.FlowEvent('cat', 1234, 'title', 7, 10, {}); - var fe2 = new tr.model.FlowEvent('cat', 1234, 'title', 8, 20, {}); - - // Make reading some properties an explosion, as a way to ensure that they - // aren't read. - var failProp = { - get: function() { - throw new Error('Should not be called'); - } - }; - Object.defineProperty(fe1, 'duration', failProp); - Object.defineProperty(fe2, 'duration', failProp); - - Object.defineProperty(fe1, 'subRows', failProp); - Object.defineProperty(fe2, 'subRows', failProp); - - Object.defineProperty(fe1, 'selfTime', failProp); - Object.defineProperty(fe2, 'selfTime', failProp); - - model.flowEvents.push(fe1); - model.flowEvents.push(fe2); - - var selection = new EventSet([fe1, fe2]); - - var viewEl = document.createElement('tr-ui-a-multi-event-details-table'); - viewEl.eventsHaveDuration = false; - viewEl.selection = selection; - this.addHTMLOutput(viewEl); - }); -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html index c6333dce9a6..c134f16c57c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view.html @@ -7,14 +7,15 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> -<link rel="import" href="/tracing/ui/analysis/selection_summary_table.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_summary_table.html"> -<link rel="import" href="/tracing/ui/analysis/multi_event_details_table.html"> -<link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/analysis/selection_summary_table.html"> +<link rel="import" href="/tracing/ui/base/radio_picker.html"> <link rel="import" href="/tracing/ui/base/table.html"> +<link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/value/diagnostics/scalar.html"> +<link rel="import" href="/tracing/value/histogram.html"> -<polymer-element name="tr-ui-a-multi-event-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-event-sub-view'> <template> <style> :host { @@ -31,6 +32,10 @@ found in the LICENSE file. flex: 0 0 auto; align-self: stretch; } + #histogramContainer { + display: flex; + } + tr-ui-a-multi-event-summary-table { border-bottom: 1px solid #aaa; } @@ -44,18 +49,69 @@ found in the LICENSE file. border-bottom: 1px solid #aaa; } </style> - <div id="content"></div> + <div id="content"> + <tr-ui-a-multi-event-summary-table id="eventSummaryTable"> + </tr-ui-a-multi-event-summary-table> + <tr-ui-a-selection-summary-table id="selectionSummaryTable"> + </tr-ui-a-selection-summary-table> + <tr-ui-b-radio-picker id="radioPicker"> + </tr-ui-b-radio-picker> + <div id="histogramContainer"> + <tr-v-ui-histogram-span id="histogramSpan"> + </tr-v-ui-histogram-span> + </div> + </div> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + var EVENT_FIELD = [ + {key: 'start', label: 'Start'}, + {key: 'cpuDuration', label: 'CPU Duration'}, + {key: 'duration', label: 'Duration'}, + {key: 'cpuSelfTime', label: 'CPU Self Time'}, + {key: 'selfTime', label: 'Self Time'} + ]; + + function buildDiagnostics_(slice, selectedKey) { + var diagnostics = {}; + for (var item of EVENT_FIELD) { + var fieldName = item.key; + if (fieldName === selectedKey || slice[fieldName] === undefined) + continue; + diagnostics[fieldName] = new tr.v.d.Scalar(new tr.v.ScalarNumeric( + tr.b.Unit.byName.timeDurationInMs, slice[fieldName])); + } + diagnostics['args'] = new tr.v.d.Generic(slice.args); + diagnostics['event'] = new tr.v.d.RelatedEventSet(slice); + return diagnostics; + } Polymer({ + is: 'tr-ui-a-multi-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + created: function() { this.currentSelection_ = undefined; this.eventsHaveDuration_ = true; this.eventsHaveSubRows_ = true; }, + ready: function() { + this.$.radioPicker.style.display = 'none'; + this.$.radioPicker.items = EVENT_FIELD; + this.$.radioPicker.select('cpuSelfTime'); + this.$.radioPicker.addEventListener('change', function(e) { + this.$.histogramSpan.histogram = + this.buildHistogram_(e.target.selectedKey); + }.bind(this)); + + this.$.histogramSpan.chartWidth = 400; + this.$.histogramContainer.style.display = 'none'; + }, + set selection(selection) { if (selection.length <= 1) throw new Error('Only supports multiple items'); @@ -89,40 +145,61 @@ found in the LICENSE file. this.updateContents_(); }, + buildHistogram_: function(selectedKey) { + var leftBoundary = Number.MAX_VALUE; + var rightBoundary = tr.b.Statistics.percentile( + this.currentSelection_, 0.95, + function(value) { + leftBoundary = Math.min(leftBoundary, value[selectedKey]); + return value[selectedKey]; + }); + + if (leftBoundary === rightBoundary) rightBoundary += 1; + var histogram = new tr.v.Histogram( + '', + tr.b.Unit.byName.timeDurationInMs, + tr.v.HistogramBinBoundaries.createLinear( + leftBoundary, rightBoundary, + Math.ceil(Math.sqrt(this.currentSelection_.length)))); + histogram.customizeSummaryOptions({sum: false}); + for (var slice of this.currentSelection_) { + histogram.addSample(slice[selectedKey], + buildDiagnostics_(slice, selectedKey)); + } + + return histogram; + }, + updateContents_: function() { var selection = this.currentSelection_; - this.$.content.textContent = ''; if (!selection) return; var eventsByTitle = selection.getEventsOrganizedByTitle(); var numTitles = tr.b.dictionaryLength(eventsByTitle); - var summaryTableEl = document.createElement( - 'tr-ui-a-multi-event-summary-table'); - summaryTableEl.configure({ + this.$.eventSummaryTable.configure({ showTotals: numTitles > 1, eventsByTitle: eventsByTitle, eventsHaveDuration: this.eventsHaveDuration_, eventsHaveSubRows: this.eventsHaveSubRows_ }); - this.$.content.appendChild(summaryTableEl); - var selectionSummaryTableEl = document.createElement( - 'tr-ui-a-selection-summary-table'); - selectionSummaryTableEl.selection = this.currentSelection_; - this.$.content.appendChild(selectionSummaryTableEl); + this.$.selectionSummaryTable.selection = this.currentSelection_; if (numTitles === 1) { - var detailsTableEl = document.createElement( - 'tr-ui-a-multi-event-details-table'); - detailsTableEl.eventsHaveDuration = this.eventsHaveDuration_; - detailsTableEl.eventsHaveSubRows = this.eventsHaveSubRows_; - detailsTableEl.selection = selection; - this.$.content.appendChild(detailsTableEl); + this.$.radioPicker.style.display = 'block'; + this.$.histogramSpan.histogram = + this.buildHistogram_(this.$.radioPicker.selectedKey); + this.$.histogramContainer.style.display = 'flex'; + } else { + this.$.radioPicker.style.display = 'none'; + this.$.histogramContainer.style.display = 'none'; } } }); - </script> -</polymer-element> + + return {}; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html index 5c26a864b78..c47543d1dac 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_sub_view_test.html @@ -19,7 +19,6 @@ tr.b.unittest.testSuite(function() { var Thread = tr.model.Thread; var EventSet = tr.model.EventSet; var newSliceEx = tr.c.TestUtils.newSliceEx; - var Slice = tr.model.Slice; test('differentTitles', function() { var model = new Model(); @@ -46,19 +45,16 @@ tr.b.unittest.testSuite(function() { var summaryTableEl = tr.b.findDeepElementMatching( viewEl, 'tr-ui-a-multi-event-summary-table'); - assert.isDefined(summaryTableEl); - assert.isTrue(summaryTableEl.showTotals); assert.equal(tr.b.dictionaryLength(summaryTableEl.eventsByTitle), 2); var selectionSummaryTableEl = tr.b.findDeepElementMatching( viewEl, 'tr-ui-a-selection-summary-table'); - assert.isDefined(selectionSummaryTableEl); assert.equal(selectionSummaryTableEl.selection, selection); - var detailsTableEl = tr.b.findDeepElementMatching( - viewEl, 'tr-ui-a-multi-event-details-table'); - assert.isUndefined(detailsTableEl); + var radioPickerEl = + tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-radio-picker'); + assert.equal(radioPickerEl.style.display, 'none'); }); test('sameTitles', function() { @@ -83,20 +79,16 @@ tr.b.unittest.testSuite(function() { var summaryTableEl = tr.b.findDeepElementMatching( viewEl, 'tr-ui-a-multi-event-summary-table'); - assert.isDefined(summaryTableEl); - assert.isFalse(summaryTableEl.showTotals); assert.equal(tr.b.dictionaryLength(summaryTableEl.eventsByTitle), 1); var selectionSummaryTableEl = tr.b.findDeepElementMatching( viewEl, 'tr-ui-a-selection-summary-table'); - assert.isDefined(selectionSummaryTableEl); assert.equal(selectionSummaryTableEl.selection, selection); - var detailsTableEl = tr.b.findDeepElementMatching( - viewEl, 'tr-ui-a-multi-event-details-table'); - assert.isDefined(detailsTableEl); - assert.equal(detailsTableEl.selection, selection); + var radioPickerEl = + tr.b.findDeepElementMatching(viewEl, 'tr-ui-b-radio-picker'); + assert.equal(radioPickerEl.style.display, 'block'); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html index 64cd636efcc..9b03bf7e090 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary.html @@ -29,11 +29,11 @@ tr.exportTo('tr.ui.analysis', function() { this.untotallableArgs_ = []; this.totalledArgs_ = undefined; - }; + } MultiEventSummary.prototype = { set title(title) { - if (title == 'Totals') + if (title === 'Totals') this.totalsRow = true; this.title_ = title; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html index 06ec9cbc17c..290ce0cfcb4 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table.html @@ -7,16 +7,16 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/range.html"> <link rel="import" href="/tracing/base/statistics.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_summary.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -</script> -<polymer-element name='tr-ui-a-multi-event-summary-table'> +<dom-module id='tr-ui-a-multi-event-summary-table'> <template> <style> :host { @@ -25,292 +25,327 @@ found in the LICENSE file. #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"> </tr-ui-b-table> </div> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.showTotals_ = false; - this.eventsHaveDuration_ = true; - this.eventsHaveSubRows_ = true; - this.eventsByTitle_ = undefined; - }, - - updateTableColumns_: function(rows, maxValues) { - var hasCpuData = false; - var hasAlerts = false; - rows.forEach(function(row) { - if (row.cpuDuration !== undefined) - hasCpuData = true; - if (row.cpuSelfTime !== undefined) - hasCpuData = true; - if (row.numAlerts) - hasAlerts = true; +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-multi-event-summary-table', + + ready: function() { + this.showTotals_ = false; + this.eventsHaveDuration_ = true; + this.eventsHaveSubRows_ = true; + this.eventsByTitle_ = undefined; + }, + + updateTableColumns_: function(rows, maxValues) { + var hasCpuData = false; + var hasAlerts = false; + rows.forEach(function(row) { + if (row.cpuDuration !== undefined) + hasCpuData = true; + if (row.cpuSelfTime !== undefined) + hasCpuData = true; + if (row.numAlerts) + hasAlerts = true; + }); + + var ownerDocument = this.ownerDocument; + + var columns = []; + + columns.push({ + title: 'Name', + value: function(row) { + if (row.title === 'Totals') + return 'Totals'; + + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent(function() { + return new tr.model.EventSet(row.events); + }, row.title); + return linkEl; + }, + width: '350px', + cmp: function(rowA, rowB) { + return rowA.title.localeCompare(rowB.title); + } + }); + if (this.eventsHaveDuration_) { + columns.push({ + title: 'Wall Duration', + value: function(row) { + return tr.v.ui.createScalarSpan(row.duration, { + unit: tr.b.Unit.byName.timeDurationInMs, + customContextRange: row.totalsRow ? undefined : + tr.b.Range.fromExplicitRange(0, maxValues.duration), + ownerDocument: ownerDocument, + rightAlign: true + }); + }, + width: '<upated further down>', + cmp: function(rowA, rowB) { + return rowA.duration - rowB.duration; + } }); + } - var ownerDocument = this.ownerDocument; + if (this.eventsHaveDuration_ && hasCpuData) { + columns.push({ + title: 'CPU Duration', + value: function(row) { + return tr.v.ui.createScalarSpan(row.cpuDuration, { + unit: tr.b.Unit.byName.timeDurationInMs, + customContextRange: row.totalsRow ? undefined : + tr.b.Range.fromExplicitRange(0, maxValues.cpuDuration), + ownerDocument: ownerDocument, + rightAlign: true + }); + }, + width: '<upated further down>', + cmp: function(rowA, rowB) { + return rowA.cpuDuration - rowB.cpuDuration; + } + }); + } - var columns = []; + if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) { + columns.push({ + title: 'Self time', + value: function(row) { + return tr.v.ui.createScalarSpan(row.selfTime, { + unit: tr.b.Unit.byName.timeDurationInMs, + customContextRange: row.totalsRow ? undefined : + tr.b.Range.fromExplicitRange(0, maxValues.selfTime), + ownerDocument: ownerDocument, + rightAlign: true + }); + }, + width: '<upated further down>', + cmp: function(rowA, rowB) { + return rowA.selfTime - rowB.selfTime; + } + }); + } + if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) { columns.push({ - title: 'Name', + title: 'CPU Self Time', value: function(row) { - if (row.title === 'Totals') - return 'Totals'; - - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return new tr.model.EventSet(row.events); - }, row.title); - return linkEl; + return tr.v.ui.createScalarSpan(row.cpuSelfTime, { + unit: tr.b.Unit.byName.timeDurationInMs, + customContextRange: row.totalsRow ? undefined : + tr.b.Range.fromExplicitRange(0, maxValues.cpuSelfTime), + ownerDocument: ownerDocument, + rightAlign: true + }); }, - width: '350px', + width: '<upated further down>', cmp: function(rowA, rowB) { - return rowA.title.localeCompare(rowB.title); + return rowA.cpuSelfTime - rowB.cpuSelfTime; } }); - if (this.eventsHaveDuration_) { - columns.push({ - title: 'Wall Duration', - value: function(row) { - return tr.v.ui.createScalarSpan(row.duration, { - unit: tr.v.Unit.byName.timeDurationInMs, - total: row.totalsRow ? undefined : maxValues.duration, - ownerDocument: ownerDocument, - rightAlign: true - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.duration - rowB.duration; - } - }); - } + } - if (this.eventsHaveDuration_ && hasCpuData) { - columns.push({ - title: 'CPU Duration', - value: function(row) { - return tr.v.ui.createScalarSpan(row.cpuDuration, { - unit: tr.v.Unit.byName.timeDurationInMs, - total: row.totalsRow ? undefined : maxValues.cpuDuration, - ownerDocument: ownerDocument, - rightAlign: true - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.cpuDuration - rowB.cpuDuration; + if (this.eventsHaveDuration_) { + columns.push({ + title: 'Average ' + (hasCpuData ? 'CPU' : 'Wall') + ' Duration', + value: function(row) { + var totalDuration = hasCpuData ? row.cpuDuration : row.duration; + return tr.v.ui.createScalarSpan(totalDuration / row.numEvents, { + unit: tr.b.Unit.byName.timeDurationInMs, + customContextRange: row.totalsRow ? undefined : + tr.b.Range.fromExplicitRange(0, maxValues.duration), + ownerDocument: ownerDocument, + rightAlign: true + }); + }, + width: '<upated further down>', + cmp: function(rowA, rowB) { + if (hasCpuData) { + return rowA.cpuDuration / rowA.numEvents - + rowB.cpuDuration / rowB.numEvents; + } else { + return rowA.duration / rowA.numEvents - + rowB.duration / rowB.numEvents; } - }); - } + } + }); + } - if (this.eventsHaveSubRows_ && this.eventsHaveDuration_) { - columns.push({ - title: 'Self time', - value: function(row) { - return tr.v.ui.createScalarSpan(row.selfTime, { - unit: tr.v.Unit.byName.timeDurationInMs, - total: row.totalsRow ? undefined : maxValues.selfTime, - ownerDocument: ownerDocument, - rightAlign: true - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.selfTime - rowB.selfTime; - } - }); + columns.push({ + title: 'Occurrences', + value: function(row) { + return row.numEvents; + }, + width: '<upated further down>', + cmp: function(rowA, rowB) { + return rowA.numEvents - rowB.numEvents; } + }); - if (this.eventsHaveSubRows_ && this.eventsHaveDuration_ && hasCpuData) { - columns.push({ - title: 'CPU Self Time', - value: function(row) { - return tr.v.ui.createScalarSpan(row.cpuSelfTime, { - unit: tr.v.Unit.byName.timeDurationInMs, - total: row.totalsRow ? undefined : maxValues.cpuSelfTime, - ownerDocument: ownerDocument, - rightAlign: true - }); - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.cpuSelfTime - rowB.cpuSelfTime; - } - }); - } + var alertsColumnIndex; + if (hasAlerts) { columns.push({ - title: 'Occurrences', + title: 'Num Alerts', value: function(row) { - return row.numEvents; + return row.numAlerts; }, width: '<upated further down>', cmp: function(rowA, rowB) { - return rowA.numEvents - rowB.numEvents; + return rowA.numAlerts - rowB.numAlerts; } }); + alertsColumnIndex = columns.length - 1; + } + var colWidthPercentage; + if (columns.length === 1) + colWidthPercentage = '100%'; + else + colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; - var alertsColumnIndex; - if (hasAlerts) { - columns.push({ - title: 'Num Alerts', - value: function(row) { - return row.numAlerts; - }, - width: '<upated further down>', - cmp: function(rowA, rowB) { - return rowA.numAlerts - rowB.numAlerts; - } - }); - alertsColumnIndex = columns.length - 1; - } - var colWidthPercentage; - if (columns.length == 1) - colWidthPercentage = '100%'; - else - colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; + for (var i = 1; i < columns.length; i++) + columns[i].width = colWidthPercentage; - for (var i = 1; i < columns.length; i++) - columns[i].width = colWidthPercentage; + this.$.table.tableColumns = columns; - this.$.table.tableColumns = columns; + if (hasAlerts) { + this.$.table.sortColumnIndex = alertsColumnIndex; + this.$.table.sortDescending = true; + } + }, - if (hasAlerts) { - this.$.table.sortColumnIndex = alertsColumnIndex; - this.$.table.sortDescending = true; - } - }, - - configure: function(config) { - if (config.eventsByTitle === undefined) - throw new Error('Required: eventsByTitle'); - - if (config.showTotals !== undefined) - this.showTotals_ = config.showTotals; - else - this.showTotals_ = true; - - if (config.eventsHaveDuration !== undefined) - this.eventsHaveDuration_ = config.eventsHaveDuration; - else - this.eventsHaveDuration_ = true; - - if (config.eventsHaveSubRows !== undefined) - this.eventsHaveSubRows_ = config.eventsHaveSubRows; - else - this.eventsHaveSubRows_ = true; - - this.eventsByTitle_ = config.eventsByTitle; - this.updateContents_(); - }, - - get showTotals() { - return this.showTotals_; - }, - - set showTotals(showTotals) { - this.showTotals_ = showTotals; - this.updateContents_(); - }, - - get eventsHaveDuration() { - return this.eventsHaveDuration_; - }, - - set eventsHaveDuration(eventsHaveDuration) { - this.eventsHaveDuration_ = eventsHaveDuration; - this.updateContents_(); - }, - - get eventsHaveSubRows() { - return this.eventsHaveSubRows_; - }, - - set eventsHaveSubRows(eventsHaveSubRows) { - this.eventsHaveSubRows_ = eventsHaveSubRows; - this.updateContents_(); - }, - - get eventsByTitle() { - return this.eventsByTitle_; - }, - - set eventsByTitle(eventsByTitle) { - this.eventsByTitle_ = eventsByTitle; - this.updateContents_(); - }, - - get selectionBounds() { - return this.selectionBounds_; - }, - - set selectionBounds(selectionBounds) { - this.selectionBounds_ = selectionBounds; - this.updateContents_(); - }, - - updateContents_: function() { - var eventsByTitle; - if (this.eventsByTitle_ !== undefined) - eventsByTitle = this.eventsByTitle_; - else - eventsByTitle = []; - - var allEvents = []; - var rows = []; - tr.b.iterItems( - eventsByTitle, - function(title, eventsOfSingleTitle) { - allEvents.push.apply(allEvents, eventsOfSingleTitle); - var row = new tr.ui.analysis.MultiEventSummary( - title, eventsOfSingleTitle); - rows.push(row); - }); + configure: function(config) { + if (config.eventsByTitle === undefined) + throw new Error('Required: eventsByTitle'); - this.updateTableColumns_(rows); - this.$.table.tableRows = rows; + if (config.showTotals !== undefined) + this.showTotals_ = config.showTotals; + else + this.showTotals_ = true; - var maxValues = { - duration: undefined, - selfTime: undefined, - cpuSelfTime: undefined, - cpuDuration: undefined - }; + if (config.eventsHaveDuration !== undefined) + this.eventsHaveDuration_ = config.eventsHaveDuration; + else + this.eventsHaveDuration_ = true; - if (this.eventsHaveDuration) { - for (var column in maxValues) { - maxValues[column] = tr.b.Statistics.max(rows, function(event) { - return event[column]; - }); - } - } + if (config.eventsHaveSubRows !== undefined) + this.eventsHaveSubRows_ = config.eventsHaveSubRows; + else + this.eventsHaveSubRows_ = true; + + this.eventsByTitle_ = config.eventsByTitle; + this.updateContents_(); + }, + + get showTotals() { + return this.showTotals_; + }, + + set showTotals(showTotals) { + this.showTotals_ = showTotals; + this.updateContents_(); + }, + + get eventsHaveDuration() { + return this.eventsHaveDuration_; + }, + + set eventsHaveDuration(eventsHaveDuration) { + this.eventsHaveDuration_ = eventsHaveDuration; + this.updateContents_(); + }, + + get eventsHaveSubRows() { + return this.eventsHaveSubRows_; + }, + + set eventsHaveSubRows(eventsHaveSubRows) { + this.eventsHaveSubRows_ = eventsHaveSubRows; + this.updateContents_(); + }, + + get eventsByTitle() { + return this.eventsByTitle_; + }, + + set eventsByTitle(eventsByTitle) { + this.eventsByTitle_ = eventsByTitle; + this.updateContents_(); + }, + + get selectionBounds() { + return this.selectionBounds_; + }, + + set selectionBounds(selectionBounds) { + this.selectionBounds_ = selectionBounds; + this.updateContents_(); + }, + + updateContents_: function() { + var eventsByTitle; + if (this.eventsByTitle_ !== undefined) + eventsByTitle = this.eventsByTitle_; + else + eventsByTitle = []; + + var allEvents = new tr.model.EventSet(); + var rows = []; + tr.b.iterItems( + eventsByTitle, + function(title, eventsOfSingleTitle) { + for (var event of allEvents) + allEvents.push(event); + var row = new tr.ui.analysis.MultiEventSummary( + title, eventsOfSingleTitle); + rows.push(row); + }); + + this.updateTableColumns_(rows); + this.$.table.tableRows = rows; - var footerRows = []; + var maxValues = { + duration: undefined, + selfTime: undefined, + cpuSelfTime: undefined, + cpuDuration: undefined + }; - if (this.showTotals_) { - var multiEventSummary = new tr.ui.analysis.MultiEventSummary( - 'Totals', allEvents); - footerRows.push(multiEventSummary); + if (this.eventsHaveDuration) { + for (var column in maxValues) { + maxValues[column] = tr.b.Statistics.max(rows, function(event) { + return event[column]; + }); } + } + var footerRows = []; - this.updateTableColumns_(rows, maxValues); - this.$.table.tableRows = rows; + if (this.showTotals_) { + var multiEventSummary = new tr.ui.analysis.MultiEventSummary( + 'Totals', allEvents); + footerRows.push(multiEventSummary); + } - // TODO(selection bounds). - // TODO(sorting) + this.updateTableColumns_(rows, maxValues); + this.$.table.tableRows = rows; - this.$.table.footerRows = footerRows; - this.$.table.rebuild(); - } - }); - </script> -</polymer-element> + // TODO(selection bounds). + + // TODO(sorting) + + this.$.table.footerRows = footerRows; + this.$.table.rebuild(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html index ebef452ab9e..97898aeed6a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_event_summary_table_test.html @@ -68,22 +68,20 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(viewEl); }); - test('noDurationNoSubRows', function() { + test('noSelfTimeNoSubRows', function() { var model = new Model(); var fe1 = new tr.model.FlowEvent('cat', 1234, 'title', 7, 10, {}); var fe2 = new tr.model.FlowEvent('cat', 1234, 'title', 8, 20, {}); // Make reading some properties an explosion, as a way to ensure that they - // aren't read. + // aren't read. Note that 'duration' is read since it is used by the + // EventSet to get the range. var failProp = { get: function() { throw new Error('Should not be called'); } }; - Object.defineProperty(fe1, 'duration', failProp); - Object.defineProperty(fe2, 'duration', failProp); - Object.defineProperty(fe1, 'subRows', failProp); Object.defineProperty(fe2, 'subRows', failProp); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html index ec185d1844b..14946562497 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_flow_event_sub_view.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> -<polymer-element name="tr-ui-a-multi-flow-event-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-flow-event-sub-view'> <template> <style> :host { @@ -18,23 +17,33 @@ found in the LICENSE file. </style> <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-multi-flow-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - ready: function() { - this.$.content.eventsHaveDuration = false; - this.$.content.eventsHaveSubRows = false; - }, + ready: function() { + this.$.content.eventsHaveDuration = false; + this.$.content.eventsHaveSubRows = false; + }, - set selection(selection) { - this.$.content.selection = selection; - }, + set selection(selection) { + this.$.content.selection = selection; + }, - get selection() { - return this.$.content.selection; - } - }); - </script> -</polymer-element> + get selection() { + return this.$.content.selection; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-flow-event-sub-view', + tr.model.FlowEvent, + { + multi: true, + title: 'Flow Events', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html index 1ecf2d02e35..dd526e655b0 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_frame_sub_view.html @@ -6,46 +6,53 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/model/event_set.html"> -<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> +<link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> + +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-multi-frame-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + set selection(selection) { + Polymer.dom(this).textContent = ''; + var realView = document.createElement('tr-ui-a-multi-event-sub-view'); + realView.eventsHaveDuration = false; + realView.eventsHaveSubRows = false; + + Polymer.dom(this).appendChild(realView); + realView.setSelectionWithoutErrorChecks(selection); + + this.currentSelection_ = selection; + }, + + get selection() { + return this.currentSelection_; + }, -<polymer-element name="tr-ui-a-multi-frame-sub-view" - extends="tr-ui-a-sub-view"> - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - set selection(selection) { - this.textContent = ''; - var realView = document.createElement('tr-ui-a-multi-event-sub-view'); - realView.eventsHaveDuration = false; - realView.eventsHaveSubRows = false; - - this.appendChild(realView); - realView.setSelectionWithoutErrorChecks(selection); - - this.currentSelection_ = selection; - }, - - get selection() { - return this.currentSelection_; - }, - - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - var selection = new tr.model.EventSet(); - this.currentSelection_.forEach(function(frameEvent) { - frameEvent.associatedEvents.forEach(function(event) { - selection.push(event); - }); + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + var selection = new tr.model.EventSet(); + this.currentSelection_.forEach(function(frameEvent) { + frameEvent.associatedEvents.forEach(function(event) { + selection.push(event); }); - return selection; - } - }); - </script> -</polymer-element> + }); + return selection; + } +}); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-frame-sub-view', + tr.model.Frame, + { + multi: true, + title: 'Frames', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html index 7d6adb91c4e..9701827e709 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_instant_event_sub_view.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> -<polymer-element name="tr-ui-a-multi-instant-event-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-instant-event-sub-view'> <template> <style> :host { @@ -18,30 +17,32 @@ found in the LICENSE file. </style> <div id='content'></div> </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - set selection(selection) { - this.$.content.textContent = ''; - var realView = document.createElement('tr-ui-a-multi-event-sub-view'); - realView.eventsHaveDuration = false; - realView.eventsHaveSubRows = false; - - this.$.content.appendChild(realView); - realView.setSelectionWithoutErrorChecks(selection); - - this.currentSelection_ = selection; - }, - - get selection() { - return this.currentSelection_; - } - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-multi-instant-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + set selection(selection) { + Polymer.dom(this.$.content).textContent = ''; + var realView = document.createElement('tr-ui-a-multi-event-sub-view'); + realView.eventsHaveDuration = false; + realView.eventsHaveSubRows = false; + + Polymer.dom(this.$.content).appendChild(realView); + realView.setSelectionWithoutErrorChecks(selection); + + this.currentSelection_ = selection; + }, + + get selection() { + return this.currentSelection_; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html index 8241ab16aa2..d95ab8ba29b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_object_sub_view.html @@ -5,89 +5,107 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-multi-object-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-object-sub-view'> <template> <style> :host { display: flex; + font-size: 12px; } </style> <tr-ui-b-table id="content"></tr-ui-b-table> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, +Polymer({ + is: 'tr-ui-a-multi-object-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - ready: function() { - this.$.content.showHeader = false; - }, + created: function() { + this.currentSelection_ = undefined; + }, - get selection() { - return this.currentSelection_; - }, + ready: function() { + this.$.content.showHeader = false; + }, - set selection(selection) { - this.currentSelection_ = selection; + get selection() { + return this.currentSelection_; + }, - var objectEvents = tr.b.asArray(selection).sort( - tr.b.Range.compareByMinTimes); + set selection(selection) { + this.currentSelection_ = selection; - var timeSpanConfig = { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: this.ownerDocument - }; - var table = this.$.content; - table.tableColumns = [ - { - title: 'First', - value: function(event) { - if (event instanceof tr.model.ObjectSnapshot) - return tr.v.ui.createScalarSpan(event.ts, timeSpanConfig); + var objectEvents = tr.b.asArray(selection).sort( + tr.b.Range.compareByMinTimes); - var spanEl = document.createElement('span'); - spanEl.appendChild(tr.v.ui.createScalarSpan( - event.creationTs, timeSpanConfig)); - spanEl.appendChild(tr.ui.b.createSpan({ - textContent: '-', - marginLeft: '4px', - marginRight: '4px' - })); - if (event.deletionTs != Number.MAX_VALUE) { - spanEl.appendChild(tr.v.ui.createScalarSpan( - event.deletionTs, timeSpanConfig)); - } - return spanEl; - }, - width: '200px' + var timeSpanConfig = { + unit: tr.b.Unit.byName.timeStampInMs, + ownerDocument: this.ownerDocument + }; + var table = this.$.content; + table.tableColumns = [ + { + title: 'First', + value: function(event) { + if (event instanceof tr.model.ObjectSnapshot) + return tr.v.ui.createScalarSpan(event.ts, timeSpanConfig); + + var spanEl = document.createElement('span'); + Polymer.dom(spanEl).appendChild(tr.v.ui.createScalarSpan( + event.creationTs, timeSpanConfig)); + Polymer.dom(spanEl).appendChild(tr.ui.b.createSpan({ + textContent: '-', + marginLeft: '4px', + marginRight: '4px' + })); + if (event.deletionTs !== Number.MAX_VALUE) { + Polymer.dom(spanEl).appendChild(tr.v.ui.createScalarSpan( + event.deletionTs, timeSpanConfig)); + } + return spanEl; }, - { - title: 'Second', - value: function(event) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return new tr.model.EventSet(event); - }, event.userFriendlyName); - return linkEl; - }, - width: '100%' - } - ]; - table.tableRows = objectEvents; - table.rebuild(); - } - }); - </script> -</polymer-element> + width: '200px' + }, + { + title: 'Second', + value: function(event) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent(function() { + return new tr.model.EventSet(event); + }, event.userFriendlyName); + return linkEl; + }, + width: '100%' + } + ]; + table.tableRows = objectEvents; + table.rebuild(); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-object-sub-view', + tr.model.ObjectInstance, + { + multi: true, + title: 'Object Instances', + }); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-object-sub-view', + tr.model.ObjectSnapshot, + { + multi: true, + title: 'Object Snapshots', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html index 2fc86530efb..2c7b8773f19 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_power_sample_sub_view.html @@ -10,8 +10,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/frame_power_usage_chart.html"> <link rel="import" href="/tracing/ui/analysis/power_sample_summary_table.html"> -<polymer-element name="tr-ui-a-multi-power-sample-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-power-sample-sub-view'> <template> <style> :host { @@ -34,14 +33,17 @@ found in the LICENSE file. <tr-ui-a-frame-power-usage-chart id="chart"> </tr-ui-a-frame-power-usage-chart> </template> -</polymer-element> +</dom-module> <script> 'use strict'; // TODO(charliea): Add a dropdown that allows the user to select which type of // power sample analysis view they want (e.g. table of samples, graph). -Polymer('tr-ui-a-multi-power-sample-sub-view', { +Polymer({ + is: 'tr-ui-a-multi-power-sample-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + ready: function() { this.currentSelection_ = undefined; }, @@ -64,4 +66,12 @@ Polymer('tr-ui-a-multi-power-sample-sub-view', { this.$.chart.setData(this.selection, vSyncTimestamps); } }); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-power-sample-sub-view', + tr.model.PowerSample, + { + multi: true, + title: 'Power Samples', + }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html index ab570d12da7..4b515be4459 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_sample_sub_view.html @@ -6,13 +6,13 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/multi_dimensional_view.html"> +<link rel="import" href="/tracing/base/range.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-multi-sample-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-sample-sub-view'> <template> <style> :host { display: block; } @@ -32,6 +32,9 @@ found in the LICENSE file. margin: 1px; margin-right: 2px; } + tr-ui-b-table { + font-size: 12px; + } </style> <div id="control"> Sample View Option @@ -39,230 +42,245 @@ found in the LICENSE file. <tr-ui-b-table id="table"> </tr-ui-b-table> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; - - (function() { - var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder; - var SAMPLE_TYPE = { - COMPILER: 'compiler', - EXTERNAL: 'external', - GC: 'gc', - NATIVEV8: '[native v8]', - OTHER: 'other', - UNKNOWN: 'unknown' - }; +(function() { + var MultiDimensionalViewBuilder = tr.b.MultiDimensionalViewBuilder; + var SAMPLE_TYPE = { + COMPILER: 'compiler', + EXTERNAL: 'external', + GC: 'gc', + NATIVEV8: '[native v8]', + OTHER: 'other', + UNKNOWN: 'unknown' + }; - Polymer({ - created: function() { - this.viewOption_ = undefined; - this.selection_ = undefined; - }, + Polymer({ + is: 'tr-ui-a-multi-sample-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - ready: function() { - var viewSelector = tr.ui.b.createSelector( - this, 'viewOption', 'tracing.ui.analysis.multi_sample_sub_view', - MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW, - [ - { - label: 'Top-down (Tree)', - value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW - }, - { - label: 'Top-down (Heavy)', - value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW - }, - { - label: 'Bottom-up (Heavy)', - value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW - } - ]); - this.$.control.appendChild(viewSelector); - this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; - }, + created: function() { + this.viewOption_ = undefined; + this.selection_ = undefined; + }, - get selection() { - return this.selection_; - }, - - set selection(selection) { - this.selection_ = selection; - this.updateContents_(); - }, + ready: function() { + var viewSelector = tr.ui.b.createSelector( + this, 'viewOption', 'tracing.ui.analysis.multi_sample_sub_view', + MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW, + [ + { + label: 'Top-down (Tree)', + value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_TREE_VIEW + }, + { + label: 'Top-down (Heavy)', + value: MultiDimensionalViewBuilder.ViewType.TOP_DOWN_HEAVY_VIEW + }, + { + label: 'Bottom-up (Heavy)', + value: MultiDimensionalViewBuilder.ViewType.BOTTOM_UP_HEAVY_VIEW + } + ]); + Polymer.dom(this.$.control).appendChild(viewSelector); + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + }, - get viewOption() { - return this.viewOption_; - }, + get selection() { + return this.selection_; + }, - set viewOption(viewOption) { - this.viewOption_ = viewOption; - this.updateContents_(); - }, + set selection(selection) { + this.selection_ = selection; + this.updateContents_(); + }, - createSamplingSummary_: function(selection, viewOption) { - var builder = new MultiDimensionalViewBuilder( - 1 /* dimensions */, 1 /* valueCount */); - var samples = selection.getEventsOrganizedByBaseType().sample; + get viewOption() { + return this.viewOption_; + }, - samples.forEach(function(sample) { - builder.addPath([sample.getUserFriendlyStackTrace().reverse()], - [1], MultiDimensionalViewBuilder.ValueKind.SELF); - }); + set viewOption(viewOption) { + this.viewOption_ = viewOption; + this.updateContents_(); + }, - return builder.buildView(viewOption); - }, + createSamplingSummary_: function(selection, viewOption) { + var builder = new MultiDimensionalViewBuilder( + 1 /* dimensions */, 1 /* valueCount */); + var samples = selection.filter(function(event) { + return event instanceof tr.model.Sample; + }); - // Constructs function name and file name of sample - // if it is compiler, external, gc, other, or unknown. - processTypedSampleRow_: function(row) { - var title = row.title[0]; - switch (title) { - case SAMPLE_TYPE.COMPILER: - case SAMPLE_TYPE.EXTERNAL: - case SAMPLE_TYPE.GC: - case SAMPLE_TYPE.OTHER: - row.functionName = title; - row.fileName = 'N/A'; - return true; - case SAMPLE_TYPE.UNKNOWN: - row.functionName = SAMPLE_TYPE.UNKNOWN; - row.fileName = SAMPLE_TYPE.UNKNOWN; - return true; - default: - return false; - } - }, + samples.forEach(function(sample) { + builder.addPath([sample.getUserFriendlyStackTrace().reverse()], + [1], MultiDimensionalViewBuilder.ValueKind.SELF); + }); - // Constructs function name and file name of native v8 sample. - processNativeV8SampleRow_: function(row) { - var title = row.title[0]; - if (!title.includes(SAMPLE_TYPE.NATIVEV8)) - return false; - var arr = title.split(SAMPLE_TYPE.NATIVEV8); - row.functionName = arr[0].trim(); - if (row.functionName === '') - row.functionName = '(anonymous function)'; - row.fileName = SAMPLE_TYPE.NATIVEV8; - var fileNameSuffix = arr[1].trim(); - if (fileNameSuffix !== '') - row.fileName += ' ' + fileNameSuffix; - return true; - }, + return builder.buildView(viewOption); + }, - // Constructs function name and file name for sample. - processGeneralSampleRow_: function(row) { - var title = row.title[0]; - var idx = title.lastIndexOf(' '); - if (idx === -1) { + // Constructs function name and file name of sample + // if it is compiler, external, gc, other, or unknown. + processTypedSampleRow_: function(row) { + var title = row.title[0]; + switch (title) { + case SAMPLE_TYPE.COMPILER: + case SAMPLE_TYPE.EXTERNAL: + case SAMPLE_TYPE.GC: + case SAMPLE_TYPE.OTHER: row.functionName = title; - row.fileName = 'unknown'; - return; - } - var prefix = title.substr(0, idx); - var suffix = title.substr(idx + 1); - if (suffix.startsWith('v8/')) { - row.functionName = suffix; - row.fileName = 'unknown'; - } else if (suffix === '') { - row.functionName = prefix; - row.fileName = 'unknown'; - } else if (prefix === '') { - row.functionName = '(anonymous function)'; - row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); - } else { - row.functionName = prefix; - row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); - } - }, + row.fileName = 'N/A'; + return true; + case SAMPLE_TYPE.UNKNOWN: + row.functionName = SAMPLE_TYPE.UNKNOWN; + row.fileName = SAMPLE_TYPE.UNKNOWN; + return true; + default: + return false; + } + }, - processSampleRows_: function(rows) { - rows.forEach(function(row) { - if (!this.processTypedSampleRow_(row) && - !this.processNativeV8SampleRow_(row)) - this.processGeneralSampleRow_(row); - this.processSampleRows_(row.subRows); - }, this); - }, + // Constructs function name and file name of native v8 sample. + processNativeV8SampleRow_: function(row) { + var title = row.title[0]; + if (!title.includes(SAMPLE_TYPE.NATIVEV8)) + return false; + var arr = title.split(SAMPLE_TYPE.NATIVEV8); + row.functionName = arr[0].trim(); + if (row.functionName === '') + row.functionName = '(anonymous function)'; + row.fileName = SAMPLE_TYPE.NATIVEV8; + var fileNameSuffix = arr[1].trim(); + if (fileNameSuffix !== '') + row.fileName += ' ' + fileNameSuffix; + return true; + }, - updateContents_: function() { - if (this.selection === undefined) { - this.$.table.tableColumns = []; - this.$.table.tableRows = []; - this.$.table.rebuild(); - return; - } + // Constructs function name and file name for sample. + processGeneralSampleRow_: function(row) { + var title = row.title[0]; + var idx = title.lastIndexOf(' '); + if (idx === -1) { + row.functionName = title; + row.fileName = 'unknown'; + return; + } + var prefix = title.substr(0, idx); + var suffix = title.substr(idx + 1); + if (suffix.startsWith('v8/')) { + row.functionName = suffix; + row.fileName = 'unknown'; + } else if (suffix === '') { + row.functionName = prefix; + row.fileName = 'unknown'; + } else if (prefix === '') { + row.functionName = '(anonymous function)'; + row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); + } else { + row.functionName = prefix; + row.fileName = suffix.substr(suffix.lastIndexOf('/') + 1); + } + }, - var samplingData = this.createSamplingSummary_( - this.selection, this.viewOption); - var total = samplingData.values[0].total; - var columns = [ - this.createPercentColumn_('Total', total), - this.createSamplesColumn_('Total'), - this.createPercentColumn_('Self', total), - this.createSamplesColumn_('Self'), - { - title: 'Function Name', - value: function(row) { return row.functionName; }, - width: '150px', - cmp: function(a, b) { - return a.functionName.localeCompare(b.functionName); - }, - showExpandButtons: true - }, - { - title: 'Location', - value: function(row) { return row.fileName; }, - width: '250px', - cmp: function(a, b) { - return a.fileName.localeCompare(b.fileName); - } - } - ]; + processSampleRows_: function(rows) { + rows.forEach(function(row) { + if (!this.processTypedSampleRow_(row) && + !this.processNativeV8SampleRow_(row)) + this.processGeneralSampleRow_(row); + this.processSampleRows_(row.subRows); + }, this); + }, - this.processSampleRows_(samplingData.subRows); - this.$.table.tableColumns = columns; - this.$.table.sortColumnIndex = 1 /* Total samples */; - this.$.table.sortDescending = true; - this.$.table.tableRows = samplingData.subRows; + updateContents_: function() { + if (this.selection === undefined) { + this.$.table.tableColumns = []; + this.$.table.tableRows = []; this.$.table.rebuild(); - }, - - createPercentColumn_: function(title, samplingDataTotal) { - var field = title.toLowerCase(); - return { - title: title + ' percent', - value: function(row) { - var percent = row.values[0][field] / samplingDataTotal; - - var span = document.createElement('tr-v-ui-scalar-span'); - span.value = (percent * 100).toFixed(2); - span.percentage = percent; - span.unit = tr.v.Unit.byName.unitlessNumber; - return span; + return; + } - }.bind(this), - width: '60px', + var samplingData = this.createSamplingSummary_( + this.selection, this.viewOption); + var total = samplingData.values[0].total; + var columns = [ + this.createPercentColumn_('Total', total), + this.createSamplesColumn_('Total'), + this.createPercentColumn_('Self', total), + this.createSamplesColumn_('Self'), + { + title: 'Function Name', + value: function(row) { return row.functionName; }, + width: '150px', cmp: function(a, b) { - return a.values[0][field] - b.values[0][field]; - } - }; - }, - - createSamplesColumn_: function(title) { - var field = title.toLowerCase(); - return { - title: title + ' samples', - value: function(row) { - return row.values[0][field]; + return a.functionName.localeCompare(b.functionName); }, - width: '60px', + showExpandButtons: true + }, + { + title: 'Location', + value: function(row) { return row.fileName; }, + width: '250px', cmp: function(a, b) { - return a.values[0][field] - b.values[0][field]; + return a.fileName.localeCompare(b.fileName); } - }; - } + } + ]; + + this.processSampleRows_(samplingData.subRows); + this.$.table.tableColumns = columns; + this.$.table.sortColumnIndex = 1 /* Total samples */; + this.$.table.sortDescending = true; + this.$.table.tableRows = samplingData.subRows; + this.$.table.rebuild(); + }, + + createPercentColumn_: function(title, samplingDataTotal) { + var field = title.toLowerCase(); + return { + title: title + ' percent', + value: function(row) { + return tr.v.ui.createScalarSpan( + row.values[0][field] / samplingDataTotal, { + customContextRange: tr.b.Range.PERCENT_RANGE, + unit: tr.b.Unit.byName.normalizedPercentage, + context: { minimumFractionDigits: 2, maximumFractionDigits: 2 }, + rightAlign: true + }); + }, + width: '60px', + cmp: function(a, b) { + return a.values[0][field] - b.values[0][field]; + } + }; + }, + + createSamplesColumn_: function(title) { + var field = title.toLowerCase(); + return { + title: title + ' samples', + value: function(row) { + return tr.v.ui.createScalarSpan(row.values[0][field], { + unit: tr.b.Unit.byName.unitlessNumber, + context: { maximumFractionDigits: 0 }, + rightAlign: true + }); + }, + width: '60px', + cmp: function(a, b) { + return a.values[0][field] - b.values[0][field]; + } + }; + } + }); + + tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-sample-sub-view', + tr.model.Sample, + { + multi: true, + title: 'Samples', }); - })(); - </script> -</polymer-element> +})(); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html index 54c1c324ab2..08e41c64d37 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_slice_sub_view.html @@ -9,8 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/related_events.html"> -<polymer-element name="tr-ui-a-multi-thread-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-thread-slice-sub-view'> <template> <style> :host { @@ -27,68 +26,78 @@ found in the LICENSE file. </style> <div id="content"></div> </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.selection_ = undefined; - }, - - get selection() { - return this.selection_; - }, - - set selection(selection) { - this.selection_ = selection; - - // TODO(nduca): This is a gross hack for cc Frame Viewer, but its only - // the frame viewer that needs this feature, so ~shrug~. - // We check for its presence so that we do not have a hard dependency - // on frame viewer. - if (tr.isExported('tr.ui.e.chrome.cc.RasterTaskSelection')) { - if (tr.ui.e.chrome.cc.RasterTaskSelection.supports(selection)) { - var ltvSelection = new tr.ui.e.chrome.cc.RasterTaskSelection( - selection); - - var ltv = new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView(); - ltv.objectSnapshot = ltvSelection.containingSnapshot; - ltv.selection = ltvSelection; - ltv.extraHighlightsByLayerId = ltvSelection.extraHighlightsByLayerId; - - this.$.content.textContent = ''; - this.$.content.appendChild(ltv); - - this.requiresTallView_ = true; - return; - } +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-multi-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.selection_ = undefined; + }, + + get selection() { + return this.selection_; + }, + + set selection(selection) { + this.selection_ = selection; + + // TODO(nduca): This is a gross hack for cc Frame Viewer, but its only + // the frame viewer that needs this feature, so ~shrug~. + // We check for its presence so that we do not have a hard dependency + // on frame viewer. + if (tr.isExported('tr.ui.e.chrome.cc.RasterTaskSelection')) { + if (tr.ui.e.chrome.cc.RasterTaskSelection.supports(selection)) { + var ltvSelection = new tr.ui.e.chrome.cc.RasterTaskSelection( + selection); + + var ltv = new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView(); + ltv.objectSnapshot = ltvSelection.containingSnapshot; + ltv.selection = ltvSelection; + ltv.extraHighlightsByLayerId = ltvSelection.extraHighlightsByLayerId; + + Polymer.dom(this.$.content).textContent = ''; + Polymer.dom(this.$.content).appendChild(ltv); + + this.requiresTallView_ = true; + return; } + } - this.$.content.textContent = ''; - - var mesv = document.createElement('tr-ui-a-multi-event-sub-view'); - mesv.selection = selection; - this.$.content.appendChild(mesv); - - var relatedEvents = document.createElement('tr-ui-a-related-events'); - relatedEvents.setRelatedEvents(selection); + Polymer.dom(this.$.content).textContent = ''; - if (relatedEvents.hasRelatedEvents()) { - this.$.content.appendChild(relatedEvents); - } - }, + var mesv = document.createElement('tr-ui-a-multi-event-sub-view'); + mesv.selection = selection; + Polymer.dom(this.$.content).appendChild(mesv); - get requiresTallView() { - if (this.$.content.children.length === 0) - return false; - var childTagName = this.$.content.children[0].tagName; - if (childTagName === 'TR-UI-A-MULTI-EVENT-SUB-VIEW') - return false; + var relatedEvents = document.createElement('tr-ui-a-related-events'); + relatedEvents.setRelatedEvents(selection); - // Using raster task view. - return true; + if (relatedEvents.hasRelatedEvents()) { + Polymer.dom(this.$.content).appendChild(relatedEvents); } - }); - </script> -</polymer-element> + }, + + get requiresTallView() { + if (this.$.content.children.length === 0) + return false; + var childTagName = this.$.content.children[0].tagName; + if (childTagName === 'TR-UI-A-MULTI-EVENT-SUB-VIEW') + return false; + + // Using raster task view. + return true; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-thread-slice-sub-view', + tr.model.ThreadSlice, + { + multi: true, + title: 'Slices', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html index 6fba8d2e857..31bd29e3567 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_thread_time_slice_sub_view.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/multi_event_sub_view.html"> -<polymer-element name="tr-ui-a-multi-thread-time-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-thread-time-slice-sub-view'> <template> <style> :host { @@ -21,22 +20,32 @@ found in the LICENSE file. </style> <tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-multi-thread-time-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - ready: function() { - this.$.content.eventsHaveSubRows = false; - }, + ready: function() { + this.$.content.eventsHaveSubRows = false; + }, - get selection() { - return this.$.content.selection; - }, + get selection() { + return this.$.content.selection; + }, - set selection(selection) { - this.$.content.setSelectionWithoutErrorChecks(selection); - } + set selection(selection) { + this.$.content.setSelectionWithoutErrorChecks(selection); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-thread-time-slice-sub-view', + tr.model.ThreadTimeSlice, + { + multi: true, + title: 'Thread Timeslices', }); - </script> -</polymer-element> +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html index 34b70762345..0caf158532c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/multi_user_expectation_sub_view.html @@ -11,8 +11,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/user_expectation_related_samples_table.html"> -<polymer-element name="tr-ui-a-multi-user-expectation-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-multi-user-expectation-sub-view'> <template> <style> :host { @@ -29,42 +28,52 @@ found in the LICENSE file. <tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table> </div> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, +Polymer({ + is: 'tr-ui-a-multi-interaction-record-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - set selection(selection) { - this.currentSelection_ = selection; - this.$.realView.setSelectionWithoutErrorChecks(selection); + created: function() { + this.currentSelection_ = undefined; + }, - this.currentSelection_ = selection; + set selection(selection) { + this.currentSelection_ = selection; + this.$.realView.setSelectionWithoutErrorChecks(selection); - this.$.relatedSamples.selection = selection; - if (this.$.relatedSamples.hasRelatedSamples()) - this.$.events.style.display = ''; - else - this.$.events.style.display = 'none'; - }, + this.currentSelection_ = selection; - get selection() { - return this.currentSelection_; - }, + this.$.relatedSamples.selection = selection; + if (this.$.relatedSamples.hasRelatedSamples()) + this.$.events.style.display = ''; + else + this.$.events.style.display = 'none'; + }, - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - var selection = new tr.model.EventSet(); - this.currentSelection_.forEach(function(ir) { - ir.associatedEvents.forEach(function(event) { - selection.push(event); - }); + get selection() { + return this.currentSelection_; + }, + + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + var selection = new tr.model.EventSet(); + this.currentSelection_.forEach(function(ir) { + ir.associatedEvents.forEach(function(event) { + selection.push(event); }); - return selection; - } - }); - </script> -</polymer-element> + }); + return selection; + } +}); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-user-expectation-sub-view', + tr.model.um.UserExpectation, + { + multi: true, + title: 'User Expectations', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html index f94aa245f6e..e07e2e4ea95 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_instance_view.html @@ -15,7 +15,7 @@ tr.exportTo('tr.ui.analysis', function() { var ObjectInstanceView = tr.ui.b.define('object-instance-view'); ObjectInstanceView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.objectInstance_ = undefined; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html index a50747beefa..4363e9fb466 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/object_snapshot_view.html @@ -15,7 +15,7 @@ tr.exportTo('tr.ui.analysis', function() { var ObjectSnapshotView = tr.ui.b.define('object-snapshot-view'); ObjectSnapshotView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.objectSnapshot_ = undefined; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html index ab314e42589..6325bd8a691 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table.html @@ -6,124 +6,132 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> +<link rel="import" href="/tracing/base/unit_scale.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/base/table.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-power-sample-summary-table"> +<dom-module id='tr-ui-a-power-sample-summary-table'> <template> + <style> + tr-ui-b-table { + font-size: 12px; + } + </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.$.table.tableColumns = [ - { - title: 'Min power', - width: '100px', - value: function(row) { - return tr.v.Unit.byName.powerInWatts.format(row.min); - } - }, - { - title: 'Max power', - width: '100px', - value: function(row) { - return tr.v.Unit.byName.powerInWatts.format(row.max); - } - }, - { - title: 'Time-weighted average', - width: '100px', - value: function(row) { - return tr.v.Unit.byName.powerInWatts.format( - row.timeWeightedAverage); - } - }, - { - title: 'Energy consumed', - width: '100px', - value: function(row) { - return tr.v.Unit.byName.energyInJoules.format(row.energyConsumed); - } - }, - { - title: 'Sample count', - width: '100%', - value: function(row) { return row.sampleCount; } +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-power-sample-summary-table', + + ready: function() { + this.$.table.tableColumns = [ + { + title: 'Min power', + width: '100px', + value: function(row) { + return tr.b.Unit.byName.powerInWatts.format(row.min); + } + }, + { + title: 'Max power', + width: '100px', + value: function(row) { + return tr.b.Unit.byName.powerInWatts.format(row.max); + } + }, + { + title: 'Time-weighted average', + width: '100px', + value: function(row) { + return tr.b.Unit.byName.powerInWatts.format( + row.timeWeightedAverageInW); + } + }, + { + title: 'Energy consumed', + width: '100px', + value: function(row) { + return tr.b.Unit.byName.energyInJoules.format(row.energyConsumedInJ); } - ]; - this.samples = new tr.model.EventSet(); - }, - - get samples() { - return this.samples_; - }, - - set samples(samples) { - if (samples === this.samples) - return; - - this.samples_ = - (samples === undefined) ? new tr.model.EventSet() : samples; - this.updateContents_(); - }, - - updateContents_: function() { - if (this.samples.length === 0) { - this.$.table.tableRows = []; - } else { - this.$.table.tableRows = [{ - min: this.getMin(), - max: this.getMax(), - timeWeightedAverage: this.getTimeWeightedAverage(), - energyConsumed: this.getEnergyConsumed(), - sampleCount: this.samples.length - }]; + }, + { + title: 'Sample count', + width: '100%', + value: function(row) { return row.sampleCount; } } - - this.$.table.rebuild(); - }, - - getMin: function() { - return Math.min.apply(null, this.samples.map(function(sample) { - return sample.power; - })); - }, - - getMax: function() { - return Math.max.apply(null, this.samples.map(function(sample) { - return sample.power; - })); - }, - - /** - * Returns a time-weighted average of the power consumption (Watts) - * in between the first sample (inclusive) and last sample (exclusive). - */ - getTimeWeightedAverage: function() { - var energyConsumed = this.getEnergyConsumed(); - - if (energyConsumed === 'N/A') - return 'N/A'; - - // Divide by 1000 to convert milliseconds to seconds. - var durationInSeconds = this.samples.bounds.duration / 1000; - - // Convert energy to power in milliwatts by dividing by time in seconds. - return this.getEnergyConsumed() / durationInSeconds; - }, - - getEnergyConsumed: function() { - if (this.samples.length < 2) - return 'N/A'; - - var bounds = this.samples.bounds; - var series = tr.b.getFirstElement(this.samples).series; - return series.getEnergyConsumed(bounds.min, bounds.max); + ]; + this.samples = new tr.model.EventSet(); + }, + + get samples() { + return this.samples_; + }, + + set samples(samples) { + if (samples === this.samples) + return; + + this.samples_ = + (samples === undefined) ? new tr.model.EventSet() : samples; + this.updateContents_(); + }, + + updateContents_: function() { + if (this.samples.length === 0) { + this.$.table.tableRows = []; + } else { + this.$.table.tableRows = [{ + min: this.getMin(), + max: this.getMax(), + timeWeightedAverageInW: this.getTimeWeightedAverageInW(), + energyConsumedInJ: this.getEnergyConsumedInJ(), + sampleCount: this.samples.length + }]; } - }); - </script> -</polymer-element> + + this.$.table.rebuild(); + }, + + getMin: function() { + return Math.min.apply(null, this.samples.map(function(sample) { + return sample.powerInW; + })); + }, + + getMax: function() { + return Math.max.apply(null, this.samples.map(function(sample) { + return sample.powerInW; + })); + }, + + /** + * Returns a time-weighted average of the power consumption (Watts) + * in between the first sample (inclusive) and last sample (exclusive). + */ + getTimeWeightedAverageInW: function() { + var energyConsumedInJ = this.getEnergyConsumedInJ(); + + if (energyConsumedInJ === 'N/A') + return 'N/A'; + + var durationInS = tr.b.convertUnit(this.samples.bounds.duration, + tr.b.UnitScale.Metric.MILLI, tr.b.UnitScale.Metric.NONE); + + return energyConsumedInJ / durationInS; + }, + + + getEnergyConsumedInJ: function() { + if (this.samples.length < 2) + return 'N/A'; + + var bounds = this.samples.bounds; + var series = tr.b.getFirstElement(this.samples).series; + return series.getEnergyConsumedInJ(bounds.min, bounds.max); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html index 82cc98dc1fb..151a36459ea 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/power_sample_summary_table_test.html @@ -58,8 +58,8 @@ tr.b.unittest.testSuite(function() { assert.lengthOf(table.$.table.tableRows, 1); assert.equal(table.$.table.tableRows[0].min, 1); assert.equal(table.$.table.tableRows[0].max, 1); - assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 'N/A'); - assert.equal(table.$.table.tableRows[0].energyConsumed, 'N/A'); + assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 'N/A'); + assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 'N/A'); assert.equal(table.$.table.tableRows[0].sampleCount, 1); }); @@ -75,8 +75,8 @@ tr.b.unittest.testSuite(function() { assert.lengthOf(table.$.table.tableRows, 1); assert.equal(table.$.table.tableRows[0].min, 1); assert.equal(table.$.table.tableRows[0].max, 2); - assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 1); - assert.equal(table.$.table.tableRows[0].energyConsumed, 1); + assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 1); + assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 1); assert.equal(table.$.table.tableRows[0].sampleCount, 2); }); @@ -93,8 +93,8 @@ tr.b.unittest.testSuite(function() { assert.lengthOf(table.$.table.tableRows, 1); assert.equal(table.$.table.tableRows[0].min, 1); assert.equal(table.$.table.tableRows[0].max, 3); - assert.equal(table.$.table.tableRows[0].timeWeightedAverage, 1.5); - assert.equal(table.$.table.tableRows[0].energyConsumed, 3); + assert.equal(table.$.table.tableRows[0].timeWeightedAverageInW, 1.5); + assert.equal(table.$.table.tableRows[0].energyConsumedInJ, 3); assert.equal(table.$.table.tableRows[0].sampleCount, 3); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html new file mode 100644 index 00000000000..65cf075a003 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior.html @@ -0,0 +1,59 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/raf.html"> + +<script> +'use strict'; + +tr.exportTo('tr.ui.analysis', function() { + + var RebuildableBehavior = { + rebuild: function() { + /** + * Rebuild the pane if necessary. + * + * This method is not intended to be overriden by subclasses. Please + * override scheduleRebuild_() instead. + */ + if (!this.paneDirty_) { + // Avoid rebuilding unnecessarily as it breaks things like table + // selection. + return; + } + + this.paneDirty_ = false; + this.onRebuild_(); + }, + + /** + * Mark the UI state of the pane as dirty and schedule a rebuild. + * + * This method is intended to be called by subclasses. + */ + scheduleRebuild_: function() { + if (this.paneDirty_) + return; + this.paneDirty_ = true; + tr.b.requestAnimationFrame(this.rebuild.bind(this)); + }, + + /** + * Called when the pane is dirty and a rebuild is triggered. + * + * This method is intended to be overriden by subclasses (instead of + * directly overriding rebuild()). + */ + onRebuild_: function() { + } + }; + + return { + RebuildableBehavior: RebuildableBehavior + }; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html new file mode 100644 index 00000000000..4b7ed3a164f --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/rebuildable_behavior_test.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + Polymer({ + is: 'tr-ui-analysis-rebuildable-test-element', + behaviors: [tr.ui.analysis.RebuildableBehavior] + }); + + test('rebuild', function() { + var el = document.createElement('tr-ui-analysis-rebuildable-test-element'); + var didFireOnRebuild; + el.onRebuild_ = function() { + assert.strictEqual(this, el); + didFireOnRebuild = true; + }; + + function checkManualRebuild(expectedDidFireOnRebuild) { + didFireOnRebuild = false; + el.rebuild(); + assert.strictEqual(didFireOnRebuild, expectedDidFireOnRebuild); + } + + function checkRAFRebuild(expectedDidFireOnRebuild) { + didFireOnRebuild = false; + tr.b.forcePendingRAFTasksToRun(); + assert.strictEqual(didFireOnRebuild, expectedDidFireOnRebuild); + } + + // No rebuilds should occur when not scheduled. + checkManualRebuild(false); + checkRAFRebuild(false); + + // Single rebuild should occur when scheduled once. + el.scheduleRebuild_(); + checkManualRebuild(true); + checkManualRebuild(false); + + el.scheduleRebuild_(); + checkRAFRebuild(true); + checkRAFRebuild(false); + + // Only a single rebuild should occur even when scheduled multiple times. + el.scheduleRebuild_(); + el.scheduleRebuild_(); + checkManualRebuild(true); + checkRAFRebuild(false); + checkManualRebuild(false); + + el.scheduleRebuild_(); + el.scheduleRebuild_(); + checkRAFRebuild(true); + checkRAFRebuild(false); + checkManualRebuild(false); + }); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html index faec4d0471e..142887260ad 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/related_events.html @@ -13,7 +13,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/table.html"> -<polymer-element name="tr-ui-a-related-events"> +<dom-module id='tr-ui-a-related-events'> <template> <style> :host { @@ -23,241 +23,302 @@ found in the LICENSE file. #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +function* getEventInFlowEvents(event) { + if (!event.inFlowEvents) + return; + yield * event.inFlowEvents; +} - Polymer({ - ready: function() { - this.eventGroups_ = []; - this.cancelFunctions_ = []; +function* getEventOutFlowEvents(event) { + if (!event.outFlowEvents) + return; + yield * event.outFlowEvents; +} - this.$.table.tableColumns = [ - { - title: 'Event(s)', - value: function(row) { - var typeEl = document.createElement('span'); - typeEl.innerText = row.type; - if (row.tooltip) - typeEl.title = row.tooltip; - return typeEl; - }, - width: '150px' +function* getEventAncestors(event) { + if (!event.enumerateAllAncestors) + return; + yield * event.enumerateAllAncestors(); +} + +function* getEventDescendents(event) { + if (!event.enumerateAllDescendents) + return; + yield * event.enumerateAllDescendents(); +} + +Polymer({ + is: 'tr-ui-a-related-events', + + ready: function() { + this.eventGroups_ = []; + this.cancelFunctions_ = []; + + this.$.table.tableColumns = [ + { + title: 'Event(s)', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.type; + if (row.tooltip) + typeEl.title = row.tooltip; + return typeEl; }, - { - title: 'Link', - width: '100%', - value: function(row) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - if (row.name) - linkEl.setSelectionAndContent(row.selection, row.name); - else - linkEl.selection = row.selection; - return linkEl; - } + width: '150px' + }, + { + title: 'Link', + width: '100%', + value: function(row) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + if (row.name) + linkEl.setSelectionAndContent(row.selection, row.name); + else + linkEl.selection = row.selection; + return linkEl; } - ]; - }, + } + ]; + }, - hasRelatedEvents: function() { - return (this.eventGroups_ && this.eventGroups_.length > 0); - }, + hasRelatedEvents: function() { + return (this.eventGroups_ && this.eventGroups_.length > 0); + }, - setRelatedEvents: function(eventSet) { - this.cancelAllTasks_(); - this.eventGroups_ = []; - this.addConnectedFlows_(eventSet); - this.addConnectedEvents_(eventSet); - this.addOverlappingSamples_(eventSet); - this.updateContents_(); - }, + setRelatedEvents: function(eventSet) { + this.cancelAllTasks_(); + this.eventGroups_ = []; + this.addRuntimeCallStats_(eventSet); + this.addV8GCObjectStats_(eventSet); + this.addV8Slices_(eventSet); + this.addConnectedFlows_(eventSet); + this.addConnectedEvents_(eventSet); + this.addOverlappingSamples_(eventSet); + this.updateContents_(); + }, - addConnectedFlows_: function(eventSet) { - var classifier = new tr.ui.analysis.FlowClassifier(); - eventSet.forEach(function(slice) { - if (slice.inFlowEvents) { - slice.inFlowEvents.forEach(function(flow) { - classifier.addInFlow(flow); - }); - } - if (slice.outFlowEvents) { - slice.outFlowEvents.forEach(function(flow) { - classifier.addOutFlow(flow); - }); - } + addConnectedFlows_: function(eventSet) { + var classifier = new tr.ui.analysis.FlowClassifier(); + eventSet.forEach(function(slice) { + if (slice.inFlowEvents) { + slice.inFlowEvents.forEach(function(flow) { + classifier.addInFlow(flow); + }); + } + if (slice.outFlowEvents) { + slice.outFlowEvents.forEach(function(flow) { + classifier.addOutFlow(flow); + }); + } + }); + if (!classifier.hasEvents()) + return; + + var addToEventGroups = function(type, flowEvent) { + this.eventGroups_.push({ + type: type, + selection: new tr.model.EventSet(flowEvent), + name: flowEvent.title }); - if (!classifier.hasEvents()) - return; + }; - var addToEventGroups = function(type, flowEvent) { - this.eventGroups_.push({ - type: type, - selection: new tr.model.EventSet(flowEvent), - name: flowEvent.title - }); - }; + classifier.inFlowEvents.forEach( + addToEventGroups.bind(this, 'Incoming flow')); + classifier.outFlowEvents.forEach( + addToEventGroups.bind(this, 'Outgoing flow')); + classifier.internalFlowEvents.forEach( + addToEventGroups.bind(this, 'Internal flow')); + }, - classifier.inFlowEvents.forEach( - addToEventGroups.bind(this, 'Incoming flow')); - classifier.outFlowEvents.forEach( - addToEventGroups.bind(this, 'Outgoing flow')); - classifier.internalFlowEvents.forEach( - addToEventGroups.bind(this, 'Internal flow')); - }, + cancelAllTasks_: function() { + this.cancelFunctions_.forEach(function(cancelFunction) { + cancelFunction(); + }); + this.cancelFunctions_ = []; + }, - cancelAllTasks_: function() { - this.cancelFunctions_.forEach(function(cancelFunction) { - cancelFunction(); - }); - this.cancelFunctions_ = []; - }, + addConnectedEvents_: function(eventSet) { + this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( + 'Preceding events', + 'Add all events that have led to the selected one(s), connected by ' + + 'flow arrows or by call stack.', + eventSet, + function*(event) { + yield * getEventInFlowEvents(event); + yield * getEventAncestors(event); + if (event.startSlice) + yield event.startSlice; + }.bind(this))); + this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( + 'Following events', + 'Add all events that have been caused by the selected one(s), ' + + 'connected by flow arrows or by call stack.', + eventSet, + function*(event) { + yield * getEventOutFlowEvents(event); + yield * getEventDescendents(event); + if (event.endSlice) + yield event.endSlice; + }.bind(this))); + this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( + 'All connected events', + 'Add all events connected to the selected one(s) by flow arrows or ' + + 'by call stack.', + eventSet, + function*(event) { + yield * getEventInFlowEvents(event); + yield * getEventOutFlowEvents(event); + yield * getEventAncestors(event); + yield * getEventDescendents(event); + if (event.startSlice) + yield event.startSlice; + if (event.endSlice) + yield event.endSlice; + }.bind(this))); + }, - addConnectedEvents_: function(eventSet) { - this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( - 'Preceding events', - 'Add all events that have led to the selected one(s), connected by ' + - 'flow arrows or by call stack.', - eventSet, - function(event, events) { - this.addInFlowEvents_(event, events); - this.addAncestors_(event, events); - if (event.startSlice) - events.push(event.startSlice); - }.bind(this))); - this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( - 'Following events', - 'Add all events that have been caused by the selected one(s), ' + - 'connected by flow arrows or by call stack.', - eventSet, - function(event, events) { - this.addOutFlowEvents_(event, events); - this.addDescendents_(event, events); - if (event.endSlice) - events.push(event.endSlice); - }.bind(this))); - this.cancelFunctions_.push(this.createEventsLinkIfNeeded_( - 'All connected events', - 'Add all events connected to the selected one(s) by flow arrows or ' + - 'by call stack.', - eventSet, - function(event, events) { - this.addInFlowEvents_(event, events); - this.addOutFlowEvents_(event, events); - this.addAncestors_(event, events); - this.addDescendents_(event, events); - if (event.startSlice) - events.push(event.startSlice); - if (event.endSlice) - events.push(event.endSlice); - }.bind(this))); - }, + createEventsLinkIfNeeded_: function(title, tooltip, events, connectedFn) { + events = new tr.model.EventSet(events); + var eventsToProcess = new Set(events); + // for (var event of events) + // eventsToProcess.add(event); + var wasChanged = false; + var task; + var isCanceled = false; + function addEventsUntilTimeout() { + if (isCanceled) + return; + // Let's grant ourselves a budget of 8 ms. If time runs out, then + // create another task to do the rest. + var timeout = window.performance.now() + 8; + // TODO(alexandermont): Don't check window.performance.now + // every iteration. + while (eventsToProcess.size > 0 && + window.performance.now() <= timeout) { + // Get the next event. + var nextEvent = tr.b.getFirstElement(eventsToProcess); + eventsToProcess.delete(nextEvent); - createEventsLinkIfNeeded_: function(title, tooltip, events, addFunction) { - events = new tr.model.EventSet(events); - var lengthBefore = events.length; - var task; - var isCanceled = false; - function addEventsUntilTimeout(startingIndex) { - if (isCanceled) - return; - var startingTime = window.performance.now(); - while (startingIndex < events.length) { - addFunction(events[startingIndex], events); - startingIndex++; - // Let's grant ourselves a budget of 8ms. - if (window.performance.now() - startingTime > 8) { - var newTask = new tr.b.Task( - addEventsUntilTimeout.bind(this, startingIndex), this); - task.after(newTask); - task = newTask; - return; + // Add the connected events to the list. + for (var eventToAdd of connectedFn(nextEvent)) { + if (!events.contains(eventToAdd)) { + events.push(eventToAdd); + eventsToProcess.add(eventToAdd); + wasChanged = true; } } - // Went through all events, add the link. - if (lengthBefore === events.length) + } + if (eventsToProcess.size > 0) { + // There are still events to process, but we ran out of time. Post + // more work for later. + var newTask = new tr.b.Task( + addEventsUntilTimeout.bind(this), this); + task.after(newTask); + task = newTask; return; - this.eventGroups_.push({ - type: title, - tooltip: tooltip, - selection: events - }); - this.updateContents_(); - }; - function cancelTask() { - isCanceled = true; } - task = new tr.b.Task(addEventsUntilTimeout.bind(this, 0), this); - tr.b.Task.RunWhenIdle(task); - return cancelTask; - }, - - addInFlowEvents_: function(event, eventSet) { - if (!event.inFlowEvents) + // Went through all events, add the link. + if (!wasChanged) return; - event.inFlowEvents.forEach(function(e) { - eventSet.push(e); + this.eventGroups_.push({ + type: title, + tooltip: tooltip, + selection: events }); - }, + this.updateContents_(); + } + function cancelTask() { + isCanceled = true; + } + task = new tr.b.Task(addEventsUntilTimeout.bind(this), this); + tr.b.Task.RunWhenIdle(task); + return cancelTask; + }, - addOutFlowEvents_: function(event, eventSet) { - if (!event.outFlowEvents) - return; - event.outFlowEvents.forEach(function(e) { - eventSet.push(e); + addOverlappingSamples_: function(eventSet) { + var samples = new tr.model.EventSet; + for (var slice of eventSet) { + if (!slice.parentContainer || !slice.parentContainer.samples) + continue; + var candidates = slice.parentContainer.samples; + var range = tr.b.Range.fromExplicitRange( + slice.start, slice.start + slice.duration); + var filteredSamples = range.filterArray( + candidates, function(value) {return value.start;}); + for (var sample of filteredSamples) + samples.push(sample); + } + if (samples.length > 0) { + this.eventGroups_.push({ + type: 'Overlapping samples', + tooltip: 'All samples overlapping the selected slice(s).', + selection: samples }); - }, + } + }, - addAncestors_: function(event, eventSet) { - if (!event.iterateAllAncestors) - return; - event.iterateAllAncestors(function(e) { - eventSet.push(e); + addV8Slices_: function(eventSet) { + var v8Slices = new tr.model.EventSet; + for (var slice of eventSet) { + if (slice.category === 'v8') + v8Slices.push(slice); + } + if (v8Slices.length > 0) { + this.eventGroups_.push({ + type: 'V8 Slices', + tooltip: 'All V8 slices in the selected slice(s).', + selection: v8Slices }); - }, + } + }, - addDescendents_: function(event, eventSet) { - if (!event.iterateAllDescendents) - return; - event.iterateAllDescendents(function(e) { - eventSet.push(e); + addRuntimeCallStats_: function(eventSet) { + var slices = new tr.model.EventSet; + for (var slice of eventSet) { + if (slice.category === 'v8' && slice.runtimeCallStats) + slices.push(slice); + } + if (slices.length > 0) { + this.eventGroups_.push({ + type: 'Runtime call stats table', + // eslint-disable-next-line + tooltip: 'All V8 slices containing runtime call stats table in the selected slice(s).', + selection: slices }); - }, - - addOverlappingSamples_: function(eventSet) { - var samples = new tr.model.EventSet; - eventSet.forEach(function(slice) { - if (!slice.parentContainer || !slice.parentContainer.samples) - return; - var candidates = slice.parentContainer.samples; - var range = tr.b.Range.fromExplicitRange( - slice.start, slice.start + slice.duration); - var filteredSamples = range.filterArray( - candidates, function(value) {return value.start;}); - filteredSamples.forEach(function(sample) { - samples.push(sample); - }); - }.bind(this)); - if (samples.length > 0) { - this.eventGroups_.push({ - type: 'Overlapping samples', - tooltip: 'All samples overlapping the selected slice(s).', - selection: samples - }); - } - }, + } + }, - updateContents_: function() { - var table = this.$.table; - if (this.eventGroups_ === undefined) - table.tableRows = []; - else - table.tableRows = this.eventGroups_.slice(); - table.rebuild(); + addV8GCObjectStats_: function(eventSet) { + var slices = new tr.model.EventSet; + for (var slice of eventSet) { + if (slice.title === 'V8.GC_Objects_Stats') + slices.push(slice); } - }); - </script> -</polymer-element> + if (slices.length > 0) { + this.eventGroups_.push({ + type: 'V8 GC stats table', + tooltip: 'All V8 GC statistics slices in the selected set.', + selection: slices + }); + } + }, + + updateContents_: function() { + var table = this.$.table; + if (this.eventGroups_ === undefined) + table.tableRows = []; + else + table.tableRows = this.eventGroups_.slice(); + table.rebuild(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html index cc3c00e410c..f4f2b62af06 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table.html @@ -6,11 +6,11 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/base.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name='tr-ui-a-selection-summary-table'> +<dom-module id='tr-ui-a-selection-summary-table'> <template> <style> :host { @@ -19,76 +19,78 @@ found in the LICENSE file. #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"> </tr-ui-b-table> </div> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - created: function() { - this.selection_ = new tr.b.Range(); - }, +Polymer({ + is: 'tr-ui-a-selection-summary-table', + created: function() { + this.selection_ = new tr.b.Range(); + }, - ready: function() { - this.$.table.showHeader = false; - this.$.table.tableColumns = [ - { - title: 'Name', - value: function(row) { return row.title; }, - width: '350px' - }, - { - title: 'Value', - width: '100%', - value: function(row) { - return row.value; - } + ready: function() { + this.$.table.showHeader = false; + this.$.table.tableColumns = [ + { + title: 'Name', + value: function(row) { return row.title; }, + width: '350px' + }, + { + title: 'Value', + width: '100%', + value: function(row) { + return row.value; } - ]; - }, + } + ]; + }, - get selection() { - return this.selection_; - }, + get selection() { + return this.selection_; + }, - set selection(selection) { - this.selection_ = selection; - this.updateContents_(); - }, + set selection(selection) { + this.selection_ = selection; + this.updateContents_(); + }, - updateContents_: function() { - var selection = this.selection_; - var rows = []; - var hasRange; - if (this.selection_ && (!selection.bounds.isEmpty)) - hasRange = true; - else - hasRange = false; + updateContents_: function() { + var selection = this.selection_; + var rows = []; + var hasRange; + if (this.selection_ && (!selection.bounds.isEmpty)) + hasRange = true; + else + hasRange = false; - rows.push({ - title: 'Selection start', - value: hasRange ? tr.v.ui.createScalarSpan( - selection.bounds.min, { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: this.ownerDocument - }) : '<empty>' - }); - rows.push({ - title: 'Selection extent', - value: hasRange ? tr.v.ui.createScalarSpan( - selection.bounds.range, { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: this.ownerDocument - }) : '<empty>' - }); + rows.push({ + title: 'Selection start', + value: hasRange ? tr.v.ui.createScalarSpan( + selection.bounds.min, { + unit: tr.b.Unit.byName.timeStampInMs, + ownerDocument: this.ownerDocument + }) : '<empty>' + }); + rows.push({ + title: 'Selection extent', + value: hasRange ? tr.v.ui.createScalarSpan( + selection.bounds.range, { + unit: tr.b.Unit.byName.timeDurationInMs, + ownerDocument: this.ownerDocument + }) : '<empty>' + }); - this.$.table.tableRows = rows; - this.$.table.rebuild(); - } - }); - </script> -</polymer-element> + this.$.table.tableRows = rows; + this.$.table.rebuild(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html index 5c1f1691efd..d8332b5a17e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/selection_summary_table_test.html @@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/core/test_utils.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/model/model.html"> <link rel="import" href="/tracing/ui/analysis/selection_summary_table.html"> <link rel="import" href="/tracing/ui/base/deep_utils.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -66,10 +66,10 @@ tr.b.unittest.testSuite(function() { summaryTable, 'tr-ui-b-table'); assert.equal(tableEl.tableRows[0].value.value, 0); assert.strictEqual(tableEl.tableRows[0].value.unit, - tr.v.Unit.byName.timeStampInMs); + tr.b.Unit.byName.timeStampInMs); assert.equal(tableEl.tableRows[1].value.value, 3); assert.strictEqual(tableEl.tableRows[1].value.unit, - tr.v.Unit.byName.timeDurationInMs); + tr.b.Unit.byName.timeDurationInMs); }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html deleted file mode 100644 index 89d8ade4c5b..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_alert_sub_view.html +++ /dev/null @@ -1,65 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2015 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/ui/base/dom_helpers.html"> -<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> -<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> - -<polymer-element name="tr-ui-a-single-alert-sub-view" - extends="tr-ui-a-sub-view"> - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - set selection(selection) { - this.currentSelection_ = selection; - - this.textContent = ''; - var realView = document.createElement('tr-ui-a-single-event-sub-view'); - realView.addExtraRowsCallback = function(rows) { - // Alert description. - var alert = this.currentSelection_[0]; - - var descriptionEl = tr.ui.b.createSpan({ - textContent: alert.info.description - }); - rows.push({ - name: 'Description', - value: descriptionEl - }); - - // Associated events... - if (alert.associatedEvents.length) { - var eventSubRows = []; - alert.associatedEvents.forEach(function(event, i) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return event; - }, event.userFriendlyName); - eventSubRows.push({ - name: i, - value: linkEl - }); - }); - - rows.push({ - name: 'Alerts', value: '', - isExpanded: true, subRows: eventSubRows - }); - } - }.bind(this); - - this.appendChild(realView); - realView.setSelectionWithoutErrorChecks(selection); - } - }); - </script> -</polymer-element> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html index 26a47706165..b2238040827 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_async_slice_sub_view.html @@ -10,8 +10,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/related_events.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> -<polymer-element name="tr-ui-a-single-async-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-async-slice-sub-view'> <template> <style> :host { @@ -28,44 +27,53 @@ found in the LICENSE file. <tr-ui-a-related-events id="relatedEvents"></tr-ui-a-related-events> </div> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-single-async-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - get selection() { - return this.$.content.selection; - }, + get selection() { + return this.$.content.selection; + }, - set selection(selection) { - if (selection.length !== 1) - throw new Error('Only supports single slices'); - this.$.content.setSelectionWithoutErrorChecks(selection); - this.$.relatedEvents.setRelatedEvents(selection); - if (this.$.relatedEvents.hasRelatedEvents()) { - this.$.relatedEvents.style.display = ''; - } else { - this.$.relatedEvents.style.display = 'none'; - } - }, + set selection(selection) { + if (selection.length !== 1) + throw new Error('Only supports single slices'); + this.$.content.setSelectionWithoutErrorChecks(selection); + this.$.relatedEvents.setRelatedEvents(selection); + if (this.$.relatedEvents.hasRelatedEvents()) { + this.$.relatedEvents.style.display = ''; + } else { + this.$.relatedEvents.style.display = 'none'; + } + }, - getEventRows_: function(event) { - // TODO(nduca): Figure out if there is a cleaner way to do this. - var rows = this.__proto__.__proto__.getEventRows_(event); + getEventRows_: function(event) { + // TODO(nduca): Figure out if there is a cleaner way to do this. + var rows = this.__proto__.__proto__.getEventRows_(event); - // Put the ID up top. - rows.splice(0, 0, { - name: 'ID', - value: event.id - }); - return rows; - }, + // Put the ID up top. + rows.splice(0, 0, { + name: 'ID', + value: event.id + }); + return rows; + }, - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; - } - }); - </script> -</polymer-element> + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; + } +}); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-async-slice-sub-view', + tr.model.AsyncSlice, + { + multi: false, + title: 'Async Slice', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html index 42081c5baf1..a4f98dd255f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view.html @@ -6,15 +6,14 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/base/utils.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-single-cpu-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-cpu-slice-sub-view'> <template> <style> table { @@ -79,61 +78,72 @@ found in the LICENSE file. </tr> </table> </template> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-cpu-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + var cpuSlice = tr.b.getOnlyElement(selection); + if (!(cpuSlice instanceof tr.model.CpuSlice)) + throw new Error('Only supports thread time slices'); + + this.currentSelection_ = selection; + + var thread = cpuSlice.threadThatWasRunning; + + var root = Polymer.dom(this.root); + if (thread) { + Polymer.dom(root.querySelector('#process-name')).textContent = + thread.parent.userFriendlyName; + Polymer.dom(root.querySelector('#thread-name')).textContent = + thread.userFriendlyName; + } else { + root.querySelector('#process-name').parentElement.style.display = + 'none'; + Polymer.dom(root.querySelector('#thread-name')).textContent = + cpuSlice.title; + } - <script> - 'use strict'; - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - var cpuSlice = tr.b.getOnlyElement(selection); - if (!(cpuSlice instanceof tr.model.CpuSlice)) - throw new Error('Only supports thread time slices'); - - this.currentSelection_ = selection; - - var thread = cpuSlice.threadThatWasRunning; - - var shadowRoot = this.shadowRoot; - if (thread) { - shadowRoot.querySelector('#process-name').textContent = - thread.parent.userFriendlyName; - shadowRoot.querySelector('#thread-name').textContent = - thread.userFriendlyName; - } else { - shadowRoot.querySelector('#process-name').parentElement.style.display = - 'none'; - shadowRoot.querySelector('#thread-name').textContent = cpuSlice.title; - } - - shadowRoot.querySelector('#start').setValueAndUnit( - cpuSlice.start, tr.v.Unit.byName.timeStampInMs); - shadowRoot.querySelector('#duration').setValueAndUnit( - cpuSlice.duration, tr.v.Unit.byName.timeDurationInMs); - - var runningThreadEl = shadowRoot.querySelector('#running-thread'); - - var timeSlice = cpuSlice.getAssociatedTimeslice(); - if (!timeSlice) { - runningThreadEl.parentElement.style.display = 'none'; - } else { - var threadLink = document.createElement('tr-ui-a-analysis-link'); - threadLink.selection = new tr.model.EventSet(timeSlice); - threadLink.textContent = 'Click to select'; - runningThreadEl.parentElement.style.display = ''; - runningThreadEl.textContent = ''; - runningThreadEl.appendChild(threadLink); - } - - shadowRoot.querySelector('#args').object = cpuSlice.args; - + root.querySelector('#start').setValueAndUnit( + cpuSlice.start, tr.b.Unit.byName.timeStampInMs); + root.querySelector('#duration').setValueAndUnit( + cpuSlice.duration, tr.b.Unit.byName.timeDurationInMs); + + var runningThreadEl = root.querySelector('#running-thread'); + + var timeSlice = cpuSlice.getAssociatedTimeslice(); + if (!timeSlice) { + runningThreadEl.parentElement.style.display = 'none'; + } else { + var threadLink = document.createElement('tr-ui-a-analysis-link'); + threadLink.selection = new tr.model.EventSet(timeSlice); + Polymer.dom(threadLink).textContent = 'Click to select'; + runningThreadEl.parentElement.style.display = ''; + Polymer.dom(runningThreadEl).textContent = ''; + Polymer.dom(runningThreadEl).appendChild(threadLink); } - }); - </script> -</polymer-element> + + root.querySelector('#args').object = cpuSlice.args; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-cpu-slice-sub-view', + tr.model.CpuSlice, + { + multi: false, + title: 'CPU Slice', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html index ea75afe6dcf..e3170dccb51 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_cpu_slice_sub_view_test.html @@ -56,7 +56,7 @@ tr.b.unittest.testSuite(function() { new tr.model.EventSet(thread.timeSlices[0]))); didSelectionChangeHappen = true; }); - view.shadowRoot.querySelector('tr-ui-a-analysis-link').click(); + Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click(); assert.isTrue(didSelectionChangeHappen); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html index 74a82c95348..55a5b0d1927 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view.html @@ -7,6 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> @@ -14,10 +15,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-single-event-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-event-sub-view'> <template> <style> :host { @@ -27,200 +26,257 @@ found in the LICENSE file. #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"> </tr-ui-b-table> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.currentSelection_ = undefined; - this.$.table.tableColumns = [ - { - title: 'Label', - value: function(row) { return row.name; }, - width: '150px' - }, - { - title: 'Value', - width: '100%', - value: function(row) { return row.value; } - } - ]; - this.$.table.showHeader = false; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - if (selection.length !== 1) - throw new Error('Only supports single slices'); - this.setSelectionWithoutErrorChecks(selection); - }, - - setSelectionWithoutErrorChecks: function(selection) { - this.currentSelection_ = selection; - this.updateContents_(); - }, - - getEventRows_: function(event) { - var rows = []; +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + properties: { + isFlow: { + type: Boolean, + value: false + } + }, + + ready: function() { + this.currentSelection_ = undefined; + this.$.table.tableColumns = [ + { + title: 'Label', + value: function(row) { return row.name; }, + width: '150px' + }, + { + title: 'Value', + width: '100%', + value: function(row) { return row.value; } + } + ]; + this.$.table.showHeader = false; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + if (selection.length !== 1) + throw new Error('Only supports single slices'); + this.setSelectionWithoutErrorChecks(selection); + }, + + setSelectionWithoutErrorChecks: function(selection) { + this.currentSelection_ = selection; + this.updateContents_(); + }, + + getFlowEventRows_: function(event) { + // TODO(nduca): Figure out if there is a cleaner way to do this. + + var rows = this.getEventRowsHelper_(event); + // var rows = this.__proto__.__proto__.getEventRows_(event); + + // Put the ID up top. + rows.splice(0, 0, { + name: 'ID', + value: event.id + }); + + function createLinkTo(slice) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent(function() { + return new tr.model.EventSet(slice); + }); + Polymer.dom(linkEl).textContent = slice.userFriendlyName; + return linkEl; + } - if (event.error) - rows.push({ name: 'Error', value: event.error }); + rows.push({ + name: 'From', + value: createLinkTo(event.startSlice) + }); + rows.push({ + name: 'To', + value: createLinkTo(event.endSlice) + }); + return rows; + }, + + getEventRowsHelper_: function(event) { + var rows = []; + + if (event.error) + rows.push({ name: 'Error', value: event.error }); + + if (event.title) + rows.push({ name: 'Title', value: event.title }); + + if (event.category) + rows.push({ name: 'Category', value: event.category }); + + if (event.model !== undefined) { + var ufc = event.model.getUserFriendlyCategoryFromEvent(event); + if (ufc !== undefined) + rows.push({ name: 'User Friendly Category', value: ufc }); + } - if (event.title) - rows.push({ name: 'Title', value: event.title }); + if (event.name) + rows.push({ name: 'Name', value: event.name }); - if (event.category) - rows.push({ name: 'Category', value: event.category }); + rows.push({ + name: 'Start', + value: tr.v.ui.createScalarSpan(event.start, { + unit: tr.b.Unit.byName.timeStampInMs + }) + }); - if (event.model !== undefined) { - var ufc = event.model.getUserFriendlyCategoryFromEvent(event); - if (ufc !== undefined) - rows.push({ name: 'User Friendly Category', value: ufc }); - } - - if (event.name) - rows.push({ name: 'Name', value: event.name }); + if (event.duration) { + rows.push({ + name: 'Wall Duration', + value: tr.v.ui.createScalarSpan(event.duration, { + unit: tr.b.Unit.byName.timeDurationInMs + }) + }); + } + if (event.cpuDuration) { rows.push({ - name: 'Start', - value: tr.v.ui.createScalarSpan(event.start, { - unit: tr.v.Unit.byName.timeStampInMs + name: 'CPU Duration', + value: tr.v.ui.createScalarSpan(event.cpuDuration, { + unit: tr.b.Unit.byName.timeDurationInMs }) }); + } - if (event.duration) { + if (event.subSlices !== undefined && event.subSlices.length !== 0) { + if (event.selfTime) { rows.push({ - name: 'Wall Duration', - value: tr.v.ui.createScalarSpan(event.duration, { - unit: tr.v.Unit.byName.timeDurationInMs + name: 'Self Time', + value: tr.v.ui.createScalarSpan(event.selfTime, { + unit: tr.b.Unit.byName.timeDurationInMs }) }); } - if (event.cpuDuration) { - rows.push({ - name: 'CPU Duration', - value: tr.v.ui.createScalarSpan(event.cpuDuration, { - unit: tr.v.Unit.byName.timeDurationInMs - }) + if (event.cpuSelfTime) { + var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, { + unit: tr.b.Unit.byName.timeDurationInMs }); - } - - if (event.subSlices !== undefined && event.subSlices.length !== 0) { - if (event.selfTime) { - rows.push({ - name: 'Self Time', - value: tr.v.ui.createScalarSpan(event.selfTime, { - unit: tr.v.Unit.byName.timeDurationInMs - }) - }); - } - - if (event.cpuSelfTime) { - var cpuSelfTimeEl = tr.v.ui.createScalarSpan(event.cpuSelfTime, { - unit: tr.v.Unit.byName.timeDurationInMs - }); - if (event.cpuSelfTime > event.selfTime) { - cpuSelfTimeEl.warning = - ' Note that CPU Self Time is larger than Self Time. ' + - 'This is a known limitation of this system, which occurs ' + - 'due to several subslices, rounding issues, and imprecise ' + - 'time at which we get cpu- and real-time.'; - } - rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl }); + if (event.cpuSelfTime > event.selfTime) { + cpuSelfTimeEl.warning = + ' Note that CPU Self Time is larger than Self Time. ' + + 'This is a known limitation of this system, which occurs ' + + 'due to several subslices, rounding issues, and imprecise ' + + 'time at which we get cpu- and real-time.'; } + rows.push({ name: 'CPU Self Time', value: cpuSelfTimeEl }); } + } - if (event.durationInUserTime) { - rows.push({ - name: 'Duration (U)', - value: tr.v.ui.createScalarSpan(event.durationInUserTime, { - unit: tr.v.Unit.byName.timeDurationInMs - }) - }); - } + if (event.durationInUserTime) { + rows.push({ + name: 'Duration (U)', + value: tr.v.ui.createScalarSpan(event.durationInUserTime, { + unit: tr.b.Unit.byName.timeDurationInMs + }) + }); + } - function createStackFrameEl(sf) { - var sfEl = document.createElement('tr-ui-a-stack-frame'); - sfEl.stackFrame = sf; - return sfEl; - } - if (event.startStackFrame && event.endStackFrame) { - if (event.startStackFrame === event.endStackFrame) { - rows.push({name: 'Start+End Stack Trace', - value: createStackFrameEl(event.startStackFrame)}); - - } else { - rows.push({ name: 'Start Stack Trace', - value: createStackFrameEl(event.startStackFrame)}); - rows.push({ name: 'End Stack Trace', - value: createStackFrameEl(event.endStackFrame)}); - } - } else if (event.startStackFrame) { - rows.push({ name: 'Start Stack Trace', + function createStackFrameEl(sf) { + var sfEl = document.createElement('tr-ui-a-stack-frame'); + sfEl.stackFrame = sf; + return sfEl; + } + if (event.startStackFrame && event.endStackFrame) { + if (event.startStackFrame === event.endStackFrame) { + rows.push({name: 'Start+End Stack Trace', value: createStackFrameEl(event.startStackFrame)}); - } else if (event.endStackFrame) { + } else { + rows.push({ name: 'Start Stack Trace', + value: createStackFrameEl(event.startStackFrame)}); rows.push({ name: 'End Stack Trace', value: createStackFrameEl(event.endStackFrame)}); } + } else if (event.startStackFrame) { + rows.push({ name: 'Start Stack Trace', + value: createStackFrameEl(event.startStackFrame)}); - if (event.info) { - var descriptionEl = tr.ui.b.createDiv({ - textContent: event.info.description, - maxWidth: '300px' - }); - rows.push({ - name: 'Description', - value: descriptionEl - }); + } else if (event.endStackFrame) { + rows.push({ name: 'End Stack Trace', + value: createStackFrameEl(event.endStackFrame)}); + } + if (event.info) { + var descriptionEl = tr.ui.b.createDiv({ + textContent: event.info.description, + maxWidth: '300px' + }); + rows.push({ + name: 'Description', + value: descriptionEl + }); - if (event.info.docLinks) { - event.info.docLinks.forEach(function(linkObject) { - var linkEl = document.createElement('a'); - linkEl.target = '_blank'; - linkEl.href = linkObject.href; - linkEl.textContent = linkObject.textContent; - rows.push({ - name: linkObject.label, - value: linkEl - }); - }); - } - } - if (event.associatedAlerts.length) { - var alertSubRows = []; - event.associatedAlerts.forEach(function(alert) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return new tr.model.EventSet(alert); - }, alert.info.description); - alertSubRows.push({ - name: alert.title, + if (event.info.docLinks) { + event.info.docLinks.forEach(function(linkObject) { + var linkEl = document.createElement('a'); + linkEl.target = '_blank'; + linkEl.href = linkObject.href; + Polymer.dom(linkEl).textContent = Polymer.dom(linkObject).textContent; + rows.push({ + name: linkObject.label, value: linkEl }); }); + } + } - rows.push({ - name: 'Alerts', value: '', - isExpanded: true, subRows: alertSubRows + if (event.associatedAlerts.length) { + var alertSubRows = []; + event.associatedAlerts.forEach(function(alert) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent(function() { + return new tr.model.EventSet(alert); + }, alert.info.description); + alertSubRows.push({ + name: alert.title, + value: linkEl }); - } - return rows; - }, + }); + + rows.push({ + name: 'Alerts', value: '', + isExpanded: true, subRows: alertSubRows + }); + } + return rows; + }, + + getEventRows_: function(event) { + + if (this.isFlow) + return this.getFlowEventRows_(event); - addArgsToRows_: function(rows, args) { - var n = 0; + return this.getEventRowsHelper_(event); + }, + + addArgsToRows_: function(rows, args) { + var n = 0; + for (var argName in args) { + n += 1; + } + if (n > 0) { + var subRows = []; for (var argName in args) { n += 1; } @@ -239,48 +295,48 @@ found in the LICENSE file. subRows: subRows }); } - }, - - addContextsToRows_: function(rows, contexts) { - if (contexts.length) { - var subRows = contexts.map(function(context) { - var contextView = - document.createElement('tr-ui-a-generic-object-view'); - contextView.object = context; - return {name: 'Context', value: contextView}; - }); - rows.push({ - name: 'Contexts', - value: '', - isExpanded: true, - subRows: subRows - }); - } - }, + } + }, + + addContextsToRows_: function(rows, contexts) { + if (contexts.length) { + var subRows = contexts.map(function(context) { + var contextView = + document.createElement('tr-ui-a-generic-object-view'); + contextView.object = context; + return {name: 'Context', value: contextView}; + }); + rows.push({ + name: 'Contexts', + value: '', + isExpanded: true, + subRows: subRows + }); + } + }, - updateContents_: function() { - if (this.currentSelection_ === undefined) { - this.$.table.rows = []; - this.$.table.rebuild(); - return; - } + updateContents_: function() { + if (this.currentSelection_ === undefined) { + this.$.table.rows = []; + this.$.table.rebuild(); + return; + } - var event = tr.b.getOnlyElement(this.currentSelection_); + var event = tr.b.getOnlyElement(this.currentSelection_); - var rows = this.getEventRows_(event); - if (event.argsStripped) - rows.push({ name: 'Args', value: 'Stripped' }); - else - this.addArgsToRows_(rows, event.args); - this.addContextsToRows_(rows, event.contexts); + var rows = this.getEventRows_(event); + if (event.argsStripped) + rows.push({ name: 'Args', value: 'Stripped' }); + else + this.addArgsToRows_(rows, event.args); + this.addContextsToRows_(rows, event.contexts); - var event = new tr.b.Event('customize-rows'); - event.rows = rows; - this.dispatchEvent(event); + var customizeRowsEvent = new tr.b.Event('customize-rows'); + customizeRowsEvent.rows = rows; + this.dispatchEvent(customizeRowsEvent); - this.$.table.tableRows = rows; - this.$.table.rebuild(); - } - }); - </script> -</polymer-element> + this.$.table.tableRows = rows; + this.$.table.rebuild(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html index b52ebaa16bc..0a3d481a2d7 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_event_sub_view_test.html @@ -58,7 +58,7 @@ tr.b.unittest.testSuite(function() { t53.sliceGroup.pushSlice(slice); }); - }; + } test('instantiate_withSingleSlice', function() { var selection = createSelectionWithSingleSlice(); @@ -125,7 +125,7 @@ tr.b.unittest.testSuite(function() { var e = tr.b.findDeepElementWithTextContent( analysisEl, /Start Stack Trace/); assert.isDefined(e); - assert.isDefined(e.nextSibling.children[0].stackFrame); + assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame); }); test('instantiate_withSingleEndStackFrame', function() { @@ -139,8 +139,8 @@ tr.b.unittest.testSuite(function() { var e = tr.b.findDeepElementWithTextContent( analysisEl, /End Stack Trace/); assert.isDefined(e); - assert.isDefined(e.nextSibling.children[0].stackFrame); - assert.equal(e.nextSibling.children[0].stackFrame.title, 'b2'); + assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame); + assert.equal(Polymer.dom(e).nextSibling.children[0].stackFrame.title, 'b2'); }); test('instantiate_withDifferentStartAndEndStackFrames', function() { @@ -155,14 +155,16 @@ tr.b.unittest.testSuite(function() { var eA = tr.b.findDeepElementWithTextContent( analysisEl, /Start Stack Trace/); assert.isDefined(eA); - assert.isDefined(eA.nextSibling.children[0].stackFrame); - assert.equal(eA.nextSibling.children[0].stackFrame.title, 'a2'); + assert.isDefined(Polymer.dom(eA).nextSibling.children[0].stackFrame); + assert.equal( + Polymer.dom(eA).nextSibling.children[0].stackFrame.title, 'a2'); var eB = tr.b.findDeepElementWithTextContent( analysisEl, /End Stack Trace/); assert.isDefined(eB); - assert.isDefined(eB.nextSibling.children[0].stackFrame); - assert.equal(eB.nextSibling.children[0].stackFrame.title, 'b2'); + assert.isDefined(Polymer.dom(eB).nextSibling.children[0].stackFrame); + assert.equal( + Polymer.dom(eB).nextSibling.children[0].stackFrame.title, 'b2'); }); test('instantiate_withSameStartAndEndStackFrames', function() { @@ -177,8 +179,8 @@ tr.b.unittest.testSuite(function() { var e = tr.b.findDeepElementWithTextContent( analysisEl, /Start\+End Stack Trace/); assert.isDefined(e); - assert.isDefined(e.nextSibling.children[0].stackFrame); - assert.equal(e.nextSibling.children[0].stackFrame.title, 'a2'); + assert.isDefined(Polymer.dom(e).nextSibling.children[0].stackFrame); + assert.equal(Polymer.dom(e).nextSibling.children[0].stackFrame.title, 'a2'); }); test('analyzeSelectionWithSingleSlice', function() { @@ -193,10 +195,10 @@ tr.b.unittest.testSuite(function() { assert.equal(table.tableRows[0].value, 'b'); assert.equal(table.tableRows[1].value.value, 0); assert.strictEqual(table.tableRows[1].value.unit, - tr.v.Unit.byName.timeStampInMs); + tr.b.Unit.byName.timeStampInMs); assert.equal(table.tableRows[2].value.value, 0.002); assert.strictEqual(table.tableRows[2].value.unit, - tr.v.Unit.byName.timeDurationInMs); + tr.b.Unit.byName.timeDurationInMs); }); test('analyzeSelectionWithSingleSliceCategory', function() { @@ -213,10 +215,10 @@ tr.b.unittest.testSuite(function() { assert.equal(table.tableRows[1].value, 'foo'); assert.equal(table.tableRows[2].value.value, 0); assert.strictEqual(table.tableRows[2].value.unit, - tr.v.Unit.byName.timeStampInMs); + tr.b.Unit.byName.timeStampInMs); assert.equal(table.tableRows[3].value.value, 0.002); assert.strictEqual(table.tableRows[3].value.unit, - tr.v.Unit.byName.timeDurationInMs); + tr.b.Unit.byName.timeDurationInMs); }); test('instantiate_withSingleSliceContainingIDRef', function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html index 899f9f2096e..ae6497b7c69 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view.html @@ -5,46 +5,78 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/model/event_set.html"> -<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> +<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> -<polymer-element name="tr-ui-a-single-flow-event-sub-view" - extends="tr-ui-a-single-event-sub-view"> - <script> - 'use strict'; - - Polymer({ - getEventRows_: function(event) { - // TODO(nduca): Figure out if there is a cleaner way to do this. - var rows = this.__proto__.__proto__.getEventRows_(event); - - // Put the ID up top. - rows.splice(0, 0, { - name: 'ID', - value: event.id - }); - - function createLinkTo(slice) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent(function() { - return new tr.model.EventSet(slice); - }); - linkEl.textContent = slice.userFriendlyName; - return linkEl; - } - - rows.push({ - name: 'From', - value: createLinkTo(event.startSlice) - }); - rows.push({ - name: 'To', - value: createLinkTo(event.endSlice) - }); - return rows; +<dom-module id="tr-ui-a-single-flow-event-sub-view"> + <template> + <style> + :host { + display: block; } - }); - </script> -</polymer-element> + </style> + <tr-ui-a-single-event-sub-view id="singleEventSubView"> + </tr-ui-a-single-event-sub-view> + </template> +</dom-module> +<script> +'use strict'; + +function createAnalysisLinkTo(event) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent( + new tr.model.EventSet(event), event.userFriendlyName); + return linkEl; +} + +Polymer({ + is: 'tr-ui-a-single-flow-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + listeners: { + 'singleEventSubView.customize-rows': 'onCustomizeRows_' + }, + + set selection(selection) { + this.currentSelection_ = selection; + this.$.singleEventSubView.setSelectionWithoutErrorChecks(selection); + }, + + get selection() { + return this.currentSelection_; + }, + + /** + * Event handler for an event that's fired after the single event sub view has + * finished row construction. This hook gives us the opportunity to customize + * the rows present in the sub view. + */ + onCustomizeRows_: function(e) { + var event = tr.b.getOnlyElement(this.currentSelection_); + var rows = e.rows; + + rows.unshift({ + name: 'ID', + value: event.id + }); + rows.push({ + name: 'From', + value: createAnalysisLinkTo(event.startSlice) + }); + rows.push({ + name: 'To', + value: createAnalysisLinkTo(event.endSlice) + }); + } +}); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-flow-event-sub-view', + tr.model.FlowEvent, + { + multi: false, + title: 'Flow Event', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html index bbd348a1b20..b4125fae2ac 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_flow_event_sub_view_test.html @@ -44,7 +44,8 @@ tr.b.unittest.testSuite(function() { selection.push(model.fe); assert.equal(selection.length, 1); - var subView = document.createElement('tr-ui-a-single-flow-event-sub-view'); + var subView = document.createElement('tr-ui-a-single-event-sub-view'); + subView.isFlow = true; subView.selection = selection; this.addHTMLOutput(subView); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html index f58168d1c87..8edcaa5203a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_frame_sub_view.html @@ -9,8 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/alert_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> -<polymer-element name="tr-ui-a-single-frame-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-frame-sub-view'> <template> <style> :host { @@ -25,28 +24,39 @@ found in the LICENSE file. <tr-ui-a-alert-sub-view id="asv"> </tr-ui-a-alert-sub-view> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.currentSelection_ = undefined; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - this.currentSelection_ = selection; - this.$.asv.selection = tr.b.getOnlyElement(selection).associatedAlerts; - }, - - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; - } - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-frame-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + ready: function() { + this.currentSelection_ = undefined; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + this.currentSelection_ = selection; + this.$.asv.selection = tr.b.getOnlyElement(selection).associatedAlerts; + }, + + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-frame-sub-view', + tr.model.Frame, + { + multi: false, + title: 'Frame', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html index c8ab4aa7389..84972063550 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_instant_event_sub_view.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> -<polymer-element name="tr-ui-a-single-instant-event-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-instant-event-sub-view'> <template> <style> :host { @@ -18,28 +17,47 @@ found in the LICENSE file. </style> <div id='content'></div> </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - set selection(selection) { - this.$.content.textContent = ''; - var realView = document.createElement('tr-ui-a-single-event-sub-view'); - realView.setSelectionWithoutErrorChecks(selection); - - this.$.content.appendChild(realView); - - this.currentSelection_ = selection; - }, - - get selection() { - return this.currentSelection_; - } - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-instant-event-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + set selection(selection) { + Polymer.dom(this.$.content).textContent = ''; + var realView = document.createElement('tr-ui-a-single-event-sub-view'); + realView.setSelectionWithoutErrorChecks(selection); + + Polymer.dom(this.$.content).appendChild(realView); + + this.currentSelection_ = selection; + }, + + get selection() { + return this.currentSelection_; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-instant-event-sub-view', + tr.model.InstantEvent, + { + multi: false, + title: 'Instant Event', + }); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-multi-instant-event-sub-view', + tr.model.InstantEvent, + { + multi: true, + title: 'Instant Events', + }); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html index ca5cd4a730d..c450bbcc9e9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_instance_sub_view.html @@ -13,8 +13,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/object_instance_view.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> -<polymer-element name="tr-ui-a-single-object-instance-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-object-instance-sub-view'> <template> <style> :host { @@ -47,70 +46,81 @@ found in the LICENSE file. </style> <div id='content'></div> </template> - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - get requiresTallView() { - if (this.$.content.children.length === 0) - return false; - if (this.$.content.children[0] instanceof - tr.ui.analysis.ObjectInstanceView) - return this.$.content.children[0].requiresTallView; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - var instance = tr.b.getOnlyElement(selection); - if (!(instance instanceof tr.model.ObjectInstance)) - throw new Error('Only supports object instances'); - - this.$.content.textContent = ''; - this.currentSelection_ = selection; - - var typeInfo = tr.ui.analysis.ObjectInstanceView.getTypeInfo( - instance.category, instance.typeName); - if (typeInfo) { - var customView = new typeInfo.constructor(); - this.$.content.appendChild(customView); - customView.modelEvent = instance; - } else { - this.appendGenericAnalysis_(instance); - } - }, - - appendGenericAnalysis_: function(instance) { - var html = ''; - html += '<div class="title">' + - instance.typeName + ' ' + - instance.id + '</div>\n'; - html += '<table>'; - html += '<tr>'; - html += '<tr><td>creationTs:</td><td>' + - instance.creationTs + '</td></tr>\n'; - if (instance.deletionTs != Number.MAX_VALUE) { - html += '<tr><td>deletionTs:</td><td>' + - instance.deletionTs + '</td></tr>\n'; - } else { - html += '<tr><td>deletionTs:</td><td>not deleted</td></tr>\n'; - } - html += '<tr><td>snapshots:</td><td id="snapshots"></td></tr>\n'; - html += '</table>'; - this.$.content.innerHTML = html; - var snapshotsEl = this.$.content.querySelector('#snapshots'); - instance.snapshots.forEach(function(snapshot) { - var snapshotLink = document.createElement('tr-ui-a-analysis-link'); - snapshotLink.selection = new tr.model.EventSet(snapshot); - snapshotsEl.appendChild(snapshotLink); - }); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-object-instance-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + get requiresTallView() { + if (this.$.content.children.length === 0) + return false; + if (this.$.content.children[0] instanceof + tr.ui.analysis.ObjectInstanceView) + return this.$.content.children[0].requiresTallView; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + var instance = tr.b.getOnlyElement(selection); + if (!(instance instanceof tr.model.ObjectInstance)) + throw new Error('Only supports object instances'); + + Polymer.dom(this.$.content).textContent = ''; + this.currentSelection_ = selection; + + var typeInfo = tr.ui.analysis.ObjectInstanceView.getTypeInfo( + instance.category, instance.typeName); + if (typeInfo) { + var customView = new typeInfo.constructor(); + Polymer.dom(this.$.content).appendChild(customView); + customView.modelEvent = instance; + } else { + this.appendGenericAnalysis_(instance); } - }); - </script> -</polymer-element> + }, + + appendGenericAnalysis_: function(instance) { + var html = ''; + html += '<div class="title">' + + instance.typeName + ' ' + + instance.id + '</div>\n'; + html += '<table>'; + html += '<tr>'; + html += '<tr><td>creationTs:</td><td>' + + instance.creationTs + '</td></tr>\n'; + if (instance.deletionTs !== Number.MAX_VALUE) { + html += '<tr><td>deletionTs:</td><td>' + + instance.deletionTs + '</td></tr>\n'; + } else { + html += '<tr><td>deletionTs:</td><td>not deleted</td></tr>\n'; + } + html += '<tr><td>snapshots:</td><td id="snapshots"></td></tr>\n'; + html += '</table>'; + Polymer.dom(this.$.content).innerHTML = html; + var snapshotsEl = Polymer.dom(this.$.content).querySelector('#snapshots'); + instance.snapshots.forEach(function(snapshot) { + var snapshotLink = document.createElement('tr-ui-a-analysis-link'); + snapshotLink.selection = new tr.model.EventSet(snapshot); + Polymer.dom(snapshotsEl).appendChild(snapshotLink); + }); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-object-instance-sub-view', + tr.model.ObjectInstance, + { + multi: false, + title: 'Object Instance', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html index d156203b904..e3b39130326 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_object_snapshot_sub_view.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> @@ -14,10 +15,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-single-object-snapshot-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-object-snapshot-sub-view'> <template> <style> #args { @@ -46,83 +45,94 @@ found in the LICENSE file. </style> <content></content> </template> - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - get requiresTallView() { - if (this.children.length === 0) - return false; - if (this.children[0] instanceof tr.ui.analysis.ObjectSnapshotView) - return this.children[0].requiresTallView; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - var snapshot = tr.b.getOnlyElement(selection); - if (!(snapshot instanceof tr.model.ObjectSnapshot)) - throw new Error('Only supports object instances'); - - this.textContent = ''; - this.currentSelection_ = selection; - - var typeInfo = tr.ui.analysis.ObjectSnapshotView.getTypeInfo( - snapshot.objectInstance.category, snapshot.objectInstance.typeName); - if (typeInfo) { - var customView = new typeInfo.constructor(); - this.appendChild(customView); - customView.modelEvent = snapshot; - } else { - this.appendGenericAnalysis_(snapshot); - } - }, - - appendGenericAnalysis_: function(snapshot) { - var instance = snapshot.objectInstance; - - this.textContent = ''; - - var titleEl = document.createElement('div'); - titleEl.classList.add('title'); - titleEl.appendChild(document.createTextNode('Snapshot of ')); - this.appendChild(titleEl); - - var instanceLinkEl = document.createElement('tr-ui-a-analysis-link'); - instanceLinkEl.selection = new tr.model.EventSet(instance); - titleEl.appendChild(instanceLinkEl); - - titleEl.appendChild(document.createTextNode(' @ ')); - - titleEl.appendChild(tr.v.ui.createScalarSpan(snapshot.ts, { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: this.ownerDocument - })); - - var tableEl = document.createElement('table'); - this.appendChild(tableEl); - - var rowEl = document.createElement('tr'); - tableEl.appendChild(rowEl); - - var labelEl = document.createElement('td'); - labelEl.textContent = 'args:'; - rowEl.appendChild(labelEl); - - var argsEl = document.createElement('td'); - argsEl.id = 'args'; - rowEl.appendChild(argsEl); - - var objectViewEl = document.createElement('tr-ui-a-generic-object-view'); - objectViewEl.object = snapshot.args; - argsEl.appendChild(objectViewEl); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-object-snapshot-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + get requiresTallView() { + if (this.children.length === 0) + return false; + if (this.children[0] instanceof tr.ui.analysis.ObjectSnapshotView) + return this.children[0].requiresTallView; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + var snapshot = tr.b.getOnlyElement(selection); + if (!(snapshot instanceof tr.model.ObjectSnapshot)) + throw new Error('Only supports object instances'); + + Polymer.dom(this).textContent = ''; + this.currentSelection_ = selection; + + var typeInfo = tr.ui.analysis.ObjectSnapshotView.getTypeInfo( + snapshot.objectInstance.category, snapshot.objectInstance.typeName); + if (typeInfo) { + var customView = new typeInfo.constructor(); + Polymer.dom(this).appendChild(customView); + customView.modelEvent = snapshot; + } else { + this.appendGenericAnalysis_(snapshot); } - }); - </script> -</polymer-element> + }, + + appendGenericAnalysis_: function(snapshot) { + var instance = snapshot.objectInstance; + + Polymer.dom(this).textContent = ''; + + var titleEl = document.createElement('div'); + Polymer.dom(titleEl).classList.add('title'); + Polymer.dom(titleEl).appendChild(document.createTextNode('Snapshot of ')); + Polymer.dom(this).appendChild(titleEl); + + var instanceLinkEl = document.createElement('tr-ui-a-analysis-link'); + instanceLinkEl.selection = new tr.model.EventSet(instance); + Polymer.dom(titleEl).appendChild(instanceLinkEl); + + Polymer.dom(titleEl).appendChild(document.createTextNode(' @ ')); + + Polymer.dom(titleEl).appendChild(tr.v.ui.createScalarSpan(snapshot.ts, { + unit: tr.b.Unit.byName.timeStampInMs, + ownerDocument: this.ownerDocument + })); + + var tableEl = document.createElement('table'); + Polymer.dom(this).appendChild(tableEl); + + var rowEl = document.createElement('tr'); + Polymer.dom(tableEl).appendChild(rowEl); + + var labelEl = document.createElement('td'); + Polymer.dom(labelEl).textContent = 'args:'; + Polymer.dom(rowEl).appendChild(labelEl); + + var argsEl = document.createElement('td'); + argsEl.id = 'args'; + Polymer.dom(rowEl).appendChild(argsEl); + + var objectViewEl = document.createElement('tr-ui-a-generic-object-view'); + objectViewEl.object = snapshot.args; + Polymer.dom(argsEl).appendChild(objectViewEl); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-object-snapshot-sub-view', + tr.model.ObjectSnapshot, + { + multi: false, + title: 'Object Snapshot', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html index 96043122244..9be2ec3fac3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_power_sample_sub_view.html @@ -5,27 +5,31 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-power-sample-table"> +<dom-module id='tr-ui-a-power-sample-table'> <template> <style> :host { display: flex; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> -</polymer-element> +</dom-module> <script> 'use strict'; -Polymer('tr-ui-a-power-sample-table', { +Polymer({ + is: 'tr-ui-a-power-sample-table', + ready: function() { this.$.table.tableColumns = [ { @@ -33,7 +37,7 @@ Polymer('tr-ui-a-power-sample-table', { width: '100px', value: function(row) { return tr.v.ui.createScalarSpan(row.start, { - unit: tr.v.Unit.byName.timeStampInMs + unit: tr.b.Unit.byName.timeStampInMs }); } }, @@ -41,8 +45,8 @@ Polymer('tr-ui-a-power-sample-table', { title: 'Power', width: '100%', value: function(row) { - return tr.v.ui.createScalarSpan(row.power, { - unit: tr.v.Unit.byName.powerInWatts + return tr.v.ui.createScalarSpan(row.powerInW, { + unit: tr.b.Unit.byName.powerInWatts }); } } @@ -60,7 +64,7 @@ Polymer('tr-ui-a-power-sample-table', { }, updateContents_: function() { - if (this.sample == undefined) + if (this.sample === undefined) this.$.table.tableRows = []; else this.$.table.tableRows = [this.sample]; @@ -69,8 +73,7 @@ Polymer('tr-ui-a-power-sample-table', { }); </script> -<polymer-element name="tr-ui-a-single-power-sample-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-power-sample-sub-view'> <template> <style> :host { display: block; } @@ -78,30 +81,40 @@ Polymer('tr-ui-a-power-sample-table', { <tr-ui-a-power-sample-table id="samplesTable"> </tr-ui-a-power-sample-table> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-single-power-sample-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - ready: function() { - this.currentSelection_ = undefined; + ready: function() { + this.currentSelection_ = undefined; + }, + + get selection() { + return this.currentSelection_; + }, - }, + set selection(selection) { + this.currentSelection_ = selection; + this.updateContents_(); + }, - get selection() { - return this.currentSelection_; - }, + updateContents_: function() { + if (this.selection.length !== 1) + throw 'Cannot pass multiple samples to sample table.'; + this.$.samplesTable.sample = tr.b.getOnlyElement(this.selection); + } +}); - set selection(selection) { - this.currentSelection_ = selection; - this.updateContents_(); - }, +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-power-sample-sub-view', + tr.model.PowerSample, + { + multi: false, + title: 'Power Sample', + }); - updateContents_: function() { - if (this.selection.length != 1) - throw 'Cannot pass multiple samples to sample table.'; - this.$.samplesTable.sample = this.selection[0]; - } - }); - </script> -</polymer-element> +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html index 29f7b2e064a..bcd0919e460 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view.html @@ -5,85 +5,95 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/stack_frame.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-single-sample-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-sample-sub-view'> <template> <style> :host { display: flex; + font-size: 12px; } </style> <tr-ui-b-table id="content"></tr-ui-b-table> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, +Polymer({ + is: 'tr-ui-a-single-sample-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - ready: function() { - this.$.content.tableColumns = [ - { - title: 'FirstColumn', - value: function(row) { return row.title; }, - width: '250px' - }, - { - title: 'SecondColumn', - value: function(row) { return row.value; }, - width: '100%' - } - ]; - this.$.content.showHeader = false; - }, + created: function() { + this.currentSelection_ = undefined; + }, - get selection() { - return this.currentSelection_; - }, + ready: function() { + this.$.content.tableColumns = [ + { + title: 'FirstColumn', + value: function(row) { return row.title; }, + width: '250px' + }, + { + title: 'SecondColumn', + value: function(row) { return row.value; }, + width: '100%' + } + ]; + this.$.content.showHeader = false; + }, - set selection(selection) { - this.currentSelection_ = selection; + get selection() { + return this.currentSelection_; + }, - if (this.currentSelection_ === undefined) { - this.$.content.tableRows = []; - return; - } + set selection(selection) { + this.currentSelection_ = selection; - var sample = this.currentSelection_[0]; - var table = this.$.content; + if (this.currentSelection_ === undefined) { + this.$.content.tableRows = []; + return; + } - var rows = []; + var sample = tr.b.getOnlyElement(this.currentSelection_); + var table = this.$.content; + var rows = []; - rows.push({ - title: 'Title', - value: sample.title - }); + rows.push({ + title: 'Title', + value: sample.title + }); - rows.push({ - title: 'Sample time', - value: tr.v.ui.createScalarSpan(sample.start, { - unit: tr.v.Unit.byName.timeStampInMs, - ownerDocument: this.ownerDocument - }) - }); + rows.push({ + title: 'Sample time', + value: tr.v.ui.createScalarSpan(sample.start, { + unit: tr.b.Unit.byName.timeStampInMs, + ownerDocument: this.ownerDocument + }) + }); - var sfEl = document.createElement('tr-ui-a-stack-frame'); - sfEl.stackFrame = sample.leafStackFrame; - rows.push({ - title: 'Stack trace', - value: sfEl - }); - table.tableRows = rows; - table.rebuild(); - } - }); - </script> -</polymer-element> + var sfEl = document.createElement('tr-ui-a-stack-frame'); + sfEl.stackFrame = sample.leafStackFrame; + rows.push({ + title: 'Stack trace', + value: sfEl + }); + table.tableRows = rows; + table.rebuild(); + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-sample-sub-view', + tr.model.Sample, + { + multi: false, + title: 'Sample', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html index d31abfaff08..802bc99aa34 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_sample_sub_view_test.html @@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/core/test_utils.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/model/model.html"> <link rel="import" href="/tracing/ui/analysis/single_sample_sub_view.html"> <link rel="import" href="/tracing/ui/base/deep_utils.html"> -<link rel="import" href="/tracing/value/unit.html"> <script> 'use strict'; @@ -53,7 +53,7 @@ tr.b.unittest.testSuite(function() { assert.equal(rows[0].value, 'X'); assert.equal(rows[1].value.value, 0.184); - assert.strictEqual(rows[1].value.unit, tr.v.Unit.byName.timeStampInMs); + assert.strictEqual(rows[1].value.unit, tr.b.Unit.byName.timeStampInMs); assert.equal(rows[2].value.stackFrame, t53.samples[0].leafStackFrame); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html index 2eeb8819785..d934bedd3b6 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_slice_sub_view.html @@ -6,11 +6,10 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> -<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/related_events.html"> +<link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> -<polymer-element name="tr-ui-a-single-thread-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-thread-slice-sub-view'> <template> <style> :host { @@ -29,23 +28,33 @@ found in the LICENSE file. </tr-ui-a-related-events> </div> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-a-single-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - Polymer({ - get selection() { - return this.$.content.selection; - }, + get selection() { + return this.$.content.selection; + }, - set selection(selection) { - this.$.content.selection = selection; - this.$.relatedEvents.setRelatedEvents(selection); - if (this.$.relatedEvents.hasRelatedEvents()) - this.$.relatedEvents.style.display = ''; - else - this.$.relatedEvents.style.display = 'none'; - } - }); - </script> -</polymer-element> + set selection(selection) { + this.$.content.selection = selection; + this.$.relatedEvents.setRelatedEvents(selection); + if (this.$.relatedEvents.hasRelatedEvents()) + this.$.relatedEvents.style.display = ''; + else + this.$.relatedEvents.style.display = 'none'; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-thread-slice-sub-view', + tr.model.ThreadSlice, + { + multi: false, + title: 'Slice', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html index 8d82ca6ee04..11574b892bf 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view.html @@ -8,6 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/color_scheme.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/sorted_array_utils.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/base/utils.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/model/model.html"> @@ -15,10 +16,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-a-single-thread-time-slice-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-thread-time-slice-sub-view'> <template> <style> table { @@ -89,86 +88,99 @@ found in the LICENSE file. </tr> </table> </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, - - get selection() { - return this.currentSelection_; - }, - - set selection(selection) { - var timeSlice = tr.b.getOnlyElement(selection); - - if (!(timeSlice instanceof tr.model.ThreadTimeSlice)) - throw new Error('Only supports thread time slices'); - - this.currentSelection_ = selection; - - var thread = timeSlice.thread; - - var shadowRoot = this.shadowRoot; - shadowRoot.querySelector('#state').textContent = timeSlice.title; - var stateColor = tr.b.ColorScheme.colorsAsStrings[timeSlice.colorId]; - shadowRoot.querySelector('#state').style.backgroundColor = stateColor; - - shadowRoot.querySelector('#process-name').textContent = - thread.parent.userFriendlyName; - shadowRoot.querySelector('#thread-name').textContent = - thread.userFriendlyName; - - shadowRoot.querySelector('#start').setValueAndUnit( - timeSlice.start, tr.v.Unit.byName.timeStampInMs); - shadowRoot.querySelector('#duration').setValueAndUnit( - timeSlice.duration, tr.v.Unit.byName.timeDurationInMs); - - var onCpuEl = shadowRoot.querySelector('#on-cpu'); - onCpuEl.textContent = ''; - var runningInsteadEl = shadowRoot.querySelector('#running-instead'); - if (timeSlice.cpuOnWhichThreadWasRunning) { - runningInsteadEl.parentElement.removeChild(runningInsteadEl); - +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-single-thread-time-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + created: function() { + this.currentSelection_ = undefined; + }, + + get selection() { + return this.currentSelection_; + }, + + set selection(selection) { + var timeSlice = tr.b.getOnlyElement(selection); + + if (!(timeSlice instanceof tr.model.ThreadTimeSlice)) + throw new Error('Only supports thread time slices'); + + this.currentSelection_ = selection; + + var thread = timeSlice.thread; + + var root = Polymer.dom(this.root); + Polymer.dom(root.querySelector('#state')).textContent = + timeSlice.title; + var stateColor = tr.b.ColorScheme.colorsAsStrings[timeSlice.colorId]; + root.querySelector('#state').style.backgroundColor = stateColor; + + Polymer.dom(root.querySelector('#process-name')).textContent = + thread.parent.userFriendlyName; + Polymer.dom(root.querySelector('#thread-name')).textContent = + thread.userFriendlyName; + + root.querySelector('#start').setValueAndUnit( + timeSlice.start, tr.b.Unit.byName.timeStampInMs); + root.querySelector('#duration').setValueAndUnit( + timeSlice.duration, tr.b.Unit.byName.timeDurationInMs); + + var onCpuEl = root.querySelector('#on-cpu'); + Polymer.dom(onCpuEl).textContent = ''; + var runningInsteadEl = root.querySelector('#running-instead'); + if (timeSlice.cpuOnWhichThreadWasRunning) { + Polymer.dom(runningInsteadEl.parentElement).removeChild(runningInsteadEl); + + var cpuLink = document.createElement('tr-ui-a-analysis-link'); + cpuLink.selection = new tr.model.EventSet( + timeSlice.getAssociatedCpuSlice()); + Polymer.dom(cpuLink).textContent = + timeSlice.cpuOnWhichThreadWasRunning.userFriendlyName; + Polymer.dom(onCpuEl).appendChild(cpuLink); + } else { + Polymer.dom(onCpuEl.parentElement).removeChild(onCpuEl); + + var cpuSliceThatTookCpu = timeSlice.getCpuSliceThatTookCpu(); + if (cpuSliceThatTookCpu) { var cpuLink = document.createElement('tr-ui-a-analysis-link'); - cpuLink.selection = new tr.model.EventSet( - timeSlice.getAssociatedCpuSlice()); - cpuLink.textContent = - timeSlice.cpuOnWhichThreadWasRunning.userFriendlyName; - onCpuEl.appendChild(cpuLink); + cpuLink.selection = new tr.model.EventSet(cpuSliceThatTookCpu); + if (cpuSliceThatTookCpu.thread) + Polymer.dom(cpuLink).textContent = + cpuSliceThatTookCpu.thread.userFriendlyName; + else + Polymer.dom(cpuLink).textContent = cpuSliceThatTookCpu.title; + Polymer.dom(runningInsteadEl).appendChild(cpuLink); } else { - onCpuEl.parentElement.removeChild(onCpuEl); - - var cpuSliceThatTookCpu = timeSlice.getCpuSliceThatTookCpu(); - if (cpuSliceThatTookCpu) { - var cpuLink = document.createElement('tr-ui-a-analysis-link'); - cpuLink.selection = new tr.model.EventSet(cpuSliceThatTookCpu); - if (cpuSliceThatTookCpu.thread) - cpuLink.textContent = cpuSliceThatTookCpu.thread.userFriendlyName; - else - cpuLink.textContent = cpuSliceThatTookCpu.title; - runningInsteadEl.appendChild(cpuLink); - } else { - runningInsteadEl.parentElement.removeChild(runningInsteadEl); - } + Polymer.dom(runningInsteadEl.parentElement).removeChild( + runningInsteadEl); } + } - var argsEl = shadowRoot.querySelector('#args'); - if (tr.b.dictionaryKeys(timeSlice.args).length > 0) { - var argsView = - document.createElement('tr-ui-a-generic-object-view'); - argsView.object = timeSlice.args; - - argsEl.parentElement.style.display = ''; - argsEl.textContent = ''; - argsEl.appendChild(argsView); - } else { - argsEl.parentElement.style.display = 'none'; - } + var argsEl = root.querySelector('#args'); + if (tr.b.dictionaryKeys(timeSlice.args).length > 0) { + var argsView = + document.createElement('tr-ui-a-generic-object-view'); + argsView.object = timeSlice.args; + + argsEl.parentElement.style.display = ''; + Polymer.dom(argsEl).textContent = ''; + Polymer.dom(argsEl).appendChild(argsView); + } else { + argsEl.parentElement.style.display = 'none'; } - }); - </script> -</polymer-element> + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-thread-time-slice-sub-view', + tr.model.ThreadTimeSlice, + { + multi: false, + title: 'Thread Timeslice', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html index 5ab48cbe2cf..f2b0faff015 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_thread_time_slice_sub_view_test.html @@ -56,7 +56,7 @@ tr.b.unittest.testSuite(function() { assert.isTrue(e.selection.equals(new tr.model.EventSet(binderSlice))); didSelectionChangeHappen = true; }); - view.shadowRoot.querySelector('tr-ui-a-analysis-link').click(); + Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click(); assert.isTrue(didSelectionChangeHappen); }); @@ -85,7 +85,7 @@ tr.b.unittest.testSuite(function() { assert.isTrue(e.selection.equals(new tr.model.EventSet(launcherSlice))); didSelectionChangeHappen = true; }); - view.shadowRoot.querySelector('tr-ui-a-analysis-link').click(); + Polymer.dom(view.root).querySelector('tr-ui-a-analysis-link').click(); assert.isTrue(didSelectionChangeHappen); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html index 0c2ba50450a..4c332b0f761 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/single_user_expectation_sub_view.html @@ -6,16 +6,15 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/single_event_sub_view.html"> <link rel="import" href="/tracing/ui/analysis/user_expectation_related_samples_table.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> <link rel="import" href="/tracing/value/value_set.html"> -<polymer-element name="tr-ui-a-single-user-expectation-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-single-user-expectation-sub-view'> <template> <style> :host { @@ -32,50 +31,61 @@ found in the LICENSE file. <tr-ui-a-user-expectation-related-samples-table id="relatedSamples"></tr-ui-a-user-expectation-related-samples-table> </div> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - created: function() { - this.currentSelection_ = undefined; - }, +Polymer({ + is: 'tr-ui-a-single-user-expectation-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], - get selection() { - return this.currentSelection_; - }, + created: function() { + this.currentSelection_ = undefined; + }, - set selection(selection) { - this.$.realView.addEventListener('customize-rows', - this.onCustomizeRows_.bind(this)); + get selection() { + return this.currentSelection_; + }, - this.currentSelection_ = selection; - this.$.realView.setSelectionWithoutErrorChecks(selection); + set selection(selection) { + this.$.realView.addEventListener('customize-rows', + this.onCustomizeRows_.bind(this)); - this.$.relatedSamples.selection = selection; - if (this.$.relatedSamples.hasRelatedSamples()) - this.$.events.style.display = ''; - else - this.$.events.style.display = 'none'; - }, + this.currentSelection_ = selection; + this.$.realView.setSelectionWithoutErrorChecks(selection); - get relatedEventsToHighlight() { - if (!this.currentSelection_) - return undefined; - return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; - }, + this.$.relatedSamples.selection = selection; + if (this.$.relatedSamples.hasRelatedSamples()) + this.$.events.style.display = ''; + else + this.$.events.style.display = 'none'; + }, - onCustomizeRows_: function(event) { - var ue = tr.b.getOnlyElement(this.selection); + get relatedEventsToHighlight() { + if (!this.currentSelection_) + return undefined; + return tr.b.getOnlyElement(this.currentSelection_).associatedEvents; + }, - if (ue.rawCpuMs) { - event.rows.push({ - name: 'Total CPU', - value: tr.v.ui.createScalarSpan(ue.totalCpuMs, { - unit: tr.v.Unit.byName.timeDurationInMs - }) - }); - } + onCustomizeRows_: function(event) { + var ue = tr.b.getOnlyElement(this.selection); + + if (ue.rawCpuMs) { + event.rows.push({ + name: 'Total CPU', + value: tr.v.ui.createScalarSpan(ue.totalCpuMs, { + unit: tr.b.Unit.byName.timeDurationInMs + }) + }); } - }); - </script> -</polymer-element> + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-single-user-expectation-sub-view', + tr.model.um.UserExpectation, + { + multi: false, + title: 'User Expectation', + }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html index aeca20ee40d..27533e3131c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stack_frame.html @@ -6,73 +6,76 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/ui/base/table.html"> -<polymer-element name="tr-ui-a-stack-frame"> +<dom-module id='tr-ui-a-stack-frame'> <template> <style> :host { display: flex; flex-direction: row; align-items: center; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - ready: function() { - this.stackFrame_ = undefined; - this.$.table.tableColumns = []; - this.$.table.showHeader = true; - }, +Polymer({ + is: 'tr-ui-a-stack-frame', - get stackFrame() { - return this.stackFrame_; - }, + ready: function() { + this.stackFrame_ = undefined; + this.$.table.tableColumns = []; + this.$.table.showHeader = true; + }, - set stackFrame(stackFrame) { - var table = this.$.table; + get stackFrame() { + return this.stackFrame_; + }, - this.stackFrame_ = stackFrame; - if (stackFrame === undefined) { - table.tableColumns = []; - table.tableRows = []; - table.rebuild(); - return; - } + set stackFrame(stackFrame) { + var table = this.$.table; - var hasName = false; - var hasTitle = false; - - table.tableRows = stackFrame.stackTrace; - table.tableRows.forEach(function(row) { - hasName |= row.name !== undefined; - hasTitle |= row.title !== undefined; - }); + this.stackFrame_ = stackFrame; + if (stackFrame === undefined) { + table.tableColumns = []; + table.tableRows = []; + table.rebuild(); + return; + } - var cols = []; - if (hasName) { - cols.push({ - title: 'Name', - value: function(row) { return row.name; } - }); - } + var hasName = false; + var hasTitle = false; - if (hasTitle) { - cols.push({ - title: 'Title', - value: function(row) { return row.title; } - }); - } + table.tableRows = stackFrame.stackTrace; + table.tableRows.forEach(function(row) { + hasName |= row.name !== undefined; + hasTitle |= row.title !== undefined; + }); - table.tableColumns = cols; - table.rebuild(); - }, + var cols = []; + if (hasName) { + cols.push({ + title: 'Name', + value: function(row) { return row.name; } + }); + } - tableForTesting: function() { - return this.$.table; + if (hasTitle) { + cols.push({ + title: 'Title', + value: function(row) { return row.title; } + }); } - }); - </script> -</polymer-element> + + table.tableColumns = cols; + table.rebuild(); + }, + + tableForTesting: function() { + return this.$.table; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html index ba5deb30330..a6446b64c4c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane.html @@ -5,55 +5,18 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/base/base.html"> +<link rel="import" href="/tracing/ui/analysis/rebuildable_behavior.html"> <!-- @fileoverview Analysis view stacked pane. See the stacked pane view element (tr-ui-a-stacked-pane-view) documentation for more details. --> -<polymer-element name="tr-ui-a-stacked-pane"> - <script> - 'use strict'; +<script> +'use strict'; - Polymer({ - rebuild: function() { - /** - * Rebuild the pane if necessary. - * - * This method is not intended to be overriden by subclasses. Please - * override scheduleRebuildPane_() instead. - */ - if (!this.paneDirty_) { - // Avoid rebuilding unnecessarily as it breaks things like table - // selection. - return; - } - - this.paneDirty_ = false; - this.rebuildPane_(); - }, - - /** - * Mark the UI state of the pane as dirty and schedule a rebuild. - * - * This method is intended to be called by subclasses. - */ - scheduleRebuildPane_: function() { - if (this.paneDirty_) - return; - this.paneDirty_ = true; - setTimeout(this.rebuild.bind(this), 0); - }, - - /** - * Called when the pane is dirty and a rebuild is triggered. - * - * This method is intended to be overriden by subclasses (instead of - * directly overriding rebuild()). - */ - rebuildPane_: function() { - }, +tr.exportTo('tr.ui.analysis', function() { + var StackedPaneImpl = { /** * Request changing the child pane of this pane in the associated stacked * pane view. If the assigned builder is undefined, request removing the @@ -76,14 +39,24 @@ found in the LICENSE file. /** * Called right after the pane is appended to a pane view. * - * This method triggers an immediate rebuild by default (if necessary). - * Subclasses are free to change this behavior (e.g. if a pane has lots of - * data to display, it might decide to defer rebuilding in order not to - * cause jank). + * This method triggers an immediate rebuild by default. Subclasses are + * free to change this behavior (e.g. if a pane has lots of data to display, + * it might decide to defer rebuilding in order not to cause jank). */ appended: function() { this.rebuild(); } - }); - </script> -</polymer-element> + }; + + var StackedPane = [tr.ui.analysis.RebuildableBehavior, StackedPaneImpl]; + + return { + StackedPane: StackedPane + }; +}); + +Polymer({ + is: 'tr-ui-a-stacked-pane', + behaviors: [tr.ui.analysis.StackedPane] +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html index f76feea8122..a4c8d5213dc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_test.html @@ -11,35 +11,6 @@ found in the LICENSE file. 'use strict'; tr.b.unittest.testSuite(function() { - test('rebuild', function() { - var pane = document.createElement('tr-ui-a-stacked-pane'); - var didFireBuildPane; - pane.rebuildPane_ = function() { - didFireBuildPane = true; - }; - - function checkRebuild(expectedDidFireBuildPane) { - didFireBuildPane = false; - pane.rebuild(); - assert.strictEqual(didFireBuildPane, expectedDidFireBuildPane); - } - - // No rebuilds should occur when not scheduled. - checkRebuild(false); - checkRebuild(false); - - // Single rebuild should occur when scheduled once. - pane.scheduleRebuildPane_(); - checkRebuild(true); - checkRebuild(false); - - // Only a single rebuild should occur even when scheduled multiple times. - pane.scheduleRebuildPane_(); - pane.scheduleRebuildPane_(); - checkRebuild(true); - checkRebuild(false); - }); - test('changeChildPane', function() { var pane = document.createElement('tr-ui-a-stacked-pane'); var didFireEvent; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html index a3c52f780e5..fe0ebf9bd90 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view.html @@ -37,10 +37,11 @@ Sample use case: Create an empty stacked pane view and add it to the DOM: var paneView = document.createElement('tr-ui-a-stacked-pane-view'); - someParentView.appendChild(paneView); + Polymer.dom(someParentView).appendChild(paneView); Define one or more pane subclasses: + TODO(polymer): Write this documentation <polymer-element name="some-pane-1" extends="tr-ui-a-stacked-pane"> ... </polymer-element> @@ -70,7 +71,7 @@ Sample use case: }.bind(this); } --> -<polymer-element name="tr-ui-a-stacked-pane-view"> +<dom-module id='tr-ui-a-stacked-pane-view'> <template> <style> :host { @@ -85,105 +86,107 @@ Sample use case: <div id="pane_container"> </div> </template> - <script> - 'use strict'; - - Polymer({ - /** - * Add a pane to the stacked pane view. This method performs two operations: - * - * 1. Remove existing descendant panes - * If the optional parent pane is provided, all its current descendant - * panes are removed. Otherwise, all panes are removed from the view. - * - * 2. Build and add new pane - * If a pane builder is provided and returns a pane, the new pane is - * appended to the view (after the provided parent, or at the top). - */ - setPaneBuilder: function(paneBuilder, opt_parentPane) { - var paneContainer = this.$.pane_container; - - // If the parent pane is provided, it must be an HTML element and a child - // of the pane container. - if (opt_parentPane) { - if (!(opt_parentPane instanceof HTMLElement)) - throw new Error('Parent pane must be an HTML element'); - if (opt_parentPane.parentElement !== paneContainer) - throw new Error('Parent pane must be a child of the pane container'); - } - - // Remove all descendants of the parent pane (or all panes if no parent - // pane was specified) in reverse order. - while (paneContainer.lastElementChild !== null && - paneContainer.lastElementChild !== opt_parentPane) { - var removedPane = this.$.pane_container.lastElementChild; - var listener = this.listeners_.get(removedPane); - if (listener === undefined) - throw new Error('No listener associated with pane'); - this.listeners_.delete(removedPane); - removedPane.removeEventListener( - 'request-child-pane-change', listener); - paneContainer.removeChild(removedPane); - } - - if (opt_parentPane && opt_parentPane.parentElement !== paneContainer) - throw new Error('Parent pane was removed from the pane container'); - - // This check is performed here (and not at the beginning of the method) - // because undefined pane builder means that the parent pane requested - // having no child pane (e.g. when selection is cleared). - if (!paneBuilder) - return; - - var pane = paneBuilder(); - if (!pane) - return; - - if (!(pane instanceof HTMLElement)) - throw new Error('Pane must be an HTML element'); - - // Listen for child pane change requests from the newly added pane. - var listener = function(event) { - this.setPaneBuilder(pane.childPaneBuilder, pane); - }.bind(this); - if (!this.listeners_) { - // Instead of initializing the listeners map in a created() callback, - // we do it lazily here so that subclasses could provide their own - // created() callback (Polymer currently doesn't allow calling overriden - // superclass methods in strict mode). - this.listeners_ = new WeakMap(); - } - this.listeners_.set(pane, listener); - pane.addEventListener('request-child-pane-change', listener); - - paneContainer.appendChild(pane); - pane.appended(); - }, - - /** - * Request rebuilding all panes in the view. The panes are rebuilt from the - * top to the bottom (so that parent panes could request changing their - * child panes when they're being rebuilt and the newly constructed child - * panes would be rebuilt as well). - */ - rebuild: function() { - var currentPane = this.$.pane_container.firstElementChild; - while (currentPane) { - currentPane.rebuild(); - currentPane = currentPane.nextElementSibling; - } - }, - - // For testing purposes. - get panesForTesting() { - var panes = []; - var currentChild = this.$.pane_container.firstElementChild; - while (currentChild) { - panes.push(currentChild); - currentChild = currentChild.nextElementSibling; - } - return panes; +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-a-stacked-pane-view', + + /** + * Add a pane to the stacked pane view. This method performs two operations: + * + * 1. Remove existing descendant panes + * If the optional parent pane is provided, all its current descendant + * panes are removed. Otherwise, all panes are removed from the view. + * + * 2. Build and add new pane + * If a pane builder is provided and returns a pane, the new pane is + * appended to the view (after the provided parent, or at the top). + */ + setPaneBuilder: function(paneBuilder, opt_parentPane) { + var paneContainer = this.$.pane_container; + + // If the parent pane is provided, it must be an HTML element and a child + // of the pane container. + if (opt_parentPane) { + if (!(opt_parentPane instanceof HTMLElement)) + throw new Error('Parent pane must be an HTML element'); + if (opt_parentPane.parentElement !== paneContainer) + throw new Error('Parent pane must be a child of the pane container'); + } + + // Remove all descendants of the parent pane (or all panes if no parent + // pane was specified) in reverse order. + while (Polymer.dom(paneContainer).lastElementChild !== null && + Polymer.dom(paneContainer).lastElementChild !== opt_parentPane) { + var removedPane = Polymer.dom(this.$.pane_container).lastElementChild; + var listener = this.listeners_.get(removedPane); + if (listener === undefined) + throw new Error('No listener associated with pane'); + this.listeners_.delete(removedPane); + removedPane.removeEventListener( + 'request-child-pane-change', listener); + Polymer.dom(paneContainer).removeChild(removedPane); + } + + if (opt_parentPane && opt_parentPane.parentElement !== paneContainer) + throw new Error('Parent pane was removed from the pane container'); + + // This check is performed here (and not at the beginning of the method) + // because undefined pane builder means that the parent pane requested + // having no child pane (e.g. when selection is cleared). + if (!paneBuilder) + return; + + var pane = paneBuilder(); + if (!pane) + return; + + if (!(pane instanceof HTMLElement)) + throw new Error('Pane must be an HTML element'); + + // Listen for child pane change requests from the newly added pane. + var listener = function(event) { + this.setPaneBuilder(pane.childPaneBuilder, pane); + }.bind(this); + if (!this.listeners_) { + // Instead of initializing the listeners map in a created() callback, + // we do it lazily here so that subclasses could provide their own + // created() callback (Polymer currently doesn't allow calling overriden + // superclass methods in strict mode). + this.listeners_ = new WeakMap(); + } + this.listeners_.set(pane, listener); + pane.addEventListener('request-child-pane-change', listener); + + Polymer.dom(paneContainer).appendChild(pane); + pane.appended(); + }, + + /** + * Request rebuilding all panes in the view. The panes are rebuilt from the + * top to the bottom (so that parent panes could request changing their + * child panes when they're being rebuilt and the newly constructed child + * panes would be rebuilt as well). + */ + rebuild: function() { + var currentPane = Polymer.dom(this.$.pane_container).firstElementChild; + while (currentPane) { + currentPane.rebuild(); + currentPane = currentPane.nextElementSibling; + } + }, + + // For testing purposes. + get panesForTesting() { + var panes = []; + var currentChild = Polymer.dom(this.$.pane_container).firstElementChild; + while (currentChild) { + panes.push(currentChild); + currentChild = currentChild.nextElementSibling; } - }); - </script> -</polymer-element> + return panes; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html index 5afcd1bd1f0..0f3a5e29e60 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stacked_pane_view_test.html @@ -21,14 +21,14 @@ tr.b.unittest.testSuite(function() { paneEl.paneId = paneId; var divEl = document.createElement('div'); - divEl.textContent = 'Pane ' + paneId; + Polymer.dom(divEl).textContent = 'Pane ' + paneId; divEl.style.width = '400px'; divEl.style.background = '#ccc'; divEl.style.textAlign = 'center'; - paneEl.appendChild(divEl); + Polymer.dom(paneEl).appendChild(divEl); if (opt_rebuildPaneCallback) - paneEl.rebuildPane_ = opt_rebuildPaneCallback; + paneEl.onRebuild_ = opt_rebuildPaneCallback; if (opt_appendedCallback) paneEl.appended = opt_appendedCallback; @@ -176,7 +176,7 @@ tr.b.unittest.testSuite(function() { // All panes are now marked as dirty, but rebuild isn't triggered (it was // only scheduled). viewEl.panesForTesting.forEach(function(pane) { - pane.scheduleRebuildPane_(); + pane.scheduleRebuild_(); }); assert.deepEqual(rebuiltPaneIds, []); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html index c08278c9b44..b606d1736a1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/stub_analysis_table.html @@ -23,8 +23,8 @@ tr.exportTo('tr.ui.analysis', function() { }, appendChild: function(node) { - if (node.tagName == 'TFOOT' || node.tagName == 'THEAD' || - node.tagName == 'TBODY') { + if (node.tagName === 'TFOOT' || node.tagName === 'THEAD' || + node.tagName === 'TBODY') { node.__proto__ = StubAnalysisTable.prototype; node.nodes_ = []; node.ownerDocument_ = document; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html b/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html index fb5b694c17b..b9cc593b5a4 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/analysis/user_expectation_related_samples_table.html @@ -8,78 +8,81 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/base/table.html"> -<polymer-element name="tr-ui-a-user-expectation-related-samples-table"> +<dom-module id='tr-ui-a-user-expectation-related-samples-table'> <template> <style> #table { flex: 1 1 auto; align-self: stretch; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - ready: function() { - this.samples_ = []; - this.$.table.tableColumns = [ - { - title: 'Event(s)', - value: function(row) { - var typeEl = document.createElement('span'); - typeEl.innerText = row.type; - if (row.tooltip) - typeEl.title = row.tooltip; - return typeEl; - }, - width: '150px' +Polymer({ + is: 'tr-ui-a-user-expectation-related-samples-table', + + ready: function() { + this.samples_ = []; + this.$.table.tableColumns = [ + { + title: 'Event(s)', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.type; + if (row.tooltip) + typeEl.title = row.tooltip; + return typeEl; }, - { - title: 'Link', - width: '100%', - value: function(row) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - if (row.name) - linkEl.setSelectionAndContent(row.selection, row.name); - else - linkEl.selection = row.selection; - return linkEl; - } + width: '150px' + }, + { + title: 'Link', + width: '100%', + value: function(row) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + if (row.name) + linkEl.setSelectionAndContent(row.selection, row.name); + else + linkEl.selection = row.selection; + return linkEl; } - ]; - }, + } + ]; + }, - hasRelatedSamples: function() { - return (this.samples_ && this.samples_.length > 0); - }, + hasRelatedSamples: function() { + return (this.samples_ && this.samples_.length > 0); + }, - set selection(eventSet) { - this.samples_ = []; - var samples = new tr.model.EventSet; - eventSet.forEach(function(ue) { - samples.addEventSet(ue.associatedSamples); - }.bind(this)); + set selection(eventSet) { + this.samples_ = []; + var samples = new tr.model.EventSet; + eventSet.forEach(function(ue) { + samples.addEventSet(ue.associatedSamples); + }.bind(this)); - if (samples.length > 0) { - this.samples_.push({ - type: 'Overlapping samples', - tooltip: 'All samples overlapping the selected user expectation(s).', - selection: samples - }); - } - this.updateContents_(); - }, - - updateContents_: function() { - var table = this.$.table; - if (this.samples_ && this.samples_.length > 0) - table.tableRows = this.samples_.slice(); - else - table.tableRows = []; - table.rebuild(); + if (samples.length > 0) { + this.samples_.push({ + type: 'Overlapping samples', + tooltip: 'All samples overlapping the selected user expectation(s).', + selection: samples + }); } - }); - </script> -</polymer-element> + this.updateContents_(); + }, + + updateContents_: function() { + var table = this.$.table; + if (this.samples_ && this.samples_.length > 0) + table.tableRows = this.samples_.slice(); + else + table.tableRows = []; + table.rebuild(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html b/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html index 03eba86146b..30be91ba622 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/annotations/comment_box_annotation_view.html @@ -33,7 +33,8 @@ tr.exportTo('tr.ui.annotations', function() { __proto__: tr.ui.annotations.AnnotationView.prototype, removeTextArea: function() { - this.textArea_.parentNode.removeChild(this.textArea_); + Polymer.dom(Polymer.dom(this.textArea_).parentNode).removeChild( + this.textArea_); }, draw: function(ctx) { @@ -52,7 +53,8 @@ tr.exportTo('tr.ui.annotations', function() { this.textArea_.value = this.annotation_.text; // Set the z-index so that this is shown on top of canvas. this.textArea_.style.zIndex = 1; - ctx.canvas.parentNode.appendChild(this.textArea_); + Polymer.dom(Polymer.dom(ctx.canvas).parentNode) + .appendChild(this.textArea_); } this.textArea_.style.width = this.styleWidth + 'px'; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html index b2893762db3..67ec5382c09 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart.html @@ -1,173 +1,135 @@ <!DOCTYPE html> <!-- -Copyright (c) 2014 The Chromium Authors. All rights reserved. +Copyright (c) 2016 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/chart_base_2d_brushable_x.html"> +<link rel="import" href="/tracing/ui/base/column_chart.html"> <script> 'use strict'; tr.exportTo('tr.ui.b', function() { - var ColorScheme = tr.b.ColorScheme; - var ChartBase2DBrushX = tr.ui.b.ChartBase2DBrushX; - var getColorOfKey = tr.ui.b.getColorOfKey; + var ColumnChart = tr.ui.b.ColumnChart; // @constructor - var BarChart = tr.ui.b.define('bar-chart', ChartBase2DBrushX); + var BarChart = tr.ui.b.define('bar-chart', ColumnChart); BarChart.prototype = { - __proto__: ChartBase2DBrushX.prototype, + __proto__: ColumnChart.prototype, decorate: function() { - ChartBase2DBrushX.prototype.decorate.call(this); - this.classList.add('bar-chart'); - this.xCushion_ = 0; - this.isStacked_ = false; + ColumnChart.prototype.decorate.call(this); + Polymer.dom(this).classList.add('bar-chart'); + this.verticalScale_ = undefined; + this.horizontalScale_ = undefined; }, - set isStacked(stacked) { - this.isStacked_ = true; - this.updateContents_(); + updateScales_: function() { + ColumnChart.prototype.updateScales_.call(this); + this.yScale_.range([this.chartAreaSize.width, 0]); + this.xScale_.range([0, this.chartAreaSize.height]); + this.verticalScale_ = this.isYLogScale_ ? d3.scale.log(10) : + d3.scale.linear(); + this.verticalScale_.domain(this.xScale_.domain()); + this.verticalScale_.range([this.chartAreaSize.height, 0]); + this.horizontalScale_ = d3.scale.linear(); + this.horizontalScale_.domain(this.yScale_.domain()); + this.horizontalScale_.range([0, this.chartAreaSize.width]); }, - get isStacked() { - return this.isStacked_; + drawBrush_: function(brushRectsSel) { + brushRectsSel + .attr('x', 0) + .attr('width', this.chartAreaSize.width) + .attr('y', function(d) { + return this.verticalScale_(d.max); + }.bind(this)) + .attr('height', function(d) { + return this.verticalScale_(d.min) - this.verticalScale_(d.max); + }.bind(this)); }, - isDatumFieldSeries_: function(fieldName) { - return fieldName != 'x'; + getDataPointAtChartPoint_: function(chartPoint) { + var flippedPoint = { + x: this.chartAreaSize.height - chartPoint.y, + y: this.chartAreaSize.width - chartPoint.x + }; + return ColumnChart.prototype.getDataPointAtChartPoint_.call( + this, flippedPoint); }, - getXForDatum_: function(datum, index) { - return datum.x; + drawXAxis_: function(xAxis) { + xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')') + .call(d3.svg.axis() + .scale(this.horizontalScale_) + .orient('bottom')); }, - updateScales_: function() { - if (this.data_.length === 0) - return; - - var xDifferences = 0; - var currentX = undefined; - var previousX = undefined; - var yRange = new tr.b.Range(); - this.data_.forEach(function(datum, index) { - previousX = currentX; - currentX = this.getXForDatum_(datum, index); - if (previousX !== undefined) { - xDifferences += currentX - previousX; - } - - this.seriesKeys_.forEach(function(key) { - // Allow for sparse data - if (datum[key] !== undefined) - yRange.addValue(datum[key]); - }); - }, this); - - // X. - // Leave a cushion on the right so that the last rect doesn't - // exceed the chart boundaries. The last rect's width is set to the - // average width of the rects, which is chart.width / data.length. - var width = this.chartAreaSize.width; - this.xScale_.range([0, width]); - var domain = d3.extent(this.data_, this.getXForDatum_.bind(this)); - this.xCushion_ = xDifferences / (this.data_.length - 1); - this.xScale_.domain([domain[0], domain[1] + this.xCushion_]); - - // Y. - this.yScale_.range([this.chartAreaSize.height, 0]); - this.yScale_.domain(this.getYScaleDomain_(yRange.min, yRange.max)); + drawYAxis_: function(yAxis) { + var axisModifier = d3.svg.axis() + .scale(this.verticalScale_) + .orient('left'); + yAxis.call(axisModifier); }, - getYScaleDomain_: function(minValue, maxValue) { - if (!this.isStacked) { - return ChartBase2DBrushX.prototype.getYScaleDomain_.call( - this, minValue, maxValue); + drawHoverValueBox_: function(rect) { + var seriesKeys = [...this.seriesByKey_.keys()]; + var chartAreaSel = d3.select(this.chartAreaElement); + chartAreaSel.selectAll('.hover').remove(); + var keyWidthPx = 0; + var keyHeightPx = 0; + if (seriesKeys.length > 1) { + keyWidthPx = tr.ui.b.getSVGTextWidth( + this.chartAreaElement, rect.key) + 5; + keyHeightPx = 16; + } + var valueWidthPx = tr.ui.b.getSVGTextWidth( + this.chartAreaElement, rect.value) + 5; + var valueHeightPx = 16; + var hoverWidthPx = Math.max(keyWidthPx, valueWidthPx); + var hoverTopPx = rect.topPx + (rect.heightPx / 2); + var hoverLeftPx = rect.leftPx + rect.widthPx - hoverWidthPx; + chartAreaSel + .append('rect') + .attr('class', 'hover') + .attr('fill', 'white') + .attr('x', hoverLeftPx) + .attr('y', hoverTopPx) + .attr('width', hoverWidthPx) + .attr('height', keyHeightPx + valueHeightPx); + if (seriesKeys.length > 1) { + chartAreaSel + .append('text') + .attr('class', 'hover') + .attr('fill', rect.color) + .attr('x', hoverLeftPx + 2) + .attr('y', hoverTopPx + keyHeightPx - 3) + .text(rect.key); } - var range = new tr.b.Range(); - range.addValue(0); - this.data_.forEach(function(datum, index) { - var sum = 0; - this.seriesKeys_.forEach(function(key) { - if (datum[key] === undefined) - return; - sum += datum[key]; - }, this); - range.addValue(sum); - }, this); - return [range.min, range.max]; - }, - - getStackedRectsForDatum_: function(datum, index) { - var stacks = []; - var bottom = this.yScale_.range()[0]; - var sum = 0; - this.seriesKeys_.forEach(function(key) { - if (datum[key] === undefined) - return; - sum += datum[key]; - var heightPx = bottom - this.yScale_(sum); - bottom -= heightPx; - stacks.push({ - color: getColorOfKey(key), - heightPx: heightPx, - topPx: bottom - }); - }, this); - return stacks; - }, - - getRectsForDatum_: function(datum, index) { - if (this.isStacked) - return this.getStackedRectsForDatum_(datum, index); - - var stacks = []; - this.seriesKeys_.forEach(function(key) { - if (datum[key] === undefined) - return; - var topPx = this.yScale_(Math.max(datum[key], this.getYScaleMin_())); - stacks.push({ - topPx: topPx, - heightPx: this.yScale_.range()[0] - topPx, - color: getColorOfKey(key) - }); - }, this); - stacks.sort(function(a, b) { - return b.topPx - a.topPx; - }); - return stacks; + chartAreaSel + .append('text') + .attr('class', 'hover') + .attr('fill', rect.color) + .attr('x', hoverLeftPx + 2) + .attr('y', hoverTopPx + keyHeightPx + valueHeightPx - 3) + .text(rect.value); }, - updateDataContents_: function(dataSel) { - dataSel.selectAll('*').remove(); - var rectsSel = dataSel.selectAll('path').data(this.seriesKeys_); - this.data_.forEach(function(datum, index) { - var currentX = this.getXForDatum_(datum, index); - var width = undefined; - if (index < (this.data_.length - 1)) { - var nextX = this.getXForDatum_(this.data_[index + 1], index + 1); - width = nextX - currentX; - } else { - width = this.xCushion_; - } - this.getRectsForDatum_(datum, index).forEach(function(rect) { - var leftPx = this.xScale_(currentX); - var rightPx = this.xScale_(currentX + width); - var widthPx = rightPx - leftPx; - rectsSel.enter() - .append('rect') - .attr('fill', rect.color) - .attr('x', leftPx) - .attr('y', rect.topPx) - .attr('width', widthPx) - .attr('height', rect.heightPx); - }, this); - }, this); - rectsSel.exit().remove(); + drawRect_: function(rect, sel) { + // Flip |rect| around |y=x|. + var colRect = { + key: rect.key, + value: rect.value, + color: rect.color, + topPx: this.chartAreaSize.height - rect.leftPx - rect.widthPx, + leftPx: this.chartAreaSize.width - rect.topPx - rect.heightPx, + widthPx: rect.heightPx, + heightPx: rect.widthPx, + }; + ColumnChart.prototype.drawRect_.call(this, colRect, sel); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html index 7d931d5ff1b..ff991993c15 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/bar_chart_test.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/ui/base/bar_chart.html"> +<link rel="import" href="/tracing/ui/base/deep_utils.html"> <script> 'use strict'; @@ -26,6 +27,18 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(chart); }); + test('instantiation_singleDatum', function() { + var chart = new tr.ui.b.BarChart(); + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 0, value: 100}, + ]; + chart.data = data; + this.addHTMLOutput(chart); + }); + test('instantiation_stacked', function() { var chart = new tr.ui.b.BarChart(); chart.isStacked = true; @@ -215,7 +228,7 @@ tr.b.unittest.testSuite(function() { updateBrushedRange(); }); chart.addEventListener('item-mousemove', function(e) { - if (e.button == undefined) + if (e.button === undefined) return; curMouseX = e.x; updateBrushedRange(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/base.html b/chromium/third_party/catapult/tracing/tracing/ui/base/base.html new file mode 100644 index 00000000000..e0ca9e23c6b --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/base.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/base/polymer_preload.html" data-suppress-import-order> + +<!-- +Polymer is imported through third-party HTML files, which means that we have to +manually list all recursive imports. +--> +<link rel="import" href="/components/polymer/polymer-micro.html" data-suppress-import-order> +<link rel="import" href="/components/polymer/polymer-mini.html" data-suppress-import-order> +<link rel="import" href="/components/polymer/polymer.html" data-suppress-import-order> + +<link rel="import" href="/tracing/ui/base/polymer_postload.html" data-suppress-import-order> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html index 5155376058a..e57daf3ac6c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base.html @@ -1,4 +1,4 @@ -<!DOCTYPE html> + <!DOCTYPE html> <!-- Copyright (c) 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be @@ -6,16 +6,146 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/color_scheme.html"> +<link rel="import" href="/tracing/ui/analysis/analysis_link.html"> <link rel="import" href="/tracing/ui/base/d3.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<dom-module id="tr-ui-b-chart-legend-key"> + <template> + <style> + #checkbox { + margin: 0; + visibility: hidden; + vertical-align: text-top; + } + #label, #link { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + display: inline-block; + } + </style> + + <input type=checkbox id="checkbox" checked> + <tr-ui-a-analysis-link id="link"></tr-ui-a-analysis-link> + <label id="label"></label> + </template> +</dom-module> + +<script> +'use strict'; + +tr.exportTo('tr.ui.b', function() { + function getSVGTextWidth(parentNode, text) { + var textNode = document.createElementNS( + 'http://www.w3.org/2000/svg', 'text'); + textNode.setAttributeNS(null, 'x', 0); + textNode.setAttributeNS(null, 'y', 0); + textNode.setAttributeNS(null, 'fill', 'black'); + textNode.appendChild(document.createTextNode(text)); + parentNode.appendChild(textNode); + var widthPx = textNode.getComputedTextLength(); + parentNode.removeChild(textNode); + return widthPx; + } + + return { + getSVGTextWidth: getSVGTextWidth + }; +}); + +Polymer({ + is: 'tr-ui-b-chart-legend-key', + + ready: function() { + this.$.checkbox.addEventListener( + 'change', this.onCheckboxChange_.bind(this)); + }, + + /** + * Dispatch an event when the checkbox is toggled. + * The checkbox is visible when optional is set to true. + */ + onCheckboxChange_: function() { + tr.b.dispatchSimpleEvent(this, tr.ui.b.DataSeriesEnableChangeEventType, + true, false, + {key: Polymer.dom(this).textContent, enabled: this.enabled}); + }, + + set textContent(t) { + Polymer.dom(this.$.label).textContent = t; + Polymer.dom(this.$.link).textContent = t; + this.updateContents_(); + }, + + set width(w) { + w -= 20; // reserve 20px for the checkbox + this.$.link.style.width = w + 'px'; + this.$.label.style.width = w + 'px'; + }, + + get textContent() { + return Polymer.dom(this.$.label).textContent; + }, + + /** + * When a legend-key is "optional", then its checkbox is visible to allow + * the user to enable/disable the data series for the key. + * + * @param {boolean} optional + */ + set optional(optional) { + this.$.checkbox.style.visibility = optional ? 'visible' : 'hidden'; + }, + + get optional() { + return this.$.checkbox.style.visibility === 'visible'; + }, + + set enabled(enabled) { + this.$.checkbox.checked = enabled ? 'checked' : ''; + }, + + get enabled() { + return this.$.checkbox.checked; + }, + + set color(c) { + this.$.label.style.color = c; + this.$.link.color = c; + }, + + /** + * When target is defined, label is hidden and link is shown. + * When the link is clicked, then a RequestSelectionChangeEvent is + * dispatched containing the target. + * When target is undefined, label is shown and link is hidden, so that the + * link is not clickable. + */ + set target(target) { + this.$.link.setSelectionAndContent( + target, Polymer.dom(this.$.label).textContent); + this.updateContents_(); + }, + + get target() { + return this.$.link.selection; + }, + + updateContents_: function() { + this.$.link.style.display = this.target ? '' : 'none'; + this.$.label.style.display = this.target ? 'none' : ''; + this.$.label.htmlFor = this.optional ? 'checkbox' : ''; + } +}); +</script> + <style> * /deep/ .chart-base #title { font-size: 16pt; } * /deep/ .chart-base { - font-size: 12pt; -webkit-user-select: none; cursor: default; } @@ -26,6 +156,10 @@ found in the LICENSE file. shape-rendering: crispEdges; stroke: #000; } + + * /deep/ .chart-base .legend body { + margin: 0; + } </style> <template id="chart-base-template"> @@ -42,6 +176,8 @@ found in the LICENSE file. 'use strict'; tr.exportTo('tr.ui.b', function() { + var DataSeriesEnableChangeEventType = 'data-series-enabled-change'; + var THIS_DOC = document.currentScript.ownerDocument; var svgNS = 'http://www.w3.org/2000/svg'; @@ -54,6 +190,65 @@ tr.exportTo('tr.ui.b', function() { return ColorScheme.colorsAsStrings[id]; } + function DataSeries(key) { + this.key_ = key; + this.target_ = undefined; + this.optional_ = false; + this.enabled_ = true; + this.color_ = getColorOfKey(key, false); + this.highlightedColor_ = getColorOfKey(key, true); + } + + DataSeries.prototype = { + get key() { + return this.key_; + }, + + get color() { + return this.color_; + }, + + set color(c) { + this.color_ = c; + }, + + get highlightedColor() { + return this.highlightedColor_; + }, + + set highlightedColor(c) { + this.highlightedColor_ = c; + }, + + get optional() { + return this.optional_; + }, + + set optional(optional) { + this.optional_ = optional; + }, + + get enabled() { + return this.enabled_; + }, + + set enabled(enabled) { + // If the caller is disabling a data series, but it wasn't optional, then + // force it to be optional. + if (!this.optional && !enabled) + this.optional = true; + this.enabled_ = enabled; + }, + + get target() { + return this.target_; + }, + + set target(t) { + this.target_ = t; + } + }; + /** * A virtual base class for basic charts that provides X and Y axes, if * needed, a title, and legend. @@ -65,20 +260,30 @@ tr.exportTo('tr.ui.b', function() { ChartBase.prototype = { __proto__: HTMLUnknownElement.prototype, + getDataSeries: function(key) { + if (!this.seriesByKey_.has(key)) + this.seriesByKey_.set(key, new DataSeries(key)); + return this.seriesByKey_.get(key); + }, + decorate: function() { - this.classList.add('chart-base'); + Polymer.dom(this).classList.add('chart-base'); this.chartTitle_ = undefined; - this.seriesKeys_ = undefined; + this.seriesByKey_ = new Map(); this.width_ = 400; this.height_ = 300; + this.margin = {top: 20, right: 72, bottom: 30, left: 50}; + this.hideLegend_ = false; // This should use tr.ui.b.instantiateTemplate. However, creating // svg-namespaced elements inside a template isn't possible. Thus, this // hack. - var template = THIS_DOC.querySelector('#chart-base-template'); - var svgEl = template.content.querySelector('svg'); - for (var i = 0; i < svgEl.children.length; i++) - this.appendChild(svgEl.children[i].cloneNode(true)); + var template = + Polymer.dom(THIS_DOC).querySelector('#chart-base-template'); + var svgEl = Polymer.dom(template.content).querySelector('svg'); + for (var i = 0; i < Polymer.dom(svgEl).children.length; i++) + Polymer.dom(this).appendChild( + Polymer.dom(svgEl.children[i]).cloneNode(true)); // svg likes to take over width & height properties for some reason. This // works around it. @@ -102,6 +307,26 @@ tr.exportTo('tr.ui.b', function() { this.updateContents_(); } }); + this.addEventListener(DataSeriesEnableChangeEventType, + this.onDataSeriesEnableChange_.bind(this)); + }, + + get hideLegend() { + return this.hideLegend_; + }, + + set hideLegend(h) { + this.hideLegend_ = h; + this.updateContents_(); + }, + + isSeriesEnabled: function(key) { + return this.getDataSeries(key).enabled; + }, + + onDataSeriesEnableChange_: function(event) { + this.getDataSeries(event.key).enabled = event.enabled; + this.updateContents_(); }, get chartTitle() { @@ -109,12 +334,21 @@ tr.exportTo('tr.ui.b', function() { }, set chartTitle(chartTitle) { + if (chartTitle && !this.chartTitle_) + this.margin.top += this.titleMarginPx; + else if (this.chartTitle_ && !chartTitle) + this.margin.top -= this.titleMarginPx; + this.chartTitle_ = chartTitle; this.updateContents_(); }, + get titleMarginPx() { + return 20; + }, + get chartAreaElement() { - return this.querySelector('#chart-area'); + return Polymer.dom(this).querySelector('#chart-area'); }, setSize: function(size) { @@ -123,43 +357,25 @@ tr.exportTo('tr.ui.b', function() { this.updateContents_(); }, - getMargin_: function() { - var margin = {top: 20, right: 20, bottom: 30, left: 50}; - if (this.chartTitle_) - margin.top += 20; - return margin; - }, - - get margin() { - return this.getMargin_(); - }, - get chartAreaSize() { - var margin = this.margin; return { - width: this.width_ - margin.left - margin.right, - height: this.height_ - margin.top - margin.bottom + width: this.width_ - this.margin.left - this.margin.right, + height: this.height_ - this.margin.top - this.margin.bottom }; }, - getLegendKeys_: function() { - throw new Error('Not implemented'); - }, - updateScales_: function() { throw new Error('Not implemented'); }, updateContents_: function() { - var margin = this.margin; - var thisSel = d3.select(this); thisSel.attr('width', this.width_); thisSel.attr('height', this.height_); var chartAreaSel = d3.select(this.chartAreaElement); chartAreaSel.attr('transform', - 'translate(' + margin.left + ',' + margin.top + ')'); + 'translate(' + this.margin.left + ',' + this.margin.top + ')'); this.updateScales_(); this.updateTitle_(chartAreaSel); @@ -181,45 +397,38 @@ tr.exportTo('tr.ui.b', function() { .text(this.chartTitle_); }, - // TODO(charliea): We should change updateLegend_ so that it ellipsizes the - // series names after a certain point. Otherwise, the series names start - // dipping below the x-axis and continue on outside of the viewport. updateLegend_: function() { - var keys = this.getLegendKeys_(); - if (keys === undefined) - return; - var chartAreaSel = d3.select(this.chartAreaElement); - var chartAreaSize = this.chartAreaSize; + chartAreaSel.selectAll('.legend').remove(); + if (this.hideLegend) + return; - var legendEntriesSel = chartAreaSel.selectAll('.legend') - .data(keys.slice().reverse()); + var series = [...this.seriesByKey_.values()].reverse(); + var legendEntriesSel = chartAreaSel.selectAll('.legend').data(series); + var width = this.margin.right - 2; legendEntriesSel.enter() - .append('g') + .append('foreignObject') .attr('class', 'legend') - .attr('transform', function(d, i) { - return 'translate(0,' + i * 20 + ')'; + .attr('x', this.chartAreaSize.width + 2) + .attr('width', width) + .attr('height', 18) + .attr('transform', function(series, i) { + return 'translate(0,' + i * 18 + ')'; }) - .append('text').text(function(key) { - return key; - }); + .append('xhtml:body') + .append('tr-ui-b-chart-legend-key') + .property('color', function(series) { + if (this.currentHighlightedLegendKey === series.key) + return series.highlightedColor; + return series.color; + }.bind(this)) + .property('width', width) + .property('target', function(series) { return series.target; }) + .property('optional', function(series) { return series.optional; }) + .property('enabled', function(series) { return series.enabled; }) + .text(function(series) { return series.key; }); legendEntriesSel.exit().remove(); - - legendEntriesSel.attr('x', chartAreaSize.width - 18) - .attr('width', 18) - .attr('height', 18) - .style('fill', function(key) { - var selected = this.currentHighlightedLegendKey === key; - return getColorOfKey(key, selected); - }.bind(this)); - - legendEntriesSel.selectAll('text') - .attr('x', chartAreaSize.width - 24) - .attr('y', 9) - .attr('dy', '.35em') - .style('text-anchor', 'end') - .text(function(d) { return d; }); }, get highlightedLegendKey() { @@ -245,7 +454,7 @@ tr.exportTo('tr.ui.b', function() { }, popTempHighlightedLegendKey: function(key) { - if (this.tempHighlightedLegendKey_ != key) + if (this.tempHighlightedLegendKey_ !== key) throw new Error('pop cannot happen'); this.tempHighlightedLegendKey_ = undefined; this.updateHighlight_(); @@ -258,18 +467,20 @@ tr.exportTo('tr.ui.b', function() { var that = this; legendEntriesSel.each(function(key) { - var highlighted = key == that.currentHighlightedLegendKey; - var color = getColorOfKey(key, highlighted); - this.style.fill = color; - if (highlighted) + var dataSeries = that.getDataSeries(key); + if (key === that.currentHighlightedLegendKey) { + this.style.fill = dataSeries.highlightedColor; this.style.fontWeight = 'bold'; - else + } else { + this.style.fill = dataSeries.color; this.style.fontWeight = ''; + } }); } }; return { + DataSeriesEnableChangeEventType: DataSeriesEnableChangeEventType, getColorOfKey: getColorOfKey, ChartBase: ChartBase }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html index 84cd5019157..566c4dcd26f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/iteration_helpers.html"> +<link rel="import" href="/tracing/base/raf.html"> <link rel="import" href="/tracing/base/range.html"> <link rel="import" href="/tracing/ui/base/chart_base.html"> <link rel="import" href="/tracing/ui/base/mouse_tracker.html"> @@ -32,16 +33,17 @@ tr.exportTo('tr.ui.b', function() { decorate: function() { ChartBase.prototype.decorate.call(this); - this.classList.add('chart-base-2d'); + Polymer.dom(this).classList.add('chart-base-2d'); this.xScale_ = d3.scale.linear(); this.yScale_ = d3.scale.linear(); this.isYLogScale_ = false; this.yLogScaleMin_ = undefined; this.dataRange_ = new tr.b.Range(); - + this.hideXAxis_ = false; + this.hideYAxis_ = false; this.data_ = []; - this.seriesKeys_ = []; - this.leftMargin_ = 50; + this.xAxisLabel_ = ''; + this.yAxisLabel_ = ''; d3.select(this.chartAreaElement) .append('g') @@ -53,6 +55,40 @@ tr.exportTo('tr.ui.b', function() { this.addEventListener('mousedown', this.onMouseDown_.bind(this)); }, + get xAxisLabel() { + return this.xAxisLabel_; + }, + + set xAxisLabel(label) { + this.xAxisLabel_ = label; + }, + + get yAxisLabel() { + return this.yAxisLabel_; + }, + + set yAxisLabel(label) { + this.yAxisLabel_ = label; + }, + + get hideXAxis() { + return this.hideXAxis_; + }, + + set hideXAxis(h) { + this.hideXAxis_ = h; + this.updateContents_(); + }, + + get hideYAxis() { + return this.hideYAxis_; + }, + + set hideYAxis(h) { + this.hideYAxis_ = h; + this.updateContents_(); + }, + get data() { return this.data_; }, @@ -109,23 +145,15 @@ tr.exportTo('tr.ui.b', function() { return leftWidth * 0.5 + rightWidth * 0.5; }, - getLegendKeys_: function() { - if (this.seriesKeys_ && - this.seriesKeys_.length > 1) - return this.seriesKeys_.slice(); - return []; - }, - updateSeriesKeys_: function() { - // Accumulate the keys on each data point. - var keySet = {}; + // Don't clear seriesByKey_; the caller might have put state in it using + // getDataSeries() before setting data. this.data_.forEach(function(datum) { Object.keys(datum).forEach(function(key) { if (this.isDatumFieldSeries_(key)) - keySet[key] = true; + this.getDataSeries(key); }, this); }, this); - this.seriesKeys_ = Object.keys(keySet); }, isDatumFieldSeries_: function(fieldName) { @@ -149,11 +177,12 @@ tr.exportTo('tr.ui.b', function() { // Y. var yRange = new tr.b.Range(); - var keySet = new Set(this.seriesKeys_); - for (var i = 0; i < this.data_.length; i++) - for (var key in this.data_[i]) - if (keySet.has(key)) + for (var i = 0; i < this.data_.length; i++) { + for (var key in this.data_[i]) { + if (!isNaN(Math.max(this.data_[i][key]))) yRange.addValue(this.data_[i][key]); + } + } this.yScale_.range([height, 0]); this.yScale_.domain([yRange.min, yRange.max]); @@ -166,30 +195,46 @@ tr.exportTo('tr.ui.b', function() { updateXAxis_: function(xAxis) { xAxis.selectAll('*').remove(); xAxis[0][0].style.opacity = 0; + if (this.hideXAxis) + return; + + this.drawXAxis_(xAxis); + + var label = xAxis.append('text').attr('class', 'label'); + + tr.b.requestAnimationFrame(() => { + this.drawXAxisTicks_(xAxis); + this.drawXAxisLabel_(label); + }); + }, + + drawXAxis_: function(xAxis) { xAxis.attr('transform', 'translate(0,' + this.chartAreaSize.height + ')') .call(d3.svg.axis() .scale(this.xScale_) .orient('bottom')); - window.requestAnimationFrame(function() { - var previousRight = undefined; - xAxis.selectAll('.tick')[0].forEach(function(tick) { - var currentLeft = tick.transform.baseVal[0].matrix.e; - if ((previousRight === undefined) || - (currentLeft > (previousRight + 3))) { - var currentWidth = tick.getBBox().width; - previousRight = currentLeft + currentWidth; - } else { - tick.style.opacity = 0; - } - }); - xAxis[0][0].style.opacity = 1; - }); }, - getMargin_: function() { - var margin = ChartBase.prototype.getMargin_.call(this); - margin.left = this.leftMargin_; - return margin; + drawXAxisLabel_: function(label) { + label + .attr('x', this.chartAreaSize.width + 16) + .attr('y', 8) + .text(this.xAxisLabel); + }, + + drawXAxisTicks_: function(xAxis) { + var previousRight = undefined; + xAxis.selectAll('.tick')[0].forEach(function(tick) { + var currentLeft = tick.transform.baseVal[0].matrix.e; + if ((previousRight === undefined) || + (currentLeft > (previousRight + 3))) { + var currentWidth = tick.getBBox().width; + previousRight = currentLeft + currentWidth; + } else { + tick.style.opacity = 0; + } + }); + xAxis[0][0].style.opacity = 1; }, updateDataRange_: function() { @@ -206,7 +251,7 @@ tr.exportTo('tr.ui.b', function() { this.yLogScaleMin_ = undefined; if (this.dataRange_.min !== undefined) { var minValue = this.dataRange_.min; - if (minValue == 0) + if (minValue === 0) minValue = 1; var onePowerLess = Math.floor( @@ -218,7 +263,20 @@ tr.exportTo('tr.ui.b', function() { updateYAxis_: function(yAxis) { yAxis.selectAll('*').remove(); yAxis[0][0].style.opacity = 0; + if (this.hideYAxis) + return; + + this.drawYAxis_(yAxis); + var label = yAxis.append('text').attr('class', 'label'); + + tr.b.requestAnimationFrame(() => { + this.drawYAxisTicks_(yAxis); + this.drawYAxisLabel_(label); + }); + }, + + drawYAxis_: function(yAxis) { var axisModifier = d3.svg.axis() .scale(this.yScale_) .orient('left'); @@ -227,7 +285,7 @@ tr.exportTo('tr.ui.b', function() { if (this.yLogScaleMin_ === undefined) return; var minValue = this.dataRange_.min; - if (minValue == 0) + if (minValue === 0) minValue = 1; var largestPower = Math.ceil( @@ -247,29 +305,40 @@ tr.exportTo('tr.ui.b', function() { } yAxis.call(axisModifier); + }, - window.requestAnimationFrame(function() { - var previousTop = undefined; - var leftMargin = 0; - yAxis.selectAll('.tick')[0].forEach(function(tick) { - var bbox = tick.getBBox(); - leftMargin = Math.max(leftMargin, bbox.width); - var currentTop = tick.transform.baseVal[0].matrix.f; - var currentBottom = currentTop + bbox.height; - if ((previousTop === undefined) || - (previousTop > (currentBottom + 3))) { - previousTop = currentTop; - } else { - tick.style.opacity = 0; - } - }); - if (leftMargin > this.leftMargin_) { - this.leftMargin_ = leftMargin; - this.updateContents_(); + drawYAxisLabel_: function(label) { + var labelWidthPx = Math.ceil(tr.ui.b.getSVGTextWidth( + this.chartAreaElement, this.yAxisLabel)); + label + .attr('x', -labelWidthPx) + .attr('y', -8) + .text(this.yAxisLabel); + }, + + drawYAxisTicks_: function(yAxis) { + var previousTop = undefined; + var leftMargin = 0; + yAxis.selectAll('.tick')[0].forEach(function(tick) { + var bbox = tick.getBBox(); + leftMargin = Math.max(leftMargin, bbox.width); + var currentTop = tick.transform.baseVal[0].matrix.f; + var currentBottom = currentTop + bbox.height; + if ((previousTop === undefined) || + (previousTop > (currentBottom + 3))) { + previousTop = currentTop; } else { - yAxis[0][0].style.opacity = 1; + tick.style.opacity = 0; } - }.bind(this)); + }); + + leftMargin = parseInt(Math.ceil(leftMargin)); + if (leftMargin > this.margin.left) { + this.margin.left = leftMargin; + this.updateContents_(); + } else { + yAxis[0][0].style.opacity = 1; + } }, updateContents_: function() { @@ -296,9 +365,9 @@ tr.exportTo('tr.ui.b', function() { */ getDataBySeriesKey_: function() { var dataBySeriesKey = {}; - this.seriesKeys_.forEach(function(seriesKey) { - dataBySeriesKey[seriesKey] = []; - }); + for (var [key, series] of this.seriesByKey_) { + dataBySeriesKey[key] = []; + } this.data_.forEach(function(multiSeriesDatum, index) { var x = this.getXForDatum_(multiSeriesDatum, index); @@ -323,16 +392,27 @@ tr.exportTo('tr.ui.b', function() { return dataBySeriesKey; }, - getDataPointAtClientPoint_: function(clientX, clientY) { + getChartPointAtClientPoint_: function(clientPoint) { var rect = this.getBoundingClientRect(); - var margin = this.margin; - var x = clientX - rect.left - margin.left; - var y = clientY - rect.top - margin.top; - x = this.xScale_.invert(x); - y = this.yScale_.invert(y); - x = tr.b.clamp(x, this.xScale_.domain()[0], this.xScale_.domain()[1]); - y = tr.b.clamp(y, this.yScale_.domain()[0], this.yScale_.domain()[1]); - return {x: x, y: y}; + return { + x: clientPoint.x - rect.left - this.margin.left, + y: clientPoint.y - rect.top - this.margin.top + }; + }, + + getDataPointAtChartPoint_: function(chartPoint) { + return { + x: tr.b.clamp(this.xScale_.invert(chartPoint.x), + this.xScale_.domain()[0], this.xScale_.domain()[1]), + y: tr.b.clamp(this.yScale_.invert(chartPoint.y), + this.yScale_.domain()[0], this.yScale_.domain()[1]) + }; + }, + + getDataPointAtClientPoint_: function(clientX, clientY) { + var chartPoint = this.getChartPointAtClientPoint_( + {x: clientX, y: clientY}); + return this.getDataPointAtChartPoint_(chartPoint); }, prepareDataEvent_: function(mouseEvent, dataEvent) { @@ -350,7 +430,7 @@ tr.exportTo('tr.ui.b', function() { mouseEvent.stopPropagation(); var dataEvent = new tr.b.Event('item-mousedown'); dataEvent.button = mouseEvent.button; - this.classList.add('updating-brushing-state'); + Polymer.dom(this).classList.add('updating-brushing-state'); this.prepareDataEvent_(mouseEvent, dataEvent); this.dispatchEvent(dataEvent); }, @@ -373,7 +453,7 @@ tr.exportTo('tr.ui.b', function() { dataEvent.button = button; this.prepareDataEvent_(mouseEvent, dataEvent); this.dispatchEvent(dataEvent); - this.classList.remove('updating-brushing-state'); + Polymer.dom(this).classList.remove('updating-brushing-state'); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html index 4cde4b58bdd..5d2f799945e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/chart_base_2d_brushable_x.html @@ -65,6 +65,10 @@ tr.exportTo('tr.ui.b', function() { var brushRectsSel = brushSel.selectAll('rect').data(brushes); brushRectsSel.enter().append('rect'); brushRectsSel.exit().remove(); + this.drawBrush_(brushRectsSel); + }, + + drawBrush_: function(brushRectsSel) { brushRectsSel .attr('x', function(d) { return this.xScale_(d.min); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html index 9de49183853..06469f68170 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox.html @@ -9,7 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name='tr-ui-b-checkbox'> +<dom-module id='tr-ui-b-checkbox'> <template> <style> .inline { @@ -20,11 +20,12 @@ found in the LICENSE file. <input type="checkbox" id="checkbox" class="inline"/> <div id="label" class="inline"></div> </template> - <script> 'use strict'; Polymer({ + is: 'tr-ui-b-checkbox', + created: function() { this.needsInit_ = true; this.defaultCheckedValue_ = undefined; @@ -100,8 +101,7 @@ found in the LICENSE file. this.checked_ = checked; this.maybeUpdateElements_(); tr.b.Settings.set(this.settingsKey_, this.checked_); - }, - + } }); </script> -</polymer-element> +</dom-module> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html index 261b15922bd..5b5d242b96b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker.html @@ -8,7 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/checkbox.html"> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name='tr-ui-b-checkbox-picker'> +<dom-module id='tr-ui-b-checkbox-picker'> <template> <style> #container { @@ -19,93 +19,91 @@ found in the LICENSE file. <div id="container"> </div> - </template> - - <script> - 'use strict'; - - Polymer({ - created: function() { - this.needsInit_ = true; - this.settingsKey_ = undefined; - this.is_ready_ = false; - this.checkboxes_ = undefined; - }, - - ready: function() { - this.is_ready_ = true; - this.maybeInit_(); - this.maybeRenderCheckboxes_(); - }, - - get settingsKey() { - return this.settingsKey_; - }, - - set settingsKey(settingsKey) { - if (!this.needsInit_) - throw new Error('Already initialized.'); - this.settingsKey_ = settingsKey; - this.maybeInit_(); - }, - - maybeInit_: function() { - if (!this.needsInit_) - return; - if (this.settingsKey_ === undefined) - return; - if (this.checkboxes_ === undefined) - return; - - this.needsInit_ = false; - - for (var key in this.checkboxes_) { - this.checkboxes_[key].defaultCheckedValue = false; - this.checkboxes_[key].settingsKey = this.settingsKey_ + key; - } - }, - - set items(items) { - this.checkboxes_ = {}; - items.forEach(function(e) { - if (e.key in this.checkboxes_) - throw new Error(e.key + ' already exists'); - var checkboxEl = document.createElement('tr-ui-b-checkbox'); - checkboxEl.label = e.label; - this.checkboxes_[e.key] = checkboxEl; - }.bind(this)); - this.maybeInit_(); - this.maybeRenderCheckboxes_(); - }, - - maybeRenderCheckboxes_: function() { - if (!this.is_ready_) - return; - if (this.checkboxes_ === undefined) - return; - for (var key in this.checkboxes_) - this.$.container.appendChild(this.checkboxes_[key]); - }, - - selectCheckbox: function(key) { - if (!(key in this.checkboxes_)) - throw new Error(key + ' does not exists'); - this.checkboxes_[key].checked = true; - }, - - unselectCheckbox: function(key) { - if (!(key in this.checkboxes_)) - throw new Error(key + ' does not exists'); - this.checkboxes_[key].checked = false; - }, - - get checkedKeys() { - return Object.keys(this.checkboxes_).filter(function(k) { - return this.checkboxes_[k].checked; - }.bind(this)); - }, - - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-b-checkbox-picker', + created: function() { + this.needsInit_ = true; + this.settingsKey_ = undefined; + this.is_ready_ = false; + this.checkboxes_ = undefined; + }, + + ready: function() { + this.is_ready_ = true; + this.maybeInit_(); + this.maybeRenderCheckboxes_(); + }, + + get settingsKey() { + return this.settingsKey_; + }, + + set settingsKey(settingsKey) { + if (!this.needsInit_) + throw new Error('Already initialized.'); + this.settingsKey_ = settingsKey; + this.maybeInit_(); + }, + + maybeInit_: function() { + if (!this.needsInit_) + return; + if (this.settingsKey_ === undefined) + return; + if (this.checkboxes_ === undefined) + return; + + this.needsInit_ = false; + + for (var key in this.checkboxes_) { + this.checkboxes_[key].defaultCheckedValue = false; + this.checkboxes_[key].settingsKey = this.settingsKey_ + key; + } + }, + + set items(items) { + this.checkboxes_ = {}; + items.forEach(function(e) { + if (e.key in this.checkboxes_) + throw new Error(e.key + ' already exists'); + var checkboxEl = document.createElement('tr-ui-b-checkbox'); + checkboxEl.label = e.label; + this.checkboxes_[e.key] = checkboxEl; + }.bind(this)); + this.maybeInit_(); + this.maybeRenderCheckboxes_(); + }, + + maybeRenderCheckboxes_: function() { + if (!this.is_ready_) + return; + if (this.checkboxes_ === undefined) + return; + for (var key in this.checkboxes_) + Polymer.dom(this.$.container).appendChild(this.checkboxes_[key]); + }, + + selectCheckbox: function(key) { + if (!(key in this.checkboxes_)) + throw new Error(key + ' does not exists'); + this.checkboxes_[key].checked = true; + }, + + unselectCheckbox: function(key) { + if (!(key in this.checkboxes_)) + throw new Error(key + ' does not exists'); + this.checkboxes_[key].checked = false; + }, + + get checkedKeys() { + return Object.keys(this.checkboxes_).filter(function(k) { + return this.checkboxes_[k].checked; + }.bind(this)); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html index 40d83361fb6..674696d898b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/checkbox_picker_test.html @@ -75,7 +75,7 @@ tr.b.unittest.testSuite(function() { ]; cp.selectCheckbox('Toyota'); cp.selectCheckbox('Tesla'); - container1.appendChild(cp); + Polymer.dom(container1).appendChild(cp); this.addHTMLOutput(container1); cp.unselectCheckbox('Tesla'); assert.deepEqual(cp.checkedKeys, ['Toyota']); @@ -93,7 +93,7 @@ tr.b.unittest.testSuite(function() { {key: 'Honda', label: 'I want to drive Honda'}, {key: 'Tesla', label: 'I want to drive electric car'}, ]; - container2.appendChild(cp2); + Polymer.dom(container2).appendChild(cp2); this.addHTMLOutput(container2); assert.deepEqual(cp2.checkedKeys, ['Toyota']); }); @@ -110,7 +110,7 @@ tr.b.unittest.testSuite(function() { cp.settingsKey = 'checkbox-picker-test-one'; cp.selectCheckbox('Toyota'); cp.selectCheckbox('Tesla'); - container1.appendChild(cp); + Polymer.dom(container1).appendChild(cp); this.addHTMLOutput(container1); assert.deepEqual(cp.checkedKeys.sort(), ['Tesla', 'Toyota']); @@ -126,7 +126,7 @@ tr.b.unittest.testSuite(function() { {key: 'Honda', label: 'I want to drive Honda'}, {key: 'Tesla', label: 'I want to drive electric car'}, ]; - container2.appendChild(cp2); + Polymer.dom(container2).appendChild(cp2); this.addHTMLOutput(container2); cp2.settingsKey = 'checkbox-picker-test-one'; assert.deepEqual(cp2.checkedKeys.sort(), ['Tesla', 'Toyota']); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html b/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html index 3804b4b144c..791440def9e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/color_legend.html @@ -15,7 +15,7 @@ found in the LICENSE file. The colored square is typically filled with the color associated with that label, using the getColorId* methods from base/color_scheme. --> -<polymer-element name="tr-ui-b-color-legend"> +<dom-module id='tr-ui-b-color-legend'> <template> <style> :host { @@ -30,50 +30,52 @@ that label, using the getColorId* methods from base/color_scheme. <span id="square"></span> <span id="label"></span> </template> - <script> - 'use strict'; +</dom-module> +<script> +'use strict'; - Polymer({ - ready: function() { - var blackSquareCharCode = 9632; - this.$.square.innerText = String.fromCharCode(blackSquareCharCode); - this.label_ = undefined; +Polymer({ + is: 'tr-ui-b-color-legend', - this.compoundEventSelectionState_ = - tr.model.CompoundEventSelectionState.NOT_SELECTED; - }, + ready: function() { + var blackSquareCharCode = 9632; + this.$.square.innerText = String.fromCharCode(blackSquareCharCode); + this.label_ = undefined; - set compoundEventSelectionState(compoundEventSelectionState) { - this.compoundEventSelectionState_ = compoundEventSelectionState; - // TODO(nduca): Adjust appearance based on associated state. - }, + this.compoundEventSelectionState_ = + tr.model.CompoundEventSelectionState.NOT_SELECTED; + }, - get label() { - return this.label_; - }, + set compoundEventSelectionState(compoundEventSelectionState) { + this.compoundEventSelectionState_ = compoundEventSelectionState; + // TODO(nduca): Adjust appearance based on associated state. + }, - set label(label) { - if (label === undefined) { - this.setLabelAndColorId(undefined, undefined); - return; - } + get label() { + return this.label_; + }, - var colorId = tr.b.ColorScheme.getColorIdForGeneralPurposeString( - label); - this.setLabelAndColorId(label, colorId); - }, + set label(label) { + if (label === undefined) { + this.setLabelAndColorId(undefined, undefined); + return; + } - setLabelAndColorId: function(label, colorId) { - this.label_ = label; + var colorId = tr.b.ColorScheme.getColorIdForGeneralPurposeString( + label); + this.setLabelAndColorId(label, colorId); + }, - this.$.label.textContent = ''; - this.$.label.appendChild(tr.ui.b.asHTMLOrTextNode(label)); + setLabelAndColorId: function(label, colorId) { + this.label_ = label; - if (colorId === undefined) - this.$.square.style.color = 'initial'; - else - this.$.square.style.color = tr.b.ColorScheme.colorsAsStrings[colorId]; - } - }); - </script> -</polymer-element> + Polymer.dom(this.$.label).textContent = ''; + Polymer.dom(this.$.label).appendChild(tr.ui.b.asHTMLOrTextNode(label)); + + if (colorId === undefined) + this.$.square.style.color = 'initial'; + else + this.$.square.style.color = tr.b.ColorScheme.colorsAsStrings[colorId]; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html new file mode 100644 index 00000000000..74141d47b08 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart.html @@ -0,0 +1,248 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2014 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/base/chart_base_2d_brushable_x.html"> + +<script> +'use strict'; + +tr.exportTo('tr.ui.b', function() { + var ColorScheme = tr.b.ColorScheme; + var ChartBase2DBrushX = tr.ui.b.ChartBase2DBrushX; + + // @constructor + var ColumnChart = tr.ui.b.define('column-chart', ChartBase2DBrushX); + + ColumnChart.prototype = { + __proto__: ChartBase2DBrushX.prototype, + + decorate: function() { + ChartBase2DBrushX.prototype.decorate.call(this); + Polymer.dom(this).classList.add('column-chart'); + + // ColumnChart allows bars to have arbitrary, non-uniform widths. Bars + // need not all be the same width. The width of each bar is automatically + // computed from the bar's x-coordinate and that of the next bar, which + // can not define the width of the last bar. This is the width (in the + // xScale's domain (as opposed to the xScale's range (which is measured in + // pixels))) of the last bar. When there are at least 2 bars, this is + // computed as the average width of the bars. When there is a single bar, + // this must default to a non-zero number so that the width of the only + // bar will not be zero. + this.xCushion_ = 1; + + this.isStacked_ = false; + }, + + set isStacked(stacked) { + this.isStacked_ = true; + this.updateContents_(); + }, + + get isStacked() { + return this.isStacked_; + }, + + isDatumFieldSeries_: function(fieldName) { + return fieldName !== 'x'; + }, + + getXForDatum_: function(datum, index) { + return datum.x; + }, + + updateScales_: function() { + if (this.data_.length === 0) + return; + + var xDifferences = 0; + var currentX = undefined; + var previousX = undefined; + var yRange = new tr.b.Range(); + this.data_.forEach(function(datum, index) { + previousX = currentX; + currentX = this.getXForDatum_(datum, index); + if (previousX !== undefined) { + xDifferences += currentX - previousX; + } + + for (var [key, series] of this.seriesByKey_) { + // Allow for sparse data + if (datum[key] !== undefined) + yRange.addValue(datum[key]); + } + }, this); + + // X. + // Leave a cushion on the right so that the last rect doesn't + // exceed the chart boundaries. The last rect's width is set to the + // average width of the rects, which is chart.width / data.length. + var width = this.chartAreaSize.width; + this.xScale_.range([0, width]); + var domain = d3.extent(this.data_, this.getXForDatum_.bind(this)); + if (this.data_.length > 1) + this.xCushion_ = xDifferences / (this.data_.length - 1); + this.xScale_.domain([domain[0], domain[1] + this.xCushion_]); + + // Y. + this.yScale_.range([this.chartAreaSize.height, 0]); + this.yScale_.domain(this.getYScaleDomain_(yRange.min, yRange.max)); + }, + + getYScaleDomain_: function(minValue, maxValue) { + if (!this.isStacked) { + return ChartBase2DBrushX.prototype.getYScaleDomain_.call( + this, minValue, maxValue); + } + + var range = new tr.b.Range(); + range.addValue(0); + this.data_.forEach(function(datum, index) { + var sum = 0; + for (var [key, series] of this.seriesByKey_) { + if (datum[key] === undefined) + continue; + sum += datum[key]; + } + range.addValue(sum); + }, this); + return [range.min, range.max]; + }, + + getStackedRectsForDatum_: function(datum, index) { + var stacks = []; + var bottom = this.yScale_.range()[0]; + var sum = 0; + for (var [key, series] of this.seriesByKey_) { + if (datum[key] === undefined || !this.isSeriesEnabled(key)) + continue; + sum += datum[key]; + var heightPx = bottom - this.yScale_(sum); + bottom -= heightPx; + stacks.push({ + key: key, + value: datum[key], + color: this.getDataSeries(key).color, + heightPx: heightPx, + topPx: bottom + }); + } + return stacks; + }, + + getRectsForDatum_: function(datum, index) { + if (this.isStacked) + return this.getStackedRectsForDatum_(datum, index); + + var stacks = []; + for (var [key, series] of this.seriesByKey_) { + if (datum[key] === undefined || !this.isSeriesEnabled(key)) + continue; + var topPx = this.yScale_(Math.max(datum[key], this.getYScaleMin_())); + stacks.push({ + key: key, + value: datum[key], + topPx: topPx, + heightPx: this.yScale_.range()[0] - topPx, + color: this.getDataSeries(key).color + }); + } + stacks.sort(function(a, b) { + return b.topPx - a.topPx; + }); + return stacks; + }, + + drawHoverValueBox_: function(rect) { + var seriesKeys = [...this.seriesByKey_.keys()]; + var chartAreaSel = d3.select(this.chartAreaElement); + chartAreaSel.selectAll('.hover').remove(); + var keyWidthPx = 0; + var keyHeightPx = 0; + if (seriesKeys.length > 1) { + keyWidthPx = tr.ui.b.getSVGTextWidth( + this.chartAreaElement, rect.key) + 5; + keyHeightPx = 16; + } + var valueWidthPx = tr.ui.b.getSVGTextWidth( + this.chartAreaElement, rect.value) + 5; + var valueHeightPx = 16; + var hoverLeftPx = rect.leftPx + (rect.widthPx / 2); + + chartAreaSel + .append('rect') + .attr('class', 'hover') + .attr('fill', 'white') + .attr('x', hoverLeftPx) + .attr('y', rect.topPx) + .attr('width', Math.max(keyWidthPx, valueWidthPx)) + .attr('height', keyHeightPx + valueHeightPx); + + if (seriesKeys.length > 1) { + chartAreaSel + .append('text') + .attr('class', 'hover') + .attr('fill', rect.color) + .attr('x', hoverLeftPx + 2) + .attr('y', rect.topPx + keyHeightPx - 3) + .text(rect.key); + } + + chartAreaSel + .append('text') + .attr('class', 'hover') + .attr('fill', rect.color) + .attr('x', hoverLeftPx + 2) + .attr('y', rect.topPx + keyHeightPx + valueHeightPx - 3) + .text(rect.value); + }, + + clearHoverValueBox_: function() { + d3.select(this.chartAreaElement).selectAll('.hover').remove(); + }, + + drawRect_: function(rect, sel) { + sel.append('rect') + .attr('fill', rect.color) + .attr('x', rect.leftPx) + .attr('y', rect.topPx) + .attr('width', rect.widthPx) + .attr('height', rect.heightPx) + .on('mouseenter', this.drawHoverValueBox_.bind(this, rect)) + .on('mouseleave', this.clearHoverValueBox_.bind(this)); + }, + + updateDataContents_: function(dataSel) { + dataSel.selectAll('*').remove(); + var chartAreaSel = d3.select(this.chartAreaElement); + var seriesKeys = [...this.seriesByKey_.keys()]; + var rectsSel = dataSel.selectAll('path').data(seriesKeys); + this.data_.forEach(function(datum, index) { + var currentX = this.getXForDatum_(datum, index); + var width = undefined; + if (index < (this.data_.length - 1)) { + var nextX = this.getXForDatum_(this.data_[index + 1], index + 1); + width = nextX - currentX; + } else { + width = this.xCushion_; + } + for (var rect of this.getRectsForDatum_(datum, index)) { + rect.leftPx = this.xScale_(currentX); + rect.rightPx = this.xScale_(currentX + width); + rect.widthPx = rect.rightPx - rect.leftPx; + this.drawRect_(rect, rectsSel.enter()); + } + }, this); + rectsSel.exit().remove(); + } + }; + + return { + ColumnChart: ColumnChart, + }; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html new file mode 100644 index 00000000000..d8a961350a4 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/column_chart_test.html @@ -0,0 +1,295 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2014 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/base/column_chart.html"> +<link rel="import" href="/tracing/ui/base/deep_utils.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + test('chartLegendKey', function() { + var key = document.createElement('tr-ui-b-chart-legend-key'); + key.textContent = 'Lorem ipsum dolor sit amet'; + key.color = 'red'; + this.addHTMLOutput(key); + + key = document.createElement('tr-ui-b-chart-legend-key'); + key.textContent = 'ipsum dolor sit amet'; + key.target = 'orange ipsum'; + key.color = 'orange'; + this.addHTMLOutput(key); + key.addEventListener('requestSelectionChange', function(e) { + console.debug(e); + }); + + key = document.createElement('tr-ui-b-chart-legend-key'); + key.target = 'brown dolor'; + key.color = 'brown'; + key.textContent = 'dolor sit amet'; + this.addHTMLOutput(key); + key.addEventListener('requestSelectionChange', function(e) { + console.debug(e); + }); + }); + + test('instantiation_legendTargets', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.getDataSeries('lorem_ipsum').target = 'lorem_ipsumTarget'; + chart.getDataSeries('qux').target = 'quxTarget'; + chart.getDataSeries('lorem_ipsum').optional = true; + chart.getDataSeries('bar').optional = true; + chart.isStacked = true; + chart.hideXAxis = true; + chart.width = 140; + chart.height = 200; + chart.chartTitle = 'title'; + chart.data = [{x: 0, foo: 3, lorem_ipsum: 5, bar: 1, qux: 2}]; + this.addHTMLOutput(chart); + chart.addEventListener('requestSelectionChange', function(e) { + console.debug(e); + }); + + assert.isDefined(tr.b.findDeepElementMatchingPredicate( + chart, function(element) { + return element.tagName === 'TR-UI-B-CHART-LEGEND-KEY' && + element.textContent === 'lorem_ipsum' && + element.target === 'lorem_ipsumTarget'; + })); + }); + + test('instantiation_singleSeries', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.xAxisLabel = 'ms'; + chart.yAxisLabel = '#'; + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, value: 100}, + {x: 20, value: 110}, + {x: 30, value: 100}, + {x: 40, value: 50} + ]; + chart.data = data; + this.addHTMLOutput(chart); + }); + + test('instantiation_singleDatum', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 0, value: 100}, + ]; + chart.data = data; + this.addHTMLOutput(chart); + }); + + test('instantiation_stacked', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.isStacked = true; + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'title'; + var data = [ + {x: 10, foo: 10, bar: 5, qux: 7}, + {x: 20, foo: 11, bar: 6, qux: 3}, + {x: 30, foo: 10, bar: 4, qux: 8}, + {x: 40, foo: 5, bar: 1, qux: 2} + ]; + chart.data = data; + this.addHTMLOutput(chart); + }); + + test('instantiation_singleSeries_yLogScale', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.isYLogScale = true; + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, value: 100}, + {x: 20, value: 10}, + {x: 30, value: 1}, + {x: 40, value: 0.1}, + {x: 50, value: 0.01}, + {x: 60, value: 0.001} + ]; + chart.data = data; + this.addHTMLOutput(chart); + }); + + test('undefined', function() { + var chart = new tr.ui.b.ColumnChart(); + assert.throws(function() { + chart.data = undefined; + }); + }); + + test('instantiation_twoSeries', function() { + var chart = new tr.ui.b.ColumnChart(); + + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, alpha: 100, beta: 50}, + {x: 20, alpha: 110, beta: 75}, + {x: 30, alpha: 100, beta: 125}, + {x: 40, alpha: 50, beta: 125} + ]; + chart.data = data; + + var r = new tr.b.Range(); + r.addValue(20); + r.addValue(40); + chart.brushedRange = r; + + this.addHTMLOutput(chart); + }); + + test('instantiation_twoSeries_yLogScale', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.isYLogScale = true; + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, alpha: 100, beta: 50}, + {x: 20, alpha: 110, beta: 75}, + {x: 30, alpha: 100, beta: 125}, + {x: 40, alpha: 50, beta: 125} + ]; + chart.data = data; + + var r = new tr.b.Range(); + r.addValue(20); + r.addValue(40); + chart.brushedRange = r; + + this.addHTMLOutput(chart); + }); + + test('instantiation_twoSparseSeriesWithFirstValueSparse', function() { + var chart = new tr.ui.b.ColumnChart(); + + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, alpha: 20, beta: undefined}, + {x: 20, alpha: undefined, beta: 10}, + {x: 30, alpha: 10, beta: undefined}, + {x: 45, alpha: undefined, beta: 20}, + {x: 50, alpha: 25, beta: 30} + ]; + chart.data = data; + + this.addHTMLOutput(chart); + }); + + test('instantiation_twoSparseSeriesWithFirstValueNotSparse', function() { + var chart = new tr.ui.b.ColumnChart(); + + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, alpha: 20, beta: 40}, + {x: 20, alpha: undefined, beta: 10}, + {x: 30, alpha: 10, beta: undefined}, + {x: 45, alpha: undefined, beta: 20}, + {x: 50, alpha: 30, beta: undefined} + ]; + chart.data = data; + + this.addHTMLOutput(chart); + }); + + test('brushRangeFromIndices', function() { + var chart = new tr.ui.b.ColumnChart(); + var data = [ + {x: 10, value: 50}, + {x: 30, value: 60}, + {x: 70, value: 70}, + {x: 80, value: 80}, + {x: 120, value: 90} + ]; + chart.data = data; + var r = new tr.b.Range(); + + // Range min should be 10. + r = chart.computeBrushRangeFromIndices(-2, 1); + assert.equal(r.min, 10); + + // Range max should be 120. + r = chart.computeBrushRangeFromIndices(3, 10); + assert.equal(r.max, 120); + + // Range should be [10, 120] + r = chart.computeBrushRangeFromIndices(-2, 10); + assert.equal(r.min, 10); + assert.equal(r.max, 120); + + // Range should be [20, 100] + r = chart.computeBrushRangeFromIndices(1, 3); + assert.equal(r.min, 20); + assert.equal(r.max, 100); + }); + + test('instantiation_interactiveBrushing', function() { + var chart = new tr.ui.b.ColumnChart(); + chart.width = 400; + chart.height = 200; + chart.chartTitle = 'Chart title'; + var data = [ + {x: 10, value: 50}, + {x: 20, value: 60}, + {x: 30, value: 80}, + {x: 40, value: 20}, + {x: 50, value: 30}, + {x: 60, value: 20}, + {x: 70, value: 15}, + {x: 80, value: 20} + ]; + chart.data = data; + + var mouseDownX = undefined; + var curMouseX = undefined; + + function updateBrushedRange() { + if (mouseDownX === undefined || (mouseDownX === curMouseX)) { + chart.brushedRange = new tr.b.Range(); + return; + } + var r = new tr.b.Range(); + r.min = Math.min(mouseDownX, curMouseX); + r.max = Math.max(mouseDownX, curMouseX); + chart.brushedRange = r; + } + + chart.addEventListener('item-mousedown', function(e) { + mouseDownX = e.x; + curMouseX = e.x; + updateBrushedRange(); + }); + chart.addEventListener('item-mousemove', function(e) { + if (e.button === undefined) + return; + curMouseX = e.x; + updateBrushedRange(); + }); + chart.addEventListener('item-mouseup', function(e) { + curMouseX = e.x; + updateBrushedRange(); + }); + this.addHTMLOutput(chart); + }); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html index 11ed53a5fda..870f266b9aa 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children.html @@ -21,7 +21,7 @@ tr.exportTo('tr.ui.b', function() { var ContainerThatDecoratesItsChildren = tr.ui.b.define('div'); ContainerThatDecoratesItsChildren.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.observer_ = new WebKitMutationObserver(this.didMutate_.bind(this)); @@ -35,34 +35,35 @@ tr.exportTo('tr.ui.b', function() { }, appendChild: function(x) { - HTMLUnknownElement.prototype.appendChild.call(this, x); + HTMLDivElement.prototype.appendChild.call(this, x); this.didMutate_(this.observer_.takeRecords()); }, insertBefore: function(x, y) { - HTMLUnknownElement.prototype.insertBefore.call(this, x, y); + HTMLDivElement.prototype.insertBefore.call(this, x, y); this.didMutate_(this.observer_.takeRecords()); }, removeChild: function(x) { - HTMLUnknownElement.prototype.removeChild.call(this, x); + HTMLDivElement.prototype.removeChild.call(this, x); this.didMutate_(this.observer_.takeRecords()); }, replaceChild: function(x, y) { - HTMLUnknownElement.prototype.replaceChild.call(this, x, y); + HTMLDivElement.prototype.replaceChild.call(this, x, y); this.didMutate_(this.observer_.takeRecords()); }, onSetTextContent_: function(textContent) { - if (textContent != '') + if (textContent !== '') throw new Error('textContent can only be set to \'\'.'); this.clear(); }, clear: function() { - while (this.lastChild) - HTMLUnknownElement.prototype.removeChild.call(this, this.lastChild); + while (Polymer.dom(this).lastChild) + HTMLDivElement.prototype.removeChild.call( + this, Polymer.dom(this).lastChild); this.didMutate_(this.observer_.takeRecords()); }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html index 0f7ff710061..23e53eab9d0 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/container_that_decorates_its_children_test.html @@ -38,9 +38,9 @@ tr.b.unittest.testSuite(function() { test('add', function() { var container = new SimpleContainer(); - container.appendChild(createChild()); - container.appendChild(createChild()); - container.appendChild(createChild()); + Polymer.dom(container).appendChild(createChild()); + Polymer.dom(container).appendChild(createChild()); + Polymer.dom(container).appendChild(createChild()); assert.isTrue(container.children[0].decorated); assert.isTrue(container.children[1].decorated); assert.isTrue(container.children[2].decorated); @@ -49,15 +49,15 @@ tr.b.unittest.testSuite(function() { test('clearUsingTextContent', function() { var c0 = createChild(); var container = new SimpleContainer(); - container.appendChild(c0); - container.textContent = ''; + Polymer.dom(container).appendChild(c0); + Polymer.dom(container).textContent = ''; assert.isFalse(c0.decorated); }); test('clear', function() { var c0 = createChild(); var container = new SimpleContainer(); - container.appendChild(c0); + Polymer.dom(container).appendChild(c0); container.clear(); assert.isFalse(c0.decorated); }); @@ -66,8 +66,8 @@ tr.b.unittest.testSuite(function() { var c0 = createChild(); var c1 = createChild(); var container = new SimpleContainer(); - container.appendChild(c1); - container.insertBefore(c0, c1); + Polymer.dom(container).appendChild(c1); + Polymer.dom(container).insertBefore(c0, c1); assert.isTrue(c0.decorated); assert.isTrue(c1.decorated); }); @@ -76,9 +76,9 @@ tr.b.unittest.testSuite(function() { var c0 = createChild(); var c1 = createChild(); var container = new SimpleContainer(); - container.appendChild(c1); - container.appendChild(c0); - container.insertBefore(c0, c1); + Polymer.dom(container).appendChild(c1); + Polymer.dom(container).appendChild(c0); + Polymer.dom(container).insertBefore(c0, c1); assert.isTrue(c0.decorated); assert.isTrue(c1.decorated); }); @@ -87,8 +87,8 @@ tr.b.unittest.testSuite(function() { var c0 = createChild(); var c1 = createChild(); var container = new SimpleContainer(); - container.appendChild(c0); - container.replaceChild(c1, c0); + Polymer.dom(container).appendChild(c0); + Polymer.dom(container).replaceChild(c1, c0); assert.isFalse(c0.decorated); assert.isTrue(c1.decorated); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html b/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html index ed4c962a25e..bce0554c512 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3.html @@ -4,4 +4,6 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<script src="/tracing/ui/base/d3_preload.js"></script> <script src="/d3.min.js"></script> +<script src="/tracing/ui/base/d3_postload.js"></script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js new file mode 100644 index 00000000000..94cefdb15f9 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_postload.js @@ -0,0 +1,8 @@ +/* Copyright (c) 2014 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ +'use strict'; + +(function(window) { + window.define = undefined; +}).call(this, this); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js new file mode 100644 index 00000000000..57548f1d175 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/d3_preload.js @@ -0,0 +1,11 @@ +/* Copyright (c) 2014 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. */ +'use strict'; + +(function(window) { + window.define = function(x) { + window.d3 = x; + }; + window.define.amd = true; +})(this); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html index 6476dee1af1..f715938d86c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils.html @@ -5,26 +5,32 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <link rel="import" href="/tracing/base/base.html"> + <script> 'use strict'; tr.exportTo('tr.b', function() { function _iterateElementDeeplyImpl(element, cb, thisArg, includeElement) { - if (includeElement) { - if (cb.call(thisArg, element)) - return true; - } + if (includeElement && cb.call(thisArg, element)) + return true; - if (element.shadowRoot) { - if (_iterateElementDeeplyImpl(element.shadowRoot, cb, thisArg, false)) - return true; + if (element.root && + element.root !== element && + _iterateElementDeeplyImpl(element.root, cb, thisArg, false)) { + // Some elements, most notably Polymer template dom-repeat='...' + // elements, are their own shadow root. Make sure that we avoid infinite + // recursion by avoiding these elements. + return true; } - for (var i = 0; i < element.children.length; i++) { - if (_iterateElementDeeplyImpl(element.children[i], cb, thisArg, true)) + var children = Polymer.dom(element).children; + for (var i = 0; i < children.length; i++) + if (_iterateElementDeeplyImpl(children[i], cb, thisArg, true)) return true; - } + + return false; } + function iterateElementDeeply(element, cb, thisArg) { _iterateElementDeeplyImpl(element, cb, thisArg, false); } @@ -69,7 +75,7 @@ tr.exportTo('tr.b', function() { return findDeepElementMatchingPredicate(element, function(element) { if (element.children.length !== 0) return false; - return re.test(element.textContent); + return re.test(Polymer.dom(element).textContent); }); } return { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html index fa0d843e106..38156654ef0 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/deep_utils_test.html @@ -7,45 +7,63 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/deep_utils.html"> +<dom-module id='tr-ui-b-deep-utils-test-a'> + <template> + <div></div> + </template> +</dom-module> +<dom-module id='tr-ui-b-deep-utils-test-b'> + <template> + <div></div> + </template> +</dom-module> +<dom-module id='tr-ui-b-deep-utils-test-c'> + <template> + <tr-ui-b-deep-utils-test-b class='x'></tr-ui-b-deep-utils-test-b> + <tr-ui-b-deep-utils-test-a class='x'></tr-ui-b-deep-utils-test-a> + <tr-ui-b-deep-utils-test-a class='x'></tr-ui-b-deep-utils-test-a> + </template> +</dom-module> +<dom-module id='tr-ui-b-deep-utils-test-d'> + <template> + <tr-ui-b-deep-utils-test-c></tr-ui-b-deep-utils-test-c> + </template> +</dom-module> <script> 'use strict'; -tr.b.unittest.testSuite(function() { - function createElement(tagName, opt_class) { - var el = document.createElement(tagName); - if (opt_class) - el.className = opt_class; - return el; - } +Polymer({ + is: 'tr-ui-b-deep-utils-test-a' +}); - test('testFindDeepElementMatching', function() { - var a = createElement('a'); - var a_ = a.createShadowRoot(); +Polymer({ + is: 'tr-ui-b-deep-utils-test-b' +}); - var b = createElement('b'); - a_.appendChild(b); +Polymer({ + is: 'tr-ui-b-deep-utils-test-c' +}); - var b_ = b.createShadowRoot(); - b_.appendChild(createElement('c', 'x')); +Polymer({ + is: 'tr-ui-b-deep-utils-test-d' +}); - var m = tr.b.findDeepElementMatching(a, 'c.x'); - assert.equal(m, b_.children[0]); +tr.b.unittest.testSuite(function() { + test('testFindDeepElementMatching', function() { + var d = document.createElement('tr-ui-b-deep-utils-test-d'); + + var b = tr.b.findDeepElementMatching(d, 'tr-ui-b-deep-utils-test-b.x'); + assert.isDefined(b); + assert.equal(b.tagName, 'TR-UI-B-DEEP-UTILS-TEST-B'); }); test('testFindDeepElementsMatching', function() { - var a = createElement('a'); - var a_ = a.createShadowRoot(); - - var b = createElement('b'); - a_.appendChild(b); - - var b_ = b.createShadowRoot(); - b_.appendChild(createElement('c', 'x')); - b_.appendChild(createElement('c', 'x')); + var d = document.createElement('tr-ui-b-deep-utils-test-d'); - var m = tr.b.findDeepElementsMatching(a, 'c.x'); - assert.equal(m[0], b_.children[0]); - assert.equal(m[1], b_.children[1]); + var a = tr.b.findDeepElementsMatching(d, 'tr-ui-b-deep-utils-test-a.x'); + assert.isDefined(a); + assert.equal(a[0].tagName, 'TR-UI-B-DEEP-UTILS-TEST-A'); + assert.equal(a[1].tagName, 'TR-UI-B-DEEP-UTILS-TEST-A'); }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html index 02af70a52fc..b2ced31ed2a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers.html @@ -28,12 +28,14 @@ tr.exportTo('tr.ui.b', function() { if (opt_dictionary) { if (opt_dictionary.className) spanEl.className = opt_dictionary.className; - if (opt_dictionary.textContent) - spanEl.textContent = opt_dictionary.textContent; + if (opt_dictionary.textContent) { + Polymer.dom(spanEl).textContent = + opt_dictionary.textContent; + } if (opt_dictionary.tooltip) spanEl.title = opt_dictionary.tooltip; if (opt_dictionary.parent) - opt_dictionary.parent.appendChild(spanEl); + Polymer.dom(opt_dictionary.parent).appendChild(spanEl); if (opt_dictionary.bold) spanEl.style.fontWeight = 'bold'; if (opt_dictionary.italic) @@ -48,7 +50,7 @@ tr.exportTo('tr.ui.b', function() { spanEl.style.color = opt_dictionary.color; } return spanEl; - }; + } function createDiv(opt_dictionary) { var divEl = document.createElement('div'); @@ -56,19 +58,20 @@ tr.exportTo('tr.ui.b', function() { if (opt_dictionary.className) divEl.className = opt_dictionary.className; if (opt_dictionary.parent) - opt_dictionary.parent.appendChild(divEl); + Polymer.dom(opt_dictionary.parent).appendChild(divEl); if (opt_dictionary.textContent) - divEl.textContent = opt_dictionary.textContent; + Polymer.dom(divEl).textContent = + opt_dictionary.textContent; if (opt_dictionary.maxWidth) divEl.style.maxWidth = opt_dictionary.maxWidth; } return divEl; - }; + } function createScopedStyle(styleContent) { var styleEl = document.createElement('style'); styleEl.scoped = true; - styleEl.innerHTML = styleContent; + Polymer.dom(styleEl).innerHTML = styleContent; return styleEl; } @@ -98,10 +101,10 @@ tr.exportTo('tr.ui.b', function() { for (var i = 0; i < items.length; i++) { var item = items[i]; var optionEl = document.createElement('option'); - optionEl.textContent = item.label; + Polymer.dom(optionEl).textContent = item.label; optionEl.targetPropertyValue = item.value; optionEl.item = item; - selectorEl.appendChild(optionEl); + Polymer.dom(selectorEl).appendChild(optionEl); } function onChange(e) { var value = selectorEl.selectedOptions[0].targetPropertyValue; @@ -119,7 +122,7 @@ tr.exportTo('tr.ui.b', function() { for (var i = 0; i < selectorEl.children.length; i++) { var value = selectorEl.children[i].targetPropertyValue; if (valuesEqual(value, v)) { - var changed = selectorEl.selectedIndex != i; + var changed = selectorEl.selectedIndex !== i; if (changed) { selectorEl.selectedIndex = i; onChange(); @@ -152,8 +155,8 @@ tr.exportTo('tr.ui.b', function() { function createEditCategorySpan(optionGroupEl, targetEl) { var spanEl = createSpan({className: 'edit-categories'}); - spanEl.textContent = 'Edit categories'; - spanEl.classList.add('labeled-option'); + Polymer.dom(spanEl).textContent = 'Edit categories'; + Polymer.dom(spanEl).classList.add('labeled-option'); spanEl.addEventListener('click', function() { targetEl.onClickEditCategories(); @@ -180,9 +183,9 @@ tr.exportTo('tr.ui.b', function() { var radioEl = document.createElement('input'); radioEl.type = 'radio'; - radioEl.setAttribute('id', id); - radioEl.setAttribute('name', 'category-presets-group'); - radioEl.setAttribute('value', item.value); + Polymer.dom(radioEl).setAttribute('id', id); + Polymer.dom(radioEl).setAttribute('name', 'category-presets-group'); + Polymer.dom(radioEl).setAttribute('value', item.value); radioEl.addEventListener('change', onChange.bind(radioEl, targetEl, targetElProperty, settingsKey)); @@ -190,12 +193,12 @@ tr.exportTo('tr.ui.b', function() { radioEl.checked = true; var labelEl = document.createElement('label'); - labelEl.textContent = item.label; - labelEl.setAttribute('for', id); + Polymer.dom(labelEl).textContent = item.label; + Polymer.dom(labelEl).setAttribute('for', id); var spanEl = createSpan({className: 'labeled-option'}); - spanEl.appendChild(radioEl); - spanEl.appendChild(labelEl); + Polymer.dom(spanEl).appendChild(radioEl); + Polymer.dom(spanEl).appendChild(labelEl); spanEl.__defineSetter__('checked', function(opt_bool) { var changed = radioEl.checked !== (!!opt_bool); @@ -209,15 +212,16 @@ tr.exportTo('tr.ui.b', function() { return radioEl.checked; }); - optionGroupEl.appendChild(spanEl); + Polymer.dom(optionGroupEl).appendChild(spanEl); } - optionGroupEl.appendChild(createEditCategorySpan(optionGroupEl, targetEl)); + Polymer.dom(optionGroupEl).appendChild( + createEditCategorySpan(optionGroupEl, targetEl)); // Since this option group element is not yet added to the tree, // querySelector will fail during updateEditCategoriesStatus_ call. // Hence, creating the element with the 'expanded' classlist category // added, if last selected value was 'Manual' selection. if (!initialValue.length) - optionGroupEl.classList.add('categories-expanded'); + Polymer.dom(optionGroupEl).classList.add('categories-expanded'); targetEl[targetElProperty] = initialValue; return optionGroupEl; @@ -230,13 +234,18 @@ tr.exportTo('tr.ui.b', function() { var buttonEl = document.createElement('input'); buttonEl.type = 'checkbox'; - var initialValue = tr.b.Settings.get(settingsKey, defaultValue); - buttonEl.checked = !!initialValue; + var initialValue = defaultValue; + if (settingsKey !== undefined) { + initialValue = tr.b.Settings.get(settingsKey, defaultValue); + buttonEl.checked = !!initialValue; + } if (targetEl) targetEl[targetElProperty] = initialValue; function onChange() { - tr.b.Settings.set(settingsKey, buttonEl.checked); + if (settingsKey !== undefined) { + tr.b.Settings.set(settingsKey, buttonEl.checked); + } if (targetEl) targetEl[targetElProperty] = buttonEl.checked; if (opt_changeCb) @@ -248,13 +257,13 @@ tr.exportTo('tr.ui.b', function() { var id = '#checkbox-' + nextCheckboxId++; var spanEl = createSpan({className: 'labeled-checkbox'}); - buttonEl.setAttribute('id', id); + Polymer.dom(buttonEl).setAttribute('id', id); var labelEl = document.createElement('label'); - labelEl.textContent = label; - labelEl.setAttribute('for', id); - spanEl.appendChild(buttonEl); - spanEl.appendChild(labelEl); + Polymer.dom(labelEl).textContent = label; + Polymer.dom(labelEl).setAttribute('for', id); + Polymer.dom(spanEl).appendChild(buttonEl); + Polymer.dom(spanEl).appendChild(labelEl); spanEl.__defineSetter__('checked', function(opt_bool) { var changed = buttonEl.checked !== (!!opt_bool); @@ -309,8 +318,8 @@ tr.exportTo('tr.ui.b', function() { function isElementAttachedToDocument(el) { var cur = el; - while (cur.parentNode) - cur = cur.parentNode; + while (Polymer.dom(cur).parentNode) + cur = Polymer.dom(cur).parentNode; return (cur === el.ownerDocument || cur.nodeName === '#document-fragment'); } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html index 64ba68ba36f..61ca370c5be 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dom_helpers_test.html @@ -9,7 +9,7 @@ found in the LICENSE file. 'use strict'; tr.b.unittest.testSuite(function() { - var THIS_DOC = document._currentScript.ownerDocument; + var THIS_DOC = document.currentScript.ownerDocument; test('simpleSpanAndDiv', function() { var divEl = tr.ui.b.createDiv({ @@ -21,9 +21,10 @@ tr.b.unittest.testSuite(function() { textContent: testText, parent: divEl }); - var eltInDocument = document.querySelector('.a-div-class>.a-span-class'); - assert.equal(eltInDocument.textContent, testText); - eltInDocument.parentElement.removeChild(eltInDocument); + var eltInDocument = Polymer.dom(document) + .querySelector('.a-div-class>.a-span-class'); + assert.equal(Polymer.dom(eltInDocument).textContent, testText); + Polymer.dom(eltInDocument.parentElement).removeChild(eltInDocument); }); test('createSpan_ownerDocument', function() { @@ -126,13 +127,13 @@ tr.b.unittest.testSuite(function() { // Default owner document. var node = tr.ui.b.asHTMLOrTextNode('Hello, World!'); assert.instanceOf(node, Node); - assert.equal(node.textContent, 'Hello, World!'); + assert.equal(Polymer.dom(node).textContent, 'Hello, World!'); assert.strictEqual(node.ownerDocument, document); // Custom owner document. var node = tr.ui.b.asHTMLOrTextNode('Bye, World!', THIS_DOC); assert.instanceOf(node, Node); - assert.equal(node.textContent, 'Bye, World!'); + assert.equal(Polymer.dom(node).textContent, 'Bye, World!'); assert.strictEqual(node.ownerDocument, THIS_DOC); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html index d919bbbad93..405f9538f35 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle.html @@ -7,7 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name="tr-ui-b-drag-handle"> +<dom-module id="tr-ui-b-drag-handle"> <template> <style> :host { @@ -42,143 +42,145 @@ found in the LICENSE file. width: 7px; } </style> + <div></div> </template> - <script> - 'use strict'; - - Polymer({ - __proto__: HTMLDivElement.prototype, - - created: function() { - this.lastMousePos_ = 0; - this.onMouseMove_ = this.onMouseMove_.bind(this); - this.onMouseUp_ = this.onMouseUp_.bind(this); - this.addEventListener('mousedown', this.onMouseDown_); - this.target_ = undefined; - this.horizontal = true; - this.observer_ = new WebKitMutationObserver( - this.didTargetMutate_.bind(this)); - this.targetSizesByModeKey_ = {}; - }, - - get modeKey_() { - return this.target_.className == '' ? '.' : this.target_.className; - }, - - get target() { - return this.target_; - }, - - set target(target) { - this.observer_.disconnect(); - this.target_ = target; - if (!this.target_) - return; - this.observer_.observe(this.target_, { - attributes: true, - attributeFilter: ['class'] - }); - }, - - get horizontal() { - return this.horizontal_; - }, - - set horizontal(h) { - this.horizontal_ = h; - if (this.horizontal_) - this.className = 'horizontal-drag-handle'; - else - this.className = 'vertical-drag-handle'; - }, - - get vertical() { - return !this.horizontal_; - }, - - set vertical(v) { - this.horizontal = !v; - }, - - forceMutationObserverFlush_: function() { - var records = this.observer_.takeRecords(); - if (records.length) - this.didTargetMutate_(records); - }, - - didTargetMutate_: function(e) { - var modeSize = this.targetSizesByModeKey_[this.modeKey_]; - if (modeSize !== undefined) { - this.setTargetSize_(modeSize); - return; - } - - // If we hadn't previously sized the target, then just remove any manual - // sizing that we applied. - this.target_.style[this.targetStyleKey_] = ''; - }, - - get targetStyleKey_() { - return this.horizontal_ ? 'height' : 'width'; - }, - - getTargetSize_: function() { - // If style is not set, start off with computed height. - var targetStyleKey = this.targetStyleKey_; - if (!this.target_.style[targetStyleKey]) { - this.target_.style[targetStyleKey] = - window.getComputedStyle(this.target_)[targetStyleKey]; - } - var size = parseInt(this.target_.style[targetStyleKey]); - this.targetSizesByModeKey_[this.modeKey_] = size; - return size; - }, - - setTargetSize_: function(s) { - this.target_.style[this.targetStyleKey_] = s + 'px'; - this.targetSizesByModeKey_[this.modeKey_] = s; - }, - - applyDelta_: function(delta) { - // Apply new size to the container. - var curSize = this.getTargetSize_(); - var newSize; - if (this.target_ === this.nextElementSibling) { - newSize = curSize + delta; - } else { - newSize = curSize - delta; - } - this.setTargetSize_(newSize); - }, - - onMouseMove_: function(e) { - // Compute the difference in height position. - var curMousePos = this.horizontal_ ? e.clientY : e.clientX; - var delta = this.lastMousePos_ - curMousePos; - - this.applyDelta_(delta); - - this.lastMousePos_ = curMousePos; - e.preventDefault(); - return true; - }, - - onMouseDown_: function(e) { - if (!this.target_) - return; - this.forceMutationObserverFlush_(); - this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX; - document.addEventListener('mousemove', this.onMouseMove_); - document.addEventListener('mouseup', this.onMouseUp_); - e.preventDefault(); - return true; - }, - - onMouseUp_: function(e) { - document.removeEventListener('mousemove', this.onMouseMove_); - document.removeEventListener('mouseup', this.onMouseUp_); - e.preventDefault(); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-b-drag-handle', + + created: function() { + this.lastMousePos_ = 0; + this.onMouseMove_ = this.onMouseMove_.bind(this); + this.onMouseUp_ = this.onMouseUp_.bind(this); + this.addEventListener('mousedown', this.onMouseDown_); + this.target_ = undefined; + this.horizontal = true; + this.observer_ = new WebKitMutationObserver( + this.didTargetMutate_.bind(this)); + this.targetSizesByModeKey_ = {}; + }, + + get modeKey_() { + return this.target_.className === '' ? '.' : this.target_.className; + }, + + get target() { + return this.target_; + }, + + set target(target) { + this.observer_.disconnect(); + this.target_ = target; + if (!this.target_) + return; + this.observer_.observe(this.target_, { + attributes: true, + attributeFilter: ['class'] + }); + }, + + get horizontal() { + return this.horizontal_; + }, + + set horizontal(h) { + this.horizontal_ = h; + if (this.horizontal_) + this.className = 'horizontal-drag-handle'; + else + this.className = 'vertical-drag-handle'; + }, + + get vertical() { + return !this.horizontal_; + }, + + set vertical(v) { + this.horizontal = !v; + }, + + forceMutationObserverFlush_: function() { + var records = this.observer_.takeRecords(); + if (records.length) + this.didTargetMutate_(records); + }, + + didTargetMutate_: function(e) { + var modeSize = this.targetSizesByModeKey_[this.modeKey_]; + if (modeSize !== undefined) { + this.setTargetSize_(modeSize); + return; } - }); - </script> -</polymer-element> + + // If we hadn't previously sized the target, then just remove any manual + // sizing that we applied. + this.target_.style[this.targetStyleKey_] = ''; + }, + + get targetStyleKey_() { + return this.horizontal_ ? 'height' : 'width'; + }, + + getTargetSize_: function() { + // If style is not set, start off with computed height. + var targetStyleKey = this.targetStyleKey_; + if (!this.target_.style[targetStyleKey]) { + this.target_.style[targetStyleKey] = + window.getComputedStyle(this.target_)[targetStyleKey]; + } + var size = parseInt(this.target_.style[targetStyleKey]); + this.targetSizesByModeKey_[this.modeKey_] = size; + return size; + }, + + setTargetSize_: function(s) { + this.target_.style[this.targetStyleKey_] = s + 'px'; + this.targetSizesByModeKey_[this.modeKey_] = s; + tr.b.dispatchSimpleEvent(this, 'drag-handle-resize', true, false); + }, + + applyDelta_: function(delta) { + // Apply new size to the container. + var curSize = this.getTargetSize_(); + var newSize; + if (this.target_ === this.nextElementSibling) { + newSize = curSize + delta; + } else { + newSize = curSize - delta; + } + this.setTargetSize_(newSize); + }, + + onMouseMove_: function(e) { + // Compute the difference in height position. + var curMousePos = this.horizontal_ ? e.clientY : e.clientX; + var delta = this.lastMousePos_ - curMousePos; + + this.applyDelta_(delta); + + this.lastMousePos_ = curMousePos; + e.preventDefault(); + return true; + }, + + onMouseDown_: function(e) { + if (!this.target_) + return; + this.forceMutationObserverFlush_(); + this.lastMousePos_ = this.horizontal_ ? e.clientY : e.clientX; + document.addEventListener('mousemove', this.onMouseMove_); + document.addEventListener('mouseup', this.onMouseUp_); + e.preventDefault(); + return true; + }, + + onMouseUp_: function(e) { + document.removeEventListener('mousemove', this.onMouseMove_); + document.removeEventListener('mouseup', this.onMouseUp_); + e.preventDefault(); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html index bd52880503d..0d5ab850564 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/drag_handle_test.html @@ -27,9 +27,9 @@ tr.b.unittest.testSuite(function() { var dragHandle = document.createElement('tr-ui-b-drag-handle'); dragHandle.target = lowerEl; - el.appendChild(upperEl); - el.appendChild(dragHandle); - el.appendChild(lowerEl); + Polymer.dom(el).appendChild(upperEl); + Polymer.dom(el).appendChild(dragHandle); + Polymer.dom(el).appendChild(lowerEl); el.upperEl = upperEl; el.dragHandle = dragHandle; el.lowerEl = lowerEl; @@ -58,9 +58,9 @@ tr.b.unittest.testSuite(function() { var el = createDragHandle(); var styleEl = document.createElement('style'); - styleEl.textContent = + Polymer.dom(styleEl).textContent = '.mode-a { height: 100px; } .mode-b { height: 50px; }'; - document.head.appendChild(styleEl); + Polymer.dom(document.head).appendChild(styleEl); this.addHTMLOutput(el); @@ -87,7 +87,7 @@ tr.b.unittest.testSuite(function() { dragHandle.forceMutationObserverFlush_(); assert.equal(el.getLowerElHeight(), 110); } finally { - document.head.removeChild(styleEl); + Polymer.dom(document.head).removeChild(styleEl); } }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html b/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html index 981f16da3e6..89b9d5dab96 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/draw_helpers.html @@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/event_presenter.html"> <link rel="import" href="/tracing/base/sorted_array_utils.html"> <link rel="import" href="/tracing/ui/base/elided_cache.html"> +<link rel="import" href="/tracing/ui/base/event_presenter.html"> <script> 'use strict'; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html index 2d0fe220eef..5c2f4dfe170 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown.html @@ -7,7 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> -<polymer-element name="tr-ui-b-dropdown"> +<dom-module id='tr-ui-b-dropdown'> <template> <style> :host { @@ -57,102 +57,104 @@ found in the LICENSE file. } </style> <tr-ui-b-toolbar-button id="outer" - on-keydown="{{ onOuterKeyDown_ }}" - on-click="{{ onOuterClick_ }}"> + on-keydown="onOuterKeyDown_" + on-click="onOuterClick_"> <div id="icon">⚙</div> <div id="state">▾</div> </tr-ui-b-toolbar-button> <dialog id="dialog" - on-click="{{ onDialogClick_ }}" - on-cancel="{{ onDialogCancel_ }}"> + on-click="onDialogClick_" + on-cancel="onDialogCancel_"> <div id="dialog-frame"> <content></content> </div> </dialog> </template> - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.$.outer.tabIndex = 0; - }, - - get iconElement() { - return this.$.icon; - }, - - onOuterKeyDown_: function(e) { - if (e.keyCode === ' '.charCodeAt(0)) { - this.toggle_(); - e.preventDefault(); - e.stopPropagation(); - } - }, - - onOuterClick_: function(e) { - var or = this.$.outer.getBoundingClientRect(); - var inside = true; - inside &= e.clientX >= or.left; - inside &= e.clientX < or.right; - inside &= e.clientY >= or.top; - inside &= e.clientY < or.bottom; - if (!inside) - return; +</dom-module> +<script> +'use strict'; - e.preventDefault(); - this.toggle_(); - }, - - toggle_: function() { - if (!this.isOpen) - this.show(); - else - this.close(); - }, - - show: function() { - if (this.isOpen) - return; - - this.$.outer.classList.add('open'); - - var ddr = this.$.outer.getBoundingClientRect(); - var rW = Math.max(ddr.width, 150); - this.$.dialog.style.minWidth = rW + 'px'; - this.$.dialog.showModal(); - - var ddw = this.$.outer.getBoundingClientRect().width; - var w = this.$.dialog.getBoundingClientRect().width; - this.$.dialog.style.top = ddr.bottom - 1 + 'px'; - this.$.dialog.style.left = ddr.left + 'px'; - }, - - onDialogClick_: function(e) { - if (!this.isOpen) - return; - if (e.srcElement !== this.$.dialog) - return; - e.preventDefault(); - this.close(); - }, +Polymer({ + is: 'tr-ui-b-dropdown', + + ready: function() { + this.$.outer.tabIndex = 0; + }, - onDialogCancel_: function(e) { + get iconElement() { + return this.$.icon; + }, + + onOuterKeyDown_: function(e) { + if (e.keyCode === ' '.charCodeAt(0)) { + this.toggle_(); e.preventDefault(); - this.close(); - }, - - close: function() { - if (!this.isOpen) - return; - this.$.dialog.close(); - this.$.outer.classList.remove('open'); - this.$.outer.focus(); - }, - - get isOpen() { - return this.$.dialog.hasAttribute('open'); + e.stopPropagation(); } - }); - </script> -</polymer-element> + }, + + onOuterClick_: function(e) { + var or = this.$.outer.getBoundingClientRect(); + var inside = true; + inside &= e.clientX >= or.left; + inside &= e.clientX < or.right; + inside &= e.clientY >= or.top; + inside &= e.clientY < or.bottom; + if (!inside) + return; + + e.preventDefault(); + this.toggle_(); + }, + + toggle_: function() { + if (!this.isOpen) + this.show(); + else + this.close(); + }, + + show: function() { + if (this.isOpen) + return; + + Polymer.dom(this.$.outer).classList.add('open'); + + var ddr = this.$.outer.getBoundingClientRect(); + var rW = Math.max(ddr.width, 150); + this.$.dialog.style.minWidth = rW + 'px'; + this.$.dialog.showModal(); + + var ddw = this.$.outer.getBoundingClientRect().width; + var w = this.$.dialog.getBoundingClientRect().width; + this.$.dialog.style.top = ddr.bottom - 1 + 'px'; + this.$.dialog.style.left = ddr.left + 'px'; + }, + + onDialogClick_: function(e) { + if (!this.isOpen) + return; + if (e.srcElement !== this.$.dialog) + return; + e.preventDefault(); + this.close(); + }, + + onDialogCancel_: function(e) { + e.preventDefault(); + this.close(); + }, + + close: function() { + if (!this.isOpen) + return; + this.$.dialog.close(); + Polymer.dom(this.$.outer).classList.remove('open'); + this.$.outer.focus(); + }, + + get isOpen() { + return this.$.dialog.hasAttribute('open'); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html index 8801a927a1f..3d6ebb41cf3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/dropdown_test.html @@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/dropdown.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/dropdown.html"> <script> 'use strict'; @@ -16,18 +16,24 @@ tr.b.unittest.testSuite(function() { var dd = document.createElement('tr-ui-b-dropdown'); dd.style.marginLeft = '50px'; dd.style.width = '50px'; - dd.iconElement.textContent = 'Settings ' + String.fromCharCode(0x2699); + Polymer.dom(dd.iconElement).textContent = + 'Settings ' + String.fromCharCode(0x2699); - dd.appendChild(tr.ui.b.createDiv({textContent: 'item 1'})); - dd.appendChild(tr.ui.b.createDiv({textContent: 'item 2 longer'})); - dd.appendChild(tr.ui.b.createDiv({textContent: 'item 3'})); + Polymer.dom(dd).appendChild(tr.ui.b.createDiv({textContent: 'item 1'})); + Polymer.dom(dd).appendChild( + tr.ui.b.createDiv({textContent: 'item 2 longer'})); + Polymer.dom(dd).appendChild( + tr.ui.b.createDiv({textContent: 'item 3'})); var container = tr.ui.b.createDiv(); container.style.height = '100px'; - container.appendChild(dd); - container.appendChild(tr.ui.b.createDiv({textContent: 'some text'})); - container.appendChild(tr.ui.b.createDiv({textContent: 'some more text'})); - container.appendChild(tr.ui.b.createDiv({textContent: 'more text'})); + Polymer.dom(container).appendChild(dd); + Polymer.dom(container).appendChild( + tr.ui.b.createDiv({textContent: 'some text'})); + Polymer.dom(container).appendChild( + tr.ui.b.createDiv({textContent: 'some more text'})); + Polymer.dom(container).appendChild( + tr.ui.b.createDiv({textContent: 'more text'})); this.addHTMLOutput(container); dd.show(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html b/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html index 7019f9807da..556123b44f4 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/elided_cache.html @@ -20,7 +20,7 @@ tr.exportTo('tr.ui.b', function() { * value: Another dict whose key is width * and value is an ElidedStringWidthPair. */ - var elidedTitleCacheDict = {}; + var elidedTitleCacheDict = new Map(); var elidedTitleCache = new ElidedTitleCache(); /** @@ -30,7 +30,7 @@ tr.exportTo('tr.ui.b', function() { function ElidedTitleCache() { // TODO(jrg): possibly obsoleted with the elided string cache. // Consider removing. - this.textWidthMap = {}; + this.textWidthMap = new Map(); } ElidedTitleCache.prototype = { @@ -45,19 +45,19 @@ tr.exportTo('tr.ui.b', function() { * @return {ElidedStringWidthPair} Elided string and width. */ get: function(ctx, pixWidth, title, width, sliceDuration) { - var elidedDict = elidedTitleCacheDict[title]; + var elidedDict = elidedTitleCacheDict.get(title); if (!elidedDict) { - elidedDict = {}; - elidedTitleCacheDict[title] = elidedDict; + elidedDict = new Map(); + elidedTitleCacheDict.set(title, elidedDict); } - var elidedDictForPixWidth = elidedDict[pixWidth]; + var elidedDictForPixWidth = elidedDict.get(pixWidth); if (!elidedDictForPixWidth) { - elidedDict[pixWidth] = {}; - elidedDictForPixWidth = elidedDict[pixWidth]; + elidedDict.set(pixWidth, new Map()); + elidedDictForPixWidth = elidedDict.get(pixWidth); } - var stringWidthPair = elidedDictForPixWidth[sliceDuration]; + var stringWidthPair = elidedDictForPixWidth.get(sliceDuration); if (stringWidthPair === undefined) { var newtitle = title; var elided = false; @@ -73,16 +73,16 @@ tr.exportTo('tr.ui.b', function() { stringWidthPair = new ElidedStringWidthPair( newtitle, this.labelWidth(ctx, newtitle)); - elidedDictForPixWidth[sliceDuration] = stringWidthPair; + elidedDictForPixWidth.set(sliceDuration, stringWidthPair); } return stringWidthPair; }, quickMeasureText_: function(ctx, text) { - var w = this.textWidthMap[text]; + var w = this.textWidthMap.get(text); if (!w) { w = ctx.measureText(text).width; - this.textWidthMap[text] = w; + this.textWidthMap.set(text, w); } return w; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html b/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html index 66e74de6f65..866591644aa 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/favicons.html @@ -11,13 +11,13 @@ found in the LICENSE file. 'use strict'; tr.exportTo('tr.ui.b', function() { var FaviconsByHue = { - blue: 'data:image/vndmicrosofticon;base64,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NP+9ZjT/vGY0/7xmNP+8ZjT/vGY0/7xmNP+8ZjT/u2U0/7FiLY0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/5+vr/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//KWI//ylSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//GVIf/xlSH/8ZUh//CUIf/vkyD/5Y0fxY1XExbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n7/f/32LL/85cj//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/wlCD/7pIg/+6SIP/pjx/lunIZM9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fv9//fYsv/zlyP/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/75Mg/+uRH//qkB//6pAf/+iPH/TIfBtQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//OXI//zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh/+6TIP/ojx//548f/+ePH//njx//5o4f+c1/HGHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n7/f/32LL/85cj//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/tkiD/5Y0f/+SNH//ljR//5Y0f/+WNH//kjB/6zn8cZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fv9//fYsv/zlyP/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/65Eg/+KMHv/iix7/4ose/+KLHv/iix7/4ose/+CLHvfLfRta3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+/3/99iy//OXI//zliH/85Yh//OWIf/zliH/85Yh//OWIf/zliH/85Yh/+qR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', // @suppress longLineCheck + blue: 'data:image/png;base64,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', // @suppress longLineCheck - green: 'data:image/vndmicrosofticon;base64,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a/9sjmr/bI1q/2yNav9sjWr/bI1q/2uNav9rjWr/a41q/16GZI0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/5+fr/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/wOfV/0vCi/9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0rCiv9Kwor/SsKK/0nAif9Jv4j/RreCxStxUBbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z6+/+/59X/TMSM/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9JwYn/SL6I/0i+iP9GuoXlOJVqM9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pr7/7/n1f9Mw4z/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/ScCJ/0e8hv9HvIb/R7yG/0a6hfQ9oXJQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/v+fV/0zDjP9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0i/iP9GuoX/RrqE/0a6hP9GuoT/RrmD+T6ldWHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z6+/+/59X/TMOM/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Ivof/RbiD/0W3gv9FuIP/RbiD/0W4g/9Ft4L6PqZ2ZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pr7/7/n1f9Mw4z/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SL2H/0W2gv9FtYH/RbWB/0W1gf9FtYH/RbWB/0S0gPc+o3Ra3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8+vv/v+fV/0zDjP9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0rDi/9Kw4v/SsOL/0e8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', // @suppress longLineCheck + green: 'data:image/png;base64,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', // @suppress longLineCheck - red: 'data:image/vndmicrosofticon;base64,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xv9HL8b/Ry/G/0cvxv9HL8b/Ry/G/0cvxv9HL8X/Ry7F/z8tuI0AAAACk5OTFu/v78X5+fn/+fn5//n5+f/6+vn/+fr5//n6+f/5+vn/+fr5//n6+f/9/fn/ub73/zhF8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zZD8v82Q/L/NkPy/zVC8f81QvD/Mz/mxR8njhbDw8Mz9PT05fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z8+f+5vff/OEX0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P81QvH/NEHv/zRB7/8zQOrlKTO6M9XV1VD39/f0+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pz5/7m99/84RfT/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NULw/zRA7P80QOv/NEDr/zNA6fQsN8lQ3d3dYfj4+Pn5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8/Pn/ub33/zhF9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zVB7/8zQOn/Mz/o/zM/6P8zQOj/Mz/n+S04zmHh4eFl+Pj4+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//z8+f+5vff/OEX0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P80Qe7/Mz/m/zM/5f8zP+b/Mz/m/zM/5v8yP+X6LjnPZeDg4Fr4+Pj3+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//Pz5/7m99/84RfT/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NEHs/zI+4/8yPuP/Mj7j/zI+4/8yPuP/Mj7j/zI+4fctOMxa3NzcQvf39+/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/8/Pn/ub33/zhF9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zZD9P82Q/T/NkP0/zRA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', // @suppress longLineCheck + red: 'data:image/png;base64,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', // @suppress longLineCheck - yellow: 'data:image/vndmicrosofticon;base64,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//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hv/3/Br36/wa9+v8GuvbsBZnLQNra2mD39/f4+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//fr5/6Xm+/8Jwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B778/wa79/8Guvf/Brr3/wa59fgFo9hg4uLidPj4+P35+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/9+vn/peb7/wnB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//we++/8GufX/Brj0/wa49P8GuPT/Brfz/QWm3XTk5OR6+Pj4/fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//36+f+l5vv/CcH//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hvfr/Brfy/wa28f8GtvH/Brbx/wa28f8GtfD9BafdeuXl5W/4+Pj8+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn//fr5/6Xm+/8Jwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B7z5/wa17/8GtO7/BrTu/wa07v8GtO7/BrTu/waz7fwFpdtv4eHhVvj4+Pb5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/9+vn/peb7/wnB//8Hwf//B8H//wfB//8Hwf//B8H//wfB//8Hwf//B8H//we7+P8Gsu3/BrHr/wax6/8Gsev/BrHr/wax6/8Gsev/BrDq9gWh1Vba2toz9vb25vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//36+f+k5fv/BsH//wPA//8DwP//A8D//wPA//8DwP//A8D//wXA//8Guvb/BrDq/wau6P8Gruj/Bq7o/wau6P8Gruj/Bq7o/wau6P8GreXmBZnLM7+/vxH09PTC+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+/r5/83v+v9x2vz/btn9/2/Z/f9v2f3/b9n9/2/Z/f9v2f3/RdL5/yXG7v8mxOz/JsTs/ybE6/8mxOv/JsTr/yXE6/8lw+v/JcPr/yK95cIQirAR////APDw8IH5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+vn5//r5+f/6+fn/+vn5//r5+f/6+fn/+vn5//r5+f+H8Pz/Oer+/zzq/v886v7/POr+/zzq/v886v7/POr+/zzq/v886v3/OuDzgWz//wD09PQA5+fnNPf39+n5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/4Xw/f846///O+v//zvr//876///O+v//zvr//876///O+v//zvp/ek32+00Ouf6AMrKygCzs7MF8/Pzmvn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/hfD9/zjr//876///O+v//zvr//876///O+v//zvr//876///OuX5miqptwUwv88AAAAAAPPz8wDp6eku9/f33fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f+F8P3/OOv//zvr//876///O+v//zvr//876///O+v//zvp/d033O8uOuX5AAAAAAAAAAAAvr6+AP///wDx8fFl+Pj49fn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5/4Xw/f846///O+v//zvr//876///O+v//zvr//876v71OeP2ZY7//wAus8IAAAAAAAAAAAAAAAAA4ODgANPT0wj09PSI+fn5+vn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/hfD9/zjr//876///O+v//zvr//876///O+v/+jrm+Ygyx9gINdPlAAAAAAAAAAAAAAAAAAAAAAAAAAAA6enpAOHh4Q309PSM+fn5+Pn5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5+f/5+fn/+fn5//n5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' // @suppress longLineCheck + yellow: 'data:image/png;base64,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' // @suppress longLineCheck }; return { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html index c599c5e3ef8..5c99f4604e9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/file.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/file.html @@ -21,8 +21,8 @@ tr.exportTo('tr.ui.b', function() { reject(err); }; - var is_binary = filename.endsWith('.gz') || filename.endsWith('.zip'); - if (is_binary) + var isBinary = filename.endsWith('.gz') || filename.endsWith('.zip'); + if (isBinary) reader.readAsArrayBuffer(fileBlob); else reader.readAsText(fileBlob); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html index 341574145c6..a0e52e85697 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table.html @@ -7,7 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/table.html"> -<polymer-element name="tr-ui-b-grouping-table"> +<dom-module id='tr-ui-b-grouping-table'> <template> <style> :host { @@ -15,11 +15,12 @@ found in the LICENSE file. } #table { flex: 1 1 auto; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -104,7 +105,9 @@ tr.exportTo('tr.ui.b', function() { } }; - Polymer('tr-ui-b-grouping-table', { + Polymer({ + is: 'tr-ui-b-grouping-table', + created: function() { this.dataToGroup_ = undefined; this.groupBy_ = undefined; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html index ef12f0450d6..ad24d1b6b7e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/grouping_table_groupby_picker.html @@ -4,89 +4,226 @@ Copyright (c) 2016 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> + <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/settings.html"> <link rel="import" href="/tracing/ui/base/dropdown.html"> -<polymer-element name="tr-ui-b-grouping-table-groupby-picker"> +<dom-module id='tr-ui-b-grouping-table-groupby-picker'> <template> <style> :host { display: flex; - flex-direction: row; align-items: center; } + + :host(:not([vertical])), :host(:not([vertical])) groups { + flex-direction: row; + } + + :host([vertical]), :host([vertical]) groups { + flex-direction: column; + } + groups { -webkit-user-select: none; display: flex; - flex-direction: row; - padding-left: 10px; } - group, possible-group { + possible-group { display: span; padding-right: 10px; padding-left: 10px; } + </style> + + <groups id="groups"></groups> + <tr-ui-b-dropdown id="add_group"></tr-ui-b-dropdown> + </template> +</dom-module> - group { - border-left: 1px solid rgba(0,0,0,0); +<dom-module id="tr-ui-b-grouping-table-groupby-picker-group"> + <template> + <style> + :host { + white-space: nowrap; + border: 3px solid white; + background-color: #dddddd; cursor: move; } - group.dragging { - opacity: 0.2; + :host(:not([vertical])) { + display: inline; } - group.drop-targeted { - border-left: 1px solid black; + :host([vertical]) { + display: block; } + :host(:not([vertical]).drop-before) { + border-left: 3px solid black; + } - #remove { - cursor: default; + :host([vertical].drop-before) { + border-top: 3px solid black; + } + + :host(:not([vertical]).drop-after) { + border-right: 3px solid black; } - #remove:not([hovered]) { + :host([vertical].drop-after) { + border-bottom: 3px solid black; + } + + :host([dragging]) { + opacity: 0.5; + } + + #remove { visibility: hidden; + padding-left: 3px; + width: 20px; + height: 20px; + cursor: auto; + } + + #key { + padding-right: 3px; } </style> - <groups> - </groups> - <tr-ui-b-dropdown id="add-group"></tr-ui-b-dropdown> - </template> -</polymer-element> -<template id="tr-ui-b-grouping-table-groupby-picker-group-template"> - <span id="key"></span> - <span id="remove">×</span> -</template> + <!-- TODO(eakuefner): Use an iron-icon here once + https://github.com/catapult-project/catapult/issues/2772 is fixed. --> + <span id="remove" on-click="remove_">×</span> + <span id="key"></span> + </template> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui.b', function() { - var THIS_DOC = document._currentScript.ownerDocument; + var THIS_DOC = document.currentScript.ownerDocument; + + Polymer({ + is: 'tr-ui-b-grouping-table-groupby-picker-group', - Polymer('tr-ui-b-grouping-table-groupby-picker', { created: function() { - this.needsInit_ = true; + this.picker_ = undefined; + this.group_ = undefined; + }, + + ready: function() { + this.setAttribute('draggable', true); + this.addEventListener('mouseover', this.onMouseOver_.bind(this)); + this.addEventListener('mouseleave', this.onMouseLeave_.bind(this)); + this.addEventListener('dragstart', this.onDragStart_.bind(this)); + this.addEventListener('dragover', this.onDragOver_.bind(this)); + }, + + set group(g) { + this.group_ = g; + this.$.key.textContent = g.label; + }, + + get key() { + return this.group_.key; + }, + + get picker() { + return this.picker_; + }, + + set picker(picker) { + this.picker_ = picker; + this.vertical = picker.vertical; + }, + + // TODO(benjhayden): Use data-binding? + get vertical() { + return this.getAttribute('vertical'); + }, + + set vertical(vertical) { + if (vertical) + this.setAttribute('vertical', true); + else + this.removeAttribute('vertical'); + }, + + onMouseOver_: function(event) { + this.$.remove.style.visibility = 'visible'; + }, + + onMouseLeave_: function(event) { + this.$.remove.style.visibility = 'hidden'; + }, + + onDragStart_: function(event) { + event.dataTransfer.effectAllowed = 'move'; + this.setAttribute('dragging', true); + }, + + onDragOver_: function(event) { + event.preventDefault(); // Allows us to drop. + event.dataTransfer.dropEffect = 'move'; + + this.picker.clearDragIndicators_(); + if (this.picker.shouldDropBefore_(this, event)) { + this.classList.add('drop-before'); + if (this.previousElementSibling) + this.previousElementSibling.classList.add('drop-after'); + } else { + this.classList.add('drop-after'); + if (this.nextElementSibling) + this.nextElementSibling.classList.add('drop-before'); + } + return false; + }, + + remove_: function(event) { + var newKeys = this.picker.currentGroupKeys.slice(); + newKeys.splice(newKeys.indexOf(this.key), 1); + this.picker.currentGroupKeys = newKeys; + } + }); + + Polymer({ + is: 'tr-ui-b-grouping-table-groupby-picker', + + created: function() { + this.currentGroupKeys_ = undefined; this.defaultGroupKeys_ = undefined; this.possibleGroups_ = []; this.settingsKey_ = []; + }, - this.currentGroupKeys_ = undefined; - - this.dragging_ = false; + ready: function() { + Polymer.dom(this.$.add_group.iconElement).textContent = 'Add another...'; + this.addEventListener('dragend', this.onDragEnd_.bind(this)); + this.addEventListener('drop', this.onDrop_.bind(this)); }, get defaultGroupKeys() { return this.defaultGroupKeys_; }, + set vertical(vertical) { + if (vertical) + this.setAttribute('vertical', true); + else + this.removeAttribute('vertical'); + + for (var groupEl of this.$.groups.childNodes) + groupEl.vertical = vertical; + }, + + get vertical() { + return this.getAttribute('vertical'); + }, + set defaultGroupKeys(defaultGroupKeys) { - if (!this.needsInit_) - throw new Error('Already initialized.'); this.defaultGroupKeys_ = defaultGroupKeys; this.maybeInit_(); }, @@ -96,8 +233,6 @@ tr.exportTo('tr.ui.b', function() { }, set possibleGroups(possibleGroups) { - if (!this.needsInit_) - throw new Error('Already initialized.'); this.possibleGroups_ = possibleGroups; this.maybeInit_(); }, @@ -107,27 +242,16 @@ tr.exportTo('tr.ui.b', function() { }, set settingsKey(settingsKey) { - if (!this.needsInit_) - throw new Error('Already initialized.'); this.settingsKey_ = settingsKey; this.maybeInit_(); }, maybeInit_: function() { - if (!this.needsInit_) - return; - - if (this.settingsKey_ === undefined) + if (!this.settingsKey_ || + !this.defaultGroupKeys_ || + !this.possibleGroups_) { return; - if (this.defaultGroupKeys_ === undefined) - return; - if (this.possibleGroups_ === undefined) - return; - - this.needsInit_ = false; - - var addGroupEl = this.shadowRoot.querySelector('#add-group'); - addGroupEl.iconElement.textContent = 'Add another...'; + } this.currentGroupKeys = tr.b.Settings.get( this.settingsKey_, this.defaultGroupKeys_); @@ -139,12 +263,9 @@ tr.exportTo('tr.ui.b', function() { get currentGroups() { var groupsByKey = {}; - this.possibleGroups_.forEach(function(group) { + for (var group of this.possibleGroups_) groupsByKey[group.key] = group; - }); - return this.currentGroupKeys_.map(function(groupKey) { - return groupsByKey[groupKey]; - }); + return this.currentGroupKeys.map(groupKey => groupsByKey[groupKey]); }, set currentGroupKeys(currentGroupKeys) { @@ -154,156 +275,136 @@ tr.exportTo('tr.ui.b', function() { if (!(currentGroupKeys instanceof Array)) throw new Error('Must be array'); - this.currentGroupKeys_ = currentGroupKeys; + var availableGroupKeys = new Set(); + for (var group of this.possibleGroups_) + availableGroupKeys.add(group.key); + this.currentGroupKeys_ = currentGroupKeys.filter( + k => availableGroupKeys.has(k)); this.updateGroups_(); tr.b.Settings.set( this.settingsKey_, this.currentGroupKeys_); - var e = new tr.b.Event('current-groups-changed'); - this.dispatchEvent(e); + this.dispatchEvent(new tr.b.Event('current-groups-changed')); }, - updateGroups_: function() { - var groupsEl = this.shadowRoot.querySelector('groups'); - var addGroupEl = this.shadowRoot.querySelector('#add-group'); + /** + * @return {undefined|Element} + */ + get draggingGroupElement() { + for (var group of this.$.groups.children) + if (group.getAttribute('dragging')) + return group; + return undefined; + }, - groupsEl.textContent = ''; - addGroupEl.textContent = ''; + shouldDropBefore_: function(groupEl, event) { + var dragBoxRect = this.draggingGroupElement.getBoundingClientRect(); + var dropBoxRect = groupEl.getBoundingClientRect(); + // compare horizontally if drag and drop overlap vertically + var dragVertRange = tr.b.Range.fromExplicitRange( + dragBoxRect.top, dragBoxRect.bottom); + var dropVertRange = tr.b.Range.fromExplicitRange( + dropBoxRect.top, dropBoxRect.bottom); + if (dragVertRange.intersectsRangeInclusive(dropVertRange)) + return event.clientX < ((dropBoxRect.left + dropBoxRect.right) / 2); + return event.clientY < ((dropBoxRect.top + dropBoxRect.bottom) / 2); + }, + + clearDragIndicators_: function() { + for (var groupEl of this.$.groups.children) { + groupEl.classList.remove('drop-before'); + groupEl.classList.remove('drop-after'); + } + }, + + onDragEnd_: function(event) { + this.clearDragIndicators_(); + for (var groupEl of this.$.groups.children) + groupEl.removeAttribute('dragging'); + }, + + onDrop_: function(event) { + event.stopPropagation(); // stops the browser from redirecting. + + var draggingGroupEl = this.draggingGroupElement; + var dropBeforeEl = undefined; + var dropAfterEl = undefined; + for (var groupEl of this.$.groups.children) { + if (groupEl.classList.contains('drop-before')) { + dropBeforeEl = groupEl; + break; + } + if (groupEl.classList.contains('drop-after')) { + dropAfterEl = groupEl; + break; + } + } + + if (!dropBeforeEl && !dropAfterEl) + return; + + this.$.groups.removeChild(draggingGroupEl); + var lastGroupEl = this.$.groups.children[ + this.$.groups.children.length - 1]; + + if (dropBeforeEl) + this.$.groups.insertBefore(draggingGroupEl, dropBeforeEl); + else if (dropAfterEl === lastGroupEl) + this.$.groups.appendChild(draggingGroupEl); + else + this.$.groups.insertBefore(draggingGroupEl, dropAfterEl.nextSibling); + + var currentGroupKeys = []; + for (var group of this.$.groups.children) + currentGroupKeys.push(group.key); + this.currentGroupKeys = currentGroupKeys; + return false; + }, + + updateGroups_: function() { + Polymer.dom(this.$.groups).textContent = ''; + Polymer.dom(this.$.add_group).textContent = ''; var unusedGroups = {}; var groupsByKey = {}; - this.possibleGroups_.forEach(function(group) { + for (var group of this.possibleGroups_) { unusedGroups[group.key] = group; groupsByKey[group.key] = group; - }); + } - this.currentGroupKeys_.forEach(function(key) { + for (var key of this.currentGroupKeys_) delete unusedGroups[key]; - }); // Create groups. - var groupTemplateEl = THIS_DOC.querySelector( - '#tr-ui-b-grouping-table-groupby-picker-group-template'); - this.currentGroupKeys_.forEach(function(key, index) { + for (var key of this.currentGroupKeys_) { var group = groupsByKey[key]; - var groupEl = document.createElement('group'); - groupEl.groupKey = key; - groupEl.appendChild(document.importNode(groupTemplateEl.content, true)); - groupEl.querySelector('#key').textContent = group.label; - groupsEl.appendChild(groupEl); - - this.configureRemoveButtonForGroup_(groupEl); - this.configureDragAndDropForGroup_(groupEl); - }, this); + var groupEl = document.createElement( + 'tr-ui-b-grouping-table-groupby-picker-group'); + groupEl.picker = this; + groupEl.group = group; + Polymer.dom(this.$.groups).appendChild(groupEl); + } // Adjust dropdown. tr.b.iterItems(unusedGroups, function(key, group) { var groupEl = document.createElement('possible-group'); - groupEl.textContent = group.label; + Polymer.dom(groupEl).textContent = group.label; groupEl.addEventListener('click', function() { var newKeys = this.currentGroupKeys.slice(); newKeys.push(key); this.currentGroupKeys = newKeys; - addGroupEl.close(); + this.$.add_group.close(); }.bind(this)); - addGroupEl.appendChild(groupEl); + Polymer.dom(this.$.add_group).appendChild(groupEl); }, this); // Hide dropdown if needed. - if (tr.b.dictionaryLength(unusedGroups) == 0) { - addGroupEl.style.display = 'none'; + if (tr.b.dictionaryLength(unusedGroups) === 0) { + this.$.add_group.style.display = 'none'; } else { - addGroupEl.style.display = ''; + this.$.add_group.style.display = ''; } - }, - - configureRemoveButtonForGroup_: function(groupEl) { - var removeEl = groupEl.querySelector('#remove'); - removeEl.addEventListener('click', function() { - var newKeys = this.currentGroupKeys.slice(); - var i = newKeys.indexOf(groupEl.groupKey); - newKeys.splice(i, 1); - this.currentGroupKeys = newKeys; - }.bind(this)); - - groupEl.addEventListener('mouseenter', function() { - removeEl.setAttribute('hovered', true); - }); - groupEl.addEventListener('mouseleave', function() { - removeEl.removeAttribute('hovered'); - }); - }, - - configureDragAndDropForGroup_: function(groupEl) { - var groupsEl = groupEl.parentElement; - - groupEl.setAttribute('draggable', true); - - groupEl.addEventListener('dragstart', function(e) { - e.dataTransfer.setData('groupKey', groupEl.groupKey); - groupEl.querySelector('#remove').removeAttribute('hovered'); - groupEl.classList.add('dragging'); - this.dragging_ = true; - }.bind(this)); - - groupEl.addEventListener('dragend', function(e) { - console.log(e.type, groupEl.groupKey); - for (var i = 0; i < groupsEl.children.length; i++) - groupsEl.children[i].classList.remove('drop-targeted'); - groupEl.classList.remove('dragging'); - this.dragging_ = false; - }.bind(this)); - - // Drop targeting. - groupEl.addEventListener('dragenter', function(e) { - if (!this.dragging_) - return; - groupEl.classList.add('drop-targeted'); - if (this.dragging_) - e.preventDefault(); - }.bind(this)); - - groupEl.addEventListener('dragleave', function(e) { - if (!this.dragging_) - return; - groupEl.classList.remove('drop-targeted'); - e.preventDefault(); - }.bind(this)); - - - // Drop logic. - groupEl.addEventListener('dragover', function(e) { - if (!this.dragging_) - return; - e.preventDefault(); - groupEl.classList.add('drop-targeted'); - }.bind(this)); - - groupEl.addEventListener('drop', function(e) { - if (!this.dragging_) - return; - - var srcKey = e.dataTransfer.getData('groupKey'); - var dstKey = groupEl.groupKey; - - if (srcKey === dstKey) - return; - - var newKeys = this.currentGroupKeys_.slice(); - - var srcIndex = this.currentGroupKeys_.indexOf(srcKey); - newKeys.splice(srcIndex, 1); - - var dstIndex = this.currentGroupKeys_.indexOf(dstKey); - newKeys.splice(dstIndex, 0, srcKey); - - this.currentGroupKeys = newKeys; - - e.dataTransfer.clearData(); - e.preventDefault(); - e.stopPropagation(); - }.bind(this)); } }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html b/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html index 0c884b65a96..b83e46c9d47 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/heading.html @@ -7,7 +7,7 @@ found in the LICENSE file. <link rel='import' href='/tracing/ui/base/constants.html'> -<polymer-element name='tr-ui-heading'> +<dom-module id='tr-ui-heading'> <template> <style> :host { @@ -39,104 +39,105 @@ found in the LICENSE file. display: none; } </style> - <heading id='heading' on-click='{{onHeadingDivClicked_}}'> + <heading id='heading' on-click='onHeadingDivClicked_'> <span id='arrow'></span> <span id='heading_content'></span> <tr-ui-a-analysis-link id='link'></tr-ui-a-analysis-link> </heading> </template> +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tr-ui-heading', + + DOWN_ARROW: String.fromCharCode(0x25BE), + RIGHT_ARROW: String.fromCharCode(0x25B8), + + ready: function(viewport) { + // Minus 6 === 1px border + 5px padding right. + this.style.width = (tr.ui.b.constants.HEADING_WIDTH - 6) + 'px'; + + this.heading_ = ''; + this.expanded_ = true; + this.arrowVisible_ = false; + this.selectionGenerator_ = undefined; + + this.updateContents_(); + }, + + get heading() { + return this.heading_; + }, + + set heading(text) { + if (this.heading_ === text) + return; + + this.heading_ = text; + this.updateContents_(); + }, + + set arrowVisible(val) { + if (this.arrowVisible_ === val) + return; + + this.arrowVisible_ = !!val; + this.updateContents_(); + }, + + set tooltip(text) { + this.$.heading.title = text; + }, + + set selectionGenerator(generator) { + if (this.selectionGenerator_ === generator) + return; + + this.selectionGenerator_ = generator; + this.updateContents_(); + }, + + get expanded() { + return this.expanded_; + }, + + set expanded(expanded) { + if (this.expanded_ === expanded) + return; + + this.expanded_ = !!expanded; + this.updateContents_(); + }, + + onHeadingDivClicked_: function() { + this.dispatchEvent(new tr.b.Event('heading-clicked', true)); + }, + + updateContents_: function() { + if (this.arrowVisible_) { + this.$.arrow.style.display = ''; + } else { + this.$.arrow.style.display = 'none'; + this.$.heading.style.display = this.expanded_ ? '' : 'none'; + } + + if (this.arrowVisible_) { + Polymer.dom(this.$.arrow).textContent = + this.expanded_ ? this.DOWN_ARROW : this.RIGHT_ARROW; + } + + this.$.link.style.display = 'none'; + this.$.heading_content.style.display = 'none'; - <script> - 'use strict'; - Polymer({ - DOWN_ARROW: String.fromCharCode(0x25BE), - RIGHT_ARROW: String.fromCharCode(0x25B8), - - ready: function(viewport) { - // Minus 6 == 1px border + 5px padding right. - this.style.width = (tr.ui.b.constants.HEADING_WIDTH - 6) + 'px'; - - this.heading_ = ''; - this.expanded_ = true; - this.arrowVisible_ = false; - this.selectionGenerator_ = undefined; - - this.updateContents_(); - }, - - get heading() { - return this.heading_; - }, - - set heading(text) { - if (this.heading_ === text) - return; - - this.heading_ = text; - this.updateContents_(); - }, - - set arrowVisible(val) { - if (this.arrowVisible_ === val) - return; - - this.arrowVisible_ = !!val; - this.updateContents_(); - }, - - set tooltip(text) { - this.$.heading.title = text; - }, - - set selectionGenerator(generator) { - if (this.selectionGenerator_ === generator) - return; - - this.selectionGenerator_ = generator; - this.updateContents_(); - }, - - get expanded() { - return this.expanded_; - }, - - set expanded(expanded) { - if (this.expanded_ === expanded) - return; - - this.expanded_ = !!expanded; - this.updateContents_(); - }, - - onHeadingDivClicked_: function() { - this.dispatchEvent(new tr.b.Event('heading-clicked', {'bubbles': true})); - }, - - updateContents_: function() { - if (this.arrowVisible_) { - this.$.arrow.style.display = ''; - } else { - this.$.arrow.style.display = 'none'; - this.$.heading.style.display = this.expanded_ ? '' : 'none'; - } - - if (this.arrowVisible_) { - this.$.arrow.textContent = - this.expanded_ ? this.DOWN_ARROW : this.RIGHT_ARROW; - } - - this.$.link.style.display = 'none'; - this.$.heading_content.style.display = 'none'; - - if (this.selectionGenerator_) { - this.$.link.style.display = 'inline-block'; - this.$.link.selection = this.selectionGenerator_; - this.$.link.textContent = this.heading_; - } else { - this.$.heading_content.style.display = 'inline-block'; - this.$.heading_content.textContent = this.heading_; - } + if (this.selectionGenerator_) { + this.$.link.style.display = 'inline-block'; + this.$.link.selection = this.selectionGenerator_; + Polymer.dom(this.$.link).textContent = this.heading_; + } else { + this.$.heading_content.style.display = 'inline-block'; + Polymer.dom(this.$.heading_content).textContent = this.heading_; } - }); - </script> -</polymer-element> + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html index 892b7e7593a..38b7967a17a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller.html @@ -7,260 +7,264 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/guid.html"> <link rel="import" href="/tracing/ui/base/hot_key.html"> -<polymer-element name="tv-ui-b-hotkey-controller"> - <script> - 'use strict'; - Polymer({ - created: function() { - this.isAttached_ = false; - this.globalMode_ = false; - this.slavedToParentController_ = undefined; - this.curHost_ = undefined; - this.childControllers_ = []; +<dom-module id='tv-ui-b-hotkey-controller'> + <template> + <div></div> + </template> +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tv-ui-b-hotkey-controller', + + created: function() { + this.isAttached_ = false; + this.globalMode_ = false; + this.slavedToParentController_ = undefined; + this.curHost_ = undefined; + this.childControllers_ = []; + + this.bubblingKeyDownHotKeys_ = {}; + this.capturingKeyDownHotKeys_ = {}; + this.bubblingKeyPressHotKeys_ = {}; + this.capturingKeyPressHotKeys_ = {}; + + this.onBubblingKeyDown_ = this.onKey_.bind(this, false); + this.onCapturingKeyDown_ = this.onKey_.bind(this, true); + this.onBubblingKeyPress_ = this.onKey_.bind(this, false); + this.onCapturingKeyPress_ = this.onKey_.bind(this, true); + }, + + attached: function() { + this.isAttached_ = true; + + var host = this.findHost_(); + if (host.__hotkeyController) + throw new Error('Multiple hotkey controllers attached to this host'); + + host.__hotkeyController = this; + this.curHost_ = host; + + var parentElement; + if (host.parentElement) + parentElement = host.parentElement; + else + parentElement = Polymer.dom(host).parentNode.host; + var parentController = tr.b.getHotkeyControllerForElement( + parentElement); + + if (parentController) { + this.slavedToParentController_ = parentController; + parentController.addChildController_(this); + return; + } - this.bubblingKeyDownHotKeys_ = {}; - this.capturingKeyDownHotKeys_ = {}; - this.bubblingKeyPressHotKeys_ = {}; - this.capturingKeyPressHotKeys_ = {}; + host.addEventListener('keydown', this.onBubblingKeyDown_, false); + host.addEventListener('keydown', this.onCapturingKeyDown_, true); + host.addEventListener('keypress', this.onBubblingKeyPress_, false); + host.addEventListener('keypress', this.onCapturingKeyPress_, true); + }, - this.onBubblingKeyDown_ = this.onKey_.bind(this, false); - this.onCapturingKeyDown_ = this.onKey_.bind(this, true); - this.onBubblingKeyPress_ = this.onKey_.bind(this, false); - this.onCapturingKeyPress_ = this.onKey_.bind(this, true); - }, + detached: function() { + this.isAttached_ = false; - attached: function() { - this.isAttached_ = true; + var host = this.curHost_; + if (!host) + return; - var host = this.findHost_(); - if (host.__hotkeyController) - throw new Error('Multiple hotkey controllers attached to this host'); + delete host.__hotkeyController; + this.curHost_ = undefined; - host.__hotkeyController = this; - this.curHost_ = host; + if (this.slavedToParentController_) { + this.slavedToParentController_.removeChildController_(this); + this.slavedToParentController_ = undefined; + return; + } - var parentElement; - if (host.parentElement) - parentElement = host.parentElement; + host.removeEventListener('keydown', this.onBubblingKeyDown_, false); + host.removeEventListener('keydown', this.onCapturingKeyDown_, true); + host.removeEventListener('keypress', this.onBubblingKeyPress_, false); + host.removeEventListener('keypress', this.onCapturingKeyPress_, true); + }, + + addChildController_: function(controller) { + var i = this.childControllers_.indexOf(controller); + if (i !== -1) + throw new Error('Controller already registered'); + this.childControllers_.push(controller); + }, + + removeChildController_: function(controller) { + var i = this.childControllers_.indexOf(controller); + if (i === -1) + throw new Error('Controller not registered'); + this.childControllers_.splice(i, 1); + return controller; + }, + + getKeyMapForEventType_: function(eventType, useCapture) { + if (eventType === 'keydown') { + if (!useCapture) + return this.bubblingKeyDownHotKeys_; else - parentElement = host.parentNode.host; - var parentController = tr.b.getHotkeyControllerForElement( - parentElement); - - if (parentController) { - this.slavedToParentController_ = parentController; - parentController.addChildController_(this); - return; - } - - host.addEventListener('keydown', this.onBubblingKeyDown_, false); - host.addEventListener('keydown', this.onCapturingKeyDown_, true); - host.addEventListener('keypress', this.onBubblingKeyPress_, false); - host.addEventListener('keypress', this.onCapturingKeyPress_, true); - }, - - detached: function() { - this.isAttached_ = false; - - var host = this.curHost_; - if (!host) - return; - - delete host.__hotkeyController; - this.curHost_ = undefined; - - if (this.slavedToParentController_) { - this.slavedToParentController_.removeChildController_(this); - this.slavedToParentController_ = undefined; - return; - } - - host.removeEventListener('keydown', this.onBubblingKeyDown_, false); - host.removeEventListener('keydown', this.onCapturingKeyDown_, true); - host.removeEventListener('keypress', this.onBubblingKeyPress_, false); - host.removeEventListener('keypress', this.onCapturingKeyPress_, true); - }, - - addChildController_: function(controller) { - var i = this.childControllers_.indexOf(controller); - if (i !== -1) - throw new Error('Controller already registered'); - this.childControllers_.push(controller); - }, - - removeChildController_: function(controller) { - var i = this.childControllers_.indexOf(controller); - if (i === -1) - throw new Error('Controller not registered'); - this.childControllers_.splice(i, 1); - return controller; - }, - - getKeyMapForEventType_: function(eventType, useCapture) { - if (eventType === 'keydown') { - if (!useCapture) - return this.bubblingKeyDownHotKeys_; - else - return this.capturingKeyDownHotKeys_; - } else if (eventType === 'keypress') { - if (!useCapture) - return this.bubblingKeyPressHotKeys_; - else - return this.capturingKeyPressHotKeys_; - } else { - throw new Error('Unsupported key event'); - } - }, + return this.capturingKeyDownHotKeys_; + } else if (eventType === 'keypress') { + if (!useCapture) + return this.bubblingKeyPressHotKeys_; + else + return this.capturingKeyPressHotKeys_; + } else { + throw new Error('Unsupported key event'); + } + }, - addHotKey: function(hotKey) { - if (!(hotKey instanceof tr.ui.b.HotKey)) - throw new Error('hotKey must be a tr.ui.b.HotKey'); + addHotKey: function(hotKey) { + if (!(hotKey instanceof tr.ui.b.HotKey)) + throw new Error('hotKey must be a tr.ui.b.HotKey'); - var keyMap = this.getKeyMapForEventType_( - hotKey.eventType, hotKey.useCapture); + var keyMap = this.getKeyMapForEventType_( + hotKey.eventType, hotKey.useCapture); - for (var i = 0; i < hotKey.keyCodes.length; i++) { - var keyCode = hotKey.keyCodes[i]; - if (keyMap[keyCode]) - throw new Error('Key is already bound for keyCode=' + keyCode); - } + for (var i = 0; i < hotKey.keyCodes.length; i++) { + var keyCode = hotKey.keyCodes[i]; + if (keyMap[keyCode]) + throw new Error('Key is already bound for keyCode=' + keyCode); + } - for (var i = 0; i < hotKey.keyCodes.length; i++) { - var keyCode = hotKey.keyCodes[i]; - keyMap[keyCode] = hotKey; - } - return hotKey; - }, + for (var i = 0; i < hotKey.keyCodes.length; i++) { + var keyCode = hotKey.keyCodes[i]; + keyMap[keyCode] = hotKey; + } + return hotKey; + }, - removeHotKey: function(hotKey) { - if (!(hotKey instanceof tr.ui.b.HotKey)) - throw new Error('hotKey must be a tr.ui.b.HotKey'); + removeHotKey: function(hotKey) { + if (!(hotKey instanceof tr.ui.b.HotKey)) + throw new Error('hotKey must be a tr.ui.b.HotKey'); - var keyMap = this.getKeyMapForEventType_( - hotKey.eventType, hotKey.useCapture); + var keyMap = this.getKeyMapForEventType_( + hotKey.eventType, hotKey.useCapture); - for (var i = 0; i < hotKey.keyCodes.length; i++) { - var keyCode = hotKey.keyCodes[i]; - if (!keyMap[keyCode]) - throw new Error('Key is not bound for keyCode=' + keyCode); - keyMap[keyCode] = hotKey; - } - for (var i = 0; i < hotKey.keyCodes.length; i++) { - var keyCode = hotKey.keyCodes[i]; - delete keyMap[keyCode]; - } - return hotKey; - }, - - get globalMode() { - return this.globalMode_; - }, - - set globalMode(globalMode) { - var wasAttached = this.isAttached_; - if (wasAttached) - this.detached(); - this.globalMode_ = !!globalMode; - if (wasAttached) - this.attached(); - }, - - get topmostConroller_() { - if (this.slavedToParentController_) - return this.slavedToParentController_.topmostConroller_; - return this; - }, - - childRequestsGeneralFocus: function(child) { - var topmost = this.topmostConroller_; - if (topmost.curHost_) { - if (topmost.curHost_.hasAttribute('tabIndex')) { - topmost.curHost_.focus(); - } else { - if (document.activeElement) - document.activeElement.blur(); - } + for (var i = 0; i < hotKey.keyCodes.length; i++) { + var keyCode = hotKey.keyCodes[i]; + if (!keyMap[keyCode]) + throw new Error('Key is not bound for keyCode=' + keyCode); + keyMap[keyCode] = hotKey; + } + for (var i = 0; i < hotKey.keyCodes.length; i++) { + var keyCode = hotKey.keyCodes[i]; + delete keyMap[keyCode]; + } + return hotKey; + }, + + get globalMode() { + return this.globalMode_; + }, + + set globalMode(globalMode) { + var wasAttached = this.isAttached_; + if (wasAttached) + this.detached(); + this.globalMode_ = !!globalMode; + if (wasAttached) + this.attached(); + }, + + get topmostConroller_() { + if (this.slavedToParentController_) + return this.slavedToParentController_.topmostConroller_; + return this; + }, + + childRequestsGeneralFocus: function(child) { + var topmost = this.topmostConroller_; + if (topmost.curHost_) { + if (topmost.curHost_.hasAttribute('tabIndex')) { + topmost.curHost_.focus(); } else { if (document.activeElement) document.activeElement.blur(); } - }, - - childRequestsBlur: function(child) { - child.blur(); + } else { + if (document.activeElement) + document.activeElement.blur(); + } + }, - var topmost = this.topmostConroller_; - if (topmost.curHost_) { - topmost.curHost_.focus(); - } - }, + childRequestsBlur: function(child) { + child.blur(); - findHost_: function() { - if (this.globalMode_) { - return document.body; - } else { - if (this.parentElement) - return this.parentElement; - - var node = this; - while (node.parentNode) { - node = node.parentNode; - } - return node.host; - } - }, - - appendMatchingHotKeysTo_: function(matchedHotKeys, - useCapture, e) { - var localKeyMap = this.getKeyMapForEventType_(e.type, useCapture); - var localHotKey = localKeyMap[e.keyCode]; - if (localHotKey) - matchedHotKeys.push(localHotKey); - - for (var i = 0; i < this.childControllers_.length; i++) { - var controller = this.childControllers_[i]; - controller.appendMatchingHotKeysTo_(matchedHotKeys, - useCapture, e); + var topmost = this.topmostConroller_; + if (topmost.curHost_) { + topmost.curHost_.focus(); + } + }, + + findHost_: function() { + if (this.globalMode_) { + return document.body; + } else { + if (this.parentElement) + return this.parentElement; + + var node = this; + while (Polymer.dom(node).parentNode) { + node = Polymer.dom(node).parentNode; } - }, + return node.host; + } + }, + + appendMatchingHotKeysTo_: function(matchedHotKeys, + useCapture, e) { + var localKeyMap = this.getKeyMapForEventType_(e.type, useCapture); + var localHotKey = localKeyMap[e.keyCode]; + if (localHotKey) + matchedHotKeys.push(localHotKey); + + for (var i = 0; i < this.childControllers_.length; i++) { + var controller = this.childControllers_[i]; + controller.appendMatchingHotKeysTo_(matchedHotKeys, + useCapture, e); + } + }, - onKey_: function(useCapture, e) { - // Keys dispatched to INPUT elements still bubble, even when they're - // handled. So, skip any events that targeted the input element. - if (useCapture == false && e.path[0].tagName == 'INPUT') - return; + onKey_: function(useCapture, e) { + // Keys dispatched to INPUT elements still bubble, even when they're + // handled. So, skip any events that targeted the input element. + if (!useCapture && e.path[0].tagName === 'INPUT') + return; - var sortedControllers; + var sortedControllers; - var matchedHotKeys = []; - this.appendMatchingHotKeysTo_(matchedHotKeys, useCapture, e); + var matchedHotKeys = []; + this.appendMatchingHotKeysTo_(matchedHotKeys, useCapture, e); - if (matchedHotKeys.length === 0) - return false; + if (matchedHotKeys.length === 0) + return false; - if (matchedHotKeys.length > 1) { - // TODO(nduca): To do support for coddling hotKeys, we need to - // sort the listeners by their capturing/bubbling order and then pick - // the one that would topologically win the tie, per DOM dispatch rules. - throw new Error('More than one hotKey is currently unsupported'); - } + if (matchedHotKeys.length > 1) { + // TODO(nduca): To do support for coddling hotKeys, we need to + // sort the listeners by their capturing/bubbling order and then pick + // the one that would topologically win the tie, per DOM dispatch rules. + throw new Error('More than one hotKey is currently unsupported'); + } - var hotKey = matchedHotKeys[0]; + var hotKey = matchedHotKeys[0]; - var prevented = 0; - prevented |= hotKey.call(e); + var prevented = 0; + prevented |= hotKey.call(e); - // We want to return false if preventDefaulted, or one of the handlers - // return false. But otherwise, we want to return undefiend. - return !prevented && e.defaultPrevented; - } - }); - </script> -</polymer-element> + // We want to return false if preventDefaulted, or one of the handlers + // return false. But otherwise, we want to return undefiend. + return !prevented && e.defaultPrevented; + } +}); +</script> <script> 'use strict'; - tr.exportTo('tr.b', function() { function getHotkeyControllerForElement(refElement) { @@ -285,8 +289,8 @@ tr.exportTo('tr.b', function() { function findHost(initialNode) { var node = initialNode; - while (node.parentNode) { - node = node.parentNode; + while (Polymer.dom(node).parentNode) { + node = Polymer.dom(node).parentNode; } return node.host; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html index 0895e724250..2ef4c5bb737 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/hotkey_controller_test.html @@ -24,15 +24,15 @@ tr.b.unittest.testSuite(function() { test('simpleHotkeyManager', function() { var rootElement = document.createElement('div'); - document.body.appendChild(rootElement); + Polymer.dom(document.body).appendChild(rootElement); try { var elementShadow = rootElement.createShadowRoot(); var hkc = document.createElement('tv-ui-b-hotkey-controller'); - elementShadow.appendChild(hkc); + Polymer.dom(elementShadow).appendChild(hkc); var subElement = document.createElement('div'); - elementShadow.appendChild(subElement); + Polymer.dom(elementShadow).appendChild(subElement); assert.equal(tr.b.getHotkeyControllerForElement(subElement), hkc); @@ -57,25 +57,25 @@ tr.b.unittest.testSuite(function() { assert.isTrue(didGetCalled); } finally { - document.body.removeChild(rootElement); + Polymer.dom(document.body).removeChild(rootElement); } }); test('nestedHotkeyController', function() { var rootElement = document.createElement('div'); - document.body.appendChild(rootElement); + Polymer.dom(document.body).appendChild(rootElement); try { var elementShadow = rootElement.createShadowRoot(); var hkc = document.createElement('tv-ui-b-hotkey-controller'); - elementShadow.appendChild(hkc); + Polymer.dom(elementShadow).appendChild(hkc); var subElement = document.createElement('div'); - elementShadow.appendChild(subElement); + Polymer.dom(elementShadow).appendChild(subElement); assert.equal(tr.b.getHotkeyControllerForElement(elementShadow), hkc); var subHKC = document.createElement('tv-ui-b-hotkey-controller'); - subElement.appendChild(subHKC); + Polymer.dom(subElement).appendChild(subHKC); assert.equal(tr.b.getHotkeyControllerForElement(subElement), subHKC); @@ -93,21 +93,21 @@ tr.b.unittest.testSuite(function() { rootElement.dispatchEvent(e); assert.isTrue(didGetCalled); } finally { - document.body.removeChild(rootElement); + Polymer.dom(document.body).removeChild(rootElement); } }); test('inputInsideHKC', function() { var rootElement = document.createElement('div'); - document.body.appendChild(rootElement); + Polymer.dom(document.body).appendChild(rootElement); try { var elementShadow = rootElement.createShadowRoot(); var hkc = document.createElement('tv-ui-b-hotkey-controller'); - elementShadow.appendChild(hkc); + Polymer.dom(elementShadow).appendChild(hkc); var inputEl = document.createElement('input'); - elementShadow.appendChild(inputEl); + Polymer.dom(elementShadow).appendChild(inputEl); var didGetCalled = false; hkc.addHotKey(new tr.ui.b.HotKey({ @@ -130,7 +130,7 @@ tr.b.unittest.testSuite(function() { inputEl.dispatchEvent(e); assert.isFalse(didGetCalled); } finally { - document.body.removeChild(rootElement); + Polymer.dom(document.body).removeChild(rootElement); } }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html index a9b188556d1..6ad1bdbbfde 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar.html @@ -8,7 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name='tr-ui-b-info-bar' is='HTMLDivElement'> +<dom-module id='tr-ui-b-info-bar'> <template> <style> :host { @@ -34,49 +34,50 @@ found in the LICENSE file. <span id='message'></span> <span id='buttons'></span> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-b-info-bar', - Polymer({ - ready: function() { - this.messageEl_ = this.$.message; - this.buttonsEl_ = this.$.buttons; + ready: function() { + this.messageEl_ = this.$.message; + this.buttonsEl_ = this.$.buttons; - this.message = ''; - this.visible = false; - }, + this.message = ''; + this.visible = false; + }, - get message() { - return this.messageEl_.textContent; - }, + get message() { + return Polymer.dom(this.messageEl_).textContent; + }, - set message(message) { - this.messageEl_.textContent = message; - }, + set message(message) { + Polymer.dom(this.messageEl_).textContent = message; + }, - get visible() { - return !this.classList.contains('info-bar-hidden'); - }, + get visible() { + return !Polymer.dom(this).classList.contains('info-bar-hidden'); + }, - set visible(visible) { - if (visible) - this.classList.remove('info-bar-hidden'); - else - this.classList.add('info-bar-hidden'); - }, + set visible(visible) { + if (visible) + Polymer.dom(this).classList.remove('info-bar-hidden'); + else + Polymer.dom(this).classList.add('info-bar-hidden'); + }, - removeAllButtons: function() { - this.buttonsEl_.textContent = ''; - }, + removeAllButtons: function() { + Polymer.dom(this.buttonsEl_).textContent = ''; + }, - addButton: function(text, clickCallback) { - var button = document.createElement('button'); - button.textContent = text; - button.addEventListener('click', clickCallback); - this.buttonsEl_.appendChild(button); - return button; - } - }); - </script> -</polymer-element> + addButton: function(text, clickCallback) { + var button = document.createElement('button'); + Polymer.dom(button).textContent = text; + button.addEventListener('click', clickCallback); + Polymer.dom(this.buttonsEl_).appendChild(button); + return button; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html index 4d44a1b1099..af82995de01 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/info_bar_group.html @@ -6,7 +6,7 @@ found in the LICENSE file. --> <link rel='import' href='/tracing/ui/base/info_bar.html'> -<polymer-element name='tr-ui-b-info-bar-group' is='HTMLUnknownElement'> +<dom-module id='tr-ui-b-info-bar-group'> <template> <style> :host { @@ -17,49 +17,50 @@ found in the LICENSE file. </style> <div id='messages'></div> </template> +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tr-ui-b-info-bar-group', - <script> - 'use strict'; - Polymer({ - ready: function() { - this.messages_ = []; - }, + ready: function() { + this.messages_ = []; + }, - clearMessages: function() { - this.messages_ = []; - this.updateContents_(); - }, + clearMessages: function() { + this.messages_ = []; + this.updateContents_(); + }, - addMessage: function(text, opt_buttons) { - opt_buttons = opt_buttons || []; - for (var i = 0; i < opt_buttons.length; i++) { - if (opt_buttons[i].buttonText === undefined) - throw new Error('buttonText must be provided'); - if (opt_buttons[i].onClick === undefined) - throw new Error('onClick must be provided'); - } - - this.messages_.push({ - text: text, - buttons: opt_buttons || [] - }); - this.updateContents_(); - }, + addMessage: function(text, opt_buttons) { + opt_buttons = opt_buttons || []; + for (var i = 0; i < opt_buttons.length; i++) { + if (opt_buttons[i].buttonText === undefined) + throw new Error('buttonText must be provided'); + if (opt_buttons[i].onClick === undefined) + throw new Error('onClick must be provided'); + } - updateContents_: function() { - this.$.messages.textContent = ''; - this.messages_.forEach(function(message) { - var bar = document.createElement('tr-ui-b-info-bar'); - bar.message = message.text; - bar.visible = true; + this.messages_.push({ + text: text, + buttons: opt_buttons || [] + }); + this.updateContents_(); + }, - message.buttons.forEach(function(button) { - bar.addButton(button.buttonText, button.onClick); - }, this); + updateContents_: function() { + Polymer.dom(this.$.messages).textContent = ''; + this.messages_.forEach(function(message) { + var bar = document.createElement('tr-ui-b-info-bar'); + bar.message = message.text; + bar.visible = true; - this.$.messages.appendChild(bar); + message.buttons.forEach(function(button) { + bar.addButton(button.buttonText, button.onClick); }, this); - } - }); - </script> -</polymer-element> + + Polymer.dom(this.$.messages).appendChild(bar); + }, this); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html index ba431695242..00acef33a19 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart.html @@ -25,11 +25,11 @@ tr.exportTo('tr.ui.b', function() { decorate: function() { ChartBase2DBrushX.prototype.decorate.call(this); - this.classList.add('line-chart'); + Polymer.dom(this).classList.add('line-chart'); }, isDatumFieldSeries_: function(fieldName) { - return fieldName != 'x'; + return fieldName !== 'x'; }, getXForDatum_: function(datum, index) { @@ -39,13 +39,14 @@ tr.exportTo('tr.ui.b', function() { updateDataContents_: function(dataSel) { dataSel.selectAll('*').remove(); var dataBySeriesKey = this.getDataBySeriesKey_(); - var pathsSel = dataSel.selectAll('path').data(this.seriesKeys_); + var seriesKeys = [...this.seriesByKey_.keys()]; + var pathsSel = dataSel.selectAll('path').data(seriesKeys); pathsSel.enter() .append('path') .attr('class', 'line') .style('stroke', function(key) { - return tr.ui.b.getColorOfKey(key); - }) + return this.getDataSeries(key).color; + }.bind(this)) .attr('d', function(key) { var line = d3.svg.line() .x(function(d) { return this.xScale_(d.x); }.bind(this)) diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html index 5a6cc13b754..eee61c646f8 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/line_chart_test.html @@ -148,7 +148,7 @@ tr.b.unittest.testSuite(function() { updateBrushedRange(); }); chart.addEventListener('item-mousemove', function(e) { - if (e.button == undefined) + if (e.button === undefined) return; curMouseIndex = e.index; updateBrushedRange(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html index 3d1d8260954..2898344a87e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view.html @@ -24,7 +24,7 @@ tr.exportTo('tr.ui.b', function() { */ var ListAndAssociatedView = tr.ui.b.define('x-list-and-associated-view'); ListAndAssociatedView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.list_ = undefined; @@ -35,8 +35,8 @@ tr.exportTo('tr.ui.b', function() { this.listView_.addEventListener('selection-changed', this.onSelectionChanged_.bind(this)); this.placeholder_ = document.createElement('div'); - this.appendChild(this.listView_); - this.appendChild(this.placeholder_); + Polymer.dom(this).appendChild(this.listView_); + Polymer.dom(this).appendChild(this.placeholder_); }, get listView() { @@ -94,19 +94,19 @@ tr.exportTo('tr.ui.b', function() { var itemEl; if (i >= this.listView_.children.length) { itemEl = document.createElement('div'); - this.listView_.appendChild(itemEl); + Polymer.dom(this.listView_).appendChild(itemEl); } else { itemEl = this.listView_.children[i]; } itemEl.item = this.list_[i]; var getter = this.list_[i].__lookupGetter__(this.listProperty_); if (getter) - itemEl.textContent = getter.call(this.list_[i]); + Polymer.dom(itemEl).textContent = getter.call(this.list_[i]); else - itemEl.textContent = this.list_[i][this.listProperty_]; + Polymer.dom(itemEl).textContent = this.list_[i][this.listProperty_]; } - if (this.children[1] == this.placeholder_) { + if (this.children[1] === this.placeholder_) { this.replaceChild(this.view_, this.children[1]); } @@ -119,7 +119,7 @@ tr.exportTo('tr.ui.b', function() { var setter = this.view_.__lookupSetter__(this.viewProperty_); if (!setter) { var prop = this.viewProperty_; - setter = function(value) { this[prop] = value; } + setter = function(value) { this[prop] = value; }; } if (this.listView_.selectedElement) { setter.call(this.view_, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html index f35a8b26861..28d95ca64fc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_and_associated_view_test.html @@ -43,7 +43,7 @@ tr.b.unittest.testSuite(function() { var lavListView = lav.listView; assert.equal(lavListView.children.length, 3); - assert.equal(lavListView.children[0].textContent, '1'); + assert.equal(Polymer.dom(lavListView.children[0]).textContent, '1'); }); test('listViewNamingWithProperty', function() { @@ -72,7 +72,7 @@ tr.b.unittest.testSuite(function() { var lavListView = lav.listView; assert.equal(lavListView.children.length, 3); - assert.equal(lavListView.children[0].textContent, '1'); + assert.equal(Polymer.dom(lavListView.children[0]).textContent, '1'); }); test('selectionChangesView', function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html index c8279565620..c50c4637758 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/list_view.html @@ -31,7 +31,7 @@ tr.exportTo('tr.ui.b', function() { decorate: function() { tr.ui.b.ContainerThatDecoratesItsChildren.prototype.decorate.call(this); - this.classList.add('x-list-view'); + Polymer.dom(this).classList.add('x-list-view'); this.onItemClicked_ = this.onItemClicked_.bind(this); this.onKeyDown_ = this.onKeyDown_.bind(this); this.tabIndex = 0; @@ -41,7 +41,7 @@ tr.exportTo('tr.ui.b', function() { }, decorateChild_: function(item) { - item.classList.add('list-item'); + Polymer.dom(item).classList.add('list-item'); item.addEventListener('click', this.onItemClicked_, true); var listView = this; @@ -51,14 +51,15 @@ tr.exportTo('tr.ui.b', function() { configurable: true, set: function(value) { var oldSelection = listView.selectedElement; - if (oldSelection && oldSelection != this && value) - listView.selectedElement.removeAttribute('selected'); + if (oldSelection && oldSelection !== this && value) + Polymer.dom(listView.selectedElement).removeAttribute( + 'selected'); if (value) - this.setAttribute('selected', 'selected'); + Polymer.dom(this).setAttribute('selected', 'selected'); else - this.removeAttribute('selected'); + Polymer.dom(this).removeAttribute('selected'); var newSelection = listView.selectedElement; - if (newSelection != oldSelection) + if (newSelection !== oldSelection) tr.b.dispatchSimpleEvent(listView, 'selection-changed', false); }, get: function() { @@ -70,7 +71,7 @@ tr.exportTo('tr.ui.b', function() { undecorateChild_: function(item) { this.selectionChanged_ |= item.selected; - item.classList.remove('list-item'); + Polymer.dom(item).classList.remove('list-item'); item.removeEventListener('click', this.onItemClicked_); delete item.selected; }, @@ -85,7 +86,7 @@ tr.exportTo('tr.ui.b', function() { }, get selectedElement() { - var el = this.querySelector('.list-item[selected]'); + var el = Polymer.dom(this).querySelector('.list-item[selected]'); if (!el) return undefined; return el; @@ -98,14 +99,15 @@ tr.exportTo('tr.ui.b', function() { return; } - if (el.parentElement != this) + if (el.parentElement !== this) throw new Error( 'Can only select elements that are children of this list view'); el.selected = true; }, getElementByIndex: function(index) { - return this.querySelector('.list-item:nth-child(' + index + ')'); + return Polymer.dom(this) + .querySelector('.list-item:nth-child(' + index + ')'); }, clear: function() { @@ -118,12 +120,12 @@ tr.exportTo('tr.ui.b', function() { onItemClicked_: function(e) { var currentSelectedElement = this.selectedElement; if (currentSelectedElement) - currentSelectedElement.removeAttribute('selected'); + Polymer.dom(currentSelectedElement).removeAttribute('selected'); var element = e.target; - while (element.parentElement != this) + while (element.parentElement !== this) element = element.parentElement; if (element !== currentSelectedElement) - element.setAttribute('selected', 'selected'); + Polymer.dom(element).setAttribute('selected', 'selected'); tr.b.dispatchSimpleEvent(this, 'selection-changed', false); }, @@ -131,16 +133,16 @@ tr.exportTo('tr.ui.b', function() { if (this.selectedElement === undefined) return; - if (e.keyCode == 38) { // Up arrow. - var prev = this.selectedElement.previousSibling; + if (e.keyCode === 38) { // Up arrow. + var prev = Polymer.dom(this.selectedElement).previousSibling; if (prev) { prev.selected = true; tr.ui.b.scrollIntoViewIfNeeded(prev); e.preventDefault(); return true; } - } else if (e.keyCode == 40) { // Down arrow. - var next = this.selectedElement.nextSibling; + } else if (e.keyCode === 40) { // Down arrow. + var next = Polymer.dom(this.selectedElement).nextSibling; if (next) { next.selected = true; tr.ui.b.scrollIntoViewIfNeeded(next); @@ -152,8 +154,8 @@ tr.exportTo('tr.ui.b', function() { addItem: function(textContent) { var item = document.createElement('div'); - item.textContent = textContent; - this.appendChild(item); + Polymer.dom(item).textContent = textContent; + Polymer.dom(this).appendChild(item); return item; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html index f31837e5c1b..f400a99656e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon.html @@ -7,7 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/ui/base/mouse_modes.html"> -<polymer-element name="tr-ui-b-mouse-mode-icon"> +<dom-module id='tr-ui-b-mouse-mode-icon'> <template> <style> :host { @@ -21,92 +21,95 @@ found in the LICENSE file. } </style> </template> - <script> - 'use strict'; - - Polymer({ - publish: { - modeName: { - value: undefined, - reflect: true - } +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-b-mouse-mode-icon', + + properties: { + modeName: { + type: String, + reflectToAttribute: true, + observer: 'modeNameChanged' }, - - created: function() { - this.active_ = false; - this.acceleratorKey_ = undefined; - }, - - ready: function() { - this.updateContents_(); - }, - - get mode() { - return tr.ui.b.MOUSE_SELECTOR_MODE[this.modeName]; - }, - - set mode(mode) { - var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode]; - var modeName = tr.b.findFirstKeyInDictMatching( - tr.ui.b.MOUSE_SELECTOR_MODE, - function(modeName, candidateMode) { - return candidateMode === mode; - }); - if (modeName === undefined) - throw new Error('Unknown mode'); - this.modeName = modeName; - }, - - modeNameChanged: function() { - this.updateContents_(); - }, - - get active() { - return this.active_; - }, - - set active(active) { - this.active_ = !!active; - if (this.active_) - this.classList.add('active'); - else - this.classList.remove('active'); - this.updateContents_(); - }, - - get acceleratorKey() { - return this.acceleratorKey_; - }, - - set acceleratorKey(acceleratorKey) { - this.acceleratorKey_ = acceleratorKey; - this.updateContents_(); - }, - - updateContents_: function() { - if (this.modeName === undefined) - return; - - var mode = this.mode; - if (mode === undefined) - throw new Error('Invalid mode'); - - var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode]; - if (!modeInfo) - throw new Error('Invalid mode'); - - var title = modeInfo.title; - if (this.acceleratorKey_) - title = title + ' (' + this.acceleratorKey_ + ')'; - this.title = title; - - var bp; - if (this.active_) - bp = modeInfo.activeBackgroundPosition; - else - bp = modeInfo.defaultBackgroundPosition; - this.style.backgroundPosition = bp; - } - }); - </script> -</polymer-element> + }, + + created: function() { + this.active_ = false; + this.acceleratorKey_ = undefined; + }, + + ready: function() { + this.updateContents_(); + }, + + get mode() { + return tr.ui.b.MOUSE_SELECTOR_MODE[this.modeName]; + }, + + set mode(mode) { + var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode]; + var modeName = tr.b.findFirstKeyInDictMatching( + tr.ui.b.MOUSE_SELECTOR_MODE, + function(modeName, candidateMode) { + return candidateMode === mode; + }); + if (modeName === undefined) + throw new Error('Unknown mode'); + this.modeName = modeName; + }, + + modeNameChanged: function() { + this.updateContents_(); + }, + + get active() { + return this.active_; + }, + + set active(active) { + this.active_ = !!active; + if (this.active_) + Polymer.dom(this).classList.add('active'); + else + Polymer.dom(this).classList.remove('active'); + this.updateContents_(); + }, + + get acceleratorKey() { + return this.acceleratorKey_; + }, + + set acceleratorKey(acceleratorKey) { + this.acceleratorKey_ = acceleratorKey; + this.updateContents_(); + }, + + updateContents_: function() { + if (this.modeName === undefined) + return; + + var mode = this.mode; + if (mode === undefined) + throw new Error('Invalid mode'); + + var modeInfo = tr.ui.b.MOUSE_SELECTOR_MODE_INFOS[mode]; + if (!modeInfo) + throw new Error('Invalid mode'); + + var title = modeInfo.title; + if (this.acceleratorKey_) + title = title + ' (' + this.acceleratorKey_ + ')'; + this.title = title; + + var bp; + if (this.active_) + bp = modeInfo.activeBackgroundPosition; + else + bp = modeInfo.defaultBackgroundPosition; + this.style.backgroundPosition = bp; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html index 905a1bbcf0d..1be3baf48a8 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_icon_test.html @@ -30,7 +30,7 @@ tr.b.unittest.testSuite(function() { test('modeNameSetter', function() { var icon = document.createElement('tr-ui-b-mouse-mode-icon'); - icon.setAttribute('modeName', 'SELECTION'); + Polymer.dom(icon).setAttribute('mode-name', 'SELECTION'); this.addHTMLOutput(icon); return Promise.resolve().then(function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html index a8980d5ee8d..3570826ac99 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/mouse_mode_selector.html @@ -8,13 +8,13 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/event.html"> <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/ui/base/hotkey_controller.html"> +<link rel="import" href="/tracing/ui/base/mouse_mode_icon.html"> +<link rel="import" href="/tracing/ui/base/mouse_modes.html"> <link rel="import" href="/tracing/ui/base/mouse_tracker.html"> <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/base/utils.html"> -<link rel="import" href="/tracing/ui/base/mouse_modes.html"> -<link rel="import" href="/tracing/ui/base/mouse_mode_icon.html"> -<polymer-element name="tr-ui-b-mouse-mode-selector"> +<dom-module id='tr-ui-b-mouse-mode-selector'> <template> <style> :host { @@ -61,7 +61,7 @@ found in the LICENSE file. <div class="buttons"> </div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -90,8 +90,8 @@ tr.exportTo('tr.ui.b', function() { * It handles the user interaction and dispatches events for the various * modes. */ - Polymer('tr-ui-b-mouse-mode-selector', { - __proto__: HTMLDivElement.prototype, + Polymer({ + is: 'tr-ui-b-mouse-mode-selector', created: function() { this.supportedModeMask_ = MOUSE_SELECTOR_MODE.ALL_MODES; @@ -122,8 +122,9 @@ tr.exportTo('tr.ui.b', function() { }, ready: function() { - this.buttonsEl_ = this.shadowRoot.querySelector('.buttons'); - this.dragHandleEl_ = this.shadowRoot.querySelector('.drag-handle'); + this.buttonsEl_ = Polymer.dom(this.root).querySelector('.buttons'); + this.dragHandleEl_ = Polymer.dom(this.root).querySelector( + '.drag-handle'); this.supportedModeMask = MOUSE_SELECTOR_MODE.ALL_MODES; this.dragHandleEl_.addEventListener('mousedown', @@ -210,9 +211,9 @@ tr.exportTo('tr.ui.b', function() { } this.supportedModeMask_ = supportedModeMask; - this.buttonsEl_.textContent = ''; + Polymer.dom(this.buttonsEl_).textContent = ''; for (var modeName in MOUSE_SELECTOR_MODE) { - if (modeName == 'ALL_MODES') + if (modeName === 'ALL_MODES') continue; var mode = MOUSE_SELECTOR_MODE[modeName]; if ((this.supportedModeMask_ & mode) === 0) @@ -220,9 +221,9 @@ tr.exportTo('tr.ui.b', function() { var button = document.createElement('tr-ui-b-mouse-mode-icon'); button.mode = mode; - button.classList.add('tool-button'); + Polymer.dom(button).classList.add('tool-button'); - this.buttonsEl_.appendChild(button); + Polymer.dom(this.buttonsEl_).appendChild(button); } }, @@ -403,7 +404,7 @@ tr.exportTo('tr.ui.b', function() { onKeyDown_: function(e) { // Keys dispatched to INPUT elements still bubble, even when they're // handled. So, skip any events that targeted the input element. - if (e.path[0].tagName == 'INPUT') + if (e.path[0].tagName === 'INPUT') return; if (e.keyCode === ' '.charCodeAt(0)) @@ -414,7 +415,7 @@ tr.exportTo('tr.ui.b', function() { onKeyUp_: function(e) { // Keys dispatched to INPUT elements still bubble, even when they're // handled. So, skip any events that targeted the input element. - if (e.path[0].tagName == 'INPUT') + if (e.path[0].tagName === 'INPUT') return; if (e.keyCode === ' '.charCodeAt(0)) diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html index dcfdbaa17c6..4a6503e4f44 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/name_bar_chart.html @@ -5,43 +5,36 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/base/range.html"> +<link rel="import" href="/tracing/base/raf.html"> +<link rel="import" href="/tracing/ui/base/column_chart.html"> <link rel="import" href="/tracing/ui/base/d3.html"> -<link rel="import" href="/tracing/ui/base/bar_chart.html"> <script> 'use strict'; tr.exportTo('tr.ui.b', function() { - var BarChart = tr.ui.b.BarChart; + var ColumnChart = tr.ui.b.ColumnChart; // @constructor - var NameBarChart = tr.ui.b.define('name-bar-chart', BarChart); + var NameBarChart = tr.ui.b.define('name-bar-chart', ColumnChart); NameBarChart.prototype = { - __proto__: BarChart.prototype, + __proto__: ColumnChart.prototype, decorate: function() { - BarChart.prototype.decorate.call(this); - this.classList.remove('bar-chart'); - this.classList.add('name-bar-chart'); - this.bottomMargin_ = 40; + ColumnChart.prototype.decorate.call(this); + Polymer.dom(this).classList.remove('bar-chart'); + Polymer.dom(this).classList.add('name-bar-chart'); }, isDatumFieldSeries_: function(fieldName) { - return fieldName != 'x'; + return fieldName !== 'x'; }, getXForDatum_: function(datum, index) { return index; }, - getMargin_: function() { - var margin = BarChart.prototype.getMargin_.call(this); - margin.bottom = this.bottomMargin_; - return margin; - }, - updateXAxis_: function(xAxis) { xAxis.selectAll('*').remove(); var y = this.chartAreaSize.height + 10; @@ -68,8 +61,10 @@ tr.exportTo('tr.ui.b', function() { // If the nameTexts extend past the bottom of the chart, then increase // this.bottomMargin_ and re-render. - var bottomMargin = this.bottomMargin_; - window.requestAnimationFrame(function() { + // TODO(benjhayden): Refactor with the code that is very similar to this + // in chart_base_2d. + var bottomMargin = this.margin.bottom; + tr.b.requestAnimationFrame(function() { nameTexts[0].forEach(function(t) { var box = t.getBBox(); // When the text is rotated, its height is the hypotenuse @@ -77,14 +72,15 @@ tr.exportTo('tr.ui.b', function() { // triangle W. The bottomMargin must be equal to a side of H plus a // side of W. var h = Math.cos(Math.PI / 4) * (box.height + box.width); - bottomMargin = Math.max(this.bottomMargin_, h); + bottomMargin = Math.max(bottomMargin, h); }, this); - if (Math.round(bottomMargin) !== Math.round(this.bottomMargin_)) { - this.bottomMargin_ = bottomMargin; + bottomMargin = parseInt(Math.ceil(bottomMargin)); + if (bottomMargin > this.margin.bottom) { + this.margin.bottom = bottomMargin; this.updateContents_(); } - }.bind(this)); + }, this); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html index df8e13ceddf..911c68afbee 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay.html @@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/base/utils.html"> <link rel="import" href="/tracing/base/event.html"> +<link rel="import" href="/tracing/base/utils.html"> <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/base/utils.html"> @@ -142,7 +142,7 @@ tr.exportTo('tr.ui.b', function() { * Initializes the overlay element. */ decorate: function() { - this.classList.add('overlay'); + Polymer.dom(this).classList.add('overlay'); this.parentEl_ = this.ownerDocument.body; @@ -162,30 +162,33 @@ tr.exportTo('tr.ui.b', function() { var createShadowRoot = this.createShadowRoot || this.webkitCreateShadowRoot; this.shadow_ = createShadowRoot.call(this); - this.shadow_.appendChild(tr.ui.b.instantiateTemplate('#overlay-template', - THIS_DOC)); + Polymer.dom(this.shadow_).appendChild( + tr.ui.b.instantiateTemplate('#overlay-template', THIS_DOC)); - this.closeBtn_ = this.shadow_.querySelector('close-button'); + this.closeBtn_ = Polymer.dom(this.shadow_).querySelector('close-button'); this.closeBtn_.addEventListener('click', this.onClose_); - this.shadow_ + Polymer.dom(this.shadow_) .querySelector('overlay-frame') .addEventListener('click', this.onClick_); this.observer_ = new WebKitMutationObserver( this.didButtonBarMutate_.bind(this)); - this.observer_.observe(this.shadow_.querySelector('button-bar'), - { childList: true }); + this.observer_.observe( + Polymer.dom(this.shadow_).querySelector('button-bar'), + { childList: true }); // title is a variable on regular HTMLElements. However, we want to // use it for something more useful. Object.defineProperty( this, 'title', { get: function() { - return this.shadow_.querySelector('title').textContent; + return Polymer.dom(Polymer.dom(this.shadow_) + .querySelector('title')).textContent; }, set: function(title) { - this.shadow_.querySelector('title').textContent = title; + Polymer.dom(Polymer.dom(this.shadow_).querySelector('title')) + .textContent = title; } }); }, @@ -197,7 +200,7 @@ tr.exportTo('tr.ui.b', function() { }, get buttons() { - return this.shadow_.querySelector('button-bar'); + return Polymer.dom(this.shadow_).querySelector('button-bar'); }, get visible() { @@ -218,11 +221,12 @@ tr.exportTo('tr.ui.b', function() { }, show_: function() { - this.parentEl_.appendChild(this); + Polymer.dom(this.parentEl_).appendChild(this); if (this.userCanClose_) { this.addEventListener('keydown', this.onKeyDown_.bind(this)); this.addEventListener('click', this.onDocumentClick_.bind(this)); + this.closeBtn_.addEventListener('click', this.onClose_); } this.parentEl_.addEventListener('focusin', this.onFocusIn_); @@ -231,7 +235,8 @@ tr.exportTo('tr.ui.b', function() { // Focus the first thing we find that makes sense. (Skip the close button // as it doesn't make sense as the first thing to focus.) var focusEl = undefined; - var elList = this.querySelectorAll('button, input, list, select, a'); + var elList = + Polymer.dom(this).querySelectorAll('button, input, list, select, a'); if (elList.length > 0) { if (elList[0] === this.closeBtn_) { if (elList.length > 1) @@ -246,7 +251,7 @@ tr.exportTo('tr.ui.b', function() { }, hide_: function() { - this.parentEl_.removeChild(this); + Polymer.dom(this.parentEl_).removeChild(this); this.parentEl_.removeEventListener('focusin', this.onFocusIn_); @@ -259,7 +264,7 @@ tr.exportTo('tr.ui.b', function() { onClose_: function(e) { this.visible = false; - if ((e.type != 'keydown') || + if ((e.type !== 'keydown') || (e.type === 'keydown' && e.keyCode === 27)) e.stopPropagation(); e.preventDefault(); @@ -277,10 +282,13 @@ tr.exportTo('tr.ui.b', function() { didButtonBarMutate_: function(e) { var hasButtons = this.buttons.children.length > 0; - if (hasButtons) - this.shadow_.querySelector('button-bar').style.display = undefined; - else - this.shadow_.querySelector('button-bar').style.display = 'none'; + if (hasButtons) { + Polymer.dom(this.shadow_).querySelector('button-bar').style.display = + undefined; + } else { + Polymer.dom(this.shadow_).querySelector('button-bar').style.display = + 'none'; + } }, onKeyDown_: function(e) { @@ -313,25 +321,25 @@ tr.exportTo('tr.ui.b', function() { Overlay.showError = function(msg, opt_err) { var o = new Overlay(); o.title = 'Error'; - o.textContent = msg; + Polymer.dom(o).textContent = msg; if (opt_err) { var e = tr.b.normalizeException(opt_err); var stackDiv = document.createElement('pre'); - stackDiv.textContent = e.stack; + Polymer.dom(stackDiv).textContent = e.stack; stackDiv.style.paddingLeft = '8px'; stackDiv.style.margin = 0; - o.appendChild(stackDiv); + Polymer.dom(o).appendChild(stackDiv); } var b = document.createElement('button'); - b.textContent = 'OK'; + Polymer.dom(b).textContent = 'OK'; b.addEventListener('click', function() { o.visible = false; }); - o.buttons.appendChild(b); + Polymer.dom(o.buttons).appendChild(b); o.visible = true; return o; - } + }; return { Overlay: Overlay diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html index d1d1b31e8e3..caf03dab11f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/overlay_test.html @@ -4,15 +4,15 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/overlay.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/overlay.html"> <script> 'use strict'; tr.b.unittest.testSuite(function() { function addShowButtonForDialog(dlg) { var btn = document.createElement('button'); - btn.textContent = 'Launch Overlay'; + Polymer.dom(btn).textContent = 'Launch Overlay'; btn.addEventListener('click', function(e) { dlg.visible = true; e.stopPropagation(); @@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() { function makeButton(title) { var btn = document.createElement('button'); - btn.textContent = title; + Polymer.dom(btn).textContent = title; return btn; } @@ -37,31 +37,31 @@ tr.b.unittest.testSuite(function() { test('instantiate', function() { var dlg = new tr.ui.b.Overlay(); - dlg.classList.add('example-overlay'); + Polymer.dom(dlg).classList.add('example-overlay'); dlg.title = 'ExampleOverlay'; - dlg.innerHTML = 'hello'; - dlg.buttons.appendChild(makeButton('i am a button')); - dlg.buttons.appendChild(makeCloseButton(dlg)); - dlg.buttons.appendChild(tr.ui.b.createSpan( + Polymer.dom(dlg).innerHTML = 'hello'; + Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button')); + Polymer.dom(dlg.buttons).appendChild(makeCloseButton(dlg)); + Polymer.dom(dlg.buttons).appendChild(tr.ui.b.createSpan( {textContent: 'i am a span'})); addShowButtonForDialog.call(this, dlg); }); test('instantiate_noButtons', function() { var dlg = new tr.ui.b.Overlay(); - dlg.classList.add('example-overlay'); + Polymer.dom(dlg).classList.add('example-overlay'); dlg.title = 'ExampleOverlay'; - dlg.innerHTML = 'hello'; + Polymer.dom(dlg).innerHTML = 'hello'; addShowButtonForDialog.call(this, dlg); }); test('instantiate_disableUserClose', function() { var dlg = new tr.ui.b.Overlay(); - dlg.classList.add('example-overlay'); + Polymer.dom(dlg).classList.add('example-overlay'); dlg.userCanClose = false; dlg.title = 'Unclosable'; - dlg.innerHTML = 'This has no close X button.'; - dlg.buttons.appendChild(makeCloseButton(dlg)); + Polymer.dom(dlg).innerHTML = 'This has no close X button.'; + Polymer.dom(dlg.buttons).appendChild(makeCloseButton(dlg)); addShowButtonForDialog.call(this, dlg); }); @@ -70,16 +70,16 @@ tr.b.unittest.testSuite(function() { dlg.title = 'TallContent'; var contentEl = document.createElement('div'); contentEl.style.overflowY = 'auto'; - dlg.appendChild(contentEl); + Polymer.dom(dlg).appendChild(contentEl); for (var i = 0; i < 1000; i++) { var el = document.createElement('div'); - el.textContent = 'line ' + i; - contentEl.appendChild(el); + Polymer.dom(el).textContent = 'line ' + i; + Polymer.dom(contentEl).appendChild(el); } - dlg.buttons.appendChild(makeButton('i am a button')); + Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button')); addShowButtonForDialog.call(this, dlg); }); @@ -89,11 +89,11 @@ tr.b.unittest.testSuite(function() { for (var i = 0; i < 100; i++) { var el = document.createElement('div'); el.style.webkitFlex = '1 0 auto'; - el.textContent = 'line ' + i; - dlg.appendChild(el); + Polymer.dom(el).textContent = 'line ' + i; + Polymer.dom(dlg).appendChild(el); } - dlg.buttons.appendChild(makeButton('i am a button')); + Polymer.dom(dlg.buttons).appendChild(makeButton('i am a button')); addShowButtonForDialog.call(this, dlg); }); @@ -101,7 +101,7 @@ tr.b.unittest.testSuite(function() { var dlg = new tr.ui.b.Overlay(); dlg.title = 'Test closeclick event'; var closeBtn = makeCloseButton(dlg); - dlg.buttons.appendChild(closeBtn); + Polymer.dom(dlg.buttons).appendChild(closeBtn); var closeClicked = false; dlg.addEventListener('closeclick', function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html index 5edfd795219..36418c41473 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart.html @@ -4,10 +4,11 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> + <link rel="import" href="/tracing/base/range.html"> +<link rel="import" href="/tracing/ui/base/chart_base.html"> <link rel="import" href="/tracing/ui/base/d3.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> -<link rel="import" href="/tracing/ui/base/chart_base.html"> <link rel="stylesheet" href="/tracing/ui/base/pie_chart.css"> <script> @@ -15,7 +16,6 @@ found in the LICENSE file. tr.exportTo('tr.ui.b', function() { var ChartBase = tr.ui.b.ChartBase; - var getColorOfKey = tr.ui.b.getColorOfKey; var MIN_RADIUS = 100; @@ -29,10 +29,9 @@ tr.exportTo('tr.ui.b', function() { decorate: function() { ChartBase.prototype.decorate.call(this); - this.classList.add('pie-chart'); + Polymer.dom(this).classList.add('pie-chart'); this.data_ = undefined; - this.seriesKeys_ = undefined; var chartAreaSel = d3.select(this.chartAreaElement); var pieGroupSel = chartAreaSel.append('g') @@ -54,6 +53,9 @@ tr.exportTo('tr.ui.b', function() { return this.data_; }, + get titleMarginPx() { + return 40; + }, /** * @param {Array} data Data for the chart, where each element in the array @@ -64,30 +66,21 @@ tr.exportTo('tr.ui.b', function() { // Figure out the label values in the data set. E.g. from // [{label: 'a', ...}, {label: 'b', ...}] // we would commpute ['a', 'y']. These become the series keys. - var seriesKeys = []; + // Don't clear seriesByKey_; the caller might have put state in it using + // getDataSeries() before setting data. var seenSeriesKeys = {}; data.forEach(function(d) { var k = d.label; if (seenSeriesKeys[k]) throw new Error('Label ' + k + ' has been used already'); - seriesKeys.push(k); + this.getDataSeries(k); seenSeriesKeys[k] = true; }, this); - this.seriesKeys_ = seriesKeys; - } else { - this.seriesKeys_ = undefined; } this.data_ = data; this.updateContents_(); }, - get margin() { - var margin = {top: 0, right: 0, bottom: 0, left: 0}; - if (this.chartTitle_) - margin.top += 40; - return margin; - }, - getMinSize: function() { this.updateContents_(); @@ -98,14 +91,14 @@ tr.exportTo('tr.ui.b', function() { labelSel.each(function(l) { var r = this.getBoundingClientRect(); maxLabelWidth = Math.max(maxLabelWidth, r.width + 32); - if (this.style.textAnchor == 'end') { + if (this.style.textAnchor === 'end') { leftTextHeightSum += r.height; } else { rightTextHeightSum += r.height; } }); - var titleWidth = this.querySelector( + var titleWidth = Polymer.dom(this).querySelector( '#title').getBoundingClientRect().width; var margin = this.margin; var marginWidth = margin.left + margin.right; @@ -119,12 +112,6 @@ tr.exportTo('tr.ui.b', function() { }; }, - - getLegendKeys_: function() { - // This class creates its own legend, instead of using ChartBase. - return undefined; - }, - updateScales_: function(width, height) { if (this.data_ === undefined) return; @@ -178,9 +165,10 @@ tr.exportTo('tr.ui.b', function() { .attr('class', 'arc') .attr('fill', function(d, i) { var origData = this.data_[i]; - var highlighted = (origData.label === - this.currentHighlightedLegendKey); - return getColorOfKey(origData.label, highlighted); + var dataSeries = this.getDataSeries(origData.label); + if (origData.label === this.currentHighlightedLegendKey) + return dataSeries.highlightedColor; + return dataSeries.color; }.bind(this)) .attr('d', pathsArc) .on('click', function(d, i) { @@ -208,6 +196,14 @@ tr.exportTo('tr.ui.b', function() { }) .attr('dy', '.35em') .style('text-anchor', 'middle') + .on('mouseenter', function(d, i) { + var origData = this.data_[i]; + this.pushTempHighlightedLegendKey(origData.label); + }.bind(this)) + .on('mouseleave', function(d, i) { + var origData = this.data_[i]; + this.popTempHighlightedLegendKey(origData.label); + }.bind(this)) .text(function(d, i) { var origData = this.data_[i]; if (origData.valueText === undefined) @@ -263,9 +259,11 @@ tr.exportTo('tr.ui.b', function() { var that = this; pathsGroupSel.selectAll('.arc').each(function(d, i) { var origData = that.data_[i]; - var highlighted = origData.label == that.currentHighlightedLegendKey; - var color = getColorOfKey(origData.label, highlighted); - this.style.fill = color; + var dataSeries = that.getDataSeries(origData.label); + if (origData.label === that.currentHighlightedLegendKey) + this.style.fill = dataSeries.highlightedColor; + else + this.style.fill = dataSeries.color; }); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html index 7c0b35f5462..854c872055e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/pie_chart_test.html @@ -63,7 +63,7 @@ tr.b.unittest.testSuite(function() { didGetClick = true; }); - var arc0 = chart.querySelectorAll('.paths > path')[1]; + var arc0 = Polymer.dom(chart).querySelectorAll('.paths > path')[1]; tr.b.dispatchSimpleEvent(arc0, 'click'); assert.isTrue(didGetClick); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html new file mode 100644 index 00000000000..fc93631bb88 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_postload.html @@ -0,0 +1,13 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<script> +'use strict'; + +if (!Polymer.Settings.useNativeShadow) { + tr.b.showPanic('Polymer error', 'base only works in shadow mode'); +} +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html new file mode 100644 index 00000000000..8860b5befec --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_preload.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<script> +'use strict'; + +// Force Polymer into native shadowDom mode +if (window.Polymer) + throw new Error('Cannot proceed. Polymer already present.'); +window.Polymer = {}; +window.Polymer.dom = 'shadow'; +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html deleted file mode 100644 index b8c5e9d050d..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils.html +++ /dev/null @@ -1,64 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright (c) 2013 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> -<link rel="import" href="/tracing/base/base.html"> - -<script> -'use strict'; - -/** - * @fileoverview Helper code for working with Polymer. - */ -tr.exportTo('tr.ui.b', function() { - - function getPolymerElementNamed(tagName) { - for (var i = 0; i < Polymer.elements.length; i++) { - if (Polymer.elements[i].name === tagName) - return Polymer.elements[i]; - } - } - - function getPolymerElementsThatSubclass(tagName) { - if (Polymer.waitingFor().length) { - throw new Error('There are unresolved polymer elements. ' + - 'Wait until Polymer.whenReady'); - } - - var baseElement; - var elementNamesThatExtend = {}; - Polymer.elements.forEach(function(element) { - if (element.name === tagName) - baseElement = element; - - if (element.extends) { - if (elementNamesThatExtend[element.extends] === undefined) - elementNamesThatExtend[element.extends] = []; - elementNamesThatExtend[element.extends].push(element.name); - } - }); - - if (!baseElement) - throw new Error(tagName + ' is not a polymer element'); - - var allFoundSubElementNames = [baseElement.name]; - for (var i = 0; i < allFoundSubElementNames.length; i++) { - var elementName = allFoundSubElementNames[i]; - allFoundSubElementNames.push.apply( - allFoundSubElementNames, elementNamesThatExtend[elementName]); - } - - // Remove the base element tag name from the list. - allFoundSubElementNames.shift(); - - return allFoundSubElementNames; - } - - return { - getPolymerElementNamed: getPolymerElementNamed, - getPolymerElementsThatSubclass: getPolymerElementsThatSubclass - }; -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html deleted file mode 100644 index 698ec0cdc17..00000000000 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/polymer_utils_test.html +++ /dev/null @@ -1,73 +0,0 @@ -<!DOCTYPE html> -<!-- -Copyright 2016 The Chromium Authors. All rights reserved. -Use of this source code is governed by a BSD-style license that can be -found in the LICENSE file. ---> - -<link rel="import" href="/tracing/ui/base/polymer_utils.html"> - -<!-- -The Polymer elements defined in this file form the following class hierarchy: - - A (common superclass) - / \ - B C - / \ - D E - / \ - F G ---> - -<polymer-element name="polymer-utils-test-element-a" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-b" - extends="polymer-utils-test-element-a" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-c" - extends="polymer-utils-test-element-a" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-d" - extends="polymer-utils-test-element-c" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-e" - extends="polymer-utils-test-element-c" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-f" - extends="polymer-utils-test-element-d" noscript> -</polymer-element> - -<polymer-element name="polymer-utils-test-element-g" - extends="polymer-utils-test-element-d" noscript> -</polymer-element> - -<script> -'use strict'; - -tr.b.unittest.testSuite(function() { - test('getPolymerElementsThatSubclass', function() { - function checkSubclasses(classNameSuffix, subclassNameSuffixes) { - var className = 'polymer-utils-test-element-' + classNameSuffix; - var subclassNames = subclassNameSuffixes.map( - function(subclassNameSuffix) { - return 'polymer-utils-test-element-' + subclassNameSuffix; - }); - assert.sameMembers( - tr.ui.b.getPolymerElementsThatSubclass(className), subclassNames); - } - - checkSubclasses('a', ['b', 'c', 'd', 'e', 'f', 'g']); - checkSubclasses('b', []); - checkSubclasses('c', ['d', 'e', 'f', 'g']); - checkSubclasses('d', ['f', 'g']); - checkSubclasses('e', []); - checkSubclasses('f', []); - checkSubclasses('g', []); - }); -}); -</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html index 7c181a61857..bb43d8bbce7 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/quad_stack_view.html @@ -85,40 +85,40 @@ tr.exportTo('tr.ui.b', function() { // Care of bckenney@ via // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 function drawTexturedTriangle(ctx, img, p0, p1, p2, t0, t1, t2) { - var tmp_p0 = [p0[0], p0[1]]; - var tmp_p1 = [p1[0], p1[1]]; - var tmp_p2 = [p2[0], p2[1]]; - var tmp_t0 = [t0[0], t0[1]]; - var tmp_t1 = [t1[0], t1[1]]; - var tmp_t2 = [t2[0], t2[1]]; + var tmpP0 = [p0[0], p0[1]]; + var tmpP1 = [p1[0], p1[1]]; + var tmpP2 = [p2[0], p2[1]]; + var tmpT0 = [t0[0], t0[1]]; + var tmpT1 = [t1[0], t1[1]]; + var tmpT2 = [t2[0], t2[1]]; ctx.beginPath(); - ctx.moveTo(tmp_p0[0], tmp_p0[1]); - ctx.lineTo(tmp_p1[0], tmp_p1[1]); - ctx.lineTo(tmp_p2[0], tmp_p2[1]); + ctx.moveTo(tmpP0[0], tmpP0[1]); + ctx.lineTo(tmpP1[0], tmpP1[1]); + ctx.lineTo(tmpP2[0], tmpP2[1]); ctx.closePath(); - tmp_p1[0] -= tmp_p0[0]; - tmp_p1[1] -= tmp_p0[1]; - tmp_p2[0] -= tmp_p0[0]; - tmp_p2[1] -= tmp_p0[1]; + tmpP1[0] -= tmpP0[0]; + tmpP1[1] -= tmpP0[1]; + tmpP2[0] -= tmpP0[0]; + tmpP2[1] -= tmpP0[1]; - tmp_t1[0] -= tmp_t0[0]; - tmp_t1[1] -= tmp_t0[1]; - tmp_t2[0] -= tmp_t0[0]; - tmp_t2[1] -= tmp_t0[1]; + tmpT1[0] -= tmpT0[0]; + tmpT1[1] -= tmpT0[1]; + tmpT2[0] -= tmpT0[0]; + tmpT2[1] -= tmpT0[1]; - var det = 1 / (tmp_t1[0] * tmp_t2[1] - tmp_t2[0] * tmp_t1[1]), + var det = 1 / (tmpT1[0] * tmpT2[1] - tmpT2[0] * tmpT1[1]), // linear transformation - a = (tmp_t2[1] * tmp_p1[0] - tmp_t1[1] * tmp_p2[0]) * det, - b = (tmp_t2[1] * tmp_p1[1] - tmp_t1[1] * tmp_p2[1]) * det, - c = (tmp_t1[0] * tmp_p2[0] - tmp_t2[0] * tmp_p1[0]) * det, - d = (tmp_t1[0] * tmp_p2[1] - tmp_t2[0] * tmp_p1[1]) * det, + a = (tmpT2[1] * tmpP1[0] - tmpT1[1] * tmpP2[0]) * det, + b = (tmpT2[1] * tmpP1[1] - tmpT1[1] * tmpP2[1]) * det, + c = (tmpT1[0] * tmpP2[0] - tmpT2[0] * tmpP1[0]) * det, + d = (tmpT1[0] * tmpP2[1] - tmpT2[0] * tmpP1[1]) * det, // translation - e = tmp_p0[0] - a * tmp_t0[0] - c * tmp_t0[1], - f = tmp_p0[1] - b * tmp_t0[0] - d * tmp_t0[1]; + e = tmpP0[0] - a * tmpT0[0] - c * tmpT0[1], + f = tmpP0[1] - b * tmpT0[0] - d * tmpT0[1]; ctx.save(); ctx.transform(a, b, c, d, e, f); @@ -128,8 +128,8 @@ tr.exportTo('tr.ui.b', function() { } function drawTriangleSub( - ctx, img, p0, p1, p2, t0, t1, t2, opt_recursion_depth) { - var depth = opt_recursion_depth || 0; + ctx, img, p0, p1, p2, t0, t1, t2, opt_recursionDepth) { + var depth = opt_recursionDepth || 0; // We may subdivide if we are not at the limit of recursion. var subdivisionIndex = 0; @@ -232,16 +232,16 @@ tr.exportTo('tr.ui.b', function() { } // Created to avoid creating garbage when doing bulk transforms. - var tmp_vec4 = vec4.create(); + var tmpVec4 = vec4.create(); function transform(transformed, point, matrix, viewport) { - vec4.set(tmp_vec4, point[0], point[1], 0, 1); - vec4.transformMat4(tmp_vec4, tmp_vec4, matrix); + vec4.set(tmpVec4, point[0], point[1], 0, 1); + vec4.transformMat4(tmpVec4, tmpVec4, matrix); - var w = tmp_vec4[3]; + var w = tmpVec4[3]; if (w < 1e-6) w = 1e-6; - transformed[0] = ((tmp_vec4[0] / w) + 1) * viewport.width / 2; - transformed[1] = ((tmp_vec4[1] / w) + 1) * viewport.height / 2; + transformed[0] = ((tmpVec4[0] / w) + 1) * viewport.width / 2; + transformed[1] = ((tmpVec4[1] / w) + 1) * viewport.height / 2; transformed[2] = w; } @@ -341,22 +341,22 @@ tr.exportTo('tr.ui.b', function() { } } - var tmp_p1 = vec3.create(); - var tmp_p2 = vec3.create(); - var tmp_p3 = vec3.create(); - var tmp_p4 = vec3.create(); + var tmpP1 = vec3.create(); + var tmpP2 = vec3.create(); + var tmpP3 = vec3.create(); + var tmpP4 = vec3.create(); function transformAndProcessQuads( matrix, viewport, quads, numPasses, handleQuadFunc, opt_arg1, opt_arg2) { for (var passNumber = 0; passNumber < numPasses; passNumber++) { for (var i = 0; i < quads.length; i++) { var quad = quads[i]; - transform(tmp_p1, quad.p1, matrix, viewport); - transform(tmp_p2, quad.p2, matrix, viewport); - transform(tmp_p3, quad.p3, matrix, viewport); - transform(tmp_p4, quad.p4, matrix, viewport); + transform(tmpP1, quad.p1, matrix, viewport); + transform(tmpP2, quad.p2, matrix, viewport); + transform(tmpP3, quad.p3, matrix, viewport); + transform(tmpP4, quad.p4, matrix, viewport); handleQuadFunc(passNumber, quad, - tmp_p1, tmp_p2, tmp_p3, tmp_p4, + tmpP1, tmpP2, tmpP3, tmpP4, opt_arg1, opt_arg2); } } @@ -368,23 +368,23 @@ tr.exportTo('tr.ui.b', function() { var QuadStackView = tr.ui.b.define('quad-stack-view'); QuadStackView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.className = 'quad-stack-view'; var node = tr.ui.b.instantiateTemplate('#quad-stack-view-template', THIS_DOC); - this.appendChild(node); + Polymer.dom(this).appendChild(node); this.updateHeaderVisibility_(); - this.canvas_ = this.querySelector('#canvas'); + this.canvas_ = Polymer.dom(this).querySelector('#canvas'); this.chromeImages_ = { - left: this.querySelector('#chrome-left'), - mid: this.querySelector('#chrome-mid'), - right: this.querySelector('#chrome-right') + left: Polymer.dom(this).querySelector('#chrome-left'), + mid: Polymer.dom(this).querySelector('#chrome-mid'), + right: Polymer.dom(this).querySelector('#chrome-right') }; - var stackingDistanceSlider = this.querySelector( + var stackingDistanceSlider = Polymer.dom(this).querySelector( '#stacking-distance-slider'); stackingDistanceSlider.value = tr.b.Settings.get( 'quadStackView.stackingDistance', 45); @@ -408,17 +408,17 @@ tr.exportTo('tr.ui.b', function() { updateHeaderVisibility_: function() { if (this.headerText) - this.querySelector('#header').style.display = ''; + Polymer.dom(this).querySelector('#header').style.display = ''; else - this.querySelector('#header').style.display = 'none'; + Polymer.dom(this).querySelector('#header').style.display = 'none'; }, get headerText() { - return this.querySelector('#header').textContent; + return Polymer.dom(this).querySelector('#header').textContent; }, set headerText(headerText) { - this.querySelector('#header').textContent = headerText; + Polymer.dom(this).querySelector('#header').textContent = headerText; this.updateHeaderVisibility_(); }, @@ -430,7 +430,7 @@ tr.exportTo('tr.ui.b', function() { }, get stackingDistance() { - return this.querySelector('#stacking-distance-slider').value; + return Polymer.dom(this).querySelector('#stacking-distance-slider').value; }, get mouseModeSelector() { @@ -643,7 +643,7 @@ tr.exportTo('tr.ui.b', function() { tr.ui.b.MOUSE_SELECTOR_MODE.ROTATE; this.mouseModeSelector_.mode = tr.ui.b.MOUSE_SELECTOR_MODE.PANSCAN; this.mouseModeSelector_.pos = {x: 0, y: 100}; - this.appendChild(this.mouseModeSelector_); + Polymer.dom(this).appendChild(this.mouseModeSelector_); this.mouseModeSelector_.settingsKey = 'quadStackView.mouseModeSelector'; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html index 85d204a9a30..ceb82527cad 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker.html @@ -7,116 +7,137 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name='tr-ui-b-radio-picker'> +<dom-module id='tr-ui-b-radio-picker'> <template> <style> + :host([vertical]) #container { + flex-direction: column; + } + :host(:not[vertical]) #container { + flex-direction: row; + } #container { display: flex; - flex-direction: column; + } + #container > div { + padding-left: 1em; + padding-bottom: 0.5em; } </style> + <div id="container"></div> + </template> +</dom-module> +<script> +'use strict'; - <div id="container"> - </div> +Polymer({ + is: 'tr-ui-b-radio-picker', - </template> + created: function() { + this.needsInit_ = true; + this.settingsKey_ = undefined; + this.isReady_ = false; + this.radioButtons_ = undefined; + // Keeping track of which key is selected. This member should only be set + // set inside select() method to make sure that logical state & the UI + // state is consistent. + this.selectedKey_ = undefined; + }, + + ready: function() { + this.isReady_ = true; + this.maybeInit_(); + this.maybeRenderRadioButtons_(); + }, + + get vertical() { + return this.getAttribute('vertical'); + }, - <script> - 'use strict'; - - Polymer({ - created: function() { - this.needsInit_ = true; - this.settingsKey_ = undefined; - this.is_ready_ = false; - this.radio_buttons_ = undefined; - // Keeping track of which key is selected. This member should only be set - // set inside select() method to make sure that logical state & the UI - // state is consistent. - this.selectedKey_ = undefined; - }, - - ready: function() { - this.is_ready_ = true; - this.maybeInit_(); - this.maybeRenderRadioButtons_(); - }, - - get settingsKey() { - return this.settingsKey_; - }, - - set settingsKey(settingsKey) { - if (!this.needsInit_) - throw new Error('Already initialized.'); - this.settingsKey_ = settingsKey; - this.maybeInit_(); - }, - - maybeInit_: function() { - if (!this.needsInit_) - return; - if (this.settingsKey_ === undefined) - return; - this.needsInit_ = false; - this.select(tr.b.Settings.get(this.settingsKey_)); - }, - - set items(items) { - this.radio_buttons_ = {}; - items.forEach(function(e) { - if (e.key in this.radio_buttons_) - throw new Error(e.key + ' already exists'); - var radio_button = document.createElement('div'); - var input = document.createElement('input'); - var label = document.createElement('div'); - input.type = 'radio'; - input.addEventListener('click', function() { - this.select(e.key); - }.bind(this)); - label.innerHTML = e.label; - label.style.display = 'inline'; - radio_button.appendChild(input); - radio_button.appendChild(label); - this.radio_buttons_[e.key] = input; + set vertical(vertical) { + if (vertical) + this.setAttribute('vertical', true); + else + this.removeAttribute('vertical'); + }, + + get settingsKey() { + return this.settingsKey_; + }, + + set settingsKey(settingsKey) { + if (!this.needsInit_) + throw new Error('Already initialized.'); + this.settingsKey_ = settingsKey; + this.maybeInit_(); + }, + + maybeInit_: function() { + if (!this.needsInit_) + return; + if (this.settingsKey_ === undefined) + return; + this.needsInit_ = false; + this.select(tr.b.Settings.get(this.settingsKey_)); + }, + + set items(items) { + this.radioButtons_ = {}; + items.forEach(function(e) { + if (e.key in this.radioButtons_) + throw new Error(e.key + ' already exists'); + var radioButton = document.createElement('div'); + var input = document.createElement('input'); + var label = document.createElement('div'); + input.type = 'radio'; + input.addEventListener('click', function() { + this.select(e.key); }.bind(this)); + Polymer.dom(label).innerHTML = e.label; + label.style.display = 'inline'; + Polymer.dom(radioButton).appendChild(input); + Polymer.dom(radioButton).appendChild(label); + this.radioButtons_[e.key] = input; + }.bind(this)); + + this.maybeInit_(); + this.maybeRenderRadioButtons_(); + }, - this.maybeInit_(); - this.maybeRenderRadioButtons_(); - }, - - maybeRenderRadioButtons_: function() { - if (!this.is_ready_) - return; - if (this.radio_buttons_ === undefined) - return; - for (var key in this.radio_buttons_) - this.$.container.appendChild(this.radio_buttons_[key].parentElement); - if (this.selectedKey_ !== undefined) - this.select(this.selectedKey_); - }, - - select: function(key) { - if (key === undefined) - return; - if (this.radio_buttons_ == undefined) { - this.selectedKey_ = key; - return; - } - if (!(key in this.radio_buttons_)) - throw new Error(key + ' does not exists'); - // Unselect the previous radio, update the key & select the new one. - if (this.selectedKey_ !== undefined) - this.radio_buttons_[this.selectedKey_].checked = false; + maybeRenderRadioButtons_: function() { + if (!this.isReady_) + return; + if (this.radioButtons_ === undefined) + return; + for (var key in this.radioButtons_) + Polymer.dom(this.$.container).appendChild( + this.radioButtons_[key].parentElement); + if (this.selectedKey_ !== undefined) + this.select(this.selectedKey_); + }, + + select: function(key) { + if (key === undefined || key === this.selectedKey_) + return; + if (this.radioButtons_ === undefined) { this.selectedKey_ = key; - tr.b.Settings.set(this.settingsKey_, this.selectedKey_); - if (this.selectedKey_ !== undefined) - this.radio_buttons_[this.selectedKey_].checked = true; - }, - - get selectedKey() { - return this.selectedKey_; - }, - }); - </script> -</polymer-element> + return; + } + if (!(key in this.radioButtons_)) + throw new Error(key + ' does not exists'); + // Unselect the previous radio, update the key & select the new one. + if (this.selectedKey_ !== undefined) + this.radioButtons_[this.selectedKey_].checked = false; + this.selectedKey_ = key; + tr.b.Settings.set(this.settingsKey_, this.selectedKey_); + if (this.selectedKey_ !== undefined) + this.radioButtons_[this.selectedKey_].checked = true; + + this.dispatchEvent(new tr.b.Event('change', false)); + }, + + get selectedKey() { + return this.selectedKey_; + }, +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html index dea60cdd492..8d29c269796 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/radio_picker_test.html @@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/radio_picker.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/radio_picker.html"> <script> 'use strict'; @@ -36,7 +36,7 @@ tr.b.unittest.testSuite(function() { var rp = document.createElement('tr-ui-b-radio-picker'); rp.items = items; rp.settingsKey = 'radio-picker-test-one'; - container1.appendChild(rp); + Polymer.dom(container1).appendChild(rp); this.addHTMLOutput(container1); assert.equal(rp.selectedKey, undefined); rp.select('Toyota'); @@ -48,7 +48,7 @@ tr.b.unittest.testSuite(function() { var rp2 = document.createElement('tr-ui-b-radio-picker'); rp2.items = items; rp2.settingsKey = 'radio-picker-test-one'; - container2.appendChild(rp2); + Polymer.dom(container2).appendChild(rp2); this.addHTMLOutput(container2); assert.equal(rp2.selectedKey, 'Toyota'); @@ -65,7 +65,7 @@ tr.b.unittest.testSuite(function() { var rp = document.createElement('tr-ui-b-radio-picker'); rp.settingsKey = 'radio-picker-test-two'; rp.items = items; - container1.appendChild(rp); + Polymer.dom(container1).appendChild(rp); this.addHTMLOutput(container1); assert.equal(rp.selectedKey, undefined); rp.select('Boeing'); @@ -76,14 +76,47 @@ tr.b.unittest.testSuite(function() { container2.style.border = 'solid'; var rp2 = document.createElement('tr-ui-b-radio-picker'); rp2.settingsKey = 'radio-picker-test-two'; - container2.appendChild(rp2); + Polymer.dom(container2).appendChild(rp2); this.addHTMLOutput(container2); rp2.items = items; assert.equal(rp2.selectedKey, 'Boeing'); }); + test('changeEventFired', function() { + var items = [ + {key: 'Toyota', label: 'I want to drive Toyota'}, + {key: 'Boeing', label: 'I want to fly'}, + {key: 'Submarine', label: 'I want to swim'} + ]; + var rp = document.createElement('tr-ui-b-radio-picker'); + rp.items = items; + this.addHTMLOutput(rp); + rp.select('Boeing'); + assert.equal(rp.selectedKey, 'Boeing'); + var fired = false; + rp.addEventListener('change', function(e) { + fired = true; + assert.equal('Toyota', e.target.selectedKey); + }); + rp.select('Toyota'); + assert.isTrue(fired); + }); - + test('verticalAttribute', function() { + var items = [ + {key: 'Toyota', label: 'I want to drive Toyota'}, + {key: 'Boeing', label: 'I want to fly'}, + {key: 'Submarine', label: 'I want to swim'} + ]; + var rp = document.createElement('tr-ui-b-radio-picker'); + rp.items = items; + this.addHTMLOutput(rp); + assert.isNull(rp.getAttribute('vertical')); + rp.vertical = true; + assert.equal(rp.getAttribute('vertical'), 'true'); + rp.vertical = false; + assert.isNull(rp.getAttribute('vertical')); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html index bbb696062bf..6eb63b79bc1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor.html @@ -12,7 +12,7 @@ found in the LICENSE file. <!-- @fileoverview A container that senses when its size changes. --> -<polymer-element name="tr-ui-b-resize-sensor"> +<dom-module id='tr-ui-b-resize-sensor'> <template> <style> :host { @@ -24,27 +24,28 @@ found in the LICENSE file. <content></content> </div> </template> +</dom-module> +<script> +'use strict'; +(function() { + Polymer({ + is: 'tr-ui-b-resize-sensor', - <script> - 'use strict'; - (function() { - Polymer({ - attached: function() { - // ResizeSensor only works if it's rooted in a document when it's - // created, so wait until the tr-ui-b-resize-sensor is attached to the - // DOM before creating the ResizeSensor. - this.sensor_ = new ResizeSensor(this.$.container, - this.onResize_.bind(this)); - // ResizeSensor appends a div to this.$.container. That div must be a - // direct sibling of <content>. - // ResizeSensor's first argument must be a Node, so it cannot be - // this.shadowRoot. - }, + attached: function() { + // ResizeSensor only works if it's rooted in a document when it's + // created, so wait until the tr-ui-b-resize-sensor is attached to the + // DOM before creating the ResizeSensor. + this.sensor_ = new ResizeSensor(this.$.container, + this.onResize_.bind(this)); + // ResizeSensor appends a div to this.$.container. That div must be a + // direct sibling of <content>. + // ResizeSensor's first argument must be a Node, so it cannot be + // this.root. + }, - onResize_: function() { - this.dispatchEvent(new tr.b.Event('resize', false, false)); - } - }); - })(); - </script> -</polymer-element> + onResize_: function() { + this.dispatchEvent(new tr.b.Event('resize', false, false)); + } + }); +})(); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html index fea1f71669b..aa4132bf54e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/resize_sensor_test.html @@ -18,7 +18,7 @@ tr.b.unittest.testSuite(function() { test('instantiate', function() { var sensor = document.createElement('tr-ui-b-resize-sensor'); - sensor.appendChild(document.createTextNode('hello')); + Polymer.dom(sensor).appendChild(document.createTextNode('hello')); var resizeCount = 0; function onResize(event) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html b/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html index 5dffbe8da02..4996f69684b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/scatter_chart.html @@ -31,7 +31,7 @@ tr.exportTo('tr.ui.b', function() { decorate: function() { ChartBase2D.prototype.decorate.call(this); - this.classList.add('scatter-chart'); + Polymer.dom(this).classList.add('scatter-chart'); this.brushedXRange_ = new tr.b.Range(); this.brushedYRange_ = new tr.b.Range(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html index c8ecceb51cd..0818c83f91f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view.html @@ -5,424 +5,265 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<polymer-element name="tr-ui-a-tab-view" - constructor="TracingAnalysisTabView"> +<link rel="import" href="/tracing/base/base.html"> + +<!-- +@fileoverview A view that allows the user to control which single tab is +displayed. + +We follow a fairly standard web convention of backing our tabs with hidden radio +buttons but visible radio button labels (the tabs themselves) which toggle the +input element when clicked. Using hidden radio buttons makes sense, as both tabs +and radio buttons are input elements that allow user selection through clicking +and limit users to having one option selected at a time. +--> +<dom-module id='tr-ui-b-tab-view'> <template> <style> :host { display: flex; - flex-flow: column nowrap; - overflow: hidden; - box-sizing: border-box; + flex-direction: column; } - tab-strip[tabs-hidden] { - display: none; + #selection_description, #tabs { + font-size: 12px; } - tab-strip { - background-color: rgb(236, 236, 236); - border-bottom: 1px solid #8e8e8e; - display: flex; - flex: 0 0 auto; - flex-flow: row; - overflow-x: auto; - padding: 0 10px 0 10px; - font-size: 12px; + #selection_description { + display: inline-block; + font-weight: bold; + margin: 9px 0px 4px 20px; } - tab-button { - display: block; + #tabs { flex: 0 0 auto; - padding: 4px 15px 1px 15px; - margin-top: 2px; + border-top: 1px solid #8e8e8e; + border-bottom: 1px solid #8e8e8e; + background-color: #ececec; + overflow: hidden; + margin: 0; } - tab-button[selected=true] { - background-color: white; - border: 1px solid rgb(163, 163, 163); - border-bottom: none; - padding: 3px 14px 1px 14px; + #tabs input[type=radio] { + display: none; } - tabs-content-container { - display: flex; - flex: 1 1 auto; - overflow: auto; - width: 100%; + #tabs tab label { + cursor: pointer; + display: inline-block; + border: 1px solid #ececec; + margin: 5px 0px 0px 15px; + padding: 3px 10px 3px 10px; } - ::content > * { - flex: 1 1 auto; + #tabs tab label span { + font-weight: bold; } - ::content > *:not([selected]) { - display: none; + #tabs:focus input[type=radio]:checked ~ label { + outline: dotted 1px #8e8e8e; + outline-offset: -2px; } - button-label { - display: inline; + #tabs input[type=radio]:checked ~ label { + background-color: white; + border: 1px solid #8e8e8e; + border-bottom: 1px solid white; } - tab-strip-heading { - display: block; - flex: 0 0 auto; - padding: 4px 15px 1px 15px; - margin-top: 2px; - margin-before: 20px; - margin-after: 10px; - } - #tsh { - display: inline; - font-weight: bold; + #subView { + flex: 1 1 auto; + overflow: auto; } </style> - - <tab-strip> - <tab-strip-heading id="tshh"> - <span id="tsh"></span> - </tab-strip-heading> - <template repeat="{{tab in tabs_}}"> - <tab-button - button-id="{{ tab.id }}" - on-click="{{ tabButtonSelectHandler_ }}" - selected="{{ selectedTab_.id === tab.id }}"> - <button-label>{{ tab.label ? tab.label : 'No Label'}}</button-label> - </tab-button> + <div id='tabs' hidden="[[tabsHidden]]"> + <label id=selection_description>[[label_]]</label> + <template is=dom-repeat items=[[subViews_]]> + <tab> + <input type=radio name=tabs id$=[[computeRadioId_(item)]] + on-change='onTabChanged_' + checked$='[[isChecked_(item)]]' /> + <label for$=[[computeRadioId_(item)]]> + <template is=dom-if if=[[item.tabIcon]]> + <span style$='[[item.tabIcon.style]]'>[[item.tabIcon.text]]</span> + </template> + [[item.tabLabel]] + </label> + </tab> </template> - </tab-strip> - - <tabs-content-container id='content-container'> - <content></content> - </tabs-content-container> - + </div> + <div id='subView'></div> + <content> + </content> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; - Polymer({ - ready: function() { - this.$.tshh.style.display = 'none'; - - // A tab is represented by the following tuple: - // (id, label, content, observer, savedScrollTop, savedScrollLeft). - // The properties are used in the following way: - // id: Uniquely identifies a tab. It is the same number as the index - // in the tabs array. Used primarily by the on-click event attached - // to buttons. - // label: A string, representing the label printed on the tab button. - // content: The light-dom child representing the contents of the tab. - // The content is appended to this tab-view by the user. - // observers: The observers attached to the content node to watch for - // attribute changes. The attributes of interest are: 'selected', - // and 'tab-label'. - // savedScrollTop/Left: Used to return the scroll position upon switching - // tabs. The values are generally saved when a tab switch occurs. - // - // The order of the tabs is relevant for the tab ordering. - this.tabs_ = []; - this.selectedTab_ = undefined; - - // Register any already existing children. - for (var i = 0; i < this.children.length; i++) - this.processAddedChild_(this.children[i]); - - // In case the user decides to add more tabs, make sure we watch for - // any child mutations. - this.childrenObserver_ = new MutationObserver( - this.childrenUpdated_.bind(this)); - this.childrenObserver_.observe(this, { childList: 'true' }); - }, - - get tabStripHeadingText() { - return this.$.tsh.textContent; - }, - - set tabStripHeadingText(tabStripHeadingText) { - this.$.tsh.textContent = tabStripHeadingText; - if (!!tabStripHeadingText) - this.$.tshh.style.display = ''; - else - this.$.tshh.style.display = 'none'; - }, - - get selectedTab() { - // Make sure we process any pending children additions / removals, before - // trying to select a tab. Otherwise, we might not find some children. - this.childrenUpdated_( - this.childrenObserver_.takeRecords(), this.childrenObserver_); - - // Do not give access to the user to the inner data structure. - // A user should only be able to mutate the added tab content. - if (this.selectedTab_) - return this.selectedTab_.content; - return undefined; - }, - - set selectedTab(content) { - // Make sure we process any pending children additions / removals, before - // trying to select a tab. Otherwise, we might not find some children. - this.childrenUpdated_( - this.childrenObserver_.takeRecords(), this.childrenObserver_); - - if (content === undefined || content === null) { - this.changeSelectedTabById_(undefined); - return; - } - - // Search for the specific node in our tabs list. - // If it is not there print a warning. - var contentTabId = undefined; - for (var i = 0; i < this.tabs_.length; i++) - if (this.tabs_[i].content === content) { - contentTabId = this.tabs_[i].id; - break; - } +Polymer({ + is: 'tr-ui-b-tab-view', - if (contentTabId === undefined) - return; - - this.changeSelectedTabById_(contentTabId); - }, - - get tabsHidden() { - var ts = this.shadowRoot.querySelector('tab-strip'); - return ts.hasAttribute('tabs-hidden'); + properties: { + label_: { + type: String, + value: () => '' }, - - set tabsHidden(tabsHidden) { - tabsHidden = !!tabsHidden; - var ts = this.shadowRoot.querySelector('tab-strip'); - if (tabsHidden) - ts.setAttribute('tabs-hidden', true); - else - ts.removeAttribute('tabs-hidden'); - }, - - get tabs() { - return this.tabs_.map(function(tabObject) { - return tabObject.content; - }); - }, - - /** - * Function called on light-dom child addition. - */ - processAddedChild_: function(child) { - var observerAttributeSelected = new MutationObserver( - this.childAttributesChanged_.bind(this)); - var observerAttributeTabLabel = new MutationObserver( - this.childAttributesChanged_.bind(this)); - var tabObject = { - id: this.tabs_.length, - content: child, - label: child.getAttribute('tab-label'), - observers: { - forAttributeSelected: observerAttributeSelected, - forAttributeTabLabel: observerAttributeTabLabel - } - }; - - this.tabs_.push(tabObject); - if (child.hasAttribute('selected')) { - // When receiving a child with the selected attribute, if we have no - // selected tab, mark the child as the selected tab, otherwise keep - // the previous selection. - if (this.selectedTab_) - child.removeAttribute('selected'); - else - this.setSelectedTabById_(tabObject.id); - } - - // This is required because the user might have set the selected - // property before we got to process the child. - var previousSelected = child.selected; - - var tabView = this; - - Object.defineProperty( - child, - 'selected', { - configurable: true, - set: function(value) { - if (value) { - tabView.changeSelectedTabById_(tabObject.id); - return; - } - - var wasSelected = tabView.selectedTab_ === tabObject; - if (wasSelected) - tabView.changeSelectedTabById_(undefined); - }, - get: function() { - return this.hasAttribute('selected'); - } - }); - - if (previousSelected) - child.selected = previousSelected; - - observerAttributeSelected.observe(child, - { attributeFilter: ['selected'] }); - observerAttributeTabLabel.observe(child, - { attributeFilter: ['tab-label'] }); - + selectedSubView_: Object, + subViews_: { + type: Array, + value: () => [] }, - - /** - * Function called on light-dom child removal. - */ - processRemovedChild_: function(child) { - for (var i = 0; i < this.tabs_.length; i++) { - // Make sure ids are the same as the tab position after removal. - this.tabs_[i].id = i; - if (this.tabs_[i].content === child) { - this.tabs_[i].observers.forAttributeSelected.disconnect(); - this.tabs_[i].observers.forAttributeTabLabel.disconnect(); - // The user has removed the currently selected tab. - if (this.tabs_[i] === this.selectedTab_) { - this.clearSelectedTab_(); - this.fire('selected-tab-change'); - } - child.removeAttribute('selected'); - delete child.selected; - // Remove the observer since we no longer care about this child. - this.tabs_.splice(i, 1); - i--; - } - } - }, - - - /** - * This function handles child attribute changes. The only relevant - * attributes for the tab-view are 'tab-label' and 'selected'. - */ - childAttributesChanged_: function(mutations, observer) { - var tabObject = undefined; - // First figure out which child has been changed. - for (var i = 0; i < this.tabs_.length; i++) { - var observers = this.tabs_[i].observers; - if (observers.forAttributeSelected === observer || - observers.forAttributeTabLabel === observer) { - tabObject = this.tabs_[i]; - break; - } - } - - // This should not happen, unless the user has messed with our internal - // data structure. - if (!tabObject) - return; - - // Next handle the attribute changes. - for (var i = 0; i < mutations.length; i++) { - var node = tabObject.content; - // 'tab-label' attribute has been changed. - if (mutations[i].attributeName === 'tab-label') - tabObject.label = node.getAttribute('tab-label'); - // 'selected' attribute has been changed. - if (mutations[i].attributeName === 'selected') { - // The attribute has been set. - var nodeIsSelected = node.hasAttribute('selected'); - if (nodeIsSelected) - this.changeSelectedTabById_(tabObject.id); - else - this.changeSelectedTabById_(undefined); - } - } - }, - - /** - * This function handles light-dom additions and removals from the - * tab-view component. - */ - childrenUpdated_: function(mutations, observer) { - mutations.forEach(function(mutation) { - for (var i = 0; i < mutation.removedNodes.length; i++) - this.processRemovedChild_(mutation.removedNodes[i]); - for (var i = 0; i < mutation.addedNodes.length; i++) - this.processAddedChild_(mutation.addedNodes[i]); - }, this); - }, - - /** - * Handler called when a click event happens on any of the tab buttons. - */ - tabButtonSelectHandler_: function(event, detail, sender) { - this.changeSelectedTabById_(sender.getAttribute('button-id')); - }, - - /** - * This does the actual work. :) - */ - changeSelectedTabById_: function(id) { - var newTab = id !== undefined ? this.tabs_[id] : undefined; - var changed = this.selectedTab_ !== newTab; - this.saveCurrentTabScrollPosition_(); - this.clearSelectedTab_(); - if (id !== undefined) { - this.setSelectedTabById_(id); - this.restoreCurrentTabScrollPosition_(); + tabsHidden: { + type: Boolean, + value: false, + observer: 'tabsHiddenChanged_' + } + }, + + ready: function() { + this.$.tabs.addEventListener('keydown', this.onKeyDown_.bind(this), true); + this.updateFocusability_(); + }, + + set label(newLabel) { + this.set('label_', newLabel); + }, + + get tabs() { + return this.get('subViews_'); + }, + + get selectedSubView() { + return this.selectedSubView_; + }, + + set selectedSubView(subView) { + if (subView === this.selectedSubView_) + return; + + if (this.selectedSubView_) { + Polymer.dom(this.$.subView).removeChild(this.selectedSubView_); + var oldInput = this.root.getElementById(this.computeRadioId_( + this.selectedSubView_)); + if (oldInput) { + oldInput.checked = false; } + } - if (changed) - this.fire('selected-tab-change'); - }, - - /** - * This function updates the currently selected tab based on its internal - * id. The corresponding light-dom element receives the selected attribute. - */ - setSelectedTabById_: function(id) { - this.selectedTab_ = this.tabs_[id]; - // Disconnect observer while we mutate the child. - this.selectedTab_.observers.forAttributeSelected.disconnect(); - this.selectedTab_.content.setAttribute('selected', 'selected'); - // Reconnect the observer to watch for changes in the future. - this.selectedTab_.observers.forAttributeSelected.observe( - this.selectedTab_.content, { attributeFilter: ['selected'] }); - - }, - - saveTabStates: function() { - // Scroll positions of unselected tabs have already been saved. - this.saveCurrentTabScrollPosition_(); - }, + this.set('selectedSubView_', subView); - saveCurrentTabScrollPosition_: function() { - if (this.selectedTab_) { - this.selectedTab_.content._savedScrollTop = - this.$['content-container'].scrollTop; - this.selectedTab_.content._savedScrollLeft = - this.$['content-container'].scrollLeft; + if (subView) { + Polymer.dom(this.$.subView).appendChild(subView); + var newInput = this.root.getElementById(this.computeRadioId_(subView)); + if (newInput) { + newInput.checked = true; } - }, + } - restoreCurrentTabScrollPosition_: function() { - if (this.selectedTab_) { - this.$['content-container'].scrollTop = - this.selectedTab_.content._savedScrollTop || 0; - this.$['content-container'].scrollLeft = - this.selectedTab_.content._savedScrollLeft || 0; - } - }, + this.fire('selected-tab-change'); + }, + + clearSubViews: function() { + this.splice('subViews_', 0, this.subViews_.length); + this.selectedSubView = undefined; + this.updateFocusability_(); + }, + + addSubView: function(subView) { + this.push('subViews_', subView); + if (!this.selectedSubView_) + this.selectedSubView = subView; + + this.updateFocusability_(); + }, + + resetSubViews: function(subViews) { + this.splice('subViews_', 0, this.subViews_.length); + if (subViews.length) { + for (var subView of subViews) + this.push('subViews_', subView); + this.selectedSubView = subViews[0]; + } + else { + this.selectedSubView = undefined; + } + this.updateFocusability_(); + }, + + onTabChanged_: function(event) { + this.selectedSubView = event.model.item; + }, + + isChecked_: function(subView) { + return this.selectedSubView_ === subView; + }, + + tabsHiddenChanged_: function() { + this.updateFocusability_(); + }, + + onKeyDown_: function(e) { + if (this.tabsHidden) + return; + + var keyHandled = false; + switch (e.keyCode) { + // Arrow left. + case 37: + keyHandled = this.selectPreviousTabIfPossible(); + break; + + // Arrow right. + case 39: + keyHandled = this.selectNextTabIfPossible(); + break; + } - /** - * This function clears the currently selected tab. This handles removal - * of the selected attribute from the light-dom element. - */ - clearSelectedTab_: function() { - if (this.selectedTab_) { - // Disconnect observer while we mutate the child. - this.selectedTab_.observers.forAttributeSelected.disconnect(); - this.selectedTab_.content.removeAttribute('selected'); - // Reconnect the observer to watch for changes in the future. - this.selectedTab_.observers.forAttributeSelected.observe( - this.selectedTab_.content, { attributeFilter: ['selected'] }); - this.selectedTab_ = undefined; - } + if (!keyHandled) + return; + e.stopPropagation(); + e.preventDefault(); + }, + + selectNextTabIfPossible: function() { + return this.selectTabByOffsetIfPossible_(1); + }, + + selectPreviousTabIfPossible: function() { + return this.selectTabByOffsetIfPossible_(-1); + }, + + selectTabByOffsetIfPossible_: function(offset) { + if (!this.selectedSubView_) + return false; + var currentIndex = this.subViews_.indexOf(this.selectedSubView_); + var newSubView = this.tabs[currentIndex + offset]; + if (!newSubView) + return false; + this.selectedSubView = newSubView; + return true; + }, + + shouldBeFocusable_: function() { + return !this.tabsHidden && this.subViews_.length > 0; + }, + + updateFocusability_: function() { + if (this.shouldBeFocusable_()) { + Polymer.dom(this.$.tabs).setAttribute('tabindex', 0); + } else { + Polymer.dom(this.$.tabs).removeAttribute('tabindex'); } - }); - </script> -</polymer-element> + }, + + computeRadioId_: function(subView) { + // We can't just use the tagName as the radio's ID because there are + // instances where a single subview type can handle multiple event types, + // and thus might be present multiple times in a single tab view. In order + // to avoid the case where we might have two tabs with the same ID, we + // uniquify this ID by appending the tab's label with all spaces replaced + // by dashes (because spaces aren't allowed in HTML IDs). + return subView.tagName + '-' + subView.tabLabel.replace(/ /g, '-'); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html index 42f16e594ae..a7be3802cb8 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/tab_view_test.html @@ -5,319 +5,122 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/core/test_utils.html"> +<link rel="import" href="/tracing/model/event_set.html"> +<link rel="import" href="/tracing/model/model.html"> +<link rel="import" href="/tracing/model/power_series.html"> +<link rel="import" href="/tracing/ui/analysis/alert_sub_view.html"> +<link rel="import" href="/tracing/ui/analysis/multi_power_sample_sub_view.html"> <link rel="import" href="/tracing/ui/base/tab_view.html"> -<template id="tab-view-test-template"> - <tr-ui-a-tab-view> - <p tab-label="Existing Label"> Tab with label already set </p> - <p> Tab Content with no label </p> - <p selected="selected" tab-label="Should be selected"> - Already selected tab - </p> - <p selected="selected" tab-label="Should not be selected"> - Second already selected tab - </p> - </tr-ui-a-tab-view> -</template> +<dom-module id='tr-ui-b-tab-view-test-non-sub-view'> + <template> + <div></div> + </template> +</dom-module> <script> 'use strict'; -tr.b.unittest.testSuite(function() { - var THIS_DOC = document._currentScript.ownerDocument; - - test('instantiate', function() { - - var TAB_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' + - ' Cras eleifend elit nec erat tristique pellentesque. Cras placerat ' + - 'lectus, sed semper tortor ornare quis. Maecenas vitae hendrerit. ' + - 'Cras mattis interdum nisi, eget egestas dui iaculis ultricies. Proi' + - 'n magna at nibh fringilla tincidunt id vitae ante. Fusce nec urna n' + - 'on porttitor tincidunt. Pellentesque habitant morbi tristique senec' + - 'tus netus et malesuada fames ac turpis egestas. Suspendisse sed vel' + - 'it mollis ornare sit amet vel augue. Nullam rhoncus in tellus id. ' + - 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices ' + - 'cubilia Curae; Nunc at velit consectetur ipsum tempus tempus. Nunc ' + - 'mattis sapien, a placerat erat. Vivamus ac enim ultricies, gravida ' + - 'nulla ut, scelerisque magna. Sed a volutpat enim. Morbi vulputate, ' + - 'sed egestas mollis, urna nisl varius sem, sed venenatis turpis null' + - 'a ipsum. Suspendisse potenti.'; - - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '500px'; - tabViewContainer.style.height = '200px'; - - var tabView = new TracingAnalysisTabView(); - - var firstTab = document.createElement('div'); - firstTab.setAttribute('tab-label', 'First Tab Label'); - firstTab.innerHTML = '<p>' + TAB_TEXT + '<p>'; - - var secondTab = document.createElement('div'); - secondTab.setAttribute('tab-label', 'Second Tab Label'); - secondTab.innerHTML = '<b>' + 'Second Tab Text' + '</b>'; - - var thirdTab = document.createElement('div'); - thirdTab.setAttribute('tab-label', 'Third Tab Label'); - thirdTab.innerHTML = '<b>' + 'Third Tab Text' + '</b>'; +var nonSubViewBehavior = {}; - tabView.appendChild(firstTab); - tabView.appendChild(secondTab); - tabView.appendChild(thirdTab); - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); - - thirdTab.setAttribute('tab-label', 'Something Different'); - - var button = document.createElement('button'); - button.textContent = 'Change label'; +Polymer({ + is: 'tr-ui-b-tab-view-test-non-sub-view', + behaviors: [nonSubViewBehavior] +}); - button.addEventListener('click', function() { - thirdTab.setAttribute('tab-label', 'Label Changed'); +tr.b.unittest.testSuite(function() { + function createPowerSampleSubView() { + var model = tr.c.TestUtils.newModel(function(m) { + m.device.powerSeries = new tr.model.PowerSeries(m.device); + + m.device.vSyncTimestamps = [0]; + m.device.powerSeries.addPowerSample(1, 1); + m.device.powerSeries.addPowerSample(2, 2); + m.device.powerSeries.addPowerSample(3, 3); + m.device.powerSeries.addPowerSample(4, 2); }); - tabView.selectedTab = secondTab; - this.addHTMLOutput(button); + var subView = document.createElement('tr-ui-a-multi-power-sample-sub-view'); + subView.selection = new tr.model.EventSet(model.device.powerSeries.samples); + subView.tabLabel = 'Power samples'; + return subView; + } + + function createAlertSubView() { + var slice = tr.c.TestUtils.newSliceEx( + {title: 'b', start: 0, duration: 0.002}); + var alertInfo = new tr.model.EventInfo( + 'Alert 1', 'Critical alert', + [{ + label: 'Example', + textContent: 'Example page', + href: 'http://www.example.com' + }]); + + var alert = new tr.model.Alert(alertInfo, 5, [slice]); + var subView = document.createElement('tr-ui-a-alert-sub-view'); + subView.selection = new tr.model.EventSet(alert); + subView.tabLabel = 'Alerts'; + subView.tabIcon = { text: '\u26A0', style: 'color: red;' }; + + return subView; + } + + test('instantiate_noTabs', function() { + var tabView = document.createElement('tr-ui-b-tab-view'); + tabView.label = 'No items selected.'; + this.addHTMLOutput(tabView); }); - - test('instantiateWithTabHeading', function() { - var TAB_TEXT = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.' + - ' Cras eleifend elit nec erat tristique pellentesque. Cras placerat ' + - 'lectus, sed semper tortor ornare quis. Maecenas vitae hendrerit. ' + - 'Cras mattis interdum nisi, eget egestas dui iaculis ultricies. Proi' + - 'n magna at nibh fringilla tincidunt id vitae ante. Fusce nec urna n' + - 'on porttitor tincidunt. Pellentesque habitant morbi tristique senec' + - 'tus netus et malesuada fames ac turpis egestas. Suspendisse sed vel' + - 'it mollis ornare sit amet vel augue. Nullam rhoncus in tellus id. ' + - 'Vestibulum ante ipsum primis in faucibus orci luctus et ultrices ' + - 'cubilia Curae; Nunc at velit consectetur ipsum tempus tempus. Nunc ' + - 'mattis sapien, a placerat erat. Vivamus ac enim ultricies, gravida ' + - 'nulla ut, scelerisque magna. Sed a volutpat enim. Morbi vulputate, ' + - 'sed egestas mollis, urna nisl varius sem, sed venenatis turpis null' + - 'a ipsum. Suspendisse potenti.'; - - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '500px'; - tabViewContainer.style.height = '200px'; - - var tabView = new TracingAnalysisTabView(); - tabView.tabStripHeadingText = 'Hello world:'; - - var firstTab = document.createElement('div'); - firstTab.setAttribute('tab-label', 'First Tab Label'); - firstTab.innerHTML = '<p>' + TAB_TEXT + '<p>'; - - var secondTab = document.createElement('div'); - secondTab.setAttribute('tab-label', 'Second Tab Label'); - secondTab.innerHTML = '<b>' + 'Second Tab Text' + '</b>'; - - var thirdTab = document.createElement('div'); - thirdTab.setAttribute('tab-label', 'Third Tab Label'); - thirdTab.innerHTML = '<b>' + 'Third Tab Text' + '</b>'; - - tabView.appendChild(firstTab); - tabView.appendChild(secondTab); - tabView.appendChild(thirdTab); - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); - tabView.selectedTab = secondTab; + test('instantiate_oneTab', function() { + var tabView = document.createElement('tr-ui-b-tab-view'); + tabView.label = '1 item selected.'; + tabView.addSubView(createPowerSampleSubView()); + this.addHTMLOutput(tabView); }); - test('instantiateChildrenAlreadyInside', function() { - var tabViewTemplate = THIS_DOC.querySelector('#tab-view-test-template'); - var tabView = tabViewTemplate.createInstance(); - - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '400px'; - tabViewContainer.style.height = '200px'; - - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); - + test('instantiate_twoTabs', function() { + var tabView = document.createElement('tr-ui-b-tab-view'); + tabView.label = '3 items selected.'; + tabView.addSubView(createPowerSampleSubView()); + tabView.addSubView(createAlertSubView()); + this.addHTMLOutput(tabView); }); - test('programaticallySetSelectedTab', function() { - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '500px'; - tabViewContainer.style.height = '200px'; - - var tabView = new TracingAnalysisTabView(); - - var t1 = document.createElement('div'); - var t2 = document.createElement('div'); - var t3 = document.createElement('div'); - - tabView.appendChild(t1); - tabView.appendChild(t2); - tabView.appendChild(t3); - - assert.isUndefined(tabView.selectedTab); - tabView.selectedTab = t1; - - assert.isTrue(t1.hasAttribute('selected')); - assert.isFalse(t2.hasAttribute('selected')); - assert.isFalse(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t1, tabView.selectedTab)); + test('clearSubViews_selectedSubViewNullAfter', function() { + var tabView = document.createElement('tr-ui-b-tab-view'); + tabView.label = '3 items selected.'; + tabView.addSubView(createPowerSampleSubView()); + tabView.addSubView(createAlertSubView()); - tabView.selectedTab = t2; - assert.isFalse(t1.hasAttribute('selected')); - assert.isTrue(t2.hasAttribute('selected')); - assert.isFalse(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t2, tabView.selectedTab)); + tabView.clearSubViews(); - tabView.selectedTab = t3; - assert.isFalse(t1.hasAttribute('selected')); - assert.isFalse(t2.hasAttribute('selected')); - assert.isTrue(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t3, tabView.selectedTab)); - - t1.selected = true; - assert.isTrue(t1.hasAttribute('selected')); - assert.isFalse(t2.hasAttribute('selected')); - assert.isFalse(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t1, tabView.selectedTab)); - - // Make sure just randomly setting a tab as not selected does not - // break the existing selection. - t2.selected = false; - t3.selected = false; - assert.isTrue(t1.hasAttribute('selected')); - assert.isFalse(t2.hasAttribute('selected')); - assert.isFalse(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t1, tabView.selectedTab)); - - t3.selected = true; - assert.isFalse(t1.hasAttribute('selected')); - assert.isFalse(t2.hasAttribute('selected')); - assert.isTrue(t3.hasAttribute('selected')); - assert.isTrue(Object.is(t3, tabView.selectedTab)); - - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); + assert.isUndefined(tabView.selectedSubView); }); - /** - * This test checks that if an element has a selected property already set, - * before being attached to the tabView, it still gets selected if the - * property is true, after it gets attached. - */ - test('instantiateSetSelectedTabAlreadySet', function() { - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '500px'; - tabViewContainer.style.height = '200px'; - - var tabView = new TracingAnalysisTabView(); - - var t1 = document.createElement('div'); - t1.textContent = 'This text should BE visible.'; - var t2 = document.createElement('div'); - t2.textContent = 'This text should NOT be visible.'; - var t3 = document.createElement('div'); - t3.textContent = 'This text should NOT be visible, also.'; - - t1.selected = true; - t2.selected = false; - t3.selected = false; - - tabView.appendChild(t1); - tabView.appendChild(t2); - tabView.appendChild(t3); - - t1.setAttribute('tab-label', 'This should be selected'); - t2.setAttribute('tab-label', 'Not selected'); - t3.setAttribute('tab-label', 'Not selected'); - - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); - }); - - test('selectingInvalidTabWorks', function() { - var tabView = new TracingAnalysisTabView(); - var t1 = document.createElement('div'); - var t2 = document.createElement('div'); - var t3 = document.createElement('div'); - var invalidChild = document.createElement('div'); - - tabView.appendChild(t1); - tabView.appendChild(t2); - tabView.appendChild(t3); - - tabView.selectedTab = t1; - - assert.equal(tabView.selectedTab, t1); - - // Make sure that selecting an invalid tab does not break the current - // selection. - tabView.selectedTab = invalidChild; - assert.equal(t1, tabView.selectedTab); - - // Also make sure the invalidChild does not influence the tab view when - // it has a selected property set. - invalidChild.selected = true; - tabView.selectedTab = invalidChild; - assert.equal(t1, tabView.selectedTab); - }); - - test('changeTabCausesEvent', function() { - var tabView = new TracingAnalysisTabView(); - var t1 = document.createElement('div'); - var t2 = document.createElement('div'); - var invalidChild = document.createElement('div'); - - tabView.appendChild(t1); - tabView.appendChild(t2); - - var numChangeEvents = 0; + test('changeSelectedSubView', function() { + var selectedTabChangeEventCount = 0; + var tabView = document.createElement('tr-ui-b-tab-view'); tabView.addEventListener('selected-tab-change', function() { - numChangeEvents++; + selectedTabChangeEventCount++; }); - tabView.selectedTab = t1; - assert.equal(numChangeEvents, 1); - tabView.selectedTab = t1; - assert.equal(numChangeEvents, 1); - tabView.selectedTab = t2; - assert.equal(numChangeEvents, 2); - tabView.selectedTab = undefined; - assert.equal(numChangeEvents, 3); - }); - - /** - * This test makes sure that removing the selected tab does not select - * any other tab. - */ - test('instantiateRemovingSelectedTab', function() { - var tabViewContainer = document.createElement('div'); - tabViewContainer.style.width = '500px'; - tabViewContainer.style.height = '200px'; - - var tabView = new TracingAnalysisTabView(); - var t1 = document.createElement('div'); - t1.textContent = 'This text should BE visible.'; - var t2 = document.createElement('div'); - t2.textContent = 'This text should NOT be visible.'; - var t3 = document.createElement('div'); - t3.textContent = 'This text should NOT be visible, also.'; + assert.isUndefined(tabView.selectedSubView); + assert.strictEqual(selectedTabChangeEventCount, 0); - tabView.appendChild(t1); - tabView.appendChild(t2); - tabView.appendChild(t3); + var view1 = createPowerSampleSubView(); + tabView.addSubView(view1); + assert.strictEqual(tabView.selectedSubView, view1); + assert.strictEqual(selectedTabChangeEventCount, 1); - t1.setAttribute('tab-label', 'This should not exist'); - t2.setAttribute('tab-label', 'Not selected'); - t3.setAttribute('tab-label', 'Not selected'); + var view2 = createAlertSubView(); + tabView.addSubView(view2); + assert.strictEqual(tabView.selectedSubView, view1); + assert.strictEqual(selectedTabChangeEventCount, 1); - tabView.selectedTab = t1; - tabView.removeChild(t1); - - tabViewContainer.appendChild(tabView); - - this.addHTMLOutput(tabViewContainer); - }); + tabView.selectedSubView = view2; + assert.strictEqual(tabView.selectedSubView, view2); + assert.strictEqual(selectedTabChangeEventCount, 2); + }) }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table.html index 1292a3af758..91b00cb9d65 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/table.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table.html @@ -57,7 +57,7 @@ tr.exportTo('tr.ui.b', function() { }); </script> -<polymer-element name="tr-ui-b-table"> +<dom-module id="tr-ui-b-table"> <template> <style> :host { @@ -66,8 +66,6 @@ tr.exportTo('tr.ui.b', function() { } table { - font-size: 12px; - flex: 1 1 auto; align-self: stretch; border-collapse: separate; @@ -78,13 +76,17 @@ tr.exportTo('tr.ui.b', function() { tr > td { padding: 2px 4px 2px 4px; - vertical-align: text-top; + vertical-align: top; } - tr:focus, - td:focus { - outline: 1px dotted rgba(0,0,0,0.1); - outline-offset: 0; + table > tbody:focus { + outline: none; + } + table > tbody:focus[selection-mode="row"] > tr[selected], + table > tbody:focus[selection-mode="cell"] > tr > td[selected], + table > tbody:focus > tr.empty-row > td { + outline: 1px dotted #666666; + outline-offset: -1px; } button.toggle-button { @@ -153,6 +155,10 @@ tr.exportTo('tr.ui.b', function() { background-color: rgb(171, 217, 202); /* semi-light turquoise */ } + table > colgroup > col[selected] { + background-color: #e6e6e6; /* grey */ + } + table > tbody > tr.empty-row > td { color: #666; font-style: italic; @@ -167,20 +173,24 @@ tr.exportTo('tr.ui.b', function() { border-top: 1px solid #ffffff; } + :host([zebra]) table tbody tr:nth-child(even) { + background-color: #f4f4f4; + } + expand-button { -webkit-user-select: none; - display: inline-block; cursor: pointer; - font-size: 9px; - min-width: 8px; - max-width: 8px; + margin-right: 3px; + font-size: smaller; } - .button-expanded { + expand-button.button-expanded { transform: rotate(90deg); } </style> <table> + <colgroup id="cols"> + </colgroup> <thead id="head"> </thead> <tbody id="body"> @@ -189,1186 +199,1419 @@ tr.exportTo('tr.ui.b', function() { </tfoot> </table> </template> - <script> - 'use strict'; - (function() { - var RIGHT_ARROW = String.fromCharCode(0x25b6); - var UNSORTED_ARROW = String.fromCharCode(0x25BF); - var ASCENDING_ARROW = String.fromCharCode(0x25B4); - var DESCENDING_ARROW = String.fromCharCode(0x25BE); - var BASIC_INDENTATION = 8; - - var SelectionMode = tr.ui.b.TableFormat.SelectionMode; - var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle; - var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment; - - Polymer({ - created: function() { - this.selectionMode_ = SelectionMode.NONE; - this.rowHighlightStyle_ = HighlightStyle.DEFAULT; - this.cellHighlightStyle_ = HighlightStyle.DEFAULT; - this.selectedTableRowInfo_ = undefined; - this.selectedColumnIndex_ = undefined; +</dom-module> +<script> +'use strict'; +(function() { + var RIGHT_ARROW = String.fromCharCode(0x25b6); + var UNSORTED_ARROW = String.fromCharCode(0x25BF); + var ASCENDING_ARROW = String.fromCharCode(0x25B4); + var DESCENDING_ARROW = String.fromCharCode(0x25BE); + + var SelectionMode = tr.ui.b.TableFormat.SelectionMode; + var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle; + var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment; - this.tableColumns_ = []; - this.tableRows_ = []; - this.tableRowsInfo_ = new WeakMap(); - this.tableFooterRows_ = []; - this.tableFooterRowsInfo_ = new WeakMap(); - this.sortColumnIndex_ = undefined; - this.sortDescending_ = false; - this.columnsWithExpandButtons_ = []; - this.headerCells_ = []; - this.showHeader_ = true; - this.emptyValue_ = undefined; - this.subRowsPropertyName_ = 'subRows'; - this.customizeTableRowCallback_ = undefined; - }, - - ready: function() { - this.$.body.addEventListener( - 'keydown', this.onKeyDown_.bind(this), true); - }, - - clear: function() { - this.selectionMode_ = SelectionMode.NONE; - this.rowHighlightStyle_ = HighlightStyle.DEFAULT; - this.cellHighlightStyle_ = HighlightStyle.DEFAULT; - this.selectedTableRowInfo_ = undefined; - this.selectedColumnIndex_ = undefined; + Polymer({ + is: 'tr-ui-b-table', - this.textContent = ''; - this.tableColumns_ = []; - this.tableRows_ = []; - this.tableRowsInfo_ = new WeakMap(); - this.tableFooterRows_ = []; - this.tableFooterRowsInfo_ = new WeakMap(); - this.sortColumnIndex_ = undefined; - this.sortDescending_ = false; - this.columnsWithExpandButtons_ = []; - this.headerCells_ = []; - this.subRowsPropertyName_ = 'subRows'; - this.defaultExpansionStateCallback_ = undefined; - }, - - get showHeader() { - return this.showHeader_; - }, - - set showHeader(showHeader) { - this.showHeader_ = showHeader; - this.scheduleRebuildHeaders_(); - }, - - set subRowsPropertyName(name) { - this.subRowsPropertyName_ = name; - }, - - /** - * This callback will be called whenever a body row is built - * for a userRow that has subRows and does not have an explicit - * isExpanded field. - * The callback should return true if the row should be expanded, - * or false if the row should be collapsed. - * @param {function(userRow, parentUserRow): boolean} cb The callback. - */ - set defaultExpansionStateCallback(cb) { - this.defaultExpansionStateCallback_ = cb; - this.scheduleRebuildBody_(); - }, - - /** - * This callback will be called whenever a body row is built. - * The callback's return value is ignored. - * @param {function(userRow, trElement)} cb The callback. - */ - set customizeTableRowCallback(cb) { - this.customizeTableRowCallback_ = cb; + created: function() { + this.selectionMode_ = SelectionMode.NONE; + this.rowHighlightStyle_ = HighlightStyle.DEFAULT; + this.cellHighlightStyle_ = HighlightStyle.DEFAULT; + this.selectedTableRowInfo_ = undefined; + this.selectedColumnIndex_ = undefined; + + this.tableColumns_ = []; + this.tableRows_ = []; + this.tableRowsInfo_ = new WeakMap(); + this.tableFooterRows_ = []; + this.tableFooterRowsInfo_ = new WeakMap(); + this.sortColumnIndex_ = undefined; + this.sortDescending_ = false; + this.columnsWithExpandButtons_ = []; + this.headerCells_ = []; + this.showHeader_ = true; + this.emptyValue_ = undefined; + this.subRowsPropertyName_ = 'subRows'; + this.customizeTableRowCallback_ = undefined; + this.defaultExpansionStateCallback_ = undefined; + this.userCanModifySortOrder_ = true; + }, + + ready: function() { + this.$.body.addEventListener( + 'keydown', this.onKeyDown_.bind(this), true); + this.$.body.addEventListener( + 'focus', this.onFocus_.bind(this), true); + }, + + clear: function() { + this.selectionMode_ = SelectionMode.NONE; + this.rowHighlightStyle_ = HighlightStyle.DEFAULT; + this.cellHighlightStyle_ = HighlightStyle.DEFAULT; + this.selectedTableRowInfo_ = undefined; + this.selectedColumnIndex_ = undefined; + + Polymer.dom(this).textContent = ''; + this.tableColumns_ = []; + this.tableRows_ = []; + this.tableRowsInfo_ = new WeakMap(); + this.tableFooterRows_ = []; + this.tableFooterRowsInfo_ = new WeakMap(); + this.sortColumnIndex_ = undefined; + this.sortDescending_ = false; + this.columnsWithExpandButtons_ = []; + this.headerCells_ = []; + this.showHeader_ = true; + this.emptyValue_ = undefined; + this.subRowsPropertyName_ = 'subRows'; + this.defaultExpansionStateCallback_ = undefined; + this.userCanModifySortOrder_ = true; + }, + + set zebra(zebra) { + if (zebra) { + this.setAttribute('zebra', true); + } else { + this.removeAttribute('zebra'); + } + }, + + get zebra() { + return this.getAttribute('zebra'); + }, + + get showHeader() { + return this.showHeader_; + }, + + set showHeader(showHeader) { + this.showHeader_ = showHeader; + this.scheduleRebuildHeaders_(); + }, + + set subRowsPropertyName(name) { + this.subRowsPropertyName_ = name; + }, + + /** + * This callback will be called whenever a body row is built + * for a userRow that has subRows and does not have an explicit + * isExpanded field. + * The callback should return true if the row should be expanded, + * or false if the row should be collapsed. + * @param {function(userRow, parentUserRow): boolean} cb The callback. + */ + set defaultExpansionStateCallback(cb) { + this.defaultExpansionStateCallback_ = cb; + this.scheduleRebuildBody_(); + }, + + /** + * This callback will be called whenever a body row is built. + * The callback's return value is ignored. + * @param {function(userRow, trElement)} cb The callback. + */ + set customizeTableRowCallback(cb) { + this.customizeTableRowCallback_ = cb; + this.scheduleRebuildBody_(); + }, + + get emptyValue() { + return this.emptyValue_; + }, + + set emptyValue(emptyValue) { + var previousEmptyValue = this.emptyValue_; + this.emptyValue_ = emptyValue; + if (this.tableRows_.length === 0 && emptyValue !== previousEmptyValue) this.scheduleRebuildBody_(); - }, - - get emptyValue() { - return this.emptyValue_; - }, - - set emptyValue(emptyValue) { - var previousEmptyValue = this.emptyValue_; - this.emptyValue_ = emptyValue; - if (this.tableRows_.length === 0 && emptyValue !== previousEmptyValue) - this.scheduleRebuildBody_(); - }, - - /** - * Data objects should have the following fields: - * mandatory: title, value - * optional: width {string}, cmp {function}, colSpan {number}, - * showExpandButtons {boolean}, - * align {tr.ui.b.TableFormat.ColumnAlignment} - * - * @param {Array} columns An array of data objects. - */ - set tableColumns(columns) { - // Figure out the columns with expand buttons... - var columnsWithExpandButtons = []; - for (var i = 0; i < columns.length; i++) { - if (columns[i].showExpandButtons) - columnsWithExpandButtons.push(i); - } - if (columnsWithExpandButtons.length === 0) { - // First column if none have specified. - columnsWithExpandButtons = [0]; - } + }, - // Sanity check columns. - for (var i = 0; i < columns.length; i++) { - var colInfo = columns[i]; - if (colInfo.width === undefined) - continue; + /** + * Data objects should have the following fields: + * mandatory: title, value + * optional: width {string}, cmp {function}, colSpan {number}, + * showExpandButtons {boolean}, + * align {tr.ui.b.TableFormat.ColumnAlignment} + * + * @param {Array} columns An array of data objects. + */ + set tableColumns(columns) { + // Figure out the columns with expand buttons... + var columnsWithExpandButtons = []; + for (var i = 0; i < columns.length; i++) { + if (columns[i].showExpandButtons) + columnsWithExpandButtons.push(i); + } + if (columnsWithExpandButtons.length === 0) { + // First column if none have specified. + columnsWithExpandButtons = [0]; + } - var hasExpandButton = columnsWithExpandButtons.indexOf(i) !== -1; + // Sanity check columns. + for (var i = 0; i < columns.length; i++) { + var colInfo = columns[i]; + if (colInfo.width === undefined) + continue; - var w = colInfo.width; - if (w) { - if (/\d+px/.test(w)) { - continue; - } else if (/\d+%/.test(w)) { - if (hasExpandButton) { - throw new Error('Columns cannot be %-sized and host ' + - ' an expand button'); - } - } else { - throw new Error('Unrecognized width string'); + var hasExpandButton = columnsWithExpandButtons.indexOf(i) !== -1; + + var w = colInfo.width; + if (w) { + if (/\d+px/.test(w)) { + continue; + } else if (/\d+%/.test(w)) { + if (hasExpandButton) { + throw new Error('Columns cannot be %-sized and host ' + + ' an expand button'); } + } else { + throw new Error('Unrecognized width string'); } } + } - // Commit the change. - this.tableColumns_ = columns; - this.headerCells_ = []; - this.columnsWithExpandButtons_ = columnsWithExpandButtons; - this.sortColumnIndex = undefined; - this.scheduleRebuildHeaders_(); - - // Blow away the table rows, too. - this.tableRows = this.tableRows_; - }, - - get tableColumns() { - return this.tableColumns_; - }, - - /** - * @param {Array} rows An array of 'row' objects with the following - * fields: - * optional: subRows An array of objects that have the same 'row' - * structure. Set subRowsPropertyName to use an - * alternative field name. - */ - set tableRows(rows) { - this.selectedTableRowInfo_ = undefined; - this.selectedColumnIndex_ = undefined; - this.maybeUpdateSelectedRow_(); - this.tableRows_ = rows; - this.tableRowsInfo_ = new WeakMap(); - this.scheduleRebuildBody_(); - }, + // Try to preserve the user's sort choice. + // This is a 'best-effort' attempt, for example we compare columns by + // thier titles which can be HTML nodes in which case we might consider + // them different even if they look the same to the user. + var sortIndex = undefined; + var currentSortColumn = this.tableColumns[this.sortColumnIndex_]; + if (currentSortColumn) { + for (var [i, column] of columns.entries()) { + if (currentSortColumn.title === column.title) { + sortIndex = i; + break; + } + } + } - get tableRows() { - return this.tableRows_; - }, + // Commit the change. + this.tableColumns_ = columns; + this.headerCells_ = []; + this.columnsWithExpandButtons_ = columnsWithExpandButtons; + this.scheduleRebuildHeaders_(); + this.sortColumnIndex = sortIndex; - set footerRows(rows) { - this.tableFooterRows_ = rows; - this.tableFooterRowsInfo_ = new WeakMap(); - this.scheduleRebuildFooter_(); - }, + // Blow away the table rows, too. + this.tableRows = this.tableRows_; + }, - get footerRows() { - return this.tableFooterRows_; - }, + get tableColumns() { + return this.tableColumns_; + }, - set sortColumnIndex(number) { - if (number === this.sortColumnIndex_) - return; + /** + * @param {Array} rows An array of 'row' objects with the following + * fields: + * optional: subRows An array of objects that have the same 'row' + * structure. Set subRowsPropertyName to use an + * alternative field name. + */ + set tableRows(rows) { + this.selectedTableRowInfo_ = undefined; + this.selectedColumnIndex_ = undefined; + this.tableRows_ = rows; + this.tableRowsInfo_ = new WeakMap(); + this.scheduleRebuildBody_(); + }, - if (number === undefined) { - this.sortColumnIndex_ = undefined; - this.updateHeaderArrows_(); - this.dispatchSortingChangedEvent_(); - return; - } + get tableRows() { + return this.tableRows_; + }, + + set footerRows(rows) { + this.tableFooterRows_ = rows; + this.tableFooterRowsInfo_ = new WeakMap(); + this.scheduleRebuildFooter_(); + }, + + get footerRows() { + return this.tableFooterRows_; + }, + + get userCanModifySortOrder() { + return this.userCanModifySortOrder_; + }, + + set userCanModifySortOrder(userCanModifySortOrder) { + var newUserCanModifySortOrder = !!userCanModifySortOrder; + if (newUserCanModifySortOrder === this.userCanModifySortOrder_) + return + this.userCanModifySortOrder_ = newUserCanModifySortOrder; + this.scheduleRebuildHeaders_(); + }, + + set sortColumnIndex(number) { + if (number === this.sortColumnIndex_) + return; + + if (number !== undefined) { if (this.tableColumns_.length <= number) throw new Error('Column number ' + number + ' is out of bounds.'); if (!this.tableColumns_[number].cmp) throw new Error('Column ' + number + ' does not have a comparator.'); + } + + this.sortColumnIndex_ = number; + this.updateHeaderArrows_(); + this.scheduleRebuildBody_(); + this.dispatchSortingChangedEvent_(); + }, + + get sortColumnIndex() { + return this.sortColumnIndex_; + }, + + set sortDescending(value) { + var newValue = !!value; - this.sortColumnIndex_ = number; + if (newValue !== this.sortDescending_) { + this.sortDescending_ = newValue; this.updateHeaderArrows_(); this.scheduleRebuildBody_(); this.dispatchSortingChangedEvent_(); - }, - - get sortColumnIndex() { - return this.sortColumnIndex_; - }, + } + }, - set sortDescending(value) { - var newValue = !!value; + get sortDescending() { + return this.sortDescending_; + }, - if (newValue !== this.sortDescending_) { - this.sortDescending_ = newValue; - this.updateHeaderArrows_(); - this.scheduleRebuildBody_(); - this.dispatchSortingChangedEvent_(); + updateHeaderArrows_: function() { + for (var i = 0; i < this.headerCells_.length; i++) { + var headerCell = this.headerCells_[i]; + var isColumnCurrentlySorted = i === this.sortColumnIndex_; + if (!this.tableColumns_[i].cmp || + (!this.userCanModifySortOrder_ && !isColumnCurrentlySorted)) { + headerCell.sideContent = ''; + continue; } - }, - - get sortDescending() { - return this.sortDescending_; - }, - - updateHeaderArrows_: function() { - for (var i = 0; i < this.headerCells_.length; i++) { - if (!this.tableColumns_[i].cmp) { - this.headerCells_[i].sideContent = ''; - continue; - } - if (i !== this.sortColumnIndex_) { - this.headerCells_[i].sideContent = UNSORTED_ARROW; - continue; - } - this.headerCells_[i].sideContent = this.sortDescending_ ? - DESCENDING_ARROW : ASCENDING_ARROW; + if (!isColumnCurrentlySorted) { + headerCell.sideContent = UNSORTED_ARROW; + headerCell.sideContentDisabled = false; + continue; } - }, + headerCell.sideContent = this.sortDescending_ ? + DESCENDING_ARROW : ASCENDING_ARROW; + headerCell.sideContentDisabled = !this.userCanModifySortOrder_; + } + }, - sortRows_: function(rows) { - rows.sort(function(rowA, rowB) { - if (this.sortDescending_) - return this.tableColumns_[this.sortColumnIndex_].cmp( - rowB.userRow, rowA.userRow); - return this.tableColumns_[this.sortColumnIndex_].cmp( - rowA.userRow, rowB.userRow); - }.bind(this)); - // Sort expanded sub rows recursively. - for (var i = 0; i < rows.length; i++) { - if (this.getExpandedForUserRow_(rows[i])) - this.sortRows_(rows[i][this.subRowsPropertyName_]); + generateHeaderColumns_: function() { + var selectedTableColumnIndex = this.selectedTableColumnIndex; + Polymer.dom(this.$.cols).textContent = ''; + for (var i = 0; i < this.tableColumns_.length; ++i) { + var colElement = document.createElement('col'); + if (i === selectedTableColumnIndex) { + colElement.setAttribute('selected', true); } - }, + Polymer.dom(this.$.cols).appendChild(colElement); + } - generateHeaderColumns_: function() { - this.headerCells_ = []; - this.$.head.textContent = ''; - if (!this.showHeader_) - return; + this.headerCells_ = []; + Polymer.dom(this.$.head).textContent = ''; + if (!this.showHeader_) + return; - var tr = this.appendNewElement_(this.$.head, 'tr'); - for (var i = 0; i < this.tableColumns_.length; i++) { - var td = this.appendNewElement_(tr, 'td'); + var tr = this.appendNewElement_(this.$.head, 'tr'); + for (var i = 0; i < this.tableColumns_.length; i++) { + var td = this.appendNewElement_(tr, 'td'); - var headerCell = document.createElement('tr-ui-b-table-header-cell'); - headerCell.cellTitle = this.tableColumns_[i].title; - headerCell.align = this.tableColumns_[i].align; + var headerCell = document.createElement('tr-ui-b-table-header-cell'); + headerCell.column = this.tableColumns_[i]; - // If the table can be sorted by this column, attach a tap callback - // to the column. - if (this.tableColumns_[i].cmp) { - td.classList.add('sensitive'); - headerCell.tapCallback = this.createSortCallback_(i); - // Set arrow position, depending on the sortColumnIndex. - if (this.sortColumnIndex_ === i) - headerCell.sideContent = this.sortDescending_ ? + // If the table can be sorted by this column and the user can modify + // the sort order, attach a tap callback to the column. + if (this.tableColumns_[i].cmp) { + var isColumnCurrentlySorted = i === this.sortColumnIndex_; + if (isColumnCurrentlySorted) { + headerCell.sideContent = this.sortDescending_ ? DESCENDING_ARROW : ASCENDING_ARROW; - else + if (!this.userCanModifySortOrder_) + headerCell.sideContentDisabled = true; + } + if (this.userCanModifySortOrder_) { + Polymer.dom(td).classList.add('sensitive'); + if (!isColumnCurrentlySorted) headerCell.sideContent = UNSORTED_ARROW; + headerCell.tapCallback = this.createSortCallback_(i); } - - td.appendChild(headerCell); - this.headerCells_.push(headerCell); } - }, - applySizes_: function() { - if (this.tableRows_.length === 0 && !this.showHeader) - return; - var rowToRemoveSizing; - var rowToSize; - if (this.showHeader) { - rowToSize = this.$.head.children[0]; - rowToRemoveSizing = this.$.body.children[0]; - } else { - rowToSize = this.$.body.children[0]; - rowToRemoveSizing = this.$.head.children[0]; - } - for (var i = 0; i < this.tableColumns_.length; i++) { - if (rowToRemoveSizing && rowToRemoveSizing.children[i]) { - var tdToRemoveSizing = rowToRemoveSizing.children[i]; - tdToRemoveSizing.style.minWidth = ''; - tdToRemoveSizing.style.width = ''; - } + Polymer.dom(td).appendChild(headerCell); + this.headerCells_.push(headerCell); + } + }, - // Apply sizing. - var td = rowToSize.children[i]; + applySizes_: function() { + if (this.tableRows_.length === 0 && !this.showHeader) + return; + var rowToRemoveSizing; + var rowToSize; + if (this.showHeader) { + rowToSize = Polymer.dom(this.$.head).children[0]; + rowToRemoveSizing = Polymer.dom(this.$.body).children[0]; + } else { + rowToSize = Polymer.dom(this.$.body).children[0]; + rowToRemoveSizing = Polymer.dom(this.$.head).children[0]; + } + for (var i = 0; i < this.tableColumns_.length; i++) { + if (rowToRemoveSizing && Polymer.dom(rowToRemoveSizing).children[i]) { + var tdToRemoveSizing = Polymer.dom(rowToRemoveSizing).children[i]; + tdToRemoveSizing.style.minWidth = ''; + tdToRemoveSizing.style.width = ''; + } - var delta; - if (this.columnsWithExpandButtons_.indexOf(i) !== -1) { - td.style.paddingLeft = BASIC_INDENTATION + 'px'; - delta = BASIC_INDENTATION + 'px'; - } else { - delta = undefined; - } + // Apply sizing. + var td = Polymer.dom(rowToSize).children[i]; - function calc(base, delta) { - if (delta) - return 'calc(' + base + ' - ' + delta + ')'; - else - return base; - } - - var w = this.tableColumns_[i].width; - if (w) { - if (/\d+px/.test(w)) { - td.style.minWidth = calc(w, delta); - } else if (/\d+%/.test(w)) { - td.style.width = w; - } else { - throw new Error('Unrecognized width string: ' + w); - } - } + var delta; + if (this.columnsWithExpandButtons_.indexOf(i) !== -1) { + td.style.paddingLeft = this.basicIndentation_ + 'px'; + delta = this.basicIndentation_ + 'px'; + } else { + delta = undefined; } - }, - - createSortCallback_: function(columnNumber) { - return function() { - var previousIndex = this.sortColumnIndex; - this.sortColumnIndex = columnNumber; - if (previousIndex !== columnNumber) - this.sortDescending = false; + + function calc(base, delta) { + if (delta) + return 'calc(' + base + ' - ' + delta + ')'; else - this.sortDescending = !this.sortDescending; - }.bind(this); - }, - - generateTableRowNodes_: function(tableSection, userRows, rowInfoMap, - indentation, lastAddedRow, - parentRowInfo) { - if (this.sortColumnIndex_ !== undefined && - tableSection === this.$.body) { - userRows = userRows.slice(); // Don't mess with the input data. - userRows.sort(function(rowA, rowB) { - var c = this.tableColumns_[this.sortColumnIndex_].cmp( - rowA, rowB); - if (this.sortDescending_) - c = -c; - return c; - }.bind(this)); + return base; } - for (var i = 0; i < userRows.length; i++) { - var userRow = userRows[i]; - var rowInfo = this.getOrCreateRowInfoFor_(rowInfoMap, userRow, - parentRowInfo); - var htmlNode = this.getHTMLNodeForRowInfo_( - tableSection, rowInfo, rowInfoMap, indentation); - - if (lastAddedRow === undefined) { - // Put first into the table. - tableSection.insertBefore(htmlNode, tableSection.firstChild); + var w = this.tableColumns_[i].width; + if (w) { + if (/\d+px/.test(w)) { + td.style.minWidth = calc(w, delta); + } else if (/\d+%/.test(w)) { + td.style.width = w; } else { - // This is shorthand for insertAfter(htmlNode, lastAdded). - var nextSiblingOfLastAdded = lastAddedRow.nextSibling; - tableSection.insertBefore(htmlNode, nextSiblingOfLastAdded); + throw new Error('Unrecognized width string: ' + w); } - this.updateTabIndexForTableRowNode_(htmlNode); - - lastAddedRow = htmlNode; - if (!rowInfo.isExpanded) - continue; - - // Append subrows now. - lastAddedRow = this.generateTableRowNodes_( - tableSection, userRow[this.subRowsPropertyName_], rowInfoMap, - indentation + 1, lastAddedRow, rowInfo); } - return lastAddedRow; - }, + } + }, - getOrCreateRowInfoFor_: function(rowInfoMap, userRow, parentRowInfo) { - var rowInfo = undefined; + createSortCallback_: function(columnNumber) { + return function() { + if (!this.userCanModifySortOrder_) + return; + var previousIndex = this.sortColumnIndex; + this.sortColumnIndex = columnNumber; + if (previousIndex !== columnNumber) + this.sortDescending = false; + else + this.sortDescending = !this.sortDescending; + }.bind(this); + }, - if (rowInfoMap.has(userRow)) { - rowInfo = rowInfoMap.get(userRow); + generateTableRowNodes_: function(tableSection, userRows, rowInfoMap, + indentation, lastAddedRow, + parentRowInfo) { + if (this.sortColumnIndex_ !== undefined && + tableSection === this.$.body) { + userRows = userRows.slice(); // Don't mess with the input data. + userRows.sort(function(rowA, rowB) { + var c = this.tableColumns_[this.sortColumnIndex_].cmp( + rowA, rowB); + if (this.sortDescending_) + c = -c; + return c; + }.bind(this)); + } + + for (var i = 0; i < userRows.length; i++) { + var userRow = userRows[i]; + var rowInfo = this.getOrCreateRowInfoFor_(rowInfoMap, userRow, + parentRowInfo); + var htmlNode = this.getHTMLNodeForRowInfo_( + tableSection, rowInfo, rowInfoMap, indentation); + + if (lastAddedRow === undefined) { + // Put first into the table. + Polymer.dom(tableSection).insertBefore( + htmlNode, Polymer.dom(tableSection).firstChild); } else { - rowInfo = { - userRow: userRow, - htmlNode: undefined, - parentRowInfo: parentRowInfo - }; - rowInfoMap.set(userRow, rowInfo); + // This is shorthand for insertAfter(htmlNode, lastAdded). + var nextSiblingOfLastAdded = Polymer.dom(lastAddedRow).nextSibling; + Polymer.dom(tableSection).insertBefore( + htmlNode, nextSiblingOfLastAdded); } - // Recompute isExpanded in case defaultExpansionStateCallback_ has - // changed. - rowInfo.isExpanded = this.getExpandedForUserRow_(userRow); + lastAddedRow = htmlNode; + if (!rowInfo.isExpanded) + continue; - return rowInfo; - }, + // Append subrows now. + lastAddedRow = this.generateTableRowNodes_( + tableSection, userRow[this.subRowsPropertyName_], rowInfoMap, + indentation + 1, lastAddedRow, rowInfo); + } + return lastAddedRow; + }, - customizeTableRow_: function(userRow, trElement) { - if (!this.customizeTableRowCallback_) - return; - this.customizeTableRowCallback_(userRow, trElement); - }, - - getHTMLNodeForRowInfo_: function(tableSection, rowInfo, - rowInfoMap, indentation) { - if (rowInfo.htmlNode) { - this.customizeTableRow_(rowInfo.userRow, rowInfo.htmlNode); - return rowInfo.htmlNode; - } + getOrCreateRowInfoFor_: function(rowInfoMap, userRow, parentRowInfo) { + var rowInfo = undefined; - var INDENT_SPACE = indentation * 16; - var INDENT_SPACE_NO_BUTTON = indentation * 16 + BASIC_INDENTATION; - var trElement = this.ownerDocument.createElement('tr'); - rowInfo.htmlNode = trElement; - rowInfo.indentation = indentation; - trElement.rowInfo = rowInfo; - this.customizeTableRow_(rowInfo.userRow, trElement); + if (rowInfoMap.has(userRow)) { + rowInfo = rowInfoMap.get(userRow); + } else { + rowInfo = { + userRow: userRow, + htmlNode: undefined, + parentRowInfo: parentRowInfo + }; + rowInfoMap.set(userRow, rowInfo); + } - for (var i = 0; i < this.tableColumns_.length;) { - var td = this.appendNewElement_(trElement, 'td'); - td.columnIndex = i; + // Recompute isExpanded in case defaultExpansionStateCallback_ has + // changed. + rowInfo.isExpanded = this.getExpandedForUserRow_(userRow); - var column = this.tableColumns_[i]; - var value = column.value(rowInfo.userRow); - var colSpan = column.colSpan ? column.colSpan : 1; - td.style.colSpan = colSpan; + return rowInfo; + }, - switch (column.align) { - case undefined: - case ColumnAlignment.LEFT: - break; + customizeTableRow_: function(userRow, trElement) { + if (!this.customizeTableRowCallback_) + return; + this.customizeTableRowCallback_(userRow, trElement); + }, - case ColumnAlignment.RIGHT: - td.style.textAlign = 'right'; - break; + get basicIndentation_() { + var px = parseInt(getComputedStyle(this).fontSize) || 16; + return px - 2; + }, - default: - throw new Error('Invalid alignment of column at index=' + i + - ': ' + column.align); - } + getHTMLNodeForRowInfo_: function(tableSection, rowInfo, + rowInfoMap, indentation) { + if (rowInfo.htmlNode) { + this.customizeTableRow_(rowInfo.userRow, rowInfo.htmlNode); + return rowInfo.htmlNode; + } - if (this.doesColumnIndexSupportSelection(i)) - td.classList.add('supports-selection'); - - if (this.columnsWithExpandButtons_.indexOf(i) != -1) { - if (rowInfo.userRow[this.subRowsPropertyName_] && - rowInfo.userRow[this.subRowsPropertyName_].length > 0) { - td.style.paddingLeft = INDENT_SPACE + 'px'; - var expandButton = this.appendNewElement_(td, - 'expand-button'); - expandButton.textContent = RIGHT_ARROW; - if (rowInfo.isExpanded) - expandButton.classList.add('button-expanded'); - } else { - td.style.paddingLeft = INDENT_SPACE_NO_BUTTON + 'px'; - } - } + var INDENT_SPACE = indentation * 16; + var INDENT_SPACE_NO_BUTTON = indentation * 16 + this.basicIndentation_; + var trElement = this.ownerDocument.createElement('tr'); + rowInfo.htmlNode = trElement; + rowInfo.indentation = indentation; + trElement.rowInfo = rowInfo; + this.customizeTableRow_(rowInfo.userRow, trElement); + + var isBodyRow = tableSection === this.$.body; + var isExpandableRow = rowInfo.userRow[this.subRowsPropertyName_] && + rowInfo.userRow[this.subRowsPropertyName_].length; + + for (var i = 0; i < this.tableColumns_.length;) { + var td = this.appendNewElement_(trElement, 'td'); + td.columnIndex = i; + + var column = this.tableColumns_[i]; + var value = column.value(rowInfo.userRow); + var colSpan = column.colSpan ? column.colSpan : 1; + td.style.colSpan = colSpan; + + switch (column.align) { + case undefined: + case ColumnAlignment.LEFT: + break; - if (value !== undefined) - td.appendChild(tr.ui.b.asHTMLOrTextNode(value, this.ownerDocument)); + case ColumnAlignment.RIGHT: + td.style.textAlign = 'right'; + break; - i += colSpan; + default: + throw new Error('Invalid alignment of column at index=' + i + + ': ' + column.align); } - var isSelectable = tableSection === this.$.body; - var isExpandable = rowInfo.userRow[this.subRowsPropertyName_] && - rowInfo.userRow[this.subRowsPropertyName_].length; + if (this.doesColumnIndexSupportSelection(i)) + Polymer.dom(td).classList.add('supports-selection'); + + if (this.columnsWithExpandButtons_.indexOf(i) !== -1) { + if (rowInfo.userRow[this.subRowsPropertyName_] && + rowInfo.userRow[this.subRowsPropertyName_].length > 0) { + td.style.paddingLeft = INDENT_SPACE + 'px'; + td.style.display = 'flex'; + var expandButton = this.appendNewElement_(td, 'expand-button'); + Polymer.dom(expandButton).textContent = RIGHT_ARROW; + if (rowInfo.isExpanded) + Polymer.dom(expandButton).classList.add('button-expanded'); + } else { + td.style.paddingLeft = INDENT_SPACE_NO_BUTTON + 'px'; + } + } + + if (value !== undefined) { + Polymer.dom(td).appendChild( + tr.ui.b.asHTMLOrTextNode(value, this.ownerDocument)); + } - if (isSelectable || isExpandable) { - trElement.addEventListener('click', function(e) { + // Add a click handler for selection and row expansion (if applicable). + if (isBodyRow || isExpandableRow) { + td.addEventListener('click', function(i, e) { e.stopPropagation(); - if (e.target.tagName == 'EXPAND-BUTTON') { + if (e.target.tagName === 'EXPAND-BUTTON') { this.setExpandedForUserRow_( tableSection, rowInfoMap, rowInfo.userRow, !rowInfo.isExpanded); return; } - function getTD(cur) { - if (cur === trElement) - throw new Error('woah'); - if (cur.parentElement === trElement) - return cur; - return getTD(cur.parentElement); - } - // If the row/cell can be selected and it's not selected yet, // select it. - if (isSelectable && this.selectionMode_ !== SelectionMode.NONE) { + if (isBodyRow && this.selectionMode_ !== SelectionMode.NONE) { var shouldSelect = false; - var columnIndex = getTD(e.target).columnIndex; + var shouldFocus = false; switch (this.selectionMode_) { case SelectionMode.ROW: shouldSelect = this.selectedTableRowInfo_ !== rowInfo; + shouldFocus = true; break; - case SelectionMode.CELL: - if (this.doesColumnIndexSupportSelection(columnIndex)) { + if (this.doesColumnIndexSupportSelection(i)) { shouldSelect = this.selectedTableRowInfo_ !== rowInfo || - this.selectedColumnIndex_ !== columnIndex; + this.selectedColumnIndex_ !== i; + shouldFocus = true; } break; - default: throw new Error('Invalid selection mode ' + this.selectionMode_); } + if (shouldFocus) { + this.focus(); + } if (shouldSelect) { - this.didTableRowInfoGetClicked_(rowInfo, columnIndex); + this.didTableRowInfoGetClicked_(rowInfo, i); return; } } // Otherwise, if the row is expandable, expand/collapse it. - if (isExpandable) { + if (isExpandableRow) { this.setExpandedForUserRow_(tableSection, rowInfoMap, rowInfo.userRow, !rowInfo.isExpanded); } - }.bind(this)); + }.bind(this, i)); } - return rowInfo.htmlNode; - }, + td.addEventListener('mousedown', function(e) { + // Prevent automatically focusing on the table upon clicking on the + // table. Explicitly focus on it when appropriate (upon clicking on a + // selectable row/cell) instead. + e.preventDefault(); + }); + + // Add a double-click handler for stepping into a row/cell (if + // applicable). + if (isBodyRow) { + td.addEventListener('dblclick', function(i, e) { + e.stopPropagation(); + this.dispatchStepIntoEvent_(rowInfo, i); + }.bind(this, i)); + } - removeSubNodes_: function(tableSection, rowInfo, rowInfoMap) { - if (rowInfo.userRow[this.subRowsPropertyName_] === undefined) - return; - for (var i = 0; - i < rowInfo.userRow[this.subRowsPropertyName_].length; i++) { - var subRow = rowInfo.userRow[this.subRowsPropertyName_][i]; - var subRowInfo = rowInfoMap.get(subRow); - if (!subRowInfo) - continue; + i += colSpan; + } - var subNode = subRowInfo.htmlNode; - if (subNode && subNode.parentNode === tableSection) { - tableSection.removeChild(subNode); - this.removeSubNodes_(tableSection, subRowInfo, rowInfoMap); - } + return rowInfo.htmlNode; + }, + + removeSubNodes_: function(tableSection, rowInfo, rowInfoMap) { + if (rowInfo.userRow[this.subRowsPropertyName_] === undefined) + return; + for (var i = 0; + i < rowInfo.userRow[this.subRowsPropertyName_].length; i++) { + var subRow = rowInfo.userRow[this.subRowsPropertyName_][i]; + var subRowInfo = rowInfoMap.get(subRow); + if (!subRowInfo) + continue; + + var subNode = subRowInfo.htmlNode; + if (subNode && Polymer.dom(subNode).parentNode === tableSection) { + Polymer.dom(tableSection).removeChild(subNode); + this.removeSubNodes_(tableSection, subRowInfo, rowInfoMap); } - }, + } + }, - scheduleRebuildHeaders_: function() { - this.headerDirty_ = true; - this.scheduleRebuild_(); - }, + scheduleRebuildHeaders_: function() { + this.headerDirty_ = true; + this.scheduleRebuild_(); + }, - scheduleRebuildBody_: function() { - this.bodyDirty_ = true; - this.scheduleRebuild_(); - }, + scheduleRebuildBody_: function() { + this.bodyDirty_ = true; + this.scheduleRebuild_(); + }, - scheduleRebuildFooter_: function() { - this.footerDirty_ = true; - this.scheduleRebuild_(); - }, + scheduleRebuildFooter_: function() { + this.footerDirty_ = true; + this.scheduleRebuild_(); + }, - scheduleRebuild_: function() { - if (this.rebuildPending_) - return; - this.rebuildPending_ = true; - setTimeout(function() { - this.rebuildPending_ = false; - this.rebuild(); - }.bind(this), 0); - }, - - rebuildIfNeeded_: function() { + scheduleRebuild_: function() { + if (this.rebuildPending_) + return; + this.rebuildPending_ = true; + setTimeout(function() { + this.rebuildPending_ = false; this.rebuild(); - }, - - rebuild: function() { - var wasBodyOrHeaderDirty = this.headerDirty_ || this.bodyDirty_; + }.bind(this), 0); + }, - if (this.headerDirty_) { - this.generateHeaderColumns_(); - this.headerDirty_ = false; - } - if (this.bodyDirty_) { - this.$.body.textContent = ''; - this.generateTableRowNodes_( - this.$.body, - this.tableRows_, this.tableRowsInfo_, 0, - undefined, undefined); - if (this.tableRows_.length === 0 && this.emptyValue_ !== undefined) { - var trElement = this.ownerDocument.createElement('tr'); - this.$.body.appendChild(trElement); - trElement.classList.add('empty-row'); - var td = this.ownerDocument.createElement('td'); - trElement.appendChild(td); - td.colSpan = this.tableColumns_.length; - var emptyValue = this.emptyValue_; - td.appendChild( - tr.ui.b.asHTMLOrTextNode(emptyValue, this.ownerDocument)); - } - this.bodyDirty_ = false; - } + rebuildIfNeeded_: function() { + this.rebuild(); + }, - if (wasBodyOrHeaderDirty) - this.applySizes_(); + rebuild: function() { + var wasBodyOrHeaderDirty = this.headerDirty_ || this.bodyDirty_; - if (this.footerDirty_) { - this.$.foot.textContent = ''; - this.generateTableRowNodes_( - this.$.foot, - this.tableFooterRows_, this.tableFooterRowsInfo_, 0, - undefined, undefined); - if (this.tableFooterRowsInfo_.length) { - this.$.body.classList.add('has-footer'); - } else { - this.$.body.classList.remove('has-footer'); - } - this.footerDirty_ = false; + if (this.headerDirty_) { + this.generateHeaderColumns_(); + this.headerDirty_ = false; + } + if (this.bodyDirty_) { + Polymer.dom(this.$.body).textContent = ''; + this.generateTableRowNodes_( + this.$.body, + this.tableRows_, this.tableRowsInfo_, 0, + undefined, undefined); + if (this.tableRows_.length === 0 && this.emptyValue_ !== undefined) { + var trElement = this.ownerDocument.createElement('tr'); + Polymer.dom(this.$.body).appendChild(trElement); + Polymer.dom(trElement).classList.add('empty-row'); + var td = this.ownerDocument.createElement('td'); + Polymer.dom(trElement).appendChild(td); + td.colSpan = this.tableColumns_.length; + var emptyValue = this.emptyValue_; + Polymer.dom(td).appendChild( + tr.ui.b.asHTMLOrTextNode(emptyValue, this.ownerDocument)); } - }, - - appendNewElement_: function(parent, tagName) { - var element = parent.ownerDocument.createElement(tagName); - parent.appendChild(element); - return element; - }, - - getExpandedForTableRow: function(userRow) { - this.rebuildIfNeeded_(); - var rowInfo = this.tableRowsInfo_.get(userRow); - if (rowInfo === undefined) - throw new Error('Row has not been seen, must expand its parents'); - return rowInfo.isExpanded; - }, - - getExpandedForUserRow_: function(userRow) { - if (userRow[this.subRowsPropertyName_] === undefined) - return false; - if (userRow[this.subRowsPropertyName_].length === 0) - return false; - if (userRow.isExpanded) - return true; - if (userRow.isExpanded === false) - return false; + this.bodyDirty_ = false; + } - var rowInfo = this.tableRowsInfo_.get(userRow); - if (rowInfo && rowInfo.isExpanded) - return true; + if (wasBodyOrHeaderDirty) + this.applySizes_(); + + if (this.footerDirty_) { + Polymer.dom(this.$.foot).textContent = ''; + this.generateTableRowNodes_( + this.$.foot, + this.tableFooterRows_, this.tableFooterRowsInfo_, 0, + undefined, undefined); + if (this.tableFooterRowsInfo_.length) { + Polymer.dom(this.$.body).classList.add('has-footer'); + } else { + Polymer.dom(this.$.body).classList.remove('has-footer'); + } + this.footerDirty_ = false; + } + }, - if (this.defaultExpansionStateCallback_ === undefined) - return false; + appendNewElement_: function(parent, tagName) { + var element = parent.ownerDocument.createElement(tagName); + Polymer.dom(parent).appendChild(element); + return element; + }, - var parentUserRow = undefined; - if (rowInfo && rowInfo.parentRowInfo) - parentUserRow = rowInfo.parentRowInfo.userRow; - - return this.defaultExpansionStateCallback_( - userRow, parentUserRow); - }, - - setExpandedForTableRow: function(userRow, expanded) { - this.rebuildIfNeeded_(); - var rowInfo = this.tableRowsInfo_.get(userRow); - if (rowInfo === undefined) - throw new Error('Row has not been seen, must expand its parents'); - return this.setExpandedForUserRow_(this.$.body, this.tableRowsInfo_, - userRow, expanded); - }, - - setExpandedForUserRow_: function(tableSection, rowInfoMap, - userRow, expanded) { - this.rebuildIfNeeded_(); - - var rowInfo = rowInfoMap.get(userRow); - if (rowInfo === undefined) - throw new Error('Row has not been seen, must expand its parents'); - - rowInfo.isExpanded = !!expanded; - // If no node, then nothing further needs doing. - if (rowInfo.htmlNode === undefined) - return; + getExpandedForTableRow: function(userRow) { + this.rebuildIfNeeded_(); + var rowInfo = this.tableRowsInfo_.get(userRow); + if (rowInfo === undefined) + throw new Error('Row has not been seen, must expand its parents'); + return rowInfo.isExpanded; + }, - // If its detached, then nothing needs doing. - if (rowInfo.htmlNode.parentElement !== tableSection) - return; + getExpandedForUserRow_: function(userRow) { + if (userRow[this.subRowsPropertyName_] === undefined) + return false; + if (userRow[this.subRowsPropertyName_].length === 0) + return false; + if (userRow.isExpanded) + return true; + if ((userRow.isExpanded !== undefined) && + (userRow.isExpanded === false)) + return false; - // Otherwise, rebuild. - var expandButton = rowInfo.htmlNode.querySelector('expand-button'); - if (rowInfo.isExpanded) { - expandButton.classList.add('button-expanded'); - var lastAddedRow = rowInfo.htmlNode; - if (rowInfo.userRow[this.subRowsPropertyName_]) { - this.generateTableRowNodes_( - tableSection, - rowInfo.userRow[this.subRowsPropertyName_], rowInfoMap, - rowInfo.indentation + 1, - lastAddedRow, rowInfo); - } - } else { - expandButton.classList.remove('button-expanded'); - this.removeSubNodes_(tableSection, rowInfo, rowInfoMap); - } + var rowInfo = this.tableRowsInfo_.get(userRow); + if (rowInfo && rowInfo.isExpanded) + return true; - this.maybeUpdateSelectedRow_(); - }, + if (this.defaultExpansionStateCallback_ === undefined) + return false; - get selectionMode() { - return this.selectionMode_; - }, + var parentUserRow = undefined; + if (rowInfo && rowInfo.parentRowInfo) + parentUserRow = rowInfo.parentRowInfo.userRow; - set selectionMode(selectionMode) { - if (!tr.b.dictionaryContainsValue(SelectionMode, selectionMode)) - throw new Error('Invalid selection mode ' + selectionMode); - this.rebuildIfNeeded_(); - this.selectionMode_ = selectionMode; - this.didSelectionStateChange_(); - }, + return this.defaultExpansionStateCallback_( + userRow, parentUserRow); + }, - get rowHighlightStyle() { - return this.rowHighlightStyle_; - }, - - set rowHighlightStyle(rowHighlightStyle) { - if (!tr.b.dictionaryContainsValue(HighlightStyle, rowHighlightStyle)) - throw new Error('Invalid row highlight style ' + rowHighlightStyle); - this.rebuildIfNeeded_(); - this.rowHighlightStyle_ = rowHighlightStyle; - this.didSelectionStateChange_(); - }, - - get resolvedRowHighlightStyle() { - if (this.rowHighlightStyle_ !== HighlightStyle.DEFAULT) - return this.rowHighlightStyle_; - switch (this.selectionMode_) { - case SelectionMode.NONE: - return HighlightStyle.NONE; - case SelectionMode.ROW: - return HighlightStyle.DARK; - case SelectionMode.CELL: - return HighlightStyle.LIGHT; - default: - throw new Error('Invalid selection mode ' + selectionMode); - } - }, + setExpandedForTableRow: function(userRow, expanded) { + this.rebuildIfNeeded_(); + var rowInfo = this.tableRowsInfo_.get(userRow); + if (rowInfo === undefined) + throw new Error('Row has not been seen, must expand its parents'); + return this.setExpandedForUserRow_(this.$.body, this.tableRowsInfo_, + userRow, expanded); + }, - get cellHighlightStyle() { - return this.cellHighlightStyle_; - }, - - set cellHighlightStyle(cellHighlightStyle) { - if (!tr.b.dictionaryContainsValue(HighlightStyle, cellHighlightStyle)) - throw new Error('Invalid cell highlight style ' + cellHighlightStyle); - this.rebuildIfNeeded_(); - this.cellHighlightStyle_ = cellHighlightStyle; - this.didSelectionStateChange_(); - }, - - get resolvedCellHighlightStyle() { - if (this.cellHighlightStyle_ !== HighlightStyle.DEFAULT) - return this.cellHighlightStyle_; - switch (this.selectionMode_) { - case SelectionMode.NONE: - case SelectionMode.ROW: - return HighlightStyle.NONE; - case SelectionMode.CELL: - return HighlightStyle.DARK; - default: - throw new Error('Invalid selection mode ' + selectionMode); + setExpandedForUserRow_: function(tableSection, rowInfoMap, + userRow, expanded) { + this.rebuildIfNeeded_(); + + var rowInfo = rowInfoMap.get(userRow); + if (rowInfo === undefined) + throw new Error('Row has not been seen, must expand its parents'); + + rowInfo.isExpanded = !!expanded; + // If no node, then nothing further needs doing. + if (rowInfo.htmlNode === undefined) + return; + + // If its detached, then nothing needs doing. + if (rowInfo.htmlNode.parentElement !== tableSection) + return; + + // Otherwise, rebuild. + var expandButton = + Polymer.dom(rowInfo.htmlNode).querySelector('expand-button'); + if (rowInfo.isExpanded) { + Polymer.dom(expandButton).classList.add('button-expanded'); + var lastAddedRow = rowInfo.htmlNode; + if (rowInfo.userRow[this.subRowsPropertyName_]) { + this.generateTableRowNodes_( + tableSection, + rowInfo.userRow[this.subRowsPropertyName_], rowInfoMap, + rowInfo.indentation + 1, + lastAddedRow, rowInfo); } - }, + } else { + Polymer.dom(expandButton).classList.remove('button-expanded'); + this.removeSubNodes_(tableSection, rowInfo, rowInfoMap); + } - setHighlightStyle_: function(highlightAttribute, resolvedHighlightStyle) { - switch (resolvedHighlightStyle) { - case HighlightStyle.NONE: - this.$.body.removeAttribute(highlightAttribute); - break; - case HighlightStyle.LIGHT: - this.$.body.setAttribute(highlightAttribute, 'light'); - break; - case HighlightStyle.DARK: - this.$.body.setAttribute(highlightAttribute, 'dark'); - break; - default: - throw new Error('Invalid resolved highlight style ' + - resolvedHighlightStyle); - } - }, + this.maybeUpdateSelectedRow_(); + }, - didSelectionStateChange_: function() { - this.setHighlightStyle_('row-highlight-style', - this.resolvedRowHighlightStyle); - this.setHighlightStyle_('cell-highlight-style', - this.resolvedCellHighlightStyle); + get selectionMode() { + return this.selectionMode_; + }, - for (var i = 0; i < this.$.body.children.length; i++) - this.updateTabIndexForTableRowNode_(this.$.body.children[i]); - this.maybeUpdateSelectedRow_(); - }, + set selectionMode(selectionMode) { + if (!tr.b.dictionaryContainsValue(SelectionMode, selectionMode)) + throw new Error('Invalid selection mode ' + selectionMode); + this.rebuildIfNeeded_(); + this.selectionMode_ = selectionMode; + this.didSelectionStateChange_(); + }, - maybeUpdateSelectedRow_: function() { - if (this.selectedTableRowInfo_ === undefined) - return; + get rowHighlightStyle() { + return this.rowHighlightStyle_; + }, - // Selection may be off. - if (this.selectionMode_ === SelectionMode.NONE) { - this.removeSelectedState_(); - this.selectedTableRowInfo_ = undefined; - return; - } + set rowHighlightStyle(rowHighlightStyle) { + if (!tr.b.dictionaryContainsValue(HighlightStyle, rowHighlightStyle)) + throw new Error('Invalid row highlight style ' + rowHighlightStyle); + this.rebuildIfNeeded_(); + this.rowHighlightStyle_ = rowHighlightStyle; + this.didSelectionStateChange_(); + }, - // selectedUserRow may not be visible - function isVisible(rowInfo) { - if (!rowInfo.htmlNode) - return false; - return !!rowInfo.htmlNode.parentElement; - } - if (isVisible(this.selectedTableRowInfo_)) { - this.updateSelectedState_(); - return; - } + get resolvedRowHighlightStyle() { + if (this.rowHighlightStyle_ !== HighlightStyle.DEFAULT) + return this.rowHighlightStyle_; + switch (this.selectionMode_) { + case SelectionMode.NONE: + return HighlightStyle.NONE; + case SelectionMode.ROW: + return HighlightStyle.DARK; + case SelectionMode.CELL: + return HighlightStyle.LIGHT; + default: + throw new Error('Invalid selection mode ' + selectionMode); + } + }, - this.removeSelectedState_(); - var curRowInfo = this.selectedTableRowInfo_; - while (curRowInfo && !isVisible(curRowInfo)) - curRowInfo = curRowInfo.parentRowInfo; + get cellHighlightStyle() { + return this.cellHighlightStyle_; + }, - this.selectedTableRowInfo_ = curRowInfo; - if (this.selectedTableRowInfo_) - this.updateSelectedState_(); - }, + set cellHighlightStyle(cellHighlightStyle) { + if (!tr.b.dictionaryContainsValue(HighlightStyle, cellHighlightStyle)) + throw new Error('Invalid cell highlight style ' + cellHighlightStyle); + this.rebuildIfNeeded_(); + this.cellHighlightStyle_ = cellHighlightStyle; + this.didSelectionStateChange_(); + }, - didTableRowInfoGetClicked_: function(rowInfo, columnIndex) { - switch (this.selectionMode_) { - case SelectionMode.NONE: - return; + get resolvedCellHighlightStyle() { + if (this.cellHighlightStyle_ !== HighlightStyle.DEFAULT) + return this.cellHighlightStyle_; + switch (this.selectionMode_) { + case SelectionMode.NONE: + case SelectionMode.ROW: + return HighlightStyle.NONE; + case SelectionMode.CELL: + return HighlightStyle.DARK; + default: + throw new Error('Invalid selection mode ' + selectionMode); + } + }, - case SelectionMode.CELL: - if (!this.doesColumnIndexSupportSelection(columnIndex)) - return; - if (this.selectedColumnIndex !== columnIndex) - this.selectedColumnIndex = columnIndex; - // Fall through. + setHighlightStyle_: function(highlightAttribute, resolvedHighlightStyle) { + switch (resolvedHighlightStyle) { + case HighlightStyle.NONE: + Polymer.dom(this.$.body).removeAttribute(highlightAttribute); + break; + case HighlightStyle.LIGHT: + Polymer.dom(this.$.body).setAttribute(highlightAttribute, 'light'); + break; + case HighlightStyle.DARK: + Polymer.dom(this.$.body).setAttribute(highlightAttribute, 'dark'); + break; + default: + throw new Error('Invalid resolved highlight style ' + + resolvedHighlightStyle); + } + }, - case SelectionMode.ROW: - if (this.selectedTableRowInfo_ !== rowInfo) - this.selectedTableRow = rowInfo.userRow; - } - }, - - get selectedTableRow() { - if (!this.selectedTableRowInfo_) - return undefined; - return this.selectedTableRowInfo_.userRow; - }, - - set selectedTableRow(userRow) { - this.rebuildIfNeeded_(); - if (this.selectionMode_ === SelectionMode.NONE) - throw new Error('Selection is off.'); - - var rowInfo; - if (userRow === undefined) { - rowInfo = undefined; - } else { - rowInfo = this.tableRowsInfo_.get(userRow); - if (!rowInfo) - throw new Error('Row has not been seen, must expand its parents.'); - } + didSelectionStateChange_: function() { + this.setHighlightStyle_('row-highlight-style', + this.resolvedRowHighlightStyle); + this.setHighlightStyle_('cell-highlight-style', + this.resolvedCellHighlightStyle); - var e = this.prepareToChangeSelection_(); - this.selectedTableRowInfo_ = rowInfo; + this.removeSelectedState_(); - if (this.selectedTableRowInfo_ === undefined) { + switch (this.selectionMode_) { + case SelectionMode.ROW: + // TODO: Replace this.selectionMode_ with a proper Polymer attribute. + Polymer.dom(this.$.body).setAttribute('selection-mode', 'row'); + Polymer.dom(this.$.body).setAttribute('tabindex', 0); this.selectedColumnIndex_ = undefined; - this.removeSelectedState_(); - } else { - switch (this.selectionMode_) { - case SelectionMode.ROW: - this.selectedColumnIndex_ = undefined; - break; + break; + case SelectionMode.CELL: + Polymer.dom(this.$.body).setAttribute('selection-mode', 'cell'); + Polymer.dom(this.$.body).setAttribute('tabindex', 0); + if (this.selectedTableRowInfo_ && + this.selectedColumnIndex_ === undefined) { + var i = this.getFirstSelectableColumnIndex_(); + if (i === -1) { + // No column is selectable. + this.selectedTableRowInfo_ = undefined; + } else { + this.selectedColumnIndex_ = i; + } + } + break; + case SelectionMode.NONE: + Polymer.dom(this.$.body).removeAttribute('selection-mode'); + Polymer.dom(this.$.body).removeAttribute('tabindex'); + this.$.body.blur(); // Remove focus (if applicable). + this.selectedTableRowInfo_ = undefined; + this.selectedColumnIndex_ = undefined; + break; + default: + throw new Error('Invalid selection mode ' + this.selectionMode_); + } - case SelectionMode.CELL: - if (this.selectedColumnIndex_ === undefined) { - var i = this.getFirstSelectableColumnIndex_(); - if (i == -1) - throw new Error('Cannot find a selectable column.'); - this.selectedColumnIndex_ = i; - } - break; + this.maybeUpdateSelectedRow_(); + }, - default: - throw new Error('Invalid selection mode ' + this.selectionMode_); - } - this.updateSelectedState_(); - } + maybeUpdateSelectedRow_: function() { + if (this.selectedTableRowInfo_ === undefined) + return; - this.dispatchEvent(e); - }, + // selectedUserRow may not be visible + function isVisible(rowInfo) { + if (!rowInfo.htmlNode) + return false; + return !!rowInfo.htmlNode.parentElement; + } + if (isVisible(this.selectedTableRowInfo_)) { + this.updateSelectedState_(); + return; + } - updateTabIndexForTableRowNode_: function(row) { - if (this.selectionMode_ === SelectionMode.ROW) - row.tabIndex = 0; - else - row.removeAttribute('tabIndex'); + this.removeSelectedState_(); + var curRowInfo = this.selectedTableRowInfo_; + while (curRowInfo && !isVisible(curRowInfo)) + curRowInfo = curRowInfo.parentRowInfo; - var enableCellTab = this.selectionMode_ === SelectionMode.CELL; - for (var i = 0; i < this.tableColumns_.length; i++) { - var cell = row.children[i]; - if (enableCellTab && this.doesColumnIndexSupportSelection(i)) - cell.tabIndex = 0; - else - cell.removeAttribute('tabIndex'); - } - }, + this.selectedTableRowInfo_ = curRowInfo; + if (this.selectedTableRowInfo_) + this.updateSelectedState_(); + else + this.selectedColumnIndex_ = undefined; + }, - prepareToChangeSelection_: function() { - var e = new tr.b.Event('selection-changed'); - var previousSelectedRowInfo = this.selectedTableRowInfo_; - if (previousSelectedRowInfo) - e.previousSelectedTableRow = previousSelectedRowInfo.userRow; - else - e.previousSelectedTableRow = undefined; + didTableRowInfoGetClicked_: function(rowInfo, columnIndex) { + switch (this.selectionMode_) { + case SelectionMode.NONE: + return; - this.removeSelectedState_(); + case SelectionMode.CELL: + if (!this.doesColumnIndexSupportSelection(columnIndex)) + return; + if (this.selectedColumnIndex !== columnIndex) + this.selectedColumnIndex = columnIndex; + // Fall through. - return e; - }, + case SelectionMode.ROW: + if (this.selectedTableRowInfo_ !== rowInfo) + this.selectedTableRow = rowInfo.userRow; + } + }, - removeSelectedState_: function() { - this.setSelectedState_(false); - }, + dispatchStepIntoEvent_: function(rowInfo, columnIndex) { + var e = new tr.b.Event('step-into'); + e.tableRow = rowInfo.userRow; + e.tableColumn = this.tableColumns_[columnIndex]; + e.columnIndex = columnIndex; + this.dispatchEvent(e); + }, - updateSelectedState_: function() { - this.setSelectedState_(true); - }, + /** + * If the selectionMode is CELL and a cell is selected, + * return an object containing the row, column, and value of the selected + * cell. + * + * @return {undefined|!Object} + */ + get selectedCell() { + var row = this.selectedTableRow; + var columnIndex = this.selectedColumnIndex; + if (row === undefined || columnIndex === undefined || + this.tableColumns_.length <= columnIndex) + return undefined; + var column = this.tableColumns_[columnIndex]; + return { + row: row, + column: column, + value: column.value(row) + }; + }, - setSelectedState_: function(select) { - if (this.selectedTableRowInfo_ === undefined) - return; + /** + * If a column is selected, return the object describing the selected + * column. + * + * Columns can be selected independently of rows and cells. So it is + * possible to select column 0 and cell [0,0], or column 1 and cell [0,0], + * for example. See |selectedCell| for how to access the selected cell when + * the selectionMode is CELL. + * + * |selectedTableColumn| is entirely independent of |selectedColumnIndex|. + * When the table selectionMode is CELL, use |selectedTableRow| and + * |selectedColumnIndex| to find the selected cell. + * When one or more columns have |selectable:true|, then use + * |selectedTableColumn| to find the selected column, which may be either + * the same as or different from |selectedColumnIndex|, if a cell is also + * selected. + * + * @return {number|undefined} + */ + get selectedTableColumnIndex() { + var cols = Polymer.dom(this.$.cols).children; + for (var i = 0; i < cols.length; ++i) { + if (cols[i].getAttribute('selected')) { + return i; + } + } + return undefined; + }, - // Row selection. - var rowNode = this.selectedTableRowInfo_.htmlNode; - if (select) - rowNode.setAttribute('selected', true); + /** + * @param {number|undefined} index + */ + set selectedTableColumnIndex(selectedIndex) { + var cols = Polymer.dom(this.$.cols).children; + for (var i = 0; i < cols.length; ++i) { + if (i === selectedIndex) + cols[i].setAttribute('selected', true); else - rowNode.removeAttribute('selected'); + cols[i].removeAttribute('selected'); + } + }, - // Cell selection (if applicable). - var cellNode = rowNode.children[this.selectedColumnIndex_]; - if (!cellNode) - return; - if (select) - cellNode.setAttribute('selected', true); - else - cellNode.removeAttribute('selected'); - }, + get selectedTableRow() { + if (!this.selectedTableRowInfo_) + return undefined; + return this.selectedTableRowInfo_.userRow; + }, - doesColumnIndexSupportSelection: function(columnIndex) { - var columnInfo = this.tableColumns_[columnIndex]; - var scs = columnInfo.supportsCellSelection; - if (scs === false) - return false; - return true; - }, + set selectedTableRow(userRow) { + this.rebuildIfNeeded_(); + if (this.selectionMode_ === SelectionMode.NONE) + throw new Error('Selection is off.'); + + var rowInfo; + if (userRow === undefined) { + rowInfo = undefined; + } else { + rowInfo = this.tableRowsInfo_.get(userRow); + if (!rowInfo) + throw new Error('Row has not been seen, must expand its parents.'); + } - getFirstSelectableColumnIndex_: function() { - for (var i = 0; i < this.tableColumns_.length; i++) { - if (this.doesColumnIndexSupportSelection(i)) - return i; - } - return -1; - }, + var e = this.prepareToChangeSelection_(); - getSelectableNodeGivenTableRowNode_: function(htmlNode) { + if (!rowInfo) { + this.selectedColumnIndex_ = undefined; + } else { switch (this.selectionMode_) { case SelectionMode.ROW: - return htmlNode; + this.selectedColumnIndex_ = undefined; + break; case SelectionMode.CELL: - return htmlNode.children[this.selectedColumnIndex_]; + if (this.selectedColumnIndex_ === undefined) { + var i = this.getFirstSelectableColumnIndex_(); + if (i === -1) + throw new Error('Cannot find a selectable column.'); + this.selectedColumnIndex_ = i; + } + break; default: throw new Error('Invalid selection mode ' + this.selectionMode_); } - }, - - get selectedColumnIndex() { - if (this.selectionMode_ !== SelectionMode.CELL) - return undefined; - return this.selectedColumnIndex_; - }, - - set selectedColumnIndex(selectedColumnIndex) { - this.rebuildIfNeeded_(); - if (this.selectionMode_ === SelectionMode.NONE) - throw new Error('Selection is off.'); - if (selectedColumnIndex < 0 || - selectedColumnIndex >= this.tableColumns_.length) - throw new Error('Invalid index'); - if (!this.doesColumnIndexSupportSelection(selectedColumnIndex)) - throw new Error('Selection is not supported on this column'); - - var e = this.prepareToChangeSelection_(); - this.selectedColumnIndex_ = selectedColumnIndex; - if (this.selectedColumnIndex_ === undefined) - this.selectedTableRowInfo_ = undefined; - this.updateSelectedState_(); + } - this.dispatchEvent(e); - }, + this.selectedTableRowInfo_ = rowInfo; + this.updateSelectedState_(); + this.dispatchEvent(e); + }, - onKeyDown_: function(e) { - if (this.selectionMode_ === SelectionMode.NONE) - return; - if (this.selectedTableRowInfo_ === undefined) - return; + prepareToChangeSelection_: function() { + var e = new tr.b.Event('selection-changed'); + var previousSelectedRowInfo = this.selectedTableRowInfo_; + if (previousSelectedRowInfo) + e.previousSelectedTableRow = previousSelectedRowInfo.userRow; + else + e.previousSelectedTableRow = undefined; - var code_to_command_names = { - 13: 'ENTER', - 37: 'ARROW_LEFT', - 38: 'ARROW_UP', - 39: 'ARROW_RIGHT', - 40: 'ARROW_DOWN' - }; - var cmdName = code_to_command_names[e.keyCode]; - if (cmdName === undefined) - return; + this.removeSelectedState_(); - e.stopPropagation(); - e.preventDefault(); - this.performKeyCommand_(cmdName); - }, - - performKeyCommand_: function(cmdName) { - this.rebuildIfNeeded_(); - - var rowInfo = this.selectedTableRowInfo_; - var htmlNode = rowInfo.htmlNode; - if (cmdName === 'ARROW_UP') { - var prev = htmlNode.previousElementSibling; - if (prev) { - tr.ui.b.scrollIntoViewIfNeeded(prev); - this.selectedTableRow = prev.rowInfo.userRow; - this.focusSelected_(); - return; - } + return e; + }, + + removeSelectedState_: function() { + this.setSelectedState_(false); + }, + + updateSelectedState_: function() { + this.setSelectedState_(true); + }, + + setSelectedState_: function(select) { + if (this.selectedTableRowInfo_ === undefined) + return; + + // Row selection. + var rowNode = this.selectedTableRowInfo_.htmlNode; + if (select) + Polymer.dom(rowNode).setAttribute('selected', true); + else + Polymer.dom(rowNode).removeAttribute('selected'); + + // Cell selection (if applicable). + var cellNode = Polymer.dom(rowNode).children[this.selectedColumnIndex_]; + if (!cellNode) + return; + if (select) + Polymer.dom(cellNode).setAttribute('selected', true); + else + Polymer.dom(cellNode).removeAttribute('selected'); + }, + + doesColumnIndexSupportSelection: function(columnIndex) { + var columnInfo = this.tableColumns_[columnIndex]; + var scs = columnInfo.supportsCellSelection; + if (scs === false) + return false; + return true; + }, + + getFirstSelectableColumnIndex_: function() { + for (var i = 0; i < this.tableColumns_.length; i++) { + if (this.doesColumnIndexSupportSelection(i)) + return i; + } + return -1; + }, + + getSelectableNodeGivenTableRowNode_: function(htmlNode) { + switch (this.selectionMode_) { + case SelectionMode.ROW: + return htmlNode; + + case SelectionMode.CELL: + return Polymer.dom(htmlNode).children[this.selectedColumnIndex_]; + + default: + throw new Error('Invalid selection mode ' + this.selectionMode_); + } + }, + + get selectedColumnIndex() { + if (this.selectionMode_ !== SelectionMode.CELL) + return undefined; + return this.selectedColumnIndex_; + }, + + set selectedColumnIndex(selectedColumnIndex) { + this.rebuildIfNeeded_(); + if (this.selectionMode_ === SelectionMode.NONE) + throw new Error('Selection is off.'); + if (selectedColumnIndex < 0 || + selectedColumnIndex >= this.tableColumns_.length) + throw new Error('Invalid index'); + if (!this.doesColumnIndexSupportSelection(selectedColumnIndex)) + throw new Error('Selection is not supported on this column'); + + var e = this.prepareToChangeSelection_(); + if (this.selectedColumnIndex_ === undefined) { + this.selectedTableRowInfo_ = undefined; + } else if (!this.selectedTableRowInfo_) { + if (this.tableRows_.length === 0) + throw new Error('No available row to be selected'); + this.selectedTableRowInfo_ = + this.tableRowsInfo_.get(this.tableRows_[0]); + } + this.selectedColumnIndex_ = selectedColumnIndex; + this.updateSelectedState_(); + this.dispatchEvent(e); + }, + + onKeyDown_: function(e) { + if (this.selectionMode_ === SelectionMode.NONE) + return; + + var CODE_TO_COMMAND_NAMES = { + 13: 'ENTER', + 32: 'SPACE', + 37: 'ARROW_LEFT', + 38: 'ARROW_UP', + 39: 'ARROW_RIGHT', + 40: 'ARROW_DOWN' + }; + var cmdName = CODE_TO_COMMAND_NAMES[e.keyCode]; + if (cmdName === undefined) + return; + + e.stopPropagation(); + e.preventDefault(); + this.performKeyCommand_(cmdName); + }, + + onFocus_: function(e) { + if (this.selectionMode_ === SelectionMode.NONE || + this.selectedTableRowInfo_ || + this.tableRows_.length === 0) { + return; + } + + if (this.selectionMode_ === SelectionMode.CELL && + this.getFirstSelectableColumnIndex_() === -1) { + // If there are no selectable columns in cell selection mode, don't do + // anything. + return; + } + + this.selectedTableRow = this.tableRows_[0]; + }, + + focus: function() { + this.$.body.focus(); + }, + + blur: function() { + this.$.body.blur(); + }, + + get isFocused() { + return this.root.activeElement === this.$.body; + }, + + performKeyCommand_: function(cmdName) { + this.rebuildIfNeeded_(); + + switch (cmdName) { + case 'ARROW_UP': + this.selectPreviousOrFirstRowIfPossible_(); return; - } - if (cmdName === 'ARROW_DOWN') { - var next = htmlNode.nextElementSibling; - if (next) { - tr.ui.b.scrollIntoViewIfNeeded(next); - this.selectedTableRow = next.rowInfo.userRow; - this.focusSelected_(); - return; - } + case 'ARROW_DOWN': + this.selectNextOrFirstRowIfPossible_(); return; - } - if (cmdName === 'ARROW_RIGHT') { + case 'ARROW_RIGHT': switch (this.selectionMode_) { + case SelectionMode.NONE: + return; // No action. case SelectionMode.ROW: - if (rowInfo.userRow[this.subRowsPropertyName_] === undefined) - return; - if (rowInfo.userRow[this.subRowsPropertyName_].length === 0) - return; - - if (!rowInfo.isExpanded) - this.setExpandedForTableRow(rowInfo.userRow, true); - this.selectedTableRow = - htmlNode.nextElementSibling.rowInfo.userRow; - this.focusSelected_(); + this.expandRowAndSelectChildRowIfPossible_(); return; - case SelectionMode.CELL: - var newIndex = this.selectedColumnIndex_ + 1; - if (newIndex >= this.tableColumns_.length) - return; - if (!this.doesColumnIndexSupportSelection(newIndex)) - return; - this.selectedColumnIndex = newIndex; - this.focusSelected_(); + this.selectNextSelectableCellToTheRightIfPossible_(); return; - default: throw new Error('Invalid selection mode ' + this.selectionMode_); } - } - if (cmdName === 'ARROW_LEFT') { + case 'ARROW_LEFT': switch (this.selectionMode_) { + case SelectionMode.NONE: + return; // No action. case SelectionMode.ROW: - if (rowInfo.isExpanded) { - this.setExpandedForTableRow(rowInfo.userRow, false); - this.focusSelected_(); - return; - } - - // Not expanded. Select parent... - var parentRowInfo = rowInfo.parentRowInfo; - if (parentRowInfo) { - this.selectedTableRow = parentRowInfo.userRow; - this.focusSelected_(); - return; - } + this.collapseRowOrSelectParentRowIfPossible_(); return; - case SelectionMode.CELL: - var newIndex = this.selectedColumnIndex_ - 1; - if (newIndex < 0) - return; - if (!this.doesColumnIndexSupportSelection(newIndex)) - return; - this.selectedColumnIndex = newIndex; - this.focusSelected_(); + this.selectNextSelectableCellToTheLeftIfPossible_(); return; - default: throw new Error('Invalid selection mode ' + this.selectionMode_); } + + case 'SPACE': + this.toggleRowExpansionStateIfPossible_(); + return; + + case 'ENTER': + this.stepIntoSelectionIfPossible_(); + return; + + default: + throw new Error('Unrecognized command ' + cmdName); + } + }, + + selectPreviousOrFirstRowIfPossible_: function() { + var prev = this.selectedTableRowInfo_ ? + this.selectedTableRowInfo_.htmlNode.previousElementSibling : + this.$.body.firstChild; + if (!prev) + return; + if (this.selectionMode_ === SelectionMode.CELL && + this.getFirstSelectableColumnIndex_() === -1) { + // If there are no selectable columns in cell selection mode, don't do + // anything. + return; + } + tr.ui.b.scrollIntoViewIfNeeded(prev); + this.selectedTableRow = prev.rowInfo.userRow; + }, + + selectNextOrFirstRowIfPossible_: function() { + this.getFirstSelectableColumnIndex_ + var next = this.selectedTableRowInfo_ ? + this.selectedTableRowInfo_.htmlNode.nextElementSibling : + this.$.body.firstChild; + if (!next) + return; + if (this.selectionMode_ === SelectionMode.CELL && + this.getFirstSelectableColumnIndex_() === -1) { + // If there are no selectable columns in cell selection mode, don't do + // anything. + return; + } + tr.ui.b.scrollIntoViewIfNeeded(next); + this.selectedTableRow = next.rowInfo.userRow; + }, + + expandRowAndSelectChildRowIfPossible_: function() { + var selectedRowInfo = this.selectedTableRowInfo_; + if (!selectedRowInfo || + selectedRowInfo.userRow[this.subRowsPropertyName_] === undefined || + selectedRowInfo.userRow[this.subRowsPropertyName_].length === 0) { + return; + } + if (!selectedRowInfo.isExpanded) + this.setExpandedForTableRow(selectedRowInfo.userRow, true); + this.selectedTableRow = + selectedRowInfo.htmlNode.nextElementSibling.rowInfo.userRow; + }, + + collapseRowOrSelectParentRowIfPossible_: function() { + var selectedRowInfo = this.selectedTableRowInfo_; + if (!selectedRowInfo) + return; + if (selectedRowInfo.isExpanded) { + // If the node is expanded, collapse it. + this.setExpandedForTableRow(selectedRowInfo.userRow, false); + } else { + // If the node is not expanded, select its parent. + var parentRowInfo = selectedRowInfo.parentRowInfo; + if (parentRowInfo) + this.selectedTableRow = parentRowInfo.userRow; + } + }, + + selectNextSelectableCellToTheRightIfPossible_: function() { + if (!this.selectedTableRowInfo_ || + this.selectedColumnIndex_ === undefined) { + return; + } + for (var i = this.selectedColumnIndex_ + 1; i < this.tableColumns_.length; + i++) { + if (this.doesColumnIndexSupportSelection(i)) { + this.selectedColumnIndex = i; + return; } + } + }, - if (cmdName === 'ENTER') { - if (rowInfo.userRow[this.subRowsPropertyName_] === undefined) - return; - if (rowInfo.userRow[this.subRowsPropertyName_].length === 0) - return; - this.setExpandedForTableRow(rowInfo.userRow, !rowInfo.isExpanded); - this.focusSelected_(); + selectNextSelectableCellToTheLeftIfPossible_: function() { + if (!this.selectedTableRowInfo_ || + this.selectedColumnIndex_ === undefined) { + return; + } + for (var i = this.selectedColumnIndex_ - 1; i >= 0; i--) { + if (this.doesColumnIndexSupportSelection(i)) { + this.selectedColumnIndex = i; return; } + } + }, + + toggleRowExpansionStateIfPossible_: function() { + var selectedRowInfo = this.selectedTableRowInfo_; + if (!selectedRowInfo || + selectedRowInfo.userRow[this.subRowsPropertyName_] === undefined || + selectedRowInfo.userRow[this.subRowsPropertyName_].length === 0) { + return; + } + this.setExpandedForTableRow(selectedRowInfo.userRow, + !selectedRowInfo.isExpanded); + }, - throw new Error('Unrecognized command ' + cmdName); - }, + stepIntoSelectionIfPossible_: function() { + if (!this.selectedTableRowInfo_) + return; + this.dispatchStepIntoEvent_(this.selectedTableRowInfo_, + this.selectedColumnIndex_); + }, - focusSelected_: function() { - if (!this.selectedTableRowInfo_) - return; - var node = this.getSelectableNodeGivenTableRowNode_( - this.selectedTableRowInfo_.htmlNode); - node.focus(); - }, - - dispatchSortingChangedEvent_: function() { - var e = new tr.b.Event('sort-column-changed'); - e.sortColumnIndex = this.sortColumnIndex_; - e.sortDescending = this.sortDescending_; - this.dispatchEvent(e); - } - }); - })(); - </script> -</polymer-element> -<polymer-element name="tr-ui-b-table-header-cell" on-tap="onTap_"> + dispatchSortingChangedEvent_: function() { + var e = new tr.b.Event('sort-column-changed'); + e.sortColumnIndex = this.sortColumnIndex_; + e.sortDescending = this.sortDescending_; + this.dispatchEvent(e); + } + }); +})(); +</script> + +<dom-module id="tr-ui-b-table-header-cell"> <template> <style> :host { @@ -1380,94 +1623,131 @@ tr.exportTo('tr.ui.b', function() { flex: 0 1 auto; } - side-element { + #side { -webkit-user-select: none; flex: 0 0 auto; - padding-left: 4px; + padding-left: 2px; + padding-right: 2px; vertical-align: top; font-size: 15px; font-family: sans-serif; - display: inline; line-height: 85%; + margin-left: 5px; } - </style> - - <span id="title"></span><side-element id="side"></side-element> - </template> - <script> - 'use strict'; + #side.disabled { + color: rgb(140, 140, 140); + } - var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment; + #title:empty, #side:empty { + display: none; + } + </style> - Polymer({ - created: function() { - this.tapCallback_ = undefined; - this.cellTitle_ = ''; - this.align_ = undefined; - }, + <span id="title"></span> + <span id="side"></span> + </template> +</dom-module> +<script> +'use strict'; - set cellTitle(value) { - this.cellTitle_ = value; +var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment; - var titleNode = tr.ui.b.asHTMLOrTextNode( - this.cellTitle_, this.ownerDocument); +Polymer({ + is: 'tr-ui-b-table-header-cell', - this.$.title.innerText = ''; - this.$.title.appendChild(titleNode); - }, + created: function() { + this.tapCallback_ = undefined; + this.cellTitle_ = ''; + this.align_ = undefined; + this.selectable_ = false; + this.column_ = undefined; + }, - get cellTitle() { - return this.cellTitle_; - }, + ready: function() { + this.addEventListener('click', this.onTap_.bind(this)); + }, - set align(align) { - switch (align) { - case undefined: - case ColumnAlignment.LEFT: - this.style.justifyContent = ''; - break; + set column(column) { + this.column_ = column; + this.align = column.align; + this.cellTitle = column.title; + }, - case ColumnAlignment.RIGHT: - this.style.justifyContent = 'flex-end'; - break; + get column() { + return this.column_; + }, - default: - throw new Error('Invalid alignment of column (title=\'' + - this.cellTitle_ + '\'): ' + align); - } - this.align_ = align; - }, + set cellTitle(value) { + this.cellTitle_ = value; - get align() { - return this.align_; - }, + var titleNode = tr.ui.b.asHTMLOrTextNode( + this.cellTitle_, this.ownerDocument); - clearSideContent: function() { - this.$.side.textContent = ''; - }, + this.$.title.innerText = ''; - set sideContent(content) { - this.$.side.textContent = content; - }, + Polymer.dom(this.$.title).appendChild(titleNode); + }, - get sideContent() { - return this.$.side.textContent; - }, + get cellTitle() { + return this.cellTitle_; + }, - set tapCallback(callback) { - this.style.cursor = 'pointer'; - this.tapCallback_ = callback; - }, + set align(align) { + switch (align) { + case undefined: + case ColumnAlignment.LEFT: + this.style.justifyContent = ''; + break; - get tapCallback() { - return this.tapCallback_; - }, + case ColumnAlignment.RIGHT: + this.style.justifyContent = 'flex-end'; + break; - onTap_: function() { - if (this.tapCallback_) - this.tapCallback_(); + default: + throw new Error('Invalid alignment of column (title=\'' + + this.cellTitle_ + '\'): ' + align); } - }); + this.align_ = align; + }, + + get align() { + return this.align_; + }, + + clearSideContent: function() { + Polymer.dom(this.$.side).textContent = ''; + }, + + set sideContent(content) { + Polymer.dom(this.$.side).textContent = content; + this.$.side.style.display = content ? 'inline' : 'none'; + }, + + get sideContent() { + return Polymer.dom(this.$.side).textContent; + }, + + set sideContentDisabled(sideContentDisabled) { + this.$.side.classList.toggle('disabled', sideContentDisabled); + }, + + get sideContentDisabled() { + return this.$.side.classList.contains('disabled'); + }, + + set tapCallback(callback) { + this.style.cursor = 'pointer'; + this.tapCallback_ = callback; + }, + + get tapCallback() { + return this.tapCallback_; + }, + + onTap_: function() { + if (this.tapCallback_) + this.tapCallback_(); + } +}); </script> -</polymer-element> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html index f6ba5eb35dd..d822c251262 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table_header_cell.html @@ -8,8 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/utils.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> -<polymer-element name="tr-ui-b-table-header-cell" - on-tap="onTap_"> +<dom-module id='tr-ui-b-table-header-cell'> <template> <style> :host { @@ -35,11 +34,17 @@ found in the LICENSE file. <span id="title"></span><side-element id="side"></side-element> </template> - +</dom-module> <script> 'use strict'; Polymer({ + is: 'tr-ui-b-table-header-cell', + + listeners: { + 'tap': 'onTap_' + }, + created: function() { this.tapCallback_ = undefined; this.cellTitle_ = ''; @@ -52,7 +57,7 @@ found in the LICENSE file. tr.ui.b.asHTMLOrTextNode(this.cellTitle_, this.ownerDocument); this.$.title.innerText = ''; - this.$.title.appendChild(titleNode); + Polymer.dom(this.$.title).appendChild(titleNode); }, get cellTitle() { @@ -60,15 +65,15 @@ found in the LICENSE file. }, clearSideContent: function() { - this.$.side.textContent = ''; + Polymer.dom(this.$.side).textContent = ''; }, set sideContent(content) { - this.$.side.textContent = content; + Polymer.dom(this.$.side).textContent = content; }, get sideContent() { - return this.$.side.textContent; + return Polymer.dom(this.$.side).textContent; }, set tapCallback(callback) { @@ -86,4 +91,3 @@ found in the LICENSE file. } }); </script> -</polymer-element> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html index 0c3504fc318..8778646c562 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/table_test.html @@ -12,7 +12,7 @@ found in the LICENSE file. 'use strict'; tr.b.unittest.testSuite(function() { - var THIS_DOC = document._currentScript.ownerDocument; + var THIS_DOC = document.currentScript.ownerDocument; var SelectionMode = tr.ui.b.TableFormat.SelectionMode; var HighlightStyle = tr.ui.b.TableFormat.HighlightStyle; var ColumnAlignment = tr.ui.b.TableFormat.ColumnAlignment; @@ -23,6 +23,16 @@ tr.b.unittest.testSuite(function() { return element.getAttribute('selected') === 'true'; } + function simulateDoubleClick(element) { + // See https://developer.mozilla.org/en/docs/Web/API/MouseEvent#Example. + var event = new MouseEvent('dblclick', { + bubbles: true, + cancelable: true, + view: window + }); + return element.dispatchEvent(event); + } + test('instantiateEmptyTable_withoutEmptyValue', function() { var columns = [ { @@ -51,7 +61,7 @@ tr.b.unittest.testSuite(function() { // Check that the first column has a non-empty header. var firstColumnTitle = tr.b.findDeepElementMatchingPredicate( firstColumnHeader, function(element) { - return element.textContent === 'First Column'; + return Polymer.dom(element).textContent === 'First Column'; }); assert.isDefined(firstColumnTitle); @@ -328,7 +338,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(table); var button = THIS_DOC.createElement('button'); - button.textContent = 'Sort By Col 0'; + Polymer.dom(button).textContent = 'Sort By Col 0'; button.addEventListener('click', function() { table.sortDescending = !table.sortDescending; table.sortColumnIndex = 0; @@ -374,18 +384,20 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(table); var a1El = tr.b.findDeepElementMatchingPredicate(table, function(element) { - return element.textContent == 'a1'; + return Polymer.dom(element).textContent === 'a1'; }); assert.isDefined(a1El); var bToplevelEl = tr.b.findDeepElementMatchingPredicate( table, function(element) { - return element.textContent == 'bToplevel'; + return Polymer.dom(element).textContent === 'bToplevel'; }); assert.isDefined(bToplevelEl); - var expandButton = bToplevelEl.parentElement.querySelector('expand-button'); - assert.isTrue(expandButton.classList.contains('button-expanded')); + var expandButton = Polymer.dom(bToplevelEl.parentElement) + .querySelector('expand-button'); + assert.isTrue(Polymer.dom(expandButton).classList.contains( + 'button-expanded')); }); @@ -692,7 +704,7 @@ tr.b.unittest.testSuite(function() { var r2 = table.$.body.children[2]; assert.equal(r2.rowInfo.userRow, rows[0].subRows[2]); - assert.isFalse(r0.hasAttribute('tabIndex')); + assert.isFalse(table.$.body.hasAttribute('tabindex')); }); function createSimpleOneColumnNestedTable() { @@ -742,6 +754,69 @@ tr.b.unittest.testSuite(function() { return table; } + function createMultiColumnNestedTable() { + var table = document.createElement('tr-ui-b-table'); + + var columns = [ + { + title: 'Title', + value: function(row) { return row.value; }, + cmp: function(rowA, rowB) { + return rowA.value.toString().localeCompare( + rowB.value.toString()); + }, + width: '150px', + supportsCellSelection: false + }, + { + title: 'A', + value: function(row) { return row.a; }, + width: '25%' + }, + { + title: 'B', + value: function(row) { return row.b; }, + width: '25%' + }, + { + title: 'C', + value: function(row) { return row.c; }, + width: '25%', + supportsCellSelection: false + }, + { + title: 'D', + value: function(row) { return row.d; }, + width: '25%' + } + ]; + + var rows = [ + { + value: 'R1', + a: 1, b: 2, c: 3, d: 4, + subRows: [ + { + value: 'R1.1', + a: 2, b: 3, c: 4, d: 1, + }, + { + value: 'R1.2', + a: 3, b: 4, c: 1, d: 2, + } + ] + }, + { + value: 'R2', + a: 3, b: 4, c: 1, d: 2 + } + ]; + + table.tableColumns = columns; + table.tableRows = rows; + return table; + } + test('expandAfterRebuild', function() { var table = createSimpleOneColumnNestedTable(); table.rebuild(); @@ -759,32 +834,38 @@ tr.b.unittest.testSuite(function() { }); test('tableSelection', function() { - var table = createSimpleOneColumnNestedTable(); + var table = createMultiColumnNestedTable(); var rows = table.tableRows; table.selectionMode = SelectionMode.ROW; table.selectedTableRow = rows[0]; + assert.isUndefined(table.selectedColumnIndex); table.setExpandedForTableRow(rows[0], true); table.selectedTableRow = rows[0].subRows[1]; - assert.equal(table.selectedTableRow, rows[0].subRows[1]); + assert.strictEqual(table.selectedTableRow, rows[0].subRows[1]); + assert.isUndefined(table.selectedColumnIndex); + + table.selectionMode = SelectionMode.CELL; + assert.strictEqual(table.selectedTableRow, rows[0].subRows[1]); + assert.strictEqual(table.selectedColumnIndex, 1); table.setExpandedForTableRow(rows[0], false); - assert.equal(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); table.selectionMode = SelectionMode.NONE; - assert.equal(table.selectedTableRow, undefined); + assert.strictEqual(table.selectedTableRow, undefined); table.selectionMode = SelectionMode.ROW; table.setExpandedForTableRow(rows[0].subRows[1], true); this.addHTMLOutput(table); - var r0 = table.$.body.children[0]; - assert.isTrue(r0.hasAttribute('tabIndex')); + assert.isTrue(table.$.body.hasAttribute('tabindex')); }); - test('keyMovement', function() { + test('keyMovement_rows', function() { var table = createSimpleOneColumnNestedTable(); table.selectionMode = SelectionMode.ROW; this.addHTMLOutput(table); @@ -800,11 +881,11 @@ tr.b.unittest.testSuite(function() { // Enter on collapsed row should expand. table.selectedTableRow = rows[0]; - table.performKeyCommand_('ENTER'); + table.performKeyCommand_('SPACE'); assert.equal(table.selectedTableRow, rows[0]); assert.isTrue(table.getExpandedForTableRow(rows[0])); - table.performKeyCommand_('ENTER'); + table.performKeyCommand_('SPACE'); assert.isFalse(table.getExpandedForTableRow(rows[0])); // Arrow right on collapsed row should expand. @@ -838,6 +919,315 @@ tr.b.unittest.testSuite(function() { assert.isFalse(table.getExpandedForTableRow(rows[1])); }); + test('keyMovement_cells', function() { + var table = createMultiColumnNestedTable(); + table.selectionMode = SelectionMode.CELL; + this.addHTMLOutput(table); + + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + var rows = table.tableRows; + table.selectedTableRow = rows[1]; + assert.strictEqual(table.selectedColumnIndex, 1); + + table.performKeyCommand_('ARROW_LEFT'); + assert.strictEqual(table.selectedTableRow, rows[1]); + // No-op (leftmost selectable cell already selected). + assert.strictEqual(table.selectedColumnIndex, 1); + + table.performKeyCommand_('ARROW_UP'); + // No-op (top row already selected). + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + + table.performKeyCommand_('ARROW_UP'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + + table.performKeyCommand_('ARROW_RIGHT'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 2); + // Right arrow should NOT expand nested rows in cell selection mode. + assert.isFalse(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_RIGHT'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 4); + assert.isFalse(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_RIGHT'); + assert.strictEqual(table.selectedTableRow, rows[0]); + // No-op (rightmost selectable cell already selected). + assert.strictEqual(table.selectedColumnIndex, 4); + assert.isFalse(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('SPACE'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 4); + // Space on collapsed row should expand it. + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_DOWN'); + assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]); + assert.strictEqual(table.selectedColumnIndex, 4); + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_LEFT'); + // Left arrow should NOT move to parent row. + assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]); + assert.strictEqual(table.selectedColumnIndex, 2); + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_LEFT'); + assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_LEFT'); + assert.strictEqual(table.selectedTableRow, rows[0].subRows[0]); + // No-op (leftmost selectable cell already selected). + assert.strictEqual(table.selectedColumnIndex, 1); + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_UP'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_LEFT'); + assert.strictEqual(table.selectedTableRow, rows[0]); + // No-op (leftmost selectable cell already selected). + assert.strictEqual(table.selectedColumnIndex, 1); + // Left arrow should NOT collapse nested rows in cell selection mode. + assert.isTrue(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('SPACE'); + assert.strictEqual(table.selectedTableRow, rows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + // Space on expanded row should collapse it. + assert.isFalse(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_DOWN'); + assert.strictEqual(table.selectedTableRow, rows[1]); + assert.strictEqual(table.selectedColumnIndex, 1); + assert.isFalse(table.getExpandedForTableRow(rows[0])); + + table.performKeyCommand_('ARROW_DOWN'); + // No-op (bottom row already selected). + assert.strictEqual(table.selectedTableRow, rows[1]); + assert.strictEqual(table.selectedColumnIndex, 1); + assert.isFalse(table.getExpandedForTableRow(rows[0])); + }); + + test('focus_empty', function() { + var table = createSimpleOneColumnNestedTable(); + table.tableRows = []; + table.emptyValue = 'This table is left intentionally empty'; + this.addHTMLOutput(table); + + assert.isFalse(table.$.body.hasAttribute('tabindex')); + assert.isFalse(table.isFocused); + + for (var selectionMode of [SelectionMode.ROW, SelectionMode.CELL]) { + table.selectionMode = selectionMode; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually focus. + table.focus(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually unfocus. + table.blur(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually focus again. + table.focus(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Unfocus via removing selection mode. + table.selectionMode = SelectionMode.NONE; + assert.isFalse(table.$.body.hasAttribute('tabindex')); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + } + + // Re-enable selection mode (for interactive testing). + table.selectionMode = SelectionMode.ROW; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + }); + + test('focus_rows', function() { + var table = createSimpleOneColumnNestedTable(); + table.selectionMode = SelectionMode.ROW; + this.addHTMLOutput(table); + + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually focus. + table.focus(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.isUndefined(table.selectedColumnIndex); + + // Manually unfocus. + table.blur(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.isUndefined(table.selectedColumnIndex); + + // Trigger focus via clicking. + table.$.body.children[1].children[0].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[1]); + assert.isUndefined(table.selectedColumnIndex); + + // Unfocus via removing selection mode. + table.selectionMode = SelectionMode.NONE; + assert.isFalse(table.$.body.hasAttribute('tabindex')); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Re-enable selection mode. + table.selectionMode = SelectionMode.ROW; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Programatically select row (should NOT steal focus). + table.selectedTableRow = table.tableRows[0]; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.isUndefined(table.selectedColumnIndex); + + // Trigger focus on the already selected row by clicking. + table.$.body.children[0].children[0].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.isUndefined(table.selectedColumnIndex); + }); + + test('focus_cells', function() { + var table = createMultiColumnNestedTable(); + table.selectionMode = SelectionMode.CELL; + this.addHTMLOutput(table); + + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually focus. + table.focus(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + + // Manually unfocus. + table.blur(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + + // Trigger focus via clicking. + table.$.body.children[1].children[4].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[1]); + assert.strictEqual(table.selectedColumnIndex, 4); + + // Unfocus via removing selection mode. + table.selectionMode = SelectionMode.NONE; + assert.isFalse(table.$.body.hasAttribute('tabindex')); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Re-enable selection mode. + table.selectionMode = SelectionMode.CELL; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Clicking on an unselectable cell should NOT trigger focus. + table.$.body.children[1].children[0].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Programatically select cell (should NOT steal focus). + table.selectedTableRow = table.tableRows[0]; + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + + // Trigger focus on the already selected cell by clicking. + table.$.body.children[0].children[1].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.strictEqual(table.selectedTableRow, table.tableRows[0]); + assert.strictEqual(table.selectedColumnIndex, 1); + }); + + test('focus_allCellsUnselectable', function() { + var table = createMultiColumnNestedTable(); + table.selectionMode = SelectionMode.CELL; + for (var c of table.tableColumns) + c.supportsCellSelection = false; + table.tableColumns = table.tableColumns; + this.addHTMLOutput(table); + + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isFalse(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Manually focus (no automatic selection). + table.focus(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + + // Trigger focus via clicking (no selection). + table.$.body.children[1].children[2].click(); + assert.strictEqual(table.$.body.getAttribute('tabindex'), '0'); + assert.isTrue(table.isFocused); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + }); + test('RightArrowKeyWhenTableSorted', function() { var table = createSimpleOneColumnNestedTable(); table.selectionMode = SelectionMode.ROW; @@ -1014,6 +1404,10 @@ tr.b.unittest.testSuite(function() { table.selectedTableRow = table.tableRows[0]; assert.equal(table.selectedColumnIndex, 1); + var selectedCell = table.selectedCell; + assert.strictEqual(selectedCell.row, table.tableRows[0]); + assert.strictEqual(selectedCell.column, columns[1]); + assert.strictEqual(selectedCell.value, '1'); table.performKeyCommand_('ARROW_DOWN'); table.performKeyCommand_('ARROW_RIGHT'); @@ -1021,11 +1415,16 @@ tr.b.unittest.testSuite(function() { table.performKeyCommand_('ARROW_LEFT'); assert.equal(table.selectedTableRow, table.tableRows[1]); assert.equal(table.selectedColumnIndex, 2); + selectedCell = table.selectedCell; + assert.strictEqual(selectedCell.row, table.tableRows[1]); + assert.strictEqual(selectedCell.column, columns[2]); + assert.strictEqual(selectedCell.value, 4); table.selectedTableRow = undefined; - assert.equal(table.selectedTableRow, undefined); - assert.equal(table.selectedColumnIndex, undefined); - assert.equal(table.selectedColumnIndex, undefined); + assert.isUndefined(table.selectedTableRow); + assert.isUndefined(table.selectedColumnIndex); + assert.isUndefined(table.selectedColumnIndex); + assert.isUndefined(table.selectedCell); }); test('cellSelectionNested', function() { @@ -1161,8 +1560,10 @@ tr.b.unittest.testSuite(function() { var firstColumnHeader = table.$.head.children[0].children[0].children[0]; var secondColumnHeader = table.$.head.children[0].children[1].children[0]; - assert.equal(firstColumnHeader.cellTitle.textContent, 'First Column'); - assert.equal(secondColumnHeader.cellTitle.textContent, 'Second Column'); + assert.equal(Polymer.dom(firstColumnHeader.cellTitle).textContent, + 'First Column'); + assert.equal(Polymer.dom(secondColumnHeader.cellTitle).textContent, + 'Second Column'); }); test('align', function() { @@ -1215,7 +1616,8 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(table); - assert.equal(2, table.$.body.children[1].children[0].textContent); + assert.equal( + 2, Polymer.dom(table.$.body.children[1].children[0]).textContent); }); test('shouldNotRenderUndefined', function() { @@ -1241,7 +1643,7 @@ tr.b.unittest.testSuite(function() { this.addHTMLOutput(table); // check that we don't have 'undefined' anywhere - assert.isTrue(table.$.body.innerHTML.indexOf('undefined') < 0); + assert.isTrue(Polymer.dom(table.$.body).innerHTML.indexOf('undefined') < 0); }); test('customizeTableRowCallback', function() { @@ -1367,7 +1769,7 @@ tr.b.unittest.testSuite(function() { var cRow = tr.b.findDeepElementMatchingPredicate( table, function(element) { - return element.textContent === 'C'; + return Polymer.dom(element).textContent === 'C'; }); assert.equal(cRow, undefined); @@ -1392,7 +1794,7 @@ tr.b.unittest.testSuite(function() { assert.isTrue(callbackCalled); cRow = tr.b.findDeepElementMatchingPredicate(table, function(element) { - return element.textContent === 'C'; + return Polymer.dom(element).textContent === 'C'; }); assert.isDefined(cRow); }); @@ -1457,5 +1859,226 @@ tr.b.unittest.testSuite(function() { // Check that 'A' is still expanded. assert.isDefined(tr.b.findDeepElementMatchingPredicate(table, isB)); }); + + test('shouldPreserveSortWhenColumnsChange', function() { + var name = { + title: 'Name', + value: function(row) { return row.name; }, + }; + + var count = { + title: 'Count', + value: function(row) { return row.count; }, + cmp: (rowA, rowB) => rowA.a - rowB.a, + }; + + var otherCount = { + title: 'Count', + value: function(row) { return row.count; }, + cmp: (rowA, rowB) => rowA.a - rowB.a, + }; + + var table = document.createElement('tr-ui-b-table'); + table.tableColumns = [count]; + table.sortColumnIndex = 0; + table.sortDescending = true; + table.rebuild(); + + this.addHTMLOutput(table); + + table.tableColumns = [name, count]; + table.rebuild(); + assert.strictEqual(1, table.sortColumnIndex); + assert.isTrue(table.sortDescending); + + table.sortDescending = false; + table.tableColumns = [otherCount, name]; + table.rebuild(); + assert.strictEqual(0, table.sortColumnIndex); + assert.isFalse(table.sortDescending); + + table.tableColumns = [name]; + table.rebuild(); + assert.isUndefined(table.sortColumnIndex); + }); + + test('userCanModifySortOrder', function() { + var table = document.createElement('tr-ui-b-table'); + table.tableColumns = [ + { + title: 'Name', + value: row => row.name + }, + { + title: 'colA', + value: row => row.a, + cmp: (rowA, rowB) => rowA.a - rowB.a + }, + { + title: 'colB', + value: row => row.b, + cmp: (rowA, rowB) => rowA.b - rowB.b + } + ]; + table.tableRows = [ + {name: 'A', a: 42, b: 0}, + {name: 'B', a: 89, b: 100}, + {name: 'C', a: 65, b: -273.15} + ]; + table.userCanModifySortOrder = false; + table.sortColumnIndex = 2; + table.sortDescending = true; + table.rebuild(); + this.addHTMLOutput(table); + + var toggleButton = document.createElement('button'); + Polymer.dom(toggleButton).textContent = + 'Toggle table.userCanModifySortOrder'; + toggleButton.addEventListener('click', function() { + table.userCanModifySortOrder = !table.userCanModifySortOrder; + }); + this.addHTMLOutput(toggleButton); + + var unsetButton = document.createElement('button'); + Polymer.dom(unsetButton).textContent = 'Unset sort order'; + unsetButton.addEventListener('click', function() { + table.sortColumnIndex = undefined; + }); + this.addHTMLOutput(unsetButton); + }); + + test('columnSelection', function() { + var table = document.createElement('tr-ui-b-table'); + table.tableColumns = [ + { + title: 'Name', + value: (row) => row.name + }, + { + title: 'colA', + selectable: true, + value: (row) => row.a, + cmp: (rowA, rowB) => rowA.a - rowB.a + }, + { + title: 'colB', + selectable: true, + value: (row) => row.b, + cmp: (rowA, rowB) => rowA.b - rowB.b + } + ]; + table.tableRows = [ + {name: 'foo', a: 42, b: -42}, + {name: 'bar', a: 57, b: 133} + ]; + table.rebuild(); + table.selectionMode = SelectionMode.CELL; + this.addHTMLOutput(table); + + table.selectedTableColumnIndex = 1; + var cols = tr.b.findDeepElementMatchingPredicate(table, + e => e.tagName === 'COLGROUP').children; + assert.isNull(cols[0].getAttribute('selected')); + assert.strictEqual(cols[1].getAttribute('selected'), 'true'); + assert.isNull(cols[2].getAttribute('selected')); + assert.strictEqual(1, table.selectedTableColumnIndex); + + table.selectedTableColumnIndex = undefined; + cols = tr.b.findDeepElementMatchingPredicate(table, + e => e.tagName === 'COLGROUP').children; + assert.isNull(cols[0].getAttribute('selected')); + assert.isNull(cols[1].getAttribute('selected')); + assert.isNull(cols[2].getAttribute('selected')); + assert.isUndefined(table.selectedTableColumnIndex); + + table.selectedTableColumnIndex = 2; + cols = tr.b.findDeepElementMatchingPredicate(table, + e => e.tagName === 'COLGROUP').children; + assert.isNull(cols[0].getAttribute('selected')); + assert.isNull(cols[1].getAttribute('selected')); + assert.strictEqual(cols[2].getAttribute('selected'), 'true'); + assert.strictEqual(2, table.selectedTableColumnIndex); + }); + + test('stepInto', function() { + var columns = [ + { + title: 'Title', + value: function(row) { return row.a; }, + width: '150px', + supportsCellSelection: false + }, + { + title: 'Col1', + value: function(row) { return row.b; }, + width: '33%' + }, + { + title: 'Col2', + value: function(row) { return row.b * 2; }, + width: '33%' + }, + { + title: 'Col3', + value: function(row) { return row.b * 3; }, + width: '33%' + } + ]; + var rows = [ + { + a: 'first', + b: '1' + }, + { + a: 'second', + b: '2' + } + ]; + + var table = document.createElement('tr-ui-b-table'); + + var firedStepIntoEvents = []; + table.addEventListener('step-into', e => firedStepIntoEvents.push(e)); + + table.cellHighlightStyle = HighlightStyle.DARK; + table.tableColumns = columns; + table.tableRows = rows; + table.rebuild(); + this.addHTMLOutput(table); + + assert.lengthOf(firedStepIntoEvents, 0); + + // Double click. + simulateDoubleClick(table.$.body.children[0].children[1]); + assert.lengthOf(firedStepIntoEvents, 1); + assert.strictEqual(firedStepIntoEvents[0].tableRow, rows[0]); + assert.strictEqual(firedStepIntoEvents[0].tableColumn, columns[1]); + assert.strictEqual(firedStepIntoEvents[0].columnIndex, 1); + + simulateDoubleClick(table.$.body.children[1].children[3]); + assert.lengthOf(firedStepIntoEvents, 2); + assert.strictEqual(firedStepIntoEvents[1].tableRow, rows[1]); + assert.strictEqual(firedStepIntoEvents[1].tableColumn, columns[3]); + assert.strictEqual(firedStepIntoEvents[1].columnIndex, 3); + + // Shift+Enter in cell selection mode. + table.selectionMode = SelectionMode.CELL; + table.selectedTableRow = rows[0]; + table.selectedColumnIndex = 2; + table.performKeyCommand_('ENTER'); + assert.lengthOf(firedStepIntoEvents, 3); + assert.strictEqual(firedStepIntoEvents[2].tableRow, rows[0]); + assert.strictEqual(firedStepIntoEvents[2].tableColumn, columns[2]); + assert.strictEqual(firedStepIntoEvents[2].columnIndex, 2); + + // Shift+Enter in row selection mode. + table.selectionMode = SelectionMode.ROW; + table.selectedTableRow = rows[1]; + table.performKeyCommand_('ENTER'); + assert.lengthOf(firedStepIntoEvents, 4); + assert.strictEqual(firedStepIntoEvents[3].tableRow, rows[1]); + assert.isUndefined(firedStepIntoEvents[3].tableColumn); + assert.isUndefined(firedStepIntoEvents[3].columnIndex); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html b/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html index 5fe8c74e86b..85ca3e440ab 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/timing_tool.html @@ -33,7 +33,7 @@ tr.exportTo('tr.ui.b', function() { // Valid only during mousedown. this.isMovingLeftEdge_ = false; - }; + } TimingTool.prototype = { @@ -189,7 +189,7 @@ tr.exportTo('tr.ui.b', function() { else ir.setMinAndMax(b, a); - if (ir.min == newWorldX) { + if (ir.min === newWorldX) { this.isMovingLeftEdge_ = true; ir.leftSelected = true; ir.rightSelected = false; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html index 9d2405d8480..74b7774255a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button.html @@ -8,7 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/base.html"> </script> -<polymer-element name='tr-ui-b-toolbar-button' noscript> +<dom-module id='tr-ui-b-toolbar-button'> <template> <style> :host { @@ -38,4 +38,8 @@ found in the LICENSE file. <content></content> </div> </template> -</polymer-element> +</dom-module> +<script> + 'use strict'; + Polymer({ is: 'tr-ui-b-toolbar-button' }); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html index 78f94081163..25d2dfe85a3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/toolbar_button_test.html @@ -4,8 +4,8 @@ Copyright (c) 2014 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/base/toolbar_button.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/toolbar_button.html"> <script> 'use strict'; @@ -15,7 +15,7 @@ tr.b.unittest.testSuite(function() { el.style.width = '100px'; el.style.height = '40px'; - el.textContent = 'blahblah'; + Polymer.dom(el).textContent = 'blahblah'; this.addHTMLOutput(el); }); @@ -25,14 +25,14 @@ tr.b.unittest.testSuite(function() { el.style.width = '100px'; el.style.height = '40px'; - el.appendChild(tr.ui.b.createSpan({textContent: 'blahblah'})); + Polymer.dom(el).appendChild(tr.ui.b.createSpan({textContent: 'blahblah'})); this.addHTMLOutput(el); }); test('puny', function() { var el = document.createElement('tr-ui-b-toolbar-button'); - el.textContent = 'M'; + Polymer.dom(el).textContent = 'M'; this.addHTMLOutput(el); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html b/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html index 20c1bd4471d..8e27b45ecea 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/ui.html @@ -20,8 +20,8 @@ tr.exportTo('tr.ui.b', function() { */ function decorate(source, constr) { var elements; - if (typeof source == 'string') - elements = tr.doc.querySelectorAll(source); + if (typeof source === 'string') + elements = Polymer.dom(tr.doc).querySelectorAll(source); else elements = [source]; @@ -72,7 +72,7 @@ tr.exportTo('tr.ui.b', function() { * constructor. */ function define(className, opt_parentConstructor, opt_tagNS) { - if (typeof className == 'function') { + if (typeof className === 'function') { throw new Error('Passing functions as className is deprecated. Please ' + 'use (className, opt_parentConstructor) to subclass'); } @@ -108,7 +108,7 @@ tr.exportTo('tr.ui.b', function() { */ function f() { if (opt_parentConstructor && - f.prototype.__proto__ != opt_parentConstructor.prototype) { + f.prototype.__proto__ !== opt_parentConstructor.prototype) { throw new Error( className + ' prototye\'s __proto__ field is messed up. ' + 'It MUST be the prototype of ' + opt_parentConstructor.tagName); @@ -148,17 +148,17 @@ tr.exportTo('tr.ui.b', function() { } function elementIsChildOf(el, potentialParent) { - if (el == potentialParent) + if (el === potentialParent) return false; var cur = el; - while (cur.parentNode) { - if (cur == potentialParent) + while (Polymer.dom(cur).parentNode) { + if (cur === potentialParent) return true; - cur = cur.parentNode; + cur = Polymer.dom(cur).parentNode; } return false; - }; + } return { decorate: decorate, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html index 9db0b9f396f..4cace3aa243 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/ui_test.html @@ -191,18 +191,18 @@ tr.b.unittest.testSuite(function() { var svgNS = 'http://www.w3.org/2000/svg'; var cls = tr.ui.b.define('svg', undefined, svgNS); cls.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { - this.setAttribute('width', 200); - this.setAttribute('height', 200); - this.setAttribute('viewPort', '0 0 200 200'); + Polymer.dom(this).setAttribute('width', 200); + Polymer.dom(this).setAttribute('height', 200); + Polymer.dom(this).setAttribute('viewPort', '0 0 200 200'); var rectEl = document.createElementNS(svgNS, 'rect'); - rectEl.setAttribute('x', 10); - rectEl.setAttribute('y', 10); - rectEl.setAttribute('width', 180); - rectEl.setAttribute('height', 180); - this.appendChild(rectEl); + Polymer.dom(rectEl).setAttribute('x', 10); + Polymer.dom(rectEl).setAttribute('y', 10); + Polymer.dom(rectEl).setAttribute('width', 180); + Polymer.dom(rectEl).setAttribute('height', 180); + Polymer.dom(this).appendChild(rectEl); } }; var el = new cls(); @@ -215,18 +215,18 @@ tr.b.unittest.testSuite(function() { var svgNS = 'http://www.w3.org/2000/svg'; var cls = tr.ui.b.define('svg', undefined, svgNS); cls.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { - this.setAttribute('width', 200); - this.setAttribute('height', 200); - this.setAttribute('viewPort', '0 0 200 200'); + Polymer.dom(this).setAttribute('width', 200); + Polymer.dom(this).setAttribute('height', 200); + Polymer.dom(this).setAttribute('viewPort', '0 0 200 200'); var rectEl = document.createElementNS(svgNS, 'rect'); - rectEl.setAttribute('x', 10); - rectEl.setAttribute('y', 10); - rectEl.setAttribute('width', 180); - rectEl.setAttribute('height', 180); - this.appendChild(rectEl); + Polymer.dom(rectEl).setAttribute('x', 10); + Polymer.dom(rectEl).setAttribute('y', 10); + Polymer.dom(rectEl).setAttribute('width', 180); + Polymer.dom(rectEl).setAttribute('height', 180); + Polymer.dom(this).appendChild(rectEl); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html b/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html index a205d1db1b7..cdb9ab36570 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/utils.html @@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/base.html"> <link rel="import" href="/tracing/base/rect.html"> <script> @@ -13,10 +14,11 @@ found in the LICENSE file. tr.exportTo('tr.ui.b', function() { function instantiateTemplate(selector, doc) { doc = doc || document; - var el = doc.querySelector(selector); + var el = Polymer.dom(doc).querySelector(selector); if (!el) throw new Error('Element not found'); - return el.createInstance(); + return doc.importNode(el.content, true); +// return el.createInstance(); } function windowRectForElement(element) { @@ -57,7 +59,19 @@ tr.exportTo('tr.ui.b', function() { undefined, {minimumFractionDigits: 3, maximumFractionDigits: 3}); } + /** + * Returns true if |name| is the name of an unknown HTML element. Registered + * polymer elements are known, so this returns false. Typos of registered + * polymer element names are unknown, so this returns true for typos. + * + * @return {boolean} + */ + function isUnknownElementName(name) { + return document.createElement(name) instanceof HTMLUnknownElement; + } + return { + isUnknownElementName: isUnknownElementName, toThreeDigitLocaleString: toThreeDigitLocaleString, instantiateTemplate: instantiateTemplate, windowRectForElement: windowRectForElement, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html b/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html index 7e82132fe8d..f24cd2be811 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/base/utils_test.html @@ -7,16 +7,16 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/utils.html"> -<polymer-element name="instantiate-template-polymer-element-test"> +<dom-module id='instantiate-template-polymer-element-test'> <template></template> - <script> - 'use strict'; - Polymer({ - testProperty: 'Test' - }); - </script> -</polymer-element> - +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'instantiate-template-polymer-element-test', + testProperty: 'Test' +}); +</script> <template id="instantiate-template-polymer-test"> <instantiate-template-polymer-element-test> </instantiate-template-polymer-element-test> @@ -31,12 +31,11 @@ found in the LICENSE file. <instantiate-template-polymer-element-test> </instantiate-template-polymer-element-test> </template> - <script> 'use strict'; tr.b.unittest.testSuite(function() { - var THIS_DOC = document._currentScript.ownerDocument; + var THIS_DOC = document.currentScript.ownerDocument; test('instantiateTemplatePolymer', function() { var e = tr.ui.b.instantiateTemplate( @@ -54,13 +53,14 @@ tr.b.unittest.testSuite(function() { assert.equal(outerElement.children[1].testProperty, 'Test'); // Make sure we can still instantiate inner templates, if we need them. - var innerElement = outerElement.children[0].createInstance(); + var innerElement = THIS_DOC.importNode( + outerElement.children[0].content, true); assert.equal(innerElement.children.length, 2); assert.equal(innerElement.children[0].testProperty, 'Test'); assert.equal( innerElement.children[1].getAttribute('test-attribute'), 'TestAttribute'); - assert.equal(innerElement.children[1].textContent, 'Foo'); + assert.equal(Polymer.dom(innerElement.children[1]).textContent, 'Foo'); }); test('extractUrlStringAcceptsBothVersions', function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html index 9996e4db952..371cfafefa3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state.html @@ -6,6 +6,7 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/guid.html"> +<link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/model/selection_state.html"> @@ -137,9 +138,11 @@ tr.exportTo('tr.ui.b', function() { this.viewSpecificBrushingStates_ = viewSpecificBrushingStates; }, - get causesDimming_() { - return this.findMatches_.length > 0 || - this.analysisViewRelatedEvents_.length > 0; + get dimmedEvents_() { + var dimmedEvents = new EventSet(); + dimmedEvents.addEventSet(this.findMatches); + dimmedEvents.addEventSet(this.analysisViewRelatedEvents_); + return dimmedEvents; }, get brightenedEvents_() { @@ -149,41 +152,70 @@ tr.exportTo('tr.ui.b', function() { return brightenedEvents; }, - applyToModelSelectionState: function(model) { + /** + * This function sets the SelectionStates according to these rules: + * + * - Events in ONE of findMatches or analysisViewRelatedEvents + * are set to SelectionState.BRIGHTENED0. + * - Events in BOTH of findMatches and analysisViewRelatedEvents + * are set to SelectionState.BRIGHTENED1. + * - Events in ONE of selection or analysisLinkHoveredEvents + * are set to SelectionState.DIMMED1. + * - Events in BOTH selection and analysisLinkHoveredEvents + * are set to SelectionState.DIMMED2. + * - Events not in any of the above are set to SelectionState.NONE + * if there are no events in selection or analysisLinkHoveredEvents + * (i.e. model is "default bright") or SelectionState.DIMMED0 (i.e. + * model is "default dimmed"). + * + * It is up to the caller to assure that all of the SelectionStates + * are the same before calling this function. Normally, + * this is done by calling unapplyFromModelSelectionState on the + * old brushing state first. + */ + applyToEventSelectionStates: function(model) { this.appliedToModel_ = model; - if (!this.causesDimming_) { - this.brightenedEvents_.forEach(function(e) { - var score; - score = 0; - if (this.selection_.contains(e)) - score++; - if (this.analysisLinkHoveredEvents_.contains(e)) - score++; - e.selectionState = SelectionState.getFromBrighteningLevel(score); - }, this); - return; + var dimmedEvents = this.dimmedEvents_; + + // It's possible for this to get called with an undefined model pointer. + // If so, skip adjusting the defaults. + if (model) { + var newDefaultState = ( + dimmedEvents.length ? SelectionState.DIMMED0 : SelectionState.NONE); + + // Since all the states are the same, we can get the current default + // state by looking at the first element. + var currentDefaultState = tr.b.getFirstElement( + model.getDescendantEvents()).selectionState; + + // If the default state was changed, then we have to iterate through + // and reset all the events to the new default state. + if (currentDefaultState !== newDefaultState) + for (var e of model.getDescendantEvents()) + e.selectionState = newDefaultState; } - var brightenedEvents = this.brightenedEvents_; - for (var e of model.getDescendantEvents()) { - var score; - if (brightenedEvents.contains(e)) { - score = 0; - if (this.selection_.contains(e)) - score++; - if (this.analysisLinkHoveredEvents_.contains(e)) - score++; - e.selectionState = SelectionState.getFromBrighteningLevel(score); - } else { - score = 0; - if (this.findMatches_.contains(e)) - score++; - if (this.analysisViewRelatedEvents_.contains(e)) - score++; - e.selectionState = SelectionState.getFromDimmingLevel(score); - } + // Now we apply the other rules above. + var score; + for (var e of dimmedEvents) { + score = 0; + if (this.findMatches_.contains(e)) + score++; + if (this.analysisViewRelatedEvents_.contains(e)) + score++; + e.selectionState = SelectionState.getFromDimmingLevel(score); } + + for (var e of this.brightenedEvents_) { + score = 0; + if (this.selection_.contains(e)) + score++; + if (this.analysisLinkHoveredEvents_.contains(e)) + score++; + e.selectionState = SelectionState.getFromBrighteningLevel(score); + } + }, transferModelOwnershipToClone: function(that) { @@ -194,20 +226,27 @@ tr.exportTo('tr.ui.b', function() { this.appliedToModel_ = undefined; }, - unapplyFromModelSelectionState: function() { + /** + * Unapplies this brushing state from the model selection state. + * Resets all the SelectionStates to their default value (DIMMED0 or NONE) + * and returns the default selection states. The caller should store this + * value and pass it into applyFromModelSelectionStat when that is called. + */ + unapplyFromEventSelectionStates: function() { if (!this.appliedToModel_) throw new Error('Not applied'); var model = this.appliedToModel_; this.appliedToModel_ = undefined; - if (!this.causesDimming_) { - for (var e of this.brightenedEvents_) - e.selectionState = SelectionState.NONE; - return; - } + var dimmedEvents = this.dimmedEvents_; + var defaultState = ( + dimmedEvents.length ? SelectionState.DIMMED0 : SelectionState.NONE); - for (var e of model.getDescendantEvents()) - e.selectionState = SelectionState.NONE; + for (var e of this.brightenedEvents_) + e.selectionState = defaultState; + for (var e of dimmedEvents) + e.selectionState = defaultState; + return defaultState; } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html index c3b9e83952b..faa01567f4a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller.html @@ -7,11 +7,11 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/event_target.html"> <link rel="import" href="/tracing/base/task.html"> -<link rel="import" href="/tracing/ui/brushing_state.html"> -<link rel="import" href="/tracing/ui/timeline_viewport.html"> -<link rel="import" href="/tracing/ui/base/ui_state.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/model/selection_state.html"> +<link rel="import" href="/tracing/ui/base/ui_state.html"> +<link rel="import" href="/tracing/ui/brushing_state.html"> +<link rel="import" href="/tracing/ui/timeline_viewport.html"> <script> 'use strict'; @@ -76,14 +76,14 @@ tr.exportTo('tr.c', function() { modelWillChange: function() { if (this.currentBrushingState_.isAppliedToModel) - this.currentBrushingState_.unapplyFromModelSelectionState(); + this.currentBrushingState_.unapplyFromEventSelectionStates(); }, modelDidChange: function() { this.selections_ = {}; this.currentBrushingState_ = new BrushingState(); - this.currentBrushingState_.applyToModelSelectionState(this.model); + this.currentBrushingState_.applyToEventSelectionStates(this.model); var e = new tr.b.Event('model-changed', false, false); this.dispatchEvent(e); @@ -153,12 +153,11 @@ tr.exportTo('tr.c', function() { } if (this.currentBrushingState_.isAppliedToModel) - this.currentBrushingState_.unapplyFromModelSelectionState(); + this.currentBrushingState_.unapplyFromEventSelectionStates(); this.currentBrushingState_ = newBrushingState; - if (this.model) - this.currentBrushingState_.applyToModelSelectionState(this.model); + this.currentBrushingState_.applyToEventSelectionStates(this.model); this.dispatchChangeEvent_(); }, @@ -291,8 +290,8 @@ tr.exportTo('tr.c', function() { // Possibly inside a shadow DOM. var currentNode = currentElement; - while (currentNode.parentNode) - currentNode = currentNode.parentNode; + while (Polymer.dom(currentNode).parentNode) + currentNode = Polymer.dom(currentNode).parentNode; currentElement = currentNode.host; } return undefined; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html index 1f44f5962b6..b8a8b0d63fd 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_controller_test.html @@ -130,7 +130,7 @@ tr.b.unittest.testSuite(function() { function addChildDiv(element) { var child = element.ownerDocument.createElement('div'); - element.appendChild(child); + Polymer.dom(element).appendChild(child); return child; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html index d0480738bd7..25606f6cb6b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/brushing_state_test.html @@ -40,9 +40,9 @@ tr.b.unittest.testSuite(function() { var bs = new tr.ui.b.BrushingState(); bs.selection = new EventSet([m.sA]); - bs.applyToModelSelectionState(m); + bs.applyToEventSelectionStates(m); assert.equal(m.sA.selectionState, SelectionState.SELECTED); - bs.unapplyFromModelSelectionState(); + bs.unapplyFromEventSelectionStates(); assert.equal(m.sA.selectionState, SelectionState.NONE); }); @@ -54,10 +54,10 @@ tr.b.unittest.testSuite(function() { bs.selection = new EventSet([m.sA]); bs.analysisLinkHoveredEvents = new EventSet([m.sA, m.sB]); - bs.applyToModelSelectionState(m); + bs.applyToEventSelectionStates(m); assert.equal(m.sA.selectionState, SelectionState.BRIGHTENED1); assert.equal(m.sB.selectionState, SelectionState.BRIGHTENED0); - bs.unapplyFromModelSelectionState(); + bs.unapplyFromEventSelectionStates(); assert.equal(m.sA.selectionState, SelectionState.NONE); }); @@ -68,14 +68,14 @@ tr.b.unittest.testSuite(function() { bs.selection = new EventSet([m.sA]); bs.findMatches = new EventSet([m.sA, m.sB]); - bs.applyToModelSelectionState(m); + bs.applyToEventSelectionStates(m); assert.equal(m.sA.selectionState, SelectionState.BRIGHTENED0); assert.equal(m.sB.selectionState, SelectionState.DIMMED1); assert.equal(m.sC.selectionState, SelectionState.DIMMED0); - bs.unapplyFromModelSelectionState(); - assert.equal(m.sA.selectionState, SelectionState.NONE); - assert.equal(m.sB.selectionState, SelectionState.NONE); - assert.equal(m.sC.selectionState, SelectionState.NONE); + bs.unapplyFromEventSelectionStates(); + assert.equal(m.sA.selectionState, SelectionState.DIMMED0); + assert.equal(m.sB.selectionState, SelectionState.DIMMED0); + assert.equal(m.sC.selectionState, SelectionState.DIMMED0); }); test('brushingTransfer', function() { @@ -86,13 +86,13 @@ tr.b.unittest.testSuite(function() { var bs2 = bs.clone(); - bs.applyToModelSelectionState(m); + bs.applyToEventSelectionStates(m); assert.equal(m.sA.selectionState, SelectionState.SELECTED); bs.transferModelOwnershipToClone(bs2); assert.isFalse(bs.isAppliedToModel); assert.isTrue(bs2.isAppliedToModel); - bs2.unapplyFromModelSelectionState(); + bs2.unapplyFromEventSelectionStates(); assert.equal(m.sA.selectionState, SelectionState.NONE); assert.equal(m.sB.selectionState, SelectionState.NONE); assert.equal(m.sC.selectionState, SelectionState.NONE); @@ -104,7 +104,7 @@ tr.b.unittest.testSuite(function() { var bs = new tr.ui.b.BrushingState(); bs.selection = new EventSet([m.sA]); bs.findMatches = new EventSet([m.sB]); - bs.applyToModelSelectionState = new EventSet([m.sC]); + bs.applyToEventSelectionStates = new EventSet([m.sC]); // Clone equality, but with shared refs. var bs2 = bs.clone(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html index 1df923b4d42..8e579d90921 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/about_tracing.html @@ -4,6 +4,8 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order> + <link rel="stylesheet" href="/tracing/ui/extras/about_tracing/common.css"> <link rel="import" href="/tracing/ui/extras/about_tracing/profiling_view.html"> <link rel="import" href="/tracing/ui/extras/full_config.html"> @@ -16,7 +18,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { document.addEventListener('DOMContentLoaded', function() { window.profilingView = new tr.ui.e.about_tracing.ProfilingView(); profilingView.timelineView.globalMode = true; - document.body.appendChild(profilingView); + Polymer.dom(document.body).appendChild(profilingView); }); return {}; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html index accff574c54..58d4e913e34 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/profiling_view.html @@ -69,31 +69,33 @@ tr.exportTo('tr.ui.e.about_tracing', function() { /** * ProfilingView * @constructor - * @extends {HTMLUnknownElement} + * @extends {HTMLDivElement} */ var ProfilingView = tr.ui.b.define('x-profiling-view'); var THIS_DOC = document.currentScript.ownerDocument; ProfilingView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function(tracingControllerClient) { - this.appendChild(tr.ui.b.instantiateTemplate('#profiling-view-template', - THIS_DOC)); + Polymer.dom(this).appendChild( + tr.ui.b.instantiateTemplate('#profiling-view-template', THIS_DOC)); - this.timelineView_ = this.querySelector('tr-ui-timeline-view'); - this.infoBarGroup_ = this.querySelector('tr-ui-b-info-bar-group'); + this.timelineView_ = + Polymer.dom(this).querySelector('tr-ui-timeline-view'); + this.infoBarGroup_ = + Polymer.dom(this).querySelector('tr-ui-b-info-bar-group'); // Detach the buttons. We will reattach them to the timeline view. // TODO(nduca): Make timeline-view have a content select="x-buttons" // that pulls in any buttons. - this.recordButton_ = this.querySelector('#record-button'); - this.loadButton_ = this.querySelector('#load-button'); - this.saveButton_ = this.querySelector('#save-button'); + this.recordButton_ = Polymer.dom(this).querySelector('#record-button'); + this.loadButton_ = Polymer.dom(this).querySelector('#load-button'); + this.saveButton_ = Polymer.dom(this).querySelector('#save-button'); - var buttons = this.querySelector('x-timeline-view-buttons'); - buttons.parentElement.removeChild(buttons); - this.timelineView_.leftControls.appendChild(buttons); + var buttons = Polymer.dom(this).querySelector('x-timeline-view-buttons'); + Polymer.dom(buttons.parentElement).removeChild(buttons); + Polymer.dom(this.timelineView_.leftControls).appendChild(buttons); this.initButtons_(); this.timelineView_.hotkeyController.addHotKey(new tr.ui.b.HotKey({ diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html index 2284b0fa3e7..a72ddfeba07 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_controller.html @@ -72,18 +72,18 @@ tr.exportTo('tr.ui.e.about_tracing', function() { var bufferPercentFullDiv; function startTracing() { progressDlg = new tr.ui.b.Overlay(); - progressDlg.textContent = 'Recording...'; + Polymer.dom(progressDlg).textContent = 'Recording...'; progressDlg.userCanClose = false; bufferPercentFullDiv = document.createElement('div'); - progressDlg.appendChild(bufferPercentFullDiv); + Polymer.dom(progressDlg).appendChild(bufferPercentFullDiv); var stopButton = document.createElement('button'); - stopButton.textContent = 'Stop'; + Polymer.dom(stopButton).textContent = 'Stop'; progressDlg.clickStopButton = function() { stopButton.click(); }; - progressDlg.appendChild(stopButton); + Polymer.dom(progressDlg).appendChild(stopButton); var recordingOptions = { categoryFilter: selectionDlg.categoryFilter(), @@ -141,21 +141,21 @@ tr.exportTo('tr.ui.e.about_tracing', function() { updateBufferPercentFull); } - function updateBufferPercentFull(percent_full) { + function updateBufferPercentFull(percentFull) { if (!bufferPercentFullDiv) return; - percent_full = Math.round(100 * parseFloat(percent_full)); - var newText = 'Buffer usage: ' + percent_full + '%'; - if (bufferPercentFullDiv.textContent != newText) - bufferPercentFullDiv.textContent = newText; + percentFull = Math.round(100 * parseFloat(percentFull)); + var newText = 'Buffer usage: ' + percentFull + '%'; + if (Polymer.dom(bufferPercentFullDiv).textContent !== newText) + Polymer.dom(bufferPercentFullDiv).textContent = newText; window.setTimeout(getBufferPercentFull, 500); } // Thats it! We're done. return finalPromise; - }; + } function endRecording(tracingControllerClient) { return tracingControllerClient.endRecording(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html index 79ce154dba8..71a333bf60d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog.html @@ -29,6 +29,7 @@ found in the LICENSE file. max-width: 0; opacity: 0; overflow: hidden; + display: none; } .categories-selection { @@ -228,24 +229,25 @@ tr.exportTo('tr.ui.e.about_tracing', function() { tr.ui.b.Overlay.prototype.decorate.call(this); this.title = 'Record a new trace...'; - this.classList.add('record-dialog-overlay'); + Polymer.dom(this).classList.add('record-dialog-overlay'); var node = tr.ui.b.instantiateTemplate('#record-selection-dialog-template', THIS_DOC); - this.appendChild(node); + Polymer.dom(this).appendChild(node); this.recordButtonEl_ = document.createElement('button'); - this.recordButtonEl_.textContent = 'Record'; + Polymer.dom(this.recordButtonEl_).textContent = 'Record'; this.recordButtonEl_.addEventListener( 'click', this.onRecordButtonClicked_.bind(this)); this.recordButtonEl_.style.fontSize = '110%'; - this.buttons.appendChild(this.recordButtonEl_); + Polymer.dom(this.buttons).appendChild(this.recordButtonEl_); - this.categoriesView_ = this.querySelector('.categories-column-view'); - this.presetsEl_ = this.querySelector('.category-presets'); - this.presetsEl_.appendChild(tr.ui.b.createOptionGroup( + this.categoriesView_ = Polymer.dom(this).querySelector( + '.categories-column-view'); + this.presetsEl_ = Polymer.dom(this).querySelector('.category-presets'); + Polymer.dom(this.presetsEl_).appendChild(tr.ui.b.createOptionGroup( this, 'currentlyChosenPreset', 'about_tracing.record_selection_dialog_preset', DEFAULT_PRESETS[0].categoryFilter, @@ -266,30 +268,37 @@ tr.exportTo('tr.ui.e.about_tracing', function() { undefined, undefined, 'recordSelectionDialog.useSampling', DEFAULT_SAMPLING_TRACING, 'State sampling'); - this.tracingModesContainerEl_ = this.querySelector('.tracing-modes'); - this.tracingModesContainerEl_.appendChild(this.tracingRecordModeSltr_); - this.tracingModesContainerEl_.appendChild(this.systemTracingBn_); - this.tracingModesContainerEl_.appendChild(this.samplingTracingBn_); - + this.tracingModesContainerEl_ = Polymer.dom(this).querySelector( + '.tracing-modes'); + Polymer.dom(this.tracingModesContainerEl_).appendChild( + this.tracingRecordModeSltr_); + Polymer.dom(this.tracingModesContainerEl_).appendChild( + this.systemTracingBn_); + Polymer.dom(this.tracingModesContainerEl_).appendChild( + this.samplingTracingBn_); this.enabledCategoriesContainerEl_ = - this.querySelector('.default-enabled-categories .categories'); + Polymer.dom(this).querySelector( + '.default-enabled-categories .categories'); this.disabledCategoriesContainerEl_ = - this.querySelector('.default-disabled-categories .categories'); + Polymer.dom(this).querySelector( + '.default-disabled-categories .categories'); this.createGroupSelectButtons_( - this.querySelector('.default-enabled-categories')); + Polymer.dom(this).querySelector('.default-enabled-categories')); this.createGroupSelectButtons_( - this.querySelector('.default-disabled-categories')); + Polymer.dom(this).querySelector('.default-disabled-categories')); this.createDefaultDisabledWarningDialog_( - this.querySelector('.warning-default-disabled-categories')); + Polymer.dom(this).querySelector( + '.warning-default-disabled-categories')); this.editCategoriesOpened_ = false; // TODO(chrishenry): When used with tr.ui.b.Overlay (such as in // chrome://tracing, this does not yet look quite right due to // the 10px overlay content padding (but it's good enough). - this.infoBarGroup_ = this.querySelector('tr-ui-b-info-bar-group'); + this.infoBarGroup_ = Polymer.dom(this).querySelector( + 'tr-ui-b-info-bar-group'); this.addEventListener('visible-change', this.onVisibleChange_.bind(this)); }, @@ -370,7 +379,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, updateManualSelectionView_: function() { - var classList = this.categoriesView_.classList; + var classList = Polymer.dom(this.categoriesView_).classList; if (!this.usingPreset_()) { classList.remove('categories-column-view-hidden'); } else { @@ -382,7 +391,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, updateCategoryColumnView_: function(shouldReadFromSettings) { - var categorySet = this.querySelectorAll('.categories'); + var categorySet = Polymer.dom(this).querySelectorAll('.categories'); for (var i = 0; i < categorySet.length; ++i) { var categoryGroup = categorySet[i].children; for (var j = 0; j < categoryGroup.length; ++j) { @@ -415,26 +424,31 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, changeEditCategoriesState_: function(editCategoriesState) { - var presetOptionsGroup = this.querySelector('.labeled-option-group'); + var presetOptionsGroup = Polymer.dom(this).querySelector( + '.labeled-option-group'); if (!presetOptionsGroup) return; this.editCategoriesOpened_ = editCategoriesState; if (this.editCategoriesOpened_) - presetOptionsGroup.classList.add('categories-expanded'); + Polymer.dom(presetOptionsGroup).classList.add('categories-expanded'); else - presetOptionsGroup.classList.remove('categories-expanded'); + Polymer.dom(presetOptionsGroup).classList.remove( + 'categories-expanded'); }, updatePresetDescription_: function() { - var description = this.querySelector('.category-description'); + var description = Polymer.dom(this).querySelector( + '.category-description'); if (this.usingPreset_()) { description.innerText = this.currentlyChosenPreset_; - description.classList.remove('category-description-hidden'); + Polymer.dom(description).classList.remove( + 'category-description-hidden'); } else { description.innerText = ''; - if (!description.classList.contains('category-description-hidden')) - description.classList.add('category-description-hidden'); + if (!Polymer.dom(description).classList.contains( + 'category-description-hidden')) + Polymer.dom(description).classList.add('category-description-hidden'); } }, @@ -443,7 +457,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { var categories = []; var allCategories = this.allCategories_(); for (var category in allCategories) { - var disabled = category.indexOf('disabled-by-default-') == 0; + var disabled = category.indexOf('disabled-by-default-') === 0; if (this.currentlyChosenPreset_.indexOf(category) >= 0) { if (disabled) categories.push(category); @@ -456,17 +470,17 @@ tr.exportTo('tr.ui.e.about_tracing', function() { } var categories = this.unselectedCategories_(); - var categories_length = categories.length; - var negated_categories = []; - for (var i = 0; i < categories_length; ++i) { + var categoriesLength = categories.length; + var negatedCategories = []; + for (var i = 0; i < categoriesLength; ++i) { // Skip any category with a , as it will cause issues when we negate. // Both sides should have been added as separate categories, these can // only come from settings. if (categories[i].match(/,/)) continue; - negated_categories.push('-' + categories[i]); + negatedCategories.push('-' + categories[i]); } - categories = negated_categories.join(','); + categories = negatedCategories.join(','); var disabledCategories = this.enabledDisabledByDefaultCategories_(); disabledCategories = disabledCategories.join(','); @@ -490,9 +504,9 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, collectInputs_: function(inputs, isChecked) { - var inputs_length = inputs.length; + var inputsLength = inputs.length; var categories = []; - for (var i = 0; i < inputs_length; ++i) { + for (var i = 0; i < inputsLength; ++i) { var input = inputs[i]; if (input.checked === isChecked) categories.push(input.value); @@ -502,13 +516,15 @@ tr.exportTo('tr.ui.e.about_tracing', function() { unselectedCategories_: function() { var inputs = - this.enabledCategoriesContainerEl_.querySelectorAll('input'); + Polymer.dom(this.enabledCategoriesContainerEl_).querySelectorAll( + 'input'); return this.collectInputs_(inputs, false); }, enabledDisabledByDefaultCategories_: function() { var inputs = - this.disabledCategoriesContainerEl_.querySelectorAll('input'); + Polymer.dom(this.disabledCategoriesContainerEl_).querySelectorAll( + 'input'); return this.collectInputs_(inputs, true); }, @@ -518,8 +534,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() { }, buildInputs_: function(inputs, checkedDefault, parent) { - var inputs_length = inputs.length; - for (var i = 0; i < inputs_length; i++) { + var inputsLength = inputs.length; + for (var i = 0; i < inputsLength; i++) { var category = inputs[i]; var inputEl = document.createElement('input'); @@ -532,14 +548,15 @@ tr.exportTo('tr.ui.e.about_tracing', function() { inputEl.onclick = this.updateSetting_.bind(this); var labelEl = document.createElement('label'); - labelEl.textContent = category.replace('disabled-by-default-', ''); - labelEl.setAttribute('for', category); + Polymer.dom(labelEl).textContent = + category.replace('disabled-by-default-', ''); + Polymer.dom(labelEl).setAttribute('for', category); var divEl = document.createElement('div'); - divEl.appendChild(inputEl); - divEl.appendChild(labelEl); + Polymer.dom(divEl).appendChild(inputEl); + Polymer.dom(divEl).appendChild(labelEl); - parent.appendChild(divEl); + Polymer.dom(parent).appendChild(divEl); } }, @@ -560,8 +577,9 @@ tr.exportTo('tr.ui.e.about_tracing', function() { return a.toLowerCase().localeCompare(b.toLowerCase()); } - this.enabledCategoriesContainerEl_.innerHTML = ''; // Clear old categories - this.disabledCategoriesContainerEl_.innerHTML = ''; + // Clear old categories + Polymer.dom(this.enabledCategoriesContainerEl_).innerHTML = ''; + Polymer.dom(this.disabledCategoriesContainerEl_).innerHTML = ''; this.recordButtonEl_.focus(); @@ -569,7 +587,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { var categories = []; var disabledCategories = []; for (var category in allCategories) { - if (category.indexOf('disabled-by-default-') == 0) + if (category.indexOf('disabled-by-default-') === 0) disabledCategories.push(category); else categories.push(category); @@ -577,7 +595,7 @@ tr.exportTo('tr.ui.e.about_tracing', function() { disabledCategories = disabledCategories.sort(ignoreCaseCompare); categories = categories.sort(ignoreCaseCompare); - if (this.categories_.length == 0) { + if (this.categories_.length === 0) { this.infoBarGroup_.addMessage( 'No categories found; recording will use default categories.'); } @@ -603,15 +621,16 @@ tr.exportTo('tr.ui.e.about_tracing', function() { var categoryEl = this.querySelector( '#category-preset-Manually-select-settings'); categoryEl.checked = true; - var description = this.querySelector('.category-description'); + var description = Polymer.dom(this).querySelector( + '.category-description'); description.innerText = ''; - description.classList.add('category-description-hidden'); + Polymer.dom(description).classList.add('category-description-hidden'); } }, createGroupSelectButtons_: function(parent) { var flipInputs = function(dir) { - var inputs = parent.querySelectorAll('input'); + var inputs = Polymer.dom(parent).querySelectorAll('input'); for (var i = 0; i < inputs.length; i++) { if (inputs[i].checked === dir) continue; @@ -621,13 +640,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() { } }; - var allBtn = parent.querySelector('.all-btn'); + var allBtn = Polymer.dom(parent).querySelector('.all-btn'); allBtn.onclick = function(evt) { flipInputs(true); evt.preventDefault(); }; - var noneBtn = parent.querySelector('.none-btn'); + var noneBtn = Polymer.dom(parent).querySelector('.none-btn'); noneBtn.onclick = function(evt) { flipInputs(false); evt.preventDefault(); @@ -639,11 +658,11 @@ tr.exportTo('tr.ui.e.about_tracing', function() { for (var i = 0; i < messages.length; ++i) { var messageDiv = document.createElement('div'); - messageDiv.textContent = messages[i]; - contentDiv.appendChild(messageDiv); + Polymer.dom(messageDiv).textContent = messages[i]; + Polymer.dom(contentDiv).appendChild(messageDiv); } - this.warningOverlay_.textContent = ''; - this.warningOverlay_.appendChild(contentDiv); + Polymer.dom(this.warningOverlay_).textContent = ''; + Polymer.dom(this.warningOverlay_).appendChild(contentDiv); }, createDefaultDisabledWarningDialog_: function(warningLink) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html index 1142f6e6035..7dfc4e0a7cf 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/record_selection_dialog_test.html @@ -15,7 +15,7 @@ found in the LICENSE file. tr.b.unittest.testSuite(function() { test('instantitate', function() { var showButton = document.createElement('button'); - showButton.textContent = 'Show record selection dialog'; + Polymer.dom(showButton).textContent = 'Show record selection dialog'; this.addHTMLOutput(showButton); showButton.addEventListener('click', function(e) { @@ -49,7 +49,7 @@ tr.b.unittest.testSuite(function() { var expected = ['"cc"', '"cc.debug"', '"disabled-by-default-one"', '"three"', '"two"']; - var labels = dlg.querySelectorAll('.categories input'); + var labels = Polymer.dom(dlg).querySelectorAll('.categories input'); var results = []; for (var i = 0; i < labels.length; i++) { results.push('"' + labels[i].value + '"'); @@ -66,7 +66,7 @@ tr.b.unittest.testSuite(function() { dlg.currentlyChosenPreset = []; dlg.updateForm_(); - var checkboxes = dlg.querySelectorAll('.categories input'); + var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input'); assert.equal(checkboxes.length, 3); assert.equal(checkboxes[0].id, 'three'); assert.equal(checkboxes[0].value, 'three'); @@ -80,11 +80,11 @@ tr.b.unittest.testSuite(function() { assert.equal(dlg.categoryFilter(), ''); - var labels = dlg.querySelectorAll('.categories label'); + var labels = Polymer.dom(dlg).querySelectorAll('.categories label'); assert.equal(labels.length, 3); - assert.equal(labels[0].textContent, 'three'); - assert.equal(labels[1].textContent, 'two'); - assert.equal(labels[2].textContent, 'one'); + assert.equal(Polymer.dom(labels[0]).textContent, 'three'); + assert.equal(Polymer.dom(labels[1]).textContent, 'two'); + assert.equal(Polymer.dom(labels[2]).textContent, 'one'); }); test('recordSelectionDialog_UpdateForm_Settings', function() { @@ -97,7 +97,7 @@ tr.b.unittest.testSuite(function() { dlg.currentlyChosenPreset = []; dlg.updateForm_(); - var checkboxes = dlg.querySelectorAll('.categories input'); + var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input'); assert.equal(checkboxes.length, 3); assert.equal(checkboxes[0].id, 'three'); assert.equal(checkboxes[0].value, 'three'); @@ -111,11 +111,11 @@ tr.b.unittest.testSuite(function() { assert.equal(dlg.categoryFilter(), '-three'); - var labels = dlg.querySelectorAll('.categories label'); + var labels = Polymer.dom(dlg).querySelectorAll('.categories label'); assert.equal(labels.length, 3); - assert.equal(labels[0].textContent, 'three'); - assert.equal(labels[1].textContent, 'two'); - assert.equal(labels[2].textContent, 'one'); + assert.equal(Polymer.dom(labels[0]).textContent, 'three'); + assert.equal(Polymer.dom(labels[1]).textContent, 'two'); + assert.equal(Polymer.dom(labels[2]).textContent, 'one'); }); test('recordSelectionDialog_UpdateForm_DisabledByDefault', function() { @@ -128,7 +128,7 @@ tr.b.unittest.testSuite(function() { assert.equal(dlg.categoryFilter(), ''); var inputs = - dlg.querySelector('input#disabled-by-default-bar').click(); + Polymer.dom(dlg).querySelector('input#disabled-by-default-bar').click(); assert.equal(dlg.categoryFilter(), 'disabled-by-default-bar'); @@ -158,27 +158,32 @@ tr.b.unittest.testSuite(function() { dlg.updateForm_(); // Enables the three option, two already enabled. - dlg.querySelector('.default-enabled-categories .all-btn').click(); + Polymer.dom(dlg).querySelector('.default-enabled-categories .all-btn') + .click(); assert.equal(dlg.categoryFilter(), ''); assert.isTrue(tr.b.Settings.get('three', false, 'categories')); // Disables three and two. - dlg.querySelector('.default-enabled-categories .none-btn').click(); + Polymer.dom(dlg).querySelector('.default-enabled-categories .none-btn') + .click(); assert.equal(dlg.categoryFilter(), '-three,-two'); assert.isFalse(tr.b.Settings.get('two', false, 'categories')); assert.isFalse(tr.b.Settings.get('three', false, 'categories')); // Turn categories back on so they can be ignored. - dlg.querySelector('.default-enabled-categories .all-btn').click(); + Polymer.dom(dlg).querySelector('.default-enabled-categories .all-btn') + .click(); // Enables disabled category. - dlg.querySelector('.default-disabled-categories .all-btn').click(); + Polymer.dom(dlg).querySelector('.default-disabled-categories .all-btn') + .click(); assert.equal(dlg.categoryFilter(), 'disabled-by-default-one'); assert.isTrue( tr.b.Settings.get('disabled-by-default-one', false, 'categories')); // Turn disabled by default back off. - dlg.querySelector('.default-disabled-categories .none-btn').click(); + Polymer.dom(dlg).querySelector('.default-disabled-categories .none-btn') + .click(); assert.equal(dlg.categoryFilter(), ''); assert.isFalse( tr.b.Settings.get('disabled-by-default-one', false, 'categories')); @@ -209,11 +214,11 @@ tr.b.unittest.testSuite(function() { assert.isFalse(dlg.useSampling); // Make sure the manual settings are not visible. - var classList = dlg.categoriesView_.classList; + var classList = Polymer.dom(dlg.categoriesView_).classList; assert.isTrue(classList.contains('categories-column-view-hidden')); // Verify manual settings do not modify the checkboxes. - var checkboxes = dlg.querySelectorAll('.categories input'); + var checkboxes = Polymer.dom(dlg).querySelectorAll('.categories input'); assert.equal(checkboxes.length, 3); assert.equal(checkboxes[0].id, 'three'); assert.equal(checkboxes[0].value, 'three'); @@ -297,7 +302,7 @@ tr.b.unittest.testSuite(function() { assert.isFalse(dlg.useSampling); // Make sure the manual settings are not visible. - var classList = dlg.categoriesView_.classList; + var classList = Polymer.dom(dlg.categoriesView_).classList; assert.isTrue(classList.contains('categories-column-view-hidden')); // Switch to manual settings and verify the default values are not returned. @@ -346,7 +351,7 @@ tr.b.unittest.testSuite(function() { assert.isTrue(dlg.useSampling); // Make sure the manual settings are not visible. - var classList = dlg.categoriesView_.classList; + var classList = Polymer.dom(dlg.categoriesView_).classList; assert.isTrue(classList.contains('categories-column-view-hidden')); // Switch to manual settings and verify the default values are not returned. diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html index c7c68cc8483..a33e614813e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/about_tracing/xhr_based_tracing_controller_client.html @@ -20,13 +20,13 @@ tr.exportTo('tr.ui.e.about_tracing', function() { data = null; return new Promise(function(resolve, reject) { var req = new XMLHttpRequest(); - if (method != 'POST' && data !== null) + if (method !== 'POST' && data !== null) throw new Error('Non-POST should have data==null'); req.open(method, path, true); req.onreadystatechange = function(e) { - if (req.readyState == 4) { + if (req.readyState === 4) { window.setTimeout(function() { - if (req.status == 200 && req.responseText != '##ERROR##') { + if (req.status === 200 && req.responseText !== '##ERROR##') { resolve(req.responseText); } else { reject(new Error('Error occured at ' + path)); @@ -58,8 +58,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() { captureMonitoring: function() { return beginXhr('GET', '/json/capture_monitoring_compressed').then( function(data) { - var decoded_size = Base64.getDecodedBufferLength(data); - var buffer = new ArrayBuffer(decoded_size); + var decodedSize = Base64.getDecodedBufferLength(data); + var buffer = new ArrayBuffer(decodedSize); Base64.DecodeToTypedArray(data, new DataView(buffer)); return buffer; } @@ -93,8 +93,8 @@ tr.exportTo('tr.ui.e.about_tracing', function() { endRecording: function() { return beginXhr('GET', '/json/end_recording_compressed').then( function(data) { - var decoded_size = Base64.getDecodedBufferLength(data); - var buffer = new ArrayBuffer(decoded_size); + var decodedSize = Base64.getDecodedBufferLength(data); + var buffer = new ArrayBuffer(decodedSize); Base64.DecodeToTypedArray(data, new DataView(buffer)); return buffer; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html index 55a028ce4c3..37403d8f7fd 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_debugger.html @@ -134,66 +134,73 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'tr-ui-e-chrome-cc-display-item-debugger'); DisplayItemDebugger.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { var node = tr.ui.b.instantiateTemplate( '#tr-ui-e-chrome-cc-display-item-debugger-template', THIS_DOC); - this.appendChild(node); + Polymer.dom(this).appendChild(node); this.pictureAsImageData_ = undefined; this.zoomScaleValue_ = 1; - this.sizeInfo_ = this.querySelector('.size'); - this.rasterArea_ = this.querySelector('raster-area'); - this.rasterCanvas_ = this.rasterArea_.querySelector('canvas'); + this.sizeInfo_ = Polymer.dom(this).querySelector('.size'); + this.rasterArea_ = Polymer.dom(this).querySelector('raster-area'); + this.rasterCanvas_ = + Polymer.dom(this.rasterArea_).querySelector('canvas'); this.rasterCtx_ = this.rasterCanvas_.getContext('2d'); this.trackMouse_(); - this.displayItemInfo_ = this.querySelector('display-item-info'); + this.displayItemInfo_ = + Polymer.dom(this).querySelector('display-item-info'); this.displayItemInfo_.addEventListener( 'click', this.onDisplayItemInfoClick_.bind(this), false); this.displayItemListView_ = new tr.ui.b.ListView(); this.displayItemListView_.addEventListener('selection-changed', this.onDisplayItemListSelection_.bind(this)); - this.displayItemInfo_.appendChild(this.displayItemListView_); + Polymer.dom(this.displayItemInfo_).appendChild(this.displayItemListView_); - this.displayListFilename_ = this.querySelector('.dlfilename'); - this.displayListExportButton_ = this.querySelector('.dlexport'); + this.displayListFilename_ = + Polymer.dom(this).querySelector('.dlfilename'); + this.displayListExportButton_ = + Polymer.dom(this).querySelector('.dlexport'); this.displayListExportButton_.addEventListener( 'click', this.onExportDisplayListClicked_.bind(this)); - this.skpFilename_ = this.querySelector('.skpfilename'); - this.skpExportButton_ = this.querySelector('.skpexport'); + this.skpFilename_ = Polymer.dom(this).querySelector('.skpfilename'); + this.skpExportButton_ = Polymer.dom(this).querySelector('.skpexport'); this.skpExportButton_.addEventListener( 'click', this.onExportSkPictureClicked_.bind(this)); - var leftPanel = this.querySelector('left-panel'); + var leftPanel = Polymer.dom(this).querySelector('left-panel'); var middleDragHandle = document.createElement('tr-ui-b-drag-handle'); middleDragHandle.horizontal = false; middleDragHandle.target = leftPanel; - var rightPanel = this.querySelector('right-panel'); + var rightPanel = Polymer.dom(this).querySelector('right-panel'); this.infoBar_ = document.createElement('tr-ui-b-info-bar'); - this.rasterArea_.insertBefore(this.infoBar_, this.rasterCanvas_); + Polymer.dom(this.rasterArea_).insertBefore( + this.infoBar_, this.rasterCanvas_); - this.insertBefore(middleDragHandle, rightPanel); + Polymer.dom(this).insertBefore(middleDragHandle, rightPanel); this.picture_ = undefined; this.pictureOpsListView_ = new tr.ui.e.chrome.cc.PictureOpsListView(); - rightPanel.insertBefore(this.pictureOpsListView_, this.rasterArea_); + Polymer.dom(rightPanel).insertBefore( + this.pictureOpsListView_, this.rasterArea_); this.pictureOpsListDragHandle_ = document.createElement('tr-ui-b-drag-handle'); this.pictureOpsListDragHandle_.horizontal = false; this.pictureOpsListDragHandle_.target = this.pictureOpsListView_; - rightPanel.insertBefore(this.pictureOpsListDragHandle_, this.rasterArea_); + Polymer.dom(rightPanel).insertBefore( + this.pictureOpsListDragHandle_, this.rasterArea_); }, get picture() { @@ -209,7 +216,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var listItem = document.createElement( 'tr-ui-e-chrome-cc-display-item-list-item'); listItem.data = item; - this.displayItemListView_.appendChild(listItem); + Polymer.dom(this.displayItemListView_).appendChild(listItem); }.bind(this)); }, @@ -266,7 +273,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.updateContentsPending_ = false; if (this.picture_) { - this.sizeInfo_.textContent = '(' + + Polymer.dom(this.sizeInfo_).textContent = '(' + this.picture_.layerRect.width + ' x ' + this.picture_.layerRect.height + ')'; } @@ -281,7 +288,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.infoBar_.message = 'Cannot rasterize...'; this.infoBar_.addButton('More info...', function(e) { var overlay = new tr.ui.b.Overlay(); - overlay.textContent = this.pictureAsImageData_.error; + Polymer.dom(overlay).textContent = this.pictureAsImageData_.error; overlay.visible = true; e.stopPropagation(); return false; @@ -346,7 +353,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }, onDisplayItemInfoClick_: function(e) { - if (e && e.target == this.displayItemInfo_) { + if (e && e.target === this.displayItemInfo_) { this.displayItemListView_.selectedElement = undefined; } }, @@ -355,12 +362,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (showOpsList) { this.pictureOpsListView_.picture = this.picture_; if (this.pictureOpsListView_.numOps > 0) { - this.pictureOpsListView_.classList.add('hasPictureOps'); - this.pictureOpsListDragHandle_.classList.add('hasPictureOps'); + Polymer.dom(this.pictureOpsListView_).classList.add('hasPictureOps'); + Polymer.dom(this.pictureOpsListDragHandle_).classList.add( + 'hasPictureOps'); } } else { - this.pictureOpsListView_.classList.remove('hasPictureOps'); - this.pictureOpsListDragHandle_.classList.remove('hasPictureOps'); + Polymer.dom(this.pictureOpsListView_).classList.remove('hasPictureOps'); + Polymer.dom(this.pictureOpsListDragHandle_).classList.remove( + 'hasPictureOps'); } }, @@ -368,7 +377,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.mouseModeSelector_ = document.createElement( 'tr-ui-b-mouse-mode-selector'); this.mouseModeSelector_.targetElement = this.rasterArea_; - this.rasterArea_.appendChild(this.mouseModeSelector_); + Polymer.dom(this.rasterArea_).appendChild(this.mouseModeSelector_); this.mouseModeSelector_.supportedModeMask = tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html index b34495a6b41..696489f33d6 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_item.html @@ -8,7 +8,7 @@ found in the LICENSE file. <!-- An element displaying basic information about a display item in a list view. --> -<polymer-element name="tr-ui-e-chrome-cc-display-item-list-item"> +<dom-module id='tr-ui-e-chrome-cc-display-item-list-item'> <template> <style> :host { @@ -51,9 +51,8 @@ An element displaying basic information about a display item in a list view. </style> <div class="header"> {{name}} - <template if="{{richDetails && richDetails.skp64}}"> - <a class="extra" - href="data:application/octet-stream;base64,{{richDetails.skp64}}" + <template is="dom-if" if="{{_computeIf(richDetails)}}"> + <a class="extra" href$="{{_computeHref(richDetails)}}" download="drawing.skp" on-click="{{stopPropagation}}">SKP</a> </template> </div> @@ -61,13 +60,13 @@ An element displaying basic information about a display item in a list view. <template if="{{rawDetails}}"> <div class="raw-details">{{rawDetails}}</div> </template> - <template if="{{richDetails}}" bind="{{richDetails}}"> + <template is="dom-if" if="{{richDetails}}" bind="{{richDetails}}"> <dl> - <template if="{{cullRect}}" bind="{{cullRect}}"> + <template is="dom-if" if="{{cullRect}}" bind="{{cullRect}}"> <dt>Cull rect</dt> <dd>{{x}},{{y}} {{width}}×{{height}}</dd> </template> - <template if="{{visualRect}}" bind="{{visualRect}}"> + <template is="dom-if" if="{{visualRect}}" bind="{{visualRect}}"> <dt>Visual rect</dt> <dd>{{x}},{{y}} {{width}}×{{height}}</dd> </template> @@ -75,50 +74,63 @@ An element displaying basic information about a display item in a list view. </template> </div> </template> - <script> - 'use strict'; - (function() { - // Extracts the "type" and "details" parts of the unstructured (plaintext) - // display item format, even if the details span multiple lines. - // For example, given "FooDisplayItem type=hello\nworld", produces - // "FooDisplayItem" as the first capture and "type=hello\nworld" as the - // second. Either capture could be the empty string, but this regex will - // still successfully match. - var DETAILS_SPLIT_REGEX = /^(\S*)\s*([\S\s]*)$/; +<script> +'use strict'; +(function() { + // Extracts the "type" and "details" parts of the unstructured (plaintext) + // display item format, even if the details span multiple lines. + // For example, given "FooDisplayItem type=hello\nworld", produces + // "FooDisplayItem" as the first capture and "type=hello\nworld" as the + // second. Either capture could be the empty string, but this regex will + // still successfully match. + var DETAILS_SPLIT_REGEX = /^(\S*)\s*([\S\s]*)$/; - Polymer({ - created: function() { - this.name = ''; - this.rawDetails = ''; - this.richDetails = undefined; - this.data_ = undefined; - }, + Polymer({ + is: 'tr-ui-e-chrome-cc-display-item-list-item', - get data() { - return this.data_; - }, + created: function() { + // TODO(charliea): Why is setAttribute necessary here but not below? We + // should reach out to the Polymer team to figure out. + Polymer.dom(this).setAttribute('name', ''); + Polymer.dom(this).setAttribute('rawDetails', ''); + Polymer.dom(this).setAttribute('richDetails', undefined); + Polymer.dom(this).setAttribute('data_', undefined); + }, - set data(data) { - this.data_ = data; + get data() { + return this.data_; + }, - if (!data) { - this.name = 'DATA MISSING'; - this.rawDetails = ''; - this.richDetails = undefined; - } else if (typeof data === 'string') { - var match = data.match(DETAILS_SPLIT_REGEX); - this.name = match[1]; - this.rawDetails = match[2]; - this.richDetails = undefined; - } else { - this.name = data.name; - this.rawDetails = ''; - this.richDetails = data; - } - }, + set data(data) { + this.data_ = data; - stopPropagation: function(e) { e.stopPropagation(); } - }); - })(); - </script> -</polymer-element> + if (!data) { + this.name = 'DATA MISSING'; + this.rawDetails = ''; + this.richDetails = undefined; + } else if (typeof data === 'string') { + var match = data.match(DETAILS_SPLIT_REGEX); + this.name = match[1]; + this.rawDetails = match[2]; + this.richDetails = undefined; + } else { + this.name = data.name; + this.rawDetails = ''; + this.richDetails = data; + } + }, + + stopPropagation: function(e) { + e.stopPropagation(); + }, + + _computeIf: function(richDetails) { + return richDetails && richDetails.skp64; + }, + + _computeHref: function(richDetails) { + return 'data:application/octet-stream;base64,' + richDetails.skp64; + } + }); +})(); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html index c66327afc57..c4f9c6b0152 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/display_item_list_view.html @@ -28,9 +28,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-chrome-cc-display-item-list-view'); + Polymer.dom(this).classList.add( + 'tr-ui-e-chrome-cc-display-item-list-view'); this.displayItemDebugger_ = new tr.ui.e.chrome.cc.DisplayItemDebugger(); - this.appendChild(this.displayItemDebugger_); + Polymer.dom(this).appendChild(this.displayItemDebugger_); }, updateContents: function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html index 780fe03d86c..c02e129d3b5 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_picker.html @@ -7,14 +7,15 @@ found in the LICENSE file. <link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/layer_picker.css"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/extras/chrome/cc/constants.html"> <link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html"> <link rel="import" href="/tracing/extras/chrome/cc/util.html"> -<link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> <link rel="import" href="/tracing/model/event.html"> +<link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> +<link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/drag_handle.html"> <link rel="import" href="/tracing/ui/base/list_view.html"> -<link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html"> <script> @@ -22,7 +23,6 @@ found in the LICENSE file. tr.exportTo('tr.ui.e.chrome.cc', function() { var constants = tr.e.cc.constants; - var bytesToRoundedMegabytes = tr.e.cc.bytesToRoundedMegabytes; var RENDER_PASS_QUADS = Math.max(constants.ACTIVE_TREE, constants.PENDING_TREE) + 1; @@ -41,14 +41,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.itemList_ = new tr.ui.b.ListView(); - this.appendChild(this.controls_); + Polymer.dom(this).appendChild(this.controls_); - this.appendChild(this.itemList_); + Polymer.dom(this).appendChild(this.itemList_); this.itemList_.addEventListener( 'selection-changed', this.onItemSelectionChanged_.bind(this)); - this.controls_.appendChild(tr.ui.b.createSelector( + Polymer.dom(this.controls_).appendChild(tr.ui.b.createSelector( this, 'whichTree', 'layerPicker.whichTree', constants.ACTIVE_TREE, [{label: 'Active tree', value: constants.ACTIVE_TREE}, @@ -60,10 +60,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this, 'showPureTransformLayers', 'layerPicker.showPureTransformLayers', false, 'Transform layers'); - showPureTransformLayers.classList.add('show-transform-layers'); + Polymer.dom(showPureTransformLayers).classList.add( + 'show-transform-layers'); showPureTransformLayers.title = 'When checked, pure transform layers are shown'; - this.controls_.appendChild(showPureTransformLayers); + Polymer.dom(this.controls_).appendChild(showPureTransformLayers); }, get lthiSnapshot() { @@ -81,7 +82,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { set whichTree(whichTree) { this.whichTree_ = whichTree; - this.renderPassQuads_ = (whichTree == RENDER_PASS_QUADS); + this.renderPassQuads_ = (whichTree === RENDER_PASS_QUADS); this.updateContents_(); tr.b.dispatchSimpleEvent(this, 'selection-change', false); }, @@ -141,8 +142,8 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { function isPureTransformLayer(layer) { if (layer.args.compositingReasons && - layer.args.compositingReasons.length != 1 && - layer.args.compositingReasons[0] != 'No reasons given') + layer.args.compositingReasons.length !== 1 && + layer.args.compositingReasons[0] !== 'No reasons given') return false; if (layer.args.drawsContent) @@ -172,7 +173,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (showPureTransformLayers || !isPureTransformLayer(layer)) layerInfos.push(info); - }; + } tree.iterLayers(visitLayer); return layerInfos; }, @@ -197,14 +198,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var id = renderPassInfo.id; var item = this.createElementWithDepth_(renderPassInfo.depth); - var labelEl = item.appendChild(tr.ui.b.createSpan()); + var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); - labelEl.textContent = renderPassInfo.name + ' ' + id; + Polymer.dom(labelEl).textContent = renderPassInfo.name + ' ' + id; item.renderPass = renderPass; item.renderPassId = id; - this.itemList_.appendChild(item); + Polymer.dom(this.itemList_).appendChild(item); - if (id == selectedRenderPassId) { + if (id === selectedRenderPassId) { renderPass.selectionState = tr.model.SelectionState.SELECTED; } @@ -226,26 +227,27 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var id = layer.layerId; var item = this.createElementWithDepth_(layerInfo.depth); - var labelEl = item.appendChild(tr.ui.b.createSpan()); + var labelEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); - labelEl.textContent = layerInfo.name + ' ' + id; + Polymer.dom(labelEl).textContent = layerInfo.name + ' ' + id; - var notesEl = item.appendChild(tr.ui.b.createSpan()); + var notesEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); if (layerInfo.isMaskLayer) - notesEl.textContent += '(mask)'; + Polymer.dom(notesEl).textContent += '(mask)'; if (layerInfo.isReplicaLayer) - notesEl.textContent += '(replica)'; + Polymer.dom(notesEl).textContent += '(replica)'; - if (layer.gpuMemoryUsageInBytes !== undefined) { - var rounded = bytesToRoundedMegabytes(layer.gpuMemoryUsageInBytes); - if (rounded !== 0) - notesEl.textContent += ' (' + rounded + ' MB)'; - } + if ((layer.gpuMemoryUsageInBytes !== undefined) && + (layer.gpuMemoryUsageInBytes > 0)) { + var gpuUsageStr = tr.b.Unit.byName.sizeInBytes.format( + layer.gpuMemoryUsageInBytes); + Polymer.dom(notesEl).textContent += ' (' + gpuUsageStr + ' MiB)'; + } item.layer = layer; - this.itemList_.appendChild(item); + Polymer.dom(this.itemList_).appendChild(item); - if (layer.layerId == selectedLayerId) { + if (layer.layerId === selectedLayerId) { layer.selectionState = tr.model.SelectionState.SELECTED; item.selected = true; } @@ -258,10 +260,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { createElementWithDepth_: function(depth) { var item = document.createElement('div'); - var indentEl = item.appendChild(tr.ui.b.createSpan()); + var indentEl = Polymer.dom(item).appendChild(tr.ui.b.createSpan()); indentEl.style.whiteSpace = 'pre'; - for (var i = 0; i < depth; i++) - indentEl.textContent = indentEl.textContent + ' '; + for (var i = 0; i < depth; i++) { + Polymer.dom(indentEl).textContent = + Polymer.dom(indentEl).textContent + ' '; + } return item; }, @@ -308,7 +312,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }, set selection(selection) { - if (this.selection_ == selection) + if (this.selection_ === selection) return; this.selection_ = selection; this.updateContents_(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html index d808bc5e869..97a8bfe75e9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.html @@ -9,11 +9,11 @@ found in the LICENSE file. href="/tracing/ui/extras/chrome/cc/layer_tree_host_impl_view.css"> <link rel="import" href="/tracing/extras/chrome/cc/layer_tree_host_impl.html"> -<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_picker.html"> -<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_view.html"> <link rel="import" href="/tracing/extras/chrome/cc/tile.html"> <link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html"> <link rel="import" href="/tracing/ui/base/drag_handle.html"> +<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_picker.html"> +<link rel="import" href="/tracing/ui/extras/chrome/cc/layer_view.html"> <script> 'use strict'; @@ -31,7 +31,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-chrome-cc-lthi-s-view'); + Polymer.dom(this).classList.add('tr-ui-e-chrome-cc-lthi-s-view'); this.selection_ = undefined; @@ -48,9 +48,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.dragHandle_.horizontal = false; this.dragHandle_.target = this.layerView_; - this.appendChild(this.layerPicker_); - this.appendChild(this.dragHandle_); - this.appendChild(this.layerView_); + Polymer.dom(this).appendChild(this.layerPicker_); + Polymer.dom(this).appendChild(this.dragHandle_); + Polymer.dom(this).appendChild(this.layerView_); // Make sure we have the current values from layerView_ and layerPicker_, // since those might have been created before we added the listener. @@ -85,7 +85,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }, set selection(selection) { - if (this.selection_ == selection) + if (this.selection_ === selection) return; this.selection_ = selection; this.layerPicker_.selection = selection; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html index a54deecabfc..100741e8bb1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_tree_quad_stack_view.html @@ -9,6 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/quad.html"> <link rel="import" href="/tracing/base/raf.html"> <link rel="import" href="/tracing/base/range.html"> +<link rel="import" href="/tracing/base/unit_scale.html"> <link rel="import" href="/tracing/extras/chrome/cc/debug_colors.html"> <link rel="import" href="/tracing/extras/chrome/cc/picture.html"> <link rel="import" href="/tracing/extras/chrome/cc/render_pass.html"> @@ -87,8 +88,6 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { {label: 'Coverage Rects', value: 'coverage'}]; } - var bytesToRoundedMegabytes = tr.e.cc.bytesToRoundedMegabytes; - /** * @constructor @@ -121,21 +120,21 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var node = tr.ui.b.instantiateTemplate( '#tr-ui-e-chrome-cc-layer-tree-quad-stack-view-template', THIS_DOC); - this.appendChild(node); - this.appendChild(this.controls_); - this.appendChild(this.infoBar_); - this.appendChild(this.quadStackView_); + Polymer.dom(this).appendChild(node); + Polymer.dom(this).appendChild(this.controls_); + Polymer.dom(this).appendChild(this.infoBar_); + Polymer.dom(this).appendChild(this.quadStackView_); this.tileRectsSelector_ = tr.ui.b.createSelector( this, 'howToShowTiles', 'layerView.howToShowTiles', 'none', createTileRectsSelectorBaseOptions()); - this.controls_.appendChild(this.tileRectsSelector_); + Polymer.dom(this.controls_).appendChild(this.tileRectsSelector_); var tileHeatmapText = tr.ui.b.createSpan({ textContent: 'Tile heatmap:' }); - this.controls_.appendChild(tileHeatmapText); + Polymer.dom(this.controls_).appendChild(tileHeatmapText); var tileHeatmapSelector = tr.ui.b.createSelector( this, 'tileHeatmapType', @@ -147,7 +146,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { {label: 'Is using GPU memory', value: TILE_HEATMAP_TYPE.USING_GPU_MEMORY} ]); - this.controls_.appendChild(tileHeatmapSelector); + Polymer.dom(this.controls_).appendChild(tileHeatmapSelector); var showOtherLayersCheckbox = tr.ui.b.createCheckBox( this, 'showOtherLayers', @@ -155,7 +154,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Other layers/passes'); showOtherLayersCheckbox.title = 'When checked, show all layers, selected or not.'; - this.controls_.appendChild(showOtherLayersCheckbox); + Polymer.dom(this.controls_).appendChild(showOtherLayersCheckbox); var showInvalidationsCheckbox = tr.ui.b.createCheckBox( this, 'showInvalidations', @@ -163,7 +162,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Invalidations'); showInvalidationsCheckbox.title = 'When checked, compositing invalidations are highlighted in red'; - this.controls_.appendChild(showInvalidationsCheckbox); + Polymer.dom(this.controls_).appendChild(showInvalidationsCheckbox); var showUnrecordedRegionCheckbox = tr.ui.b.createCheckBox( this, 'showUnrecordedRegion', @@ -171,7 +170,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Unrecorded area'); showUnrecordedRegionCheckbox.title = 'When checked, unrecorded areas are highlighted in yellow'; - this.controls_.appendChild(showUnrecordedRegionCheckbox); + Polymer.dom(this.controls_).appendChild(showUnrecordedRegionCheckbox); var showBottlenecksCheckbox = tr.ui.b.createCheckBox( this, 'showBottlenecks', @@ -179,7 +178,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Bottlenecks'); showBottlenecksCheckbox.title = 'When checked, scroll bottlenecks are highlighted'; - this.controls_.appendChild(showBottlenecksCheckbox); + Polymer.dom(this.controls_).appendChild(showBottlenecksCheckbox); var showLayoutRectsCheckbox = tr.ui.b.createCheckBox( this, 'showLayoutRects', @@ -187,7 +186,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Layout rects'); showLayoutRectsCheckbox.title = 'When checked, shows rects for regions where layout happened'; - this.controls_.appendChild(showLayoutRectsCheckbox); + Polymer.dom(this.controls_).appendChild(showLayoutRectsCheckbox); var showContentsCheckbox = tr.ui.b.createCheckBox( this, 'showContents', @@ -195,7 +194,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Contents'); showContentsCheckbox.title = 'When checked, show the rendered contents inside the layer outlines'; - this.controls_.appendChild(showContentsCheckbox); + Polymer.dom(this.controls_).appendChild(showContentsCheckbox); var showAnimationBoundsCheckbox = tr.ui.b.createCheckBox( this, 'showAnimationBounds', @@ -203,7 +202,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Animation Bounds'); showAnimationBoundsCheckbox.title = 'When checked, show a border around' + ' a layer showing the extent of its animation.'; - this.controls_.appendChild(showAnimationBoundsCheckbox); + Polymer.dom(this.controls_).appendChild(showAnimationBoundsCheckbox); var showInputEventsCheckbox = tr.ui.b.createCheckBox( this, 'showInputEvents', @@ -211,14 +210,14 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'Input events'); showInputEventsCheckbox.title = 'When checked, input events are ' + 'displayed as circles.'; - this.controls_.appendChild(showInputEventsCheckbox); + Polymer.dom(this.controls_).appendChild(showInputEventsCheckbox); this.whatRasterizedLink_ = document.createElement('a'); - this.whatRasterizedLink_.classList.add('what-rasterized'); - this.whatRasterizedLink_.textContent = 'What rasterized?'; + Polymer.dom(this.whatRasterizedLink_).classList.add('what-rasterized'); + Polymer.dom(this.whatRasterizedLink_).textContent = 'What rasterized?'; this.whatRasterizedLink_.addEventListener( 'click', this.onWhatRasterizedLinkClicked_.bind(this)); - this.appendChild(this.whatRasterizedLink_); + Polymer.dom(this).appendChild(this.whatRasterizedLink_); }, get layerTreeImpl() { @@ -383,7 +382,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var selectableQuads = e.quads.filter(function(q) { return q.selectionToSetIfClicked !== undefined; }); - if (selectableQuads.length == 0) { + if (selectableQuads.length === 0) { this.selection = undefined; return; } @@ -391,7 +390,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { // Sort the quads low to high on stackingGroupId. selectableQuads.sort(function(x, y) { var z = x.stackingGroupId - y.stackingGroupId; - if (z != 0) + if (z !== 0) return z; return x.selectionToSetIfClicked.specicifity - y.selectionToSetIfClicked.specicifity; @@ -440,18 +439,20 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var thisTreeUsageInBytes = this.layerTreeImpl_.gpuMemoryUsageInBytes; var otherTreeUsageInBytes = lthi.gpuMemoryUsageInBytes - thisTreeUsageInBytes; - message += bytesToRoundedMegabytes(thisTreeUsageInBytes) + - 'MB on this tree'; + message += tr.b.convertUnit(thisTreeUsageInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on this tree'; if (otherTreeUsageInBytes) { - message += ', ' + - bytesToRoundedMegabytes(otherTreeUsageInBytes) + - 'MB on the other tree'; + message += ', ' + tr.b.convertUnit(otherTreeUsageInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on the other tree'; } } else { if (this.layerTreeImpl_) { var thisTreeUsageInBytes = this.layerTreeImpl_.gpuMemoryUsageInBytes; - message += bytesToRoundedMegabytes(thisTreeUsageInBytes) + - 'MB on this tree'; + message += tr.b.convertUnit(thisTreeUsageInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB on this tree'; if (this.layerTreeImpl_.otherTree) { // Older Chromes don't report enough data to know how much memory is @@ -461,7 +462,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { // plus one tree, to guess the unique on the other tree, etc. Newer // chromes report memory per tile, which allows LTHI to compute the // total tile memory usage, letting us figure things out properly. - message += ', ???MB on other tree. '; + message += ', ??? MiB on other tree. '; } } } @@ -469,10 +470,13 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (lthi.args.tileManagerBasicState) { var tmgs = lthi.args.tileManagerBasicState.globalState; message += ' (softMax=' + - bytesToRoundedMegabytes(tmgs.softMemoryLimitInBytes) + - 'MB, hardMax=' + - bytesToRoundedMegabytes(tmgs.hardMemoryLimitInBytes) + 'MB, ' + - tmgs.memoryLimitPolicy + ')'; + tr.b.convertUnit(tmgs.softMemoryLimitInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, hardMax=' + + tr.b.convertUnit(tmgs.hardMemoryLimitInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, ' + + tmgs.memoryLimitPolicy + ')'; } else { // Old Chromes do not have a globalState on the LTHI dump. @@ -495,10 +499,13 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var newest = didManageTilesSlices[didManageTilesSlices.length - 1]; var tmgs = newest.args.state.global_state; message += ' (softMax=' + - bytesToRoundedMegabytes(tmgs.soft_memory_limit_in_bytes) + - 'MB, hardMax=' + - bytesToRoundedMegabytes(tmgs.hard_memory_limit_in_bytes) + 'MB, ' + - tmgs.memory_limit_policy + ')'; + tr.b.convertUnit(tmgs.softMemoryLimitInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, hardMax=' + + tr.b.convertUnit(tmgs.hardMemoryLimitInBytes, + tr.b.UnitScale.Binary.NONE, + tr.b.UnitScale.Binary.MEBI).toFixed(1) + ' MiB, ' + + tmgs.memoryLimitPolicy + ')'; } } @@ -530,12 +537,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { } // Then create a new selector and replace the old one. - var new_selector = tr.ui.b.createSelector( + var newSelector = tr.ui.b.createSelector( this, 'howToShowTiles', 'layerView.howToShowTiles', 'none', data); - this.controls_.replaceChild(new_selector, this.tileRectsSelector_); - this.tileRectsSelector_ = new_selector; + this.controls_.replaceChild(newSelector, this.tileRectsSelector_); + this.tileRectsSelector_ = newSelector; }, computePictureLoadingStatus_: function() { @@ -614,7 +621,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { } if (this.showInputEvents && this.layerTreeImpl.tracedInputLatencies && this.inputEventImageData_ === undefined) { - var image = this.querySelector('#input-event'); + var image = Polymer.dom(this).querySelector('#input-event'); if (!image.src) { this.loadDataForImageElement_(image, function(imageData) { this.inputEventImageData_ = imageData; @@ -858,11 +865,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }, getValueForHeatmap_: function(tile, heatmapType) { - if (heatmapType == TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) { - return tile.scheduledPriority == 0 ? + if (heatmapType === TILE_HEATMAP_TYPE.SCHEDULED_PRIORITY) { + return tile.scheduledPriority === 0 ? undefined : tile.scheduledPriority; - } else if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) { + } else if (heatmapType === TILE_HEATMAP_TYPE.USING_GPU_MEMORY) { if (tile.isSolidColor) return 0.5; return tile.isUsingGpuMemory ? 0 : 1; @@ -871,7 +878,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { getMinMaxForHeatmap_: function(tiles, heatmapType) { var range = new tr.b.Range(); - if (heatmapType == TILE_HEATMAP_TYPE.USING_GPU_MEMORY) { + if (heatmapType === TILE_HEATMAP_TYPE.USING_GPU_MEMORY) { range.addValue(0); range.addValue(1); return range; @@ -926,7 +933,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { // TODO(vmpstr): Make the stiching of tiles and layers a part of // tile construction (issue 346) - if (layer.layerId != tile.layerId) + if (layer.layerId !== tile.layerId) continue; tiles.push(tile); @@ -1030,7 +1037,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { // Generate quads back-to-front. var layer = layers[layers.length - i]; alreadyVisitedLayerIds[layer.layerId] = true; - if (layer.objectInstance.name == 'cc::NinePatchLayerImpl') + if (layer.objectInstance.name === 'cc::NinePatchLayerImpl') continue; var layerQuad = layer.layerQuad.clone(); @@ -1044,7 +1051,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { layerQuad.stackingGroupId = nextStackingGroupId++; layerQuad.selectionToSetIfClicked = new cc.LayerSelection(layer); layerQuad.layer = layer; - if (this.showOtherLayers && this.selectedLayer == layer) + if (this.showOtherLayers && this.selectedLayer === layer) layerQuad.upperBorderColor = 'rgb(156,189,45)'; if (this.showAnimationBounds) @@ -1088,7 +1095,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { } this.layerTreeImpl.iterLayers(function(layer, depth, isMask, isReplica) { - if (!this.showOtherLayers && this.selectedLayer != layer) + if (!this.showOtherLayers && this.selectedLayer !== layer) return; if (alreadyVisitedLayerIds[layer.layerId]) return; @@ -1124,16 +1131,16 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.infoBar_.message = 'Some problems were encountered...'; this.infoBar_.addButton('More info...', function(e) { var overlay = new tr.ui.b.Overlay(); - overlay.textContent = ''; + Polymer.dom(overlay).textContent = ''; infoBarMessages.forEach(function(message) { var title = document.createElement('h3'); - title.textContent = message.header; + Polymer.dom(title).textContent = message.header; var details = document.createElement('div'); - details.textContent = message.details; + Polymer.dom(details).textContent = message.details; - overlay.appendChild(title); - overlay.appendChild(details); + Polymer.dom(overlay).appendChild(title); + Polymer.dom(overlay).appendChild(details); }); overlay.visible = true; @@ -1160,7 +1167,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (tile === undefined) continue; - if (tile.containingSnapshot == lthi) + if (tile.containingSnapshot === lthi) tasks.push(event); } return tasks; @@ -1169,10 +1176,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { updateWhatRasterizedLinkState_: function() { var tasks = this.getWhatRasterized_(); if (tasks.length) { - this.whatRasterizedLink_.textContent = tasks.length + ' raster tasks'; + Polymer.dom(this.whatRasterizedLink_).textContent = + tasks.length + ' raster tasks'; this.whatRasterizedLink_.style.display = ''; } else { - this.whatRasterizedLink_.textContent = ''; + Polymer.dom(this.whatRasterizedLink_).textContent = ''; this.whatRasterizedLink_.style.display = 'none'; } }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html index ab2a403283b..9bd34e084b6 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/layer_view.html @@ -31,7 +31,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var LayerView = tr.ui.b.define('tr-ui-e-chrome-cc-layer-view'); LayerView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.layerTreeQuadStackView_ = @@ -44,9 +44,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.dragBar_.target = this.analysisEl_; - this.appendChild(this.layerTreeQuadStackView_); - this.appendChild(this.dragBar_); - this.appendChild(this.analysisEl_); + Polymer.dom(this).appendChild(this.layerTreeQuadStackView_); + Polymer.dom(this).appendChild(this.dragBar_); + Polymer.dom(this).appendChild(this.analysisEl_); this.layerTreeQuadStackView_.addEventListener('selection-change', function() { @@ -84,22 +84,22 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (selection) { this.dragBar_.style.display = ''; this.analysisEl_.style.display = ''; - this.analysisEl_.textContent = ''; + Polymer.dom(this.analysisEl_).textContent = ''; var layer = selection.layer; if (layer && layer.args && layer.args.pictures) { - this.analysisEl_.appendChild( + Polymer.dom(this.analysisEl_).appendChild( this.createPictureBtn_(layer.args.pictures)); } var analysis = selection.createAnalysis(); - this.analysisEl_.appendChild(analysis); + Polymer.dom(this.analysisEl_).appendChild(analysis); } else { this.dragBar_.style.display = 'none'; this.analysisEl_.style.display = 'none'; - var analysis = this.analysisEl_.firstChild; + var analysis = Polymer.dom(this.analysisEl_).firstChild; if (analysis) - this.analysisEl_.removeChild(analysis); + Polymer.dom(this.analysisEl_).removeChild(analysis); this.layerTreeQuadStackView_.style.height = window.getComputedStyle(this).height; } @@ -120,7 +120,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { selection.push(snapshot); return selection; }; - link.textContent = 'View in Picture Debugger'; + Polymer.dom(link).textContent = 'View in Picture Debugger'; return link; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html index 28d51d16d93..7240a75f386 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_debugger.html @@ -9,8 +9,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/extras/chrome/cc/picture.html"> <link rel="import" href="/tracing/ui/analysis/generic_object_view.html"> <link rel="import" href="/tracing/ui/base/drag_handle.html"> -<link rel="import" href="/tracing/ui/base/info_bar.html"> <link rel="import" href="/tracing/ui/base/hotkey_controller.html"> +<link rel="import" href="/tracing/ui/base/info_bar.html"> <link rel="import" href="/tracing/ui/base/list_view.html"> <link rel="import" href="/tracing/ui/base/mouse_mode_selector.html"> <link rel="import" href="/tracing/ui/base/overlay.html"> @@ -120,24 +120,25 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var PictureDebugger = tr.ui.b.define('tr-ui-e-chrome-cc-picture-debugger'); PictureDebugger.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { var node = tr.ui.b.instantiateTemplate( '#tr-ui-e-chrome-cc-picture-debugger-template', THIS_DOC); - this.appendChild(node); + Polymer.dom(this).appendChild(node); this.pictureAsImageData_ = undefined; this.showOverdraw_ = false; this.zoomScaleValue_ = 1; - this.sizeInfo_ = this.querySelector('.size'); - this.rasterArea_ = this.querySelector('raster-area'); - this.rasterCanvas_ = this.rasterArea_.querySelector('canvas'); + this.sizeInfo_ = Polymer.dom(this).querySelector('.size'); + this.rasterArea_ = Polymer.dom(this).querySelector('raster-area'); + this.rasterCanvas_ = Polymer.dom(this.rasterArea_) + .querySelector('canvas'); this.rasterCtx_ = this.rasterCanvas_.getContext('2d'); - this.filename_ = this.querySelector('.filename'); + this.filename_ = Polymer.dom(this).querySelector('.filename'); this.drawOpsChartSummaryView_ = new tr.ui.e.chrome.cc.PictureOpsChartSummaryView(); @@ -145,7 +146,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.drawOpsChartView_.addEventListener( 'selection-changed', this.onChartBarClicked_.bind(this)); - this.exportButton_ = this.querySelector('.export'); + this.exportButton_ = Polymer.dom(this).querySelector('.export'); this.exportButton_.addEventListener( 'click', this.onSaveAsSkPictureClicked_.bind(this)); @@ -161,31 +162,31 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'pictureView.showSummaryChart', false, 'Show timing summary'); - var pictureInfo = this.querySelector('picture-info'); - pictureInfo.appendChild(overdrawCheckbox); - pictureInfo.appendChild(chartCheckbox); + var pictureInfo = Polymer.dom(this).querySelector('picture-info'); + Polymer.dom(pictureInfo).appendChild(overdrawCheckbox); + Polymer.dom(pictureInfo).appendChild(chartCheckbox); this.drawOpsView_ = new tr.ui.e.chrome.cc.PictureOpsListView(); this.drawOpsView_.addEventListener( 'selection-changed', this.onChangeDrawOps_.bind(this)); - var leftPanel = this.querySelector('left-panel'); - leftPanel.appendChild(this.drawOpsChartSummaryView_); - leftPanel.appendChild(this.drawOpsView_); + var leftPanel = Polymer.dom(this).querySelector('left-panel'); + Polymer.dom(leftPanel).appendChild(this.drawOpsChartSummaryView_); + Polymer.dom(leftPanel).appendChild(this.drawOpsView_); var middleDragHandle = document.createElement('tr-ui-b-drag-handle'); middleDragHandle.horizontal = false; middleDragHandle.target = leftPanel; - var rightPanel = this.querySelector('right-panel'); + var rightPanel = Polymer.dom(this).querySelector('right-panel'); rightPanel.replaceChild( - this.drawOpsChartView_, - rightPanel.querySelector('tr-ui-e-chrome-cc-picture-ops-chart-view')); + this.drawOpsChartView_, Polymer.dom(rightPanel) + .querySelector('tr-ui-e-chrome-cc-picture-ops-chart-view')); this.infoBar_ = document.createElement('tr-ui-b-info-bar'); - this.rasterArea_.appendChild(this.infoBar_); + Polymer.dom(this.rasterArea_).appendChild(this.infoBar_); - this.insertBefore(middleDragHandle, rightPanel); + Polymer.dom(this).insertBefore(middleDragHandle, rightPanel); this.picture_ = undefined; @@ -208,7 +209,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { e.stopPropagation(); } })); - this.appendChild(hkc); + Polymer.dom(this).appendChild(hkc); // Add a mutation observer so that when the view is resized we can // update the chart summary view. @@ -315,7 +316,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.updateContentsPending_ = false; if (this.picture_) { - this.sizeInfo_.textContent = '(' + + Polymer.dom(this.sizeInfo_).textContent = '(' + this.picture_.layerRect.width + ' x ' + this.picture_.layerRect.height + ')'; } @@ -333,7 +334,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.infoBar_.message = 'Cannot rasterize...'; this.infoBar_.addButton('More info...', function(e) { var overlay = new tr.ui.b.Overlay(); - overlay.textContent = this.pictureAsImageData_.error; + Polymer.dom(overlay).textContent = this.pictureAsImageData_.error; overlay.visible = true; e.stopPropagation(); return false; @@ -432,7 +433,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.mouseModeSelector_ = document.createElement( 'tr-ui-b-mouse-mode-selector'); this.mouseModeSelector_.targetElement = this.rasterArea_; - this.rasterArea_.appendChild(this.mouseModeSelector_); + Polymer.dom(this.rasterArea_).appendChild(this.mouseModeSelector_); this.mouseModeSelector_.supportedModeMask = tr.ui.b.MOUSE_SELECTOR_MODE.ZOOM; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html index 5ac0efb3d71..c9d60769fdc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_summary_view.html @@ -39,7 +39,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { 'tr-ui-e-chrome-cc-picture-ops-chart-summary-view'); PictureOpsChartSummaryView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.picture_ = undefined; @@ -49,7 +49,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.chart_ = document.createElement('canvas'); this.chartCtx_ = this.chart_.getContext('2d'); - this.appendChild(this.chart_); + Polymer.dom(this).appendChild(this.chart_); this.opsTimingData_ = []; @@ -78,7 +78,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.picture_ = picture; this.pictureDataProcessed_ = false; - if (this.classList.contains('hidden')) + if (Polymer.dom(this).classList.contains('hidden')) return; this.processPictureData_(); @@ -87,12 +87,12 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }, hide: function() { - this.classList.add('hidden'); + Polymer.dom(this).classList.add('hidden'); }, show: function() { - this.classList.remove('hidden'); + Polymer.dom(this).classList.remove('hidden'); if (this.pictureDataProcessed_) return; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html index a62f128e6b9..fe71fc87735 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_chart_view.html @@ -38,7 +38,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { tr.ui.b.define('tr-ui-e-chrome-cc-picture-ops-chart-view'); PictureOpsChartView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.picture_ = undefined; @@ -49,7 +49,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this.chart_ = document.createElement('canvas'); this.chartCtx_ = this.chart_.getContext('2d'); - this.appendChild(this.chart_); + Polymer.dom(this).appendChild(this.chart_); this.selectedOpIndex_ = undefined; this.chartWidth_ = 0; @@ -69,8 +69,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { this, 'usePercentileScale', 'PictureOpsChartView.usePercentileScale', false, 'Limit to 95%-ile'); - this.usePercentileScaleCheckbox_.classList.add('use-percentile-scale'); - this.appendChild(this.usePercentileScaleCheckbox_); + Polymer.dom(this.usePercentileScaleCheckbox_).classList.add( + 'use-percentile-scale'); + Polymer.dom(this).appendChild(this.usePercentileScaleCheckbox_); }, get dimensionsHaveChanged() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html index 1bae14a635f..806a54c5c30 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_ops_list_view.html @@ -8,8 +8,8 @@ found in the LICENSE file. <link rel="stylesheet" href="/tracing/ui/extras/chrome/cc/picture_ops_list_view.css"> <link rel="import" href="/tracing/extras/chrome/cc/constants.html"> -<link rel="import" href="/tracing/ui/base/list_view.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> +<link rel="import" href="/tracing/ui/base/list_view.html"> <link rel="import" href="/tracing/ui/base/utils.html"> <link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html"> @@ -34,11 +34,11 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { tr.ui.b.define('tr-ui-e-chrome-cc-picture-ops-list-view'); PictureOpsListView.prototype = { - __proto__: HTMLUnknownElement.prototype, + __proto__: HTMLDivElement.prototype, decorate: function() { this.opsList_ = new tr.ui.b.ListView(); - this.appendChild(this.opsList_); + Polymer.dom(this).appendChild(this.opsList_); this.selectedOp_ = undefined; this.selectedOpIndex_ = undefined; @@ -75,21 +75,21 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { var op = ops[i]; var item = document.createElement('div'); item.opIndex = op.opIndex; - item.textContent = i + ') ' + op.cmd_string; + Polymer.dom(item).textContent = i + ') ' + op.cmd_string; // Display the element info associated with the op, if available. if (op.elementInfo.tag || op.elementInfo.id || op.elementInfo.class) { var elementInfo = document.createElement('span'); - elementInfo.classList.add('elementInfo'); + Polymer.dom(elementInfo).classList.add('elementInfo'); var tag = op.elementInfo.tag ? op.elementInfo.tag : 'unknown'; var id = op.elementInfo.id ? 'id=' + op.elementInfo.id : undefined; var className = op.elementInfo.class ? 'class=' + op.elementInfo.class : undefined; - elementInfo.textContent = + Polymer.dom(elementInfo).textContent = '<' + tag + (id ? ' ' : '') + (id ? id : '') + (className ? ' ' : '') + (className ? className : '') + '>'; - item.appendChild(elementInfo); + Polymer.dom(item).appendChild(elementInfo); } // Display the Skia params. @@ -97,20 +97,20 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { // (https://github.com/google/trace-viewer/issues/782) if (op.info.length > 0) { var infoItem = document.createElement('div'); - infoItem.textContent = JSON.stringify(op.info); - item.appendChild(infoItem); + Polymer.dom(infoItem).textContent = JSON.stringify(op.info); + Polymer.dom(item).appendChild(infoItem); } // Display the op timing, if available. if (op.cmd_time && op.cmd_time >= 0.0001) { var time = document.createElement('span'); - time.classList.add('time'); + Polymer.dom(time).classList.add('time'); var rounded = op.cmd_time.toFixed(4); - time.textContent = '(' + rounded + 'ms)'; - item.appendChild(time); + Polymer.dom(time).textContent = '(' + rounded + 'ms)'; + Polymer.dom(item).appendChild(time); } - this.opsList_.appendChild(item); + Polymer.dom(this.opsList_).appendChild(item); } }, @@ -134,9 +134,9 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { beforeSelectedOp = false; this.selectedOpIndex_ = op.opIndex; } else if (beforeSelectedOp) { - op.setAttribute('beforeSelection', 'beforeSelection'); + Polymer.dom(op).setAttribute('beforeSelection', 'beforeSelection'); } else { - op.removeAttribute('beforeSelection'); + Polymer.dom(op).removeAttribute('beforeSelection'); } } @@ -204,15 +204,15 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { elementInfo = {}; annotationGroup.forEach(function(annotation) { annotation.info.forEach(function(info) { - if (info.indexOf(ANNOTATION_TAG) != -1) + if (info.indexOf(ANNOTATION_TAG) !== -1) elementInfo.tag = info.substring( info.indexOf(ANNOTATION_TAG) + ANNOTATION_TAG.length).toLowerCase(); - else if (info.indexOf(ANNOTATION_ID) != -1) + else if (info.indexOf(ANNOTATION_ID) !== -1) elementInfo.id = info.substring( info.indexOf(ANNOTATION_ID) + ANNOTATION_ID.length); - else if (info.indexOf(ANNOTATION_CLASS) != -1) + else if (info.indexOf(ANNOTATION_CLASS) !== -1) elementInfo.class = info.substring( info.indexOf(ANNOTATION_CLASS) + ANNOTATION_CLASS.length); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html index 74acef3e37b..ccb0b04e88e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/picture_view.html @@ -28,9 +28,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-chrome-cc-picture-snapshot-view'); + Polymer.dom(this).classList.add( + 'tr-ui-e-chrome-cc-picture-snapshot-view'); this.pictureDebugger_ = new tr.ui.e.chrome.cc.PictureDebugger(); - this.appendChild(this.pictureDebugger_); + Polymer.dom(this).appendChild(this.pictureDebugger_); }, updateContents: function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html index 2838c5b63ed..7dd256e40c7 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection.html @@ -52,7 +52,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { if (!referenceSnapshot) { referenceSnapshot = tile.containingSnapshot; } else { - if (tile.containingSnapshot != referenceSnapshot) { + if (tile.containingSnapshot !== referenceSnapshot) { return { ok: false, why: 'Raster tasks are from different compositor instances' @@ -77,7 +77,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { get associatedLayerId() { var tile0 = this.tiles_[0]; var allSameLayer = this.tiles_.every(function(tile) { - tile.layerId == tile0.layerId; + tile.layerId === tile0.layerId; }); if (allSameLayer) return tile0.layerId; @@ -105,7 +105,7 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { }); var analysis; - if (sel.length == 1) + if (sel.length === 1) analysis = document.createElement('tr-ui-a-single-event-sub-view'); else analysis = document.createElement('tr-ui-e-chrome-cc-raster-task-view'); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html index ee8e91c3c77..652bbc9b7cf 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_selection_test.html @@ -23,7 +23,7 @@ tr.b.unittest.testSuite(function() { var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]); var p = m.processes[1]; var rasterTasks = p.threads[1].sliceGroup.slices.filter(function(slice) { - return slice.title == 'RasterTask'; + return slice.title === 'RasterTask'; }); var selection = new tr.model.EventSet(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html index b4020840303..7ab2cbda14b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view.html @@ -4,15 +4,16 @@ Copyright (c) 2013 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> + +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/extras/chrome/cc/raster_task.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/extras/chrome/cc/selection.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-e-chrome-cc-raster-task-view"> +<dom-module id='tr-ui-e-chrome-cc-raster-task-view'> <template> <style> :host { @@ -22,6 +23,9 @@ found in the LICENSE file. #heading { flex: 0 0 auto; } + tr-ui-b-table { + font-size: 12px; + } </style> <div id="heading"> @@ -30,187 +34,187 @@ found in the LICENSE file. </div> <tr-ui-b-table id="content"></tr-ui-b-table> </template> - - <script> - 'use strict'; - Polymer({ - created: function() { - this.selection_ = undefined; - }, - - set selection(selection) { - this.selection_ = selection; - - this.updateContents_(); - }, - - updateColumns_: function(hadCpuDurations) { - var timeSpanConfig = { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: this.ownerDocument - }; - - var columns = [ - { - title: 'Layer', - value: function(row) { - if (row.isTotals) - return 'Totals'; - if (row.layer) { - var linkEl = document.createElement('tr-ui-a-analysis-link'); - linkEl.setSelectionAndContent( - function() { - return new tr.ui.e.chrome.cc.LayerSelection(costs.layer); - }, - 'Layer ' + row.layerId); - return linkEl; - } else { - return 'Layer ' + row.layerId; - } - }, - width: '250px' - }, - { - title: 'Num Tiles', - value: function(row) { return row.numTiles; }, - cmp: function(a, b) { return a.numTiles - b.numTiles; } - }, - { - title: 'Num Analysis Tasks', - value: function(row) { return row.numAnalysisTasks; }, - cmp: function(a, b) { - return a.numAnalysisTasks - b.numAnalysisTasks; +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tr-ui-e-chrome-cc-raster-task-view', + + created: function() { + this.selection_ = undefined; + }, + + set selection(selection) { + this.selection_ = selection; + + this.updateContents_(); + }, + + updateColumns_: function(hadCpuDurations) { + var timeSpanConfig = { + unit: tr.b.Unit.byName.timeDurationInMs, + ownerDocument: this.ownerDocument + }; + + var columns = [ + { + title: 'Layer', + value: function(row) { + if (row.isTotals) + return 'Totals'; + if (row.layer) { + var linkEl = document.createElement('tr-ui-a-analysis-link'); + linkEl.setSelectionAndContent( + function() { + return new tr.ui.e.chrome.cc.LayerSelection(costs.layer); + }, + 'Layer ' + row.layerId); + return linkEl; + } else { + return 'Layer ' + row.layerId; } }, - { - title: 'Num Raster Tasks', - value: function(row) { return row.numRasterTasks; }, - cmp: function(a, b) { return a.numRasterTasks - b.numRasterTasks; } - }, - { - title: 'Wall Duration (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.duration, timeSpanConfig); - }, - cmp: function(a, b) { return a.duration - b.duration; } + width: '250px' + }, + { + title: 'Num Tiles', + value: function(row) { return row.numTiles; }, + cmp: function(a, b) { return a.numTiles - b.numTiles; } + }, + { + title: 'Num Analysis Tasks', + value: function(row) { return row.numAnalysisTasks; }, + cmp: function(a, b) { + return a.numAnalysisTasks - b.numAnalysisTasks; } - ]; - - if (hadCpuDurations) { - columns.push({ - title: 'CPU Duration (ms)', - value: function(row) { - return tr.v.ui.createScalarSpan(row.cpuDuration, timeSpanConfig); - }, - cmp: function(a, b) { return a.cpuDuration - b.cpuDuration; } - }); + }, + { + title: 'Num Raster Tasks', + value: function(row) { return row.numRasterTasks; }, + cmp: function(a, b) { return a.numRasterTasks - b.numRasterTasks; } + }, + { + title: 'Wall Duration (ms)', + value: function(row) { + return tr.v.ui.createScalarSpan(row.duration, timeSpanConfig); + }, + cmp: function(a, b) { return a.duration - b.duration; } } + ]; - var colWidthPercentage; - if (columns.length == 1) - colWidthPercentage = '100%'; - else - colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; + if (hadCpuDurations) { + columns.push({ + title: 'CPU Duration (ms)', + value: function(row) { + return tr.v.ui.createScalarSpan(row.cpuDuration, timeSpanConfig); + }, + cmp: function(a, b) { return a.cpuDuration - b.cpuDuration; } + }); + } - for (var i = 1; i < columns.length; i++) - columns[i].width = colWidthPercentage; + var colWidthPercentage; + if (columns.length === 1) + colWidthPercentage = '100%'; + else + colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; - this.$.content.tableColumns = columns; - this.$.content.sortColumnIndex = columns.length - 1; - }, + for (var i = 1; i < columns.length; i++) + columns[i].width = colWidthPercentage; - updateContents_: function() { - var table = this.$.content; + this.$.content.tableColumns = columns; + this.$.content.sortColumnIndex = columns.length - 1; + }, - if (this.selection_.length === 0) { - this.$.link.setSelectionAndContent(undefined, ''); - table.tableRows = []; - table.footerRows = []; - table.rebuild(); - return; - } + updateContents_: function() { + var table = this.$.content; - // LTHI link. - var lthi = tr.e.cc.getTileFromRasterTaskSlice( - this.selection_[0]).containingSnapshot; - this.$.link.setSelectionAndContent(function() { - return new tr.model.EventSet(lthi); - }, lthi.userFriendlyName); - - // Get costs by layer. - var costsByLayerId = {}; - function getCurrentCostsForLayerId(tile) { - var layerId = tile.layerId; - var lthi = tile.containingSnapshot; - var layer; - if (lthi.activeTree) - layer = lthi.activeTree.findLayerWithId(layerId); - if (layer === undefined && lthi.pendingTree) - layer = lthi.pendingTree.findLayerWithId(layerId); - if (costsByLayerId[layerId] === undefined) { - costsByLayerId[layerId] = { - layerId: layerId, - layer: layer, - numTiles: 0, - numAnalysisTasks: 0, - numRasterTasks: 0, - duration: 0, - cpuDuration: 0 - }; - } - return costsByLayerId[layerId]; + if (this.selection_.length === 0) { + this.$.link.setSelectionAndContent(undefined, ''); + table.tableRows = []; + table.footerRows = []; + table.rebuild(); + return; + } + // LTHI link. + var lthi = tr.e.cc.getTileFromRasterTaskSlice( + tr.b.getFirstElement(this.selection_)).containingSnapshot; + this.$.link.setSelectionAndContent(function() { + return new tr.model.EventSet(lthi); + }, lthi.userFriendlyName); + + // Get costs by layer. + var costsByLayerId = {}; + function getCurrentCostsForLayerId(tile) { + var layerId = tile.layerId; + var lthi = tile.containingSnapshot; + var layer; + if (lthi.activeTree) + layer = lthi.activeTree.findLayerWithId(layerId); + if (layer === undefined && lthi.pendingTree) + layer = lthi.pendingTree.findLayerWithId(layerId); + if (costsByLayerId[layerId] === undefined) { + costsByLayerId[layerId] = { + layerId: layerId, + layer: layer, + numTiles: 0, + numAnalysisTasks: 0, + numRasterTasks: 0, + duration: 0, + cpuDuration: 0 + }; } + return costsByLayerId[layerId]; + } - var totalDuration = 0; - var totalCpuDuration = 0; - var totalNumAnalyzeTasks = 0; - var totalNumRasterizeTasks = 0; - var hadCpuDurations = false; - - var tilesThatWeHaveSeen = {}; - - this.selection_.forEach(function(slice) { - var tile = tr.e.cc.getTileFromRasterTaskSlice(slice); - var curCosts = getCurrentCostsForLayerId(tile); + var totalDuration = 0; + var totalCpuDuration = 0; + var totalNumAnalyzeTasks = 0; + var totalNumRasterizeTasks = 0; + var hadCpuDurations = false; - if (!tilesThatWeHaveSeen[tile.objectInstance.id]) { - tilesThatWeHaveSeen[tile.objectInstance.id] = true; - curCosts.numTiles += 1; - } + var tilesThatWeHaveSeen = {}; - if (tr.e.cc.isSliceDoingAnalysis(slice)) { - curCosts.numAnalysisTasks += 1; - totalNumAnalyzeTasks += 1; - } else { - curCosts.numRasterTasks += 1; - totalNumRasterizeTasks += 1; - } - curCosts.duration += slice.duration; - totalDuration += slice.duration; - if (slice.cpuDuration !== undefined) { - curCosts.cpuDuration += slice.cpuDuration; - totalCpuDuration += slice.cpuDuration; - hadCpuDurations = true; - } - }); + this.selection_.forEach(function(slice) { + var tile = tr.e.cc.getTileFromRasterTaskSlice(slice); + var curCosts = getCurrentCostsForLayerId(tile); - // Apply to the table. - this.updateColumns_(hadCpuDurations); - table.tableRows = tr.b.dictionaryValues(costsByLayerId); - table.rebuild(); + if (!tilesThatWeHaveSeen[tile.objectInstance.id]) { + tilesThatWeHaveSeen[tile.objectInstance.id] = true; + curCosts.numTiles += 1; + } - // Footer. - table.footerRows = [ - { - isTotals: true, - numTiles: tr.b.dictionaryLength(tilesThatWeHaveSeen), - numAnalysisTasks: totalNumAnalyzeTasks, - numRasterTasks: totalNumRasterizeTasks, - duration: totalDuration, - cpuDuration: totalCpuDuration - } - ]; - } - }); - </script> -</polymer-element> + if (tr.e.cc.isSliceDoingAnalysis(slice)) { + curCosts.numAnalysisTasks += 1; + totalNumAnalyzeTasks += 1; + } else { + curCosts.numRasterTasks += 1; + totalNumRasterizeTasks += 1; + } + curCosts.duration += slice.duration; + totalDuration += slice.duration; + if (slice.cpuDuration !== undefined) { + curCosts.cpuDuration += slice.cpuDuration; + totalCpuDuration += slice.cpuDuration; + hadCpuDurations = true; + } + }); + + // Apply to the table. + this.updateColumns_(hadCpuDurations); + table.tableRows = tr.b.dictionaryValues(costsByLayerId); + table.rebuild(); + + // Footer. + table.footerRows = [ + { + isTotals: true, + numTiles: tr.b.dictionaryLength(tilesThatWeHaveSeen), + numAnalysisTasks: totalNumAnalyzeTasks, + numRasterTasks: totalNumRasterizeTasks, + duration: totalDuration, + cpuDuration: totalCpuDuration + } + ]; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html index be771775cb7..cb3d11d4953 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/raster_task_view_test.html @@ -29,7 +29,7 @@ tr.b.unittest.testSuite(function() { var m = tr.c.TestUtils.newModelWithEvents([g_catLTHIEvents]); var p = m.processes[1]; var rasterTasks = p.threads[1].sliceGroup.slices.filter(function(slice) { - return slice.title == 'RasterTask' || slice.title == 'AnalyzeTask'; + return slice.title === 'RasterTask' || slice.title === 'AnalyzeTask'; }); var selection = new tr.model.EventSet(); @@ -58,7 +58,7 @@ tr.b.unittest.testSuite(function() { analysisEl.brushingStateController = brushingStateController; brushingStateController.changeSelectionFromTimeline(selection); - assert.isDefined(analysisEl.querySelector( + assert.isDefined(Polymer.dom(analysisEl).querySelector( 'tr-ui-e-chrome-cc-raster-task-view')); var sv = tr.b.findDeepElementMatching( diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html index 2c556c67a7b..16e0bf0f347 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/cc/tile_view.html @@ -26,10 +26,10 @@ tr.exportTo('tr.ui.e.chrome.cc', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-chrome-cc-tile-snapshot-view'); + Polymer.dom(this).classList.add('tr-ui-e-chrome-cc-tile-snapshot-view'); this.layerTreeView_ = new tr.ui.e.chrome.cc.LayerTreeHostImplSnapshotView(); - this.appendChild(this.layerTreeView_); + Polymer.dom(this).appendChild(this.layerTreeView_); }, updateContents: function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html index 77bb005fcf3..51f3f444a29 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/gpu/state_view.html @@ -25,9 +25,9 @@ tr.exportTo('tr.ui.e.chrome.gpu', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-chrome-gpu-state-snapshot-view'); + Polymer.dom(this).classList.add('tr-ui-e-chrome-gpu-state-snapshot-view'); this.screenshotImage_ = document.createElement('img'); - this.appendChild(this.screenshotImage_); + Polymer.dom(this).appendChild(this.screenshotImage_); }, updateContents: function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/analysis/layout_tree_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/layout_tree_sub_view.html index 75a42c01d42..26b38f6d402 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/analysis/layout_tree_sub_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome/layout_tree_sub_view.html @@ -5,19 +5,27 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/extras/chrome/layout_tree.html"> <link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> -<polymer-element name="tr-ui-a-layout-tree-sub-view" - extends="tr-ui-a-sub-view"> +<dom-module id='tr-ui-a-layout-tree-sub-view'> <template> + <style> + tr-ui-b-table { + font-size: 12px; + } + </style> <div id="content"></div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui.analysis', function() { - Polymer('tr-ui-a-layout-tree-sub-view', { + Polymer({ + is: 'tr-ui-a-layout-tree-sub-view', + behaviors: ['tr-ui-a-sub-view'], + set selection(selection) { this.currentSelection_ = selection; this.updateContents_(); @@ -28,7 +36,7 @@ tr.exportTo('tr.ui.analysis', function() { }, updateContents_: function() { - this.$.content.textContent = ''; + this.set('$.content.textContent', ''); if (!this.currentSelection_) return; @@ -193,11 +201,26 @@ tr.exportTo('tr.ui.analysis', function() { return snapshot.rootLayoutObject; }); table.rebuild(); - this.$.content.appendChild(table); - } - }); + Polymer.dom(this.$.content).appendChild(table); + }, + }); return {}; }); +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-layout-tree-sub-view', + tr.e.chrome.LayoutTreeSnapshot, + { + multi: false, + title: 'Layout Tree', + }); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-a-layout-tree-sub-view', + tr.e.chrome.LayoutTreeSnapshot, + { + multi: true, + title: 'Layout Trees', + }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html index cd9fb3f91c4..e2065a701e5 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/chrome_config.html @@ -13,12 +13,21 @@ The chrome config is heavily used: - telemetry --> +<!-- +TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the +same way that all non-UI files depend on tracing/base/base.html. Enforce this +dependency with a presubmit. +--> +<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order> + <link rel="import" href="/tracing/extras/chrome_config.html"> <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/extras/chrome/cc/cc.html"> <link rel="import" href="/tracing/ui/extras/chrome/gpu/gpu.html"> +<link rel="import" href="/tracing/ui/extras/chrome/layout_tree_sub_view.html"> <link rel="import" href="/tracing/ui/extras/side_panel/frame_data_side_panel.html"> <link rel="import" href="/tracing/ui/extras/side_panel/input_latency_side_panel.html"> <link rel="import" href="/tracing/ui/extras/side_panel/time_summary_side_panel.html"> <link rel="import" href="/tracing/ui/extras/system_stats/system_stats.html"> +<link rel="import" href="/tracing/ui/extras/v8_config.html"> <link rel="import" href="/tracing/ui/timeline_view.html"> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html index a515ac4123f..2324a1d9214 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/deep_reports/html_results.html @@ -12,106 +12,110 @@ This class tries to (simply) copy the telemetry Results object, but outputs directly to an HTML table. It takes things that look like Telemetry values, and updates the table internally. --> -<polymer-element name="tr-ui-e-deep-reports-html-results"> +<dom-module id='tr-ui-e-deep-reports-html-results'> <template> <style> :host { display: flex; + font-size: 12px; } </style> <tr-ui-b-table id="table"></tr-ui-b-table> </template> - <script> - 'use strict'; - - Polymer({ - created: function() { - this.hasColumnNamed_ = {}; - this.pageToRowMap_ = new WeakMap(); - }, - - ready: function() { - var table = this.$.table; - table.tableColumns = [ - { - title: 'Label', - value: function(row) { return row.label; }, - width: '350px' - } - ]; - this.clear(); - }, - - clear: function() { - this.$.table.tableRows = []; - }, - - addColumnIfNeeded_: function(columnName) { - if (this.hasColumnNamed_[columnName]) - return; - this.hasColumnNamed_[columnName] = true; - - var column = { - title: columnName, - value: function(row) { - if (row[columnName] === undefined) - return ''; - return row[columnName]; - } - }; - - var columns = this.$.table.tableColumns; - columns.push(column); - - // Update widths. - var colWidthPercentage; - if (columns.length == 1) - colWidthPercentage = '100%'; - else - colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; - - for (var i = 1; i < columns.length; i++) - columns[i].width = colWidthPercentage; - - this.$.table.tableColumns = columns; - }, - - getRowForPage_: function(page) { - if (!this.pageToRowMap_.has(page)) { - var i = page.url.lastIndexOf('/'); - var baseName = page.url.substring(i + 1); - - var link = document.createElement('a'); - link.href = 'trace_viewer.html#' + page.url; - link.textContent = baseName; - - var row = { - label: link, - value: '', - subRows: [], - isExpanded: true - }; - this.$.table.tableRows.push(row); - this.pageToRowMap_.set(page, row); - - // Kick table rebuild. - this.$.table.tableRows = this.$.table.tableRows; +</dom-module> + +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-deep-reports-html-results', + + created: function() { + this.hasColumnNamed_ = {}; + this.pageToRowMap_ = new WeakMap(); + }, + + ready: function() { + var table = this.$.table; + table.tableColumns = [ + { + title: 'Label', + value: function(row) { return row.label; }, + width: '350px' } - return this.pageToRowMap_.get(page); - }, - - addValue: function(value) { - /* Value is expected to be a scalar telemetry-style Value. */ - if (value.type !== 'scalar') - throw new Error('wat'); - - this.addColumnIfNeeded_(value.name); - var rowForPage = this.getRowForPage_(value.page); - rowForPage[value.name] = value.value; + ]; + this.clear(); + }, + + clear: function() { + this.$.table.tableRows = []; + }, + + addColumnIfNeeded_: function(columnName) { + if (this.hasColumnNamed_[columnName]) + return; + this.hasColumnNamed_[columnName] = true; + + var column = { + title: columnName, + value: function(row) { + if (row[columnName] === undefined) + return ''; + return row[columnName]; + } + }; + + var columns = this.$.table.tableColumns; + columns.push(column); + + // Update widths. + var colWidthPercentage; + if (columns.length === 1) + colWidthPercentage = '100%'; + else + colWidthPercentage = (100 / (columns.length - 1)).toFixed(3) + '%'; + + for (var i = 1; i < columns.length; i++) + columns[i].width = colWidthPercentage; + + this.$.table.tableColumns = columns; + }, + + getRowForPage_: function(page) { + if (!this.pageToRowMap_.has(page)) { + var i = page.url.lastIndexOf('/'); + var baseName = page.url.substring(i + 1); + + var link = document.createElement('a'); + link.href = 'trace_viewer.html#' + page.url; + Polymer.dom(link).textContent = baseName; + + var row = { + label: link, + value: '', + subRows: [], + isExpanded: true + }; + this.$.table.tableRows.push(row); + this.pageToRowMap_.set(page, row); // Kick table rebuild. this.$.table.tableRows = this.$.table.tableRows; } - }); - </script> -</polymer-element> + return this.pageToRowMap_.get(page); + }, + + addValue: function(value) { + /* Value is expected to be a scalar telemetry-style Value. */ + if (value.type !== 'scalar') + throw new Error('wat'); + + this.addColumnIfNeeded_(value.name); + var rowForPage = this.getRowForPage_(value.page); + rowForPage[value.name] = value.value; + + // Kick table rebuild. + this.$.table.tableRows = this.$.table.tableRows; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html index 180f2ce97b4..fa19a804bc5 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comment_element.html @@ -5,7 +5,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<polymer-element name="tr-ui-e-drive-comment-element" attributes="comment"> +<dom-module id='tr-ui-e-drive-comment-element'> <template> <style> :host { @@ -56,16 +56,29 @@ found in the LICENSE file. <div id="comment-date">{{ createdDate }}</div> </div> </div> - <div id="comment-content">{{ comment.anchor ? '⚓ ' : '' }} + <div id="comment-content">{{_computeCommentContentPrefix( comment)}} {{ comment.content }}</div> </div> </template> - <script> - 'use strict'; - Polymer({ - commentChanged: function() { - this.createdDate = new Date(this.comment.createdDate).toLocaleString(); +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tr-ui-e-drive-comment-element', + + properties: { + comment: { + type: String, + observer: '_commentChanged' } - }); - </script> -</polymer-element> + }, + + _commentChanged: function() { + this.createdDate = new Date(this.comment.createdDate).toLocaleString(); + }, + + _computeCommentContentPrefix: function(comment) { + return comment.anchor ? '⚓ ' : ''; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html index 3728481be17..19cc2cc46b1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/comments_side_panel.html @@ -6,9 +6,9 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/ui/extras/drive/comment_element.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> -<polymer-element name='tr-ui-e-drive-comments-side-panel' - extends='tr-ui-side-panel'> +<dom-module id='tr-ui-e-drive-comments-side-panel'> <template> <style> :host { @@ -40,141 +40,146 @@ found in the LICENSE file. <toolbar id='toolbar'></toolbar> <result-area id='result_area'> - <template repeat="{{ comment in comments_ }}"> + <template is="dom-repeat" items="{{comments_}}" repeat="{{ comment in comments_ }}"> <tr-ui-e-drive-comment-element comment="{{comment}}" - on-click="{{commentClick}}"> + on-click="commentClick"> </tr-ui-e-drive-comment-element> </template> <div id="comments-textarea-container"> - <textarea id="commentinput" on-focus='{{textAreaFocus}}' - on-blur='{{textAreaBlur}}' - on-keypress="{{textareaKeypress}}"></textarea> + <textarea id="commentinput" on-focus='textAreaFocus' + on-blur='textAreaBlur' + on-keypress="textareaKeypress"></textarea> </div> </result-area> </template> - - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.rangeOfInterest_ = new tr.b.Range(); - this.selection_ = undefined; - this.comments_ = []; - this.annotationFromComment_ = undefined; - this.textAreaFocused = false; - }, - - setCommentProvider: function(commentProvider) { - this.commentProvider_ = commentProvider; - }, - - attached: function() { - if (this.commentProvider_ === undefined) { - this.commentProvider_ = - new tr.ui.e.drive.analysis.DefaultCommentProvider(); - } - this.commentProvider_.attachToElement(this); - }, - - detached: function() { - this.commentProvider_.detachFromElement(); - }, - - commentClick: function(event, detail, sender) { - var anchor = sender.comment.anchor; - if (anchor === undefined) - return; - - var uiState = - JSON.parse(anchor).a[0][tr.ui.e.drive.constants.ANCHOR_NAME]; - - var myEvent = new CustomEvent('navigateToUIState', { detail: - new tr.ui.b.UIState(new tr.model.Location(uiState.location.xWorld, - uiState.location.yComponents), - uiState.scaleX) - }); - document.dispatchEvent(myEvent); - - if (this.annotationFromComment_) - this.model.removeAnnotation(this.annotationFromComment_); - var loc = new tr.model.Location(uiState.location.xWorld, - uiState.location.yComponents); - - var text = sender.comment.author.displayName + ': ' + - sender.comment.content; - this.annotationFromComment_ = - new tr.model.CommentBoxAnnotation(loc, text); - this.model.addAnnotation(this.annotationFromComment_); - }, - - textareaKeypress: function(event, detail, sender) { - // Check for return key. - if (event.keyCode === 13 && !event.ctrlKey) { - this.commentProvider_.addComment(this.$.commentinput.value); - this.$.commentinput.value = ''; - } - event.stopPropagation(); - return true; - }, - - textAreaFocus: function(event) { - this.textAreaFocused = true; - }, - - textAreaBlur: function(event) { - this.textAreaFocused = false; - }, - - get rangeOfInterest() { +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-drive-comments-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + + ready: function() { + this.rangeOfInterest_ = new tr.b.Range(); + this.selection_ = undefined; + this.comments_ = []; + this.annotationFromComment_ = undefined; + this.textAreaFocused = false; + }, + + setCommentProvider: function(commentProvider) { + this.commentProvider_ = commentProvider; + }, + + attached: function() { + if (this.commentProvider_ === undefined) { + this.commentProvider_ = + new tr.ui.e.drive.analysis.DefaultCommentProvider(); + } + this.commentProvider_.attachToElement(this); + }, + + detached: function() { + this.commentProvider_.detachFromElement(); + }, + + commentClick: function(event) { + var anchor = event.currentTarget.comment.anchor; + if (!anchor) + return; + + var uiState = + JSON.parse(anchor).a[0][tr.ui.e.drive.constants.ANCHOR_NAME]; + + var myEvent = new CustomEvent('navigateToUIState', { detail: + new tr.ui.b.UIState(new tr.model.Location(uiState.location.xWorld, + uiState.location.yComponents), + uiState.scaleX) + }); + document.dispatchEvent(myEvent); + + if (this.annotationFromComment_) + this.model.removeAnnotation(this.annotationFromComment_); + var loc = new tr.model.Location(uiState.location.xWorld, + uiState.location.yComponents); + + var text = sender.comment.author.displayName + ': ' + + sender.comment.content; + this.annotationFromComment_ = + new tr.model.CommentBoxAnnotation(loc, text); + this.model.addAnnotation(this.annotationFromComment_); + }, + + textareaKeypress: function(event) { + // Check for return key. + if (event.keyCode === 13 && !event.ctrlKey) { + this.commentProvider_.addComment(this.$.commentinput.value); + this.$.commentinput.value = ''; + } + event.stopPropagation(); + return true; + }, + + textAreaFocus: function(event) { + this.textAreaFocused = true; + }, + + textAreaBlur: function(event) { + this.textAreaFocused = false; + }, + + get rangeOfInterest() { + return this.rangeOfInterest_; + }, + + set rangeOfInterest(rangeOfInterest) { + this.rangeOfInterest_ = rangeOfInterest; + this.updateContents_(); + }, + + get currentRangeOfInterest() { + if (this.rangeOfInterest_.isEmpty) + return this.model_.bounds; + else return this.rangeOfInterest_; - }, - - set rangeOfInterest(rangeOfInterest) { - this.rangeOfInterest_ = rangeOfInterest; - this.updateContents_(); - }, - - get currentRangeOfInterest() { - if (this.rangeOfInterest_.isEmpty) - return this.model_.bounds; - else - return this.rangeOfInterest_; - }, - - get model() { - return this.model_; - }, - - set model(model) { - this.model_ = model; - this.updateContents_(); - }, - - set selection(selection) { - this.selection_ = selection; - }, - - updateContents_: function() { - this.commentProvider_.updateComments(); - }, - - supportsModel: function(m) { - if (m === undefined) { - return { - supported: false, - reason: 'Unknown tracing model' - }; - } + }, + + get model() { + return this.model_; + }, + + set model(model) { + this.model_ = model; + this.updateContents_(); + }, + + set selection(selection) { + this.selection_ = selection; + }, + + updateContents_: function() { + this.commentProvider_.updateComments(); + }, + + supportsModel: function(m) { + if (m === undefined) { return { - supported: true + supported: false, + reason: 'Unknown tracing model' }; - }, - - get textLabel() { - return 'Comments'; } - }); - - </script> -</polymer-element> + return { + supported: true + }; + }, + + get textLabel() { + return 'Comments'; + } +}); + +tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-e-drive-comments-side-panel'); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html index 2c44cea24ff..4b31b5fc68d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/drive/index.html @@ -10,9 +10,9 @@ found in the LICENSE file. <script type="text/javascript" src="https://apis.google.com/js/api.js"></script> <link rel="import" href="/components/polymer/polymer.html"> + <link rel="import" href="/tracing/ui/extras/drive/drive_comment_provider.html"> <link rel="import" href="/tracing/ui/extras/full_config.html"> <link rel="import" href="/tracing/ui/timeline_view.html"> - <link rel="import" href="/tracing/ui/extras/drive/drive_comment_provider.html"> <style> body { @@ -196,7 +196,7 @@ found in the LICENSE file. // Use the Google API Loader script to load the google.picker script. onAPIClientLoaded_ = function() { var driveState = parseGETParameter('state'); - if (driveState != null) { + if (driveState !== null) { var driveStateJson = JSON.parse(driveState); fileIdToLoad_ = String(driveStateJson.ids); } @@ -209,7 +209,7 @@ found in the LICENSE file. setTimeout(onRepeatAuthApiLoad, 30000); }, 30000); }}); - } + }; function onAuthApiLoad(tryImmediate, resultCallback) { window.gapi.auth.authorize( @@ -222,12 +222,12 @@ found in the LICENSE file. function onPickerApiLoad() { pickerApiLoaded_ = true; - if (fileIdToLoad_ == null) + if (fileIdToLoad_ === null) createPicker(); } function onAuthResultSuccess() { - if (fileIdToLoad_ == null) + if (fileIdToLoad_ === null) createPicker(); else loadFileFromDrive(fileIdToLoad_); @@ -261,7 +261,7 @@ found in the LICENSE file. } function pickerCallback(data) { - if (data.action == google.picker.Action.PICKED) { + if (data.action === google.picker.Action.PICKED) { loadFileFromDrive(data.docs[0].id); } } @@ -287,11 +287,11 @@ found in the LICENSE file. downloadingOverlay.title = 'Downloading...'; downloadingOverlay.userCanClose = false; downloadingOverlay.msgEl = document.createElement('div'); - downloadingOverlay.appendChild(downloadingOverlay.msgEl); + Polymer.dom(downloadingOverlay).appendChild(downloadingOverlay.msgEl); downloadingOverlay.msgEl.style.margin = '20px'; downloadingOverlay.update = function(msg) { - this.msgEl.textContent = msg; - } + Polymer.dom(this.msgEl).textContent = msg; + }; downloadingOverlay.visible = true; var accessToken = gapi.auth.getToken().access_token; @@ -317,7 +317,7 @@ found in the LICENSE file. var allCollaborators = driveDocument_.getCollaborators(); var collaboratorCount = allCollaborators.length; var collabspan = document.getElementById('collabs'); - collabspan.innerHTML = ''; + Polymer.dom(collabspan).innerHTML = ''; var imageList = []; for (var i = 0; i < collaboratorCount; i++) { var user = allCollaborators[i]; @@ -328,7 +328,7 @@ found in the LICENSE file. img.height = 30; img.width = 30; img.className = 'collaborator-img'; - collabspan.appendChild(img); + Polymer.dom(collabspan).appendChild(img); imageList.push({'image': img, 'name': user.displayName}); } for (i = 0; i < imageList.length; i++) { @@ -338,18 +338,18 @@ found in the LICENSE file. var collabTooltipContent = tr.ui.b.createDiv({ className: 'collaborator-tooltip-content' }); - collabTooltipContent.textContent = imageList[i].name; - collabTooltip.appendChild(collabTooltipContent); - collabspan.appendChild(collabTooltip); + Polymer.dom(collabTooltipContent).textContent = imageList[i].name; + Polymer.dom(collabTooltip).appendChild(collabTooltipContent); + Polymer.dom(collabspan).appendChild(collabTooltip); var collabTooltipArrow = tr.ui.b.createDiv({ className: 'collaborator-tooltip-arrow'}); - collabTooltip.appendChild(collabTooltipArrow); + Polymer.dom(collabTooltip).appendChild(collabTooltipArrow); var collabTooltipArrowBefore = tr.ui.b.createDiv({ className: 'collaborator-tooltip-arrow-before'}); - collabTooltipArrow.appendChild(collabTooltipArrowBefore); + Polymer.dom(collabTooltipArrow).appendChild(collabTooltipArrowBefore); var collabTooltipArrowAfter = tr.ui.b.createDiv({ className: 'collaborator-tooltip-arrow-after'}); - collabTooltipArrow.appendChild(collabTooltipArrowAfter); + Polymer.dom(collabTooltipArrow).appendChild(collabTooltipArrowAfter); var rect = imageList[i].image.getBoundingClientRect(); collabTooltip.style.top = (rect.bottom - 6) + 'px'; @@ -414,7 +414,7 @@ found in the LICENSE file. }, function(err) { var downloadingOverlay = new tr.ui.b.Overlay(); - downloadingOverlay.textContent = + Polymer.dom(downloadingOverlay).textContent = tr.b.normalizeException(err).message; downloadingOverlay.title = 'Import error'; downloadingOverlay.visible = true; @@ -434,7 +434,7 @@ found in the LICENSE file. } function onLoad() { - timelineViewEl_ = document.querySelector('x-timeline-view'); + timelineViewEl_ = Polymer.dom(document).querySelector('x-timeline-view'); timelineViewEl_.globalMode = true; var navbar = document.getElementById('navbar'); timelineViewEl_.style.top = navbar.offsetHeight + 'px'; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html index f27fbafd1ce..6d1e29d4e20 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/full_config.html @@ -5,6 +5,13 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<!-- +TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the +same way that all non-UI files depend on tracing/base/base.html. Enforce this +dependency with a presubmit. +--> +<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order> + <!-- The full config is all the configs slammed together. --> <link rel="import" href="/tracing/extras/importer/gcloud_trace/gcloud_trace_importer.html"> <link rel="import" href="/tracing/ui/extras/chrome_config.html"> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html index b804717a76a..a36021dd7b3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/highlighter/vsync_highlighter.html @@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/tracks/highlighter.html"> <link rel="import" href="/tracing/ui/timeline_track_view.html"> <link rel="import" href="/tracing/ui/timeline_viewport.html"> +<link rel="import" href="/tracing/ui/tracks/highlighter.html"> <link rel="import" href="/tracing/ui/tracks/model_track.html"> <script> @@ -81,7 +81,7 @@ tr.exportTo('tr.ui.e.highlighter', function() { var stripes = VSyncHighlighter.generateStripes( this.times_, viewLWorld, viewRWorld); - if (stripes.length == 0) { + if (stripes.length === 0) { return; } @@ -93,7 +93,7 @@ tr.exportTo('tr.ui.e.highlighter', function() { var opacity = (VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT - clampedStripeDensity) / VSyncHighlighter.VSYNC_DENSITY_RANGE; - if (opacity == 0) { + if (opacity === 0) { return; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html index 0197474ce45..ba6ae9990d8 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/lean_config.html @@ -5,7 +5,13 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/extras/lean_config.html"> +<!-- +TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the same way that +all non-UI files depend on tracing/base/base.html. Enforce this dependency with a presubmit. +--> +<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order> + +<link rel="import" href="/tracing/extras/lean_config.html" data-suppress-import-order> <!-- The lean config is just enough to import uncompressed, trace-event-formatted diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html index 5cc5b6dc241..0988f6367cc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel.html @@ -7,13 +7,13 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/statistics.html"> <link rel="import" href="/tracing/model/event_set.html"> -<link rel="import" href="/tracing/ui/base/table.html"> -<link rel="import" href="/tracing/ui/side_panel/side_panel.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/line_chart.html"> +<link rel="import" href="/tracing/ui/base/table.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> -<polymer-element name='tr-ui-e-s-alerts-side-panel' - extends='tr-ui-side-panel'> +<dom-module id='tr-ui-e-s-alerts-side-panel'> <template> <style> :host { @@ -24,6 +24,9 @@ found in the LICENSE file. flex-direction: column; display: flex; } + tr-ui-b-table { + font-size: 12px; + } </style> <div id='content'> @@ -31,131 +34,138 @@ found in the LICENSE file. <result-area id='result_area'></result-area> </div> </template> - - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.rangeOfInterest_ = new tr.b.Range(); - this.selection_ = undefined; - }, - - get model() { - return this.model_; - }, - - set model(model) { - this.model_ = model; - this.updateContents_(); - }, - - set selection(selection) { - }, - - set rangeOfInterest(rangeOfInterest) { - }, - - /** - * Fires a selection event selecting all alerts of the specified - * type. - */ - selectAlertsOfType: function(alertTypeString) { - var alertsOfType = this.model_.alerts.filter(function(alert) { - return alert.title === alertTypeString; - }); - - var event = new tr.model.RequestSelectionChangeEvent(); - event.selection = new tr.model.EventSet(alertsOfType); - this.dispatchEvent(event); - }, - - /** - * Returns a map for the specified alerts where each key is the - * alert type string and each value is a list of alerts with that - * type. - */ - alertsByType_: function(alerts) { - var alertsByType = {}; - alerts.forEach(function(alert) { - if (!alertsByType[alert.title]) - alertsByType[alert.title] = []; - - alertsByType[alert.title].push(alert); - }); - return alertsByType; - }, - - alertsTableRows_: function(alertsByType) { - return Object.keys(alertsByType).map(function(key) { - return { - alertType: key, - count: alertsByType[key].length - }; - }); - }, - - alertsTableColumns_: function() { - return [ - { - title: 'Alert type', - value: function(row) { return row.alertType; }, - width: '180px' - }, - { - title: 'Count', - width: '100%', - value: function(row) { return row.count; } - } - ]; - }, - - createAlertsTable_: function(alerts) { - var alertsByType = this.alertsByType_(alerts); - - var table = document.createElement('tr-ui-b-table'); - table.tableColumns = this.alertsTableColumns_(); - table.tableRows = this.alertsTableRows_(alertsByType); - table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; - table.addEventListener('selection-changed', function(e) { - var row = table.selectedTableRow; - if (row) - this.selectAlertsOfType(row.alertType); - }.bind(this)); - - return table; - }, - - updateContents_: function() { - this.$.result_area.textContent = ''; - if (this.model_ === undefined) - return; - - var panel = this.createAlertsTable_(this.model_.alerts); - this.$.result_area.appendChild(panel); - }, - - supportsModel: function(m) { - if (m == undefined) { - return { - supported: false, - reason: 'Unknown tracing model' - }; - } else if (m.alerts.length === 0) { - return { - supported: false, - reason: 'No alerts in tracing model' - }; +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-s-alerts-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + + + ready: function() { + this.rangeOfInterest_ = new tr.b.Range(); + this.selection_ = undefined; + }, + + get model() { + return this.model_; + }, + + set model(model) { + this.model_ = model; + this.updateContents_(); + }, + + set selection(selection) { + }, + + set rangeOfInterest(rangeOfInterest) { + }, + + /** + * Fires a selection event selecting all alerts of the specified + * type. + */ + selectAlertsOfType: function(alertTypeString) { + var alertsOfType = this.model_.alerts.filter(function(alert) { + return alert.title === alertTypeString; + }); + + var event = new tr.model.RequestSelectionChangeEvent(); + event.selection = new tr.model.EventSet(alertsOfType); + this.dispatchEvent(event); + }, + + /** + * Returns a map for the specified alerts where each key is the + * alert type string and each value is a list of alerts with that + * type. + */ + alertsByType_: function(alerts) { + var alertsByType = {}; + alerts.forEach(function(alert) { + if (!alertsByType[alert.title]) + alertsByType[alert.title] = []; + + alertsByType[alert.title].push(alert); + }); + return alertsByType; + }, + + alertsTableRows_: function(alertsByType) { + return Object.keys(alertsByType).map(function(key) { + return { + alertType: key, + count: alertsByType[key].length + }; + }); + }, + + alertsTableColumns_: function() { + return [ + { + title: 'Alert type', + value: function(row) { return row.alertType; }, + width: '180px' + }, + { + title: 'Count', + width: '100%', + value: function(row) { return row.count; } } - + ]; + }, + + createAlertsTable_: function(alerts) { + var alertsByType = this.alertsByType_(alerts); + + var table = document.createElement('tr-ui-b-table'); + table.tableColumns = this.alertsTableColumns_(); + table.tableRows = this.alertsTableRows_(alertsByType); + table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + table.addEventListener('selection-changed', function(e) { + var row = table.selectedTableRow; + if (row) + this.selectAlertsOfType(row.alertType); + }.bind(this)); + + return table; + }, + + updateContents_: function() { + Polymer.dom(this.$.result_area).textContent = ''; + if (this.model_ === undefined) + return; + + var panel = this.createAlertsTable_(this.model_.alerts); + Polymer.dom(this.$.result_area).appendChild(panel); + }, + + supportsModel: function(m) { + if (m === undefined) { return { - supported: true + supported: false, + reason: 'Unknown tracing model' + }; + } else if (m.alerts.length === 0) { + return { + supported: false, + reason: 'No alerts in tracing model' }; - }, - - get textLabel() { - return 'Alerts'; } - }); - </script> -</polymer-element> + + return { + supported: true + }; + }, + + get textLabel() { + return 'Alerts'; + } +}); + +tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-e-s-alerts-side-panel'); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html index 2ca6250b69e..83ce91aca62 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/alerts_side_panel_test.html @@ -37,7 +37,7 @@ tr.b.unittest.testSuite(function() { new tr.model.Alert(ALERT_INFO_2, 3) ]; - var predicted_alerts = new tr.model.EventSet([alerts[0], alerts[1]]); + var predictedAlerts = new tr.model.EventSet([alerts[0], alerts[1]]); panel.model = createModelWithAlerts(alerts); panel.style.height = '100px'; this.addHTMLOutput(panel); @@ -45,7 +45,7 @@ tr.b.unittest.testSuite(function() { var selectionChanged = false; panel.addEventListener('requestSelectionChange', function(e) { selectionChanged = true; - assert.isTrue(e.selection.equals(predicted_alerts)); + assert.isTrue(e.selection.equals(predictedAlerts)); }); panel.selectAlertsOfType(ALERT_INFO_1.title); @@ -56,6 +56,6 @@ tr.b.unittest.testSuite(function() { var m = new tr.Model(); m.alerts = alerts; return m; - }; + } }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html index ebaff275896..f8ed34df15c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/frame_data_side_panel.html @@ -5,17 +5,17 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/extras/chrome/blame_context/frame_tree_node.html"> <link rel="import" href="/tracing/extras/chrome/blame_context/render_frame.html"> <link rel="import" href="/tracing/extras/chrome/blame_context/top_level.html"> <link rel="import" href="/tracing/model/helpers/chrome_model_helper.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name='tr-ui-e-s-frame-data-side-panel' - extends='tr-ui-side-panel'> +<dom-module id='tr-ui-e-s-frame-data-side-panel'> <template> <style> :host { @@ -26,13 +26,21 @@ found in the LICENSE file. table-container { display: flex; overflow: auto; + font-size: 12px; } </style> + <div> + Organize by: + <select id="select"> + <option value="none">None</option> + <option value="tree">Frame Tree</option> + </select> + </div> <table-container> <tr-ui-b-table id="table"></tr-ui-b-table> </table-container> </template> -</polymer-element> +</dom-module> <script> 'use strict'; @@ -49,12 +57,24 @@ tr.exportTo('tr.ui.e.s', function() { /** * @constructor + * If |context| is provided, creates a row for the given context. + * Otherwise, creates an empty Row template which can be used for aggregating + * data from a group of subrows. */ function Row(context) { - this.type = context.objectInstance.blameContextType; + this.subRows = undefined; + this.contexts = []; + this.type = undefined; + this.renderer = 'N/A'; + this.url = undefined; + this.time = 0; + this.eventsOfInterest = new tr.model.EventSet(); + + if (context === undefined) + return; - this.contexts = [context]; - this.renderer = undefined; + this.type = context.objectInstance.blameContextType; + this.contexts.push(context); if (context instanceof FrameTreeNodeSnapshot) { if (context.renderFrame) { this.contexts.push(context.renderFrame); @@ -69,24 +89,89 @@ tr.exportTo('tr.ui.e.s', function() { } else { throw new Error('Unknown context type'); } + this.eventsOfInterest.addEventSet(this.contexts); // TODO(xiaochengh): Handle the case where a subframe has a trivial url // (e.g., about:blank), but inherits the origin of its parent. This is not // needed now, but will be required if we want to group rows by origin. this.url = context.url; - - // To be computed in batch later for efficiency. - this.eventsOfInterest = new tr.model.EventSet(this.contexts); - this.time = 0; } - Polymer('tr-ui-e-s-frame-data-side-panel', { + var groupFunctions = { + none: rows => rows, + + // Group the rows according to the frame tree structure. + // Example: consider frame tree a(b, c(d)), where each frame has 1ms time + // attributed to it. The resulting table should look like: + // Type | Time | URL + // --------------+------+----- + // Frame Tree | 4 | a + // +- Frame | 1 | a + // +- Subframe | 1 | b + // +- Frame Tree | 2 | c + // +- Frame | 1 | c + // +- Subframe | 1 | d + tree: function(rows, rowMap) { + // Finds the parent of a specific row. When there is conflict between the + // browser's dump of the frame tree and the renderers', use the browser's. + var getParentRow = function(row) { + var pivot; + row.contexts.forEach(function(context) { + if (context instanceof tr.e.chrome.FrameTreeNodeSnapshot) + pivot = context; + }); + if (pivot && pivot.parentContext) + return rowMap[pivot.parentContext.guid]; + return undefined; + }; + + var rootRows = []; + rows.forEach(function(row) { + var parentRow = getParentRow(row); + if (parentRow === undefined) { + rootRows.push(row); + return; + } + if (parentRow.subRows === undefined) + parentRow.subRows = []; + parentRow.subRows.push(row); + }); + + var aggregateAllDescendants = function(row) { + if (!row.subRows) { + if (getParentRow(row)) + row.type = 'Subframe'; + return row; + } + var result = new Row(); + result.type = 'Frame Tree'; + result.renderer = row.renderer; + result.url = row.url; + result.subRows = [row]; + row.subRows.forEach( + subRow => result.subRows.push(aggregateAllDescendants(subRow))); + result.subRows.forEach(function(subRow) { + result.time += subRow.time; + result.eventsOfInterest.addEventSet(subRow.eventsOfInterest); + }); + row.subRows = undefined; + return result; + }; + + return rootRows.map(rootRow => aggregateAllDescendants(rootRow)); + } + + // TODO(xiaochengh): Add grouping by site and probably more... + }; + + Polymer({ + is: 'tr-ui-e-s-frame-data-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + ready: function() { this.model_ = undefined; this.rangeOfInterest_ = new tr.b.Range(); - // TODO(xiaochengh): Design proper grouping of the rows (by renderer - // pid, frame tree topology, site, ...) in a follow-up patch. this.$.table.showHeader = true; this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; this.$.table.tableColumns = this.createFrameDataTableColumns_(); @@ -94,6 +179,10 @@ tr.exportTo('tr.ui.e.s', function() { this.$.table.addEventListener('selection-changed', function(e) { this.selectEventSet_(this.$.table.selectedTableRow.eventsOfInterest); }.bind(this)); + + this.$.select.addEventListener('change', function(e) { + this.updateContents_(); + }.bind(this)); }, selectEventSet_: function(eventSet) { @@ -121,7 +210,7 @@ tr.exportTo('tr.ui.e.s', function() { { title: 'Time', value: row => tr.v.ui.createScalarSpan(row.time, { - unit: tr.v.Unit.byName.timeStampInMs, + unit: tr.b.Unit.byName.timeStampInMs, ownerDocument: this.ownerDocument }), cmp: (a, b) => a.time - b.time @@ -173,7 +262,11 @@ tr.exportTo('tr.ui.e.s', function() { }, this); }, this); - return rows; + // Apply grouping to rows. + var select = this.$.select; + var groupOption = select.options[select.selectedIndex].value; + var groupFunction = groupFunctions[groupOption]; + return groupFunction(rows, rowMap); }, updateContents_: function() { @@ -239,5 +332,9 @@ tr.exportTo('tr.ui.e.s', function() { this.updateContents_(); } }); + + tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-e-s-frame-data-side-panel'); + }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html index 4b3a9a5917b..7375c09e050 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel.html @@ -11,9 +11,9 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/line_chart.html"> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> -<polymer-element name='tr-ui-e-s-input-latency-side-panel' - extends='tr-ui-side-panel'> +<dom-module id='tr-ui-e-s-input-latency-side-panel'> <template> <style> :host { @@ -36,291 +36,299 @@ found in the LICENSE file. <toolbar id='toolbar'></toolbar> <result-area id='result_area'></result-area> </template> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-s-input-latency-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + + + ready: function() { + this.rangeOfInterest_ = new tr.b.Range(); + this.frametimeType_ = tr.model.helpers.IMPL_FRAMETIME_TYPE; + this.latencyChart_ = undefined; + this.frametimeChart_ = undefined; + this.selectedProcessId_ = undefined; + this.mouseDownIndex_ = undefined; + this.curMouseIndex_ = undefined; + }, + + get model() { + return this.model_; + }, + + set model(model) { + this.model_ = model; + if (this.model_) { + this.modelHelper_ = this.model_.getOrCreateHelper( + tr.model.helpers.ChromeModelHelper); + } else { + this.modelHelper_ = undefined; + } - <script> - 'use strict'; - - Polymer({ - ready: function() { - this.rangeOfInterest_ = new tr.b.Range(); - this.frametimeType_ = tr.model.helpers.IMPL_FRAMETIME_TYPE; - this.latencyChart_ = undefined; - this.frametimeChart_ = undefined; - this.selectedProcessId_ = undefined; - this.mouseDownIndex_ = undefined; - this.curMouseIndex_ = undefined; - }, - - get model() { - return this.model_; - }, - - set model(model) { - this.model_ = model; - if (this.model_) { - this.modelHelper_ = this.model_.getOrCreateHelper( - tr.model.helpers.ChromeModelHelper); - } else { - this.modelHelper_ = undefined; - } - - this.updateToolbar_(); - this.updateContents_(); - }, - - get frametimeType() { - return this.frametimeType_; - }, - - set frametimeType(type) { - if (this.frametimeType_ === type) - return; - this.frametimeType_ = type; - this.updateContents_(); - }, - - get selectedProcessId() { - return this.selectedProcessId_; - }, - - set selectedProcessId(process) { - if (this.selectedProcessId_ === process) - return; - this.selectedProcessId_ = process; - this.updateContents_(); - }, - - set selection(selection) { - if (this.latencyChart_ === undefined) - return; - this.latencyChart_.brushedRange = selection.bounds; - }, - - // This function is for testing purpose. - setBrushedIndices: function(mouseDownIndex, curIndex) { - this.mouseDownIndex_ = mouseDownIndex; - this.curMouseIndex_ = curIndex; - this.updateBrushedRange_(); - }, - - updateBrushedRange_: function() { - if (this.latencyChart_ === undefined) - return; - - var r = new tr.b.Range(); - if (this.mouseDownIndex_ === undefined) { - this.latencyChart_.brushedRange = r; - return; - } - r = this.latencyChart_.computeBrushRangeFromIndices( - this.mouseDownIndex_, this.curMouseIndex_); + this.updateToolbar_(); + this.updateContents_(); + }, + + get frametimeType() { + return this.frametimeType_; + }, + + set frametimeType(type) { + if (this.frametimeType_ === type) + return; + this.frametimeType_ = type; + this.updateContents_(); + }, + + get selectedProcessId() { + return this.selectedProcessId_; + }, + + set selectedProcessId(process) { + if (this.selectedProcessId_ === process) + return; + this.selectedProcessId_ = process; + this.updateContents_(); + }, + + set selection(selection) { + if (this.latencyChart_ === undefined) + return; + this.latencyChart_.brushedRange = selection.bounds; + }, + + // This function is for testing purpose. + setBrushedIndices: function(mouseDownIndex, curIndex) { + this.mouseDownIndex_ = mouseDownIndex; + this.curMouseIndex_ = curIndex; + this.updateBrushedRange_(); + }, + + updateBrushedRange_: function() { + if (this.latencyChart_ === undefined) + return; + + var r = new tr.b.Range(); + if (this.mouseDownIndex_ === undefined) { this.latencyChart_.brushedRange = r; + return; + } + r = this.latencyChart_.computeBrushRangeFromIndices( + this.mouseDownIndex_, this.curMouseIndex_); + this.latencyChart_.brushedRange = r; + + // Based on the brushed range, update the selection of LatencyInfo in + // the timeline view by sending a selectionChange event. + var latencySlices = []; + for (var thread of this.model_.getAllThreads()) + for (var event of thread.getDescendantEvents()) + if (event.title.indexOf('InputLatency:') === 0) + latencySlices.push(event); + latencySlices = tr.model.helpers.getSlicesIntersectingRange( + r, latencySlices); + + var event = new tr.model.RequestSelectionChangeEvent(); + event.selection = new tr.model.EventSet(latencySlices); + this.latencyChart_.dispatchEvent(event); + }, + + registerMouseEventForLatencyChart_: function() { + this.latencyChart_.addEventListener('item-mousedown', function(e) { + this.mouseDownIndex_ = e.index; + this.curMouseIndex_ = e.index; + this.updateBrushedRange_(); + }.bind(this)); - // Based on the brushed range, update the selection of LatencyInfo in - // the timeline view by sending a selectionChange event. - var latencySlices = []; - for (var thread of this.model_.getAllThreads()) - for (var event of thread.getDescendantEvents()) - if (event.title.indexOf('InputLatency:') === 0) - latencySlices.push(event); - latencySlices = tr.model.helpers.getSlicesIntersectingRange( - r, latencySlices); - - var event = new tr.model.RequestSelectionChangeEvent(); - event.selection = new tr.model.EventSet(latencySlices); - this.latencyChart_.dispatchEvent(event); - }, - - registerMouseEventForLatencyChart_: function() { - this.latencyChart_.addEventListener('item-mousedown', function(e) { - this.mouseDownIndex_ = e.index; - this.curMouseIndex_ = e.index; - this.updateBrushedRange_(); - }.bind(this)); - - this.latencyChart_.addEventListener('item-mousemove', function(e) { - if (e.button == undefined) - return; - this.curMouseIndex_ = e.index; - this.updateBrushedRange_(); - }.bind(this)); - - this.latencyChart_.addEventListener('item-mouseup', function(e) { - this.curMouseIndex = e.index; - this.updateBrushedRange_(); - }.bind(this)); - }, - - updateToolbar_: function() { - var browserProcess = this.modelHelper_.browserProcess; - var labels = []; - - if (browserProcess !== undefined) { - var label_str = 'Browser: ' + browserProcess.pid; - labels.push({label: label_str, value: browserProcess.pid}); - } - - tr.b.iterItems(this.modelHelper_.rendererHelpers, - function(pid, rendererHelper) { - var rendererProcess = rendererHelper.process; - var label_str = 'Renderer: ' + rendererProcess.userFriendlyName; - labels.push({label: label_str, value: rendererProcess.userFriendlyName - }); - }, this); - - if (labels.length === 0) - return; - - this.selectedProcessId_ = labels[0].value; - var toolbarEl = this.$.toolbar; - toolbarEl.appendChild(tr.ui.b.createSelector( - this, 'frametimeType', - 'inputLatencySidePanel.frametimeType', this.frametimeType_, - [{label: 'Main Thread Frame Times', - value: tr.model.helpers.MAIN_FRAMETIME_TYPE}, - {label: 'Impl Thread Frame Times', - value: tr.model.helpers.IMPL_FRAMETIME_TYPE} - ])); - toolbarEl.appendChild(tr.ui.b.createSelector( - this, 'selectedProcessId', - 'inputLatencySidePanel.selectedProcessId', - this.selectedProcessId_, - labels)); - }, - - get currentRangeOfInterest() { - if (this.rangeOfInterest_.isEmpty) - return this.model_.bounds; - else - return this.rangeOfInterest_; - }, - - createLatencyLineChart: function(data, title) { - var chart = new tr.ui.b.LineChart(); - var width = 600; - if (document.body.clientWidth != undefined) - width = document.body.clientWidth * 0.5; - chart.setSize({width: width, height: chart.height}); - chart.chartTitle = title; - chart.data = data; - return chart; - }, - - updateContents_: function() { - var resultArea = this.$.result_area; - this.latencyChart_ = undefined; - this.frametimeChart_ = undefined; - resultArea.textContent = ''; - - if (this.modelHelper_ === undefined) + this.latencyChart_.addEventListener('item-mousemove', function(e) { + if (e.button === undefined) return; + this.curMouseIndex_ = e.index; + this.updateBrushedRange_(); + }.bind(this)); - var rangeOfInterest = this.currentRangeOfInterest; - - var chromeProcess; - if (this.modelHelper_.rendererHelpers[this.selectedProcessId_]) - chromeProcess = this.modelHelper_.rendererHelpers[ - this.selectedProcessId_ - ]; - else - chromeProcess = this.modelHelper_.browserHelper; + this.latencyChart_.addEventListener('item-mouseup', function(e) { + this.curMouseIndex = e.index; + this.updateBrushedRange_(); + }.bind(this)); + }, - var frameEvents = chromeProcess.getFrameEventsInRange( - this.frametimeType, rangeOfInterest); + updateToolbar_: function() { + var browserProcess = this.modelHelper_.browserProcess; + var labels = []; - var frametimeData = tr.model.helpers.getFrametimeDataFromEvents( - frameEvents); - var averageFrametime = tr.b.Statistics.mean(frametimeData, function(d) { - return d.frametime; - }); - - var latencyEvents = this.modelHelper_.browserHelper. - getLatencyEventsInRange( - rangeOfInterest); - - var latencyData = []; - latencyEvents.forEach(function(event) { - if (event.inputLatency === undefined) - return; - latencyData.push({ - x: event.start, - latency: event.inputLatency / 1000 - }); - }); + if (browserProcess !== undefined) { + var labelStr = 'Browser: ' + browserProcess.pid; + labels.push({label: labelStr, value: browserProcess.pid}); + } - var averageLatency = tr.b.Statistics.mean(latencyData, function(d) { - return d.latency; + tr.b.iterItems(this.modelHelper_.rendererHelpers, + function(pid, rendererHelper) { + var rendererProcess = rendererHelper.process; + var labelStr = 'Renderer: ' + rendererProcess.userFriendlyName; + labels.push({label: labelStr, value: rendererProcess.userFriendlyName }); - - // Create summary. - var latencySummaryText = document.createElement('div'); - latencySummaryText.appendChild(tr.ui.b.createSpan({ - textContent: 'Average Latency ' + averageLatency + ' ms', - bold: true})); - resultArea.appendChild(latencySummaryText); - - var frametimeSummaryText = document.createElement('div'); - frametimeSummaryText.appendChild(tr.ui.b.createSpan({ - textContent: 'Average Frame Time ' + averageFrametime + ' ms', - bold: true})); - resultArea.appendChild(frametimeSummaryText); - - if (latencyData.length !== 0) { - this.latencyChart_ = this.createLatencyLineChart( - latencyData, 'Latency Over Time'); - this.registerMouseEventForLatencyChart_(); - resultArea.appendChild(this.latencyChart_); - } - - if (frametimeData.length != 0) { - this.frametimeChart_ = this.createLatencyLineChart( - frametimeData, 'Frame Times'); - resultArea.appendChild(this.frametimeChart_); - } - }, - - get rangeOfInterest() { + }, this); + + if (labels.length === 0) + return; + + this.selectedProcessId_ = labels[0].value; + var toolbarEl = this.$.toolbar; + Polymer.dom(toolbarEl).appendChild(tr.ui.b.createSelector( + this, 'frametimeType', + 'inputLatencySidePanel.frametimeType', this.frametimeType_, + [{label: 'Main Thread Frame Times', + value: tr.model.helpers.MAIN_FRAMETIME_TYPE}, + {label: 'Impl Thread Frame Times', + value: tr.model.helpers.IMPL_FRAMETIME_TYPE} + ])); + Polymer.dom(toolbarEl).appendChild(tr.ui.b.createSelector( + this, 'selectedProcessId', + 'inputLatencySidePanel.selectedProcessId', + this.selectedProcessId_, + labels)); + }, + + // TODO(charliea): Delete this function in favor of rangeOfInterest. + get currentRangeOfInterest() { + if (this.rangeOfInterest_.isEmpty) + return this.model_.bounds; + else return this.rangeOfInterest_; - }, + }, + + createLatencyLineChart: function(data, title) { + var chart = new tr.ui.b.LineChart(); + var width = 600; + if (document.body.clientWidth !== undefined) + width = document.body.clientWidth * 0.5; + chart.setSize({width: width, height: chart.height}); + chart.chartTitle = title; + chart.data = data; + return chart; + }, + + updateContents_: function() { + var resultArea = this.$.result_area; + this.latencyChart_ = undefined; + this.frametimeChart_ = undefined; + Polymer.dom(resultArea).textContent = ''; + + if (this.modelHelper_ === undefined) + return; + + var rangeOfInterest = this.currentRangeOfInterest; + + var chromeProcess; + if (this.modelHelper_.rendererHelpers[this.selectedProcessId_]) + chromeProcess = this.modelHelper_.rendererHelpers[ + this.selectedProcessId_ + ]; + else + chromeProcess = this.modelHelper_.browserHelper; + + var frameEvents = chromeProcess.getFrameEventsInRange( + this.frametimeType, rangeOfInterest); + + var frametimeData = tr.model.helpers.getFrametimeDataFromEvents( + frameEvents); + var averageFrametime = tr.b.Statistics.mean(frametimeData, function(d) { + return d.frametime; + }); + + var latencyEvents = this.modelHelper_.browserHelper. + getLatencyEventsInRange( + rangeOfInterest); + + var latencyData = []; + latencyEvents.forEach(function(event) { + if (event.inputLatency === undefined) + return; + latencyData.push({ + x: event.start, + latency: event.inputLatency / 1000 + }); + }); + + var averageLatency = tr.b.Statistics.mean(latencyData, function(d) { + return d.latency; + }); + + // Create summary. + var latencySummaryText = document.createElement('div'); + Polymer.dom(latencySummaryText).appendChild(tr.ui.b.createSpan({ + textContent: 'Average Latency ' + averageLatency + ' ms', + bold: true})); + Polymer.dom(resultArea).appendChild(latencySummaryText); + + var frametimeSummaryText = document.createElement('div'); + Polymer.dom(frametimeSummaryText).appendChild(tr.ui.b.createSpan({ + textContent: 'Average Frame Time ' + averageFrametime + ' ms', + bold: true})); + Polymer.dom(resultArea).appendChild(frametimeSummaryText); + + if (latencyData.length !== 0) { + this.latencyChart_ = this.createLatencyLineChart( + latencyData, 'Latency Over Time'); + this.registerMouseEventForLatencyChart_(); + Polymer.dom(resultArea).appendChild(this.latencyChart_); + } - set rangeOfInterest(rangeOfInterest) { - this.rangeOfInterest_ = rangeOfInterest; - this.updateContents_(); - }, + if (frametimeData.length !== 0) { + this.frametimeChart_ = this.createLatencyLineChart( + frametimeData, 'Frame Times'); + Polymer.dom(resultArea).appendChild(this.frametimeChart_); + } + }, - supportsModel: function(m) { - if (m == undefined) { - return { - supported: false, - reason: 'Unknown tracing model' - }; - } + get rangeOfInterest() { + return this.rangeOfInterest_; + }, - if (!tr.model.helpers.ChromeModelHelper.supportsModel(m)) { - return { - supported: false, - reason: 'No Chrome browser or renderer process found' - }; - } + set rangeOfInterest(rangeOfInterest) { + this.rangeOfInterest_ = rangeOfInterest; + this.updateContents_(); + }, - var modelHelper = m.getOrCreateHelper(tr.model.helpers.ChromeModelHelper); - if (modelHelper.browserHelper && - modelHelper.browserHelper.hasLatencyEvents) { - return { - supported: true - }; - } + supportsModel: function(m) { + if (m === undefined) { + return { + supported: false, + reason: 'Unknown tracing model' + }; + } + if (!tr.model.helpers.ChromeModelHelper.supportsModel(m)) { return { supported: false, - reason: 'No InputLatency events trace. Consider enabling ' + - 'benchmark" and "input" category when recording the trace' + reason: 'No Chrome browser or renderer process found' }; - }, + } - get textLabel() { - return 'Input Latency'; + var modelHelper = m.getOrCreateHelper(tr.model.helpers.ChromeModelHelper); + if (modelHelper.browserHelper && + modelHelper.browserHelper.hasLatencyEvents) { + return { + supported: true + }; } - }); - </script> -</polymer-element> + + return { + supported: false, + reason: 'No InputLatency events trace. Consider enabling ' + + 'benchmark" and "input" category when recording the trace' + }; + }, + + get textLabel() { + return 'Input Latency'; + } +}); + +tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-e-s-input-latency-side-panel'); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html index 51021bd4aa3..417c171b977 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/input_latency_side_panel_test.html @@ -64,14 +64,14 @@ tr.b.unittest.testSuite(function() { test('brushedRangeChange', function() { var events = []; for (var i = 0; i < 10; i++) { - var start_ts = i * 10000; - var end_ts = start_ts + 1000 * (i % 2); + var startTs = i * 10000; + var endTs = startTs + 1000 * (i % 2); events.push( { 'cat': 'benchmark', 'pid': 3507, 'tid': 3507, - 'ts': start_ts, + 'ts': startTs, 'ph': 'S', 'name': 'InputLatency', 'id': i @@ -81,7 +81,7 @@ tr.b.unittest.testSuite(function() { 'cat': 'benchmark', 'pid': 3507, 'tid': 3507, - 'ts': end_ts, + 'ts': endTs, 'ph': 'T', 'name': 'InputLatency', 'args': {'step': 'GestureScrollUpdate'}, @@ -92,16 +92,16 @@ tr.b.unittest.testSuite(function() { 'cat': 'benchmark', 'pid': 3507, 'tid': 3507, - 'ts': end_ts, + 'ts': endTs, 'ph': 'F', 'name': 'InputLatency', 'args': { 'data': { 'INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT': { - 'time': start_ts + 'time': startTs }, 'INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT': { - 'time': end_ts + 'time': endTs } } }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html index a0b6d9df6b6..7391d050ced 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/side_panel/time_summary_side_panel.html @@ -7,15 +7,14 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/statistics.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/model/event_set.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/pie_chart.html"> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name="tr-ui-e-s-time-summary-side-panel" - extends="tr-ui-side-panel"> +<dom-module id='tr-ui-e-s-time-summary-side-panel'> <template> <style> :host { @@ -38,401 +37,404 @@ found in the LICENSE file. <toolbar id='toolbar'></toolbar> <result-area id='result_area'></result-area> </template> - - <script> - 'use strict'; - (function() { - var GROUP_BY_PROCESS_NAME = 'process'; - var GROUP_BY_THREAD_NAME = 'thread'; - - var WALL_TIME_GROUPING_UNIT = 'Wall time'; - var CPU_TIME_GROUPING_UNIT = 'CPU time'; +</dom-module> +<script> +'use strict'; +(function() { + var GROUP_BY_PROCESS_NAME = 'process'; + var GROUP_BY_THREAD_NAME = 'thread'; + + var WALL_TIME_GROUPING_UNIT = 'Wall time'; + var CPU_TIME_GROUPING_UNIT = 'CPU time'; + + /** + * @constructor + */ + function ResultsForGroup(model, name) { + this.model = model; + this.name = name; + this.topLevelSlices = []; + this.allSlices = []; + } + + ResultsForGroup.prototype = { + get wallTime() { + var wallSum = tr.b.Statistics.sum( + this.topLevelSlices, function(x) { return x.duration; }); + return wallSum; + }, + + get cpuTime() { + var cpuDuration = 0; + for (var i = 0; i < this.topLevelSlices.length; i++) { + var x = this.topLevelSlices[i]; + // Only report thread-duration if we have it for all events. + // + // A thread_duration of 0 is valid, so this only returns 0 if it is + // None. + if (x.cpuDuration === undefined) { + if (x.duration === undefined) + continue; + return 0; + } + cpuDuration += x.cpuDuration; + } + return cpuDuration; + }, + + appendGroupContents: function(group) { + if (group.model !== this.model) + throw new Error('Models must be the same'); + + group.allSlices.forEach(function(slice) { + this.allSlices.push(slice); + }, this); + group.topLevelSlices.forEach(function(slice) { + this.topLevelSlices.push(slice); + }, this); + }, + + appendThreadSlices: function(rangeOfInterest, thread) { + var tmp = this.getSlicesIntersectingRange( + rangeOfInterest, thread.sliceGroup.slices); + tmp.forEach(function(slice) { + this.allSlices.push(slice); + }, this); + tmp = this.getSlicesIntersectingRange( + rangeOfInterest, thread.sliceGroup.topLevelSlices); + tmp.forEach(function(slice) { + this.topLevelSlices.push(slice); + }, this); + }, + + getSlicesIntersectingRange: function(rangeOfInterest, slices) { + var slicesInFilterRange = []; + for (var i = 0; i < slices.length; i++) { + var slice = slices[i]; + if (rangeOfInterest.intersectsExplicitRangeInclusive( + slice.start, slice.end)) + slicesInFilterRange.push(slice); + } + return slicesInFilterRange; + } + }; + + Polymer({ + is: 'tr-ui-e-s-time-summary-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + + ready: function() { + this.rangeOfInterest_ = new tr.b.Range(); + this.selection_ = undefined; + this.groupBy_ = GROUP_BY_PROCESS_NAME; + this.groupingUnit_ = CPU_TIME_GROUPING_UNIT; + this.showCpuIdleTime_ = true; + this.chart_ = undefined; + + var toolbarEl = this.$.toolbar; + this.groupBySelector_ = tr.ui.b.createSelector( + this, 'groupBy', + 'timeSummarySidePanel.groupBy', this.groupBy_, + [{label: 'Group by process', value: GROUP_BY_PROCESS_NAME}, + {label: 'Group by thread', value: GROUP_BY_THREAD_NAME} + ]); + Polymer.dom(toolbarEl).appendChild(this.groupBySelector_); + + this.groupingUnitSelector_ = tr.ui.b.createSelector( + this, 'groupingUnit', + 'timeSummarySidePanel.groupingUnit', this.groupingUnit_, + [{label: 'Wall time', value: WALL_TIME_GROUPING_UNIT}, + {label: 'CPU time', value: CPU_TIME_GROUPING_UNIT} + ]); + Polymer.dom(toolbarEl).appendChild(this.groupingUnitSelector_); + + this.showCpuIdleTimeCheckbox_ = tr.ui.b.createCheckBox( + this, 'showCpuIdleTime', + 'timeSummarySidePanel.showCpuIdleTime', this.showCpuIdleTime_, + 'Show CPU idle time'); + Polymer.dom(toolbarEl).appendChild(this.showCpuIdleTimeCheckbox_); + this.updateShowCpuIdleTimeCheckboxVisibility_(); + }, /** - * @constructor + * This function takes an array of groups and merges smaller groups into + * the provided 'Other' group item such that the remaining items are ready + * for pie-chart consumption. Otherwise, the pie chart gets overwhelmed + * with tons of little slices. */ - function ResultsForGroup(model, name) { - this.model = model; - this.name = name; - this.topLevelSlices = []; - this.allSlices = []; - } - - ResultsForGroup.prototype = { - get wallTime() { - var wallSum = tr.b.Statistics.sum( - this.topLevelSlices, function(x) { return x.duration; }); - return wallSum; - }, - - get cpuTime() { - var cpuDuration = 0; - for (var i = 0; i < this.topLevelSlices.length; i++) { - var x = this.topLevelSlices[i]; - // Only report thread-duration if we have it for all events. - // - // A thread_duration of 0 is valid, so this only returns 0 if it is - // None. - if (x.cpuDuration === undefined) { - if (x.duration === undefined) - continue; - return 0; - } - cpuDuration += x.cpuDuration; - } - return cpuDuration; - }, - - appendGroupContents: function(group) { - if (group.model != this.model) - throw new Error('Models must be the same'); - - group.allSlices.forEach(function(slice) { - this.allSlices.push(slice); - }, this); - group.topLevelSlices.forEach(function(slice) { - this.topLevelSlices.push(slice); - }, this); - }, - - appendThreadSlices: function(rangeOfInterest, thread) { - var tmp = this.getSlicesIntersectingRange( - rangeOfInterest, thread.sliceGroup.slices); - tmp.forEach(function(slice) { - this.allSlices.push(slice); - }, this); - tmp = this.getSlicesIntersectingRange( - rangeOfInterest, thread.sliceGroup.topLevelSlices); - tmp.forEach(function(slice) { - this.topLevelSlices.push(slice); - }, this); - }, - - getSlicesIntersectingRange: function(rangeOfInterest, slices) { - var slicesInFilterRange = []; - for (var i = 0; i < slices.length; i++) { - var slice = slices[i]; - if (rangeOfInterest.intersectsExplicitRangeInclusive( - slice.start, slice.end)) - slicesInFilterRange.push(slice); - } - return slicesInFilterRange; + trimPieChartData: function(groups, otherGroup, getValue, opt_extraValue) { + // Copy the array so it can be mutated. + groups = groups.filter(function(d) { + return getValue(d) !== 0; + }); + + // Figure out total array range. + var sum = tr.b.Statistics.sum(groups, getValue); + if (opt_extraValue !== undefined) + sum += opt_extraValue; + + // Sort by value. + function compareByValue(a, b) { + return getValue(a) - getValue(b); + } + groups.sort(compareByValue); + + // Now start fusing elements until none are less than threshold in size. + var thresshold = 0.1 * sum; + while (groups.length > 1) { + var group = groups[0]; + if (getValue(group) >= thresshold) + break; + + var v = getValue(group); + if (v + getValue(otherGroup) > thresshold) + break; + + // Remove the group from the list and add it to the 'Other' group. + groups.splice(0, 1); + otherGroup.appendGroupContents(group); } - }; - - Polymer({ - ready: function() { - this.rangeOfInterest_ = new tr.b.Range(); - this.selection_ = undefined; - this.groupBy_ = GROUP_BY_PROCESS_NAME; - this.groupingUnit_ = CPU_TIME_GROUPING_UNIT; - this.showCpuIdleTime_ = true; - this.chart_ = undefined; - - var toolbarEl = this.$.toolbar; - this.groupBySelector_ = tr.ui.b.createSelector( - this, 'groupBy', - 'timeSummarySidePanel.groupBy', this.groupBy_, - [{label: 'Group by process', value: GROUP_BY_PROCESS_NAME}, - {label: 'Group by thread', value: GROUP_BY_THREAD_NAME} - ]); - toolbarEl.appendChild(this.groupBySelector_); - - this.groupingUnitSelector_ = tr.ui.b.createSelector( - this, 'groupingUnit', - 'timeSummarySidePanel.groupingUnit', this.groupingUnit_, - [{label: 'Wall time', value: WALL_TIME_GROUPING_UNIT}, - {label: 'CPU time', value: CPU_TIME_GROUPING_UNIT} - ]); - toolbarEl.appendChild(this.groupingUnitSelector_); - - this.showCpuIdleTimeCheckbox_ = tr.ui.b.createCheckBox( - this, 'showCpuIdleTime', - 'timeSummarySidePanel.showCpuIdleTime', this.showCpuIdleTime_, - 'Show CPU idle time'); - toolbarEl.appendChild(this.showCpuIdleTimeCheckbox_); - this.updateShowCpuIdleTimeCheckboxVisibility_(); - }, - - /** - * This function takes an array of groups and merges smaller groups into - * the provided 'Other' group item such that the remaining items are ready - * for pie-chart consumption. Otherwise, the pie chart gets overwhelmed - * with tons of little slices. - */ - trimPieChartData: function(groups, otherGroup, getValue, opt_extraValue) { - // Copy the array so it can be mutated. - groups = groups.filter(function(d) { - return getValue(d) != 0; - }); - - // Figure out total array range. - var sum = tr.b.Statistics.sum(groups, getValue); - if (opt_extraValue !== undefined) - sum += opt_extraValue; - - // Sort by value. - function compareByValue(a, b) { - return getValue(a) - getValue(b); - } - groups.sort(compareByValue); - - // Now start fusing elements until none are less than threshold in size. - var thresshold = 0.1 * sum; - while (groups.length > 1) { - var group = groups[0]; - if (getValue(group) >= thresshold) - break; - - var v = getValue(group); - if (v + getValue(otherGroup) > thresshold) - break; - - // Remove the group from the list and add it to the 'Other' group. - groups.splice(0, 1); - otherGroup.appendGroupContents(group); - } - - // Final return. - if (getValue(otherGroup) > 0) - groups.push(otherGroup); - - groups.sort(compareByValue); - return groups; - }, + // Final return. + if (getValue(otherGroup) > 0) + groups.push(otherGroup); - generateResultsForGroup: function(model, name) { - return new ResultsForGroup(model, name); - }, + groups.sort(compareByValue); - createPieChartFromResultGroups: function( - groups, title, getValue, opt_extraData) { - var chart = new tr.ui.b.PieChart(); + return groups; + }, - function pushDataForGroup(data, resultsForGroup, value) { - data.push({ - label: resultsForGroup.name, - value: value, - valueText: tr.v.Unit.byName.timeDurationInMs.format(value), - resultsForGroup: resultsForGroup - }); - } - chart.addEventListener('item-click', function(clickEvent) { - var resultsForGroup = clickEvent.data.resultsForGroup; - if (resultsForGroup === undefined) - return; - - var event = new tr.model.RequestSelectionChangeEvent(); - event.selection = new tr.model.EventSet(resultsForGroup.allSlices); - event.selection.timeSummaryGroupName = resultsForGroup.name; - chart.dispatchEvent(event); - }); + generateResultsForGroup: function(model, name) { + return new ResultsForGroup(model, name); + }, + createPieChartFromResultGroups: function( + groups, title, getValue, opt_extraData) { + var chart = new tr.ui.b.PieChart(); - // Build chart data. - var data = []; - groups.forEach(function(resultsForGroup) { - var value = getValue(resultsForGroup); - if (value === 0) - return; - pushDataForGroup(data, resultsForGroup, value); + function pushDataForGroup(data, resultsForGroup, value) { + data.push({ + label: resultsForGroup.name, + value: value, + valueText: tr.b.Unit.byName.timeDurationInMs.format(value), + resultsForGroup: resultsForGroup }); - if (opt_extraData) - data.push.apply(data, opt_extraData); - - chart.chartTitle = title; - chart.data = data; - return chart; - }, - - get model() { - return this.model_; - }, - - set model(model) { - this.model_ = model; - this.updateContents_(); - }, - - get groupBy() { - return groupBy_; - }, - - set groupBy(groupBy) { - this.groupBy_ = groupBy; - if (this.groupBySelector_) - this.groupBySelector_.selectedValue = groupBy; - this.updateContents_(); - }, - - get groupingUnit() { - return groupingUnit_; - }, - - set groupingUnit(groupingUnit) { - this.groupingUnit_ = groupingUnit; - if (this.groupingUnitSelector_) - this.groupingUnitSelector_.selectedValue = groupingUnit; - this.updateShowCpuIdleTimeCheckboxVisibility_(); - this.updateContents_(); - }, - - get showCpuIdleTime() { - return this.showCpuIdleTime_; - }, - - set showCpuIdleTime(showCpuIdleTime) { - this.showCpuIdleTime_ = showCpuIdleTime; - if (this.showCpuIdleTimeCheckbox_) - this.showCpuIdleTimeCheckbox_.checked = showCpuIdleTime; - this.updateContents_(); - }, - - updateShowCpuIdleTimeCheckboxVisibility_: function() { - if (!this.showCpuIdleTimeCheckbox_) - return; - var visible = this.groupingUnit_ == CPU_TIME_GROUPING_UNIT; - if (visible) - this.showCpuIdleTimeCheckbox_.style.display = ''; - else - this.showCpuIdleTimeCheckbox_.style.display = 'none'; - }, - - getGroupNameForThread_: function(thread) { - if (this.groupBy_ == GROUP_BY_THREAD_NAME) - return thread.name ? thread.name : thread.userFriendlyName; - - if (this.groupBy_ == GROUP_BY_PROCESS_NAME) - return thread.parent.userFriendlyName; - }, - - updateContents_: function() { - var resultArea = this.$.result_area; - this.chart_ = undefined; - resultArea.textContent = ''; - - if (this.model_ === undefined) + } + chart.addEventListener('item-click', function(clickEvent) { + var resultsForGroup = clickEvent.data.resultsForGroup; + if (resultsForGroup === undefined) return; - var rangeOfInterest; - if (this.rangeOfInterest_.isEmpty) - rangeOfInterest = this.model_.bounds; - else - rangeOfInterest = this.rangeOfInterest_; - - var allGroup = this.generateResultsForGroup(this.model_, 'all'); - var resultsByGroupName = {}; - this.model_.getAllThreads().forEach(function(thread) { - var groupName = this.getGroupNameForThread_(thread); - if (resultsByGroupName[groupName] === undefined) { - resultsByGroupName[groupName] = this.generateResultsForGroup( - this.model_, groupName); - } - resultsByGroupName[groupName].appendThreadSlices( - rangeOfInterest, thread); - - allGroup.appendThreadSlices(rangeOfInterest, thread); - }, this); - - // Helper function for working with the produced group. - var getValueFromGroup = function(group) { - if (this.groupingUnit_ == WALL_TIME_GROUPING_UNIT) - return group.wallTime; - return group.cpuTime; - }.bind(this); - - // Create summary. - var summaryText = document.createElement('div'); - summaryText.appendChild(tr.ui.b.createSpan({ - textContent: 'Total ' + this.groupingUnit_ + ': ', - bold: true})); - summaryText.appendChild(tr.v.ui.createScalarSpan( - getValueFromGroup(allGroup), { - unit: tr.v.Unit.byName.timeDurationInMs, - ownerDocument: this.ownerDocument - })); - resultArea.appendChild(summaryText); - - // If needed, add in the idle time. - var extraValue = 0; - var extraData = []; - if (this.showCpuIdleTime_ && - this.groupingUnit_ === CPU_TIME_GROUPING_UNIT && - this.model.kernel.bestGuessAtCpuCount !== undefined) { - var maxCpuTime = rangeOfInterest.range * - this.model.kernel.bestGuessAtCpuCount; - var idleTime = Math.max(0, maxCpuTime - allGroup.cpuTime); - extraData.push({ - label: 'CPU Idle', - value: idleTime, - valueText: tr.v.Unit.byName.timeDurationInMs.format(idleTime) - }); - extraValue += idleTime; - } - - // Create the actual chart. - var otherGroup = this.generateResultsForGroup(this.model_, 'Other'); - var groups = this.trimPieChartData( - tr.b.dictionaryValues(resultsByGroupName), - otherGroup, - getValueFromGroup, - extraValue); - - if (groups.length == 0) { - resultArea.appendChild(tr.ui.b.createSpan({textContent: 'No data'})); - return undefined; - } + var event = new tr.model.RequestSelectionChangeEvent(); + event.selection = new tr.model.EventSet(resultsForGroup.allSlices); + event.selection.timeSummaryGroupName = resultsForGroup.name; + chart.dispatchEvent(event); + }); - this.chart_ = this.createPieChartFromResultGroups( - groups, - this.groupingUnit_ + ' breakdown by ' + this.groupBy_, - getValueFromGroup, extraData); - resultArea.appendChild(this.chart_); - this.chart_.addEventListener('click', function() { - var event = new tr.model.RequestSelectionChangeEvent(); - event.selection = new tr.c.EventSet([]); - this.dispatchEvent(event); - }); - this.chart_.setSize(this.chart_.getMinSize()); - }, - - get selection() { - return selection_; - }, - - set selection(selection) { - this.selection_ = selection; - - if (this.chart_ === undefined) + // Build chart data. + var data = []; + groups.forEach(function(resultsForGroup) { + var value = getValue(resultsForGroup); + if (value === 0) return; + pushDataForGroup(data, resultsForGroup, value); + }); + if (opt_extraData) + data.push.apply(data, opt_extraData); + + chart.chartTitle = title; + chart.data = data; + return chart; + }, + + get model() { + return this.model_; + }, + + set model(model) { + this.model_ = model; + this.updateContents_(); + }, + + get groupBy() { + return groupBy_; + }, + + set groupBy(groupBy) { + this.groupBy_ = groupBy; + if (this.groupBySelector_) + this.groupBySelector_.selectedValue = groupBy; + this.updateContents_(); + }, + + get groupingUnit() { + return groupingUnit_; + }, + + set groupingUnit(groupingUnit) { + this.groupingUnit_ = groupingUnit; + if (this.groupingUnitSelector_) + this.groupingUnitSelector_.selectedValue = groupingUnit; + this.updateShowCpuIdleTimeCheckboxVisibility_(); + this.updateContents_(); + }, + + get showCpuIdleTime() { + return this.showCpuIdleTime_; + }, + + set showCpuIdleTime(showCpuIdleTime) { + this.showCpuIdleTime_ = showCpuIdleTime; + if (this.showCpuIdleTimeCheckbox_) + this.showCpuIdleTimeCheckbox_.checked = showCpuIdleTime; + this.updateContents_(); + }, + + updateShowCpuIdleTimeCheckboxVisibility_: function() { + if (!this.showCpuIdleTimeCheckbox_) + return; + var visible = this.groupingUnit_ === CPU_TIME_GROUPING_UNIT; + if (visible) + this.showCpuIdleTimeCheckbox_.style.display = ''; + else + this.showCpuIdleTimeCheckbox_.style.display = 'none'; + }, + + getGroupNameForThread_: function(thread) { + if (this.groupBy_ === GROUP_BY_THREAD_NAME) + return thread.name ? thread.name : thread.userFriendlyName; + + if (this.groupBy_ === GROUP_BY_PROCESS_NAME) + return thread.parent.userFriendlyName; + }, + + updateContents_: function() { + var resultArea = this.$.result_area; + this.chart_ = undefined; + Polymer.dom(resultArea).textContent = ''; + + if (this.model_ === undefined) + return; + + var rangeOfInterest; + if (this.rangeOfInterest_.isEmpty) + rangeOfInterest = this.model_.bounds; + else + rangeOfInterest = this.rangeOfInterest_; + + var allGroup = this.generateResultsForGroup(this.model_, 'all'); + var resultsByGroupName = {}; + this.model_.getAllThreads().forEach(function(thread) { + var groupName = this.getGroupNameForThread_(thread); + if (resultsByGroupName[groupName] === undefined) { + resultsByGroupName[groupName] = this.generateResultsForGroup( + this.model_, groupName); + } + resultsByGroupName[groupName].appendThreadSlices( + rangeOfInterest, thread); + + allGroup.appendThreadSlices(rangeOfInterest, thread); + }, this); + + // Helper function for working with the produced group. + var getValueFromGroup = function(group) { + if (this.groupingUnit_ === WALL_TIME_GROUPING_UNIT) + return group.wallTime; + return group.cpuTime; + }.bind(this); + + // Create summary. + var summaryText = document.createElement('div'); + Polymer.dom(summaryText).appendChild(tr.ui.b.createSpan({ + textContent: 'Total ' + this.groupingUnit_ + ': ', + bold: true})); + Polymer.dom(summaryText).appendChild(tr.v.ui.createScalarSpan( + getValueFromGroup(allGroup), { + unit: tr.b.Unit.byName.timeDurationInMs, + ownerDocument: this.ownerDocument + })); + Polymer.dom(resultArea).appendChild(summaryText); + + // If needed, add in the idle time. + var extraValue = 0; + var extraData = []; + if (this.showCpuIdleTime_ && + this.groupingUnit_ === CPU_TIME_GROUPING_UNIT && + this.model.kernel.bestGuessAtCpuCount !== undefined) { + var maxCpuTime = rangeOfInterest.range * + this.model.kernel.bestGuessAtCpuCount; + var idleTime = Math.max(0, maxCpuTime - allGroup.cpuTime); + extraData.push({ + label: 'CPU Idle', + value: idleTime, + valueText: tr.b.Unit.byName.timeDurationInMs.format(idleTime) + }); + extraValue += idleTime; + } - if (selection.timeSummaryGroupName) - this.chart_.highlightedLegendKey = selection.timeSummaryGroupName; - else - this.chart_.highlightedLegendKey = undefined; - }, - - get rangeOfInterest() { - return this.rangeOfInterest_; - }, - - set rangeOfInterest(rangeOfInterest) { - this.rangeOfInterest_ = rangeOfInterest; - this.updateContents_(); - }, - - supportsModel: function(model) { - return { - supported: false - }; - }, - - get textLabel() { - return 'Time Summary'; + // Create the actual chart. + var otherGroup = this.generateResultsForGroup(this.model_, 'Other'); + var groups = this.trimPieChartData( + tr.b.dictionaryValues(resultsByGroupName), + otherGroup, + getValueFromGroup, + extraValue); + + if (groups.length === 0) { + Polymer.dom(resultArea).appendChild( + tr.ui.b.createSpan({textContent: 'No data'})); + return undefined; } - }); - }()); - </script> -</polymer-element> + + this.chart_ = this.createPieChartFromResultGroups( + groups, + this.groupingUnit_ + ' breakdown by ' + this.groupBy_, + getValueFromGroup, extraData); + Polymer.dom(resultArea).appendChild(this.chart_); + + this.chart_.addEventListener('click', function() { + var event = new tr.model.RequestSelectionChangeEvent(); + event.selection = new tr.c.EventSet([]); + this.dispatchEvent(event); + }); + this.chart_.setSize(this.chart_.getMinSize()); + }, + + get selection() { + return selection_; + }, + + set selection(selection) { + this.selection_ = selection; + + if (this.chart_ === undefined) + return; + + if (selection.timeSummaryGroupName) + this.chart_.highlightedLegendKey = selection.timeSummaryGroupName; + else + this.chart_.highlightedLegendKey = undefined; + }, + + get rangeOfInterest() { + return this.rangeOfInterest_; + }, + + set rangeOfInterest(rangeOfInterest) { + this.rangeOfInterest_ = rangeOfInterest; + this.updateContents_(); + }, + + supportsModel: function(model) { + return { + supported: false + }; + }, + + get textLabel() { + return 'Time Summary'; + } + }); +}()); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html index 9aa10212de6..2e096b65ec9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track.html @@ -9,10 +9,10 @@ found in the LICENSE file. href="/tracing/ui/extras/system_stats/system_stats_instance_track.css"> <link rel="import" href="/tracing/base/sorted_array_utils.html"> -<link rel="import" href="/tracing/ui/tracks/stacked_bars_track.html"> -<link rel="import" href="/tracing/ui/tracks/object_instance_track.html"> <link rel="import" href="/tracing/ui/base/event_presenter.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/object_instance_track.html"> +<link rel="import" href="/tracing/ui/tracks/stacked_bars_track.html"> <script> 'use strict'; @@ -57,7 +57,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { decorate: function(viewport) { tr.ui.tracks.StackedBarsTrack.prototype.decorate.call(this, viewport); - this.classList.add('tr-ui-e-system-stats-instance-track'); + Polymer.dom(this).classList.add('tr-ui-e-system-stats-instance-track'); this.objectInstance_ = null; }, @@ -66,7 +66,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { this.objectInstance_ = []; return; } - if (objectInstances.length != 1) + if (objectInstances.length !== 1) throw new Error('Bad object instance count.'); this.objectInstance_ = objectInstances[0]; if (this.objectInstance_ !== null) { @@ -83,7 +83,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { var prevSnapshot; var prevStats; - if (i == 0) { + if (i === 0) { // Deltas will be zero. prevSnapshot = snapshots[0]; } else { @@ -92,7 +92,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { prevStats = prevSnapshot.getStats(); var timeIntervalSeconds = (snapshot.ts - prevSnapshot.ts) / 1000; // Prevent divide by zero. - if (timeIntervalSeconds == 0) + if (timeIntervalSeconds === 0) timeIntervalSeconds = 1; this.computeRatesRecursive_(prevStats, stats, @@ -108,28 +108,28 @@ tr.exportTo('tr.ui.e.system_stats', function() { stats[statName], timeIntervalSeconds); } else { - if (statName == 'sectors_read') { + if (statName === 'sectors_read') { stats['bytes_read_per_sec'] = (stats['sectors_read'] - prevStats['sectors_read']) * 512 / timeIntervalSeconds; } - if (statName == 'sectors_written') { + if (statName === 'sectors_written') { stats['bytes_written_per_sec'] = (stats['sectors_written'] - prevStats['sectors_written']) * 512 / timeIntervalSeconds; } - if (statName == 'pgmajfault') { + if (statName === 'pgmajfault') { stats['pgmajfault_per_sec'] = (stats['pgmajfault'] - prevStats['pgmajfault']) / timeIntervalSeconds; } - if (statName == 'pswpin') { + if (statName === 'pswpin') { stats['bytes_swpin_per_sec'] = (stats['pswpin'] - prevStats['pswpin']) * 1000 / timeIntervalSeconds; } - if (statName == 'pswpout') { + if (statName === 'pswpout') { stats['bytes_swpout_per_sec'] = (stats['pswpout'] - prevStats['pswpout']) * 1000 / timeIntervalSeconds; @@ -237,7 +237,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { // Compute the edges for the column graph bar. var right; - if (i != objectSnapshots.length - 1) { + if (i !== objectSnapshots.length - 1) { right = objectSnapshots[i + 1].ts; } else { // If this is the last snaphot of multiple snapshots, use the width of @@ -267,7 +267,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { maxStats, currentY); - if (i == lowIndex) + if (i === lowIndex) this.drawStatNames_(leftView, height, currentY, '', maxStats); } ctx.lineWidth = 1; @@ -332,7 +332,7 @@ tr.exportTo('tr.ui.e.system_stats', function() { } else { var fullname = statName; - if (prefix != '') + if (prefix !== '') fullname = prefix + ' :: ' + statName; ctx.fillText(fullname, leftView - 10, currentY - height / 4); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html index 684887c2f0d..b13eaa921d6 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_instance_track_test.html @@ -49,11 +49,11 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new SystemStatsInstanceTrack(viewport); track.objectInstances = objectInstances; - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html index 11421e91453..ba093134da3 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/system_stats/system_stats_snapshot_view.html @@ -24,20 +24,20 @@ tr.exportTo('tr.ui.e.system_stats', function() { __proto__: tr.ui.analysis.ObjectSnapshotView.prototype, decorate: function() { - this.classList.add('tr-ui-e-system-stats-snapshot-view'); + Polymer.dom(this).classList.add('tr-ui-e-system-stats-snapshot-view'); }, updateContents: function() { var snapshot = this.objectSnapshot_; if (!snapshot || !snapshot.getStats()) { - this.textContent = 'No system stats snapshot found.'; + Polymer.dom(this).textContent = 'No system stats snapshot found.'; return; } // Clear old snapshot view. - this.textContent = ''; + Polymer.dom(this).textContent = ''; var stats = snapshot.getStats(); - this.appendChild(this.buildList_(stats)); + Polymer.dom(this).appendChild(this.buildList_(stats)); }, isFloat: function(n) { @@ -55,16 +55,16 @@ tr.exportTo('tr.ui.e.system_stats', function() { for (var statName in stats) { var statText = document.createElement('li'); - statText.textContent = '' + statName + ': '; - statList.appendChild(statText); + Polymer.dom(statText).textContent = '' + statName + ': '; + Polymer.dom(statList).appendChild(statText); if (stats[statName] instanceof Object) { - statList.appendChild(this.buildList_(stats[statName])); + Polymer.dom(statList).appendChild(this.buildList_(stats[statName])); } else { if (this.isFloat(stats[statName])) - statText.textContent += stats[statName].toFixed(2); + Polymer.dom(statText).textContent += stats[statName].toFixed(2); else - statText.textContent += stats[statName]; + Polymer.dom(statText).textContent += stats[statName]; } } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html index 3ba4626e1c3..5045dd13d34 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/systrace_config.html @@ -5,6 +5,13 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<!-- +TODO(charliea): Make all UI files depend on tracing/ui/base/base.html in the +same way that all non-UI files depend on tracing/base/base.html. Enforce this +dependency with a presubmit. +--> +<link rel="import" href="/tracing/ui/base/base.html" data-suppress-import-order> + <link rel="import" href="/tracing/extras/systrace_config.html"> <link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/extras/highlighter/vsync_highlighter.html"> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html new file mode 100644 index 00000000000..a33ec56e07f --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/gc_objects_stats_table.html @@ -0,0 +1,556 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/extras/v8/v8_gc_stats_thread_slice.html"> +<link rel="import" href="/tracing/ui/base/table.html"> + +<dom-module id='tr-ui-e-v8-gc-objects-stats-table'> + <template> + <style> + tr-ui-b-table { + flex: 0 0 auto; + align-self: stretch; + margin-top: 1em; + font-size: 12px; + } + </style> + <tr-ui-b-table id="table"></tr-ui-b-table> + </template> +</dom-module> +<script> +'use strict'; + +tr.exportTo('tr.ui.e.v8', function() { + + // The constant variables below should be consistent with + // https://github.com/mlippautz/v8-heap-stats/blob/master/app/utils.js#L120 + var InstanceTypeGroups = { + Rest: [ + "ACCESSOR_INFO_TYPE", + "ACCESSOR_PAIR_TYPE", + "ACCESS_CHECK_INFO_TYPE", + "ALLOCATION_MEMENTO_TYPE", + "ALLOCATION_SITE_TYPE", + "CALL_HANDLER_INFO_TYPE", + "CELL_TYPE", + "FIXED_INT8_ARRAY_TYPE", + "FIXED_UINT8_ARRAY_TYPE", + "FIXED_UINT8_CLAMPED_ARRAY_TYPE", + "FIXED_INT16_ARRAY_TYPE", + "FIXED_UINT16_ARRAY_TYPE", + "FIXED_INT32_ARRAY_TYPE", + "FIXED_UINT32_ARRAY_TYPE", + "FIXED_FLOAT32_ARRAY_TYPE", + "FIXED_FLOAT64_ARRAY_TYPE", + "FIXED_DOUBLE_ARRAY_TYPE", + "FOREIGN_TYPE", + "FUNCTION_TEMPLATE_INFO_TYPE", + "HEAP_NUMBER_TYPE", + "INTERCEPTOR_INFO_TYPE", + "MUTABLE_HEAP_NUMBER_TYPE", + "OBJECT_TEMPLATE_INFO_TYPE", + "ODDBALL_TYPE", + "PROPERTY_CELL_TYPE", + "PROTOTYPE_INFO_TYPE", + "SCRIPT_TYPE", + "SYMBOL_TYPE", + "TRANSITION_ARRAY_TYPE", + "TYPE_FEEDBACK_INFO_TYPE" + ], + Strings: [ + "CONS_ONE_BYTE_STRING_TYPE", + "CONS_STRING_TYPE", + "EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE", + "EXTERNAL_ONE_BYTE_STRING_TYPE", + "EXTERNAL_INTERNALIZED_STRING_TYPE", + "EXTERNAL_STRING_TYPE", + "INTERNALIZED_STRING_TYPE", + "ONE_BYTE_INTERNALIZED_STRING_TYPE", + "ONE_BYTE_STRING_TYPE", + "SHORT_EXTERNAL_INTERNALIZED_STRING_TYPE", + "SHORT_EXTERNAL_ONE_BYTE_STRING_TYPE", + "SHORT_EXTERNAL_ONE_BYTE_INTERNALIZED_STRING_TYPE", + "SHORT_EXTERNAL_STRING_TYPE", + "SLICED_ONE_BYTE_STRING_TYPE", + "SLICED_STRING_TYPE", + "STRING_TYPE" + ], + JS_OTHER: [ + "JS_API_OBJECT_TYPE", + "JS_ARGUMENTS_TYPE", + "JS_ARRAY_BUFFER_TYPE", + "JS_ARRAY_TYPE", + "JS_BOUND_FUNCTION_TYPE", + "JS_ERROR_TYPE", + "JS_DATE_TYPE", + "JS_FUNCTION_TYPE", + "JS_GLOBAL_OBJECT_TYPE", + "JS_GLOBAL_PROXY_TYPE", + "JS_MAP_ITERATOR_TYPE", + "JS_MAP_TYPE", + "JS_MESSAGE_OBJECT_TYPE", + "JS_PROMISE_TYPE", + "JS_REGEXP_TYPE", + "JS_SPECIAL_API_OBJECT_TYPE", + "JS_TYPED_ARRAY_TYPE", + "JS_VALUE_TYPE", + "JS_WEAK_MAP_TYPE" + ], + FIXED_ARRAY_TYPE: [ + "*FIXED_ARRAY_CODE_STUBS_TABLE_SUB_TYPE", + "*FIXED_ARRAY_COMPILATION_CACHE_TABLE_SUB_TYPE", + "*FIXED_ARRAY_CONTEXT_SUB_TYPE", + "*FIXED_ARRAY_COPY_ON_WRITE_SUB_TYPE", + "*FIXED_ARRAY_DEOPTIMIZATION_DATA_SUB_TYPE", + "*FIXED_ARRAY_DESCRIPTOR_ARRAY_SUB_TYPE", + "*FIXED_ARRAY_EMBEDDED_OBJECT_SUB_TYPE", + "*FIXED_ARRAY_ENUM_CACHE_SUB_TYPE", + "*FIXED_ARRAY_ENUM_INDICES_CACHE_SUB_TYPE", + "*FIXED_ARRAY_DEPENDENT_CODE_SUB_TYPE", + "*FIXED_ARRAY_DICTIONARY_ELEMENTS_SUB_TYPE", + "*FIXED_ARRAY_DICTIONARY_PROPERTIES_SUB_TYPE", + "*FIXED_ARRAY_EMPTY_PROPERTIES_DICTIONARY_SUB_TYPE", + "*FIXED_ARRAY_FAST_ELEMENTS_SUB_TYPE", + "*FIXED_ARRAY_FAST_PROPERTIES_SUB_TYPE", + "*FIXED_ARRAY_HANDLER_TABLE_SUB_TYPE", + "*FIXED_ARRAY_INTRINSIC_FUNCTION_NAMES_SUB_TYPE", + "*FIXED_ARRAY_JS_COLLECTION_SUB_TYPE", + "*FIXED_ARRAY_JS_WEAK_COLLECTION_SUB_TYPE", + "*FIXED_ARRAY_LITERALS_ARRAY_SUB_TYPE", + "*FIXED_ARRAY_MAP_CODE_CACHE_SUB_TYPE", + "*FIXED_ARRAY_NOSCRIPT_SHARED_FUNCTION_INFOS_SUB_TYPE", + "*FIXED_ARRAY_NUMBER_STRING_CACHE_SUB_TYPE", + "*FIXED_ARRAY_OBJECT_TO_CODE_SUB_TYPE", + "*FIXED_ARRAY_OPTIMIZED_CODE_LITERALS_TUB_TYPE", + "*FIXED_ARRAY_OPTIMIZED_CODE_MAP_SUB_TYPE", + "*FIXED_ARRAY_PROTOTYPE_USERS_SUB_TYPE", + "*FIXED_ARRAY_REGEXP_MULTIPLE_CACHE_SUB_TYPE", + "*FIXED_ARRAY_RETAINED_MAPS_SUB_TYPE", + "*FIXED_ARRAY_SCOPE_INFO_SUB_TYPE", + "*FIXED_ARRAY_SCRIPT_LIST_SUB_TYPE", + "*FIXED_ARRAY_SERIALIZED_TEMPLATES_SUB_TYPE", + "*FIXED_ARRAY_SHARED_FUNCTION_INFOS_SUB_TYPE", + "*FIXED_ARRAY_SINGLE_CHARACTER_STRING_CACHE_SUB_TYPE", + "*FIXED_ARRAY_STRING_SPLIT_CACHE_SUB_TYPE", + "*FIXED_ARRAY_STRING_TABLE_SUB_TYPE", + "*FIXED_ARRAY_TEMPLATE_INFO_SUB_TYPE", + "*FIXED_ARRAY_TEMPLATE_INSTANTIATIONS_CACHE_SUB_TYPE", + "*FIXED_ARRAY_TYPE_FEEDBACK_VECTOR_SUB_TYPE", + "*FIXED_ARRAY_TYPE_FEEDBACK_METADATA_SUB_TYPE", + "*FIXED_ARRAY_WEAK_NEW_SPACE_OBJECT_TO_CODE_SUB_TYPE", + "*FIXED_ARRAY_UNKNOWN_SUB_TYPE" + ], + CODE_TYPE: [ + "*CODE_FUNCTION", + "*CODE_OPTIMIZED_FUNCTION", + "*CODE_BYTECODE_HANDLER", + "*CODE_STUB", + "*CODE_HANDLER", + "*CODE_BUILTIN", + "*CODE_REGEXP", + "*CODE_WASM_FUNCTION", + "*CODE_WASM_TO_JS_FUNCTION", + "*CODE_JS_TO_WASM_FUNCTION", + "*CODE_LOAD_IC", + "*CODE_LOAD_GLOBAL_IC", + "*CODE_KEYED_LOAD_IC", + "*CODE_CALL_IC", + "*CODE_STORE_IC", + "*CODE_KEYED_STORE_IC", + "*CODE_BINARY_OP_IC", + "*CODE_COMPARE_IC", + "*CODE_TO_BOOLEAN_IC" + ], + CONTEXT_EXTENSION_TYPE: [ + 'CONTEXT_EXTENSION_TYPE' + ], + MAP_TYPE: [ + 'MAP_TYPE' + ], + BYTE_ARRAY_TYPE: [ + 'BYTE_ARRAY_TYPE' + ], + SHARED_FUNCTION_INFO_TYPE: [ + 'SHARED_FUNCTION_INFO_TYPE' + ], + WEAK_CELL_TYPE: [ + 'WEAK_CELL_TYPE' + ], + JS_OBJECT_TYPE: [ + 'JS_OBJECT_TYPE' + ], + JS_CONTEXT_EXTENSION_OBJECT_TYPE: [ + 'JS_CONTEXT_EXTENSION_OBJECT_TYPE' + ] + }; + + var InstanceSubTypeNames = { + FIXED_ARRAY_TYPE: { + keyToName: key => key.slice("*FIXED_ARRAY_".length) + .slice(0, -("_SUB_TYPE".length)), + nameToKey: name => "*FIXED_ARRAY_" + name + "_SUB_TYPE" + }, + CODE_TYPE: { + keyToName: key => key.slice("*CODE_".length), + nameToKey: name => "*CODE_" + name + }, + Strings: { + keyToName: key => key, + nameToKey: name => name + }, + Rest: { + keyToName: key => key, + nameToKey: name => name + }, + JS_OTHER: { + keyToName: key => key, + nameToKey: name => name + } + }; + + class Entry { + constructor(title, count, overall, overAllocated, histogram, + overAllocatedHistogram) { + this.title_ = title; + this.overall_ = overall; + this.count_ = count; + this.overAllocated_ = overAllocated; + this.histogram_ = histogram; + this.overAllocatedHistogram_ = overAllocatedHistogram; + this.bucketSize_ = this.histogram_.length; + this.overallPercent_ = 100; + this.overAllocatedPercent_ = 100; + } + + get title() { + return this.title_; + } + + get overall() { + return this.overall_; + } + + get count() { + return this.count_; + } + + get overAllocated() { + return this.overAllocated_; + } + + get histogram() { + return this.histogram_; + } + + get overAllocatedHistogram() { + return this.overAllocatedHistogram_; + } + + get bucketSize() { + return this.bucketSize_; + } + + get overallPercent() { + return this.overallPercent_; + } + + set overallPercent(value) { + this.overallPercent_ = value; + } + + get overAllocatedPercent() { + return this.overAllocatedPercent_; + } + + set overAllocatedPercent(value) { + this.overAllocatedPercent_ = value; + } + + setFromObject(obj) { + this.count_ = obj.count; + this.overall_ = obj.overall; + this.overAllocated_ = obj.over_allocated; + this.histogram_ = obj.histogram; + this.overAllocatedHistogram_ = obj.over_allocated_histogram; + } + } + + class GroupedEntry extends Entry { + constructor(title, count, overall, overAllocated, histogram, + overAllocatedHistogram) { + super(title, count, overall, overAllocated, histogram, + overAllocatedHistogram); + this.histogram_.fill(0); + this.overAllocatedHistogram_.fill(0); + this.entries_ = new Map(); + } + + get subRows() { + return Array.from(this.entries_.values()); + } + + getEntryFromTitle(title) { + return this.entries_.get(title); + } + + add(entry) { + this.count_ += entry.count; + this.overall_ += entry.overall; + this.overAllocated_ += entry.overAllocated; + if (this.bucketSize_ === entry.bucketSize) { + for (var i = 0; i < this.bucketSize_; ++i) { + this.histogram_[i] += entry.histogram[i]; + this.overAllocatedHistogram_[i] += entry.overAllocatedHistogram[i]; + } + } + this.entries_.set(entry.title, entry); + } + + accumulateUnknown(title) { + var unknownCount = this.count_; + var unknownOverall = this.overall_; + var unknownOverAllocated = this.overAllocated_; + var unknownHistogram = tr.b.deepCopy(this.histogram_); + var unknownOverAllocatedHistogram = + tr.b.deepCopy(this.overAllocatedHistogram_); + for (var entry of this.entries_.values()) { + unknownCount -= entry.count; + unknownOverall -= entry.overall; + unknownOverAllocated -= entry.overAllocated; + for (var i = 0; i < this.bucketSize_; ++i) { + unknownHistogram[i] -= entry.histogram[i]; + unknownOverAllocatedHistogram[i] -= entry.overAllocatedHistogram[i]; + } + } + this.entries_.set(title, new Entry(title, unknownCount, unknownOverall, + unknownOverAllocated, unknownHistogram, + unknownOverAllocatedHistogram)); + } + + calculatePercentage() { + for (var entry of this.entries_.values()) { + if (this.overall_ > 0) { + entry.overallPercent = + (entry.overall / this.overall_ * 100).toFixed(3); + } else { + entry.overallPercent = 0; + } + + if (this.overAllocated_ > 0) { + entry.overAllocatedPercent = + (entry.overAllocated / this.overAllocated_ * 100).toFixed(3); + } else { + entry.overAllocatedPercent = 0; + } + + if (entry instanceof GroupedEntry) entry.calculatePercentage(); + } + } + } + + Polymer({ + is: 'tr-ui-e-v8-gc-objects-stats-table', + + ready: function() { + this.isolateEntries_ = []; + }, + + constructTable_: function() { + this.$.table.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + this.$.table.tableColumns = [ + { + title: 'Component', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.title; + return typeEl; + }, + showExpandButtons: true + }, + { + title: 'Overall Memory (KB)', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = (row.overall / 1024).toFixed(3); + return typeEl; + }, + cmp: function(a, b) { + return a.overall - b.overall; + } + }, + { + title: 'Over Allocated Memory (KB)', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = (row.overAllocated / 1024).toFixed(3); + return typeEl; + }, + cmp: function(a, b) { + return a.overAllocated - b.overAllocated; + } + }, + { + title: 'Overall Count', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.count; + return typeEl; + }, + cmp: function(a, b) { + return a.count - b.count; + } + }, + { + title: 'Overall Memory Percent', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.overallPercent + '%'; + return typeEl; + }, + cmp: function(a, b) { + return a.overall - b.overall; + } + }, + { + title: 'Overall Allocated Memory Percent', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.overAllocatedPercent + '%'; + return typeEl; + }, + cmp: function(a, b) { + return a.overAllocated - b.overAllocated; + } + } + ]; + + this.$.table.sortColumnIndex = 1; + this.$.table.sortDescending = true; + }, + + buildSubEntry_: function(objects, groupEntry, keyToName) { + var typeGroup = InstanceTypeGroups[groupEntry.title]; + for (var instanceType of typeGroup) { + var e = objects[instanceType]; + delete objects[instanceType]; + if (e === undefined) continue; + var title = instanceType; + if (keyToName !== undefined) title = keyToName(title); + groupEntry.add(new Entry(title, e.count, e.overall, e.over_allocated, + e.histogram, e.over_allocated_histogram)); + } + }, + + buildOthers_: function(objects, groupEntry) { + for (var title of Object.getOwnPropertyNames(objects)) { + if (title === 'END') continue; + var obj = objects[title]; + groupEntry.add(new Entry(title, obj.count, obj.overall, + obj.over_allocated, obj.histogram, + obj.over_allocated_histogram)) + } + }, + + build_: function(objects, objectEntry, bucketSize) { + var fixedArrayObject = objects['FIXED_ARRAY_TYPE']; + if (fixedArrayObject === undefined) + throw new Error('Fixed Array Object not found.'); + + var groupEntries = { + restEntry: new GroupedEntry('Rest', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)), + stringEntry: new GroupedEntry('Strings', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)), + jsEntry: new GroupedEntry('JS_OTHER', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)), + fixedArrayEntry: new GroupedEntry('FIXED_ARRAY_TYPE', 0, 0, 0, + new Array(bucketSize), + new Array(bucketSize)), + codeEntry: new GroupedEntry('CODE_TYPE', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)), + contextExtensionEntry: new GroupedEntry('CONTEXT_EXTENSION_TYPE', 0, 0, + 0, new Array(bucketSize), + new Array(bucketSize)), + mapEntry: new GroupedEntry('MAP_TYPE', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)), + byteArrayEntry: new GroupedEntry('BYTE_ARRAY_TYPE', 0, 0, 0, + new Array(bucketSize), + new Array(bucketSize)), + sharedFunctionInfoEntry: new GroupedEntry('SHARED_FUNCTION_INFO_TYPE', + 0, 0, 0, + new Array(bucketSize), + new Array(bucketSize)), + weakCellEntry: new GroupedEntry('WEAK_CELL_TYPE', 0, 0, 0, + new Array(bucketSize), + new Array(bucketSize)), + jsObjectEntry: new GroupedEntry('JS_OBJECT_TYPE', 0, 0, 0, + new Array(bucketSize), + new Array(bucketSize)), + jsContextExtensionObjectEntry: new GroupedEntry( + 'JS_CONTEXT_EXTENSION_OBJECT_TYPE', 0, 0, 0, new Array(bucketSize), + new Array(bucketSize)) + }; + for (var name of Object.getOwnPropertyNames(groupEntries)) { + var groupEntry = groupEntries[name]; + var keyToName = undefined; + if (InstanceSubTypeNames[groupEntry.title] !== undefined) { + keyToName = InstanceSubTypeNames[groupEntry.title].keyToName; + } + this.buildSubEntry_(objects, groupEntry, keyToName); + if (name === 'fixedArrayEntry') { + groupEntry.setFromObject(fixedArrayObject); + groupEntry.accumulateUnknown('UNKNOWN'); + } + objectEntry.add(groupEntry); + } + }, + + set selection(slices) { + slices.sortEvents(function(a, b) { + return b.start - a.start; + }); + var previous = undefined; + for (let slice of slices) { + if (!slice instanceof tr.e.v8.V8GCStatsThreadSlice) continue; + var liveObjects = slice.liveObjects; + var deadObjects = slice.deadObjects; + var isolate = liveObjects.isolate; + + var isolateEntry = + new GroupedEntry( + 'Isolate_' + isolate + ' at ' + slice.start.toFixed(3) + ' ms', + 0, 0, 0, [], []); + var liveEntry = new GroupedEntry('live objects', 0, 0, 0, [], []); + var deadEntry = new GroupedEntry('dead objects', 0, 0, 0, [], []); + + var liveBucketSize = liveObjects.bucket_sizes.length; + var deadBucketSize = deadObjects.bucket_sizes.length; + + this.build_(tr.b.deepCopy(liveObjects.type_data), liveEntry, + liveBucketSize); + isolateEntry.add(liveEntry); + + this.build_(tr.b.deepCopy(deadObjects.type_data), deadEntry, + deadBucketSize); + isolateEntry.add(deadEntry); + + isolateEntry.calculatePercentage(); + this.isolateEntries_.push(isolateEntry); + } + this.updateTable_(); + }, + + updateTable_: function() { + this.constructTable_(); + this.$.table.tableRows = this.isolateEntries_; + this.$.table.rebuild(); + }, + }); + + return {}; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html new file mode 100644 index 00000000000..02c5c0e27d6 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html @@ -0,0 +1,45 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html"> + +<dom-module id='tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view'> + <template> + <style> + </style> + <tr-ui-e-v8-gc-objects-stats-table id="gcObjectsStats"> + </tr-ui-e-v8-gc-objects-stats-table> + </template> +</dom-module> + +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + get selection() { + return this.$.content.selection; + }, + + set selection(selection) { + this.$.gcObjectsStats.selection = selection; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-e-multi-v8-gc-stats-thread-slice-sub-view', + tr.e.v8.V8GCStatsThreadSlice, + { + multi: true, + title: 'V8 GC Stats slices' + } +); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html new file mode 100644 index 00000000000..a2dfecbfb04 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html @@ -0,0 +1,44 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html"> + +<dom-module id='tr-ui-e-multi-v8-thread-slice-sub-view'> + <template> + <tr-ui-a-multi-thread-slice-sub-view id="content"></tr-ui-a-multi-thread-slice-sub-view> + <tr-ui-e-v8-runtime-call-stats-table id="runtimeCallStats"></tr-ui-e-v8-runtime-call-stats-table> + </template> +</dom-module> + +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-e-multi-v8-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + get selection() { + return this.$.content.selection; + }, + + set selection(selection) { + this.$.runtimeCallStats.slices = selection; + this.$.content.selection = selection; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-e-multi-v8-thread-slice-sub-view', + tr.e.v8.V8ThreadSlice, + { + multi: true, + title: 'V8 slices' + } +); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html new file mode 100644 index 00000000000..7bf81d1d043 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view_test.html @@ -0,0 +1,79 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/core/test_utils.html"> +<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html"> +<link rel="import" href="/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + var newSliceEx = tr.c.TestUtils.newSliceEx; + + function createModel() { + var m = tr.c.TestUtils.newModel(function(m) { + m.p1 = m.getOrCreateProcess(1); + m.t2 = m.p1.getOrCreateThread(2); + + m.s1 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 0, + end: 10, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + CompileFullCode: [3, 345], + LoadIC_Miss: [5, 567], + ParseLazy: [8, 890] + }}})); + m.s2 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 11, + end: 15, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + HandleApiCall: [1, 123], + OptimizeCode: [7, 789] + }}})); + }); + return m; + } + + test('selectMultiV8ThreadSlices', function() { + var m = createModel(); + + var viewEl = + document.createElement('tr-ui-e-multi-v8-thread-slice-sub-view'); + var selection = new tr.model.EventSet(); + selection.push(m.s1); + selection.push(m.s2); + viewEl.selection = selection; + this.addHTMLOutput(viewEl); + var rows = viewEl.$.runtimeCallStats.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 2714, + 567, + 789, + 345, + 890, + 0, + 0, + 0, + 0, + 123 + ]); + }); + +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html new file mode 100644 index 00000000000..d09d0f1f754 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table.html @@ -0,0 +1,230 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html"> +<link rel="import" href="/tracing/ui/base/table.html"> + +<dom-module id='tr-ui-e-v8-runtime-call-stats-table'> + <template> + <style> + #table { + flex: 0 0 auto; + align-self: stretch; + margin-top: 1em; + font-size: 12px; + } + </style> + <tr-ui-b-table id="table"></tr-ui-b-table> + </template> +</dom-module> +<script> +'use strict'; + +tr.exportTo('tr.ui.e.v8', function() { + + function handleCodeSearch_(event) { + if (event.target.parentNode === undefined) return; + var name = event.target.parentNode.entryName; + var url = 'https://cs.chromium.org/search/?sq=package:chromium&type=cs&q='; + if (name.startsWith('API_')) name = name.substring(4); + url += encodeURIComponent(name) + '+file:src/v8/src'; + window.open(url, '_blank'); + } + + var Entry = function(name, count, time) { + this.name_ = name; + this.count_ = count; + this.time_ = time; + }; + + Entry.prototype = { + __proto__: Object.prototype, + + get name() { + return this.name_; + }, + + get count() { + return this.count_; + }, + + get time() { + return this.time_; + }, + + accumulate: function(count, time) { + this.count_ += count; + this.time_ += time; + }, + + reset: function() { + this.count_ = 0; + this.time_ = 0; + } + }; + + var GroupedEntry = function(name, matchRegex) { + Entry.call(this, name, 0, 0); + this.regex_ = matchRegex; + this.entries_ = new Map(); + }; + + GroupedEntry.prototype = { + __proto__: Entry.prototype, + + match: function(name) { + return this.regex_ && !(!name.match(this.regex_)); + }, + + add: function(entry) { + var value = this.entries_.get(entry.name); + if (value !== undefined) + value.accumulate(entry.count, entry.time); + else + this.entries_.set(entry.name, entry); + this.count_ += entry.count; + this.time_ += entry.time; + }, + + get subRows() { + return Array.from(this.entries_.values()); + }, + + reset: function(entry) { + this.time_ = 0; + this.count_ = 0; + this.entries_.clear(); + } + }; + + Polymer({ + is: 'tr-ui-e-v8-runtime-call-stats-table', + + ready: function() { + this.table_ = this.$.table; + this.totalTime_ = 0; + }, + + constructTable_: function() { + var totalTime = this.totalTime_; + this.table_.selectionMode = tr.ui.b.TableFormat.SelectionMode.ROW; + this.table_.tableColumns = [ + { + title: 'Name', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.name; + if (!(row instanceof GroupedEntry)) { + typeEl.title = 'click ? for code search'; + typeEl.entryName = row.name; + var codeSearchEl = document.createElement('span'); + codeSearchEl.innerText = '?'; + codeSearchEl.style.float = 'right'; + codeSearchEl.style.borderRadius = '5px'; + codeSearchEl.style.backgroundColor = '#EEE'; + codeSearchEl.addEventListener('click', + handleCodeSearch_.bind(this)); + typeEl.appendChild(codeSearchEl); + } + return typeEl; + }, + width: '200px', + showExpandButtons: true + }, + { + title: 'Time', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = (row.time / 1000.0).toFixed(3) + ' ms'; + return typeEl; + }, + width: '100px', + cmp: function(a, b) { + return a.time - b.time; + } + }, + { + title: 'Count', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = row.count; + return typeEl; + }, + width: '100px', + cmp: function(a, b) { + return a.count - b.count; + } + }, + { + title: 'Percent', + value: function(row) { + var typeEl = document.createElement('span'); + typeEl.innerText = (row.time / totalTime * 100).toFixed(3) + '%'; + return typeEl; + }, + width: '100px', + cmp: function(a, b) { + return a.time - b.time; + } + } + ]; + + this.table_.sortColumnIndex = 1; + this.table_.sortDescending = true; + }, + + set slices(slices) { + var groups = new Array( + new GroupedEntry('Total'), + new GroupedEntry('IC', /.*IC.*/), + new GroupedEntry('Optimize', + /StackGuard|.*Optimize.*|.*Deoptimize.*|Recompile.*/), + new GroupedEntry('Compile', /.*Compile.*/), + new GroupedEntry('Parse', /.*Parse.*/), + new GroupedEntry('Callback', /.*Callback$/), + new GroupedEntry('API', /.*API.*/), + new GroupedEntry('GC', /GC|AllocateInTargetSpace/), + new GroupedEntry('JavaScript', /JS_Execution/), + new GroupedEntry('Runtime', /.*/) + ); + + slices.forEach(function(slice) { + if (!(slice instanceof tr.e.v8.V8ThreadSlice)) return; + try { + var runtimeCallStats = JSON.parse(slice.runtimeCallStats); + } catch (e) { + var runtimeCallStats = slice.runtimeCallStats; + } + if (runtimeCallStats !== undefined) { + Object.getOwnPropertyNames(runtimeCallStats).forEach( + function(runtimeCallStatName) { + for (var i = 1; i < groups.length; ++i) { + if (groups[i].match(runtimeCallStatName)) { + var runtimeCallStat = runtimeCallStats[runtimeCallStatName]; + if (runtimeCallStat.length !== 2) break; + var entry = new Entry(runtimeCallStatName, runtimeCallStat[0], + runtimeCallStat[1]); + groups[0].accumulate(runtimeCallStat[0], runtimeCallStat[1]); + groups[i].add(entry); + break; + } + } + }, this); + } + }, this); + this.totalTime_ = groups[0].time; + if (this.totalTime_ > 0) { + this.constructTable_(); + this.table_.tableRows = groups; + this.table_.rebuild(); + } + } + }); + + return {}; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html new file mode 100644 index 00000000000..71696479d72 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/runtime_call_stats_table_test.html @@ -0,0 +1,181 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/core/test_utils.html"> +<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html"> +<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + var newSliceEx = tr.c.TestUtils.newSliceEx; + var apiObjectGet = [1, 123]; + var functionCallback = [2, 234]; + var compileFullCode = [3, 345]; + var allocateInTargetSpace = [4, 456]; + var loadIcMiss = [5, 567]; + var jsExecution = [6, 678]; + var optimizeCode = [7, 789]; + var parseLazy = [8, 890]; + var handleApiCall = [9, 901]; + + function createModel() { + var m = tr.c.TestUtils.newModel(function(m) { + m.p1 = m.getOrCreateProcess(1); + m.t2 = m.p1.getOrCreateThread(2); + + m.s1 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 0, + end: 10, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + JS_Execution: jsExecution, + HandleApiCall: handleApiCall, + CompileFullCode: compileFullCode, + LoadIC_Miss: loadIcMiss, + ParseLazy: parseLazy, + OptimizeCode: optimizeCode, + FunctionCallback: functionCallback, + AllocateInTargetSpace: allocateInTargetSpace, + API_Object_Get: apiObjectGet + }}})); + m.s2 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 11, + end: 15, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + JS_Execution: jsExecution, + HandleApiCall: handleApiCall, + CompileFullCode: compileFullCode, + LoadIC_Miss: loadIcMiss, + ParseLazy: parseLazy, + OptimizeCode: optimizeCode, + FunctionCallback: functionCallback, + AllocateInTargetSpace: allocateInTargetSpace, + API_Object_Get: apiObjectGet + }}})); + m.s3 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 11, + end: 15, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + LoadIC_LoadCallback: [1, 111], + StoreIC_StoreCallback: [2, 222], + }}})); + }); + return m; + } + + test('SingleSliceSelection', function() { + var m = createModel(); + + var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table'); + viewEl.slices = [m.s1]; + this.addHTMLOutput(viewEl); + tr.b.forceAllPendingTasksToRunForTest(); + var rows = viewEl.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 4983, + loadIcMiss[1], + optimizeCode[1], + compileFullCode[1], + parseLazy[1], + functionCallback[1], + apiObjectGet[1], + allocateInTargetSpace[1], + jsExecution[1], + handleApiCall[1] + ]); + }); + + test('MultiSliceSelection', function() { + var m = createModel(); + + var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table'); + viewEl.slices = [m.s1, m.s2]; + this.addHTMLOutput(viewEl); + tr.b.forceAllPendingTasksToRunForTest(); + var rows = viewEl.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 9966, + loadIcMiss[1] * 2, + optimizeCode[1] * 2, + compileFullCode[1] * 2, + parseLazy[1] * 2, + functionCallback[1] * 2, + apiObjectGet[1] * 2, + allocateInTargetSpace[1] * 2, + jsExecution[1] * 2, + handleApiCall[1] * 2 + ]); + + assert.deepEqual(rows.map(r => r.entries_.size), [ + 0, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ]); + }); + + test('groupCorrectly', function() { + var m = createModel(); + + var viewEl = document.createElement('tr-ui-e-v8-runtime-call-stats-table'); + viewEl.slices = [m.s3]; + this.addHTMLOutput(viewEl); + tr.b.forceAllPendingTasksToRunForTest(); + var rows = viewEl.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 333, + 333, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]); + + assert.deepEqual(rows.map(r => r.entries_.size), [ + 0, + 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ]); + }); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html new file mode 100644 index 00000000000..6926ffa2e72 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html"> + +<dom-module id='tr-ui-e-single-v8-gc-stats-thread-slice-sub-view'> + <template> + <tr-ui-a-single-event-sub-view id="content"></tr-ui-a-single-event-sub-view> + <tr-ui-e-v8-gc-objects-stats-table id="gcObjectsStats"></tr-ui-e-v8-gc-objects-stats-table> + </template> +</dom-module> + +<script> +'use strict'; +Polymer({ + is: 'tr-ui-e-single-v8-gc-stats-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + get selection() { + return this.$.content.selection; + }, + + set selection(selection) { + this.$.content.selection = selection; + this.$.gcObjectsStats.selection = selection; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-e-single-v8-gc-stats-thread-slice-sub-view', + tr.e.v8.V8GCStatsThreadSlice, + { + multi: false, + title: 'V8 GC stats slice' + } +); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html new file mode 100644 index 00000000000..8162d201fbe --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html @@ -0,0 +1,43 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/ui/analysis/analysis_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html"> + +<dom-module id='tr-ui-e-single-v8-thread-slice-sub-view'> + <template> + <tr-ui-a-single-thread-slice-sub-view id="content"></tr-ui-a-single-thread-slice-sub-view> + <tr-ui-e-v8-runtime-call-stats-table id="runtimeCallStats"></tr-ui-e-v8-runtime-call-stats-table> + </template> +</dom-module> + +<script> +'use strict'; +Polymer({ + is: 'tr-ui-e-single-v8-thread-slice-sub-view', + behaviors: [tr.ui.analysis.AnalysisSubView], + + get selection() { + return this.$.content.selection; + }, + + set selection(selection) { + this.$.runtimeCallStats.slices = selection; + this.$.content.selection = selection; + } +}); + +tr.ui.analysis.AnalysisSubView.register( + 'tr-ui-e-single-v8-thread-slice-sub-view', + tr.e.v8.V8ThreadSlice, + { + multi: false, + title: 'V8 slice' + } +); + +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html new file mode 100644 index 00000000000..a23d18a1682 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8/single_v8_thread_slice_sub_view_test.html @@ -0,0 +1,96 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/core/test_utils.html"> +<link rel="import" href="/tracing/extras/v8/v8_thread_slice.html"> +<link rel="import" href="/tracing/model/event_set.html"> +<link rel="import" href="/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + var newSliceEx = tr.c.TestUtils.newSliceEx; + + function createModel() { + var m = tr.c.TestUtils.newModel(function(m) { + m.p1 = m.getOrCreateProcess(1); + m.t2 = m.p1.getOrCreateThread(2); + + m.s1 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 0, + end: 10, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + CompileFullCode: [3, 345], + LoadIC_Miss: [5, 567], + ParseLazy: [8, 890] + }}})); + m.s2 = m.t2.sliceGroup.pushSlice( + newSliceEx( + {title: 'V8.Execute', + start: 11, + end: 15, + type: tr.e.v8.V8ThreadSlice, + cat: 'v8', + args: {'runtime-call-stats': + { + HandleApiCall: [1, 123], + OptimizeCode: [7, 789] + }}})); + }); + return m; + } + + test('selectV8ThreadSlice', function() { + var m = createModel(); + + var viewEl = + document.createElement('tr-ui-e-single-v8-thread-slice-sub-view'); + var selection1 = new tr.model.EventSet(); + selection1.push(m.s1); + viewEl.selection = selection1; + this.addHTMLOutput(viewEl); + var rows = viewEl.$.runtimeCallStats.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 1802, + 567, + 0, + 345, + 890, + 0, + 0, + 0, + 0, + 0 + ]); + + var selection2 = new tr.model.EventSet(); + selection2.push(m.s2); + viewEl.selection = selection2; + rows = viewEl.$.runtimeCallStats.$.table.tableRows; + assert.lengthOf(rows, 10); + assert.deepEqual(rows.map(r => r.time), [ + 912, + 0, + 789, + 0, + 0, + 0, + 0, + 0, + 0, + 123 + ]); + }); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html new file mode 100644 index 00000000000..ac9794d1de7 --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/extras/v8_config.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<!-- +Copyright (c) 2013 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + + +<link rel="import" href="/tracing/extras/v8_config.html"> +<link rel="import" href="/tracing/ui/extras/v8/gc_objects_stats_table.html"> +<link rel="import" href="/tracing/ui/extras/v8/multi_v8_gc_stats_thread_slice_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/multi_v8_thread_slice_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/runtime_call_stats_table.html"> +<link rel="import" href="/tracing/ui/extras/v8/single_v8_gc_stats_thread_slice_sub_view.html"> +<link rel="import" href="/tracing/ui/extras/v8/single_v8_thread_slice_sub_view.html"> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_control.html b/chromium/third_party/catapult/tracing/tracing/ui/find_control.html index 6f2c636b281..0660438b199 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/find_control.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/find_control.html @@ -9,7 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/find_controller.html"> <link rel="import" href="/tracing/ui/timeline_track_view.html"> -<polymer-element name="tr-ui-find-control"> +<dom-module id='tr-ui-find-control'> <template> <style> :host { @@ -64,110 +64,111 @@ found in the LICENSE file. </style> <input type='text' id='filter' - on-input="{{ filterTextChanged }}" - on-keydown="{{ filterKeyDown }}" - on-blur="{{ filterBlur }}" - on-focus="{{ filterFocus }}" - on-mouseup="{{ filterMouseUp }}" /> + on-input="filterTextChanged" + on-keydown="filterKeyDown" + on-blur="filterBlur" + on-focus="filterFocus" + on-mouseup="filterMouseUp" /> <div id="spinner"></div> - <tr-ui-b-toolbar-button on-click="{{ findPrevious }}"> + <tr-ui-b-toolbar-button on-click="findPrevious"> ← </tr-ui-b-toolbar-button> - <tr-ui-b-toolbar-button on-click="{{ findNext }}"> + <tr-ui-b-toolbar-button on-click="findNext"> → </tr-ui-b-toolbar-button> <div id="hitCount">0 of 0</div> </template> - - <script> - 'use strict'; - - Polymer({ - filterKeyDown: function(e) { - if (e.keyCode === 27) { - var hkc = tr.b.getHotkeyControllerForElement(this); - if (hkc) { - hkc.childRequestsBlur(this); - } else { - this.blur(); - } - e.preventDefault(); - e.stopPropagation(); - return; - } else if (e.keyCode === 13) { - if (e.shiftKey) - this.findPrevious(); - else - this.findNext(); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-find-control', + + filterKeyDown: function(e) { + if (e.keyCode === 27) { + var hkc = tr.b.getHotkeyControllerForElement(this); + if (hkc) { + hkc.childRequestsBlur(this); + } else { + this.blur(); } - }, - - filterBlur: function(e) { - this.updateHitCountEl(); - }, - - filterFocus: function(e) { - this.$.filter.select(); - }, - - // Prevent that the input text is deselected after focusing the find - // control with the mouse. - filterMouseUp: function(e) { e.preventDefault(); - }, - - get controller() { - return this.controller_; - }, - - set controller(c) { - this.controller_ = c; - this.updateHitCountEl(); - }, - - focus: function() { - this.$.filter.focus(); - }, - - get hasFocus() { - return this === document.activeElement; - }, - - filterTextChanged: function() { - this.$.hitCount.textContent = ''; - this.$.spinner.style.visibility = 'visible'; - this.controller.startFiltering(this.$.filter.value).then(function() { - this.$.spinner.style.visibility = 'hidden'; - this.updateHitCountEl(); - }.bind(this)); - }, - - findNext: function() { - if (this.controller) - this.controller.findNext(); - this.updateHitCountEl(); - }, - - findPrevious: function() { - if (this.controller) - this.controller.findPrevious(); + e.stopPropagation(); + return; + } else if (e.keyCode === 13) { + if (e.shiftKey) + this.findPrevious(); + else + this.findNext(); + } + }, + + filterBlur: function(e) { + this.updateHitCountEl(); + }, + + filterFocus: function(e) { + this.$.filter.select(); + }, + + // Prevent that the input text is deselected after focusing the find + // control with the mouse. + filterMouseUp: function(e) { + e.preventDefault(); + }, + + get controller() { + return this.controller_; + }, + + set controller(c) { + this.controller_ = c; + this.updateHitCountEl(); + }, + + focus: function() { + this.$.filter.focus(); + }, + + get hasFocus() { + return this === document.activeElement; + }, + + filterTextChanged: function() { + Polymer.dom(this.$.hitCount).textContent = ''; + this.$.spinner.style.visibility = 'visible'; + this.controller.startFiltering(this.$.filter.value).then(function() { + this.$.spinner.style.visibility = 'hidden'; this.updateHitCountEl(); - }, - - updateHitCountEl: function() { - if (!this.controller || this.$.filter.value.length === 0) { - this.$.hitCount.textContent = ''; - return; - } + }.bind(this)); + }, + + findNext: function() { + if (this.controller) + this.controller.findNext(); + this.updateHitCountEl(); + }, + + findPrevious: function() { + if (this.controller) + this.controller.findPrevious(); + this.updateHitCountEl(); + }, + + updateHitCountEl: function() { + if (!this.controller || this.$.filter.value.length === 0) { + Polymer.dom(this.$.hitCount).textContent = ''; + return; + } - var n = this.controller.filterHits.length; - var i = n === 0 ? -1 : this.controller.currentHitIndex; - this.$.hitCount.textContent = (i + 1) + ' of ' + n; - }, + var n = this.controller.filterHits.length; + var i = n === 0 ? -1 : this.controller.currentHitIndex; + Polymer.dom(this.$.hitCount).textContent = (i + 1) + ' of ' + n; + }, - setText: function(string) { - this.$.filter.value = string; - } - }); - </script> -</polymer-element> + setText: function(string) { + this.$.filter.value = string; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html b/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html index 4247676856b..223b9621d1a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/find_controller.html @@ -82,7 +82,7 @@ tr.exportTo('tr.ui', function() { } catch (e) { this.enqueueOperation_(function() { var overlay = new tr.ui.b.Overlay(); - overlay.textContent = e.message; + Polymer.dom(overlay).textContent = e.message; overlay.title = 'UI State Navigation Error'; overlay.visible = true; }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html b/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html index f6509f88cbc..fed4812a985 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/find_controller_test.html @@ -221,7 +221,7 @@ tr.b.unittest.testSuite(function() { container.id = 'track_view_container'; var timeline = document.createElement('tr-ui-timeline-view'); - timeline.appendChild(container); + Polymer.dom(timeline).appendChild(container); // This is for testing only, have to make sure things link up right. timeline.trackViewContainer_ = container; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html b/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html index 5164a80d7bb..72c30ca4579 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/metrics_debugger_app.html @@ -4,43 +4,44 @@ Copyright 2016 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/perf_insights/mre/mre_result.html"> <link rel="import" href="/tracing/extras/full_config.html"> <link rel="import" href="/tracing/importer/import.html"> <link rel="import" href="/tracing/metrics/all_metrics.html"> <link rel="import" href="/tracing/metrics/metric_map_function.html"> <link rel="import" href="/tracing/model/model.html"> +<link rel="import" href="/tracing/mre/mre_result.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/base/file.html"> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name="tracing-ui-metrics-debugger-app"> - <template> - <style> - pre { - overflow: auto; - } - #bar { - display: flex; - flex-direction: row; - padding: 1px 6px; - } - </style> +<dom-module id='tracing-ui-metrics-debugger-app'> + <style> + pre { + overflow: auto; + } + #bar { + display: flex; + flex-direction: row; + padding: 1px 6px; + } + </style> - <top-left-controls id="top_left_controls"></top-left-controls> - <input id="load_trace" type="file"/> - <button id="run_metric">Run metric</button> - <div id="trace_info"></div> - <pre id="map_results"> - </pre> + <template> + <top-left-controls id="top_left_controls"></top-left-controls> + <input id="load_trace" type="file"/> + <button id="run_metric">Run metric</button> + <div id="trace_info"></div> + <pre id="map_results"> + </pre> </template> -</polymer-element> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui', function() { - Polymer('tracing-ui-metrics-debugger-app', { + Polymer({ + is: 'tracing-ui-metrics-debugger-app', created: function() { this.metrics_ = []; tr.metrics.MetricRegistry.getAllRegisteredTypeInfos().forEach( @@ -62,7 +63,8 @@ tr.exportTo('tr.ui', function() { this.settingsKey_, this.metrics_[0].value, this.metrics_); - this.$.top_left_controls.appendChild(metricSelector); + Polymer.dom(this.$.top_left_controls).appendChild( + metricSelector); this.$.load_trace.addEventListener('change', function(event) { var file = event.target.files[0]; @@ -80,13 +82,14 @@ tr.exportTo('tr.ui', function() { tr.ui.b.Overlay.showError('You must load a trace first!'); return; } - var result = new pi.mre.MreResult(); + var result = new tr.mre.MreResult(); var model = this.activeTrace_.model; - var options = {metric: this.currentMetricName_}; + var options = {metrics: [this.currentMetricName_]}; try { tr.metrics.metricMapFunction(result, model, options); - this.$.map_results.textContent = 'Metric result:\n' + - JSON.stringify(result.asDict(), undefined, 2); + this.set( + '$.map_results.textContent', + 'Metric result:\n' + JSON.stringify(result.asDict(), undefined, 2)); } catch (err) { tr.ui.b.Overlay.showError('Error running metric:\n' + err.stack); console.error(err); @@ -117,8 +120,8 @@ tr.exportTo('tr.ui', function() { filename: filename, model: model, }; - this.$.trace_info.textContent = 'Trace file ' + filename + - ' is loaded.'; + Polymer.dom(this.$.trace_info).textContent = 'Trace file ' + + filename + ' is loaded.'; }.bind(this), function(err) { tr.ui.b.Overlay.showError('Trace import error: ' + err); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html b/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html index 208cc35577e..22d8bd183ac 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/scripting_control.html @@ -7,8 +7,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/extras/tquery/tquery.html"> -<polymer-element - name="tr-ui-scripting-control"> +<dom-module id='tr-ui-scripting-control'> <template> <style> :host { @@ -64,125 +63,130 @@ found in the LICENSE file. </style> <div id="root" class="root hidden" tabindex="0" - on-focus="{{ onConsoleFocus }}"> + on-focus="onConsoleFocus"> <div id='history'></div> <div id='prompt' - on-keypress="{{ promptKeyPress }}" - on-keydown="{{ promptKeyDown }}" - on-blur="{{ onConsoleBlur }}"></div> + on-keypress="promptKeyPress" + on-keydown="promptKeyDown" + on-blur="onConsoleBlur"></div> </div> </template> - - <script> - 'use strict'; - - Polymer({ - _isEnterKey: function(event) { - // Check if in IME. - return event.keyCode !== 229 && event.keyIdentifier === 'Enter'; - }, - - _setFocused: function(focused) { - var promptEl = this.$.prompt; - if (focused) { - promptEl.focus(); - this.$.root.classList.add('focused'); - // Move cursor to the end of any existing text. - if (promptEl.innerText.length > 0) { - var sel = window.getSelection(); - sel.collapse(promptEl.firstChild, promptEl.innerText.length); - } - } else { - promptEl.blur(); - this.$.root.classList.remove('focused'); - // Workaround for crbug.com/89026 to ensure the prompt doesn't retain - // keyboard focus. - var parent = promptEl.parentElement; - var nextEl = promptEl.nextSibling; - promptEl.remove(); - parent.insertBefore(promptEl, nextEl); +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-scripting-control', + + _isEnterKey: function(event) { + // Check if in IME. + // Remove keyIdentifier after reference build rolls past M51 when + // KeyboardEvent.key was added. + return event.keyCode !== 229 && + (event.key === 'Enter' || event.keyIdentifier === 'Enter'); + }, + + _setFocused: function(focused) { + var promptEl = this.$.prompt; + if (focused) { + promptEl.focus(); + Polymer.dom(this.$.root).classList.add('focused'); + // Move cursor to the end of any existing text. + if (promptEl.innerText.length > 0) { + var sel = window.getSelection(); + sel.collapse( + Polymer.dom(promptEl).firstChild, promptEl.innerText.length); } - }, + } else { + promptEl.blur(); + Polymer.dom(this.$.root).classList.remove('focused'); + // Workaround for crbug.com/89026 to ensure the prompt doesn't retain + // keyboard focus. + var parent = promptEl.parentElement; + var nextEl = Polymer.dom(promptEl).nextSibling; + promptEl.remove(); + Polymer.dom(parent).insertBefore(promptEl, nextEl); + } + }, + + onConsoleFocus: function(e) { + e.stopPropagation(); + this._setFocused(true); + }, + + onConsoleBlur: function(e) { + e.stopPropagation(); + this._setFocused(false); + }, + + promptKeyDown: function(e) { + e.stopPropagation(); + if (!this._isEnterKey(e)) + return; + e.preventDefault(); + var promptEl = this.$.prompt; + var command = promptEl.innerText; + if (command.length === 0) + return; + promptEl.innerText = ''; + this.addLine_(String.fromCharCode(187) + ' ' + command); + + try { + var result = this.controller_.executeCommand(command); + } catch (e) { + result = e.stack || e.stackTrace; + } - onConsoleFocus: function(e) { - e.stopPropagation(); + if (result instanceof tr.e.tquery.TQuery) { + // TODO(skyostil): Show a cool spinner. + result.ready().then(function(selection) { + this.addLine_(selection.length + ' matches'); + this.controller_.brushingStateController. + showScriptControlSelection(selection); + }.bind(this)); + } else { + this.addLine_(result); + } + promptEl.scrollIntoView(); + }, + + addLine_: function(line) { + var historyEl = this.$.history; + if (historyEl.innerText.length !== 0) + historyEl.innerText += '\n'; + historyEl.innerText += line; + }, + + promptKeyPress: function(e) { + e.stopPropagation(); + }, + + toggleVisibility: function() { + var root = this.$.root; + if (!this.visible) { + Polymer.dom(root).classList.remove('hidden'); this._setFocused(true); - }, - - onConsoleBlur: function(e) { - e.stopPropagation(); + } else { + Polymer.dom(root).classList.add('hidden'); this._setFocused(false); - }, - - promptKeyDown: function(e) { - e.stopPropagation(); - if (!this._isEnterKey(e)) - return; - e.preventDefault(); - var promptEl = this.$.prompt; - var command = promptEl.innerText; - if (command.length === 0) - return; - promptEl.innerText = ''; - this.addLine_(String.fromCharCode(187) + ' ' + command); - - try { - var result = this.controller_.executeCommand(command); - } catch (e) { - result = e.stack || e.stackTrace; - } - - if (result instanceof tr.e.tquery.TQuery) { - // TODO(skyostil): Show a cool spinner. - result.ready().then(function(selection) { - this.addLine_(selection.length + ' matches'); - this.controller_.brushingStateController. - showScriptControlSelection(selection); - }.bind(this)); - } else { - this.addLine_(result); - } - promptEl.scrollIntoView(); - }, - - addLine_: function(line) { - var historyEl = this.$.history; - if (historyEl.innerText.length !== 0) - historyEl.innerText += '\n'; - historyEl.innerText += line; - }, - - promptKeyPress: function(e) { - e.stopPropagation(); - }, - - toggleVisibility: function() { - var root = this.$.root; - if (!this.visible) { - root.classList.remove('hidden'); - this._setFocused(true); - } else { - root.classList.add('hidden'); - this._setFocused(false); - } - }, - - get hasFocus() { - return this === document.activeElement; - }, - - get visible() { - var root = this.$.root; - return !root.classList.contains('hidden'); - }, - - get controller() { - return this.controller_; - }, - - set controller(c) { - this.controller_ = c; } - }); - </script> -</polymer-element> + }, + + get hasFocus() { + return this === document.activeElement; + }, + + get visible() { + var root = this.$.root; + return !Polymer.dom(root).classList.contains('hidden'); + }, + + get controller() { + return this.controller_; + }, + + set controller(c) { + this.controller_ = c; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html index 6e96d27da06..a2e80c29966 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/file_size_stats_side_panel.html @@ -6,16 +6,16 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/statistics.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/ui/base/grouping_table.html"> <link rel="import" href="/tracing/ui/base/grouping_table_groupby_picker.html"> <link rel="import" href="/tracing/ui/base/table.html"> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> <link rel="import" href="/tracing/value/numeric.html"> <link rel="import" href="/tracing/value/ui/scalar_span.html"> -<link rel="import" href="/tracing/value/unit.html"> -<polymer-element name='tr-ui-sp-file-size-stats-side-panel' - extends='tr-ui-side-panel'> +<dom-module id='tr-ui-sp-file-size-stats-side-panel'> <template> <style> :host { @@ -49,13 +49,16 @@ found in the LICENSE file. <tr-ui-b-grouping-table id="table"></tr-ui-b-grouping-table> </table-container> </template> -</polymer-element> +</dom-module> <script> 'use strict'; (function() { - Polymer('tr-ui-sp-file-size-stats-side-panel', { + Polymer({ + is: 'tr-ui-sp-file-size-stats-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + ready: function() { this.model_ = undefined; this.selection_ = new tr.model.EventSet(); @@ -133,7 +136,7 @@ found in the LICENSE file. title: 'Title', value: function(row) { var titleEl = document.createElement('span'); - titleEl.textContent = row.title; + Polymer.dom(titleEl).textContent = row.title; titleEl.style.textOverflow = 'ellipsis'; return titleEl; }, @@ -160,7 +163,7 @@ found in the LICENSE file. title: 'Bytes', align: tr.ui.b.TableFormat.ColumnAlignment.RIGHT, value: function(row) { - var value = new tr.v.ScalarNumeric(tr.v.Unit.byName.sizeInBytes, + var value = new tr.v.ScalarNumeric(tr.b.Unit.byName.sizeInBytes, row.rowStats.totalEventSizeinBytes); var spanEl = tr.v.ui.createScalarSpan(value); return spanEl; @@ -208,5 +211,9 @@ found in the LICENSE file. this.$.table.rebuild(); } }); + + tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-sp-file-size-stats-side-panel'); + }); })(); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html index 724ca970eac..94990b467f2 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/metrics_side_panel.html @@ -6,33 +6,46 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/raf.html"> +<link rel="import" href="/tracing/metrics/metric_map_function.html"> <link rel="import" href="/tracing/metrics/metric_registry.html"> <link rel="import" href="/tracing/model/event_set.html"> +<link rel="import" href="/tracing/mre/mre_result.html"> <link rel="import" href="/tracing/ui/base/dom_helpers.html"> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> -<link rel="import" href="/tracing/value/ui/value_set_table.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> <link rel="import" href="/tracing/value/ui/value_set_view.html"> <link rel="import" href="/tracing/value/value_set.html"> -<polymer-element name='tr-ui-sp-metrics-side-panel' - extends='tr-ui-side-panel'> +<dom-module id="tr-ui-sp-metrics-side-panel"> <template> <style> :host { display: flex; flex-direction: column; } + div#error { + color: red; + } + #results { + font-size: 12px; + } </style> <top-left-controls id="top_left_controls"></top-left-controls> + <tr-v-ui-value-set-view id="results"></tr-v-ui-value-set-view> + + <div id="error"></div> </template> -</polymer-element> +</dom-module> <script> 'use strict'; tr.exportTo('tr.ui', function() { - Polymer('tr-ui-sp-metrics-side-panel', { + Polymer({ + is: 'tr-ui-sp-metrics-side-panel', + behaviors: [tr.ui.behaviors.SidePanel], + ready: function() { this.model_ = undefined; @@ -57,7 +70,7 @@ tr.exportTo('tr.ui', function() { this.settingsKey_, this.currentMetricName_, this.metrics_); - this.$.top_left_controls.appendChild(metricSelector); + Polymer.dom(this.$.top_left_controls).appendChild(metricSelector); metricSelector.addEventListener('change', this.onMetricChange_.bind(this)); this.currentMetricTypeInfo_ = @@ -66,7 +79,7 @@ tr.exportTo('tr.ui', function() { this.recomputeButton_ = tr.ui.b.createButton( 'Recompute', this.onRecompute_, this); - this.$.top_left_controls.appendChild(this.recomputeButton_); + Polymer.dom(this.$.top_left_controls).appendChild(this.recomputeButton_); }, /** @@ -155,24 +168,15 @@ tr.exportTo('tr.ui', function() { }, updateContents_: function() { - this.style.width = ''; - tr.b.requestAnimationFrame(function() { - var width = this.$.results.getBoundingClientRect().width + 15; - this.style.width = width + 'px'; - }, this); + Polymer.dom(this.$.error).textContent = ''; + this.$.results.style.display = 'none'; if (!this.model_) { - this.$.results.values = new tr.v.ValueSet([ - new tr.v.FailureValue('missing', { - description: 'Missing model', - stack: '' - }) - ]); + Polymer.dom(this.$.error).textContent = 'Missing model'; return; } - var values = new tr.v.ValueSet(); - var options = {}; + var options = {metrics: [this.currentMetricName_]}; if (this.currentMetricTypeInfo_ && this.currentMetricTypeInfo_.metadata.supportsRangeOfInterest && @@ -182,15 +186,13 @@ tr.exportTo('tr.ui', function() { var startDate = new Date(); try { - this.currentMetricTypeInfo_.constructor(values, this.model_, options); + var values = tr.metrics.runMetrics(this.model_, options); } catch (err) { - console.error(err.stack); - this.$.results.values = new tr.v.ValueSet([ - new tr.v.FailureValue('error', { - description: err.message, - stack: err.stack - }) - ]); + console.warn( + this.currentMetricName_ + + ' could not be computed for the current model:\n' + + err.stack); + Polymer.dom(this.$.error).textContent = err.message; return; } @@ -199,10 +201,16 @@ tr.exportTo('tr.ui', function() { this.metricLatenciesMs_.shift(); this.recomputeButton_.style.background = ''; + + this.$.results.style.display = ''; this.$.results.values = values; } }); + tr.ui.side_panel.SidePanelRegistry.register(function() { + return document.createElement('tr-ui-sp-metrics-side-panel'); + }); + return {}; }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html index 1fc54ed4f0e..fd39923d190 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel.html @@ -1,25 +1,18 @@ <!DOCTYPE html> <!-- -Copyright (c) 2013 The Chromium Authors. All rights reserved. +Copyright 2013 The Chromium Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <link rel="import" href="/tracing/ui/base/ui.html"> -<polymer-element name='tr-ui-side-panel'> - <template> - <style> - :host { - overflow: auto; - } - </style> - </template> - <script> - 'use strict'; - Polymer({ - ready: function() { - }, +<script> +'use strict'; + +tr.exportTo('tr.ui.behaviors', function() { + + var SidePanel = { get rangeOfInterest() { throw new Error('Not implemented'); @@ -48,6 +41,11 @@ found in the LICENSE file. supportsModel: function(m) { throw new Error('Not implemented'); } - }); - </script> -</polymer-element> + }; + + return { + SidePanel: SidePanel + }; + +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html index 0f3b5219ef6..2f2067f2e84 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_container.html @@ -6,10 +6,10 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/range.html"> -<link rel='import' href='/tracing/ui/base/polymer_utils.html'> <link rel="import" href="/tracing/ui/side_panel/side_panel.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> -<polymer-element name='tr-ui-side-panel-container' is='HTMLUnknownElement'> +<dom-module id='tr-ui-side-panel-container'> <template> <style> :host { @@ -18,12 +18,14 @@ found in the LICENSE file. background-color: white; } + :host([expanded]) > #side_panel_drag_handle, :host([expanded]) > active-panel-container { -webkit-flex: 1 1 auto; border-left: 1px solid black; display: -webkit-flex; } + :host(:not([expanded])) > #side_panel_drag_handle, :host(:not([expanded])) > active-panel-container { display: none; } @@ -64,189 +66,192 @@ found in the LICENSE file. border-left: none; padding: 14px 2px 14px 1px; } + + #active_panel_container { + overflow: auto; + } </style> + <tr-ui-b-drag-handle id="side_panel_drag_handle"></tr-ui-b-drag-handle> <active-panel-container id='active_panel_container'> - <tr-ui-b-drag-handle id="side_panel_drag_handle"></tr-ui-b-drag-handle> </active-panel-container> <tab-strip id='tab_strip'></tab-strip> </template> +</dom-module> +<script> +'use strict'; +Polymer({ + is: 'tr-ui-side-panel-container', + + ready: function() { + this.activePanelContainer_ = this.$.active_panel_container; + this.tabStrip_ = this.$.tab_strip; + + this.dragHandle_ = this.$.side_panel_drag_handle; + this.dragHandle_.horizontal = false; + this.dragHandle_.target = this.activePanelContainer_; + this.rangeOfInterest_ = new tr.b.Range(); + this.brushingStateController_ = undefined; + this.onSelectionChanged_ = this.onSelectionChanged_.bind(this); + this.onModelChanged_ = this.onModelChanged_.bind(this); + }, + + get brushingStateController() { + return this.brushingStateController_; + }, + + set brushingStateController(brushingStateController) { + if (this.brushingStateController) { + this.brushingStateController_.removeEventListener( + 'change', this.onSelectionChanged_); + this.brushingStateController_.removeEventListener( + 'model-changed', this.onModelChanged_); + } + this.brushingStateController_ = brushingStateController; + if (this.brushingStateController) { + this.brushingStateController_.addEventListener( + 'change', this.onSelectionChanged_); + this.brushingStateController_.addEventListener( + 'model-changed', this.onModelChanged_); + } + }, - <script> - 'use strict'; - Polymer({ - ready: function() { - this.activePanelContainer_ = this.$.active_panel_container; - this.tabStrip_ = this.$.tab_strip; - - this.dragHandle_ = this.$.side_panel_drag_handle; - this.dragHandle_.horizontal = false; - this.rangeOfInterest_ = new tr.b.Range(); - this.brushingStateController_ = undefined; - this.onSelectionChanged_ = this.onSelectionChanged_.bind(this); - this.onModelChanged_ = this.onModelChanged_.bind(this); - }, - - get brushingStateController() { - return this.brushingStateController_; - }, - - set brushingStateController(brushingStateController) { - if (this.brushingStateController) { - this.brushingStateController_.removeEventListener( - 'change', this.onSelectionChanged_); - this.brushingStateController_.removeEventListener( - 'model-changed', this.onModelChanged_); - } - this.brushingStateController_ = brushingStateController; - if (this.brushingStateController) { - this.brushingStateController_.addEventListener( - 'change', this.onSelectionChanged_); - this.brushingStateController_.addEventListener( - 'model-changed', this.onModelChanged_); - } - }, - - get selection() { - return this.brushingStateController_.selection; - }, + onSelectionChanged_: function() { + if (this.activePanel) + this.activePanel.selection = this.selection; + }, - onSelectionChanged_: function() { - if (this.activePanel) - this.activePanel.selection = this.selection; - }, + get model() { + return this.brushingStateController_.model; + }, - get model() { - return this.brushingStateController_.model; - }, + onModelChanged_: function() { + this.activePanelType_ = undefined; + this.updateContents_(); + }, - onModelChanged_: function() { - this.activePanelType_ = undefined; - this.updateContents_(); - }, + get expanded() { + this.hasAttribute('expanded'); + }, - get expanded() { - this.hasAttribute('expanded'); - }, + get activePanel() { + return this.activePanelContainer_.children[0]; + }, - get activePanel() { - if (this.activePanelContainer_.children.length < 2) - return undefined; - return this.activePanelContainer_.children[1]; - }, + get activePanelType() { + return this.activePanelType_; + }, - get activePanelType() { - return this.activePanelType_; - }, + set activePanelType(panelType) { + if (this.model === undefined) + throw new Error('Cannot activate panel without a model'); - set activePanelType(panelType) { - if (this.model === undefined) - throw new Error('Cannot activate panel without a model'); + var panel = undefined; + if (panelType) + panel = document.createElement(panelType); - var panel = undefined; - if (panelType) - panel = document.createElement(panelType); + if (panel !== undefined && !panel.supportsModel(this.model)) + throw new Error('Cannot activate panel: does not support this model'); - if (panel !== undefined && !panel.supportsModel(this.model)) - throw new Error('Cannot activate panel: does not support this model'); + if (this.activePanelType) { + Polymer.dom(this.getLabelElementForPanelType_( + this.activePanelType)).removeAttribute('selected'); + } - if (this.activePanelType) { - this.getLabelElementForPanelType_( - this.activePanelType).removeAttribute('selected'); - } + if (this.activePanelType) { + this.getLabelElementForPanelType_( + this.activePanelType).removeAttribute('selected'); + } - if (this.activePanel) - this.activePanelContainer_.removeChild(this.activePanel); + if (this.activePanel) + this.activePanelContainer_.removeChild(this.activePanel); - if (panelType === undefined) { - this.removeAttribute('expanded'); - this.activePanelType_ = undefined; - return; - } + if (panelType === undefined) { + Polymer.dom(this).removeAttribute('expanded'); + this.activePanelType_ = undefined; + return; + } - this.getLabelElementForPanelType_(panelType). - setAttribute('selected', true); - this.setAttribute('expanded', true); + Polymer.dom(this.getLabelElementForPanelType_(panelType)). + setAttribute('selected', true); + Polymer.dom(this).setAttribute('expanded', true); - this.activePanelContainer_.appendChild(panel); - this.dragHandle_.target = panel; - panel.rangeOfInterest = this.rangeOfInterest_; - panel.selection = this.selection_; - panel.model = this.model; + Polymer.dom(this.activePanelContainer_).appendChild(panel); + panel.rangeOfInterest = this.rangeOfInterest_; + panel.selection = this.selection_; + panel.model = this.model; - this.activePanelType_ = panelType; - }, + this.activePanelType_ = panelType; + }, - getPanelTypeForConstructor_: function(constructor) { - for (var i = 0; i < this.tabStrip_.children.length; i++) { - if (this.tabStrip_.children[i].panelType.constructor == constructor) - return this.tabStrip_.children[i].panelType; - } - }, + getPanelTypeForConstructor_: function(constructor) { + for (var i = 0; i < this.tabStrip_.children.length; i++) { + if (this.tabStrip_.children[i].panelType.constructor === constructor) + return this.tabStrip_.children[i].panelType; + } + }, - getLabelElementForPanelType_: function(panelType) { - for (var i = 0; i < this.tabStrip_.children.length; i++) { - if (this.tabStrip_.children[i].panelType == panelType) - return this.tabStrip_.children[i]; - } - return undefined; - }, - - updateContents_: function() { - var previouslyActivePanelType = this.activePanelType; - - this.tabStrip_.textContent = ''; - var supportedPanelTypes = []; - - var panelTypes = - tr.ui.b.getPolymerElementsThatSubclass('tr-ui-side-panel'); - panelTypes.forEach(function(panelType) { - var labelEl = document.createElement('tab-strip-label'); - var panel = document.createElement(panelType); - - labelEl.textContent = panel.textLabel; - labelEl.panelType = panelType; - - var supported = panel.supportsModel(this.model); - if (this.model && supported.supported) { - supportedPanelTypes.push(panelType); - labelEl.setAttribute('enabled', true); - labelEl.addEventListener('click', function() { - this.activePanelType = - this.activePanelType === panelType ? undefined : panelType; - }.bind(this)); - } else { - labelEl.title = 'Not supported for the current trace: ' + - supported.reason; - labelEl.style.display = 'none'; - } - this.tabStrip_.appendChild(labelEl); - }, this); - - // Restore the active panel, or collapse - if (previouslyActivePanelType && - supportedPanelTypes.indexOf(previouslyActivePanelType) != -1) { - this.activePanelType = previouslyActivePanelType; - this.setAttribute('expanded', true); + getLabelElementForPanelType_: function(panelType) { + for (var i = 0; i < this.tabStrip_.children.length; i++) { + if (this.tabStrip_.children[i].panelType === panelType) + return this.tabStrip_.children[i]; + } + return undefined; + }, + + updateContents_: function() { + var previouslyActivePanelType = this.activePanelType; + + Polymer.dom(this.tabStrip_).textContent = ''; + var supportedPanelTypes = []; + + for (var panelTypeInfo of + tr.ui.side_panel.SidePanelRegistry.getAllRegisteredTypeInfos()) { + var labelEl = document.createElement('tab-strip-label'); + var panel = panelTypeInfo.constructor(); + var panelType = panel.tagName; + + Polymer.dom(labelEl).textContent = panel.textLabel; + labelEl.panelType = panelType; + + var supported = panel.supportsModel(this.model); + if (this.model && supported.supported) { + supportedPanelTypes.push(panelType); + Polymer.dom(labelEl).setAttribute('enabled', true); + labelEl.addEventListener('click', function(panelType) { + this.activePanelType = + this.activePanelType === panelType ? undefined : panelType; + }.bind(this, panelType)); } else { if (this.activePanel) this.activePanelContainer_.removeChild(this.activePanel); this.removeAttribute('expanded'); } - }, - - get rangeOfInterest() { - return this.rangeOfInterest_; - }, + Polymer.dom(this.tabStrip_).appendChild(labelEl); + } - set rangeOfInterest(range) { - if (range == undefined) - throw new Error('Must not be undefined'); - this.rangeOfInterest_ = range; + // Restore the active panel, or collapse + if (previouslyActivePanelType && + supportedPanelTypes.indexOf(previouslyActivePanelType) !== -1) { + this.activePanelType = previouslyActivePanelType; + Polymer.dom(this).setAttribute('expanded', true); + } else { if (this.activePanel) - this.activePanel.rangeOfInterest = range; + Polymer.dom(this.activePanelContainer_).removeChild(this.activePanel); + Polymer.dom(this).removeAttribute('expanded'); } - }); - </script> -</polymer-element> - + }, + + get rangeOfInterest() { + return this.rangeOfInterest_; + }, + + set rangeOfInterest(range) { + if (range === undefined) + throw new Error('Must not be undefined'); + this.rangeOfInterest_ = range; + if (this.activePanel) + this.activePanel.rangeOfInterest = range; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html new file mode 100644 index 00000000000..ef86dbe06dd --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry.html @@ -0,0 +1,39 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<link rel="import" href="/tracing/base/extension_registry.html"> + +<script> +'use strict'; + +// TODO(charliea): This can probably be cleaned up so that we don't have to +// manually wrap the Polymer element names with a function and +// `document.createElement` at each of the registration sites by creating a +// new "Polymer" registration mode. +tr.exportTo('tr.ui.side_panel', function() { + /** + * SidePanelRegistry is an entity for side panel Polymer elements to register + * on so that they'll render a side panel if the model has the correct data. + * + * Example usage: + * + * SidePanelRegistry.register(function() { + * return document.createElement('my-side-panel'); + * }); + * + * @constructor + */ + function SidePanelRegistry() {} + + var options = new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE); + tr.b.decorateExtensionRegistry(SidePanelRegistry, options); + + return { + SidePanelRegistry: SidePanelRegistry + }; +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html new file mode 100644 index 00000000000..9e91ce0494f --- /dev/null +++ b/chromium/third_party/catapult/tracing/tracing/ui/side_panel/side_panel_registry_test.html @@ -0,0 +1,40 @@ +<!DOCTYPE html> +<!-- +Copyright 2016 The Chromium Authors. All rights reserved. +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<link rel="import" href="/tracing/core/test_utils.html"> +<link rel="import" href="/tracing/ui/side_panel/side_panel_registry.html"> + +<script> +'use strict'; + +tr.b.unittest.testSuite(function() { + var SidePanelRegistry = tr.ui.side_panel.SidePanelRegistry; + + var testOptions = { + setUp: function() { + SidePanelRegistry.pushCleanStateBeforeTest(); + }, + + tearDown: function() { + SidePanelRegistry.popCleanStateAfterTest(); + }, + }; + + test('register', function() { + SidePanelRegistry.register(function() { + return document.createElement('div'); + }); + SidePanelRegistry.register(function() { + return document.createElement('span'); + }); + + var typeInfos = SidePanelRegistry.getAllRegisteredTypeInfos(); + assert.equal(typeInfos[0].constructor().tagName, 'DIV'); + assert.equal(typeInfos[1].constructor().tagName, 'SPAN'); + assert.lengthOf(typeInfos, 2); + }, testOptions); +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html index 49c10e29123..bc1bc4cc12c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform.html @@ -57,7 +57,7 @@ tr.exportTo('tr.ui', function() { }, xPanWorldPosToViewPos: function(worldX, viewX, viewWidth) { - if (typeof viewX == 'string') { + if (typeof viewX === 'string') { if (viewX === 'left') { viewX = 0; } else if (viewX === 'center') { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html index 7122d9ba51c..a1f5ecff9b1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_display_transform_animations.html @@ -130,7 +130,7 @@ tr.exportTo('tr.ui', function() { __proto__: tr.ui.b.Animation.prototype, get affectsPanY() { - return this.startPanY != this.goalFocalPointY; + return this.startPanY !== this.goalFocalPointY; }, canTakeOverFor: function(existingAnimation) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html index 240104d6322..b28d7af8c0e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_interest_range.html @@ -95,7 +95,7 @@ tr.exportTo('tr.ui', function() { }, set leftSelected(leftSelected) { - if (this.leftSelected_ == leftSelected) + if (this.leftSelected_ === leftSelected) return; this.leftSelected_ = leftSelected; this.viewport_.dispatchChangeEvent(); @@ -106,7 +106,7 @@ tr.exportTo('tr.ui', function() { }, set rightSelected(rightSelected) { - if (this.rightSelected_ == rightSelected) + if (this.rightSelected_ === rightSelected) return; this.rightSelected_ = rightSelected; this.viewport_.dispatchChangeEvent(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html index 36454ffb9e3..c4c84bc9a2f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view.html @@ -9,6 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/base/settings.html"> <link rel="import" href="/tracing/base/task.html"> +<link rel="import" href="/tracing/base/unit.html"> <link rel="import" href="/tracing/core/filter.html"> <link rel="import" href="/tracing/model/event.html"> <link rel="import" href="/tracing/model/event_set.html"> @@ -22,7 +23,6 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/tracks/drawing_container.html"> <link rel="import" href="/tracing/ui/tracks/model_track.html"> <link rel="import" href="/tracing/ui/tracks/ruler_track.html"> -<link rel="import" href="/tracing/value/unit.html"> <!-- Interactive visualizaiton of Model objects based loosely on gantt charts. @@ -36,7 +36,7 @@ found in the LICENSE file. BBBB BB Thread2: CCCCCC CCCCC --> -<polymer-element name='tr-ui-timeline-track-view'> +<dom-module id='tr-ui-timeline-track-view'> <template> <style> :host { @@ -72,1079 +72,1080 @@ found in the LICENSE file. <tv-ui-b-hotkey-controller id='hotkey_controller'> </tv-ui-b-hotkey-controller> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-timeline-track-view', - Polymer({ - ready: function() { - this.displayTransform_ = new tr.ui.TimelineDisplayTransform(); - this.model_ = undefined; + ready: function() { + this.displayTransform_ = new tr.ui.TimelineDisplayTransform(); + this.model_ = undefined; - this.timelineView_ = undefined; + this.timelineView_ = undefined; - this.viewport_ = new tr.ui.TimelineViewport(this); - this.viewportDisplayTransformAtMouseDown_ = undefined; - this.brushingStateController_ = undefined; + this.viewport_ = new tr.ui.TimelineViewport(this); + this.viewportDisplayTransformAtMouseDown_ = undefined; + this.brushingStateController_ = undefined; - this.rulerTrackContainer_ = - new tr.ui.tracks.DrawingContainer(this.viewport_); - this.appendChild(this.rulerTrackContainer_); - this.rulerTrackContainer_.invalidate(); + this.rulerTrackContainer_ = + new tr.ui.tracks.DrawingContainer(this.viewport_); + Polymer.dom(this).appendChild(this.rulerTrackContainer_); + this.rulerTrackContainer_.invalidate(); - this.rulerTrack_ = new tr.ui.tracks.RulerTrack(this.viewport_); - this.rulerTrackContainer_.appendChild(this.rulerTrack_); + this.rulerTrack_ = new tr.ui.tracks.RulerTrack(this.viewport_); + Polymer.dom(this.rulerTrackContainer_).appendChild(this.rulerTrack_); - this.upperModelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_); - this.upperModelTrack_.upperMode = true; - this.rulerTrackContainer_.appendChild(this.upperModelTrack_); + this.upperModelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_); + this.upperModelTrack_.upperMode = true; + Polymer.dom(this.rulerTrackContainer_).appendChild(this.upperModelTrack_); - this.modelTrackContainer_ = - new tr.ui.tracks.DrawingContainer(this.viewport_); - this.appendChild(this.modelTrackContainer_); - this.modelTrackContainer_.style.display = 'block'; - this.modelTrackContainer_.invalidate(); + this.modelTrackContainer_ = + new tr.ui.tracks.DrawingContainer(this.viewport_); + Polymer.dom(this).appendChild(this.modelTrackContainer_); + this.modelTrackContainer_.style.display = 'block'; + this.modelTrackContainer_.invalidate(); - this.viewport_.modelTrackContainer = this.modelTrackContainer_; + this.viewport_.modelTrackContainer = this.modelTrackContainer_; - this.modelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_); - this.modelTrackContainer_.appendChild(this.modelTrack_); + this.modelTrack_ = new tr.ui.tracks.ModelTrack(this.viewport_); + Polymer.dom(this.modelTrackContainer_).appendChild(this.modelTrack_); - this.timingTool_ = new tr.ui.b.TimingTool(this.viewport_, this); + this.timingTool_ = new tr.ui.b.TimingTool(this.viewport_, this); - this.initMouseModeSelector(); + this.initMouseModeSelector(); - this.hideDragBox_(); + this.hideDragBox_(); - this.initHintText_(); + this.initHintText_(); - this.onSelectionChanged_ = this.onSelectionChanged_.bind(this); + this.onSelectionChanged_ = this.onSelectionChanged_.bind(this); - this.onDblClick_ = this.onDblClick_.bind(this); - this.addEventListener('dblclick', this.onDblClick_); + this.onDblClick_ = this.onDblClick_.bind(this); + this.addEventListener('dblclick', this.onDblClick_); - this.onMouseWheel_ = this.onMouseWheel_.bind(this); - this.addEventListener('mousewheel', this.onMouseWheel_); + this.onMouseWheel_ = this.onMouseWheel_.bind(this); + this.addEventListener('mousewheel', this.onMouseWheel_); - this.onMouseDown_ = this.onMouseDown_.bind(this); - this.addEventListener('mousedown', this.onMouseDown_); + this.onMouseDown_ = this.onMouseDown_.bind(this); + this.addEventListener('mousedown', this.onMouseDown_); - this.onMouseMove_ = this.onMouseMove_.bind(this); - this.addEventListener('mousemove', this.onMouseMove_); + this.onMouseMove_ = this.onMouseMove_.bind(this); + this.addEventListener('mousemove', this.onMouseMove_); - this.onTouchStart_ = this.onTouchStart_.bind(this); - this.addEventListener('touchstart', this.onTouchStart_); + this.onTouchStart_ = this.onTouchStart_.bind(this); + this.addEventListener('touchstart', this.onTouchStart_); - this.onTouchMove_ = this.onTouchMove_.bind(this); - this.addEventListener('touchmove', this.onTouchMove_); + this.onTouchMove_ = this.onTouchMove_.bind(this); + this.addEventListener('touchmove', this.onTouchMove_); - this.onTouchEnd_ = this.onTouchEnd_.bind(this); - this.addEventListener('touchend', this.onTouchEnd_); + this.onTouchEnd_ = this.onTouchEnd_.bind(this); + this.addEventListener('touchend', this.onTouchEnd_); - this.addHotKeys_(); + this.addHotKeys_(); - this.mouseViewPosAtMouseDown_ = {x: 0, y: 0}; - this.lastMouseViewPos_ = {x: 0, y: 0}; + this.mouseViewPosAtMouseDown_ = {x: 0, y: 0}; + this.lastMouseViewPos_ = {x: 0, y: 0}; - this.lastTouchViewPositions_ = []; + this.lastTouchViewPositions_ = []; - this.alert_ = undefined; + this.alert_ = undefined; - this.isPanningAndScanning_ = false; - this.isZooming_ = false; - }, + this.isPanningAndScanning_ = false; + this.isZooming_ = false; + }, - initMouseModeSelector: function() { - this.mouseModeSelector_ = document.createElement( - 'tr-ui-b-mouse-mode-selector'); - this.mouseModeSelector_.targetElement = this; - this.appendChild(this.mouseModeSelector_); + initMouseModeSelector: function() { + this.mouseModeSelector_ = document.createElement( + 'tr-ui-b-mouse-mode-selector'); + this.mouseModeSelector_.targetElement = this; + Polymer.dom(this).appendChild(this.mouseModeSelector_); - this.mouseModeSelector_.addEventListener('beginpan', - this.onBeginPanScan_.bind(this)); - this.mouseModeSelector_.addEventListener('updatepan', - this.onUpdatePanScan_.bind(this)); - this.mouseModeSelector_.addEventListener('endpan', - this.onEndPanScan_.bind(this)); + this.mouseModeSelector_.addEventListener('beginpan', + this.onBeginPanScan_.bind(this)); + this.mouseModeSelector_.addEventListener('updatepan', + this.onUpdatePanScan_.bind(this)); + this.mouseModeSelector_.addEventListener('endpan', + this.onEndPanScan_.bind(this)); - this.mouseModeSelector_.addEventListener('beginselection', - this.onBeginSelection_.bind(this)); - this.mouseModeSelector_.addEventListener('updateselection', - this.onUpdateSelection_.bind(this)); - this.mouseModeSelector_.addEventListener('endselection', - this.onEndSelection_.bind(this)); + this.mouseModeSelector_.addEventListener('beginselection', + this.onBeginSelection_.bind(this)); + this.mouseModeSelector_.addEventListener('updateselection', + this.onUpdateSelection_.bind(this)); + this.mouseModeSelector_.addEventListener('endselection', + this.onEndSelection_.bind(this)); - this.mouseModeSelector_.addEventListener('beginzoom', - this.onBeginZoom_.bind(this)); - this.mouseModeSelector_.addEventListener('updatezoom', - this.onUpdateZoom_.bind(this)); - this.mouseModeSelector_.addEventListener('endzoom', - this.onEndZoom_.bind(this)); + this.mouseModeSelector_.addEventListener('beginzoom', + this.onBeginZoom_.bind(this)); + this.mouseModeSelector_.addEventListener('updatezoom', + this.onUpdateZoom_.bind(this)); + this.mouseModeSelector_.addEventListener('endzoom', + this.onEndZoom_.bind(this)); - this.mouseModeSelector_.addEventListener('entertiming', - this.timingTool_.onEnterTiming.bind(this.timingTool_)); - this.mouseModeSelector_.addEventListener('begintiming', - this.timingTool_.onBeginTiming.bind(this.timingTool_)); - this.mouseModeSelector_.addEventListener('updatetiming', - this.timingTool_.onUpdateTiming.bind(this.timingTool_)); - this.mouseModeSelector_.addEventListener('endtiming', - this.timingTool_.onEndTiming.bind(this.timingTool_)); - this.mouseModeSelector_.addEventListener('exittiming', - this.timingTool_.onExitTiming.bind(this.timingTool_)); + this.mouseModeSelector_.addEventListener('entertiming', + this.timingTool_.onEnterTiming.bind(this.timingTool_)); + this.mouseModeSelector_.addEventListener('begintiming', + this.timingTool_.onBeginTiming.bind(this.timingTool_)); + this.mouseModeSelector_.addEventListener('updatetiming', + this.timingTool_.onUpdateTiming.bind(this.timingTool_)); + this.mouseModeSelector_.addEventListener('endtiming', + this.timingTool_.onEndTiming.bind(this.timingTool_)); + this.mouseModeSelector_.addEventListener('exittiming', + this.timingTool_.onExitTiming.bind(this.timingTool_)); - var m = tr.ui.b.MOUSE_SELECTOR_MODE; - this.mouseModeSelector_.supportedModeMask = - m.SELECTION | m.PANSCAN | m.ZOOM | m.TIMING; - this.mouseModeSelector_.settingsKey = - 'timelineTrackView.mouseModeSelector'; - this.mouseModeSelector_.setKeyCodeForMode(m.PANSCAN, '2'.charCodeAt(0)); - this.mouseModeSelector_.setKeyCodeForMode(m.SELECTION, '1'.charCodeAt(0)); - this.mouseModeSelector_.setKeyCodeForMode(m.ZOOM, '3'.charCodeAt(0)); - this.mouseModeSelector_.setKeyCodeForMode(m.TIMING, '4'.charCodeAt(0)); + var m = tr.ui.b.MOUSE_SELECTOR_MODE; + this.mouseModeSelector_.supportedModeMask = + m.SELECTION | m.PANSCAN | m.ZOOM | m.TIMING; + this.mouseModeSelector_.settingsKey = + 'timelineTrackView.mouseModeSelector'; + this.mouseModeSelector_.setKeyCodeForMode(m.PANSCAN, '2'.charCodeAt(0)); + this.mouseModeSelector_.setKeyCodeForMode(m.SELECTION, '1'.charCodeAt(0)); + this.mouseModeSelector_.setKeyCodeForMode(m.ZOOM, '3'.charCodeAt(0)); + this.mouseModeSelector_.setKeyCodeForMode(m.TIMING, '4'.charCodeAt(0)); - this.mouseModeSelector_.setModifierForAlternateMode( - m.SELECTION, tr.ui.b.MODIFIER.SHIFT); - this.mouseModeSelector_.setModifierForAlternateMode( - m.PANSCAN, tr.ui.b.MODIFIER.SPACE); - }, + this.mouseModeSelector_.setModifierForAlternateMode( + m.SELECTION, tr.ui.b.MODIFIER.SHIFT); + this.mouseModeSelector_.setModifierForAlternateMode( + m.PANSCAN, tr.ui.b.MODIFIER.SPACE); + }, - get brushingStateController() { - return this.brushingStateController_; - }, - - set brushingStateController(brushingStateController) { - if (this.brushingStateController_) { - this.brushingStateController_.removeEventListener('change', - this.onSelectionChanged_); - } - this.brushingStateController_ = brushingStateController; - if (this.brushingStateController_) { - this.brushingStateController_.addEventListener('change', - this.onSelectionChanged_); - } - }, - - set timelineView(view) { - this.timelineView_ = view; - }, - - onSelectionChanged_: function() { - this.showHintText_('Press \'m\' to mark current selection'); - this.viewport_.dispatchChangeEvent(); - }, - - set selection(selection) { - throw new Error('DO NOT CALL THIS'); - }, - - set highlight(highlight) { - throw new Error('DO NOT CALL THIS'); - }, - - detach: function() { - this.modelTrack_.detach(); - this.upperModelTrack_.detach(); - - this.viewport_.detach(); - }, - - get viewport() { - return this.viewport_; - }, - - get model() { - return this.model_; - }, - - set model(model) { - if (!model) - throw new Error('Model cannot be undefined'); - - var modelInstanceChanged = this.model_ !== model; - this.model_ = model; - this.modelTrack_.model = model; - this.upperModelTrack_.model = model; - - // Set up a reasonable viewport. - if (modelInstanceChanged) - this.viewport_.setWhenPossible(this.setInitialViewport_.bind(this)); - }, - - get hasVisibleContent() { - return this.modelTrack_.hasVisibleContent || - this.upperModelTrack_.hasVisibleContent; - }, - - setInitialViewport_: function() { - // We need the canvas size to be up-to-date at this point. We maybe in - // here before the raf fires, so the size may have not been updated since - // the canvas was resized. - this.modelTrackContainer_.updateCanvasSizeIfNeeded_(); - var w = this.modelTrackContainer_.canvas.width; - - var min; - var range; - - if (this.model_.bounds.isEmpty) { - min = 0; - range = 1000; - } else if (this.model_.bounds.range === 0) { - min = this.model_.bounds.min; - range = 1000; - } else { - min = this.model_.bounds.min; - range = this.model_.bounds.range; - } - - var boost = range * 0.15; - this.displayTransform_.set(this.viewport_.currentDisplayTransform); - this.displayTransform_.xSetWorldBounds( - min - boost, min + range + boost, w); - this.viewport_.setDisplayTransformImmediately(this.displayTransform_); - }, - - /** - * @param {Filter} filter The filter to use for finding matches. - * @param {Selection} selection The selection to add matches to. - * @return {Task} which performs the filtering. - */ - addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) { - var modelTrack = this.modelTrack_; - var firstT = modelTrack.addAllEventsMatchingFilterToSelectionAsTask( - filter, selection); - var lastT = firstT.after(function() { - this.upperModelTrack_.addAllEventsMatchingFilterToSelection( - filter, selection); - - }, this); - return firstT; - }, - - onMouseMove_: function(e) { - // Zooming requires the delta since the last mousemove so we need to avoid - // tracking it when the zoom interaction is active. - if (this.isZooming_) - return; - - this.storeLastMousePos_(e); - }, - - onTouchStart_: function(e) { - this.storeLastTouchPositions_(e); - this.focusElements_(); - }, - - onTouchMove_: function(e) { - e.preventDefault(); - this.onUpdateTransformForTouch_(e); - }, - - onTouchEnd_: function(e) { - this.storeLastTouchPositions_(e); - this.focusElements_(); - }, - - addHotKeys_: function() { - this.addKeyDownHotKeys_(); - this.addKeyPressHotKeys_(); - }, - - addKeyPressHotKeys_: function() { - var addBinding = function(dict) { - dict.eventType = 'keypress'; - dict.useCapture = false; - dict.thisArg = this; - var binding = new tr.ui.b.HotKey(dict); - this.$.hotkey_controller.addHotKey(binding); - }.bind(this); - - addBinding({ - keyCodes: ['w'.charCodeAt(0), ','.charCodeAt(0)], - callback: function(e) { - this.zoomBy_(1.5, true); - e.stopPropagation(); - } - }); - - addBinding({ - keyCodes: ['s'.charCodeAt(0), 'o'.charCodeAt(0)], - callback: function(e) { - this.zoomBy_(1 / 1.5, true); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'g'.charCodeAt(0), - callback: function(e) { - this.onGridToggle_(true); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'G'.charCodeAt(0), - callback: function(e) { - this.onGridToggle_(false); - e.stopPropagation(); - } - }); - - addBinding({ - keyCodes: ['W'.charCodeAt(0), '<'.charCodeAt(0)], - callback: function(e) { - this.zoomBy_(10, true); - e.stopPropagation(); - } - }); - - addBinding({ - keyCodes: ['S'.charCodeAt(0), 'O'.charCodeAt(0)], - callback: function(e) { - this.zoomBy_(1 / 10, true); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'a'.charCodeAt(0), - callback: function(e) { - this.queueSmoothPan_(this.viewWidth_ * 0.3, 0); - e.stopPropagation(); - } - }); - - addBinding({ - keyCodes: ['d'.charCodeAt(0), 'e'.charCodeAt(0)], - callback: function(e) { - this.queueSmoothPan_(this.viewWidth_ * -0.3, 0); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'A'.charCodeAt(0), - callback: function(e) { - this.queueSmoothPan_(viewWidth * 0.5, 0); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'D'.charCodeAt(0), - callback: function(e) { - this.queueSmoothPan_(viewWidth * -0.5, 0); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: '0'.charCodeAt(0), - callback: function(e) { - this.setInitialViewport_(); - e.stopPropagation(); - } - }); - - addBinding({ - keyCode: 'f'.charCodeAt(0), - callback: function(e) { - this.zoomToSelection(); - e.stopPropagation(); - } - }); + get brushingStateController() { + return this.brushingStateController_; + }, + + set brushingStateController(brushingStateController) { + if (this.brushingStateController_) { + this.brushingStateController_.removeEventListener('change', + this.onSelectionChanged_); + } + this.brushingStateController_ = brushingStateController; + if (this.brushingStateController_) { + this.brushingStateController_.addEventListener('change', + this.onSelectionChanged_); + } + }, + + set timelineView(view) { + this.timelineView_ = view; + }, + + onSelectionChanged_: function() { + this.showHintText_('Press \'m\' to mark current selection'); + this.viewport_.dispatchChangeEvent(); + }, + + set selection(selection) { + throw new Error('DO NOT CALL THIS'); + }, + + set highlight(highlight) { + throw new Error('DO NOT CALL THIS'); + }, + + detach: function() { + this.modelTrack_.detach(); + this.upperModelTrack_.detach(); + + this.viewport_.detach(); + }, + + get viewport() { + return this.viewport_; + }, + + get model() { + return this.model_; + }, + + set model(model) { + if (!model) + throw new Error('Model cannot be undefined'); + + var modelInstanceChanged = this.model_ !== model; + this.model_ = model; + this.modelTrack_.model = model; + this.upperModelTrack_.model = model; + + // Set up a reasonable viewport. + if (modelInstanceChanged) + this.viewport_.setWhenPossible(this.setInitialViewport_.bind(this)); + }, + + get hasVisibleContent() { + return this.modelTrack_.hasVisibleContent || + this.upperModelTrack_.hasVisibleContent; + }, + + setInitialViewport_: function() { + // We need the canvas size to be up-to-date at this point. We maybe in + // here before the raf fires, so the size may have not been updated since + // the canvas was resized. + this.modelTrackContainer_.updateCanvasSizeIfNeeded_(); + var w = this.modelTrackContainer_.canvas.width; + + var min; + var range; + + if (this.model_.bounds.isEmpty) { + min = 0; + range = 1000; + } else if (this.model_.bounds.range === 0) { + min = this.model_.bounds.min; + range = 1000; + } else { + min = this.model_.bounds.min; + range = this.model_.bounds.range; + } - addBinding({ - keyCode: 'm'.charCodeAt(0), - callback: function(e) { - this.setCurrentSelectionAsInterestRange_(); - e.stopPropagation(); - } - }); + var boost = range * 0.15; + this.displayTransform_.set(this.viewport_.currentDisplayTransform); + this.displayTransform_.xSetWorldBounds( + min - boost, min + range + boost, w); + this.viewport_.setDisplayTransformImmediately(this.displayTransform_); + }, + + /** + * @param {Filter} filter The filter to use for finding matches. + * @param {Selection} selection The selection to add matches to. + * @return {Task} which performs the filtering. + */ + addAllEventsMatchingFilterToSelectionAsTask: function(filter, selection) { + var modelTrack = this.modelTrack_; + var firstT = modelTrack.addAllEventsMatchingFilterToSelectionAsTask( + filter, selection); + var lastT = firstT.after(function() { + this.upperModelTrack_.addAllEventsMatchingFilterToSelection( + filter, selection); + + }, this); + return firstT; + }, + + onMouseMove_: function(e) { + // Zooming requires the delta since the last mousemove so we need to avoid + // tracking it when the zoom interaction is active. + if (this.isZooming_) + return; + + this.storeLastMousePos_(e); + }, + + onTouchStart_: function(e) { + this.storeLastTouchPositions_(e); + this.focusElements_(); + }, + + onTouchMove_: function(e) { + e.preventDefault(); + this.onUpdateTransformForTouch_(e); + }, + + onTouchEnd_: function(e) { + this.storeLastTouchPositions_(e); + this.focusElements_(); + }, + + addHotKeys_: function() { + this.addKeyDownHotKeys_(); + this.addKeyPressHotKeys_(); + }, + + addKeyPressHotKeys_: function() { + var addBinding = function(dict) { + dict.eventType = 'keypress'; + dict.useCapture = false; + dict.thisArg = this; + var binding = new tr.ui.b.HotKey(dict); + this.$.hotkey_controller.addHotKey(binding); + }.bind(this); + + addBinding({ + keyCodes: ['w'.charCodeAt(0), ','.charCodeAt(0)], + callback: function(e) { + this.zoomBy_(1.5, true); + e.stopPropagation(); + } + }); - addBinding({ - keyCode: 'p'.charCodeAt(0), - callback: function(e) { - this.selectPowerSamplesInCurrentTimeRange_(); - e.stopPropagation(); - } - }); + addBinding({ + keyCodes: ['s'.charCodeAt(0), 'o'.charCodeAt(0)], + callback: function(e) { + this.zoomBy_(1 / 1.5, true); + e.stopPropagation(); + } + }); - addBinding({ - keyCode: 'h'.charCodeAt(0), - callback: function(e) { - this.toggleHighDetails_(); - e.stopPropagation(); - } - }); - }, - - get viewWidth_() { - return this.modelTrackContainer_.canvas.clientWidth; - }, - - addKeyDownHotKeys_: function() { - var addBinding = function(dict) { - dict.eventType = 'keydown'; - dict.useCapture = false; - dict.thisArg = this; - var binding = new tr.ui.b.HotKey(dict); - this.$.hotkey_controller.addHotKey(binding); - }.bind(this); - - addBinding({ - keyCode: 37, // Left arrow. - callback: function(e) { - var curSel = this.brushingStateController_.selection; - var sel = this.viewport.getShiftedSelection(curSel, -1); - - if (sel) { - this.brushingStateController.changeSelectionFromTimeline(sel); - this.panToSelection(); - } else { - this.queueSmoothPan_(this.viewWidth_ * 0.3, 0); - } - e.preventDefault(); - e.stopPropagation(); - } - }); + addBinding({ + keyCode: 'g'.charCodeAt(0), + callback: function(e) { + this.onGridToggle_(true); + e.stopPropagation(); + } + }); - addBinding({ - keyCode: 39, // Right arrow. - callback: function(e) { - var curSel = this.brushingStateController_.selection; - var sel = this.viewport.getShiftedSelection(curSel, 1); - if (sel) { - this.brushingStateController.changeSelectionFromTimeline(sel); - this.panToSelection(); - } else { - this.queueSmoothPan_(-this.viewWidth_ * 0.3, 0); - } - e.preventDefault(); - e.stopPropagation(); - } - }); - }, + addBinding({ + keyCode: 'G'.charCodeAt(0), + callback: function(e) { + this.onGridToggle_(false); + e.stopPropagation(); + } + }); - onDblClick_: function(e) { - if (this.mouseModeSelector_.mode !== - tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION) - return; + addBinding({ + keyCodes: ['W'.charCodeAt(0), '<'.charCodeAt(0)], + callback: function(e) { + this.zoomBy_(10, true); + e.stopPropagation(); + } + }); - var curSelection = this.brushingStateController_.selection; - if (!curSelection.length || !tr.b.getOnlyElement(curSelection).title) - return; + addBinding({ + keyCodes: ['S'.charCodeAt(0), 'O'.charCodeAt(0)], + callback: function(e) { + this.zoomBy_(1 / 10, true); + e.stopPropagation(); + } + }); - var selection = new tr.model.EventSet(); - var filter = new tr.c.ExactTitleFilter( - tr.b.getOnlyElement(curSelection).title); - this.modelTrack_.addAllEventsMatchingFilterToSelection(filter, - selection); + addBinding({ + keyCode: 'a'.charCodeAt(0), + callback: function(e) { + this.queueSmoothPan_(this.viewWidth_ * 0.3, 0); + e.stopPropagation(); + } + }); - this.brushingStateController.changeSelectionFromTimeline(selection); - }, + addBinding({ + keyCodes: ['d'.charCodeAt(0), 'e'.charCodeAt(0)], + callback: function(e) { + this.queueSmoothPan_(this.viewWidth_ * -0.3, 0); + e.stopPropagation(); + } + }); - onMouseWheel_: function(e) { - if (!e.altKey) - return; + addBinding({ + keyCode: 'A'.charCodeAt(0), + callback: function(e) { + this.queueSmoothPan_(viewWidth * 0.5, 0); + e.stopPropagation(); + } + }); - var delta = e.wheelDelta / 120; - var zoomScale = Math.pow(1.5, delta); - this.zoomBy_(zoomScale); - e.preventDefault(); - }, + addBinding({ + keyCode: 'D'.charCodeAt(0), + callback: function(e) { + this.queueSmoothPan_(viewWidth * -0.5, 0); + e.stopPropagation(); + } + }); - onMouseDown_: function(e) { - if (this.mouseModeSelector_.mode !== - tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION) - return; + addBinding({ + keyCode: '0'.charCodeAt(0), + callback: function(e) { + this.setInitialViewport_(); + e.stopPropagation(); + } + }); - // Mouse down must start on ruler track for crosshair guide lines to draw. - if (e.target !== this.rulerTrack_) - return; + addBinding({ + keyCode: 'f'.charCodeAt(0), + callback: function(e) { + this.zoomToSelection(); + e.stopPropagation(); + } + }); - // Make sure we don't start a selection drag event here. - this.dragBeginEvent_ = undefined; + addBinding({ + keyCode: 'm'.charCodeAt(0), + callback: function(e) { + this.setCurrentSelectionAsInterestRange_(); + e.stopPropagation(); + } + }); - // Remove nav string marker if it exists, since we're clearing the - // find control box. - if (this.xNavStringMarker_) { - this.model.removeAnnotation(this.xNavStringMarker_); - this.xNavStringMarker_ = undefined; + addBinding({ + keyCode: 'p'.charCodeAt(0), + callback: function(e) { + this.selectPowerSamplesInCurrentTimeRange_(); + e.stopPropagation(); } + }); - var dt = this.viewport_.currentDisplayTransform; - tr.ui.b.trackMouseMovesUntilMouseUp(function(e) { // Mouse move handler. - // If mouse event is on ruler, don't do anything. - if (e.target === this.rulerTrack_) - return; - - var relativePosition = this.extractRelativeMousePosition_(e); - var loc = tr.model.Location.fromViewCoordinates( - this.viewport_, relativePosition.x, relativePosition.y); - // Not all points on the timeline represents a valid location. - // ex. process header tracks, letter dot tracks. - if (!loc) - return; - - if (this.guideLineAnnotation_ === undefined) { - this.guideLineAnnotation_ = - new tr.model.XMarkerAnnotation(loc.xWorld); - this.model.addAnnotation(this.guideLineAnnotation_); + addBinding({ + keyCode: 'h'.charCodeAt(0), + callback: function(e) { + this.toggleHighDetails_(); + e.stopPropagation(); + } + }); + }, + + get viewWidth_() { + return this.modelTrackContainer_.canvas.clientWidth; + }, + + addKeyDownHotKeys_: function() { + var addBinding = function(dict) { + dict.eventType = 'keydown'; + dict.useCapture = false; + dict.thisArg = this; + var binding = new tr.ui.b.HotKey(dict); + this.$.hotkey_controller.addHotKey(binding); + }.bind(this); + + addBinding({ + keyCode: 37, // Left arrow. + callback: function(e) { + var curSel = this.brushingStateController_.selection; + var sel = this.viewport.getShiftedSelection(curSel, -1); + + if (sel) { + this.brushingStateController.changeSelectionFromTimeline(sel); + this.panToSelection(); } else { - this.guideLineAnnotation_.timestamp = loc.xWorld; - this.modelTrackContainer_.invalidate(); - } - - // Set the findcontrol's text to nav string of current state. - var state = new tr.ui.b.UIState(loc, - this.viewport_.currentDisplayTransform.scaleX); - this.timelineView_.setFindCtlText( - state.toUserFriendlyString(this.viewport_)); - }.bind(this), - undefined, // Mouse up handler. - function onKeyUpDuringDrag() { - if (this.dragBeginEvent_) { - this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_, - this.dragBoxXEnd_, this.dragBoxYEnd_); + this.queueSmoothPan_(this.viewWidth_ * 0.3, 0); } - }.bind(this)); - }, - - queueSmoothPan_: function(viewDeltaX, deltaY) { - var deltaX = this.viewport_.currentDisplayTransform.xViewVectorToWorld( - viewDeltaX); - var animation = new tr.ui.TimelineDisplayTransformPanAnimation( - deltaX, deltaY); - this.viewport_.queueDisplayTransformAnimation(animation); - }, - - /** - * Zoom in or out on the timeline by the given scale factor. - * @param {Number} scale The scale factor to apply. If <1, zooms out. - * @param {boolean} Whether to change the zoom level smoothly. - */ - zoomBy_: function(scale, smooth) { - if (scale <= 0) { - return; - } - - smooth = !!smooth; - var vp = this.viewport_; - var pixelRatio = window.devicePixelRatio || 1; - - var goalFocalPointXView = this.lastMouseViewPos_.x * pixelRatio; - var goalFocalPointXWorld = vp.currentDisplayTransform.xViewToWorld( - goalFocalPointXView); - if (smooth) { - var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( - goalFocalPointXWorld, goalFocalPointXView, - vp.currentDisplayTransform.panY, - scale); - vp.queueDisplayTransformAnimation(animation); - } else { - this.displayTransform_.set(vp.currentDisplayTransform); - this.displayTransform_.scaleX *= scale; - this.displayTransform_.xPanWorldPosToViewPos( - goalFocalPointXWorld, goalFocalPointXView, this.viewWidth_); - vp.setDisplayTransformImmediately(this.displayTransform_); + e.preventDefault(); + e.stopPropagation(); } - }, - - /** - * Zoom into the current selection. - */ - zoomToSelection: function() { - if (!this.brushingStateController.selectionOfInterest.length) - return; - - var bounds = this.brushingStateController.selectionOfInterest.bounds; - if (!bounds.range) - return; - - var worldCenter = bounds.center; - var viewCenter = this.modelTrackContainer_.canvas.width / 2; - var adjustedWorldRange = bounds.range * 1.25; - var newScale = this.modelTrackContainer_.canvas.width / - adjustedWorldRange; - var zoomInRatio = newScale / - this.viewport_.currentDisplayTransform.scaleX; - - var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( - worldCenter, viewCenter, - this.viewport_.currentDisplayTransform.panY, - zoomInRatio); - this.viewport_.queueDisplayTransformAnimation(animation); - }, - - /** - * Pan the view so the current selection becomes visible. - */ - panToSelection: function() { - if (!this.brushingStateController.selectionOfInterest.length) - return; - - var bounds = this.brushingStateController.selectionOfInterest.bounds; - var worldCenter = bounds.center; - var viewWidth = this.viewWidth_; - - var dt = this.viewport_.currentDisplayTransform; - if (false && !bounds.range) { - if (dt.xWorldToView(bounds.center) < 0 || - dt.xWorldToView(bounds.center) > viewWidth) { - this.displayTransform_.set(dt); - this.displayTransform_.xPanWorldPosToViewPos( - worldCenter, 'center', viewWidth); - var deltaX = this.displayTransform_.panX - dt.panX; - var animation = new tr.ui.TimelineDisplayTransformPanAnimation( - deltaX, 0); - this.viewport_.queueDisplayTransformAnimation(animation); + }); + + addBinding({ + keyCode: 39, // Right arrow. + callback: function(e) { + var curSel = this.brushingStateController_.selection; + var sel = this.viewport.getShiftedSelection(curSel, 1); + if (sel) { + this.brushingStateController.changeSelectionFromTimeline(sel); + this.panToSelection(); + } else { + this.queueSmoothPan_(-this.viewWidth_ * 0.3, 0); } - return; + e.preventDefault(); + e.stopPropagation(); } + }); + }, + + onDblClick_: function(e) { + if (this.mouseModeSelector_.mode !== + tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION) + return; + + var curSelection = this.brushingStateController_.selection; + if (!curSelection.length || !tr.b.getOnlyElement(curSelection).title) + return; + + var selection = new tr.model.EventSet(); + var filter = new tr.c.ExactTitleFilter( + tr.b.getOnlyElement(curSelection).title); + this.modelTrack_.addAllEventsMatchingFilterToSelection(filter, + selection); + + this.brushingStateController.changeSelectionFromTimeline(selection); + }, + + onMouseWheel_: function(e) { + if (!e.altKey) + return; + + var delta = e.wheelDelta / 120; + var zoomScale = Math.pow(1.5, delta); + this.zoomBy_(zoomScale); + e.preventDefault(); + }, + + onMouseDown_: function(e) { + if (this.mouseModeSelector_.mode !== + tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION) + return; + + // Mouse down must start on ruler track for crosshair guide lines to draw. + if (e.target !== this.rulerTrack_) + return; + + // Make sure we don't start a selection drag event here. + this.dragBeginEvent_ = undefined; + + // Remove nav string marker if it exists, since we're clearing the + // find control box. + if (this.xNavStringMarker_) { + this.model.removeAnnotation(this.xNavStringMarker_); + this.xNavStringMarker_ = undefined; + } - this.displayTransform_.set(dt); - this.displayTransform_.xPanWorldBoundsIntoView( - bounds.min, - bounds.max, - viewWidth); - var deltaX = this.displayTransform_.panX - dt.panX; - var animation = new tr.ui.TimelineDisplayTransformPanAnimation( - deltaX, 0); - this.viewport_.queueDisplayTransformAnimation(animation); - }, - - navToPosition: function(uiState, showNavLine) { - var location = uiState.location; - var scaleX = uiState.scaleX; - var track = location.getContainingTrack(this.viewport_); - - var worldCenter = location.xWorld; - var viewCenter = this.modelTrackContainer_.canvas.width / 5; - var zoomInRatio = scaleX / - this.viewport_.currentDisplayTransform.scaleX; - - // Vertically scroll so track is in view. - track.scrollIntoViewIfNeeded(); - - // Perform zoom and panX animation. - var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( - worldCenter, viewCenter, - this.viewport_.currentDisplayTransform.panY, - zoomInRatio); - this.viewport_.queueDisplayTransformAnimation(animation); - - if (!showNavLine) + var dt = this.viewport_.currentDisplayTransform; + tr.ui.b.trackMouseMovesUntilMouseUp(function(e) { // Mouse move handler. + // If mouse event is on ruler, don't do anything. + if (e.target === this.rulerTrack_) return; - // Add an X Marker Annotation at the specified timestamp. - if (this.xNavStringMarker_) - this.model.removeAnnotation(this.xNavStringMarker_); - this.xNavStringMarker_ = - new tr.model.XMarkerAnnotation(worldCenter); - this.model.addAnnotation(this.xNavStringMarker_); - }, - - selectPowerSamplesInCurrentTimeRange_: function() { - var selectionBounds = this.brushingStateController_.selection.bounds; - if (this.model.device.powerSeries && !selectionBounds.empty) { - var events = this.model.device.powerSeries.getSamplesWithinRange( - selectionBounds.min, selectionBounds.max); - var selection = new tr.model.EventSet(events); - this.brushingStateController_.changeSelectionFromTimeline(selection); - } - }, - setCurrentSelectionAsInterestRange_: function() { - var selectionBounds = this.brushingStateController_.selection.bounds; - if (selectionBounds.empty) { - this.viewport_.interestRange.reset(); + var relativePosition = this.extractRelativeMousePosition_(e); + var loc = tr.model.Location.fromViewCoordinates( + this.viewport_, relativePosition.x, relativePosition.y); + // Not all points on the timeline represents a valid location. + // ex. process header tracks, letter dot tracks. + if (!loc) return; - } - if (this.viewport_.interestRange.min == selectionBounds.min && - this.viewport_.interestRange.max == selectionBounds.max) - this.viewport_.interestRange.reset(); - else - this.viewport_.interestRange.set(selectionBounds); - }, - - toggleHighDetails_: function() { - this.viewport_.highDetails = !this.viewport_.highDetails; - }, - - hideDragBox_: function() { - this.$.drag_box.style.left = '-1000px'; - this.$.drag_box.style.top = '-1000px'; - this.$.drag_box.style.width = 0; - this.$.drag_box.style.height = 0; - }, - - setDragBoxPosition_: function(xStart, yStart, xEnd, yEnd) { - var loY = Math.min(yStart, yEnd); - var hiY = Math.max(yStart, yEnd); - var loX = Math.min(xStart, xEnd); - var hiX = Math.max(xStart, xEnd); - var modelTrackRect = this.modelTrack_.getBoundingClientRect(); - var dragRect = {left: loX, top: loY, width: hiX - loX, height: hiY - loY}; - - dragRect.right = dragRect.left + dragRect.width; - dragRect.bottom = dragRect.top + dragRect.height; - - var modelTrackContainerRect = - this.modelTrackContainer_.getBoundingClientRect(); - var clipRect = { - left: modelTrackContainerRect.left, - top: modelTrackContainerRect.top, - right: modelTrackContainerRect.right, - bottom: modelTrackContainerRect.bottom - }; - - var headingWidth = window.getComputedStyle( - this.querySelector('tr-ui-heading')).width; - var trackTitleWidth = parseInt(headingWidth); - clipRect.left = clipRect.left + trackTitleWidth; - - var intersectRect_ = function(r1, r2) { - if (r2.left > r1.right || r2.right < r1.left || - r2.top > r1.bottom || r2.bottom < r1.top) - return false; - - var results = {}; - results.left = Math.max(r1.left, r2.left); - results.top = Math.max(r1.top, r2.top); - results.right = Math.min(r1.right, r2.right); - results.bottom = Math.min(r1.bottom, r2.bottom); - results.width = results.right - results.left; - results.height = results.bottom - results.top; - return results; - }; - - // TODO(dsinclair): intersectRect_ can return false (which should actually - // be undefined) but we use finalDragBox without checking the return value - // which could potentially blowup. Fix this ..... - var finalDragBox = intersectRect_(clipRect, dragRect); - - this.$.drag_box.style.left = finalDragBox.left + 'px'; - this.$.drag_box.style.width = finalDragBox.width + 'px'; - this.$.drag_box.style.top = finalDragBox.top + 'px'; - this.$.drag_box.style.height = finalDragBox.height + 'px'; - this.$.drag_box.style.whiteSpace = 'nowrap'; - - var pixelRatio = window.devicePixelRatio || 1; - var canv = this.modelTrackContainer_.canvas; - var dt = this.viewport_.currentDisplayTransform; - var loWX = dt.xViewToWorld( - (loX - canv.offsetLeft) * pixelRatio); - var hiWX = dt.xViewToWorld( - (hiX - canv.offsetLeft) * pixelRatio); - - this.$.drag_box.textContent = - tr.v.Unit.byName.timeDurationInMs.format(hiWX - loWX); - - var e = new tr.b.Event('selectionChanging'); - e.loWX = loWX; - e.hiWX = hiWX; - this.dispatchEvent(e); - }, - - onGridToggle_: function(left) { - var selection = this.brushingStateController_.selection; - var tb = left ? selection.bounds.min : selection.bounds.max; - - // Toggle the grid off if the grid is on, the marker position is the same - // and the same element is selected (same timebase). - if (this.viewport_.gridEnabled && - this.viewport_.gridSide === left && - this.viewport_.gridInitialTimebase === tb) { - this.viewport_.gridside = undefined; - this.viewport_.gridEnabled = false; - this.viewport_.gridInitialTimebase = undefined; - return; + if (this.guideLineAnnotation_ === undefined) { + this.guideLineAnnotation_ = + new tr.model.XMarkerAnnotation(loc.xWorld); + this.model.addAnnotation(this.guideLineAnnotation_); + } else { + this.guideLineAnnotation_.timestamp = loc.xWorld; + this.modelTrackContainer_.invalidate(); } - // Shift the timebase left until its just left of model_.bounds.min. - var numIntervalsSinceStart = Math.ceil((tb - this.model_.bounds.min) / - this.viewport_.gridStep_); - - this.viewport_.gridEnabled = true; - this.viewport_.gridSide = left; - this.viewport_.gridInitialTimebase = tb; - this.viewport_.gridTimebase = tb - - (numIntervalsSinceStart + 1) * this.viewport_.gridStep_; - }, - - storeLastMousePos_: function(e) { - this.lastMouseViewPos_ = this.extractRelativeMousePosition_(e); - }, - - storeLastTouchPositions_: function(e) { - this.lastTouchViewPositions_ = this.extractRelativeTouchPositions_(e); - }, - - extractRelativeMousePosition_: function(e) { - var canv = this.modelTrackContainer_.canvas; - return { - x: e.clientX - canv.offsetLeft, - y: e.clientY - canv.offsetTop - }; - }, - - extractRelativeTouchPositions_: function(e) { - var canv = this.modelTrackContainer_.canvas; - - var touches = []; - for (var i = 0; i < e.touches.length; ++i) { - touches.push({ - x: e.touches[i].clientX - canv.offsetLeft, - y: e.touches[i].clientY - canv.offsetTop - }); + // Set the findcontrol's text to nav string of current state. + var state = new tr.ui.b.UIState(loc, + this.viewport_.currentDisplayTransform.scaleX); + this.timelineView_.setFindCtlText( + state.toUserFriendlyString(this.viewport_)); + }.bind(this), + undefined, // Mouse up handler. + function onKeyUpDuringDrag() { + if (this.dragBeginEvent_) { + this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_, + this.dragBoxXEnd_, this.dragBoxYEnd_); } - return touches; - }, - - storeInitialMouseDownPos_: function(e) { - - var position = this.extractRelativeMousePosition_(e); - - this.mouseViewPosAtMouseDown_.x = position.x; - this.mouseViewPosAtMouseDown_.y = position.y; - }, - - focusElements_: function() { - this.$.hotkey_controller.childRequestsGeneralFocus(this); - }, - - storeInitialInteractionPositionsAndFocus_: function(e) { + }.bind(this)); + }, + + queueSmoothPan_: function(viewDeltaX, deltaY) { + var deltaX = this.viewport_.currentDisplayTransform.xViewVectorToWorld( + viewDeltaX); + var animation = new tr.ui.TimelineDisplayTransformPanAnimation( + deltaX, deltaY); + this.viewport_.queueDisplayTransformAnimation(animation); + }, + + /** + * Zoom in or out on the timeline by the given scale factor. + * @param {Number} scale The scale factor to apply. If <1, zooms out. + * @param {boolean} Whether to change the zoom level smoothly. + */ + zoomBy_: function(scale, smooth) { + if (scale <= 0) { + return; + } - this.storeInitialMouseDownPos_(e); - this.storeLastMousePos_(e); + smooth = !!smooth; + var vp = this.viewport_; + var pixelRatio = window.devicePixelRatio || 1; - this.focusElements_(); - }, + var goalFocalPointXView = this.lastMouseViewPos_.x * pixelRatio; + var goalFocalPointXWorld = vp.currentDisplayTransform.xViewToWorld( + goalFocalPointXView); + if (smooth) { + var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( + goalFocalPointXWorld, goalFocalPointXView, + vp.currentDisplayTransform.panY, + scale); + vp.queueDisplayTransformAnimation(animation); + } else { + this.displayTransform_.set(vp.currentDisplayTransform); + this.displayTransform_.scaleX *= scale; + this.displayTransform_.xPanWorldPosToViewPos( + goalFocalPointXWorld, goalFocalPointXView, this.viewWidth_); + vp.setDisplayTransformImmediately(this.displayTransform_); + } + }, + + /** + * Zoom into the current selection. + */ + zoomToSelection: function() { + if (!this.brushingStateController.selectionOfInterest.length) + return; + + var bounds = this.brushingStateController.selectionOfInterest.bounds; + if (!bounds.range) + return; + + var worldCenter = bounds.center; + var viewCenter = this.modelTrackContainer_.canvas.width / 2; + var adjustedWorldRange = bounds.range * 1.25; + var newScale = this.modelTrackContainer_.canvas.width / + adjustedWorldRange; + var zoomInRatio = newScale / + this.viewport_.currentDisplayTransform.scaleX; + + var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( + worldCenter, viewCenter, + this.viewport_.currentDisplayTransform.panY, + zoomInRatio); + this.viewport_.queueDisplayTransformAnimation(animation); + }, + + /** + * Pan the view so the current selection becomes visible. + */ + panToSelection: function() { + if (!this.brushingStateController.selectionOfInterest.length) + return; + + var bounds = this.brushingStateController.selectionOfInterest.bounds; + var worldCenter = bounds.center; + var viewWidth = this.viewWidth_; + + var dt = this.viewport_.currentDisplayTransform; + if (false && !bounds.range) { + if (dt.xWorldToView(bounds.center) < 0 || + dt.xWorldToView(bounds.center) > viewWidth) { + this.displayTransform_.set(dt); + this.displayTransform_.xPanWorldPosToViewPos( + worldCenter, 'center', viewWidth); + var deltaX = this.displayTransform_.panX - dt.panX; + var animation = new tr.ui.TimelineDisplayTransformPanAnimation( + deltaX, 0); + this.viewport_.queueDisplayTransformAnimation(animation); + } + return; + } - onBeginPanScan_: function(e) { - var vp = this.viewport_; - this.viewportDisplayTransformAtMouseDown_ = - vp.currentDisplayTransform.clone(); - this.isPanningAndScanning_ = true; + this.displayTransform_.set(dt); + this.displayTransform_.xPanWorldBoundsIntoView( + bounds.min, + bounds.max, + viewWidth); + var deltaX = this.displayTransform_.panX - dt.panX; + var animation = new tr.ui.TimelineDisplayTransformPanAnimation( + deltaX, 0); + this.viewport_.queueDisplayTransformAnimation(animation); + }, + + navToPosition: function(uiState, showNavLine) { + var location = uiState.location; + var scaleX = uiState.scaleX; + var track = location.getContainingTrack(this.viewport_); + + var worldCenter = location.xWorld; + var viewCenter = this.modelTrackContainer_.canvas.width / 5; + var zoomInRatio = scaleX / + this.viewport_.currentDisplayTransform.scaleX; + + // Vertically scroll so track is in view. + track.scrollIntoViewIfNeeded(); + + // Perform zoom and panX animation. + var animation = new tr.ui.TimelineDisplayTransformZoomToAnimation( + worldCenter, viewCenter, + this.viewport_.currentDisplayTransform.panY, + zoomInRatio); + this.viewport_.queueDisplayTransformAnimation(animation); + + if (!showNavLine) + return; + // Add an X Marker Annotation at the specified timestamp. + if (this.xNavStringMarker_) + this.model.removeAnnotation(this.xNavStringMarker_); + this.xNavStringMarker_ = + new tr.model.XMarkerAnnotation(worldCenter); + this.model.addAnnotation(this.xNavStringMarker_); + }, + + selectPowerSamplesInCurrentTimeRange_: function() { + var selectionBounds = this.brushingStateController_.selection.bounds; + if (this.model.device.powerSeries && !selectionBounds.empty) { + var events = this.model.device.powerSeries.getSamplesWithinRange( + selectionBounds.min, selectionBounds.max); + var selection = new tr.model.EventSet(events); + this.brushingStateController_.changeSelectionFromTimeline(selection); + } + }, - this.storeInitialInteractionPositionsAndFocus_(e); - e.preventDefault(); - }, + setCurrentSelectionAsInterestRange_: function() { + var selectionBounds = this.brushingStateController_.selection.bounds; + if (selectionBounds.empty) { + this.viewport_.interestRange.reset(); + return; + } - onUpdatePanScan_: function(e) { - if (!this.isPanningAndScanning_) - return; + if (this.viewport_.interestRange.min === selectionBounds.min && + this.viewport_.interestRange.max === selectionBounds.max) + this.viewport_.interestRange.reset(); + else + this.viewport_.interestRange.set(selectionBounds); + }, + + toggleHighDetails_: function() { + this.viewport_.highDetails = !this.viewport_.highDetails; + }, + + hideDragBox_: function() { + this.$.drag_box.style.left = '-1000px'; + this.$.drag_box.style.top = '-1000px'; + this.$.drag_box.style.width = 0; + this.$.drag_box.style.height = 0; + }, + + setDragBoxPosition_: function(xStart, yStart, xEnd, yEnd) { + var loY = Math.min(yStart, yEnd); + var hiY = Math.max(yStart, yEnd); + var loX = Math.min(xStart, xEnd); + var hiX = Math.max(xStart, xEnd); + var modelTrackRect = this.modelTrack_.getBoundingClientRect(); + var dragRect = {left: loX, top: loY, width: hiX - loX, height: hiY - loY}; + + dragRect.right = dragRect.left + dragRect.width; + dragRect.bottom = dragRect.top + dragRect.height; + + var modelTrackContainerRect = + this.modelTrackContainer_.getBoundingClientRect(); + var clipRect = { + left: modelTrackContainerRect.left, + top: modelTrackContainerRect.top, + right: modelTrackContainerRect.right, + bottom: modelTrackContainerRect.bottom + }; + + var headingWidth = window.getComputedStyle( + Polymer.dom(this).querySelector('tr-ui-heading')).width; + var trackTitleWidth = parseInt(headingWidth); + clipRect.left = clipRect.left + trackTitleWidth; + + var intersectRect_ = function(r1, r2) { + if (r2.left > r1.right || r2.right < r1.left || + r2.top > r1.bottom || r2.bottom < r1.top) + return false; + + var results = {}; + results.left = Math.max(r1.left, r2.left); + results.top = Math.max(r1.top, r2.top); + results.right = Math.min(r1.right, r2.right); + results.bottom = Math.min(r1.bottom, r2.bottom); + results.width = results.right - results.left; + results.height = results.bottom - results.top; + return results; + }; + + // TODO(dsinclair): intersectRect_ can return false (which should actually + // be undefined) but we use finalDragBox without checking the return value + // which could potentially blowup. Fix this ..... + var finalDragBox = intersectRect_(clipRect, dragRect); + + this.$.drag_box.style.left = finalDragBox.left + 'px'; + this.$.drag_box.style.width = finalDragBox.width + 'px'; + this.$.drag_box.style.top = finalDragBox.top + 'px'; + this.$.drag_box.style.height = finalDragBox.height + 'px'; + this.$.drag_box.style.whiteSpace = 'nowrap'; + + var pixelRatio = window.devicePixelRatio || 1; + var canv = this.modelTrackContainer_.canvas; + var dt = this.viewport_.currentDisplayTransform; + var loWX = dt.xViewToWorld( + (loX - canv.offsetLeft) * pixelRatio); + var hiWX = dt.xViewToWorld( + (hiX - canv.offsetLeft) * pixelRatio); + + Polymer.dom(this.$.drag_box).textContent = + tr.b.Unit.byName.timeDurationInMs.format(hiWX - loWX); + + var e = new tr.b.Event('selectionChanging'); + e.loWX = loWX; + e.hiWX = hiWX; + this.dispatchEvent(e); + }, + + onGridToggle_: function(left) { + var selection = this.brushingStateController_.selection; + var tb = left ? selection.bounds.min : selection.bounds.max; + + // Toggle the grid off if the grid is on, the marker position is the same + // and the same element is selected (same timebase). + if (this.viewport_.gridEnabled && + this.viewport_.gridSide === left && + this.viewport_.gridInitialTimebase === tb) { + this.viewport_.gridside = undefined; + this.viewport_.gridEnabled = false; + this.viewport_.gridInitialTimebase = undefined; + return; + } - var viewWidth = this.viewWidth_; + // Shift the timebase left until its just left of model_.bounds.min. + var numIntervalsSinceStart = Math.ceil((tb - this.model_.bounds.min) / + this.viewport_.gridStep_); + + this.viewport_.gridEnabled = true; + this.viewport_.gridSide = left; + this.viewport_.gridInitialTimebase = tb; + this.viewport_.gridTimebase = tb - + (numIntervalsSinceStart + 1) * this.viewport_.gridStep_; + }, + + storeLastMousePos_: function(e) { + this.lastMouseViewPos_ = this.extractRelativeMousePosition_(e); + }, + + storeLastTouchPositions_: function(e) { + this.lastTouchViewPositions_ = this.extractRelativeTouchPositions_(e); + }, + + extractRelativeMousePosition_: function(e) { + var canv = this.modelTrackContainer_.canvas; + return { + x: e.clientX - canv.offsetLeft, + y: e.clientY - canv.offsetTop + }; + }, + + extractRelativeTouchPositions_: function(e) { + var canv = this.modelTrackContainer_.canvas; + + var touches = []; + for (var i = 0; i < e.touches.length; ++i) { + touches.push({ + x: e.touches[i].clientX - canv.offsetLeft, + y: e.touches[i].clientY - canv.offsetTop + }); + } + return touches; + }, - var pixelRatio = window.devicePixelRatio || 1; - var xDeltaView = pixelRatio * (this.lastMouseViewPos_.x - - this.mouseViewPosAtMouseDown_.x); + storeInitialMouseDownPos_: function(e) { - var yDelta = this.lastMouseViewPos_.y - - this.mouseViewPosAtMouseDown_.y; + var position = this.extractRelativeMousePosition_(e); - this.displayTransform_.set(this.viewportDisplayTransformAtMouseDown_); - this.displayTransform_.incrementPanXInViewUnits(xDeltaView); - this.displayTransform_.panY -= yDelta; - this.viewport_.setDisplayTransformImmediately(this.displayTransform_); + this.mouseViewPosAtMouseDown_.x = position.x; + this.mouseViewPosAtMouseDown_.y = position.y; + }, - e.preventDefault(); - e.stopPropagation(); + focusElements_: function() { + this.$.hotkey_controller.childRequestsGeneralFocus(this); + }, - this.storeLastMousePos_(e); - }, + storeInitialInteractionPositionsAndFocus_: function(e) { - onEndPanScan_: function(e) { - this.isPanningAndScanning_ = false; + this.storeInitialMouseDownPos_(e); + this.storeLastMousePos_(e); - this.storeLastMousePos_(e); + this.focusElements_(); + }, - if (!e.isClick) - e.preventDefault(); - }, - - onBeginSelection_: function(e) { - var canv = this.modelTrackContainer_.canvas; - var rect = this.modelTrack_.getBoundingClientRect(); - var canvRect = canv.getBoundingClientRect(); - - var inside = rect && - e.clientX >= rect.left && - e.clientX < rect.right && - e.clientY >= rect.top && - e.clientY < rect.bottom && - e.clientX >= canvRect.left && - e.clientX < canvRect.right; - - if (!inside) - return; + onBeginPanScan_: function(e) { + var vp = this.viewport_; + this.viewportDisplayTransformAtMouseDown_ = + vp.currentDisplayTransform.clone(); + this.isPanningAndScanning_ = true; - this.dragBeginEvent_ = e; + this.storeInitialInteractionPositionsAndFocus_(e); + e.preventDefault(); + }, - this.storeInitialInteractionPositionsAndFocus_(e); - e.preventDefault(); - }, + onUpdatePanScan_: function(e) { + if (!this.isPanningAndScanning_) + return; - onUpdateSelection_: function(e) { - if (!this.dragBeginEvent_) - return; + var viewWidth = this.viewWidth_; - // Update the drag box - this.dragBoxXStart_ = this.dragBeginEvent_.clientX; - this.dragBoxXEnd_ = e.clientX; - this.dragBoxYStart_ = this.dragBeginEvent_.clientY; - this.dragBoxYEnd_ = e.clientY; - this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_, - this.dragBoxXEnd_, this.dragBoxYEnd_); + var pixelRatio = window.devicePixelRatio || 1; + var xDeltaView = pixelRatio * (this.lastMouseViewPos_.x - + this.mouseViewPosAtMouseDown_.x); - }, + var yDelta = this.lastMouseViewPos_.y - + this.mouseViewPosAtMouseDown_.y; - onEndSelection_: function(e) { - e.preventDefault(); + this.displayTransform_.set(this.viewportDisplayTransformAtMouseDown_); + this.displayTransform_.incrementPanXInViewUnits(xDeltaView); + this.displayTransform_.panY -= yDelta; + this.viewport_.setDisplayTransformImmediately(this.displayTransform_); - if (!this.dragBeginEvent_) - return; + e.preventDefault(); + e.stopPropagation(); - // Stop the dragging. - this.hideDragBox_(); - var eDown = this.dragBeginEvent_; - this.dragBeginEvent_ = undefined; - - // Figure out extents of the drag. - var loY = Math.min(eDown.clientY, e.clientY); - var hiY = Math.max(eDown.clientY, e.clientY); - var loX = Math.min(eDown.clientX, e.clientX); - var hiX = Math.max(eDown.clientX, e.clientX); - - // Convert to worldspace. - var canv = this.modelTrackContainer_.canvas; - var worldOffset = canv.getBoundingClientRect().left; - var loVX = loX - worldOffset; - var hiVX = hiX - worldOffset; - - // Figure out what has been selected. - var selection = new tr.model.EventSet(); - if (eDown.appendSelection) { - var previousSelection = this.brushingStateController_.selection; - if (previousSelection !== undefined) - selection.addEventSet(previousSelection); - } - this.modelTrack_.addIntersectingEventsInRangeToSelection( - loVX, hiVX, loY, hiY, selection); + this.storeLastMousePos_(e); + }, - // Activate the new selection. - this.brushingStateController_.changeSelectionFromTimeline(selection); - }, + onEndPanScan_: function(e) { + this.isPanningAndScanning_ = false; - onBeginZoom_: function(e) { - this.isZooming_ = true; + this.storeLastMousePos_(e); - this.storeInitialInteractionPositionsAndFocus_(e); + if (!e.isClick) e.preventDefault(); - }, - - onUpdateZoom_: function(e) { - if (!this.isZooming_) - return; - var newPosition = this.extractRelativeMousePosition_(e); - - var zoomScaleValue = 1 + (this.lastMouseViewPos_.y - - newPosition.y) * 0.01; - - this.zoomBy_(zoomScaleValue, false); - this.storeLastMousePos_(e); - }, - - onEndZoom_: function(e) { - this.isZooming_ = false; - - if (!e.isClick) - e.preventDefault(); - }, - - computeTouchCenter_: function(positions) { - var xSum = 0; - var ySum = 0; - for (var i = 0; i < positions.length; ++i) { - xSum += positions[i].x; - ySum += positions[i].y; - } - return { - x: xSum / positions.length, - y: ySum / positions.length - }; - }, - - computeTouchSpan_: function(positions) { - var xMin = Number.MAX_VALUE; - var yMin = Number.MAX_VALUE; - var xMax = Number.MIN_VALUE; - var yMax = Number.MIN_VALUE; - for (var i = 0; i < positions.length; ++i) { - xMin = Math.min(xMin, positions[i].x); - yMin = Math.min(yMin, positions[i].y); - xMax = Math.max(xMax, positions[i].x); - yMax = Math.max(yMax, positions[i].y); - } - return Math.sqrt((xMin - xMax) * (xMin - xMax) + - (yMin - yMax) * (yMin - yMax)); - }, - - onUpdateTransformForTouch_: function(e) { - var newPositions = this.extractRelativeTouchPositions_(e); - var currentPositions = this.lastTouchViewPositions_; - - var newCenter = this.computeTouchCenter_(newPositions); - var currentCenter = this.computeTouchCenter_(currentPositions); - - var newSpan = this.computeTouchSpan_(newPositions); - var currentSpan = this.computeTouchSpan_(currentPositions); + }, + + onBeginSelection_: function(e) { + var canv = this.modelTrackContainer_.canvas; + var rect = this.modelTrack_.getBoundingClientRect(); + var canvRect = canv.getBoundingClientRect(); + + var inside = rect && + e.clientX >= rect.left && + e.clientX < rect.right && + e.clientY >= rect.top && + e.clientY < rect.bottom && + e.clientX >= canvRect.left && + e.clientX < canvRect.right; + + if (!inside) + return; + + this.dragBeginEvent_ = e; + + this.storeInitialInteractionPositionsAndFocus_(e); + e.preventDefault(); + }, + + onUpdateSelection_: function(e) { + if (!this.dragBeginEvent_) + return; + + // Update the drag box + this.dragBoxXStart_ = this.dragBeginEvent_.clientX; + this.dragBoxXEnd_ = e.clientX; + this.dragBoxYStart_ = this.dragBeginEvent_.clientY; + this.dragBoxYEnd_ = e.clientY; + this.setDragBoxPosition_(this.dragBoxXStart_, this.dragBoxYStart_, + this.dragBoxXEnd_, this.dragBoxYEnd_); + + }, + + onEndSelection_: function(e) { + e.preventDefault(); + + if (!this.dragBeginEvent_) + return; + + // Stop the dragging. + this.hideDragBox_(); + var eDown = this.dragBeginEvent_; + this.dragBeginEvent_ = undefined; + + // Figure out extents of the drag. + var loY = Math.min(eDown.clientY, e.clientY); + var hiY = Math.max(eDown.clientY, e.clientY); + var loX = Math.min(eDown.clientX, e.clientX); + var hiX = Math.max(eDown.clientX, e.clientX); + + // Convert to worldspace. + var canv = this.modelTrackContainer_.canvas; + var worldOffset = canv.getBoundingClientRect().left; + var loVX = loX - worldOffset; + var hiVX = hiX - worldOffset; + + // Figure out what has been selected. + var selection = new tr.model.EventSet(); + if (eDown.appendSelection) { + var previousSelection = this.brushingStateController_.selection; + if (previousSelection !== undefined) + selection.addEventSet(previousSelection); + } + this.modelTrack_.addIntersectingEventsInRangeToSelection( + loVX, hiVX, loY, hiY, selection); - var vp = this.viewport_; - var viewWidth = this.viewWidth_; - var pixelRatio = window.devicePixelRatio || 1; + // Activate the new selection. + this.brushingStateController_.changeSelectionFromTimeline(selection); + }, - var xDelta = pixelRatio * (newCenter.x - currentCenter.x); - var yDelta = newCenter.y - currentCenter.y; - var zoomScaleValue = currentSpan > 10 ? newSpan / currentSpan : 1; + onBeginZoom_: function(e) { + this.isZooming_ = true; - var viewFocus = pixelRatio * newCenter.x; - var worldFocus = vp.currentDisplayTransform.xViewToWorld(viewFocus); + this.storeInitialInteractionPositionsAndFocus_(e); + e.preventDefault(); + }, - this.displayTransform_.set(vp.currentDisplayTransform); - this.displayTransform_.scaleX *= zoomScaleValue; - this.displayTransform_.xPanWorldPosToViewPos( - worldFocus, viewFocus, viewWidth); - this.displayTransform_.incrementPanXInViewUnits(xDelta); - this.displayTransform_.panY -= yDelta; - vp.setDisplayTransformImmediately(this.displayTransform_); - this.storeLastTouchPositions_(e); - }, + onUpdateZoom_: function(e) { + if (!this.isZooming_) + return; + var newPosition = this.extractRelativeMousePosition_(e); - initHintText_: function() { - this.$.hint_text.style.display = 'none'; + var zoomScaleValue = 1 + (this.lastMouseViewPos_.y - + newPosition.y) * 0.01; - this.pendingHintTextClearTimeout_ = undefined; - }, + this.zoomBy_(zoomScaleValue, false); + this.storeLastMousePos_(e); + }, - showHintText_: function(text) { - if (this.pendingHintTextClearTimeout_) { - window.clearTimeout(this.pendingHintTextClearTimeout_); - this.pendingHintTextClearTimeout_ = undefined; - } - this.pendingHintTextClearTimeout_ = setTimeout( - this.hideHintText_.bind(this), 1000); - this.$.hint_text.textContent = text; - this.$.hint_text.style.display = ''; - }, + onEndZoom_: function(e) { + this.isZooming_ = false; - hideHintText_: function() { + if (!e.isClick) + e.preventDefault(); + }, + + computeTouchCenter_: function(positions) { + var xSum = 0; + var ySum = 0; + for (var i = 0; i < positions.length; ++i) { + xSum += positions[i].x; + ySum += positions[i].y; + } + return { + x: xSum / positions.length, + y: ySum / positions.length + }; + }, + + computeTouchSpan_: function(positions) { + var xMin = Number.MAX_VALUE; + var yMin = Number.MAX_VALUE; + var xMax = Number.MIN_VALUE; + var yMax = Number.MIN_VALUE; + for (var i = 0; i < positions.length; ++i) { + xMin = Math.min(xMin, positions[i].x); + yMin = Math.min(yMin, positions[i].y); + xMax = Math.max(xMax, positions[i].x); + yMax = Math.max(yMax, positions[i].y); + } + return Math.sqrt((xMin - xMax) * (xMin - xMax) + + (yMin - yMax) * (yMin - yMax)); + }, + + onUpdateTransformForTouch_: function(e) { + var newPositions = this.extractRelativeTouchPositions_(e); + var currentPositions = this.lastTouchViewPositions_; + + var newCenter = this.computeTouchCenter_(newPositions); + var currentCenter = this.computeTouchCenter_(currentPositions); + + var newSpan = this.computeTouchSpan_(newPositions); + var currentSpan = this.computeTouchSpan_(currentPositions); + + var vp = this.viewport_; + var viewWidth = this.viewWidth_; + var pixelRatio = window.devicePixelRatio || 1; + + var xDelta = pixelRatio * (newCenter.x - currentCenter.x); + var yDelta = newCenter.y - currentCenter.y; + var zoomScaleValue = currentSpan > 10 ? newSpan / currentSpan : 1; + + var viewFocus = pixelRatio * newCenter.x; + var worldFocus = vp.currentDisplayTransform.xViewToWorld(viewFocus); + + this.displayTransform_.set(vp.currentDisplayTransform); + this.displayTransform_.scaleX *= zoomScaleValue; + this.displayTransform_.xPanWorldPosToViewPos( + worldFocus, viewFocus, viewWidth); + this.displayTransform_.incrementPanXInViewUnits(xDelta); + this.displayTransform_.panY -= yDelta; + vp.setDisplayTransformImmediately(this.displayTransform_); + this.storeLastTouchPositions_(e); + }, + + initHintText_: function() { + this.$.hint_text.style.display = 'none'; + + this.pendingHintTextClearTimeout_ = undefined; + }, + + showHintText_: function(text) { + if (this.pendingHintTextClearTimeout_) { + window.clearTimeout(this.pendingHintTextClearTimeout_); this.pendingHintTextClearTimeout_ = undefined; - this.$.hint_text.style.display = 'none'; } - }); - </script> -</polymer-element> + this.pendingHintTextClearTimeout_ = setTimeout( + this.hideHintText_.bind(this), 1000); + Polymer.dom(this.$.hint_text).textContent = text; + this.$.hint_text.style.display = ''; + }, + + hideHintText_: function() { + this.pendingHintTextClearTimeout_ = undefined; + this.$.hint_text.style.display = 'none'; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html index 70c00ec74d0..3c026b86718 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_track_view_test.html @@ -20,15 +20,15 @@ tr.b.unittest.testSuite(function() { var Task = tr.b.Task; test('instantiate', function() { - var num_threads = 500; + var numThreads = 500; var model = tr.c.TestUtils.newModelWithEvents([], { shiftWorldToZero: false, pruneContainers: false, customizeModelCallback: function(model) { var p100 = model.getOrCreateProcess(100); - for (var i = 0; i < num_threads; i++) { + for (var i = 0; i < numThreads; i++) { var t = p100.getOrCreateThread(101 + i); - if (i % 2 == 0) { + if (i % 2 === 0) { t.sliceGroup.beginSlice('cat', 'a', 100); t.sliceGroup.endSlice(110); } else { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html index e6dc34ab422..88a9419e731 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view.html @@ -29,7 +29,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/timeline_view_metadata_overlay.html"> <link rel="import" href="/tracing/value/ui/preferred_display_unit.html"> -<polymer-element name='tr-ui-timeline-view'> +<dom-module id='tr-ui-timeline-view'> <template> <style> :host { @@ -133,398 +133,409 @@ found in the LICENSE file. <tr-v-ui-preferred-display-unit id="display_unit"> </tr-v-ui-preferred-display-unit> </template> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-timeline-view', + + attached: function() { + this.async(function() { + this.trackViewContainer_ = Polymer.dom(this).querySelector( + '#track_view_container'); + if (!this.trackViewContainer_) + console.error('missing trackviewContainer'); + }); + }, + + ready: function() { + this.tabIndex = 0; // Let the timeline able to receive key events. + + this.titleEl_ = this.$.title; + this.leftControlsEl_ = this.$.left_controls; + this.rightControlsEl_ = this.$.right_controls; + this.collapsingControlsEl_ = this.$.collapsing_controls; + this.sidePanelContainer_ = this.$.side_panel_container; + + this.brushingStateController_ = new tr.c.BrushingStateController(this); + + this.findCtl_ = this.$.view_find_control; + this.findCtl_.controller = new tr.ui.FindController( + this.brushingStateController_); + + this.scriptingCtl_ = document.createElement('tr-ui-scripting-control'); + this.scriptingCtl_.controller = new tr.c.ScriptingController( + this.brushingStateController_); + + this.sidePanelContainer_.brushingStateController = + this.brushingStateController_; + + if (window.tr.metrics && window.tr.metrics.sh && + window.tr.metrics.sh.SystemHealthMetric) { + this.railScoreSpan_ = document.createElement( + 'tr-metrics-ui-sh-system-health-span'); + Polymer.dom(this.rightControls).appendChild(this.railScoreSpan_); + } else { + this.railScoreSpan_ = undefined; + } - <script> - 'use strict'; + this.optionsDropdown_ = this.$.view_options_dropdown; + Polymer.dom(this.optionsDropdown_.iconElement).textContent = 'View Options'; + + this.showFlowEvents_ = false; + Polymer.dom(this.optionsDropdown_).appendChild(tr.ui.b.createCheckBox( + this, 'showFlowEvents', + 'tr.ui.TimelineView.showFlowEvents', false, + 'Flow events')); + this.highlightVSync_ = false; + this.highlightVSyncCheckbox_ = tr.ui.b.createCheckBox( + this, 'highlightVSync', + 'tr.ui.TimelineView.highlightVSync', false, + 'Highlight VSync'); + Polymer.dom(this.optionsDropdown_).appendChild( + this.highlightVSyncCheckbox_); + + this.initMetadataButton_(); + this.initConsoleButton_(); + this.initHelpButton_(); + + Polymer.dom(this.collapsingControls).appendChild(this.scriptingCtl_); + + this.dragEl_ = this.$.drag_handle; + + this.analysisEl_ = this.$.analysis; + this.analysisEl_.brushingStateController = this.brushingStateController_; + + this.addEventListener( + 'requestSelectionChange', + function(e) { + var sc = this.brushingStateController_; + sc.changeSelectionFromRequestSelectionChangeEvent(e.selection); + }.bind(this)); + + // Bookkeeping. + this.onViewportChanged_ = this.onViewportChanged_.bind(this); + this.bindKeyListeners_(); + + this.dragEl_.target = this.analysisEl_; + }, + + get globalMode() { + return this.hotkeyController.globalMode; + }, + + set globalMode(globalMode) { + globalMode = !!globalMode; + this.brushingStateController_.historyEnabled = globalMode; + this.hotkeyController.globalMode = globalMode; + }, + + get hotkeyController() { + return this.$.hkc; + }, + + updateDocumentFavicon: function() { + var hue; + if (!this.model) + hue = 'blue'; + else + hue = this.model.faviconHue; + + var faviconData = tr.ui.b.FaviconsByHue[hue]; + if (faviconData === undefined) + faviconData = tr.ui.b.FaviconsByHue['blue']; + + // Find link if its there + var link = Polymer.dom(document.head).querySelector( + 'link[rel="shortcut icon"]'); + if (!link) { + link = document.createElement('link'); + link.rel = 'shortcut icon'; + Polymer.dom(document.head).appendChild(link); + } + link.href = faviconData; + }, + + get showFlowEvents() { + return this.showFlowEvents_; + }, + + set showFlowEvents(showFlowEvents) { + this.showFlowEvents_ = showFlowEvents; + if (!this.trackView_) + return; + this.trackView_.viewport.showFlowEvents = showFlowEvents; + }, + + get highlightVSync() { + return this.highlightVSync_; + }, + + set highlightVSync(highlightVSync) { + this.highlightVSync_ = highlightVSync; + if (!this.trackView_) + return; + this.trackView_.viewport.highlightVSync = highlightVSync; + }, + + initHelpButton_: function() { + var helpButtonEl = this.$.view_help_button; + + var dlg = new tr.ui.b.Overlay(); + dlg.title = 'Chrome Tracing Help'; + dlg.visible = false; + dlg.appendChild( + document.createElement('tr-ui-timeline-view-help-overlay')); + + function onClick(e) { + dlg.visible = !dlg.visible; + // Stop event so it doesn't trigger new click listener on document. + e.stopPropagation(); + } - Polymer({ - ready: function() { - this.tabIndex = 0; // Let the timeline able to receive key events. + helpButtonEl.addEventListener('click', onClick.bind(this)); + }, - this.titleEl_ = this.$.title; - this.leftControlsEl_ = this.$.left_controls; - this.rightControlsEl_ = this.$.right_controls; - this.collapsingControlsEl_ = this.$.collapsing_controls; - this.sidePanelContainer_ = this.$.side_panel_container; + initConsoleButton_: function() { + var toggleEl = this.$.view_console_button; - this.brushingStateController_ = new tr.c.BrushingStateController(this); + function onClick(e) { + this.scriptingCtl_.toggleVisibility(); + e.stopPropagation(); + return false; + } + toggleEl.addEventListener('click', onClick.bind(this)); + }, - this.findCtl_ = this.$.view_find_control; - this.findCtl_.controller = new tr.ui.FindController( - this.brushingStateController_); + initMetadataButton_: function() { + var showEl = this.$.view_metadata_button; - this.scriptingCtl_ = document.createElement('tr-ui-scripting-control'); - this.scriptingCtl_.controller = new tr.c.ScriptingController( - this.brushingStateController_); + function onClick(e) { + var dlg = new tr.ui.b.Overlay(); + dlg.title = 'Metadata for trace'; - this.sidePanelContainer_.brushingStateController = - this.brushingStateController_; + var metadataOverlay = document.createElement( + 'tr-ui-timeline-view-metadata-overlay'); + metadataOverlay.metadata = this.model.metadata; - if (window.tr.metrics && window.tr.metrics.sh && - window.tr.metrics.sh.systemHealthMetric) { - this.railScoreSpan_ = document.createElement( - 'tr-metrics-ui-sh-system-health-span'); - this.rightControls.appendChild(this.railScoreSpan_); - } else { - this.railScoreSpan_ = undefined; - } + Polymer.dom(dlg).appendChild(metadataOverlay); + dlg.visible = true; - this.optionsDropdown_ = this.$.view_options_dropdown; - this.optionsDropdown_.iconElement.textContent = 'View Options'; - - this.showFlowEvents_ = false; - this.optionsDropdown_.appendChild(tr.ui.b.createCheckBox( - this, 'showFlowEvents', - 'tr.ui.TimelineView.showFlowEvents', false, - 'Flow events')); - this.highlightVSync_ = false; - this.highlightVSyncCheckbox_ = tr.ui.b.createCheckBox( - this, 'highlightVSync', - 'tr.ui.TimelineView.highlightVSync', false, - 'Highlight VSync'); - this.optionsDropdown_.appendChild(this.highlightVSyncCheckbox_); - - this.initMetadataButton_(); - this.initConsoleButton_(); - this.initHelpButton_(); - - this.collapsingControls.appendChild(this.scriptingCtl_); - - this.dragEl_ = this.$.drag_handle; - - this.analysisEl_ = this.$.analysis; - this.analysisEl_.brushingStateController = this.brushingStateController_; - - this.addEventListener( - 'requestSelectionChange', - function(e) { - var sc = this.brushingStateController_; - sc.changeSelectionFromRequestSelectionChangeEvent(e.selection); - }.bind(this)); - - // Bookkeeping. - this.onViewportChanged_ = this.onViewportChanged_.bind(this); - this.bindKeyListeners_(); - - this.dragEl_.target = this.analysisEl_; - }, - - domReady: function() { - this.trackViewContainer_ = this.querySelector('#track_view_container'); - }, - - get globalMode() { - return this.hotkeyController.globalMode; - }, - - set globalMode(globalMode) { - globalMode = !!globalMode; - this.brushingStateController_.historyEnabled = globalMode; - this.hotkeyController.globalMode = globalMode; - }, - - get hotkeyController() { - return this.$.hkc; - }, - - updateDocumentFavicon: function() { - var hue; - if (!this.model) - hue = 'blue'; - else - hue = this.model.faviconHue; - - var faviconData = tr.ui.b.FaviconsByHue[hue]; - if (faviconData === undefined) - faviconData = tr.ui.b.FaviconsByHue['blue']; - - // Find link if its there - var link = document.head.querySelector('link[rel="shortcut icon"]'); - if (!link) { - link = document.createElement('link'); - link.rel = 'shortcut icon'; - document.head.appendChild(link); - } - link.href = faviconData; - }, - - get showFlowEvents() { - return this.showFlowEvents_; - }, - - set showFlowEvents(showFlowEvents) { - this.showFlowEvents_ = showFlowEvents; - if (!this.trackView_) - return; - this.trackView_.viewport.showFlowEvents = showFlowEvents; - }, - - get highlightVSync() { - return this.highlightVSync_; - }, - - set highlightVSync(highlightVSync) { - this.highlightVSync_ = highlightVSync; - if (!this.trackView_) - return; - this.trackView_.viewport.highlightVSync = highlightVSync; - }, - - initHelpButton_: function() { - var helpButtonEl = this.$.view_help_button; - - function onClick(e) { - var dlg = new tr.ui.b.Overlay(); - dlg.title = 'Chrome Tracing Help'; - dlg.appendChild( - document.createElement('tr-ui-timeline-view-help-overlay')); - dlg.visible = true; - - // Stop event so it doesn't trigger new click listener on document. - e.stopPropagation(); + e.stopPropagation(); + return false; + } + showEl.addEventListener('click', onClick.bind(this)); + + this.updateMetadataButtonVisibility_(); + }, + + updateMetadataButtonVisibility_: function() { + var showEl = this.$.view_metadata_button; + showEl.style.display = + (this.model && this.model.metadata.length) ? '' : 'none'; + }, + + get leftControls() { + return this.leftControlsEl_; + }, + + get rightControls() { + return this.rightControlsEl_; + }, + + get collapsingControls() { + return this.collapsingControlsEl_; + }, + + get viewTitle() { + return Polymer.dom(this.titleEl_).textContent.substring( + Polymer.dom(this.titleEl_).textContent.length - 2); + }, + + set viewTitle(text) { + if (text === undefined) { + Polymer.dom(this.titleEl_).textContent = ''; + this.titleEl_.hidden = true; + return; + } + this.titleEl_.hidden = false; + Polymer.dom(this.titleEl_).textContent = text; + }, + + get model() { + if (this.trackView_) + return this.trackView_.model; + return undefined; + }, + + set model(model) { + var modelInstanceChanged = model !== this.model; + var modelValid = model && !model.bounds.isEmpty; + + var importWarningsEl = Polymer.dom(this.root).querySelector( + '#import-warnings'); + Polymer.dom(importWarningsEl).textContent = ''; + + // Remove old trackView if the model has completely changed. + if (modelInstanceChanged) { + if (this.railScoreSpan_) + this.railScoreSpan_.model = undefined; + Polymer.dom(this.trackViewContainer_).textContent = ''; + if (this.trackView_) { + this.trackView_.viewport.removeEventListener( + 'change', this.onViewportChanged_); + this.trackView_.brushingStateController = undefined; + this.trackView_.detach(); + this.trackView_ = undefined; } - helpButtonEl.addEventListener('click', onClick.bind(this)); - }, - - initConsoleButton_: function() { - var toggleEl = this.$.view_console_button; + this.brushingStateController_.modelWillChange(); + } - function onClick(e) { - this.scriptingCtl_.toggleVisibility(); - e.stopPropagation(); - return false; - } - toggleEl.addEventListener('click', onClick.bind(this)); - }, + // Create new trackView if needed. + if (modelValid && !this.trackView_) { + this.trackView_ = document.createElement('tr-ui-timeline-track-view'); + this.trackView_.timelineView = this; - initMetadataButton_: function() { - var showEl = this.$.view_metadata_button; + this.trackView.brushingStateController = this.brushingStateController_; - function onClick(e) { - var dlg = new tr.ui.b.Overlay(); - dlg.title = 'Metadata for trace'; + Polymer.dom(this.trackViewContainer_).appendChild(this.trackView_); + this.trackView_.viewport.addEventListener( + 'change', this.onViewportChanged_); + } - var metadataOverlay = document.createElement( - 'tr-ui-timeline-view-metadata-overlay'); - metadataOverlay.metadata = this.model.metadata; + // Set the model. + if (modelValid) { + this.trackView_.model = model; + this.trackView_.viewport.showFlowEvents = this.showFlowEvents; + this.trackView_.viewport.highlightVSync = this.highlightVSync; + if (this.railScoreSpan_) + this.railScoreSpan_.model = model; - dlg.appendChild(metadataOverlay); - dlg.visible = true; + this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit; + } - e.stopPropagation(); - return false; - } - showEl.addEventListener('click', onClick.bind(this)); + if (model) { + model.importWarningsThatShouldBeShownToUser.forEach( + function(importWarning) { + importWarningsEl.addMessage( + 'Import Warning: ' + importWarning.type + ': ' + + importWarning.message); + }, this); + } + // Do things that are selection specific + if (modelInstanceChanged) { this.updateMetadataButtonVisibility_(); - }, - - updateMetadataButtonVisibility_: function() { - var showEl = this.$.view_metadata_button; - showEl.style.display = - (this.model && this.model.metadata.length) ? '' : 'none'; - }, - - get leftControls() { - return this.leftControlsEl_; - }, - - get rightControls() { - return this.rightControlsEl_; - }, - - get collapsingControls() { - return this.collapsingControlsEl_; - }, - - get viewTitle() { - return this.titleEl_.textContent.substring( - this.titleEl_.textContent.length - 2); - }, - - set viewTitle(text) { - if (text === undefined) { - this.titleEl_.textContent = ''; - this.titleEl_.hidden = true; - return; - } - this.titleEl_.hidden = false; - this.titleEl_.textContent = text; - }, - - get model() { - if (this.trackView_) - return this.trackView_.model; - return undefined; - }, - - set model(model) { - var modelInstanceChanged = model != this.model; - var modelValid = model && !model.bounds.isEmpty; - - var importWarningsEl = this.shadowRoot.querySelector('#import-warnings'); - importWarningsEl.textContent = ''; - - // Remove old trackView if the model has completely changed. - if (modelInstanceChanged) { - if (this.railScoreSpan_) - this.railScoreSpan_.model = undefined; - this.trackViewContainer_.textContent = ''; - if (this.trackView_) { - this.trackView_.viewport.removeEventListener( - 'change', this.onViewportChanged_); - this.trackView_.brushingStateController = undefined; - this.trackView_.detach(); - this.trackView_ = undefined; - } - this.brushingStateController_.modelWillChange(); - } - - // Create new trackView if needed. - if (modelValid && !this.trackView_) { - this.trackView_ = document.createElement('tr-ui-timeline-track-view'); - this.trackView_.timelineView = this; - - this.trackView.brushingStateController = this.brushingStateController_; - - this.trackViewContainer_.appendChild(this.trackView_); - this.trackView_.viewport.addEventListener( - 'change', this.onViewportChanged_); - } - - // Set the model. - if (modelValid) { - this.trackView_.model = model; - this.trackView_.viewport.showFlowEvents = this.showFlowEvents; - this.trackView_.viewport.highlightVSync = this.highlightVSync; - if (this.railScoreSpan_) - this.railScoreSpan_.model = model; - - this.$.display_unit.preferredTimeDisplayMode = model.intrinsicTimeUnit; + this.brushingStateController_.modelDidChange(); + this.onViewportChanged_(); + } + }, + + get brushingStateController() { + return this.brushingStateController_; + }, + + get trackView() { + return this.trackView_; + }, + + get settings() { + if (!this.settings_) + this.settings_ = new tr.b.Settings(); + return this.settings_; + }, + + /** + * Deprecated. Kept around because third_party code occasionally calls + * this to set up embedding. + */ + set focusElement(value) { + throw new Error('This is deprecated. Please set globalMode to true.'); + }, + + bindKeyListeners_: function() { + var hkc = this.hotkeyController; + + // Shortcuts that *can* steal focus from the console and the filter text + // box. + hkc.addHotKey(new tr.ui.b.HotKey({ + eventType: 'keypress', + keyCode: '`'.charCodeAt(0), + useCapture: true, + thisArg: this, + callback: function(e) { + this.scriptingCtl_.toggleVisibility(); + if (!this.scriptingCtl_.hasFocus) + this.focus(); + e.stopPropagation(); } - - if (model) { - model.importWarningsThatShouldBeShownToUser.forEach( - function(importWarning) { - importWarningsEl.addMessage( - 'Import Warning: ' + importWarning.type + ': ' + - importWarning.message); - }, this); + })); + + // Shortcuts that *can* steal focus from the filter text box. + hkc.addHotKey(new tr.ui.b.HotKey({ + eventType: 'keypress', + keyCode: '/'.charCodeAt(0), + useCapture: true, + thisArg: this, + callback: function(e) { + if (this.scriptingCtl_.hasFocus) + return; + if (this.findCtl_.hasFocus) + this.focus(); + else + this.findCtl_.focus(); + e.preventDefault(); + e.stopPropagation(); } - - // Do things that are selection specific - if (modelInstanceChanged) { - this.updateMetadataButtonVisibility_(); - this.brushingStateController_.modelDidChange(); - this.onViewportChanged_(); + })); + + // Shortcuts that *can't* steal focus. + hkc.addHotKey(new tr.ui.b.HotKey({ + eventType: 'keypress', + keyCode: '?'.charCodeAt(0), + useCapture: false, + thisArg: this, + callback: function(e) { + this.$.view_help_button.click(); + e.stopPropagation(); } - }, - - get brushingStateController() { - return this.brushingStateController_; - }, - - get trackView() { - return this.trackView_; - }, - - get settings() { - if (!this.settings_) - this.settings_ = new tr.b.Settings(); - return this.settings_; - }, - - /** - * Deprecated. Kept around because third_party code occasionally calls - * this to set up embedding. - */ - set focusElement(value) { - throw new Error('This is deprecated. Please set globalMode to true.'); - }, - - bindKeyListeners_: function() { - var hkc = this.hotkeyController; - - // Shortcuts that *can* steal focus from the console and the filter text - // box. - hkc.addHotKey(new tr.ui.b.HotKey({ - eventType: 'keypress', - keyCode: '`'.charCodeAt(0), - useCapture: true, - thisArg: this, - callback: function(e) { - this.scriptingCtl_.toggleVisibility(); - if (!this.scriptingCtl_.hasFocus) - this.focus(); - e.stopPropagation(); - } - })); - - // Shortcuts that *can* steal focus from the filter text box. - hkc.addHotKey(new tr.ui.b.HotKey({ - eventType: 'keypress', - keyCode: '/'.charCodeAt(0), - useCapture: true, - thisArg: this, - callback: function(e) { - if (this.scriptingCtl_.hasFocus) - return; - if (this.findCtl_.hasFocus) - this.focus(); - else - this.findCtl_.focus(); - e.preventDefault(); - e.stopPropagation(); - } - })); - - // Shortcuts that *can't* steal focus. - hkc.addHotKey(new tr.ui.b.HotKey({ - eventType: 'keypress', - keyCode: '?'.charCodeAt(0), - useCapture: false, - thisArg: this, - callback: function(e) { - this.$.view_help_button.click(); - e.stopPropagation(); - } - })); - - hkc.addHotKey(new tr.ui.b.HotKey({ - eventType: 'keypress', - keyCode: 'v'.charCodeAt(0), - useCapture: false, - thisArg: this, - callback: function(e) { - this.toggleHighlightVSync_(); - e.stopPropagation(); - } - })); - }, - - onViewportChanged_: function(e) { - var spc = this.sidePanelContainer_; - if (!this.trackView_) { - spc.rangeOfInterest.reset(); - return; + })); + + hkc.addHotKey(new tr.ui.b.HotKey({ + eventType: 'keypress', + keyCode: 'v'.charCodeAt(0), + useCapture: false, + thisArg: this, + callback: function(e) { + this.toggleHighlightVSync_(); + e.stopPropagation(); } + })); + }, + + onViewportChanged_: function(e) { + var spc = this.sidePanelContainer_; + if (!this.trackView_) { + spc.rangeOfInterest.reset(); + return; + } - var vr = this.trackView_.viewport.interestRange.asRangeObject(); - if (!spc.rangeOfInterest.equals(vr)) - spc.rangeOfInterest = vr; + var vr = this.trackView_.viewport.interestRange.asRangeObject(); + if (!spc.rangeOfInterest.equals(vr)) + spc.rangeOfInterest = vr; - if (this.railScoreSpan_ && this.model) - this.railScoreSpan_.model = this.model; - }, + if (this.railScoreSpan_ && this.model) + this.railScoreSpan_.model = this.model; + }, - toggleHighlightVSync_: function() { - this.highlightVSyncCheckbox_.checked = - !this.highlightVSyncCheckbox_.checked; - }, + toggleHighlightVSync_: function() { + this.highlightVSyncCheckbox_.checked = + !this.highlightVSyncCheckbox_.checked; + }, - setFindCtlText: function(string) { - this.findCtl_.setText(string); - } - }); - </script> -</polymer-element> + setFindCtlText: function(string) { + this.findCtl_.setText(string); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html index 1cde57bd69c..8e35cf3ccca 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_help_overlay.html @@ -8,7 +8,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/mouse_mode_icon.html"> <link rel="import" href="/tracing/ui/base/overlay.html"> -<polymer-element name="tr-ui-timeline-view-help-overlay"> +<dom-module id='tr-ui-timeline-view-help-overlay'> <template> <style> :host { @@ -102,7 +102,7 @@ found in the LICENSE file. </div> <h3> - <tr-ui-b-mouse-mode-icon modeName="SELECTION"></tr-ui-b-mouse-mode-icon> + <tr-ui-b-mouse-mode-icon mode-name="SELECTION"></tr-ui-b-mouse-mode-icon> Select mode </h3> <div class='pair'> @@ -121,7 +121,7 @@ found in the LICENSE file. </div> <h3> - <tr-ui-b-mouse-mode-icon modeName="PANSCAN"></tr-ui-b-mouse-mode-icon> + <tr-ui-b-mouse-mode-icon mode-name="PANSCAN"></tr-ui-b-mouse-mode-icon> Pan mode </h3> <div class='pair'> @@ -130,7 +130,7 @@ found in the LICENSE file. </div> <h3> - <tr-ui-b-mouse-mode-icon modeName="ZOOM"></tr-ui-b-mouse-mode-icon> + <tr-ui-b-mouse-mode-icon mode-name="ZOOM"></tr-ui-b-mouse-mode-icon> Zoom mode </h3> <div class='pair'> @@ -139,7 +139,7 @@ found in the LICENSE file. </div> <h3> - <tr-ui-b-mouse-mode-icon modeName="TIMING"></tr-ui-b-mouse-mode-icon> + <tr-ui-b-mouse-mode-icon mode-name="TIMING"></tr-ui-b-mouse-mode-icon> Timing mode </h3> <div class='pair'> @@ -226,18 +226,19 @@ found in the LICENSE file. </div> </div> </template> - - <script> - 'use strict'; - - Polymer('tr-ui-timeline-view-help-overlay', { - ready: function() { - var mod = tr.isMac ? 'cmd ' : 'ctrl'; - var spans = this.shadowRoot.querySelectorAll('span.mod'); - for (var i = 0; i < spans.length; i++) { - spans[i].textContent = mod; - } - } - }); - </script> -</polymer-element> +</dom-module> +<script> +'use strict'; + +Polymer({ + is: 'tr-ui-timeline-view-help-overlay', + + ready: function() { + var mod = tr.isMac ? 'cmd ' : 'ctrl'; + var spans = Polymer.dom(this.root).querySelectorAll( + 'span.mod'); + for (var i = 0; i < spans.length; i++) + Polymer.dom(spans[i]).textContent = mod; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html index 0727958cfbe..2ea3ea2453f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_metadata_overlay.html @@ -9,7 +9,7 @@ found in the LICENSE file. <link rel="import" href="/tracing/ui/base/overlay.html"> <link rel="import" href="/tracing/value/ui/generic_table_view.html"> -<polymer-element name="tr-ui-timeline-view-metadata-overlay"> +<dom-module id='tr-ui-timeline-view-metadata-overlay'> <template> <style> :host { @@ -20,23 +20,24 @@ found in the LICENSE file. </style> <tr-v-ui-generic-table-view id="gtv"></tr-v-ui-generic-table-view> </template> +</dom-module> +<script> +'use strict'; - <script> - 'use strict'; +Polymer({ + is: 'tr-ui-timeline-view-metadata-overlay', - Polymer('tr-ui-timeline-view-metadata-overlay', { - created: function() { - this.metadata_ = undefined; - }, + created: function() { + this.metadata_ = undefined; + }, - get metadata() { - return this.metadata_; - }, + get metadata() { + return this.metadata_; + }, - set metadata(metadata) { - this.metadata_ = metadata; - this.$.gtv.items = this.metadata_; - } - }); - </script> -</polymer-element> + set metadata(metadata) { + this.metadata_ = metadata; + this.$.gtv.items = this.metadata_; + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html index e3e2e060985..c87b325f17f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_view_test.html @@ -22,7 +22,7 @@ tr.b.unittest.testSuite(function() { container.id = 'track_view_container'; var view = document.createElement('tr-ui-timeline-view'); - view.appendChild(container); + Polymer.dom(view).appendChild(container); view.trackViewContainer_ = container; return view; } @@ -32,7 +32,7 @@ tr.b.unittest.testSuite(function() { var withMetadata = opt_withMetadata !== undefined ? opt_withMetadata : true; - var num_tests = 50; + var numTests = 50; var testIndex = 0; var startTime = 0; @@ -41,19 +41,19 @@ tr.b.unittest.testSuite(function() { io.showImportWarnings = false; model.importOptions = io; - for (testIndex = 0; testIndex < num_tests; ++testIndex) { + for (testIndex = 0; testIndex < numTests; ++testIndex) { var process = model.getOrCreateProcess(10000 + testIndex); - if (testIndex % 2 == 0) { + if (testIndex % 2 === 0) { var thread = process.getOrCreateThread('Thread Name Here'); - thread.sliceGroup.pushSlice(new tr.model.Slice( + thread.sliceGroup.pushSlice(new tr.model.ThreadSlice( 'foo', 'a', 0, startTime, {}, 1)); - thread.sliceGroup.pushSlice(new tr.model.Slice( + thread.sliceGroup.pushSlice(new tr.model.ThreadSlice( 'bar', 'b', 0, startTime + 23, {}, 10)); } else { var thread = process.getOrCreateThread('Name'); - thread.sliceGroup.pushSlice(new tr.model.Slice( + thread.sliceGroup.pushSlice(new tr.model.ThreadSlice( 'foo', 'a', 0, startTime + 4, {}, 11)); - thread.sliceGroup.pushSlice(new tr.model.Slice( + thread.sliceGroup.pushSlice(new tr.model.ThreadSlice( 'bar', 'b', 0, startTime + 22, {}, 14)); } } @@ -111,12 +111,12 @@ tr.b.unittest.testSuite(function() { view.model = model11; var simpleButton1 = document.createElement('tr-ui-b-toolbar-button'); - simpleButton1.textContent = 'M'; - view.leftControls.appendChild(simpleButton1); + Polymer.dom(simpleButton1).textContent = 'M'; + Polymer.dom(view.leftControls).appendChild(simpleButton1); var simpleButton2 = document.createElement('tr-ui-b-toolbar-button'); - simpleButton2.textContent = 'am button'; - view.leftControls.appendChild(simpleButton2); + Polymer.dom(simpleButton2).textContent = 'am button'; + Polymer.dom(view.leftControls).appendChild(simpleButton2); this.addHTMLOutput(view); }); @@ -158,4 +158,3 @@ tr.b.unittest.testSuite(function() { }); }); </script> - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html index 92f4679ae01..59301b9a62e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport.html @@ -113,17 +113,10 @@ tr.exportTo('tr.ui', function() { * and then runs the pendingSetFunction_, if present. */ checkForAttach_: function() { - if (!this.isAttachedToDocumentOrInTestMode || this.clientWidth == 0) + if (!this.isAttachedToDocumentOrInTestMode || this.clientWidth === 0) return; - if (!this.iframe_) { - this.iframe_ = document.createElement('iframe'); - this.iframe_.style.cssText = - 'position:absolute;width:100%;height:0;border:0;visibility:hidden;'; - this.parentEl_.appendChild(this.iframe_); - - this.iframe_.contentWindow.addEventListener('resize', this.onResize_); - } + window.addEventListener('resize', this.dispatchChangeEvent.bind(this)); var curSize = this.parentEl_.clientWidth + 'x' + this.parentEl_.clientHeight; @@ -155,10 +148,7 @@ tr.exportTo('tr.ui', function() { window.clearInterval(this.checkForAttachInterval_); this.checkForAttachInterval_ = undefined; } - if (this.iframe_) { - this.iframe_.removeEventListener('resize', this.onResize_); - this.parentEl_.removeChild(this.iframe_); - } + window.removeEventListener('resize', this.dispatchChangeEvent.bind(this)); }, initAnimationController_: function() { @@ -297,7 +287,7 @@ tr.exportTo('tr.ui', function() { }, set gridEnabled(enabled) { - if (this.gridEnabled_ == enabled) + if (this.gridEnabled_ === enabled) return; this.gridEnabled_ = enabled && true; @@ -309,7 +299,7 @@ tr.exportTo('tr.ui', function() { }, set gridTimebase(timebase) { - if (this.gridTimebase_ == timebase) + if (this.gridTimebase_ === timebase) return; this.gridTimebase_ = timebase; this.dispatchChangeEvent(); @@ -398,7 +388,7 @@ tr.exportTo('tr.ui', function() { event, offset, newSelection); } - if (newSelection.length == 0) + if (newSelection.length === 0) return undefined; return newSelection; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html index 75a4939427e..7492a56d7c1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/timeline_viewport_test.html @@ -64,87 +64,6 @@ tr.b.unittest.testSuite(function() { assert.isTrue(shifted.equals( new tr.model.EventSet(t1.sliceGroup.slices[1]))); }); - - test('locationObj', function() { - var process; - var thread; - var model = tr.c.TestUtils.newModelWithEvents([], { - shiftWorldToZero: false, - pruneContainers: false, - customizeModelCallback: function(model) { - process = model.getOrCreateProcess(123); - thread = process.getOrCreateThread(456); - - thread.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('a', 80, 20, thread, thread)); - thread.asyncSliceGroup.push( - tr.c.TestUtils.newAsyncSliceNamed('a', 85, 10, thread, thread)); - } - }); - - var timeline = document.createElement('tr-ui-timeline-track-view'); - var vp = new tr.ui.TimelineViewport(timeline); - timeline.model = model; - timeline.style.maxHeight = '600px'; - this.addHTMLOutput(timeline); - - // Our stableId to track map is not automatically built. We need to - // search for the tracks and manually build the stableId map here. - var processTracks = document.getElementsByClassName('process-track-base'); - vp.modelTrackContainer = { - addContainersToTrackMap: function(containerToTrackMap) { - // Invoking the process track's addContainersToTrackMap is enough to - // build the map for all children (i.e. Threads, AsyncSliceGroups) - // as well. - for (var i = 0; i < processTracks.length; i++) - processTracks[i].addContainersToTrackMap(containerToTrackMap); - }, - addEventListener: function() {}, - canvas: { - offsetLeft: tr.ui.b.constants.HEADING_WIDTH, - offsetTop: 0 - } - }; - vp.rebuildContainerToTrackMap(); - - var asyncTrack = - vp.containerToTrackMap.getTrackByStableId('123.456.AsyncSliceGroup'); - assert.isDefined(asyncTrack); - assert.isFalse(asyncTrack.expanded); // Make sure this starts unexpanded. - - // Hack to allow Location to find the element we're looking for. - // This ensures the correct behaviour of document.elementFrompoint(x,y) of - // an originally off-screen element. - asyncTrack.scrollIntoView(); - - var boundRect = asyncTrack.getBoundingClientRect(); - var viewX = boundRect.left; - var viewY = boundRect.top + boundRect.height / 2; - var location = Location.fromViewCoordinates(vp, viewX, viewY); - assert.equal(asyncTrack, location.getContainingTrack(vp)); - assert.deepEqual(location.toViewCoordinates(vp), - { viewX: viewX, viewY: viewY }); - - // Try expanding the multi-row track so that the dimensions of the thread - // track changes. - asyncTrack.expanded = true; - // Expanding the track causes the height to double. We can calculate the new - // viewY with respect to the track's old boundRect. ViewX remains unchanged. - var expandedViewY = boundRect.top + boundRect.height; - assert.deepEqual(location.toViewCoordinates(vp), - { viewX: viewX, viewY: expandedViewY }); - - // Test the functionality of fromStableIdAndTimestamp. - var locationFromCoord = - Location.fromViewCoordinates(vp, viewX, boundRect.top); - var locationFromStableId = - Location.fromStableIdAndTimestamp(vp, '123.456.AsyncSliceGroup', - location.xWorld); - assert.deepEqual(locationFromCoord, locationFromStableId); - - // Undo scroll. - document.getElementById('results-container').scrollTop = 0; - }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html index 48d488e3e48..723ca4522d9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/alert_track_test.html @@ -43,10 +43,10 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = AlertTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html index 56971486083..229402eba6b 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track.html @@ -28,14 +28,14 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport); - this.classList.add('async-slice-group-track'); + Polymer.dom(this).classList.add('async-slice-group-track'); this.group_ = undefined; }, addSubTrack_: function(slices) { var track = new tr.ui.tracks.SliceTrack(this.viewport); track.slices = slices; - this.appendChild(track); + Polymer.dom(this).appendChild(track); track.asyncStyle = true; return track; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html index cb924f42113..824b7d0cf2e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/async_slice_group_track_test.html @@ -6,8 +6,8 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/core/test_utils.html"> -<link rel="import" href="/tracing/ui/timeline_track_view.html"> <link rel="import" href="/tracing/model/model.html"> +<link rel="import" href="/tracing/ui/timeline_track_view.html"> <script> 'use strict'; @@ -216,8 +216,8 @@ tr.b.unittest.testSuite(function() { processTrack.process = process; threadTrack.thread = thread; groupTrack.group = group; - processTrack.appendChild(threadTrack); - threadTrack.appendChild(groupTrack); + Polymer.dom(processTrack).appendChild(threadTrack); + Polymer.dom(threadTrack).appendChild(groupTrack); assert.equal(processTrack.eventContainer, process); assert.equal(threadTrack.eventContainer, thread); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html index bf84ef56c6a..c8a974c8ba9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_series_test.html @@ -49,7 +49,7 @@ tr.b.unittest.testSuite(function() { function drawSeriesWithDetails(test, series, highDetails) { var div = document.createElement('div'); var canvas = document.createElement('canvas'); - div.appendChild(canvas); + Polymer.dom(div).appendChild(canvas); var pixelRatio = window.devicePixelRatio || 1; @@ -166,31 +166,29 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); series.addIntersectingEventsInRangeToSelectionInWorldSpace( -30.5, -29.5, 40, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 0); + assert.equal(tr.b.getOnlyElement(sel).index, 0); // Select second point. var sel = new EventSet(); series.addIntersectingEventsInRangeToSelectionInWorldSpace( -28.8, -28.2, 40, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 1); + assert.equal(tr.b.getOnlyElement(sel).index, 1); // Select points in the middle. var sel = new EventSet(); series.addIntersectingEventsInRangeToSelectionInWorldSpace( -0.99, 1.01, 40, sel); assert.lengthOf(sel, 3); - assert.equal(sel[0].index, 29); - assert.equal(sel[1].index, 30); - assert.equal(sel[2].index, 31); + var iterator = sel[Symbol.iterator](); + assert.equal(iterator.next().value.index, 29); + assert.equal(iterator.next().value.index, 30); + assert.equal(iterator.next().value.index, 31); // Select the last point. var sel = new EventSet(); series.addIntersectingEventsInRangeToSelectionInWorldSpace( 668.99, 668.99, 40, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 59); + assert.equal(tr.b.getOnlyElement(sel).index, 59); // Too far right. var sel = new EventSet(); @@ -223,8 +221,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); assert.isTrue(series.addEventNearToProvidedEventToSelection( series.points[0].modelItem, 1, sel)); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 1); + assert.equal(tr.b.getOnlyElement(sel).index, 1); var sel = new EventSet(); assert.isFalse(series.addEventNearToProvidedEventToSelection( @@ -235,14 +232,12 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); assert.isTrue(series.addEventNearToProvidedEventToSelection( series.points[30].modelItem, 1, sel)); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 31); + assert.equal(tr.b.getOnlyElement(sel).index, 31); var sel = new EventSet(); assert.isTrue(series.addEventNearToProvidedEventToSelection( series.points[30].modelItem, -1, sel)); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 29); + assert.equal(tr.b.getOnlyElement(sel).index, 29); // Last point. var sel = new EventSet(); @@ -253,8 +248,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); assert.isTrue(series.addEventNearToProvidedEventToSelection( series.points[59].modelItem, -1, sel)); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 58); + assert.equal(tr.b.getOnlyElement(sel).index, 58); }); test('checkAddClosestEventToSelection', function() { @@ -267,8 +261,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); series.addClosestEventToSelection(-40, 11, -0.5, 0.5, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 0); + assert.equal(tr.b.getOnlyElement(sel).index, 0); // Between two points. var sel = new EventSet(); @@ -277,8 +270,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); series.addClosestEventToSelection(0.4, 0.4, -0.5, 0.5, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 30); + assert.equal(tr.b.getOnlyElement(sel).index, 30); // Right of last point. var sel = new EventSet(); @@ -287,8 +279,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); series.addClosestEventToSelection(40, 12, -0.5, 0.5, sel); - assert.lengthOf(sel, 1); - assert.equal(sel[0].index, 59); + assert.equal(tr.b.getOnlyElement(sel).index, 59); }); }); </script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html index 86e80ae1cde..f736a5bfd13 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track.html @@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/tracks/chart_transform.html"> -<link rel="import" href="/tracing/ui/tracks/track.html"> <link rel="import" href="/tracing/ui/base/heading.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/chart_transform.html"> +<link rel="import" href="/tracing/ui/tracks/track.html"> <style> .chart-track { @@ -36,7 +36,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('chart-track'); + Polymer.dom(this).classList.add('chart-track'); this.series_ = undefined; // GUID -> {axis: ChartAxis, series: [ChartSeries]}. @@ -47,7 +47,7 @@ tr.exportTo('tr.ui.tracks', function() { this.bottomPadding_ = undefined; this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, set heading(heading) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html index 7595a2e2cd7..e7dfbb02131 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_track_test.html @@ -101,10 +101,10 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = buildTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); @@ -122,10 +122,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); viewport.highDetails = true; var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = buildTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); track.series[0].points[1].modelItem.selectionState = SelectionState.SELECTED; @@ -167,9 +167,10 @@ tr.b.unittest.testSuite(function() { track.addIntersectingEventsInRangeToSelectionInWorldSpace( -1.1, -0.7, 0.01, sel); assert.lengthOf(sel, 3); - assert.equal(sel[0], track.series[0].points[1].modelItem); - assert.equal(sel[1], track.series[1].points[1].modelItem); - assert.equal(sel[2], track.series[2].points[3].modelItem); + var iterator = sel[Symbol.iterator](); + assert.equal(iterator.next().value, track.series[0].points[1].modelItem); + assert.equal(iterator.next().value, track.series[1].points[1].modelItem); + assert.equal(iterator.next().value, track.series[2].points[3].modelItem); }); test('checkaddEventNearToProvidedEventToSelection', function() { @@ -185,8 +186,7 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); assert.isTrue(track.addEventNearToProvidedEventToSelection( track.series[1].points[1].modelItem, 1, sel)); - assert.lengthOf(sel, 1); - assert.equal(sel[0], track.series[1].points[2].modelItem); + assert.equal(tr.b.getOnlyElement(sel), track.series[1].points[2].modelItem); }); test('checkAddClosestEventToSelection', function() { @@ -195,8 +195,9 @@ tr.b.unittest.testSuite(function() { var sel = new EventSet(); track.addClosestEventToSelection(-0.8, 0.4, 0.5, 1.5, sel); assert.lengthOf(sel, 2); - assert.equal(sel[0], track.series[0].points[2].modelItem); - assert.equal(sel[1], track.series[2].points[4].modelItem); + var iterator = sel[Symbol.iterator](); + assert.equal(iterator.next().value, track.series[0].points[2].modelItem); + assert.equal(iterator.next().value, track.series[2].points[4].modelItem); }); test('checkAutoSetAllAxes', function() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html index ff98f4057e0..026c432b161 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/chart_transform.html @@ -26,7 +26,7 @@ tr.exportTo('tr.ui.tracks', function() { * outerTopViewY -> +--------------------/-\-------+ <- Top padding * innerTopViewY -> + - - - - - - - - - -| |- - - -+ <- Axis max * | .. ==\-/== | - * | == Series == | + * | === Series === | * | ==/-\== .. | * innerBottomViewY -> + - - -Point- - - - - - - - - -+ <- Axis min * outerBottomViewY -> +-------\-/--------------------+ <- Bottom padding @@ -60,7 +60,7 @@ tr.exportTo('tr.ui.tracks', function() { this.axis_ = axis; this.innerHeight_ = this.innerBottomViewY - this.innerTopViewY; - }; + } ChartTransform.prototype = { worldXToViewX: function(worldX) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html index cdad43bef5c..566004740c9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/container_track.html @@ -6,9 +6,9 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/base/task.html"> -<link rel="import" href="/tracing/ui/tracks/track.html"> <link rel="import" href="/tracing/core/filter.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/track.html"> <script> 'use strict'; @@ -29,7 +29,7 @@ tr.exportTo('tr.ui.tracks', function() { }, detach: function() { - this.textContent = ''; + Polymer.dom(this).textContent = ''; }, get tracks_() { @@ -120,7 +120,7 @@ tr.exportTo('tr.ui.tracks', function() { clearTracks_: function() { this.tracks_.forEach(function(track) { - this.removeChild(track); + Polymer.dom(this).removeChild(track); }, this); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html index 759b2433596..638c8bbce41 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track.html @@ -5,11 +5,11 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/tracks/chart_axis.html"> <link rel="import" href="/tracing/ui/tracks/chart_point.html"> <link rel="import" href="/tracing/ui/tracks/chart_series.html"> <link rel="import" href="/tracing/ui/tracks/chart_track.html"> -<link rel="import" href="/tracing/ui/base/ui.html"> <script> 'use strict'; @@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.ChartTrack.prototype.decorate.call(this, viewport); - this.classList.add('counter-track'); + Polymer.dom(this).classList.add('counter-track'); }, get counter() { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html index afa3ad3f967..1224676b0d7 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_perf_test.html @@ -56,11 +56,11 @@ tr.b.unittest.testSuite(function() { viewport.modelTrackContainer = drawingContainer; var modelTrack = new tr.ui.tracks.ModelTrack(viewport); - drawingContainer.appendChild(modelTrack); + Polymer.dom(drawingContainer).appendChild(modelTrack); modelTrack.model = model; - viewportDiv.appendChild(drawingContainer); + Polymer.dom(viewportDiv).appendChild(drawingContainer); this.addHTMLOutput(viewportDiv); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html index 8cf6dcdfa00..4a1b8b0badc 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/counter_track_test.html @@ -41,10 +41,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(testEl); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - testEl.appendChild(drawingContainer); + Polymer.dom(testEl).appendChild(drawingContainer); var track = new CounterTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(testEl); // Force the container to update sizes so the test can use coordinates that @@ -88,10 +88,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new CounterTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html index 84b7afe6582..dd4dfe0c97a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track.html @@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport); - this.classList.add('cpu-track'); + Polymer.dom(this).classList.add('cpu-track'); this.detailedMode_ = true; }, @@ -81,7 +81,7 @@ tr.exportTo('tr.ui.tracks', function() { var track = new tr.ui.tracks.SliceTrack(this.viewport); track.slices = slices; track.heading = this.cpu_.userFriendlyName + ':'; - this.appendChild(track); + Polymer.dom(this).appendChild(track); } if (this.detailedMode_) { @@ -93,7 +93,7 @@ tr.exportTo('tr.ui.tracks', function() { track.heading = this.cpu_.userFriendlyName + ' ' + counter.name + ':'; track.counter = counter; - this.appendChild(track); + Polymer.dom(this).appendChild(track); } } }, @@ -127,7 +127,7 @@ tr.exportTo('tr.ui.tracks', function() { } return selection; }; - this.appendChild(samplesTrack); + Polymer.dom(this).appendChild(samplesTrack); }, this); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html index 61108d514fc..bd268b50940 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/cpu_track_test.html @@ -6,8 +6,8 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/core/test_utils.html"> -<link rel="import" href="/tracing/ui/timeline_track_view.html"> <link rel="import" href="/tracing/model/model.html"> +<link rel="import" href="/tracing/ui/timeline_track_view.html"> <script> 'use strict'; @@ -15,7 +15,7 @@ found in the LICENSE file. tr.b.unittest.testSuite(function() { var Cpu = tr.model.Cpu; var CpuTrack = tr.ui.tracks.CpuTrack; - var Slice = tr.model.Slice; + var ThreadSlice = tr.model.ThreadSlice; var StackFrame = tr.model.StackFrame; var Sample = tr.model.Sample; var Thread = tr.model.Thread; @@ -24,8 +24,8 @@ tr.b.unittest.testSuite(function() { test('basicCpu', function() { var cpu = new Cpu({}, 7); cpu.slices = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 2.1, {}, 4.8) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 2.1, {}, 4.8) ]; cpu.updateBounds(); @@ -35,7 +35,7 @@ tr.b.unittest.testSuite(function() { var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); var track = new CpuTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); track.heading = 'CPU ' + cpu.cpuNumber; track.cpu = cpu; @@ -86,7 +86,7 @@ tr.b.unittest.testSuite(function() { var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); var track = new CpuTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); track.heading = 'CPU ' + cpu.cpuNumber; track.cpu = cpu; @@ -96,4 +96,3 @@ tr.b.unittest.testSuite(function() { }); }); </script> - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html index dfc6c364eea..c29086490f9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track.html @@ -32,7 +32,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { ContainerTrack.prototype.decorate.call(this, viewport); - this.classList.add('device-track'); + Polymer.dom(this).classList.add('device-track'); this.device_ = undefined; this.powerSeriesTrack_ = undefined; }, @@ -72,8 +72,9 @@ tr.exportTo('tr.ui.tracks', function() { this.powerSeriesTrack_.powerSeries = this.device.powerSeries; if (this.powerSeriesTrack_.hasVisibleContent) { - this.appendChild(this.powerSeriesTrack_); - this.appendChild(new tr.ui.tracks.SpacingTrack(this.viewport)); + Polymer.dom(this).appendChild(this.powerSeriesTrack_); + Polymer.dom(this).appendChild( + new tr.ui.tracks.SpacingTrack(this.viewport)); } }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html index ce849355882..ed670eb5baa 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/device_track_test.html @@ -28,7 +28,7 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new tr.ui.TimelineViewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); if (series) { series.updateBounds(); @@ -62,7 +62,7 @@ tr.b.unittest.testSuite(function() { var drawingContainer = createDrawingContainer(device.powerSeries); var track = new DeviceTrack(drawingContainer.viewport); track.device = device; - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(drawingContainer); }); @@ -73,7 +73,7 @@ tr.b.unittest.testSuite(function() { var drawingContainer = createDrawingContainer(device.powerSeries); var track = new DeviceTrack(drawingContainer.viewport); track.device = device; - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); // Adding output should throw due to no visible content. assert.throw(function() { this.addHTMLOutput(drawingContainer); }); @@ -94,7 +94,7 @@ tr.b.unittest.testSuite(function() { var track = new DeviceTrack(drawingContainer.viewport); track.device = device; track.device = device; - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(drawingContainer); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html index 69a8ca43026..56014ac31a0 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container.html @@ -8,9 +8,9 @@ found in the LICENSE file. <link rel="stylesheet" href="/tracing/ui/tracks/drawing_container.css"> <link rel="import" href="/tracing/base/raf.html"> -<link rel="import" href="/tracing/ui/tracks/track.html"> <link rel="import" href="/tracing/ui/base/constants.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/track.html"> <script> 'use strict'; @@ -35,12 +35,12 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('drawing-container'); + Polymer.dom(this).classList.add('drawing-container'); this.canvas_ = document.createElement('canvas'); this.canvas_.className = 'drawing-container-canvas'; this.canvas_.style.left = tr.ui.b.constants.HEADING_WIDTH + 'px'; - this.appendChild(this.canvas_); + Polymer.dom(this).appendChild(this.canvas_); this.ctx_ = this.canvas_.getContext('2d'); @@ -112,6 +112,10 @@ tr.exportTo('tr.ui.tracks', function() { var visibleChildTracks = tr.b.asArray(this.children).filter(this.visibleFilter_); + if (visibleChildTracks.length === 0) { + return; + } + var thisBounds = this.getBoundingClientRect(); var firstChildTrackBounds = visibleChildTracks[0].getBoundingClientRect(); @@ -124,12 +128,12 @@ tr.exportTo('tr.ui.tracks', function() { var innerHeight = lastChildTrackBounds.bottom - firstChildTrackBounds.top; var pixelRatio = window.devicePixelRatio || 1; - if (this.canvas_.width != innerWidth * pixelRatio) { + if (this.canvas_.width !== innerWidth * pixelRatio) { this.canvas_.width = innerWidth * pixelRatio; this.canvas_.style.width = innerWidth + 'px'; } - if (this.canvas_.height != innerHeight * pixelRatio) { + if (this.canvas_.height !== innerHeight * pixelRatio) { this.canvas_.height = innerHeight * pixelRatio; this.canvas_.style.height = innerHeight + 'px'; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html index 9cb3d727c66..3645c4b8394 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/drawing_container_perf_test.html @@ -42,11 +42,11 @@ tr.b.unittest.testSuite(function() { this.viewport.modelTrackContainer = this.drawingContainer; var modelTrack = new tr.ui.tracks.ModelTrack(this.viewport); - this.drawingContainer.appendChild(modelTrack); + Polymer.dom(this.drawingContainer).appendChild(modelTrack); modelTrack.model = model; - this.viewportDiv.appendChild(this.drawingContainer); + Polymer.dom(this.viewportDiv).appendChild(this.drawingContainer); this.addHTMLOutput(this.viewportDiv); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html index 943e245b37c..9918fec0935 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/frame_track_test.html @@ -48,10 +48,10 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = FrameTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html index 0e2e4d54c24..143957a8640 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track.html @@ -63,7 +63,7 @@ tr.exportTo('tr.ui.tracks', function() { var track = new tr.ui.tracks.LetterDotTrack(this.viewport); track.heading = 'Memory Dumps'; track.items = items; - this.appendChild(track); + Polymer.dom(this).appendChild(track); }, appendUsedMemoryTrack_: function() { @@ -77,7 +77,7 @@ tr.exportTo('tr.ui.tracks', function() { track.height = USED_MEMORY_TRACK_HEIGHT + 'px'; track.series = series; track.autoSetAllAxes({expandMax: true}); - this.appendChild(track); + Polymer.dom(this).appendChild(track); }, appendAllocatedMemoryTrack_: function() { @@ -91,7 +91,7 @@ tr.exportTo('tr.ui.tracks', function() { track.height = ALLOCATED_MEMORY_TRACK_HEIGHT + 'px'; track.series = series; track.autoSetAllAxes({expandMax: true}); - this.appendChild(track); + Polymer.dom(this).appendChild(track); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html index 268da37bcf7..0add321fca7 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/global_memory_dump_track_test.html @@ -26,10 +26,10 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new GlobalMemoryDumpTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); drawingContainer.invalidate(); track.memoryDumps = dumps; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html index 8e8f181ff90..7c9c049d956 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track.html @@ -56,7 +56,7 @@ tr.exportTo('tr.ui.tracks', function() { addSubTrack_: function(slices) { var track = new tr.ui.tracks.SliceTrack(this.viewport); track.slices = slices; - this.appendChild(track); + Polymer.dom(this).appendChild(track); return track; } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html index 1b2c1346a16..b98c2417c7e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/interaction_track_test.html @@ -22,7 +22,7 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new tr.ui.TimelineViewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new tr.ui.tracks.InteractionTrack(viewport); track.model = tr.c.TestUtils.newModel(function(model) { var process = model.getOrCreateProcess(1); @@ -44,7 +44,7 @@ tr.b.unittest.testSuite(function() { assert.equal(2, track.subRows_.length); assert.equal(2, track.subRows_[0].length); assert.equal(3, track.subRows_[1].length); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); }); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html index 20ffea84d05..f69f61ef0e9 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/kernel_track.html @@ -5,8 +5,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/tracks/process_track_base.html"> <link rel="import" href="/tracing/ui/tracks/cpu_track.html"> +<link rel="import" href="/tracing/ui/tracks/process_track_base.html"> <link rel="import" href="/tracing/ui/tracks/spacing_track.html"> <script> @@ -66,11 +66,11 @@ tr.exportTo('tr.ui.tracks', function() { track.cpu = cpu; if (!track.hasVisibleContent) continue; - this.appendChild(track); + Polymer.dom(this).appendChild(track); didAppendAtLeastOneTrack = true; } if (didAppendAtLeastOneTrack) - this.appendChild(new SpacingTrack(this.viewport)); + Polymer.dom(this).appendChild(new SpacingTrack(this.viewport)); } }; @@ -80,4 +80,3 @@ tr.exportTo('tr.ui.tracks', function() { }; }); </script> - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html index 64f26e4fb4f..75ff6c86927 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track.html @@ -39,11 +39,11 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('letter-dot-track'); + Polymer.dom(this).classList.add('letter-dot-track'); this.items_ = undefined; this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, set heading(heading) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html index 93c2bcfbb9a..6f55ed14b62 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/letter_dot_track_test.html @@ -38,10 +38,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = LetterDotTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html index 2d13a901ba8..517eec0f2db 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_test_utils.html @@ -29,6 +29,7 @@ tr.exportTo('tr.ui.tracks', function() { var addProcessMemoryDump = tr.model.MemoryDumpTestUtils.addProcessMemoryDump; var newAllocatorDump = tr.model.MemoryDumpTestUtils.newAllocatorDump; var addOwnershipLink = tr.model.MemoryDumpTestUtils.addOwnershipLink; + var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND; var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT; var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED; @@ -54,7 +55,8 @@ tr.exportTo('tr.ui.tracks', function() { var allocatorDumps = tr.b.mapItems(dumpData, function(allocatorName, data) { var size = data.size; assert.typeOf(size, 'number'); // Sanity check. - return newAllocatorDump(memoryDump, allocatorName, { size: size }); + return newAllocatorDump(memoryDump, allocatorName, + {numerics: {size: size}}); }); // Add ownership links between them. @@ -76,7 +78,7 @@ tr.exportTo('tr.ui.tracks', function() { function addProcessMemoryDumpWithFields(globalMemoryDump, process, start, opt_pssValues, opt_dumpData) { - var pmd = addProcessMemoryDump(globalMemoryDump, process, start); + var pmd = addProcessMemoryDump(globalMemoryDump, process, {ts: start}); if (opt_pssValues !== undefined) pmd.vmRegions = createVMRegions(opt_pssValues); if (opt_dumpData !== undefined) @@ -96,12 +98,12 @@ tr.exportTo('tr.ui.tracks', function() { var pb = model.getOrCreateProcess(6); var pc = model.getOrCreateProcess(9); - var gmd1 = addGlobalMemoryDump(model, 0, LIGHT); + var gmd1 = addGlobalMemoryDump(model, {ts: 0, levelOfDetail: LIGHT}); addProcessMemoryDumpWithFields(gmd1, pa, 0, maybePssValues([111])); addProcessMemoryDumpWithFields(gmd1, pb, 0.2, undefined, maybeDumpData({oilpan: {size: 1024}})); - var gmd2 = addGlobalMemoryDump(model, 5, DETAILED); + var gmd2 = addGlobalMemoryDump(model, {ts: 5, levelOfDetail: DETAILED}); addProcessMemoryDumpWithFields(gmd2, pa, 0); addProcessMemoryDumpWithFields(gmd2, pb, 4.99, maybePssValues([100, 50]), maybeDumpData({v8: {size: 512}})); @@ -109,13 +111,20 @@ tr.exportTo('tr.ui.tracks', function() { maybeDumpData({oilpan: {size: 128, owns: 'v8'}, v8: {size: 384, owns: 'tracing'}, tracing: {size: 65920}})); - var gmd3 = addGlobalMemoryDump(model, 15, DETAILED); + var gmd3 = addGlobalMemoryDump(model, {ts: 15, levelOfDetail: DETAILED}); addProcessMemoryDumpWithFields(gmd3, pa, 15.5, maybePssValues([]), maybeDumpData({v8: {size: 768}})); addProcessMemoryDumpWithFields(gmd3, pc, 14.5, maybePssValues([70, 70, 70]), maybeDumpData({oilpan: {size: 512}})); - var gmd4 = addGlobalMemoryDump(model, 18, LIGHT); + var gmd4 = addGlobalMemoryDump(model, {ts: 18, levelOfDetail: LIGHT}); + + var gmd5 = addGlobalMemoryDump(model, + {ts: 20, levelOfDetail: BACKGROUND}); + addProcessMemoryDumpWithFields(gmd5, pa, 0, maybePssValues([105])); + addProcessMemoryDumpWithFields(gmd5, pb, 0.2, undefined, + maybeDumpData({oilpan: {size: 100}})); + }); } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html index 821186182b4..a7fd6d19380 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util.html @@ -5,6 +5,7 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/base/iteration_helpers.html"> <link rel="import" href="/tracing/model/container_memory_dump.html"> <link rel="import" href="/tracing/model/memory_allocator_dump.html"> <link rel="import" href="/tracing/ui/tracks/chart_axis.html"> @@ -22,35 +23,26 @@ tr.exportTo('tr.ui.tracks', function() { var DISPLAYED_SIZE_NUMERIC_NAME = tr.model.MemoryAllocatorDump.DISPLAYED_SIZE_NUMERIC_NAME; + var BACKGROUND = tr.model.ContainerMemoryDump.LevelOfDetail.BACKGROUND; var LIGHT = tr.model.ContainerMemoryDump.LevelOfDetail.LIGHT; var DETAILED = tr.model.ContainerMemoryDump.LevelOfDetail.DETAILED; - /** - * Add numeric values from a source dictionary to the numeric values in - * a destination dictionary. Undefined values are treated as zeros. Note that - * this method modifies the destination dictionary in place. - * - * Example: addDictionary({a: 1, b: 2}, {b: 3, c: 4}) will update the - * destination dictionary (first argument) to {a: 1, b: 5, c: 4}. - */ - function addDictionary(dstDict, srcDict) { - tr.b.iterItems(srcDict, function(key, value) { - var existingValue = dstDict[key]; - if (existingValue === undefined) - existingValue = 0; - dstDict[key] = existingValue + value; + /** Extract PSS values of processes in a global memory dump. */ + function extractGlobalMemoryDumpUsedSizes(globalMemoryDump, addSize) { + tr.b.iterItems(globalMemoryDump.processMemoryDumps, function(pid, pmd) { + var mostRecentVmRegions = pmd.mostRecentVmRegions; + if (mostRecentVmRegions === undefined) + return; + addSize(pid, mostRecentVmRegions.byteStats.proportionalResident || 0, + pmd.process.userFriendlyName); }); } - /** - * Get a dictionary mapping root allocator names (e.g. 'v8') to the - * corresponding sizes (e.g. 1024) in a process memory dump. - */ - function getProcessMemoryDumpAllocatorSizes(processMemoryDump) { + /** Extract sizes of root allocators in a process memory dump. */ + function extractProcessMemoryDumpAllocatorSizes(processMemoryDump, addSize) { var allocatorDumps = processMemoryDump.memoryAllocatorDumps; if (allocatorDumps === undefined) - return {}; - var allocatorSizes = {}; + return; allocatorDumps.forEach(function(allocatorDump) { // Don't show tracing overhead in the charts. // TODO(petrcermak): Find a less hacky way to do this. @@ -62,72 +54,91 @@ tr.exportTo('tr.ui.tracks', function() { var allocatorSizeValue = allocatorSize.value; if (allocatorSizeValue === undefined) return; - allocatorSizes[allocatorDump.fullName] = allocatorSizeValue; + addSize(allocatorDump.fullName, allocatorSizeValue); }); - return allocatorSizes; - }; + } - /** - * Get a dictionary mapping root allocator names (e.g. 'v8') to the - * corresponding sizes (e.g. 1024) in a global memory dump (i.e. summed over - * all simultaneous process memory dumps). - */ - function getGlobalMemoryDumpAllocatorSizes(globalMemoryDump) { - var globalAllocatorSizes = {}; - tr.b.iterItems(globalMemoryDump.processMemoryDumps, - function(pid, processMemoryDump) { - addDictionary(globalAllocatorSizes, - getProcessMemoryDumpAllocatorSizes(processMemoryDump)); - }); - return globalAllocatorSizes; + /** Extract sizes of root allocators in a global memory dump. */ + function extractGlobalMemoryDumpAllocatorSizes(globalMemoryDump, addSize) { + tr.b.iterItems( + globalMemoryDump.processMemoryDumps, + (pid, pmd) => extractProcessMemoryDumpAllocatorSizes(pmd, addSize)); } /** - * A generic function which converts a list of memory dumps to a list of chart - * series (one per root allocator). Each series represents the evolution of - * the size of a the corresponding root allocator (e.g. 'v8') over time. + * A generic function which converts a list of memory dumps to a list of + * chart series. + * + * @param {!Array<!tr.model.ContainerMemoryDump>} memoryDumps List of + * container memory dumps. + * @param {!function( + * !tr.model.ContainerMemoryDump, + * !function(string, number, string=))} dumpSizeExtractor Callback for + * extracting sizes from a container memory dump. + * @return {(!Array<!tr.ui.tracks.ChartSeries>|undefined)} List of chart + * series (or undefined if no size is extracted from any container memory + * dump). */ - function buildAllocatedMemoryChartSeries(memoryDumps, - memoryDumpToAllocatorSizesFn) { - var allocatorNameToPoints = {}; - var dumpsData = memoryDumps.map(function(memoryDump) { - var allocatorSizes = memoryDumpToAllocatorSizesFn(memoryDump); - tr.b.iterItems(allocatorSizes, function(allocatorName) { - allocatorNameToPoints[allocatorName] = []; + function buildMemoryChartSeries(memoryDumps, dumpSizeExtractor) { + var dumpCount = memoryDumps.length; + var idToTimestampToPoint = {}; + var idToName = {}; + + // Extract the sizes of all components from each memory dump. + memoryDumps.forEach(function(dump, index) { + dumpSizeExtractor(dump, function addSize(id, size, opt_name) { + var timestampToPoint = idToTimestampToPoint[id]; + if (timestampToPoint === undefined) { + idToTimestampToPoint[id] = timestampToPoint = new Array(dumpCount); + for (var i = 0; i < dumpCount; i++) { + var modelItem = memoryDumps[i]; + timestampToPoint[i] = new tr.ui.tracks.ChartPoint( + modelItem, modelItem.start, 0); + } + } + timestampToPoint[index].y += size; + if (opt_name !== undefined) + idToName[id] = opt_name; }); - return {dump: memoryDump, sizes: allocatorSizes}; }); - // Do not generate any chart series if no process memory dump contains any - // allocator dumps. - if (Object.keys(allocatorNameToPoints).length === 0) + // Do not generate any chart series if no sizes were extracted. + var ids = Object.keys(idToTimestampToPoint); + if (ids.length === 0) return undefined; - dumpsData.forEach(function(dumpData) { - var memoryDump = dumpData.dump; - var allocatorSizes = dumpData.sizes; - tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) { - var allocatorSize = allocatorSizes[allocatorName] || 0; - points.push(new tr.ui.tracks.ChartPoint( - memoryDump, memoryDump.start, allocatorSize)); - }); - }); + ids.sort(); + for (var i = 0; i < dumpCount; i++) { + var baseSize = 0; + // Traverse |ids| in reverse (alphabetical) order so that the first id is + // at the top of the chart. + for (var j = ids.length - 1; j >= 0; j--) { + var point = idToTimestampToPoint[ids[j]][i]; + point.yBase = baseSize; + point.y += baseSize; + baseSize = point.y; + } + } - // Create one common axis for all allocated memory chart series. + // Create one common axis for all memory chart series. var axis = new tr.ui.tracks.ChartAxis(0); - // Build a chart series for each allocator. - var series = []; - tr.b.iterItems(allocatorNameToPoints, function(allocatorName, points) { + // Build a chart series for each id. + var series = ids.map(function(id) { var colorId = ColorScheme.getColorIdForGeneralPurposeString( - allocatorName); + idToName[id] || id); var renderingConfig = { - chartType: tr.ui.tracks.ChartSeriesType.LINE, - colorId: colorId + chartType: tr.ui.tracks.ChartSeriesType.AREA, + colorId: colorId, + backgroundOpacity: 0.8 }; - series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig)); + return new tr.ui.tracks.ChartSeries(idToTimestampToPoint[id], + axis, renderingConfig); }); + // Ensure that the series at the top of the chart are drawn last. + series.reverse(); + return series; } @@ -136,6 +147,8 @@ tr.exportTo('tr.ui.tracks', function() { * inside). */ function buildMemoryLetterDots(memoryDumps) { + var backgroundMemoryColorId = + ColorScheme.getColorIdForReservedName('background_memory_dump'); var lightMemoryColorId = ColorScheme.getColorIdForReservedName('light_memory_dump'); var detailedMemoryColorId = @@ -143,6 +156,9 @@ tr.exportTo('tr.ui.tracks', function() { return memoryDumps.map(function(memoryDump) { var memoryColorId; switch (memoryDump.levelOfDetail) { + case BACKGROUND: + memoryColorId = backgroundMemoryColorId; + break; case DETAILED: memoryColorId = detailedMemoryColorId; break; @@ -161,71 +177,8 @@ tr.exportTo('tr.ui.tracks', function() { * process over time. */ function buildGlobalUsedMemoryChartSeries(globalMemoryDumps) { - // Do not generate the chart if no process memory dump contains VM regions. - var containsVmRegions = globalMemoryDumps.some(function(globalDump) { - for (var pid in globalDump.processMemoryDumps) - if (globalDump.processMemoryDumps[pid].mostRecentVmRegions) - return true; - return false; - }); - if (!containsVmRegions) - return undefined; - - // Find all processes that dump memory at least once. - var pidToProcess = {}; - globalMemoryDumps.forEach(function(globalDump) { - tr.b.iterItems(globalDump.processMemoryDumps, function(pid, processDump) { - pidToProcess[pid] = processDump.process; - }); - }); - - // Build one list of points for each instrumented process. - var pidToPoints = {}; - tr.b.iterItems(pidToProcess, function(pid, process) { - pidToPoints[pid] = []; - }); - - // For every timestamp, calculate the total PSS (proportional set size) of - // each process and append it to the corresponding list of points. - globalMemoryDumps.forEach(function(globalDump) { - var pssBase = 0; - tr.b.iterItems(pidToPoints, function(pid, points) { - var processMemoryDump = globalDump.processMemoryDumps[pid]; - var cumulativePss = pssBase; - // If no dump was found (probably dead) or it does not provide the - // necessary information (namely most recent VM regions), assume zero. - if (processMemoryDump !== undefined) { - var vmRegions = processMemoryDump.mostRecentVmRegions; - if (vmRegions !== undefined) - cumulativePss += vmRegions.byteStats.proportionalResident || 0; - } - points.push(new tr.ui.tracks.ChartPoint( - globalDump, globalDump.start, cumulativePss, pssBase)); - pssBase = cumulativePss; - }); - }); - - // Create one common axis for all used memory chart series. - var axis = new tr.ui.tracks.ChartAxis(0); - - // Build a chart series for each instrumented process. - var series = []; - tr.b.iterItems(pidToPoints, function(pid, points) { - var process = pidToProcess[pid]; - var colorId = ColorScheme.getColorIdForGeneralPurposeString( - process.userFriendlyName); - var renderingConfig = { - chartType: tr.ui.tracks.ChartSeriesType.AREA, - colorId: colorId, - backgroundOpacity: 0.8 - }; - series.push(new tr.ui.tracks.ChartSeries(points, axis, renderingConfig)); - }); - - // Show the first series (with the smallest cumulative value) at the top. - series.reverse(); - - return series; + return buildMemoryChartSeries(globalMemoryDumps, + extractGlobalMemoryDumpUsedSizes); } /** @@ -234,8 +187,8 @@ tr.exportTo('tr.ui.tracks', function() { * corresponding root allocator (e.g. 'v8') over time. */ function buildProcessAllocatedMemoryChartSeries(processMemoryDumps) { - return buildAllocatedMemoryChartSeries(processMemoryDumps, - getProcessMemoryDumpAllocatorSizes); + return buildMemoryChartSeries(processMemoryDumps, + extractProcessMemoryDumpAllocatorSizes); } /** @@ -244,8 +197,8 @@ tr.exportTo('tr.ui.tracks', function() { * corresponding root allocator (e.g. 'v8') over time. */ function buildGlobalAllocatedMemoryChartSeries(globalMemoryDumps) { - return buildAllocatedMemoryChartSeries(globalMemoryDumps, - getGlobalMemoryDumpAllocatorSizes); + return buildMemoryChartSeries(globalMemoryDumps, + extractGlobalMemoryDumpAllocatorSizes); } return { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html index 58e46078245..f19757c1553 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/memory_dump_track_util_test.html @@ -22,11 +22,12 @@ tr.b.unittest.testSuite(function() { var dumps = createTestGlobalMemoryDumps(false, false); var items = tr.ui.tracks.buildMemoryLetterDots(dumps); - assert.lengthOf(items, 4); + assert.lengthOf(items, 5); assert.equal(items[0].start, 0); assert.equal(items[1].start, 5); assert.equal(items[2].start, 15); assert.equal(items[3].start, 18); + assert.equal(items[4].start, 20); // Check model mapping. assert.equal(items[1].selectionState, SelectionState.HIGHLIGHTED); @@ -38,11 +39,12 @@ tr.b.unittest.testSuite(function() { var dumps = createTestGlobalMemoryDumps(false, false); var items = tr.ui.tracks.buildMemoryLetterDots(dumps); - assert.lengthOf(items, 4); + assert.lengthOf(items, 5); assert.equal(items[0].start, 0); assert.equal(items[1].start, 5); assert.equal(items[2].start, 15); assert.equal(items[3].start, 18); + assert.equal(items[4].start, 20); // Check model mapping. assert.equal(items[1].selectionState, SelectionState.HIGHLIGHTED); @@ -67,9 +69,9 @@ tr.b.unittest.testSuite(function() { var sb = series[1]; var sc = series[0]; - assert.lengthOf(sa.points, 4); - assert.lengthOf(sb.points, 4); - assert.lengthOf(sc.points, 4); + assert.lengthOf(sa.points, 5); + assert.lengthOf(sb.points, 5); + assert.lengthOf(sc.points, 5); // Process A: VM regions defined -> sum their PSS values (111). // Process B: VM regions undefined and no previous value -> assume zero. @@ -78,36 +80,36 @@ tr.b.unittest.testSuite(function() { assert.equal(sb.points[0].x, 0); assert.equal(sc.points[0].x, 0); assert.equal(sa.points[0].y, 111); - assert.equal(sb.points[0].y, 111); - assert.equal(sc.points[0].y, 111); + assert.equal(sb.points[0].y, 0); + assert.equal(sc.points[0].y, 0); assert.equal(sa.points[0].yBase, 0); - assert.equal(sb.points[0].yBase, 111); - assert.equal(sc.points[0].yBase, 111); + assert.equal(sb.points[0].yBase, 0); + assert.equal(sc.points[0].yBase, 0); // Process A: VM regions undefined -> assume previous value (111). - // Process B: VM regions defined -> sum their PSS values (555). + // Process B: VM regions defined -> sum their PSS values (100 + 50). // Process C: VM regions undefined -> assume previous value (0). assert.equal(sa.points[1].x, 5); assert.equal(sb.points[1].x, 5); assert.equal(sc.points[1].x, 5); - assert.equal(sa.points[1].y, 111); - assert.equal(sb.points[1].y, 261); - assert.equal(sc.points[1].y, 261); - assert.equal(sa.points[1].yBase, 0); - assert.equal(sb.points[1].yBase, 111); - assert.equal(sc.points[1].yBase, 261); + assert.equal(sa.points[1].y, 150 + 111); + assert.equal(sb.points[1].y, 150); + assert.equal(sc.points[1].y, 0); + assert.equal(sa.points[1].yBase, 150); + assert.equal(sb.points[1].yBase, 0); + assert.equal(sc.points[1].yBase, 0); // Process A: VM regions defined -> sum their PSS values (0). // Process B: Memory dump not present -> assume process not alive (0). - // Process C: VM regions defined -> sum their PSS values (999). + // Process C: VM regions defined -> sum their PSS values (70 + 70 + 70). assert.equal(sa.points[2].x, 15); assert.equal(sb.points[2].x, 15); assert.equal(sc.points[2].x, 15); - assert.equal(sa.points[2].y, 0); - assert.equal(sb.points[2].y, 0); + assert.equal(sa.points[2].y, 210); + assert.equal(sb.points[2].y, 210); assert.equal(sc.points[2].y, 210); - assert.equal(sa.points[2].yBase, 0); - assert.equal(sb.points[2].yBase, 0); + assert.equal(sa.points[2].yBase, 210); + assert.equal(sb.points[2].yBase, 210); assert.equal(sc.points[2].yBase, 0); // All processes: Memory dump not present -> assume process not alive (0). @@ -117,10 +119,23 @@ tr.b.unittest.testSuite(function() { assert.equal(sa.points[3].y, 0); assert.equal(sb.points[3].y, 0); assert.equal(sc.points[3].y, 0); - assert.equal(sc.points[3].yBase, 0); - assert.equal(sc.points[3].yBase, 0); + assert.equal(sa.points[3].yBase, 0); + assert.equal(sb.points[3].yBase, 0); assert.equal(sc.points[3].yBase, 0); + // Process A: VM regions defined -> sum their PSS values (105). + // Process B: VM regions undefined and no previous value -> assume zero. + // Process C: Memory dump not present -> assume process not alive (0). + assert.equal(sa.points[4].x, 20); + assert.equal(sb.points[4].x, 20); + assert.equal(sc.points[4].x, 20); + assert.equal(sa.points[4].y, 105); + assert.equal(sb.points[4].y, 0); + assert.equal(sc.points[4].y, 0); + assert.equal(sa.points[4].yBase, 0); + assert.equal(sb.points[4].yBase, 0); + assert.equal(sc.points[4].yBase, 0); + // Check model mapping. assert.equal(sa.points[1].selectionState, SelectionState.HIGHLIGHTED); assert.isTrue(sb.points[2].selected); @@ -142,11 +157,11 @@ tr.b.unittest.testSuite(function() { assert.lengthOf(series, 2); - var so = series[0]; - var sv = series[1]; + var so = series[1]; + var sv = series[0]; - assert.lengthOf(so.points, 4); - assert.lengthOf(sv.points, 4); + assert.lengthOf(so.points, 5); + assert.lengthOf(sv.points, 5); // Oilpan: Only process B dumps allocated objects size (1024). // V8: No process dumps allocated objects size (0). @@ -154,27 +169,42 @@ tr.b.unittest.testSuite(function() { assert.equal(sv.points[0].x, 0); assert.equal(so.points[0].y, 1024); assert.equal(sv.points[0].y, 0); + assert.equal(so.points[0].yBase, 0); + assert.equal(sv.points[0].yBase, 0); // Oilpan: Process B did not provide a value and process C dumps (128). // V8: Processes B and C dump (512 + 256). assert.equal(so.points[1].x, 5); assert.equal(sv.points[1].x, 5); - assert.equal(so.points[1].y, 128); + assert.equal(so.points[1].y, 768 + 128); assert.equal(sv.points[1].y, 768); + assert.equal(so.points[1].yBase, 768); + assert.equal(sv.points[1].yBase, 0); // Oilpan: Process B assumed not alive and process C dumps (512) // V8: Process A dumps now, process B assumed not alive, process C did not // provide a value (768). assert.equal(so.points[2].x, 15); assert.equal(sv.points[2].x, 15); - assert.equal(so.points[2].y, 512); + assert.equal(so.points[2].y, 768 + 512); assert.equal(sv.points[2].y, 768); + assert.equal(so.points[2].yBase, 768); + assert.equal(sv.points[2].yBase, 0); // All processes: Memory dump not present -> assume process not alive (0). assert.equal(so.points[3].x, 18); assert.equal(sv.points[3].x, 18); assert.equal(so.points[3].y, 0); assert.equal(sv.points[3].y, 0); + assert.equal(so.points[3].yBase, 0); + assert.equal(sv.points[3].yBase, 0); + + // Oilpan: Only process B dumps allocated objects size (100). + // V8: No process dumps allocated objects size (0). + assert.equal(so.points[4].x, 20); + assert.equal(sv.points[4].x, 20); + assert.equal(so.points[4].y, 100); + assert.equal(sv.points[4].y, 0); // Check model mapping. assert.equal(so.points[1].selectionState, SelectionState.HIGHLIGHTED); @@ -199,8 +229,8 @@ tr.b.unittest.testSuite(function() { // charts). assert.lengthOf(series, 2); - var so = series[0]; - var sv = series[1]; + var so = series[1]; + var sv = series[0]; assert.lengthOf(so.points, 2); assert.lengthOf(sv.points, 2); @@ -209,8 +239,10 @@ tr.b.unittest.testSuite(function() { // V8: Process dumps (256). assert.equal(so.points[0].x, 5.12); assert.equal(sv.points[0].x, 5.12); - assert.equal(so.points[0].y, 128); + assert.equal(so.points[0].y, 256 + 128); assert.equal(sv.points[0].y, 256); + assert.equal(so.points[0].yBase, 256); + assert.equal(sv.points[0].yBase, 0); // Oilpan: Process dumps (512). // V8: Process did not provide a value (0). @@ -218,6 +250,8 @@ tr.b.unittest.testSuite(function() { assert.equal(sv.points[1].x, 14.5); assert.equal(so.points[1].y, 512); assert.equal(sv.points[1].y, 0); + assert.equal(so.points[1].yBase, 0); + assert.equal(sv.points[1].yBase, 0); // Check model mapping. assert.equal(so.points[1].selectionState, SelectionState.HIGHLIGHTED); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html index 29e8b94c85e..051135d49e1 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/model_track.html @@ -43,7 +43,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport); - this.classList.add('model-track'); + Polymer.dom(this).classList.add('model-track'); var typeInfos = tr.ui.tracks.Highlighter.getAllRegisteredTypeInfos(); this.highlighters_ = typeInfos.map( @@ -86,7 +86,7 @@ tr.exportTo('tr.ui.tracks', function() { }, updateContents_: function() { - this.textContent = ''; + Polymer.dom(this).textContent = ''; if (!this.model_) return; @@ -103,19 +103,19 @@ tr.exportTo('tr.ui.tracks', function() { if (this.model_.userModel.expectations.length) { var mrt = new tr.ui.tracks.InteractionTrack(this.viewport_); mrt.model = this.model_; - this.appendChild(mrt); + Polymer.dom(this).appendChild(mrt); } if (this.model_.alerts.length) { var at = new tr.ui.tracks.AlertTrack(this.viewport_); at.alerts = this.model_.alerts; - this.appendChild(at); + Polymer.dom(this).appendChild(at); } if (this.model_.globalMemoryDumps.length) { var gmdt = new tr.ui.tracks.GlobalMemoryDumpTrack(this.viewport_); gmdt.memoryDumps = this.model_.globalMemoryDumps; - this.appendChild(gmdt); + Polymer.dom(this).appendChild(gmdt); } this.appendDeviceTrack_(); @@ -134,7 +134,7 @@ tr.exportTo('tr.ui.tracks', function() { if (!track.hasVisibleContent) continue; - this.appendChild(track); + Polymer.dom(this).appendChild(track); } this.viewport_.rebuildEventToTrackMap(); this.viewport_.rebuildContainerToTrackMap(); @@ -179,7 +179,7 @@ tr.exportTo('tr.ui.tracks', function() { track.device = this.model.device; if (!track.hasVisibleContent) return; - this.appendChild(track); + Polymer.dom(this).appendChild(track); }, appendKernelTrack_: function() { @@ -188,6 +188,14 @@ tr.exportTo('tr.ui.tracks', function() { track.kernel = this.model.kernel; if (!track.hasVisibleContent) return; + Polymer.dom(this).appendChild(track); + }, + + appendCpuUsageTrack_: function() { + var track = new tr.ui.tracks.CpuUsageTrack(this.viewport); + track.initialize(this.model); + if (!track.hasVisibleContent) + return; this.appendChild(track); }, @@ -318,17 +326,17 @@ tr.exportTo('tr.ui.tracks', function() { var startBounds = startTrack.getBoundingClientRect(); var endBounds = endTrack.getBoundingClientRect(); - if (flowEvent.selectionState == SelectionState.SELECTED) { + if (flowEvent.selectionState === SelectionState.SELECTED) { ctx.shadowBlur = 1; ctx.shadowColor = 'red'; ctx.shadowOffsety = 2; ctx.strokeStyle = 'red'; - } else if (flowEvent.selectionState == SelectionState.HIGHLIGHTED) { + } else if (flowEvent.selectionState === SelectionState.HIGHLIGHTED) { ctx.shadowBlur = 1; ctx.shadowColor = 'red'; ctx.shadowOffsety = 2; ctx.strokeStyle = 'red'; - } else if (flowEvent.selectionState == SelectionState.DIMMED) { + } else if (flowEvent.selectionState === SelectionState.DIMMED) { ctx.shadowBlur = 0; ctx.shadowOffsetX = 0; ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; @@ -394,7 +402,8 @@ tr.exportTo('tr.ui.tracks', function() { var bounds = track.getBoundingClientRect(); var size = bounds.left + bounds.top + bounds.bottom + bounds.right; if (size === 0) - return this.calculateTrackY_(track.parentNode, canvasBounds); + return this.calculateTrackY_( + Polymer.dom(track).parentNode, canvasBounds); return bounds.top - canvasBounds.top + (bounds.height / 2); }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html index 04637ef2d2a..787dc1a17ac 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/multi_row_track.html @@ -5,10 +5,10 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/tracks/container_track.html"> <link rel="import" href="/tracing/base/sorted_array_utils.html"> <link rel="import" href="/tracing/model/model_settings.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/container_track.html"> <script> 'use strict'; @@ -84,7 +84,7 @@ tr.exportTo('tr.ui.tracks', function() { }, set expanded(expanded) { - if (this.expanded_ == expanded) + if (this.expanded_ === expanded) return; this.expanded_ = expanded; this.expandedStateChanged_(); @@ -178,10 +178,10 @@ tr.exportTo('tr.ui.tracks', function() { }, updateHeadingAndTooltip_: function() { - if (!this.firstChild) + if (!Polymer.dom(this).firstChild) return; - this.firstChild.heading = this.heading_; - this.firstChild.tooltip = this.tooltip_; + Polymer.dom(this).firstChild.heading = this.heading_; + Polymer.dom(this).firstChild.tooltip = this.tooltip_; }, /** @@ -201,10 +201,10 @@ tr.exportTo('tr.ui.tracks', function() { return false; if (!a.length || !b.length) return false; - if (a.length != b.length) + if (a.length !== b.length) return false; for (var i = 0; i < a.length; ++i) { - if (a[i] != b[i]) + if (a[i] !== b[i]) return false; } return true; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html index 6bb39093015..7910ed1857a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_group_track.html @@ -5,12 +5,12 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html"> +<link rel="import" href="/tracing/base/sorted_array_utils.html"> <link rel="import" href="/tracing/ui/analysis/object_instance_view.html"> +<link rel="import" href="/tracing/ui/analysis/object_snapshot_view.html"> +<link rel="import" href="/tracing/ui/base/ui.html"> <link rel="import" href="/tracing/ui/tracks/multi_row_track.html"> <link rel="import" href="/tracing/ui/tracks/object_instance_track.html"> -<link rel="import" href="/tracing/base/sorted_array_utils.html"> -<link rel="import" href="/tracing/ui/base/ui.html"> <script> 'use strict'; @@ -30,7 +30,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport); - this.classList.add('object-instance-group-track'); + Polymer.dom(this).classList.add('object-instance-group-track'); this.objectInstances_ = undefined; }, @@ -46,7 +46,7 @@ tr.exportTo('tr.ui.tracks', function() { var hasMultipleRows = this.subRows.length > 1; var track = new tr.ui.tracks.ObjectInstanceTrack(this.viewport); track.objectInstances = objectInstances; - this.appendChild(track); + Polymer.dom(this).appendChild(track); return track; }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html index 4b6d3cacf11..f6a4fdda61c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track.html @@ -36,12 +36,12 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('object-instance-track'); + Polymer.dom(this).classList.add('object-instance-track'); this.objectInstances_ = []; this.objectSnapshots_ = []; this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, set heading(heading) { @@ -61,7 +61,7 @@ tr.exportTo('tr.ui.tracks', function() { }, set objectInstances(objectInstances) { - if (!objectInstances || objectInstances.length == 0) { + if (!objectInstances || objectInstances.length === 0) { this.heading = ''; this.objectInstances_ = []; this.objectSnapshots_ = []; @@ -133,7 +133,7 @@ tr.exportTo('tr.ui.tracks', function() { if (x > viewRWorld) break; - var right = instance.deletionTs == Number.MAX_VALUE ? + var right = instance.deletionTs === Number.MAX_VALUE ? viewRWorld : instance.deletionTs; ctx.fillStyle = EventPresenter.getObjectInstanceColor(instance); ctx.fillRect(x, pixelRatio, right - x, height - 2 * pixelRatio); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html index 1ba79b9db6c..aa0ab3f9a82 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/object_instance_track_test.html @@ -49,10 +49,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = ObjectInstanceTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html index 5905882acff..c650bdaf80d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track.html @@ -39,7 +39,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { ChartTrack.prototype.decorate.call(this, viewport); - this.classList.add('power-series-track'); + Polymer.dom(this).classList.add('power-series-track'); this.heading = 'Power'; this.powerSeries_ = undefined; }, @@ -65,7 +65,7 @@ tr.exportTo('tr.ui.tracks', function() { var axis = new tr.ui.tracks.ChartAxis(0, undefined); var pts = this.powerSeries_.samples.map(function(smpl) { - return new tr.ui.tracks.ChartPoint(smpl, smpl.start, smpl.power); + return new tr.ui.tracks.ChartPoint(smpl, smpl.start, smpl.powerInW); }); var renderingConfig = { chartType: tr.ui.tracks.ChartSeriesType.AREA, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html index 29997361918..9c0913afb54 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/power_series_track_test.html @@ -28,7 +28,7 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new tr.ui.TimelineViewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); if (series) { series.updateBounds(); @@ -61,7 +61,7 @@ tr.b.unittest.testSuite(function() { var drawingContainer = createDrawingContainer(series); var track = new PowerSeriesTrack(drawingContainer.viewport); track.powerSeries = series; - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(drawingContainer); }); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html index c197bd9d010..c0051a7bd19 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track.html @@ -62,7 +62,7 @@ tr.exportTo('tr.ui.tracks', function() { track.height = ALLOCATED_MEMORY_TRACK_HEIGHT + 'px'; track.series = series; track.autoSetAllAxes({expandMax: true}); - this.appendChild(track); + Polymer.dom(this).appendChild(track); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html index a4515d50403..06c2df6894e 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_memory_dump_track_test.html @@ -8,8 +8,8 @@ found in the LICENSE file. <link rel="import" href="/tracing/core/test_utils.html"> <link rel="import" href="/tracing/ui/timeline_viewport.html"> <link rel="import" href="/tracing/ui/tracks/drawing_container.html"> -<link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html"> <link rel="import" href="/tracing/ui/tracks/memory_dump_track_test_utils.html"> +<link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html"> <script> 'use strict'; @@ -26,10 +26,10 @@ tr.b.unittest.testSuite(function() { var div = document.createElement('div'); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new ProcessMemoryDumpTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); drawingContainer.invalidate(); track.memoryDumps = dumps; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html index 4390766292d..9069ca86abe 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_summary_track.html @@ -76,7 +76,7 @@ tr.exportTo('tr.ui.tracks', function() { if (currentSlice) { // simply find end of current important slice - if (!op.isStart && op.slice == currentSlice) { + if (!op.isStart && op.slice === currentSlice) { // important slice has ended pushRect(lastStart, op.time, currentSlice); lastStart = depth >= 1 ? op.time : undefined; @@ -84,19 +84,19 @@ tr.exportTo('tr.ui.tracks', function() { } } else { if (op.isStart) { - if (depth == 1) { + if (depth === 1) { lastStart = op.time; currentSlice = op.slice; } else if (op.slice) { // switch to slice - if (op.time != lastStart) { + if (op.time !== lastStart) { pushRect(lastStart, op.time, undefined); lastStart = op.time; } currentSlice = op.slice; } } else { - if (depth == 0) { + if (depth === 0) { pushRect(lastStart, op.time, undefined); lastStart = undefined; } diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html index 42451c042d9..84263855eef 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track.html @@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> +<link rel="import" href="/tracing/ui/base/draw_helpers.html"> <link rel="import" href="/tracing/ui/tracks/process_memory_dump_track.html"> <link rel="import" href="/tracing/ui/tracks/process_track_base.html"> -<link rel="import" href="/tracing/ui/base/draw_helpers.html"> <script> 'use strict'; @@ -117,7 +117,7 @@ tr.exportTo('tr.ui.tracks', function() { if (processMemoryDumps.length) { var pmdt = new tr.ui.tracks.ProcessMemoryDumpTrack(this.viewport_); pmdt.memoryDumps = processMemoryDumps; - this.appendChild(pmdt); + Polymer.dom(this).appendChild(pmdt); } }, @@ -152,4 +152,3 @@ tr.exportTo('tr.ui.tracks', function() { }; }); </script> - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html index d96f1ce02cb..b56b2cf3002 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/process_track_base.html @@ -44,17 +44,17 @@ tr.exportTo('tr.ui.tracks', function() { this.processBase_ = undefined; - this.classList.add('process-track-base'); - this.classList.add('expanded'); + Polymer.dom(this).classList.add('process-track-base'); + Polymer.dom(this).classList.add('expanded'); this.processNameEl_ = tr.ui.b.createSpan(); - this.processNameEl_.classList.add('process-track-name'); + Polymer.dom(this.processNameEl_).classList.add('process-track-name'); this.headerEl_ = tr.ui.b.createDiv({className: 'process-track-header'}); - this.headerEl_.appendChild(this.processNameEl_); + Polymer.dom(this.headerEl_).appendChild(this.processNameEl_); this.headerEl_.addEventListener('click', this.onHeaderClick_.bind(this)); - this.appendChild(this.headerEl_); + Polymer.dom(this).appendChild(this.headerEl_); }, get processBase() { @@ -75,7 +75,7 @@ tr.exportTo('tr.ui.tracks', function() { }, get expanded() { - return this.classList.contains('expanded'); + return Polymer.dom(this).classList.contains('expanded'); }, set expanded(expanded) { @@ -84,7 +84,7 @@ tr.exportTo('tr.ui.tracks', function() { if (this.expanded === expanded) return; - this.classList.toggle('expanded'); + Polymer.dom(this).classList.toggle('expanded'); // Expanding and collapsing tracks is, essentially, growing and shrinking // the viewport. We dispatch a change event to trigger any processing @@ -119,7 +119,8 @@ tr.exportTo('tr.ui.tracks', function() { if (!this.processBase_) return; - this.processNameEl_.textContent = this.processBase_.userFriendlyName; + Polymer.dom(this.processNameEl_).textContent = + this.processBase_.userFriendlyName; this.headerEl_.title = this.processBase_.userFriendlyDetails; // Create the object instance tracks for this process. @@ -156,7 +157,7 @@ tr.exportTo('tr.ui.tracks', function() { track.process = this.process; if (!track.hasVisibleContent) return; - this.appendChild(track); + Polymer.dom(this).appendChild(track); // no spacing track, since this track only shown in collapsed state }, @@ -167,7 +168,7 @@ tr.exportTo('tr.ui.tracks', function() { var track = new tr.ui.tracks.FrameTrack(this.viewport); track.frames = frames; - this.appendChild(track); + Polymer.dom(this).appendChild(track); }, appendObjectInstanceTracks_: function() { @@ -228,11 +229,11 @@ tr.exportTo('tr.ui.tracks', function() { } var track = new trackConstructor(this.viewport); track.objectInstances = visibleInstances; - this.appendChild(track); + Polymer.dom(this).appendChild(track); didAppendAtLeastOneTrack = true; }, this); if (didAppendAtLeastOneTrack) - this.appendChild(new SpacingTrack(this.viewport)); + Polymer.dom(this).appendChild(new SpacingTrack(this.viewport)); }, appendCounterTracks_: function() { @@ -244,8 +245,8 @@ tr.exportTo('tr.ui.tracks', function() { counters.forEach(function(counter) { var track = new tr.ui.tracks.CounterTrack(this.viewport); track.counter = counter; - this.appendChild(track); - this.appendChild(new SpacingTrack(this.viewport)); + Polymer.dom(this).appendChild(track); + Polymer.dom(this).appendChild(new SpacingTrack(this.viewport)); }.bind(this)); }, @@ -260,8 +261,8 @@ tr.exportTo('tr.ui.tracks', function() { track.thread = thread; if (!track.hasVisibleContent) return; - this.appendChild(track); - this.appendChild(new SpacingTrack(this.viewport)); + Polymer.dom(this).appendChild(track); + Polymer.dom(this).appendChild(new SpacingTrack(this.viewport)); }.bind(this)); } }; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html index 70da91be408..770dc97318d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track.html @@ -34,12 +34,12 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('rect-track'); + Polymer.dom(this).classList.add('rect-track'); this.asyncStyle_ = false; this.rects_ = null; this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, set heading(heading) { @@ -163,7 +163,7 @@ tr.exportTo('tr.ui.tracks', function() { var instantEventWidth = 2 * viewPixWidthWorld; tr.b.iterateOverIntersectingIntervals(this.rects_, function(x) { return x.start; }, - function(x) { return x.duration == 0 ? + function(x) { return x.duration === 0 ? x.duration + instantEventWidth : x.duration; }, loWX, hiWX, @@ -237,7 +237,7 @@ tr.exportTo('tr.ui.tracks', function() { this.start = start; this.duration = duration; this.end = start + duration; - }; + } Rect.prototype = { __proto__: tr.model.ProxySelectableItem.prototype diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html index 6dcb905a304..f6d33831a9d 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/rect_track_test.html @@ -19,7 +19,7 @@ tr.b.unittest.testSuite(function() { var EventSet = tr.model.EventSet; var RectTrack = tr.ui.tracks.RectTrack; var Rect = tr.ui.tracks.Rect; - var Slice = tr.model.Slice; + var ThreadSlice = tr.model.ThreadSlice; var Viewport = tr.ui.TimelineViewport; test('instantiate_withRects', function() { @@ -27,10 +27,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); @@ -53,20 +53,20 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); track.heading = 'testBasicSlices'; track.rects = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 2.1, {}, 4.8), - new Slice('', 'b', 1, 7, {}, 0.5), - new Slice('', 'c', 2, 7.6, {}, 0.4) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 2.1, {}, 4.8), + new ThreadSlice('', 'b', 1, 7, {}, 0.5), + new ThreadSlice('', 'c', 2, 7.6, {}, 0.4) ]; var dt = new tr.ui.TimelineDisplayTransform(); @@ -79,10 +79,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); @@ -114,14 +114,14 @@ tr.b.unittest.testSuite(function() { var dict = optDicts[dictIndex]; var div = document.createElement('div'); - div.appendChild(document.createTextNode(dict.trackName)); + Polymer.dom(div).appendChild(document.createTextNode(dict.trackName)); var viewport = new Viewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = new RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); @@ -144,10 +144,10 @@ tr.b.unittest.testSuite(function() { test('findAllObjectsMatchingInRectTrack', function() { var track = new RectTrack(new tr.ui.TimelineViewport()); track.rects = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 2.1, {}, 4.8), - new Slice('', 'b', 1, 7, {}, 0.5), - new Slice('', 'c', 2, 7.6, {}, 0.4) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 2.1, {}, 4.8), + new ThreadSlice('', 'b', 1, 7, {}, 0.5), + new ThreadSlice('', 'c', 2, 7.6, {}, 0.4) ]; var selection = new EventSet(); track.addAllEventsMatchingFilterToSelection( @@ -160,23 +160,24 @@ tr.b.unittest.testSuite(function() { test('selectionHitTesting', function() { var testEl = document.createElement('div'); - testEl.appendChild(tr.ui.b.createScopedStyle('heading { width: 100px; }')); + Polymer.dom(testEl).appendChild( + tr.ui.b.createScopedStyle('heading { width: 100px; }')); testEl.style.width = '600px'; var viewport = new Viewport(testEl); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - testEl.appendChild(drawingContainer); + Polymer.dom(testEl).appendChild(drawingContainer); var track = new RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(testEl); drawingContainer.updateCanvasSizeIfNeeded_(); track.heading = 'testSelectionHitTesting'; track.rects = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 5, {}, 4.8) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 5, {}, 4.8) ]; var y = track.getBoundingClientRect().top + 5; var pixelRatio = window.devicePixelRatio || 1; @@ -217,10 +218,10 @@ tr.b.unittest.testSuite(function() { var viewport = new Viewport(testEl); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - testEl.appendChild(drawingContainer); + Polymer.dom(testEl).appendChild(drawingContainer); var track = new RectTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(testEl); drawingContainer.updateCanvasSizeIfNeeded_(); @@ -231,8 +232,8 @@ tr.b.unittest.testSuite(function() { track.heading = 'testElide'; track.rects = [ // title, colorId, start, args, opt_duration - new Slice('', bigtitle, 0, 1, {}, 1), - new Slice('', smalltitle, 1, 2, {}, 1) + new ThreadSlice('', bigtitle, 0, 1, {}, 1), + new ThreadSlice('', smalltitle, 1, 2, {}, 1) ]; var dt = new tr.ui.TimelineDisplayTransform(); dt.xSetWorldBounds(0, 3.3, track.clientWidth); @@ -296,10 +297,10 @@ tr.b.unittest.testSuite(function() { test('rectTrackAddItemNearToProvidedEvent', function() { var track = new RectTrack(new tr.ui.TimelineViewport()); track.rects = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 2.1, {}, 4.8), - new Slice('', 'b', 1, 7, {}, 0.5), - new Slice('', 'c', 2, 7.6, {}, 0.4) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 2.1, {}, 4.8), + new ThreadSlice('', 'b', 1, 7, {}, 0.5), + new ThreadSlice('', 'c', 2, 7.6, {}, 0.4) ]; var sel = new EventSet(); track.addAllEventsMatchingFilterToSelection( @@ -308,27 +309,30 @@ tr.b.unittest.testSuite(function() { // Select to the right of B. var selRight = new EventSet(); - ret = track.addEventNearToProvidedEventToSelection(sel[0], 1, selRight); + ret = track.addEventNearToProvidedEventToSelection( + tr.b.getFirstElement(sel), 1, selRight); assert.isTrue(ret); - assert.equal(track.rects[2].modelItem, selRight[0]); + assert.equal(track.rects[2].modelItem, tr.b.getFirstElement(selRight)); // Select to the right of the 2nd b. var selRight2 = new EventSet(); - ret = track.addEventNearToProvidedEventToSelection(sel[0], 2, selRight2); + ret = track.addEventNearToProvidedEventToSelection( + tr.b.getFirstElement(sel), 2, selRight2); assert.isTrue(ret); - assert.equal(track.rects[3].modelItem, selRight2[0]); + assert.equal(track.rects[3].modelItem, tr.b.getFirstElement(selRight2)); // Select to 2 to the right of the 2nd b. var selRightOfRight = new EventSet(); ret = track.addEventNearToProvidedEventToSelection( - selRight[0], 1, selRightOfRight); + tr.b.getFirstElement(selRight), 1, selRightOfRight); assert.isTrue(ret); - assert.equal(track.rects[3].modelItem, selRightOfRight[0]); + assert.equal(track.rects[3].modelItem, + tr.b.getFirstElement(selRightOfRight)); // Select to the right of the rightmost slice. var selNone = new EventSet(); ret = track.addEventNearToProvidedEventToSelection( - selRightOfRight[0], 1, selNone); + tr.b.getFirstElement(selRightOfRight), 1, selNone); assert.isFalse(ret); assert.equal(0, selNone.length); @@ -339,7 +343,8 @@ tr.b.unittest.testSuite(function() { var ret; selNone = new EventSet(); - ret = track.addEventNearToProvidedEventToSelection(sel[0], -1, selNone); + ret = track.addEventNearToProvidedEventToSelection( + tr.b.getFirstElement(sel), -1, selNone); assert.isFalse(ret); assert.equal(0, selNone.length); }); @@ -347,10 +352,10 @@ tr.b.unittest.testSuite(function() { test('rectTrackAddClosestEventToSelection', function() { var track = new RectTrack(new tr.ui.TimelineViewport()); track.rects = [ - new Slice('', 'a', 0, 1, {}, 1), - new Slice('', 'b', 1, 2.1, {}, 4.8), - new Slice('', 'b', 1, 7, {}, 0.5), - new Slice('', 'c', 2, 7.6, {}, 0.4) + new ThreadSlice('', 'a', 0, 1, {}, 1), + new ThreadSlice('', 'b', 1, 2.1, {}, 4.8), + new ThreadSlice('', 'b', 1, 7, {}, 0.5), + new ThreadSlice('', 'c', 2, 7.6, {}, 0.4) ]; // Before with not range. diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html index 30ce44be39d..63d409c45da 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track.html @@ -33,7 +33,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('ruler-track'); + Polymer.dom(this).classList.add('ruler-track'); this.strings_secs_ = []; this.strings_msecs_ = []; this.strings_usecs_ = []; @@ -44,7 +44,7 @@ tr.exportTo('tr.ui.tracks', function() { var heading = document.createElement('tr-ui-heading'); heading.arrowVisible = false; - this.appendChild(heading); + Polymer.dom(this).appendChild(heading); }, detach: function() { @@ -55,9 +55,9 @@ tr.exportTo('tr.ui.tracks', function() { viewportChange_: function() { if (this.viewport.interestRange.isEmpty) - this.classList.remove('tall-mode'); + Polymer.dom(this).classList.remove('tall-mode'); else - this.classList.add('tall-mode'); + Polymer.dom(this).classList.add('tall-mode'); }, draw: function(type, viewLWorld, viewRWorld) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html index 3ca0d72fdf4..bde5c5c916f 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/ruler_track_test.html @@ -19,10 +19,10 @@ tr.b.unittest.testSuite(function() { var viewport = new tr.ui.TimelineViewport(div); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - div.appendChild(drawingContainer); + Polymer.dom(div).appendChild(drawingContainer); var track = tr.ui.tracks.RulerTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); this.addHTMLOutput(div); drawingContainer.invalidate(); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html index 78ffd07cf00..70c7bc5c26c 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track.html @@ -5,9 +5,9 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> -<link rel="import" href="/tracing/ui/tracks/multi_row_track.html"> <link rel="import" href="/tracing/base/sorted_array_utils.html"> <link rel="import" href="/tracing/ui/base/ui.html"> +<link rel="import" href="/tracing/ui/tracks/multi_row_track.html"> <script> 'use strict'; @@ -27,7 +27,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this, viewport); - this.classList.add('slice-group-track'); + Polymer.dom(this).classList.add('slice-group-track'); this.group_ = undefined; // Set the collapse threshold so we don't collapse by default, but the // user can explicitly collapse if they want it. @@ -37,7 +37,7 @@ tr.exportTo('tr.ui.tracks', function() { addSubTrack_: function(slices) { var track = new tr.ui.tracks.SliceTrack(this.viewport); track.slices = slices; - this.appendChild(track); + Polymer.dom(this).appendChild(track); return track; }, @@ -111,7 +111,7 @@ tr.exportTo('tr.ui.tracks', function() { ops.sort(function(ix, iy) { var x = slices[ix]; var y = slices[iy]; - if (x.start != y.start) + if (x.start !== y.start) return x.start - y.start; // Elements get inserted into the slices array in order of when the @@ -131,7 +131,7 @@ tr.exportTo('tr.ui.tracks', function() { // Try to fit the slice into the existing subrows. var inserted = false; for (var j = subRows.length - 1; j >= 0; j--) { - if (subRows[j].length == 0) + if (subRows[j].length === 0) continue; var insertedSlice = subRows[j][subRows[j].length - 1]; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html index 6e3ff9813c4..fa5f75fad57 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_group_track_test.html @@ -6,8 +6,8 @@ found in the LICENSE file. --> <link rel="import" href="/tracing/core/test_utils.html"> -<link rel="import" href="/tracing/ui/timeline_track_view.html"> <link rel="import" href="/tracing/model/slice_group.html"> +<link rel="import" href="/tracing/ui/timeline_track_view.html"> <script> 'use strict'; @@ -163,7 +163,7 @@ tr.b.unittest.testSuite(function() { // Pattern being tested: // [ a ] - // [ b1 ] []<- b2 where b2.duration = 0 and b2.end == a.end. + // [ b1 ] []<- b2 where b2.duration = 0 and b2.end === a.end. var sA = group.pushSlice(newSliceEx({title: 'a', start: 1, duration: 3})); var sB1 = group.pushSlice(newSliceEx({title: 'b1', start: 1, duration: 2})); var sB2 = group.pushSlice(newSliceEx({title: 'b2', start: 4, duration: 0})); @@ -256,8 +256,8 @@ test('sliceGroupContainerMap', function() { processTrack.process = process; threadTrack.thread = thread; groupTrack.group = group; - processTrack.appendChild(threadTrack); - threadTrack.appendChild(groupTrack); + Polymer.dom(processTrack).appendChild(threadTrack); + Polymer.dom(threadTrack).appendChild(groupTrack); assert.equal(processTrack.eventContainer, process); assert.equal(threadTrack.eventContainer, thread); @@ -290,4 +290,3 @@ test('sliceGroupContainerMap', function() { }); }); </script> - diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html index 2c22784a848..f0af57af087 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/slice_track_test.html @@ -15,11 +15,11 @@ found in the LICENSE file. tr.b.unittest.testSuite(function() { var SliceTrack = tr.ui.tracks.SliceTrack; - var Slice = tr.model.Slice; + var ThreadSlice = tr.model.ThreadSlice; test('modelMapping', function() { var track = new SliceTrack(new tr.ui.TimelineViewport()); - var slice = new Slice('', 'a', 0, 1, {}, 1); + var slice = new ThreadSlice('', 'a', 0, 1, {}, 1); track.slices = [slice]; var me0 = track.rects[0].modelItem; assert.equal(slice, me0); diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html index 5eea1c903e0..7b2fa252627 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/spacing_track.html @@ -27,10 +27,10 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('spacing-track'); + Polymer.dom(this).classList.add('spacing-track'); this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, addAllEventsMatchingFilterToSelection: function(filter, selection) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html index e3e9ea89d40..0f47419bf9a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/stacked_bars_track.html @@ -27,11 +27,11 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.Track.prototype.decorate.call(this, viewport); - this.classList.add('stacked-bars-track'); + Polymer.dom(this).classList.add('stacked-bars-track'); this.objectInstance_ = null; this.heading_ = document.createElement('tr-ui-heading'); - this.appendChild(this.heading_); + Polymer.dom(this).appendChild(this.heading_); }, set heading(heading) { @@ -69,8 +69,8 @@ tr.exportTo('tr.ui.tracks', function() { snapshots, function(x) { return x.ts; }, function(x, i) { - if (i == snapshots.length - 1) { - if (snapshots.length == 1) + if (i === snapshots.length - 1) { + if (snapshots.length === 1) return maxBounds; return snapshots[i].ts - snapshots[i - 1].ts; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html index aca956546b3..ece278cee1a 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track.html @@ -32,7 +32,7 @@ tr.exportTo('tr.ui.tracks', function() { decorate: function(viewport) { tr.ui.tracks.ContainerTrack.prototype.decorate.call(this, viewport); - this.classList.add('thread-track'); + Polymer.dom(this).classList.add('thread-track'); }, get thread() { @@ -78,7 +78,7 @@ tr.exportTo('tr.ui.tracks', function() { timeSlicesTrack.height = tr.ui.b.THIN_SLICE_HEIGHT + 'px'; timeSlicesTrack.slices = this.thread_.timeSlices; if (timeSlicesTrack.hasVisibleContent) - this.appendChild(timeSlicesTrack); + Polymer.dom(this).appendChild(timeSlicesTrack); } if (this.thread_.sliceGroup.length) { @@ -87,7 +87,7 @@ tr.exportTo('tr.ui.tracks', function() { track.tooltip = this.thread_.userFriendlyDetails; track.group = this.thread_.sliceGroup; if (track.hasVisibleContent) - this.appendChild(track); + Polymer.dom(this).appendChild(track); } }, @@ -99,7 +99,7 @@ tr.exportTo('tr.ui.tracks', function() { asyncTrack.group = subGroup; asyncTrack.heading = title; if (asyncTrack.hasVisibleContent) - this.appendChild(asyncTrack); + Polymer.dom(this).appendChild(asyncTrack); }, this); }, @@ -132,7 +132,7 @@ tr.exportTo('tr.ui.tracks', function() { } return selection; }; - this.appendChild(samplesTrack); + Polymer.dom(this).appendChild(samplesTrack); }, this); }, diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html index 068c4f01e02..ed658480fd4 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/thread_track_test.html @@ -37,15 +37,16 @@ tr.b.unittest.testSuite(function() { t1.sliceGroup.pushSlice(new ThreadSlice('', 'b', 0, 5.1, {}, 4)); var testEl = document.createElement('div'); - testEl.appendChild(tr.ui.b.createScopedStyle('heading { width: 100px; }')); + Polymer.dom(testEl).appendChild( + tr.ui.b.createScopedStyle('heading { width: 100px; }')); testEl.style.width = '600px'; var viewport = new Viewport(testEl); var drawingContainer = new tr.ui.tracks.DrawingContainer(viewport); - testEl.appendChild(drawingContainer); + Polymer.dom(testEl).appendChild(drawingContainer); var track = new ThreadTrack(viewport); - drawingContainer.appendChild(track); + Polymer.dom(drawingContainer).appendChild(track); drawingContainer.updateCanvasSizeIfNeeded_(); track.thread = t1; diff --git a/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html b/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html index 09a54c27223..4b151ebf8f5 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/tracks/track.html @@ -28,7 +28,7 @@ tr.exportTo('tr.ui.tracks', function() { throw new Error('viewport is required when creating a Track.'); this.viewport_ = viewport; - this.classList.add('track'); + Polymer.dom(this).classList.add('track'); }, get viewport() { @@ -57,11 +57,11 @@ tr.exportTo('tr.ui.tracks', function() { context: function() { // This is a little weird here, but we have to be able to walk up the // parent tree to get the context. - if (!this.parentNode) + if (!Polymer.dom(this).parentNode) return undefined; - if (!this.parentNode.context) + if (!Polymer.dom(this).parentNode.context) throw new Error('Parent container does not support context() method.'); - return this.parentNode.context(); + return Polymer.dom(this).parentNode.context(); }, decorateChild_: function(childTrack) { diff --git a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html index 0300e36d672..b4704f25a47 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state.html @@ -29,61 +29,64 @@ with a brushingStateController field to persist the state (see the tr.c.BrushingStateController and tr.ui.b.BrushingState classes for more details). --> -<polymer-element name="tr-ui-b-view-specific-brushing-state"> - <script> - 'use strict'; +<dom-module id='tr-ui-b-view-specific-brushing-state'> + <template></template> +</dom-module> +<script> +'use strict'; - Polymer({ - /** Compulsory unique identifier of the associated view. */ - get viewId() { - return this.getAttribute('view-id'); - }, +Polymer({ + is: 'tr-ui-b-view-specific-brushing-state', - set viewId(viewId) { - this.setAttribute('view-id', viewId); - }, + /** Compulsory unique identifier of the associated view. */ + get viewId() { + return this.getAttribute('view-id'); + }, - /** - * Retrieve the persisted state of the associated view. The returned object - * (or any of its fields) must not be modified by the caller (unless the - * object/field is treated as a reference). - * - * If no state has been persisted yet or there is no ancestor element with - * a brushingStateController field, this method returns undefined. - */ - get: function() { - var viewId = this.viewId; - if (!viewId) - throw new Error('Element must have a view-id attribute!'); + set viewId(viewId) { + Polymer.dom(this).setAttribute('view-id', viewId); + }, - var brushingStateController = - tr.c.BrushingStateController.getControllerForElement(this); - if (!brushingStateController) - return undefined; + /** + * Retrieve the persisted state of the associated view. The returned object + * (or any of its fields) must not be modified by the caller (unless the + * object/field is treated as a reference). + * + * If no state has been persisted yet or there is no ancestor element with + * a brushingStateController field, this method returns undefined. + */ + get: function() { + var viewId = this.viewId; + if (!viewId) + throw new Error('Element must have a view-id attribute!'); - return brushingStateController.getViewSpecificBrushingState(viewId); - }, + var brushingStateController = + tr.c.BrushingStateController.getControllerForElement(this); + if (!brushingStateController) + return undefined; - /** - * Persist the provided state of the associated view. The provided object - * (or any of its fields) must not be modified afterwards (unless the - * object/field is treated as a reference). - * - * If there is no ancestor element with a brushingStateController field, - * this method does nothing. - */ - set: function(state) { - var viewId = this.viewId; - if (!viewId) - throw new Error('Element must have a view-id attribute!'); + return brushingStateController.getViewSpecificBrushingState(viewId); + }, - var brushingStateController = - tr.c.BrushingStateController.getControllerForElement(this); - if (!brushingStateController) - return; + /** + * Persist the provided state of the associated view. The provided object + * (or any of its fields) must not be modified afterwards (unless the + * object/field is treated as a reference). + * + * If there is no ancestor element with a brushingStateController field, + * this method does nothing. + */ + set: function(state) { + var viewId = this.viewId; + if (!viewId) + throw new Error('Element must have a view-id attribute!'); - brushingStateController.changeViewSpecificBrushingState(viewId, state); - } - }); - </script> -</polymer-element> + var brushingStateController = + tr.c.BrushingStateController.getControllerForElement(this); + if (!brushingStateController) + return; + + brushingStateController.changeViewSpecificBrushingState(viewId, state); + } +}); +</script> diff --git a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html index e4e8ece0441..aff2cc5a473 100644 --- a/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html +++ b/chromium/third_party/catapult/tracing/tracing/ui/view_specific_brushing_state_test.html @@ -18,13 +18,13 @@ tr.b.unittest.testSuite(function() { var stateElement = document.createElement( 'tr-ui-b-view-specific-brushing-state'); stateElement.viewId = viewId; - containerEl.appendChild(stateElement); + Polymer.dom(containerEl).appendChild(stateElement); return stateElement; } function addChildDiv(element) { var child = element.ownerDocument.createElement('div'); - element.appendChild(child); + Polymer.dom(element).appendChild(child); return child; } |