1// Copyright (C) 2019 The Android Open Source Project 2// 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 15import {hsl} from 'color-convert'; 16import {translateState} from '../common/thread_state'; 17import {ThreadDesc} from './globals'; 18 19export interface Color { 20 c: string; 21 h: number; 22 s: number; 23 l: number; 24 a?: number; 25} 26 27const MD_PALETTE: Color[] = [ 28 {c: 'red', h: 4, s: 90, l: 58}, 29 {c: 'pink', h: 340, s: 82, l: 52}, 30 {c: 'purple', h: 291, s: 64, l: 42}, 31 {c: 'deep purple', h: 262, s: 52, l: 47}, 32 {c: 'indigo', h: 231, s: 48, l: 48}, 33 {c: 'blue', h: 207, s: 90, l: 54}, 34 {c: 'light blue', h: 199, s: 98, l: 48}, 35 {c: 'cyan', h: 187, s: 100, l: 42}, 36 {c: 'teal', h: 174, s: 100, l: 29}, 37 {c: 'green', h: 122, s: 39, l: 49}, 38 {c: 'light green', h: 88, s: 50, l: 53}, 39 {c: 'lime', h: 66, s: 70, l: 54}, 40 {c: 'amber', h: 45, s: 100, l: 51}, 41 {c: 'orange', h: 36, s: 100, l: 50}, 42 {c: 'deep orange', h: 14, s: 100, l: 57}, 43 {c: 'brown', h: 16, s: 25, l: 38}, 44 {c: 'blue gray', h: 200, s: 18, l: 46}, 45 {c: 'yellow', h: 54, s: 100, l: 62}, 46]; 47 48const GREY_COLOR: Color = { 49 c: 'grey', 50 h: 0, 51 s: 0, 52 l: 62 53}; 54 55function hash(s: string, max: number): number { 56 let hash = 0x811c9dc5 & 0xfffffff; 57 for (let i = 0; i < s.length; i++) { 58 hash ^= s.charCodeAt(i); 59 hash = (hash * 16777619) & 0xffffffff; 60 } 61 return Math.abs(hash) % max; 62} 63 64export function hueForCpu(cpu: number): number { 65 return (128 + (32 * cpu)) % 256; 66} 67 68const DARK_GREEN: Color = { 69 c: 'dark green', 70 h: 120, 71 s: 44, 72 l: 34 73}; 74const LIME_GREEN: Color = { 75 c: 'lime green', 76 h: 75, 77 s: 55, 78 l: 47 79}; 80const TRANSPARENT_WHITE: Color = { 81 c: 'white', 82 h: 0, 83 s: 1, 84 l: 97, 85 a: 0.55, 86}; 87const ORANGE: Color = { 88 c: 'orange', 89 h: 36, 90 s: 100, 91 l: 50 92}; 93const INDIGO: Color = { 94 c: 'indigo', 95 h: 231, 96 s: 48, 97 l: 48 98}; 99 100export function colorForState(stateCode: string): Readonly<Color> { 101 const state = translateState(stateCode); 102 if (state === 'Running') { 103 return DARK_GREEN; 104 } else if (state.startsWith('Runnable')) { 105 return LIME_GREEN; 106 } else if (state.includes('Uninterruptible Sleep')) { 107 return ORANGE; 108 } else if (state.includes('Sleeping')) { 109 return TRANSPARENT_WHITE; 110 } 111 return INDIGO; 112} 113 114export function colorForTid(tid: number): Color { 115 const colorIdx = hash(tid.toString(), MD_PALETTE.length); 116 return Object.assign({}, MD_PALETTE[colorIdx]); 117} 118 119export function colorForThread(thread: ThreadDesc|undefined): Color { 120 if (thread === undefined) { 121 return Object.assign({}, GREY_COLOR); 122 } 123 const tid = thread.pid ? thread.pid : thread.tid; 124 return colorForTid(tid); 125} 126 127// 40 different random hues 9 degrees apart. 128export function randomColor(): string { 129 const hue = Math.floor(Math.random() * 40) * 9; 130 return '#' + hsl.hex([hue, 90, 30]); 131} 132