//split all existing clip rectangles against the passed rect void Context_subtract_clip_rect(Context* context, Rect* subtracted_rect) { //Check each item already in the list to see if it overlaps with //the new rectangle int i, j; Rect* cur_rect; List* split_rects; context->clipping_on = 1; for(i = 0; i < context->clip_rects->count; ) { cur_rect = (Rect*)List_get_at(context->clip_rects, i); //Standard rect intersect test (if no intersect, skip to next) //see here for an example of why this works: //http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other#tab-top if(!(cur_rect->left <= subtracted_rect->right && cur_rect->right >= subtracted_rect->left && cur_rect->top <= subtracted_rect->bottom && cur_rect->bottom >= subtracted_rect->top)) { i++; continue; } //If this rectangle does intersect with the new rectangle, //we need to split it List_remove_at(context->clip_rects, i); //Original will be replaced w/splits split_rects = Rect_split(cur_rect, subtracted_rect); //Do the split Object_delete((Object*)cur_rect); //We can throw this away now, we're done with it //Copy the split, non-overlapping result rectangles into the list while(split_rects->count) { cur_rect = (Rect*)List_remove_at(split_rects, 0); List_add(context->clip_rects, (Object*)cur_rect); } //Free the empty split_rect list Object_delete((Object*)split_rects); //Since we removed an item from the list, we need to start counting over again //In this way, we'll only exit this loop once nothing in the list overlaps i = 0; } }
//Remove all of the clipping rects from the passed context object void Context_clear_clip_rects(Context* context) { Rect* cur_rect; context->clipping_on = 0; while(context->clip_rects->count) Object_delete(List_remove_at(context->clip_rects, 0)); }
List* Rect_split(Rect subject_rect, Rect cutting_rect) { //Allocate the list of result rectangles List* output_rects; if(!(output_rects = List_new())) return output_rects; Rect subject_copy = subject_rect; //We need a rectangle to hold new rectangles before //they get pushed into the output list Rect* temp_rect; //Begin splitting //1 -Split by left edge if that edge is between the subject's left and right edges if(rect_min_x(cutting_rect) > rect_min_x(subject_copy) && rect_min_x(cutting_rect) <= rect_max_x(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's left and stopping before //the cutting rectangle's left if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_min_x(subject_copy), rect_max_y(subject_copy), rect_min_x(cutting_rect) - 1))) { //If the object creation failed, we need to delete the list and exit failed kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int diff = rect_min_x(cutting_rect) - rect_min_x(subject_copy); rect_min_x(subject_copy) += diff; subject_copy.size.width -= diff; } //2 -Split by top edge if that edge is between the subject's top and bottom edges if(rect_min_y(cutting_rect) > rect_min_y(subject_copy) && rect_min_y(cutting_rect) <= rect_max_y(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's top and stopping before //the cutting rectangle's top if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_min_x(subject_copy), rect_min_y(cutting_rect) - 1, rect_max_x(subject_copy)))) { //If the object creation failed, we need to delete the list and exit failed //This time, also delete any previously allocated rectangles for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int diff = rect_min_y(cutting_rect) - rect_min_y(subject_copy); rect_min_y(subject_copy) += diff; subject_copy.size.height -= diff; } //3 -Split by right edge if that edge is between the subject's left and right edges if(rect_max_x(cutting_rect) >= rect_min_x(subject_copy) && rect_max_x(cutting_rect) < rect_max_x(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's right and stopping before //the cutting rectangle's right if(!(temp_rect = Rect_new(rect_min_y(subject_copy), rect_max_x(cutting_rect) + 1, rect_max_y(subject_copy), rect_max_x(subject_copy)))) { //Free on fail for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int shrink_amount = rect_max_x(subject_copy) - rect_max_x(cutting_rect); subject_copy.size.width -= shrink_amount; } //4 -Split by bottom edge if that edge is between the subject's top and bottom edges if(rect_max_y(cutting_rect) >= rect_min_y(subject_copy) && rect_max_y(cutting_rect) < rect_max_y(subject_copy)) { //Try to make a new rectangle spanning from the subject rectangle's bottom and stopping before //the cutting rectangle's bottom if(!(temp_rect = Rect_new(rect_max_y(cutting_rect) + 1, rect_min_x(subject_copy), rect_max_y(subject_copy), rect_max_x(subject_copy)))) { //Free on fail for(; output_rects->count; temp_rect = List_remove_at(output_rects, 0)) kfree(temp_rect); kfree(output_rects); return (List*)0; } //Add the new rectangle to the output list List_add(output_rects, temp_rect); //Shrink the subject rectangle to exclude the split portion int shrink_amount = rect_max_y(subject_copy) - rect_max_y(cutting_rect); subject_copy.size.height -= shrink_amount; } //Finally, after all that, we can return the output rectangles return output_rects; }