Changeset 237669 in webkit
- Timestamp:
- Oct 31, 2018 9:12:59 PM (6 years ago)
- Location:
- trunk/Source
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r237645 r237669 1 2018-10-31 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls 4 https://bugs.webkit.org/show_bug.cgi?id=190641 5 <rdar://problem/45319049> 6 7 Reviewed by Joseph Pecoraro. 8 9 * inspector/protocol/DOM.json: 10 Add `videoLowPowerChanged` event that is fired when `InspectorDOMAgent` is able to determine 11 whether a video element's low power state has changed. 12 1 13 2018-10-31 Tadeu Zagallo <tzagallo@apple.com> 2 14 -
trunk/Source/JavaScriptCore/inspector/protocol/DOM.json
r237431 r237669 670 670 { "name": "data", "type": "object", "optional": true, "description": "Holds ancillary information about the event or its target." } 671 671 ] 672 }, 673 { 674 "name": "videoLowPowerChanged", 675 "description": "Called when a video element enters/exits low power mode.", 676 "parameters": [ 677 { "name": "nodeId", "$ref": "NodeId" }, 678 { "name": "timestamp", "$ref": "Network.Timestamp", "description": "Time when the video element entered/exited low power mode" }, 679 { "name": "isLowPower", "type": "boolean" } 680 ] 672 681 } 673 682 ] -
trunk/Source/WebCore/ChangeLog
r237657 r237669 1 2018-10-31 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls 4 https://bugs.webkit.org/show_bug.cgi?id=190641 5 <rdar://problem/45319049> 6 7 Reviewed by Joseph Pecoraro. 8 9 No new tests, as low power mode is indeterminate. Should not affect functionality. 10 11 * inspector/agents/InspectorDOMAgent.h: 12 * inspector/agents/InspectorDOMAgent.cpp: 13 (WebCore::InspectorDOMAgent::InspectorDOMAgent): 14 (WebCore::InspectorDOMAgent::addEventListenersToNode): 15 (WebCore::InspectorDOMAgent::mediaMetricsTimerFired): Added. 16 1 17 2018-10-31 Alicia Boya García <aboya@igalia.com> 2 18 -
trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.cpp
r237441 r237669 68 68 #include "HTMLStyleElement.h" 69 69 #include "HTMLTemplateElement.h" 70 #include "HTMLVideoElement.h" 70 71 #include "HitTestResult.h" 71 72 #include "InspectorClient.h" … … 97 98 #include "TextNodeTraversal.h" 98 99 #include "Timer.h" 100 #include "VideoPlaybackQuality.h" 99 101 #include "WebInjectedScriptManager.h" 100 102 #include "XPathResult.h" … … 283 285 , m_pageAgent(pageAgent) 284 286 , m_overlay(overlay) 287 , m_mediaMetricsTimer(*this, &InspectorDOMAgent::mediaMetricsTimerFired) 285 288 { 286 289 } … … 2179 2182 createEventListener(eventNames().volumechangeEvent); 2180 2183 createEventListener(eventNames().waitingEvent); 2184 2185 if (!m_mediaMetricsTimer.isActive()) 2186 m_mediaMetricsTimer.start(0_s, 1_s / 15.); 2181 2187 } 2182 2188 } … … 2448 2454 } 2449 2455 2456 void InspectorDOMAgent::mediaMetricsTimerFired() 2457 { 2458 // FIXME: remove metrics information for any media element when it's destroyed 2459 2460 if (HTMLMediaElement::allMediaElements().isEmpty()) { 2461 if (m_mediaMetricsTimer.isActive()) 2462 m_mediaMetricsTimer.stop(); 2463 m_mediaMetrics.clear(); 2464 return; 2465 } 2466 2467 for (auto* mediaElement : HTMLMediaElement::allMediaElements()) { 2468 if (!is<HTMLVideoElement>(mediaElement) || !mediaElement->isPlaying()) 2469 continue; 2470 2471 auto videoPlaybackQuality = mediaElement->getVideoPlaybackQuality(); 2472 unsigned displayCompositedVideoFrames = videoPlaybackQuality->displayCompositedVideoFrames(); 2473 2474 auto iterator = m_mediaMetrics.find(mediaElement); 2475 if (iterator == m_mediaMetrics.end()) { 2476 m_mediaMetrics.set(mediaElement, MediaMetrics(displayCompositedVideoFrames)); 2477 continue; 2478 } 2479 2480 bool isLowPower = (displayCompositedVideoFrames - iterator->value.displayCompositedFrames) > 0; 2481 if (iterator->value.isLowPower != isLowPower) { 2482 iterator->value.isLowPower = isLowPower; 2483 2484 int nodeId = pushNodePathToFrontend(mediaElement); 2485 if (nodeId) { 2486 auto timestamp = m_environment.executionStopwatch()->elapsedTime().seconds(); 2487 m_frontendDispatcher->videoLowPowerChanged(nodeId, timestamp, iterator->value.isLowPower); 2488 } 2489 } 2490 2491 iterator->value.displayCompositedFrames = displayCompositedVideoFrames; 2492 } 2493 2494 m_mediaMetrics.removeIf([&] (auto& entry) { 2495 return !HTMLMediaElement::allMediaElements().contains(entry.key); 2496 }); 2497 } 2498 2450 2499 Node* InspectorDOMAgent::nodeForPath(const String& path) 2451 2500 { -
trunk/Source/WebCore/inspector/agents/InspectorDOMAgent.h
r237431 r237669 32 32 #include "EventTarget.h" 33 33 #include "InspectorWebAgentBase.h" 34 #include "Timer.h" 34 35 #include <JavaScriptCore/InspectorBackendDispatchers.h> 35 36 #include <JavaScriptCore/InspectorFrontendDispatchers.h> … … 64 65 class InspectorOverlay; 65 66 class InspectorPageAgent; 67 class HTMLMediaElement; 66 68 class HitTestResult; 67 69 class Node; … … 224 226 225 227 private: 228 void mediaMetricsTimerFired(); 229 226 230 void highlightMousedOverNode(); 227 231 void setSearchingForNode(ErrorString&, bool enabled, const JSON::Object* highlightConfig); … … 285 289 bool m_documentRequested { false }; 286 290 291 Timer m_mediaMetricsTimer; 292 struct MediaMetrics { 293 unsigned displayCompositedFrames { 0 }; 294 bool isLowPower { false }; 295 296 MediaMetrics() { } 297 298 MediaMetrics(unsigned displayCompositedFrames) 299 : displayCompositedFrames(displayCompositedFrames) 300 { 301 } 302 }; 303 304 // The pointer key for this map should not be used for anything other than matching. 305 HashMap<HTMLMediaElement*, MediaMetrics> m_mediaMetrics; 306 287 307 struct InspectorEventListener { 288 308 int identifier { 1 }; -
trunk/Source/WebInspectorUI/ChangeLog
r237665 r237669 1 2018-10-31 Devin Rousso <drousso@apple.com> 2 3 Web Inspector: display low-power enter/exit events in Timelines and Network node waterfalls 4 https://bugs.webkit.org/show_bug.cgi?id=190641 5 <rdar://problem/45319049> 6 7 Reviewed by Joseph Pecoraro. 8 9 * UserInterface/Protocol/DOMObserver.js: 10 (WI.DOMObserver.prototype.videoLowPowerChanged): Added. 11 12 * UserInterface/Controllers/DOMManager.js: 13 (WI.DOMManager.prototype.videoLowPowerChanged): Added. 14 15 * UserInterface/Models/DOMNode.js: 16 (WI.DOMNode): 17 (WI.DOMNode.prototype.get lowPowerRanges): Added. 18 (WI.DOMNode.prototype.videoLowPowerChanged): Added. 19 (WI.DOMNode.prototype.canEnterLowPowerMode): Added. 20 21 * UserInterface/Views/NetworkTableContentView.js: 22 (WI.NetworkTableContentView.prototype._populateDomainCell): 23 (WI.NetworkTableContentView.prototype._tryLinkResourceToDOMNode): 24 (WI.NetworkTableContentView.prototype._handleNodeLowPowerChanged): Added. 25 * UserInterface/Views/NetworkTableContentView.css: 26 (.network-table :not(.header) .cell.waterfall .waterfall-container > .area): 27 (.network-table :not(.header) .cell.waterfall .waterfall-container > .area.dom-fullscreen): Added. 28 (.network-table :not(.header) .cell.waterfall .waterfall-container > .area.low-power): Added. 29 (.network-table :not(.header) .cell.waterfall .waterfall-container > .dom-fullscreen): Deleted. 30 31 * UserInterface/Views/DOMNodeEventsContentView.js: 32 (WI.DOMNodeEventsContentView): 33 (WI.DOMNodeEventsContentView.prototype.initialLayout): 34 (WI.DOMNodeEventsContentView.prototype.closed): Deleted. 35 (WI.DOMNodeEventsContentView.prototype._handleDOMNodeDidFireEvent): Deleted. 36 37 * UserInterface/Views/DOMEventsBreakdownView.js: 38 (WI.DOMEventsBreakdownView): 39 (WI.DOMEventsBreakdownView.prototype.initialLayout): 40 (WI.DOMEventsBreakdownView.prototype.layout): Added. 41 (WI.DOMEventsBreakdownView.prototype._handleDOMNodeDidFireEvent): Added. 42 (WI.DOMEventsBreakdownView.prototype._handleDOMNodeLowPowerChanged): Added. 43 (WI.DOMEventsBreakdownView.prototype.addEvent): Deleted. 44 (WI.DOMEventsBreakdownView.prototype._populateTable.percentOfTotalTime): Deleted. 45 (WI.DOMEventsBreakdownView.prototype._populateTable): Deleted. 46 * UserInterface/Views/DOMEventsBreakdownView.css: 47 (.dom-events-breakdown .graph > .area): Added. 48 (.dom-events-breakdown .graph > .area.fullscreen): 49 (.dom-events-breakdown .graph > .area.low-power): Added. 50 51 * Localizations/en.lproj/localizedStrings.js: 52 1 53 2018-10-31 Devin Rousso <drousso@apple.com> 2 54 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r237660 r237669 423 423 localizedStrings["Full Garbage Collection"] = "Full Garbage Collection"; 424 424 localizedStrings["Full URL"] = "Full URL"; 425 localizedStrings["Fullscreen"] = "Fullscreen"; 425 426 localizedStrings["Fullscreen from “%s“"] = "Fullscreen from “%s“"; 426 427 localizedStrings["Function"] = "Function"; … … 536 537 localizedStrings["Logs"] = "Logs"; 537 538 localizedStrings["Low"] = "Low"; 539 localizedStrings["Low Power Mode"] = "Low Power Mode"; 538 540 localizedStrings["Lowest: %s"] = "Lowest: %s"; 539 541 localizedStrings["MIME Type"] = "MIME Type"; -
trunk/Source/WebInspectorUI/UserInterface/Controllers/DOMManager.js
r237652 r237669 148 148 } 149 149 150 videoLowPowerChanged(nodeId, timestamp, isLowPower) 151 { 152 // Called from WI.DOMObserver. 153 154 let node = this._idToDOMNode[nodeId]; 155 if (!node) 156 return; 157 158 node.videoLowPowerChanged(timestamp, isLowPower); 159 } 160 150 161 // Private 151 162 -
trunk/Source/WebInspectorUI/UserInterface/Models/DOMNode.js
r237661 r237669 140 140 141 141 this._domEvents = []; 142 this._lowPowerRanges = []; 142 143 143 144 if (this._shouldListenForEventListeners()) … … 159 160 160 161 get domEvents() { return this._domEvents; } 162 get lowPowerRanges() { return this._lowPowerRanges; } 161 163 162 164 get frameIdentifier() … … 727 729 } 728 730 731 videoLowPowerChanged(timestamp, isLowPower) 732 { 733 // Called from WI.DOMManager. 734 735 console.assert(this.canEnterLowPowerMode()); 736 737 let lastValue = this._lowPowerRanges.lastValue; 738 739 if (isLowPower) { 740 console.assert(!lastValue || lastValue.endTimestamp); 741 if (!lastValue || lastValue.endTimestamp) 742 this._lowPowerRanges.push({startTimestamp: timestamp}); 743 } else { 744 console.assert(!lastValue || lastValue.startTimestamp); 745 if (!lastValue) 746 this._lowPowerRanges.push({endTimestamp: timestamp}); 747 else if (lastValue.startTimestamp) 748 lastValue.endTimestamp = timestamp; 749 } 750 751 this.dispatchEventToListeners(WI.DOMNode.Event.LowPowerChanged, {isLowPower, timestamp}); 752 } 753 754 canEnterLowPowerMode() 755 { 756 return this.localName() === "video" || this.nodeName().toLowerCase() === "video"; 757 } 758 729 759 _handleDOMNodeDidFireEvent(event) 730 760 { … … 899 929 EventListenersChanged: "dom-node-event-listeners-changed", 900 930 DidFireEvent: "dom-node-did-fire-event", 931 LowPowerChanged: "dom-node-video-low-power-changed", 901 932 }; 902 933 -
trunk/Source/WebInspectorUI/UserInterface/Protocol/DOMObserver.js
r237431 r237669 117 117 WI.domManager.didFireEvent(nodeId, eventName, timestamp, data); 118 118 } 119 120 videoLowPowerChanged(nodeId, timestamp, isLowPower) 121 { 122 WI.domManager.videoLowPowerChanged(nodeId, timestamp, isLowPower); 123 } 119 124 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.css
r237431 r237669 70 70 } 71 71 72 .dom-events-breakdown .graph > .area .fullscreen{72 .dom-events-breakdown .graph > .area { 73 73 top: 0; 74 74 height: 100%; 75 background-color: var(--panel-background-color); 75 } 76 77 .dom-events-breakdown .graph > .area.fullscreen { 78 background-color: hsla(0, 0%, 75%, 0.25); 79 } 80 81 .dom-events-breakdown .graph > .area.low-power { 82 background-color: hsla(83, 100%, 48%, 0.4); 76 83 } 77 84 -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMEventsBreakdownView.js
r237431 r237669 26 26 WI.DOMEventsBreakdownView = class DOMEventsBreakdownView extends WI.View 27 27 { 28 constructor(dom Events, {includeGraph, startTimestamp} = {})28 constructor(domNodeOrEvents, {includeGraph, startTimestamp} = {}) 29 29 { 30 console.assert(domNodeOrEvents instanceof WI.DOMNode || Array.isArray(domNodeOrEvents)); 31 30 32 super(); 31 33 32 this._domEvents = domEvents; 34 if (domNodeOrEvents instanceof WI.DOMNode) { 35 this._domNode = domNodeOrEvents; 36 this._domNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleDOMNodeDidFireEvent, this); 37 if (this._domNode.canEnterLowPowerMode()) 38 this._domNode.addEventListener(WI.DOMNode.Event.LowPowerChanged, this._handleDOMNodeLowPowerChanged, this); 39 40 this._domEvents = null; 41 } else { 42 this._domNode = null; 43 this._domEvents = domNodeOrEvents; 44 this._lowPowerRanges = []; 45 } 46 33 47 this._includeGraph = includeGraph || false; 34 48 this._startTimestamp = startTimestamp || 0; … … 37 51 38 52 this.element.classList.add("dom-events-breakdown"); 39 }40 41 // Public42 43 addEvent(domEvent)44 {45 this._domEvents.push(domEvent);46 47 this.soon._populateTable();48 53 } 49 54 … … 75 80 76 81 this._tableBodyElement = tableElement.appendChild(document.createElement("tbody")); 77 78 this._populateTable();79 82 } 80 83 81 // Private 84 layout() 85 { 86 if (this.layoutReason !== WI.View.LayoutReason.Dirty) 87 return; 82 88 83 _populateTable()84 {85 89 this._tableBodyElement.removeChildren(); 86 90 87 let startTimestamp = this._domEvents[0].timestamp; 88 let endTimestamp = this._domEvents.lastValue.timestamp; 91 console.assert(this._domEvents || (this._domNode && this._domNode.domEvents)); 92 let domEvents = this._domEvents || this._domNode.domEvents; 93 let startTimestamp = domEvents[0].timestamp; 94 let endTimestamp = domEvents.lastValue.timestamp; 89 95 let totalTime = endTimestamp - startTimestamp; 90 96 let styleAttribute = WI.resolvedLayoutDirection() === WI.LayoutDirection.LTR ? "left" : "right"; … … 95 101 96 102 let fullscreenRanges = []; 97 let fullscreenDOMEvents = WI.DOMNode.getFullscreenDOMEvents( this._domEvents);103 let fullscreenDOMEvents = WI.DOMNode.getFullscreenDOMEvents(domEvents); 98 104 for (let fullscreenDOMEvent of fullscreenDOMEvents) { 99 105 let {enabled} = fullscreenDOMEvent.data; … … 104 110 } 105 111 fullscreenRanges.lastValue.endTimestamp = (enabled && fullscreenDOMEvent === fullscreenDOMEvents.lastValue) ? endTimestamp : fullscreenDOMEvent.timestamp; 112 if (fullscreenDOMEvent.originator) 113 fullscreenRanges.lastValue.originator = fullscreenDOMEvent.originator; 106 114 } 107 115 108 for (let domEvent of this._domEvents) { 116 let lowPowerRanges = this._domNode ? this._domNode.lowPowerRanges : []; 117 118 for (let domEvent of domEvents) { 109 119 let rowElement = this._tableBodyElement.appendChild(document.createElement("tr")); 110 120 … … 123 133 fullscreenArea.style.setProperty(styleAttribute, percentOfTotalTime(fullscreenRange.startTimestamp - startTimestamp) + "%"); 124 134 fullscreenArea.style.setProperty("width", percentOfTotalTime(fullscreenRange.endTimestamp - fullscreenRange.startTimestamp) + "%"); 135 136 if (fullscreenRange.originator) 137 fullscreenArea.title = WI.UIString("Fullscreen from “%s“").format(fullscreenRange.originator.displayName); 138 else 139 fullscreenArea.title = WI.UIString("Fullscreen"); 140 } 141 142 let lowPowerRange = lowPowerRanges.find((range) => domEvent.timestamp >= range.startTimestamp && domEvent.timestamp <= range.endTimestamp); 143 if (lowPowerRange) { 144 let lowPowerArea = graphCell.appendChild(document.createElement("div")); 145 lowPowerArea.classList.add("area", "low-power"); 146 lowPowerArea.title = WI.UIString("Low Power Mode"); 147 lowPowerArea.style.setProperty(styleAttribute, percentOfTotalTime(lowPowerRange.startTimestamp - startTimestamp) + "%"); 148 lowPowerArea.style.setProperty("width", percentOfTotalTime(lowPowerRange.endTimestamp - lowPowerRange.startTimestamp) + "%"); 125 149 } 126 150 … … 146 170 } 147 171 } 172 173 // Private 174 175 _handleDOMNodeDidFireEvent(event) 176 { 177 this.needsLayout(); 178 } 179 180 _handleDOMNodeLowPowerChanged(event) 181 { 182 this.needsLayout(); 183 } 148 184 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/DOMNodeEventsContentView.js
r237028 r237669 47 47 super.initialLayout(); 48 48 49 this._breakdownView = new WI.DOMEventsBreakdownView(this._domNode .domEvents.slice(), {49 this._breakdownView = new WI.DOMEventsBreakdownView(this._domNode, { 50 50 includeGraph: true, 51 51 startTimestamp: this._startTimestamp, 52 52 }); 53 53 this.addSubview(this._breakdownView); 54 55 this._domNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleDOMNodeDidFireEvent, this);56 }57 58 closed()59 {60 this._domNode.removeEventListener(null, null, this);61 62 super.closed();63 }64 65 // Private66 67 _handleDOMNodeDidFireEvent(event)68 {69 let {domEvent} = event.data;70 71 if (this._breakdownView)72 this._breakdownView.addEvent(domEvent);73 54 } 74 55 }; -
trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.css
r237432 r237669 176 176 } 177 177 178 .network-table :not(.header) .cell.waterfall .waterfall-container > .area { 179 position: absolute; 180 top: var(--area-padding); 181 height: calc(100% - (var(--area-padding) * 2)); 182 183 /* Half of the vertical space above any .dom-event node */ 184 --area-padding: calc((50% - (var(--node-waterfall-dom-event-size) / 2)) / 2); 185 } 186 187 .network-table :not(.header) .cell.waterfall .waterfall-container > .area.dom-fullscreen { 188 background-color: hsla(0, 0%, 75%, 0.75); 189 } 190 191 .network-table :not(.header) .cell.waterfall .waterfall-container > .area.low-power { 192 background-color: var(--network-request-color); 193 } 194 178 195 .network-table .timeline-ruler { 179 196 position: absolute; … … 181 198 bottom: 0; 182 199 overflow: hidden; 183 }184 185 .network-table :not(.header) .cell.waterfall .waterfall-container > .dom-fullscreen {186 position: absolute;187 top: var(--dom-fullscreen-vertical-padding);188 height: calc(100% - (var(--dom-fullscreen-vertical-padding) * 2));189 background-color: lightgrey;190 191 /* Half of the vertical space above any .dom-event node */192 --dom-fullscreen-vertical-padding: calc((50% - (var(--node-waterfall-dom-event-size) / 2)) / 2);193 200 } 194 201 -
trunk/Source/WebInspectorUI/UserInterface/Views/NetworkTableContentView.js
r237661 r237669 543 543 } 544 544 545 cell.append(domain );545 cell.append(domain || emDash); 546 546 } 547 547 … … 556 556 557 557 createIconAndText(uniqueSchemeValues.values().next().value, uniqueDomainValues.values().next().value); 558 return;559 }560 561 if (!entry.domain) {562 cell.textContent = emDash;563 558 return; 564 559 } … … 687 682 for (let i = 0; i < fullscreenDOMEvents.length; i += 2) { 688 683 let fullscreenElement = container.appendChild(document.createElement("div")); 689 fullscreenElement.classList.add(" dom-fullscreen");684 fullscreenElement.classList.add("area", "dom-fullscreen"); 690 685 positionByStartOffset(fullscreenElement, fullscreenDOMEvents[i].timestamp); 691 686 setWidthForDuration(fullscreenElement, fullscreenDOMEvents[i].timestamp, fullscreenDOMEvents[i + 1].timestamp); … … 694 689 if (originator) 695 690 fullscreenElement.title = WI.UIString("Fullscreen from “%s“").format(originator.displayName); 691 else 692 fullscreenElement.title = WI.UIString("Fullscreen"); 696 693 } 694 } 695 696 for (let lowPowerRange of domNode.lowPowerRanges) { 697 let startTimestamp = lowPowerRange.startTimestamp || graphStartTime; 698 let endTimestamp = lowPowerRange.endTimestamp || this._waterfallEndTime; 699 700 let lowPowerElement = container.appendChild(document.createElement("div")); 701 lowPowerElement.classList.add("area", "low-power"); 702 lowPowerElement.title = WI.UIString("Low Power Mode"); 703 positionByStartOffset(lowPowerElement, startTimestamp); 704 setWidthForDuration(lowPowerElement, startTimestamp, endTimestamp); 697 705 } 698 706 … … 1559 1567 1560 1568 resource.initiatorNode.addEventListener(WI.DOMNode.Event.DidFireEvent, this._handleNodeDidFireEvent, this); 1569 if (resource.initiatorNode.canEnterLowPowerMode()) 1570 resource.initiatorNode.addEventListener(WI.DOMNode.Event.LowPowerChanged, this._handleNodeLowPowerChanged, this); 1561 1571 } 1562 1572 … … 1590 1600 if (domEvent.timestamp > this._waterfallEndTime) 1591 1601 this._waterfallEndTime = domEvent.timestamp + (this._waterfallTimelineRuler.secondsPerPixel * 10); 1602 1603 this.needsLayout(); 1604 } 1605 1606 _handleNodeLowPowerChanged(event) 1607 { 1608 let domNode = event.target; 1609 let {timestamp} = event.data; 1610 1611 this._pendingUpdates.push(domNode); 1612 1613 if (timestamp > this._waterfallEndTime) 1614 this._waterfallEndTime = timestamp + (this._waterfallTimelineRuler.secondsPerPixel * 10); 1592 1615 1593 1616 this.needsLayout();
Note: See TracChangeset
for help on using the changeset viewer.