OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | 2 * Copyright (C) 2013 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 * @param {WebInspector.TimelineModel} model | 641 * @param {WebInspector.TimelineModel} model |
642 */ | 642 */ |
643 WebInspector.TimelineFrameOverview = function(model) | 643 WebInspector.TimelineFrameOverview = function(model) |
644 { | 644 { |
645 WebInspector.TimelineOverviewBase.call(this, model); | 645 WebInspector.TimelineOverviewBase.call(this, model); |
646 this.element.id = "timeline-overview-frames"; | 646 this.element.id = "timeline-overview-frames"; |
647 this.reset(); | 647 this.reset(); |
648 | 648 |
649 this._outerPadding = 4 * window.devicePixelRatio; | 649 this._outerPadding = 4 * window.devicePixelRatio; |
650 this._maxInnerBarWidth = 10 * window.devicePixelRatio; | 650 this._maxInnerBarWidth = 10 * window.devicePixelRatio; |
| 651 this._topPadding = 6 * window.devicePixelRatio; |
651 | 652 |
652 // The below two are really computed by update() -- but let's have something
so that windowTimes() is happy. | 653 // The below two are really computed by update() -- but let's have something
so that windowTimes() is happy. |
653 this._actualPadding = 5 * window.devicePixelRatio; | 654 this._actualPadding = 5 * window.devicePixelRatio; |
654 this._actualOuterBarWidth = this._maxInnerBarWidth + this._actualPadding; | 655 this._actualOuterBarWidth = this._maxInnerBarWidth + this._actualPadding; |
655 | 656 |
656 this._fillStyles = {}; | 657 this._fillStyles = {}; |
657 var categories = WebInspector.TimelinePresentationModel.categories(); | 658 var categories = WebInspector.TimelinePresentationModel.categories(); |
658 for (var category in categories) | 659 for (var category in categories) |
659 this._fillStyles[category] = WebInspector.TimelinePresentationModel.crea
teFillStyleForCategory(this._context, this._maxInnerBarWidth, 0, categories[cate
gory]); | 660 this._fillStyles[category] = WebInspector.TimelinePresentationModel.crea
teFillStyleForCategory(this._context, this._maxInnerBarWidth, 0, categories[cate
gory]); |
| 661 this._frameTopShadeGradient = this._context.createLinearGradient(0, 0, 0, th
is._topPadding); |
| 662 this._frameTopShadeGradient.addColorStop(0, "rgba(255, 255, 255, 0.9)"); |
| 663 this._frameTopShadeGradient.addColorStop(1, "rgba(255, 255, 255, 0.2)"); |
660 } | 664 } |
661 | 665 |
662 WebInspector.TimelineFrameOverview.prototype = { | 666 WebInspector.TimelineFrameOverview.prototype = { |
663 reset: function() | 667 reset: function() |
664 { | 668 { |
665 this._recordsPerBar = 1; | 669 this._recordsPerBar = 1; |
666 /** @type {!Array.<{startTime:number, endTime:number}>} */ | 670 /** @type {!Array.<{startTime:number, endTime:number}>} */ |
667 this._barTimes = []; | 671 this._barTimes = []; |
668 this._frames = []; | 672 this._mainThreadFrames = []; |
| 673 this._backgroundFrames = []; |
| 674 this._framesById = {}; |
669 }, | 675 }, |
670 | 676 |
671 update: function() | 677 update: function() |
672 { | 678 { |
673 this._resetCanvas(); | 679 this._resetCanvas(); |
674 this._barTimes = []; | 680 this._barTimes = []; |
675 | 681 |
| 682 var backgroundFramesHeight = 15; |
| 683 var mainThreadFramesHeight = this._canvas.height - backgroundFramesHeigh
t; |
676 const minBarWidth = 4 * window.devicePixelRatio; | 684 const minBarWidth = 4 * window.devicePixelRatio; |
677 var frameCount = this._frames.length; | 685 var frameCount = this._backgroundFrames.length || this._mainThreadFrames
.length; |
678 var framesPerBar = Math.max(1, frameCount * minBarWidth / this._canvas.w
idth); | 686 var framesPerBar = Math.max(1, frameCount * minBarWidth / this._canvas.w
idth); |
679 var visibleFrames = this._aggregateFrames(this._frames, framesPerBar); | 687 |
680 var windowHeight = this._canvas.height; | 688 var mainThreadVisibleFrames; |
681 const paddingTop = 4 * window.devicePixelRatio; | 689 var backgroundVisibleFrames; |
682 var scale = (windowHeight - paddingTop) / this._computeTargetFrameLength
(visibleFrames); | 690 if (this._backgroundFrames.length) { |
683 this._renderBars(visibleFrames, scale, windowHeight); | 691 backgroundVisibleFrames = this._aggregateFrames(this._backgroundFram
es, framesPerBar); |
684 this._drawFPSMarks(scale, windowHeight); | 692 mainThreadVisibleFrames = new Array(backgroundVisibleFrames.length); |
| 693 for (var i = 0; i < backgroundVisibleFrames.length; ++i) { |
| 694 var frameId = backgroundVisibleFrames[i].mainThreadFrameId; |
| 695 mainThreadVisibleFrames[i] = frameId && this._framesById[frameId
]; |
| 696 } |
| 697 } else { |
| 698 mainThreadVisibleFrames = this._aggregateFrames(this._mainThreadFram
es, framesPerBar); |
| 699 } |
| 700 |
| 701 this._context.save(); |
| 702 this._setCanvasWindow(0, backgroundFramesHeight, this._canvas.width, mai
nThreadFramesHeight); |
| 703 var scale = (mainThreadFramesHeight - this._topPadding) / this._computeT
argetFrameLength(mainThreadVisibleFrames); |
| 704 this._renderBars(mainThreadVisibleFrames, scale, mainThreadFramesHeight)
; |
| 705 this._context.fillStyle = this._frameTopShadeGradient; |
| 706 this._context.fillRect(0, 0, this._canvas.width, this._topPadding); |
| 707 this._drawFPSMarks(scale, mainThreadFramesHeight); |
| 708 this._context.restore(); |
| 709 |
| 710 var bottom = backgroundFramesHeight + 0.5; |
| 711 this._context.strokeStyle = "rgba(120, 120, 120, 0.8)"; |
| 712 this._context.beginPath(); |
| 713 this._context.moveTo(0, bottom); |
| 714 this._context.lineTo(this._canvas.width, bottom); |
| 715 this._context.stroke(); |
| 716 |
| 717 if (backgroundVisibleFrames) { |
| 718 const targetFPS = 30.0; |
| 719 scale = (backgroundFramesHeight - this._topPadding) / (1.0 / targetF
PS); |
| 720 this._renderBars(backgroundVisibleFrames, scale, backgroundFramesHei
ght); |
| 721 } |
685 }, | 722 }, |
686 | 723 |
687 /** | 724 /** |
688 * @param {WebInspector.TimelineFrame} frame | 725 * @param {WebInspector.TimelineFrame} frame |
689 */ | 726 */ |
690 addFrame: function(frame) | 727 addFrame: function(frame) |
691 { | 728 { |
692 this._frames.push(frame); | 729 var frames; |
| 730 if (frame.isBackground) { |
| 731 frames = this._backgroundFrames; |
| 732 } else { |
| 733 frames = this._mainThreadFrames; |
| 734 this._framesById[frame.id] = frame; |
| 735 } |
| 736 frames.push(frame); |
693 }, | 737 }, |
694 | 738 |
| 739 /** |
| 740 * @param {number} x0 |
| 741 * @param {number} y0 |
| 742 * @param {number} width |
| 743 * @param {number} height |
| 744 */ |
| 745 _setCanvasWindow: function(x0, y0, width, height) |
| 746 { |
| 747 this._context.translate(x0, y0); |
| 748 this._context.beginPath(); |
| 749 this._context.moveTo(0, 0); |
| 750 this._context.lineTo(width, 0); |
| 751 this._context.lineTo(width, height); |
| 752 this._context.lineTo(0, height); |
| 753 this._context.lineTo(0, 0); |
| 754 this._context.clip(); |
| 755 }, |
695 | 756 |
696 /** | 757 /** |
697 * @param {Array.<WebInspector.TimelineFrame>} frames | 758 * @param {Array.<WebInspector.TimelineFrame>} frames |
698 * @param {number} framesPerBar | 759 * @param {number} framesPerBar |
699 * @return {Array.<WebInspector.TimelineFrame>} | 760 * @return {Array.<WebInspector.TimelineFrame>} |
700 */ | 761 */ |
701 _aggregateFrames: function(frames, framesPerBar) | 762 _aggregateFrames: function(frames, framesPerBar) |
702 { | 763 { |
703 var visibleFrames = []; | 764 var visibleFrames = []; |
704 for (var barNumber = 0, currentFrame = 0; currentFrame < frames.length;
++barNumber) { | 765 for (var barNumber = 0, currentFrame = 0; currentFrame < frames.length;
++barNumber) { |
705 var barStartTime = frames[currentFrame].startTime; | 766 var barStartTime = frames[currentFrame].startTime; |
706 var longestFrame = null; | 767 var longestFrame = null; |
707 var longestDuration = 0; | 768 var longestDuration = 0; |
708 | 769 |
709 for (var lastFrame = Math.min(Math.floor((barNumber + 1) * framesPer
Bar), frames.length); | 770 for (var lastFrame = Math.min(Math.floor((barNumber + 1) * framesPer
Bar), frames.length); |
710 currentFrame < lastFrame; ++currentFrame) { | 771 currentFrame < lastFrame; ++currentFrame) { |
711 var duration = frames[currentFrame].duration; | 772 var duration = this._frameDuration(frames[currentFrame]); |
712 if (!longestFrame || longestDuration < duration) { | 773 if (!longestFrame || longestDuration < duration) { |
713 longestFrame = frames[currentFrame]; | 774 longestFrame = frames[currentFrame]; |
714 longestDuration = duration; | 775 longestDuration = duration; |
715 } | 776 } |
716 } | 777 } |
717 var barEndTime = frames[currentFrame - 1].endTime; | 778 var barEndTime = frames[currentFrame - 1].endTime; |
718 if (longestFrame) { | 779 if (longestFrame) { |
719 visibleFrames.push(longestFrame); | 780 visibleFrames.push(longestFrame); |
720 this._barTimes.push({ startTime: barStartTime, endTime: barEndTi
me }); | 781 this._barTimes.push({ startTime: barStartTime, endTime: barEndTi
me }); |
721 } | 782 } |
722 } | 783 } |
723 return visibleFrames; | 784 return visibleFrames; |
724 }, | 785 }, |
725 | 786 |
726 /** | 787 /** |
| 788 * @param {WebInspector.TimelineFrame} frame |
| 789 */ |
| 790 _frameDuration: function(frame) |
| 791 { |
| 792 var relatedFrame = frame.mainThreadFrameId && this._framesById[frame.mai
nThreadFrameId]; |
| 793 return frame.duration + (relatedFrame ? relatedFrame.duration : 0); |
| 794 }, |
| 795 |
| 796 /** |
727 * @param {Array.<WebInspector.TimelineFrame>} frames | 797 * @param {Array.<WebInspector.TimelineFrame>} frames |
728 * @return {number} | 798 * @return {number} |
729 */ | 799 */ |
730 _computeTargetFrameLength: function(frames) | 800 _computeTargetFrameLength: function(frames) |
731 { | 801 { |
732 var durations = frames.select("duration"); | 802 var durations = []; |
| 803 for (var i = 0; i < frames.length; ++i) { |
| 804 if (frames[i]) |
| 805 durations.push(frames[i].duration); |
| 806 } |
733 var medianFrameLength = durations.qselect(Math.floor(durations.length /
2)); | 807 var medianFrameLength = durations.qselect(Math.floor(durations.length /
2)); |
734 | 808 |
735 // Optimize appearance for 30fps. However, if at least half frames won't
fit at this scale, | 809 // Optimize appearance for 30fps. However, if at least half frames won't
fit at this scale, |
736 // fall back to using autoscale. | 810 // fall back to using autoscale. |
737 const targetFPS = 30; | 811 const targetFPS = 30; |
738 var result = 1.0 / targetFPS; | 812 var result = 1.0 / targetFPS; |
739 if (result >= medianFrameLength) | 813 if (result >= medianFrameLength) |
740 return result; | 814 return result; |
741 | 815 |
742 var maxFrameLength = Math.max.apply(Math, durations); | 816 var maxFrameLength = Math.max.apply(Math, durations); |
743 return Math.min(medianFrameLength * 2, maxFrameLength); | 817 return Math.min(medianFrameLength * 2, maxFrameLength); |
744 }, | 818 }, |
745 | 819 |
746 /** | 820 /** |
747 * @param {Array.<WebInspector.TimelineFrame>} frames | 821 * @param {Array.<WebInspector.TimelineFrame>} frames |
748 * @param {number} scale | 822 * @param {number} scale |
749 * @param {number} windowHeight | 823 * @param {number} windowHeight |
750 */ | 824 */ |
751 _renderBars: function(frames, scale, windowHeight) | 825 _renderBars: function(frames, scale, windowHeight) |
752 { | 826 { |
753 const maxPadding = 5 * window.devicePixelRatio; | 827 const maxPadding = 5 * window.devicePixelRatio; |
754 this._actualOuterBarWidth = Math.min((this._canvas.width - 2 * this._out
erPadding) / frames.length, this._maxInnerBarWidth + maxPadding); | 828 this._actualOuterBarWidth = Math.min((this._canvas.width - 2 * this._out
erPadding) / frames.length, this._maxInnerBarWidth + maxPadding); |
755 this._actualPadding = Math.min(Math.floor(this._actualOuterBarWidth / 3)
, maxPadding); | 829 this._actualPadding = Math.min(Math.floor(this._actualOuterBarWidth / 3)
, maxPadding); |
756 | 830 |
757 var barWidth = this._actualOuterBarWidth - this._actualPadding; | 831 var barWidth = this._actualOuterBarWidth - this._actualPadding; |
758 for (var i = 0; i < frames.length; ++i) | 832 for (var i = 0; i < frames.length; ++i) { |
759 this._renderBar(this._barNumberToScreenPosition(i), barWidth, window
Height, frames[i], scale); | 833 if (frames[i]) |
| 834 this._renderBar(this._barNumberToScreenPosition(i), barWidth, wi
ndowHeight, frames[i], scale); |
| 835 } |
760 }, | 836 }, |
761 | 837 |
762 /** | 838 /** |
763 * @param {number} n | 839 * @param {number} n |
764 */ | 840 */ |
765 _barNumberToScreenPosition: function(n) | 841 _barNumberToScreenPosition: function(n) |
766 { | 842 { |
767 return this._outerPadding + this._actualOuterBarWidth * n; | 843 return this._outerPadding + this._actualOuterBarWidth * n; |
768 }, | 844 }, |
769 | 845 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 | 879 |
804 this._context.moveTo(0, y); | 880 this._context.moveTo(0, y); |
805 this._context.lineTo(this._canvas.width, y); | 881 this._context.lineTo(this._canvas.width, y); |
806 | 882 |
807 this._context.fillStyle = "rgba(255, 255, 255, 0.5)"; | 883 this._context.fillStyle = "rgba(255, 255, 255, 0.5)"; |
808 this._context.fillRect(labelX - labelWidth, labelY, labelWidth, line
Height); | 884 this._context.fillRect(labelX - labelWidth, labelY, labelWidth, line
Height); |
809 this._context.fillStyle = "black"; | 885 this._context.fillStyle = "black"; |
810 this._context.fillText(label, labelX - labelPadding, labelY + lineHe
ight - baselineHeight); | 886 this._context.fillText(label, labelX - labelPadding, labelY + lineHe
ight - baselineHeight); |
811 labelTopMargin = labelY + lineHeight; | 887 labelTopMargin = labelY + lineHeight; |
812 } | 888 } |
813 this._context.strokeStyle = "rgba(128, 128, 128, 0.5)"; | 889 this._context.strokeStyle = "rgba(60, 60, 60, 0.4)"; |
814 this._context.stroke(); | 890 this._context.stroke(); |
815 this._context.restore(); | 891 this._context.restore(); |
816 }, | 892 }, |
817 | 893 |
818 /** | 894 /** |
819 * @param {number} left | 895 * @param {number} left |
820 * @param {number} width | 896 * @param {number} width |
821 * @param {number} windowHeight | 897 * @param {number} windowHeight |
822 * @param {WebInspector.TimelineFrame} frame | 898 * @param {WebInspector.TimelineFrame} frame |
823 * @param {number} scale | 899 * @param {number} scale |
824 */ | 900 */ |
825 _renderBar: function(left, width, windowHeight, frame, scale) | 901 _renderBar: function(left, width, windowHeight, frame, scale) |
826 { | 902 { |
827 var categories = Object.keys(WebInspector.TimelinePresentationModel.cate
gories()); | 903 var categories = Object.keys(WebInspector.TimelinePresentationModel.cate
gories()); |
828 if (!categories.length) | 904 if (!categories.length) |
829 return; | 905 return; |
830 var x = Math.floor(left) + 0.5; | 906 var x = Math.floor(left) + 0.5; |
831 width = Math.floor(width); | 907 width = Math.floor(width); |
832 | 908 |
833 for (var i = 0, bottomOffset = windowHeight; i < categories.length; ++i)
{ | 909 for (var i = 0, bottomOffset = windowHeight; i < categories.length; ++i)
{ |
834 var category = categories[i]; | 910 var category = categories[i]; |
835 var duration = frame.timeByCategory[category]; | 911 var duration = frame.timeByCategory[category]; |
836 | 912 |
837 if (!duration) | 913 if (!duration) |
838 continue; | 914 continue; |
839 var height = duration * scale; | 915 var height = Math.round(duration * scale); |
840 var y = Math.floor(bottomOffset - height) + 0.5; | 916 var y = Math.floor(bottomOffset - height) + 0.5; |
841 | 917 |
842 this._context.save(); | 918 this._context.save(); |
843 this._context.translate(x, 0); | 919 this._context.translate(x, 0); |
844 this._context.scale(width / this._maxInnerBarWidth, 1); | 920 this._context.scale(width / this._maxInnerBarWidth, 1); |
845 this._context.fillStyle = this._fillStyles[category]; | 921 this._context.fillStyle = this._fillStyles[category]; |
846 this._context.fillRect(0, y, this._maxInnerBarWidth, Math.floor(heig
ht)); | 922 this._context.fillRect(0, y, this._maxInnerBarWidth, Math.floor(heig
ht)); |
847 this._context.strokeStyle = WebInspector.TimelinePresentationModel.c
ategories()[category].borderColor; | 923 this._context.strokeStyle = WebInspector.TimelinePresentationModel.c
ategories()[category].borderColor; |
848 this._context.beginPath(); | 924 this._context.beginPath(); |
849 this._context.moveTo(0, y); | 925 this._context.moveTo(0, y); |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
961 WebInspector.TimelineWindowFilter.prototype = { | 1037 WebInspector.TimelineWindowFilter.prototype = { |
962 /** | 1038 /** |
963 * @param {!WebInspector.TimelinePresentationModel.Record} record | 1039 * @param {!WebInspector.TimelinePresentationModel.Record} record |
964 * @return {boolean} | 1040 * @return {boolean} |
965 */ | 1041 */ |
966 accept: function(record) | 1042 accept: function(record) |
967 { | 1043 { |
968 return record.lastChildEndTime >= this._pane._windowStartTime && record.
startTime <= this._pane._windowEndTime; | 1044 return record.lastChildEndTime >= this._pane._windowStartTime && record.
startTime <= this._pane._windowEndTime; |
969 } | 1045 } |
970 } | 1046 } |
OLD | NEW |