2011-10-21 01:28:59 +04:00
|
|
|
/**
|
2012-10-09 07:02:04 +04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2011-10-21 01:28:59 +04:00
|
|
|
* Graphical Objects
|
|
|
|
*
|
|
|
|
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
2016-04-05 18:07:45 +03:00
|
|
|
* Copyright 2016 Armin Novak <armin.novak@thincast.com>
|
|
|
|
* Copyright 2016 Thincast Technologies GmbH
|
2011-10-21 01:28:59 +04:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2022-02-16 13:20:38 +03:00
|
|
|
#include <freerdp/config.h>
|
2012-08-15 01:09:01 +04:00
|
|
|
|
2012-11-22 05:21:08 +04:00
|
|
|
#include <winpr/crt.h>
|
|
|
|
|
2014-09-15 11:01:05 +04:00
|
|
|
#include <freerdp/log.h>
|
2023-03-14 12:39:18 +03:00
|
|
|
#include <freerdp/freerdp.h>
|
2011-10-21 01:28:59 +04:00
|
|
|
#include <freerdp/gdi/dc.h>
|
2011-11-09 08:26:44 +04:00
|
|
|
#include <freerdp/gdi/shape.h>
|
|
|
|
#include <freerdp/gdi/region.h>
|
2011-10-21 01:28:59 +04:00
|
|
|
#include <freerdp/gdi/bitmap.h>
|
|
|
|
|
2016-07-19 14:02:08 +03:00
|
|
|
#include "clipping.h"
|
2016-04-05 18:07:45 +03:00
|
|
|
#include "drawing.h"
|
|
|
|
#include "brush.h"
|
2011-10-21 01:28:59 +04:00
|
|
|
#include "graphics.h"
|
|
|
|
|
2014-09-15 11:01:05 +04:00
|
|
|
#define TAG FREERDP_TAG("gdi")
|
2011-11-09 21:16:09 +04:00
|
|
|
/* Bitmap Class */
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 SrcFormat,
|
|
|
|
BYTE* data)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
UINT32 nSrcStep = 0;
|
|
|
|
UINT32 nDstStep = 0;
|
|
|
|
BYTE* pSrcData = NULL;
|
|
|
|
BYTE* pDstData = NULL;
|
|
|
|
HGDI_BITMAP bitmap = NULL;
|
2016-07-19 14:02:08 +03:00
|
|
|
|
|
|
|
if (!gdi)
|
|
|
|
return NULL;
|
|
|
|
|
2022-04-28 06:43:31 +03:00
|
|
|
nDstStep = nWidth * FreeRDPGetBytesPerPixel(gdi->dstFormat);
|
2023-08-22 10:41:28 +03:00
|
|
|
pDstData = winpr_aligned_malloc(1ull * nHeight * nDstStep, 16);
|
2014-09-16 00:08:06 +04:00
|
|
|
|
|
|
|
if (!pDstData)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
pSrcData = data;
|
2022-04-28 06:43:31 +03:00
|
|
|
nSrcStep = nWidth * FreeRDPGetBytesPerPixel(SrcFormat);
|
2016-04-23 12:25:55 +03:00
|
|
|
|
2024-05-23 11:07:14 +03:00
|
|
|
if (!freerdp_image_copy_no_overlap(pDstData, gdi->dstFormat, nDstStep, 0, 0, nWidth, nHeight,
|
|
|
|
pSrcData, SrcFormat, nSrcStep, 0, 0, &gdi->palette,
|
|
|
|
FREERDP_FLIP_NONE))
|
2016-04-23 12:25:55 +03:00
|
|
|
{
|
2022-05-11 12:28:55 +03:00
|
|
|
winpr_aligned_free(pDstData);
|
2016-04-23 12:25:55 +03:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
bitmap = gdi_CreateBitmap(nWidth, nHeight, gdi->dstFormat, pDstData);
|
2011-10-21 01:28:59 +04:00
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
static BOOL gdi_Bitmap_New(rdpContext* context, rdpBitmap* bitmap)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
gdiBitmap* gdi_bitmap = NULL;
|
2011-10-21 01:28:59 +04:00
|
|
|
rdpGdi* gdi = context->gdi;
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_bitmap = (gdiBitmap*)bitmap;
|
2011-10-21 01:28:59 +04:00
|
|
|
gdi_bitmap->hdc = gdi_CreateCompatibleDC(gdi->hdc);
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2015-04-26 23:28:49 +03:00
|
|
|
if (!gdi_bitmap->hdc)
|
2015-04-14 11:14:23 +03:00
|
|
|
return FALSE;
|
2011-10-21 01:28:59 +04:00
|
|
|
|
2014-07-08 23:07:19 +04:00
|
|
|
if (!bitmap->data)
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_bitmap->bitmap = gdi_CreateCompatibleBitmap(gdi->hdc, bitmap->width, bitmap->height);
|
2011-10-21 01:28:59 +04:00
|
|
|
else
|
2016-04-05 18:07:45 +03:00
|
|
|
{
|
2016-04-19 22:30:28 +03:00
|
|
|
UINT32 format = bitmap->format;
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_bitmap->bitmap =
|
|
|
|
gdi_create_bitmap(gdi, bitmap->width, bitmap->height, format, bitmap->data);
|
2016-04-05 18:07:45 +03:00
|
|
|
}
|
2011-10-21 01:28:59 +04:00
|
|
|
|
2015-04-14 11:14:23 +03:00
|
|
|
if (!gdi_bitmap->bitmap)
|
|
|
|
{
|
2015-05-08 22:39:23 +03:00
|
|
|
gdi_DeleteDC(gdi_bitmap->hdc);
|
2020-06-02 10:28:47 +03:00
|
|
|
gdi_bitmap->hdc = NULL;
|
2015-04-14 11:14:23 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2016-07-18 18:45:30 +03:00
|
|
|
gdi_bitmap->hdc->format = gdi_bitmap->bitmap->format;
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->bitmap);
|
2011-10-21 01:28:59 +04:00
|
|
|
gdi_bitmap->org_bitmap = NULL;
|
2015-04-14 11:14:23 +03:00
|
|
|
return TRUE;
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
static void gdi_Bitmap_Free(rdpContext* context, rdpBitmap* bitmap)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
|
2011-10-21 01:28:59 +04:00
|
|
|
|
2014-07-08 23:07:19 +04:00
|
|
|
if (gdi_bitmap)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2018-10-16 16:56:17 +03:00
|
|
|
if (gdi_bitmap->hdc)
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_SelectObject(gdi_bitmap->hdc, (HGDIOBJECT)gdi_bitmap->org_bitmap);
|
2018-10-16 16:56:17 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_DeleteObject((HGDIOBJECT)gdi_bitmap->bitmap);
|
2011-10-21 01:28:59 +04:00
|
|
|
gdi_DeleteDC(gdi_bitmap->hdc);
|
2022-05-11 12:28:55 +03:00
|
|
|
winpr_aligned_free(bitmap->data);
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
2018-02-13 12:18:43 +03:00
|
|
|
|
|
|
|
free(bitmap);
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
static BOOL gdi_Bitmap_Paint(rdpContext* context, rdpBitmap* bitmap)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
gdiBitmap* gdi_bitmap = (gdiBitmap*)bitmap;
|
2016-07-14 13:42:24 +03:00
|
|
|
UINT32 width = bitmap->right - bitmap->left + 1;
|
|
|
|
UINT32 height = bitmap->bottom - bitmap->top + 1;
|
2019-11-06 17:24:51 +03:00
|
|
|
return gdi_BitBlt(context->gdi->primary->hdc, bitmap->left, bitmap->top, width, height,
|
|
|
|
gdi_bitmap->hdc, 0, 0, GDI_SRCCOPY, &context->gdi->palette);
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static BOOL gdi_Bitmap_Decompress(rdpContext* context, rdpBitmap* bitmap, const BYTE* pSrcData,
|
|
|
|
UINT32 DstWidth, UINT32 DstHeight, UINT32 bpp, UINT32 length,
|
|
|
|
BOOL compressed, UINT32 codecId)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
int status = 0;
|
2016-07-15 17:23:00 +03:00
|
|
|
UINT32 SrcSize = length;
|
2014-09-12 09:03:19 +04:00
|
|
|
rdpGdi* gdi = context->gdi;
|
2018-10-22 17:30:20 +03:00
|
|
|
UINT32 size = DstWidth * DstHeight;
|
2016-07-15 17:23:00 +03:00
|
|
|
bitmap->compressed = FALSE;
|
|
|
|
bitmap->format = gdi->dstFormat;
|
2018-10-22 17:30:20 +03:00
|
|
|
|
2022-04-28 06:43:31 +03:00
|
|
|
if ((FreeRDPGetBytesPerPixel(bitmap->format) == 0) || (DstWidth == 0) || (DstHeight == 0) ||
|
2019-11-06 17:24:51 +03:00
|
|
|
(DstWidth > UINT32_MAX / DstHeight) ||
|
2022-04-28 06:43:31 +03:00
|
|
|
(size > (UINT32_MAX / FreeRDPGetBytesPerPixel(bitmap->format))))
|
2022-12-12 15:05:48 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "invalid input data");
|
2018-10-22 17:30:20 +03:00
|
|
|
return FALSE;
|
2022-12-12 15:05:48 +03:00
|
|
|
}
|
2018-10-22 17:30:20 +03:00
|
|
|
|
2022-04-28 06:43:31 +03:00
|
|
|
size *= FreeRDPGetBytesPerPixel(bitmap->format);
|
2018-10-22 17:30:20 +03:00
|
|
|
bitmap->length = size;
|
2022-05-11 12:28:55 +03:00
|
|
|
bitmap->data = (BYTE*)winpr_aligned_malloc(bitmap->length, 16);
|
2016-09-06 15:20:07 +03:00
|
|
|
|
|
|
|
if (!bitmap->data)
|
|
|
|
return FALSE;
|
2014-09-12 09:03:19 +04:00
|
|
|
|
|
|
|
if (compressed)
|
2012-07-24 23:05:22 +04:00
|
|
|
{
|
2022-05-26 16:33:49 +03:00
|
|
|
if ((codecId == RDP_CODEC_ID_REMOTEFX) || (codecId == RDP_CODEC_ID_IMAGE_REMOTEFX))
|
|
|
|
{
|
|
|
|
REGION16 invalidRegion;
|
|
|
|
region16_init(&invalidRegion);
|
|
|
|
|
2022-05-31 12:48:30 +03:00
|
|
|
if (!rfx_process_message(context->codecs->rfx, pSrcData, SrcSize, bitmap->left,
|
2022-06-23 08:57:38 +03:00
|
|
|
bitmap->top, bitmap->data, bitmap->format, gdi->stride,
|
|
|
|
gdi->height, &invalidRegion))
|
2022-05-26 16:33:49 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "rfx_process_message failed");
|
2022-05-26 16:33:49 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
else if (codecId == RDP_CODEC_ID_NSCODEC)
|
|
|
|
{
|
|
|
|
status = nsc_process_message(context->codecs->nsc, 32, DstWidth, DstHeight, pSrcData,
|
|
|
|
SrcSize, bitmap->data, bitmap->format, 0, 0, 0, DstWidth,
|
|
|
|
DstHeight, FREERDP_FLIP_VERTICAL);
|
|
|
|
|
|
|
|
if (status < 1)
|
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "nsc_process_message failed");
|
2022-05-26 16:33:49 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2024-05-23 11:07:14 +03:00
|
|
|
return freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth,
|
|
|
|
DstHeight, pSrcData, PIXEL_FORMAT_XRGB32, 0, 0, 0,
|
|
|
|
&gdi->palette, FREERDP_FLIP_VERTICAL);
|
2022-05-26 16:33:49 +03:00
|
|
|
}
|
|
|
|
else if (bpp < 32)
|
2014-09-12 09:03:19 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!interleaved_decompress(context->codecs->interleaved, pSrcData, SrcSize, DstWidth,
|
|
|
|
DstHeight, bpp, bitmap->data, bitmap->format, 0, 0, 0,
|
|
|
|
DstWidth, DstHeight, &gdi->palette))
|
2022-12-12 15:05:48 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "interleaved_decompress failed");
|
2016-07-18 12:16:36 +03:00
|
|
|
return FALSE;
|
2022-12-12 15:05:48 +03:00
|
|
|
}
|
2014-09-12 09:03:19 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-05-02 11:55:44 +03:00
|
|
|
const BOOL fidelity =
|
|
|
|
freerdp_settings_get_bool(context->settings, FreeRDP_DrawAllowDynamicColorFidelity);
|
|
|
|
freerdp_planar_switch_bgr(context->codecs->planar, fidelity);
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!planar_decompress(context->codecs->planar, pSrcData, SrcSize, DstWidth, DstHeight,
|
|
|
|
bitmap->data, bitmap->format, 0, 0, 0, DstWidth, DstHeight,
|
|
|
|
TRUE))
|
2022-12-12 15:05:48 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "planar_decompress failed");
|
2016-07-18 12:16:36 +03:00
|
|
|
return FALSE;
|
2022-12-12 15:05:48 +03:00
|
|
|
}
|
2014-09-12 09:03:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-17 11:09:37 +03:00
|
|
|
const UINT32 SrcFormat = gdi_get_pixel_format(bpp);
|
2022-04-28 06:43:31 +03:00
|
|
|
const size_t sbpp = FreeRDPGetBytesPerPixel(SrcFormat);
|
|
|
|
const size_t dbpp = FreeRDPGetBytesPerPixel(bitmap->format);
|
2016-07-18 12:16:36 +03:00
|
|
|
|
2018-10-17 12:36:32 +03:00
|
|
|
if ((sbpp == 0) || (dbpp == 0))
|
2018-10-16 18:10:03 +03:00
|
|
|
return FALSE;
|
2018-10-17 12:36:32 +03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
const size_t dstSize = SrcSize * dbpp / sbpp;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
if (dstSize < bitmap->length)
|
2022-12-12 15:05:48 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "dstSize %" PRIuz " < bitmap->length %" PRIu32, dstSize,
|
|
|
|
bitmap->length);
|
2018-10-17 12:36:32 +03:00
|
|
|
return FALSE;
|
2022-12-12 15:05:48 +03:00
|
|
|
}
|
2018-10-17 12:36:32 +03:00
|
|
|
}
|
2018-10-16 18:10:03 +03:00
|
|
|
|
2024-05-23 11:07:14 +03:00
|
|
|
if (!freerdp_image_copy_no_overlap(bitmap->data, bitmap->format, 0, 0, 0, DstWidth,
|
|
|
|
DstHeight, pSrcData, SrcFormat, 0, 0, 0, &gdi->palette,
|
|
|
|
FREERDP_FLIP_VERTICAL))
|
2022-12-12 15:05:48 +03:00
|
|
|
{
|
2023-01-23 14:03:18 +03:00
|
|
|
WLog_ERR(TAG, "freerdp_image_copy failed");
|
2016-07-18 12:16:36 +03:00
|
|
|
return FALSE;
|
2022-12-12 15:05:48 +03:00
|
|
|
}
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
|
|
|
|
2015-04-14 11:14:23 +03:00
|
|
|
return TRUE;
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL primary)
|
2011-10-21 02:18:45 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpGdi* gdi = NULL;
|
2017-05-11 14:34:37 +03:00
|
|
|
|
|
|
|
if (!context)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi = context->gdi;
|
2018-10-16 16:56:17 +03:00
|
|
|
|
2017-05-11 14:34:37 +03:00
|
|
|
if (!gdi)
|
|
|
|
return FALSE;
|
2011-10-21 02:18:45 +04:00
|
|
|
|
|
|
|
if (primary)
|
|
|
|
gdi->drawing = gdi->primary;
|
|
|
|
else
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi->drawing = (gdiBitmap*)bitmap;
|
2015-04-14 11:14:23 +03:00
|
|
|
|
|
|
|
return TRUE;
|
2011-10-21 02:18:45 +04:00
|
|
|
}
|
|
|
|
|
2011-11-09 21:16:09 +04:00
|
|
|
/* Glyph Class */
|
2021-08-27 13:47:46 +03:00
|
|
|
static BOOL gdi_Glyph_New(rdpContext* context, rdpGlyph* glyph)
|
2011-11-09 08:26:44 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
BYTE* data = NULL;
|
|
|
|
gdiGlyph* gdi_glyph = NULL;
|
2016-07-18 18:45:30 +03:00
|
|
|
|
|
|
|
if (!context || !glyph)
|
|
|
|
return FALSE;
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_glyph = (gdiGlyph*)glyph;
|
2011-11-09 08:26:44 +04:00
|
|
|
gdi_glyph->hdc = gdi_GetDC();
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2015-04-14 11:14:23 +03:00
|
|
|
if (!gdi_glyph->hdc)
|
|
|
|
return FALSE;
|
2011-11-09 08:26:44 +04:00
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
gdi_glyph->hdc->format = PIXEL_FORMAT_MONO;
|
2011-11-09 08:26:44 +04:00
|
|
|
data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj);
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2015-04-14 11:14:23 +03:00
|
|
|
if (!data)
|
|
|
|
{
|
|
|
|
gdi_DeleteDC(gdi_glyph->hdc);
|
|
|
|
return FALSE;
|
|
|
|
}
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_glyph->bitmap = gdi_CreateBitmap(glyph->cx, glyph->cy, PIXEL_FORMAT_MONO, data);
|
2016-04-05 18:07:45 +03:00
|
|
|
|
2015-04-14 11:14:23 +03:00
|
|
|
if (!gdi_glyph->bitmap)
|
|
|
|
{
|
|
|
|
gdi_DeleteDC(gdi_glyph->hdc);
|
2022-05-11 12:28:55 +03:00
|
|
|
winpr_aligned_free(data);
|
2015-04-14 11:14:23 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
2011-11-09 08:26:44 +04:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->bitmap);
|
2011-11-09 08:26:44 +04:00
|
|
|
gdi_glyph->org_bitmap = NULL;
|
2015-04-14 11:14:23 +03:00
|
|
|
return TRUE;
|
2011-11-09 08:26:44 +04:00
|
|
|
}
|
|
|
|
|
2016-04-05 18:07:45 +03:00
|
|
|
static void gdi_Glyph_Free(rdpContext* context, rdpGlyph* glyph)
|
2011-11-09 08:26:44 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
gdiGlyph* gdi_glyph = NULL;
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_glyph = (gdiGlyph*)glyph;
|
2011-11-09 08:26:44 +04:00
|
|
|
|
2014-07-08 23:07:19 +04:00
|
|
|
if (gdi_glyph)
|
2011-11-09 08:26:44 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
gdi_SelectObject(gdi_glyph->hdc, (HGDIOBJECT)gdi_glyph->org_bitmap);
|
|
|
|
gdi_DeleteObject((HGDIOBJECT)gdi_glyph->bitmap);
|
2011-11-09 08:26:44 +04:00
|
|
|
gdi_DeleteDC(gdi_glyph->hdc);
|
2016-07-18 15:30:26 +03:00
|
|
|
free(glyph->aj);
|
|
|
|
free(glyph);
|
2011-11-09 08:26:44 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static BOOL gdi_Glyph_Draw(rdpContext* context, const rdpGlyph* glyph, INT32 x, INT32 y, INT32 w,
|
|
|
|
INT32 h, INT32 sx, INT32 sy, BOOL fOpRedundant)
|
2011-11-09 08:26:44 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
const gdiGlyph* gdi_glyph = NULL;
|
|
|
|
rdpGdi* gdi = NULL;
|
|
|
|
HGDI_BRUSH brush = NULL;
|
2016-08-16 15:30:18 +03:00
|
|
|
BOOL rc = FALSE;
|
2016-07-18 15:16:13 +03:00
|
|
|
|
|
|
|
if (!context || !glyph)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi = context->gdi;
|
2021-08-02 13:13:34 +03:00
|
|
|
gdi_glyph = (const gdiGlyph*)glyph;
|
2016-08-17 10:26:59 +03:00
|
|
|
|
2022-12-09 16:05:00 +03:00
|
|
|
if (!fOpRedundant)
|
2016-08-17 10:26:59 +03:00
|
|
|
{
|
|
|
|
GDI_RECT rect = { 0 };
|
|
|
|
|
|
|
|
if (x > 0)
|
|
|
|
rect.left = x;
|
|
|
|
|
|
|
|
if (y > 0)
|
|
|
|
rect.top = y;
|
|
|
|
|
|
|
|
if (x + w > 0)
|
|
|
|
rect.right = x + w - 1;
|
|
|
|
|
|
|
|
if (y + h > 0)
|
|
|
|
rect.bottom = y + h - 1;
|
|
|
|
|
|
|
|
if ((rect.left < rect.right) && (rect.top < rect.bottom))
|
|
|
|
{
|
|
|
|
brush = gdi_CreateSolidBrush(gdi->drawing->hdc->bkColor);
|
|
|
|
|
|
|
|
if (!brush)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi_FillRect(gdi->drawing->hdc, &rect, brush);
|
|
|
|
gdi_DeleteObject((HGDIOBJECT)brush);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-16 15:30:18 +03:00
|
|
|
brush = gdi_CreateSolidBrush(gdi->drawing->hdc->textColor);
|
|
|
|
|
|
|
|
if (!brush)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi_SelectObject(gdi->drawing->hdc, (HGDIOBJECT)brush);
|
2019-11-06 17:24:51 +03:00
|
|
|
rc = gdi_BitBlt(gdi->drawing->hdc, x, y, w, h, gdi_glyph->hdc, sx, sy, GDI_GLYPH_ORDER,
|
|
|
|
&context->gdi->palette);
|
2016-08-16 15:30:18 +03:00
|
|
|
gdi_DeleteObject((HGDIOBJECT)brush);
|
|
|
|
return rc;
|
2011-11-09 08:26:44 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static BOOL gdi_Glyph_BeginDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
|
|
|
|
UINT32 bgcolor, UINT32 fgcolor, BOOL fOpRedundant)
|
2018-11-19 15:58:53 +03:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpGdi* gdi = NULL;
|
2016-07-18 13:36:22 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (!context || !context->gdi)
|
2016-07-19 14:02:08 +03:00
|
|
|
return FALSE;
|
2016-07-18 13:36:22 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
gdi = context->gdi;
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (!gdi->drawing || !gdi->drawing->hdc)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!fOpRedundant)
|
2016-08-16 15:30:18 +03:00
|
|
|
{
|
2018-11-19 15:58:53 +03:00
|
|
|
if (!gdi_decode_color(gdi, bgcolor, &bgcolor, NULL))
|
|
|
|
return FALSE;
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (!gdi_decode_color(gdi, fgcolor, &fgcolor, NULL))
|
2016-08-16 15:30:18 +03:00
|
|
|
return FALSE;
|
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
gdi_SetClipRgn(gdi->drawing->hdc, x, y, width, height);
|
|
|
|
gdi_SetTextColor(gdi->drawing->hdc, bgcolor);
|
|
|
|
gdi_SetBkColor(gdi->drawing->hdc, fgcolor);
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (1)
|
|
|
|
{
|
|
|
|
GDI_RECT rect = { 0 };
|
|
|
|
HGDI_BRUSH brush = gdi_CreateSolidBrush(fgcolor);
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (!brush)
|
|
|
|
return FALSE;
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (x > 0)
|
|
|
|
rect.left = x;
|
2016-08-16 15:30:18 +03:00
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
if (y > 0)
|
|
|
|
rect.top = y;
|
|
|
|
|
|
|
|
rect.right = x + width - 1;
|
|
|
|
rect.bottom = y + height - 1;
|
|
|
|
|
|
|
|
if ((x + width > rect.left) && (y + height > rect.top))
|
|
|
|
gdi_FillRect(gdi->drawing->hdc, &rect, brush);
|
|
|
|
|
|
|
|
gdi_DeleteObject((HGDIOBJECT)brush);
|
|
|
|
}
|
|
|
|
|
|
|
|
return gdi_SetNullClipRgn(gdi->drawing->hdc);
|
2016-08-16 15:30:18 +03:00
|
|
|
}
|
|
|
|
|
2018-11-19 15:58:53 +03:00
|
|
|
return TRUE;
|
2011-11-09 08:26:44 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
static BOOL gdi_Glyph_EndDraw(rdpContext* context, INT32 x, INT32 y, INT32 width, INT32 height,
|
|
|
|
UINT32 bgcolor, UINT32 fgcolor)
|
2011-11-09 08:26:44 +04:00
|
|
|
{
|
2024-01-23 18:49:54 +03:00
|
|
|
rdpGdi* gdi = NULL;
|
2016-07-19 14:02:08 +03:00
|
|
|
|
|
|
|
if (!context || !context->gdi)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi = context->gdi;
|
|
|
|
|
|
|
|
if (!gdi->drawing || !gdi->drawing->hdc)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
gdi_SetNullClipRgn(gdi->drawing->hdc);
|
2015-04-14 11:14:23 +03:00
|
|
|
return TRUE;
|
2011-11-09 08:26:44 +04:00
|
|
|
}
|
|
|
|
|
2011-11-09 21:16:09 +04:00
|
|
|
/* Graphics Module */
|
2015-04-14 11:14:23 +03:00
|
|
|
BOOL gdi_register_graphics(rdpGraphics* graphics)
|
2011-10-21 01:28:59 +04:00
|
|
|
{
|
2023-10-19 18:05:44 +03:00
|
|
|
rdpBitmap bitmap = { 0 };
|
|
|
|
rdpGlyph glyph = { 0 };
|
2016-07-21 11:07:42 +03:00
|
|
|
bitmap.size = sizeof(gdiBitmap);
|
|
|
|
bitmap.New = gdi_Bitmap_New;
|
|
|
|
bitmap.Free = gdi_Bitmap_Free;
|
|
|
|
bitmap.Paint = gdi_Bitmap_Paint;
|
|
|
|
bitmap.Decompress = gdi_Bitmap_Decompress;
|
|
|
|
bitmap.SetSurface = gdi_Bitmap_SetSurface;
|
|
|
|
graphics_register_bitmap(graphics, &bitmap);
|
|
|
|
glyph.size = sizeof(gdiGlyph);
|
|
|
|
glyph.New = gdi_Glyph_New;
|
|
|
|
glyph.Free = gdi_Glyph_Free;
|
|
|
|
glyph.Draw = gdi_Glyph_Draw;
|
|
|
|
glyph.BeginDraw = gdi_Glyph_BeginDraw;
|
|
|
|
glyph.EndDraw = gdi_Glyph_EndDraw;
|
|
|
|
graphics_register_glyph(graphics, &glyph);
|
2015-04-14 11:14:23 +03:00
|
|
|
return TRUE;
|
2011-10-21 01:28:59 +04:00
|
|
|
}
|