app: implement gimp_paint_core_replace() using gimp_paint_core_loops_process()

Implement the no-applicator path of gimp_paint_core_replace() in
terms of gimp_paint_core_loops_process(), using the algorithms
added in the previous commit, instead of using
gimp_drawable_replace_buffer().  This improves speed, consolidates
code, and fixes some cases in which the latter is broken.

Furthermore, when using CONSTANT paint application-mode, use the
paint-core's undo_buffer as the compositing source, rather than the
drawable buffer, which is the correct behavior.
This commit is contained in:
Ell
2019-02-12 06:25:28 -05:00
parent 183a55613e
commit ddb69b77a7

View File

@ -989,9 +989,7 @@ gimp_paint_core_replace (GimpPaintCore *core,
gdouble image_opacity,
GimpPaintApplicationMode mode)
{
GeglRectangle mask_rect;
GeglBuffer *paint_mask_buffer;
gint width, height;
gint width, height;
if (! gimp_drawable_has_alpha (drawable))
{
@ -1009,14 +1007,17 @@ gimp_paint_core_replace (GimpPaintCore *core,
width = gegl_buffer_get_width (core->paint_buffer);
height = gegl_buffer_get_height (core->paint_buffer);
if (mode == GIMP_PAINT_CONSTANT &&
/* Some tools (ink) paint the mask to paint_core->canvas_buffer
* directly. Don't need to copy it in this case.
*/
paint_mask != NULL)
if (core->applicator)
{
if (core->applicator)
GeglRectangle mask_rect;
GeglBuffer *paint_mask_buffer;
if (mode == GIMP_PAINT_CONSTANT &&
/* Some tools (ink) paint the mask to paint_core->canvas_buffer
* directly. Don't need to copy it in this case.
*/
paint_mask != NULL)
{
paint_mask_buffer =
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
@ -1034,48 +1035,123 @@ gimp_paint_core_replace (GimpPaintCore *core,
GIMP_IS_AIRBRUSH (core));
g_object_unref (paint_mask_buffer);
/* initialize the maskPR from the canvas buffer */
paint_mask_buffer = g_object_ref (core->canvas_buffer);
mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
core->paint_buffer_y,
width, height);
}
else
{
/* Mix paint mask and canvas_buffer */
combine_paint_mask_to_canvas_buffer (paint_mask,
paint_mask_offset_x,
paint_mask_offset_y,
core->canvas_buffer,
core->paint_buffer_x,
core->paint_buffer_y,
paint_opacity,
GIMP_IS_AIRBRUSH (core));
paint_mask_buffer =
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x,
paint_mask_offset_y,
width, height);
}
/* initialize the maskPR from the canvas buffer */
paint_mask_buffer = g_object_ref (core->canvas_buffer);
/* apply the paint area to the image */
gimp_drawable_replace_buffer (drawable, core->paint_buffer,
GEGL_RECTANGLE (0, 0, width, height),
FALSE, NULL,
image_opacity,
paint_mask_buffer, &mask_rect,
core->paint_buffer_x,
core->paint_buffer_y);
mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x,
core->paint_buffer_y,
width, height);
g_object_unref (paint_mask_buffer);
}
else
{
paint_mask_buffer =
gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask);
GimpPaintCoreLoopsParams params = {};
GimpPaintCoreLoopsAlgorithm algorithms = GIMP_PAINT_CORE_LOOPS_ALGORITHM_NONE;
mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x,
paint_mask_offset_y,
width, height);
params.paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer);
params.paint_buf_offset_x = core->paint_buffer_x;
params.paint_buf_offset_y = core->paint_buffer_y;
if (! params.paint_buf)
return;
if (core->comp_buffer)
params.dest_buffer = core->comp_buffer;
else
params.dest_buffer = gimp_drawable_get_buffer (drawable);
if (mode == GIMP_PAINT_CONSTANT)
{
params.canvas_buffer = core->canvas_buffer;
/* This step is skipped by the ink tool, which writes
* directly to canvas_buffer
*/
if (paint_mask != NULL)
{
/* Mix paint mask and canvas_buffer */
params.paint_mask = paint_mask;
params.paint_mask_offset_x = paint_mask_offset_x;
params.paint_mask_offset_y = paint_mask_offset_y;
params.stipple = GIMP_IS_AIRBRUSH (core);
params.paint_opacity = paint_opacity;
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_COMBINE_PAINT_MASK_TO_CANVAS_BUFFER;
}
/* Write canvas_buffer to the compositing mask */
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
/* undo buf -> paint_buf -> dest_buffer */
params.src_buffer = core->undo_buffer;
}
else
{
g_return_if_fail (paint_mask);
/* Write paint_mask to the compositing mask, does not modify
* canvas_buffer
*/
params.paint_mask = paint_mask;
params.paint_mask_offset_x = paint_mask_offset_x;
params.paint_mask_offset_y = paint_mask_offset_y;
params.paint_opacity = paint_opacity;
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_PAINT_MASK_TO_COMP_MASK;
/* dest_buffer -> paint_buf -> dest_buffer */
if (core->comp_buffer)
params.src_buffer = gimp_drawable_get_buffer (drawable);
else
params.src_buffer = params.dest_buffer;
}
params.mask_buffer = core->mask_buffer;
params.mask_offset_x = core->mask_x_offset;
params.mask_offset_y = core->mask_y_offset;
params.image_opacity = image_opacity;
params.paint_mode = GIMP_LAYER_MODE_REPLACE;
algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_DO_LAYER_BLEND;
gimp_paint_core_loops_process (&params, algorithms);
if (core->comp_buffer)
{
mask_components_onto (params.src_buffer,
core->comp_buffer,
gimp_drawable_get_buffer (drawable),
GEGL_RECTANGLE (core->paint_buffer_x,
core->paint_buffer_y,
width,
height),
gimp_drawable_get_active_mask (drawable),
gimp_drawable_get_trc (drawable),
gimp_drawable_get_space (drawable));
}
}
/* apply the paint area to the image */
gimp_drawable_replace_buffer (drawable, core->paint_buffer,
GEGL_RECTANGLE (0, 0, width, height),
FALSE, NULL,
image_opacity,
paint_mask_buffer, &mask_rect,
core->paint_buffer_x,
core->paint_buffer_y);
g_object_unref (paint_mask_buffer);
/* Update the undo extents */
core->x1 = MIN (core->x1, core->paint_buffer_x);
core->y1 = MIN (core->y1, core->paint_buffer_y);