GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_canvas_pixelmap_rotate.c Lines: 80 80 100.0 %
Date: 2024-12-05 08:52:37 Branches: 32 32 100.0 %

Line Branch Exec Source
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
/**************************************************************************/
75
17863
static UINT  _gx_canvas_rotated_pixelmap_bound_calculate(GX_RECTANGLE *rect, INT angle, INT rot_cx, INT rot_cy)
76
{
77
17863
INT mx[4] = {-1, 1, 1, -1};
78
17863
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
17863
    angle %= 360;
94
95
17863
    if (angle < 0)
96
    {
97
359
        angle += 360;
98
    }
99
100
    /* Calculate rectangle width and height. */
101
17863
    width = (GX_VALUE)(rect -> gx_rectangle_right - rect -> gx_rectangle_left + 1);
102
17863
    height = (GX_VALUE)(rect -> gx_rectangle_bottom - rect -> gx_rectangle_top + 1);
103
104
17863
    if (angle == 0)
105
    {
106
35
        return GX_SUCCESS;
107
    }
108
17828
    if (angle == 90)
109
    {
110
62
        GX_SWAP_VALS(width, height);
111
112
62
        rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cy));
113
62
        rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - rot_cx);
114
    }
115
17766
    else if (angle == 180)
116
    {
117
57
        rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cx));
118
57
        rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cy));
119
    }
120
17709
    else if (angle == 270)
121
    {
122
57
        GX_SWAP_VALS(width, height);
123
57
        rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - rot_cy);
124
57
        rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cx));
125
    }
126
    else
127
    {
128
17652
        idxminx = (angle / 90) & 0x3;
129
17652
        idxmaxx = (idxminx + 2) & 0x3;
130
17652
        idxmaxy = (idxminx + 1) & 0x3;
131
132
        /* Calculate the source x and y center. */
133
17652
        srcxres = width >> 1;
134
17652
        srcyres = height >> 1;
135
136
17652
        cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
137
17652
        sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
138
139
17652
        xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
140
17652
        yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
141
142
17652
        xres = GX_FIXED_VAL_TO_INT(xres);
143
17652
        yres = GX_FIXED_VAL_TO_INT(yres);
144
145
        /* Calculate destination width and height. */
146
17652
        width = (xres << 1);
147
17652
        height = (yres << 1);
148
149
        /* Calculate the new rotation axis. */
150
17652
        x = GX_FIXED_VAL_TO_INT((rot_cx - srcxres) * cosv - (rot_cy - srcyres) * sinv);
151
17652
        y = GX_FIXED_VAL_TO_INT((rot_cy - srcyres) * cosv + (rot_cx - srcxres) * sinv);
152
153
17652
        x += xres;
154
17652
        y += yres;
155
156
17652
        rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - x);
157
17652
        rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - y);
158
    }
159
17828
    rect -> gx_rectangle_right = (GX_VALUE)(rect -> gx_rectangle_left + width - 1);
160
17828
    rect -> gx_rectangle_bottom = (GX_VALUE)(rect -> gx_rectangle_top + height - 1);
161
162
17828
    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
/**************************************************************************/
224
17863
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
17863
    context = _gx_system_current_draw_context;
238
239
    /* pick up current display driver */
240
17863
    display = context -> gx_draw_context_display;
241
242
    /* calculate rectangle that bounds the pixelmap */
243
17863
    _gx_utility_rectangle_define(&bound, x_position, y_position,
244
17863
                                 (GX_VALUE)(x_position + pixelmap -> gx_pixelmap_width - 1),
245
17863
                                 (GX_VALUE)(y_position + pixelmap -> gx_pixelmap_height - 1));
246
247
17863
    if (rot_cx == -1)
248
    {
249
10661
        cx = pixelmap -> gx_pixelmap_width >> 1;
250
    }
251
    else
252
    {
253
7202
        cx = rot_cx;
254
    }
255
256
17863
    if (rot_cy == -1)
257
    {
258
10661
        cy = pixelmap -> gx_pixelmap_height >> 1;
259
    }
260
    else
261
    {
262
7202
        cy = rot_cy;
263
    }
264
265
    /* calculate rectangle that bounds the rotated pixelmap */
266
17863
    _gx_canvas_rotated_pixelmap_bound_calculate(&bound, angle, cx, cy);
267
268
    /* clip the line bounding box to the dirty rectangle */
269
17863
    if (!_gx_utility_rectangle_overlap_detect(&bound, &context -> gx_draw_context_dirty, &bound))
270
    {
271
        /* nothing to draw, return */
272
1
        return GX_SUCCESS;
273
    }
274
275
    /* Range angle to [0, 360). */
276
17862
    angle = angle % 360;
277
278
17862
    if (angle < 0)
279
    {
280
359
        angle += 360;
281
    }
282
283
17862
    if (angle == 0)
284
    {
285
34
        if (!display->gx_display_driver_pixelmap_draw)
286
        {
287
1
            return GX_FAILURE;
288
        }
289
    }
290
291
17861
    if (pixelmap->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED)
292
    {
293
1
        return GX_NOT_SUPPORTED;
294
    }
295
296
    /* pickup pointer to correct pixelmap drawing function */
297
17860
    pmp_function = display -> gx_display_driver_pixelmap_rotate;
298
299
17860
    if (!pmp_function)
300
    {
301
        /* display driver does not support requested action */
302
1
        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
17859
    view = context -> gx_draw_context_view_head;
309
310
35719
    while (view)
311
    {
312
17860
        if (!_gx_utility_rectangle_overlap_detect(&view -> gx_view_rectangle, &bound, &clip_rect))
313
        {
314
2
            view = view -> gx_view_next;
315
2
            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
17858
        context -> gx_draw_context_clip = &clip_rect;
322
323
17858
        if (angle == 0)
324
        {
325
33
            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
17825
            pmp_function(context, x_position, y_position, pixelmap, angle, cx, cy);
331
        }
332
333
        /* go to the next view */
334
17858
        view = view -> gx_view_next;
335
    }
336
337
    /* Return successful completion.  */
338
17859
    return(GX_SUCCESS);
339
}
340