/** * xrdp: A Remote Desktop Protocol server. * * Copyright (C) Jay Sorg 2004-2014 * * 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. * * painter, gc */ #if defined(HAVE_CONFIG_H) #include #endif #include "xrdp.h" #if defined(XRDP_PAINTER) #include /* 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 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 * 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->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; } /*****************************************************************************/ void 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); } /*****************************************************************************/ int wm_painter_set_target(struct xrdp_painter *self) { int surface_index; 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) { libxrdp_orders_send_switch_os_surface(self->session, 0xffff); self->wm->current_surface_index = 0xffff; } } else if (self->wm->target_surface->type == WND_TYPE_OFFSCREEN) { surface_index = self->wm->target_surface->item_index; if (surface_index != self->wm->current_surface_index) { if (self->wm->target_surface->tab_stop == 0) /* tab_stop is hack */ { del_list = self->wm->cache->xrdp_os_del_list; index = list_index_of(del_list, surface_index); list_remove_item(del_list, index); libxrdp_orders_send_create_os_surface(self->session, surface_index, self->wm->target_surface->width, self->wm->target_surface->height, del_list); self->wm->target_surface->tab_stop = 1; list_clear(del_list); } libxrdp_orders_send_switch_os_surface(self->session, surface_index); self->wm->current_surface_index = surface_index; } } else { g_writeln("xrdp_painter_begin_update: bad target_surface"); } return 0; } /*****************************************************************************/ int 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; } /*****************************************************************************/ int 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; } /*****************************************************************************/ int xrdp_painter_font_needed(struct xrdp_painter *self) { if (self->font == 0) { self->font = self->wm->default_font; } return 0; } #if 0 /*****************************************************************************/ /* returns boolean, true if there is something to draw */ static int xrdp_painter_clip_adj(struct xrdp_painter *self, int *x, int *y, int *cx, int *cy) { int dx; int dy; if (!self->use_clip) { return 1; } if (self->clip.left > *x) { dx = self->clip.left - *x; } else { dx = 0; } if (self->clip.top > *y) { dy = self->clip.top - *y; } else { dy = 0; } if (*x + *cx > self->clip.right) { *cx = *cx - ((*x + *cx) - self->clip.right); } if (*y + *cy > self->clip.bottom) { *cy = *cy - ((*y + *cy) - self->clip.bottom); } *cx = *cx - dx; *cy = *cy - dy; if (*cx <= 0) { return 0; } if (*cy <= 0) { return 0; } *x = *x + dx; *y = *y + dy; return 1; } #endif /*****************************************************************************/ int xrdp_painter_set_clip(struct xrdp_painter *self, int x, int y, int cx, int cy) { self->use_clip = &self->clip; self->clip.left = x; self->clip.top = y; self->clip.right = x + cx; self->clip.bottom = y + cy; return 0; } /*****************************************************************************/ int xrdp_painter_clr_clip(struct xrdp_painter *self) { self->use_clip = 0; return 0; } #if 0 /*****************************************************************************/ static int xrdp_painter_rop(int rop, int src, int dst) { switch (rop & 0x0f) { case 0x0: return 0; case 0x1: return ~(src | dst); case 0x2: return (~src) & dst; case 0x3: return ~src; case 0x4: return src & (~dst); case 0x5: return ~(dst); case 0x6: return src ^ dst; case 0x7: return ~(src & dst); case 0x8: return src & dst; case 0x9: return ~(src) ^ dst; case 0xa: return dst; case 0xb: return (~src) | dst; case 0xc: return src; case 0xd: return src | (~dst); case 0xe: return src | dst; case 0xf: return ~0; } return dst; } #endif /*****************************************************************************/ int xrdp_painter_text_width(struct xrdp_painter *self, const char *text) { int index; int rv; int len; struct xrdp_font_char *font_item; twchar *wstr; LLOGLN(10, ("xrdp_painter_text_width:")); xrdp_painter_font_needed(self); if (self->font == 0) { return 0; } if (text == 0) { return 0; } rv = 0; len = g_mbstowcs(0, text, 0); wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); for (index = 0; index < len; index++) { font_item = self->font->font_items + wstr[index]; rv = rv + font_item->incby; } g_free(wstr); return rv; } /*****************************************************************************/ int xrdp_painter_text_height(struct xrdp_painter *self, const char *text) { int index; int rv; int len; struct xrdp_font_char *font_item; twchar *wstr; LLOGLN(10, ("xrdp_painter_text_height:")); xrdp_painter_font_needed(self); if (self->font == 0) { return 0; } if (text == 0) { return 0; } rv = 0; len = g_mbstowcs(0, text, 0); wstr = (twchar *)g_malloc((len + 2) * sizeof(twchar), 0); g_mbstowcs(wstr, text, len + 1); for (index = 0; index < len; index++) { font_item = self->font->font_items + wstr[index]; rv = MAX(rv, font_item->height); } g_free(wstr); return rv; } /*****************************************************************************/ static int xrdp_painter_setup_brush(struct xrdp_painter *self, struct xrdp_brush *out_brush, struct xrdp_brush *in_brush) { 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) { if (self->session->client_info->brush_cache_code == 1) { cache_id = xrdp_cache_add_brush(self->wm->cache, in_brush->pattern); g_memset(out_brush->pattern, 0, 8); out_brush->pattern[0] = cache_id; out_brush->style = 0x81; } } return 0; } #if defined(XRDP_PAINTER) /*****************************************************************************/ static int 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 xrdp_painter_fill_rect(struct xrdp_painter *self, struct xrdp_bitmap *dst, int x, int y, int cx, int cy) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region *region; struct xrdp_brush brush; int k; int dx; 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 */ { return 0; } xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); } else { xrdp_region_add_rect(region, &clip_rect); } x += dx; y += dy; if (self->mix_mode == 0 && self->rop == 0xcc) { k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_rect(self->session, x, y, cx, cy, self->fg_color, &draw_rect); } k++; } } else if (self->mix_mode == 0 && ((self->rop & 0xf) == 0x0 || /* black */ (self->rop & 0xf) == 0xf || /* white */ (self->rop & 0xf) == 0x5)) /* DSTINVERT */ { k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_dest_blt(self->session, x, y, cx, cy, self->rop, &draw_rect); } k++; } } else { k = 0; rop = self->rop; /* if opcode is in the form 0x00, 0x11, 0x22, ... convert it */ if (((rop & 0xf0) >> 4) == (rop & 0xf)) { switch (rop) { case 0x66: /* xor */ rop = 0x5a; break; case 0xaa: /* noop */ rop = 0xfb; break; case 0xcc: /* copy */ rop = 0xf0; break; case 0x88: /* and */ rop = 0xc0; break; } } xrdp_painter_setup_brush(self, &brush, &self->brush); while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_pat_blt(self->session, x, y, cx, cy, rop, self->bg_color, self->fg_color, &brush, &draw_rect); } k++; } } xrdp_region_delete(region); return 0; } /*****************************************************************************/ int xrdp_painter_draw_text(struct xrdp_painter *self, struct xrdp_bitmap *dst, int x, int y, const char *text) { int i; int f; int c; int k; int x1; int y1; int flags; int len; int index; int total_width; int total_height; int dx; int dy; char *data; struct xrdp_region *region; struct xrdp_rect rect; struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_font *font; 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) { return 0; } /* todo data */ if (dst->type == 0) { return 0; } xrdp_painter_font_needed(self); if (self->font == 0) { 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); font = self->font; f = 0; k = 0; total_width = 0; total_height = 0; data = (char *)g_malloc(len * 4, 1); for (index = 0; index < len; index++) { font_item = font->font_items + wstr[index]; i = xrdp_cache_add_char(self->wm->cache, font_item); f = HIWORD(i); c = LOWORD(i); data[index * 2] = c; data[index * 2 + 1] = k; 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); if (dst->type != WND_TYPE_OFFSCREEN) { xrdp_wm_get_vis_region(self->wm, dst, x, y, total_width, total_height, region, self->clip_children); } else { xrdp_region_add_rect(region, &clip_rect); } x += dx; y += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { x1 = x; y1 = y + total_height; flags = 0x03; /* 0x03 0x73; TEXT2_IMPLICIT_X and something else */ libxrdp_orders_text(self->session, f, flags, 0, self->fg_color, 0, x - 1, y - 1, x + total_width, y + total_height, 0, 0, 0, 0, x1, y1, data, len * 2, &draw_rect); } k++; } xrdp_region_delete(region); g_free(data); g_free(wstr); return 0; } /*****************************************************************************/ int xrdp_painter_draw_text2(struct xrdp_painter *self, struct xrdp_bitmap *dst, int font, int flags, int mixmode, int clip_left, int clip_top, int clip_right, int clip_bottom, int box_left, int box_top, int box_right, int box_bottom, int x, int y, char *data, int data_len) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region *region; int k; 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) { return 0; } xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { if (box_right - box_left > 1) { xrdp_wm_get_vis_region(self->wm, dst, box_left, box_top, box_right - box_left, box_bottom - box_top, region, self->clip_children); } else { xrdp_wm_get_vis_region(self->wm, dst, clip_left, clip_top, clip_right - clip_left, clip_bottom - clip_top, region, self->clip_children); } } else { xrdp_region_add_rect(region, &clip_rect); } clip_left += dx; clip_top += dy; clip_right += dx; clip_bottom += dy; box_left += dx; box_top += dy; box_right += dx; box_bottom += dy; x += dx; y += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_text(self->session, font, flags, mixmode, self->fg_color, self->bg_color, clip_left, clip_top, clip_right, clip_bottom, box_left, box_top, box_right, box_bottom, x, y, data, data_len, &draw_rect); } k++; } xrdp_region_delete(region); return 0; } /*****************************************************************************/ int xrdp_painter_copy(struct xrdp_painter *self, struct xrdp_bitmap *src, struct xrdp_bitmap *dst, int x, int y, int cx, int cy, int srcx, int srcy) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect1; struct xrdp_rect rect2; struct xrdp_region *region; struct xrdp_bitmap *b; int i; int j; int k; int dx; int dy; int palette_id; int bitmap_id; int cache_id; int cache_idx; int dstx; int dsty; int w; int h; 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) { return 0; } if (src->type == WND_TYPE_SCREEN) { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); } else { xrdp_region_add_rect(region, &clip_rect); } x += dx; y += dy; srcx += dx; srcy += dy; k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &draw_rect)) { libxrdp_orders_screen_blt(self->session, x, y, cx, cy, srcx, srcy, self->rop, &draw_rect); } k++; } xrdp_region_delete(region); } else if (src->type == WND_TYPE_OFFSCREEN) { //g_writeln("xrdp_painter_copy: todo"); xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { //g_writeln("off screen to screen"); xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); } else { //g_writeln("off screen to off screen"); xrdp_region_add_rect(region, &clip_rect); } x += dx; y += dy; palette_id = 0; cache_id = 255; // todo cache_idx = src->item_index; // todo if (src->tab_stop == 0) { g_writeln("xrdp_painter_copy: warning src not created"); del_list = self->wm->cache->xrdp_os_del_list; index = list_index_of(del_list, cache_idx); list_remove_item(del_list, index); libxrdp_orders_send_create_os_surface(self->session, cache_idx, src->width, src->height, del_list); src->tab_stop = 1; list_clear(del_list); } k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &rect2)) { MAKERECT(rect1, x, y, cx, cy); if (rect_intersect(&rect2, &rect1, &draw_rect)) { libxrdp_orders_mem_blt(self->session, cache_id, palette_id, x, y, cx, cy, self->rop, srcx, srcy, cache_idx, &draw_rect); } } k++; } xrdp_region_delete(region); } else if (src->data != 0) /* todo, the non bitmap cache part is gone, it should be put back */ { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { xrdp_wm_get_vis_region(self->wm, dst, x, y, cx, cy, region, self->clip_children); } else { xrdp_region_add_rect(region, &clip_rect); } x += dx; y += dy; palette_id = 0; j = srcy; while (j < (srcy + cy)) { i = srcx; while (i < (srcx + cx)) { w = MIN(64, ((srcx + cx) - i)); 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); #else xrdp_bitmap_copy_box(src, b, i, j, w, h); xrdp_bitmap_hash_crc(b); #endif bitmap_id = xrdp_cache_add_bitmap(self->wm->cache, b, self->wm->hints); cache_id = HIWORD(bitmap_id); cache_idx = LOWORD(bitmap_id); dstx = (x + i) - srcx; dsty = (y + j) - srcy; k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &rect2)) { MAKERECT(rect1, dstx, dsty, w, h); if (rect_intersect(&rect2, &rect1, &draw_rect)) { libxrdp_orders_mem_blt(self->session, cache_id, palette_id, dstx, dsty, w, h, self->rop, 0, 0, cache_idx, &draw_rect); } } k++; } i += 64; } j += 64; } xrdp_region_delete(region); } return 0; } /*****************************************************************************/ int xrdp_painter_composite(struct xrdp_painter* self, struct xrdp_bitmap* src, int srcformat, int srcwidth, int srcrepeat, struct xrdp_bitmap* dst, int* srctransform, int mskflags, struct xrdp_bitmap* msk, int mskformat, int mskwidth, int mskrepeat, int op, int srcx, int srcy, int mskx, int msky, int dstx, int dsty, int width, int height, int dstformat) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect1; struct xrdp_rect rect2; struct xrdp_region* region; int k; int dx; int dy; 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) { return 0; } if (src->type == WND_TYPE_OFFSCREEN) { xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); xrdp_region_add_rect(region, &clip_rect); dstx += dx; dsty += dy; cache_srcidx = src->item_index; cache_mskidx = -1; if (mskflags & 1) { if (msk != 0) { cache_mskidx = msk->item_index; // todo } } k = 0; while (xrdp_region_get_rect(region, k, &rect1) == 0) { if (rect_intersect(&rect1, &clip_rect, &rect2)) { MAKERECT(rect1, dstx, dsty, width, height); if (rect_intersect(&rect2, &rect1, &draw_rect)) { libxrdp_orders_composite_blt(self->session, cache_srcidx, srcformat, srcwidth, srcrepeat, srctransform, mskflags, cache_mskidx, mskformat, mskwidth, mskrepeat, op, srcx, srcy, mskx, msky, dstx, dsty, width, height, dstformat, &draw_rect); } } k++; } xrdp_region_delete(region); } return 0; } /*****************************************************************************/ int xrdp_painter_line(struct xrdp_painter *self, struct xrdp_bitmap *dst, int x1, int y1, int x2, int y2) { struct xrdp_rect clip_rect; struct xrdp_rect draw_rect; struct xrdp_rect rect; struct xrdp_region *region; int k; int dx; 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, y2, 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 */ if (dst->type == WND_TYPE_BITMAP) { return 0; } xrdp_bitmap_get_screen_clip(dst, self, &clip_rect, &dx, &dy); region = xrdp_region_create(self->wm); if (dst->type != WND_TYPE_OFFSCREEN) { xrdp_wm_get_vis_region(self->wm, dst, MIN(x1, x2), MIN(y1, y2), g_abs(x1 - x2) + 1, g_abs(y1 - y2) + 1, region, self->clip_children); } else { xrdp_region_add_rect(region, &clip_rect); } x1 += dx; y1 += dy; x2 += dx; y2 += dy; k = 0; rop = self->rop; if (rop < 0x01 || rop > 0x10) { rop = (rop & 0xf) + 1; } while (xrdp_region_get_rect(region, k, &rect) == 0) { if (rect_intersect(&rect, &clip_rect, &draw_rect)) { libxrdp_orders_line(self->session, 1, x1, y1, x2, y2, rop, self->bg_color, &self->pen, &draw_rect); } k++; } xrdp_region_delete(region); return 0; }