Exemple #1
0
static void
_boxblur (guchar      *buffer,
          int          width,
          int          height,
          int          radius,
          GskBlurFlags flags)
{
  guchar *flipped_buffer;
  int d = get_box_filter_size (radius);

  flipped_buffer = g_malloc (width * height);

  if (flags & GSK_BLUR_Y)
    {
      /* Step 1: swap rows and columns */
      flip_buffer (flipped_buffer, buffer, width, height);

      /* Step 2: blur rows (really columns) */
      blur_rows (flipped_buffer, buffer, height, width, d);

      /* Step 3: swap rows and columns */
      flip_buffer (buffer, flipped_buffer, height, width);
    }

  if (flags & GSK_BLUR_X)
    {
      /* Step 4: blur rows */
      blur_rows (buffer, flipped_buffer, width, height, d);
    }

  g_free (flipped_buffer);
}
/* The "spread" of the filter is the number of pixels from an original
 * pixel that it's blurred image extends. (A no-op blur that doesn't
 * blur would have a spread of 0.) See comment in blur_rows() for why the
 * odd and even cases are different
 */
static int
get_shadow_spread (int radius)
{
  int d = get_box_filter_size (radius);

  if (d % 2 == 1)
    return 3 * (d / 2);
  else
    return 3 * (d / 2) - 1;
}
static void
make_shadow (MetaShadow     *shadow,
             cairo_region_t *region)
{
  int d = get_box_filter_size (shadow->key.radius);
  int spread = get_shadow_spread (shadow->key.radius);
  cairo_rectangle_int_t extents;
  cairo_region_t *row_convolve_region;
  cairo_region_t *column_convolve_region;
  guchar *buffer;
  int buffer_width;
  int buffer_height;
  int x_offset;
  int y_offset;
  int n_rectangles, j, k;

  cairo_region_get_extents (region, &extents);

  /* In the case where top_fade >= 0 and the portion above the top
   * edge of the shape will be cropped, it seems like we could create
   * a smaller buffer and omit the top portion, but actually, in our
   * multi-pass blur algorithm, the blur into the area above the window
   * in the first pass will contribute back to the final pixel values
   * for the top pixels, so we create a buffer as if we weren't cropping
   * and only crop when creating the CoglTexture.
   */

  buffer_width = extents.width + 2 * spread;
  buffer_height = extents.height + 2 * spread;

  /* Round up so we have aligned rows/columns */
  buffer_width = (buffer_width + 3) & ~3;
  buffer_height = (buffer_height + 3) & ~3;

  /* Square buffer allows in-place swaps, which are roughly 70% faster, but we
   * don't want to over-allocate too much memory.
   */
  if (buffer_height < buffer_width && buffer_height > (3 * buffer_width) / 4)
    buffer_height = buffer_width;
  if (buffer_width < buffer_height && buffer_width > (3 * buffer_height) / 4)
    buffer_width = buffer_height;

  buffer = g_malloc0 (buffer_width * buffer_height);

  /* Blurring with multiple box-blur passes is fast, but (especially for
   * large shadow sizes) we can improve efficiency by restricting the blur
   * to the region that actually needs to be blurred.
   */
  row_convolve_region = meta_make_border_region (region, spread, spread, FALSE);
  column_convolve_region = meta_make_border_region (region, 0, spread, TRUE);

  /* Offsets between coordinates of the regions and coordinates in the buffer */
  x_offset = spread;
  y_offset = spread;

  /* Step 1: unblurred image */
  n_rectangles = cairo_region_num_rectangles (region);
  for (k = 0; k < n_rectangles; k++)
    {
      cairo_rectangle_int_t rect;

      cairo_region_get_rectangle (region, k, &rect);
      for (j = y_offset + rect.y; j < y_offset + rect.y + rect.height; j++)
	memset (buffer + buffer_width * j + x_offset + rect.x, 255, rect.width);
    }

  /* Step 2: swap rows and columns */
  buffer = flip_buffer (buffer, buffer_width, buffer_height);

  /* Step 3: blur rows (really columns) */
  blur_rows (column_convolve_region, y_offset, x_offset,
             buffer, buffer_height, buffer_width,
             d);

  /* Step 4: swap rows and columns */
  buffer = flip_buffer (buffer, buffer_height, buffer_width);

  /* Step 5: blur rows */
  blur_rows (row_convolve_region, x_offset, y_offset,
             buffer, buffer_width, buffer_height,
             d);

  /* Step 6: fade out the top, if applicable */
  if (shadow->key.top_fade >= 0)
    {
      for (j = y_offset; j < y_offset + MIN (shadow->key.top_fade, extents.height + shadow->outer_border_bottom); j++)
        fade_bytes(buffer + j * buffer_width, buffer_width, j - y_offset, shadow->key.top_fade);
    }

  /* We offset the passed in pixels to crop off the extra area we allocated at the top
   * in the case of top_fade >= 0. We also account for padding at the left for symmetry
   * though that doesn't currently occur.
   */
  shadow->texture = cogl_texture_new_from_data (shadow->outer_border_left + extents.width + shadow->outer_border_right,
                                                shadow->outer_border_top + extents.height + shadow->outer_border_bottom,
                                                COGL_TEXTURE_NONE,
                                                COGL_PIXEL_FORMAT_A_8,
                                                COGL_PIXEL_FORMAT_ANY,
                                                buffer_width,
                                                (buffer +
                                                 (y_offset - shadow->outer_border_top) * buffer_width +
                                                 (x_offset - shadow->outer_border_left)));

  cairo_region_destroy (row_convolve_region);
  cairo_region_destroy (column_convolve_region);
  g_free (buffer);

  shadow->material = meta_create_texture_material (shadow->texture);
}