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); }
static bool rect_fullscreen(struct fb_info *info, struct omap3epfb_update_area *p) { struct omap3epfb_update_area full = {0}; full.x0 = 0; full.y0 = 0; full.x1 = info->var.xres-1; full.y1 = info->var.yres-1; full.wvfid = OMAP3EPFB_WVFID_GC; full.threshold = 0; return rect_equal(&full, p); }
// Find the area(s) that fit into the update. // If any, then draw the update and then draw the areas that fit into it on top. // This functio is trying to recover from the case where Android merge multiple updates into // a single update. static int waveform_decompose(struct fb_info *info, struct omap3epfb_update_area *p) { struct omap3epfb_par *par = info->par; int i = 0; int ret = 0; // Nothing to do DEBUG_LOG(DEBUG_LEVEL5,"DECOMPOSE++\n"); mutex_lock(&par->area_mutex); { // Intercept updates to force waveform. if (par->effect_active != 0) { for (i = 0; i < EFFECT_ARRAY_SIZE; i++) { // Setup a new update struct omap3epfb_update_area new_sub_area = par->effect_array[i].effect_area; // Setup a new effect struct omap3epfb_area new_effect_area = {0}; new_effect_area.effect_area = *p; new_effect_area.effect_area.wvfid = par->effect_array[i].effect_area.wvfid; new_effect_area.effect_flags = par->effect_array[i].effect_flags; if ((par->effect_active & (1 << i)) && process_area(i, info, &new_effect_area, &new_sub_area)) { if ((ret == 0) && !rect_equal(&new_sub_area, p)) { // Do the update as a normal update first batch_update(info, p); } // Indicate that we have a match. ret = 1; // Override AUTO waveform behaviour if (batch_update(info, &new_sub_area)) { // If is was full screen, do not continue break; } } } } } mutex_unlock(&par->area_mutex); DEBUG_LOG(DEBUG_LEVEL5,"DECOMPOSE--\n"); return ret; }
/* 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; }
graphene_rect_t ops_set_viewport (RenderOpBuilder *builder, const graphene_rect_t *viewport) { RenderOp op; graphene_rect_t prev_viewport; if (builder->current_program_state != NULL && rect_equal (&builder->current_program_state->viewport, viewport)) return builder->current_program_state->viewport; op.op = OP_CHANGE_VIEWPORT; op.viewport = *viewport; g_array_append_val (builder->render_ops, op); if (builder->current_program != NULL) builder->current_program_state->viewport = *viewport; prev_viewport = builder->current_viewport; builder->current_viewport = *viewport; return prev_viewport; }
static pdf_obj* pdf_get_page_obj (pdf_file *pf, int page_no, pdf_obj **ret_bbox, pdf_obj **ret_resources) { pdf_obj *page_tree; pdf_obj *bbox = NULL, *resources = NULL, *rotate = NULL; int page_idx; /* * Get Page Tree. */ page_tree = NULL; { pdf_obj *trailer, *catalog; pdf_obj *markinfo, *tmp; trailer = pdf_file_get_trailer(pf); if (pdf_lookup_dict(trailer, "Encrypt")) { WARN("This PDF document is encrypted."); pdf_release_obj(trailer); return NULL; } catalog = pdf_deref_obj(pdf_lookup_dict(trailer, "Root")); if (!PDF_OBJ_DICTTYPE(catalog)) { WARN("Can't read document catalog."); pdf_release_obj(trailer); if (catalog) pdf_release_obj(catalog); return NULL; } pdf_release_obj(trailer); markinfo = pdf_deref_obj(pdf_lookup_dict(catalog, "MarkInfo")); if (markinfo) { tmp = pdf_lookup_dict(markinfo, "Marked"); if (PDF_OBJ_BOOLEANTYPE(tmp) && pdf_boolean_value(tmp)) WARN("PDF file is tagged... Ignoring tags."); pdf_release_obj(markinfo); } page_tree = pdf_deref_obj(pdf_lookup_dict(catalog, "Pages")); pdf_release_obj(catalog); } if (!page_tree) { WARN("Page tree not found."); return NULL; } /* * Negative page numbers are counted from the back. */ { int count = pdf_number_value(pdf_lookup_dict(page_tree, "Count")); page_idx = page_no + (page_no >= 0 ? -1 : count); if (page_idx < 0 || page_idx >= count) { WARN("Page %ld does not exist.", page_no); pdf_release_obj(page_tree); return NULL; } page_no = page_idx+1; } /* * Seek correct page. Get Media/Crop Box. * Media box and resources can be inherited. */ { pdf_obj *kids_ref, *kids; pdf_obj *crop_box = NULL; pdf_obj *tmp; tmp = pdf_lookup_dict(page_tree, "Resources"); resources = tmp ? pdf_deref_obj(tmp) : pdf_new_dict(); while (1) { int kids_length, i; if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "MediaBox")))) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "BleedBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "TrimBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "ArtBox")))) { if (!rect_equal(tmp, bbox)) { if (bbox) pdf_release_obj(bbox); bbox = tmp; } else { pdf_release_obj(tmp); } } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "CropBox")))) { if (crop_box) pdf_release_obj(crop_box); crop_box = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Rotate")))) { if (rotate) pdf_release_obj(rotate); rotate = tmp; } if ((tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Resources")))) { #if 0 pdf_merge_dict(tmp, resources); #endif if (resources) pdf_release_obj(resources); resources = tmp; } kids_ref = pdf_lookup_dict(page_tree, "Kids"); if (!kids_ref) break; kids = pdf_deref_obj(kids_ref); kids_length = pdf_array_length(kids); for (i = 0; i < kids_length; i++) { int count; pdf_release_obj(page_tree); page_tree = pdf_deref_obj(pdf_get_array(kids, i)); tmp = pdf_deref_obj(pdf_lookup_dict(page_tree, "Count")); if (tmp) { /* Pages object */ count = pdf_number_value(tmp); pdf_release_obj(tmp); } else { /* Page object */ count = 1; } if (page_idx < count) break; page_idx -= count; } pdf_release_obj(kids); if (i == kids_length) { WARN("Page %ld not found! Broken PDF file?", page_no); if (bbox) pdf_release_obj(bbox); if (crop_box) pdf_release_obj(crop_box); if (rotate) pdf_release_obj(rotate); pdf_release_obj(resources); pdf_release_obj(page_tree); return NULL; } } if (crop_box) { pdf_release_obj(bbox); bbox = crop_box; } } if (!bbox) { WARN("No BoundingBox information available."); pdf_release_obj(page_tree); pdf_release_obj(resources); if (rotate) pdf_release_obj(rotate); return NULL; } if (rotate) { if (pdf_number_value(rotate) != 0.0) WARN("<< /Rotate %d >> found. (Not supported yet)", (int)pdf_number_value(rotate)); pdf_release_obj(rotate); rotate = NULL; } if (ret_bbox != NULL) *ret_bbox = bbox; if (ret_resources != NULL) *ret_resources = resources; return page_tree; }
static int scrollrect(VTermRect rect, int downward, int rightward, void *user) { VTermScreen *screen = user; if(screen->damage_merge != VTERM_DAMAGE_SCROLL) { vterm_scroll_rect(rect, downward, rightward, moverect_internal, erase_internal, screen); vterm_screen_flush_damage(screen); vterm_scroll_rect(rect, downward, rightward, moverect_user, erase_user, screen); return 1; } if(screen->damaged.start_row != -1 && !rect_intersects(&rect, &screen->damaged)) { vterm_screen_flush_damage(screen); } if(screen->pending_scrollrect.start_row == -1) { screen->pending_scrollrect = rect; screen->pending_scroll_downward = downward; screen->pending_scroll_rightward = rightward; } else if(rect_equal(&screen->pending_scrollrect, &rect) && ((screen->pending_scroll_downward == 0 && downward == 0) || (screen->pending_scroll_rightward == 0 && rightward == 0))) { screen->pending_scroll_downward += downward; screen->pending_scroll_rightward += rightward; } else { vterm_screen_flush_damage(screen); screen->pending_scrollrect = rect; screen->pending_scroll_downward = downward; screen->pending_scroll_rightward = rightward; } vterm_scroll_rect(rect, downward, rightward, moverect_internal, erase_internal, screen); if(screen->damaged.start_row == -1) return 1; if(rect_contains(&rect, &screen->damaged)) { /* Scroll region entirely contains the damage; just move it */ vterm_rect_move(&screen->damaged, -downward, -rightward); rect_clip(&screen->damaged, &rect); } /* There are a number of possible cases here, but lets restrict this to only * the common case where we might actually gain some performance by * optimising it. Namely, a vertical scroll that neatly cuts the damage * region in half. */ else if(rect.start_col <= screen->damaged.start_col && rect.end_col >= screen->damaged.end_col && rightward == 0) { if(screen->damaged.start_row >= rect.start_row && screen->damaged.start_row < rect.end_row) { screen->damaged.start_row -= downward; if(screen->damaged.start_row < rect.start_row) screen->damaged.start_row = rect.start_row; if(screen->damaged.start_row > rect.end_row) screen->damaged.start_row = rect.end_row; } if(screen->damaged.end_row >= rect.start_row && screen->damaged.end_row < rect.end_row) { screen->damaged.end_row -= downward; if(screen->damaged.end_row < rect.start_row) screen->damaged.end_row = rect.start_row; if(screen->damaged.end_row > rect.end_row) screen->damaged.end_row = rect.end_row; } } else { DEBUG_LOG2("TODO: Just flush and redo damaged=" STRFrect " rect=" STRFrect "\n", ARGSrect(screen->damaged), ARGSrect(rect)); } return 1; }
void ops_set_program (RenderOpBuilder *builder, const Program *program) { /* The tricky part about this is that we want to initialize all uniforms of a program * to the current value from the builder, but only once. */ static const GskRoundedRect empty_clip; static const graphene_matrix_t empty_matrix; static const graphene_rect_t empty_rect; RenderOp op; ProgramState *program_state; if (builder->current_program == program) return; op.op = OP_CHANGE_PROGRAM; op.program = program; g_array_append_val (builder->render_ops, op); builder->current_program = program; program_state = &builder->program_state[program->index]; /* If the projection is not yet set for this program, we use the current one. */ if (memcmp (&empty_matrix, &program_state->projection, sizeof (graphene_matrix_t)) == 0 || memcmp (&builder->current_projection, &program_state->projection, sizeof (graphene_matrix_t)) != 0) { op.op = OP_CHANGE_PROJECTION; op.projection = builder->current_projection; g_array_append_val (builder->render_ops, op); program_state->projection = builder->current_projection; } if (memcmp (&empty_matrix, &program_state->modelview, sizeof (graphene_matrix_t)) == 0 || memcmp (builder->current_modelview, &program_state->modelview, sizeof (graphene_matrix_t)) != 0) { op.op = OP_CHANGE_MODELVIEW; op.modelview = *builder->current_modelview; g_array_append_val (builder->render_ops, op); program_state->modelview = *builder->current_modelview; } if (rect_equal (&empty_rect, &program_state->viewport) || !rect_equal (&builder->current_viewport, &program_state->viewport)) { op.op = OP_CHANGE_VIEWPORT; op.viewport = builder->current_viewport; g_array_append_val (builder->render_ops, op); program_state->viewport = builder->current_viewport; } if (memcmp (&empty_clip, &program_state->clip, sizeof (GskRoundedRect)) == 0 || memcmp (&builder->current_clip, &program_state->clip, sizeof (GskRoundedRect)) != 0) { op.op = OP_CHANGE_CLIP; op.clip = *builder->current_clip; g_array_append_val (builder->render_ops, op); program_state->clip = *builder->current_clip; } if (program_state->opacity != builder->current_opacity) { op.op = OP_CHANGE_OPACITY; op.opacity = builder->current_opacity; g_array_append_val (builder->render_ops, op); program_state->opacity = builder->current_opacity; } builder->current_program_state = &builder->program_state[program->index]; }
static int process_area(int index, struct fb_info *info, struct omap3epfb_area *area, struct omap3epfb_update_area *p) { struct omap3epfb_par *par = info->par; int change = 0; if (!(area->effect_flags & (EFFECT_ONESHOT | EFFECT_ACTIVE | EFFECT_CLEAR))) return change; if (!rect_inside(&area->effect_area, p)) { DEBUG_REGION(DEBUG_LEVEL5, p,"no match 0x%02x region %d = ", area->effect_flags, index); return change; } if (area->effect_flags & EFFECT_ONESHOT) { p->wvfid = area->effect_area.wvfid; p->threshold = area->effect_area.threshold; DEBUG_REGION(DEBUG_LEVEL2, p,"process ONESHOT region %d = ", index); if (area->effect_flags & EFFECT_REGION) { p->x0 = area->effect_area.x0; p->y0 = area->effect_area.y0; p->x1 = area->effect_area.x1; p->y1 = area->effect_area.y1; } par->effect_array[index].effect_flags = 0; change = 1; } else if (area->effect_flags & EFFECT_ACTIVE) { p->wvfid = area->effect_area.wvfid; p->threshold = area->effect_area.threshold; DEBUG_REGION(DEBUG_LEVEL2, p,"process ACTIVE region %d = ", index); change = 1; if (p->wvfid == OMAP3EPFB_WVFID_AUTO) { // Calculate the percentage of the screen that needs an update. int percent = ((rect_width(p) * rect_height(p) * 100)) / ((info->var.xres-1) * (info->var.yres-1)); // Check if we need to do a GC of the whole screen if ((par->refresh_percent > 0) && (percent >= par->refresh_percent)) { DEBUG_REGION(DEBUG_LEVEL1, p,"process ACTIVE %d%% region %d = ", percent, index); p->x0 = p->y0 = 0; p->x1 = info->var.xres-1; p->y1 = info->var.yres-1; p->wvfid = OMAP3EPFB_WVFID_GC; p->threshold = 0; } } else { if (area->effect_flags & EFFECT_REGION) { p->x0 = area->effect_area.x0; p->y0 = area->effect_area.y0; p->x1 = area->effect_area.x1; p->y1 = area->effect_area.y1; } } } else if ((area->effect_flags & EFFECT_CLEAR) && rect_equal(&area->effect_area, p)) { // Turn the next update of the effect area into a full page flushing update, // then clear the effect area. // This is used as a hint that a dialog is closing, then we forcing a full screen GC update. p->wvfid = area->effect_area.wvfid; p->threshold = area->effect_area.threshold; DEBUG_REGION(DEBUG_LEVEL2, p,"process RESET region %d = ", index); p->x0 = p->y0 = 0; p->x1 = info->var.xres-1; p->y1 = info->var.yres-1; p->wvfid = OMAP3EPFB_WVFID_GC; par->effect_array[index].effect_flags = 0; change = 1; } // Update the fast scan flags. update_effect(par, index); return change; }
/************************************************************************* ** ** ** Function Definitions ** ** ** **************************************************************************/ int abobjP_move_object_outline( ABObj obj, XMotionEvent *mevent ) { static XRectangle parent_rect; static XRectangle last_rect; static int x_offset, y_offset; static Dimension border_w; static Display *dpy; XRectangle widget_rect; int trans_x, trans_y; /* First time: set up initial move variables */ if (first_move) { if (obj_is_item(obj)) obj = obj_get_parent(obj); obj = obj_get_root(obj); /* Multiple objects might be selected...*/ if (obj_is_control(obj) || obj_is_group(obj) || obj_is_pane(obj)) { abobj_get_selected(obj_get_root(obj_get_parent(obj)), False, False, &sel); } else { sel.count = 1; sel.list = (ABObj*)util_malloc(sizeof(ABObj)); sel.list[0] = obj; } xy_obj = objxm_comp_get_subobj(obj, AB_CFG_POSITION_OBJ); xy_widget = (Widget)xy_obj->ui_handle; if (xy_widget == NULL) { if (util_get_verbosity() > 2) fprintf(stderr,"abobjP_move_object_outline: %s :no POSITION widget\n", util_strsafe(obj_get_name(obj))); return ERROR; } dpy = XtDisplay(xy_widget); parent = XtParent(xy_widget); x_get_widget_rect(xy_widget, &widget_rect); x_get_widget_rect(parent, &parent_rect); if (sel.count > 1) { abobj_get_rect_for_objects(sel.list, sel.count, &orig_rect); } else { orig_rect = widget_rect; XtVaGetValues(xy_widget, XtNborderWidth, &border_w, NULL); orig_rect.width += (2*border_w); orig_rect.height += (2*border_w); orig_rect.width--; orig_rect.height--; } move_rect = orig_rect; drag_init_rect.x = mevent->x - AB_drag_threshold; drag_init_rect.y = mevent->y - AB_drag_threshold; drag_init_rect.width = drag_init_rect.height = 2 * AB_drag_threshold; x_offset = widget_rect.x - orig_rect.x + mevent->x; y_offset = widget_rect.y - orig_rect.y + mevent->y; first_move = False; rect_zero_out(&last_rect); } /* Don't begin rendering move outline until pointer is out of * the drag_init bounding box */ else if (!rect_includespoint(&drag_init_rect, mevent->x, mevent->y)) { Window win; /* event coords are relative to widget-must translate to parent */ XTranslateCoordinates(dpy, XtWindow(xy_widget), XtWindow(parent), mevent->x, mevent->y, &trans_x, &trans_y, &win); move_rect.x = trans_x - x_offset; move_rect.y = trans_y - y_offset; /* Ensure move outline is within the parent's rect */ if (move_rect.x < 0) move_rect.x = 0; else if ((move_rect.x + (short)move_rect.width + 1) >= (short)parent_rect.width) move_rect.x = parent_rect.width - (move_rect.width + 1); if (move_rect.y < 0) move_rect.y = 0; else if ((move_rect.y + (short)move_rect.height + 1) >= (short)parent_rect.height) move_rect.y = parent_rect.height - (move_rect.height + 1); /* If cursor has moved since last event, erase previous outline * and render new one (using XOR function) */ if (!rect_equal(&move_rect, &last_rect)) { if (!rect_isnull(&last_rect)) x_box_r(parent, &last_rect); x_box_r(parent, &move_rect); last_rect = move_rect; } } return OK; }
void progressive_display_split_and_merge(struct list* self) { int i, j; struct update_rect* item1; struct update_rect* item2; struct xrdp_rect first; struct xrdp_rect second; bool merged = true; bool remove; while (merged) { merged = false; for (i = 0; i < self->count; i++) { item1 = (struct update_rect*) list_get_item(self, i); first = item1->rect; for (j = self->count - 1; j > i; j--) { item2 = (struct update_rect*) list_get_item(self, j); second = item2->rect; if (item1->quality_already_send == item2->quality_already_send) { if (!rect_equal(&first, &second)) { int adj = rect_adjacency(&first, &second); switch (adj) { case 0: break; case 1: // first is at right of second merged = true; if (rect_height(&first) == rect_height(&second)) { item1->rect.left = item2->rect.left; list_remove_item(self, j); } else { progressive_display_rect_split_h(self, item1, item2, &remove); if (remove) { list_remove_item(self, j); list_remove_item(self, i); } else merged = false; } break; case 2: // first is at left of second merged = true; if (rect_height(&first) == rect_height(&second)) { item1->rect.right = item2->rect.right; list_remove_item(self, j); } else { progressive_display_rect_split_h(self, item2, item1, &remove); if (remove) { list_remove_item(self, j); list_remove_item(self, i); } else merged = false; } break; case 3: // first is under second merged = true; if (rect_width(&first) == rect_width(&second)) { item1->rect.top = item2->rect.top; list_remove_item(self, j); } else { progressive_display_rect_split_v(self, item1, item2, &remove); if (remove) { list_remove_item(self, j); list_remove_item(self, i); } else merged = false; } break; case 4: // first is above second merged = true; if (rect_width(&first) == rect_width(&second)) { item1->rect.bottom = item2->rect.bottom; list_remove_item(self, j); } else { progressive_display_rect_split_v(self, item2, item1, &remove); if (remove) { list_remove_item(self, j); list_remove_item(self, i); } else merged = false; } break; } } else { list_remove_item(self, j); merged = true; } } else { merged = false; } if (merged) break; } if (merged) break; } } }
/* 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; }