• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.internal.widget.remotecompose.core.operations;
17 
18 import android.annotation.NonNull;
19 
20 /** Utilities to be used across all core operations */
21 public class Utils {
22     /**
23      * Convert an integer id into a float
24      *
25      * @param v the integer id to convert
26      * @return the id as an float
27      */
asNan(int v)28     public static float asNan(int v) {
29         return Float.intBitsToFloat(v | -0x800000);
30     }
31 
32     /**
33      * convert a float into an integer id
34      *
35      * @param value the float id to convert
36      * @return the id as an integer
37      */
idFromNan(float value)38     public static int idFromNan(float value) {
39         int b = Float.floatToRawIntBits(value);
40         return b & 0x3FFFFF;
41     }
42 
43     /**
44      * Converts an id encoded in a float to the corresponding long id.
45      *
46      * @param value the float if to convert
47      * @return the float id converted to a long id
48      */
longIdFromNan(float value)49     public static long longIdFromNan(float value) {
50         return ((long) idFromNan(value)) + 0x100000000L;
51     }
52 
53     /**
54      * convert a long into an ID
55      *
56      * @param v the long to convert
57      * @return the id still as a long
58      */
idFromLong(long v)59     public static long idFromLong(long v) {
60         return v - 0x100000000L;
61     }
62 
63     /**
64      * convert a float id and turn it into a string
65      *
66      * @param value float to convert
67      * @return string form of an id
68      */
69     @NonNull
idStringFromNan(float value)70     public static String idStringFromNan(float value) {
71         int b = Float.floatToRawIntBits(value) & 0x3FFFFF;
72         return idString(b);
73     }
74 
75     /**
76      * print an id as a string
77      *
78      * @param b the id
79      * @return the id as a string
80      */
81     @NonNull
idString(int b)82     public static String idString(int b) {
83         return (b > 0xFFFFF) ? "A_" + (b & 0xFFFFF) : "" + b;
84     }
85 
86     /**
87      * trim a string to n characters if needing to trim end in "..."
88      *
89      * @param str
90      * @param n
91      * @return
92      */
93     @NonNull
trimString(@onNull String str, int n)94     public static String trimString(@NonNull String str, int n) {
95         if (str.length() > n) {
96             str = str.substring(0, n - 3) + "...";
97         }
98         return str;
99     }
100 
101     /**
102      * print the id and the value of a float
103      *
104      * @param idvalue
105      * @param value
106      * @return
107      */
floatToString(float idvalue, float value)108     public static @NonNull String floatToString(float idvalue, float value) {
109         if (Float.isNaN(idvalue)) {
110             if (idFromNan(value) == 0) {
111                 return "NaN";
112             }
113             return "[" + idFromNan(idvalue) + "]" + floatToString(value);
114         }
115         return floatToString(value);
116     }
117 
118     /**
119      * Convert float to string but render nan id in brackets [n]
120      *
121      * @param value
122      * @return
123      */
floatToString(float value)124     public static @NonNull String floatToString(float value) {
125         if (Float.isNaN(value)) {
126             if (idFromNan(value) == 0) {
127                 return "NaN";
128             }
129             return "[" + idFromNan(value) + "]";
130         }
131         return Float.toString(value);
132     }
133 
134     /**
135      * Debugging util to print a message and include the file/line it came from
136      *
137      * @param str
138      */
log(@onNull String str)139     public static void log(@NonNull String str) {
140         StackTraceElement s = new Throwable().getStackTrace()[1];
141         System.out.println(
142                 "("
143                         + s.getFileName()
144                         + ":"
145                         + s.getLineNumber()
146                         + "). "
147                         + s.getMethodName()
148                         + "() "
149                         + str);
150     }
151 
152     /**
153      * Debugging util to print the stack
154      *
155      * @param str
156      * @param n
157      */
logStack(@onNull String str, int n)158     public static void logStack(@NonNull String str, int n) {
159         StackTraceElement[] st = new Throwable().getStackTrace();
160         for (int i = 1; i < n + 1; i++) {
161             StackTraceElement s = st[i];
162             String space = new String(new char[i]).replace('\0', ' ');
163             System.out.println(
164                     space + "(" + s.getFileName() + ":" + s.getLineNumber() + ")." + str);
165         }
166     }
167 
168     /**
169      * Is a variable Allowed int calculation and references.
170      *
171      * @param v
172      * @return
173      */
isVariable(float v)174     public static boolean isVariable(float v) {
175         if (Float.isNaN(v)) {
176             int id = idFromNan(v);
177             if (id == 0) return false;
178             return id > 40 || id < 10;
179         }
180         return false;
181     }
182 
183     /**
184      * print a color in the familiar 0xAARRGGBB pattern
185      *
186      * @param color
187      * @return
188      */
189     @NonNull
colorInt(int color)190     public static String colorInt(int color) {
191         String str = "000000000000" + Integer.toHexString(color);
192         return "0x" + str.substring(str.length() - 8);
193     }
194 
195     /**
196      * Interpolate two colors. gamma corrected colors are interpolated in the form c1 * (1-t) + c2 *
197      * t
198      *
199      * @param c1
200      * @param c2
201      * @param t
202      * @return
203      */
interpolateColor(int c1, int c2, float t)204     public static int interpolateColor(int c1, int c2, float t) {
205         if (Float.isNaN(t) || t == 0.0f) {
206             return c1;
207         } else if (t == 1.0f) {
208             return c2;
209         }
210         int a = 0xFF & (c1 >> 24);
211         int r = 0xFF & (c1 >> 16);
212         int g = 0xFF & (c1 >> 8);
213         int b = 0xFF & c1;
214         float f_r = (float) Math.pow(r / 255.0f, 2.2);
215         float f_g = (float) Math.pow(g / 255.0f, 2.2);
216         float f_b = (float) Math.pow(b / 255.0f, 2.2);
217         float c1fr = f_r;
218         float c1fg = f_g;
219         float c1fb = f_b;
220         float c1fa = a / 255f;
221 
222         a = 0xFF & (c2 >> 24);
223         r = 0xFF & (c2 >> 16);
224         g = 0xFF & (c2 >> 8);
225         b = 0xFF & c2;
226         f_r = (float) Math.pow(r / 255.0f, 2.2);
227         f_g = (float) Math.pow(g / 255.0f, 2.2);
228         f_b = (float) Math.pow(b / 255.0f, 2.2);
229         float c2fr = f_r;
230         float c2fg = f_g;
231         float c2fb = f_b;
232         float c2fa = a / 255f;
233         f_r = c1fr + t * (c2fr - c1fr);
234         f_g = c1fg + t * (c2fg - c1fg);
235         f_b = c1fb + t * (c2fb - c1fb);
236         float f_a = c1fa + t * (c2fa - c1fa);
237 
238         int outr = clamp((int) ((float) Math.pow(f_r, 1.0 / 2.2) * 255.0f));
239         int outg = clamp((int) ((float) Math.pow(f_g, 1.0 / 2.2) * 255.0f));
240         int outb = clamp((int) ((float) Math.pow(f_b, 1.0 / 2.2) * 255.0f));
241         int outa = clamp((int) (f_a * 255.0f));
242 
243         return (outa << 24 | outr << 16 | outg << 8 | outb);
244     }
245 
246     /**
247      * Efficient clamping function
248      *
249      * @param c
250      * @return number between 0 and 255
251      */
clamp(int c)252     public static int clamp(int c) {
253         int n = 255;
254         c &= ~(c >> 31);
255         c -= n;
256         c &= (c >> 31);
257         c += n;
258         return c;
259     }
260 
261     /**
262      * convert hue saturation and value to RGB
263      *
264      * @param hue 0..1
265      * @param saturation 0..1 0=on the gray scale
266      * @param value 0..1 0=black
267      * @return
268      */
hsvToRgb(float hue, float saturation, float value)269     public static int hsvToRgb(float hue, float saturation, float value) {
270         int h = (int) (hue * 6);
271         float f = hue * 6 - h;
272         int p = (int) (0.5f + 255 * value * (1 - saturation));
273         int q = (int) (0.5f + 255 * value * (1 - f * saturation));
274         int t = (int) (0.5f + 255 * value * (1 - (1 - f) * saturation));
275         int v = (int) (0.5f + 255 * value);
276         switch (h) {
277             case 0:
278                 return 0XFF000000 | (v << 16) + (t << 8) + p;
279             case 1:
280                 return 0XFF000000 | (q << 16) + (v << 8) + p;
281             case 2:
282                 return 0XFF000000 | (p << 16) + (v << 8) + t;
283             case 3:
284                 return 0XFF000000 | (p << 16) + (q << 8) + v;
285             case 4:
286                 return 0XFF000000 | (t << 16) + (p << 8) + v;
287             case 5:
288                 return 0XFF000000 | (v << 16) + (p << 8) + q;
289         }
290         return 0;
291     }
292 
293     /**
294      * Convert float alpha, red,g reen, blue to ARGB int
295      *
296      * @param alpha alpha value
297      * @param red red value
298      * @param green green value
299      * @param blue blue value
300      * @return ARGB int
301      */
toARGB(float alpha, float red, float green, float blue)302     public static int toARGB(float alpha, float red, float green, float blue) {
303         int a = (int) (alpha * 255.0f + 0.5f);
304         int r = (int) (red * 255.0f + 0.5f);
305         int g = (int) (green * 255.0f + 0.5f);
306         int b = (int) (blue * 255.0f + 0.5f);
307         return (a << 24 | r << 16 | g << 8 | b);
308     }
309 
310     /**
311      * Returns the hue of an ARGB int
312      *
313      * @param argb the color int
314      * @return
315      */
getHue(int argb)316     public static float getHue(int argb) {
317         int r = (argb >> 16) & 0xFF;
318         int g = (argb >> 8) & 0xFF;
319         int b = argb & 0xFF;
320         float hsl1, hsl2, hsl3;
321         final float rf = r / 255f;
322         final float gf = g / 255f;
323         final float bf = b / 255f;
324         final float max = Math.max(rf, Math.max(gf, bf));
325         final float min = Math.min(rf, Math.min(gf, bf));
326         final float deltaMaxMin = max - min;
327         float h;
328         if (max == min) {
329             // Monochromatic
330             h = 0f;
331         } else {
332             if (max == rf) {
333                 h = ((gf - bf) / deltaMaxMin) % 6f;
334             } else if (max == gf) {
335                 h = ((bf - rf) / deltaMaxMin) + 2f;
336             } else {
337                 h = ((rf - gf) / deltaMaxMin) + 4f;
338             }
339         }
340         h = (h * 60f) % 360f;
341         if (h < 0) {
342             h += 360f;
343         }
344         return h / 360f;
345     }
346 
347     /**
348      * Get the saturation of an ARGB int
349      *
350      * @param argb the color int
351      * @return
352      */
getSaturation(int argb)353     public static float getSaturation(int argb) {
354         int r = (argb >> 16) & 0xFF;
355         int g = (argb >> 8) & 0xFF;
356         int b = argb & 0xFF;
357 
358         final float rf = r / 255f;
359         final float gf = g / 255f;
360         final float bf = b / 255f;
361         final float max = Math.max(rf, Math.max(gf, bf));
362         final float min = Math.min(rf, Math.min(gf, bf));
363         final float deltaMaxMin = max - min;
364         float s;
365         float l = (max + min) / 2f;
366         if (max == min) {
367             // Monochromatic
368             s = 0f;
369         } else {
370 
371             s = deltaMaxMin / (1f - Math.abs(2f * l - 1f));
372         }
373 
374         return s;
375     }
376 
377     /**
378      * Get the brightness of an ARGB int
379      *
380      * @param argb the color int
381      * @return
382      */
getBrightness(int argb)383     public static float getBrightness(int argb) {
384         int r = (argb >> 16) & 0xFF;
385         int g = (argb >> 8) & 0xFF;
386         int b = argb & 0xFF;
387         final float rf = r / 255f;
388         final float gf = g / 255f;
389         final float bf = b / 255f;
390         final float max = Math.max(rf, Math.max(gf, bf));
391         final float min = Math.min(rf, Math.min(gf, bf));
392 
393         return (max + min) / 2f;
394     }
395 }
396