From 169a9c83eea4b6fbad198ccec7a496be6a93d74a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 29 Sep 2014 14:07:48 -0400 Subject: [PATCH] shadow: initial font rendering --- server/shadow/shadow_client.c | 48 +++++++++--- server/shadow/shadow_font.c | 172 ++++++++++++++++++++++++++++++++++++++++-- server/shadow/shadow_font.h | 5 +- server/shadow/shadow_server.c | 13 +++- 4 files changed, 219 insertions(+), 19 deletions(-) diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 2fe6c1b..e03e97d 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -33,6 +33,8 @@ #define TAG CLIENT_TAG("shadow") +extern rdpShadowFont* g_Font; + void shadow_client_context_new(freerdp_peer* peer, rdpShadowClient* client) { rdpSettings* settings; @@ -130,13 +132,47 @@ BOOL shadow_client_capabilities(freerdp_peer* peer) return TRUE; } +int shadow_client_init_lobby(rdpShadowClient* client) +{ + int width; + int height; + RECTANGLE_16 invalidRect; + rdpShadowSurface* lobby; + rdpContext* context = (rdpContext*) client; + rdpSettings* settings = context->settings; + + width = settings->DesktopWidth; + height = settings->DesktopHeight; + + lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height); + + if (!client->lobby) + return -1; + + freerdp_image_fill(lobby->data, PIXEL_FORMAT_XRGB32, lobby->scanline, + 0, 0, lobby->width, lobby->height, 0x3BB9FF); + + if (g_Font) + { + shadow_font_draw_text(lobby, 16, 16, g_Font, "Welcome to the shadow server!"); + } + + invalidRect.left = 0; + invalidRect.top = 0; + invalidRect.right = width; + invalidRect.bottom = height; + + region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect); + + return 1; +} + BOOL shadow_client_post_connect(freerdp_peer* peer) { int authStatus; int width, height; rdpSettings* settings; rdpShadowClient* client; - rdpShadowSurface* lobby; rdpShadowServer* server; RECTANGLE_16 invalidRect; rdpShadowSubsystem* subsystem; @@ -177,15 +213,7 @@ BOOL shadow_client_post_connect(freerdp_peer* peer) region16_union_rect(&(client->invalidRegion), &(client->invalidRegion), &invalidRect); - lobby = client->lobby = shadow_surface_new(client->server, 0, 0, width, height); - - if (!client->lobby) - return FALSE; - - freerdp_image_fill(lobby->data, PIXEL_FORMAT_XRGB32, lobby->scanline, - 0, 0, lobby->width, lobby->height, 0x3BB9FF); - - region16_union_rect(&(lobby->invalidRegion), &(lobby->invalidRegion), &invalidRect); + shadow_client_init_lobby(client); authStatus = -1; diff --git a/server/shadow/shadow_font.c b/server/shadow/shadow_font.c index 83d9ce8..c61c401 100644 --- a/server/shadow/shadow_font.c +++ b/server/shadow/shadow_font.c @@ -20,12 +20,117 @@ #include "config.h" #endif +#include +#include + #include "shadow.h" #include "shadow_font.h" -#define TEST_FONT_IMAGE "source_serif_pro_regular_12.png" -#define TEST_FONT_DESCRIPTOR "source_serif_pro_regular_12.xml" +int shadow_font_draw_glyph(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, rdpShadowGlyph* glyph) +{ + int x, y; + int nXSrc; + int nYSrc; + int nWidth; + int nHeight; + int nSrcStep; + int nDstStep; + int nSrcPad; + int nDstPad; + BYTE* pSrcData; + BYTE* pSrcPixel; + BYTE* pDstData; + BYTE* pDstPixel; + BYTE A, R, G, B; + + nXDst += glyph->offsetX; + nYDst += glyph->offsetY; + + nXSrc = glyph->rectX; + nYSrc = glyph->rectY; + + nWidth = glyph->rectWidth; + nHeight = glyph->rectHeight; + + nSrcStep = font->image->scanline; + pSrcData = font->image->data; + + pDstData = surface->data; + nDstStep = surface->scanline; + + nSrcPad = (nSrcStep - (nWidth * 4)); + nDstPad = (nDstStep - (nWidth * 4)); + + pSrcPixel = &pSrcData[(nYSrc * nSrcStep) + (nXSrc * 4)]; + pDstPixel = &pDstData[(nYDst * nDstStep) + (nXDst * 4)]; + + for (y = 0; y < nHeight; y++) + { + pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)]; + 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 (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; + } + + pSrcPixel += nSrcPad; + pDstPixel += nDstPad; + } + + return 1; +} + +int shadow_font_draw_text(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, const char* text) +{ + int index; + int length; + rdpShadowGlyph* glyph; + + length = strlen(text); + + for (index = 0; index < length; index++) + { + glyph = &font->glyphs[text[index] - 32]; + shadow_font_draw_glyph(surface, nXDst, nYDst, font, glyph); + nXDst += (glyph->width + 1); + } + + return 1; +} char* shadow_font_load_descriptor_file(const char* filename, int* pSize) { @@ -86,6 +191,9 @@ int shadow_font_convert_descriptor_code_to_utf8(const char* str, BYTE* utf8) *((UINT32*) utf8) = 0; + if (len < 1) + return 1; + if (len == 1) { if ((str[0] > 31) && (str[0] < 127)) @@ -93,6 +201,22 @@ int shadow_font_convert_descriptor_code_to_utf8(const char* str, BYTE* utf8) utf8[0] = str[0]; } } + 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; } @@ -416,10 +540,45 @@ int shadow_font_load_descriptor(rdpShadowFont* font, const char* filename) return 1; } -rdpShadowFont* shadow_font_new(const char* filename) +rdpShadowFont* shadow_font_new(const char* path, const char* file) { int status; + int length; rdpShadowFont* font; + char* fontBaseFile; + char* fontImageFile; + char* fontDescriptorFile; + + fontBaseFile = GetCombinedPath(path, file); + + if (!fontBaseFile) + return NULL; + + length = strlen(fontBaseFile); + + fontImageFile = (char*) malloc(length + 8); + + if (!fontImageFile) + return NULL; + + strcpy(fontImageFile, fontBaseFile); + strcpy(&fontImageFile[length], ".png"); + + fontDescriptorFile = (char*) malloc(length + 8); + + if (!fontImageFile) + return NULL; + + strcpy(fontDescriptorFile, fontBaseFile); + strcpy(&fontDescriptorFile[length], ".xml"); + + free(fontBaseFile); + + if (!PathFileExistsA(fontImageFile)) + return NULL; + + if (!PathFileExistsA(fontDescriptorFile)) + return NULL; font = (rdpShadowFont*) calloc(1, sizeof(rdpShadowFont)); @@ -431,12 +590,15 @@ rdpShadowFont* shadow_font_new(const char* filename) if (!font->image) return NULL; - status = winpr_image_read(font->image, TEST_FONT_IMAGE); + status = winpr_image_read(font->image, fontImageFile); if (status < 0) return NULL; - status = shadow_font_load_descriptor(font, TEST_FONT_DESCRIPTOR); + status = shadow_font_load_descriptor(font, fontDescriptorFile); + + free(fontImageFile); + free(fontDescriptorFile); return font; } diff --git a/server/shadow/shadow_font.h b/server/shadow/shadow_font.h index 69615e5..2ec8ecb 100644 --- a/server/shadow/shadow_font.h +++ b/server/shadow/shadow_font.h @@ -53,7 +53,10 @@ struct rdp_shadow_font extern "C" { #endif -rdpShadowFont* shadow_font_new(const char* filename); +int shadow_font_draw_text(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, const char* text); +int shadow_font_draw_glyph(rdpShadowSurface* surface, int nXDst, int nYDst, rdpShadowFont* font, rdpShadowGlyph* glyph); + +rdpShadowFont* shadow_font_new(const char* path, const char* file); void shadow_font_free(rdpShadowFont* font); #ifdef __cplusplus diff --git a/server/shadow/shadow_server.c b/server/shadow/shadow_server.c index caf6d95..c4acec3 100644 --- a/server/shadow/shadow_server.c +++ b/server/shadow/shadow_server.c @@ -41,6 +41,8 @@ #define TAG SERVER_TAG("shadow") +rdpShadowFont* g_Font = NULL; + static COMMAND_LINE_ARGUMENT_A shadow_args[] = { { "port", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Server port" }, @@ -529,11 +531,16 @@ int shadow_server_init_certificate(rdpShadowServer* server) int shadow_server_init_fonts(rdpShadowServer* server) { + char* fontPath; rdpShadowFont* font; - font = shadow_font_new("source_serif_pro_regular_12"); + fontPath = GetCombinedPath(server->ConfigPath, "shadow/fonts"); + + font = shadow_font_new(fontPath, "source_serif_pro_regular_12"); + + g_Font = font; - shadow_font_free(font); + free(fontPath); return 1; } @@ -562,7 +569,7 @@ int shadow_server_init(rdpShadowServer* server) if (status < 0) return -1; - //shadow_server_init_fonts(server); + shadow_server_init_fonts(server); server->listener = freerdp_listener_new(); -- 2.7.4