892cbe3261
Covscan report contains various memory leak defects which were marked as important. I have spent some time analyzing them and although they were marked as important, most of them are in error cases, so probably nothing serious. Let's fix most of them anyway. The rest are false positives, or too complicated to fix, or already fixed in master, or simply I am unsure about them. Relates: https://github.com/FreeRDP/FreeRDP/issues/6981
449 lines
10 KiB
C
449 lines
10 KiB
C
/**
|
|
* RdTk: Remote Desktop Toolkit
|
|
*
|
|
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <freerdp/codec/color.h>
|
|
|
|
#include "rdtk_resources.h"
|
|
|
|
#include "rdtk_nine_patch.h"
|
|
|
|
static int rdtk_image_copy_alpha_blend(BYTE* pDstData, int nDstStep, int nXDst, int nYDst,
|
|
int nWidth, int nHeight, BYTE* pSrcData, int nSrcStep,
|
|
int nXSrc, int nYSrc)
|
|
{
|
|
int x, y;
|
|
BYTE A, R, G, B;
|
|
|
|
for (y = 0; y < nHeight; y++)
|
|
{
|
|
const BYTE* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
|
|
BYTE* pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
|
|
|
|
for (x = 0; x < nWidth; x++)
|
|
{
|
|
B = pSrcPixel[0];
|
|
G = pSrcPixel[1];
|
|
R = pSrcPixel[2];
|
|
A = pSrcPixel[3];
|
|
pSrcPixel += 4;
|
|
|
|
if (A == 255)
|
|
{
|
|
pDstPixel[0] = B;
|
|
pDstPixel[1] = G;
|
|
pDstPixel[2] = R;
|
|
}
|
|
else
|
|
{
|
|
R = (R * A) / 255;
|
|
G = (G * A) / 255;
|
|
B = (B * A) / 255;
|
|
pDstPixel[0] = B + (pDstPixel[0] * (255 - A) + (255 / 2)) / 255;
|
|
pDstPixel[1] = G + (pDstPixel[1] * (255 - A) + (255 / 2)) / 255;
|
|
pDstPixel[2] = R + (pDstPixel[2] * (255 - A) + (255 / 2)) / 255;
|
|
}
|
|
|
|
pDstPixel[3] = 0xFF;
|
|
pDstPixel += 4;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int rdtk_nine_patch_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight,
|
|
rdtkNinePatch* ninePatch)
|
|
{
|
|
int x, y;
|
|
int width;
|
|
int height;
|
|
int nXSrc;
|
|
int nYSrc;
|
|
int nSrcStep;
|
|
int nDstStep;
|
|
BYTE* pSrcData;
|
|
BYTE* pDstData;
|
|
int scaleWidth;
|
|
|
|
if (nWidth < ninePatch->width)
|
|
nWidth = ninePatch->width;
|
|
|
|
if (nHeight < ninePatch->height)
|
|
nHeight = ninePatch->height;
|
|
|
|
scaleWidth = nWidth - (ninePatch->width - ninePatch->scaleWidth);
|
|
nSrcStep = ninePatch->scanline;
|
|
pSrcData = ninePatch->data;
|
|
pDstData = surface->data;
|
|
nDstStep = surface->scanline;
|
|
/* top */
|
|
x = 0;
|
|
y = 0;
|
|
/* top left */
|
|
nXSrc = 0;
|
|
nYSrc = 0;
|
|
width = ninePatch->scaleLeft;
|
|
height = ninePatch->scaleTop;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
/* top middle (scalable) */
|
|
nXSrc = ninePatch->scaleLeft;
|
|
nYSrc = 0;
|
|
height = ninePatch->scaleTop;
|
|
|
|
while (x < (nXSrc + scaleWidth))
|
|
{
|
|
width = (nXSrc + scaleWidth) - x;
|
|
|
|
if (width > ninePatch->scaleWidth)
|
|
width = ninePatch->scaleWidth;
|
|
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
|
|
pSrcData, nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
}
|
|
|
|
/* top right */
|
|
nXSrc = ninePatch->scaleRight;
|
|
nYSrc = 0;
|
|
width = ninePatch->width - ninePatch->scaleRight;
|
|
height = ninePatch->scaleTop;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
/* middle */
|
|
x = 0;
|
|
y = ninePatch->scaleTop;
|
|
/* middle left */
|
|
nXSrc = 0;
|
|
nYSrc = ninePatch->scaleTop;
|
|
width = ninePatch->scaleLeft;
|
|
height = ninePatch->scaleHeight;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
/* middle (scalable) */
|
|
nXSrc = ninePatch->scaleLeft;
|
|
nYSrc = ninePatch->scaleTop;
|
|
height = ninePatch->scaleHeight;
|
|
|
|
while (x < (nXSrc + scaleWidth))
|
|
{
|
|
width = (nXSrc + scaleWidth) - x;
|
|
|
|
if (width > ninePatch->scaleWidth)
|
|
width = ninePatch->scaleWidth;
|
|
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
|
|
pSrcData, nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
}
|
|
|
|
/* middle right */
|
|
nXSrc = ninePatch->scaleRight;
|
|
nYSrc = ninePatch->scaleTop;
|
|
width = ninePatch->width - ninePatch->scaleRight;
|
|
height = ninePatch->scaleHeight;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
/* bottom */
|
|
x = 0;
|
|
y = ninePatch->scaleBottom;
|
|
/* bottom left */
|
|
nXSrc = 0;
|
|
nYSrc = ninePatch->scaleBottom;
|
|
width = ninePatch->scaleLeft;
|
|
height = ninePatch->height - ninePatch->scaleBottom;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
/* bottom middle (scalable) */
|
|
nXSrc = ninePatch->scaleLeft;
|
|
nYSrc = ninePatch->scaleBottom;
|
|
height = ninePatch->height - ninePatch->scaleBottom;
|
|
|
|
while (x < (nXSrc + scaleWidth))
|
|
{
|
|
width = (nXSrc + scaleWidth) - x;
|
|
|
|
if (width > ninePatch->scaleWidth)
|
|
width = ninePatch->scaleWidth;
|
|
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
|
|
pSrcData, nSrcStep, nXSrc, nYSrc);
|
|
x += width;
|
|
}
|
|
|
|
/* bottom right */
|
|
nXSrc = ninePatch->scaleRight;
|
|
nYSrc = ninePatch->scaleBottom;
|
|
width = ninePatch->width - ninePatch->scaleRight;
|
|
height = ninePatch->height - ninePatch->scaleBottom;
|
|
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height, pSrcData,
|
|
nSrcStep, nXSrc, nYSrc);
|
|
return 1;
|
|
}
|
|
|
|
int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image)
|
|
{
|
|
int x, y;
|
|
BYTE* data;
|
|
int beg, end;
|
|
int scanline;
|
|
UINT32* pixel;
|
|
int width, height;
|
|
ninePatch->image = image;
|
|
width = image->width;
|
|
height = image->height;
|
|
scanline = image->scanline;
|
|
data = image->data;
|
|
/* parse scalable area */
|
|
beg = end = -1;
|
|
pixel = (UINT32*)&data[4]; /* (1, 0) */
|
|
|
|
for (x = 1; x < width - 1; x++)
|
|
{
|
|
if (beg < 0)
|
|
{
|
|
if (*pixel)
|
|
{
|
|
beg = x;
|
|
}
|
|
}
|
|
else if (end < 0)
|
|
{
|
|
if (!(*pixel))
|
|
{
|
|
end = x;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pixel++;
|
|
}
|
|
|
|
ninePatch->scaleLeft = beg - 1;
|
|
ninePatch->scaleRight = end - 1;
|
|
ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft;
|
|
beg = end = -1;
|
|
pixel = (UINT32*)&data[scanline]; /* (0, 1) */
|
|
|
|
for (y = 1; y < height - 1; y++)
|
|
{
|
|
if (beg < 0)
|
|
{
|
|
if (*pixel)
|
|
{
|
|
beg = y;
|
|
}
|
|
}
|
|
else if (end < 0)
|
|
{
|
|
if (!(*pixel))
|
|
{
|
|
end = y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pixel = (UINT32*)&((BYTE*)pixel)[scanline];
|
|
}
|
|
|
|
ninePatch->scaleTop = beg - 1;
|
|
ninePatch->scaleBottom = end - 1;
|
|
ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop;
|
|
/* parse fillable area */
|
|
beg = end = -1;
|
|
pixel = (UINT32*)&data[((height - 1) * scanline) + 4]; /* (1, height - 1) */
|
|
|
|
for (x = 1; x < width - 1; x++)
|
|
{
|
|
if (beg < 0)
|
|
{
|
|
if (*pixel)
|
|
{
|
|
beg = x;
|
|
}
|
|
}
|
|
else if (end < 0)
|
|
{
|
|
if (!(*pixel))
|
|
{
|
|
end = x;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pixel++;
|
|
}
|
|
|
|
ninePatch->fillLeft = beg - 1;
|
|
ninePatch->fillRight = end - 1;
|
|
ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft;
|
|
beg = end = -1;
|
|
pixel = (UINT32*)&data[((width - 1) * 4) + scanline]; /* (width - 1, 1) */
|
|
|
|
for (y = 1; y < height - 1; y++)
|
|
{
|
|
if (beg < 0)
|
|
{
|
|
if (*pixel)
|
|
{
|
|
beg = y;
|
|
}
|
|
}
|
|
else if (end < 0)
|
|
{
|
|
if (!(*pixel))
|
|
{
|
|
end = y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pixel = (UINT32*)&((BYTE*)pixel)[scanline];
|
|
}
|
|
|
|
ninePatch->fillTop = beg - 1;
|
|
ninePatch->fillBottom = end - 1;
|
|
ninePatch->fillHeight = ninePatch->fillBottom - ninePatch->fillTop;
|
|
/* cut out borders from image */
|
|
ninePatch->width = width - 2;
|
|
ninePatch->height = height - 2;
|
|
ninePatch->data = &data[scanline + 4]; /* (1, 1) */
|
|
ninePatch->scanline = scanline;
|
|
#if 0
|
|
printf("width: %d height: %d\n", ninePatch->width, ninePatch->height);
|
|
printf("scale: left: %d right: %d top: %d bottom: %d\n",
|
|
ninePatch->scaleLeft, ninePatch->scaleRight,
|
|
ninePatch->scaleTop, ninePatch->scaleBottom);
|
|
printf("fill: left: %d right: %d top: %d bottom: %d\n",
|
|
ninePatch->fillLeft, ninePatch->fillRight,
|
|
ninePatch->fillTop, ninePatch->fillBottom);
|
|
#endif
|
|
return 1;
|
|
}
|
|
|
|
rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine)
|
|
{
|
|
rdtkNinePatch* ninePatch;
|
|
ninePatch = (rdtkNinePatch*)calloc(1, sizeof(rdtkNinePatch));
|
|
|
|
if (!ninePatch)
|
|
return NULL;
|
|
|
|
ninePatch->engine = engine;
|
|
return ninePatch;
|
|
}
|
|
|
|
void rdtk_nine_patch_free(rdtkNinePatch* ninePatch)
|
|
{
|
|
if (!ninePatch)
|
|
return;
|
|
|
|
winpr_image_free(ninePatch->image, TRUE);
|
|
free(ninePatch);
|
|
}
|
|
|
|
int rdtk_nine_patch_engine_init(rdtkEngine* engine)
|
|
{
|
|
int status;
|
|
wImage* image = NULL;
|
|
rdtkNinePatch* ninePatch;
|
|
|
|
if (!engine->button9patch)
|
|
{
|
|
int size;
|
|
BYTE* data;
|
|
status = -1;
|
|
size = rdtk_get_embedded_resource_file("btn_default_normal.9.png", &data);
|
|
|
|
if (size > 0)
|
|
{
|
|
image = winpr_image_new();
|
|
|
|
if (image)
|
|
status = winpr_image_read_buffer(image, data, size);
|
|
}
|
|
|
|
if (status > 0)
|
|
{
|
|
ninePatch = engine->button9patch = rdtk_nine_patch_new(engine);
|
|
|
|
if (ninePatch)
|
|
rdtk_nine_patch_set_image(ninePatch, image);
|
|
else
|
|
winpr_image_free(image, TRUE);
|
|
}
|
|
else
|
|
winpr_image_free(image, TRUE);
|
|
}
|
|
|
|
if (!engine->textField9patch)
|
|
{
|
|
int size;
|
|
BYTE* data;
|
|
status = -1;
|
|
size = rdtk_get_embedded_resource_file("textfield_default.9.png", &data);
|
|
image = NULL;
|
|
|
|
if (size > 0)
|
|
{
|
|
image = winpr_image_new();
|
|
|
|
if (image)
|
|
status = winpr_image_read_buffer(image, data, size);
|
|
}
|
|
|
|
if (status > 0)
|
|
{
|
|
ninePatch = engine->textField9patch = rdtk_nine_patch_new(engine);
|
|
|
|
if (ninePatch)
|
|
rdtk_nine_patch_set_image(ninePatch, image);
|
|
else
|
|
winpr_image_free(image, TRUE);
|
|
}
|
|
else
|
|
winpr_image_free(image, TRUE);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int rdtk_nine_patch_engine_uninit(rdtkEngine* engine)
|
|
{
|
|
if (engine->button9patch)
|
|
{
|
|
rdtk_nine_patch_free(engine->button9patch);
|
|
engine->button9patch = NULL;
|
|
}
|
|
|
|
if (engine->textField9patch)
|
|
{
|
|
rdtk_nine_patch_free(engine->textField9patch);
|
|
engine->textField9patch = NULL;
|
|
}
|
|
|
|
return 1;
|
|
}
|