rhino/demo/c/dr_libs/old/dr_2d.h
Go to the documentation of this file.
1 // Public Domain. See "unlicense" statement at the end of this file.
2 
3 // ABOUT
4 //
5 // dr_2d is a simple library for drawing simple 2D graphics.
6 //
7 //
8 //
9 // USAGE
10 //
11 // This is a single-file library. To use it, do something like the following in one .c file.
12 // #define DR_2D_IMPLEMENTATION
13 // #include "dr_2d.h"
14 //
15 // You can then #include dr_2d.h in other parts of the program as you would with any other header file.
16 //
17 //
18 //
19 // QUICK NOTES
20 //
21 // - Drawing must be done inside a dr2d_begin_draw() and dr2d_end_draw() pair. Rationale: 1) required for compatibility
22 // with GDI's BeginPaint() and EndPaint() APIs; 2) gives implementations opportunity to save and restore state, such as
23 // OpenGL state and whatnot.
24 // - This library is not thread safe.
25 //
26 //
27 //
28 // OPTIONS
29 //
30 // #define DR2D_NO_GDI
31 // Excludes the GDI back-end.
32 //
33 // #define DR2D_NO_CAIRO
34 // Excludes the Cairo back-end.
35 //
36 //
37 //
38 // TODO
39 // - Document resource management.
40 
41 #ifndef dr_2d_h
42 #define dr_2d_h
43 
44 #include <stdlib.h>
45 #include <stdbool.h>
46 
47 #if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)
48 #include <windows.h>
49 
50 // No Cairo on Win32 builds.
51 #ifndef DR2D_NO_CAIRO
52 #define DR2D_NO_CAIRO
53 #endif
54 #else
55 // No GDI on non-Win32 builds.
56 #ifndef DR2D_NO_GDI
57 #define DR2D_NO_GDI
58 #endif
59 #endif
60 
61 #ifndef DR2D_MAX_FONT_FAMILY_LENGTH
62 #define DR2D_MAX_FONT_FAMILY_LENGTH 128
63 #endif
64 
65 
66 #ifdef __cplusplus
67 extern "C" {
68 #endif
69 
70 
72 //
73 // CORE 2D API
74 //
76 
77 typedef unsigned char dr2d_byte;
78 
79 typedef struct dr2d_context dr2d_context;
80 typedef struct dr2d_surface dr2d_surface;
81 typedef struct dr2d_font dr2d_font;
82 typedef struct dr2d_image dr2d_image;
83 typedef struct dr2d_color dr2d_color;
87 
88 
90 struct dr2d_color
91 {
92  dr2d_byte r;
93  dr2d_byte g;
94  dr2d_byte b;
95  dr2d_byte a;
96 };
97 
98 struct dr2d_font_metrics
99 {
100  int ascent;
101  int descent;
102  int lineHeight;
103  int spaceWidth;
104 };
105 
106 struct dr2d_glyph_metrics
107 {
108  int width;
109  int height;
110  int originX;
111  int originY;
112  int advanceX;
113  int advanceY;
114 };
115 
116 typedef enum
117 {
129 
132 
134 
135 typedef enum
136 {
140 
142 
143 typedef enum
144 {
149 
150 
151 #define DR2D_IMAGE_DRAW_BACKGROUND (1 << 0)
152 #define DR2D_IMAGE_HINT_NO_ALPHA (1 << 1)
153 
154 #define DR2D_READ (1 << 0)
155 #define DR2D_WRITE (1 << 1)
156 
157 #define DR2D_FONT_NO_CLEARTYPE (1 << 0)
158 
159 typedef struct
160 {
162  float dstX;
163 
165  float dstY;
166 
168  float dstWidth;
169 
171  float dstHeight;
172 
173 
175  float srcX;
176 
178  float srcY;
179 
181  float srcWidth;
182 
184  float srcHeight;
185 
186 
188  dr2d_color foregroundTint;
189 
191  dr2d_color backgroundColor;
192 
193 
195  unsigned int options;
196 
198 
199 
200 typedef bool (* dr2d_on_create_context_proc) (dr2d_context* pContext, const void* pUserData);
201 typedef void (* dr2d_on_delete_context_proc) (dr2d_context* pContext);
202 typedef bool (* dr2d_on_create_surface_proc) (dr2d_surface* pSurface, float width, float height);
203 typedef void (* dr2d_on_delete_surface_proc) (dr2d_surface* pSurface);
204 typedef bool (* dr2d_on_create_font_proc) (dr2d_font* pFont);
205 typedef void (* dr2d_on_delete_font_proc) (dr2d_font* pFont);
206 typedef bool (* dr2d_on_create_image_proc) (dr2d_image* pImage, unsigned int stride, const void* pData);
207 typedef void (* dr2d_on_delete_image_proc) (dr2d_image* pImage);
208 typedef void (* dr2d_begin_draw_proc) (dr2d_surface* pSurface);
209 typedef void (* dr2d_end_draw_proc) (dr2d_surface* pSurface);
210 typedef void (* dr2d_clear_proc) (dr2d_surface* pSurface, dr2d_color color);
211 typedef void (* dr2d_draw_rect_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color);
212 typedef void (* dr2d_draw_rect_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth);
213 typedef void (* dr2d_draw_rect_with_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor);
214 typedef void (* dr2d_draw_round_rect_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width);
215 typedef void (* dr2d_draw_round_rect_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth);
216 typedef void (* dr2d_draw_round_rect_with_outline_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth, dr2d_color outlineColor);
217 typedef void (* dr2d_draw_text_proc) (dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor);
218 typedef void (* dr2d_draw_image_proc) (dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs);
219 typedef void (* dr2d_set_clip_proc) (dr2d_surface* pSurface, float left, float top, float right, float bottom);
220 typedef void (* dr2d_get_clip_proc) (dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut);
222 typedef void* (* dr2d_map_image_data_proc) (dr2d_image* pImage, unsigned int accessFlags);
223 typedef void (* dr2d_unmap_image_data_proc) (dr2d_image* pImage);
224 typedef bool (* dr2d_get_font_metrics_proc) (dr2d_font* pFont, dr2d_font_metrics* pMetricsOut);
225 typedef bool (* dr2d_get_glyph_metrics_proc) (dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut);
226 typedef bool (* dr2d_measure_string_proc) (dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut);
227 typedef bool (* dr2d_get_text_cursor_position_from_point_proc)(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut);
228 typedef bool (* dr2d_get_text_cursor_position_from_char_proc) (dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut);
229 
230 
232 {
241 
255 
259 
265 };
266 
267 struct dr2d_image
268 {
271 
273  unsigned int width;
274 
276  unsigned int height;
277 
280 
282  bool isMapped;
283 
286 };
287 
288 struct dr2d_font
289 {
292 
295 
297  unsigned int size;
298 
301 
304 
306  float rotation;
307 
310  unsigned int flags;
311 
314 };
315 
316 struct dr2d_surface
317 {
320 
322  float width;
323 
325  float height;
326 
329 };
330 
331 struct dr2d_context
332 {
335 
337  size_t imageExtraBytes;
338 
340  size_t fontExtraBytes;
341 
343  size_t surfaceExtraBytes;
344 
346  size_t contextExtraBytes;
347 
350 };
351 
352 
353 
355 dr2d_context* dr2d_create_context(dr2d_drawing_callbacks drawingCallbacks, size_t contextExtraBytes, size_t surfaceExtraBytes, size_t fontExtraBytes, size_t imageExtraBytes, const void* pUserData);
356 
358 void dr2d_delete_context(dr2d_context* pContext);
359 
362 
363 
365 dr2d_surface* dr2d_create_surface(dr2d_context* pContext, float width, float height);
366 
368 void dr2d_delete_surface(dr2d_surface* pSurface);
369 
371 float dr2d_get_surface_width(const dr2d_surface* pSurface);
372 
374 float dr2d_get_surface_height(const dr2d_surface* pSurface);
375 
378 
379 
380 
382 
384 void dr2d_begin_draw(dr2d_surface* pSurface);
385 
387 void dr2d_end_draw(dr2d_surface* pSurface);
388 
390 void dr2d_clear(dr2d_surface* pSurface, dr2d_color color);
391 
393 void dr2d_draw_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color);
394 
396 void dr2d_draw_rect_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth);
397 
399 void dr2d_draw_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor);
400 
402 void dr2d_draw_round_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius);
403 
405 void dr2d_draw_round_rect_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth);
406 
408 void dr2d_draw_round_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor);
409 
411 void dr2d_draw_text(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor);
412 
414 void dr2d_draw_image(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs);
415 
417 void dr2d_set_clip(dr2d_surface* pSurface, float left, float top, float right, float bottom);
418 
420 void dr2d_get_clip(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut);
421 
422 
424 dr2d_font* dr2d_create_font(dr2d_context* pContext, const char* family, unsigned int size, dr2d_font_weight weight, dr2d_font_slant slant, float rotation, unsigned int flags);
425 
427 void dr2d_delete_font(dr2d_font* pFont);
428 
430 void* dr2d_get_font_extra_data(dr2d_font* pFont);
431 
433 unsigned int dr2d_get_font_size(dr2d_font* pFont);
434 
436 bool dr2d_get_font_metrics(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut);
437 
439 bool dr2d_get_glyph_metrics(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut);
440 
442 bool dr2d_measure_string(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut);
443 
445 bool dr2d_get_text_cursor_position_from_point(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut);
446 
448 bool dr2d_get_text_cursor_position_from_char(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut);
449 
450 
459 dr2d_image* dr2d_create_image(dr2d_context* pContext, unsigned int width, unsigned int height, dr2d_image_format format, unsigned int stride, const void* pData);
460 
462 void dr2d_delete_image(dr2d_image* pImage);
463 
466 
468 void dr2d_get_image_size(dr2d_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut);
469 
480 void* dr2d_map_image_data(dr2d_image* pImage, unsigned int accessFlags);
481 
485 void dr2d_unmap_image_data(dr2d_image* pImage);
486 
489 
490 
492 //
493 // UTILITY API
494 //
496 
499 
502 
503 
504 
505 
507 //
508 // WINDOWS GDI 2D API
509 //
510 // When using GDI as the rendering back-end you will usually want to only call drawing functions in response to a WM_PAINT message.
511 //
513 #ifndef DR2D_NO_GDI
514 
518 dr2d_context* dr2d_create_context_gdi(HDC hDC);
519 
524 dr2d_surface* dr2d_create_surface_gdi_HWND(dr2d_context* pContext, HWND hWnd);
525 dr2d_surface* dr2d_create_surface_gdi_HDC(dr2d_context* pContext, HDC hDC);
526 
531 HDC dr2d_get_HDC(dr2d_surface* pSurface);
532 
537 HBITMAP dr2d_get_HBITMAP(dr2d_surface* pSurface);
538 
540 HFONT dr2d_get_HFONT(dr2d_font* pFont);
541 
542 #endif // GDI
543 
544 
545 
547 //
548 // CAIRO 2D API
549 //
551 #ifndef DR2D_NO_CAIRO
552 #include <cairo/cairo.h>
553 
556 
558 dr2d_surface* dr2d_create_surface_cairo(dr2d_context* pContext, cairo_t* cr);
559 
564 cairo_surface_t* dr2d_get_cairo_surface_t(dr2d_surface* pSurface);
565 
567 cairo_t* dr2d_get_cairo_t(dr2d_surface* pSurface);
568 
569 #endif // Cairo
570 
571 
572 #ifdef __cplusplus
573 }
574 #endif
575 
576 #endif //dr_2d_h
577 
578 
580 //
581 // IMPLEMENTATION
582 //
584 #ifdef DR_2D_IMPLEMENTATION
585 #include <assert.h>
586 #include <stdlib.h>
587 #include <string.h>
588 #include <errno.h>
589 #include <math.h>
590 
591 #ifndef DR2D_PRIVATE
592 #define DR2D_PRIVATE static
593 #endif
594 
595 static int dr2d_strcpy_s(char* dst, size_t dstSizeInBytes, const char* src)
596 {
597 #ifdef _WIN32
598  return strcpy_s(dst, dstSizeInBytes, src);
599 #else
600  if (dst == 0) {
601  return EINVAL;
602  }
603  if (dstSizeInBytes == 0) {
604  return ERANGE;
605  }
606  if (src == 0) {
607  dst[0] = '\0';
608  return EINVAL;
609  }
610 
611  size_t i;
612  for (i = 0; i < dstSizeInBytes && src[i] != '\0'; ++i) {
613  dst[i] = src[i];
614  }
615 
616  if (i < dstSizeInBytes) {
617  dst[i] = '\0';
618  return 0;
619  }
620 
621  dst[0] = '\0';
622  return ERANGE;
623 #endif
624 }
625 
626 
627 dr2d_context* dr2d_create_context(dr2d_drawing_callbacks drawingCallbacks, size_t contextExtraBytes, size_t surfaceExtraBytes, size_t fontExtraBytes, size_t imageExtraBytes, const void* pUserData)
628 {
629  dr2d_context* pContext = (dr2d_context*)malloc(sizeof(dr2d_context) + contextExtraBytes);
630  if (pContext != NULL)
631  {
632  pContext->drawingCallbacks = drawingCallbacks;
633  pContext->imageExtraBytes = imageExtraBytes;
634  pContext->fontExtraBytes = fontExtraBytes;
635  pContext->surfaceExtraBytes = surfaceExtraBytes;
636  pContext->contextExtraBytes = contextExtraBytes;
637  memset(pContext->pExtraData, 0, contextExtraBytes);
638 
639  // The create_context callback is optional. If it is set to NULL, we just finish up here and return successfully. Otherwise
640  // we want to call the create_context callback and check it's return value. If it's return value if false it means there
641  // was an error and we need to return null.
642  if (pContext->drawingCallbacks.on_create_context != NULL)
643  {
644  if (!pContext->drawingCallbacks.on_create_context(pContext, pUserData))
645  {
646  // An error was thrown from the callback.
647  free(pContext);
648  pContext = NULL;
649  }
650  }
651  }
652 
653  return pContext;
654 }
655 
656 void dr2d_delete_context(dr2d_context* pContext)
657 {
658  if (pContext != NULL) {
659  if (pContext->drawingCallbacks.on_delete_context != NULL) {
660  pContext->drawingCallbacks.on_delete_context(pContext);
661  }
662 
663  free(pContext);
664  }
665 }
666 
668 {
669  return pContext->pExtraData;
670 }
671 
672 
673 dr2d_surface* dr2d_create_surface(dr2d_context* pContext, float width, float height)
674 {
675  if (pContext != NULL)
676  {
677  dr2d_surface* pSurface = (dr2d_surface*)malloc(sizeof(dr2d_surface) + pContext->surfaceExtraBytes);
678  if (pSurface != NULL)
679  {
680  pSurface->pContext = pContext;
681  pSurface->width = width;
682  pSurface->height = height;
683  memset(pSurface->pExtraData, 0, pContext->surfaceExtraBytes);
684 
685  // The create_surface callback is optional. If it is set to NULL, we just finish up here and return successfully. Otherwise
686  // we want to call the create_surface callback and check it's return value. If it's return value if false it means there
687  // was an error and we need to return null.
688  if (pContext->drawingCallbacks.on_create_surface != NULL)
689  {
690  if (!pContext->drawingCallbacks.on_create_surface(pSurface, width, height))
691  {
692  free(pSurface);
693  pSurface = NULL;
694  }
695  }
696  }
697 
698  return pSurface;
699  }
700 
701  return NULL;
702 }
703 
704 void dr2d_delete_surface(dr2d_surface* pSurface)
705 {
706  if (pSurface != NULL)
707  {
708  assert(pSurface->pContext != NULL);
709 
710  if (pSurface->pContext->drawingCallbacks.on_delete_surface != NULL) {
711  pSurface->pContext->drawingCallbacks.on_delete_surface(pSurface);
712  }
713 
714  free(pSurface);
715  }
716 }
717 
718 float dr2d_get_surface_width(const dr2d_surface* pSurface)
719 {
720  if (pSurface != NULL) {
721  return pSurface->width;
722  }
723 
724  return 0;
725 }
726 
727 float dr2d_get_surface_height(const dr2d_surface* pSurface)
728 {
729  if (pSurface != NULL) {
730  return pSurface->height;
731  }
732 
733  return 0;
734 }
735 
737 {
738  if (pSurface != NULL) {
739  return pSurface->pExtraData;
740  }
741 
742  return NULL;
743 }
744 
745 
746 void dr2d_begin_draw(dr2d_surface* pSurface)
747 {
748  if (pSurface != NULL)
749  {
750  assert(pSurface->pContext != NULL);
751 
752  if (pSurface->pContext->drawingCallbacks.begin_draw != NULL) {
753  pSurface->pContext->drawingCallbacks.begin_draw(pSurface);
754  }
755  }
756 }
757 
758 void dr2d_end_draw(dr2d_surface* pSurface)
759 {
760  if (pSurface != NULL)
761  {
762  assert(pSurface->pContext != NULL);
763 
764  if (pSurface->pContext->drawingCallbacks.end_draw != NULL) {
765  pSurface->pContext->drawingCallbacks.end_draw(pSurface);
766  }
767  }
768 }
769 
770 void dr2d_clear(dr2d_surface * pSurface, dr2d_color color)
771 {
772  if (pSurface != NULL)
773  {
774  assert(pSurface->pContext != NULL);
775 
776  if (pSurface->pContext->drawingCallbacks.clear != NULL) {
777  pSurface->pContext->drawingCallbacks.clear(pSurface, color);
778  }
779  }
780 }
781 
782 void dr2d_draw_rect(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color)
783 {
784  if (pSurface != NULL)
785  {
786  assert(pSurface->pContext != NULL);
787 
788  if (pSurface->pContext->drawingCallbacks.draw_rect != NULL) {
789  pSurface->pContext->drawingCallbacks.draw_rect(pSurface, left, top, right, bottom, color);
790  }
791  }
792 }
793 
794 void dr2d_draw_rect_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth)
795 {
796  if (pSurface != NULL)
797  {
798  assert(pSurface->pContext != NULL);
799 
800  if (pSurface->pContext->drawingCallbacks.draw_rect_outline != NULL) {
801  pSurface->pContext->drawingCallbacks.draw_rect_outline(pSurface, left, top, right, bottom, color, outlineWidth);
802  }
803  }
804 }
805 
806 void dr2d_draw_rect_with_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor)
807 {
808  if (pSurface != NULL)
809  {
810  assert(pSurface->pContext != NULL);
811 
813  pSurface->pContext->drawingCallbacks.draw_rect_with_outline(pSurface, left, top, right, bottom, color, outlineWidth, outlineColor);
814  }
815  }
816 }
817 
818 void dr2d_draw_round_rect(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius)
819 {
820  if (pSurface != NULL)
821  {
822  assert(pSurface->pContext != NULL);
823 
824  if (pSurface->pContext->drawingCallbacks.draw_round_rect != NULL) {
825  pSurface->pContext->drawingCallbacks.draw_round_rect(pSurface, left, top, right, bottom, color, radius);
826  }
827  }
828 }
829 
830 void dr2d_draw_round_rect_outline(dr2d_surface * pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth)
831 {
832  if (pSurface != NULL)
833  {
834  assert(pSurface->pContext != NULL);
835 
837  pSurface->pContext->drawingCallbacks.draw_round_rect_outline(pSurface, left, top, right, bottom, color, radius, outlineWidth);
838  }
839  }
840 }
841 
842 void dr2d_draw_round_rect_with_outline(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor)
843 {
844  if (pSurface != NULL)
845  {
846  assert(pSurface->pContext != NULL);
847 
849  pSurface->pContext->drawingCallbacks.draw_round_rect_with_outline(pSurface, left, top, right, bottom, color, radius, outlineWidth, outlineColor);
850  }
851  }
852 }
853 
854 void dr2d_draw_text(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor)
855 {
856  if (pSurface != NULL)
857  {
858  assert(pSurface->pContext != NULL);
859 
860  if (pSurface->pContext->drawingCallbacks.draw_text != NULL) {
861  pSurface->pContext->drawingCallbacks.draw_text(pSurface, pFont, text, textSizeInBytes, posX, posY, color, backgroundColor);
862  }
863  }
864 }
865 
866 void dr2d_draw_image(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs)
867 {
868  if (pSurface == NULL || pImage == NULL || pArgs == NULL) {
869  return;
870  }
871 
872  assert(pSurface->pContext != NULL);
873 
874  if (pSurface->pContext->drawingCallbacks.draw_image) {
875  pSurface->pContext->drawingCallbacks.draw_image(pSurface, pImage, pArgs);
876  }
877 }
878 
879 void dr2d_set_clip(dr2d_surface* pSurface, float left, float top, float right, float bottom)
880 {
881  if (pSurface != NULL)
882  {
883  assert(pSurface->pContext != NULL);
884 
885  if (pSurface->pContext->drawingCallbacks.set_clip != NULL) {
886  pSurface->pContext->drawingCallbacks.set_clip(pSurface, left, top, right, bottom);
887  }
888  }
889 }
890 
891 void dr2d_get_clip(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut)
892 {
893  if (pSurface != NULL)
894  {
895  assert(pSurface->pContext != NULL);
896 
897  if (pSurface->pContext->drawingCallbacks.get_clip != NULL) {
898  pSurface->pContext->drawingCallbacks.get_clip(pSurface, pLeftOut, pTopOut, pRightOut, pBottomOut);
899  }
900  }
901 }
902 
903 dr2d_font* dr2d_create_font(dr2d_context* pContext, const char* family, unsigned int size, dr2d_font_weight weight, dr2d_font_slant slant, float rotation, unsigned int flags)
904 {
905  if (pContext == NULL) {
906  return NULL;
907  }
908 
909  dr2d_font* pFont = (dr2d_font*)malloc(sizeof(dr2d_font) + pContext->fontExtraBytes);
910  if (pFont == NULL) {
911  return NULL;
912  }
913 
914  pFont->pContext = pContext;
915  pFont->family[0] = '\0';
916  pFont->size = size;
917  pFont->weight = weight;
918  pFont->slant = slant;
919  pFont->rotation = rotation;
920  pFont->flags = flags;
921 
922  if (family != NULL) {
923  dr2d_strcpy_s(pFont->family, sizeof(pFont->family), family);
924  }
925 
926  if (pContext->drawingCallbacks.on_create_font != NULL) {
927  if (!pContext->drawingCallbacks.on_create_font(pFont)) {
928  free(pFont);
929  return NULL;
930  }
931  }
932 
933  return pFont;
934 }
935 
936 void dr2d_delete_font(dr2d_font* pFont)
937 {
938  if (pFont == NULL) {
939  return;
940  }
941 
942  assert(pFont->pContext != NULL);
943 
944  if (pFont->pContext->drawingCallbacks.on_delete_font != NULL) {
946  }
947 
948  free(pFont);
949 }
950 
952 {
953  if (pFont == NULL) {
954  return NULL;
955  }
956 
957  return pFont->pExtraData;
958 }
959 
960 unsigned int dr2d_get_font_size(dr2d_font* pFont)
961 {
962  if (pFont == NULL) {
963  return 0;
964  }
965 
966  return pFont->size;
967 }
968 
969 bool dr2d_get_font_metrics(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut)
970 {
971  if (pFont == NULL) {
972  return false;
973  }
974 
975  assert(pFont->pContext != NULL);
976 
978  return pFont->pContext->drawingCallbacks.get_font_metrics(pFont, pMetricsOut);
979  }
980 
981  return false;
982 }
983 
984 bool dr2d_get_glyph_metrics(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pMetricsOut)
985 {
986  if (pFont == NULL || pMetricsOut == NULL) {
987  return false;
988  }
989 
990  assert(pFont->pContext != NULL);
991 
993  return pFont->pContext->drawingCallbacks.get_glyph_metrics(pFont, utf32, pMetricsOut);
994  }
995 
996  return false;
997 }
998 
999 bool dr2d_measure_string(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut)
1000 {
1001  if (pFont == NULL) {
1002  return false;
1003  }
1004 
1005  assert(pFont->pContext != NULL);
1006 
1007  if (pFont->pContext->drawingCallbacks.measure_string != NULL) {
1008  return pFont->pContext->drawingCallbacks.measure_string(pFont, text, textSizeInBytes, pWidthOut, pHeightOut);
1009  }
1010 
1011  return false;
1012 }
1013 
1014 bool dr2d_get_text_cursor_position_from_point(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut)
1015 {
1016  if (pFont == NULL) {
1017  return false;
1018  }
1019 
1020  assert(pFont->pContext != NULL);
1021 
1023  return pFont->pContext->drawingCallbacks.get_text_cursor_position_from_point(pFont, text, textSizeInBytes, maxWidth, inputPosX, pTextCursorPosXOut, pCharacterIndexOut);
1024  }
1025 
1026  return false;
1027 }
1028 
1029 bool dr2d_get_text_cursor_position_from_char(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut)
1030 {
1031  if (pFont == NULL) {
1032  return false;
1033  }
1034 
1035  assert(pFont->pContext != NULL);
1036 
1038  return pFont->pContext->drawingCallbacks.get_text_cursor_position_from_char(pFont, text, characterIndex, pTextCursorPosXOut);
1039  }
1040 
1041  return false;
1042 }
1043 
1044 
1045 dr2d_image* dr2d_create_image(dr2d_context* pContext, unsigned int width, unsigned int height, dr2d_image_format format, unsigned int stride, const void* pData)
1046 {
1047  if (pContext == NULL || width == 0 || height == 0) {
1048  return NULL;
1049  }
1050 
1051  dr2d_image* pImage = (dr2d_image*)malloc(sizeof(dr2d_image) + pContext->imageExtraBytes);
1052  if (pImage == NULL) {
1053  return NULL;
1054  }
1055 
1056  pImage->pContext = pContext;
1057  pImage->width = width;
1058  pImage->height = height;
1059  pImage->format = format;
1060  pImage->isMapped = false;
1061 
1062  if (pContext->drawingCallbacks.on_create_image != NULL) {
1063  if (!pContext->drawingCallbacks.on_create_image(pImage, stride, pData)) {
1064  free(pImage);
1065  return NULL;
1066  }
1067  }
1068 
1069  return pImage;
1070 }
1071 
1072 void dr2d_delete_image(dr2d_image* pImage)
1073 {
1074  if (pImage == NULL) {
1075  return;
1076  }
1077 
1078  assert(pImage->pContext != NULL);
1079 
1080  if (pImage->pContext->drawingCallbacks.on_delete_image != NULL) {
1081  pImage->pContext->drawingCallbacks.on_delete_image(pImage);
1082  }
1083 
1084  free(pImage);
1085 }
1086 
1088 {
1089  if (pImage == NULL) {
1090  return NULL;
1091  }
1092 
1093  return pImage->pExtraData;
1094 }
1095 
1096 void dr2d_get_image_size(dr2d_image* pImage, unsigned int* pWidthOut, unsigned int* pHeightOut)
1097 {
1098  if (pImage == NULL) {
1099  return;
1100  }
1101 
1102  if (pWidthOut) {
1103  *pWidthOut = pImage->width;
1104  }
1105  if (pHeightOut) {
1106  *pHeightOut = pImage->height;
1107  }
1108 }
1109 
1110 void* dr2d_map_image_data(dr2d_image* pImage, unsigned int accessFlags)
1111 {
1112  if (pImage == NULL || pImage->pContext->drawingCallbacks.map_image_data == NULL || pImage->pContext->drawingCallbacks.unmap_image_data == NULL || pImage->isMapped) {
1113  return NULL;
1114  }
1115 
1116  void* pImageData = pImage->pContext->drawingCallbacks.map_image_data(pImage, accessFlags);
1117  if (pImageData != NULL) {
1118  pImage->isMapped = true;
1119  }
1120 
1121  return pImageData;
1122 }
1123 
1124 void dr2d_unmap_image_data(dr2d_image* pImage)
1125 {
1126  if (pImage == NULL || pImage->pContext->drawingCallbacks.unmap_image_data == NULL || !pImage->isMapped) {
1127  return;
1128  }
1129 
1130  pImage->pContext->drawingCallbacks.unmap_image_data(pImage);
1131  pImage->isMapped = false;
1132 }
1133 
1135 {
1136  if (pContext == NULL || pContext->drawingCallbacks.get_optimal_image_format == NULL) {
1137  return dr2d_image_format_rgba8;
1138  }
1139 
1140  return pContext->drawingCallbacks.get_optimal_image_format(pContext);
1141 }
1142 
1143 
1144 
1146 //
1147 // UTILITY API
1148 //
1150 
1152 {
1153  dr2d_color color;
1154  color.r = r;
1155  color.g = g;
1156  color.b = b;
1157  color.a = a;
1158 
1159  return color;
1160 }
1161 
1163 {
1164  dr2d_color color;
1165  color.r = r;
1166  color.g = g;
1167  color.b = b;
1168  color.a = 255;
1169 
1170  return color;
1171 }
1172 
1173 
1174 
1176 //
1177 // PRIVATE UTILITY API
1178 //
1180 
1181 // RGBA8 <-> BGRA8 swap with alpha pre-multiply.
1182 void dr2d__rgba8_bgra8_swap__premul(const void* pSrc, void* pDst, unsigned int width, unsigned int height, unsigned int srcStride, unsigned int dstStride)
1183 {
1184  assert(pSrc != NULL);
1185  assert(pDst != NULL);
1186 
1187  const unsigned int srcStride32 = srcStride/4;
1188  const unsigned int dstStride32 = dstStride/4;
1189 
1190  const unsigned int* pSrcRow = (const unsigned int*)pSrc;
1191  unsigned int* pDstRow = (unsigned int*)pDst;
1192 
1193  for (unsigned int iRow = 0; iRow < height; ++iRow)
1194  {
1195  for (unsigned int iCol = 0; iCol < width; ++iCol)
1196  {
1197  unsigned int srcTexel = pSrcRow[iCol];
1198  unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24;
1199  unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16;
1200  unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8;
1201  unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0;
1202 
1203  srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f));
1204  srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f));
1205  srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f));
1206 
1207  pDstRow[iCol] = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
1208  }
1209 
1210  pSrcRow += srcStride32;
1211  pDstRow += dstStride32;
1212  }
1213 }
1214 
1215 
1217 //
1218 // WINDOWS GDI 2D API
1219 //
1221 #ifndef DR2D_NO_GDI
1222 
1223 typedef struct
1224 {
1226  HDC hDC;
1227 
1230  wchar_t* wcharBuffer;
1231 
1233  unsigned int wcharBufferLength;
1234 
1236  int* pGlyphCache;
1237  size_t glyphCacheSize;
1238 
1240  bool ownsDC;
1241 
1242 } gdi_context_data;
1243 
1244 typedef struct
1245 {
1248  HWND hWnd;
1249 
1251  HDC hDC;
1252 
1254  HDC hIntermediateDC;
1255 
1257  PAINTSTRUCT ps;
1258 
1261  HBITMAP hBitmap;
1262 
1264  void* pBitmapData;
1265 
1266 
1268  HGDIOBJ hStockDCBrush;
1269 
1271  HGDIOBJ hStockNullBrush;
1272 
1274  HGDIOBJ hStockDCPen;
1275 
1277  HGDIOBJ hStockNullPen;
1278 
1279 
1281  HGDIOBJ hPrevPen;
1282 
1284  HGDIOBJ hPrevBrush;
1285 
1287  COLORREF prevBrushColor;
1288 
1290  HGDIOBJ hPrevFont;
1291 
1293  int prevBkMode;
1294 
1296  COLORREF prevBkColor;
1297 
1298 
1299 } gdi_surface_data;
1300 
1301 typedef struct
1302 {
1304  HFONT hFont;
1305 
1307  dr2d_font_metrics metrics;
1308 
1309 } gdi_font_data;
1310 
1311 typedef struct
1312 {
1314  HBITMAP hSrcBitmap;
1315 
1317  unsigned int* pSrcBitmapData;
1318 
1321  HBITMAP hIntermediateBitmap;
1322 
1324  unsigned int* pIntermediateBitmapData;
1325 
1326 
1328  void* pMappedImageData;
1329 
1331  unsigned int mapAccessFlags;
1332 
1333 } gdi_image_data;
1334 
1335 
1336 bool dr2d_on_create_context_gdi(dr2d_context* pContext, const void* pUserData);
1337 void dr2d_on_delete_context_gdi(dr2d_context* pContext);
1338 bool dr2d_on_create_surface_gdi(dr2d_surface* pSurface, float width, float height);
1339 void dr2d_on_delete_surface_gdi(dr2d_surface* pSurface);
1340 bool dr2d_on_create_font_gdi(dr2d_font* pFont);
1341 void dr2d_on_delete_font_gdi(dr2d_font* pFont);
1342 bool dr2d_on_create_image_gdi(dr2d_image* pImage, unsigned int stride, const void* pData);
1343 void dr2d_on_delete_image_gdi(dr2d_image* pImage);
1344 
1345 void dr2d_begin_draw_gdi(dr2d_surface* pSurface);
1346 void dr2d_end_draw_gdi(dr2d_surface* pSurface);
1347 void dr2d_clear_gdi(dr2d_surface* pSurface, dr2d_color color);
1348 void dr2d_draw_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color);
1349 void dr2d_draw_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth);
1350 void dr2d_draw_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor);
1351 void dr2d_draw_round_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius);
1352 void dr2d_draw_round_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth);
1353 void dr2d_draw_round_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor);
1354 void dr2d_draw_text_gdi(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor);
1355 void dr2d_draw_image_gdi(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs);
1356 void dr2d_set_clip_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom);
1357 void dr2d_get_clip_gdi(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut);
1358 
1359 dr2d_image_format dr2d_get_optimal_image_format_gdi(dr2d_context* pContext);
1360 void* dr2d_map_image_data_gdi(dr2d_image* pImage, unsigned accessFlags);
1361 void dr2d_unmap_image_data_gdi(dr2d_image* pImage);
1362 
1363 bool dr2d_get_font_metrics_gdi(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut);
1364 bool dr2d_get_glyph_metrics_gdi(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics);
1365 bool dr2d_measure_string_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut);
1366 bool dr2d_get_text_cursor_position_from_point_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut);
1367 bool dr2d_get_text_cursor_position_from_char_gdi(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut);
1368 
1370 wchar_t* dr2d_to_wchar_gdi(dr2d_context* pContext, const char* text, size_t textSizeInBytes, unsigned int* characterCountOut);
1371 
1373 static int dr2d_utf32_to_utf16(unsigned int utf32, unsigned short utf16[2])
1374 {
1375  if (utf16 == NULL) {
1376  return 0;
1377  }
1378 
1379  if (utf32 < 0xD800 || (utf32 >= 0xE000 && utf32 <= 0xFFFF))
1380  {
1381  utf16[0] = (unsigned short)utf32;
1382  utf16[1] = 0;
1383  return 1;
1384  }
1385  else
1386  {
1387  if (utf32 >= 0x10000 && utf32 <= 0x10FFFF)
1388  {
1389  utf16[0] = (unsigned short)(0xD7C0 + (unsigned short)(utf32 >> 10));
1390  utf16[1] = (unsigned short)(0xDC00 + (unsigned short)(utf32 & 0x3FF));
1391  return 2;
1392  }
1393  else
1394  {
1395  // Invalid.
1396  utf16[0] = 0;
1397  utf16[0] = 0;
1398  return 0;
1399  }
1400  }
1401 }
1402 
1403 dr2d_context* dr2d_create_context_gdi(HDC hDC)
1404 {
1405  dr2d_drawing_callbacks callbacks;
1406  callbacks.on_create_context = dr2d_on_create_context_gdi;
1407  callbacks.on_delete_context = dr2d_on_delete_context_gdi;
1408  callbacks.on_create_surface = dr2d_on_create_surface_gdi;
1409  callbacks.on_delete_surface = dr2d_on_delete_surface_gdi;
1410  callbacks.on_create_font = dr2d_on_create_font_gdi;
1411  callbacks.on_delete_font = dr2d_on_delete_font_gdi;
1412  callbacks.on_create_image = dr2d_on_create_image_gdi;
1413  callbacks.on_delete_image = dr2d_on_delete_image_gdi;
1414 
1415  callbacks.begin_draw = dr2d_begin_draw_gdi;
1416  callbacks.end_draw = dr2d_end_draw_gdi;
1417  callbacks.clear = dr2d_clear_gdi;
1418  callbacks.draw_rect = dr2d_draw_rect_gdi;
1419  callbacks.draw_rect_outline = dr2d_draw_rect_outline_gdi;
1420  callbacks.draw_rect_with_outline = dr2d_draw_rect_with_outline_gdi;
1421  callbacks.draw_round_rect = dr2d_draw_round_rect_gdi;
1422  callbacks.draw_round_rect_outline = dr2d_draw_round_rect_outline_gdi;
1423  callbacks.draw_round_rect_with_outline = dr2d_draw_round_rect_with_outline_gdi;
1424  callbacks.draw_text = dr2d_draw_text_gdi;
1425  callbacks.draw_image = dr2d_draw_image_gdi;
1426  callbacks.set_clip = dr2d_set_clip_gdi;
1427  callbacks.get_clip = dr2d_get_clip_gdi;
1428 
1429  callbacks.get_optimal_image_format = dr2d_get_optimal_image_format_gdi;
1430  callbacks.map_image_data = dr2d_map_image_data_gdi;
1431  callbacks.unmap_image_data = dr2d_unmap_image_data_gdi;
1432 
1433  callbacks.get_font_metrics = dr2d_get_font_metrics_gdi;
1434  callbacks.get_glyph_metrics = dr2d_get_glyph_metrics_gdi;
1435  callbacks.measure_string = dr2d_measure_string_gdi;
1436  callbacks.get_text_cursor_position_from_point = dr2d_get_text_cursor_position_from_point_gdi;
1437  callbacks.get_text_cursor_position_from_char = dr2d_get_text_cursor_position_from_char_gdi;
1438 
1439  return dr2d_create_context(callbacks, sizeof(gdi_context_data), sizeof(gdi_surface_data), sizeof(gdi_font_data), sizeof(gdi_image_data), &hDC);
1440 }
1441 
1442 dr2d_surface* dr2d_create_surface_gdi_HWND(dr2d_context* pContext, HWND hWnd)
1443 {
1444  dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0);
1445  if (pSurface != NULL) {
1446  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1447  if (pGDIData != NULL) {
1448  pGDIData->hWnd = hWnd;
1449  }
1450  }
1451 
1452  return pSurface;
1453 }
1454 
1455 dr2d_surface* dr2d_create_surface_gdi_HDC(dr2d_context* pContext, HDC hDC)
1456 {
1457  dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0);
1458  if (pSurface != NULL) {
1459  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1460  if (pGDIData != NULL) {
1461  pGDIData->hDC = hDC;
1462  }
1463  }
1464 
1465  return pSurface;
1466 }
1467 
1468 HDC dr2d_get_HDC(dr2d_surface* pSurface)
1469 {
1470  if (pSurface != NULL) {
1471  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1472  if (pGDIData != NULL) {
1473  return pGDIData->hDC;
1474  }
1475  }
1476 
1477  return NULL;
1478 }
1479 
1480 HBITMAP dr2d_get_HBITMAP(dr2d_surface* pSurface)
1481 {
1482  if (pSurface != NULL) {
1483  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1484  if (pGDIData != NULL) {
1485  return pGDIData->hBitmap;
1486  }
1487  }
1488 
1489  return NULL;
1490 }
1491 
1492 HFONT dr2d_get_HFONT(dr2d_font* pFont)
1493 {
1494  gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
1495  if (pGDIData == NULL) {
1496  return NULL;
1497  }
1498 
1499  return pGDIData->hFont;
1500 }
1501 
1502 
1503 bool dr2d_on_create_context_gdi(dr2d_context* pContext, const void* pUserData)
1504 {
1505  assert(pContext != NULL);
1506 
1507  HDC hDC = NULL;
1508  if (pUserData != NULL) {
1509  hDC = *(HDC*)pUserData;
1510  }
1511 
1512  bool ownsDC = false;
1513  if (hDC == NULL) {
1514  hDC = CreateCompatibleDC(GetDC(GetDesktopWindow()));
1515  ownsDC = true;
1516  }
1517 
1518 
1519  // We need to create the DC that all of our rendering commands will be drawn to.
1520  gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext);
1521  if (pGDIData == NULL) {
1522  return false;
1523  }
1524 
1525  pGDIData->hDC = hDC;
1526  if (pGDIData->hDC == NULL) {
1527  return false;
1528  }
1529 
1530  pGDIData->ownsDC = ownsDC;
1531 
1532 
1533  // We want to use the advanced graphics mode so that GetTextExtentPoint32() performs the conversions for font rotation for us.
1534  SetGraphicsMode(pGDIData->hDC, GM_ADVANCED);
1535 
1536 
1537  pGDIData->wcharBuffer = NULL;
1538  pGDIData->wcharBufferLength = 0;
1539 
1540  pGDIData->pGlyphCache = NULL;
1541  pGDIData->glyphCacheSize = 0;
1542 
1543  return true;
1544 }
1545 
1546 void dr2d_on_delete_context_gdi(dr2d_context* pContext)
1547 {
1548  assert(pContext != NULL);
1549 
1550  gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext);
1551  if (pGDIData != NULL)
1552  {
1553  free(pGDIData->pGlyphCache);
1554  pGDIData->glyphCacheSize = 0;
1555 
1556  free(pGDIData->wcharBuffer);
1557  pGDIData->wcharBuffer = 0;
1558  pGDIData->wcharBufferLength = 0;
1559 
1560  if (pGDIData->ownsDC) {
1561  DeleteDC(pGDIData->hDC);
1562  }
1563 
1564  pGDIData->hDC = NULL;
1565  }
1566 }
1567 
1568 bool dr2d_on_create_surface_gdi(dr2d_surface* pSurface, float width, float height)
1569 {
1570  assert(pSurface != NULL);
1571 
1572  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pSurface->pContext);
1573  if (pGDIContextData == NULL) {
1574  return false;
1575  }
1576 
1577  gdi_surface_data* pGDISurfaceData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1578  if (pGDISurfaceData == NULL) {
1579  return false;
1580  }
1581 
1582  HDC hDC = pGDIContextData->hDC;
1583  if (hDC == NULL) {
1584  return false;
1585  }
1586 
1587  HDC hIntermediateDC = CreateCompatibleDC(hDC);
1588  if (hIntermediateDC == NULL) {
1589  return false;
1590  }
1591 
1592  pGDISurfaceData->hIntermediateDC = hIntermediateDC;
1593  pGDISurfaceData->hWnd = NULL;
1594 
1595 
1596  if (width != 0 && height != 0)
1597  {
1598  pGDISurfaceData->hDC = hDC;
1599 
1600  BITMAPINFO bmi;
1601  ZeroMemory(&bmi, sizeof(bmi));
1602  bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1603  bmi.bmiHeader.biWidth = (LONG)width;
1604  bmi.bmiHeader.biHeight = (LONG)height;
1605  bmi.bmiHeader.biPlanes = 1;
1606  bmi.bmiHeader.biBitCount = 32;
1607  bmi.bmiHeader.biCompression = BI_RGB;
1608  pGDISurfaceData->hBitmap = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pGDISurfaceData->pBitmapData, NULL, 0);
1609  if (pGDISurfaceData->hBitmap == NULL) {
1610  return false;
1611  }
1612  }
1613  else
1614  {
1615  pGDISurfaceData->hBitmap = NULL;
1616  pGDISurfaceData->hDC = NULL;
1617  }
1618 
1619 
1620  return true;
1621 }
1622 
1623 void dr2d_on_delete_surface_gdi(dr2d_surface* pSurface)
1624 {
1625  assert(pSurface != NULL);
1626 
1627  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1628  if (pGDIData != NULL)
1629  {
1630  DeleteObject(pGDIData->hBitmap);
1631  pGDIData->hBitmap = NULL;
1632 
1633  DeleteDC(pGDIData->hIntermediateDC);
1634  pGDIData->hIntermediateDC = NULL;
1635  }
1636 }
1637 
1638 bool dr2d_on_create_font_gdi(dr2d_font* pFont)
1639 {
1640  assert(pFont != NULL);
1641 
1642  gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
1643  if (pGDIData == NULL) {
1644  return false;
1645  }
1646 
1647 
1648  LONG weightGDI = FW_REGULAR;
1649  switch (pFont->weight)
1650  {
1651  case dr2d_font_weight_medium: weightGDI = FW_MEDIUM; break;
1652  case dr2d_font_weight_thin: weightGDI = FW_THIN; break;
1653  case dr2d_font_weight_extra_light: weightGDI = FW_EXTRALIGHT; break;
1654  case dr2d_font_weight_light: weightGDI = FW_LIGHT; break;
1655  case dr2d_font_weight_semi_bold: weightGDI = FW_SEMIBOLD; break;
1656  case dr2d_font_weight_bold: weightGDI = FW_BOLD; break;
1657  case dr2d_font_weight_extra_bold: weightGDI = FW_EXTRABOLD; break;
1658  case dr2d_font_weight_heavy: weightGDI = FW_HEAVY; break;
1659  default: break;
1660  }
1661 
1662  BYTE slantGDI = FALSE;
1663  if (pFont->slant == dr2d_font_slant_italic || pFont->slant == dr2d_font_slant_oblique) {
1664  slantGDI = TRUE;
1665  }
1666 
1667 
1668  LOGFONTA logfont;
1669  memset(&logfont, 0, sizeof(logfont));
1670 
1671 
1672 
1673  logfont.lfHeight = -(LONG)pFont->size;
1674  logfont.lfWeight = weightGDI;
1675  logfont.lfItalic = slantGDI;
1676  logfont.lfCharSet = DEFAULT_CHARSET;
1677  //logfont.lfQuality = (pFont->size > 36) ? ANTIALIASED_QUALITY : CLEARTYPE_QUALITY;
1678  logfont.lfQuality = (pFont->flags & DR2D_FONT_NO_CLEARTYPE) ? ANTIALIASED_QUALITY : CLEARTYPE_QUALITY;
1679  logfont.lfEscapement = (LONG)pFont->rotation * 10;
1680  logfont.lfOrientation = (LONG)pFont->rotation * 10;
1681 
1682  size_t familyLength = strlen(pFont->family);
1683  memcpy(logfont.lfFaceName, pFont->family, (familyLength < 31) ? familyLength : 31);
1684 
1685 
1686  pGDIData->hFont = CreateFontIndirectA(&logfont);
1687  if (pGDIData->hFont == NULL) {
1688  return false;
1689  }
1690 
1691 
1692  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext);
1693  if (pGDIContextData == NULL) {
1694  return false;
1695  }
1696 
1697  // Cache the font metrics.
1698  HGDIOBJ hPrevFont = SelectObject(pGDIContextData->hDC, pGDIData->hFont);
1699  {
1700  TEXTMETRIC metrics;
1701  GetTextMetrics(pGDIContextData->hDC, &metrics);
1702 
1703  pGDIData->metrics.ascent = metrics.tmAscent;
1704  pGDIData->metrics.descent = metrics.tmDescent;
1705  pGDIData->metrics.lineHeight = metrics.tmHeight;
1706 
1707 
1708  const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // <-- Identity matrix
1709 
1710  GLYPHMETRICS spaceMetrics;
1711  DWORD bitmapBufferSize = GetGlyphOutlineW(pGDIContextData->hDC, ' ', GGO_NATIVE, &spaceMetrics, 0, NULL, &transform);
1712  if (bitmapBufferSize == GDI_ERROR) {
1713  pGDIData->metrics.spaceWidth = 4;
1714  } else {
1715  pGDIData->metrics.spaceWidth = spaceMetrics.gmCellIncX;
1716  }
1717  }
1718  SelectObject(pGDIContextData->hDC, hPrevFont);
1719 
1720 
1721  return true;
1722 }
1723 
1724 void dr2d_on_delete_font_gdi(dr2d_font* pFont)
1725 {
1726  assert(pFont != NULL);
1727 
1728  gdi_font_data* pGDIData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
1729  if (pGDIData == NULL) {
1730  return;
1731  }
1732 
1733  DeleteObject(pGDIData->hFont);
1734 }
1735 
1736 bool dr2d_on_create_image_gdi(dr2d_image* pImage, unsigned int stride, const void* pData)
1737 {
1738  assert(pImage != NULL);
1739 
1740  gdi_image_data* pGDIData = (gdi_image_data*)dr2d_get_image_extra_data(pImage);
1741  if (pGDIData == NULL) {
1742  return false;
1743  }
1744 
1745  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pImage->pContext);
1746  if (pGDIContextData == NULL) {
1747  return false;
1748  }
1749 
1750 
1751  BITMAPINFO bmi;
1752  ZeroMemory(&bmi, sizeof(bmi));
1753  bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1754  bmi.bmiHeader.biWidth = pImage->width;
1755  bmi.bmiHeader.biHeight = pImage->height;
1756  bmi.bmiHeader.biPlanes = 1;
1757  bmi.bmiHeader.biBitCount = 32; // Only supporting 32-bit formats.
1758  bmi.bmiHeader.biCompression = BI_RGB;
1759  pGDIData->hSrcBitmap = CreateDIBSection(pGDIContextData->hDC, &bmi, DIB_RGB_COLORS, (void**)&pGDIData->pSrcBitmapData, NULL, 0);
1760  if (pGDIData->hSrcBitmap == NULL) {
1761  return false;
1762  }
1763 
1764  pGDIData->hIntermediateBitmap = CreateDIBSection(pGDIContextData->hDC, &bmi, DIB_RGB_COLORS, (void**)&pGDIData->pIntermediateBitmapData, NULL, 0);
1765  if (pGDIData->hIntermediateBitmap == NULL) {
1766  DeleteObject(pGDIData->hSrcBitmap);
1767  return false;
1768  }
1769 
1770 
1771  // We need to convert the data so it renders correctly with AlphaBlend().
1772  if (pData != NULL) {
1773  dr2d__rgba8_bgra8_swap__premul(pData, pGDIData->pSrcBitmapData, pImage->width, pImage->height, stride, pImage->width*4);
1774  }
1775 
1776  // Flush GDI to let it know we are finished with the bitmap object's data.
1777  GdiFlush();
1778 
1779 
1780  pGDIData->pMappedImageData = NULL;
1781  pGDIData->mapAccessFlags = 0;
1782 
1783  // At this point everything should be good.
1784  return true;
1785 }
1786 
1787 void dr2d_on_delete_image_gdi(dr2d_image* pImage)
1788 {
1789  assert(pImage != NULL);
1790 
1791  gdi_image_data* pGDIData = (gdi_image_data*)dr2d_get_image_extra_data(pImage);
1792  if (pGDIData == NULL) {
1793  return;
1794  }
1795 
1796  DeleteObject(pGDIData->hSrcBitmap);
1797  pGDIData->hSrcBitmap = NULL;
1798 
1799  DeleteObject(pGDIData->hIntermediateBitmap);
1800  pGDIData->hIntermediateBitmap = NULL;
1801 }
1802 
1803 
1804 void dr2d_begin_draw_gdi(dr2d_surface* pSurface)
1805 {
1806  assert(pSurface != NULL);
1807 
1808  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1809  if (pGDIData != NULL) {
1810  if (pGDIData->hWnd != NULL) {
1811  pGDIData->hDC = BeginPaint(pGDIData->hWnd, &pGDIData->ps);
1812  } else {
1813  SelectObject(dr2d_get_HDC(pSurface), pGDIData->hBitmap);
1814  }
1815 
1816  HDC hDC = dr2d_get_HDC(pSurface);
1817 
1818  pGDIData->hStockDCBrush = GetStockObject(DC_BRUSH);
1819  pGDIData->hStockNullBrush = GetStockObject(NULL_BRUSH);
1820  pGDIData->hStockDCPen = GetStockObject(DC_PEN);
1821  pGDIData->hStockNullPen = GetStockObject(NULL_PEN);
1822 
1823  // Retrieve the defaults so they can be restored later.
1824  pGDIData->hPrevPen = GetCurrentObject(hDC, OBJ_PEN);
1825  pGDIData->hPrevBrush = GetCurrentObject(hDC, OBJ_BRUSH);
1826  pGDIData->prevBrushColor = GetDCBrushColor(hDC);
1827  pGDIData->hPrevFont = GetCurrentObject(hDC, OBJ_FONT);
1828  pGDIData->prevBkMode = GetBkMode(hDC);
1829  pGDIData->prevBkColor = GetBkColor(hDC);
1830  }
1831 }
1832 
1833 void dr2d_end_draw_gdi(dr2d_surface* pSurface)
1834 {
1835  assert(pSurface != NULL);
1836 
1837  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1838  if (pGDIData != NULL) {
1839  HDC hDC = dr2d_get_HDC(pSurface);
1840 
1841  SelectClipRgn(hDC, NULL);
1842 
1843  SelectObject(hDC, pGDIData->hPrevPen);
1844  SelectObject(hDC, pGDIData->hPrevBrush);
1845  SetDCBrushColor(hDC, pGDIData->prevBrushColor);
1846  SelectObject(hDC, pGDIData->hPrevFont);
1847  SetBkMode(hDC, pGDIData->prevBkMode);
1848  SetBkColor(hDC, pGDIData->prevBkColor);
1849 
1850  if (pGDIData->hWnd != NULL) {
1851  EndPaint(pGDIData->hWnd, &pGDIData->ps);
1852  }
1853  }
1854 }
1855 
1856 void dr2d_clear_gdi(dr2d_surface* pSurface, dr2d_color color)
1857 {
1858  assert(pSurface != NULL);
1859 
1860  dr2d_draw_rect_gdi(pSurface, 0, 0, pSurface->width, pSurface->height, color);
1861 }
1862 
1863 void dr2d_draw_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color)
1864 {
1865  assert(pSurface != NULL);
1866 
1867  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1868  if (pGDIData != NULL)
1869  {
1870  HDC hDC = dr2d_get_HDC(pSurface);
1871 
1872  SelectObject(hDC, pGDIData->hStockNullPen);
1873  SelectObject(hDC, pGDIData->hStockDCBrush);
1874  SetDCBrushColor(hDC, RGB(color.r, color.g, color.b));
1875 
1876  // Now draw the rectangle. The documentation for this says that the width and height is 1 pixel less when the pen is null. Therefore we will
1877  // increase the width and height by 1 since we have got the pen set to null.
1878  Rectangle(hDC, (int)left, (int)top, (int)right + 1, (int)bottom + 1);
1879  }
1880 }
1881 
1882 void dr2d_draw_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth)
1883 {
1884  assert(pSurface != NULL);
1885 
1886  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1887  if (pGDIData != NULL)
1888  {
1889  HDC hDC = dr2d_get_HDC(pSurface);
1890 
1891  SelectObject(hDC, pGDIData->hStockNullPen);
1892  SelectObject(hDC, pGDIData->hStockDCBrush);
1893  SetDCBrushColor(hDC, RGB(color.r, color.g, color.b));
1894 
1895  // Now draw the rectangle. The documentation for this says that the width and height is 1 pixel less when the pen is null. Therefore we will
1896  // increase the width and height by 1 since we have got the pen set to null.
1897 
1898  Rectangle(hDC, (int)left, (int)top, (int)(left + outlineWidth + 1), (int)(bottom + 1)); // Left.
1899  Rectangle(hDC, (int)(right - outlineWidth), (int)top, (int)(right + 1), (int)(bottom + 1)); // Right.
1900  Rectangle(hDC, (int)(left + outlineWidth), (int)top, (int)(right - outlineWidth + 1), (int)(top + outlineWidth + 1)); // Top
1901  Rectangle(hDC, (int)(left + outlineWidth), (int)(bottom - outlineWidth), (int)(right - outlineWidth + 1), (int)(bottom + 1)); // Bottom
1902  }
1903 }
1904 
1905 void dr2d_draw_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor)
1906 {
1907  assert(pSurface != NULL);
1908 
1909  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1910  if (pGDIData != NULL)
1911  {
1912  HDC hDC = dr2d_get_HDC(pSurface);
1913 
1914  HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(outlineColor.r, outlineColor.g, outlineColor.b));
1915  if (hPen != NULL)
1916  {
1917  SelectObject(hDC, hPen);
1918  SelectObject(hDC, pGDIData->hStockDCBrush);
1919  SetDCBrushColor(hDC, RGB(color.r, color.g, color.b));
1920 
1921  Rectangle(hDC, (int)left, (int)top, (int)right, (int)bottom);
1922 
1923  DeleteObject(hPen);
1924  }
1925  }
1926 }
1927 
1928 void dr2d_draw_round_rect_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius)
1929 {
1930  assert(pSurface != NULL);
1931 
1932  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1933  if (pGDIData != NULL)
1934  {
1935  HDC hDC = dr2d_get_HDC(pSurface);
1936 
1937  SelectObject(hDC, pGDIData->hStockNullPen);
1938  SelectObject(hDC, pGDIData->hStockDCBrush);
1939  SetDCBrushColor(hDC, RGB(color.r, color.g, color.b));
1940 
1941  RoundRect(hDC, (int)left, (int)top, (int)right + 1, (int)bottom + 1, (int)(radius*2), (int)(radius*2));
1942  }
1943 }
1944 
1945 void dr2d_draw_round_rect_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth)
1946 {
1947  assert(pSurface != NULL);
1948 
1949  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1950  if (pGDIData != NULL)
1951  {
1952  HDC hDC = dr2d_get_HDC(pSurface);
1953 
1954  HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(color.r, color.g, color.b));
1955  if (hPen != NULL)
1956  {
1957  SelectObject(hDC, pGDIData->hStockNullBrush);
1958  SelectObject(hDC, hPen);
1959 
1960  RoundRect(hDC, (int)left, (int)top, (int)right, (int)bottom, (int)(radius*2), (int)(radius*2));
1961 
1962  DeleteObject(hPen);
1963  }
1964  }
1965 }
1966 
1967 void dr2d_draw_round_rect_with_outline_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor)
1968 {
1969  assert(pSurface != NULL);
1970 
1971  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
1972  if (pGDIData != NULL)
1973  {
1974  HDC hDC = dr2d_get_HDC(pSurface);
1975 
1976  HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (int)outlineWidth, RGB(outlineColor.r, outlineColor.g, outlineColor.b));
1977  if (hPen != NULL)
1978  {
1979  SelectObject(hDC, hPen);
1980  SelectObject(hDC, pGDIData->hStockDCBrush);
1981  SetDCBrushColor(hDC, RGB(color.r, color.g, color.b));
1982 
1983  RoundRect(hDC, (int)left, (int)top, (int)right, (int)bottom, (int)(radius*2), (int)(radius*2));
1984 
1985  DeleteObject(hPen);
1986  }
1987  }
1988 }
1989 
1990 void dr2d_draw_text_gdi(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor)
1991 {
1992  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
1993  if (pGDIFontData == NULL) {
1994  return;
1995  }
1996 
1997 
1998  HDC hDC = dr2d_get_HDC(pSurface);
1999 
2000  HFONT hFontGDI = pGDIFontData->hFont;
2001  if (hFontGDI != NULL)
2002  {
2003  // We actually want to use the W version of TextOut because otherwise unicode doesn't work properly.
2004 
2005  unsigned int textWLength;
2006  wchar_t* textW = dr2d_to_wchar_gdi(pSurface->pContext, text, textSizeInBytes, &textWLength);
2007  if (textW != NULL)
2008  {
2009  SelectObject(hDC, hFontGDI);
2010 
2011  UINT options = 0;
2012  RECT rect = {0, 0, 0, 0};
2013 
2014  if (backgroundColor.a == 0) {
2015  SetBkMode(hDC, TRANSPARENT);
2016  } else {
2017  SetBkMode(hDC, OPAQUE);
2018  SetBkColor(hDC, RGB(backgroundColor.r, backgroundColor.g, backgroundColor.b));
2019 
2020  // There is an issue with the way GDI draws the background of a string of text. When ClearType is enabled, the rectangle appears
2021  // to be wider than it is supposed to be. As a result, drawing text right next to each other results in the most recent one being
2022  // drawn slightly on top of the previous one. To fix this we need to use ExtTextOut() with the ETO_CLIPPED parameter enabled.
2023  options |= ETO_CLIPPED;
2024 
2025  SIZE textSize = {0, 0};
2026  GetTextExtentPoint32W(hDC, textW, textWLength, &textSize);
2027  rect.left = (LONG)posX;
2028  rect.top = (LONG)posY;
2029  rect.right = (LONG)(posX + textSize.cx);
2030  rect.bottom = (LONG)(posY + textSize.cy);
2031  }
2032 
2033  SetTextColor(hDC, RGB(color.r, color.g, color.b));
2034 
2035  ExtTextOutW(hDC, (int)posX, (int)posY, options, &rect, textW, textWLength, NULL);
2036  }
2037  }
2038 }
2039 
2040 void dr2d_draw_image_gdi(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs)
2041 {
2042  gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage);
2043  if (pGDIImageData == NULL) {
2044  return;
2045  }
2046 
2047  gdi_surface_data* pGDISurfaceData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
2048  if (pGDISurfaceData == NULL) {
2049  return;
2050  }
2051 
2052  bool drawFlipped = false;
2053  HBITMAP hSrcBitmap = NULL;
2054 
2055  if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) == 0 && (pArgs->options & DR2D_IMAGE_HINT_NO_ALPHA) != 0 && pArgs->foregroundTint.r == 255 && pArgs->foregroundTint.g == 255 && pArgs->foregroundTint.b == 255)
2056  {
2057  // Fast path. No tint, no background, no alpha.
2058  hSrcBitmap = pGDIImageData->hSrcBitmap;
2059  drawFlipped = true;
2060  }
2061  else
2062  {
2063  // Slow path. We need to manually change the color values of the intermediate bitmap and use that as the source when drawing it. This is also flipped.
2064  unsigned int* pSrcBitmapData = pGDIImageData->pSrcBitmapData;
2065  unsigned int* pDstBitmapData = pGDIImageData->pIntermediateBitmapData;
2066  for (unsigned int iRow = 0; iRow < pImage->height; ++iRow)
2067  {
2068  for (unsigned int iCol = 0; iCol < pImage->width; ++iCol)
2069  {
2070  unsigned int srcTexel = *(pSrcBitmapData + (iRow * pImage->width) + iCol);
2071  unsigned int* dstTexel = (pDstBitmapData + ((pImage->height - iRow - 1) * pImage->width) + iCol);
2072 
2073  unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24;
2074  unsigned int srcTexelR = (unsigned int)(((srcTexel & 0x00FF0000) >> 16) * (pArgs->foregroundTint.r / 255.0f));
2075  unsigned int srcTexelG = (unsigned int)(((srcTexel & 0x0000FF00) >> 8) * (pArgs->foregroundTint.g / 255.0f));
2076  unsigned int srcTexelB = (unsigned int)(((srcTexel & 0x000000FF) >> 0) * (pArgs->foregroundTint.b / 255.0f));
2077 
2078  if (srcTexelR > 255) srcTexelR = 255;
2079  if (srcTexelG > 255) srcTexelG = 255;
2080  if (srcTexelB > 255) srcTexelB = 255;
2081 
2082  if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0)
2083  {
2084  srcTexelB += (unsigned int)(pArgs->backgroundColor.b * ((255 - srcTexelA) / 255.0f));
2085  srcTexelG += (unsigned int)(pArgs->backgroundColor.g * ((255 - srcTexelA) / 255.0f));
2086  srcTexelR += (unsigned int)(pArgs->backgroundColor.r * ((255 - srcTexelA) / 255.0f));
2087  srcTexelA = 0xFF;
2088  }
2089 
2090  *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
2091  }
2092  }
2093 
2094  // Flush GDI to let it know we are finished with the bitmap object's data.
2095  GdiFlush();
2096 
2097  // If we have drawn the background manually we don't need to do an alpha blend.
2098  if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0) {
2100  }
2101 
2102  hSrcBitmap = pGDIImageData->hIntermediateBitmap;
2103  }
2104 
2105  HGDIOBJ hPrevBitmap = SelectObject(pGDISurfaceData->hIntermediateDC, hSrcBitmap);
2106  if ((pArgs->options & DR2D_IMAGE_HINT_NO_ALPHA) != 0)
2107  {
2108  if (drawFlipped) {
2109  StretchBlt(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY + (int)pArgs->dstHeight - 1, (int)pArgs->dstWidth, -(int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, SRCCOPY);
2110  } else {
2111  StretchBlt(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY, (int)pArgs->dstWidth, (int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, SRCCOPY);
2112  }
2113  }
2114  else
2115  {
2116  assert(drawFlipped == false); // <-- Error if this is hit.
2117  BLENDFUNCTION blend = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
2118  AlphaBlend(pGDISurfaceData->hDC, (int)pArgs->dstX, (int)pArgs->dstY, (int)pArgs->dstWidth, (int)pArgs->dstHeight, pGDISurfaceData->hIntermediateDC, (int)pArgs->srcX, (int)pArgs->srcY, (int)pArgs->srcWidth, (int)pArgs->srcHeight, blend);
2119  }
2120  SelectObject(pGDISurfaceData->hIntermediateDC, hPrevBitmap);
2121 }
2122 
2123 void dr2d_set_clip_gdi(dr2d_surface* pSurface, float left, float top, float right, float bottom)
2124 {
2125  assert(pSurface != NULL);
2126 
2127  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
2128  if (pGDIData != NULL)
2129  {
2130  HDC hDC = dr2d_get_HDC(pSurface);
2131 
2132  SelectClipRgn(hDC, NULL);
2133  IntersectClipRect(hDC, (int)left, (int)top, (int)right, (int)bottom);
2134  }
2135 }
2136 
2137 void dr2d_get_clip_gdi(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut)
2138 {
2139  assert(pSurface != NULL);
2140 
2141  gdi_surface_data* pGDIData = (gdi_surface_data*)dr2d_get_surface_extra_data(pSurface);
2142  if (pGDIData != NULL)
2143  {
2144  RECT rect;
2145  GetClipBox(dr2d_get_HDC(pSurface), &rect);
2146 
2147  if (pLeftOut != NULL) {
2148  *pLeftOut = (float)rect.left;
2149  }
2150  if (pTopOut != NULL) {
2151  *pTopOut = (float)rect.top;
2152  }
2153  if (pRightOut != NULL) {
2154  *pRightOut = (float)rect.right;
2155  }
2156  if (pBottomOut != NULL) {
2157  *pBottomOut = (float)rect.bottom;
2158  }
2159  }
2160 }
2161 
2162 
2163 dr2d_image_format dr2d_get_optimal_image_format_gdi(dr2d_context* pContext)
2164 {
2165  (void)pContext;
2166  return dr2d_image_format_bgra8;
2167 }
2168 
2169 void* dr2d_map_image_data_gdi(dr2d_image* pImage, unsigned accessFlags)
2170 {
2171  assert(pImage != NULL);
2172 
2173  gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage);
2174  if (pGDIImageData == NULL) {
2175  return NULL;
2176  }
2177 
2178  assert(pGDIImageData->pMappedImageData == NULL); // This function should never be called while the image is already mapped.
2179 
2180  pGDIImageData->mapAccessFlags = accessFlags;
2181 
2182  if (pImage->format == dr2d_image_format_bgra8)
2183  {
2184  pGDIImageData->pMappedImageData = pGDIImageData->pSrcBitmapData;
2185  }
2186  else
2187  {
2188  pGDIImageData->pMappedImageData = malloc(pImage->width * pImage->height * 4);
2189  if (pGDIImageData->pMappedImageData == NULL) {
2190  return NULL;
2191  }
2192 
2193  for (unsigned int iRow = 0; iRow < pImage->height; ++iRow)
2194  {
2195  const unsigned int iRowSrc = pImage->height - (iRow + 1);
2196  const unsigned int iRowDst = iRow;
2197 
2198  for (unsigned int iCol = 0; iCol < pImage->width; ++iCol)
2199  {
2200  unsigned int srcTexel = ((const unsigned int*)(pGDIImageData->pSrcBitmapData))[ (iRowSrc * pImage->width) + iCol];
2201  unsigned int* dstTexel = (( unsigned int*)(pGDIImageData->pMappedImageData)) + (iRowDst * pImage->width) + iCol;
2202 
2203  unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24;
2204  unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16;
2205  unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8;
2206  unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0;
2207 
2208  srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f));
2209  srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f));
2210  srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f));
2211 
2212  *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
2213  }
2214  }
2215  }
2216 
2217  return pGDIImageData->pMappedImageData;
2218 }
2219 
2220 void dr2d_unmap_image_data_gdi(dr2d_image* pImage)
2221 {
2222  assert(pImage != NULL);
2223 
2224  gdi_image_data* pGDIImageData = (gdi_image_data*)dr2d_get_image_extra_data(pImage);
2225  if (pGDIImageData == NULL) {
2226  return;
2227  }
2228 
2229  assert(pGDIImageData->pMappedImageData != NULL); // This function should never be called while the image is not mapped.
2230 
2231  if (pImage->format == dr2d_image_format_bgra8)
2232  {
2233  // It's in the native format, so just do a flush.
2234  GdiFlush();
2235  }
2236  else
2237  {
2238  // Update the actual image data if applicable.
2239  if (pGDIImageData->mapAccessFlags & DR2D_WRITE) {
2240  dr2d__rgba8_bgra8_swap__premul(pGDIImageData->pMappedImageData, pGDIImageData->pSrcBitmapData, pImage->width, pImage->height, pImage->width*4, pImage->width*4);
2241  }
2242 
2243  free(pGDIImageData->pMappedImageData);
2244  }
2245 
2246  pGDIImageData->pMappedImageData = NULL;
2247  pGDIImageData->mapAccessFlags = 0;
2248 }
2249 
2250 
2251 bool dr2d_get_font_metrics_gdi(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut)
2252 {
2253  assert(pFont != NULL);
2254  assert(pMetricsOut != NULL);
2255 
2256  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
2257  if (pGDIFontData == NULL) {
2258  return false;
2259  }
2260 
2261  *pMetricsOut = pGDIFontData->metrics;
2262  return true;
2263 }
2264 
2265 bool dr2d_get_glyph_metrics_gdi(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics)
2266 {
2267  assert(pFont != NULL);
2268  assert(pGlyphMetrics != NULL);
2269 
2270  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
2271  if (pGDIFontData == NULL) {
2272  return false;
2273  }
2274 
2275  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext);
2276  if (pGDIContextData == NULL) {
2277  return false;
2278  }
2279 
2280 
2281  SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2282 
2283 
2284  const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}}; // <-- Identity matrix
2285 
2286  unsigned short utf16[2];
2287  int utf16Len = dr2d_utf32_to_utf16(utf32, utf16);
2288 
2289  WCHAR glyphIndices[2];
2290 
2291  GCP_RESULTSW glyphResults;
2292  ZeroMemory(&glyphResults, sizeof(glyphResults));
2293  glyphResults.lStructSize = sizeof(glyphResults);
2294  glyphResults.lpGlyphs = glyphIndices;
2295  glyphResults.nGlyphs = 2;
2296  if (GetCharacterPlacementW(pGDIContextData->hDC, (LPCWSTR)utf16, utf16Len, 0, &glyphResults, 0) != 0)
2297  {
2298  GLYPHMETRICS metrics;
2299  DWORD bitmapBufferSize = GetGlyphOutlineW(pGDIContextData->hDC, glyphIndices[0], GGO_NATIVE | GGO_GLYPH_INDEX, &metrics, 0, NULL, &transform);
2300  if (bitmapBufferSize != GDI_ERROR)
2301  {
2302  pGlyphMetrics->width = metrics.gmBlackBoxX;
2303  pGlyphMetrics->height = metrics.gmBlackBoxY;
2304  pGlyphMetrics->originX = metrics.gmptGlyphOrigin.x;
2305  pGlyphMetrics->originY = metrics.gmptGlyphOrigin.y;
2306  pGlyphMetrics->advanceX = metrics.gmCellIncX;
2307  pGlyphMetrics->advanceY = metrics.gmCellIncY;
2308 
2309  return true;
2310  }
2311  }
2312 
2313  return false;
2314 }
2315 
2316 bool dr2d_measure_string_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut)
2317 {
2318  assert(pFont != NULL);
2319 
2320  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
2321  if (pGDIFontData == NULL) {
2322  return false;
2323  }
2324 
2325  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext);
2326  if (pGDIContextData == NULL) {
2327  return false;
2328  }
2329 
2330 
2331  SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2332 
2333  unsigned int textWLength;
2334  wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, textSizeInBytes, &textWLength);
2335  if (textW != NULL)
2336  {
2337  SIZE sizeWin32;
2338  if (GetTextExtentPoint32W(pGDIContextData->hDC, textW, textWLength, &sizeWin32))
2339  {
2340  if (pWidthOut != NULL) {
2341  *pWidthOut = (float)sizeWin32.cx;
2342  }
2343  if (pHeightOut != NULL) {
2344  *pHeightOut = (float)sizeWin32.cy;
2345  }
2346 
2347  return true;
2348  }
2349  }
2350 
2351  return false;
2352 }
2353 
2354 bool dr2d_get_text_cursor_position_from_point_gdi(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut)
2355 {
2356  bool successful = false;
2357 
2358  assert(pFont != NULL);
2359 
2360  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
2361  if (pGDIFontData == NULL) {
2362  return false;
2363  }
2364 
2365  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext);
2366  if (pGDIContextData == NULL) {
2367  return false;
2368  }
2369 
2370 
2371  SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2372 
2373 
2374  GCP_RESULTSW results;
2375  ZeroMemory(&results, sizeof(results));
2376  results.lStructSize = sizeof(results);
2377  results.nGlyphs = (UINT)textSizeInBytes;
2378 
2379  unsigned int textWLength;
2380  wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, textSizeInBytes, &textWLength);
2381  if (textW != NULL)
2382  {
2383  if (results.nGlyphs > pGDIContextData->glyphCacheSize) {
2384  free(pGDIContextData->pGlyphCache);
2385  pGDIContextData->pGlyphCache = (int*)malloc(sizeof(int) * results.nGlyphs);
2386  pGDIContextData->glyphCacheSize = results.nGlyphs;
2387  }
2388 
2389  results.lpCaretPos = pGDIContextData->pGlyphCache;
2390  if (results.lpCaretPos != NULL)
2391  {
2392  if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, (int)maxWidth, &results, GCP_MAXEXTENT | GCP_USEKERNING) != 0)
2393  {
2394  float textCursorPosX = 0;
2395  unsigned int iChar;
2396  for (iChar = 0; iChar < results.nGlyphs; ++iChar)
2397  {
2398  float charBoundsLeft = charBoundsLeft = (float)results.lpCaretPos[iChar];
2399  float charBoundsRight = 0;
2400  if (iChar < results.nGlyphs - 1) {
2401  charBoundsRight = (float)results.lpCaretPos[iChar + 1];
2402  } else {
2403  charBoundsRight = maxWidth;
2404  }
2405 
2406  if (inputPosX >= charBoundsLeft && inputPosX <= charBoundsRight)
2407  {
2408  // The input position is somewhere on top of this character. If it's positioned on the left side of the character, set the output
2409  // value to the character at iChar. Otherwise it should be set to the character at iChar + 1.
2410  float charBoundsRightHalf = charBoundsLeft + ceilf(((charBoundsRight - charBoundsLeft) / 2.0f));
2411  if (inputPosX <= charBoundsRightHalf) {
2412  break;
2413  } else {
2414  textCursorPosX = charBoundsRight;
2415  iChar += 1;
2416  break;
2417  }
2418  }
2419 
2420  textCursorPosX = charBoundsRight;
2421  }
2422 
2423  if (pTextCursorPosXOut) {
2424  *pTextCursorPosXOut = textCursorPosX;
2425  }
2426  if (pCharacterIndexOut) {
2427  *pCharacterIndexOut = iChar;
2428  }
2429 
2430  successful = true;
2431  }
2432  }
2433  }
2434 
2435  return successful;
2436 }
2437 
2438 bool dr2d_get_text_cursor_position_from_char_gdi(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut)
2439 {
2440  bool successful = false;
2441 
2442  assert(pFont != NULL);
2443 
2444  gdi_font_data* pGDIFontData = (gdi_font_data*)dr2d_get_font_extra_data(pFont);
2445  if (pGDIFontData == NULL) {
2446  return false;
2447  }
2448 
2449  gdi_context_data* pGDIContextData = (gdi_context_data*)dr2d_get_context_extra_data(pFont->pContext);
2450  if (pGDIContextData == NULL) {
2451  return false;
2452  }
2453 
2454 
2455  SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2456 
2457 
2458  GCP_RESULTSW results;
2459  ZeroMemory(&results, sizeof(results));
2460  results.lStructSize = sizeof(results);
2461  results.nGlyphs = (DWORD)(characterIndex + 1);
2462 
2463  unsigned int textWLength;
2464  wchar_t* textW = dr2d_to_wchar_gdi(pFont->pContext, text, (int)results.nGlyphs, &textWLength);
2465  if (textW != NULL)
2466  {
2467  if (results.nGlyphs > pGDIContextData->glyphCacheSize) {
2468  free(pGDIContextData->pGlyphCache);
2469  pGDIContextData->pGlyphCache = (int*)malloc(sizeof(int) * results.nGlyphs);
2470  pGDIContextData->glyphCacheSize = results.nGlyphs;
2471  }
2472 
2473  results.lpCaretPos = pGDIContextData->pGlyphCache;
2474  if (results.lpCaretPos != NULL)
2475  {
2476  if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, 0, &results, GCP_USEKERNING) != 0)
2477  {
2478  if (pTextCursorPosXOut) {
2479  *pTextCursorPosXOut = (float)results.lpCaretPos[characterIndex];
2480  }
2481 
2482  successful = true;
2483  }
2484  }
2485  }
2486 
2487  return successful;
2488 }
2489 
2490 
2491 wchar_t* dr2d_to_wchar_gdi(dr2d_context* pContext, const char* text, size_t textSizeInBytes, unsigned int* characterCountOut)
2492 {
2493  if (pContext == NULL || text == NULL) {
2494  return NULL;
2495  }
2496 
2497  gdi_context_data* pGDIData = (gdi_context_data*)dr2d_get_context_extra_data(pContext);
2498  if (pGDIData == NULL) {
2499  return NULL;
2500  }
2501 
2502  int wcharCount = 0;
2503 
2504 
2505  // We first try to copy the string into the already-allocated buffer. If it fails we fall back to the slow path which requires
2506  // two conversions.
2507  if (pGDIData->wcharBuffer == NULL) {
2508  goto fallback;
2509  }
2510 
2511  wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, pGDIData->wcharBuffer, pGDIData->wcharBufferLength);
2512  if (wcharCount != 0) {
2513  if (characterCountOut) *characterCountOut = wcharCount;
2514  return pGDIData->wcharBuffer;
2515  }
2516 
2517 
2518 
2519 fallback:;
2520  wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, NULL, 0);
2521  if (wcharCount == 0) {
2522  return NULL;
2523  }
2524 
2525  if (pGDIData->wcharBufferLength < (unsigned int)wcharCount + 1) {
2526  free(pGDIData->wcharBuffer);
2527  pGDIData->wcharBuffer = (wchar_t*)malloc(sizeof(wchar_t) * (wcharCount + 1));
2528  pGDIData->wcharBufferLength = wcharCount + 1;
2529  }
2530 
2531  wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (int)textSizeInBytes, pGDIData->wcharBuffer, pGDIData->wcharBufferLength);
2532  if (wcharCount == 0) {
2533  return NULL;
2534  }
2535 
2536 
2537  if (characterCountOut != NULL) {
2538  *characterCountOut = wcharCount;
2539  }
2540 
2541  return pGDIData->wcharBuffer;
2542 }
2543 
2544 #endif // GDI
2545 
2546 
2548 //
2549 // CAIRO 2D API
2550 //
2552 #ifndef DR2D_NO_CAIRO
2553 
2554 typedef struct
2555 {
2556  cairo_surface_t* pCairoSurface;
2557  cairo_t* pCairoContext;
2558 
2559  float clipRectLeft;
2560  float clipRectTop;
2561  float clipRectRight;
2562  float clipRectBottom;
2563 
2564 } cairo_surface_data;
2565 
2566 typedef struct
2567 {
2568  cairo_font_face_t* pFace;
2569  cairo_scaled_font_t* pFont;
2570 
2571  // The font metrics. This is initialized when the font is created.
2572  dr2d_font_metrics metrics;
2573 
2574 } cairo_font_data;
2575 
2576 typedef struct
2577 {
2579  cairo_surface_t* pCairoSurface;
2580 
2582  unsigned char* pData;
2583 
2584 } cairo_image_data;
2585 
2586 bool dr2d_on_create_context_cairo(dr2d_context* pContext, const void* pUserData);
2587 void dr2d_on_delete_context_cairo(dr2d_context* pContext);
2588 bool dr2d_on_create_surface_cairo(dr2d_surface* pSurface, float width, float height);
2589 void dr2d_on_delete_surface_cairo(dr2d_surface* pSurface);
2590 bool dr2d_on_create_font_cairo(dr2d_font* pFont);
2591 void dr2d_on_delete_font_cairo(dr2d_font* pFont);
2592 bool dr2d_on_create_image_cairo(dr2d_image* pImage, unsigned int stride, const void* pData);
2593 void dr2d_on_delete_image_cairo(dr2d_image* pImage);
2594 
2595 void dr2d_begin_draw_cairo(dr2d_surface* pSurface);
2596 void dr2d_end_draw_cairo(dr2d_surface* pSurface);
2597 void dr2d_clear_cairo(dr2d_surface* pSurface, dr2d_color color);
2598 void dr2d_draw_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color);
2599 void dr2d_draw_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth);
2600 void dr2d_draw_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor);
2601 void dr2d_draw_round_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius);
2602 void dr2d_draw_round_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth);
2603 void dr2d_draw_round_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor);
2604 void dr2d_draw_text_cairo(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor);
2605 void dr2d_draw_image_cairo(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs);
2606 void dr2d_set_clip_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom);
2607 void dr2d_get_clip_cairo(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut);
2608 
2609 dr2d_image_format dr2d_get_optimal_image_format_cairo(dr2d_context* pContext);
2610 void* dr2d_map_image_data_cairo(dr2d_image* pImage, unsigned accessFlags);
2611 void dr2d_unmap_image_data_cairo(dr2d_image* pImage);
2612 
2613 bool dr2d_get_font_metrics_cairo(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut);
2614 bool dr2d_get_glyph_metrics_cairo(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics);
2615 bool dr2d_measure_string_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut);
2616 bool dr2d_get_text_cursor_position_from_point_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut);
2617 bool dr2d_get_text_cursor_position_from_char_cairo(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut);
2618 
2619 
2621 {
2622  dr2d_drawing_callbacks callbacks;
2623  callbacks.on_create_context = dr2d_on_create_context_cairo;
2624  callbacks.on_delete_context = dr2d_on_delete_context_cairo;
2625  callbacks.on_create_surface = dr2d_on_create_surface_cairo;
2626  callbacks.on_delete_surface = dr2d_on_delete_surface_cairo;
2627  callbacks.on_create_font = dr2d_on_create_font_cairo;
2628  callbacks.on_delete_font = dr2d_on_delete_font_cairo;
2629  callbacks.on_create_image = dr2d_on_create_image_cairo;
2630  callbacks.on_delete_image = dr2d_on_delete_image_cairo;
2631 
2632  callbacks.begin_draw = dr2d_begin_draw_cairo;
2633  callbacks.end_draw = dr2d_end_draw_cairo;
2634  callbacks.clear = dr2d_clear_cairo;
2635  callbacks.draw_rect = dr2d_draw_rect_cairo;
2636  callbacks.draw_rect_outline = dr2d_draw_rect_outline_cairo;
2637  callbacks.draw_rect_with_outline = dr2d_draw_rect_with_outline_cairo;
2638  callbacks.draw_round_rect = dr2d_draw_round_rect_cairo;
2639  callbacks.draw_round_rect_outline = dr2d_draw_round_rect_outline_cairo;
2640  callbacks.draw_round_rect_with_outline = dr2d_draw_round_rect_with_outline_cairo;
2641  callbacks.draw_text = dr2d_draw_text_cairo;
2642  callbacks.draw_image = dr2d_draw_image_cairo;
2643  callbacks.set_clip = dr2d_set_clip_cairo;
2644  callbacks.get_clip = dr2d_get_clip_cairo;
2645 
2646  callbacks.map_image_data = dr2d_map_image_data_cairo;
2647  callbacks.unmap_image_data = dr2d_unmap_image_data_cairo;
2648 
2649  callbacks.get_font_metrics = dr2d_get_font_metrics_cairo;
2650  callbacks.get_glyph_metrics = dr2d_get_glyph_metrics_cairo;
2651  callbacks.measure_string = dr2d_measure_string_cairo;
2652  callbacks.get_text_cursor_position_from_point = dr2d_get_text_cursor_position_from_point_cairo;
2653  callbacks.get_text_cursor_position_from_char = dr2d_get_text_cursor_position_from_char_cairo;
2654 
2655 
2656  return dr2d_create_context(callbacks, 0, sizeof(cairo_surface_data), sizeof(cairo_font_data), sizeof(cairo_image_data), NULL);
2657 }
2658 
2659 dr2d_surface* dr2d_create_surface_cairo(dr2d_context* pContext, cairo_t* cr)
2660 {
2661  if (cr == NULL) {
2662  return NULL;
2663  }
2664 
2665  dr2d_surface* pSurface = dr2d_create_surface(pContext, 0, 0);
2666  if (pSurface != NULL) {
2667  cairo_surface_data* pCairoData = (cairo_surface_data*)dr2d_get_surface_extra_data(pSurface);
2668  if (pCairoData != NULL) {
2669  pCairoData->pCairoContext = cairo_reference(cr);
2670  pCairoData->pCairoSurface = cairo_surface_reference(cairo_get_target(cr));
2671  }
2672  }
2673 
2674  return pSurface;
2675 }
2676 
2677 cairo_surface_t* dr2d_get_cairo_surface_t(dr2d_surface* pSurface)
2678 {
2679  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2680  if (pCairoData != NULL) {
2681  return pCairoData->pCairoSurface;
2682  }
2683 
2684  return NULL;
2685 }
2686 
2687 cairo_t* dr2d_get_cairo_t(dr2d_surface* pSurface)
2688 {
2689  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2690  if (pCairoData != NULL) {
2691  return pCairoData->pCairoContext;
2692  }
2693 
2694  return NULL;
2695 }
2696 
2697 
2698 bool dr2d_on_create_context_cairo(dr2d_context* pContext, const void* pUserData)
2699 {
2700  assert(pContext != NULL);
2701  (void)pContext;
2702  (void)pUserData;
2703 
2704  return true;
2705 }
2706 
2707 void dr2d_on_delete_context_cairo(dr2d_context* pContext)
2708 {
2709  assert(pContext != NULL);
2710  (void)pContext;
2711 }
2712 
2713 bool dr2d_on_create_surface_cairo(dr2d_surface* pSurface, float width, float height)
2714 {
2715  assert(pSurface != NULL);
2716 
2717  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2718  if (pCairoData == NULL) {
2719  return false;
2720  }
2721 
2722  if (width != 0 && height != 0) {
2723  pCairoData->pCairoSurface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, (int)width, (int)height);
2724  if (pCairoData->pCairoSurface == NULL) {
2725  return false;
2726  }
2727 
2728  pCairoData->pCairoContext = cairo_create(pCairoData->pCairoSurface);
2729  if (pCairoData->pCairoContext == NULL) {
2730  cairo_surface_destroy(pCairoData->pCairoSurface);
2731  return false;
2732  }
2733  } else {
2734  pCairoData->pCairoSurface = NULL;
2735  pCairoData->pCairoContext = NULL;
2736  }
2737 
2738 
2739  return true;
2740 }
2741 
2742 void dr2d_on_delete_surface_cairo(dr2d_surface* pSurface)
2743 {
2744  assert(pSurface != NULL);
2745 
2746  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2747  if (pCairoData != NULL)
2748  {
2749  cairo_destroy(pCairoData->pCairoContext);
2750  cairo_surface_destroy(pCairoData->pCairoSurface);
2751  }
2752 }
2753 
2754 bool dr2d_on_create_font_cairo(dr2d_font* pFont)
2755 {
2756  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
2757  if (pCairoFont == NULL) {
2758  return false;
2759  }
2760 
2761  cairo_font_slant_t cairoSlant = CAIRO_FONT_SLANT_NORMAL;
2762  if (pFont->slant == dr2d_font_slant_italic) {
2763  cairoSlant = CAIRO_FONT_SLANT_ITALIC;
2764  } else if (pFont->slant == dr2d_font_slant_oblique) {
2765  cairoSlant = CAIRO_FONT_SLANT_OBLIQUE;
2766  }
2767 
2768  cairo_font_weight_t cairoWeight = CAIRO_FONT_WEIGHT_NORMAL;
2770  cairoWeight = CAIRO_FONT_WEIGHT_BOLD;
2771  }
2772 
2773  pCairoFont->pFace = cairo_toy_font_face_create(pFont->family, cairoSlant, cairoWeight);
2774  if (pCairoFont->pFace == NULL) {
2775  return false;
2776  }
2777 
2778  cairo_matrix_t fontMatrix;
2779  cairo_matrix_init_scale(&fontMatrix, (double)pFont->size, (double)pFont->size);
2780  cairo_matrix_rotate(&fontMatrix, pFont->rotation * (3.14159265 / 180.0));
2781 
2782  cairo_matrix_t ctm;
2783  cairo_matrix_init_identity(&ctm);
2784 
2785  cairo_font_options_t* options = cairo_font_options_create();
2786  cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL); // TODO: Control this with option flags in pFont.
2787 
2788  pCairoFont->pFont = cairo_scaled_font_create(pCairoFont->pFace, &fontMatrix, &ctm, options);
2789  if (pCairoFont->pFont == NULL) {
2790  cairo_font_face_destroy(pCairoFont->pFace);
2791  return false;
2792  }
2793 
2794 
2795  // Metrics.
2796  cairo_font_extents_t fontMetrics;
2797  cairo_scaled_font_extents(pCairoFont->pFont, &fontMetrics);
2798 
2799  pCairoFont->metrics.ascent = fontMetrics.ascent;
2800  pCairoFont->metrics.descent = fontMetrics.descent;
2801  //pCairoFont->metrics.lineHeight = fontMetrics.height;
2802  pCairoFont->metrics.lineHeight = fontMetrics.ascent + fontMetrics.descent;
2803 
2804  // The width of a space needs to be retrieved via glyph metrics.
2805  const char space[] = " ";
2806  cairo_text_extents_t spaceMetrics;
2807  cairo_scaled_font_text_extents(pCairoFont->pFont, space, &spaceMetrics);
2808  pCairoFont->metrics.spaceWidth = spaceMetrics.x_advance;
2809 
2810  return true;
2811 }
2812 
2813 void dr2d_on_delete_font_cairo(dr2d_font* pFont)
2814 {
2815  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
2816  if (pCairoFont == NULL) {
2817  return;
2818  }
2819 
2820  cairo_scaled_font_destroy(pCairoFont->pFont);
2821  cairo_font_face_destroy(pCairoFont->pFace);
2822 }
2823 
2824 bool dr2d_on_create_image_cairo(dr2d_image* pImage, unsigned int stride, const void* pData)
2825 {
2826  cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage);
2827  if (pCairoImage == NULL) {
2828  return false;
2829  }
2830 
2831  size_t dataSize = pImage->height * pImage->width * 4;
2832  pCairoImage->pData = malloc(dataSize);
2833  if (pCairoImage->pData == NULL) {
2834  return false;
2835  }
2836 
2837  if (pData != NULL)
2838  {
2839  for (unsigned int iRow = 0; iRow < pImage->height; ++iRow)
2840  {
2841  const unsigned int iRowSrc = iRow; //pImage->height - (iRow + 1);
2842  const unsigned int iRowDst = iRow;
2843 
2844  for (unsigned int iCol = 0; iCol < pImage->width; ++iCol)
2845  {
2846  unsigned int srcTexel = ((const unsigned int*)(pData ))[ (iRowSrc * (stride/4)) + iCol];
2847  unsigned int* dstTexel = (( unsigned int*)(pCairoImage->pData)) + (iRowDst * pImage->width) + iCol;
2848 
2849  unsigned int srcTexelA = (srcTexel & 0xFF000000) >> 24;
2850  unsigned int srcTexelB = (srcTexel & 0x00FF0000) >> 16;
2851  unsigned int srcTexelG = (srcTexel & 0x0000FF00) >> 8;
2852  unsigned int srcTexelR = (srcTexel & 0x000000FF) >> 0;
2853 
2854  srcTexelB = (unsigned int)(srcTexelB * (srcTexelA / 255.0f));
2855  srcTexelG = (unsigned int)(srcTexelG * (srcTexelA / 255.0f));
2856  srcTexelR = (unsigned int)(srcTexelR * (srcTexelA / 255.0f));
2857 
2858  *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
2859  }
2860  }
2861  }
2862 
2863  pCairoImage->pCairoSurface = cairo_image_surface_create_for_data(pCairoImage->pData, CAIRO_FORMAT_ARGB32, (int)pImage->width, (int)pImage->height, (int)pImage->width*4);
2864  if (pCairoImage->pCairoSurface == NULL) {
2865  free(pCairoImage->pData);
2866  return false;
2867  }
2868 
2869  return true;
2870 }
2871 
2872 void dr2d_on_delete_image_cairo(dr2d_image* pImage)
2873 {
2874  cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage);
2875  if (pCairoImage == NULL) {
2876  return;
2877  }
2878 
2879  cairo_surface_destroy(pCairoImage->pCairoSurface);
2880  free(pCairoImage->pData);
2881 }
2882 
2883 
2884 void dr2d_begin_draw_cairo(dr2d_surface* pSurface)
2885 {
2886  assert(pSurface != NULL);
2887 
2888  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2889  if (pCairoData == NULL) {
2890  return;
2891  }
2892 
2893  cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_NONE);
2894 }
2895 
2896 void dr2d_end_draw_cairo(dr2d_surface* pSurface)
2897 {
2898  assert(pSurface != NULL);
2899 
2900  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2901  if (pCairoData == NULL) {
2902  return;
2903  }
2904 
2905  cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_DEFAULT);
2906 }
2907 
2908 void dr2d_clear_cairo(dr2d_surface* pSurface, dr2d_color color)
2909 {
2910  // TODO: I forget... is this supposed to ignore the current clip? If so, this needs to be changed so that
2911  // the clip is reset first then restored afterwards.
2912  dr2d_draw_rect_cairo(pSurface, 0, 0, dr2d_get_surface_width(pSurface), dr2d_get_surface_height(pSurface), color);
2913 }
2914 
2915 void dr2d_draw_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color)
2916 {
2917  assert(pSurface != NULL);
2918 
2919  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2920  if (pCairoData != NULL)
2921  {
2922  cairo_set_source_rgba(pCairoData->pCairoContext, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
2923  cairo_rectangle(pCairoData->pCairoContext, left, top, (right - left), (bottom - top));
2924  cairo_fill(pCairoData->pCairoContext);
2925  }
2926 }
2927 
2928 void dr2d_draw_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth)
2929 {
2930  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
2931  if (pCairoData == NULL) {
2932  return;
2933  }
2934 
2935  cairo_t* cr = pCairoData->pCairoContext;
2936 
2937  cairo_set_source_rgba(cr, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
2938 
2939  // We do this as 4 separate rectangles.
2940  cairo_rectangle(cr, left, top, outlineWidth, bottom - top); // Left
2941  cairo_fill(cr);
2942  cairo_rectangle(cr, right - outlineWidth, top, outlineWidth, bottom - top); // Right
2943  cairo_fill(cr);
2944  cairo_rectangle(cr, left + outlineWidth, top, right - left - (outlineWidth*2), outlineWidth); // Top
2945  cairo_fill(cr);
2946  cairo_rectangle(cr, left + outlineWidth, bottom - outlineWidth, right - left - (outlineWidth*2), outlineWidth); // Bottom
2947  cairo_fill(cr);
2948 }
2949 
2950 void dr2d_draw_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor)
2951 {
2952  dr2d_draw_rect_cairo(pSurface, left + outlineWidth, top + outlineWidth, right - outlineWidth, bottom - outlineWidth, color);
2953  dr2d_draw_rect_outline_cairo(pSurface, left, top, right, bottom, outlineColor, outlineWidth);
2954 }
2955 
2956 void dr2d_draw_round_rect_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius)
2957 {
2958  // FIXME: This does not draw rounded corners.
2959  (void)radius;
2960 
2961  dr2d_draw_rect_cairo(pSurface, left, top, right, bottom, color);
2962 }
2963 
2964 void dr2d_draw_round_rect_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth)
2965 {
2966  // FIXME: This does not draw rounded corners.
2967  (void)radius;
2968 
2969  dr2d_draw_rect_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth);
2970 }
2971 
2972 void dr2d_draw_round_rect_with_outline_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor)
2973 {
2974  // FIXME: This does not draw rounded corners.
2975  (void)radius;
2976 
2977  dr2d_draw_rect_with_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth, outlineColor);
2978 }
2979 
2980 void dr2d_draw_text_cairo(dr2d_surface* pSurface, dr2d_font* pFont, const char* text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor)
2981 {
2982  cairo_surface_data* pCairoSurface = dr2d_get_surface_extra_data(pSurface);
2983  if (pCairoSurface == NULL) {
2984  return;
2985  }
2986 
2987  cairo_t* cr = pCairoSurface->pCairoContext;
2988 
2989 
2990  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
2991  if (pCairoFont == NULL) {
2992  return;
2993  }
2994 
2995  // Cairo expends null terminated strings, however the input string is not guaranteed to be null terminated.
2996  char* textNT;
2997  if (textSizeInBytes != (size_t)-1) {
2998  textNT = malloc(textSizeInBytes + 1);
2999  memcpy(textNT, text, textSizeInBytes);
3000  textNT[textSizeInBytes] = '\0';
3001  } else {
3002  textNT = (char*)text;
3003  }
3004 
3005 
3006  cairo_set_scaled_font(cr, pCairoFont->pFont);
3007 
3008 
3009 
3010  // Background.
3011  cairo_text_extents_t textMetrics;
3012  cairo_text_extents(cr, textNT, &textMetrics);
3013  cairo_set_source_rgba(cr, backgroundColor.r / 255.0, backgroundColor.g / 255.0, backgroundColor.b / 255.0, backgroundColor.a / 255.0);
3014  cairo_rectangle(cr, posX, posY, textMetrics.x_advance, pCairoFont->metrics.lineHeight);
3015  cairo_fill(cr);
3016 
3017 
3018  // Text.
3019  cairo_move_to(cr, posX, posY + pCairoFont->metrics.ascent);
3020  cairo_set_source_rgba(cr, color.r / 255.0, color.g / 255.0, color.b / 255.0, color.a / 255.0);
3021  cairo_show_text(cr, textNT);
3022 
3023 
3024  if (textNT != text) {
3025  free(textNT);
3026  }
3027 }
3028 
3029 void dr2d_draw_image_cairo(dr2d_surface* pSurface, dr2d_image* pImage, dr2d_draw_image_args* pArgs)
3030 {
3031  cairo_surface_data* pCairoSurface = dr2d_get_surface_extra_data(pSurface);
3032  if (pCairoSurface == NULL) {
3033  return;
3034  }
3035 
3036  cairo_image_data* pCairoImage = dr2d_get_image_extra_data(pImage);
3037  if (pCairoImage == NULL) {
3038  return;
3039  }
3040 
3041  cairo_t* cr = pCairoSurface->pCairoContext;
3042 
3043  cairo_save(cr);
3044  cairo_translate(cr, pArgs->dstX, pArgs->dstY);
3045 
3046  // Background.
3047  if ((pArgs->options & DR2D_IMAGE_DRAW_BACKGROUND) != 0)
3048  {
3049  cairo_set_source_rgba(cr, pArgs->backgroundColor.r / 255.0, pArgs->backgroundColor.g / 255.0, pArgs->backgroundColor.b / 255.0, pArgs->backgroundColor.a / 255.0);
3050  cairo_rectangle(cr, 0, 0, pArgs->dstWidth, pArgs->dstHeight);
3051  cairo_fill(cr);
3052  }
3053 
3054  if (pArgs->foregroundTint.r == 255 && pArgs->foregroundTint.g == 255 && pArgs->foregroundTint.b == 255 && pArgs->foregroundTint.a == 255) {
3055  cairo_scale(cr, pArgs->dstWidth / pArgs->srcWidth, pArgs->dstHeight / pArgs->srcHeight);
3056  cairo_set_source_surface(cr, pCairoImage->pCairoSurface, pArgs->srcX, pArgs->srcY);
3057  cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
3058  cairo_paint(cr);
3059  } else {
3060  // Slower path. The image needs to be tinted. We create a temporary image for this.
3061  // NOTE: This is incorrect. It's just a temporary solution until I figure out a better way.
3062  cairo_surface_t* pTempImageSurface = cairo_surface_create_similar_image(pCairoImage->pCairoSurface, CAIRO_FORMAT_ARGB32,
3063  cairo_image_surface_get_width(pCairoImage->pCairoSurface), cairo_image_surface_get_height(pCairoImage->pCairoSurface));
3064  if (pTempImageSurface != NULL) {
3065  cairo_t* cr2 = cairo_create(pTempImageSurface);
3066 
3067  cairo_set_operator(cr2, CAIRO_OPERATOR_SOURCE);
3068  cairo_set_source_surface(cr2, pCairoImage->pCairoSurface, 0, 0);
3069  cairo_pattern_set_filter(cairo_get_source(cr2), CAIRO_FILTER_NEAREST);
3070  cairo_paint(cr2);
3071 
3072  // Tint.
3073  cairo_set_operator(cr2, CAIRO_OPERATOR_ATOP);
3074  cairo_set_source_rgba(cr2, pArgs->foregroundTint.r / 255.0, pArgs->foregroundTint.g / 255.0, pArgs->foregroundTint.b / 255.0, 1);
3075  cairo_rectangle(cr2, 0, 0, pArgs->dstWidth, pArgs->dstHeight);
3076  cairo_fill(cr2);
3077 
3078  /*cairo_set_operator(cr2, CAIRO_OPERATOR_MULTIPLY);
3079  cairo_set_source_surface(cr2, pCairoImage->pCairoSurface, 0, 0);
3080  cairo_pattern_set_filter(cairo_get_source(cr2), CAIRO_FILTER_NEAREST);
3081  cairo_paint(cr2);*/
3082 
3083  // Draw the temporary surface onto the main surface.
3084  cairo_scale(cr, pArgs->dstWidth / pArgs->srcWidth, pArgs->dstHeight / pArgs->srcHeight);
3085  cairo_set_source_surface(cr, pTempImageSurface, pArgs->srcX, pArgs->srcY);
3086  cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
3087  //cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
3088  cairo_paint(cr);
3089 
3090  cairo_destroy(cr2);
3091  cairo_surface_destroy(pTempImageSurface);
3092  }
3093  }
3094 
3095  cairo_restore(cr);
3096 }
3097 
3098 void dr2d_set_clip_cairo(dr2d_surface* pSurface, float left, float top, float right, float bottom)
3099 {
3100  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
3101  if (pCairoData == NULL) {
3102  return;
3103  }
3104 
3105  pCairoData->clipRectLeft = left;
3106  pCairoData->clipRectTop = top;
3107  pCairoData->clipRectRight = right;
3108  pCairoData->clipRectBottom = bottom;
3109 
3110  cairo_reset_clip(pCairoData->pCairoContext);
3111  cairo_rectangle(pCairoData->pCairoContext, left, top, right - left, bottom - top);
3112  cairo_clip(pCairoData->pCairoContext);
3113 }
3114 
3115 void dr2d_get_clip_cairo(dr2d_surface* pSurface, float* pLeftOut, float* pTopOut, float* pRightOut, float* pBottomOut)
3116 {
3117  (void)pSurface;
3118  (void)pLeftOut;
3119  (void)pTopOut;
3120  (void)pRightOut;
3121  (void)pBottomOut;
3122 
3123  cairo_surface_data* pCairoData = dr2d_get_surface_extra_data(pSurface);
3124  if (pCairoData == NULL) {
3125  return;
3126  }
3127 
3128  if (pLeftOut) { *pLeftOut = pCairoData->clipRectLeft; }
3129  if (pTopOut) { *pTopOut = pCairoData->clipRectTop; }
3130  if (pRightOut) { *pRightOut = pCairoData->clipRectRight; }
3131  if (pBottomOut) { *pBottomOut = pCairoData->clipRectBottom; }
3132 }
3133 
3134 
3135 dr2d_image_format dr2d_get_optimal_image_format_cairo(dr2d_context* pContext)
3136 {
3137  (void)pContext;
3138  return dr2d_image_format_argb8;
3139 }
3140 
3141 void* dr2d_map_image_data_cairo(dr2d_image* pImage, unsigned accessFlags)
3142 {
3143  (void)pImage;
3144  (void)accessFlags;
3145  return NULL;
3146 }
3147 
3148 void dr2d_unmap_image_data_cairo(dr2d_image* pImage)
3149 {
3150  (void)pImage;
3151 }
3152 
3153 
3154 bool dr2d_get_font_metrics_cairo(dr2d_font* pFont, dr2d_font_metrics* pMetricsOut)
3155 {
3156  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
3157  if (pCairoFont == NULL) {
3158  return false;
3159  }
3160 
3161  if (pMetricsOut) {
3162  *pMetricsOut = pCairoFont->metrics;
3163  }
3164 
3165  return true;
3166 }
3167 
3168 static size_t dr2d__utf32_to_utf8(unsigned int utf32, char* utf8, size_t utf8Size)
3169 {
3170  // NOTE: This function is untested.
3171 
3172  size_t utf8ByteCount = 0;
3173  if (utf32 < 0x80) {
3174  utf8ByteCount = 1;
3175  } else if (utf32 < 0x800) {
3176  utf8ByteCount = 2;
3177  } else if (utf32 < 0x10000) {
3178  utf8ByteCount = 3;
3179  } else if (utf32 < 0x110000) {
3180  utf8ByteCount = 4;
3181  }
3182 
3183  if (utf8ByteCount > utf8Size) {
3184  if (utf8 != NULL && utf8Size > 0) {
3185  utf8[0] = '\0';
3186  }
3187  return 0;
3188  }
3189 
3190  utf8 += utf8ByteCount;
3191  if (utf8ByteCount < utf8Size) {
3192  utf8[0] = '\0'; // Null terminate.
3193  }
3194 
3195  const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
3196  switch (utf8ByteCount)
3197  {
3198  case 4: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6;
3199  case 3: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6;
3200  case 2: *--utf8 = (char)((utf32 | 0x80) & 0xBF); utf32 >>= 6;
3201  case 1: *--utf8 = (char)(utf32 | firstByteMark[utf8ByteCount]);
3202  default: break;
3203  }
3204 
3205  return utf8ByteCount;
3206 }
3207 
3208 bool dr2d_get_glyph_metrics_cairo(dr2d_font* pFont, unsigned int utf32, dr2d_glyph_metrics* pGlyphMetrics)
3209 {
3210  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
3211  if (pCairoFont == NULL) {
3212  return false;
3213  }
3214 
3215  // The UTF-32 code point needs to be converted to a UTF-8 character.
3216  char utf8[16];
3217  size_t utf8len = dr2d__utf32_to_utf8(utf32, utf8, sizeof(utf8)); // This will null-terminate.
3218  if (utf8len == 0) {
3219  return false; // Error converting UTF-32 to UTF-8.
3220  }
3221 
3222 
3223  cairo_text_extents_t glyphExtents;
3224  cairo_scaled_font_text_extents(pCairoFont->pFont, utf8, &glyphExtents);
3225 
3226  if (pGlyphMetrics)
3227  {
3228  pGlyphMetrics->width = glyphExtents.width;
3229  pGlyphMetrics->height = glyphExtents.height;
3230  pGlyphMetrics->originX = glyphExtents.x_bearing;
3231  pGlyphMetrics->originY = glyphExtents.y_bearing;
3232  pGlyphMetrics->advanceX = glyphExtents.x_advance;
3233  pGlyphMetrics->advanceY = glyphExtents.y_advance;
3234  }
3235 
3236  return true;
3237 }
3238 
3239 bool dr2d_measure_string_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float* pWidthOut, float* pHeightOut)
3240 {
3241  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
3242  if (pCairoFont == NULL) {
3243  return false;
3244  }
3245 
3246 
3247  // Cairo expends null terminated strings, however the input string is not guaranteed to be null terminated.
3248  char* textNT;
3249  if (textSizeInBytes != (size_t)-1) {
3250  textNT = malloc(textSizeInBytes + 1);
3251  if (textNT == NULL) {
3252  return false;
3253  }
3254  memcpy(textNT, text, textSizeInBytes);
3255  textNT[textSizeInBytes] = '\0';
3256  } else {
3257  textNT = (char*)text;
3258  }
3259 
3260 
3261  cairo_text_extents_t textMetrics;
3262  cairo_scaled_font_text_extents(pCairoFont->pFont, textNT, &textMetrics);
3263 
3264  if (pWidthOut) {
3265  *pWidthOut = textMetrics.x_advance;
3266  }
3267  if (pHeightOut) {
3268  //*pHeightOut = textMetrics.height;
3269  *pHeightOut = pCairoFont->metrics.ascent + pCairoFont->metrics.descent;
3270  }
3271 
3272 
3273  if (textNT != text) {
3274  free(textNT);
3275  }
3276 
3277  return true;
3278 }
3279 
3280 bool dr2d_get_text_cursor_position_from_point_cairo(dr2d_font* pFont, const char* text, size_t textSizeInBytes, float maxWidth, float inputPosX, float* pTextCursorPosXOut, size_t* pCharacterIndexOut)
3281 {
3282  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
3283  if (pCairoFont == NULL) {
3284  return false;
3285  }
3286 
3287  cairo_glyph_t* pGlyphs = NULL;
3288  int glyphCount = 0;
3289  cairo_status_t result = cairo_scaled_font_text_to_glyphs(pCairoFont->pFont, 0, 0, text, textSizeInBytes, &pGlyphs, &glyphCount, NULL, NULL, NULL);
3290  if (result != CAIRO_STATUS_SUCCESS) {
3291  return false;
3292  }
3293 
3294  float cursorPosX = 0;
3295  int charIndex = 0;
3296 
3297  // We just iterate over each glyph until we find the one sitting under <inputPosX>.
3298  float runningPosX = 0;
3299  for (int iGlyph = 0; iGlyph < glyphCount; ++iGlyph)
3300  {
3301  cairo_text_extents_t glyphMetrics;
3302  cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics);
3303 
3304  float glyphLeft = runningPosX;
3305  float glyphRight = glyphLeft + glyphMetrics.x_advance;
3306 
3307  // Are we sitting on top of inputPosX?
3308  if (inputPosX >= glyphLeft && inputPosX <= glyphRight)
3309  {
3310  float glyphHalf = glyphLeft + ceilf(((glyphRight - glyphLeft) / 2.0f));
3311  if (inputPosX <= glyphHalf) {
3312  cursorPosX = glyphLeft;
3313  charIndex = iGlyph;
3314  } else {
3315  cursorPosX = glyphRight;
3316  charIndex = iGlyph + 1;
3317  }
3318 
3319  break;
3320  }
3321  else
3322  {
3323  // Have we moved past maxWidth?
3324  if (glyphRight > maxWidth)
3325  {
3326  cursorPosX = maxWidth;
3327  charIndex = iGlyph;
3328  break;
3329  }
3330  else
3331  {
3332  runningPosX = glyphRight;
3333 
3334  cursorPosX = runningPosX;
3335  charIndex = iGlyph;
3336  }
3337  }
3338  }
3339 
3340  cairo_glyph_free(pGlyphs);
3341 
3342  if (pTextCursorPosXOut) {
3343  *pTextCursorPosXOut = cursorPosX;
3344  }
3345  if (pCharacterIndexOut) {
3346  *pCharacterIndexOut = charIndex;
3347  }
3348 
3349  return true;
3350 }
3351 
3352 bool dr2d_get_text_cursor_position_from_char_cairo(dr2d_font* pFont, const char* text, size_t characterIndex, float* pTextCursorPosXOut)
3353 {
3354  cairo_font_data* pCairoFont = dr2d_get_font_extra_data(pFont);
3355  if (pCairoFont == NULL) {
3356  return false;
3357  }
3358 
3359  cairo_glyph_t* pGlyphs = NULL;
3360  int glyphCount = 0;
3361  cairo_status_t result = cairo_scaled_font_text_to_glyphs(pCairoFont->pFont, 0, 0, text, -1, &pGlyphs, &glyphCount, NULL, NULL, NULL);
3362  if (result != CAIRO_STATUS_SUCCESS) {
3363  return false;
3364  }
3365 
3366  float cursorPosX = 0;
3367 
3368  // We just iterate over each glyph until we find the one sitting under <inputPosX>.
3369  for (int iGlyph = 0; iGlyph < glyphCount; ++iGlyph)
3370  {
3371  if (iGlyph == (int)characterIndex) {
3372  break;
3373  }
3374 
3375  cairo_text_extents_t glyphMetrics;
3376  cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics);
3377 
3378  cursorPosX += glyphMetrics.x_advance;
3379  }
3380 
3381  cairo_glyph_free(pGlyphs);
3382 
3383  if (pTextCursorPosXOut) {
3384  *pTextCursorPosXOut = cursorPosX;
3385  }
3386 
3387  return true;
3388 }
3389 #endif // Cairo
3390 #endif
3391 
3392 /*
3393 This is free and unencumbered software released into the public domain.
3394 
3395 Anyone is free to copy, modify, publish, use, compile, sell, or
3396 distribute this software, either in source code form or as a compiled
3397 binary, for any purpose, commercial or non-commercial, and by any
3398 means.
3399 
3400 In jurisdictions that recognize copyright laws, the author or authors
3401 of this software dedicate any and all copyright interest in the
3402 software to the public domain. We make this dedication for the benefit
3403 of the public at large and to the detriment of our heirs and
3404 successors. We intend this dedication to be an overt act of
3405 relinquishment in perpetuity of all present and future rights to this
3406 software under copyright law.
3407 
3408 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
3409 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
3410 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
3411 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
3412 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
3413 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
3414 OTHER DEALINGS IN THE SOFTWARE.
3415 
3416 For more information, please refer to <http://unlicense.org/>
3417 */
dr2d_font_metrics::ascent
int ascent
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:100
dr2d_draw_rect_with_outline_proc
void(* dr2d_draw_rect_with_outline_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:213
dr2d_font_slant
dr2d_font_slant
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:135
dr2d_drawing_callbacks::get_text_cursor_position_from_point
dr2d_get_text_cursor_position_from_point_proc get_text_cursor_position_from_point
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:263
dr2d_drawing_callbacks::on_create_font
dr2d_on_create_font_proc on_create_font
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:237
dr2d_drawing_callbacks::get_font_metrics
dr2d_get_font_metrics_proc get_font_metrics
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:260
dr2d_font_slant
dr2d_font_slant
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:135
dr2d_image_format
dr2d_image_format
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:143
dr2d_drawing_callbacks::get_glyph_metrics
dr2d_get_glyph_metrics_proc get_glyph_metrics
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:261
dr2d_font_weight_extra_bold
@ dr2d_font_weight_extra_bold
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:126
dr2d_on_create_surface_proc
bool(* dr2d_on_create_surface_proc)(dr2d_surface *pSurface, float width, float height)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:202
dr2d_font_weight_heavy
@ dr2d_font_weight_heavy
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:127
dr2d_font::pContext
dr2d_context * pContext
A pointer to the context that owns the font.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:291
dr2d_drawing_callbacks::draw_round_rect
dr2d_draw_round_rect_proc draw_round_rect
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:248
dr2d_font_weight_extra_light
@ dr2d_font_weight_extra_light
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:120
dr2d_map_image_data_proc
void *(* dr2d_map_image_data_proc)(dr2d_image *pImage, unsigned int accessFlags)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:222
dr2d_surface::width
float width
The width of the surface.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:322
dr2d_draw_image
void dr2d_draw_image(dr2d_surface *pSurface, dr2d_image *pImage, dr2d_draw_image_args *pArgs)
Draws an image.
NULL
#define NULL
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/speex_resampler/thirdparty/resample.c:92
dr2d_unmap_image_data
void dr2d_unmap_image_data(dr2d_image *pImage)
dr2d_draw_text_proc
void(* dr2d_draw_text_proc)(dr2d_surface *pSurface, dr2d_font *pFont, const char *text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:217
dr2d_drawing_callbacks::map_image_data
dr2d_map_image_data_proc map_image_data
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:257
dr2d_image
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:267
dr2d_context::fontExtraBytes
size_t fontExtraBytes
The number of extra bytes to allocate for each font.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:340
dr2d_unmap_image_data_proc
void(* dr2d_unmap_image_data_proc)(dr2d_image *pImage)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:223
dr2d_font_weight
dr2d_font_weight
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:116
dr2d_image_format
dr2d_image_format
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:143
dr2d_font_slant_italic
@ dr2d_font_slant_italic
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:138
dr2d_context::drawingCallbacks
dr2d_drawing_callbacks drawingCallbacks
The drawing callbacks.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:334
dr2d_surface
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:316
dr2d_get_glyph_metrics
bool dr2d_get_glyph_metrics(dr2d_font *pFont, unsigned int utf32, dr2d_glyph_metrics *pMetricsOut)
Retrieves the metrics of the glyph for the given character when rendered with the given font.
dr2d_glyph_metrics::advanceX
int advanceX
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:112
dr2d_on_create_image_proc
bool(* dr2d_on_create_image_proc)(dr2d_image *pImage, unsigned int stride, const void *pData)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:206
dr2d_draw_rect_outline_proc
void(* dr2d_draw_rect_outline_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:212
dr2d_get_context_extra_data
void * dr2d_get_context_extra_data(dr2d_context *pContext)
Retrieves a pointer to the given context's extra data buffer.
FALSE
#define FALSE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:642
dr2d_map_image_data
void * dr2d_map_image_data(dr2d_image *pImage, unsigned int accessFlags)
dr2d_draw_image_args::srcX
float srcX
The source offset on the x axis.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:175
dr2d_drawing_callbacks::get_optimal_image_format
dr2d_get_optimal_image_format_proc get_optimal_image_format
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:256
dr2d_draw_round_rect_outline_proc
void(* dr2d_draw_round_rect_outline_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:215
dr2d_drawing_callbacks::on_create_context
dr2d_on_create_context_proc on_create_context
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:233
dr2d_font_weight_extra_heavy
@ dr2d_font_weight_extra_heavy
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:128
BYTE
unsigned char BYTE
dr2d_get_font_metrics_proc
bool(* dr2d_get_font_metrics_proc)(dr2d_font *pFont, dr2d_font_metrics *pMetricsOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:224
dr2d_draw_rect_outline
void dr2d_draw_rect_outline(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth)
Draws the outline of the given rectangle.
dr2d_color
Structure representing an RGBA color. Color components are specified in the range of 0 - 255.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:90
dr2d_begin_draw
void dr2d_begin_draw(dr2d_surface *pSurface)
Marks the beginning of a paint operation.
dr2d_draw_image_args::srcWidth
float srcWidth
The source width.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:181
dr2d_drawing_callbacks::on_create_surface
dr2d_on_create_surface_proc on_create_surface
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:235
dr2d_color::g
dr2d_byte g
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:93
dr2d_drawing_callbacks::set_clip
dr2d_set_clip_proc set_clip
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:253
dr2d_create_context_cairo
dr2d_context * dr2d_create_context_cairo()
Creates a 2D context with Cairo as the backend.
dr2d_delete_image
void dr2d_delete_image(dr2d_image *pImage)
Deletes the given image.
dr2d_end_draw
void dr2d_end_draw(dr2d_surface *pSurface)
Marks the end of a paint operation.
dr2d_glyph_metrics::originY
int originY
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:111
dr2d_get_optimal_image_format
dr2d_image_format dr2d_get_optimal_image_format(dr2d_context *pContext)
Retrieves the optimal image format for the given context. This depends on the backend.
dr2d_drawing_callbacks::get_clip
dr2d_get_clip_proc get_clip
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:254
dr2d_font_metrics::lineHeight
int lineHeight
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:102
DR2D_IMAGE_DRAW_BACKGROUND
#define DR2D_IMAGE_DRAW_BACKGROUND
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:151
dr2d_get_clip
void dr2d_get_clip(dr2d_surface *pSurface, float *pLeftOut, float *pTopOut, float *pRightOut, float *pBottomOut)
Retrieves the clipping rectangle.
dr2d_drawing_callbacks::draw_text
dr2d_draw_text_proc draw_text
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:251
dr2d_image::isMapped
bool isMapped
Whether or not the image's data is already mapped.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:282
dr2d_create_surface_cairo
dr2d_surface * dr2d_create_surface_cairo(dr2d_context *pContext, cairo_t *cr)
Creates a surface that draws directly to the given cairo context.
dr2d_on_create_font_proc
bool(* dr2d_on_create_font_proc)(dr2d_font *pFont)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:204
dr2d_glyph_metrics
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:106
dr2d_font_metrics::spaceWidth
int spaceWidth
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:103
dr2d_drawing_callbacks::measure_string
dr2d_measure_string_proc measure_string
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:262
dr2d_on_delete_context_proc
void(* dr2d_on_delete_context_proc)(dr2d_context *pContext)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:201
dr2d_image::pExtraData
dr2d_byte pExtraData[1]
The extra bytes. The size of this buffer is equal to pContext->imageExtraBytes.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:285
dr2d_drawing_callbacks::on_delete_image
dr2d_on_delete_image_proc on_delete_image
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:240
dr2d_delete_surface
void dr2d_delete_surface(dr2d_surface *pSurface)
Deletes the given surface.
dr2d_drawing_callbacks::draw_rect_outline
dr2d_draw_rect_outline_proc draw_rect_outline
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:246
dr2d_get_image_size
void dr2d_get_image_size(dr2d_image *pImage, unsigned int *pWidthOut, unsigned int *pHeightOut)
Retrieves the size of the given image.
dr2d_set_clip
void dr2d_set_clip(dr2d_surface *pSurface, float left, float top, float right, float bottom)
Sets the clipping rectangle.
dr2d_end_draw_proc
void(* dr2d_end_draw_proc)(dr2d_surface *pSurface)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:209
dr2d_create_surface
dr2d_surface * dr2d_create_surface(dr2d_context *pContext, float width, float height)
Creates a surface.
TRUE
#define TRUE
Definition: porcupine/demo/c/dr_libs/tests/external/miniaudio/extras/stb_vorbis.c:641
dr2d_get_surface_height
float dr2d_get_surface_height(const dr2d_surface *pSurface)
Retrieves the height of the surface.
dr2d_draw_image_args::srcHeight
float srcHeight
The source height.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:184
dr2d_get_cairo_surface_t
cairo_surface_t * dr2d_get_cairo_surface_t(dr2d_surface *pSurface)
dr2d_draw_image_args::foregroundTint
dr2d_color foregroundTint
The foreground tint color. This is not applied to the background color, and the alpha component is ig...
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:188
strcpy_s
DR_INLINE int strcpy_s(char *dst, size_t dstSizeInBytes, const char *src)
Definition: porcupine/demo/c/dr_libs/old/dr.h:157
dr2d_image::pContext
dr2d_context * pContext
A pointer to the context that owns the image.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:270
dr2d_get_glyph_metrics_proc
bool(* dr2d_get_glyph_metrics_proc)(dr2d_font *pFont, unsigned int utf32, dr2d_glyph_metrics *pMetricsOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:225
dr2d_glyph_metrics::originX
int originX
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:110
dr2d_create_context
dr2d_context * dr2d_create_context(dr2d_drawing_callbacks drawingCallbacks, size_t contextExtraBytes, size_t surfaceExtraBytes, size_t fontExtraBytes, size_t imageExtraBytes, const void *pUserData)
Creats a context.
dr2d_draw_image_args::dstWidth
float dstWidth
The destination width.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:168
dr2d_clear
void dr2d_clear(dr2d_surface *pSurface, dr2d_color color)
Clears the given surface with the given color.
dr2d_glyph_metrics::height
int height
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:109
dr2d_image::format
dr2d_image_format format
The format of the image data.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:279
dr2d_rgb
dr2d_color dr2d_rgb(dr2d_byte r, dr2d_byte g, dr2d_byte b)
Creates a fully opaque color object from a set of RGB color components.
dr2d_draw_round_rect_proc
void(* dr2d_draw_round_rect_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float width)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:214
dr2d_font_weight_thin
@ dr2d_font_weight_thin
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:119
dr2d_get_cairo_t
cairo_t * dr2d_get_cairo_t(dr2d_surface *pSurface)
Retrieves the internal cairo_t object from the given surface.
dr2d_get_text_cursor_position_from_point_proc
bool(* dr2d_get_text_cursor_position_from_point_proc)(dr2d_font *pFont, const char *text, size_t textSizeInBytes, float maxWidth, float inputPosX, float *pTextCursorPosXOut, size_t *pCharacterIndexOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:227
dr2d_measure_string
bool dr2d_measure_string(dr2d_font *pFont, const char *text, size_t textSizeInBytes, float *pWidthOut, float *pHeightOut)
Retrieves the dimensions of the given string when drawn with the given font.
dr2d_font_weight_bold
@ dr2d_font_weight_bold
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:125
dr2d_glyph_metrics::advanceY
int advanceY
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:113
dr2d_draw_image_args::dstHeight
float dstHeight
The destination height.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:171
dr2d_drawing_callbacks::draw_rect_with_outline
dr2d_draw_rect_with_outline_proc draw_rect_with_outline
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:247
dr2d_font::rotation
float rotation
The font's rotation, in degrees.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:306
dr2d_context::contextExtraBytes
size_t contextExtraBytes
The number of extra bytes to allocate for the context.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:346
dr2d_draw_round_rect_with_outline_proc
void(* dr2d_draw_round_rect_with_outline_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float width, float outlineWidth, dr2d_color outlineColor)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:216
dr2d_font_slant_none
@ dr2d_font_slant_none
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:137
dr2d_font_slant_oblique
@ dr2d_font_slant_oblique
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:139
dr2d_draw_image_args::dstX
float dstX
The destination position on the x axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:162
dr2d_on_delete_image_proc
void(* dr2d_on_delete_image_proc)(dr2d_image *pImage)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:207
dr2d_image::width
unsigned int width
The width of the image.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:273
dr2d_draw_image_args::options
unsigned int options
Flags for controlling how the image should be drawn.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:195
dr2d_context::surfaceExtraBytes
size_t surfaceExtraBytes
The number of extra bytes to allocate for each surface.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:343
dr2d_font::size
unsigned int size
The size of the font.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:297
dr2d_get_image_extra_data
void * dr2d_get_image_extra_data(dr2d_image *pImage)
Retrieves a pointer to the given image's extra data buffer.
dr2d_font_metrics
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:98
dr2d_surface::pContext
dr2d_context * pContext
A pointer to the context that owns the surface.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:319
dr2d_surface::pExtraData
dr2d_byte pExtraData[1]
The extra bytes. The size of this buffer is equal to pContext->surfaceExtraBytes.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:328
dr2d_get_text_cursor_position_from_char_proc
bool(* dr2d_get_text_cursor_position_from_char_proc)(dr2d_font *pFont, const char *text, size_t characterIndex, float *pTextCursorPosXOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:228
dr2d_byte
unsigned char dr2d_byte
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:77
dr2d_font_weight
dr2d_font_weight
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:116
dr2d_get_surface_extra_data
void * dr2d_get_surface_extra_data(dr2d_surface *pSurface)
Retrieves a pointer to the given surface's extra data buffer.
dr2d_on_delete_font_proc
void(* dr2d_on_delete_font_proc)(dr2d_font *pFont)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:205
dr2d_draw_round_rect_with_outline
void dr2d_draw_round_rect_with_outline(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth, dr2d_color outlineColor)
Draws a filled rectangle with an outline.
dr2d_get_clip_proc
void(* dr2d_get_clip_proc)(dr2d_surface *pSurface, float *pLeftOut, float *pTopOut, float *pRightOut, float *pBottomOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:220
dr2d_set_clip_proc
void(* dr2d_set_clip_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:219
dr2d_clear_proc
void(* dr2d_clear_proc)(dr2d_surface *pSurface, dr2d_color color)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:210
dr2d_drawing_callbacks::on_delete_context
dr2d_on_delete_context_proc on_delete_context
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:234
dr2d_byte
unsigned char dr2d_byte
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:77
dr2d_font_metrics::descent
int descent
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:101
dr2d_drawing_callbacks::begin_draw
dr2d_begin_draw_proc begin_draw
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:242
dr2d_draw_image_args::dstY
float dstY
The destination position on the y axis. This is ignored if the DR2D_IMAGE_ALIGN_CENTER option is set.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:165
dr2d_draw_image_args::srcY
float srcY
The source offset on the y axis.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:178
dr2d_context
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:331
dr2d_color::b
dr2d_byte b
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:94
dr2d_image_format_bgra8
@ dr2d_image_format_bgra8
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:146
dr2d_get_optimal_image_format_proc
dr2d_image_format(* dr2d_get_optimal_image_format_proc)(dr2d_context *pContext)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:221
dr2d_drawing_callbacks::on_delete_font
dr2d_on_delete_font_proc on_delete_font
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:238
dr2d_drawing_callbacks::end_draw
dr2d_end_draw_proc end_draw
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:243
dr2d_get_text_cursor_position_from_char
bool dr2d_get_text_cursor_position_from_char(dr2d_font *pFont, const char *text, size_t characterIndex, float *pTextCursorPosXOut)
Retrieves the position to palce a text cursor based on the character at the given index for the given...
dr2d_context::pExtraData
dr2d_byte pExtraData[1]
The extra bytes.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:349
dr2d_on_create_context_proc
bool(* dr2d_on_create_context_proc)(dr2d_context *pContext, const void *pUserData)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:200
dr2d_draw_image_proc
void(* dr2d_draw_image_proc)(dr2d_surface *pSurface, dr2d_image *pImage, dr2d_draw_image_args *pArgs)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:218
dr2d_glyph_metrics::width
int width
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:108
DR2D_MAX_FONT_FAMILY_LENGTH
#define DR2D_MAX_FONT_FAMILY_LENGTH
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:62
DR2D_FONT_NO_CLEARTYPE
#define DR2D_FONT_NO_CLEARTYPE
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:157
dr2d_surface::height
float height
The height of the surface.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:325
dr2d_font_weight_default
@ dr2d_font_weight_default
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:131
dr2d_rgba
dr2d_color dr2d_rgba(dr2d_byte r, dr2d_byte g, dr2d_byte b, dr2d_byte a)
Creates a color object from a set of RGBA color components.
dr2d_drawing_callbacks::on_delete_surface
dr2d_on_delete_surface_proc on_delete_surface
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:236
dr2d_create_font
dr2d_font * dr2d_create_font(dr2d_context *pContext, const char *family, unsigned int size, dr2d_font_weight weight, dr2d_font_slant slant, float rotation, unsigned int flags)
Creates a font that can be passed to dr2d_draw_text().
dr2d_begin_draw_proc
void(* dr2d_begin_draw_proc)(dr2d_surface *pSurface)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:208
dr2d_font::slant
dr2d_font_slant slant
The font's slant.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:303
dr2d_image::height
unsigned int height
The height of the image.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:276
dr2d_font_weight_semi_bold
@ dr2d_font_weight_semi_bold
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:124
DR2D_WRITE
#define DR2D_WRITE
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:155
dr2d_drawing_callbacks::on_create_image
dr2d_on_create_image_proc on_create_image
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:239
dr2d_drawing_callbacks::unmap_image_data
dr2d_unmap_image_data_proc unmap_image_data
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:258
dr2d_image_format_argb8
@ dr2d_image_format_argb8
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:147
dr2d_image_format_rgba8
@ dr2d_image_format_rgba8
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:145
dr2d_font::pExtraData
dr2d_byte pExtraData[1]
The extra bytes. The size of this buffer is equal to pContext->fontExtraBytes.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:313
dr2d_drawing_callbacks::draw_round_rect_outline
dr2d_draw_round_rect_outline_proc draw_round_rect_outline
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:249
dr2d_font_weight_book
@ dr2d_font_weight_book
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:123
dr2d_color::r
dr2d_byte r
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:92
dr2d_get_surface_width
float dr2d_get_surface_width(const dr2d_surface *pSurface)
Retrieves the width of the surface.
dr2d_font
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:288
dr2d_on_delete_surface_proc
void(* dr2d_on_delete_surface_proc)(dr2d_surface *pSurface)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:203
dr2d_measure_string_proc
bool(* dr2d_measure_string_proc)(dr2d_font *pFont, const char *text, size_t textSizeInBytes, float *pWidthOut, float *pHeightOut)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:226
dr2d_font_weight_semi_light
@ dr2d_font_weight_semi_light
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:122
DR2D_IMAGE_HINT_NO_ALPHA
#define DR2D_IMAGE_HINT_NO_ALPHA
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:152
dr2d_draw_image_args
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:159
dr2d_get_font_size
unsigned int dr2d_get_font_size(dr2d_font *pFont)
Retrieves the size of the given font.
dr2d_font_weight_normal
@ dr2d_font_weight_normal
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:130
dr2d_draw_image_args::backgroundColor
dr2d_color backgroundColor
The background color. Only used if the DR2D_IMAGE_DRAW_BACKGROUND option is set.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:191
dr2d_font_weight_medium
@ dr2d_font_weight_medium
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:118
dr2d_drawing_callbacks::clear
dr2d_clear_proc clear
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:244
dr2d_draw_rect
void dr2d_draw_rect(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color)
Draws a filled rectangle without an outline.
assert.h
dr2d_drawing_callbacks::get_text_cursor_position_from_char
dr2d_get_text_cursor_position_from_char_proc get_text_cursor_position_from_char
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:264
dr2d_create_image
dr2d_image * dr2d_create_image(dr2d_context *pContext, unsigned int width, unsigned int height, dr2d_image_format format, unsigned int stride, const void *pData)
dr2d_color::a
dr2d_byte a
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:95
dr2d_draw_text
void dr2d_draw_text(dr2d_surface *pSurface, dr2d_font *pFont, const char *text, size_t textSizeInBytes, float posX, float posY, dr2d_color color, dr2d_color backgroundColor)
Draws a run of text.
dr2d_font_weight_light
@ dr2d_font_weight_light
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:121
dr2d_draw_rect_with_outline
void dr2d_draw_rect_with_outline(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float outlineWidth, dr2d_color outlineColor)
Draws a filled rectangle with an outline.
dr2d_delete_font
void dr2d_delete_font(dr2d_font *pFont)
Deletes a font that was previously created with dr2d_create_font()
dr2d_draw_round_rect_outline
void dr2d_draw_round_rect_outline(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius, float outlineWidth)
Draws the outline of the given rectangle with rounded corners.
dr2d_context::imageExtraBytes
size_t imageExtraBytes
The number of extra bytes to allocate for each image.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:337
dr2d_font::weight
dr2d_font_weight weight
The font's weight.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:300
dr2d_get_text_cursor_position_from_point
bool dr2d_get_text_cursor_position_from_point(dr2d_font *pFont, const char *text, size_t textSizeInBytes, float maxWidth, float inputPosX, float *pTextCursorPosXOut, size_t *pCharacterIndexOut)
Retrieves the position to place a text cursor based on the given point for the given string when draw...
dr2d_drawing_callbacks::draw_round_rect_with_outline
dr2d_draw_round_rect_with_outline_proc draw_round_rect_with_outline
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:250
dr2d_draw_rect_proc
void(* dr2d_draw_rect_proc)(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color)
Definition: rhino/demo/c/dr_libs/old/dr_2d.h:211
dr2d_draw_round_rect
void dr2d_draw_round_rect(dr2d_surface *pSurface, float left, float top, float right, float bottom, dr2d_color color, float radius)
Draws a filled rectangle without an outline with rounded corners.
dr2d_font::family
char family[DR2D_MAX_FONT_FAMILY_LENGTH]
The font family.
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:294
dr2d_drawing_callbacks::draw_image
dr2d_draw_image_proc draw_image
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:252
dr2d_get_font_extra_data
void * dr2d_get_font_extra_data(dr2d_font *pFont)
Retrieves a pointer to the given font's extra data buffer.
dr2d_delete_context
void dr2d_delete_context(dr2d_context *pContext)
Deletes the given context.
dr2d_get_font_metrics
bool dr2d_get_font_metrics(dr2d_font *pFont, dr2d_font_metrics *pMetricsOut)
Retrieves the metrics of the given font.
dr2d_drawing_callbacks
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:231
dr2d_drawing_callbacks::draw_rect
dr2d_draw_rect_proc draw_rect
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:245
dr2d_font::flags
unsigned int flags
Definition: porcupine/demo/c/dr_libs/old/dr_2d.h:310


picovoice_driver
Author(s):
autogenerated on Fri Apr 1 2022 02:13:49