microui  1.1.1
microui
LLUI_PAINTER_impl.c
1 
2 /*
3  * Copyright 2020-2022 MicroEJ Corp. All rights reserved.
4  * Use of this source code is governed by a BSD-style license that can be found with this software.
5  */
6 
7 /*
8  * @file
9  * @brief This file implements all MicroUI drawing native functions.
10  * @see LLUI_PAINTER_impl.h file comment
11  * @author MicroEJ Developer Team
12  * @version 1.1.1
13  * @date 27 April 2022
14  * @since MicroEJ UI Pack 13.0.0
15  */
16 
17 // --------------------------------------------------------------------------------
18 // Includes
19 // --------------------------------------------------------------------------------
20 
21 // implements LLUI_PAINTER_impl functions
22 #include "LLUI_PAINTER_impl.h"
23 
24 // calls ui_drawing functions
25 #include "ui_drawing.h"
26 
27 // use graphical engine functions to synchronize drawings
28 #include "LLUI_DISPLAY.h"
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 // --------------------------------------------------------------------------------
35 // Macros and Defines
36 // --------------------------------------------------------------------------------
37 
38 // macros to log a drawing
39 #define LOG_DRAW_START(fn) LLUI_DISPLAY_logDrawingStart(CONCAT_DEFINES(LOG_DRAW_, fn))
40 #define LOG_DRAW_END(fn) LLUI_DISPLAY_logDrawingEnd(CONCAT_DEFINES(LOG_DRAW_, fn))
41 
42 #define MICROUI_PAINTER_NATIVE_NAME(fn) (CONCAT_DEFINES(MICROUI_PAINTER_NATIVE_PREFIX, fn))
43 
44 /*
45  * LOG_DRAW_EVENT logs identifiers
46  */
47 #define LOG_DRAW_writePixel 1
48 #define LOG_DRAW_drawLine 2
49 #define LOG_DRAW_drawHorizontalLine 3
50 #define LOG_DRAW_drawVerticalLine 4
51 #define LOG_DRAW_drawRectangle 5
52 #define LOG_DRAW_fillRectangle 6
53 #define LOG_DRAW_drawRoundedRectangle 8
54 #define LOG_DRAW_fillRoundedRectangle 9
55 #define LOG_DRAW_drawCircleArc 10
56 #define LOG_DRAW_fillCircleArc 11
57 #define LOG_DRAW_drawEllipseArc 12
58 #define LOG_DRAW_fillEllipseArc 13
59 #define LOG_DRAW_drawEllipse 14
60 #define LOG_DRAW_fillEllipse 15
61 #define LOG_DRAW_drawCircle 16
62 #define LOG_DRAW_fillCircle 17
63 #define LOG_DRAW_drawARGB 18
64 #define LOG_DRAW_drawImage 19
65 
66 // --------------------------------------------------------------------------------
67 // Private functions
68 // --------------------------------------------------------------------------------
69 
70 /*
71  * Checks given bound to fit in bound limits: 0 and max (excluded). Updates size and
72  * origin in consequence
73  */
74 static inline void _check_bound(jint max, jint* bound, jint* size, jint* origin) {
75  if (*bound < 0) {
76  *size += *bound; // decrease size
77  *origin -= *bound; // increase origin
78  *bound = 0;
79  }
80 
81  if ((*bound + *size) > max) {
82  *size = max - *bound; // decrease size
83  }
84 }
85 
86 // --------------------------------------------------------------------------------
87 // LLUI_PAINTER_impl.h functions
88 // --------------------------------------------------------------------------------
89 
90 void MICROUI_PAINTER_NATIVE(writePixel, MICROUI_GraphicsContext* gc, jint x, jint y) {
91  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(writePixel))) {
92  DRAWING_Status status;
93  LOG_DRAW_START(writePixel);
94  if (LLUI_DISPLAY_isPixelInClip(gc, x, y)) {
95  LLUI_DISPLAY_configureClip(gc, false/* point is in clip */);
96  status = UI_DRAWING_writePixel(gc, x, y);
97  }
98  else {
99  // requestDrawing() has been called and accepted: notify the end of empty drawing
100  status = DRAWING_DONE;
101  }
102  LLUI_DISPLAY_setDrawingStatus(status);
103  LOG_DRAW_END(writePixel);
104  }
105  // else: pixel out of clip: nothing to do (requestDrawing() has not been called)
106 }
107 
108 void MICROUI_PAINTER_NATIVE(drawLine, MICROUI_GraphicsContext* gc, jint startX, jint startY, jint endX, jint endY) {
109  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawLine))) {
110  LOG_DRAW_START(drawLine);
111  // cannot reduce/clip line: may be endX < startX and / or endY < startY
112  LLUI_DISPLAY_setDrawingStatus(UI_DRAWING_drawLine(gc, startX, startY, endX, endY));
113  LOG_DRAW_END(drawLine);
114  }
115  // else: refused drawing
116 }
117 
118 void MICROUI_PAINTER_NATIVE(drawHorizontalLine, MICROUI_GraphicsContext* gc, jint x, jint y, jint length) {
119  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawHorizontalLine))) {
120  DRAWING_Status status;
121  LOG_DRAW_START(drawHorizontalLine);
122 
123  jint x1 = x;
124  jint x2 = x + length - 1;
125 
126  // tests on size and clip are performed after suspend to prevent to perform it several times
127  if ((length > 0) && LLUI_DISPLAY_clipHorizontalLine(gc, &x1, &x2, y)) {
128  LLUI_DISPLAY_configureClip(gc, false /* line has been clipped */);
129  status = UI_DRAWING_drawHorizontalLine(gc, x1, x2, y);
130  }
131  else {
132  // requestDrawing() has been called and accepted: notify the end of empty drawing
133  status = DRAWING_DONE;
134  }
135  LLUI_DISPLAY_setDrawingStatus(status);
136  LOG_DRAW_END(drawHorizontalLine);
137  }
138  // else: line out of clip: nothing to do (requestDrawing() has not been called)
139 }
140 
141 void MICROUI_PAINTER_NATIVE(drawVerticalLine, MICROUI_GraphicsContext* gc, jint x, jint y, jint length) {
142  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawVerticalLine))) {
143  DRAWING_Status status;
144  LOG_DRAW_START(drawVerticalLine);
145 
146  jint y1 = y;
147  jint y2 = y + length - 1;
148 
149  // tests on size and clip are performed after suspend to prevent to perform it several times
150  if ((length > 0) && LLUI_DISPLAY_clipVerticalLine(gc, &y1, &y2, x)) {
151  LLUI_DISPLAY_configureClip(gc, false /* line has been clipped */);
152  status = UI_DRAWING_drawVerticalLine(gc, x, y1, y2);
153  }
154  else {
155  // requestDrawing() has been called and accepted: notify the end of empty drawing
156  status = DRAWING_DONE;
157  }
158  LLUI_DISPLAY_setDrawingStatus(status);
159  LOG_DRAW_END(drawVerticalLine);
160  }
161  // else: line out of clip: nothing to do (requestDrawing() has not been called)
162 }
163 
164 void MICROUI_PAINTER_NATIVE(drawRectangle, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) {
165  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawRectangle))) {
166  DRAWING_Status status;
167  LOG_DRAW_START(drawRectangle);
168 
169  // tests on size and clip are performed after suspend to prevent to perform it several times
170  if ((width > 0) && (height > 0)) {
171  jint x1 = x;
172  jint x2 = x + width - 1;
173  jint y1 = y;
174  jint y2 = y + height - 1;
175 
176  // cannot reduce rectangle; can only check if it is fully in clip
177  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRectangleInClip(gc, x1, y1, x2, y2));
178  status = UI_DRAWING_drawRectangle(gc, x1, y1, x2, y2);
179  }
180  else {
181  // requestDrawing() has been called and accepted: notify the end of empty drawing
182  status = DRAWING_DONE;
183  }
184  LLUI_DISPLAY_setDrawingStatus(status);
185  LOG_DRAW_END(drawRectangle);
186  }
187  // else: refused drawing
188 }
189 
190 void MICROUI_PAINTER_NATIVE(fillRectangle, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) {
191  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillRectangle))) {
192  DRAWING_Status status;
193  LOG_DRAW_START(fillRectangle);
194 
195  jint x1 = x;
196  jint x2 = x + width - 1;
197  jint y1 = y;
198  jint y2 = y + height - 1;
199 
200  // tests on size and clip are performed after suspend to prevent to perform it several times
201  if ((width > 0) && (height) > 0 && LLUI_DISPLAY_clipRectangle(gc, &x1, &y1, &x2, &y2)) {
202  LLUI_DISPLAY_configureClip(gc, false /* rectangle has been clipped */);
203  status = UI_DRAWING_fillRectangle(gc, x1, y1, x2, y2);
204  }
205  else {
206  // requestDrawing() has been called and accepted: notify the end of empty drawing
207  status = DRAWING_DONE;
208  }
209  LLUI_DISPLAY_setDrawingStatus(status);
210  LOG_DRAW_END(fillRectangle);
211  }
212  // else: rectangle out of clip: nothing to do (requestDrawing() has not been called)
213 }
214 
215 void MICROUI_PAINTER_NATIVE(drawRoundedRectangle, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint cornerEllipseWidth, jint cornerEllipseHeight) {
216  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawRoundedRectangle))) {
217  DRAWING_Status status;
218  LOG_DRAW_START(drawRoundedRectangle);
219 
220  // tests on size and clip are performed after suspend to prevent to perform it several times
221  if ((width > 0) && (height > 0)) {
222  // cannot reduce rectangle; can only check if it is fully in clip
223  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
224  status = UI_DRAWING_drawRoundedRectangle(gc, x, y, width, height, cornerEllipseWidth, cornerEllipseHeight);
225  }
226  else {
227  // requestDrawing() has been called and accepted: notify the end of empty drawing
228  status = DRAWING_DONE;
229  }
230  LLUI_DISPLAY_setDrawingStatus(status);
231  LOG_DRAW_END(drawRoundedRectangle);
232  }
233  // else: refused drawing
234 }
235 
236 void MICROUI_PAINTER_NATIVE(fillRoundedRectangle, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jint cornerEllipseWidth, jint cornerEllipseHeight) {
237  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillRoundedRectangle))) {
238  DRAWING_Status status;
239  LOG_DRAW_START(fillRoundedRectangle);
240 
241  // tests on size and clip are performed after suspend to prevent to perform it several times
242  if ((width > 0) && (height > 0)) {
243  // cannot reduce rectangle; can only check if it is fully in clip
244  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
245  status = UI_DRAWING_fillRoundedRectangle(gc, x, y, width, height, cornerEllipseWidth, cornerEllipseHeight);
246  }
247  else {
248  // requestDrawing() has been called and accepted: notify the end of empty drawing
249  status = DRAWING_DONE;
250  }
251  LLUI_DISPLAY_setDrawingStatus(status);
252  LOG_DRAW_END(fillRoundedRectangle);
253  }
254  // else: refused drawing
255 }
256 
257 void MICROUI_PAINTER_NATIVE(drawCircleArc, MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle) {
258  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawCircleArc))) {
259  DRAWING_Status status;
260  LOG_DRAW_START(drawCircleArc);
261 
262  // tests on size and clip are performed after suspend to prevent to perform it several times
263  if ((diameter > 0) && ((int32_t)arcAngle != 0)) {
264  // cannot reduce rectangle; can only check if it is fully in clip
265  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter));
266  status = UI_DRAWING_drawCircleArc(gc, x, y, diameter, startAngle, arcAngle);
267  }
268  else {
269  // requestDrawing() has been called and accepted: notify the end of empty drawing
270  status = DRAWING_DONE;
271  }
272  LLUI_DISPLAY_setDrawingStatus(status);
273  LOG_DRAW_END(drawCircleArc);
274  }
275  // else: refused drawing
276 }
277 
278 void MICROUI_PAINTER_NATIVE(drawEllipseArc, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jfloat startAngle, jfloat arcAngle) {
279  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawEllipseArc))) {
280  DRAWING_Status status;
281  LOG_DRAW_START(drawEllipseArc);
282 
283  // tests on size and clip are performed after suspend to prevent to perform it several times
284  if ((width > 0) && (height > 0) && ((int32_t)arcAngle != 0)) {
285  // cannot reduce rectangle; can only check if it is fully in clip
286  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
287  status = UI_DRAWING_drawEllipseArc(gc, x, y, width, height, startAngle, arcAngle);
288  }
289  else {
290  // requestDrawing() has been called and accepted: notify the end of empty drawing
291  status = DRAWING_DONE;
292  }
293  LLUI_DISPLAY_setDrawingStatus(status);
294  LOG_DRAW_END(drawEllipseArc);
295  }
296  // else: refused drawing
297 }
298 
299 void MICROUI_PAINTER_NATIVE(fillCircleArc, MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter, jfloat startAngle, jfloat arcAngle) {
300  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillCircleArc))) {
301  DRAWING_Status status;
302  LOG_DRAW_START(fillCircleArc);
303 
304  // tests on size and clip are performed after suspend to prevent to perform it several times
305  if ((diameter > 0) && ((int32_t)arcAngle != 0)) {
306  // cannot reduce rectangle; can only check if it is fully in clip
307  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter));
308  status = UI_DRAWING_fillCircleArc(gc, x, y, diameter, startAngle, arcAngle);
309  }
310  else {
311  // requestDrawing() has been called and accepted: notify the end of empty drawing
312  status = DRAWING_DONE;
313  }
314  LLUI_DISPLAY_setDrawingStatus(status);
315  LOG_DRAW_END(fillCircleArc);
316  }
317  // else: refused drawing
318 }
319 
320 void MICROUI_PAINTER_NATIVE(fillEllipseArc, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height, jfloat startAngle, jfloat arcAngle) {
321  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillEllipseArc))) {
322  DRAWING_Status status;
323  LOG_DRAW_START(fillEllipseArc);
324 
325  // tests on size and clip are performed after suspend to prevent to perform it several times
326  if ((width > 0) && (height > 0) && ((int32_t)arcAngle != 0)) {
327  // cannot reduce rectangle; can only check if it is fully in clip
328  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
329  status = UI_DRAWING_fillEllipseArc(gc, x, y, width, height, startAngle, arcAngle);
330  }
331  else {
332  // requestDrawing() has been called and accepted: notify the end of empty drawing
333  status = DRAWING_DONE;
334  }
335  LLUI_DISPLAY_setDrawingStatus(status);
336  LOG_DRAW_END(fillEllipseArc);
337  }
338  // else: refused drawing
339 }
340 
341 void MICROUI_PAINTER_NATIVE(drawEllipse, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) {
342  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawEllipse))) {
343  DRAWING_Status status;
344  LOG_DRAW_START(drawEllipse);
345 
346  // tests on size and clip are performed after suspend to prevent to perform it several times
347  if ((width > 0) && (height > 0)) {
348  // cannot reduce rectangle; can only check if it is fully in clip
349  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
350  status = UI_DRAWING_drawEllipse(gc, x, y, width, height);
351  }
352  else {
353  // requestDrawing() has been called and accepted: notify the end of empty drawing
354  status = DRAWING_DONE;
355  }
356  LLUI_DISPLAY_setDrawingStatus(status);
357  LOG_DRAW_END(drawEllipse);
358  }
359  // else: refused drawing
360 }
361 
362 void MICROUI_PAINTER_NATIVE(fillEllipse, MICROUI_GraphicsContext* gc, jint x, jint y, jint width, jint height) {
363  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillEllipse))) {
364  DRAWING_Status status;
365  LOG_DRAW_START(fillEllipse);
366 
367  // tests on size and clip are performed after suspend to prevent to perform it several times
368  if ((width > 0) && (height > 0)) {
369  // cannot reduce rectangle; can only check if it is fully in clip
370  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, width, height));
371  status = UI_DRAWING_fillEllipse(gc, x, y, width, height);
372  }
373  else {
374  // requestDrawing() has been called and accepted: notify the end of empty drawing
375  status = DRAWING_DONE;
376  }
377  LLUI_DISPLAY_setDrawingStatus(status);
378  LOG_DRAW_END(fillEllipse);
379  }
380  // else: refused drawing
381 }
382 
383 void MICROUI_PAINTER_NATIVE(drawCircle, MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter) {
384  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawCircle))) {
385  DRAWING_Status status;
386  LOG_DRAW_START(drawCircle);
387 
388  // tests on size and clip are performed after suspend to prevent to perform it several times
389  if (diameter > 0) {
390  // cannot reduce rectangle; can only check if it is fully in clip
391  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter));
392  status = UI_DRAWING_drawCircle(gc, x, y, diameter);
393  }
394  else {
395  // requestDrawing() has been called and accepted: notify the end of empty drawing
396  status = DRAWING_DONE;
397  }
398  LLUI_DISPLAY_setDrawingStatus(status);
399  LOG_DRAW_END(drawCircle);
400  }
401  // else: refused drawing
402 }
403 
404 void MICROUI_PAINTER_NATIVE(fillCircle, MICROUI_GraphicsContext* gc, jint x, jint y, jint diameter) {
405  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(fillCircle))) {
406  DRAWING_Status status;
407  LOG_DRAW_START(fillCircle);
408 
409  // tests on size and clip are performed after suspend to prevent to perform it several times
410  if (diameter > 0) {
411  // cannot reduce rectangle; can only check if it is fully in clip
412  LLUI_DISPLAY_configureClip(gc, !LLUI_DISPLAY_isRegionInClip(gc, x, y, diameter, diameter));
413  status = UI_DRAWING_fillCircle(gc, x, y, diameter);
414  }
415  else {
416  // requestDrawing() has been called and accepted: notify the end of empty drawing
417  status = DRAWING_DONE;
418  }
419  LLUI_DISPLAY_setDrawingStatus(status);
420  LOG_DRAW_END(fillCircle);
421  }
422  // else: refused drawing
423 }
424 
425 void MICROUI_PAINTER_NATIVE(drawImage, MICROUI_GraphicsContext* gc, MICROUI_Image* img, jint regionX, jint regionY, jint width, jint height, jint x, jint y, jint alpha) {
426  if (LLUI_DISPLAY_requestDrawing(gc, (SNI_callback)&MICROUI_PAINTER_NATIVE_NAME(drawImage))) {
427  DRAWING_Status status = DRAWING_DONE;
428  LOG_DRAW_START(drawImage);
429 
430  // tests on parameters and clip are performed after suspend to prevent to perform it several times
431  if (!LLUI_DISPLAY_isClosed(img) && (alpha > 0)) {
432  jint l_alpha = (alpha > 255) ? 255 : alpha;
433 
434  // compute inside image bounds
435  _check_bound(img->width, &regionX, &width, &x);
436  _check_bound(img->height, &regionY, &height, &y);
437 
438  // compute inside graphics context bounds
439  _check_bound(gc->image.width, &x, &width, &regionX);
440  _check_bound(gc->image.height, &y, &height, &regionY);
441 
442  if ((width > 0) && (height > 0) && LLUI_DISPLAY_clipRegion(gc, &regionX, &regionY, &width, &height, &x, &y)) {
443  LLUI_DISPLAY_configureClip(gc, false /* region has been clipped */);
444  status = UI_DRAWING_drawImage(gc, img, regionX, regionY, width, height, x, y, l_alpha);
445  }
446  // else: nothing to do
447  }
448  // else: nothing to do
449 
450  // requestDrawing() has been called and accepted: notify the end of empty drawing
451  LLUI_DISPLAY_setDrawingStatus(status);
452  LOG_DRAW_END(drawImage);
453  }
454  // else: refused drawing
455 }
456 
457 // --------------------------------------------------------------------------------
458 // EOF
459 // --------------------------------------------------------------------------------
460 
461 #ifdef __cplusplus
462 }
463 #endif