Restrict last commit's workaround to layer groups only (which is
the only relevant case ATM), since it negatively impacts the warp
tool, which does rely on the ability to perform (accurate) partial
updates with filters to improve performance. It's only a temporary
hack anyway.
(cherry picked from commit 18870975b8)
When a drawable has filters attached, they may influence the area
affected by drawable updates. Currently, we ignore that, updating
the original region regardless. This can lead to drawable updates
not affecting the correct regions. This couldn't be triggered
until now, but since layer groups can now have a transform op
attached as a filter, updates to their sublayers -- which can
happen while the transform tool is active -- run into this problem.
Fix it for now by simply updating the full drawable region when the
drawable has filters. This is a very conservative approach -- we
don't even bother checking if we're only dealing with point
filters, as this change only influences transformed groups right
now. Ultimately, we need to rely on node invalidation to drive
updates, which takes this into account.
(cherry picked from commit 8be0e646bc)
Add a new GimpDrawable::supports_alpha() virtual function, and a
corresponding gimp_drawable_supports_alpha() function, which
determine if the drawable supports an alpha channel. The default
implementation returns FALSE, and GimpLayer overrides it to return
TRUE.
Change the default implementation of
GimpDrawable::get_bounding_box() to return the drawable source
node's bounding box, instead of the drawable's item bounds. This
allows filters to affect the size of all drawables, including, in
particular, layer masks.
Change GimpLayer's implementation of get_bounding_box() to return
the intersection of the layer's own bounding box, and the layer
mask's bounding box (if it has one), and update the layer's
bounding box when the mask is enabled/disabled, or when its
bounding box changes.
Maintain the bounding box of drawables (i.e., the bounds of their
actual rendered content) separately from their logical boundary (as
shown in the UI).
The bounding box is calculated through the new
GimpDrawable::get_bounding_box() virtual function, which has a
corresponding gimp_drawable_get_bounding_box() function; the
default implementation simply returns the drawable's logical
boundary. The bounding box is specified in drawable coordinates,
i.e., it's not affected by the drawable's offset.
The bounding box is recalculated through
gimp_drawable_update_bounding_box(), which should be called
whenever a change may affect the bounding box (for example, when
setting a new buffer, as done implicitly by GimpDrawable's
::set_buffer() implementation, or when a drawable filter's
properties change, as will be done by GimpDrawableFilter in a
following commit). When the bounding box changes, the affected
regions of the drawable are updated, and the
GimpDrawable::bounding-box-changed signal is emitted.
When gimp_drawable_update() is called with negative width/height
values, the entire drawable's bounding box is updated, rather than
only its logical boundary.
Likewise, GimpDrawableStack and GimpLayerStack are adapted to use
the bounding box, instead of the logical bounds, when updating the
drawable's area.
(cherry picked from commit 153cb33eec)
In GimpDrawable::set_buffer(), and the corresponding
gimp_drawable_set_buffer_full() function, take a bounds rectangle,
which specifies both the drawable's new offset and its new size,
instead of only taking the new offset. In
gimp_drawable_real_set_buffer(), set the item size according to the
rect dimensions, instead of the buffer dimensions. The rect's
width/height may be 0, in which case the buffer's dimensions are
used.
Adapt the rest of the code.
We do this in preparation for maintaining the drawable's bounding
box separately from its logical bounds, allowing the drawable
content to extend beyond its bounds.
(cherry picked from commit 3afdd7c5c2)
Add a new GimpDrawable::update_all() virtual function, and a
corresponding gimp_drawable_update_all() function, which updates
the full contents of the drawable. Unlike calling
`gimp_drawable_update (drawable, 0, 0, -1, -1)`, which updates the
entire drawable area, gimp_drawable_update_all() only updates the
area that has actual content. While the default implentation does
simply update the entire drawable area, GimpGroupLayer overrides
this function to recursively update its child layers, rather than
the its entire area.
(cherry picked from commit 3e5cbb03d9)
When freezing/thawing a top-level drawable's preview, only freeze/
thaw the image preview if the drawable is attached.
(cherry picked from commit de36e33347)
Add GimpViewable::preview_{freeze,thaw}() virtual functions, which
get called when the viewable's preview is frozen/thawed. Implement
the functions in GimpDrawable, recursively freezing the parent
drawable's preview (or the image's preview, for top-level
drawables) while the drawable's preview is frozen. For layer
masks, freeze the associated layer's parent.
This avoids updating layer-group/image previews while painting on,
or applying a filter to, a descendant layer. This both reduces
lag, and fixes a discrepancy between the layer's preview, which
isn't updated, and its parents' previews.
(cherry picked from commit e2ea2e4a82)
In gimp_drawable_get_active_mask(), when the drawable doesn't have
an alpha channel, set or clear the mask's alpha bit, according to
the state of the other bits, so that it never gets in the way of a
fully set/clear mask. The value of the alpha bit doesn't matter
when there's no alpha channel, however, having a uniform mask
allows us to skip component masking altogether.
Additionally, provide a default implementation for
GimpDrawable::get_active_mask() which returns a full mask, and
remove the equivalent implementation for GimpChannel.
(cherry picked from commit 1b900bfa16)
Remove gimp_drawable_replace_buffer(), which is no longer used
anywhere since commits ddb69b77a7 and
3451ffb62c. This eliminates
redundancy, since all compositing is now done through the layer-
mode code.
Furthermore, gimp_drawable_replace_buffer() used the drawable's
active-component array, whose layout depends on the image mode, as
an argument to gimp_gegl_replace(), which always expects an RGBA
component array, resulting in broken component masking in non-RGB
images.
(cherry picked from commit 2074accb60)
We now perform the conversion of filter output to the drawable
format as part of the individual filter nodes (see the last few
commits), so there's no need for another conversion after the
filter stack.
This reverts commit d6e0ca5054.
(cherry picked from commit 95393722cc)
In GimpLineArt, use the "invalidate-preview" signal of the input
viewable, instead of its "painted" or "rendered" signals, for
asynchronously computing the line art. Subsequently, remove the
aforementioned signals from GimpDrawable and GimpProjection,
respectively. This simplifies the code, and reduces the number of
signals.
(cherry picked from commit ef9b1f6694)
This commit completely removes the "Edit -> Fade..." feature,
because...
- The main reason is that "fade" requires us to keep two buffers,
instead of one, for each fadeable undo step, doubling (or worse,
since the extra buffer might have higher precision than the
drawable) the space consumed by these steps. This has notable
impact when editing large images. This overhead is incurred even
when not actually using "fade", and since it seems to be very
rarely used, this is too wasteful.
- "Fade" is broken in 2.10: when comitting a filter, we copy the
cached parts of the result into the apply buffer. However, the
result cache sits after the mode node, while the apply buffer
should contain the result of the filter *before* the mode node,
which can lead to wrong results in the general case.
- The same behavior can be trivially achieved "manually", by
duplicating the layer, editing the duplicate, and changing its
opacity/mode.
- If we really want this feature, now that most filters are GEGL
ops, it makes more sense to just add opacity/mode options to the
filter tool, instead of having this be a separate step.
(cherry picked from commit ed7ea51fb7)
The "update" signal on drawable or projection can actually be emitted
many times for a single painting event. Just add new signals ("painted"
on GimpDrawable and "rendered" on GimpProjection) which are emitted once
for a single update (from user point of view), at the end, after actual
rendering is done (i.e. after the various "update" signals).
Also better support the sample merge vs current drawable paths for
bucket fill.
(cherry picked from commit 047265333c)
When creating a drawable undo from the drawable's buffer, align the
copied rectangle to the buffer's tile grid, so that all the copied
tiles are COWed, saving memory and gaining speed.
Add applied_x and applied_y fields to GimpDrawableUndo, specifying
the position at which to apply the applied_buffer, so that we apply
it in the right place, even if the undo rect has changed due to
alignment.
(cherry picked from commit bb9dd049fb)
... and G_TYPE_INSTANCE_GET_PRIVATE()
g_type_class_add_private() and G_TYPE_INSTANCE_GET_PRIVATE() were
deprecated in GLib 2.58. Instead, use
G_DEFINE_[ABSTRACT_]TYPE_WITH_PRIVATE(), and
G_ADD_PRIVATE[_DYNAMIC](), and the implictly-defined
foo_get_instance_private() functions, all of which are available in
the GLib versions we depend on.
This commit only covers types registered using one of the
G_DEFINE_FOO() macros (i.e., most types), but not types with a
custom registration function, of which we still have a few -- GLib
currently only provides a (non-deprecated) public API for adding a
private struct using the G_DEFINE_FOO() macros.
Note that this commit was 99% auto-generated (because I'm not
*that* crazy :), so if there are any style mismatches... we'll have
to live with them for now.
... which specifies whether or not to update the drawable in
response to the buffer change.
Pass TRUE for "update" at all existing call sites, to keep the
current behavior.
(cherry picked from commit 26a8d141f6)
This is mostly core code which we want to keep in sync with master as
long as possible, so I picked this one even though not strictly
neccessary.
(cherry picked from commit 1b7d63cce9)
Implement GimpPickable::get_pixel_average(), added in the previous
commit, in GimpDrawable, GimpImage, and GimpProjection, using
gimp_gegl_average_color(), added in the commit before last. This
is significantly faster than the default implementation.
...like gaussian blur in indexed mode
In GimpDrawable's source node, after the filter stack, insert a node
that converts the pixels back to the drawable's format if the drawable
is indexed.
In GimpPaintTool, brush outline generation took place during
gimp_paint_tool_draw() even while painting. This function is run
concurrently with the paint thread. When using dynamics, this
introduced a race conidition between updating the brush mask in the
paint thread, and updating the brush boundary in the main thread.
Move brush outline generation during painting to
gimppainttool-paint.c, and perform it in the display-update
timeout, while the main thread and the paint thread are
synchronized.
gimp_drawable_start/end_paint() are used to enter/exit paint mode
for a given drawable. While the drawable is in paint mode,
gimp_drawable_get_buffer() returns a copy of the real drawable's
buffer, referred to as the paint buffer, so that modifications to
the returned buffer don't immediately affect the projection, and
calls to gimp_drawable_update() queue the updated region, instead
of emitting an "update" signal.
gimp_drawable_flush_paint() can be called while the drawable is in
paint mode, in order to copy the updated region of the paint buffer
back to the drawable's real buffer, and to emit "update" signals
for the queued region.
We use these functions in the next commit, to move painting to a
separate thread in the paint tools.
Revert commit 24fcabc1ca, which
allowed passing a NULL buffer to gimp_drawable_set_buffer[_full](),
leaving the drawable without a buffer in a semi-functional state --
this is too risky.
Instead, have gimp_drawable_steal_buffer() assign an empty 1x1
buffer to the stolen-from drawable, rather than leaving it without
a buffer at all.
... which transfers a buffer from one drawable to another in a safe
manner, leaving the source drawable empty.
There are already two ad-hoc instances where we steal a drawable's
buffer through simple pointer assignment, however, this avoids
performing potentially necessary cleanup and setup. In particular,
since commit d0ae244fe8 this causes
actual errors. The next two commits replace those instances with
calls to gimp_drawable_steal_buffer().
... which clears the drawable's buffer, performing any necessary
cleanup, without setting a new buffer. While the drawable has no
buffer, it can only be used in a very limited way, in particular,
it may be destroyed, and it may be assigned a new buffer.
This is used by the next commit to implement
gimp_drawable_steal_buffer(), which transfers a buffer from one
drawable to another in a safe manner, leaving the source drawable
empty.
Have GimpChannel connect to the drawable buffer's "changed" signal,
so that we can invalidate the channel's boundary whenever the
buffer contents change. Currently, the calls to
gimp_drawable_invalidate_boundary() dispersed throughout the code
are not enough.
Moreover, invalidate both the boundary and the bounds in
gimp_channel_invalidate_boundary(), since both are necessary when
the buffer changes.
Currently, when a GimpFilter's visibility changes, we rely on its
various visibility-changed signal handlers to rewire the filter
node's graph to reflect the change. This has two main
disadvantages:
- There's no easy, generic way to toggle a filter's effect,
especially one that is not subclassed, since GimpFilter only
takes care of the case where visibility becomes FALSE, and does
nothing by itself when it becomes TRUE again.
- While GimpDrawable does handle the visibility => TRUE case, it
doesn't disconnect the filter's input from its mode and
(potentially) source nodes when it becomes invisible. As a
result, while none of the drawable's graph is processed as part
of the composition when not visible, the mode and source nodes
do get invalidated when the filter's input is invalidated, such
as while painting on a layer below the drawable. This is
particularly bad for pass-through groups, since their source
node can be an arbitrarily complex graph, whose invlidation
incurs a nontrivial overhead.
Instead, don't touch the filter's node at all when visibility
changes, and rather have GimpFilterStack remove it from the graph
entirely when the filter becomes invisible, and re-add it once it
becomes visible again. This solves both of the above problems, as
well as simplifies the code.
Use gimp:buffer-source-validate, introduced in the previous commit,
for the source node of GimpDrawables. This avoids threading issues
with layer groups, or any other drawables that may use a validating
buffer, by making sure the buffer is validated before any
succeeding operations, and hence the associated graph is processed
on the same thread as the parent composition.
Restore multithreaded processing in GimpOperationLayerMode.
When any of the children of a pass-through group excludes its
backdrop, the group itself should exclude the backdrop too. Override
get_excludes_backdrop() to follow this logic, and call
update_excludes_backdrop() when this condition might change.
Note that we always composite pass-through groups using src-over mode,
so to actually hide the backdrop, we need to disconnect it from the
group's mode node's input pad (and reconnect it, when the backdrop is
no longer hidden).
Make sure the input of the layer's filter node is connected to its
source node (when it has an input pad), so that, once we implement
pass-though mode, the group's source node can see the backdrop.
For pass-through groups, we want to use the group's layer-stack
graph directly in its filter node, in place of the drawable's
buffer-source node. Add a get_source_node() vfunc to GimpDrawable,
which defaults to returning the buffer-source node, and use it in
gimp_drawable_get_source_node() instead of using the buffer-source
node directly. We'll later override this function for
GimpGroupLayer.
More than 2000 lines of code less in app/, instead of
if (instance->member)
{
g_object_unref/g_free/g_whatever (instance->member);
instance->member = NULL;
}
we now simply use
g_clear_object/pointer (&instance->member);
Largely based on a patch by Ell, with the enum type renamed and
various small changes. Adds another axis of configurability to the
existing layer mode madness, and is WIP too.
with proper value names. Mark most values as _BROKEN because they use
weird alpha compositing that has to die. Move GimpLayerModeEffects to
libgimpbase, deprecate it, and set it as compat enum for GimpLayerMode.
Add the GimpLayerModeEffects values as compat constants to script-fu
and pygimp.
Add a GimpFillType argument to GimpItem::resize() and fill type
widgets to the canvas and layer resize dialogs. Fill the new parts of
the drawable according to fill type in gimp_drawable_resize(). Make
sure places that need the old behavior get GIMP_FILL_TRANSPARENT
passed by hardcoding it in the GimpItem::resize() implemetations of
channel, mask, selection etc.