]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-xray/xray-color-helper.cc
Merge ACPICA 20170929.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-xray / xray-color-helper.cc
1 //===-- xray-graph.cc - XRay Function Call Graph Renderer -----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // A class to get a color from a specified gradient.
11 //
12 //===----------------------------------------------------------------------===//
13 #include <algorithm>
14 #include <iostream>
15
16 #include "xray-color-helper.h"
17 #include "llvm/Support/FormatVariadic.h"
18 #include "llvm/Support/raw_ostream.h"
19
20 using namespace llvm;
21 using namespace xray;
22
23 //  Sequential ColorMaps, which are used to represent information
24 //  from some minimum to some maximum.
25
26 static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialMaps[][9] = {
27     {// The greys color scheme from http://colorbrewer2.org/
28      std::make_tuple(255, 255, 255), std::make_tuple(240, 240, 240),
29      std::make_tuple(217, 217, 217), std::make_tuple(189, 189, 189),
30      std::make_tuple(150, 150, 150), std::make_tuple(115, 115, 115),
31      std::make_tuple(82, 82, 82), std::make_tuple(37, 37, 37),
32      std::make_tuple(0, 0, 0)},
33     {// The OrRd color scheme from http://colorbrewer2.org/
34      std::make_tuple(255, 247, 236), std::make_tuple(254, 232, 200),
35      std::make_tuple(253, 212, 158), std::make_tuple(253, 187, 132),
36      std::make_tuple(252, 141, 89), std::make_tuple(239, 101, 72),
37      std::make_tuple(215, 48, 31), std::make_tuple(179, 0, 0),
38      std::make_tuple(127, 0, 0)},
39     {// The PuBu color scheme from http://colorbrewer2.org/
40      std::make_tuple(255, 247, 251), std::make_tuple(236, 231, 242),
41      std::make_tuple(208, 209, 230), std::make_tuple(166, 189, 219),
42      std::make_tuple(116, 169, 207), std::make_tuple(54, 144, 192),
43      std::make_tuple(5, 112, 176), std::make_tuple(4, 90, 141),
44      std::make_tuple(2, 56, 88)}};
45
46 // Sequential Maps extend the last colors given out of range inputs.
47 static const std::tuple<uint8_t, uint8_t, uint8_t> SequentialBounds[][2] = {
48     {// The Bounds for the greys color scheme
49      std::make_tuple(255, 255, 255), std::make_tuple(0, 0, 0)},
50     {// The Bounds for the OrRd color Scheme
51      std::make_tuple(255, 247, 236), std::make_tuple(127, 0, 0)},
52     {// The Bounds for the PuBu color Scheme
53      std::make_tuple(255, 247, 251), std::make_tuple(2, 56, 88)}};
54
55 ColorHelper::ColorHelper(ColorHelper::SequentialScheme S)
56     : MinIn(0.0), MaxIn(1.0), ColorMap(SequentialMaps[static_cast<int>(S)]),
57       BoundMap(SequentialBounds[static_cast<int>(S)]) {}
58
59 // Diverging ColorMaps, which are used to represent information
60 // representing differenes, or a range that goes from negative to positive.
61 // These take an input in the range [-1,1].
62
63 static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingCoeffs[][11] = {
64     {// The PiYG color scheme from http://colorbrewer2.org/
65      std::make_tuple(142, 1, 82), std::make_tuple(197, 27, 125),
66      std::make_tuple(222, 119, 174), std::make_tuple(241, 182, 218),
67      std::make_tuple(253, 224, 239), std::make_tuple(247, 247, 247),
68      std::make_tuple(230, 245, 208), std::make_tuple(184, 225, 134),
69      std::make_tuple(127, 188, 65), std::make_tuple(77, 146, 33),
70      std::make_tuple(39, 100, 25)}};
71
72 // Diverging maps use out of bounds ranges to show missing data. Missing Right
73 // Being below min, and missing left being above max.
74 static const std::tuple<uint8_t, uint8_t, uint8_t> DivergingBounds[][2] = {
75     {// The PiYG color scheme has green and red for missing right and left
76      // respectively.
77      std::make_tuple(255, 0, 0), std::make_tuple(0, 255, 0)}};
78
79 ColorHelper::ColorHelper(ColorHelper::DivergingScheme S)
80     : MinIn(-1.0), MaxIn(1.0), ColorMap(DivergingCoeffs[static_cast<int>(S)]),
81       BoundMap(DivergingBounds[static_cast<int>(S)]) {}
82
83 // Takes a tuple of uint8_ts representing a color in RGB and converts them to
84 // HSV represented by a tuple of doubles
85 static std::tuple<double, double, double>
86 convertToHSV(const std::tuple<uint8_t, uint8_t, uint8_t> &Color) {
87   double Scaled[3] = {std::get<0>(Color) / 255.0, std::get<1>(Color) / 255.0,
88                       std::get<2>(Color) / 255.0};
89   int Min = 0;
90   int Max = 0;
91   for (int i = 1; i < 3; ++i) {
92     if (Scaled[i] < Scaled[Min])
93       Min = i;
94     if (Scaled[i] > Scaled[Max])
95       Max = i;
96   }
97
98   double C = Scaled[Max] - Scaled[Min];
99
100   double HPrime =
101       (C == 0) ? 0 : (Scaled[(Max + 1) % 3] - Scaled[(Max + 2) % 3]) / C;
102   HPrime = HPrime + 2.0 * Max;
103
104   double H = (HPrime < 0) ? (HPrime + 6.0) * 60
105                           : HPrime * 60; // Scale to between 0 and 360
106   double V = Scaled[Max];
107
108   double S = (V == 0.0) ? 0.0 : C / V;
109
110   return std::make_tuple(H, S, V);
111 }
112
113 // Takes a double precision number, clips it between 0 and 1 and then converts
114 // that to an integer between 0x00 and 0xFF with proxpper rounding.
115 static uint8_t unitIntervalTo8BitChar(double B) {
116   double n = std::max(std::min(B, 1.0), 0.0);
117   return static_cast<uint8_t>(255 * n + 0.5);
118 }
119
120 // Takes a typle of doubles representing a color in HSV and converts them to
121 // RGB represented as a tuple of uint8_ts
122 static std::tuple<uint8_t, uint8_t, uint8_t>
123 convertToRGB(const std::tuple<double, double, double> &Color) {
124   const double &H = std::get<0>(Color);
125   const double &S = std::get<1>(Color);
126   const double &V = std::get<2>(Color);
127
128   double C = V * S;
129
130   double HPrime = H / 60;
131   double X = C * (1 - std::abs(std::fmod(HPrime, 2.0) - 1));
132
133   double RGB1[3];
134   int HPrimeInt = static_cast<int>(HPrime);
135   if (HPrimeInt % 2 == 0) {
136     RGB1[(HPrimeInt / 2) % 3] = C;
137     RGB1[(HPrimeInt / 2 + 1) % 3] = X;
138     RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
139   } else {
140     RGB1[(HPrimeInt / 2) % 3] = X;
141     RGB1[(HPrimeInt / 2 + 1) % 3] = C;
142     RGB1[(HPrimeInt / 2 + 2) % 3] = 0.0;
143   }
144
145   double Min = V - C;
146   double RGB2[3] = {RGB1[0] + Min, RGB1[1] + Min, RGB1[2] + Min};
147
148   return std::make_tuple(unitIntervalTo8BitChar(RGB2[0]),
149                          unitIntervalTo8BitChar(RGB2[1]),
150                          unitIntervalTo8BitChar(RGB2[2]));
151 }
152
153 // The Hue component of the HSV interpolation Routine
154 static double interpolateHue(double H0, double H1, double T) {
155   double D = H1 - H0;
156   if (H0 > H1) {
157     std::swap(H0, H1);
158
159     D = -D;
160     T = 1 - T;
161   }
162
163   if (D <= 180) {
164     return H0 + T * (H1 - H0);
165   } else {
166     H0 = H0 + 360;
167     return std::fmod(H0 + T * (H1 - H0) + 720, 360);
168   }
169 }
170
171 // Interpolates between two HSV Colors both represented as a tuple of doubles
172 // Returns an HSV Color represented as a tuple of doubles
173 static std::tuple<double, double, double>
174 interpolateHSV(const std::tuple<double, double, double> &C0,
175                const std::tuple<double, double, double> &C1, double T) {
176   double H = interpolateHue(std::get<0>(C0), std::get<0>(C1), T);
177   double S = std::get<1>(C0) + T * (std::get<1>(C1) - std::get<1>(C0));
178   double V = std::get<2>(C0) + T * (std::get<2>(C1) - std::get<2>(C0));
179   return std::make_tuple(H, S, V);
180 }
181
182 // Get the Color as a tuple of uint8_ts
183 std::tuple<uint8_t, uint8_t, uint8_t>
184 ColorHelper::getColorTuple(double Point) const {
185   assert(!ColorMap.empty() && "ColorMap must not be empty!");
186   assert(!BoundMap.empty() && "BoundMap must not be empty!");
187
188   if (Point < MinIn)
189     return BoundMap[0];
190   if (Point > MaxIn)
191     return BoundMap[1];
192
193   size_t MaxIndex = ColorMap.size() - 1;
194   double IntervalWidth = MaxIn - MinIn;
195   double OffsetP = Point - MinIn;
196   double SectionWidth = IntervalWidth / static_cast<double>(MaxIndex);
197   size_t SectionNo = std::floor(OffsetP / SectionWidth);
198   double T = (OffsetP - SectionNo * SectionWidth) / SectionWidth;
199
200   auto &RGBColor0 = ColorMap[SectionNo];
201   auto &RGBColor1 = ColorMap[std::min(SectionNo + 1, MaxIndex)];
202
203   auto HSVColor0 = convertToHSV(RGBColor0);
204   auto HSVColor1 = convertToHSV(RGBColor1);
205
206   auto InterpolatedHSVColor = interpolateHSV(HSVColor0, HSVColor1, T);
207   return convertToRGB(InterpolatedHSVColor);
208 }
209
210 // A helper method to convert a color represented as tuple of uint8s to a hex
211 // string.
212 std::string
213 ColorHelper::getColorString(std::tuple<uint8_t, uint8_t, uint8_t> t) {
214   return llvm::formatv("#{0:X-2}{1:X-2}{2:X-2}", std::get<0>(t), std::get<1>(t),
215                        std::get<2>(t));
216 }
217
218 // Gets a color in a gradient given a number in the interval [0,1], it does this
219 // by evaluating a polynomial which maps [0, 1] -> [0, 1] for each of the R G
220 // and B values in the color. It then converts this [0,1] colors to a 24 bit
221 // color as a hex string.
222 std::string ColorHelper::getColorString(double Point) const {
223   return getColorString(getColorTuple(Point));
224 }