diff --git a/cunit/test_orders.c b/cunit/test_orders.c index b295b0240..04f316f1e 100644 --- a/cunit/test_orders.c +++ b/cunit/test_orders.c @@ -669,7 +669,7 @@ void test_read_cache_brush_order(void) update_read_cache_brush_order(s, &cache_brush, 0); - CU_ASSERT(cache_brush.cacheEntry == 0); + CU_ASSERT(cache_brush.index == 0); CU_ASSERT(cache_brush.bpp == 1); CU_ASSERT(cache_brush.cx == 8); CU_ASSERT(cache_brush.cy == 8); diff --git a/include/freerdp/update.h b/include/freerdp/update.h index bb058f004..acce83e21 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -546,13 +546,13 @@ typedef struct _CACHE_GLYPH_V2_ORDER CACHE_GLYPH_V2_ORDER; struct _CACHE_BRUSH_ORDER { - uint8 cacheEntry; + uint8 index; uint8 bpp; uint8 cx; uint8 cy; uint8 style; uint8 length; - uint8* brushData; + uint8* data; }; typedef struct _CACHE_BRUSH_ORDER CACHE_BRUSH_ORDER; diff --git a/libfreerdp-cache/CMakeLists.txt b/libfreerdp-cache/CMakeLists.txt index d7aa12923..99f324007 100644 --- a/libfreerdp-cache/CMakeLists.txt +++ b/libfreerdp-cache/CMakeLists.txt @@ -18,6 +18,8 @@ # limitations under the License. set(FREERDP_CACHE_SRCS + brush.c + brush.h offscreen.c offscreen.h color_table.c diff --git a/libfreerdp-cache/brush.c b/libfreerdp-cache/brush.c new file mode 100644 index 000000000..0bf8b9de8 --- /dev/null +++ b/libfreerdp-cache/brush.c @@ -0,0 +1,83 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Brush Cache + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 +#include + +#include "brush.h" + +void* brush_get(rdpBrush* brush, uint8 index, uint8* bpp) +{ + void* entry; + + if (index > brush->maxEntries) + { + printf("invalid brush index: 0x%04X\n", index); + return NULL; + } + + *bpp = brush->entries[index].bpp; + entry = brush->entries[index].entry; + + if (entry == NULL) + { + printf("invalid brush at index: 0x%04X\n", index); + return NULL; + } + + return entry; +} + +void brush_put(rdpBrush* brush, uint8 index, void* entry, uint8 bpp) +{ + if (index > brush->maxEntries) + { + printf("invalid brush index: 0x%04X\n", index); + return; + } + + brush->entries[index].bpp = bpp; + brush->entries[index].entry = entry; +} + +rdpBrush* brush_new(rdpSettings* settings) +{ + rdpBrush* brush; + + brush = (rdpBrush*) xzalloc(sizeof(rdpBrush)); + + if (brush != NULL) + { + brush->settings = settings; + + brush->maxEntries = 64; + + brush->entries = (BRUSH_ENTRY*) xzalloc(sizeof(BRUSH_ENTRY) * brush->maxEntries); + } + + return brush; +} + +void brush_free(rdpBrush* brush) +{ + if (brush != NULL) + { + xfree(brush); + } +} diff --git a/libfreerdp-cache/brush.h b/libfreerdp-cache/brush.h new file mode 100644 index 000000000..7993de8f7 --- /dev/null +++ b/libfreerdp-cache/brush.h @@ -0,0 +1,47 @@ +/** + * FreeRDP: A Remote Desktop Protocol Client + * Brush Cache + * + * Copyright 2011 Marc-Andre Moreau + * + * 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 __BRUSH_CACHE_H +#define __BRUSH_CACHE_H + +#include +#include + +struct _BRUSH_ENTRY +{ + uint8 bpp; + void* entry; +}; +typedef struct _BRUSH_ENTRY BRUSH_ENTRY; + +struct rdp_brush +{ + uint8 maxEntries; + rdpSettings* settings; + BRUSH_ENTRY* entries; +}; +typedef struct rdp_brush rdpBrush; + +void* brush_get(rdpBrush* brush, uint8 index, uint8* bpp); +void brush_put(rdpBrush* brush, uint8 index, void* entry, uint8 bpp); + +rdpBrush* brush_new(rdpSettings* settings); +void brush_free(rdpBrush* brush); + +#endif /* __BRUSH_CACHE_H */ diff --git a/libfreerdp-cache/cache.c b/libfreerdp-cache/cache.c index 4c4d989af..dac83d1b0 100644 --- a/libfreerdp-cache/cache.c +++ b/libfreerdp-cache/cache.c @@ -31,6 +31,7 @@ rdpCache* cache_new(rdpSettings* settings) if (cache != NULL) { cache->settings = settings; + cache->brush = brush_new(settings); cache->offscreen = offscreen_new(settings); cache->color_table = color_table_new(settings); } @@ -42,6 +43,7 @@ void cache_free(rdpCache* cache) { if (cache != NULL) { + brush_free(cache->brush); offscreen_free(cache->offscreen); color_table_free(cache->color_table); xfree(cache); diff --git a/libfreerdp-cache/cache.h b/libfreerdp-cache/cache.h index 2301339c7..04f8ca953 100644 --- a/libfreerdp-cache/cache.h +++ b/libfreerdp-cache/cache.h @@ -20,6 +20,7 @@ #ifndef __CACHE_H #define __CACHE_H +#include "brush.h" #include "offscreen.h" #include "color_table.h" @@ -31,6 +32,8 @@ typedef struct rdp_cache rdpCache; struct rdp_cache { rdpSettings* settings; + + rdpBrush* brush; rdpOffscreen* offscreen; rdpColorTable* color_table; }; diff --git a/libfreerdp-cache/color_table.c b/libfreerdp-cache/color_table.c index a1fa7f1e8..32d67483e 100644 --- a/libfreerdp-cache/color_table.c +++ b/libfreerdp-cache/color_table.c @@ -28,15 +28,15 @@ void* color_table_get(rdpColorTable* color_table, uint8 index) if (index > color_table->maxEntries) { - printf("invalid color table bitmap index: 0x%04X\n", index); + printf("invalid color table index: 0x%04X\n", index); return NULL; } - entry = color_table->entries[index].color_table; + entry = color_table->entries[index].entry; if (entry == NULL) { - printf("invalid color table bitmap at index: 0x%04X\n", index); + printf("invalid color table at index: 0x%04X\n", index); return NULL; } @@ -47,11 +47,11 @@ void color_table_put(rdpColorTable* color_table, uint8 index, void* entry) { if (index > color_table->maxEntries) { - printf("invalid color table bitmap index: 0x%04X\n", index); + printf("invalid color table index: 0x%04X\n", index); return; } - color_table->entries[index].color_table = entry; + color_table->entries[index].entry = entry; } rdpColorTable* color_table_new(rdpSettings* settings) @@ -79,3 +79,4 @@ void color_table_free(rdpColorTable* color_table) xfree(color_table); } } + diff --git a/libfreerdp-cache/color_table.h b/libfreerdp-cache/color_table.h index bc695e709..58b1479d4 100644 --- a/libfreerdp-cache/color_table.h +++ b/libfreerdp-cache/color_table.h @@ -25,7 +25,7 @@ struct _COLOR_TABLE_ENTRY { - void* color_table; + void* entry; }; typedef struct _COLOR_TABLE_ENTRY COLOR_TABLE_ENTRY; diff --git a/libfreerdp-core/orders.c b/libfreerdp-core/orders.c index 0c6587c8b..383b002f1 100644 --- a/libfreerdp-core/orders.c +++ b/libfreerdp-core/orders.c @@ -1381,11 +1381,38 @@ void update_read_cache_glyph_v2_order(STREAM* s, CACHE_GLYPH_V2_ORDER* cache_gly } } +void update_decompress_brush(STREAM* s, uint8* output, uint8 bpp) +{ + int index; + int x, y, k; + uint8 byte; + uint8* palette; + + palette = s->p + 16; + + for (y = 7; y >= 0; y--) + { + for (x = 0; x < 8; x++) + { + if (x % 4 == 0) + stream_read_uint8(s, byte); + + index = (byte >> ((3 - (x % 4)) * 2)); + + for (k = 0; k < bpp; k++) + { + output[(y * 8 + x) * (bpp / 8) + k] = palette[index * (bpp / 8) + k]; + } + } + } +} + void update_read_cache_brush_order(STREAM* s, CACHE_BRUSH_ORDER* cache_brush_order, uint16 flags) { + int size; uint8 iBitmapFormat; - stream_read_uint8(s, cache_brush_order->cacheEntry); /* cacheEntry (1 byte) */ + stream_read_uint8(s, cache_brush_order->index); /* cacheEntry (1 byte) */ stream_read_uint8(s, iBitmapFormat); /* iBitmapFormat (1 byte) */ cache_brush_order->bpp = BMF_BPP[iBitmapFormat]; @@ -1395,12 +1422,45 @@ void update_read_cache_brush_order(STREAM* s, CACHE_BRUSH_ORDER* cache_brush_ord stream_read_uint8(s, cache_brush_order->style); /* style (1 byte) */ stream_read_uint8(s, cache_brush_order->length); /* iBytes (1 byte) */ - if (cache_brush_order->brushData == NULL) - cache_brush_order->brushData = (uint8*) xmalloc(cache_brush_order->length); - else - cache_brush_order->brushData = (uint8*) xrealloc(cache_brush_order->brushData, cache_brush_order->length); + if ((cache_brush_order->cx == 8) && (cache_brush_order->cy == 8)) + { + size = (cache_brush_order->bpp == 1) ? 8 : 8 * 8 * cache_brush_order->bpp; - stream_read(s, cache_brush_order->brushData, cache_brush_order->length); + cache_brush_order->data = (uint8*) xmalloc(size); + + if (cache_brush_order->bpp == 1) + { + int i; + + if (cache_brush_order->length != 8) + { + printf("incompatible 1bpp brush of length:%d\n", cache_brush_order->length); + return; + } + + /* rows are encoded in reverse order */ + + for (i = 7; i >= 0; i--) + { + stream_read_uint8(s, cache_brush_order->data[i]); + } + } + else + { + if (cache_brush_order->length == COMPRESSED_BRUSH_LENGTH * cache_brush_order->bpp) + { + /* compressed brush */ + update_decompress_brush(s, cache_brush_order->data, cache_brush_order->bpp); + } + else + { + /* uncompressed brush */ + stream_read(s, cache_brush_order->data, cache_brush_order->length); + } + } + + stream_read(s, cache_brush_order->data, cache_brush_order->length); + } } /* Alternate Secondary Drawing Orders */ diff --git a/libfreerdp-core/orders.h b/libfreerdp-core/orders.h index 658ed3077..080c682cb 100644 --- a/libfreerdp-core/orders.h +++ b/libfreerdp-core/orders.h @@ -97,6 +97,8 @@ #define SO_CHAR_INC_EQUAL_BM_BASE 0x20 #define SO_MAXEXT_EQUAL_BM_SIDE 0x40 +#define COMPRESSED_BRUSH_LENGTH 20 + /* Primary Drawing Orders */ #define ORDER_TYPE_DSTBLT 0x00 #define ORDER_TYPE_PATBLT 0x01 diff --git a/libfreerdp-gdi/gdi.c b/libfreerdp-gdi/gdi.c index 63ef9db55..6768f6f45 100644 --- a/libfreerdp-gdi/gdi.c +++ b/libfreerdp-gdi/gdi.c @@ -490,14 +490,20 @@ void gdi_dstblt(rdpUpdate* update, DSTBLT_ORDER* dstblt) void gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt) { + uint8* data; HGDI_BRUSH originalBrush; GDI* gdi = GET_GDI(update); if (patblt->brushStyle & CACHED_BRUSH) { - /* obtain brush from cache */ - printf("should obtain brush from cache.\n"); - return; + uint8 bpp; + uint8* cachedBrush; + data = (uint8*) &patblt->brushHatch; + + cachedBrush = brush_get(gdi->cache->brush, patblt->brushHatch, &bpp); + memcpy(data, cachedBrush, (bpp / 8) * 64); + + patblt->brushStyle = 0; } patblt->brushStyle &= 0x7F; @@ -518,7 +524,6 @@ void gdi_patblt(rdpUpdate* update, PATBLT_ORDER* patblt) } else if (patblt->brushStyle == BS_PATTERN) { - uint8* data; HGDI_BITMAP hBmp; data = (uint8*) &patblt->brushHatch; @@ -676,6 +681,12 @@ void gdi_cache_color_table(rdpUpdate* update, CACHE_COLOR_TABLE_ORDER* cache_col color_table_put(gdi->cache->color_table, cache_color_table->cacheIndex, (void*) cache_color_table->colorTable); } +void gdi_cache_brush(rdpUpdate* update, CACHE_BRUSH_ORDER* cache_brush) +{ + GDI* gdi = GET_GDI(update); + brush_put(gdi->cache->brush, cache_brush->index, cache_brush->data, cache_brush->bpp); +} + /** * Register GDI callbacks with libfreerdp-core. * @param inst current instance @@ -713,6 +724,7 @@ void gdi_register_update_callbacks(rdpUpdate* update) update->SwitchSurface = gdi_switch_surface; update->CacheColorTable = gdi_cache_color_table; + update->CacheBrush = gdi_cache_brush; } /**