summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/xrdp_client_info.h2
-rw-r--r--common/xrdp_constants.h34
-rw-r--r--configure.ac5
-rw-r--r--libxrdp/libxrdp.c158
-rw-r--r--libxrdp/xrdp_caps.c21
-rw-r--r--xrdp/Makefile.am6
-rw-r--r--xrdp/xrdp_bitmap.c8
-rw-r--r--xrdp/xrdp_painter.c555
-rw-r--r--xrdp/xrdp_types.h3
-rw-r--r--xrdp/xrdp_wm.c53
10 files changed, 771 insertions, 74 deletions
diff --git a/common/xrdp_client_info.h b/common/xrdp_client_info.h
index 254708f1..e71f8d71 100644
--- a/common/xrdp_client_info.h
+++ b/common/xrdp_client_info.h
@@ -148,6 +148,8 @@ struct xrdp_client_info
int client_os_major;
int client_os_minor;
+
+ int no_orders_supported;
};
#endif
diff --git a/common/xrdp_constants.h b/common/xrdp_constants.h
index 41c4a5ee..6a055678 100644
--- a/common/xrdp_constants.h
+++ b/common/xrdp_constants.h
@@ -495,6 +495,40 @@
#define XR_ORDERFLAGS_EX_ALTSEC_FRAME_MARKER_SUPPORT 0x0004
#define XR_ORDERFLAGS_EX_OFFSCREEN_COMPOSITE_SUPPORT 0x0100
+/* orders negotiation indexes */
+#define TS_NEG_DSTBLT_INDEX 0x00
+#define TS_NEG_PATBLT_INDEX 0x01
+#define TS_NEG_SCRBLT_INDEX 0x02
+#define TS_NEG_MEMBLT_INDEX 0x03
+#define TS_NEG_MEM3BLT_INDEX 0x04
+ /* 0x05 */
+ /* 0x06 */
+#define TS_NEG_DRAWNINEGRID_INDEX 0x07
+#define TS_NEG_LINETO_INDEX 0x08
+#define TS_NEG_MULTI_DRAWNINEGRID_INDEX 0x09
+ /* 0x0A */
+#define TS_NEG_SAVEBITMAP_INDEX 0x0B
+ /* 0x0C */
+ /* 0x0D */
+ /* 0x0E */
+#define TS_NEG_MULTIDSTBLT_INDEX 0x0F
+#define TS_NEG_MULTIPATBLT_INDEX 0x10
+#define TS_NEG_MULTISCRBLT_INDEX 0x11
+#define TS_NEG_MULTIOPAQUERECT_INDEX 0x12
+#define TS_NEG_FAST_INDEX_INDEX 0x13
+#define TS_NEG_POLYGON_SC_INDEX 0x14
+#define TS_NEG_POLYGON_CB_INDEX 0x15
+#define TS_NEG_POLYLINE_INDEX 0x16
+ /* 0x17 */
+#define TS_NEG_FAST_GLYPH_INDEX 0x18
+#define TS_NEG_ELLIPSE_SC_INDEX 0x19
+#define TS_NEG_ELLIPSE_CB_INDEX 0x1A
+#define TS_NEG_INDEX_INDEX 0x1B
+ /* 0x1C */
+ /* 0x1D */
+ /* 0x1E */
+ /* 0x1F */
+
/* drawable types */
#define WND_TYPE_BITMAP 0
#define WND_TYPE_WND 1
diff --git a/configure.ac b/configure.ac
index fea0e4cb..4168c1b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -119,6 +119,11 @@ AC_ARG_ENABLE(pixman, AS_HELP_STRING([--enable-pixman],
[Use pixman library (default: no)]),
[], [enable_pixman=no])
AM_CONDITIONAL(XRDP_PIXMAN, [test x$enable_pixman = xyes])
+AM_CONDITIONAL(XRDP_PAINTER, [test x$enable_painter = xyes])
+AC_ARG_ENABLE(painter, AS_HELP_STRING([--enable-painter],
+ [Use painter library (default: no)]),
+ [], [enable_painter=no])
+AM_CONDITIONAL(XRDP_PAINTER, [test x$enable_painter = xyes])
# Check if -ldl is needed to use dlopen()
DLOPEN_LIBS=
diff --git a/libxrdp/libxrdp.c b/libxrdp/libxrdp.c
index 2d59621a..c52829f8 100644
--- a/libxrdp/libxrdp.c
+++ b/libxrdp/libxrdp.c
@@ -27,6 +27,8 @@
#define LLOGLN(_level, _args) \
do { if (_level < LOG_LEVEL) { g_writeln _args ; } } while (0)
+#define MAX_BITMAP_BUF_SIZE (16 * 1024) /* 16K */
+
/******************************************************************************/
struct xrdp_session *EXPORT_CC
libxrdp_init(tbus id, struct trans *trans)
@@ -373,15 +375,15 @@ libxrdp_send_bell(struct xrdp_session *session)
return 0;
}
-
/*****************************************************************************/
int EXPORT_CC
libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
int bpp, char *data, int x, int y, int cx, int cy)
{
- int line_size = 0;
+ int line_bytes = 0;
int i = 0;
int j = 0;
+ int k;
int total_lines = 0;
int lines_sending = 0;
int Bpp = 0;
@@ -389,27 +391,43 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
int bufsize = 0;
int total_bufsize = 0;
int num_updates = 0;
+ int line_pad_bytes;
+ int server_line_bytes;
char *p_num_updates = (char *)NULL;
char *p = (char *)NULL;
char *q = (char *)NULL;
struct stream *s = (struct stream *)NULL;
struct stream *temp_s = (struct stream *)NULL;
+ tui32 pixel;
- DEBUG(("libxrdp_send_bitmap sending bitmap"));
+ LLOGLN(10, ("libxrdp_send_bitmap: sending bitmap"));
Bpp = (bpp + 7) / 8;
- e = width % 4;
-
- if (e != 0)
+ e = (4 - width) & 3;
+ switch (bpp)
{
- e = 4 - e;
+ case 15:
+ case 16:
+ server_line_bytes = width * 2;
+ break;
+ case 24:
+ case 32:
+ server_line_bytes = width * 4;
+ break;
+ default: /* 8 bpp */
+ server_line_bytes = width;
+ break;
}
+ line_bytes = width * Bpp;
+ line_pad_bytes = line_bytes + e * Bpp;
- line_size = width * Bpp;
+ LLOGLN(10, ("libxrdp_send_bitmap: bpp %d Bpp %d line_bytes %d "
+ "server_line_bytes %d", bpp, Bpp, line_bytes, server_line_bytes));
make_stream(s);
- init_stream(s, 8192);
+ init_stream(s, MAX_BITMAP_BUF_SIZE);
if (session->client_info->use_bitmap_comp)
{
+ LLOGLN(10, ("libxrdp_send_bitmap: compression"));
make_stream(temp_s);
init_stream(temp_s, 65536);
i = 0;
@@ -421,6 +439,8 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
while (i > 0)
{
+ LLOGLN(10, ("libxrdp_send_bitmap: i %d", i));
+
total_bufsize = 0;
num_updates = 0;
xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s);
@@ -440,10 +460,26 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
}
p = s->p;
- lines_sending = xrdp_bitmap_compress(data, width, height,
- s, bpp,
- 4096 - total_bufsize,
- i - 1, temp_s, e);
+
+ if (bpp > 24)
+ {
+ LLOGLN(10, ("libxrdp_send_bitmap: 32 bpp"));
+ lines_sending = xrdp_bitmap32_compress(data, width, height,
+ s, 32,
+ (MAX_BITMAP_BUF_SIZE - 100) - total_bufsize,
+ i - 1, temp_s, e, 0x10);
+ LLOGLN(10, ("libxrdp_send_bitmap: i %d lines_sending %d",
+ i, lines_sending));
+ }
+ else
+ {
+ lines_sending = xrdp_bitmap_compress(data, width, height,
+ s, bpp,
+ (MAX_BITMAP_BUF_SIZE - 100) - total_bufsize,
+ i - 1, temp_s, e);
+ LLOGLN(10, ("libxrdp_send_bitmap: i %d lines_sending %d",
+ i, lines_sending));
+ }
if (lines_sending == 0)
{
@@ -470,6 +506,7 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
out_uint16_le(s, bufsize); /* compressed size */
j = (width + e) * Bpp;
j = j * lines_sending;
+ total_bufsize += 18; /* bytes since pop layer */
}
else
{
@@ -481,31 +518,42 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
out_uint16_le(s, j); /* line size */
j = j * lines_sending;
out_uint16_le(s, j); /* final size */
+ total_bufsize += 26; /* bytes since pop layer */
}
- if (j > 32768)
+ LLOGLN(10, ("libxrdp_send_bitmap: decompressed pixels %d "
+ "decompressed bytes %d compressed bytes %d",
+ lines_sending * (width + e),
+ line_pad_bytes * lines_sending, bufsize));
+
+ if (j > MAX_BITMAP_BUF_SIZE)
{
- g_writeln("error, decompressed size too big: %d bytes", j);
+ LLOGLN(0, ("libxrdp_send_bitmap: error, decompressed "
+ "size too big: %d bytes", j));
}
- if (bufsize > 8192)
+ if (bufsize > MAX_BITMAP_BUF_SIZE)
{
- g_writeln("error, compressed size too big: %d bytes", bufsize);
+ LLOGLN(0, ("libxrdp_send_bitmap: error, compressed size "
+ "too big: %d bytes", bufsize));
}
s->p = s->end;
}
- while (total_bufsize < 4096 && i > 0);
+ while (total_bufsize < MAX_BITMAP_BUF_SIZE && i > 0);
+
+ LLOGLN(10, ("libxrdp_send_bitmap: num_updates %d total_bufsize %d",
+ num_updates, total_bufsize));
p_num_updates[0] = num_updates;
p_num_updates[1] = num_updates >> 8;
xrdp_rdp_send_data((struct xrdp_rdp *)session->rdp, s,
RDP_DATA_PDU_UPDATE);
- if (total_bufsize > 8192)
+ if (total_bufsize > MAX_BITMAP_BUF_SIZE)
{
- g_writeln("error, total compressed size too big: %d bytes",
- total_bufsize);
+ LLOGLN(0, ("libxrdp_send_bitmap: error, total compressed "
+ "size too big: %d bytes", total_bufsize));
}
}
@@ -513,22 +561,30 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
}
else
{
+ LLOGLN(10, ("libxrdp_send_bitmap: no compression"));
total_lines = height;
i = 0;
p = data;
- if (line_size > 0 && total_lines > 0)
+ if (line_bytes > 0 && total_lines > 0)
{
while (i < total_lines)
{
- lines_sending = 4096 / (line_size + e * Bpp);
+
+ lines_sending = (MAX_BITMAP_BUF_SIZE - 100) / line_pad_bytes;
if (i + lines_sending > total_lines)
{
lines_sending = total_lines - i;
}
- p = p + line_size * lines_sending;
+ if (lines_sending == 0)
+ {
+ LLOGLN(0, ("libxrdp_send_bitmap: error, lines_sending == zero"));
+ break;
+ }
+
+ p += server_line_bytes * lines_sending;
xrdp_rdp_init_data((struct xrdp_rdp *)session->rdp, s);
out_uint16_le(s, RDP_UPDATE_BITMAP);
out_uint16_le(s, 1); /* num updates */
@@ -540,14 +596,58 @@ libxrdp_send_bitmap(struct xrdp_session *session, int width, int height,
out_uint16_le(s, lines_sending);
out_uint16_le(s, bpp); /* bpp */
out_uint16_le(s, 0); /* compress */
- out_uint16_le(s, (line_size + e * Bpp) * lines_sending); /* bufsize */
+ out_uint16_le(s, line_pad_bytes * lines_sending); /* bufsize */
q = p;
- for (j = 0; j < lines_sending; j++)
+ switch (bpp)
{
- q = q - line_size;
- out_uint8a(s, q, line_size); /* B_ENDIAN doesn't work here, todo */
- out_uint8s(s, e * Bpp);
+ case 8:
+ for (j = 0; j < lines_sending; j++)
+ {
+ q = q - line_bytes;
+ out_uint8a(s, q, line_bytes);
+ out_uint8s(s, e);
+ }
+ break;
+ case 15:
+ case 16:
+ for (j = 0; j < lines_sending; j++)
+ {
+ q = q - server_line_bytes;
+ for (k = 0; k < width; k++)
+ {
+ pixel = *((tui16*)(q + k * 2));
+ out_uint16_le(s, pixel);
+ }
+ out_uint8s(s, e * 2);
+ }
+ break;
+ case 24:
+ for (j = 0; j < lines_sending; j++)
+ {
+ q = q - server_line_bytes;
+ for (k = 0; k < width; k++)
+ {
+ pixel = *((tui32*)(q + k * 4));
+ out_uint8(s, pixel);
+ out_uint8(s, pixel >> 8);
+ out_uint8(s, pixel >> 16);
+ }
+ out_uint8s(s, e * 3);
+ }
+ break;
+ case 32:
+ for (j = 0; j < lines_sending; j++)
+ {
+ q = q - server_line_bytes;
+ for (k = 0; k < width; k++)
+ {
+ pixel = *((int*)(q + k * 4));
+ out_uint32_le(s, pixel);
+ }
+ out_uint8s(s, e * 4);
+ }
+ break;
}
s_mark_end(s);
diff --git a/libxrdp/xrdp_caps.c b/libxrdp/xrdp_caps.c
index a8b9344f..ec971648 100644
--- a/libxrdp/xrdp_caps.c
+++ b/libxrdp/xrdp_caps.c
@@ -80,6 +80,7 @@ xrdp_caps_process_general(struct xrdp_rdp *self, struct stream *s,
in_uint8s(s, 6);
in_uint16_le(s, extraFlags); /* extraFlags (2 bytes) */
+ self->client_info.op1 = extraFlags & NO_BITMAP_COMPRESSION_HDR;
/* use_compact_packets is pretty much 'use rdp5' */
self->client_info.use_compact_packets = (extraFlags != 0);
/* op2 is a boolean to use compact bitmap headers in bitmap cache */
@@ -159,6 +160,15 @@ xrdp_caps_process_order(struct xrdp_rdp *self, struct stream *s,
DEBUG(("desktop cache size %d", i));
in_uint8s(s, 4); /* Unknown */
in_uint8s(s, 4); /* Unknown */
+
+ /* check if libpainter should be used for drawing, instead of orders */
+ if (!(order_caps[TS_NEG_DSTBLT_INDEX] && order_caps[TS_NEG_PATBLT_INDEX] &&
+ order_caps[TS_NEG_SCRBLT_INDEX] && order_caps[TS_NEG_MEMBLT_INDEX]))
+ {
+ g_writeln("xrdp_caps_process_order: not enough orders supported by client, using painter.");
+ self->client_info.no_orders_supported = 1;
+ }
+
return 0;
}
@@ -682,6 +692,17 @@ xrdp_caps_process_confirm_active(struct xrdp_rdp *self, struct stream *s)
s->p = p + len + 4;
}
+ if (self->client_info.no_orders_supported &&
+ (self->client_info.offscreen_support_level != 0))
+ {
+ g_writeln("xrdp_caps_process_confirm_active: not enough orders "
+ "supported by client, client wants off screen bitmap but "
+ "offscreen bitmaps disabled");
+ self->client_info.offscreen_support_level = 0;
+ self->client_info.offscreen_cache_size = 0;
+ self->client_info.offscreen_cache_entries = 0;
+ }
+
DEBUG(("out xrdp_caps_process_confirm_active"));
return 0;
}
diff --git a/xrdp/Makefile.am b/xrdp/Makefile.am
index df0b1558..8e22d182 100644
--- a/xrdp/Makefile.am
+++ b/xrdp/Makefile.am
@@ -33,6 +33,12 @@ AM_CPPFLAGS += $(PIXMAN_CFLAGS)
XRDP_EXTRA_LIBS += $(PIXMAN_LIBS)
endif
+if XRDP_PAINTER
+AM_CPPFLAGS += -DXRDP_PAINTER
+AM_CPPFLAGS += -I$(top_srcdir)/libpainter/include
+XRDP_EXTRA_LIBS += $(top_srcdir)/libpainter/src/.libs/libpainter.a
+endif
+
sbin_PROGRAMS = \
xrdp
diff --git a/xrdp/xrdp_bitmap.c b/xrdp/xrdp_bitmap.c
index 053be88b..deb56a2c 100644
--- a/xrdp/xrdp_bitmap.c
+++ b/xrdp/xrdp_bitmap.c
@@ -123,6 +123,14 @@ xrdp_bitmap_create(int width, int height, int bpp,
self->data = (char *)g_malloc(width * height * Bpp, 0);
}
+#if defined(XRDP_PAINTER)
+ if (self->type == WND_TYPE_SCREEN) /* noorders */
+ {
+ LLOGLN(0, ("xrdp_bitmap_create: noorders"));
+ self->data = (char *) g_malloc(width * height * Bpp, 0);
+ }
+#endif
+
if (self->type != WND_TYPE_BITMAP)
{
self->child_list = list_create();
diff --git a/xrdp/xrdp_painter.c b/xrdp/xrdp_painter.c
index f5605717..361a6a74 100644
--- a/xrdp/xrdp_painter.c
+++ b/xrdp/xrdp_painter.c
@@ -20,17 +20,152 @@
#include "xrdp.h"
+#if defined(XRDP_PAINTER)
+#include <painter.h> /* libpainter */
+#endif
+
+#define LLOG_LEVEL 1
+#define LLOGLN(_level, _args) \
+ do \
+ { \
+ if (_level < LLOG_LEVEL) \
+ { \
+ g_write("xrdp:xrdp_painter [%10.10u]: ", g_time3()); \
+ g_writeln _args ; \
+ } \
+ } \
+ while (0)
+
+#if defined(XRDP_PAINTER)
+
+/*****************************************************************************/
+static int APP_CC
+xrdp_painter_add_dirty_rect(struct xrdp_painter *self, int x, int y,
+ int cx, int cy, struct xrdp_rect *clip_rect)
+{
+ int x2;
+ int y2;
+ struct xrdp_rect rect;
+
+ if (clip_rect != 0)
+ {
+ x2 = x + cx;
+ y2 = y + cy;
+ x = MAX(x, clip_rect->left);
+ y = MAX(y, clip_rect->top);
+ x2 = MIN(x2, clip_rect->right);
+ y2 = MIN(y2, clip_rect->bottom);
+ cx = x2 - x;
+ cy = y2 - y;
+ }
+ if (cx < 1 || cy < 1)
+ {
+ return 0;
+ }
+ rect.left = x;
+ rect.top = y;
+ rect.right = x + cx;
+ rect.bottom = y + cy;
+ xrdp_region_add_rect(self->dirty_region, &rect);
+ LLOGLN(10, ("xrdp_painter_add_dirty_rect: x %d y %d cx %d cy %d",
+ x, y, cx, cy));
+ return 0;
+}
+
+/*****************************************************************************/
+static int
+xrdp_painter_send_dirty(struct xrdp_painter *self)
+{
+ int cx;
+ int cy;
+ int bpp;
+ int Bpp;
+ int index;
+ int jndex;
+ int error;
+ char *ldata;
+ char *src;
+ char *dst;
+ struct xrdp_rect rect;
+
+ LLOGLN(10, ("xrdp_painter_send_dirty:"));
+
+ bpp = self->wm->screen->bpp;
+ Bpp = (bpp + 7) / 8;
+ if (Bpp == 3)
+ {
+ Bpp = 4;
+ }
+
+ jndex = 0;
+ error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
+ while (error == 0)
+ {
+ cx = rect.right - rect.left;
+ cy = rect.bottom - rect.top;
+ ldata = (char *)g_malloc(cx * cy * Bpp, 0);
+ if (ldata == 0)
+ {
+ return 1;
+ }
+ src = self->wm->screen->data;
+ src += self->wm->screen->line_size * rect.top;
+ src += rect.left * Bpp;
+ dst = ldata;
+ for (index = 0; index < cy; index++)
+ {
+ g_memcpy(dst, src, cx * Bpp);
+ src += self->wm->screen->line_size;
+ dst += cx * Bpp;
+ }
+ LLOGLN(10, ("xrdp_painter_send_dirty: x %d y %d cx %d cy %d",
+ rect.left, rect.top, cx, cy));
+ libxrdp_send_bitmap(self->session, cx, cy, bpp,
+ ldata, rect.left, rect.top, cx, cy);
+ g_free(ldata);
+
+ jndex++;
+ error = xrdp_region_get_rect(self->dirty_region, jndex, &rect);
+ }
+
+ xrdp_region_delete(self->dirty_region);
+ self->dirty_region = xrdp_region_create(self->wm);
+
+ return 0;
+}
+
+#endif
+
/*****************************************************************************/
struct xrdp_painter *APP_CC
xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session)
{
struct xrdp_painter *self;
+ LLOGLN(10, ("xrdp_painter_create:"));
self = (struct xrdp_painter *)g_malloc(sizeof(struct xrdp_painter), 1);
self->wm = wm;
self->session = session;
- self->rop = 0xcc; /* copy will use 0xcc*/
+ self->rop = 0xcc; /* copy will use 0xcc */
self->clip_children = 1;
+
+
+ if (self->session->client_info->no_orders_supported)
+ {
+#if defined(XRDP_PAINTER)
+ if (painter_create(&(self->painter)) != PT_ERROR_NONE)
+ {
+ self->painter = 0;
+ LLOGLN(0, ("xrdp_painter_create: painter_create failed"));
+ }
+ else
+ {
+ LLOGLN(10, ("xrdp_painter_create: painter_create success"));
+ }
+ self->dirty_region = xrdp_region_create(wm);
+#endif
+ }
+
return self;
}
@@ -38,11 +173,17 @@ xrdp_painter_create(struct xrdp_wm *wm, struct xrdp_session *session)
void APP_CC
xrdp_painter_delete(struct xrdp_painter *self)
{
+ LLOGLN(10, ("xrdp_painter_delete:"));
if (self == 0)
{
return;
}
+#if defined(XRDP_PAINTER)
+ painter_delete(self->painter);
+ xrdp_region_delete(self->dirty_region);
+#endif
+
g_free(self);
}
@@ -54,6 +195,13 @@ wm_painter_set_target(struct xrdp_painter *self)
int index;
struct list *del_list;
+ LLOGLN(10, ("wm_painter_set_target:"));
+
+ if (self->painter != 0)
+ {
+ return 0;
+ }
+
if (self->wm->target_surface->type == WND_TYPE_SCREEN)
{
if (self->wm->current_surface_index != 0xffff)
@@ -97,11 +245,19 @@ wm_painter_set_target(struct xrdp_painter *self)
int APP_CC
xrdp_painter_begin_update(struct xrdp_painter *self)
{
+ LLOGLN(10, ("xrdp_painter_begin_update:"));
if (self == 0)
{
return 0;
}
+ self->begin_end_level++;
+
+ if (self->painter != 0)
+ {
+ return 0;
+ }
+
libxrdp_orders_init(self->session);
wm_painter_set_target(self);
return 0;
@@ -111,11 +267,25 @@ xrdp_painter_begin_update(struct xrdp_painter *self)
int APP_CC
xrdp_painter_end_update(struct xrdp_painter *self)
{
+ LLOGLN(10, ("xrdp_painter_end_update:"));
if (self == 0)
{
return 0;
}
+ self->begin_end_level--;
+
+ if (self->painter != 0)
+ {
+#if defined(XRDP_PAINTER)
+ if (self->begin_end_level == 0)
+ {
+ xrdp_painter_send_dirty(self);
+ return 0;
+ }
+#endif
+ }
+
libxrdp_orders_send(self->session);
return 0;
}
@@ -270,6 +440,7 @@ xrdp_painter_text_width(struct xrdp_painter *self, const char *text)
struct xrdp_font_char *font_item;
twchar *wstr;
+ LLOGLN(10, ("xrdp_painter_text_width:"));
xrdp_painter_font_needed(self);
if (self->font == 0)
@@ -307,6 +478,7 @@ xrdp_painter_text_height(struct xrdp_painter *self, const char *text)
struct xrdp_font_char *font_item;
twchar *wstr;
+ LLOGLN(10, ("xrdp_painter_text_height:"));
xrdp_painter_font_needed(self);
if (self->font == 0)
@@ -342,6 +514,13 @@ xrdp_painter_setup_brush(struct xrdp_painter *self,
{
int cache_id;
+ LLOGLN(10, ("xrdp_painter_setup_brush:"));
+
+ if (self->painter != 0)
+ {
+ return 0;
+ }
+
g_memcpy(out_brush, in_brush, sizeof(struct xrdp_brush));
if (in_brush->style == 3)
@@ -358,6 +537,38 @@ xrdp_painter_setup_brush(struct xrdp_painter *self,
return 0;
}
+#if defined(XRDP_PAINTER)
+
+/*****************************************************************************/
+static int APP_CC
+get_pt_format(struct xrdp_painter *self)
+{
+ switch (self->wm->screen->bpp)
+ {
+ case 8:
+ return PT_FORMAT_r3g3b2;
+ case 15:
+ return PT_FORMAT_a1r5g5b5;
+ case 16:
+ return PT_FORMAT_r5g6b5;
+ }
+ return PT_FORMAT_a8r8g8b8;
+}
+
+/*****************************************************************************/
+static int
+get_rgb_from_rdp_color(struct xrdp_painter *self, int rdp_color)
+{
+ if (self->wm->screen->bpp < 24)
+ {
+ return rdp_color;
+ }
+ /* well, this is really BGR2RGB */
+ return XR_RGB2BGR(rdp_color);
+}
+
+#endif
+
/*****************************************************************************/
/* fill in an area of the screen with one color */
int APP_CC
@@ -375,11 +586,120 @@ xrdp_painter_fill_rect(struct xrdp_painter *self,
int dy;
int rop;
+ LLOGLN(10, ("xrdp_painter_fill_rect:"));
+
if (self == 0)
{
return 0;
}
+ dx = 0;
+ dy = 0;
+
+ if (self->painter != 0)
+ {
+#if defined(XRDP_PAINTER)
+ struct painter_bitmap dst_pb;
+ struct xrdp_bitmap *ldst;
+ struct painter_bitmap pat;
+
+ LLOGLN(10, ("xrdp_painter_fill_rect: dst->type %d", dst->type));
+ if (dst->type != WND_TYPE_OFFSCREEN)
+ {
+ LLOGLN(10, ("xrdp_painter_fill_rect: using painter"));
+
+ ldst = self->wm->screen;
+
+ g_memset(&dst_pb, 0, sizeof(dst_pb));
+ dst_pb.format = get_pt_format(self);
+ dst_pb.width = ldst->width;
+ dst_pb.stride_bytes = ldst->line_size;
+ dst_pb.height = ldst->height;
+ dst_pb.data = ldst->data;
+
+ LLOGLN(10, ("xrdp_painter_fill_rect: ldst->width %d ldst->height %d "
+ "dst->data %p self->fg_color %d",
+ ldst->width, ldst->height, ldst->data, self->fg_color));
+
+ xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy);
+ region = xrdp_region_create(self->wm);
+ xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region,
+ self->clip_children);
+ x += dx;
+ y += dy;
+
+ rop = self->rop;
+ switch (self->rop)
+ {
+ case 0x5a:
+ rop = PT_ROP_DSx;
+ break;
+ case 0xf0:
+ rop = PT_ROP_S;
+ break;
+ case 0xfb:
+ rop = PT_ROP_D;
+ break;
+ case 0xc0:
+ rop = PT_ROP_DSa;
+ break;
+ }
+ painter_set_rop(self->painter, rop);
+
+ if (self->mix_mode == 0)
+ {
+ painter_set_pattern_mode(self->painter, PT_PATTERN_MODE_OPAQUE);
+ painter_set_fgcolor(self->painter, get_rgb_from_rdp_color(self, self->fg_color));
+ k = 0;
+ while (xrdp_region_get_rect(region, k, &rect) == 0)
+ {
+ if (rect_intersect(&rect, &clip_rect, &draw_rect))
+ {
+ painter_set_clip(self->painter,
+ draw_rect.left, draw_rect.top,
+ draw_rect.right - draw_rect.left,
+ draw_rect.bottom - draw_rect.top);
+ painter_fill_rect(self->painter, &dst_pb, x, y, cx, cy);
+ xrdp_painter_add_dirty_rect(self, x, y, cx, cy, &draw_rect);
+ }
+ k++;
+ }
+ }
+ else
+ {
+ painter_set_pattern_mode(self->painter, PT_PATTERN_MODE_OPAQUE);
+ painter_set_fgcolor(self->painter, get_rgb_from_rdp_color(self, self->fg_color));
+ painter_set_bgcolor(self->painter, get_rgb_from_rdp_color(self, self->bg_color));
+ painter_set_pattern_origin(self->painter, self->brush.x_origin, self->brush.y_origin);
+ g_memset(&pat, 0, sizeof(pat));
+ pat.format = PT_FORMAT_c1;
+ pat.width = 8;
+ pat.stride_bytes = 1;
+ pat.height = 8;
+ pat.data = self->brush.pattern;
+ k = 0;
+ while (xrdp_region_get_rect(region, k, &rect) == 0)
+ {
+ if (rect_intersect(&rect, &clip_rect, &draw_rect))
+ {
+ painter_set_clip(self->painter,
+ draw_rect.left, draw_rect.top,
+ draw_rect.right - draw_rect.left,
+ draw_rect.bottom - draw_rect.top);
+ painter_fill_pattern(self->painter, &dst_pb, &pat,
+ x, y, x, y, cx, cy);
+ xrdp_painter_add_dirty_rect(self, x, y, cx, cy, &draw_rect);
+ }
+ k++;
+ }
+ }
+ painter_clear_clip(self->painter);
+ xrdp_region_delete(region);
+ }
+ return 0;
+#endif
+ }
+
/* todo data */
if (dst->type == WND_TYPE_BITMAP) /* 0 */
@@ -508,11 +828,14 @@ xrdp_painter_draw_text(struct xrdp_painter *self,
struct xrdp_font_char *font_item;
twchar *wstr;
+ LLOGLN(10, ("xrdp_painter_draw_text:"));
+
if (self == 0)
{
return 0;
}
+
len = g_mbstowcs(0, text, 0);
if (len < 1)
@@ -534,6 +857,88 @@ xrdp_painter_draw_text(struct xrdp_painter *self,
return 0;
}
+ if (self->painter != 0)
+ {
+#if defined(XRDP_PAINTER)
+ struct painter_bitmap pat;
+ struct painter_bitmap dst_pb;
+ struct xrdp_bitmap *ldst;
+
+ if (dst->type != WND_TYPE_OFFSCREEN)
+ {
+ ldst = self->wm->screen;
+ /* convert to wide char */
+ wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0);
+ g_mbstowcs(wstr, text, len + 1);
+ font = self->font;
+ total_width = 0;
+ total_height = 0;
+ for (index = 0; index < len; index++)
+ {
+ font_item = font->font_items + wstr[index];
+ k = font_item->incby;
+ total_width += k;
+ total_height = MAX(total_height, font_item->height);
+ }
+ xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy);
+ region = xrdp_region_create(self->wm);
+ xrdp_wm_get_vis_region(self->wm, dst, x, y,
+ total_width, total_height,
+ region, self->clip_children);
+ x += dx;
+ y += dy;
+ g_memset(&dst_pb, 0, sizeof(dst_pb));
+ dst_pb.format = get_pt_format(self);
+ dst_pb.width = ldst->width;
+ dst_pb.stride_bytes = ldst->line_size;
+ dst_pb.height = ldst->height;
+ dst_pb.data = ldst->data;
+ painter_set_rop(self->painter, PT_ROP_S);
+ painter_set_pattern_origin(self->painter, 0, 0);
+ painter_set_pattern_mode(self->painter, PT_PATTERN_MODE_NORMAL);
+ painter_set_fgcolor(self->painter,
+ get_rgb_from_rdp_color(self, self->fg_color));
+ k = 0;
+ while (xrdp_region_get_rect(region, k, &rect) == 0)
+ {
+ if (rect_intersect(&rect, &clip_rect, &draw_rect))
+ {
+ painter_set_clip(self->painter,
+ draw_rect.left, draw_rect.top,
+ draw_rect.right - draw_rect.left,
+ draw_rect.bottom - draw_rect.top);
+ for (index = 0; index < len; index++)
+ {
+ font_item = font->font_items + wstr[index];
+ g_memset(&pat, 0, sizeof(pat));
+ pat.format = PT_FORMAT_c1;
+ pat.width = font_item->width;
+ pat.stride_bytes = (font_item->width + 7) / 8;
+ pat.height = font_item->height;
+ pat.data = font_item->data;
+ x1 = x + font_item->offset;
+ y1 = y + (font_item->height + font_item->baseline);
+ painter_fill_pattern(self->painter, &dst_pb, &pat,
+ 0, 0, x1, y1,
+ font_item->width,
+ font_item->height);
+ xrdp_painter_add_dirty_rect(self, x, y,
+ font_item->width,
+ font_item->height,
+ &draw_rect);
+ x += font_item->incby;
+ }
+ }
+ k++;
+ }
+ painter_clear_clip(self->painter);
+ xrdp_region_delete(region);
+ g_free(wstr);
+ }
+ return 0;
+#endif
+ }
+
/* convert to wide char */
wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0);
g_mbstowcs(wstr, text, len + 1);
@@ -616,11 +1021,18 @@ xrdp_painter_draw_text2(struct xrdp_painter *self,
int dx;
int dy;
+ LLOGLN(0, ("xrdp_painter_draw_text2:"));
+
if (self == 0)
{
return 0;
}
+ if (self->painter != 0)
+ {
+ return 0;
+ }
+
/* todo data */
if (dst->type == WND_TYPE_BITMAP)
@@ -711,11 +1123,76 @@ xrdp_painter_copy(struct xrdp_painter *self,
int index;
struct list *del_list;
+ LLOGLN(10, ("xrdp_painter_copy:"));
+
if (self == 0 || src == 0 || dst == 0)
{
return 0;
}
+ if (self->painter != 0)
+ {
+#if defined(XRDP_PAINTER)
+ struct painter_bitmap src_pb;
+ struct painter_bitmap dst_pb;
+ struct xrdp_bitmap *ldst;
+
+ LLOGLN(10, ("xrdp_painter_copy: src->type %d dst->type %d", src->type, dst->type));
+ LLOGLN(10, ("xrdp_painter_copy: self->rop 0x%2.2x", self->rop));
+
+ if (dst->type != WND_TYPE_OFFSCREEN)
+ {
+ LLOGLN(10, ("xrdp_painter_copy: using painter"));
+ ldst = self->wm->screen;
+
+ g_memset(&dst_pb, 0, sizeof(dst_pb));
+ dst_pb.format = get_pt_format(self);
+ dst_pb.width = ldst->width;
+ dst_pb.stride_bytes = ldst->line_size;
+ dst_pb.height = ldst->height;
+ dst_pb.data = ldst->data;
+
+ g_memset(&src_pb, 0, sizeof(src_pb));
+ src_pb.format = get_pt_format(self);
+ src_pb.width = src->width;
+ src_pb.stride_bytes = src->line_size;
+ src_pb.height = src->height;
+ src_pb.data = src->data;
+
+ xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy);
+ region = xrdp_region_create(self->wm);
+ xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region,
+ self->clip_children);
+ x += dx;
+ y += dy;
+ k = 0;
+
+ painter_set_rop(self->painter, self->rop);
+ while (xrdp_region_get_rect(region, k, &rect1) == 0)
+ {
+ if (rect_intersect(&rect1, &clip_rect, &draw_rect))
+ {
+ painter_set_clip(self->painter,
+ draw_rect.left, draw_rect.top,
+ draw_rect.right - draw_rect.left,
+ draw_rect.bottom - draw_rect.top);
+ LLOGLN(10, (" x %d y %d cx %d cy %d srcx %d srcy %d",
+ x, y, cx, cy, srcx, srcy));
+ painter_copy(self->painter, &dst_pb, x, y, cx, cy,
+ &src_pb, srcx, srcy);
+ xrdp_painter_add_dirty_rect(self, x, y, cx, cy,
+ &draw_rect);
+ }
+ k++;
+ }
+ painter_clear_clip(self->painter);
+ xrdp_region_delete(region);
+ }
+
+ return 0;
+#endif
+ }
+
/* todo data */
if (dst->type == WND_TYPE_BITMAP)
@@ -848,7 +1325,7 @@ xrdp_painter_copy(struct xrdp_painter *self,
while (i < (srcx + cx))
{
w = MIN(64, ((srcx + cx) - i));
- h = MIN(63, ((srcy + cy) - j));
+ h = MIN(64, ((srcy + cy) - j));
b = xrdp_bitmap_create(w, h, src->bpp, 0, self->wm);
#if 1
xrdp_bitmap_copy_box_with_crc(src, b, i, j, w, h);
@@ -883,7 +1360,7 @@ xrdp_painter_copy(struct xrdp_painter *self,
i += 64;
}
- j += 63;
+ j += 64;
}
xrdp_region_delete(region);
@@ -918,11 +1395,18 @@ xrdp_painter_composite(struct xrdp_painter* self,
int cache_srcidx;
int cache_mskidx;
+ LLOGLN(0, ("xrdp_painter_composite:"));
+
if (self == 0 || src == 0 || dst == 0)
{
return 0;
}
+ if (self->painter != 0)
+ {
+ return 0;
+ }
+
/* todo data */
if (dst->type == WND_TYPE_BITMAP)
@@ -985,10 +1469,75 @@ xrdp_painter_line(struct xrdp_painter *self,
int dy;
int rop;
+ LLOGLN(10, ("xrdp_painter_line:"));
if (self == 0)
{
return 0;
}
+ if (self->painter != 0)
+ {
+#if defined(XRDP_PAINTER)
+ int x;
+ int y;
+ int cx;
+ int cy;
+ struct painter_bitmap dst_pb;
+ struct xrdp_bitmap *ldst;
+
+ LLOGLN(10, ("xrdp_painter_line: dst->type %d", dst->type));
+ LLOGLN(10, ("xrdp_painter_line: self->rop 0x%2.2x", self->rop));
+
+ if (dst->type != WND_TYPE_OFFSCREEN)
+ {
+ LLOGLN(10, ("xrdp_painter_line: using painter"));
+ ldst = self->wm->screen;
+
+ g_memset(&dst_pb, 0, sizeof(dst_pb));
+ dst_pb.format = get_pt_format(self);
+ dst_pb.width = ldst->width;
+ dst_pb.stride_bytes = ldst->line_size;
+ dst_pb.height = ldst->height;
+ dst_pb.data = ldst->data;
+
+ xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy);
+ region = xrdp_region_create(self->wm);
+ x = MIN(x1, x2);
+ y = MIN(y1, y2);
+ cx = g_abs(x1 - x2) + 1;
+ cy = g_abs(y1 - y2) + 1;
+ xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy,
+ region, self->clip_children);
+ x1 += dx;
+ y1 += dy;
+ x2 += dx;
+ y2 += dy;
+ k = 0;
+ rop = self->rop;
+
+ painter_set_rop(self->painter, rop);
+ painter_set_fgcolor(self->painter, self->pen.color);
+ while (xrdp_region_get_rect(region, k, &rect) == 0)
+ {
+ if (rect_intersect(&rect, &clip_rect, &draw_rect))
+ {
+ painter_set_clip(self->painter,
+ draw_rect.left, draw_rect.top,
+ draw_rect.right - draw_rect.left,
+ draw_rect.bottom - draw_rect.top);
+ painter_line(self->painter, &dst_pb, x1, y1, x2, x2,
+ self->pen.width, 0);
+ xrdp_painter_add_dirty_rect(self, x, y, cx, cy,
+ &draw_rect);
+ }
+ k++;
+ }
+ painter_clear_clip(self->painter);
+ xrdp_region_delete(region);
+ }
+
+ return 0;
+#endif
+ }
/* todo data */
diff --git a/xrdp/xrdp_types.h b/xrdp/xrdp_types.h
index 46a23ca1..cc0eaa3c 100644
--- a/xrdp/xrdp_types.h
+++ b/xrdp/xrdp_types.h
@@ -429,6 +429,9 @@ struct xrdp_painter
struct xrdp_session* session;
struct xrdp_wm* wm; /* owner */
struct xrdp_font* font;
+ void *painter;
+ struct xrdp_region *dirty_region;
+ int begin_end_level;
};
/* window or bitmap */
diff --git a/xrdp/xrdp_wm.c b/xrdp/xrdp_wm.c
index 446939bc..065bca5c 100644
--- a/xrdp/xrdp_wm.c
+++ b/xrdp/xrdp_wm.c
@@ -835,44 +835,6 @@ xrdp_wm_xor_pat(struct xrdp_wm *self, int x, int y, int cx, int cy)
}
/*****************************************************************************/
-/* this don't are about nothing, just copy the bits */
-/* no clipping rects, no windows in the way, nothing */
-static int APP_CC
-xrdp_wm_bitblt(struct xrdp_wm *self,
- struct xrdp_bitmap *dst, int dx, int dy,
- struct xrdp_bitmap *src, int sx, int sy,
- int sw, int sh, int rop)
-{
- // int i;
- // int line_size;
- // int Bpp;
- // char* s;
- // char* d;
-
- // if (sw <= 0 || sh <= 0)
- // return 0;
- if (self->screen == dst && self->screen == src)
- {
- /* send a screen blt */
- // Bpp = (dst->bpp + 7) / 8;
- // line_size = sw * Bpp;
- // s = src->data + (sy * src->width + sx) * Bpp;
- // d = dst->data + (dy * dst->width + dx) * Bpp;
- // for (i = 0; i < sh; i++)
- // {
- // //g_memcpy(d, s, line_size);
- // s += src->width * Bpp;
- // d += dst->width * Bpp;
- // }
- libxrdp_orders_init(self->session);
- libxrdp_orders_screen_blt(self->session, dx, dy, sw, sh, sx, sy, rop, 0);
- libxrdp_orders_send(self->session);
- }
-
- return 0;
-}
-
-/*****************************************************************************/
/* return true if rect is totally exposed going in reverse z order */
/* from wnd up */
static int APP_CC
@@ -935,6 +897,7 @@ xrdp_wm_move_window(struct xrdp_wm *self, struct xrdp_bitmap *wnd,
MAKERECT(rect1, wnd->left, wnd->top, wnd->width, wnd->height);
+ self->painter->clip_children = 0;
if (xrdp_wm_is_rect_vis(self, wnd, &rect1))
{
rect2 = rect1;
@@ -942,10 +905,13 @@ xrdp_wm_move_window(struct xrdp_wm *self, struct xrdp_bitmap *wnd,
if (xrdp_wm_is_rect_vis(self, wnd, &rect2))
{
- /* if both src and dst are unobscured, we can do a bitblt move */
- xrdp_wm_bitblt(self, self->screen, wnd->left + dx, wnd->top + dy,
- self->screen, wnd->left, wnd->top,
- wnd->width, wnd->height, 0xcc);
+ xrdp_painter_begin_update(self->painter);
+ xrdp_painter_copy(self->painter, self->screen, self->screen,
+ wnd->left + dx, wnd->top + dy,
+ wnd->width, wnd->height,
+ wnd->left, wnd->top);
+ xrdp_painter_end_update(self->painter);
+
wnd->left += dx;
wnd->top += dy;
r = xrdp_region_create(self);
@@ -960,9 +926,11 @@ xrdp_wm_move_window(struct xrdp_wm *self, struct xrdp_bitmap *wnd,
}
xrdp_region_delete(r);
+ self->painter->clip_children = 1;
return 0;
}
}
+ self->painter->clip_children = 1;
wnd->left += dx;
wnd->top += dy;
@@ -971,6 +939,7 @@ xrdp_wm_move_window(struct xrdp_wm *self, struct xrdp_bitmap *wnd,
return 0;
}
+
/*****************************************************************************/
static int APP_CC
xrdp_wm_undraw_dragging_box(struct xrdp_wm *self, int do_begin_end)