1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   Utility (Utility)                                                   */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define ALPHAVAL(_c) (GX_UBYTE)(((_c) >> 12) & 0xf)
22 #define REDVAL(_c)   (GX_UBYTE)(((_c) >> 8) & 0xf)
23 #define GREENVAL(_c) (GX_UBYTE)(((_c) >> 4) & 0xf)
24 #define BLUEVAL(_c)  (GX_UBYTE)(((_c)) & 0xf)
25 
26 #define ASSEMBLECOLOR(_a, _r, _g, _b)            \
27     (USHORT)((((_a) & 0xf) << 12)              | \
28              (((_r) & 0xf) << 8)               | \
29              (((_g) & 0xf) << 4)               | \
30              ((_b) & 0xf))
31 
32 #define GX_SOURCE_CODE
33 
34 
35 /* Include necessary system files.  */
36 
37 #include "gx_api.h"
38 #include "gx_display.h"
39 #include "gx_context.h"
40 #include "gx_utility.h"
41 #include "gx_system.h"
42 
43 /**************************************************************************/
44 /*                                                                        */
45 /*  FUNCTION                                               RELEASE        */
46 /*                                                                        */
47 /*    _gx_utility_4444argb_pixelmap_rotate                PORTABLE C      */
48 /*                                                           6.1          */
49 /*  AUTHOR                                                                */
50 /*                                                                        */
51 /*    Kenneth Maxwell, Microsoft Corporation                              */
52 /*                                                                        */
53 /*  DESCRIPTION                                                           */
54 /*                                                                        */
55 /*    Internal helper funciton that rotate an 4444argb format uncompressed*/
56 /*    pixelmap.                                                           */
57 /*                                                                        */
58 /*  INPUT                                                                 */
59 /*                                                                        */
60 /*    src                                   The pixelmap to be rotated    */
61 /*    angle                                 The angle to be rotated       */
62 /*    destination                           The rotated bitmap to be      */
63 /*                                            returned                    */
64 /*    rot_cx                                X coordinate of rotation      */
65 /*                                            center                      */
66 /*    rot_cy                                Y coordinate of rotation      */
67 /*                                            center                      */
68 /*                                                                        */
69 /*  OUTPUT                                                                */
70 /*                                                                        */
71 /*    status                                Completion status             */
72 /*                                                                        */
73 /*  CALLS                                                                 */
74 /*                                                                        */
75 /*    _gx_system_memory_allocator           Application defined memory    */
76 /*                                            allocation function         */
77 /*    _gx_utility_math_cos                  Calculate cosine of supplied  */
78 /*                                            angle                       */
79 /*    _gx_utility_math_sin                  Calculate sine of supplied    */
80 /*                                            angle                       */
81 /*                                                                        */
82 /*  CALLED BY                                                             */
83 /*                                                                        */
84 /*    GUIX Internal Code                                                  */
85 /*                                                                        */
86 /*  RELEASE HISTORY                                                       */
87 /*                                                                        */
88 /*    DATE              NAME                      DESCRIPTION             */
89 /*                                                                        */
90 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
91 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
92 /*                                            resulting in version 6.1    */
93 /*                                                                        */
94 /**************************************************************************/
_gx_utility_4444argb_pixelmap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)95 UINT _gx_utility_4444argb_pixelmap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
96 {
97 USHORT *get;
98 USHORT *put;
99 INT     srcxres;
100 INT     srcyres;
101 INT     cosv;
102 INT     sinv;
103 USHORT  red, green, blue;
104 INT     idxminx, idxmaxx, idxmaxy;
105 INT    *mx;
106 INT    *my;
107 INT     xres;
108 INT     yres;
109 INT     width, height;
110 INT     x, y;
111 INT     xx, yy;
112 USHORT  a, b, c, d;
113 USHORT  alpha[4];
114 INT     xdiff, ydiff;
115 
116     mx = _gx_system_scratchpad;
117     my = mx + 4;
118 
119     mx[0] = mx[3] = -1;
120     mx[1] = mx[2] = 1;
121 
122     my[0] = my[1] = 1;
123     my[2] = my[3] = -1;
124 
125     idxminx = (angle / 90) & 0x3;
126     idxmaxx = (idxminx + 2) & 0x3;
127     idxmaxy = (idxminx + 1) & 0x3;
128 
129     /* Calculate the source x and y center. */
130     srcxres = src -> gx_pixelmap_width >> 1;
131     srcyres = src -> gx_pixelmap_height >> 1;
132 
133     cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
134     sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
135 
136     xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
137     yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
138 
139     xres = GX_FIXED_VAL_TO_INT(xres);
140     yres = GX_FIXED_VAL_TO_INT(yres);
141 
142     /* Calculate destination width and height. */
143     width = (xres << 1);
144     height = (yres << 1);
145 
146     /* Calculate the new rotation axis. */
147     if (rot_cx && rot_cy)
148     {
149         x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
150         y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
151 
152         srcxres = *rot_cx;
153         srcyres = *rot_cy;
154 
155         x = GX_FIXED_VAL_TO_INT(x) + xres;
156         y = GX_FIXED_VAL_TO_INT(y) + yres;
157 
158         *rot_cx = x;
159         *rot_cy = y;
160 
161         xres = *rot_cx;
162         yres = *rot_cy;
163     }
164 
165     destination -> gx_pixelmap_height = (GX_VALUE)height;
166     destination -> gx_pixelmap_width = (GX_VALUE)width;
167     destination -> gx_pixelmap_flags |= GX_PIXELMAP_ALPHA;
168 
169     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
170        overflow cannot occur. */
171     destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(USHORT);
172     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
173 
174     if (destination -> gx_pixelmap_data == GX_NULL)
175     {
176         return GX_SYSTEM_MEMORY_ERROR;
177     }
178 
179     put = (USHORT *)destination -> gx_pixelmap_data;
180 
181     /* Loop through the destination's pixels.  */
182     for (y = 0; y < height; y++)
183     {
184         for (x = 0; x < width; x++)
185         {
186             xx = (x - xres) * cosv + (y - yres) * sinv;
187             yy = (y - yres) * cosv - (x - xres) * sinv;
188 
189             xdiff = GX_FIXED_VAL_TO_INT(xx << 8) & 0xff;
190             ydiff = GX_FIXED_VAL_TO_INT(yy << 8) & 0xff;
191 
192             xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
193             yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
194 
195             if ((xx >= -1) && (xx < src -> gx_pixelmap_width) &&
196                 (yy >= -1) && (yy < src -> gx_pixelmap_height))
197             {
198 
199                 if ((xx >= 0) && (xx < src -> gx_pixelmap_width - 1) &&
200                     (yy >= 0) && (yy < src -> gx_pixelmap_height - 1))
201                 {
202                     get = (USHORT *)src -> gx_pixelmap_data;
203                     get += yy * src -> gx_pixelmap_width;
204                     get += xx;
205 
206                     a = *get;
207                     b = *(get + 1);
208                     c = *(get + src -> gx_pixelmap_width);
209                     d = *(get + src -> gx_pixelmap_width + 1);
210                     alpha[0] = ALPHAVAL(a);
211                     alpha[1] = ALPHAVAL(b);
212                     alpha[2] = ALPHAVAL(c);
213                     alpha[3] = ALPHAVAL(d);
214                 }
215                 else
216                 {
217                     get = (USHORT *)src -> gx_pixelmap_data;
218 
219                     a = 0;
220                     b = 0;
221                     c = 0;
222                     d = 0;
223 
224                     if (xx == -1)
225                     {
226                         /* handle left edge.  */
227                         if (yy >= 0)
228                         {
229                             b = *(get + yy * src -> gx_pixelmap_width);
230                             alpha[1] = ALPHAVAL(b);
231                         }
232 
233                         if (yy < src -> gx_pixelmap_height - 1)
234                         {
235                             d = *(get + (yy + 1) * src -> gx_pixelmap_width);
236                             alpha[3] = ALPHAVAL(d);
237                         }
238                     }
239                     else if (yy == -1)
240                     {
241                         /* handle top edge.  */
242                         c = *(get + xx);
243                         alpha[2] = ALPHAVAL(c);
244 
245                         if (xx < src -> gx_pixelmap_width - 1)
246                         {
247                             d = *(get + xx + 1);
248                             alpha[3] = ALPHAVAL(d);
249                         }
250                     }
251                     else if (xx == src -> gx_pixelmap_width - 1)
252                     {
253                         /* handle right edget. */
254                         a = *(get + yy * src -> gx_pixelmap_width + xx);
255                         alpha[0] = ALPHAVAL(a);
256 
257                         if (yy < src -> gx_pixelmap_height - 1)
258                         {
259                             c = *(get + (yy + 1) * src -> gx_pixelmap_width + xx);
260                             alpha[2] = ALPHAVAL(c);
261                         }
262                     }
263                     else
264                     {
265                         /* handle bottom edge. */
266                         a = *(get + yy * src -> gx_pixelmap_width + xx);
267                         alpha[0] = ALPHAVAL(a);
268 
269                         b = *(get + yy * src -> gx_pixelmap_width + xx + 1);
270                         alpha[1] = ALPHAVAL(b);
271                     }
272 
273                     if (!a)
274                     {
275                         alpha[0] = 0;
276                     }
277 
278                     if (!b)
279                     {
280                         alpha[1] = 0;
281                     }
282 
283                     if (!c)
284                     {
285                         alpha[2] = 0;
286                     }
287 
288                     if (!d)
289                     {
290                         alpha[3] = 0;
291                     }
292                 }
293 
294                 red = (USHORT)((REDVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
295                                 REDVAL(b) * alpha[1] * xdiff * (256 - ydiff) +         \
296                                 REDVAL(c) * alpha[2] * ydiff * (256 - xdiff) +         \
297                                 REDVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
298 
299                 green = (USHORT)((GREENVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
300                                   GREENVAL(b) * alpha[1] * xdiff * (256 - ydiff) +         \
301                                   GREENVAL(c) * alpha[2] * ydiff * (256 - xdiff) +         \
302                                   GREENVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
303 
304                 blue = (USHORT)((BLUEVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
305                                  BLUEVAL(b) * alpha[1] * xdiff * (256 - ydiff) +         \
306                                  BLUEVAL(c) * alpha[2] * ydiff * (256 - xdiff) +         \
307                                  BLUEVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
308 
309                 alpha[0] = (USHORT)((alpha[0] * (256 - xdiff) * (256 - ydiff) + \
310                                      alpha[1] * xdiff * (256 - ydiff) +         \
311                                      alpha[2] * ydiff * (256 - xdiff) +         \
312                                      alpha[3] * xdiff * ydiff) >> 16);
313 
314                 if (alpha[0])
315                 {
316                     red /= alpha[0];
317                     green /= alpha[0];
318                     blue /= alpha[0];
319                 }
320                 red = red > 15 ? 15 : red;
321                 green = green > 15 ? 15 : green;
322                 blue = blue > 15 ? 15 : blue;
323                 alpha[0] = alpha[0] > 15 ? 15 : alpha[0];
324 
325                 *put++ = ASSEMBLECOLOR(alpha[0], red, green, blue);
326             }
327             else
328             {
329                 *put++ = 0;
330             }
331         }
332     }
333     return GX_SUCCESS;
334 }
335 
336 /**************************************************************************/
337 /*                                                                        */
338 /*  FUNCTION                                               RELEASE        */
339 /*                                                                        */
340 /*    _gx_utility_4444argb_pixelmap_simple_rotate           PORTABLE C    */
341 /*                                                           6.1          */
342 /*  AUTHOR                                                                */
343 /*                                                                        */
344 /*    Kenneth Maxwell, Microsoft Corporation                              */
345 /*                                                                        */
346 /*  DESCRIPTION                                                           */
347 /*                                                                        */
348 /*    4444argb pixelmap rotation function that handles 90, 180 and 270    */
349 /*    degree case.                                                        */
350 /*                                                                        */
351 /*  INPUT                                                                 */
352 /*                                                                        */
353 /*    src                                   The pixelmap to be rotated    */
354 /*    angle                                 The angle to be rotated       */
355 /*    destination                           The rotated bitmap to be      */
356 /*                                            returned                    */
357 /*    rot_cx                                X coordinate of rotation      */
358 /*                                            center                      */
359 /*    rot_cy                                Y coordinate of rotation      */
360 /*                                            center                      */
361 /*                                                                        */
362 /*  OUTPUT                                                                */
363 /*                                                                        */
364 /*    status                                Completion status             */
365 /*                                                                        */
366 /*  CALLS                                                                 */
367 /*                                                                        */
368 /*    _gx_system_memory_allocator           Application defined memory    */
369 /*                                            allocation function         */
370 /*                                                                        */
371 /*  CALLED BY                                                             */
372 /*                                                                        */
373 /*    GUIX Internal Code                                                  */
374 /*                                                                        */
375 /*  RELEASE HISTORY                                                       */
376 /*                                                                        */
377 /*    DATE              NAME                      DESCRIPTION             */
378 /*                                                                        */
379 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
380 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
381 /*                                            resulting in version 6.1    */
382 /*                                                                        */
383 /**************************************************************************/
_gx_utility_4444argb_pixelmap_simple_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)384 UINT _gx_utility_4444argb_pixelmap_simple_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
385 {
386 USHORT *put;
387 USHORT *get;
388 INT     width;
389 INT     height;
390 INT     x;
391 INT     y;
392 
393     width = src -> gx_pixelmap_height;
394     height = src -> gx_pixelmap_width;
395 
396     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
397        overflow cannot occur. */
398     destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(USHORT);
399     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
400 
401     if (destination -> gx_pixelmap_data == GX_NULL)
402     {
403         return GX_SYSTEM_MEMORY_ERROR;
404     }
405 
406     if (angle == 90)
407     {
408         put = (USHORT *)destination -> gx_pixelmap_data;
409 
410         for (y = 0; y < height; y++)
411         {
412             for (x = 0; x < width; x++)
413             {
414                 get = (USHORT *)src -> gx_pixelmap_data;
415                 get += (width - 1 - x) * height;
416                 get += y;
417 
418                 *put++ = *get;
419             }
420         }
421 
422         if (rot_cx && rot_cy)
423         {
424             x = *rot_cx;
425             y = *rot_cy;
426 
427             /* Get new rotation point. */
428             *rot_cx = (width - 1 - y);
429             *rot_cy = x;
430         }
431     }
432     else if (angle == 180)
433     {
434         GX_SWAP_VALS(width, height);
435         put = (USHORT *)destination -> gx_pixelmap_data;
436         for (y = 0; y < height; y++)
437         {
438             for (x = 0; x < width; x++)
439             {
440                 get = (USHORT *)src -> gx_pixelmap_data;
441                 get += (height - 1 - y) * width;
442                 get += width - 1 - x;
443 
444                 *put++ = *get;
445             }
446         }
447 
448         if (rot_cx && rot_cy)
449         {
450             x = *rot_cx;
451             y = *rot_cy;
452 
453             /* Get new rotation point. */
454             *rot_cx = (width - 1 - x);
455             *rot_cy = (height - 1 - y);
456         }
457     }
458     else
459     {
460         /* angle  = 270. */
461         put = (USHORT *)destination -> gx_pixelmap_data;
462 
463         for (y = 0; y < height; y++)
464         {
465             for (x = 0; x < width; x++)
466             {
467                 get = (USHORT *)src -> gx_pixelmap_data;
468                 get += x * height;
469                 get += height - 1 - y;
470 
471                 *put++ = *get;
472             }
473         }
474 
475         if (rot_cx && rot_cy)
476         {
477             x = *rot_cx;
478             y = *rot_cy;
479 
480             /* Get new rotation point. */
481             *rot_cx = y;
482             *rot_cy = (height - 1 - x);
483         }
484     }
485 
486     destination -> gx_pixelmap_height = (GX_VALUE)height;
487     destination -> gx_pixelmap_width = (GX_VALUE)width;
488 
489     return GX_SUCCESS;
490 }
491 
492