void gimp_paint_core_validate_canvas_tiles (GimpPaintCore *core, gint x, gint y, gint w, gint h) { gint i, j; g_return_if_fail (GIMP_IS_PAINT_CORE (core)); g_return_if_fail (core->canvas_tiles != NULL); for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT))) { for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH))) { Tile *tile = tile_manager_get_tile (core->canvas_tiles, j, i, FALSE, FALSE); if (! tile_is_valid (tile)) { tile = tile_manager_get_tile (core->canvas_tiles, j, i, TRUE, TRUE); memset (tile_data_pointer (tile, 0, 0), 0, tile_size (tile)); tile_release (tile, TRUE); } } } }
void tile_update_rowhints (Tile *tile, gint start, gint rows) { const guchar *ptr; gint bpp, ewidth; gint x, y; #ifdef HINTS_SANITY g_assert (tile != NULL); #endif tile_allocate_rowhints (tile); bpp = tile_bpp (tile); ewidth = tile_ewidth (tile); switch (bpp) { case 1: case 3: for (y = start; y < start + rows; y++) tile_set_rowhint (tile, y, TILEROWHINT_OPAQUE); break; case 4: #ifdef HINTS_SANITY g_assert (tile != NULL); #endif ptr = tile_data_pointer (tile, 0, start); #ifdef HINTS_SANITY g_assert (ptr != NULL); #endif for (y = start; y < start + rows; y++) { TileRowHint hint = tile_get_rowhint (tile, y); #ifdef HINTS_SANITY if (hint == TILEROWHINT_BROKEN) g_error ("BROKEN y=%d", y); if (hint == TILEROWHINT_OUTOFRANGE) g_error ("OOR y=%d", y); if (hint == TILEROWHINT_UNDEFINED) g_error ("UNDEFINED y=%d - bpp=%d ew=%d eh=%d", y, bpp, ewidth, eheight); #endif #ifdef HINTS_SANITY if (hint == TILEROWHINT_TRANSPARENT || hint == TILEROWHINT_MIXED || hint == TILEROWHINT_OPAQUE) { goto next_row4; } if (hint != TILEROWHINT_UNKNOWN) { g_error ("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d", y, bpp, ewidth, eheight); } #endif if (hint == TILEROWHINT_UNKNOWN) { const guchar alpha = ptr[3]; /* row is all-opaque or all-transparent? */ if (alpha == 0 || alpha == 255) { if (ewidth > 1) { for (x = 1; x < ewidth; x++) { if (ptr[x * 4 + 3] != alpha) { tile_set_rowhint (tile, y, TILEROWHINT_MIXED); goto next_row4; } } } tile_set_rowhint (tile, y, (alpha == 0) ? TILEROWHINT_TRANSPARENT : TILEROWHINT_OPAQUE); } else { tile_set_rowhint (tile, y, TILEROWHINT_MIXED); } } next_row4: ptr += 4 * ewidth; } break; case 2: #ifdef HINTS_SANITY g_assert (tile != NULL); #endif ptr = tile_data_pointer (tile, 0, start); #ifdef HINTS_SANITY g_assert (ptr != NULL); #endif for (y = start; y < start + rows; y++) { TileRowHint hint = tile_get_rowhint (tile, y); #ifdef HINTS_SANITY if (hint == TILEROWHINT_BROKEN) g_error ("BROKEN y=%d",y); if (hint == TILEROWHINT_OUTOFRANGE) g_error ("OOR y=%d",y); if (hint == TILEROWHINT_UNDEFINED) g_error ("UNDEFINED y=%d - bpp=%d ew=%d eh=%d", y, bpp, ewidth, eheight); #endif #ifdef HINTS_SANITY if (hint == TILEROWHINT_TRANSPARENT || hint == TILEROWHINT_MIXED || hint == TILEROWHINT_OPAQUE) { goto next_row2; } if (hint != TILEROWHINT_UNKNOWN) { g_error ("MEGABOGUS y=%d - bpp=%d ew=%d eh=%d", y, bpp, ewidth, eheight); } #endif if (hint == TILEROWHINT_UNKNOWN) { const guchar alpha = ptr[1]; /* row is all-opaque or all-transparent? */ if (alpha == 0 || alpha == 255) { if (ewidth > 1) { for (x = 1; x < ewidth; x++) { if (ptr[x * 2 + 1] != alpha) { tile_set_rowhint (tile, y, TILEROWHINT_MIXED); goto next_row2; } } } tile_set_rowhint (tile, y, (alpha == 0) ? TILEROWHINT_TRANSPARENT : TILEROWHINT_OPAQUE); } else { tile_set_rowhint (tile, y, TILEROWHINT_MIXED); } } next_row2: ptr += 2 * ewidth; } break; default: g_return_if_reached (); break; } }
static void find_empty_segs (PixelRegion *maskPR, gint scanline, gint empty_segs[], gint max_empty, gint *num_empty, BoundaryType type, gint x1, gint y1, gint x2, gint y2, guchar threshold) { const guchar *data = NULL; Tile *tile = NULL; gint start = 0; gint end = 0; gint endx = 0; gint bpp = 0; gint tilex = -1; gint last = -1; gint l_num_empty; gint x; *num_empty = 0; if (scanline < maskPR->y || scanline >= (maskPR->y + maskPR->h)) { empty_segs[(*num_empty)++] = 0; empty_segs[(*num_empty)++] = G_MAXINT; return; } if (type == BOUNDARY_WITHIN_BOUNDS) { if (scanline < y1 || scanline >= y2) { empty_segs[(*num_empty)++] = 0; empty_segs[(*num_empty)++] = G_MAXINT; return; } start = x1; end = x2; } else if (type == BOUNDARY_IGNORE_BOUNDS) { start = maskPR->x; end = maskPR->x + maskPR->w; if (scanline < y1 || scanline >= y2) x2 = -1; } empty_segs[(*num_empty)++] = 0; l_num_empty = *num_empty; bpp = maskPR->bytes; if (! maskPR->tiles) { data = maskPR->data + scanline * maskPR->rowstride; endx = end; } for (x = start; x < end;) { /* Check to see if we must advance to next tile */ if (maskPR->tiles) { if ((x / TILE_WIDTH) != tilex) { if (tile) tile_release (tile, FALSE); tile = tile_manager_get_tile (maskPR->tiles, x, scanline, TRUE, FALSE); data = ((const guchar *) tile_data_pointer (tile, x, scanline) + bpp - 1); tilex = x / TILE_WIDTH; } endx = x + (TILE_WIDTH - (x % TILE_WIDTH)); endx = MIN (end, endx); } if (type == BOUNDARY_IGNORE_BOUNDS && (endx > x1 || x < x2)) { for (; x < endx; x++) { gint val; if (*data > threshold) { if (x >= x1 && x < x2) val = -1; else val = 1; } else { val = -1; } data += bpp; if (last != val) empty_segs[l_num_empty++] = x; last = val; } } else { for (; x < endx; x++) { gint val; if (*data > threshold) val = 1; else val = -1; data += bpp; if (last != val) empty_segs[l_num_empty++] = x; last = val; } } } *num_empty = l_num_empty; if (last > 0) empty_segs[(*num_empty)++] = x; empty_segs[(*num_empty)++] = G_MAXINT; if (tile) tile_release (tile, FALSE); }
TempBuf * gimp_paint_core_get_orig_proj (GimpPaintCore *core, GimpPickable *pickable, gint x, gint y, gint width, gint height) { TileManager *src_tiles; PixelRegion srcPR; PixelRegion destPR; Tile *saved_tile; gboolean release_tile; gint h; gint pixelwidth; gint pickable_width; gint pickable_height; const guchar *s; guchar *d; gpointer pr; g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL); g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL); g_return_val_if_fail (core->saved_proj_tiles != NULL, NULL); core->orig_proj_buf = temp_buf_resize (core->orig_proj_buf, gimp_pickable_get_bytes (pickable), x, y, width, height); src_tiles = gimp_pickable_get_tiles (pickable); pickable_width = tile_manager_width (src_tiles); pickable_height = tile_manager_height (src_tiles); gimp_rectangle_intersect (x, y, width, height, 0, 0, pickable_width, pickable_height, &x, &y, &width, &height); /* configure the pixel regions */ pixel_region_init (&srcPR, src_tiles, x, y, width, height, FALSE); pixel_region_init_temp_buf (&destPR, core->orig_proj_buf, x - core->orig_proj_buf->x, y - core->orig_proj_buf->y, width, height); for (pr = pixel_regions_register (2, &srcPR, &destPR); pr != NULL; pr = pixel_regions_process (pr)) { /* If the saved tile corresponding to this location is valid, use it */ saved_tile = tile_manager_get_tile (core->saved_proj_tiles, srcPR.x, srcPR.y, FALSE, FALSE); if (tile_is_valid (saved_tile)) { release_tile = TRUE; saved_tile = tile_manager_get_tile (core->saved_proj_tiles, srcPR.x, srcPR.y, TRUE, FALSE); s = tile_data_pointer (saved_tile, srcPR.x, srcPR.y); } else { release_tile = FALSE; s = srcPR.data; } d = destPR.data; pixelwidth = srcPR.w * srcPR.bytes; h = srcPR.h; while (h --) { memcpy (d, s, pixelwidth); s += srcPR.rowstride; d += destPR.rowstride; } if (release_tile) tile_release (saved_tile, FALSE); } return core->orig_proj_buf; }
static void tile_pyramid_write_quarter (Tile *dest, Tile *src, gint i, gint j) { const guchar *src_data = tile_data_pointer (src, 0, 0); guchar *dest_data = tile_data_pointer (dest, 0, 0); const gint src_ewidth = tile_ewidth (src); const gint src_eheight = tile_eheight (src); const gint dest_ewidth = tile_ewidth (dest); const gint bpp = tile_bpp (dest); gint y; /* Adjust dest pointer to the right quadrant. */ dest_data += i * bpp * (TILE_WIDTH / 2) + j * bpp * dest_ewidth * (TILE_HEIGHT / 2); for (y = 0; y < src_eheight / 2; y++) { const guchar *src0 = src_data; const guchar *src1 = src_data + bpp; const guchar *src2 = src0 + bpp * src_ewidth; const guchar *src3 = src1 + bpp * src_ewidth; guchar *dst = dest_data; gint x; switch (bpp) { case 1: for (x = 0; x < src_ewidth / 2; x++) { dst[0] = (src0[0] + src1[0] + src2[0] + src3[0]) >> 2; dst += 1; src0 += 2; src1 += 2; src2 += 2; src3 += 2; } break; case 2: for (x = 0; x < src_ewidth / 2; x++) { guint a = src0[1] + src1[1] + src2[1] + src3[1]; switch (a) { case 0: /* all transparent */ dst[0] = dst[1] = 0; break; case 1020: /* all opaque */ dst[0] = (src0[0] + src1[0] + src2[0] + src3[0]) >> 2; dst[1] = 255; break; default: dst[0] = ((src0[0] * src0[1] + src1[0] * src1[1] + src2[0] * src2[1] + src3[0] * src3[1]) / a); dst[1] = (a + 2) >> 2; break; } dst += 2; src0 += 4; src1 += 4; src2 += 4; src3 += 4; } break; case 3: for (x = 0; x < src_ewidth / 2; x++) { dst[0] = (src0[0] + src1[0] + src2[0] + src3[0]) >> 2; dst[1] = (src0[1] + src1[1] + src2[1] + src3[1]) >> 2; dst[2] = (src0[2] + src1[2] + src2[2] + src3[2]) >> 2; dst += 3; src0 += 6; src1 += 6; src2 += 6; src3 += 6; } break; case 4: for (x = 0; x < src_ewidth / 2; x++) { guint a = src0[3] + src1[3] + src2[3] + src3[3]; switch (a) { case 0: /* all transparent */ dst[0] = dst[1] = dst[2] = dst[3] = 0; break; case 1020: /* all opaque */ dst[0] = (src0[0] + src1[0] + src2[0] + src3[0]) >> 2; dst[1] = (src0[1] + src1[1] + src2[1] + src3[1]) >> 2; dst[2] = (src0[2] + src1[2] + src2[2] + src3[2]) >> 2; dst[3] = 255; break; default: dst[0] = ((src0[0] * src0[3] + src1[0] * src1[3] + src2[0] * src2[3] + src3[0] * src3[3]) / a); dst[1] = ((src0[1] * src0[3] + src1[1] * src1[3] + src2[1] * src2[3] + src3[1] * src3[3]) / a); dst[2] = ((src0[2] * src0[3] + src1[2] * src1[3] + src2[2] * src2[3] + src3[2] * src3[3]) / a); dst[3] = (a + 2) >> 2; break; } dst += 4; src0 += 8; src1 += 8; src2 += 8; src3 += 8; } break; } dest_data += dest_ewidth * bpp; src_data += src_ewidth * bpp * 2; } }