FreeRDP/rdtk/librdtk/rdtk_nine_patch.c
Ondrej Holy 892cbe3261 Fix various memory leaks reported by Coverity
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
2021-04-27 14:25:20 +02:00

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;
}