Milestone 5: deliver embedded RDP sessions and lifecycle hardening

This commit is contained in:
Keith Smith
2026-03-03 18:59:26 -07:00
parent 230a401386
commit 36006bd4aa
2941 changed files with 724359 additions and 77 deletions

100
third_party/FreeRDP/rdtk/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,100 @@
# RdTk: Remote Desktop Toolkit
# rdtk cmake build script
#
# 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.
# Soname versioning
set(RDTK_VERSION_MAJOR "0")
set(RDTK_VERSION_MINOR "2")
set(RDTK_VERSION_REVISION "0")
set(RDTK_VERSION "${RDTK_VERSION_MAJOR}.${RDTK_VERSION_MINOR}.${RDTK_VERSION_REVISION}")
set(RDTK_VERSION_FULL "${RDTK_VERSION}")
set(RDTK_API_VERSION "${RDTK_VERSION_MAJOR}")
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/)
if(NOT FREERDP_UNIFIED_BUILD)
cmake_minimum_required(VERSION 3.13)
project(RdTk VERSION ${RDTK_VERSION} LANGUAGES C)
include(ProjectCStandard)
set(WINPR_VERSION_MAJOR 3)
include(ExportAllSymbols)
else()
set(WINPR_VERSION_MAJOR ${FREERDP_VERSION_MAJOR})
endif()
# Include our extra modules
include(CommonConfigOptions)
# Include cmake modules
include(CheckIncludeFiles)
include(CheckLibraryExists)
include(CheckStructHasMember)
include(TestBigEndian)
# Check for cmake compatibility (enable/disable features)
include(CheckCmakeCompat)
include(FindFeature)
include(CheckCCompilerFlag)
include(CMakePackageConfigHelpers)
include(SetFreeRDPCMakeInstallDir)
include(WarnUnmaintained)
warn_unmaintained(${MODULE_NAME} "-DWITH_RDTK=OFF")
option(RDTK_FORCE_STATIC_BUILD "Force RDTK to be build as static library (recommended)" OFF)
if(RDTK_FORCE_STATIC_BUILD)
set(BUILD_SHARED_LIBS OFF)
endif()
add_compile_definitions(RDTK_EXPORTS)
if(NOT IOS)
check_include_files(stdbool.h RDTK_HAVE_STDBOOL_H)
if(NOT RDTK_HAVE_STDBOOL_H)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/../compat/stdbool)
endif()
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
if(FREERDP_UNIFIED_BUILD)
include_directories(${PROJECT_SOURCE_DIR}/winpr/include)
include_directories(${PROJECT_BINARY_DIR}/winpr/include)
else()
find_package(WinPR 3 REQUIRED)
include_directories(${WinPR_INCLUDE_DIR})
endif()
setfreerdpcmakeinstalldir(RDTK_CMAKE_INSTALL_DIR "rdtk${RDTK_VERSION_MAJOR}")
set(RDTK_INCLUDE_DIR include/rdtk${RDTK_API_VERSION})
add_subdirectory(librdtk)
add_subdirectory(templates)
add_subdirectory(include)
if(NOT RDTK_FORCE_STATIC_BUILD)
install(EXPORT rdtk DESTINATION ${RDTK_CMAKE_INSTALL_DIR})
endif()
if(WITH_SAMPLE)
if(WITH_X11)
add_subdirectory(sample)
endif()
endif()

View File

@@ -0,0 +1,4 @@
if(NOT RDTK_FORCE_STATIC_BUILD)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/ DESTINATION ${RDTK_INCLUDE_DIR} FILES_MATCHING PATTERN "*.h")
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/rdtk DESTINATION ${RDTK_INCLUDE_DIR} FILES_MATCHING PATTERN "*.h")
endif()

View File

@@ -0,0 +1,52 @@
/**
* 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.
*/
#ifndef RDTK_API_H
#define RDTK_API_H
#include <winpr/spec.h>
#if defined _WIN32 || defined __CYGWIN__
#ifdef RDTK_EXPORTS
#ifdef __GNUC__
#define RDTK_EXPORT __attribute__((dllexport))
#else
#define RDTK_EXPORT __declspec(dllexport)
#endif
#else
#ifdef __GNUC__
#define RDTK_EXPORT __attribute__((dllimport))
#else
#define RDTK_EXPORT __declspec(dllimport)
#endif
#endif
#else
#if __GNUC__ >= 4
#if defined(__cplusplus) && (__cplusplus >= 201703L)
#define RDTK_EXPORT [[gnu::visibility("default")]]
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 202311L)
#define RDTK_EXPORT [[gnu::visibility("default")]]
#else
#define RDTK_EXPORT __attribute__((visibility("default")))
#endif
#else
#define RDTK_EXPORT
#endif
#endif
#endif /* RDTK_API_H */

View File

@@ -0,0 +1,94 @@
/**
* 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.
*/
#ifndef RDTK_H
#define RDTK_H
#include <winpr/assert.h>
#include <winpr/winpr.h>
#include <stdint.h>
#include <rdtk/api.h>
typedef struct rdtk_engine rdtkEngine;
typedef struct rdtk_font rdtkFont;
typedef struct rdtk_glyph rdtkGlyph;
typedef struct rdtk_surface rdtkSurface;
typedef struct rdtk_button rdtkButton;
typedef struct rdtk_label rdtkLabel;
typedef struct rdtk_text_field rdtkTextField;
typedef struct rdtk_nine_patch rdtkNinePatch;
#ifdef __cplusplus
extern "C"
{
#endif
/* Engine */
RDTK_EXPORT void rdtk_engine_free(rdtkEngine* engine);
WINPR_ATTR_MALLOC(rdtk_engine_free, 1)
WINPR_ATTR_NODISCARD
RDTK_EXPORT rdtkEngine* rdtk_engine_new(void);
/* Surface */
WINPR_ATTR_NODISCARD
RDTK_EXPORT int rdtk_surface_fill(rdtkSurface* surface, uint16_t x, uint16_t y, uint16_t width,
uint16_t height, uint32_t color);
RDTK_EXPORT void rdtk_surface_free(rdtkSurface* surface);
WINPR_ATTR_MALLOC(rdtk_surface_free, 1)
WINPR_ATTR_NODISCARD
RDTK_EXPORT rdtkSurface* rdtk_surface_new(rdtkEngine* engine, uint8_t* data, uint16_t width,
uint16_t height, uint32_t scanline);
/* Font */
WINPR_ATTR_NODISCARD
RDTK_EXPORT int rdtk_font_draw_text(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst,
rdtkFont* font, const char* text);
/* Button */
WINPR_ATTR_NODISCARD
RDTK_EXPORT int rdtk_button_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst,
uint16_t nWidth, uint16_t nHeight, rdtkButton* button,
const char* text);
/* Label */
WINPR_ATTR_NODISCARD
RDTK_EXPORT int rdtk_label_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst,
uint16_t nWidth, uint16_t nHeight, rdtkLabel* label,
const char* text, uint16_t hAlign, uint16_t vAlign);
/* TextField */
WINPR_ATTR_NODISCARD
RDTK_EXPORT int rdtk_text_field_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst,
uint16_t nWidth, uint16_t nHeight,
rdtkTextField* textField, const char* text);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_H */

View File

@@ -0,0 +1,70 @@
# 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.
set(MODULE_NAME "rdtk")
set(MODULE_PREFIX "RDTK")
set(${MODULE_PREFIX}_SRCS
rdtk_resources.c
rdtk_resources.h
rdtk_surface.c
rdtk_surface.h
rdtk_font.c
rdtk_font.h
rdtk_button.c
rdtk_button.h
rdtk_label.c
rdtk_label.h
rdtk_nine_patch.c
rdtk_nine_patch.h
rdtk_text_field.c
rdtk_text_field.h
rdtk_engine.c
rdtk_engine.h
)
addtargetwithresourcefile(${MODULE_NAME} FALSE "${RDTK_VERSION}" ${MODULE_PREFIX}_SRCS)
list(APPEND ${MODULE_PREFIX}_LIBS winpr)
target_include_directories(${MODULE_NAME} INTERFACE $<INSTALL_INTERFACE:include>)
target_link_libraries(${MODULE_NAME} PRIVATE ${${MODULE_PREFIX}_LIBS})
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "RdTk")
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
add_subdirectory(test)
endif()
if(NOT RDTK_FORCE_STATIC_BUILD)
installwithrpath(
TARGETS
${MODULE_NAME}
COMPONENT
libraries
EXPORT
rdtk
ARCHIVE
DESTINATION
${CMAKE_INSTALL_LIBDIR}
LIBRARY
DESTINATION
${CMAKE_INSTALL_LIBDIR}
RUNTIME
DESTINATION
${CMAKE_INSTALL_BINDIR}
)
endif()

View File

@@ -0,0 +1,134 @@
/**
* 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.
*/
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <rdtk/config.h>
#include "rdtk_font.h"
#include "rdtk_button.h"
int rdtk_button_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst, uint16_t nWidth,
uint16_t nHeight, rdtkButton* button, const char* text)
{
uint16_t textWidth = 0;
uint16_t textHeight = 0;
WINPR_ASSERT(surface);
WINPR_ASSERT(button);
WINPR_ASSERT(text);
rdtkEngine* engine = surface->engine;
rdtkFont* font = engine->font;
rdtkNinePatch* ninePatch = button->ninePatch;
const int rc1 = rdtk_font_text_draw_size(font, &textWidth, &textHeight, text);
if (rc1 < 0)
return rc1;
const int rc2 = rdtk_nine_patch_draw(surface, nXDst, nYDst, nWidth, nHeight, ninePatch);
if (rc2 < 0)
return rc2;
if ((textWidth > 0) && (textHeight > 0))
{
const int wd = (ninePatch->width - ninePatch->fillWidth);
const int hd = (ninePatch->height - ninePatch->fillHeight);
const uint16_t fillWidth = nWidth - WINPR_ASSERTING_INT_CAST(uint16_t, wd);
const uint16_t fillHeight = nHeight - WINPR_ASSERTING_INT_CAST(uint16_t, hd);
uint16_t offsetX = WINPR_ASSERTING_INT_CAST(UINT16, ninePatch->fillLeft);
uint16_t offsetY = WINPR_ASSERTING_INT_CAST(UINT16, ninePatch->fillTop);
if (textWidth < fillWidth)
{
const int twd = ((fillWidth - textWidth) / 2) + ninePatch->fillLeft;
offsetX = WINPR_ASSERTING_INT_CAST(uint16_t, twd);
}
else if (textWidth < ninePatch->width)
{
const int twd = ((ninePatch->width - textWidth) / 2);
offsetX = WINPR_ASSERTING_INT_CAST(uint16_t, twd);
}
if (textHeight < fillHeight)
{
const int twd = ((fillHeight - textHeight) / 2) + ninePatch->fillTop;
offsetY = WINPR_ASSERTING_INT_CAST(uint16_t, twd);
}
else if (textHeight < ninePatch->height)
{
const int twd = ((ninePatch->height - textHeight) / 2);
offsetY = WINPR_ASSERTING_INT_CAST(uint16_t, twd);
}
return rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text);
}
return 1;
}
rdtkButton* rdtk_button_new(rdtkEngine* engine, rdtkNinePatch* ninePatch)
{
WINPR_ASSERT(engine);
WINPR_ASSERT(ninePatch);
rdtkButton* button = (rdtkButton*)calloc(1, sizeof(rdtkButton));
if (!button)
return nullptr;
button->engine = engine;
button->ninePatch = ninePatch;
return button;
}
void rdtk_button_free(rdtkButton* button)
{
free(button);
}
int rdtk_button_engine_init(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (!engine->button)
{
engine->button = rdtk_button_new(engine, engine->button9patch);
if (!engine->button)
return -1;
}
return 1;
}
int rdtk_button_engine_uninit(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (engine->button)
{
rdtk_button_free(engine->button);
engine->button = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,55 @@
/**
* 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.
*/
#ifndef RDTK_BUTTON_PRIVATE_H
#define RDTK_BUTTON_PRIVATE_H
#include <rdtk/rdtk.h>
#include "rdtk_surface.h"
#include "rdtk_nine_patch.h"
#include "rdtk_engine.h"
struct rdtk_button
{
rdtkEngine* engine;
rdtkNinePatch* ninePatch;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
int rdtk_button_engine_init(rdtkEngine* engine);
int rdtk_button_engine_uninit(rdtkEngine* engine);
void rdtk_button_free(rdtkButton* button);
WINPR_ATTR_MALLOC(rdtk_button_free, 1)
WINPR_ATTR_NODISCARD
rdtkButton* rdtk_button_new(rdtkEngine* engine, rdtkNinePatch* ninePatch);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_BUTTON_PRIVATE_H */

View File

@@ -0,0 +1,64 @@
/**
* 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.
*/
#include <winpr/assert.h>
#include <rdtk/config.h>
#include "rdtk_font.h"
#include "rdtk_nine_patch.h"
#include "rdtk_button.h"
#include "rdtk_text_field.h"
#include "rdtk_engine.h"
rdtkEngine* rdtk_engine_new(void)
{
rdtkEngine* engine = (rdtkEngine*)calloc(1, sizeof(rdtkEngine));
if (!engine)
return nullptr;
if (rdtk_font_engine_init(engine) < 0)
goto fail;
if (rdtk_nine_patch_engine_init(engine) < 0)
goto fail;
if (rdtk_button_engine_init(engine) < 0)
goto fail;
if (rdtk_text_field_engine_init(engine) < 0)
goto fail;
return engine;
fail:
rdtk_engine_free(engine);
return nullptr;
}
void rdtk_engine_free(rdtkEngine* engine)
{
if (!engine)
return;
rdtk_font_engine_uninit(engine);
rdtk_nine_patch_engine_uninit(engine);
rdtk_button_engine_uninit(engine);
rdtk_text_field_engine_uninit(engine);
free(engine);
}

View File

@@ -0,0 +1,46 @@
/**
* 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.
*/
#ifndef RDTK_ENGINE_PRIVATE_H
#define RDTK_ENGINE_PRIVATE_H
#include <rdtk/rdtk.h>
struct rdtk_engine
{
rdtkFont* font;
rdtkLabel* label;
rdtkButton* button;
rdtkNinePatch* button9patch;
rdtkTextField* textField;
rdtkNinePatch* textField9patch;
};
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef __cplusplus
}
#endif
#endif /* RDTK_ENGINE_PRIVATE_H */

View File

@@ -0,0 +1,806 @@
/**
* 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.
*/
#include <rdtk/config.h>
#include <errno.h>
#include <winpr/config.h>
#include <winpr/wtypes.h>
#include <winpr/crt.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/path.h>
#include <winpr/file.h>
#include <winpr/print.h>
#include "rdtk_engine.h"
#include "rdtk_resources.h"
#include "rdtk_surface.h"
#include "rdtk_font.h"
#if defined(WINPR_WITH_PNG)
#define FILE_EXT "png"
#else
#define FILE_EXT "bmp"
#endif
WINPR_ATTR_NODISCARD
static int rdtk_font_draw_glyph(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst,
rdtkFont* font, rdtkGlyph* glyph)
{
WINPR_ASSERT(surface);
WINPR_ASSERT(font);
WINPR_ASSERT(glyph);
nXDst += glyph->offsetX;
nYDst += glyph->offsetY;
const size_t nXSrc = WINPR_ASSERTING_INT_CAST(size_t, glyph->rectX);
const size_t nYSrc = WINPR_ASSERTING_INT_CAST(size_t, glyph->rectY);
const size_t nWidth = WINPR_ASSERTING_INT_CAST(size_t, glyph->rectWidth);
const size_t nHeight = WINPR_ASSERTING_INT_CAST(size_t, glyph->rectHeight);
const uint32_t nSrcStep = font->image->scanline;
const uint8_t* pSrcData = font->image->data;
uint8_t* pDstData = surface->data;
const uint32_t nDstStep = surface->scanline;
for (size_t y = 0; y < nHeight; y++)
{
const uint8_t* pSrcPixel = &pSrcData[((1ULL * nYSrc + y) * nSrcStep) + (4ULL * nXSrc)];
uint8_t* pDstPixel = &pDstData[((1ULL * nYDst + y) * nDstStep) + (4ULL * nXDst)];
for (size_t x = 0; x < nWidth; x++)
{
uint8_t B = pSrcPixel[0];
uint8_t G = pSrcPixel[1];
uint8_t R = pSrcPixel[2];
uint8_t A = pSrcPixel[3];
pSrcPixel += 4;
if (1)
{
/* tint black */
R = 255 - R;
G = 255 - G;
B = 255 - B;
}
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_font_draw_text(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst, rdtkFont* font,
const char* text)
{
WINPR_ASSERT(surface);
WINPR_ASSERT(font);
WINPR_ASSERT(text);
const size_t length = strlen(text);
for (size_t index = 0; index < length; index++)
{
rdtkGlyph* glyph = &font->glyphs[text[index] - 32];
const int rc = rdtk_font_draw_glyph(surface, nXDst, nYDst, font, glyph);
if (rc < 0)
return rc;
nXDst += (glyph->width + 1);
}
return 1;
}
int rdtk_font_text_draw_size(rdtkFont* font, uint16_t* width, uint16_t* height, const char* text)
{
WINPR_ASSERT(font);
WINPR_ASSERT(width);
WINPR_ASSERT(height);
WINPR_ASSERT(text);
*width = 0;
*height = 0;
const size_t length = strlen(text);
for (size_t index = 0; index < length; index++)
{
const size_t glyphIndex = WINPR_ASSERTING_INT_CAST(size_t, text[index] - 32);
if (glyphIndex < font->glyphCount)
{
rdtkGlyph* glyph = &font->glyphs[glyphIndex];
*width += (glyph->width + 1);
}
}
*height = font->height + 2;
return 1;
}
WINPR_ATTR_MALLOC(free, 1)
WINPR_ATTR_NODISCARD
static char* rdtk_font_load_descriptor_file(const char* filename, size_t* pSize)
{
WINPR_ASSERT(filename);
WINPR_ASSERT(pSize);
union
{
size_t s;
INT64 i64;
} fileSize;
FILE* fp = winpr_fopen(filename, "r");
if (!fp)
return nullptr;
if (_fseeki64(fp, 0, SEEK_END) != 0)
goto fail;
fileSize.i64 = _ftelli64(fp);
if (_fseeki64(fp, 0, SEEK_SET) != 0)
goto fail;
if (fileSize.i64 < 1)
goto fail;
{
char* buffer = (char*)calloc(fileSize.s + 4, sizeof(char));
if (!buffer)
goto fail;
{
size_t readSize = fread(buffer, fileSize.s, 1, fp);
if (readSize == 0)
{
if (!ferror(fp))
readSize = fileSize.s;
}
(void)fclose(fp);
if (readSize < 1)
{
free(buffer);
return nullptr;
}
}
buffer[fileSize.s] = '\0';
buffer[fileSize.s + 1] = '\0';
*pSize = fileSize.s;
return buffer;
}
fail:
(void)fclose(fp);
return nullptr;
}
WINPR_ATTR_NODISCARD
static int rdtk_font_convert_descriptor_code_to_utf8(const char* str, uint8_t* utf8)
{
WINPR_ASSERT(str);
WINPR_ASSERT(utf8);
const size_t len = strlen(str);
*((uint32_t*)utf8) = 0;
if (len < 1)
return 1;
if (len == 1)
{
if ((str[0] > 31) && (str[0] < 127))
{
utf8[0] = WINPR_ASSERTING_INT_CAST(uint8_t, str[0] & 0xFF);
}
}
else
{
if (str[0] == '&')
{
const char* acc = &str[1];
if (strcmp(acc, "quot;") == 0)
utf8[0] = '"';
else if (strcmp(acc, "amp;") == 0)
utf8[0] = '&';
else if (strcmp(acc, "lt;") == 0)
utf8[0] = '<';
else if (strcmp(acc, "gt;") == 0)
utf8[0] = '>';
}
}
return 1;
}
WINPR_ATTR_NODISCARD
static int rdtk_font_parse_descriptor_buffer(rdtkFont* font, char* buffer,
WINPR_ATTR_UNUSED size_t size)
{
int rc = -1;
WINPR_ASSERT(font);
const char xmlversion[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
const char xmlfont[] = "<Font ";
char* p = strstr(buffer, xmlversion);
if (!p)
goto fail;
p += sizeof(xmlversion) - 1;
p = strstr(p, xmlfont);
if (!p)
goto fail;
p += sizeof(xmlfont) - 1;
/* find closing font tag */
{
char* end = strstr(p, "</Font>");
if (!end)
goto fail;
/* parse font size */
p = strstr(p, "size=\"");
if (!p)
goto fail;
p += sizeof("size=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
errno = 0;
{
long val = strtol(p, nullptr, 0);
if ((errno != 0) || (val == 0) || (val > UINT32_MAX))
goto fail;
font->size = (UINT32)val;
}
*q = '"';
if (font->size <= 0)
goto fail;
p = q + 1;
}
/* parse font family */
p = strstr(p, "family=\"");
if (!p)
goto fail;
p += sizeof("family=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
font->family = _strdup(p);
*q = '"';
if (!font->family)
goto fail;
p = q + 1;
}
/* parse font height */
p = strstr(p, "height=\"");
if (!p)
goto fail;
p += sizeof("height=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
errno = 0;
{
const unsigned long val = strtoul(p, nullptr, 0);
if ((errno != 0) || (val > UINT16_MAX))
goto fail;
font->height = (uint16_t)val;
}
*q = '"';
if (font->height <= 0)
goto fail;
p = q + 1;
}
/* parse font style */
p = strstr(p, "style=\"");
if (!p)
goto fail;
p += sizeof("style=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
font->style = _strdup(p);
*q = '"';
if (!font->style)
goto fail;
p = q + 1;
}
// printf("size: %d family: %s height: %d style: %s\n",
// font->size, font->family, font->height, font->style);
{
char* beg = p;
size_t count = 0;
while (p < end)
{
p = strstr(p, "<Char ");
if (!p)
goto fail;
p += sizeof("<Char ") - 1;
char* r = strstr(p, "/>");
if (!r)
goto fail;
*r = '\0';
p = r + sizeof("/>");
*r = '/';
count++;
}
if (count > UINT16_MAX)
goto fail;
font->glyphCount = (uint16_t)count;
font->glyphs = nullptr;
if (count > 0)
font->glyphs = (rdtkGlyph*)calloc(font->glyphCount, sizeof(rdtkGlyph));
if (!font->glyphs)
goto fail;
p = beg;
}
{
size_t index = 0;
while (p < end)
{
p = strstr(p, "<Char ");
if (!p)
goto fail;
p += sizeof("<Char ") - 1;
char* r = strstr(p, "/>");
if (!r)
goto fail;
*r = '\0';
/* start parsing glyph */
if (index >= font->glyphCount)
goto fail;
rdtkGlyph* glyph = &font->glyphs[index];
/* parse glyph width */
p = strstr(p, "width=\"");
if (!p)
goto fail;
p += sizeof("width=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
errno = 0;
{
long val = strtol(p, nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->width = (INT32)val;
}
*q = '"';
if (glyph->width < 0)
goto fail;
p = q + 1;
}
/* parse glyph offset x,y */
p = strstr(p, "offset=\"");
if (!p)
goto fail;
p += sizeof("offset=\"") - 1;
char* tok[4] = WINPR_C_ARRAY_INIT;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
tok[0] = p;
p = strchr(tok[0] + 1, ' ');
if (!p)
goto fail;
*p = 0;
tok[1] = p + 1;
errno = 0;
{
long val = strtol(tok[0], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->offsetX = (INT32)val;
}
{
long val = strtol(tok[1], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->offsetY = (INT32)val;
}
*q = '"';
p = q + 1;
}
/* parse glyph rect x,y,w,h */
p = strstr(p, "rect=\"");
if (!p)
goto fail;
p += sizeof("rect=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
tok[0] = p;
p = strchr(tok[0] + 1, ' ');
if (!p)
goto fail;
*p = 0;
tok[1] = p + 1;
p = strchr(tok[1] + 1, ' ');
if (!p)
goto fail;
*p = 0;
tok[2] = p + 1;
p = strchr(tok[2] + 1, ' ');
if (!p)
goto fail;
*p = 0;
tok[3] = p + 1;
errno = 0;
{
long val = strtol(tok[0], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->rectX = (INT32)val;
}
{
long val = strtol(tok[1], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->rectY = (INT32)val;
}
{
long val = strtol(tok[2], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->rectWidth = (INT32)val;
}
{
long val = strtol(tok[3], nullptr, 0);
if ((errno != 0) || (val < INT32_MIN) || (val > INT32_MAX))
goto fail;
glyph->rectHeight = (INT32)val;
}
*q = '"';
p = q + 1;
}
/* parse code */
p = strstr(p, "code=\"");
if (!p)
goto fail;
p += sizeof("code=\"") - 1;
{
char* q = strchr(p, '"');
if (!q)
goto fail;
*q = '\0';
rc = rdtk_font_convert_descriptor_code_to_utf8(p, glyph->code);
if (rc < 0)
goto fail;
*q = '"';
}
/* finish parsing glyph */
p = r + sizeof("/>");
*r = '/';
index++;
}
}
}
rc = 1;
fail:
free(buffer);
return rc;
}
WINPR_ATTR_NODISCARD
static int rdtk_font_load_descriptor(rdtkFont* font, const char* filename)
{
size_t size = 0;
WINPR_ASSERT(font);
char* buffer = rdtk_font_load_descriptor_file(filename, &size);
if (!buffer)
return -1;
return rdtk_font_parse_descriptor_buffer(font, buffer, size);
}
rdtkFont* rdtk_font_new(rdtkEngine* engine, const char* path, const char* file)
{
size_t length = 0;
rdtkFont* font = nullptr;
char* fontImageFile = nullptr;
char* fontDescriptorFile = nullptr;
WINPR_ASSERT(engine);
WINPR_ASSERT(path);
WINPR_ASSERT(file);
char* fontBaseFile = GetCombinedPath(path, file);
if (!fontBaseFile)
goto cleanup;
winpr_asprintf(&fontImageFile, &length, "%s." FILE_EXT, fontBaseFile);
if (!fontImageFile)
goto cleanup;
winpr_asprintf(&fontDescriptorFile, &length, "%s.xml", fontBaseFile);
if (!fontDescriptorFile)
goto cleanup;
if (!winpr_PathFileExists(fontImageFile))
goto cleanup;
if (!winpr_PathFileExists(fontDescriptorFile))
goto cleanup;
font = (rdtkFont*)calloc(1, sizeof(rdtkFont));
if (!font)
goto cleanup;
font->engine = engine;
font->image = winpr_image_new();
if (!font->image)
goto cleanup;
{
const int status = winpr_image_read(font->image, fontImageFile);
if (status < 0)
goto cleanup;
}
{
const int status2 = rdtk_font_load_descriptor(font, fontDescriptorFile);
if (status2 < 0)
goto cleanup;
}
free(fontBaseFile);
free(fontImageFile);
free(fontDescriptorFile);
return font;
cleanup:
free(fontBaseFile);
free(fontImageFile);
free(fontDescriptorFile);
rdtk_font_free(font);
return nullptr;
}
WINPR_ATTR_MALLOC(rdtk_font_free, 1)
WINPR_ATTR_NODISCARD
static rdtkFont* rdtk_embedded_font_new(rdtkEngine* engine, const uint8_t* imageData,
size_t imageSize, const uint8_t* descriptorData,
size_t descriptorSize)
{
size_t size = 0;
WINPR_ASSERT(engine);
rdtkFont* font = (rdtkFont*)calloc(1, sizeof(rdtkFont));
if (!font)
return nullptr;
font->engine = engine;
font->image = winpr_image_new();
if (!font->image)
{
free(font);
return nullptr;
}
const int status = winpr_image_read_buffer(font->image, imageData, imageSize);
if (status < 0)
{
winpr_image_free(font->image, TRUE);
free(font);
return nullptr;
}
size = descriptorSize;
char* buffer = (char*)calloc(size + 4, sizeof(char));
if (!buffer)
goto fail;
CopyMemory(buffer, descriptorData, size);
{
const int status2 = rdtk_font_parse_descriptor_buffer(font, buffer, size);
if (status2 < 0)
goto fail;
}
return font;
fail:
rdtk_font_free(font);
return nullptr;
}
void rdtk_font_free(rdtkFont* font)
{
if (font)
{
free(font->family);
free(font->style);
winpr_image_free(font->image, TRUE);
free(font->glyphs);
free(font);
}
}
int rdtk_font_engine_init(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (!engine->font)
{
const uint8_t* imageData = nullptr;
const uint8_t* descriptorData = nullptr;
const SSIZE_T imageSize =
rdtk_get_embedded_resource_file("source_serif_pro_regular_12." FILE_EXT, &imageData);
const SSIZE_T descriptorSize =
rdtk_get_embedded_resource_file("source_serif_pro_regular_12.xml", &descriptorData);
if ((imageSize < 0) || (descriptorSize < 0))
return -1;
engine->font = rdtk_embedded_font_new(engine, imageData, (size_t)imageSize, descriptorData,
(size_t)descriptorSize);
if (!engine->font)
return -1;
}
return 1;
}
int rdtk_font_engine_uninit(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (engine->font)
{
rdtk_font_free(engine->font);
engine->font = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,79 @@
/**
* 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.
*/
#ifndef RDTK_FONT_PRIVATE_H
#define RDTK_FONT_PRIVATE_H
#include <stdint.h>
#include <rdtk/rdtk.h>
#include <winpr/image.h>
#include "rdtk_engine.h"
struct rdtk_glyph
{
int width;
int offsetX;
int offsetY;
int rectX;
int rectY;
int rectWidth;
int rectHeight;
uint8_t code[4];
};
struct rdtk_font
{
rdtkEngine* engine;
uint32_t size;
uint16_t height;
char* family;
char* style;
wImage* image;
uint16_t glyphCount;
rdtkGlyph* glyphs;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
int rdtk_font_text_draw_size(rdtkFont* font, uint16_t* width, uint16_t* height,
const char* text);
WINPR_ATTR_NODISCARD
int rdtk_font_engine_init(rdtkEngine* engine);
int rdtk_font_engine_uninit(rdtkEngine* engine);
void rdtk_font_free(rdtkFont* font);
WINPR_ATTR_MALLOC(rdtk_font_free, 1)
WINPR_ATTR_NODISCARD
rdtkFont* rdtk_font_new(rdtkEngine* engine, const char* path, const char* file);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_FONT_PRIVATE_H */

View File

@@ -0,0 +1,103 @@
/**
* 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.
*/
#include <winpr/assert.h>
#include <rdtk/config.h>
#include "rdtk_font.h"
#include "rdtk_label.h"
int rdtk_label_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst, uint16_t nWidth,
uint16_t nHeight, WINPR_ATTR_UNUSED rdtkLabel* label, const char* text,
WINPR_ATTR_UNUSED uint16_t hAlign, WINPR_ATTR_UNUSED uint16_t vAlign)
{
uint16_t offsetX = 0;
uint16_t offsetY = 0;
uint16_t textWidth = 0;
uint16_t textHeight = 0;
WINPR_ASSERT(surface);
rdtkEngine* engine = surface->engine;
rdtkFont* font = engine->font;
const int rc1 = rdtk_font_text_draw_size(font, &textWidth, &textHeight, text);
if (rc1 < 0)
return rc1;
if ((textWidth > 0) && (textHeight > 0))
{
offsetX = 0;
offsetY = 0;
if (textWidth < nWidth)
offsetX = ((nWidth - textWidth) / 2);
if (textHeight < nHeight)
offsetY = ((nHeight - textHeight) / 2);
const int rc2 = rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text);
if (rc2 < 0)
return rc2;
}
return 1;
}
rdtkLabel* rdtk_label_new(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
rdtkLabel* label = (rdtkLabel*)calloc(1, sizeof(rdtkLabel));
if (!label)
return nullptr;
label->engine = engine;
return label;
}
void rdtk_label_free(rdtkLabel* label)
{
free(label);
}
int rdtk_label_engine_init(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (!engine->label)
{
engine->label = rdtk_label_new(engine);
}
return 1;
}
int rdtk_label_engine_uninit(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (engine->label)
{
rdtk_label_free(engine->label);
engine->label = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,53 @@
/**
* 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.
*/
#ifndef RDTK_LABEL_PRIVATE_H
#define RDTK_LABEL_PRIVATE_H
#include <rdtk/rdtk.h>
#include "rdtk_surface.h"
#include "rdtk_engine.h"
struct rdtk_label
{
rdtkEngine* engine;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
int rdtk_label_engine_init(rdtkEngine* engine);
WINPR_ATTR_NODISCARD
int rdtk_label_engine_uninit(rdtkEngine* engine);
void rdtk_label_free(rdtkLabel* label);
WINPR_ATTR_MALLOC(rdtk_label_free, 1)
WINPR_ATTR_NODISCARD
rdtkLabel* rdtk_label_new(rdtkEngine* engine);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_LABEL_PRIVATE_H */

View File

@@ -0,0 +1,606 @@
/**
* 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.
*/
#include <winpr/config.h>
#include <winpr/assert.h>
#include <rdtk/config.h>
#include "rdtk_resources.h"
#include "rdtk_nine_patch.h"
#if defined(WINPR_WITH_PNG)
#define FILE_EXT "png"
#else
#define FILE_EXT "bmp"
#endif
WINPR_ATTR_NODISCARD
static int rdtk_image_copy_alpha_blend(uint8_t* pDstData, int nDstStep, int nXDst, int nYDst,
int nWidth, int nHeight, const uint8_t* pSrcData,
int nSrcStep, int nXSrc, int nYSrc)
{
WINPR_ASSERT(pDstData);
WINPR_ASSERT(pSrcData);
for (int y = 0; y < nHeight; y++)
{
const uint8_t* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
uint8_t* pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
for (int x = 0; x < nWidth; x++)
{
uint8_t B = pSrcPixel[0];
uint8_t G = pSrcPixel[1];
uint8_t R = pSrcPixel[2];
uint8_t 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)
{
WINPR_ASSERT(surface);
WINPR_ASSERT(ninePatch);
if (nWidth < ninePatch->width)
nWidth = ninePatch->width;
if (nHeight < ninePatch->height)
nHeight = ninePatch->height;
WINPR_UNUSED(nHeight);
int scaleWidth = nWidth - (ninePatch->width - ninePatch->scaleWidth);
int nSrcStep = ninePatch->scanline;
const uint8_t* pSrcData = ninePatch->data;
uint8_t* pDstData = surface->data;
WINPR_ASSERT(surface->scanline <= INT_MAX);
int nDstStep = (int)surface->scanline;
/* top */
int x = 0;
int y = 0;
/* top left */
int nXSrc = 0;
int nYSrc = 0;
int width = ninePatch->scaleLeft;
int height = ninePatch->scaleTop;
{
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
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;
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
x += width;
}
/* top right */
nXSrc = ninePatch->scaleRight;
nYSrc = 0;
width = ninePatch->width - ninePatch->scaleRight;
height = ninePatch->scaleTop;
{
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
/* middle */
x = 0;
y = ninePatch->scaleTop;
/* middle left */
nXSrc = 0;
nYSrc = ninePatch->scaleTop;
width = ninePatch->scaleLeft;
height = ninePatch->scaleHeight;
{
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
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;
{
const int rc =
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
x += width;
}
/* middle right */
nXSrc = ninePatch->scaleRight;
nYSrc = ninePatch->scaleTop;
width = ninePatch->width - ninePatch->scaleRight;
height = ninePatch->scaleHeight;
{
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
/* bottom */
x = 0;
y = ninePatch->scaleBottom;
/* bottom left */
nXSrc = 0;
nYSrc = ninePatch->scaleBottom;
width = ninePatch->scaleLeft;
height = ninePatch->height - ninePatch->scaleBottom;
{
const int rc = rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width,
height, pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
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;
{
const int rc =
rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
pSrcData, nSrcStep, nXSrc, nYSrc);
if (rc < 0)
return rc;
}
x += width;
}
/* bottom right */
nXSrc = ninePatch->scaleRight;
nYSrc = ninePatch->scaleBottom;
width = ninePatch->width - ninePatch->scaleRight;
height = ninePatch->height - ninePatch->scaleBottom;
return rdtk_image_copy_alpha_blend(pDstData, nDstStep, nXDst + x, nYDst + y, width, height,
pSrcData, nSrcStep, nXSrc, nYSrc);
}
WINPR_ATTR_NODISCARD
static uint32_t rdtk_get_image_pixel(const wImage* image, size_t y, size_t x)
{
WINPR_ASSERT(image);
WINPR_ASSERT(y < image->height);
WINPR_ASSERT(x < image->width);
WINPR_ASSERT(image->bytesPerPixel > 0);
WINPR_ASSERT(image->bytesPerPixel <= 4);
WINPR_ASSERT(image->scanline >= image->width * image->bytesPerPixel);
const size_t offset = 1ull * image->scanline * y;
const BYTE* data = &image->data[offset + 1ull * image->bytesPerPixel * x];
uint32_t result = 0;
for (size_t i = 0; i < image->bytesPerPixel; i++)
{
result <<= 8;
result |= data[i];
}
return result;
}
WINPR_ATTR_NODISCARD
static BOOL rdtk_nine_patch_get_scale_lr(rdtkNinePatch* ninePatch, wImage* image)
{
WINPR_ASSERT(image);
WINPR_ASSERT(ninePatch);
WINPR_ASSERT(image->data);
WINPR_ASSERT(image->width > 0);
int64_t beg = -1;
int64_t end = -1;
for (uint32_t y = 0; y < image->height; y++)
{
for (uint32_t x = 1; x < image->width - 1; x++)
{
const uint32_t pixel = rdtk_get_image_pixel(image, y, x); /* (1, 0) */
if (beg < 0)
{
if (pixel != 0)
beg = x;
}
else if (end < 0)
{
if (pixel == 0)
{
end = x;
break;
}
}
}
}
if ((beg <= 0) || (end <= 0))
return FALSE;
WINPR_ASSERT(beg <= INT32_MAX);
WINPR_ASSERT(end <= INT32_MAX);
ninePatch->scaleLeft = (int32_t)beg - 1;
ninePatch->scaleRight = (int32_t)end - 1;
ninePatch->scaleWidth = ninePatch->scaleRight - ninePatch->scaleLeft;
return TRUE;
}
static bool lineValid(const wImage* image, size_t y)
{
for (size_t x = 0; x < image->width; x++)
{
const uint32_t p = rdtk_get_image_pixel(image, y, x);
if (p != 0)
return true;
}
return false;
}
WINPR_ATTR_NODISCARD
static BOOL rdtk_nine_patch_get_scale_ht(rdtkNinePatch* ninePatch, wImage* image)
{
WINPR_ASSERT(image);
WINPR_ASSERT(ninePatch);
WINPR_ASSERT(image->data);
WINPR_ASSERT(image->height > 0);
int64_t beg = -1;
int64_t end = -1;
for (uint32_t y = 1; y < image->height - 1; y++)
{
if (beg < 0)
{
if (lineValid(image, y))
beg = y;
}
else if (end < 0)
{
if (!lineValid(image, y))
{
end = y;
break;
}
}
}
if ((beg <= 0) || (end <= 0))
return FALSE;
WINPR_ASSERT(beg <= INT32_MAX);
WINPR_ASSERT(end <= INT32_MAX);
ninePatch->scaleTop = (int32_t)beg - 1;
ninePatch->scaleBottom = (int32_t)end - 1;
ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop;
return TRUE;
}
WINPR_ATTR_NODISCARD
static BOOL rdtk_nine_patch_get_fill_lr(rdtkNinePatch* ninePatch, wImage* image)
{
WINPR_ASSERT(image);
WINPR_ASSERT(ninePatch);
WINPR_ASSERT(image->data);
WINPR_ASSERT(image->width > 0);
WINPR_ASSERT(image->height > 0);
int64_t beg = -1;
int64_t end = -1;
for (uint32_t y = 0; y < image->height; y++)
{
for (uint32_t x = 1; x < image->width - 1; x++)
{
const uint32_t pixel =
rdtk_get_image_pixel(image, image->height - 1 - y, x); /* (1, height - 1) */
if (beg < 0)
{
if (pixel != 0)
beg = x;
}
else if (end < 0)
{
if (pixel == 0)
{
end = x;
break;
}
}
}
}
if ((beg <= 0) || (end <= 0))
return FALSE;
WINPR_ASSERT(beg <= INT32_MAX);
WINPR_ASSERT(end <= INT32_MAX);
ninePatch->fillLeft = (int32_t)beg - 1;
ninePatch->fillRight = (int32_t)end - 1;
ninePatch->fillWidth = ninePatch->fillRight - ninePatch->fillLeft;
return TRUE;
}
WINPR_ATTR_NODISCARD
static BOOL rdtk_nine_patch_get_fill_ht(rdtkNinePatch* ninePatch, wImage* image)
{
WINPR_ASSERT(image);
WINPR_ASSERT(ninePatch);
WINPR_ASSERT(image->data);
WINPR_ASSERT(image->width > 0);
WINPR_ASSERT(image->height > 0);
int64_t beg = -1;
int64_t end = -1;
for (uint32_t y = 1; y < image->height - 1; y++)
{
for (uint32_t x = 0; x < image->width; x++)
{
const uint32_t pixel =
rdtk_get_image_pixel(image, y, image->width - 1 - x); /* (width - 1, 1) */
if (beg < 0)
{
if (pixel != 0)
beg = y;
}
else if (end < 0)
{
if (pixel == 0)
{
end = y;
break;
}
}
}
}
if ((beg <= 0) || (end <= 0))
return FALSE;
WINPR_ASSERT(beg <= INT32_MAX);
WINPR_ASSERT(end <= INT32_MAX);
ninePatch->scaleTop = (int32_t)beg - 1;
ninePatch->scaleBottom = (int32_t)end - 1;
ninePatch->scaleHeight = ninePatch->scaleBottom - ninePatch->scaleTop;
return TRUE;
}
int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image)
{
WINPR_ASSERT(image);
WINPR_ASSERT(ninePatch);
ninePatch->image = image;
/* parse scalable area */
if (!rdtk_nine_patch_get_scale_lr(ninePatch, image))
return -1;
if (!rdtk_nine_patch_get_scale_ht(ninePatch, image))
return -1;
/* parse fillable area */
if (!rdtk_nine_patch_get_fill_lr(ninePatch, image))
return -1;
if (!rdtk_nine_patch_get_fill_ht(ninePatch, image))
return -1;
/* cut out borders from image */
WINPR_ASSERT(image->width >= 2);
WINPR_ASSERT(image->height >= 2);
WINPR_ASSERT(image->scanline > 0);
WINPR_ASSERT(image->width <= INT32_MAX);
WINPR_ASSERT(image->height <= INT32_MAX);
WINPR_ASSERT(image->scanline <= INT32_MAX);
WINPR_ASSERT(image->data);
ninePatch->width = (int32_t)image->width - 2;
ninePatch->height = (int32_t)image->height - 2;
ninePatch->data = &image->data[image->scanline + 4]; /* (1, 1) */
ninePatch->scanline = (int32_t)image->scanline;
return 1;
}
rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
rdtkNinePatch* ninePatch = (rdtkNinePatch*)calloc(1, sizeof(rdtkNinePatch));
if (!ninePatch)
return nullptr;
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 = 0;
rdtkNinePatch* ninePatch = nullptr;
WINPR_ASSERT(engine);
if (!engine->button9patch)
{
SSIZE_T size = 0;
const uint8_t* data = nullptr;
wImage* image = nullptr;
status = -1;
size = rdtk_get_embedded_resource_file("btn_default_normal.9." FILE_EXT, &data);
if (size > 0)
{
image = winpr_image_new();
if (image)
status = winpr_image_read_buffer(image, data, (size_t)size);
}
if (status > 0)
{
ninePatch = engine->button9patch = rdtk_nine_patch_new(engine);
if (ninePatch)
{
const int rc = rdtk_nine_patch_set_image(ninePatch, image);
if (rc < 0)
return rc;
}
else
winpr_image_free(image, TRUE);
}
else
winpr_image_free(image, TRUE);
}
if (!engine->textField9patch)
{
const uint8_t* data = nullptr;
status = -1;
const SSIZE_T size =
rdtk_get_embedded_resource_file("textfield_default.9." FILE_EXT, &data);
wImage* image = nullptr;
if (size > 0)
{
image = winpr_image_new();
if (image)
status = winpr_image_read_buffer(image, data, (size_t)size);
}
if (status > 0)
{
ninePatch = engine->textField9patch = rdtk_nine_patch_new(engine);
if (ninePatch)
{
const int rc = rdtk_nine_patch_set_image(ninePatch, image);
if (rc < 0)
return rc;
}
else
winpr_image_free(image, TRUE);
}
else
winpr_image_free(image, TRUE);
}
return 1;
}
int rdtk_nine_patch_engine_uninit(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (engine->button9patch)
{
rdtk_nine_patch_free(engine->button9patch);
engine->button9patch = nullptr;
}
if (engine->textField9patch)
{
rdtk_nine_patch_free(engine->textField9patch);
engine->textField9patch = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,84 @@
/**
* 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.
*/
#ifndef RDTK_NINE_PATCH_PRIVATE_H
#define RDTK_NINE_PATCH_PRIVATE_H
#include <stdint.h>
#include <rdtk/rdtk.h>
#include <winpr/image.h>
#include "rdtk_surface.h"
#include "rdtk_engine.h"
struct rdtk_nine_patch
{
rdtkEngine* engine;
wImage* image;
int width;
int height;
int scanline;
uint8_t* data;
int scaleLeft;
int scaleRight;
int scaleWidth;
int scaleTop;
int scaleBottom;
int scaleHeight;
int fillLeft;
int fillRight;
int fillWidth;
int fillTop;
int fillBottom;
int fillHeight;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
int rdtk_nine_patch_set_image(rdtkNinePatch* ninePatch, wImage* image);
WINPR_ATTR_NODISCARD
int rdtk_nine_patch_draw(rdtkSurface* surface, int nXDst, int nYDst, int nWidth, int nHeight,
rdtkNinePatch* ninePatch);
WINPR_ATTR_NODISCARD
int rdtk_nine_patch_engine_init(rdtkEngine* engine);
int rdtk_nine_patch_engine_uninit(rdtkEngine* engine);
void rdtk_nine_patch_free(rdtkNinePatch* ninePatch);
WINPR_ATTR_MALLOC(rdtk_nine_patch_free, 1)
WINPR_ATTR_NODISCARD
rdtkNinePatch* rdtk_nine_patch_new(rdtkEngine* engine);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_NINE_PATCH_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
/**
* 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.
*/
#ifndef RDTK_RESOURCES_PRIVATE_H
#define RDTK_RESOURCES_PRIVATE_H
#include <stdint.h>
#include <winpr/wtypes.h>
#include <rdtk/rdtk.h>
#include "rdtk_engine.h"
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
SSIZE_T rdtk_get_embedded_resource_file(const char* filename, const uint8_t** pData);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_RESOURCES_PRIVATE_H */

View File

@@ -0,0 +1,94 @@
/**
* 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.
*/
#include <winpr/assert.h>
#include <rdtk/config.h>
#include "rdtk_surface.h"
#include <string.h>
int rdtk_surface_fill(rdtkSurface* surface, uint16_t x, uint16_t y, uint16_t width, uint16_t height,
uint32_t color)
{
WINPR_ASSERT(surface);
for (uint32_t i = y; i < y * 1ul + height; i++)
{
uint8_t* line = &surface->data[1ULL * i * surface->scanline];
for (uint32_t j = x; j < x * 1ul + width; j++)
{
uint32_t* pixel = (uint32_t*)&line[j + 4ul];
*pixel = color;
}
}
return 1;
}
rdtkSurface* rdtk_surface_new(rdtkEngine* engine, uint8_t* data, uint16_t width, uint16_t height,
uint32_t scanline)
{
WINPR_ASSERT(engine);
rdtkSurface* surface = (rdtkSurface*)calloc(1, sizeof(rdtkSurface));
if (!surface)
return nullptr;
surface->engine = engine;
surface->width = width;
surface->height = height;
if (scanline == 0)
scanline = width * 4ul;
surface->scanline = scanline;
surface->data = data;
surface->owner = false;
if (!data)
{
surface->scanline = (surface->width + (surface->width % 4ul)) * 4ul;
surface->data = (uint8_t*)calloc(surface->height, surface->scanline);
if (!surface->data)
{
free(surface);
return nullptr;
}
surface->owner = true;
}
return surface;
}
void rdtk_surface_free(rdtkSurface* surface)
{
if (!surface)
return;
if (surface->owner)
free(surface->data);
free(surface);
}

View File

@@ -0,0 +1,38 @@
/**
* 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.
*/
#ifndef RDTK_SURFACE_PRIVATE_H
#define RDTK_SURFACE_PRIVATE_H
#include <stdint.h>
#include <stdbool.h>
#include <rdtk/rdtk.h>
#include "rdtk_engine.h"
struct rdtk_surface
{
rdtkEngine* engine;
uint16_t width;
uint16_t height;
uint32_t scanline;
uint8_t* data;
bool owner;
};
#endif /* RDTK_SURFACE_PRIVATE_H */

View File

@@ -0,0 +1,133 @@
/**
* 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.
*/
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <rdtk/config.h>
#include "rdtk_font.h"
#include "rdtk_text_field.h"
int rdtk_text_field_draw(rdtkSurface* surface, uint16_t nXDst, uint16_t nYDst, uint16_t nWidth,
uint16_t nHeight, rdtkTextField* textField, const char* text)
{
uint16_t textWidth = 0;
uint16_t textHeight = 0;
WINPR_ASSERT(surface);
WINPR_ASSERT(textField);
WINPR_ASSERT(text);
rdtkEngine* engine = surface->engine;
rdtkFont* font = engine->font;
textField = surface->engine->textField;
rdtkNinePatch* ninePatch = textField->ninePatch;
const int rc = rdtk_font_text_draw_size(font, &textWidth, &textHeight, text);
if (rc < 0)
return rc;
const int rc2 = rdtk_nine_patch_draw(surface, nXDst, nYDst, nWidth, nHeight, ninePatch);
if (rc2 < 0)
return rc2;
if ((textWidth > 0) && (textHeight > 0))
{
const int fwd = (ninePatch->width - ninePatch->fillWidth);
const int fhd = (ninePatch->height - ninePatch->fillHeight);
uint16_t fillWidth = nWidth - WINPR_ASSERTING_INT_CAST(uint16_t, fwd);
uint16_t fillHeight = nHeight - WINPR_ASSERTING_INT_CAST(uint16_t, fhd);
uint16_t offsetX = WINPR_ASSERTING_INT_CAST(uint16_t, ninePatch->fillLeft);
uint16_t offsetY = WINPR_ASSERTING_INT_CAST(uint16_t, ninePatch->fillTop);
if (textWidth < fillWidth)
{
const int wd = ((fillWidth - textWidth) / 2) + ninePatch->fillLeft;
offsetX = WINPR_ASSERTING_INT_CAST(uint16_t, wd);
}
else if (textWidth < ninePatch->width)
{
const int wd = ((ninePatch->width - textWidth) / 2);
offsetX = WINPR_ASSERTING_INT_CAST(uint16_t, wd);
}
if (textHeight < fillHeight)
{
const int wd = ((fillHeight - textHeight) / 2) + ninePatch->fillTop;
offsetY = WINPR_ASSERTING_INT_CAST(uint16_t, wd);
}
else if (textHeight < ninePatch->height)
{
const int wd = ((ninePatch->height - textHeight) / 2);
offsetY = WINPR_ASSERTING_INT_CAST(uint16_t, wd);
}
return rdtk_font_draw_text(surface, nXDst + offsetX, nYDst + offsetY, font, text);
}
return 1;
}
rdtkTextField* rdtk_text_field_new(rdtkEngine* engine, rdtkNinePatch* ninePatch)
{
WINPR_ASSERT(engine);
WINPR_ASSERT(ninePatch);
rdtkTextField* textField = (rdtkTextField*)calloc(1, sizeof(rdtkTextField));
if (!textField)
return nullptr;
textField->engine = engine;
textField->ninePatch = ninePatch;
return textField;
}
void rdtk_text_field_free(rdtkTextField* textField)
{
free(textField);
}
int rdtk_text_field_engine_init(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (!engine->textField)
{
engine->textField = rdtk_text_field_new(engine, engine->textField9patch);
if (!engine->textField)
return -1;
}
return 1;
}
int rdtk_text_field_engine_uninit(rdtkEngine* engine)
{
WINPR_ASSERT(engine);
if (engine->textField)
{
rdtk_text_field_free(engine->textField);
engine->textField = nullptr;
}
return 1;
}

View File

@@ -0,0 +1,55 @@
/**
* 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.
*/
#ifndef RDTK_TEXT_FIELD_PRIVATE_H
#define RDTK_TEXT_FIELD_PRIVATE_H
#include <rdtk/rdtk.h>
#include "rdtk_surface.h"
#include "rdtk_nine_patch.h"
#include "rdtk_engine.h"
struct rdtk_text_field
{
rdtkEngine* engine;
rdtkNinePatch* ninePatch;
};
#ifdef __cplusplus
extern "C"
{
#endif
WINPR_ATTR_NODISCARD
int rdtk_text_field_engine_init(rdtkEngine* engine);
int rdtk_text_field_engine_uninit(rdtkEngine* engine);
void rdtk_text_field_free(rdtkTextField* textField);
WINPR_ATTR_MALLOC(rdtk_text_field_free, 1)
WINPR_ATTR_NODISCARD
rdtkTextField* rdtk_text_field_new(rdtkEngine* engine, rdtkNinePatch* ninePatch);
#ifdef __cplusplus
}
#endif
#endif /* RDTK_TEXT_FIELD_PRIVATE_H */

View File

@@ -0,0 +1,23 @@
set(MODULE_NAME "TestRdTk")
set(MODULE_PREFIX "TEST_RDTK")
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
set(${MODULE_PREFIX}_TESTS TestRdTkNinePatch.c)
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
target_link_libraries(${MODULE_NAME} winpr rdtk)
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
foreach(test ${${MODULE_PREFIX}_TESTS})
get_filename_component(TestName ${test} NAME_WE)
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
endforeach()
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "RdTk/Test")

View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include <stdint.h>
#include <rdtk/rdtk.h>
#include <winpr/error.h>
int TestRdTkNinePatch(int argc, char* argv[])
{
rdtkEngine* engine = nullptr;
rdtkSurface* surface = nullptr;
uint32_t scanline = 0;
uint32_t width = 0;
uint32_t height = 0;
uint8_t* data = nullptr;
int ret = -1;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
if (!(engine = rdtk_engine_new()))
{
printf("%s: error creating rdtk engine (%" PRIu32 ")\n", __func__, GetLastError());
goto out;
}
width = 1024;
height = 768;
scanline = width * 4;
/* let rdtk allocate the surface buffer */
if (!(surface = rdtk_surface_new(engine, nullptr, width, height, scanline)))
{
printf("%s: error creating auto-allocated surface (%" PRIu32 ")\n", __func__,
GetLastError());
goto out;
}
rdtk_surface_free(surface);
surface = nullptr;
/* test self-allocated buffer */
if (!(data = calloc(height, scanline)))
{
printf("%s: error allocating surface buffer (%" PRIu32 ")\n", __func__, GetLastError());
goto out;
}
if (!(surface = rdtk_surface_new(engine, data, width, height, scanline)))
{
printf("%s: error creating self-allocated surface (%" PRIu32 ")\n", __func__,
GetLastError());
goto out;
}
ret = 0;
out:
rdtk_surface_free(surface);
rdtk_engine_free(engine);
free(data);
return ret;
}

View File

@@ -0,0 +1,35 @@
# RdTk: Remote Desktop Toolkit
# rdtk cmake build script
#
# 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.
set(MODULE_NAME "rdtk-sample")
set(MODULE_PREFIX "RDTK_SAMPLE")
find_package(X11 REQUIRED)
include_directories(SYSTEM ${X11_INCLUDE_DIR})
set(SRCS rdtk_x11.c)
addtargetwithresourcefile(${MODULE_NAME} TRUE "${RDTK_VERSION}" SRCS)
set(LIBS rdtk)
list(APPEND LIBS ${X11_LIBRARIES})
target_link_libraries(${MODULE_NAME} PRIVATE ${LIBS} winpr)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "RdTk")

View File

@@ -0,0 +1,146 @@
/**
* 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.
*/
#include <rdtk/config.h>
#include <stdint.h>
#include <winpr/wlog.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <rdtk/rdtk.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#define TAG "rdtk.sample"
int main(int argc, char** argv)
{
int rc = 1;
int pf_count = 0;
XEvent event;
XImage* image = nullptr;
Pixmap pixmap = 0;
Window window = 0;
rdtkSurface* surface = nullptr;
WINPR_UNUSED(argc);
WINPR_UNUSED(argv);
Display* display = XOpenDisplay(nullptr);
if (!display)
{
WLog_ERR(TAG, "Cannot open display");
return 1;
}
const INT32 x = 10;
const INT32 y = 10;
const UINT32 width = 640;
const UINT32 height = 480;
const int screen_number = DefaultScreen(display);
const Screen* screen = ScreenOfDisplay(display, screen_number);
Visual* visual = DefaultVisual(display, screen_number);
const GC gc = DefaultGC(display, screen_number);
const int depth = DefaultDepthOfScreen(screen);
const Window root_window = RootWindow(display, screen_number);
const unsigned long border = BlackPixel(display, screen_number);
const unsigned long background = WhitePixel(display, screen_number);
int scanline_pad = 0;
XPixmapFormatValues* pfs = XListPixmapFormats(display, &pf_count);
for (int index = 0; index < pf_count; index++)
{
XPixmapFormatValues* pf = &pfs[index];
if (pf->depth == depth)
{
scanline_pad = pf->scanline_pad;
break;
}
}
XFree(pfs);
rdtkEngine* engine = rdtk_engine_new();
const size_t scanline = width * 4ULL;
uint8_t* buffer = (uint8_t*)calloc(height, scanline);
if (!engine || !buffer || (depth < 0))
goto fail;
surface = rdtk_surface_new(engine, buffer, width, height, scanline);
if (rdtk_surface_fill(surface, 0, 0, width, height, 0x3BB9FF) < 0)
goto fail;
if (rdtk_label_draw(surface, 16, 16, 128, 32, nullptr, "label", 0, 0) < 0)
goto fail;
if (rdtk_button_draw(surface, 16, 64, 128, 32, nullptr, "button") < 0)
goto fail;
if (rdtk_text_field_draw(surface, 16, 128, 128, 32, nullptr, "text field") < 0)
goto fail;
window = XCreateSimpleWindow(display, root_window, x, y, width, height, 1, border, background);
XSelectInput(display, window, ExposureMask | KeyPressMask);
XMapWindow(display, window);
XSetFunction(display, gc, GXcopy);
XSetFillStyle(display, gc, FillSolid);
pixmap = XCreatePixmap(display, window, width, height, (unsigned)depth);
image = XCreateImage(display, visual, (unsigned)depth, ZPixmap, 0, (char*)buffer, width, height,
scanline_pad, 0);
while (1)
{
XNextEvent(display, &event);
if (event.type == Expose)
{
XPutImage(display, pixmap, gc, image, 0, 0, 0, 0, width, height);
XCopyArea(display, pixmap, window, gc, 0, 0, width, height, 0, 0);
}
if (event.type == KeyPress)
break;
if (event.type == ClientMessage)
break;
}
XFlush(display);
rc = 0;
fail:
if (image)
XDestroyImage(image);
XCloseDisplay(display);
rdtk_surface_free(surface);
free(buffer);
rdtk_engine_free(engine);
return rc;
}

View File

@@ -0,0 +1,53 @@
if(NOT RDTK_FORCE_STATIC_BUILD)
include(SetFreeRDPCMakeInstallDir)
# cmake package
export(PACKAGE rdtk)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/rdtkConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/rdtkConfig.cmake
INSTALL_DESTINATION ${RDTK_CMAKE_INSTALL_DIR} PATH_VARS RDTK_INCLUDE_DIR
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/rdtkConfigVersion.cmake VERSION ${RDTK_VERSION} COMPATIBILITY SameMajorVersion
)
endif()
set(RDTK_BUILD_CONFIG_LIST "")
get_cmake_property(res VARIABLES)
foreach(var ${res})
if(var MATCHES "^WITH_*|^BUILD_TESTING*|^RDTK_HAVE_*")
list(APPEND RDTK_BUILD_CONFIG_LIST "${var}=${${var}}")
endif()
endforeach()
include(pkg-config-install-prefix)
string(REPLACE ";" " " RDTK_BUILD_CONFIG "${RDTK_BUILD_CONFIG_LIST}")
cleaning_configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/rdtk/version.h)
cleaning_configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/buildflags.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/rdtk/buildflags.h
)
cleaning_configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/build-config.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/rdtk/build-config.h
)
cleaning_configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/../include/rdtk/config.h)
if(NOT RDTK_FORCE_STATIC_BUILD)
# Do not set Requires.Private if not a static build
if(NOT BUILD_SHARED_LIBS)
set(RDTK_PC_REQUIRES_PRIVATE "winpr${WINPR_VERSION_MAJOR} libssl")
set(RDTK_PC_LIBRARY_PRIVATE "")
endif()
cleaning_configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/rdtk.pc.in ${CMAKE_CURRENT_BINARY_DIR}/rdtk${RDTK_VERSION_MAJOR}.pc @ONLY
)
set(RDTK_INSTALL_INCLUDE_DIR ${RDTK_INCLUDE_DIR}/rdtk)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rdtk${RDTK_VERSION_MAJOR}.pc DESTINATION ${PKG_CONFIG_PC_INSTALL_DIR})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/rdtkConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/rdtkConfigVersion.cmake
DESTINATION ${RDTK_CMAKE_INSTALL_DIR}
)
endif()

View File

@@ -0,0 +1,20 @@
#ifndef RDTK_BUILD_CONFIG_H
#define RDTK_BUILD_CONFIG_H
#define RDTK_DATA_PATH "${WINPR_DATA_PATH}"
#define RDTK_KEYMAP_PATH "${WINPR_KEYMAP_PATH}"
#define RDTK_PLUGIN_PATH "${WINPR_PLUGIN_PATH}"
#define RDTK_INSTALL_PREFIX "${WINPR_INSTALL_PREFIX}"
#define RDTK_LIBRARY_PATH "${WINPR_LIBRARY_PATH}"
#define RDTK_ADDIN_PATH "${WINPR_ADDIN_PATH}"
#define RDTK_SHARED_LIBRARY_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}"
#define RDTK_SHARED_LIBRARY_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}"
#define RDTK_VENDOR_STRING "${VENDOR}"
#define RDTK_PRODUCT_STRING "${PRODUCT}"
#endif /* RDTK_BUILD_CONFIG_H */

View File

@@ -0,0 +1,11 @@
#ifndef RDTK_BUILD_FLAGS_H
#define RDTK_BUILD_FLAGS_H
#define RDTK_CFLAGS "${CMAKE_CURRENT_C_FLAGS}"
#define RDTK_COMPILER_ID "${CMAKE_C_COMPILER_ID}"
#define RDTK_COMPILER_VERSION "${CMAKE_C_COMPILER_VERSION}"
#define RDTK_TARGET_ARCH "${TARGET_ARCH}"
#define RDTK_BUILD_CONFIG "${RDTK_BUILD_CONFIG}"
#define RDTK_BUILD_TYPE "${CURRENT_BUILD_CONFIG}"
#endif /* RDTK_BUILD_FLAGS_H */

View File

@@ -0,0 +1,4 @@
#ifndef RDTK_CONFIG_H
#define RDTK_CONFIG_H
#endif /* RDTK_CONFIG_H */

View File

@@ -0,0 +1,15 @@
prefix=@PKG_CONFIG_INSTALL_PREFIX@
exec_prefix=${prefix}
libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@RDTK_INCLUDE_DIR@
libs=-lrdtk@RDTK_VERSION_MAJOR@
Name: rdtk@RDTK_API_VERSION@
Description: rdtk:
URL: http://www.freerdp.com/
Version: @RDTK_VERSION@
Requires:
Requires.private: @RDTK_PC_REQUIRES_PRIVATE@
Libs: -L${libdir} ${libs}
Libs.private: @RDTK_PC_LIBRARY_PRIVATE@
Cflags: -I${includedir}

View File

@@ -0,0 +1,9 @@
@PACKAGE_INIT@
set(RDTK_VERSION_MAJOR "@RDTK_VERSION_MAJOR@")
set(RDTK_VERSION_MINOR "@RDTK_VERSION_MINOR@")
set(RDTK_VERSION_REVISION "@RDTK_VERSION_REVISION@")
set_and_check(RDTK_INCLUDE_DIR "@PACKAGE_RDTK_INCLUDE_DIR@")
include("${CMAKE_CURRENT_LIST_DIR}/rdtk.cmake")

View File

@@ -0,0 +1,32 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Version includes
*
* Copyright 2021 Thincast Technologies GmbH
* Copyright 2021 Armin Novak <armin.novak@thincast.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.
*/
#ifndef RDTK_VERSION_H
#define RDTK_VERSION_H
#define RDTK_VERSION_MAJOR ${RDTK_VERSION_MAJOR}
#define RDTK_VERSION_MINOR ${RDTK_VERSION_MINOR}
#define RDTK_VERSION_REVISION ${RDTK_VERSION_REVISION}
#define RDTK_VERSION_SUFFIX "${RDTK_VERSION_SUFFIX}"
#define RDTK_API_VERSION "${RDTK_API_VERSION}"
#define RDTK_VERSION "${RDTK_VERSION}"
#define RDTK_VERSION_FULL "${RDTK_VERSION_FULL}"
#define RDTK_GIT_REVISION "${GIT_REVISION}"
#endif /* RDTK_VERSION_H */