diff --git a/cache.c b/cache.c index 8b36920..a26931b 100644 --- a/cache.c +++ b/cache.c @@ -432,30 +432,41 @@ cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor) } /* BRUSH CACHE */ -static BRUSHDATA g_brushcache[64]; +/* index 0 is 2 colour brush, index 1 is muti colour brush */ +static BRUSHDATA g_brushcache[2][64]; /* Retrieve brush from cache */ BRUSHDATA * -cache_get_brush_data(uint16 cache_idx) +cache_get_brush_data(uint8 colour_code, uint8 idx) { - if (cache_idx < NUM_ELEMENTS(g_brushcache)) + colour_code = colour_code == 1 ? 0 : 1; + if (idx < NUM_ELEMENTS(g_brushcache[0])) { - return &g_brushcache[cache_idx]; + return &g_brushcache[colour_code][idx]; } - error("get brush %d\n", cache_idx); + error("get brush %d %d\n", colour_code, idx); return NULL; } /* Store brush in cache */ +/* this function takes over the data pointer in struct, eg, caller gives it up */ void -cache_put_brush_data(uint16 cache_idx, BRUSHDATA * brush_data) +cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data) { - if (cache_idx < NUM_ELEMENTS(g_brushcache)) + BRUSHDATA * bd; + + colour_code = colour_code == 1 ? 0 : 1; + if (idx < NUM_ELEMENTS(g_brushcache[0])) { - memcpy(&g_brushcache[cache_idx], brush_data, sizeof(BRUSHDATA)); + bd = &g_brushcache[colour_code][idx]; + if (bd->data != 0) + { + xfree(bd->data); + } + memcpy(bd, brush_data, sizeof(BRUSHDATA)); } else { - error("put brush %d\n", cache_idx); + error("put brush %d %d\n", colour_code, idx); } } diff --git a/orders.c b/orders.c index 2c9fa95..e494ddc 100644 --- a/orders.c +++ b/orders.c @@ -152,30 +152,24 @@ static void setup_brush(BRUSH * out_brush, BRUSH * in_brush) { BRUSHDATA *brush_data; - uint16 cache_idx; - uint8 brush_bpp; + uint8 cache_idx; + uint8 colour_code; memcpy(out_brush, in_brush, sizeof(BRUSH)); if (out_brush->style & 0x80) { - brush_bpp = out_brush->style & 0x0f; - if (brush_bpp == 1) /* 1 bpp */ + colour_code = out_brush->style & 0x0f; + cache_idx = out_brush->pattern[0]; + brush_data = cache_get_brush_data(colour_code, cache_idx); + if ((brush_data == NULL) || (brush_data->data == NULL)) { - cache_idx = out_brush->pattern[0]; - brush_data = cache_get_brush_data(cache_idx); - if (brush_data == NULL) - { - error("error getting brush data, style %x\n", out_brush->style); - } - else - { - memcpy(out_brush->pattern, brush_data->pattern, - sizeof(out_brush->pattern)); - } + error("error getting brush data, style %x\n", out_brush->style); + out_brush->bd = NULL; + memset(out_brush->pattern, 0, 8); } else { - error("bad brush bpp %d\n", brush_bpp); + out_brush->bd = brush_data; } out_brush->style = 3; } @@ -1154,31 +1148,105 @@ process_fontcache(STREAM s) } } +static void +process_compressed_8x8_brush_data(uint8 * in, uint8 * out, int Bpp) +{ + int x, y, pal_index, in_index, shift, do2, i; + uint8 * pal; + + in_index = 0; + pal = in + 16; + /* read it bottom up */ + for (y = 7; y >= 0; y--) + { + /* 2 bytes per row */ + x = 0; + for (do2 = 0; do2 < 2; do2++) + { + /* 4 pixels per byte */ + shift = 6; + while (shift >= 0) + { + pal_index = (in[in_index] >> shift) & 3; + /* size of palette entries depends on Bpp */ + for (i = 0; i < Bpp; i++) + { + out[(y * 8 + x) * Bpp + i] = pal[pal_index * Bpp + i]; + } + x++; + shift -= 2; + } + in_index++; + } + } +} + /* Process a brush cache order */ static void process_brushcache(STREAM s, uint16 flags) { BRUSHDATA brush_data; - uint8 cache_idx, depth, width, height, size; + uint8 cache_idx, colour_code, width, height, size, type; + uint8 * comp_brush; + int index; + int Bpp; in_uint8(s, cache_idx); - in_uint8(s, depth); + in_uint8(s, colour_code); in_uint8(s, width); in_uint8(s, height); - in_uint8s(s, 1); /* type, 0x80 = cached */ + in_uint8(s, type); /* type, 0x8x = cached */ in_uint8(s, size); DEBUG(("BRUSHCACHE(idx=%d,dp=%d,wd=%d,ht=%d,sz=%d)\n", cache_idx, depth, width, height, size)); - if ((depth == 1) && (width == 8) && (height == 8) && (size == 8)) + if ((width == 8) && (height == 8)) { - in_uint8a(s, brush_data.pattern, sizeof(brush_data.pattern)); - cache_put_brush_data(cache_idx, &brush_data); + if (colour_code == 1) + { + brush_data.colour_code = 1; + brush_data.data_size = 8; + brush_data.data = xmalloc(8); + if (size == 8) + { + /* read it bottom up */ + for (index = 7; index >= 0; index--) + { + in_uint8(s, brush_data.data[index]); + } + } + else + { + warning("incompatible brush, colour_code %d size %d\n", colour_code, size); + } + cache_put_brush_data(1, cache_idx, &brush_data); + } + else if ((colour_code >= 3) && (colour_code <= 6)) + { + Bpp = colour_code - 2; + brush_data.colour_code = colour_code; + brush_data.data_size = 8 * 8 * Bpp; + brush_data.data = xmalloc(8 * 8 * Bpp); + if (size == 16 + 4 * Bpp) + { + in_uint8p(s, comp_brush, 16 + 4 * Bpp); + process_compressed_8x8_brush_data(comp_brush, brush_data.data, Bpp); + } + else + { + in_uint8a(s, brush_data.data, 8 * 8 * Bpp); + } + cache_put_brush_data(colour_code, cache_idx, &brush_data); + } + else + { + warning("incompatible brush, colour_code %d size %d\n", colour_code, size); + } } else { - warning("ignoring incompatible brush type. display may be incorrect\n"); + warning("incompatible brush, width height %d %d\n", width, height); } } diff --git a/proto.h b/proto.h index 1b6d9b2..40457e6 100644 --- a/proto.h +++ b/proto.h @@ -44,8 +44,8 @@ void cache_put_desktop(uint32 offset, int cx, int cy, int scanline, int bytes_pe uint8 * data); RD_HCURSOR cache_get_cursor(uint16 cache_idx); void cache_put_cursor(uint16 cache_idx, RD_HCURSOR cursor); -BRUSHDATA *cache_get_brush_data(uint16 cache_idx); -void cache_put_brush_data(uint16 cache_idx, BRUSHDATA * brush_data); +BRUSHDATA *cache_get_brush_data(uint8 colour_code, uint8 idx); +void cache_put_brush_data(uint8 colour_code, uint8 idx, BRUSHDATA * brush_data); /* channels.c */ VCHANNEL *channel_register(char *name, uint32 flags, void (*callback) (STREAM)); STREAM channel_init(VCHANNEL * channel, uint32 length); diff --git a/rdp.c b/rdp.c index b52f4d1..004ed45 100644 --- a/rdp.c +++ b/rdp.c @@ -858,6 +858,7 @@ rdp_send_confirm_active(void) RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE + RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL + RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + + RDP_CAPLEN_BRUSHCACHE + 0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ + 4 /* w2k fix, why? */ ; @@ -885,10 +886,7 @@ rdp_send_confirm_active(void) rdp_out_control_caps(s); rdp_out_pointer_caps(s); rdp_out_share_caps(s); -#if 0 - /* Temporarily disabled due to bug 2167833. When re-enabling, add RDP_CAPLEN_BRUSHCACHE to caplen. */ rdp_out_brushcache_caps(s); -#endif rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */ rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c); diff --git a/types.h b/types.h index fada605..aba4797 100644 --- a/types.h +++ b/types.h @@ -82,7 +82,9 @@ PEN; /* this is whats in the brush cache */ typedef struct _BRUSHDATA { - uint8 pattern[8]; + uint32 colour_code; + uint32 data_size; + uint8 * data; } BRUSHDATA; @@ -92,7 +94,7 @@ typedef struct _BRUSH uint8 yorigin; uint8 style; uint8 pattern[8]; - + BRUSHDATA * bd; } BRUSH; diff --git a/xwin.c b/xwin.c index 83e75a8..54e8e12 100644 --- a/xwin.c +++ b/xwin.c @@ -3070,18 +3070,45 @@ ui_patblt(uint8 opcode, break; case 3: /* Pattern */ - for (i = 0; i != 8; i++) - ipattern[7 - i] = brush->pattern[i]; - fill = (Pixmap) ui_create_glyph(8, 8, ipattern); - SET_FOREGROUND(bgcolour); - SET_BACKGROUND(fgcolour); - XSetFillStyle(g_display, g_gc, FillOpaqueStippled); - XSetStipple(g_display, g_gc, fill); - XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); - FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); - XSetFillStyle(g_display, g_gc, FillSolid); - XSetTSOrigin(g_display, g_gc, 0, 0); - ui_destroy_glyph((RD_HGLYPH) fill); + if (brush->bd == 0) /* rdp4 brush */ + { + for (i = 0; i != 8; i++) + ipattern[7 - i] = brush->pattern[i]; + fill = (Pixmap) ui_create_glyph(8, 8, ipattern); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } + else if (brush->bd->colour_code > 1) /* > 1 bpp */ + { + fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); + XSetFillStyle(g_display, g_gc, FillTiled); + XSetTile(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_bitmap((RD_HBITMAP) fill); + } + else + { + fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_RECTANGLE_BACKSTORE(x, y, cx, cy); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } break; default: @@ -3244,18 +3271,45 @@ ui_polygon(uint8 opcode, break; case 3: /* Pattern */ - for (i = 0; i != 8; i++) - ipattern[7 - i] = brush->pattern[i]; - fill = (Pixmap) ui_create_glyph(8, 8, ipattern); - SET_FOREGROUND(bgcolour); - SET_BACKGROUND(fgcolour); - XSetFillStyle(g_display, g_gc, FillOpaqueStippled); - XSetStipple(g_display, g_gc, fill); - XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); - FILL_POLYGON((XPoint *) point, npoints); - XSetFillStyle(g_display, g_gc, FillSolid); - XSetTSOrigin(g_display, g_gc, 0, 0); - ui_destroy_glyph((RD_HGLYPH) fill); + if (brush->bd == 0) /* rdp4 brush */ + { + for (i = 0; i != 8; i++) + ipattern[7 - i] = brush->pattern[i]; + fill = (Pixmap) ui_create_glyph(8, 8, ipattern); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_POLYGON((XPoint *) point, npoints); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } + else if (brush->bd->colour_code > 1) /* > 1 bpp */ + { + fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); + XSetFillStyle(g_display, g_gc, FillTiled); + XSetTile(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_POLYGON((XPoint *) point, npoints); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_bitmap((RD_HBITMAP) fill); + } + else + { + fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + FILL_POLYGON((XPoint *) point, npoints); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } break; default: @@ -3322,18 +3376,45 @@ ui_ellipse(uint8 opcode, break; case 3: /* Pattern */ - for (i = 0; i != 8; i++) - ipattern[7 - i] = brush->pattern[i]; - fill = (Pixmap) ui_create_glyph(8, 8, ipattern); - SET_FOREGROUND(bgcolour); - SET_BACKGROUND(fgcolour); - XSetFillStyle(g_display, g_gc, FillOpaqueStippled); - XSetStipple(g_display, g_gc, fill); - XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); - DRAW_ELLIPSE(x, y, cx, cy, fillmode); - XSetFillStyle(g_display, g_gc, FillSolid); - XSetTSOrigin(g_display, g_gc, 0, 0); - ui_destroy_glyph((RD_HGLYPH) fill); + if (brush->bd == 0) /* rdp4 brush */ + { + for (i = 0; i != 8; i++) + ipattern[7 - i] = brush->pattern[i]; + fill = (Pixmap) ui_create_glyph(8, 8, ipattern); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } + else if (brush->bd->colour_code > 1) /* > 1 bpp */ + { + fill = (Pixmap) ui_create_bitmap(8, 8, brush->bd->data); + XSetFillStyle(g_display, g_gc, FillTiled); + XSetTile(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_bitmap((RD_HBITMAP) fill); + } + else + { + fill = (Pixmap) ui_create_glyph(8, 8, brush->bd->data); + SET_FOREGROUND(bgcolour); + SET_BACKGROUND(fgcolour); + XSetFillStyle(g_display, g_gc, FillOpaqueStippled); + XSetStipple(g_display, g_gc, fill); + XSetTSOrigin(g_display, g_gc, brush->xorigin, brush->yorigin); + DRAW_ELLIPSE(x, y, cx, cy, fillmode); + XSetFillStyle(g_display, g_gc, FillSolid); + XSetTSOrigin(g_display, g_gc, 0, 0); + ui_destroy_glyph((RD_HGLYPH) fill); + } break; default: