/* * Precalculate the rectangles needed to perform video looping: * * The nominal pipeline is that the video output buffer is cropped by * crop_out, scaled to compose_out, overlaid with the output overlay, * cropped on the capture side by crop_cap and scaled again to the video * capture buffer using compose_cap. * * To keep things efficient we calculate the intersection of compose_out * and crop_cap (since that's the only part of the video that will * actually end up in the capture buffer), determine which part of the * video output buffer that is and which part of the video capture buffer * so we can scale the video straight from the output buffer to the capture * buffer without any intermediate steps. * * If we need to deal with an output overlay, then there is no choice and * that intermediate step still has to be taken. For the output overlay * support we calculate the intersection of the framebuffer and the overlay * window (which may be partially or wholly outside of the framebuffer * itself) and the intersection of that with loop_vid_copy (i.e. the part of * the actual looped video that will be overlaid). The result is calculated * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates * (loop_vid_overlay). Finally calculate the part of the capture buffer that * will receive that overlaid video. */ static void vivid_precalc_copy_rects(struct vivid_dev *dev) { /* Framebuffer rectangle */ struct v4l2_rect r_fb = { 0, 0, dev->display_width, dev->display_height }; /* Overlay window rectangle in framebuffer coordinates */ struct v4l2_rect r_overlay = { dev->overlay_out_left, dev->overlay_out_top, dev->compose_out.width, dev->compose_out.height }; dev->loop_vid_copy = rect_intersect(&dev->crop_cap, &dev->compose_out); dev->loop_vid_out = dev->loop_vid_copy; rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); dev->loop_vid_out.left += dev->crop_out.left; dev->loop_vid_out.top += dev->crop_out.top; dev->loop_vid_cap = dev->loop_vid_copy; rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); dprintk(dev, 1, "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", dev->loop_vid_copy.width, dev->loop_vid_copy.height, dev->loop_vid_copy.left, dev->loop_vid_copy.top, dev->loop_vid_out.width, dev->loop_vid_out.height, dev->loop_vid_out.left, dev->loop_vid_out.top, dev->loop_vid_cap.width, dev->loop_vid_cap.height, dev->loop_vid_cap.left, dev->loop_vid_cap.top); r_overlay = rect_intersect(&r_fb, &r_overlay); /* shift r_overlay to the same origin as compose_out */ r_overlay.left += dev->compose_out.left - dev->overlay_out_left; r_overlay.top += dev->compose_out.top - dev->overlay_out_top; dev->loop_vid_overlay = rect_intersect(&r_overlay, &dev->loop_vid_copy); dev->loop_fb_copy = dev->loop_vid_overlay; /* shift dev->loop_fb_copy back again to the fb origin */ dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left; dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; dev->loop_vid_overlay_cap = dev->loop_vid_overlay; rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); dprintk(dev, 1, "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", dev->loop_fb_copy.width, dev->loop_fb_copy.height, dev->loop_fb_copy.left, dev->loop_fb_copy.top, dev->loop_vid_overlay.width, dev->loop_vid_overlay.height, dev->loop_vid_overlay.left, dev->loop_vid_overlay.top, dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height, dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); }
inline void clip_set(Rect rect) { Rect canvas_rect = rect_make_size(0, 0, CORE->canvas->width, CORE->canvas->height); rect_intersect(&rect, &canvas_rect); CORE->clip = rect; }
void progressive_display_add_rect(struct xrdp_screen * self) { int i, j; struct list* update_rects = self->update_rects; struct update_rect* urect; struct update_rect* fu_rect; struct update_rect* ur; struct xrdp_rect intersection; struct update_rect* tmp; struct list* l_tmp = list_create(); l_tmp->auto_free = 1; bool no_inter = true; while (!fifo_is_empty(self->candidate_update_rects)) { fu_rect = (struct update_rect*) fifo_pop(self->candidate_update_rects); if (update_rects->count > 0) { no_inter = true; for (i = update_rects->count - 1; i >= 0; i--) { urect = (struct update_rect*) list_get_item(update_rects, i); if (!rect_equal(&urect->rect, &fu_rect->rect)) { if (rect_intersect(&urect->rect, &fu_rect->rect, &intersection)) { no_inter = false; progressive_display_rect_union(fu_rect, urect, l_tmp); list_remove_item(update_rects, i); for (j = 0; j < l_tmp->count; j++) { ur = (struct update_rect*) list_get_item(l_tmp, j); tmp = (struct update_rect*) g_malloc(sizeof(struct update_rect), 0); g_memcpy(tmp, ur, sizeof(struct update_rect)); fifo_push(self->candidate_update_rects, tmp); } list_clear(l_tmp); break; } } else { no_inter = false; urect->quality = fu_rect->quality; urect->quality_already_send = fu_rect->quality_already_send; break; } } if (no_inter) { list_add_progressive_display_rect(update_rects, fu_rect->rect.left, fu_rect->rect.top, fu_rect->rect.right, fu_rect->rect.bottom, fu_rect->quality, fu_rect->quality_already_send); } } else { list_add_progressive_display_rect(update_rects, fu_rect->rect.left, fu_rect->rect.top, fu_rect->rect.right, fu_rect->rect.bottom, fu_rect->quality, fu_rect->quality_already_send); } } list_delete(l_tmp); }
/* returns int */ int APP_CC rect_update_bounding_box(struct xrdp_rect* BB, struct xrdp_rect* r, int DELTA) { struct xrdp_rect inter; if (rect_equal(BB, r)) { return 0; } if (rect_contained_by(r, BB->left, BB->top, BB->right, BB->bottom)) { BB->left = r->left; BB->top = r->top; BB->bottom = r->bottom; BB->right = r->right; return 0; } if (rect_contained_by(BB, r->left, r->top, r->right, r->bottom)) { return 0; } struct xrdp_rect tmp; tmp.left = BB->left - DELTA; tmp.right = BB->right + DELTA; tmp.top = BB->top - DELTA; tmp.bottom = BB->bottom + DELTA; if (rect_intersect(BB, r, &inter) || rect_intersect(&tmp, r, &inter)) { BB->top = MIN(BB->top, r->top); BB->left = MIN(BB->left, r->left); BB->right = MAX(BB->right, r->right); BB->bottom = MAX(BB->bottom, r->bottom); return 0; } else { return 1; } return -1; }
/* schedule redraw coords. */ void redraw_slot_schedule(struct s_redrw_slots * slots, short x0, short y0, short x1, short y1, bool force) { int i = 0; struct rect area; area.x0 = x0; area.y0 = y0; area.x1 = x1; area.y1 = y1; if (force == false) { for (i=0; i<slots->areas_used; i++) { if (slots->areas[i].x0 <= x0 && slots->areas[i].x1 >= x1 && slots->areas[i].y0 <= y0 && slots->areas[i].y1 >= y1) { /* the area is already queued for redraw */ return; } else { if (rect_intersect(&slots->areas[i], &area )) { slots->areas[i].x0 = MIN(slots->areas[i].x0, x0); slots->areas[i].y0 = MIN(slots->areas[i].y0, y0); slots->areas[i].x1 = MAX(slots->areas[i].x1, x1); slots->areas[i].y1 = MAX(slots->areas[i].y1, y1); return; } } } } if (slots->areas_used < slots->size) { slots->areas[slots->areas_used].x0 = x0; slots->areas[slots->areas_used].x1 = x1; slots->areas[slots->areas_used].y0 = y0; slots->areas[slots->areas_used].y1 = y1; slots->areas_used++; } else { /* we are out of available slots, merge box with last slot this is dumb... but also a very rare case. */ slots->areas[slots->size-1].x0 = MIN(slots->areas[i].x0, x0); slots->areas[slots->size-1].y0 = MIN(slots->areas[i].y0, y0); slots->areas[slots->size-1].x1 = MAX(slots->areas[i].x1, x1); slots->areas[slots->size-1].y1 = MAX(slots->areas[i].y1, y1); } done: return; }
int entity_intersect_rect(Entity *a,SDL_Rect r) { SDL_Rect aB; if (!a) { slog("ERROR: Missing entity for check"); return 0; } aB = rect( a->position.x + a->bounds.x, a->position.y + a->bounds.y, a->bounds.w, a->bounds.h); return rect_intersect(aB,r); }
void rect_draw(Rect r, u8 color) { rect_tr(&r, CORE->translate_x, CORE->translate_y); rect_intersect(&r, &CORE->clip); if (r.max_x > r.min_x && r.max_y > r.min_y) { u32 canvas_pitch = CORE->canvas->width; u8 *row = CORE->canvas->pixels + r.min_x + (r.min_y * canvas_pitch); i32 w = r.max_x - r.min_x; while (r.max_y != r.min_y) { memset(row, color, w); row += canvas_pitch; r.max_y--; } } }
int entity_intersect(Entity *a, Entity *b) { SDL_Rect aB,bB; if ((!a) || (!b)) { slog("ERROR: Missing entity for check"); return 0; } aB = rect( a->position.x + a->bounds.x, a->position.y + a->bounds.y, a->bounds.w, a->bounds.h); bB = rect( b->position.x + b->bounds.x, b->position.y + b->bounds.y, b->bounds.w, b->bounds.h); return rect_intersect(aB,bB); }
int bitmap_set_viewport(struct bitmap * bitmap, struct rect * rect) { struct rect r, x; if(!bitmap || !rect) return 0; x.left = 0; x.top = 0; x.right = bitmap->info.width; x.bottom = bitmap->info.height; if(rect_intersect(&r, &x, rect) == 0) return 0; bitmap->viewport.left = r.left; bitmap->viewport.top = r.top; bitmap->viewport.right = r.right; bitmap->viewport.bottom = r.bottom; return 1; }
struct surface_t * map_software_rotate(struct surface_t * surface, struct rect_t * rect, enum rotate_type type) { struct surface_t * rotate; struct rect_t clipped; u32_t w, h; if(!surface) return NULL; if (!surface->pixels) return NULL; if (surface->info.bits_per_pixel < 8) return NULL; clipped.x = 0; clipped.y = 0; clipped.w = surface->w; clipped.h = surface->h; if(rect) { if (!rect_intersect(rect, &clipped, &clipped)) return NULL; } rect = &clipped; switch(type) { case ROTATE_DEGREE_0: case ROTATE_DEGREE_180: case ROTATE_MIRROR_H: case ROTATE_MIRROR_V: w = rect->w; h = rect->h; break; case ROTATE_DEGREE_90: case ROTATE_DEGREE_270: w = rect->h; h = rect->w; break; default: return NULL; } rotate = surface_alloc(NULL, w, h, surface->info.fmt); if(!rotate) return NULL; switch (surface->info.bytes_per_pixel) { case 1: software_rotate_1byte(rotate, surface, rect, type); break; case 2: software_rotate_2byte(rotate, surface, rect, type); break; case 3: software_rotate_3byte(rotate, surface, rect, type); break; case 4: software_rotate_4byte(rotate, surface, rect, type); break; default: surface_free(rotate); return NULL; } return rotate; }
static void TraverseLayer2D(GF_Node *node, void *rs, Bool is_destroy) { GF_List *oldb, *oldv; GF_Node *viewport; GF_Node *back; Bool prev_layer; GF_Matrix2D backup; SFVec2f prev_vp; #ifndef GPAC_DISABLE_3D GF_Matrix mx3d; GF_List *oldf, *oldn; GF_List *node_list_backup; GF_Rect prev_clipper; Bool had_clip; #endif M_Layer2D *l = (M_Layer2D *)node; Layer2DStack *st = (Layer2DStack *) gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *) rs; if (is_destroy) { gf_list_del(st->backs); gf_list_del(st->views); group_2d_destroy(node, (GroupingNode2D*)st); gf_free(st); return; } /*layers can only be used in a 2D context*/ #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d && tr_state->camera->is_3D) return; #endif /*layer2D maintains its own stacks*/ oldb = tr_state->backgrounds; oldv = tr_state->viewpoints; tr_state->backgrounds = st->backs; tr_state->viewpoints = st->views; prev_layer = tr_state->is_layer; tr_state->is_layer = 1; #ifndef GPAC_DISABLE_3D oldf = tr_state->fogs; oldn = tr_state->navigations; tr_state->fogs = tr_state->navigations = NULL; #endif l2d_CheckBindables(node, tr_state, st->first); back = (GF_Node*)gf_list_get(st->backs, 0); viewport = (GF_Node*)gf_list_get(st->views, 0); if ((tr_state->traversing_mode == TRAVERSE_SORT) || (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS)) { /*override group bounds*/ visual_get_size_info(tr_state, &st->clip.width, &st->clip.height); /*setup bounds in local coord system*/ if (l->size.x>=0) st->clip.width = l->size.x; if (l->size.y>=0) st->clip.height = l->size.y; st->clip = gf_rect_center(st->clip.width, st->clip.height); st->bounds = st->clip; } prev_vp = tr_state->vp_size; tr_state->vp_size.x = st->clip.width; tr_state->vp_size.y = st->clip.height; switch (tr_state->traversing_mode) { case TRAVERSE_SORT: #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { tr_state->layer_clipper = compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 1); visual_3d_matrix_push(tr_state->visual); gf_mx_copy(mx3d, tr_state->model_matrix); /*setup clipping*/ visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper); /*apply background BEFORE viewport*/ if (back) { tr_state->traversing_mode = TRAVERSE_BINDABLE; gf_bbox_from_rect(&tr_state->bbox, &st->clip); gf_node_traverse(back, tr_state); } /*sort all children without transform, and use current transform when flushing contexts*/ gf_mx_init(tr_state->model_matrix); /*apply viewport*/ if (viewport) { tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); visual_3d_matrix_add(tr_state->visual, tr_state->model_matrix.m); } node_list_backup = tr_state->visual->alpha_nodes_to_draw; tr_state->visual->alpha_nodes_to_draw = gf_list_new(); tr_state->traversing_mode = TRAVERSE_SORT; /*reset cull flag*/ tr_state->cull_flag = 0; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); visual_3d_flush_contexts(tr_state->visual, tr_state); tr_state->traversing_mode = TRAVERSE_SORT; assert(!gf_list_count(tr_state->visual->alpha_nodes_to_draw)); gf_list_del(tr_state->visual->alpha_nodes_to_draw); tr_state->visual->alpha_nodes_to_draw = node_list_backup; visual_3d_matrix_pop(tr_state->visual); gf_mx_copy(tr_state->model_matrix, mx3d); visual_3d_reset_clipper_2d(tr_state->visual); tr_state->has_layer_clip = had_clip; if (had_clip) { tr_state->layer_clipper = prev_clipper; visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper); } } else #endif { GF_IRect prev_clip; GF_Rect rc; gf_mx2d_copy(backup, tr_state->transform); prev_clip = tr_state->visual->top_clipper; rc = st->clip; /*get clipper in world coordinate*/ gf_mx2d_apply_rect(&tr_state->transform, &rc); if (viewport) { tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); #if VIEWPORT_CLIPS /*move viewport box in world coordinate*/ gf_mx2d_apply_rect(&backup, &tr_state->bounds); /*and intersect with layer clipper*/ rect_intersect(&rc, &tr_state->bounds); #endif } tr_state->visual->top_clipper = gf_rect_pixelize(&rc); gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip); tr_state->traversing_mode = TRAVERSE_SORT; if (tr_state->visual->top_clipper.width && tr_state->visual->top_clipper.height) { if (back && Bindable_GetIsBound(back) ) { DrawableContext *ctx; ctx = b2d_get_context((M_Background2D*) back, st->backs); gf_mx2d_init(ctx->transform); ctx->bi->clip = tr_state->visual->top_clipper; ctx->bi->unclip = rc; if (tr_state->immediate_draw) { tr_state->ctx = ctx; tr_state->traversing_mode = TRAVERSE_DRAW_2D; gf_node_traverse(back, tr_state); tr_state->traversing_mode = TRAVERSE_SORT; tr_state->ctx = NULL; } else { DrawableContext *back_ctx = visual_2d_get_drawable_context(tr_state->visual); gf_node_traverse(back, tr_state); back_ctx->flags = ctx->flags; back_ctx->flags &= ~CTX_IS_TRANSPARENT; back_ctx->flags |= CTX_IS_BACKGROUND; back_ctx->aspect = ctx->aspect; back_ctx->drawable = ctx->drawable; drawable_check_bounds(back_ctx, tr_state->visual); back_ctx->bi->clip = ctx->bi->clip; back_ctx->bi->unclip = ctx->bi->unclip; } /*keep track of node drawn*/ if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) { struct _drawable_store *it; GF_SAFEALLOC(it, struct _drawable_store); it->drawable = ctx->drawable; if (tr_state->visual->last_prev_entry) { tr_state->visual->last_prev_entry->next = it; tr_state->visual->last_prev_entry = it; } else { tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it; } GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node))); ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL; } } group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } tr_state->visual->top_clipper = prev_clip; gf_mx2d_copy(tr_state->transform, backup); } break; /*check picking - we must fall in our 2D clipper*/ case TRAVERSE_PICK: if (gf_sc_pick_in_clipper(tr_state, &st->clip)) { #ifndef GPAC_DISABLE_3D if (tr_state->visual->type_3d) { /*apply viewport*/ if (viewport) { gf_mx_copy(mx3d, tr_state->model_matrix); tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); tr_state->traversing_mode = TRAVERSE_PICK; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); gf_mx_copy(tr_state->model_matrix, mx3d); } else { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } } else #endif { if (viewport) { gf_mx2d_copy(backup, tr_state->transform); tr_state->traversing_mode = TRAVERSE_BINDABLE; tr_state->bounds = st->clip; gf_node_traverse(viewport, tr_state); tr_state->traversing_mode = TRAVERSE_PICK; group_2d_traverse(node, (GroupingNode2D *)st, tr_state); gf_mx2d_copy(tr_state->transform, backup); } else { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } } } break; case TRAVERSE_GET_BOUNDS: if (tr_state->for_node) { group_2d_traverse(node, (GroupingNode2D *)st, tr_state); } else { tr_state->bounds = st->clip; #ifndef GPAC_DISABLE_3D gf_bbox_from_rect(&tr_state->bbox, &st->clip); #endif } break; case TRAVERSE_DRAW_2D: group_2d_traverse(node, (GroupingNode2D *)st, tr_state); break; #ifndef GPAC_DISABLE_3D /*drawing a layer means drawing all sub-elements as a whole (no depth sorting with parents)*/ case TRAVERSE_DRAW_3D: assert(0); break; #endif } /*restore traversing state*/ tr_state->vp_size = prev_vp; tr_state->backgrounds = oldb; tr_state->viewpoints = oldv; tr_state->is_layer = prev_layer; #ifndef GPAC_DISABLE_3D tr_state->fogs = oldf; tr_state->navigations = oldn; #endif /*in case we missed bindables*/ if (st->first) { st->first = 0; gf_sc_invalidate(tr_state->visual->compositor, NULL); } }
/* We take the trouble to do this efficiently in the simple cases. */ int gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) { const gs_rect *rlist = pr; gx_clip_path *pcpath; uint rcount = count; int code; gx_device * pdev = pgs->device; gx_device_color *pdc = gs_currentdevicecolor_inline(pgs); const gs_imager_state *pis = (const gs_imager_state *)pgs; bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc); bool hl_color = (hl_color_available && dev_proc(pdev, dev_spec_op)(pdev, gxdso_supports_hlcolor, NULL, 0)); bool center_of_pixel = (pgs->fill_adjust.x == 0 && pgs->fill_adjust.y == 0); /* Processing a fill object operation */ dev_proc(pgs->device, set_graphics_type_tag)(pgs->device, GS_PATH_TAG); code = gx_set_dev_color(pgs); if (code != 0) return code; if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && gx_effective_clip_path(pgs, &pcpath) >= 0 && clip_list_is_rectangle(gx_cpath_list(pcpath)) && (hl_color || pdc->type == gx_dc_type_pure || pdc->type == gx_dc_type_ht_binary || pdc->type == gx_dc_type_ht_colored) && gs_state_color_load(pgs) >= 0 && (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics) <= 1 && (!pgs->overprint || !pgs->effective_overprint_mode) ) { uint i; gs_fixed_rect clip_rect; gx_cpath_inner_box(pcpath, &clip_rect); /* We should never plot anything for an empty clip rectangle */ if ((clip_rect.p.x >= clip_rect.q.x) && (clip_rect.p.y >= clip_rect.q.y)) return 0; for (i = 0; i < count; ++i) { gs_fixed_point p, q; gs_fixed_rect draw_rect; if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 || gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0 ) { /* Switch to the slow algorithm. */ goto slow; } draw_rect.p.x = min(p.x, q.x); draw_rect.p.y = min(p.y, q.y); draw_rect.q.x = max(p.x, q.x); draw_rect.q.y = max(p.y, q.y); if (hl_color) { rect_intersect(draw_rect, clip_rect); /* We do pass on 0 extant rectangles to high level devices. It isn't clear how a client and an output device should interact if one uses a center of pixel algorithm and the other uses any part of pixel. For now we punt and just pass the high level rectangle on without adjustment. */ if (draw_rect.p.x <= draw_rect.q.x && draw_rect.p.y <= draw_rect.q.y) { code = dev_proc(pdev, fill_rectangle_hl_color)(pdev, &draw_rect, pis, pdc, pcpath); if (code < 0) return code; } } else { int x, y, w, h; rect_intersect(draw_rect, clip_rect); if (center_of_pixel) { draw_rect.p.x = fixed_rounded(draw_rect.p.x); draw_rect.p.y = fixed_rounded(draw_rect.p.y); draw_rect.q.x = fixed_rounded(draw_rect.q.x); draw_rect.q.y = fixed_rounded(draw_rect.q.y); } else { /* any part of pixel rule - touched */ draw_rect.p.x = fixed_floor(draw_rect.p.x); draw_rect.p.y = fixed_floor(draw_rect.p.y); draw_rect.q.x = fixed_ceiling(draw_rect.q.x); draw_rect.q.y = fixed_ceiling(draw_rect.q.y); } x = fixed2int(draw_rect.p.x); y = fixed2int(draw_rect.p.y); w = fixed2int(draw_rect.q.x) - x; h = fixed2int(draw_rect.q.y) - y; /* clients that use the "any part of pixel" rule also fill 0 areas. This is true of current graphics library clients but not a general rule. */ if (!center_of_pixel) { if (w == 0) w = 1; /* yes Adobe Acrobat 8, seems to back up the y coordinate when the width is 0, sigh. */ if (h == 0) { y--; h = 1; } } if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0) goto slow; } } return 0; slow:rlist = pr + i; rcount = count - i; } { bool do_save = !gx_path_is_null(pgs->path); if (do_save) { if ((code = gs_gsave(pgs)) < 0) return code; gs_newpath(pgs); } if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 || (code = gs_fill(pgs)) < 0 ) DO_NOTHING; if (do_save) gs_grestore(pgs); else if (code < 0) gs_newpath(pgs); } return code; }
/* We take the trouble to do this efficiently in the simple cases. */ int gs_rectfill(gs_state * pgs, const gs_rect * pr, uint count) { const gs_rect *rlist = pr; gx_clip_path *pcpath; uint rcount = count; int code; gx_device * pdev = pgs->device; gx_device_color *pdc = pgs->dev_color; const gs_imager_state *pis = (const gs_imager_state *)pgs; bool hl_color_available = gx_hld_is_hl_color_available(pis, pdc); gs_fixed_rect empty = {{0, 0}, {0, 0}}; bool hl_color = (hl_color_available && dev_proc(pdev, fill_rectangle_hl_color)(pdev, &empty, pis, pdc, NULL) == 0); gx_set_dev_color(pgs); if ((is_fzero2(pgs->ctm.xy, pgs->ctm.yx) || is_fzero2(pgs->ctm.xx, pgs->ctm.yy)) && gx_effective_clip_path(pgs, &pcpath) >= 0 && clip_list_is_rectangle(gx_cpath_list(pcpath)) && (hl_color || pdc->type == gx_dc_type_pure || pdc->type == gx_dc_type_ht_binary || pdc->type == gx_dc_type_ht_colored /* DeviceN todo: add wts case */) && gs_state_color_load(pgs) >= 0 && (*dev_proc(pdev, get_alpha_bits)) (pdev, go_graphics) <= 1 && (!pgs->overprint || !pgs->effective_overprint_mode) ) { uint i; gs_fixed_rect clip_rect; gx_cpath_inner_box(pcpath, &clip_rect); for (i = 0; i < count; ++i) { gs_fixed_point p, q; gs_fixed_rect draw_rect; if (gs_point_transform2fixed(&pgs->ctm, pr[i].p.x, pr[i].p.y, &p) < 0 || gs_point_transform2fixed(&pgs->ctm, pr[i].q.x, pr[i].q.y, &q) < 0 ) { /* Switch to the slow algorithm. */ goto slow; } draw_rect.p.x = min(p.x, q.x); draw_rect.p.y = min(p.y, q.y); draw_rect.q.x = max(p.x, q.x); draw_rect.q.y = max(p.y, q.y); if (hl_color) { rect_intersect(draw_rect, clip_rect); if (draw_rect.p.x < draw_rect.q.x && draw_rect.p.y < draw_rect.q.y) { code = dev_proc(pdev, fill_rectangle_hl_color)(pdev, &draw_rect, pis, pdc, pcpath); if (code < 0) return code; } } else { int x, y, w, h; draw_rect.p.x -= pgs->fill_adjust.x; draw_rect.p.y -= pgs->fill_adjust.x; draw_rect.q.x += pgs->fill_adjust.x; draw_rect.q.y += pgs->fill_adjust.x; rect_intersect(draw_rect, clip_rect); x = fixed2int_pixround(draw_rect.p.x); y = fixed2int_pixround(draw_rect.p.y); w = fixed2int_pixround(draw_rect.q.x) - x; h = fixed2int_pixround(draw_rect.q.y) - y; if (w > 0 && h > 0) if (gx_fill_rectangle(x, y, w, h, pdc, pgs) < 0) goto slow; } } return 0; slow:rlist = pr + i; rcount = count - i; } { bool do_save = !gx_path_is_null(pgs->path); if (do_save) { if ((code = gs_gsave(pgs)) < 0) return code; gs_newpath(pgs); } if ((code = gs_rectappend(pgs, rlist, rcount)) < 0 || (code = gs_fill(pgs)) < 0 ) DO_NOTHING; if (do_save) gs_grestore(pgs); else if (code < 0) gs_newpath(pgs); } return code; }
/* returns boolean */ int APP_CC rect_union(struct xrdp_rect* in1, struct xrdp_rect* in2, struct list* out) { struct xrdp_rect tmp; if (!rect_intersect(in1, in2, &tmp)) { return 0; } if (rect_equal(in1, in2)) { return 0; } if (in1->left <= in2->left && in1->top <= in2->top && in1->right >= in2->right && in1->bottom >= in2->bottom) { list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); } else if (in1->left <= in2->left && in1->right >= in2->right && in1->bottom < in2->bottom && in1->top <= in2->top) { /* partially covered(whole top) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in1->bottom, in2->right, in2->bottom); } else if (in1->top <= in2->top && in1->bottom >= in2->bottom && in1->right < in2->right && in1->left <= in2->left) { /* partially covered(left) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in1->right, in2->top, in2->right, in2->bottom); } else if (in1->left <= in2->left && in1->right >= in2->right && in1->top > in2->top && in1->bottom >= in2->bottom) { /* partially covered(bottom) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in2->right, in1->top); } else if (in1->top <= in2->top && in1->bottom >= in2->bottom && in1->left > in2->left && in1->right >= in2->right) { /* partially covered(right) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in1->left, in2->bottom); } else if (in1->left <= in2->left && in1->top <= in2->top && in1->right < in2->right && in1->bottom < in2->bottom) { /* partially covered(top left) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in1->right, in2->top, in2->right, in1->bottom); list_add_rect(out, in2->left, in1->bottom, in2->right, in2->bottom); } else if (in1->left <= in2->left && in1->bottom >= in2->bottom && in1->right < in2->right && in1->top > in2->top) { /* partially covered(bottom left) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in2->right, in1->top); list_add_rect(out, in1->right, in1->top, in2->right, in2->bottom); } else if (in1->left > in2->left && in1->right >= in2->right && in1->top <= in2->top && in1->bottom < in2->bottom) { /* partially covered(top right) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in1->left, in2->bottom); list_add_rect(out, in2->left, in1->bottom, in2->right, in2->bottom); } else if (in1->left > in2->left && in1->right >= in2->right && in1->top > in2->top && in1->bottom >= in2->bottom) { /* partially covered(bottom right) */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in2->right, in1->top); list_add_rect(out, in2->left, in1->top, in1->left, in2->bottom); } else if (in1->left > in2->left && in1->top <= in2->top && in1->right < in2->right && in1->bottom >= in2->bottom) { /* 2 rects, one on each end */ list_add_rect(out, in1->left, in1->top, in1->right, in1->bottom); list_add_rect(out, in2->left, in2->top, in1->left, in2->bottom); list_add_rect(out, in1->right, in2->top, in2->right, in2->bottom); } else if (in1->left <= in2->left && in1->top > in2->top && in1->right >= in2->right && in1->bottom < in2->bottom) { /* 2 rects, one on each end */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); list_add_rect(out, in1->left, in1->top, in2->left, in1->bottom); list_add_rect(out, in2->right, in1->top, in1->right, in1->bottom); } else if (in1->left > in2->left && in1->right < in2->right && in1->top <= in2->top && in1->bottom < in2->bottom) { /* partially covered(top) */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); list_add_rect(out, in1->left, in1->top, in1->right, in2->top); } else if (in1->top > in2->top && in1->bottom < in2->bottom && in1->left <= in2->left && in1->right < in2->right) { /* partially covered(left) */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); list_add_rect(out, in1->left, in1->top, in2->left, in1->bottom); } else if (in1->left > in2->left && in1->right < in2->right && in1->bottom >= in2->bottom && in1->top > in2->top) { /* partially covered(bottom) */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); list_add_rect(out, in1->left, in2->bottom, in1->right, in1->bottom); } else if (in1->top > in2->top && in1->bottom < in2->bottom && in1->right >= in2->right && in1->left > in2->left) { /* partially covered(right) */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); list_add_rect(out, in2->right, in1->top, in1->right, in1->bottom); } else if (in1->left > in2->left && in1->top > in2->top && in1->right < in2->right && in1->bottom < in2->bottom) { /* totally contained, 4 rects */ list_add_rect(out, in2->left, in2->top, in2->right, in2->bottom); } return 0; }