47 #if defined(__WIN32__) || defined(_WIN32) || defined(_WIN64)
61 #ifndef DR2D_MAX_FONT_FAMILY_LENGTH
62 #define DR2D_MAX_FONT_FAMILY_LENGTH 128
151 #define DR2D_IMAGE_DRAW_BACKGROUND (1 << 0)
152 #define DR2D_IMAGE_HINT_NO_ALPHA (1 << 1)
154 #define DR2D_READ (1 << 0)
155 #define DR2D_WRITE (1 << 1)
157 #define DR2D_FONT_NO_CLEARTYPE (1 << 0)
222 typedef void* (* dr2d_map_image_data_proc) (
dr2d_image* pImage,
unsigned int accessFlags);
551 #ifndef DR2D_NO_CAIRO
552 #include <cairo/cairo.h>
584 #ifdef DR_2D_IMPLEMENTATION
592 #define DR2D_PRIVATE static
595 static int dr2d_strcpy_s(
char* dst,
size_t dstSizeInBytes,
const char* src)
598 return strcpy_s(dst, dstSizeInBytes, src);
603 if (dstSizeInBytes == 0) {
612 for (i = 0; i < dstSizeInBytes && src[i] !=
'\0'; ++i) {
616 if (i < dstSizeInBytes) {
630 if (pContext !=
NULL)
637 memset(pContext->
pExtraData, 0, contextExtraBytes);
658 if (pContext !=
NULL) {
675 if (pContext !=
NULL)
678 if (pSurface !=
NULL)
681 pSurface->
width = width;
682 pSurface->
height = height;
706 if (pSurface !=
NULL)
720 if (pSurface !=
NULL) {
721 return pSurface->
width;
729 if (pSurface !=
NULL) {
738 if (pSurface !=
NULL) {
748 if (pSurface !=
NULL)
760 if (pSurface !=
NULL)
772 if (pSurface !=
NULL)
784 if (pSurface !=
NULL)
796 if (pSurface !=
NULL)
808 if (pSurface !=
NULL)
820 if (pSurface !=
NULL)
832 if (pSurface !=
NULL)
844 if (pSurface !=
NULL)
856 if (pSurface !=
NULL)
868 if (pSurface ==
NULL || pImage ==
NULL || pArgs ==
NULL) {
881 if (pSurface !=
NULL)
893 if (pSurface !=
NULL)
905 if (pContext ==
NULL) {
918 pFont->
slant = slant;
920 pFont->
flags = flags;
922 if (family !=
NULL) {
923 dr2d_strcpy_s(pFont->
family,
sizeof(pFont->
family), family);
986 if (pFont ==
NULL || pMetricsOut ==
NULL) {
1001 if (pFont ==
NULL) {
1016 if (pFont ==
NULL) {
1031 if (pFont ==
NULL) {
1047 if (pContext ==
NULL || width == 0 || height == 0) {
1052 if (pImage ==
NULL) {
1057 pImage->
width = width;
1074 if (pImage ==
NULL) {
1089 if (pImage ==
NULL) {
1098 if (pImage ==
NULL) {
1103 *pWidthOut = pImage->
width;
1106 *pHeightOut = pImage->
height;
1117 if (pImageData !=
NULL) {
1182 void dr2d__rgba8_bgra8_swap__premul(
const void* pSrc,
void* pDst,
unsigned int width,
unsigned int height,
unsigned int srcStride,
unsigned int dstStride)
1184 assert(pSrc !=
NULL);
1185 assert(pDst !=
NULL);
1187 const unsigned int srcStride32 = srcStride/4;
1188 const unsigned int dstStride32 = dstStride/4;
1190 const unsigned int* pSrcRow = (
const unsigned int*)pSrc;
1191 unsigned int* pDstRow = (
unsigned int*)pDst;
1193 for (
unsigned int iRow = 0; iRow < height; ++iRow)
1195 for (
unsigned int iCol = 0; iCol < width; ++iCol)
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;
1203 srcTexelB = (
unsigned int)(srcTexelB * (srcTexelA / 255.0f));
1204 srcTexelG = (
unsigned int)(srcTexelG * (srcTexelA / 255.0f));
1205 srcTexelR = (
unsigned int)(srcTexelR * (srcTexelA / 255.0f));
1207 pDstRow[iCol] = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
1210 pSrcRow += srcStride32;
1211 pDstRow += dstStride32;
1230 wchar_t* wcharBuffer;
1233 unsigned int wcharBufferLength;
1237 size_t glyphCacheSize;
1254 HDC hIntermediateDC;
1268 HGDIOBJ hStockDCBrush;
1271 HGDIOBJ hStockNullBrush;
1274 HGDIOBJ hStockDCPen;
1277 HGDIOBJ hStockNullPen;
1287 COLORREF prevBrushColor;
1296 COLORREF prevBkColor;
1317 unsigned int* pSrcBitmapData;
1321 HBITMAP hIntermediateBitmap;
1324 unsigned int* pIntermediateBitmapData;
1328 void* pMappedImageData;
1331 unsigned int mapAccessFlags;
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);
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);
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);
1360 void* dr2d_map_image_data_gdi(
dr2d_image* pImage,
unsigned accessFlags);
1361 void dr2d_unmap_image_data_gdi(
dr2d_image* pImage);
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);
1370 wchar_t* dr2d_to_wchar_gdi(
dr2d_context* pContext,
const char* text,
size_t textSizeInBytes,
unsigned int* characterCountOut);
1373 static int dr2d_utf32_to_utf16(
unsigned int utf32,
unsigned short utf16[2])
1375 if (utf16 ==
NULL) {
1379 if (utf32 < 0xD800 || (utf32 >= 0xE000 && utf32 <= 0xFFFF))
1381 utf16[0] = (
unsigned short)utf32;
1387 if (utf32 >= 0x10000 && utf32 <= 0x10FFFF)
1389 utf16[0] = (
unsigned short)(0xD7C0 + (
unsigned short)(utf32 >> 10));
1390 utf16[1] = (
unsigned short)(0xDC00 + (
unsigned short)(utf32 & 0x3FF));
1416 callbacks.
end_draw = dr2d_end_draw_gdi;
1417 callbacks.
clear = dr2d_clear_gdi;
1418 callbacks.
draw_rect = dr2d_draw_rect_gdi;
1424 callbacks.
draw_text = dr2d_draw_text_gdi;
1426 callbacks.
set_clip = dr2d_set_clip_gdi;
1427 callbacks.
get_clip = dr2d_get_clip_gdi;
1439 return dr2d_create_context(callbacks,
sizeof(gdi_context_data),
sizeof(gdi_surface_data),
sizeof(gdi_font_data),
sizeof(gdi_image_data), &hDC);
1445 if (pSurface !=
NULL) {
1447 if (pGDIData !=
NULL) {
1448 pGDIData->hWnd = hWnd;
1458 if (pSurface !=
NULL) {
1460 if (pGDIData !=
NULL) {
1461 pGDIData->hDC = hDC;
1470 if (pSurface !=
NULL) {
1472 if (pGDIData !=
NULL) {
1473 return pGDIData->hDC;
1482 if (pSurface !=
NULL) {
1484 if (pGDIData !=
NULL) {
1485 return pGDIData->hBitmap;
1495 if (pGDIData ==
NULL) {
1499 return pGDIData->hFont;
1503 bool dr2d_on_create_context_gdi(
dr2d_context* pContext,
const void* pUserData)
1505 assert(pContext !=
NULL);
1508 if (pUserData !=
NULL) {
1509 hDC = *(HDC*)pUserData;
1512 bool ownsDC =
false;
1514 hDC = CreateCompatibleDC(GetDC(GetDesktopWindow()));
1521 if (pGDIData ==
NULL) {
1525 pGDIData->hDC = hDC;
1526 if (pGDIData->hDC ==
NULL) {
1530 pGDIData->ownsDC = ownsDC;
1534 SetGraphicsMode(pGDIData->hDC, GM_ADVANCED);
1537 pGDIData->wcharBuffer =
NULL;
1538 pGDIData->wcharBufferLength = 0;
1540 pGDIData->pGlyphCache =
NULL;
1541 pGDIData->glyphCacheSize = 0;
1546 void dr2d_on_delete_context_gdi(
dr2d_context* pContext)
1548 assert(pContext !=
NULL);
1551 if (pGDIData !=
NULL)
1553 free(pGDIData->pGlyphCache);
1554 pGDIData->glyphCacheSize = 0;
1556 free(pGDIData->wcharBuffer);
1557 pGDIData->wcharBuffer = 0;
1558 pGDIData->wcharBufferLength = 0;
1560 if (pGDIData->ownsDC) {
1561 DeleteDC(pGDIData->hDC);
1564 pGDIData->hDC =
NULL;
1568 bool dr2d_on_create_surface_gdi(
dr2d_surface* pSurface,
float width,
float height)
1570 assert(pSurface !=
NULL);
1573 if (pGDIContextData ==
NULL) {
1578 if (pGDISurfaceData ==
NULL) {
1582 HDC hDC = pGDIContextData->hDC;
1587 HDC hIntermediateDC = CreateCompatibleDC(hDC);
1588 if (hIntermediateDC ==
NULL) {
1592 pGDISurfaceData->hIntermediateDC = hIntermediateDC;
1593 pGDISurfaceData->hWnd =
NULL;
1596 if (width != 0 && height != 0)
1598 pGDISurfaceData->hDC = hDC;
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) {
1615 pGDISurfaceData->hBitmap =
NULL;
1616 pGDISurfaceData->hDC =
NULL;
1623 void dr2d_on_delete_surface_gdi(
dr2d_surface* pSurface)
1625 assert(pSurface !=
NULL);
1628 if (pGDIData !=
NULL)
1630 DeleteObject(pGDIData->hBitmap);
1631 pGDIData->hBitmap =
NULL;
1633 DeleteDC(pGDIData->hIntermediateDC);
1634 pGDIData->hIntermediateDC =
NULL;
1638 bool dr2d_on_create_font_gdi(
dr2d_font* pFont)
1640 assert(pFont !=
NULL);
1643 if (pGDIData ==
NULL) {
1648 LONG weightGDI = FW_REGULAR;
1669 memset(&logfont, 0,
sizeof(logfont));
1673 logfont.lfHeight = -(LONG)pFont->
size;
1674 logfont.lfWeight = weightGDI;
1675 logfont.lfItalic = slantGDI;
1676 logfont.lfCharSet = DEFAULT_CHARSET;
1679 logfont.lfEscapement = (LONG)pFont->
rotation * 10;
1680 logfont.lfOrientation = (LONG)pFont->
rotation * 10;
1682 size_t familyLength = strlen(pFont->
family);
1683 memcpy(logfont.lfFaceName, pFont->
family, (familyLength < 31) ? familyLength : 31);
1686 pGDIData->hFont = CreateFontIndirectA(&logfont);
1687 if (pGDIData->hFont ==
NULL) {
1693 if (pGDIContextData ==
NULL) {
1698 HGDIOBJ hPrevFont = SelectObject(pGDIContextData->hDC, pGDIData->hFont);
1701 GetTextMetrics(pGDIContextData->hDC, &metrics);
1703 pGDIData->metrics.ascent = metrics.tmAscent;
1704 pGDIData->metrics.descent = metrics.tmDescent;
1705 pGDIData->metrics.lineHeight = metrics.tmHeight;
1708 const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
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;
1715 pGDIData->metrics.spaceWidth = spaceMetrics.gmCellIncX;
1718 SelectObject(pGDIContextData->hDC, hPrevFont);
1724 void dr2d_on_delete_font_gdi(
dr2d_font* pFont)
1726 assert(pFont !=
NULL);
1729 if (pGDIData ==
NULL) {
1733 DeleteObject(pGDIData->hFont);
1736 bool dr2d_on_create_image_gdi(
dr2d_image* pImage,
unsigned int stride,
const void* pData)
1738 assert(pImage !=
NULL);
1741 if (pGDIData ==
NULL) {
1746 if (pGDIContextData ==
NULL) {
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;
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) {
1764 pGDIData->hIntermediateBitmap = CreateDIBSection(pGDIContextData->hDC, &bmi, DIB_RGB_COLORS, (
void**)&pGDIData->pIntermediateBitmapData,
NULL, 0);
1765 if (pGDIData->hIntermediateBitmap ==
NULL) {
1766 DeleteObject(pGDIData->hSrcBitmap);
1772 if (pData !=
NULL) {
1773 dr2d__rgba8_bgra8_swap__premul(pData, pGDIData->pSrcBitmapData, pImage->
width, pImage->
height, stride, pImage->
width*4);
1780 pGDIData->pMappedImageData =
NULL;
1781 pGDIData->mapAccessFlags = 0;
1787 void dr2d_on_delete_image_gdi(
dr2d_image* pImage)
1789 assert(pImage !=
NULL);
1792 if (pGDIData ==
NULL) {
1796 DeleteObject(pGDIData->hSrcBitmap);
1797 pGDIData->hSrcBitmap =
NULL;
1799 DeleteObject(pGDIData->hIntermediateBitmap);
1800 pGDIData->hIntermediateBitmap =
NULL;
1806 assert(pSurface !=
NULL);
1809 if (pGDIData !=
NULL) {
1810 if (pGDIData->hWnd !=
NULL) {
1811 pGDIData->hDC = BeginPaint(pGDIData->hWnd, &pGDIData->ps);
1813 SelectObject(dr2d_get_HDC(pSurface), pGDIData->hBitmap);
1816 HDC hDC = dr2d_get_HDC(pSurface);
1818 pGDIData->hStockDCBrush = GetStockObject(DC_BRUSH);
1819 pGDIData->hStockNullBrush = GetStockObject(NULL_BRUSH);
1820 pGDIData->hStockDCPen = GetStockObject(DC_PEN);
1821 pGDIData->hStockNullPen = GetStockObject(NULL_PEN);
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);
1835 assert(pSurface !=
NULL);
1838 if (pGDIData !=
NULL) {
1839 HDC hDC = dr2d_get_HDC(pSurface);
1841 SelectClipRgn(hDC,
NULL);
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);
1850 if (pGDIData->hWnd !=
NULL) {
1851 EndPaint(pGDIData->hWnd, &pGDIData->ps);
1858 assert(pSurface !=
NULL);
1860 dr2d_draw_rect_gdi(pSurface, 0, 0, pSurface->
width, pSurface->
height, color);
1863 void dr2d_draw_rect_gdi(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color)
1865 assert(pSurface !=
NULL);
1868 if (pGDIData !=
NULL)
1870 HDC hDC = dr2d_get_HDC(pSurface);
1872 SelectObject(hDC, pGDIData->hStockNullPen);
1873 SelectObject(hDC, pGDIData->hStockDCBrush);
1874 SetDCBrushColor(hDC, RGB(color.
r, color.
g, color.
b));
1878 Rectangle(hDC, (
int)left, (
int)top, (
int)right + 1, (
int)bottom + 1);
1882 void dr2d_draw_rect_outline_gdi(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color,
float outlineWidth)
1884 assert(pSurface !=
NULL);
1887 if (pGDIData !=
NULL)
1889 HDC hDC = dr2d_get_HDC(pSurface);
1891 SelectObject(hDC, pGDIData->hStockNullPen);
1892 SelectObject(hDC, pGDIData->hStockDCBrush);
1893 SetDCBrushColor(hDC, RGB(color.
r, color.
g, color.
b));
1898 Rectangle(hDC, (
int)left, (
int)top, (
int)(left + outlineWidth + 1), (
int)(bottom + 1));
1899 Rectangle(hDC, (
int)(right - outlineWidth), (
int)top, (
int)(right + 1), (
int)(bottom + 1));
1900 Rectangle(hDC, (
int)(left + outlineWidth), (
int)top, (
int)(right - outlineWidth + 1), (
int)(top + outlineWidth + 1));
1901 Rectangle(hDC, (
int)(left + outlineWidth), (
int)(bottom - outlineWidth), (
int)(right - outlineWidth + 1), (
int)(bottom + 1));
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)
1907 assert(pSurface !=
NULL);
1910 if (pGDIData !=
NULL)
1912 HDC hDC = dr2d_get_HDC(pSurface);
1914 HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (
int)outlineWidth, RGB(outlineColor.
r, outlineColor.
g, outlineColor.
b));
1917 SelectObject(hDC, hPen);
1918 SelectObject(hDC, pGDIData->hStockDCBrush);
1919 SetDCBrushColor(hDC, RGB(color.
r, color.
g, color.
b));
1921 Rectangle(hDC, (
int)left, (
int)top, (
int)right, (
int)bottom);
1928 void dr2d_draw_round_rect_gdi(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color,
float radius)
1930 assert(pSurface !=
NULL);
1933 if (pGDIData !=
NULL)
1935 HDC hDC = dr2d_get_HDC(pSurface);
1937 SelectObject(hDC, pGDIData->hStockNullPen);
1938 SelectObject(hDC, pGDIData->hStockDCBrush);
1939 SetDCBrushColor(hDC, RGB(color.
r, color.
g, color.
b));
1941 RoundRect(hDC, (
int)left, (
int)top, (
int)right + 1, (
int)bottom + 1, (
int)(radius*2), (
int)(radius*2));
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)
1947 assert(pSurface !=
NULL);
1950 if (pGDIData !=
NULL)
1952 HDC hDC = dr2d_get_HDC(pSurface);
1954 HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (
int)outlineWidth, RGB(color.
r, color.
g, color.
b));
1957 SelectObject(hDC, pGDIData->hStockNullBrush);
1958 SelectObject(hDC, hPen);
1960 RoundRect(hDC, (
int)left, (
int)top, (
int)right, (
int)bottom, (
int)(radius*2), (
int)(radius*2));
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)
1969 assert(pSurface !=
NULL);
1972 if (pGDIData !=
NULL)
1974 HDC hDC = dr2d_get_HDC(pSurface);
1976 HPEN hPen = CreatePen(PS_SOLID | PS_INSIDEFRAME, (
int)outlineWidth, RGB(outlineColor.
r, outlineColor.
g, outlineColor.
b));
1979 SelectObject(hDC, hPen);
1980 SelectObject(hDC, pGDIData->hStockDCBrush);
1981 SetDCBrushColor(hDC, RGB(color.
r, color.
g, color.
b));
1983 RoundRect(hDC, (
int)left, (
int)top, (
int)right, (
int)bottom, (
int)(radius*2), (
int)(radius*2));
1993 if (pGDIFontData ==
NULL) {
1998 HDC hDC = dr2d_get_HDC(pSurface);
2000 HFONT hFontGDI = pGDIFontData->hFont;
2001 if (hFontGDI !=
NULL)
2005 unsigned int textWLength;
2006 wchar_t* textW = dr2d_to_wchar_gdi(pSurface->
pContext, text, textSizeInBytes, &textWLength);
2009 SelectObject(hDC, hFontGDI);
2012 RECT rect = {0, 0, 0, 0};
2014 if (backgroundColor.
a == 0) {
2015 SetBkMode(hDC, TRANSPARENT);
2017 SetBkMode(hDC, OPAQUE);
2018 SetBkColor(hDC, RGB(backgroundColor.
r, backgroundColor.
g, backgroundColor.
b));
2023 options |= ETO_CLIPPED;
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);
2033 SetTextColor(hDC, RGB(color.
r, color.
g, color.
b));
2035 ExtTextOutW(hDC, (
int)posX, (
int)posY, options, &rect, textW, textWLength,
NULL);
2043 if (pGDIImageData ==
NULL) {
2048 if (pGDISurfaceData ==
NULL) {
2052 bool drawFlipped =
false;
2053 HBITMAP hSrcBitmap =
NULL;
2058 hSrcBitmap = pGDIImageData->hSrcBitmap;
2064 unsigned int* pSrcBitmapData = pGDIImageData->pSrcBitmapData;
2065 unsigned int* pDstBitmapData = pGDIImageData->pIntermediateBitmapData;
2066 for (
unsigned int iRow = 0; iRow < pImage->
height; ++iRow)
2068 for (
unsigned int iCol = 0; iCol < pImage->
width; ++iCol)
2070 unsigned int srcTexel = *(pSrcBitmapData + (iRow * pImage->
width) + iCol);
2071 unsigned int* dstTexel = (pDstBitmapData + ((pImage->
height - iRow - 1) * pImage->
width) + iCol);
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));
2078 if (srcTexelR > 255) srcTexelR = 255;
2079 if (srcTexelG > 255) srcTexelG = 255;
2080 if (srcTexelB > 255) srcTexelB = 255;
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));
2090 *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
2102 hSrcBitmap = pGDIImageData->hIntermediateBitmap;
2105 HGDIOBJ hPrevBitmap = SelectObject(pGDISurfaceData->hIntermediateDC, hSrcBitmap);
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);
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);
2116 assert(drawFlipped ==
false);
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);
2120 SelectObject(pGDISurfaceData->hIntermediateDC, hPrevBitmap);
2123 void dr2d_set_clip_gdi(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom)
2125 assert(pSurface !=
NULL);
2128 if (pGDIData !=
NULL)
2130 HDC hDC = dr2d_get_HDC(pSurface);
2132 SelectClipRgn(hDC,
NULL);
2133 IntersectClipRect(hDC, (
int)left, (
int)top, (
int)right, (
int)bottom);
2137 void dr2d_get_clip_gdi(
dr2d_surface* pSurface,
float* pLeftOut,
float* pTopOut,
float* pRightOut,
float* pBottomOut)
2139 assert(pSurface !=
NULL);
2142 if (pGDIData !=
NULL)
2145 GetClipBox(dr2d_get_HDC(pSurface), &rect);
2147 if (pLeftOut !=
NULL) {
2148 *pLeftOut = (float)rect.left;
2150 if (pTopOut !=
NULL) {
2151 *pTopOut = (float)rect.top;
2153 if (pRightOut !=
NULL) {
2154 *pRightOut = (float)rect.right;
2156 if (pBottomOut !=
NULL) {
2157 *pBottomOut = (float)rect.bottom;
2169 void* dr2d_map_image_data_gdi(
dr2d_image* pImage,
unsigned accessFlags)
2171 assert(pImage !=
NULL);
2174 if (pGDIImageData ==
NULL) {
2178 assert(pGDIImageData->pMappedImageData ==
NULL);
2180 pGDIImageData->mapAccessFlags = accessFlags;
2184 pGDIImageData->pMappedImageData = pGDIImageData->pSrcBitmapData;
2188 pGDIImageData->pMappedImageData = malloc(pImage->
width * pImage->
height * 4);
2189 if (pGDIImageData->pMappedImageData ==
NULL) {
2193 for (
unsigned int iRow = 0; iRow < pImage->
height; ++iRow)
2195 const unsigned int iRowSrc = pImage->
height - (iRow + 1);
2196 const unsigned int iRowDst = iRow;
2198 for (
unsigned int iCol = 0; iCol < pImage->
width; ++iCol)
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;
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;
2208 srcTexelB = (
unsigned int)(srcTexelB * (srcTexelA / 255.0f));
2209 srcTexelG = (
unsigned int)(srcTexelG * (srcTexelA / 255.0f));
2210 srcTexelR = (
unsigned int)(srcTexelR * (srcTexelA / 255.0f));
2212 *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
2217 return pGDIImageData->pMappedImageData;
2220 void dr2d_unmap_image_data_gdi(
dr2d_image* pImage)
2222 assert(pImage !=
NULL);
2225 if (pGDIImageData ==
NULL) {
2229 assert(pGDIImageData->pMappedImageData !=
NULL);
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);
2243 free(pGDIImageData->pMappedImageData);
2246 pGDIImageData->pMappedImageData =
NULL;
2247 pGDIImageData->mapAccessFlags = 0;
2253 assert(pFont !=
NULL);
2254 assert(pMetricsOut !=
NULL);
2257 if (pGDIFontData ==
NULL) {
2261 *pMetricsOut = pGDIFontData->metrics;
2267 assert(pFont !=
NULL);
2268 assert(pGlyphMetrics !=
NULL);
2271 if (pGDIFontData ==
NULL) {
2276 if (pGDIContextData ==
NULL) {
2281 SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2284 const MAT2 transform = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
2286 unsigned short utf16[2];
2287 int utf16Len = dr2d_utf32_to_utf16(utf32, utf16);
2289 WCHAR glyphIndices[2];
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)
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)
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;
2316 bool dr2d_measure_string_gdi(
dr2d_font* pFont,
const char* text,
size_t textSizeInBytes,
float* pWidthOut,
float* pHeightOut)
2318 assert(pFont !=
NULL);
2321 if (pGDIFontData ==
NULL) {
2326 if (pGDIContextData ==
NULL) {
2331 SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2333 unsigned int textWLength;
2334 wchar_t* textW = dr2d_to_wchar_gdi(pFont->
pContext, text, textSizeInBytes, &textWLength);
2338 if (GetTextExtentPoint32W(pGDIContextData->hDC, textW, textWLength, &sizeWin32))
2340 if (pWidthOut !=
NULL) {
2341 *pWidthOut = (float)sizeWin32.cx;
2343 if (pHeightOut !=
NULL) {
2344 *pHeightOut = (float)sizeWin32.cy;
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)
2356 bool successful =
false;
2358 assert(pFont !=
NULL);
2361 if (pGDIFontData ==
NULL) {
2366 if (pGDIContextData ==
NULL) {
2371 SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2374 GCP_RESULTSW results;
2375 ZeroMemory(&results,
sizeof(results));
2376 results.lStructSize =
sizeof(results);
2377 results.nGlyphs = (UINT)textSizeInBytes;
2379 unsigned int textWLength;
2380 wchar_t* textW = dr2d_to_wchar_gdi(pFont->
pContext, text, textSizeInBytes, &textWLength);
2383 if (results.nGlyphs > pGDIContextData->glyphCacheSize) {
2384 free(pGDIContextData->pGlyphCache);
2385 pGDIContextData->pGlyphCache = (
int*)malloc(
sizeof(
int) * results.nGlyphs);
2386 pGDIContextData->glyphCacheSize = results.nGlyphs;
2389 results.lpCaretPos = pGDIContextData->pGlyphCache;
2390 if (results.lpCaretPos !=
NULL)
2392 if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, (
int)maxWidth, &results, GCP_MAXEXTENT | GCP_USEKERNING) != 0)
2394 float textCursorPosX = 0;
2396 for (iChar = 0; iChar < results.nGlyphs; ++iChar)
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];
2403 charBoundsRight = maxWidth;
2406 if (inputPosX >= charBoundsLeft && inputPosX <= charBoundsRight)
2410 float charBoundsRightHalf = charBoundsLeft + ceilf(((charBoundsRight - charBoundsLeft) / 2.0f));
2411 if (inputPosX <= charBoundsRightHalf) {
2414 textCursorPosX = charBoundsRight;
2420 textCursorPosX = charBoundsRight;
2423 if (pTextCursorPosXOut) {
2424 *pTextCursorPosXOut = textCursorPosX;
2426 if (pCharacterIndexOut) {
2427 *pCharacterIndexOut = iChar;
2438 bool dr2d_get_text_cursor_position_from_char_gdi(
dr2d_font* pFont,
const char* text,
size_t characterIndex,
float* pTextCursorPosXOut)
2440 bool successful =
false;
2442 assert(pFont !=
NULL);
2445 if (pGDIFontData ==
NULL) {
2450 if (pGDIContextData ==
NULL) {
2455 SelectObject(pGDIContextData->hDC, pGDIFontData->hFont);
2458 GCP_RESULTSW results;
2459 ZeroMemory(&results,
sizeof(results));
2460 results.lStructSize =
sizeof(results);
2461 results.nGlyphs = (DWORD)(characterIndex + 1);
2463 unsigned int textWLength;
2464 wchar_t* textW = dr2d_to_wchar_gdi(pFont->
pContext, text, (
int)results.nGlyphs, &textWLength);
2467 if (results.nGlyphs > pGDIContextData->glyphCacheSize) {
2468 free(pGDIContextData->pGlyphCache);
2469 pGDIContextData->pGlyphCache = (
int*)malloc(
sizeof(
int) * results.nGlyphs);
2470 pGDIContextData->glyphCacheSize = results.nGlyphs;
2473 results.lpCaretPos = pGDIContextData->pGlyphCache;
2474 if (results.lpCaretPos !=
NULL)
2476 if (GetCharacterPlacementW(pGDIContextData->hDC, textW, results.nGlyphs, 0, &results, GCP_USEKERNING) != 0)
2478 if (pTextCursorPosXOut) {
2479 *pTextCursorPosXOut = (float)results.lpCaretPos[characterIndex];
2491 wchar_t* dr2d_to_wchar_gdi(
dr2d_context* pContext,
const char* text,
size_t textSizeInBytes,
unsigned int* characterCountOut)
2493 if (pContext ==
NULL || text ==
NULL) {
2498 if (pGDIData ==
NULL) {
2507 if (pGDIData->wcharBuffer ==
NULL) {
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;
2520 wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (
int)textSizeInBytes,
NULL, 0);
2521 if (wcharCount == 0) {
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;
2531 wcharCount = MultiByteToWideChar(CP_UTF8, 0, text, (
int)textSizeInBytes, pGDIData->wcharBuffer, pGDIData->wcharBufferLength);
2532 if (wcharCount == 0) {
2537 if (characterCountOut !=
NULL) {
2538 *characterCountOut = wcharCount;
2541 return pGDIData->wcharBuffer;
2552 #ifndef DR2D_NO_CAIRO
2556 cairo_surface_t* pCairoSurface;
2557 cairo_t* pCairoContext;
2561 float clipRectRight;
2562 float clipRectBottom;
2564 } cairo_surface_data;
2568 cairo_font_face_t* pFace;
2569 cairo_scaled_font_t* pFont;
2579 cairo_surface_t* pCairoSurface;
2582 unsigned char* pData;
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);
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);
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);
2610 void* dr2d_map_image_data_cairo(
dr2d_image* pImage,
unsigned accessFlags);
2611 void dr2d_unmap_image_data_cairo(
dr2d_image* pImage);
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);
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;
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;
2656 return dr2d_create_context(callbacks, 0,
sizeof(cairo_surface_data),
sizeof(cairo_font_data),
sizeof(cairo_image_data),
NULL);
2666 if (pSurface !=
NULL) {
2668 if (pCairoData !=
NULL) {
2669 pCairoData->pCairoContext = cairo_reference(cr);
2670 pCairoData->pCairoSurface = cairo_surface_reference(cairo_get_target(cr));
2680 if (pCairoData !=
NULL) {
2681 return pCairoData->pCairoSurface;
2690 if (pCairoData !=
NULL) {
2691 return pCairoData->pCairoContext;
2698 bool dr2d_on_create_context_cairo(
dr2d_context* pContext,
const void* pUserData)
2700 assert(pContext !=
NULL);
2707 void dr2d_on_delete_context_cairo(
dr2d_context* pContext)
2709 assert(pContext !=
NULL);
2713 bool dr2d_on_create_surface_cairo(
dr2d_surface* pSurface,
float width,
float height)
2715 assert(pSurface !=
NULL);
2718 if (pCairoData ==
NULL) {
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) {
2728 pCairoData->pCairoContext = cairo_create(pCairoData->pCairoSurface);
2729 if (pCairoData->pCairoContext ==
NULL) {
2730 cairo_surface_destroy(pCairoData->pCairoSurface);
2734 pCairoData->pCairoSurface =
NULL;
2735 pCairoData->pCairoContext =
NULL;
2742 void dr2d_on_delete_surface_cairo(
dr2d_surface* pSurface)
2744 assert(pSurface !=
NULL);
2747 if (pCairoData !=
NULL)
2749 cairo_destroy(pCairoData->pCairoContext);
2750 cairo_surface_destroy(pCairoData->pCairoSurface);
2754 bool dr2d_on_create_font_cairo(
dr2d_font* pFont)
2757 if (pCairoFont ==
NULL) {
2761 cairo_font_slant_t cairoSlant = CAIRO_FONT_SLANT_NORMAL;
2763 cairoSlant = CAIRO_FONT_SLANT_ITALIC;
2765 cairoSlant = CAIRO_FONT_SLANT_OBLIQUE;
2768 cairo_font_weight_t cairoWeight = CAIRO_FONT_WEIGHT_NORMAL;
2770 cairoWeight = CAIRO_FONT_WEIGHT_BOLD;
2773 pCairoFont->pFace = cairo_toy_font_face_create(pFont->
family, cairoSlant, cairoWeight);
2774 if (pCairoFont->pFace ==
NULL) {
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));
2783 cairo_matrix_init_identity(&ctm);
2785 cairo_font_options_t* options = cairo_font_options_create();
2786 cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_SUBPIXEL);
2788 pCairoFont->pFont = cairo_scaled_font_create(pCairoFont->pFace, &fontMatrix, &ctm, options);
2789 if (pCairoFont->pFont ==
NULL) {
2790 cairo_font_face_destroy(pCairoFont->pFace);
2796 cairo_font_extents_t fontMetrics;
2797 cairo_scaled_font_extents(pCairoFont->pFont, &fontMetrics);
2799 pCairoFont->metrics.ascent = fontMetrics.ascent;
2800 pCairoFont->metrics.descent = fontMetrics.descent;
2802 pCairoFont->metrics.lineHeight = fontMetrics.ascent + fontMetrics.descent;
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;
2813 void dr2d_on_delete_font_cairo(
dr2d_font* pFont)
2816 if (pCairoFont ==
NULL) {
2820 cairo_scaled_font_destroy(pCairoFont->pFont);
2821 cairo_font_face_destroy(pCairoFont->pFace);
2824 bool dr2d_on_create_image_cairo(
dr2d_image* pImage,
unsigned int stride,
const void* pData)
2827 if (pCairoImage ==
NULL) {
2831 size_t dataSize = pImage->
height * pImage->
width * 4;
2832 pCairoImage->pData = malloc(dataSize);
2833 if (pCairoImage->pData ==
NULL) {
2839 for (
unsigned int iRow = 0; iRow < pImage->
height; ++iRow)
2841 const unsigned int iRowSrc = iRow;
2842 const unsigned int iRowDst = iRow;
2844 for (
unsigned int iCol = 0; iCol < pImage->
width; ++iCol)
2846 unsigned int srcTexel = ((
const unsigned int*)(pData ))[ (iRowSrc * (stride/4)) + iCol];
2847 unsigned int* dstTexel = ((
unsigned int*)(pCairoImage->pData)) + (iRowDst * pImage->
width) + iCol;
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;
2854 srcTexelB = (
unsigned int)(srcTexelB * (srcTexelA / 255.0f));
2855 srcTexelG = (
unsigned int)(srcTexelG * (srcTexelA / 255.0f));
2856 srcTexelR = (
unsigned int)(srcTexelR * (srcTexelA / 255.0f));
2858 *dstTexel = (srcTexelR << 16) | (srcTexelG << 8) | (srcTexelB << 0) | (srcTexelA << 24);
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);
2872 void dr2d_on_delete_image_cairo(
dr2d_image* pImage)
2875 if (pCairoImage ==
NULL) {
2879 cairo_surface_destroy(pCairoImage->pCairoSurface);
2880 free(pCairoImage->pData);
2886 assert(pSurface !=
NULL);
2889 if (pCairoData ==
NULL) {
2893 cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_NONE);
2898 assert(pSurface !=
NULL);
2901 if (pCairoData ==
NULL) {
2905 cairo_set_antialias(pCairoData->pCairoContext, CAIRO_ANTIALIAS_DEFAULT);
2915 void dr2d_draw_rect_cairo(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color)
2917 assert(pSurface !=
NULL);
2920 if (pCairoData !=
NULL)
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);
2928 void dr2d_draw_rect_outline_cairo(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color,
float outlineWidth)
2931 if (pCairoData ==
NULL) {
2935 cairo_t* cr = pCairoData->pCairoContext;
2937 cairo_set_source_rgba(cr, color.
r / 255.0, color.
g / 255.0, color.
b / 255.0, color.
a / 255.0);
2940 cairo_rectangle(cr, left, top, outlineWidth, bottom - top);
2942 cairo_rectangle(cr, right - outlineWidth, top, outlineWidth, bottom - top);
2944 cairo_rectangle(cr, left + outlineWidth, top, right - left - (outlineWidth*2), outlineWidth);
2946 cairo_rectangle(cr, left + outlineWidth, bottom - outlineWidth, right - left - (outlineWidth*2), outlineWidth);
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)
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);
2956 void dr2d_draw_round_rect_cairo(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom,
dr2d_color color,
float radius)
2961 dr2d_draw_rect_cairo(pSurface, left, top, right, bottom, color);
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)
2969 dr2d_draw_rect_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth);
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)
2977 dr2d_draw_rect_with_outline_cairo(pSurface, left, top, right, bottom, color, outlineWidth, outlineColor);
2983 if (pCairoSurface ==
NULL) {
2987 cairo_t* cr = pCairoSurface->pCairoContext;
2991 if (pCairoFont ==
NULL) {
2997 if (textSizeInBytes != (
size_t)-1) {
2998 textNT = malloc(textSizeInBytes + 1);
2999 memcpy(textNT, text, textSizeInBytes);
3000 textNT[textSizeInBytes] =
'\0';
3002 textNT = (
char*)text;
3006 cairo_set_scaled_font(cr, pCairoFont->pFont);
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);
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);
3024 if (textNT != text) {
3032 if (pCairoSurface ==
NULL) {
3037 if (pCairoImage ==
NULL) {
3041 cairo_t* cr = pCairoSurface->pCairoContext;
3044 cairo_translate(cr, pArgs->
dstX, pArgs->
dstY);
3056 cairo_set_source_surface(cr, pCairoImage->pCairoSurface, pArgs->
srcX, pArgs->
srcY);
3057 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
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);
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);
3073 cairo_set_operator(cr2, CAIRO_OPERATOR_ATOP);
3085 cairo_set_source_surface(cr, pTempImageSurface, pArgs->
srcX, pArgs->
srcY);
3086 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
3091 cairo_surface_destroy(pTempImageSurface);
3098 void dr2d_set_clip_cairo(
dr2d_surface* pSurface,
float left,
float top,
float right,
float bottom)
3101 if (pCairoData ==
NULL) {
3105 pCairoData->clipRectLeft = left;
3106 pCairoData->clipRectTop = top;
3107 pCairoData->clipRectRight = right;
3108 pCairoData->clipRectBottom = bottom;
3110 cairo_reset_clip(pCairoData->pCairoContext);
3111 cairo_rectangle(pCairoData->pCairoContext, left, top, right - left, bottom - top);
3112 cairo_clip(pCairoData->pCairoContext);
3115 void dr2d_get_clip_cairo(
dr2d_surface* pSurface,
float* pLeftOut,
float* pTopOut,
float* pRightOut,
float* pBottomOut)
3124 if (pCairoData ==
NULL) {
3128 if (pLeftOut) { *pLeftOut = pCairoData->clipRectLeft; }
3129 if (pTopOut) { *pTopOut = pCairoData->clipRectTop; }
3130 if (pRightOut) { *pRightOut = pCairoData->clipRectRight; }
3131 if (pBottomOut) { *pBottomOut = pCairoData->clipRectBottom; }
3141 void* dr2d_map_image_data_cairo(
dr2d_image* pImage,
unsigned accessFlags)
3148 void dr2d_unmap_image_data_cairo(
dr2d_image* pImage)
3157 if (pCairoFont ==
NULL) {
3162 *pMetricsOut = pCairoFont->metrics;
3168 static size_t dr2d__utf32_to_utf8(
unsigned int utf32,
char* utf8,
size_t utf8Size)
3172 size_t utf8ByteCount = 0;
3175 }
else if (utf32 < 0x800) {
3177 }
else if (utf32 < 0x10000) {
3179 }
else if (utf32 < 0x110000) {
3183 if (utf8ByteCount > utf8Size) {
3184 if (utf8 !=
NULL && utf8Size > 0) {
3190 utf8 += utf8ByteCount;
3191 if (utf8ByteCount < utf8Size) {
3195 const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
3196 switch (utf8ByteCount)
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]);
3205 return utf8ByteCount;
3211 if (pCairoFont ==
NULL) {
3217 size_t utf8len = dr2d__utf32_to_utf8(utf32, utf8,
sizeof(utf8));
3223 cairo_text_extents_t glyphExtents;
3224 cairo_scaled_font_text_extents(pCairoFont->pFont, utf8, &glyphExtents);
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;
3239 bool dr2d_measure_string_cairo(
dr2d_font* pFont,
const char* text,
size_t textSizeInBytes,
float* pWidthOut,
float* pHeightOut)
3242 if (pCairoFont ==
NULL) {
3249 if (textSizeInBytes != (
size_t)-1) {
3250 textNT = malloc(textSizeInBytes + 1);
3251 if (textNT ==
NULL) {
3254 memcpy(textNT, text, textSizeInBytes);
3255 textNT[textSizeInBytes] =
'\0';
3257 textNT = (
char*)text;
3261 cairo_text_extents_t textMetrics;
3262 cairo_scaled_font_text_extents(pCairoFont->pFont, textNT, &textMetrics);
3265 *pWidthOut = textMetrics.x_advance;
3269 *pHeightOut = pCairoFont->metrics.ascent + pCairoFont->metrics.descent;
3273 if (textNT != text) {
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)
3283 if (pCairoFont ==
NULL) {
3287 cairo_glyph_t* pGlyphs =
NULL;
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) {
3294 float cursorPosX = 0;
3298 float runningPosX = 0;
3299 for (
int iGlyph = 0; iGlyph < glyphCount; ++iGlyph)
3301 cairo_text_extents_t glyphMetrics;
3302 cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics);
3304 float glyphLeft = runningPosX;
3305 float glyphRight = glyphLeft + glyphMetrics.x_advance;
3308 if (inputPosX >= glyphLeft && inputPosX <= glyphRight)
3310 float glyphHalf = glyphLeft + ceilf(((glyphRight - glyphLeft) / 2.0f));
3311 if (inputPosX <= glyphHalf) {
3312 cursorPosX = glyphLeft;
3315 cursorPosX = glyphRight;
3316 charIndex = iGlyph + 1;
3324 if (glyphRight > maxWidth)
3326 cursorPosX = maxWidth;
3332 runningPosX = glyphRight;
3334 cursorPosX = runningPosX;
3340 cairo_glyph_free(pGlyphs);
3342 if (pTextCursorPosXOut) {
3343 *pTextCursorPosXOut = cursorPosX;
3345 if (pCharacterIndexOut) {
3346 *pCharacterIndexOut = charIndex;
3352 bool dr2d_get_text_cursor_position_from_char_cairo(
dr2d_font* pFont,
const char* text,
size_t characterIndex,
float* pTextCursorPosXOut)
3355 if (pCairoFont ==
NULL) {
3359 cairo_glyph_t* pGlyphs =
NULL;
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) {
3366 float cursorPosX = 0;
3369 for (
int iGlyph = 0; iGlyph < glyphCount; ++iGlyph)
3371 if (iGlyph == (
int)characterIndex) {
3375 cairo_text_extents_t glyphMetrics;
3376 cairo_scaled_font_glyph_extents(pCairoFont->pFont, pGlyphs + iGlyph, 1, &glyphMetrics);
3378 cursorPosX += glyphMetrics.x_advance;
3381 cairo_glyph_free(pGlyphs);
3383 if (pTextCursorPosXOut) {
3384 *pTextCursorPosXOut = cursorPosX;