1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { ColorUtils } from '../../component/trace/base/ColorUtils'; 17import { TraceRow } from '../../component/trace/base/TraceRow'; 18import { 19 BaseStruct, 20 drawLoadingFrame, 21 drawString, 22 isFrameContainPoint, 23 ns2x, 24 Rect, 25 Render, 26} from './ProcedureWorkerCommon'; 27import { SpSystemTrace } from '../../component/SpSystemTrace'; 28 29export class FrameAnimationRender extends Render { 30 renderMainThread( 31 req: { 32 useCache: boolean; 33 context: CanvasRenderingContext2D; 34 type: string; 35 }, 36 row: TraceRow<FrameAnimationStruct> 37 ): void { 38 let frameAnimationList: FrameAnimationStruct[] = row.dataList; 39 let frameAnimationFilter: FrameAnimationStruct[] = row.dataListCache; 40 this.frameAnimation( 41 frameAnimationList, 42 frameAnimationFilter, 43 TraceRow.range!.startNS, 44 TraceRow.range!.endNS, 45 TraceRow.range!.totalNS, // @ts-ignore 46 row.frame, 47 req.useCache || !TraceRow.range!.refresh 48 ); 49 drawLoadingFrame(req.context, row.dataListCache, row); 50 req.context.beginPath(); 51 let find: boolean = false; 52 for (let index: number = 0; index < frameAnimationFilter.length; index++) { 53 let currentAnimationStruct: FrameAnimationStruct = frameAnimationFilter[index]; 54 FrameAnimationStruct.draw(req.context, currentAnimationStruct, row); 55 if ( 56 row.isHover && 57 currentAnimationStruct.frame && 58 isFrameContainPoint(currentAnimationStruct.frame, row.hoverX, row.hoverY) 59 ) { 60 FrameAnimationStruct.hoverFrameAnimationStruct = currentAnimationStruct; 61 find = true; 62 } 63 } 64 if (!find && row.isHover) { 65 FrameAnimationStruct.hoverFrameAnimationStruct = undefined; 66 } 67 req.context.closePath(); 68 } 69 70 private frameAnimation( 71 frameAnimationList: FrameAnimationStruct[], 72 frameAnimationFilter: FrameAnimationStruct[], 73 startNS: number = 0, 74 endNS: number = 0, 75 totalNS: number, 76 frame: Rect, 77 use: boolean 78 ): void { 79 if (use && frameAnimationFilter.length > 0) { 80 for (let index: number = 0; index < frameAnimationFilter.length; index++) { 81 let frameAnimationNode: FrameAnimationStruct = frameAnimationFilter[index]; 82 frameAnimationNode.frame = undefined; 83 FrameAnimationStruct.setFrameAnimation(frameAnimationNode, padding, startNS, endNS, totalNS, frame); 84 } 85 return; 86 } 87 frameAnimationFilter.length = 0; 88 if (frameAnimationList) { 89 for (let index: number = 0; index < frameAnimationList.length; index++) { 90 let currentFrameAnimation: FrameAnimationStruct = frameAnimationList[index]; 91 if ( 92 (currentFrameAnimation.startTs || 0) + (currentFrameAnimation.dur || 0) > startNS && 93 (currentFrameAnimation.startTs || 0) < endNS 94 ) { 95 FrameAnimationStruct.setFrameAnimation( 96 currentFrameAnimation, 97 padding, 98 startNS, 99 endNS || 0, 100 totalNS || 0, 101 frame 102 ); 103 frameAnimationFilter.push(currentFrameAnimation); 104 } 105 } 106 } 107 } 108} 109export function FrameAnimationStructOnClick( 110 clickRowType: string, 111 sp: SpSystemTrace, 112 scrollToFuncHandler: Function, 113 row: TraceRow<FrameAnimationStruct>, 114 entry?: FrameAnimationStruct, 115): Promise<unknown> { 116 return new Promise((resolve, reject) => { 117 if (clickRowType === TraceRow.ROW_TYPE_FRAME_ANIMATION) { 118 FrameAnimationStruct.selectFrameAnimationStruct = 119 FrameAnimationStruct.hoverFrameAnimationStruct || row.getHoverStruct(); 120 if (FrameAnimationStruct.selectFrameAnimationStruct || entry) { 121 let data = entry || FrameAnimationStruct.selectFrameAnimationStruct; 122 sp.traceSheetEL?.displayFrameAnimationData( 123 data!, 124 scrollToFuncHandler 125 ); 126 sp.timerShaftEL?.modifyFlagList(undefined); 127 } 128 reject(new Error()); 129 } else { 130 resolve(null); 131 } 132 }); 133} 134export class FrameAnimationStruct extends BaseStruct { 135 static hoverFrameAnimationStruct: FrameAnimationStruct | undefined; 136 static selectFrameAnimationStruct: FrameAnimationStruct | undefined; 137 dur: number = 0; 138 status: string = ''; 139 animationId: number | undefined; 140 fps: number | undefined; 141 depth: number = 0; 142 startTs: number = 0; 143 endTs: number = 0; 144 frameInfo: string | undefined; 145 name: string | undefined; 146 inputTime: number = 0; 147 endTime: number = 0; 148 149 static setFrameAnimation( 150 animationNode: FrameAnimationStruct, 151 padding: number, 152 startNS: number, 153 endNS: number, 154 totalNS: number, 155 frame: Rect 156 ): void { 157 let stateStartPointX: number; 158 let stateEndPointX: number; 159 if ((animationNode.startTs || 0) < startNS) { 160 stateStartPointX = 0; 161 } else { 162 stateStartPointX = ns2x(animationNode.startTs || 0, startNS, endNS, totalNS, frame); 163 } 164 if ((animationNode.startTs || 0) + (animationNode.dur || 0) > endNS) { 165 stateEndPointX = frame.width; 166 } else { 167 stateEndPointX = ns2x((animationNode.startTs || 0) + (animationNode.dur || 0), startNS, endNS, totalNS, frame); 168 } 169 let frameWidth: number = 170 stateEndPointX - stateStartPointX <= unitIndex ? unitIndex : stateEndPointX - stateStartPointX; 171 if (!animationNode.frame) { 172 animationNode.frame = new Rect(0, 0, 0, 0); 173 } 174 animationNode.frame.x = Math.floor(stateStartPointX); 175 animationNode.frame.y = frame.y + animationNode.depth * 20 + padding; 176 animationNode.frame.width = Math.ceil(frameWidth); 177 animationNode.frame.height = 20 - multiple * padding; 178 } 179 180 static draw( 181 ctx: CanvasRenderingContext2D, 182 frameAnimationNode: FrameAnimationStruct, 183 row: TraceRow<FrameAnimationStruct> 184 ): void { 185 let tsFixed: number = 6; 186 let isHover: boolean = row.isHover; 187 let frame = frameAnimationNode.frame; 188 if (frame) { 189 let nsToMillisecond = 1000_000; 190 ctx.globalAlpha = 1.0; 191 ctx.lineWidth = 1; 192 ctx.lineJoin = 'round'; 193 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[6]; 194 ctx.fillRect(frame.x, frame.y, frame.width, frame.height); 195 ctx.fillStyle = ColorUtils.ANIMATION_COLOR[3]; 196 ctx.textBaseline = 'middle'; 197 ctx.font = '8px sans-serif'; 198 drawString( 199 ctx, 200 `${frameAnimationNode.status} (${(frameAnimationNode.dur / nsToMillisecond).toFixed(tsFixed)} ms)`, 201 textPadding, 202 frame, 203 frameAnimationNode 204 ); 205 ctx.lineWidth = 2; 206 if ( 207 (frameAnimationNode === FrameAnimationStruct.hoverFrameAnimationStruct && isHover) || 208 frameAnimationNode === FrameAnimationStruct.selectFrameAnimationStruct 209 ) { 210 ctx.globalAlpha = 0.8; 211 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[3]; 212 213 ctx.strokeRect(frame.x + padding, frame.y, frame.width - padding, frame.height); 214 } else { 215 ctx.strokeStyle = ColorUtils.ANIMATION_COLOR[2]; 216 ctx.strokeRect(frame.x + padding, frame.y, frame.width - padding, frame.height); 217 } 218 } 219 } 220} 221 222const padding: number = 2; 223const multiple: number = 2; 224const unitIndex: number = 1; 225const textPadding: number = 5; 226