19#include <winpr/config.h>
20#include <winpr/assert.h>
22#include <rdtk/config.h>
24#include "rdtk_resources.h"
26#include "rdtk_nine_patch.h"
28#if defined(WINPR_WITH_PNG)
35static int rdtk_image_copy_alpha_blend(uint8_t* pDstData,
int nDstStep,
int nXDst,
int nYDst,
36 int nWidth,
int nHeight,
const uint8_t* pSrcData,
37 int nSrcStep,
int nXSrc,
int nYSrc)
39 WINPR_ASSERT(pDstData);
40 WINPR_ASSERT(pSrcData);
42 for (
int y = 0; y < nHeight; y++)
44 const uint8_t* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
45 uint8_t* pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
47 for (
int x = 0; x < nWidth; x++)
49 uint8_t B = pSrcPixel[0];
50 uint8_t G = pSrcPixel[1];
51 uint8_t R = pSrcPixel[2];
52 uint8_t A = pSrcPixel[3];
66 pDstPixel[0] = B + (pDstPixel[0] * (255 - A) + (255 / 2)) / 255;
67 pDstPixel[1] = G + (pDstPixel[1] * (255 - A) + (255 / 2)) / 255;
68 pDstPixel[2] = R + (pDstPixel[2] * (255 - A) + (255 / 2)) / 255;
79int rdtk_nine_patch_draw(rdtkSurface* surface,
int nXDst,
int nYDst,
int nWidth,
int nHeight,
80 rdtkNinePatch* ninePatch)
82 WINPR_ASSERT(surface);
83 WINPR_ASSERT(ninePatch);
85 if (nWidth < ninePatch->width)
86 nWidth = ninePatch->width;
88 if (nHeight < ninePatch->height)
89 nHeight = ninePatch->height;
91 WINPR_UNUSED(nHeight);
93 int scaleWidth = nWidth - (ninePatch->width - ninePatch->scaleWidth);
94 int nSrcStep = ninePatch->scanline;
95 const uint8_t* pSrcData = ninePatch->data;
96 uint8_t* pDstData = surface->data;
97 WINPR_ASSERT(surface->scanline <= INT_MAX);
98 int nDstStep = (int)surface->scanline;
105 int width = ninePatch->scaleLeft;
106 int height = ninePatch->scaleTop;
108 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
109 height, pSrcData, nSrcStep, nXSrc, nYSrc);
115 nXSrc = ninePatch->scaleLeft;
117 height = ninePatch->scaleTop;
119 while (x < (nXSrc + scaleWidth))
121 width = (nXSrc + scaleWidth) - x;
123 if (width > ninePatch->scaleWidth)
124 width = ninePatch->scaleWidth;
126 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
127 height, pSrcData, nSrcStep, nXSrc, nYSrc);
134 nXSrc = ninePatch->scaleRight;
136 width = ninePatch->width - ninePatch->scaleRight;
137 height = ninePatch->scaleTop;
139 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
140 height, pSrcData, nSrcStep, nXSrc, nYSrc);
146 y = ninePatch->scaleTop;
149 nYSrc = ninePatch->scaleTop;
150 width = ninePatch->scaleLeft;
151 height = ninePatch->scaleHeight;
153 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
154 height, pSrcData, nSrcStep, nXSrc, nYSrc);
160 nXSrc = ninePatch->scaleLeft;
161 nYSrc = ninePatch->scaleTop;
162 height = ninePatch->scaleHeight;
164 while (x < (nXSrc + scaleWidth))
166 width = (nXSrc + scaleWidth) - x;
168 if (width > ninePatch->scaleWidth)
169 width = ninePatch->scaleWidth;
173 rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
174 pSrcData, nSrcStep, nXSrc, nYSrc);
182 nXSrc = ninePatch->scaleRight;
183 nYSrc = ninePatch->scaleTop;
184 width = ninePatch->width - ninePatch->scaleRight;
185 height = ninePatch->scaleHeight;
187 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
188 height, pSrcData, nSrcStep, nXSrc, nYSrc);
194 y = ninePatch->scaleBottom;
197 nYSrc = ninePatch->scaleBottom;
198 width = ninePatch->scaleLeft;
199 height = ninePatch->height - ninePatch->scaleBottom;
201 const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
202 height, pSrcData, nSrcStep, nXSrc, nYSrc);
208 nXSrc = ninePatch->scaleLeft;
209 nYSrc = ninePatch->scaleBottom;
210 height = ninePatch->height - ninePatch->scaleBottom;
212 while (x < (nXSrc + scaleWidth))
214 width = (nXSrc + scaleWidth) - x;
216 if (width > ninePatch->scaleWidth)
217 width = ninePatch->scaleWidth;
221 rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
222 pSrcData, nSrcStep, nXSrc, nYSrc);
230 nXSrc = ninePatch->scaleRight;
231 nYSrc = ninePatch->scaleBottom;
232 width = ninePatch->width - ninePatch->scaleRight;
233 height = ninePatch->height - ninePatch->scaleBottom;
234 return rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
235 pSrcData, nSrcStep, nXSrc, nYSrc);
239static uint32_t rdtk_get_image_pixel(
const wImage* image,
size_t y,
size_t x)
242 WINPR_ASSERT(y < image->height);
243 WINPR_ASSERT(x < image->width);
244 WINPR_ASSERT(image->bytesPerPixel > 0);
245 WINPR_ASSERT(image->bytesPerPixel <= 4);
246 WINPR_ASSERT(image->scanline >= image->width * image->bytesPerPixel);
248 const size_t offset = 1ull * image->scanline * y;
249 const BYTE* data = &image->data[offset + 1ull * image->bytesPerPixel * x];
252 for (
size_t i = 0; i < image->bytesPerPixel; i++)
261static BOOL rdtk_nine_patch_get_scale_lr(rdtkNinePatch* ninePatch,
wImage* image)
264 WINPR_ASSERT(ninePatch);
266 WINPR_ASSERT(image->data);
267 WINPR_ASSERT(image->width > 0);
272 for (uint32_t y = 0; y < image->height; y++)
274 for (uint32_t x = 1; x < image->width - 1; x++)
276 const uint32_t pixel = rdtk_get_image_pixel(image, y, x);
293 if ((beg <= 0) || (end <= 0))
296 WINPR_ASSERT(beg <= INT32_MAX);
297 WINPR_ASSERT(end <= INT32_MAX);
298 ninePatch->scaleLeft = (int32_t)beg - 1;
299 ninePatch->scaleRight = (int32_t)end - 1;
300 ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft;
305static bool lineValid(
const wImage* image,
size_t y)
307 for (
size_t x = 0; x < image->width; x++)
309 const uint32_t p = rdtk_get_image_pixel(image, y, x);
318static BOOL rdtk_nine_patch_get_scale_ht(rdtkNinePatch* ninePatch,
wImage* image)
321 WINPR_ASSERT(ninePatch);
323 WINPR_ASSERT(image->data);
324 WINPR_ASSERT(image->height > 0);
329 for (uint32_t y = 1; y < image->height - 1; y++)
333 if (lineValid(image, y))
338 if (!lineValid(image, y))
346 if ((beg <= 0) || (end <= 0))
349 WINPR_ASSERT(beg <= INT32_MAX);
350 WINPR_ASSERT(end <= INT32_MAX);
351 ninePatch->scaleTop = (int32_t)beg - 1;
352 ninePatch->scaleBottom = (int32_t)end - 1;
353 ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop;
359static BOOL rdtk_nine_patch_get_fill_lr(rdtkNinePatch* ninePatch,
wImage* image)
362 WINPR_ASSERT(ninePatch);
364 WINPR_ASSERT(image->data);
365 WINPR_ASSERT(image->width > 0);
366 WINPR_ASSERT(image->height > 0);
371 for (uint32_t y = 0; y < image->height; y++)
373 for (uint32_t x = 1; x < image->width - 1; x++)
375 const uint32_t pixel =
376 rdtk_get_image_pixel(image, image->height - 1 - y, x);
393 if ((beg <= 0) || (end <= 0))
396 WINPR_ASSERT(beg <= INT32_MAX);
397 WINPR_ASSERT(end <= INT32_MAX);
399 ninePatch->fillLeft = (int32_t)beg - 1;
400 ninePatch->fillRight = (int32_t)end - 1;
401 ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft;
407static BOOL rdtk_nine_patch_get_fill_ht(rdtkNinePatch* ninePatch,
wImage* image)
410 WINPR_ASSERT(ninePatch);
412 WINPR_ASSERT(image->data);
413 WINPR_ASSERT(image->width > 0);
414 WINPR_ASSERT(image->height > 0);
419 for (uint32_t y = 1; y < image->height - 1; y++)
421 for (uint32_t x = 0; x < image->width; x++)
423 const uint32_t pixel =
424 rdtk_get_image_pixel(image, y, image->width - 1 - x);
441 if ((beg <= 0) || (end <= 0))
444 WINPR_ASSERT(beg <= INT32_MAX);
445 WINPR_ASSERT(end <= INT32_MAX);
446 ninePatch->scaleTop = (int32_t)beg - 1;
447 ninePatch->scaleBottom = (int32_t)end - 1;
448 ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop;
453int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch,
wImage* image)
456 WINPR_ASSERT(ninePatch);
458 ninePatch->image = image;
461 if (!rdtk_nine_patch_get_scale_lr(ninePatch, image))
464 if (!rdtk_nine_patch_get_scale_ht(ninePatch, image))
468 if (!rdtk_nine_patch_get_fill_lr(ninePatch, image))
471 if (!rdtk_nine_patch_get_fill_ht(ninePatch, image))
475 WINPR_ASSERT(image->width >= 2);
476 WINPR_ASSERT(image->height >= 2);
477 WINPR_ASSERT(image->scanline > 0);
478 WINPR_ASSERT(image->width <= INT32_MAX);
479 WINPR_ASSERT(image->height <= INT32_MAX);
480 WINPR_ASSERT(image->scanline <= INT32_MAX);
481 WINPR_ASSERT(image->data);
483 ninePatch->width = (int32_t)image->width - 2;
484 ninePatch->height = (int32_t)image->height - 2;
485 ninePatch->data = &image->data[image->scanline + 4];
486 ninePatch->scanline = (int32_t)image->scanline;
491rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine)
493 WINPR_ASSERT(engine);
494 rdtkNinePatch* ninePatch = (rdtkNinePatch*)calloc(1,
sizeof(rdtkNinePatch));
499 ninePatch->engine = engine;
503void rdtk_nine_patch_free(rdtkNinePatch* ninePatch)
508 winpr_image_free(ninePatch->image, TRUE);
512int rdtk_nine_patch_engine_init(rdtkEngine* engine)
515 rdtkNinePatch* ninePatch = NULL;
517 WINPR_ASSERT(engine);
519 if (!engine->button9patch)
523 const uint8_t* data = NULL;
527 size = rdtk_get_embedded_resource_file(
"btn_default_normal.9." FILE_EXT, &data);
531 image = winpr_image_new();
534 status = winpr_image_read_buffer(image, data, (
size_t)size);
539 ninePatch = engine->button9patch = rdtk_nine_patch_new(engine);
543 const int rc = rdtk_nine_patch_set_image(ninePatch, image);
548 winpr_image_free(image, TRUE);
551 winpr_image_free(image, TRUE);
554 if (!engine->textField9patch)
556 const uint8_t* data = NULL;
559 rdtk_get_embedded_resource_file(
"textfield_default.9." FILE_EXT, &data);
564 image = winpr_image_new();
567 status = winpr_image_read_buffer(image, data, (
size_t)size);
572 ninePatch = engine->textField9patch = rdtk_nine_patch_new(engine);
576 const int rc = rdtk_nine_patch_set_image(ninePatch, image);
581 winpr_image_free(image, TRUE);
584 winpr_image_free(image, TRUE);
590int rdtk_nine_patch_engine_uninit(rdtkEngine* engine)
592 WINPR_ASSERT(engine);
593 if (engine->button9patch)
595 rdtk_nine_patch_free(engine->button9patch);
596 engine->button9patch = NULL;
599 if (engine->textField9patch)
601 rdtk_nine_patch_free(engine->textField9patch);
602 engine->textField9patch = NULL;