rect.c (7791B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21#include "common/rect.h" 22 23void guac_common_rect_init(guac_common_rect* rect, int x, int y, int width, int height) { 24 rect->x = x; 25 rect->y = y; 26 rect->width = width; 27 rect->height = height; 28} 29 30void guac_common_rect_extend(guac_common_rect* rect, const guac_common_rect* min) { 31 32 /* Calculate extents of existing dirty rect */ 33 int left = rect->x; 34 int top = rect->y; 35 int right = left + rect->width; 36 int bottom = top + rect->height; 37 38 /* Calculate missing extents of given new rect */ 39 int min_left = min->x; 40 int min_top = min->y; 41 int min_right = min_left + min->width; 42 int min_bottom = min_top + min->height; 43 44 /* Update minimums */ 45 if (min_left < left) left = min_left; 46 if (min_top < top) top = min_top; 47 if (min_right > right) right = min_right; 48 if (min_bottom > bottom) bottom = min_bottom; 49 50 /* Commit rect */ 51 guac_common_rect_init(rect, left, top, right - left, bottom - top); 52 53} 54 55void guac_common_rect_constrain(guac_common_rect* rect, const guac_common_rect* max) { 56 57 /* Calculate extents of existing dirty rect */ 58 int left = rect->x; 59 int top = rect->y; 60 int right = left + rect->width; 61 int bottom = top + rect->height; 62 63 /* Calculate missing extents of given new rect */ 64 int max_left = max->x; 65 int max_top = max->y; 66 int max_right = max_left + max->width; 67 int max_bottom = max_top + max->height; 68 69 /* Update maximums */ 70 if (max_left > left) left = max_left; 71 if (max_top > top) top = max_top; 72 if (max_right < right) right = max_right; 73 if (max_bottom < bottom) bottom = max_bottom; 74 75 /* Commit rect */ 76 guac_common_rect_init(rect, left, top, right - left, bottom - top); 77 78} 79 80int guac_common_rect_expand_to_grid(int cell_size, guac_common_rect* rect, 81 const guac_common_rect* max_rect) { 82 83 /* Invalid cell_size received */ 84 if (cell_size <= 0) 85 return -1; 86 87 /* Nothing to do */ 88 if (cell_size == 1) 89 return 0; 90 91 /* Calculate how much the rectangle must be adjusted to fit within the 92 * given cell size. */ 93 int dw = cell_size - rect->width % cell_size; 94 int dh = cell_size - rect->height % cell_size; 95 96 int dx = dw / 2; 97 int dy = dh / 2; 98 99 /* Set initial extents of adjusted rectangle. */ 100 int top = rect->y - dy; 101 int left = rect->x - dx; 102 int bottom = top + rect->height + dh; 103 int right = left + rect->width + dw; 104 105 /* The max rectangle */ 106 int max_left = max_rect->x; 107 int max_top = max_rect->y; 108 int max_right = max_left + max_rect->width; 109 int max_bottom = max_top + max_rect->height; 110 111 /* If the adjusted rectangle has sides beyond the max rectangle, or is larger 112 * in any direction; shift or adjust the rectangle while trying to fit in 113 * the grid */ 114 115 /* Adjust left/right */ 116 if (right > max_right) { 117 118 /* shift to left */ 119 dw = right - max_right; 120 right -= dw; 121 left -= dw; 122 123 /* clamp left if too far */ 124 if (left < max_left) { 125 left = max_left; 126 } 127 } 128 else if (left < max_left) { 129 130 /* shift to right */ 131 dw = max_left - left; 132 left += dw; 133 right += dw; 134 135 /* clamp right if too far */ 136 if (right > max_right) { 137 right = max_right; 138 } 139 } 140 141 /* Adjust top/bottom */ 142 if (bottom > max_bottom) { 143 144 /* shift up */ 145 dh = bottom - max_bottom; 146 bottom -= dh; 147 top -= dh; 148 149 /* clamp top if too far */ 150 if (top < max_top) { 151 top = max_top; 152 } 153 } 154 else if (top < max_top) { 155 156 /* shift down */ 157 dh = max_top - top; 158 top += dh; 159 bottom += dh; 160 161 /* clamp bottom if too far */ 162 if (bottom > max_bottom) { 163 bottom = max_bottom; 164 } 165 } 166 167 /* Commit rect */ 168 guac_common_rect_init(rect, left, top, right - left, bottom - top); 169 170 return 0; 171 172} 173 174int guac_common_rect_intersects(const guac_common_rect* rect, 175 const guac_common_rect* other) { 176 177 /* Empty (no intersection) */ 178 if (other->x + other->width < rect->x || rect->x + rect->width < other->x || 179 other->y + other->height < rect->y || rect->y + rect->height < other->y) { 180 return 0; 181 } 182 /* Complete */ 183 else if (other->x <= rect->x && (other->x + other->width) >= (rect->x + rect->width) && 184 other->y <= rect->y && (other->y + other->height) >= (rect->y + rect->height)) { 185 return 2; 186 } 187 /* Partial intersection */ 188 return 1; 189 190} 191 192int guac_common_rect_clip_and_split(guac_common_rect* rect, 193 const guac_common_rect* hole, guac_common_rect* split_rect) { 194 195 /* Only continue if the rectangles intersects */ 196 if (!guac_common_rect_intersects(rect, hole)) 197 return 0; 198 199 int top, left, bottom, right; 200 201 /* Clip and split top */ 202 if (rect->y < hole->y) { 203 top = rect->y; 204 left = rect->x; 205 bottom = hole->y; 206 right = rect->x + rect->width; 207 guac_common_rect_init(split_rect, left, top, right - left, bottom - top); 208 209 /* Re-initialize original rect */ 210 top = hole->y; 211 bottom = rect->y + rect->height; 212 guac_common_rect_init(rect, left, top, right - left, bottom - top); 213 214 return 1; 215 } 216 217 /* Clip and split left */ 218 else if (rect->x < hole->x) { 219 top = rect->y; 220 left = rect->x; 221 bottom = rect->y + rect->height; 222 right = hole->x; 223 guac_common_rect_init(split_rect, left, top, right - left, bottom - top); 224 225 /* Re-initialize original rect */ 226 left = hole->x; 227 right = rect->x + rect->width; 228 guac_common_rect_init(rect, left, top, right - left, bottom - top); 229 230 return 1; 231 } 232 233 /* Clip and split bottom */ 234 else if (rect->y + rect->height > hole->y + hole->height) { 235 top = hole->y + hole->height; 236 left = rect->x; 237 bottom = rect->y + rect->height; 238 right = rect->x + rect->width; 239 guac_common_rect_init(split_rect, left, top, right - left, bottom - top); 240 241 /* Re-initialize original rect */ 242 top = rect->y; 243 bottom = hole->y + hole->height; 244 guac_common_rect_init(rect, left, top, right - left, bottom - top); 245 246 return 1; 247 } 248 249 /* Clip and split right */ 250 else if (rect->x + rect->width > hole->x + hole->width) { 251 top = rect->y; 252 left = hole->x + hole->width; 253 bottom = rect->y + rect->height; 254 right = rect->x + rect->width; 255 guac_common_rect_init(split_rect, left, top, right - left, bottom - top); 256 257 /* Re-initialize original rect */ 258 left = rect->x; 259 right = hole->x + hole->width; 260 guac_common_rect_init(rect, left, top, right - left, bottom - top); 261 262 return 1; 263 } 264 265 return 0; 266}