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 GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_display.h"
28 #include "gx_context.h"
29 #include "gx_utility.h"
30 #include "gx_system.h"
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _gx_utility_8bpp_pixelmap_rotate                    PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Kenneth Maxwell, Microsoft Corporation                              */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function rotates an 8bpp format uncompressed pixelmap with or  */
45 /*    without alpha channel.                                              */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    src                                   The pixelmap to be rotated    */
50 /*    angle                                 The angle to be rotated       */
51 /*    destination                           The rotated bitmap to be      */
52 /*                                            returned                    */
53 /*    rot_cx                                X coordinate of rotation      */
54 /*                                            center                      */
55 /*    rot_cy                                Y coordinate of rotation      */
56 /*                                            center                      */
57 /*                                                                        */
58 /*  OUTPUT                                                                */
59 /*                                                                        */
60 /*    Completion Status                                                   */
61 /*                                                                        */
62 /*  CALLS                                                                 */
63 /*                                                                        */
64 /*    _gx_system_memory_allocator           Memory Allocation routine     */
65 /*    _gx_utility_math_cos                  Compute the cosine value      */
66 /*    _gx_utility_math_sin                  Compute the sine value        */
67 /*                                                                        */
68 /*  CALLED BY                                                             */
69 /*                                                                        */
70 /*    GUIX Internal Code                                                  */
71 /*                                                                        */
72 /*  RELEASE HISTORY                                                       */
73 /*                                                                        */
74 /*    DATE              NAME                      DESCRIPTION             */
75 /*                                                                        */
76 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
77 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
78 /*                                            resulting in version 6.1    */
79 /*                                                                        */
80 /**************************************************************************/
_gx_utility_8bpp_pixelmap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)81 UINT _gx_utility_8bpp_pixelmap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
82 {
83 GX_UBYTE *putrow;
84 GX_UBYTE *put;
85 GX_UBYTE *get;
86 INT       srcxres;
87 INT       srcyres;
88 INT       cosv;
89 INT       sinv;
90 INT       idxminx, idxmaxx, idxmaxy;
91 INT       mx[] = {-1, 1, 1, -1};
92 INT       my[] = {1, 1, -1, -1};
93 INT       xres;
94 INT       yres;
95 INT       width, height;
96 INT       x, y;
97 INT       xx, yy;
98 
99     /* Set transparent color.  */
100     if (src -> gx_pixelmap_flags & GX_PIXELMAP_TRANSPARENT)
101     {
102         destination -> gx_pixelmap_transparent_color = src -> gx_pixelmap_transparent_color;
103     }
104     else
105     {
106         destination -> gx_pixelmap_transparent_color = 0xff;
107     }
108 
109     idxminx = (angle / 90) & 0x3;
110     idxmaxx = (idxminx + 2) & 0x3;
111     idxmaxy = (idxminx + 1) & 0x3;
112 
113     /* Calculate the source x and y center. */
114     srcxres = src -> gx_pixelmap_width >> 1;
115     srcyres = src -> gx_pixelmap_height >> 1;
116 
117     cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
118     sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
119 
120     xres = GX_FIXED_VAL_TO_INT((mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv));
121     yres = GX_FIXED_VAL_TO_INT((my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv));
122 
123     /* Calculate destination width and height. */
124     width = (xres << 1);
125     height = (yres << 1);
126 
127     if (rot_cx && rot_cy)
128     {
129         /* Calculate the new rotation axis. */
130         x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
131         y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
132 
133         x = GX_FIXED_VAL_TO_INT(x) + xres;
134         y = GX_FIXED_VAL_TO_INT(y) + yres;
135 
136         srcxres = *rot_cx;
137         srcyres = *rot_cy;
138 
139         *rot_cx = x;
140         *rot_cy = y;
141 
142         xres = *rot_cx;
143         yres = *rot_cy;
144     }
145 
146     /* Set width and height of destination pixelmap.  */
147     destination -> gx_pixelmap_width = (GX_VALUE)width;
148     destination -> gx_pixelmap_height = (GX_VALUE)height;
149     destination -> gx_pixelmap_flags |= GX_PIXELMAP_TRANSPARENT;
150 
151     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
152        overflow cannot occur. */
153     destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(GX_UBYTE);
154 
155     /* Allocate memory for destination pixelmap to load pixel information.  */
156     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
157 
158     if (destination -> gx_pixelmap_data == GX_NULL)
159     {
160         return GX_SYSTEM_MEMORY_ERROR;
161     }
162 
163     putrow = (GX_UBYTE *)destination -> gx_pixelmap_data;
164 
165     /* For every pixel in destination bitmap, find its position in source bitmap,
166        and set the pixel with the value in source bitmap.  */
167     for (y = 0; y < height; y++)
168     {
169         put = putrow;
170 
171         for (x = 0; x < width; x++)
172         {
173             xx = (x - xres) * cosv + (y - yres) * sinv;
174             yy = (y - yres) * cosv - (x - xres) * sinv;
175 
176             xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
177             yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
178 
179             if ((xx >= 0) && (xx < src -> gx_pixelmap_width) &&
180                 (yy >= 0) && (yy < src -> gx_pixelmap_height))
181             {
182                 get = (GX_UBYTE *)src -> gx_pixelmap_data;
183                 get += yy * src -> gx_pixelmap_width;
184                 get += xx;
185 
186                 *put++ = *get;
187             }
188             else
189             {
190                 *put++ = (GX_UBYTE)destination -> gx_pixelmap_transparent_color;
191             }
192         }
193         putrow += destination -> gx_pixelmap_width;
194     }
195 
196     return GX_SUCCESS;
197 }
198 
199 /**************************************************************************/
200 /*                                                                        */
201 /*  FUNCTION                                               RELEASE        */
202 /*                                                                        */
203 /*    _gx_utility_8bpp_pixelmap_simple_rotate             PORTABLE C      */
204 /*                                                           6.1          */
205 /*  AUTHOR                                                                */
206 /*                                                                        */
207 /*    Kenneth Maxwell, Microsoft Corporation                              */
208 /*                                                                        */
209 /*  DESCRIPTION                                                           */
210 /*                                                                        */
211 /*    This function rotates an 8bpp format uncompressed pixelmap with     */
212 /*    special rotation angle 90, 180 or 270 degree.                       */
213 /*                                                                        */
214 /*  INPUT                                                                 */
215 /*                                                                        */
216 /*    src                                   The pixelmap to be rotated    */
217 /*    angle                                 The angle to be rotated       */
218 /*    destination                           The rotated bitmap to be      */
219 /*                                            returned                    */
220 /*    rot_cx                                X coordinate of rotation      */
221 /*                                            center                      */
222 /*    rot_cy                                Y coordinate of rotation      */
223 /*                                            center                      */
224 /*                                                                        */
225 /*  OUTPUT                                                                */
226 /*                                                                        */
227 /*    Completion Status                                                   */
228 /*                                                                        */
229 /*  CALLS                                                                 */
230 /*                                                                        */
231 /*    _gx_system_memory_allocator           Memory Allocation routine     */
232 /*                                                                        */
233 /*  CALLED BY                                                             */
234 /*                                                                        */
235 /*    GUIX Internal Code                                                  */
236 /*                                                                        */
237 /*  RELEASE HISTORY                                                       */
238 /*                                                                        */
239 /*    DATE              NAME                      DESCRIPTION             */
240 /*                                                                        */
241 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
242 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
243 /*                                            resulting in version 6.1    */
244 /*                                                                        */
245 /**************************************************************************/
_gx_utility_8bpp_pixelmap_simple_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)246 UINT _gx_utility_8bpp_pixelmap_simple_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
247 {
248 GX_UBYTE *put;
249 GX_UBYTE *get;
250 INT       width, height;
251 INT       x, y;
252 
253     destination -> gx_pixelmap_transparent_color = src -> gx_pixelmap_transparent_color;
254 
255     width = src -> gx_pixelmap_height;
256     height = src -> gx_pixelmap_width;
257 
258     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
259        overflow cannot occur. */
260     destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(GX_UBYTE);
261     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
262 
263     if (destination -> gx_pixelmap_data == GX_NULL)
264     {
265         return GX_SYSTEM_MEMORY_ERROR;
266     }
267 
268     if (angle == 90)
269     {
270         put = (GX_UBYTE *)destination -> gx_pixelmap_data;
271 
272         for (y = 0; y < height; y++)
273         {
274             for (x = 0; x < width; x++)
275             {
276                 get = (GX_UBYTE *)src -> gx_pixelmap_data;
277                 get += (width - 1 - x) * height;
278                 get += y;
279 
280                 *put++ = *get;
281             }
282         }
283 
284         if (rot_cx && rot_cy)
285         {
286             x = *rot_cx;
287             y = *rot_cy;
288 
289             *rot_cx = (width - 1 - y);
290             *rot_cy = x;
291         }
292     }
293     else if (angle == 180)
294     {
295         GX_SWAP_VALS(width, height);
296 
297         put = (GX_UBYTE *)destination -> gx_pixelmap_data;
298 
299         for (y = 0; y < height; y++)
300         {
301             for (x = 0; x < width; x++)
302             {
303                 get = (GX_UBYTE *)src -> gx_pixelmap_data;
304                 get += (height - 1 - y) * width;
305                 get += width - 1 - x;
306 
307                 *put++ = *get;
308             }
309         }
310 
311         if (rot_cx && rot_cy)
312         {
313             x = *rot_cx;
314             y = *rot_cy;
315 
316             *rot_cx = (width - 1 - x);
317             *rot_cy = (height - 1 - y);
318         }
319     }
320     else
321     {
322         /* angle = 270. */
323         put = (GX_UBYTE *)destination -> gx_pixelmap_data;
324 
325         for (y = 0; y < height; y++)
326         {
327             for (x = 0; x < width; x++)
328             {
329                 get = (GX_UBYTE *)src -> gx_pixelmap_data;
330                 get += x * height;
331                 get += height - 1 - y;
332 
333                 *put++ = *get;
334             }
335         }
336 
337         if (rot_cx && rot_cy)
338         {
339             x = *rot_cx;
340             y = *rot_cy;
341 
342             *rot_cx = y;
343             *rot_cy = (height - 1 - x);
344         }
345     }
346 
347     destination -> gx_pixelmap_height = (GX_VALUE)height;
348     destination -> gx_pixelmap_width  = (GX_VALUE)width;
349 
350     return GX_SUCCESS;
351 }
352 
353 /**************************************************************************/
354 /*                                                                        */
355 /*  FUNCTION                                               RELEASE        */
356 /*                                                                        */
357 /*    _gx_utility_8bit_alphamap_rotate                    PORTABLE C      */
358 /*                                                           6.1          */
359 /*  AUTHOR                                                                */
360 /*                                                                        */
361 /*    Kenneth Maxwell, Microsoft Corporation                              */
362 /*                                                                        */
363 /*  DESCRIPTION                                                           */
364 /*                                                                        */
365 /*    This function rotates an 8bit alphamap.                             */
366 /*                                                                        */
367 /*  INPUT                                                                 */
368 /*                                                                        */
369 /*    src                                   The pixelmap to be rotated    */
370 /*    angle                                 The angle to be rotated       */
371 /*    destination                           The rotated bitmap to be      */
372 /*                                            returned                    */
373 /*    rot_cx                                X coordinate of rotation      */
374 /*                                            center                      */
375 /*    rot_cy                                Y coordinate of rotation      */
376 /*                                            center                      */
377 /*                                                                        */
378 /*  OUTPUT                                                                */
379 /*                                                                        */
380 /*    Completion Status                                                   */
381 /*                                                                        */
382 /*  CALLS                                                                 */
383 /*                                                                        */
384 /*    _gx_system_memory_allocator           Memory Allocation routine     */
385 /*    _gx_utility_math_cos                  Compute the cosine value      */
386 /*    _gx_utility_math_sin                  Compute the sine value        */
387 /*                                                                        */
388 /*  CALLED BY                                                             */
389 /*                                                                        */
390 /*    GUIX Internal Code                                                  */
391 /*                                                                        */
392 /*  RELEASE HISTORY                                                       */
393 /*                                                                        */
394 /*    DATE              NAME                      DESCRIPTION             */
395 /*                                                                        */
396 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
397 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
398 /*                                            resulting in version 6.1    */
399 /*                                                                        */
400 /**************************************************************************/
_gx_utility_8bit_alphamap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)401 UINT _gx_utility_8bit_alphamap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
402 {
403 GX_UBYTE          *put;
404 GX_CONST GX_UBYTE *get;
405 INT                srcxres;
406 INT                srcyres;
407 INT                cosv;
408 INT                sinv;
409 INT                alpha;
410 INT                idxminx;
411 INT                idxmaxx;
412 INT                idxmaxy;
413 INT               *mx;
414 INT               *my;
415 INT                xres;
416 INT                yres;
417 INT                width;
418 INT                height;
419 INT                x;
420 INT                y;
421 INT                xx;
422 INT                yy;
423 GX_UBYTE           a;
424 GX_UBYTE           b;
425 GX_UBYTE           c;
426 GX_UBYTE           d;
427 INT                xdiff;
428 INT                ydiff;
429 
430     mx = _gx_system_scratchpad;
431     my = mx + 4;
432 
433     mx[0] = mx[3] = -1;
434     mx[1] = mx[2] = 1;
435 
436     my[0] = my[1] = 1;
437     my[2] = my[3] = -1;
438 
439     idxminx = (angle / 90) & 0x3;
440     idxmaxx = (idxminx + 2) & 0x3;
441     idxmaxy = (idxminx + 1) & 0x3;
442 
443     /* Calculate the source x and y center. */
444     srcxres = src -> gx_pixelmap_width >> 1;
445     srcyres = src -> gx_pixelmap_height >> 1;
446 
447     cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
448     sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
449 
450     xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
451     yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
452 
453     xres = GX_FIXED_VAL_TO_INT(xres);
454     yres = GX_FIXED_VAL_TO_INT(yres);
455 
456     /* Calculate destination width and height. */
457     width = (xres << 1);
458     height = (yres << 1);
459 
460     /* Calculate the new rotation axis. */
461     if (rot_cx && rot_cy)
462     {
463         x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
464         y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
465 
466         srcxres = *rot_cx;
467         srcyres = *rot_cy;
468 
469         x = GX_FIXED_VAL_TO_INT(x) + xres;
470         y = GX_FIXED_VAL_TO_INT(y) + yres;
471 
472         *rot_cx = x;
473         *rot_cy = y;
474 
475         xres = *rot_cx;
476         yres = *rot_cy;
477     }
478 
479     destination -> gx_pixelmap_height = (GX_VALUE)height;
480     destination -> gx_pixelmap_width = (GX_VALUE)width;
481     destination -> gx_pixelmap_flags |= GX_PIXELMAP_TRANSPARENT;
482     destination -> gx_pixelmap_transparent_color = 0;
483     destination -> gx_pixelmap_format = GX_COLOR_FORMAT_8BIT_ALPHAMAP;
484 
485     /* Safe int math is not required here, calling function limits max width, height to 14 bits so
486        overflow cannot occur. */
487     destination -> gx_pixelmap_data_size = (UINT)(height * width);
488     destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
489 
490     if (destination -> gx_pixelmap_data == GX_NULL)
491     {
492         return GX_SYSTEM_MEMORY_ERROR;
493     }
494 
495     put = (GX_UBYTE *)destination -> gx_pixelmap_data;
496 
497     /* Loop through the source's pixels.  */
498     for (y = 0; y < height; y++)
499     {
500         for (x = 0; x < width; x++)
501         {
502             xx = (x - xres) * cosv + (y - yres) * sinv;
503             yy = (y - yres) * cosv - (x - xres) * sinv;
504 
505             xdiff = GX_FIXED_VAL_TO_INT(xx << 8) & 0xff;
506             ydiff = GX_FIXED_VAL_TO_INT(yy << 8) & 0xff;
507 
508             xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
509             yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
510 
511             if ((xx >= -1) && (xx < src -> gx_pixelmap_width) &&
512                 (yy >= -1) && (yy < src -> gx_pixelmap_height))
513             {
514                 if ((xx >= 0) && (xx < src -> gx_pixelmap_width - 1) && \
515                     (yy >= 0) && (yy < src -> gx_pixelmap_height - 1))
516                 {
517                     get = src -> gx_pixelmap_data;
518                     get += yy * src -> gx_pixelmap_width;
519                     get += xx;
520 
521                     a = *get;
522                     b = *(get + 1);
523                     c = *(get + src -> gx_pixelmap_width);
524                     d = *(get + src -> gx_pixelmap_width + 1);
525                 }
526                 else
527                 {
528                     get = src -> gx_pixelmap_data;
529 
530                     a = 0;
531                     b = a;
532                     c = a;
533                     d = a;
534 
535                     if (xx == -1)
536                     {
537                         /* handle left edge.  */
538                         if (yy >= 0)
539                         {
540                             b = *(get + yy * src -> gx_pixelmap_width);
541                         }
542 
543                         if (yy < src -> gx_pixelmap_height - 1)
544                         {
545                             d = *(get + (yy + 1) * src -> gx_pixelmap_width);
546                         }
547                     }
548                     else if (yy == -1)
549                     {
550                         /* handle top edge.  */
551                         c = *(get + xx);
552 
553                         if (xx < src -> gx_pixelmap_width - 1)
554                         {
555                             d = *(get + xx + 1);
556                         }
557                     }
558                     else if (xx == src -> gx_pixelmap_width - 1)
559                     {
560                         /* handle right edget. */
561                         a = *(get + yy * src -> gx_pixelmap_width + xx);
562 
563                         if (yy < src -> gx_pixelmap_height - 1)
564                         {
565                             c = *(get + (yy + 1) * src -> gx_pixelmap_width + xx);
566                         }
567                     }
568                     else
569                     {
570                         /* handle bottom edge. */
571                         a = *(get + yy * src -> gx_pixelmap_width + xx);
572                         b = *(get + yy * src -> gx_pixelmap_width + xx + 1);
573                     }
574                 }
575 
576                 alpha = (INT)((a * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
577                                b * (ULONG)xdiff * (256 - (ULONG)ydiff) +         \
578                                c * (ULONG)ydiff * (256 - (ULONG)xdiff) +         \
579                                d * (ULONG)xdiff * (ULONG)ydiff) >> 16);
580 
581                 *put++ = (GX_UBYTE)alpha;
582             }
583             else
584             {
585                 *put++ = 0;
586             }
587         }
588     }
589 
590     return GX_SUCCESS;
591 }
592 
593