In gimp_image_reorder_item(), call gimp_item_start/end_move()
before/after reordering the item (and use an undo group, so that
the resulting undo actions are grouped together with the reordering
undo action,) so that if the item is a child of a group layer, and
reordering moves it out of the group in a way that causes the
group's mask to be resized, the mask will be properly restored when
undoing the operation.
Rename gimpdrawable-blend.h to gimpdrawable-gradient.h. Note that
this commit only renames the file; the actual changes are done in
the next commit, so that git doesn't consider this a new file.
Partially revert commits 4f2e078ccb
and b0beb0197a, since the changes
they introduced to some of the renamed files were big enough for
git to consider them entirely new files, hence we lost their
history. The next few commits fix this.
This commit also partially or entirely undoes followup commits
5f6dfc7617,
c3f98cccbd,
6b0f5136e0,
and 3736bfd189, which will be
restored by the next few commits as well.
Using CIE Lab yields gradients that more closely resemble the perceptual
gradients but without the gamma based blending problems of linear-RGB / CIE
XYZ.
This includes migrating properly any custom shortcut (menurc), as well
as a few strings in tool-presets/, and finally "gimp-blend-tool" in
contextrc and devicerc.
File toolrc also has some occurrences, but we are already skipping it
anyway, same as whatever is under tool-options/.
Hopefully I missed nothing.
First WIP commit, adds:
- enum GimpGradientBlendColorSpace { RGB_PERCEPTUAL, RGB_LINEAR }
- linear blending mode for gradient segments
- tool options GUI for the blend and paint tools which use gradients
... edges for MyPaint brush.
Adding the concept of "stateful" symmetry when a tool needs to make sure
of corresponding stroke numbers and orders while painting (i.e. stroke N
at time T+1 is the continuation of stroke N at time T). This is the case
for the MyPaint brushes and the ink tool.
Make sure a channel -> selection -> channel roundtrip never does any
gamma conversion.
In gimp_channel_duplicate(), make sure a created channel has the
right format, and the right data. Fixes selection -> channel.
When switching off quick mask, call gimp_item_to_selection() instead
if gimp_selection_load(), the latter was implementing a shortcut which
is now wrong.
Remove gimp_selection_load() which is now unused.
Unrelated: also remove gimp_selection_save(), it was an obvious
3-liner used only twice.
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.
Storing selections and layer masks as linear grayscale, but channels
as whatever-the-layers-are caused severe problems in images with
gamma-corrected layers: when combining channels with the selection,
they would go thorugh a gamma conversion before being combined, giving
unexpected results.
This commit changes all channels to always be linear, except in 8-bit
images, where they continue to be "Y' u8", for compatibility with old
XCF files, and because linear 8-bit can't really be used in
compositing (channels can be visible too).
To fix channel -> selection combinations also for these images, add a
small hack to gimp_gegl_mask_combine_buffer() which makes sure the
to-be-combined channel's pixels are always read as-is, without any
gamma conversion. After changing channels to linear, this makes no
difference except in the 8-bit images where we need this hack.
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.
Last commit caused -xobjective-c to be passed during linking on
Mac, causing object files to be treated as source files. Add a
-xnone flag to AM_LDFLAGS, canceling the effect of -xobjective-c.
Additinally, add a -xobjective-c++ flag to AM_CXXFLAGS, so that we
can use Objective-C in C++ files on Mac, if we ever need to.
On Mac, pass -xobjective-c to the compiler through AM_CFLAGS, not
AM_CPPFLAGS, so that it's only used for C sources, and not C++
sources. In the latter case, it clashes with the -std=... flag,
spewing an error. Thanks, Partha :)
gimp-templates.c:143:15: warning: ‘strncpy’ output truncated before terminating nul copying 3 bytes from a string of the same length [-Wstringop-truncation]
strncpy (dpi, "ppi", 3);
^~~~~~~~~~~~~~~~~~~~~~~
The next commit is going to parallelize gimpbrush-transform using
the gimp_parallel_distribute_foo() functions. To spare us a lot of
boilerplate code, we're going to use C++ lambdas as callback
arguments to these functions.
This commit does the initial conversion of gimpbrush-transform.c to
C++, renaming it to gimpbrush-transform.cc. We do this in a
separate commit, so that the changes are small enough for git to
register this as a renamed file, rather than a new file, so that we
don't lose the file's history.
Add gimp-parallel.[cc,h], which provides a set of parallel
algorithms.
These currently include:
- gimp_parallel_distribute(): Calls a callback function in
parallel on multiple threads, passing it the current thread
index, and the total number of threads. Allows specifying the
maximal number of threads used.
- gimp_parallel_distribute_range(): Splits a range of integers
between multiple threads, passing the sub-range to a callback
function. Allows specifying the minimal sub-range size.
- gimp_parallel_distribute_area(): Splits a rectangular area
between multiple threads, passing the sub-area to a callback
function. Allows specifying the minimal sub-area.
The callback function is passed using an appropriately-typed
function pointer, and a user-data pointer. Additionally, when used
in a C++ file, each of the above functions has an overloaded
template version, taking the callback through a generic parameter,
without a user-data pointer, which allows using function objects.
If variables are edited directly, in some cases, the GUI and the
symmetries may end up out-of-sync. The variable can only be edited
through property setting.
This value is actually used as a special value when removing a guide to
get rid of a symmetry, in particular it is set in the guides' callback
gimp_mirror_guide_removed_cb() for "removed" signal.
If not setting to 0, when adding back a symmetry, it starts with weird
low or high values near to border (whereas when set to 0, it is reset to
default position afterwards).
... parasite.
Not sure if that should be considered a bug. On one hand, it should
because that's core code. On the other hand, symmetry saving currently
uses parasites, which is a feature which can also be used by people
randomly. So "theoretically", there could be any data in a parasite and
we should not assume specific format.
Anyway still keep the error message but just print to standard error
output instead. Also print a bit more details (parasite name and
contents) as it would help for debugging when such a case were to occur.
Care for future changes of symmetries, by adding a version property. For
now, all symmetries are at version 0, and no real check is done. If any
symmetry bumps its settings in the future, it will have to override also
update_version() to change settings properly if necessary, according to
any new behavior.
When adding a rectangle to a projection's update area, align the
rectangle to a coarse grid, to reduce the complexity of the overall
area. We currently align the rectangle to a 32x32 grid, which
seems to be a good tradeoff between the overhead of processing a
complex area, and the overhead of processing a large area.
The debug menu is currently not included in stable versions.
Include the menu unconditionally, but hide it, and its associated
actions, by default in stable versions. Allow enabling the menu
using a new --show-debug-menu command-line option, in the same vein
as --show-playground.
when setting a custom parse error with g_scanner_error() we *must*
return G_TOKEN_NONE as expected token, or general GimpConfig error
handling will try to overwrite our error with its generic "unexpected
token" message, which triggers a warning.
In gimp_image_convert_precision(), don't overwrite the 'progress'
parameter with the object queue, since we need to call
gimp_progress_end() on it at the end of the process.
In gimp_image_resize_with_layers(), calculate the set of resized
layers before changing the image size, so that we correctly
identify image-sized layers w.r.t. the old image size. (Fixes
commit 139a23451ddc588c91610f67daa799afc2f89080.)
Add gimp_item_scale_by_factors_with_origin(), which is an extension
of gimp_item_scale_by_factors(), taking the input/output points of
origin for the transformation (both of which are (0, 0) in the case
of gimp_item_scale_by_factors()). Implement
gimp_item_scale_by_factors() in terms of the new function, and Use
the new function when scaling group layers, instead of manually
calculating the children boundaries, so that the behavior is
uniform across whole-image scaling and group-layer scaling.
The new function rounds all four edges of the boundary to the
image-global pixel grid, instead of only rounding the top/left
edges to the global grid, and the bottom/right edges to the item-
local grid. This preserves layer-adjacency when scaling.
Use GimpObjectQueue, added in the previous commit, in various
instances where we perform an action on a set of objects. This
improves progress reporting, by using a single progress for the
entire operation, rather than reporting the progress of each object
individually, and by taking the relative cost of each object into
account, instead of assuming a uniform cost for all objects.
In particular, this affects the various whole-image operations
(i.e., transformations and color conversions), operations on linked
items, and operations on layer groups. This also affects layers
with masks, whose progress is now reported together instead of
individually.
Additionally, this commit fixes erroneous group-layer mask cropping
during undo when resizing the image, by properly calling
{start,end}_move() on all the resized layers before starting the
operation, and when scaling the image, by only scaling top-level
layers, and letting group layers scale their children themselves.
GimpObjectQueue implements a queue of GimpObjects. It derives from
GimpSubProgress, and hence can be used as a GimpProgress object.
It keeps track of the total memsize of the objects that were
pushed-to and popped-from the queue, and uses these numbers to set
the corresponding subrange of the progress object when an object is
popped.
This provides an easy way to perform an operation on a set of
objects, correctly reporting progress based on the relative sizes
of the objects, which is assumed to be a good estimate of the
relative cost of processing each object.
Make the parent GimpProgress object of a GimpSubProgress instance
settable through a property during construction, so that we can use
it as a base class.
In gimp_group_layer_{start,end}_move(), push corresponding undo
steps, which perform the opposite operation during undo, and make
sure that mask-cropping is frozen during group-layer move
operations.
This fixed erroneous group-layer mask cropping when undoing/redoing
a group-layer move operation multiple times.
When pasting in place over a layer group or a content-locked item,
change the paste type to NEW_LAYER_IN_PLACE, rather than NEW_LAYER,
so that the new layer is still pasted in the right location.
Additionally, avoid showing the "Pasted as new layer because ..."
message when pasting over a layer group or a content-locked item,
when the paste type is NEW_LAYER[_IN_PLACE] to begin with.
Add a crop_input parameter to gimp_gegl_apply_[cached_]operation().
When TRUE, the functions crop the op's input to the destination
rect. This is particularly useful for functions that process the
entire input in one go (by means of get_cached_region()). See the
next commit.
Pass crop_input = FALSE at all call sites for now, to keep the
current behavior.
... (gimp-context-set-paint-method...) is called.
GimpContext initialized with standard paint info at constructed() time
to ensure there is always a paint_info even if none were set manually.
This property is currently only used for gimp_edit_blend() to control
how are computed distances. In the future, it could be used for more
functions making use of "gegl:distance-transform" operation, or even for
other algorithms, if relevant.
This new property obviously comes with 2 new PDB calls:
gimp_context_get_distance_metric() & gimp_context_set_distance_metric()
It seems old blend tool (from GIMP 2.8) was using manhattan distance,
whereas the new one uses euclidean. I guess there must be use cases for
both. In any case, it is a good idea to simply propose the option since
the property exists in the "gegl:distance-transform" operation.
See also bug 781621.
Our composite modes don't correspond directly to the Porter-Duff
operators after which they're named, and these names aren't too
descriptive anyway.
Rename the composite modes as follows:
Source Over => Union
Source Atop => Clip to Backdrop
Destination Atop => Clip to Layer
Source In => Intersection
Update relevant code, including UI text, enumerator names, function
names, and action names.
PDB function gimp_edit_blend() was based on "gimp:shapeburst" operation
whereas the rest of GIMP (in particular, the Blend tool) used
"gegl:distance-transform" which is much faster.
Setting the operation to "manhattan" metric ensures that it still
renders the same way as in 2.8 while being a lot faster.
There was still a problem regarding as how it renders differently from
the Blend tool, but it turns out that the Blend tool is the one
rendering differently from how it used to in 2.8. We should discuss
adding the "metric" property in the tool options.
gimp_spawn_async() is similar to, but more limited than,
g_spawn_sync(). Unlike the latter, gimp_spawn_async() uses
vfork(), instead of fork(), when possible.
On Linux, a process that uses large amounts of memory (as GIMP may)
can hang during a fork() if overcommitting is enabled, and there's
not enough memroy. Using vfork() avoids that, since it doesn't
duplicate the parent's address space.
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.
Since a few commits, I don't generate the traces anymore in errors.c but
delay this to gui-message.c and rely on the message severity to decide
whether or not generating traces.
Unfortunately none of the current severities are properly describing
this new type of messages. Even GIMP_MESSAGE_ERROR is used everywhere in
our code NOT for actual programming bug, but often for data errors
(which are not bugs but proper messages and should obviously not prompt
a debug trace).
Setting push_undo to FALSE in these functions is premature -- let
this stuff be handled at the actual point where the undo is
pushed, which might correspond to a different item than the one for
which gimp_item_{start,end}_move() was called.
In particular, when removing a layer from the image,
gimp_item_end_move() is called (with push_undo == TRUE) on the
layer after it's been removed, but we still need the appropriate
undo enrties to be pushed for the affected group layers.
... a selection.
The crash was the result of an unmatched gimp_item_end_move() call,
which is an error. Add the matching gimp_item_start_move() call
when starting to drag a selection in GimpEditSelectionTool. Revert
last commit, so that unmatched gimp_layer_end_move() calls are not
silently ignored, and add a check instead.
... a selection.
The regression appeared with commit 10c125c627.
gimp_layer_end_move() may sometimes run even while a symmetric
gimp_layer_start_move() had not run. For instance this happens when
releasing the mouse button after dragging a ctrl-alt-click created
floating layer.
Therefore let's check that layer->move_stack is not NULL before
dereferencing it.
We don't want an infinite number of traces because it takes some time to
get. Until now I was keeping track of traces in app/errors.c, but that
was very sucky because then I was limiting traces per session. Instead
save them as a variable of a GimpCriticalDialog instance. Therefore only
generate the traces for WARNING/CRITICAL at the last second, when
calling the dialog.
When too many traces are displayed, just fallback to just add error
messages only. But then even errors without traces can be time-consuming
(if you have dozens of thousands of errors in a few seconds, as I had
the other day, updating the dialog for all of them would just freeze the
whole application for a long time).
So also keep track of errors as well and as last fallback, just send the
remaining errors to the stderr.
which is just a #define to g_assert for now, but can now easily be
turned into something that does some nicer debugging using our new
stack trace infrastructure. This commit also reverts all constructed()
functions to use assert again.
Completing previous commit, the next switch was not raising any error,
but I believe the new "in place" variants of paste as floating selection
also have to be processed for mask removal.
In a switch(), not all paste type were listed (the new "In Place"
versions in particular were missing), therefore we were hitting a
g_return_val_if_reached() error.
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.
In gimp_layer_start_move(), keep the set of ancestors for which for
which we suspended mask cropping, so that we can resume mask
cropping for the same groups in gimp_layer_end_move(). This is
necessary, since gimp_image_remove_layer() calls gimp_item
start_move() before removing the layer from the layer tree, and
gimp_item_end_move() after removing the layer from the layer tree,
at which point the layer has no ancestors.
Replacing the boolean property "generate-backtrace" by an enum
"debug-policy". This property allows one to choose whether to debug
WARNING, CRITICAL and FATAL (crashes), or CRITICAL and FATAL only, or
only FATAL, or finally nothing.
By default, a stable release will debug CRITICAL and crashes, and
unstable builds will start debugging at WARNINGs.
The reason for the settings is that if you stumble upon a reccurring bug
in your workflow (and this bug is not major enough for data corruption,
and "you can live with it"), you still have to wait for a new release.
At some point, you may want to disable getting a debug dialog, at least
temporarily. Oppositely, even when using a stable build, you may want to
obtain debug info for lesser issues, even WARNINGs, if you wish to help
the GIMP project.
It can be argued though whether the value GIMP_DEBUG_POLICY_NEVER is
really useful. There is nothing to gain from refusing debugging info
when the software crashed anyway. But I could still imagine that someone
is not interested in helping at all. It's sad but not like we are going
to force people to report. Let's just allow disabling the whole
debugging system.
We avoid resizing the mask as a result of changes in the group's
bounding box while the group is being moved (i.e., translated,
rotated, etc.), so that GimpLayer transforms the original mask,
rather than a cropped mask. We still need to crop the mask after
we're finished moving the group, however. This commit takes care
of that.
Override GimpItem::resize(), instead of GimpLayer::resize(), when
resizing a group layer, so that GimpLayer doesn't try to resize the
mask. Instead, the let the usual mask resizing logic in
GimpGroupLayer handle that.
Also, make sure that the mask is properly restored upon undo when
group resizing is suspended outside of any mask-suspension block,
which can happen when resizing the group.
Add layer-mask support for group layers. Group-layer masks work
similarly to ordinary-layer masks, with the following
considerations:
The group's mask size is the same as group's size (i.e., the
bounding box of its children) at all times. When the group's size
changes, the mask is cropped to the new size -- areas of the mask
that fall outside of the new bounds are discarded and their data is
lost (sans undo), and newly added areas are filled with black (and
hence are transparent by default).
The new gimp_group_layer_{suspend,resume}_mask() functions can be
used to modify this behavior. Between the outermost pair of
suspend/resume calls, the old mask data is remembered, and is used
to fill the newly added areas while cropping the mask when the
group is resized. We override GimpItem::{start,end}_move() for
GimpLayer, to call these functions (suspend() in start_move(), and
resume() in end_move()) for each of the layer's ancestors.
As a result, while moving a layer, or a set of layers, atomically,
such as while dragging with the move tool, or moving linked layers,
the ancestors' mask data is not lost, and is only discarded at the
end of the operation.
This commit also takes care of properly handling undo for group-
layer mask crops, properly invalidating the image when the group
layer's mask is shown, and enabling the mask actions for group
layers (obviously :).