gdkregion-generic.c 13.9 KB
Newer Older
1
#include "config.h"
Elliot Lee's avatar
Elliot Lee committed
2 3
#include <stdlib.h>
#include <string.h>
4
#include <gdkregion.h>
5
#include "gdkalias.h"
6

7 8 9 10 11 12
/**
 * gdk_region_new:
 *
 * Creates a new empty #GdkRegion.
 *
 * Returns: a new empty #GdkRegion
Benjamin Otte's avatar
Benjamin Otte committed
13 14
 *
 * Deprecated: 2.22: Use cairo_region_create() instead.
15
 */
16
GdkRegion *
Matthias Clasen's avatar
Matthias Clasen committed
17
gdk_region_new (void)
18
{
19
  return cairo_region_create ();
20 21
}

Havoc Pennington's avatar
Havoc Pennington committed
22 23 24 25 26 27 28
/**
 * gdk_region_rectangle:
 * @rectangle: a #GdkRectangle
 * 
 * Creates a new region containing the area @rectangle.
 * 
 * Return value: a new region
Benjamin Otte's avatar
Benjamin Otte committed
29 30
 *
 * Deprecated: 2.22: Use cairo_region_create_rectangle()
Havoc Pennington's avatar
Havoc Pennington committed
31
 **/
32
GdkRegion *
33
gdk_region_rectangle (const GdkRectangle *rectangle)
34
{
35 36
  g_return_val_if_fail (rectangle != NULL, NULL);

37 38 39
  if (rectangle->width <= 0 || rectangle->height <= 0)
    return gdk_region_new();

40
  return cairo_region_create_rectangle (rectangle);
41 42
}

Havoc Pennington's avatar
Havoc Pennington committed
43 44 45 46 47 48 49
/**
 * gdk_region_copy:
 * @region: a #GdkRegion
 * 
 * Copies @region, creating an identical new region.
 * 
 * Return value: a new region identical to @region
Benjamin Otte's avatar
Benjamin Otte committed
50 51
 *
 * Deprecated: 2.22: Use cairo_region_copy()
Havoc Pennington's avatar
Havoc Pennington committed
52
 **/
53
GdkRegion *
54
gdk_region_copy (const GdkRegion *region)
55
{
56
  return cairo_region_copy (region);
57 58
}

59 60 61 62 63
/**
 * gdk_region_get_clipbox:
 * @region: a #GdkRegion
 * @rectangle: return location for the clipbox
 *
Matthias Clasen's avatar
Matthias Clasen committed
64 65
 * Obtains the smallest rectangle which includes the entire #GdkRegion.
 *
Benjamin Otte's avatar
Benjamin Otte committed
66
 * Deprecated: 2.22: Use cairo_region_get_extents()
67
 */
68
void
69 70
gdk_region_get_clipbox (const GdkRegion *region,
			GdkRectangle    *rectangle)
71
{
72 73
  g_return_if_fail (region != NULL);
  g_return_if_fail (rectangle != NULL);
74
  
75
  cairo_region_get_extents (region, rectangle);
76 77
}

78 79 80 81

/**
 * gdk_region_get_rectangles:
 * @region: a #GdkRegion
82
 * @rectangles: (array length=n_rectangles) (transfer container): return location for an array of rectangles
83 84 85 86
 * @n_rectangles: length of returned array
 *
 * Obtains the area covered by the region as a list of rectangles.
 * The array returned in @rectangles must be freed with g_free().
Benjamin Otte's avatar
Benjamin Otte committed
87 88
 *
 * Deprecated: 2.22: Use cairo_region_num_rectangles() and cairo_region_get_rectangle() instead.
89 90
 **/
void
91 92 93
gdk_region_get_rectangles (const GdkRegion  *region,
                           GdkRectangle    **rectangles,
                           gint             *n_rectangles)
94
{
95 96
  gint i, n;
  GdkRectangle *rects;
97 98 99 100 101
  
  g_return_if_fail (region != NULL);
  g_return_if_fail (rectangles != NULL);
  g_return_if_fail (n_rectangles != NULL);
  
102 103
  n = cairo_region_num_rectangles (region);
  rects = g_new (GdkRectangle, n);
104

105
  for (i = 0; i < n; i++)
106
    {
107
      cairo_region_get_rectangle (region, i, &rects[i]);
108
    }
109 110 111

  *n_rectangles = n;
  *rectangles = rects;
112 113
}

114 115 116 117 118 119 120 121
/**
 * gdk_region_union_with_rect:
 * @region: a #GdkRegion.
 * @rect: a #GdkRectangle.
 * 
 * Sets the area of @region to the union of the areas of @region and
 * @rect. The resulting area is the set of pixels contained in
 * either @region or @rect.
Benjamin Otte's avatar
Benjamin Otte committed
122 123
 *
 * Deprecated: 2.22: Use cairo_region_union_rectangle() instead.
124
 **/
125
void
126 127
gdk_region_union_with_rect (GdkRegion          *region,
			    const GdkRectangle *rect)
128
{
129 130 131
  g_return_if_fail (region != NULL);
  g_return_if_fail (rect != NULL);

132
  if (rect->width <= 0 || rect->height <= 0)
133 134
    return;
    
135
  cairo_region_union_rectangle (region, rect);
136 137
}

138 139 140 141 142
/**
 * gdk_region_destroy:
 * @region: a #GdkRegion
 *
 * Destroys a #GdkRegion.
Benjamin Otte's avatar
Benjamin Otte committed
143 144
 *
 * Deprecated: 2.22: Use cairo_region_destroy() instead.
145
 */
146
void
147
gdk_region_destroy (GdkRegion *region)
148
{
149
  g_return_if_fail (region != NULL);
150

151
  cairo_region_destroy (region);
152
}
153 154


155 156 157 158 159 160 161
/**
 * gdk_region_offset:
 * @region: a #GdkRegion
 * @dx: the distance to move the region horizontally
 * @dy: the distance to move the region vertically
 *
 * Moves a region the specified distance.
Benjamin Otte's avatar
Benjamin Otte committed
162 163
 *
 * Deprecated: 2.22: Use cairo_region_translate() instead.
164
 */
165 166 167 168 169
void
gdk_region_offset (GdkRegion *region,
		   gint       x,
		   gint       y)
{
170
  cairo_region_translate (region, x, y);
171 172
}

173 174 175 176 177 178 179 180
/**
 * gdk_region_shrink:
 * @region: a #GdkRegion
 * @dx: the number of pixels to shrink the region horizontally
 * @dy: the number of pixels to shrink the region vertically
 *
 * Resizes a region by the specified amount.
 * Positive values shrink the region. Negative values expand it.
Benjamin Otte's avatar
Benjamin Otte committed
181 182
 *
 * Deprecated: 2.22: There is no replacement for this function.
183
 */
184
void
185
gdk_region_shrink (GdkRegion *region,
186 187 188
		   int        dx,
		   int        dy)
{
189 190
  GdkRectangle *rects;
  int i, n_rects;
191

192 193 194
  gdk_region_get_rectangles (region, &rects, &n_rects);
  /* clear region */
  gdk_region_subtract (region, region);
195

196
  for (i = 0; i < n_rects; i++)
197
    {
198 199 200 201 202 203 204 205 206
      if (rects[i].width <= 2 * dx ||
          rects[i].height <= 2 * dy)
        continue;

      rects[i].x += dx;
      rects[i].y += dy;
      rects[i].width -= 2 * dx;
      rects[i].height -= 2 * dy;
      cairo_region_union_rectangle (region, &rects[i]);
207 208 209
    }
}

Havoc Pennington's avatar
Havoc Pennington committed
210 211 212 213 214
/**
 * gdk_region_intersect:
 * @source1: a #GdkRegion
 * @source2: another #GdkRegion
 *
215 216 217
 * Sets the area of @source1 to the intersection of the areas of @source1
 * and @source2. The resulting area is the set of pixels contained in
 * both @source1 and @source2.
Benjamin Otte's avatar
Benjamin Otte committed
218 219
 *
 * Deprecated: 2.22: Use cairo_region_intersect() instead.
Havoc Pennington's avatar
Havoc Pennington committed
220
 **/
221
void
222 223
gdk_region_intersect (GdkRegion       *source1,
		      const GdkRegion *source2)
224
{
225 226
  g_return_if_fail (source1 != NULL);
  g_return_if_fail (source2 != NULL);
227
  
228
  cairo_region_intersect (source1, (cairo_region_t *) source2);
229 230
}

231 232 233 234 235 236 237 238
/**
 * gdk_region_union:
 * @source1:  a #GdkRegion
 * @source2: a #GdkRegion 
 * 
 * Sets the area of @source1 to the union of the areas of @source1 and
 * @source2. The resulting area is the set of pixels contained in
 * either @source1 or @source2.
Benjamin Otte's avatar
Benjamin Otte committed
239 240
 *
 * Deprecated: 2.22: Use cairo_region_union() instead.
241
 **/
242
void
243 244
gdk_region_union (GdkRegion       *source1,
		  const GdkRegion *source2)
245
{
246 247
  g_return_if_fail (source1 != NULL);
  g_return_if_fail (source2 != NULL);
248
  
249
  cairo_region_union (source1, (cairo_region_t *) source2);
250 251
}

Havoc Pennington's avatar
Havoc Pennington committed
252 253 254 255 256
/**
 * gdk_region_subtract:
 * @source1: a #GdkRegion
 * @source2: another #GdkRegion
 *
257 258
 * Subtracts the area of @source2 from the area @source1. The resulting
 * area is the set of pixels contained in @source1 but not in @source2.
Benjamin Otte's avatar
Benjamin Otte committed
259 260
 *
 * Deprecated: 2.22: Use cairo_region_subtract() instead.
Havoc Pennington's avatar
Havoc Pennington committed
261
 **/
262
void
263 264
gdk_region_subtract (GdkRegion       *source1,
		     const GdkRegion *source2)
265
{
266 267
  g_return_if_fail (source1 != NULL);
  g_return_if_fail (source2 != NULL);
268
  
269
  cairo_region_subtract (source1, source2);
270 271
}

Havoc Pennington's avatar
Havoc Pennington committed
272 273 274 275 276
/**
 * gdk_region_xor:
 * @source1: a #GdkRegion
 * @source2: another #GdkRegion
 *
277 278 279
 * Sets the area of @source1 to the exclusive-OR of the areas of @source1
 * and @source2. The resulting area is the set of pixels contained in one
 * or the other of the two sources but not in both.
Benjamin Otte's avatar
Benjamin Otte committed
280 281 282 283
 *
 * Deprecated: 2.22: There is no replacement, but the function can be
 *                   reimplemented using cairo_region_intersect() and
 *                   cairo_region_subract() easily.
Havoc Pennington's avatar
Havoc Pennington committed
284
 **/
285
void
286 287
gdk_region_xor (GdkRegion       *source1,
		const GdkRegion *source2)
288 289 290
{
  GdkRegion *trb;

291 292
  g_return_if_fail (source1 != NULL);
  g_return_if_fail (source2 != NULL);
293

294
  trb = gdk_region_copy (source2);
295

296 297
  gdk_region_subtract (trb, source1);
  gdk_region_subtract (source1, source2);
298

299
  gdk_region_union (source1, trb);
300 301 302 303
  
  gdk_region_destroy (trb);
}

304 305 306 307
/**
 * gdk_region_empty: 
 * @region: a #GdkRegion
 *
Matthias Clasen's avatar
Matthias Clasen committed
308
 * Finds out if the #GdkRegion is empty.
309 310
 *
 * Returns: %TRUE if @region is empty.
Benjamin Otte's avatar
Benjamin Otte committed
311 312
 *
 * Deprecated: 2.22: Use cairo_region_is_empty() instead.
313 314
 */
gboolean
315
gdk_region_empty (const GdkRegion *region)
316
{
317
  g_return_val_if_fail (region != NULL, FALSE);
318
  
319
  return cairo_region_is_empty (region);
320 321
}

322 323 324 325 326
/**
 * gdk_region_equal:
 * @region1: a #GdkRegion
 * @region2: a #GdkRegion
 *
Matthias Clasen's avatar
Matthias Clasen committed
327
 * Finds out if the two regions are the same.
328 329
 *
 * Returns: %TRUE if @region1 and @region2 are equal.
Benjamin Otte's avatar
Benjamin Otte committed
330 331
 *
 * Deprecated: 2.22: Use cairo_region_equal() instead.
332 333
 */
gboolean
334 335
gdk_region_equal (const GdkRegion *region1,
		  const GdkRegion *region2)
336
{
337 338
  g_return_val_if_fail (region1 != NULL, FALSE);
  g_return_val_if_fail (region2 != NULL, FALSE);
339

340
  return cairo_region_equal (region1, region2);
341 342
}

343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
/**
 * gdk_region_rect_equal:
 * @region: a #GdkRegion
 * @rectangle: a #GdkRectangle
 *
 * Finds out if a regions is the same as a rectangle.
 *
 * Returns: %TRUE if @region and @rectangle are equal.
 *
 * Since: 2.18
 */
gboolean
gdk_region_rect_equal (const GdkRegion    *region,
		       const GdkRectangle *rectangle)
{
358 359
  cairo_rectangle_int_t extents;

360 361 362
  g_return_val_if_fail (region != NULL, FALSE);
  g_return_val_if_fail (rectangle != NULL, FALSE);

363 364 365 366 367 368
  if (cairo_region_num_rectangles (region) != 1) return FALSE;
  cairo_region_get_extents (region, &extents);
  if (extents.x != rectangle->x) return FALSE;
  else if (extents.y != rectangle->y) return FALSE;
  else if (extents.width != rectangle->width) return FALSE;
  else if (extents.height != rectangle->height) return FALSE;
369 370 371
  return TRUE;
}

372 373 374 375 376 377
/**
 * gdk_region_point_in:
 * @region: a #GdkRegion
 * @x: the x coordinate of a point
 * @y: the y coordinate of a point
 *
Matthias Clasen's avatar
Matthias Clasen committed
378
 * Finds out if a point is in a region.
379 380
 *
 * Returns: %TRUE if the point is in @region.
Benjamin Otte's avatar
Benjamin Otte committed
381 382
 *
 * Deprecated: 2.22: Use cairo_region_contains_point() instead.
383
 */
384
gboolean
385 386 387
gdk_region_point_in (const GdkRegion *region,
		     int              x,
		     int              y)
388
{
389 390
  g_return_val_if_fail (region != NULL, FALSE);

391
  return cairo_region_contains_point (region, x, y);
392 393
}

394 395 396 397 398 399 400 401 402 403
/**
 * gdk_region_rect_in: 
 * @region: a #GdkRegion.
 * @rectangle: a #GdkRectangle.
 *
 * Tests whether a rectangle is within a region.
 *
 * Returns: %GDK_OVERLAP_RECTANGLE_IN, %GDK_OVERLAP_RECTANGLE_OUT, or
 *   %GDK_OVERLAP_RECTANGLE_PART, depending on whether the rectangle is inside,
 *   outside, or partly inside the #GdkRegion, respectively.
Benjamin Otte's avatar
Benjamin Otte committed
404 405
 *
 * Deprecated: 2.22: Use cairo_region_contains_rectangle() instead.
406
 */
407
GdkOverlapType
408 409
gdk_region_rect_in (const GdkRegion    *region,
		    const GdkRectangle *rectangle)
410
{
411 412
  g_return_val_if_fail (region != NULL, GDK_OVERLAP_RECTANGLE_OUT);
  g_return_val_if_fail (rectangle != NULL, GDK_OVERLAP_RECTANGLE_OUT);
413

414
  return cairo_region_contains_rectangle (region, rectangle);
415
}
416 417 418


static void
419 420 421 422 423
gdk_region_unsorted_spans_intersect_foreach (GdkRegion     *region,
					     const GdkSpan *spans,
					     int            n_spans,
					     GdkSpanFunc    function,
					     gpointer       data)
424
{
425
  gint i, j, left, right, y, n_rects;
426
  gint clipped_left, clipped_right;
427
  cairo_rectangle_int_t pbox, extents;
428

429 430
  n_rects = cairo_region_num_rectangles (region);
  if (!n_rects)
431 432
    return;

433
  cairo_region_get_extents (region, &extents);
434 435 436 437 438 439
  for (i=0;i<n_spans;i++)
    {
      y = spans[i].y;
      left = spans[i].x;
      right = left + spans[i].width; /* right is not in the span! */
    
440 441 442 443
      if (! ((extents.y <= y) &&
	     (extents.y + extents.height > y) &&
	     (extents.x < right) &&
	     (extents.x + extents.width > left)) ) 
444 445 446
	continue;

      /* can stop when we passed y */
447
      for (j = 0; j < n_rects; j++)
448
	{
449 450 451
          cairo_region_get_rectangle (region, j, &pbox);

	  if (pbox.y + pbox.height <= y)
452 453
	    continue; /* Not quite there yet */
	  
454
	  if (pbox.y > y)
455 456
	    break; /* passed the spanline */
	  
457
	  if ((right > pbox.x) && (left < pbox.x + pbox.width)) 
458
	    {
459 460
              GdkSpan out_span;

461 462
	      clipped_left = MAX (left, pbox.x);
	      clipped_right = MIN (right, pbox.x + pbox.width);
463 464 465 466 467 468 469 470 471 472
	      
	      out_span.y = y;
	      out_span.x = clipped_left;
	      out_span.width = clipped_right - clipped_left;
	      (*function) (&out_span, data);
	    }
	}
    }
}

473 474 475 476 477 478 479 480 481 482
/**
 * gdk_region_spans_intersect_foreach:
 * @region: a #GdkRegion
 * @spans: an array of #GdkSpans
 * @n_spans: the length of @spans
 * @sorted: %TRUE if @spans is sorted wrt. the y coordinate
 * @function: function to call on each span in the intersection
 * @data: data to pass to @function
 *
 * Calls a function on each span in the intersection of @region and @spans.
Benjamin Otte's avatar
Benjamin Otte committed
483 484
 *
 * Deprecated: 2.22: There is no replacement.
485
 */
486
void
487 488 489 490 491 492
gdk_region_spans_intersect_foreach (GdkRegion     *region,
				    const GdkSpan *spans,
				    int            n_spans,
				    gboolean       sorted,
				    GdkSpanFunc    function,
				    gpointer       data)
493
{
494
  gint i, left, right, y, n_rects;
495
  gint clipped_left, clipped_right;
496
  GdkRectangle pbox;
497 498
  const GdkSpan *span, *tmpspan;
  const GdkSpan *end_span;
499

500 501 502
  g_return_if_fail (region != NULL);
  g_return_if_fail (spans != NULL);

503 504 505 506 507 508 509 510 511 512
  if (!sorted)
    {
      gdk_region_unsorted_spans_intersect_foreach (region,
						   spans,
						   n_spans,
						   function,
						   data);
      return;
    }
  
513 514
  n_rects = cairo_region_num_rectangles (region);
  if (n_rects == 0 || n_spans == 0)
515 516 517 518 519 520 521 522 523 524
    return;

  /* The main method here is to step along the
   * sorted rectangles and spans in lock step, and
   * clipping the spans that are in the current
   * rectangle before going on to the next rectangle.
   */

  span = spans;
  end_span = spans + n_spans;
525
  for (i = 0; i < n_rects; i++)
526
    {
527 528 529
      cairo_region_get_rectangle (region, i, &pbox);

      while ((pbox.y + pbox.height < span->y) || (span->y < pbox.y))
530 531
	{
	  /* Skip any rectangles that are above the current span */
532
	  if (pbox.y + pbox.height < span->y)
533
	    {
534 535
	      i++;
	      if (i == n_rects)
536
		return;
537
              cairo_region_get_rectangle (region, i, &pbox);
538 539
	    }
	  /* Skip any spans that are above the current rectangle */
540
	  if (span->y < pbox.y)
541 542 543 544 545 546 547 548 549 550
	    {
	      span++;
	      if (span == end_span)
		return;
	    }
	}
      
      /* Ok, we got at least one span that might intersect this rectangle. */
      tmpspan = span;
      while ((tmpspan < end_span) &&
551
	     (tmpspan->y < pbox.y + pbox.height))
552 553 554 555 556
	{
	  y = tmpspan->y;
	  left = tmpspan->x;
	  right = left + tmpspan->width; /* right is not in the span! */
	  
557
	  if ((right > pbox.x) && (left < pbox.x + pbox.width))
558
	    {
559 560
              GdkSpan out_span;

561 562
	      clipped_left = MAX (left, pbox.x);
	      clipped_right = MIN (right, pbox.x + pbox.width);
563 564 565 566 567 568 569 570 571 572 573
	      
	      out_span.y = y;
	      out_span.x = clipped_left;
	      out_span.width = clipped_right - clipped_left;
	      (*function) (&out_span, data);
	    }
	  
	  tmpspan++;
	}
    }
}
574 575 576

#define __GDK_REGION_GENERIC_C__
#include "gdkaliasdef.c"