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