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 /**   Canvas Management (Canvas)                                          */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_utility.h"
29 #include "gx_display.h"
30 #include "gx_canvas.h"
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _gx_canvas_rotated_pixelmap_bound_calculate         PORTABLE C      */
37 /*                                                           6.1          */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Kenneth Maxwell, Microsoft Corporation                              */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function calcuates the bounding rectangle of a rotated         */
45 /*    pixelmap.                                                           */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    rect                                  Rectangle of source pixelmao. */
50 /*    angle                                 Angle of rotation in degrees. */
51 /*    rot_cx                                x-coord of rotating center    */
52 /*    rot_cy                                y-coord of rotating center    */
53 /*                                                                        */
54 /*  OUTPUT                                                                */
55 /*                                                                        */
56 /*    status                                Completion status             */
57 /*                                                                        */
58 /*  CALLS                                                                 */
59 /*                                                                        */
60 /*    None                                                                */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    GUIX Internal Code                                                  */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
71 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*                                                                        */
74 /**************************************************************************/
_gx_canvas_rotated_pixelmap_bound_calculate(GX_RECTANGLE * rect,INT angle,INT rot_cx,INT rot_cy)75 static UINT  _gx_canvas_rotated_pixelmap_bound_calculate(GX_RECTANGLE *rect, INT angle, INT rot_cx, INT rot_cy)
76 {
77 INT mx[4] = {-1, 1, 1, -1};
78 INT my[4] = {1, 1, -1, -1};
79 INT idxminx;
80 INT idxmaxx;
81 INT idxmaxy;
82 INT srcxres;
83 INT srcyres;
84 INT cosv;
85 INT sinv;
86 INT xres;
87 INT yres;
88 INT width;
89 INT height;
90 INT x;
91 INT y;
92 
93     angle %= 360;
94 
95     if (angle < 0)
96     {
97         angle += 360;
98     }
99 
100     /* Calculate rectangle width and height. */
101     width = (GX_VALUE)(rect -> gx_rectangle_right - rect -> gx_rectangle_left + 1);
102     height = (GX_VALUE)(rect -> gx_rectangle_bottom - rect -> gx_rectangle_top + 1);
103 
104     if (angle == 0)
105     {
106         return GX_SUCCESS;
107     }
108     if (angle == 90)
109     {
110         GX_SWAP_VALS(width, height);
111 
112         rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cy));
113         rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - rot_cx);
114     }
115     else if (angle == 180)
116     {
117         rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cx));
118         rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cy));
119     }
120     else if (angle == 270)
121     {
122         GX_SWAP_VALS(width, height);
123         rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - rot_cy);
124         rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cx));
125     }
126     else
127     {
128         idxminx = (angle / 90) & 0x3;
129         idxmaxx = (idxminx + 2) & 0x3;
130         idxmaxy = (idxminx + 1) & 0x3;
131 
132         /* Calculate the source x and y center. */
133         srcxres = width >> 1;
134         srcyres = height >> 1;
135 
136         cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
137         sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
138 
139         xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
140         yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
141 
142         xres = GX_FIXED_VAL_TO_INT(xres);
143         yres = GX_FIXED_VAL_TO_INT(yres);
144 
145         /* Calculate destination width and height. */
146         width = (xres << 1);
147         height = (yres << 1);
148 
149         /* Calculate the new rotation axis. */
150         x = GX_FIXED_VAL_TO_INT((rot_cx - srcxres) * cosv - (rot_cy - srcyres) * sinv);
151         y = GX_FIXED_VAL_TO_INT((rot_cy - srcyres) * cosv + (rot_cx - srcxres) * sinv);
152 
153         x += xres;
154         y += yres;
155 
156         rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - x);
157         rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - y);
158     }
159     rect -> gx_rectangle_right = (GX_VALUE)(rect -> gx_rectangle_left + width - 1);
160     rect -> gx_rectangle_bottom = (GX_VALUE)(rect -> gx_rectangle_top + height - 1);
161 
162     return(GX_SUCCESS);
163 }
164 
165 /**************************************************************************/
166 /*                                                                        */
167 /*  FUNCTION                                               RELEASE        */
168 /*                                                                        */
169 /*    _gx_canvas_pixelmap_rotate                          PORTABLE C      */
170 /*                                                           6.1.7        */
171 /*  AUTHOR                                                                */
172 /*                                                                        */
173 /*    Kenneth Maxwell, Microsoft Corporation                              */
174 /*                                                                        */
175 /*  DESCRIPTION                                                           */
176 /*                                                                        */
177 /*    This function prepares to draw the specified pixelmap at the        */
178 /*    requested position.                                                 */
179 /*                                                                        */
180 /*  INPUT                                                                 */
181 /*                                                                        */
182 /*    x_position                            Top-left x-coord to place     */
183 /*                                            pixelmap                    */
184 /*    y_position                            Top-left y-coord to place     */
185 /*                                            pixelmap                    */
186 /*    pixelmap                              Pointer to actual pixelmap    */
187 /*                                            to draw                     */
188 /*    angle                                 The angle to rotate           */
189 /*    rot_cx                                x-coord of rotating center, if*/
190 /*                                            -1 is set, default it to    */
191 /*                                            image center.               */
192 /*    rot_cy                                y-coord of rotationg center.  */
193 /*                                            -1 is set, default it to    */
194 /*                                            image center.               */
195 /*                                                                        */
196 /*  OUTPUT                                                                */
197 /*                                                                        */
198 /*    status                                Completion status             */
199 /*                                                                        */
200 /*  CALLS                                                                 */
201 /*                                                                        */
202 /*    _gx_utility_rectangle_define                                        */
203 /*    _gx_utility_rectangle_overlap_detect                                */
204 /*    _gx_canvas_rotated_pixelmap_bound_calculate                         */
205 /*    [gx_display_driver_pixelmap_rotate]                                 */
206 /*                                                                        */
207 /*  CALLED BY                                                             */
208 /*                                                                        */
209 /*    Application code                                                    */
210 /*                                                                        */
211 /*  RELEASE HISTORY                                                       */
212 /*                                                                        */
213 /*    DATE              NAME                      DESCRIPTION             */
214 /*                                                                        */
215 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
216 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
217 /*                                            resulting in version 6.1    */
218 /*  06-02-2021     Kenneth Maxwell          Modified comment(s),          */
219 /*                                            removed duplicate variable  */
220 /*                                            assignment,                 */
221 /*                                            resulting in version 6.1.7  */
222 /*                                                                        */
223 /**************************************************************************/
_gx_canvas_pixelmap_rotate(GX_VALUE x_position,GX_VALUE y_position,GX_PIXELMAP * pixelmap,INT angle,INT rot_cx,INT rot_cy)224 UINT  _gx_canvas_pixelmap_rotate(GX_VALUE x_position, GX_VALUE y_position, GX_PIXELMAP *pixelmap,
225                                  INT angle, INT rot_cx, INT rot_cy)
226 {
227 GX_DRAW_CONTEXT *context;
228 GX_DISPLAY      *display;
229 GX_RECTANGLE     clip_rect;
230 GX_RECTANGLE     bound;
231 GX_VIEW         *view;
232 VOID             (*pmp_function)(GX_DRAW_CONTEXT *, INT, INT, GX_PIXELMAP *, INT, INT, INT);
233 INT              cx;
234 INT              cy;
235 
236     /* pick up the current drawing context */
237     context = _gx_system_current_draw_context;
238 
239     /* pick up current display driver */
240     display = context -> gx_draw_context_display;
241 
242     /* calculate rectangle that bounds the pixelmap */
243     _gx_utility_rectangle_define(&bound, x_position, y_position,
244                                  (GX_VALUE)(x_position + pixelmap -> gx_pixelmap_width - 1),
245                                  (GX_VALUE)(y_position + pixelmap -> gx_pixelmap_height - 1));
246 
247     if (rot_cx == -1)
248     {
249         cx = pixelmap -> gx_pixelmap_width >> 1;
250     }
251     else
252     {
253         cx = rot_cx;
254     }
255 
256     if (rot_cy == -1)
257     {
258         cy = pixelmap -> gx_pixelmap_height >> 1;
259     }
260     else
261     {
262         cy = rot_cy;
263     }
264 
265     /* calculate rectangle that bounds the rotated pixelmap */
266     _gx_canvas_rotated_pixelmap_bound_calculate(&bound, angle, cx, cy);
267 
268     /* clip the line bounding box to the dirty rectangle */
269     if (!_gx_utility_rectangle_overlap_detect(&bound, &context -> gx_draw_context_dirty, &bound))
270     {
271         /* nothing to draw, return */
272         return GX_SUCCESS;
273     }
274 
275     /* Range angle to [0, 360). */
276     angle = angle % 360;
277 
278     if (angle < 0)
279     {
280         angle += 360;
281     }
282 
283     if (angle == 0)
284     {
285         if (!display->gx_display_driver_pixelmap_draw)
286         {
287             return GX_FAILURE;
288         }
289     }
290 
291     if (pixelmap->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED)
292     {
293         return GX_NOT_SUPPORTED;
294     }
295 
296     /* pickup pointer to correct pixelmap drawing function */
297     pmp_function = display -> gx_display_driver_pixelmap_rotate;
298 
299     if (!pmp_function)
300     {
301         /* display driver does not support requested action */
302         return GX_FAILURE;
303     }
304 
305     /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
306        into. For each view that overlaps the bounding rectangle, do some drawing.
307      */
308     view = context -> gx_draw_context_view_head;
309 
310     while (view)
311     {
312         if (!_gx_utility_rectangle_overlap_detect(&view -> gx_view_rectangle, &bound, &clip_rect))
313         {
314             view = view -> gx_view_next;
315             continue;
316         }
317 
318         /* we have a view into which we can draw the pixelmap, do it */
319 
320         /* first, set the context clip rectangle */
321         context -> gx_draw_context_clip = &clip_rect;
322 
323         if (angle == 0)
324         {
325             display->gx_display_driver_pixelmap_draw(context, x_position, y_position, pixelmap);
326         }
327         else
328         {
329             /* now pass the context and drawing params to driver level function */
330             pmp_function(context, x_position, y_position, pixelmap, angle, cx, cy);
331         }
332 
333         /* go to the next view */
334         view = view -> gx_view_next;
335     }
336 
337     /* Return successful completion.  */
338     return(GX_SUCCESS);
339 }
340 
341