1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <cairo.h>
23 #include <gegl.h>
24 #include <gdk-pixbuf/gdk-pixbuf.h>
25 
26 #include "libgimpcolor/gimpcolor.h"
27 #include "libgimpmath/gimpmath.h"
28 
29 #include "core-types.h"
30 
31 #include "gimpcontext.h"
32 #include "gimpgradient.h"
33 #include "gimpgradient-load.h"
34 #include "gimpgradient-save.h"
35 #include "gimptagged.h"
36 #include "gimptempbuf.h"
37 
38 
39 #define EPSILON 1e-10
40 
41 
42 static void          gimp_gradient_tagged_iface_init (GimpTaggedInterface *iface);
43 static void          gimp_gradient_finalize          (GObject             *object);
44 
45 static gint64        gimp_gradient_get_memsize       (GimpObject          *object,
46                                                       gint64              *gui_size);
47 
48 static void          gimp_gradient_get_preview_size  (GimpViewable        *viewable,
49                                                       gint                 size,
50                                                       gboolean             popup,
51                                                       gboolean             dot_for_dot,
52                                                       gint                *width,
53                                                       gint                *height);
54 static gboolean      gimp_gradient_get_popup_size    (GimpViewable        *viewable,
55                                                       gint                 width,
56                                                       gint                 height,
57                                                       gboolean             dot_for_dot,
58                                                       gint                *popup_width,
59                                                       gint                *popup_height);
60 static GimpTempBuf * gimp_gradient_get_new_preview   (GimpViewable        *viewable,
61                                                       GimpContext         *context,
62                                                       gint                 width,
63                                                       gint                 height);
64 
65 static const gchar * gimp_gradient_get_extension     (GimpData            *data);
66 static void          gimp_gradient_copy              (GimpData            *data,
67                                                       GimpData            *src_data);
68 static gint          gimp_gradient_compare           (GimpData            *data1,
69                                                       GimpData            *data2);
70 
71 static gchar       * gimp_gradient_get_checksum      (GimpTagged          *tagged);
72 
73 static inline GimpGradientSegment *
74               gimp_gradient_get_segment_at_internal  (GimpGradient        *gradient,
75                                                       GimpGradientSegment *seg,
76                                                       gdouble              pos);
77 static void          gimp_gradient_get_flat_color    (GimpContext         *context,
78                                                       const GimpRGB       *color,
79                                                       GimpGradientColor    color_type,
80                                                       GimpRGB             *flat_color);
81 
82 
83 static inline gdouble  gimp_gradient_calc_linear_factor            (gdouble  middle,
84                                                                     gdouble  pos);
85 static inline gdouble  gimp_gradient_calc_curved_factor            (gdouble  middle,
86                                                                     gdouble  pos);
87 static inline gdouble  gimp_gradient_calc_sine_factor              (gdouble  middle,
88                                                                     gdouble  pos);
89 static inline gdouble  gimp_gradient_calc_sphere_increasing_factor (gdouble  middle,
90                                                                     gdouble  pos);
91 static inline gdouble  gimp_gradient_calc_sphere_decreasing_factor (gdouble  middle,
92                                                                     gdouble  pos);
93 static inline gdouble  gimp_gradient_calc_step_factor              (gdouble  middle,
94                                                                     gdouble  pos);
95 
96 
97 G_DEFINE_TYPE_WITH_CODE (GimpGradient, gimp_gradient, GIMP_TYPE_DATA,
98                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_TAGGED,
99                                                 gimp_gradient_tagged_iface_init))
100 
101 #define parent_class gimp_gradient_parent_class
102 
103 static const Babl *fish_srgb_to_linear_rgb = NULL;
104 static const Babl *fish_linear_rgb_to_srgb = NULL;
105 static const Babl *fish_srgb_to_cie_lab    = NULL;
106 static const Babl *fish_cie_lab_to_srgb    = NULL;
107 
108 
109 static void
gimp_gradient_class_init(GimpGradientClass * klass)110 gimp_gradient_class_init (GimpGradientClass *klass)
111 {
112   GObjectClass      *object_class      = G_OBJECT_CLASS (klass);
113   GimpObjectClass   *gimp_object_class = GIMP_OBJECT_CLASS (klass);
114   GimpViewableClass *viewable_class    = GIMP_VIEWABLE_CLASS (klass);
115   GimpDataClass     *data_class        = GIMP_DATA_CLASS (klass);
116 
117   object_class->finalize            = gimp_gradient_finalize;
118 
119   gimp_object_class->get_memsize    = gimp_gradient_get_memsize;
120 
121   viewable_class->default_icon_name = "gimp-tool-gradient";
122   viewable_class->get_preview_size  = gimp_gradient_get_preview_size;
123   viewable_class->get_popup_size    = gimp_gradient_get_popup_size;
124   viewable_class->get_new_preview   = gimp_gradient_get_new_preview;
125 
126   data_class->save                  = gimp_gradient_save;
127   data_class->get_extension         = gimp_gradient_get_extension;
128   data_class->copy                  = gimp_gradient_copy;
129   data_class->compare               = gimp_gradient_compare;
130 
131   fish_srgb_to_linear_rgb = babl_fish (babl_format ("R'G'B' double"),
132                                        babl_format ("RGB double"));
133   fish_linear_rgb_to_srgb = babl_fish (babl_format ("RGB double"),
134                                        babl_format ("R'G'B' double"));
135   fish_srgb_to_cie_lab    = babl_fish (babl_format ("R'G'B' double"),
136                                        babl_format ("CIE Lab double"));
137   fish_cie_lab_to_srgb    = babl_fish (babl_format ("CIE Lab double"),
138                                        babl_format ("R'G'B' double"));
139 }
140 
141 static void
gimp_gradient_tagged_iface_init(GimpTaggedInterface * iface)142 gimp_gradient_tagged_iface_init (GimpTaggedInterface *iface)
143 {
144   iface->get_checksum = gimp_gradient_get_checksum;
145 }
146 
147 static void
gimp_gradient_init(GimpGradient * gradient)148 gimp_gradient_init (GimpGradient *gradient)
149 {
150   gradient->segments = NULL;
151 }
152 
153 static void
gimp_gradient_finalize(GObject * object)154 gimp_gradient_finalize (GObject *object)
155 {
156   GimpGradient *gradient = GIMP_GRADIENT (object);
157 
158   if (gradient->segments)
159     {
160       gimp_gradient_segments_free (gradient->segments);
161       gradient->segments = NULL;
162     }
163 
164   G_OBJECT_CLASS (parent_class)->finalize (object);
165 }
166 
167 static gint64
gimp_gradient_get_memsize(GimpObject * object,gint64 * gui_size)168 gimp_gradient_get_memsize (GimpObject *object,
169                            gint64     *gui_size)
170 {
171   GimpGradient        *gradient = GIMP_GRADIENT (object);
172   GimpGradientSegment *segment;
173   gint64               memsize  = 0;
174 
175   for (segment = gradient->segments; segment; segment = segment->next)
176     memsize += sizeof (GimpGradientSegment);
177 
178   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
179                                                                   gui_size);
180 }
181 
182 static void
gimp_gradient_get_preview_size(GimpViewable * viewable,gint size,gboolean popup,gboolean dot_for_dot,gint * width,gint * height)183 gimp_gradient_get_preview_size (GimpViewable *viewable,
184                                 gint          size,
185                                 gboolean      popup,
186                                 gboolean      dot_for_dot,
187                                 gint         *width,
188                                 gint         *height)
189 {
190   *width  = size;
191   *height = 1 + size / 2;
192 }
193 
194 static gboolean
gimp_gradient_get_popup_size(GimpViewable * viewable,gint width,gint height,gboolean dot_for_dot,gint * popup_width,gint * popup_height)195 gimp_gradient_get_popup_size (GimpViewable *viewable,
196                               gint          width,
197                               gint          height,
198                               gboolean      dot_for_dot,
199                               gint         *popup_width,
200                               gint         *popup_height)
201 {
202   if (width < 128 || height < 32)
203     {
204       *popup_width  = 128;
205       *popup_height =  32;
206 
207       return TRUE;
208     }
209 
210   return FALSE;
211 }
212 
213 static GimpTempBuf *
gimp_gradient_get_new_preview(GimpViewable * viewable,GimpContext * context,gint width,gint height)214 gimp_gradient_get_new_preview (GimpViewable *viewable,
215                                GimpContext  *context,
216                                gint          width,
217                                gint          height)
218 {
219   GimpGradient        *gradient = GIMP_GRADIENT (viewable);
220   GimpGradientSegment *seg      = NULL;
221   GimpTempBuf         *temp_buf;
222   guchar              *buf;
223   guchar              *p;
224   guchar              *row;
225   gint                 x, y;
226   gdouble              dx, cur_x;
227   GimpRGB              color;
228 
229   dx    = 1.0 / (width - 1);
230   cur_x = 0.0;
231   p     = row = g_malloc (width * 4);
232 
233   /* Create lines to fill the image */
234 
235   for (x = 0; x < width; x++)
236     {
237       seg = gimp_gradient_get_color_at (gradient, context, seg, cur_x,
238                                         FALSE,
239                                         GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL,
240                                         &color);
241 
242       *p++ = ROUND (color.r * 255.0);
243       *p++ = ROUND (color.g * 255.0);
244       *p++ = ROUND (color.b * 255.0);
245       *p++ = ROUND (color.a * 255.0);
246 
247       cur_x += dx;
248     }
249 
250   temp_buf = gimp_temp_buf_new (width, height, babl_format ("R'G'B'A u8"));
251 
252   buf = gimp_temp_buf_get_data (temp_buf);
253 
254   for (y = 0; y < height; y++)
255     memcpy (buf + (width * y * 4), row, width * 4);
256 
257   g_free (row);
258 
259   return temp_buf;
260 }
261 
262 static void
gimp_gradient_copy(GimpData * data,GimpData * src_data)263 gimp_gradient_copy (GimpData *data,
264                     GimpData *src_data)
265 {
266   GimpGradient        *gradient     = GIMP_GRADIENT (data);
267   GimpGradient        *src_gradient = GIMP_GRADIENT (src_data);
268   GimpGradientSegment *head, *prev, *cur, *orig;
269 
270   if (gradient->segments)
271     {
272       gimp_gradient_segments_free (gradient->segments);
273       gradient->segments = NULL;
274     }
275 
276   prev = NULL;
277   orig = src_gradient->segments;
278   head = NULL;
279 
280   while (orig)
281     {
282       cur = gimp_gradient_segment_new ();
283 
284       *cur = *orig;  /* Copy everything */
285 
286       cur->prev = prev;
287       cur->next = NULL;
288 
289       if (prev)
290         prev->next = cur;
291       else
292         head = cur;  /* Remember head */
293 
294       prev = cur;
295       orig = orig->next;
296     }
297 
298   gradient->segments = head;
299 
300   gimp_data_dirty (GIMP_DATA (gradient));
301 }
302 
303 static gint
gimp_gradient_compare(GimpData * data1,GimpData * data2)304 gimp_gradient_compare (GimpData *data1,
305                        GimpData *data2)
306 {
307   gboolean is_custom1;
308   gboolean is_custom2;
309 
310   /* check whether data1 and data2 are the custom gradient, which is the only
311    * writable internal gradient.
312    */
313   is_custom1 = gimp_data_is_internal (data1) && gimp_data_is_writable (data1);
314   is_custom2 = gimp_data_is_internal (data2) && gimp_data_is_writable (data2);
315 
316   /* order the custom gradient before all the other gradients; use the default
317    * ordering for the rest.
318    */
319   if (is_custom1)
320     {
321       if (is_custom2)
322         return 0;
323       else
324         return -1;
325     }
326   else if (is_custom2)
327     {
328       return +1;
329     }
330   else
331     return GIMP_DATA_CLASS (parent_class)->compare (data1, data2);
332 }
333 
334 static gchar *
gimp_gradient_get_checksum(GimpTagged * tagged)335 gimp_gradient_get_checksum (GimpTagged *tagged)
336 {
337   GimpGradient *gradient        = GIMP_GRADIENT (tagged);
338   gchar        *checksum_string = NULL;
339 
340   if (gradient->segments)
341     {
342       GChecksum           *checksum = g_checksum_new (G_CHECKSUM_MD5);
343       GimpGradientSegment *segment  = gradient->segments;
344 
345       while (segment)
346         {
347           g_checksum_update (checksum,
348                              (const guchar *) &segment->left,
349                              sizeof (segment->left));
350           g_checksum_update (checksum,
351                              (const guchar *) &segment->middle,
352                              sizeof (segment->middle));
353           g_checksum_update (checksum,
354                              (const guchar *) &segment->right,
355                              sizeof (segment->right));
356           g_checksum_update (checksum,
357                              (const guchar *) &segment->left_color_type,
358                              sizeof (segment->left_color_type));
359           g_checksum_update (checksum,
360                              (const guchar *) &segment->left_color,
361                              sizeof (segment->left_color));
362           g_checksum_update (checksum,
363                              (const guchar *) &segment->right_color_type,
364                              sizeof (segment->right_color_type));
365           g_checksum_update (checksum,
366                              (const guchar *) &segment->right_color,
367                              sizeof (segment->right_color));
368           g_checksum_update (checksum,
369                              (const guchar *) &segment->type,
370                              sizeof (segment->type));
371           g_checksum_update (checksum,
372                              (const guchar *) &segment->color,
373                              sizeof (segment->color));
374 
375           segment = segment->next;
376         }
377 
378       checksum_string = g_strdup (g_checksum_get_string (checksum));
379 
380       g_checksum_free (checksum);
381     }
382 
383   return checksum_string;
384 }
385 
386 
387 /*  public functions  */
388 
389 GimpData *
gimp_gradient_new(GimpContext * context,const gchar * name)390 gimp_gradient_new (GimpContext *context,
391                    const gchar *name)
392 {
393   GimpGradient *gradient;
394 
395   g_return_val_if_fail (name != NULL, NULL);
396   g_return_val_if_fail (*name != '\0', NULL);
397 
398   gradient = g_object_new (GIMP_TYPE_GRADIENT,
399                            "name", name,
400                            NULL);
401 
402   gradient->segments = gimp_gradient_segment_new ();
403 
404   return GIMP_DATA (gradient);
405 }
406 
407 GimpData *
gimp_gradient_get_standard(GimpContext * context)408 gimp_gradient_get_standard (GimpContext *context)
409 {
410   static GimpData *standard_gradient = NULL;
411 
412   if (! standard_gradient)
413     {
414       standard_gradient = gimp_gradient_new (context, "Standard");
415 
416       gimp_data_clean (standard_gradient);
417       gimp_data_make_internal (standard_gradient, "gimp-gradient-standard");
418 
419       g_object_add_weak_pointer (G_OBJECT (standard_gradient),
420                                  (gpointer *) &standard_gradient);
421     }
422 
423   return standard_gradient;
424 }
425 
426 static const gchar *
gimp_gradient_get_extension(GimpData * data)427 gimp_gradient_get_extension (GimpData *data)
428 {
429   return GIMP_GRADIENT_FILE_EXTENSION;
430 }
431 
432 /**
433  * gimp_gradient_get_color_at:
434  * @gradient:          a gradient
435  * @context:           a context
436  * @seg:               a segment to seed the search with (or %NULL)
437  * @pos:               position in the gradient (between 0.0 and 1.0)
438  * @reverse:           when %TRUE, use the reversed gradient
439  * @blend_color_space: color space to use for blending RGB segments
440  * @color:             returns the color
441  *
442  * If you are iterating over an gradient, you should pass the the
443  * return value from the last call for @seg.
444  *
445  * Return value: the gradient segment the color is from
446  **/
447 GimpGradientSegment *
gimp_gradient_get_color_at(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * seg,gdouble pos,gboolean reverse,GimpGradientBlendColorSpace blend_color_space,GimpRGB * color)448 gimp_gradient_get_color_at (GimpGradient                *gradient,
449                             GimpContext                 *context,
450                             GimpGradientSegment         *seg,
451                             gdouble                      pos,
452                             gboolean                     reverse,
453                             GimpGradientBlendColorSpace  blend_color_space,
454                             GimpRGB                     *color)
455 {
456   gdouble  factor = 0.0;
457   gdouble  seg_len;
458   gdouble  middle;
459   GimpRGB  left_color;
460   GimpRGB  right_color;
461   GimpRGB  rgb;
462 
463   /* type-check disabled to improve speed */
464   /* g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL); */
465   g_return_val_if_fail (color != NULL, NULL);
466 
467   pos = CLAMP (pos, 0.0, 1.0);
468 
469   if (reverse)
470     pos = 1.0 - pos;
471 
472   seg = gimp_gradient_get_segment_at_internal (gradient, seg, pos);
473 
474   seg_len = seg->right - seg->left;
475 
476   if (seg_len < EPSILON)
477     {
478       middle = 0.5;
479       pos    = 0.5;
480     }
481   else
482     {
483       middle = (seg->middle - seg->left) / seg_len;
484       pos    = (pos - seg->left) / seg_len;
485     }
486 
487   switch (seg->type)
488     {
489     case GIMP_GRADIENT_SEGMENT_LINEAR:
490       factor = gimp_gradient_calc_linear_factor (middle, pos);
491       break;
492 
493     case GIMP_GRADIENT_SEGMENT_CURVED:
494       factor = gimp_gradient_calc_curved_factor (middle, pos);
495       break;
496 
497     case GIMP_GRADIENT_SEGMENT_SINE:
498       factor = gimp_gradient_calc_sine_factor (middle, pos);
499       break;
500 
501     case GIMP_GRADIENT_SEGMENT_SPHERE_INCREASING:
502       factor = gimp_gradient_calc_sphere_increasing_factor (middle, pos);
503       break;
504 
505     case GIMP_GRADIENT_SEGMENT_SPHERE_DECREASING:
506       factor = gimp_gradient_calc_sphere_decreasing_factor (middle, pos);
507       break;
508 
509     case GIMP_GRADIENT_SEGMENT_STEP:
510       factor = gimp_gradient_calc_step_factor (middle, pos);
511       break;
512 
513     default:
514       g_warning ("%s: Unknown gradient type %d.", G_STRFUNC, seg->type);
515       break;
516     }
517 
518   /* Get left/right colors */
519 
520   if (context)
521     {
522       gimp_gradient_segment_get_left_flat_color (gradient,
523                                                  context, seg, &left_color);
524 
525       gimp_gradient_segment_get_right_flat_color (gradient,
526                                                   context, seg, &right_color);
527     }
528   else
529     {
530       left_color  = seg->left_color;
531       right_color = seg->right_color;
532     }
533 
534   /* Calculate color components */
535 
536   if (seg->color == GIMP_GRADIENT_SEGMENT_RGB)
537     {
538       switch (blend_color_space)
539         {
540         case GIMP_GRADIENT_BLEND_CIE_LAB:
541           babl_process (fish_srgb_to_cie_lab,
542                         &left_color, &left_color, 1);
543           babl_process (fish_srgb_to_cie_lab,
544                         &right_color, &right_color, 1);
545           break;
546 
547         case GIMP_GRADIENT_BLEND_RGB_LINEAR:
548           babl_process (fish_srgb_to_linear_rgb,
549                         &left_color, &left_color, 1);
550           babl_process (fish_srgb_to_linear_rgb,
551                         &right_color, &right_color, 1);
552 
553         case GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL:
554           break;
555         }
556 
557       rgb.r = left_color.r + (right_color.r - left_color.r) * factor;
558       rgb.g = left_color.g + (right_color.g - left_color.g) * factor;
559       rgb.b = left_color.b + (right_color.b - left_color.b) * factor;
560 
561       switch (blend_color_space)
562         {
563         case GIMP_GRADIENT_BLEND_CIE_LAB:
564           babl_process (fish_cie_lab_to_srgb,
565                         &rgb, &rgb, 1);
566           break;
567 
568         case GIMP_GRADIENT_BLEND_RGB_LINEAR:
569           babl_process (fish_linear_rgb_to_srgb,
570                         &rgb, &rgb, 1);
571 
572         case GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL:
573           break;
574         }
575     }
576   else
577     {
578       GimpHSV left_hsv;
579       GimpHSV right_hsv;
580 
581       gimp_rgb_to_hsv (&left_color,  &left_hsv);
582       gimp_rgb_to_hsv (&right_color, &right_hsv);
583 
584       left_hsv.s = left_hsv.s + (right_hsv.s - left_hsv.s) * factor;
585       left_hsv.v = left_hsv.v + (right_hsv.v - left_hsv.v) * factor;
586 
587       switch (seg->color)
588         {
589         case GIMP_GRADIENT_SEGMENT_HSV_CCW:
590           if (left_hsv.h < right_hsv.h)
591             {
592               left_hsv.h += (right_hsv.h - left_hsv.h) * factor;
593             }
594           else
595             {
596               left_hsv.h += (1.0 - (left_hsv.h - right_hsv.h)) * factor;
597 
598               if (left_hsv.h > 1.0)
599                 left_hsv.h -= 1.0;
600             }
601           break;
602 
603         case GIMP_GRADIENT_SEGMENT_HSV_CW:
604           if (right_hsv.h < left_hsv.h)
605             {
606               left_hsv.h -= (left_hsv.h - right_hsv.h) * factor;
607             }
608           else
609             {
610               left_hsv.h -= (1.0 - (right_hsv.h - left_hsv.h)) * factor;
611 
612               if (left_hsv.h < 0.0)
613                 left_hsv.h += 1.0;
614             }
615           break;
616 
617         default:
618           g_warning ("%s: Unknown coloring mode %d",
619                      G_STRFUNC, (gint) seg->color);
620           break;
621         }
622 
623       gimp_hsv_to_rgb (&left_hsv, &rgb);
624     }
625 
626   /* Calculate alpha */
627 
628   rgb.a = left_color.a + (right_color.a - left_color.a) * factor;
629 
630   *color = rgb;
631 
632   return seg;
633 }
634 
635 GimpGradientSegment *
gimp_gradient_get_segment_at(GimpGradient * gradient,gdouble pos)636 gimp_gradient_get_segment_at (GimpGradient *gradient,
637                               gdouble       pos)
638 {
639   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL);
640 
641   return gimp_gradient_get_segment_at_internal (gradient, NULL, pos);
642 }
643 
644 gboolean
gimp_gradient_has_fg_bg_segments(GimpGradient * gradient)645 gimp_gradient_has_fg_bg_segments (GimpGradient *gradient)
646 {
647   GimpGradientSegment *segment;
648 
649   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), FALSE);
650 
651   for (segment = gradient->segments; segment; segment = segment->next)
652     if (segment->left_color_type  != GIMP_GRADIENT_COLOR_FIXED ||
653         segment->right_color_type != GIMP_GRADIENT_COLOR_FIXED)
654       return TRUE;
655 
656   return FALSE;
657 }
658 
659 void
gimp_gradient_split_at(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * seg,gdouble pos,GimpGradientBlendColorSpace blend_color_space,GimpGradientSegment ** newl,GimpGradientSegment ** newr)660 gimp_gradient_split_at (GimpGradient                 *gradient,
661                         GimpContext                  *context,
662                         GimpGradientSegment          *seg,
663                         gdouble                       pos,
664                         GimpGradientBlendColorSpace   blend_color_space,
665                         GimpGradientSegment         **newl,
666                         GimpGradientSegment         **newr)
667 {
668   GimpRGB              color;
669   GimpGradientSegment *newseg;
670 
671   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
672   g_return_if_fail (GIMP_IS_CONTEXT (context));
673 
674   gimp_data_freeze (GIMP_DATA (gradient));
675 
676   pos = CLAMP (pos, 0.0, 1.0);
677   seg = gimp_gradient_get_segment_at_internal (gradient, seg, pos);
678 
679   /* Get color at pos */
680   gimp_gradient_get_color_at (gradient, context, seg, pos,
681                               FALSE, blend_color_space, &color);
682 
683   /* Create a new segment and insert it in the list */
684 
685   newseg = gimp_gradient_segment_new ();
686 
687   newseg->prev = seg;
688   newseg->next = seg->next;
689 
690   seg->next = newseg;
691 
692   if (newseg->next)
693     newseg->next->prev = newseg;
694 
695   /* Set coordinates of new segment */
696 
697   newseg->left   = pos;
698   newseg->right  = seg->right;
699   newseg->middle = (newseg->left + newseg->right) / 2.0;
700 
701   /* Set coordinates of original segment */
702 
703   seg->right  = newseg->left;
704   seg->middle = (seg->left + seg->right) / 2.0;
705 
706   /* Set colors of both segments */
707 
708   newseg->right_color_type = seg->right_color_type;
709   newseg->right_color      = seg->right_color;
710 
711   seg->right_color_type = newseg->left_color_type = GIMP_GRADIENT_COLOR_FIXED;
712   seg->right_color      = newseg->left_color      = color;
713 
714   /* Set parameters of new segment */
715 
716   newseg->type  = seg->type;
717   newseg->color = seg->color;
718 
719   /* Done */
720 
721   if (newl) *newl = seg;
722   if (newr) *newr = newseg;
723 
724   gimp_data_thaw (GIMP_DATA (gradient));
725 }
726 
727 GimpGradient *
gimp_gradient_flatten(GimpGradient * gradient,GimpContext * context)728 gimp_gradient_flatten (GimpGradient *gradient,
729                        GimpContext  *context)
730 {
731   GimpGradient        *flat;
732   GimpGradientSegment *seg;
733 
734   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), NULL);
735   g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
736 
737   flat = GIMP_GRADIENT (gimp_data_duplicate (GIMP_DATA (gradient)));
738 
739   for (seg = flat->segments; seg; seg = seg->next)
740     {
741       gimp_gradient_segment_get_left_flat_color (gradient,
742                                                  context, seg,
743                                                  &seg->left_color);
744 
745       seg->left_color_type = GIMP_GRADIENT_COLOR_FIXED;
746 
747       gimp_gradient_segment_get_right_flat_color (gradient,
748                                                   context, seg,
749                                                   &seg->right_color);
750 
751       seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED;
752     }
753 
754   return flat;
755 }
756 
757 
758 /*  gradient segment functions  */
759 
760 GimpGradientSegment *
gimp_gradient_segment_new(void)761 gimp_gradient_segment_new (void)
762 {
763   GimpGradientSegment *seg;
764 
765   seg = g_slice_new0 (GimpGradientSegment);
766 
767   seg->left   = 0.0;
768   seg->middle = 0.5;
769   seg->right  = 1.0;
770 
771   seg->left_color_type = GIMP_GRADIENT_COLOR_FIXED;
772   gimp_rgba_set (&seg->left_color,  0.0, 0.0, 0.0, 1.0);
773 
774   seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED;
775   gimp_rgba_set (&seg->right_color, 1.0, 1.0, 1.0, 1.0);
776 
777   seg->type  = GIMP_GRADIENT_SEGMENT_LINEAR;
778   seg->color = GIMP_GRADIENT_SEGMENT_RGB;
779 
780   seg->prev = seg->next = NULL;
781 
782   return seg;
783 }
784 
785 
786 void
gimp_gradient_segment_free(GimpGradientSegment * seg)787 gimp_gradient_segment_free (GimpGradientSegment *seg)
788 {
789   g_return_if_fail (seg != NULL);
790 
791   g_slice_free (GimpGradientSegment, seg);
792 }
793 
794 void
gimp_gradient_segments_free(GimpGradientSegment * seg)795 gimp_gradient_segments_free (GimpGradientSegment *seg)
796 {
797   g_return_if_fail (seg != NULL);
798 
799   g_slice_free_chain (GimpGradientSegment, seg, next);
800 }
801 
802 GimpGradientSegment *
gimp_gradient_segment_get_last(GimpGradientSegment * seg)803 gimp_gradient_segment_get_last (GimpGradientSegment *seg)
804 {
805   if (! seg)
806     return NULL;
807 
808   while (seg->next)
809     seg = seg->next;
810 
811   return seg;
812 }
813 
814 GimpGradientSegment *
gimp_gradient_segment_get_first(GimpGradientSegment * seg)815 gimp_gradient_segment_get_first (GimpGradientSegment *seg)
816 {
817   if (! seg)
818     return NULL;
819 
820   while (seg->prev)
821     seg = seg->prev;
822 
823   return seg;
824 }
825 
826 GimpGradientSegment *
gimp_gradient_segment_get_nth(GimpGradientSegment * seg,gint index)827 gimp_gradient_segment_get_nth (GimpGradientSegment *seg,
828                                gint                 index)
829 {
830   gint i = 0;
831 
832   g_return_val_if_fail (index >= 0, NULL);
833 
834   if (! seg)
835     return NULL;
836 
837   while (seg && (i < index))
838     {
839       seg = seg->next;
840       i++;
841     }
842 
843   if (i == index)
844     return seg;
845 
846   return NULL;
847 }
848 
849 void
gimp_gradient_segment_split_midpoint(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * lseg,GimpGradientBlendColorSpace blend_color_space,GimpGradientSegment ** newl,GimpGradientSegment ** newr)850 gimp_gradient_segment_split_midpoint (GimpGradient                 *gradient,
851                                       GimpContext                  *context,
852                                       GimpGradientSegment          *lseg,
853                                       GimpGradientBlendColorSpace   blend_color_space,
854                                       GimpGradientSegment         **newl,
855                                       GimpGradientSegment         **newr)
856 {
857   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
858   g_return_if_fail (GIMP_IS_CONTEXT (context));
859   g_return_if_fail (lseg != NULL);
860   g_return_if_fail (newl != NULL);
861   g_return_if_fail (newr != NULL);
862 
863   gimp_gradient_split_at (gradient, context, lseg, lseg->middle,
864                           blend_color_space, newl, newr);
865 }
866 
867 void
gimp_gradient_segment_split_uniform(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * lseg,gint parts,GimpGradientBlendColorSpace blend_color_space,GimpGradientSegment ** newl,GimpGradientSegment ** newr)868 gimp_gradient_segment_split_uniform (GimpGradient                 *gradient,
869                                      GimpContext                  *context,
870                                      GimpGradientSegment          *lseg,
871                                      gint                          parts,
872                                      GimpGradientBlendColorSpace   blend_color_space,
873                                      GimpGradientSegment         **newl,
874                                      GimpGradientSegment         **newr)
875 {
876   GimpGradientSegment *seg, *prev, *tmp;
877   gdouble              seg_len;
878   gint                 i;
879 
880   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
881   g_return_if_fail (GIMP_IS_CONTEXT (context));
882   g_return_if_fail (lseg != NULL);
883   g_return_if_fail (newl != NULL);
884   g_return_if_fail (newr != NULL);
885 
886   gimp_data_freeze (GIMP_DATA (gradient));
887 
888   seg_len = (lseg->right - lseg->left) / parts; /* Length of divisions */
889 
890   seg  = NULL;
891   prev = NULL;
892   tmp  = NULL;
893 
894   for (i = 0; i < parts; i++)
895     {
896       seg = gimp_gradient_segment_new ();
897 
898       if (i == 0)
899         tmp = seg; /* Remember first segment */
900 
901       seg->left   = lseg->left + i * seg_len;
902       seg->right  = lseg->left + (i + 1) * seg_len;
903       seg->middle = (seg->left + seg->right) / 2.0;
904 
905       seg->left_color_type  = GIMP_GRADIENT_COLOR_FIXED;
906       seg->right_color_type = GIMP_GRADIENT_COLOR_FIXED;
907 
908       gimp_gradient_get_color_at (gradient, context, lseg,
909                                   seg->left,  FALSE, blend_color_space,
910                                   &seg->left_color);
911       gimp_gradient_get_color_at (gradient, context, lseg,
912                                   seg->right, FALSE, blend_color_space,
913                                   &seg->right_color);
914 
915       seg->type  = lseg->type;
916       seg->color = lseg->color;
917 
918       seg->prev = prev;
919       seg->next = NULL;
920 
921       if (prev)
922         prev->next = seg;
923 
924       prev = seg;
925     }
926 
927   /* Fix edges */
928 
929   tmp->left_color_type = lseg->left_color_type;
930   tmp->left_color      = lseg->left_color;
931 
932   seg->right_color_type = lseg->right_color_type;
933   seg->right_color      = lseg->right_color;
934 
935   tmp->left  = lseg->left;
936   seg->right = lseg->right; /* To squish accumulative error */
937 
938   /* Link in list */
939 
940   tmp->prev = lseg->prev;
941   seg->next = lseg->next;
942 
943   if (lseg->prev)
944     lseg->prev->next = tmp;
945   else
946     gradient->segments = tmp; /* We are on leftmost segment */
947 
948   if (lseg->next)
949     lseg->next->prev = seg;
950 
951   /* Done */
952   *newl = tmp;
953   *newr = seg;
954 
955   /* Delete old segment */
956   gimp_gradient_segment_free (lseg);
957 
958   gimp_data_thaw (GIMP_DATA (gradient));
959 }
960 
961 void
gimp_gradient_segment_get_left_color(GimpGradient * gradient,GimpGradientSegment * seg,GimpRGB * color)962 gimp_gradient_segment_get_left_color (GimpGradient        *gradient,
963                                       GimpGradientSegment *seg,
964                                       GimpRGB             *color)
965 {
966   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
967   g_return_if_fail (seg != NULL);
968   g_return_if_fail (color != NULL);
969 
970   *color = seg->left_color;
971 }
972 
973 void
gimp_gradient_segment_set_left_color(GimpGradient * gradient,GimpGradientSegment * seg,const GimpRGB * color)974 gimp_gradient_segment_set_left_color (GimpGradient        *gradient,
975                                       GimpGradientSegment *seg,
976                                       const GimpRGB       *color)
977 {
978   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
979   g_return_if_fail (seg != NULL);
980   g_return_if_fail (color != NULL);
981 
982   gimp_data_freeze (GIMP_DATA (gradient));
983 
984   gimp_gradient_segment_range_blend (gradient, seg, seg,
985                                      color, &seg->right_color,
986                                      TRUE, TRUE);
987 
988   gimp_data_thaw (GIMP_DATA (gradient));
989 }
990 
991 void
gimp_gradient_segment_get_right_color(GimpGradient * gradient,GimpGradientSegment * seg,GimpRGB * color)992 gimp_gradient_segment_get_right_color (GimpGradient        *gradient,
993                                        GimpGradientSegment *seg,
994                                        GimpRGB             *color)
995 {
996   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
997   g_return_if_fail (seg != NULL);
998   g_return_if_fail (color != NULL);
999 
1000   *color = seg->right_color;
1001 }
1002 
1003 void
gimp_gradient_segment_set_right_color(GimpGradient * gradient,GimpGradientSegment * seg,const GimpRGB * color)1004 gimp_gradient_segment_set_right_color (GimpGradient        *gradient,
1005                                        GimpGradientSegment *seg,
1006                                        const GimpRGB       *color)
1007 {
1008   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1009   g_return_if_fail (seg != NULL);
1010   g_return_if_fail (color != NULL);
1011 
1012   gimp_data_freeze (GIMP_DATA (gradient));
1013 
1014   gimp_gradient_segment_range_blend (gradient, seg, seg,
1015                                      &seg->left_color, color,
1016                                      TRUE, TRUE);
1017 
1018   gimp_data_thaw (GIMP_DATA (gradient));
1019 }
1020 
1021 GimpGradientColor
gimp_gradient_segment_get_left_color_type(GimpGradient * gradient,GimpGradientSegment * seg)1022 gimp_gradient_segment_get_left_color_type (GimpGradient        *gradient,
1023                                            GimpGradientSegment *seg)
1024 {
1025   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0);
1026   g_return_val_if_fail (seg != NULL, 0);
1027 
1028   return seg->left_color_type;
1029 }
1030 
1031 void
gimp_gradient_segment_set_left_color_type(GimpGradient * gradient,GimpGradientSegment * seg,GimpGradientColor color_type)1032 gimp_gradient_segment_set_left_color_type (GimpGradient        *gradient,
1033                                            GimpGradientSegment *seg,
1034                                            GimpGradientColor    color_type)
1035 {
1036   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1037   g_return_if_fail (seg != NULL);
1038 
1039   gimp_data_freeze (GIMP_DATA (gradient));
1040 
1041   seg->left_color_type = color_type;
1042 
1043   gimp_data_thaw (GIMP_DATA (gradient));
1044 }
1045 
1046 GimpGradientColor
gimp_gradient_segment_get_right_color_type(GimpGradient * gradient,GimpGradientSegment * seg)1047 gimp_gradient_segment_get_right_color_type (GimpGradient        *gradient,
1048                                             GimpGradientSegment *seg)
1049 {
1050   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0);
1051   g_return_val_if_fail (seg != NULL, 0);
1052 
1053   return seg->right_color_type;
1054 }
1055 
1056 void
gimp_gradient_segment_set_right_color_type(GimpGradient * gradient,GimpGradientSegment * seg,GimpGradientColor color_type)1057 gimp_gradient_segment_set_right_color_type (GimpGradient        *gradient,
1058                                             GimpGradientSegment *seg,
1059                                             GimpGradientColor    color_type)
1060 {
1061   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1062   g_return_if_fail (seg != NULL);
1063 
1064   gimp_data_freeze (GIMP_DATA (gradient));
1065 
1066   seg->right_color_type = color_type;
1067 
1068   gimp_data_thaw (GIMP_DATA (gradient));
1069 }
1070 
1071 void
gimp_gradient_segment_get_left_flat_color(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * seg,GimpRGB * color)1072 gimp_gradient_segment_get_left_flat_color (GimpGradient        *gradient,
1073                                            GimpContext         *context,
1074                                            GimpGradientSegment *seg,
1075                                            GimpRGB             *color)
1076 {
1077   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1078   g_return_if_fail (seg != NULL);
1079   g_return_if_fail (color != NULL);
1080 
1081   gimp_gradient_get_flat_color (context,
1082                                 &seg->left_color, seg->left_color_type,
1083                                 color);
1084 }
1085 
1086 void
gimp_gradient_segment_get_right_flat_color(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * seg,GimpRGB * color)1087 gimp_gradient_segment_get_right_flat_color (GimpGradient        *gradient,
1088                                             GimpContext         *context,
1089                                             GimpGradientSegment *seg,
1090                                             GimpRGB             *color)
1091 {
1092   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1093   g_return_if_fail (seg != NULL);
1094   g_return_if_fail (color != NULL);
1095 
1096   gimp_gradient_get_flat_color (context,
1097                                 &seg->right_color, seg->right_color_type,
1098                                 color);
1099 }
1100 
1101 gdouble
gimp_gradient_segment_get_left_pos(GimpGradient * gradient,GimpGradientSegment * seg)1102 gimp_gradient_segment_get_left_pos (GimpGradient        *gradient,
1103                                     GimpGradientSegment *seg)
1104 {
1105   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1106   g_return_val_if_fail (seg != NULL, 0.0);
1107 
1108   return seg->left;
1109 }
1110 
1111 gdouble
gimp_gradient_segment_set_left_pos(GimpGradient * gradient,GimpGradientSegment * seg,gdouble pos)1112 gimp_gradient_segment_set_left_pos (GimpGradient        *gradient,
1113                                     GimpGradientSegment *seg,
1114                                     gdouble              pos)
1115 {
1116   gdouble final_pos;
1117 
1118   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1119   g_return_val_if_fail (seg != NULL, 0.0);
1120 
1121   if (seg->prev == NULL)
1122     {
1123       final_pos = 0;
1124     }
1125   else
1126     {
1127       gimp_data_freeze (GIMP_DATA (gradient));
1128 
1129       final_pos = seg->prev->right = seg->left =
1130           CLAMP (pos,
1131                  seg->prev->middle + EPSILON,
1132                  seg->middle - EPSILON);
1133 
1134       gimp_data_thaw (GIMP_DATA (gradient));
1135     }
1136 
1137   return final_pos;
1138 }
1139 
1140 gdouble
gimp_gradient_segment_get_right_pos(GimpGradient * gradient,GimpGradientSegment * seg)1141 gimp_gradient_segment_get_right_pos (GimpGradient        *gradient,
1142                                      GimpGradientSegment *seg)
1143 {
1144   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1145   g_return_val_if_fail (seg != NULL, 0.0);
1146 
1147   return seg->right;
1148 }
1149 
1150 gdouble
gimp_gradient_segment_set_right_pos(GimpGradient * gradient,GimpGradientSegment * seg,gdouble pos)1151 gimp_gradient_segment_set_right_pos (GimpGradient        *gradient,
1152                                      GimpGradientSegment *seg,
1153                                      gdouble              pos)
1154 {
1155   gdouble final_pos;
1156 
1157   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1158   g_return_val_if_fail (seg != NULL, 0.0);
1159 
1160   if (seg->next == NULL)
1161     {
1162       final_pos = 1.0;
1163     }
1164   else
1165     {
1166       gimp_data_freeze (GIMP_DATA (gradient));
1167 
1168       final_pos = seg->next->left = seg->right =
1169           CLAMP (pos,
1170                  seg->middle + EPSILON,
1171                  seg->next->middle - EPSILON);
1172 
1173       gimp_data_thaw (GIMP_DATA (gradient));
1174     }
1175 
1176   return final_pos;
1177 }
1178 
1179 gdouble
gimp_gradient_segment_get_middle_pos(GimpGradient * gradient,GimpGradientSegment * seg)1180 gimp_gradient_segment_get_middle_pos (GimpGradient        *gradient,
1181                                       GimpGradientSegment *seg)
1182 {
1183   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1184   g_return_val_if_fail (seg != NULL, 0.0);
1185 
1186   return seg->middle;
1187 }
1188 
1189 gdouble
gimp_gradient_segment_set_middle_pos(GimpGradient * gradient,GimpGradientSegment * seg,gdouble pos)1190 gimp_gradient_segment_set_middle_pos (GimpGradient        *gradient,
1191                                       GimpGradientSegment *seg,
1192                                       gdouble              pos)
1193 {
1194   gdouble final_pos;
1195 
1196   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
1197   g_return_val_if_fail (seg != NULL, 0.0);
1198 
1199   gimp_data_freeze (GIMP_DATA (gradient));
1200 
1201   final_pos = seg->middle =
1202       CLAMP (pos,
1203              seg->left + EPSILON,
1204              seg->right - EPSILON);
1205 
1206   gimp_data_thaw (GIMP_DATA (gradient));
1207 
1208   return final_pos;
1209 }
1210 
1211 GimpGradientSegmentType
gimp_gradient_segment_get_blending_function(GimpGradient * gradient,GimpGradientSegment * seg)1212 gimp_gradient_segment_get_blending_function (GimpGradient        *gradient,
1213                                              GimpGradientSegment *seg)
1214 {
1215   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0);
1216 
1217   return seg->type;
1218 }
1219 
1220 GimpGradientSegmentColor
gimp_gradient_segment_get_coloring_type(GimpGradient * gradient,GimpGradientSegment * seg)1221 gimp_gradient_segment_get_coloring_type (GimpGradient        *gradient,
1222                                          GimpGradientSegment *seg)
1223 {
1224   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0);
1225 
1226   return seg->color;
1227 }
1228 
1229 gint
gimp_gradient_segment_range_get_n_segments(GimpGradient * gradient,GimpGradientSegment * range_l,GimpGradientSegment * range_r)1230 gimp_gradient_segment_range_get_n_segments (GimpGradient        *gradient,
1231                                             GimpGradientSegment *range_l,
1232                                             GimpGradientSegment *range_r)
1233 {
1234   gint n_segments = 0;
1235 
1236   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0);
1237   g_return_val_if_fail (range_l != NULL, 0);
1238 
1239   for (; range_l != range_r; range_l = range_l->next)
1240     n_segments++;
1241 
1242   if (range_r != NULL)
1243     n_segments++;
1244 
1245   return n_segments;
1246 }
1247 
1248 void
gimp_gradient_segment_range_compress(GimpGradient * gradient,GimpGradientSegment * range_l,GimpGradientSegment * range_r,gdouble new_l,gdouble new_r)1249 gimp_gradient_segment_range_compress (GimpGradient        *gradient,
1250                                       GimpGradientSegment *range_l,
1251                                       GimpGradientSegment *range_r,
1252                                       gdouble              new_l,
1253                                       gdouble              new_r)
1254 {
1255   gdouble              orig_l, orig_r;
1256   GimpGradientSegment *seg, *aseg;
1257 
1258   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1259   g_return_if_fail (range_l != NULL);
1260 
1261   gimp_data_freeze (GIMP_DATA (gradient));
1262 
1263   if (! range_r)
1264     range_r = gimp_gradient_segment_get_last (range_l);
1265 
1266   orig_l = range_l->left;
1267   orig_r = range_r->right;
1268 
1269   if (orig_r - orig_l > EPSILON)
1270     {
1271       gdouble scale;
1272 
1273       scale = (new_r - new_l) / (orig_r - orig_l);
1274 
1275       seg = range_l;
1276 
1277       do
1278         {
1279           if (seg->prev)
1280             seg->left  = new_l + (seg->left - orig_l) * scale;
1281           seg->middle  = new_l + (seg->middle - orig_l) * scale;
1282           if (seg->next)
1283             seg->right = new_l + (seg->right - orig_l) * scale;
1284 
1285           /* Next */
1286 
1287           aseg = seg;
1288           seg  = seg->next;
1289         }
1290       while (aseg != range_r);
1291     }
1292   else
1293     {
1294       gint n;
1295       gint i;
1296 
1297       n = gimp_gradient_segment_range_get_n_segments (gradient,
1298                                                       range_l, range_r);
1299 
1300       for (i = 0, seg = range_l; i < n; i++, seg = seg->next)
1301         {
1302           if (seg->prev)
1303             seg->left  = new_l + (new_r - new_l) * (i + 0.0) / n;
1304           seg->middle  = new_l + (new_r - new_l) * (i + 0.5) / n;;
1305           if (seg->next)
1306             seg->right = new_l + (new_r - new_l) * (i + 1.0) / n;
1307         }
1308     }
1309 
1310   /* Make sure that the left and right endpoints of the range are *exactly*
1311    * equal to new_l and new_r; the above computations can introduce
1312    * numerical inaccuracies.
1313    */
1314 
1315   range_l->left  = new_l;
1316   range_l->right = new_r;
1317 
1318   gimp_data_thaw (GIMP_DATA (gradient));
1319 }
1320 
1321 void
gimp_gradient_segment_range_blend(GimpGradient * gradient,GimpGradientSegment * lseg,GimpGradientSegment * rseg,const GimpRGB * rgb1,const GimpRGB * rgb2,gboolean blend_colors,gboolean blend_opacity)1322 gimp_gradient_segment_range_blend (GimpGradient        *gradient,
1323                                    GimpGradientSegment *lseg,
1324                                    GimpGradientSegment *rseg,
1325                                    const GimpRGB       *rgb1,
1326                                    const GimpRGB       *rgb2,
1327                                    gboolean             blend_colors,
1328                                    gboolean             blend_opacity)
1329 {
1330   GimpRGB              d;
1331   gdouble              left, len;
1332   GimpGradientSegment *seg;
1333   GimpGradientSegment *aseg;
1334 
1335   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1336   g_return_if_fail (lseg != NULL);
1337 
1338   gimp_data_freeze (GIMP_DATA (gradient));
1339 
1340   if (! rseg)
1341     rseg = gimp_gradient_segment_get_last (lseg);
1342 
1343   d.r = rgb2->r - rgb1->r;
1344   d.g = rgb2->g - rgb1->g;
1345   d.b = rgb2->b - rgb1->b;
1346   d.a = rgb2->a - rgb1->a;
1347 
1348   left  = lseg->left;
1349   len   = rseg->right - left;
1350 
1351   seg = lseg;
1352 
1353   do
1354     {
1355       if (blend_colors)
1356         {
1357           seg->left_color.r  = rgb1->r + (seg->left - left) / len * d.r;
1358           seg->left_color.g  = rgb1->g + (seg->left - left) / len * d.g;
1359           seg->left_color.b  = rgb1->b + (seg->left - left) / len * d.b;
1360 
1361           seg->right_color.r = rgb1->r + (seg->right - left) / len * d.r;
1362           seg->right_color.g = rgb1->g + (seg->right - left) / len * d.g;
1363           seg->right_color.b = rgb1->b + (seg->right - left) / len * d.b;
1364         }
1365 
1366       if (blend_opacity)
1367         {
1368           seg->left_color.a  = rgb1->a + (seg->left - left) / len * d.a;
1369           seg->right_color.a = rgb1->a + (seg->right - left) / len * d.a;
1370         }
1371 
1372       aseg = seg;
1373       seg = seg->next;
1374     }
1375   while (aseg != rseg);
1376   gimp_data_thaw (GIMP_DATA (gradient));
1377 
1378 }
1379 
1380 void
gimp_gradient_segment_range_set_blending_function(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientSegmentType new_type)1381 gimp_gradient_segment_range_set_blending_function (GimpGradient            *gradient,
1382                                                    GimpGradientSegment     *start_seg,
1383                                                    GimpGradientSegment     *end_seg,
1384                                                    GimpGradientSegmentType  new_type)
1385 {
1386   GimpGradientSegment *seg;
1387   gboolean             reached_last_segment = FALSE;
1388 
1389   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1390 
1391   gimp_data_freeze (GIMP_DATA (gradient));
1392 
1393   seg = start_seg;
1394   while (seg && ! reached_last_segment)
1395     {
1396       if (seg == end_seg)
1397         reached_last_segment = TRUE;
1398 
1399       seg->type = new_type;
1400       seg = seg->next;
1401     }
1402 
1403   gimp_data_thaw (GIMP_DATA (gradient));
1404 }
1405 
1406 void
gimp_gradient_segment_range_set_coloring_type(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientSegmentColor new_color)1407 gimp_gradient_segment_range_set_coloring_type (GimpGradient             *gradient,
1408                                                GimpGradientSegment      *start_seg,
1409                                                GimpGradientSegment      *end_seg,
1410                                                GimpGradientSegmentColor  new_color)
1411 {
1412   GimpGradientSegment *seg;
1413   gboolean             reached_last_segment = FALSE;
1414 
1415   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1416 
1417   gimp_data_freeze (GIMP_DATA (gradient));
1418 
1419   seg = start_seg;
1420   while (seg && ! reached_last_segment)
1421     {
1422       if (seg == end_seg)
1423         reached_last_segment = TRUE;
1424 
1425       seg->color = new_color;
1426       seg = seg->next;
1427     }
1428 
1429   gimp_data_thaw (GIMP_DATA (gradient));
1430 }
1431 
1432 void
gimp_gradient_segment_range_flip(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1433 gimp_gradient_segment_range_flip (GimpGradient         *gradient,
1434                                   GimpGradientSegment  *start_seg,
1435                                   GimpGradientSegment  *end_seg,
1436                                   GimpGradientSegment **final_start_seg,
1437                                   GimpGradientSegment **final_end_seg)
1438 {
1439   GimpGradientSegment *oseg, *oaseg;
1440   GimpGradientSegment *seg, *prev, *tmp;
1441   GimpGradientSegment *lseg, *rseg;
1442   gdouble              left, right;
1443 
1444   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1445 
1446   gimp_data_freeze (GIMP_DATA (gradient));
1447 
1448   if (! end_seg)
1449     end_seg = gimp_gradient_segment_get_last (start_seg);
1450 
1451   left  = start_seg->left;
1452   right = end_seg->right;
1453 
1454   /* Build flipped segments */
1455 
1456   prev = NULL;
1457   oseg = end_seg;
1458   tmp  = NULL;
1459 
1460   do
1461     {
1462       seg = gimp_gradient_segment_new ();
1463 
1464       if (prev == NULL)
1465         {
1466           seg->left = left;
1467           tmp = seg; /* Remember first segment */
1468         }
1469       else
1470         seg->left = left + right - oseg->right;
1471 
1472       seg->middle = left + right - oseg->middle;
1473       seg->right  = left + right - oseg->left;
1474 
1475       seg->left_color_type = oseg->right_color_type;
1476       seg->left_color      = oseg->right_color;
1477 
1478       seg->right_color_type = oseg->left_color_type;
1479       seg->right_color      = oseg->left_color;
1480 
1481       switch (oseg->type)
1482         {
1483         case GIMP_GRADIENT_SEGMENT_SPHERE_INCREASING:
1484           seg->type = GIMP_GRADIENT_SEGMENT_SPHERE_DECREASING;
1485           break;
1486 
1487         case GIMP_GRADIENT_SEGMENT_SPHERE_DECREASING:
1488           seg->type = GIMP_GRADIENT_SEGMENT_SPHERE_INCREASING;
1489           break;
1490 
1491         default:
1492           seg->type = oseg->type;
1493         }
1494 
1495       switch (oseg->color)
1496         {
1497         case GIMP_GRADIENT_SEGMENT_HSV_CCW:
1498           seg->color = GIMP_GRADIENT_SEGMENT_HSV_CW;
1499           break;
1500 
1501         case GIMP_GRADIENT_SEGMENT_HSV_CW:
1502           seg->color = GIMP_GRADIENT_SEGMENT_HSV_CCW;
1503           break;
1504 
1505         default:
1506           seg->color = oseg->color;
1507         }
1508 
1509       seg->prev = prev;
1510       seg->next = NULL;
1511 
1512       if (prev)
1513         prev->next = seg;
1514 
1515       prev = seg;
1516 
1517       oaseg = oseg;
1518       oseg  = oseg->prev; /* Move backwards! */
1519     }
1520   while (oaseg != start_seg);
1521 
1522   seg->right = right; /* Squish accumulative error */
1523 
1524   /* Free old segments */
1525 
1526   lseg = start_seg->prev;
1527   rseg = end_seg->next;
1528 
1529   oseg = start_seg;
1530 
1531   do
1532     {
1533       oaseg = oseg->next;
1534       gimp_gradient_segment_free (oseg);
1535       oseg = oaseg;
1536     }
1537   while (oaseg != rseg);
1538 
1539   /* Link in new segments */
1540 
1541   if (lseg)
1542     lseg->next = tmp;
1543   else
1544     gradient->segments = tmp;
1545 
1546   tmp->prev = lseg;
1547 
1548   seg->next = rseg;
1549 
1550   if (rseg)
1551     rseg->prev = seg;
1552 
1553   /* Reset selection */
1554 
1555   if (final_start_seg)
1556     *final_start_seg = tmp;
1557 
1558   if (final_end_seg)
1559     *final_end_seg = seg;
1560 
1561   /* Done */
1562 
1563   gimp_data_thaw (GIMP_DATA (gradient));
1564 }
1565 
1566 void
gimp_gradient_segment_range_replicate(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,gint replicate_times,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1567 gimp_gradient_segment_range_replicate (GimpGradient         *gradient,
1568                                        GimpGradientSegment  *start_seg,
1569                                        GimpGradientSegment  *end_seg,
1570                                        gint                  replicate_times,
1571                                        GimpGradientSegment **final_start_seg,
1572                                        GimpGradientSegment **final_end_seg)
1573 {
1574   gdouble              sel_left, sel_right, sel_len;
1575   gdouble              new_left;
1576   gdouble              factor;
1577   GimpGradientSegment *prev, *seg, *tmp;
1578   GimpGradientSegment *oseg, *oaseg;
1579   GimpGradientSegment *lseg, *rseg;
1580   gint                 i;
1581 
1582   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1583 
1584   if (! end_seg)
1585     end_seg = gimp_gradient_segment_get_last (start_seg);
1586 
1587   if (replicate_times < 2)
1588     {
1589       *final_start_seg = start_seg;
1590       *final_end_seg   = end_seg;
1591       return;
1592     }
1593 
1594   gimp_data_freeze (GIMP_DATA (gradient));
1595 
1596   /* Remember original parameters */
1597   sel_left  = start_seg->left;
1598   sel_right = end_seg->right;
1599   sel_len   = sel_right - sel_left;
1600 
1601   factor = 1.0 / replicate_times;
1602 
1603   /* Build replicated segments */
1604 
1605   prev = NULL;
1606   seg  = NULL;
1607   tmp  = NULL;
1608 
1609   for (i = 0; i < replicate_times; i++)
1610     {
1611       /* Build one cycle */
1612 
1613       new_left  = sel_left + i * factor * sel_len;
1614 
1615       oseg = start_seg;
1616 
1617       do
1618         {
1619           seg = gimp_gradient_segment_new ();
1620 
1621           if (prev == NULL)
1622             {
1623               seg->left = sel_left;
1624               tmp = seg; /* Remember first segment */
1625             }
1626           else
1627             {
1628               seg->left = new_left + factor * (oseg->left - sel_left);
1629             }
1630 
1631           seg->middle = new_left + factor * (oseg->middle - sel_left);
1632           seg->right  = new_left + factor * (oseg->right - sel_left);
1633 
1634           seg->left_color_type = oseg->left_color_type;
1635           seg->left_color      = oseg->left_color;
1636 
1637           seg->right_color_type = oseg->right_color_type;
1638           seg->right_color      = oseg->right_color;
1639 
1640           seg->type  = oseg->type;
1641           seg->color = oseg->color;
1642 
1643           seg->prev = prev;
1644           seg->next = NULL;
1645 
1646           if (prev)
1647             prev->next = seg;
1648 
1649           prev = seg;
1650 
1651           oaseg = oseg;
1652           oseg  = oseg->next;
1653         }
1654       while (oaseg != end_seg);
1655     }
1656 
1657   seg->right = sel_right; /* Squish accumulative error */
1658 
1659   /* Free old segments */
1660 
1661   lseg = start_seg->prev;
1662   rseg = end_seg->next;
1663 
1664   oseg = start_seg;
1665 
1666   do
1667     {
1668       oaseg = oseg->next;
1669       gimp_gradient_segment_free (oseg);
1670       oseg = oaseg;
1671     }
1672   while (oaseg != rseg);
1673 
1674   /* Link in new segments */
1675 
1676   if (lseg)
1677     lseg->next = tmp;
1678   else
1679     gradient->segments = tmp;
1680 
1681   tmp->prev = lseg;
1682 
1683   seg->next = rseg;
1684 
1685   if (rseg)
1686     rseg->prev = seg;
1687 
1688   /* Reset selection */
1689 
1690   if (final_start_seg)
1691     *final_start_seg = tmp;
1692 
1693   if (final_end_seg)
1694     *final_end_seg = seg;
1695 
1696   /* Done */
1697 
1698   gimp_data_thaw (GIMP_DATA (gradient));
1699 }
1700 
1701 void
gimp_gradient_segment_range_split_midpoint(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientBlendColorSpace blend_color_space,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1702 gimp_gradient_segment_range_split_midpoint (GimpGradient                 *gradient,
1703                                             GimpContext                  *context,
1704                                             GimpGradientSegment          *start_seg,
1705                                             GimpGradientSegment          *end_seg,
1706                                             GimpGradientBlendColorSpace   blend_color_space,
1707                                             GimpGradientSegment         **final_start_seg,
1708                                             GimpGradientSegment         **final_end_seg)
1709 {
1710   GimpGradientSegment *seg, *lseg, *rseg;
1711 
1712   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1713   g_return_if_fail (GIMP_IS_CONTEXT (context));
1714 
1715   gimp_data_freeze (GIMP_DATA (gradient));
1716 
1717   if (! end_seg)
1718     end_seg = gimp_gradient_segment_get_last (start_seg);
1719 
1720   seg = start_seg;
1721 
1722   do
1723     {
1724       gimp_gradient_segment_split_midpoint (gradient, context,
1725                                             seg, blend_color_space,
1726                                             &lseg, &rseg);
1727       seg = rseg->next;
1728     }
1729   while (lseg != end_seg);
1730 
1731   if (final_start_seg)
1732     *final_start_seg = start_seg;
1733 
1734   if (final_end_seg)
1735     *final_end_seg = rseg;
1736 
1737   gimp_data_thaw (GIMP_DATA (gradient));
1738 }
1739 
1740 void
gimp_gradient_segment_range_split_uniform(GimpGradient * gradient,GimpContext * context,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,gint parts,GimpGradientBlendColorSpace blend_color_space,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1741 gimp_gradient_segment_range_split_uniform (GimpGradient                 *gradient,
1742                                            GimpContext                  *context,
1743                                            GimpGradientSegment          *start_seg,
1744                                            GimpGradientSegment          *end_seg,
1745                                            gint                          parts,
1746                                            GimpGradientBlendColorSpace   blend_color_space,
1747                                            GimpGradientSegment         **final_start_seg,
1748                                            GimpGradientSegment         **final_end_seg)
1749 {
1750   GimpGradientSegment *seg, *aseg, *lseg, *rseg, *lsel;
1751 
1752   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1753   g_return_if_fail (GIMP_IS_CONTEXT (context));
1754 
1755   if (! end_seg)
1756     end_seg = gimp_gradient_segment_get_last (start_seg);
1757 
1758   if (parts < 2)
1759     {
1760       *final_start_seg = start_seg;
1761       *final_end_seg   = end_seg;
1762       return;
1763     }
1764 
1765   gimp_data_freeze (GIMP_DATA (gradient));
1766 
1767   seg = start_seg;
1768   lsel = NULL;
1769 
1770   do
1771     {
1772       aseg = seg;
1773 
1774       gimp_gradient_segment_split_uniform (gradient, context, seg,
1775                                            parts, blend_color_space,
1776                                            &lseg, &rseg);
1777 
1778       if (seg == start_seg)
1779         lsel = lseg;
1780 
1781       seg = rseg->next;
1782     }
1783   while (aseg != end_seg);
1784 
1785   if (final_start_seg)
1786     *final_start_seg = lsel;
1787 
1788   if (final_end_seg)
1789     *final_end_seg = rseg;
1790 
1791   gimp_data_thaw (GIMP_DATA (gradient));
1792 }
1793 
1794 void
gimp_gradient_segment_range_delete(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1795 gimp_gradient_segment_range_delete (GimpGradient         *gradient,
1796                                     GimpGradientSegment  *start_seg,
1797                                     GimpGradientSegment  *end_seg,
1798                                     GimpGradientSegment **final_start_seg,
1799                                     GimpGradientSegment **final_end_seg)
1800 {
1801   GimpGradientSegment *lseg, *rseg, *seg, *aseg, *next;
1802   gdouble              join;
1803 
1804   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1805 
1806   if (! end_seg)
1807     end_seg = gimp_gradient_segment_get_last (start_seg);
1808 
1809   /* Remember segments to the left and to the right of the selection */
1810 
1811   lseg = start_seg->prev;
1812   rseg = end_seg->next;
1813 
1814   /* Cannot delete all the segments in the gradient */
1815 
1816   if ((lseg == NULL) && (rseg == NULL))
1817     goto premature_return;
1818 
1819   gimp_data_freeze (GIMP_DATA (gradient));
1820 
1821   /* Calculate join point */
1822 
1823   join = (start_seg->left +
1824           end_seg->right) / 2.0;
1825 
1826   if (lseg == NULL)
1827     join = 0.0;
1828   else if (rseg == NULL)
1829     join = 1.0;
1830 
1831   /* Move segments */
1832 
1833   if (lseg != NULL)
1834     gimp_gradient_segment_range_compress (gradient, lseg, lseg,
1835                                           lseg->left, join);
1836 
1837   if (rseg != NULL)
1838     gimp_gradient_segment_range_compress (gradient, rseg, rseg,
1839                                           join, rseg->right);
1840 
1841   /* Link */
1842 
1843   if (lseg)
1844     lseg->next = rseg;
1845 
1846   if (rseg)
1847     rseg->prev = lseg;
1848 
1849   /* Delete old segments */
1850 
1851   seg = start_seg;
1852 
1853   do
1854     {
1855       next = seg->next;
1856       aseg = seg;
1857 
1858       gimp_gradient_segment_free (seg);
1859 
1860       seg = next;
1861     }
1862   while (aseg != end_seg);
1863 
1864   /* Change selection */
1865 
1866   if (rseg)
1867     {
1868       if (final_start_seg)
1869         *final_start_seg = rseg;
1870 
1871       if (final_end_seg)
1872         *final_end_seg = rseg;
1873     }
1874   else
1875     {
1876       if (final_start_seg)
1877         *final_start_seg = lseg;
1878 
1879       if (final_end_seg)
1880         *final_end_seg = lseg;
1881     }
1882 
1883   if (lseg == NULL)
1884     gradient->segments = rseg;
1885 
1886   gimp_data_thaw (GIMP_DATA (gradient));
1887 
1888   return;
1889 
1890  premature_return:
1891   if (final_start_seg)
1892     *final_start_seg = start_seg;
1893   if (final_end_seg)
1894     *final_end_seg = end_seg;
1895 }
1896 
1897 void
gimp_gradient_segment_range_merge(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg,GimpGradientSegment ** final_start_seg,GimpGradientSegment ** final_end_seg)1898 gimp_gradient_segment_range_merge (GimpGradient         *gradient,
1899                                    GimpGradientSegment  *start_seg,
1900                                    GimpGradientSegment  *end_seg,
1901                                    GimpGradientSegment **final_start_seg,
1902                                    GimpGradientSegment **final_end_seg)
1903 {
1904   GimpGradientSegment *seg;
1905 
1906   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1907 
1908   if (! end_seg)
1909     end_seg = gimp_gradient_segment_get_last (start_seg);
1910 
1911   gimp_data_freeze (GIMP_DATA (gradient));
1912 
1913   /* Copy the end segment's right position and color to the start segment */
1914 
1915   start_seg->right            = end_seg->right;
1916   start_seg->right_color_type = end_seg->right_color_type;
1917   start_seg->right_color      = end_seg->right_color;
1918 
1919   /* Center the start segment's midpoint */
1920 
1921   start_seg->middle = (start_seg->left + start_seg->right) / 2.0;
1922 
1923   /* Remove range segments past the start segment from the segment list */
1924 
1925   start_seg->next = end_seg->next;
1926 
1927   if (start_seg->next)
1928     start_seg->next->prev = start_seg;
1929 
1930   /* Merge the range's blend function and coloring type, and free the rest of
1931    * the segments.
1932    */
1933 
1934   seg = end_seg;
1935 
1936   while (seg != start_seg)
1937     {
1938       GimpGradientSegment *prev = seg->prev;
1939 
1940       /* If the blend function and/or coloring type aren't uniform, reset them. */
1941 
1942       if (seg->type != start_seg->type)
1943         start_seg->type = GIMP_GRADIENT_SEGMENT_LINEAR;
1944 
1945       if (seg->color != start_seg->color)
1946         start_seg->color = GIMP_GRADIENT_SEGMENT_RGB;
1947 
1948       gimp_gradient_segment_free (seg);
1949 
1950       seg = prev;
1951     }
1952 
1953   if (final_start_seg)
1954     *final_start_seg = start_seg;
1955   if (final_end_seg)
1956     *final_end_seg = start_seg;
1957 
1958   gimp_data_thaw (GIMP_DATA (gradient));
1959 }
1960 
1961 void
gimp_gradient_segment_range_recenter_handles(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg)1962 gimp_gradient_segment_range_recenter_handles (GimpGradient        *gradient,
1963                                               GimpGradientSegment *start_seg,
1964                                               GimpGradientSegment *end_seg)
1965 {
1966   GimpGradientSegment *seg, *aseg;
1967 
1968   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
1969 
1970   gimp_data_freeze (GIMP_DATA (gradient));
1971 
1972   if (! end_seg)
1973     end_seg = gimp_gradient_segment_get_last (start_seg);
1974 
1975   seg = start_seg;
1976 
1977   do
1978     {
1979       seg->middle = (seg->left + seg->right) / 2.0;
1980 
1981       aseg = seg;
1982       seg  = seg->next;
1983     }
1984   while (aseg != end_seg);
1985 
1986   gimp_data_thaw (GIMP_DATA (gradient));
1987 }
1988 
1989 void
gimp_gradient_segment_range_redistribute_handles(GimpGradient * gradient,GimpGradientSegment * start_seg,GimpGradientSegment * end_seg)1990 gimp_gradient_segment_range_redistribute_handles (GimpGradient        *gradient,
1991                                                   GimpGradientSegment *start_seg,
1992                                                   GimpGradientSegment *end_seg)
1993 {
1994   GimpGradientSegment *seg, *aseg;
1995   gdouble              left, right, seg_len;
1996   gint                 num_segs;
1997   gint                 i;
1998 
1999   g_return_if_fail (GIMP_IS_GRADIENT (gradient));
2000 
2001   gimp_data_freeze (GIMP_DATA (gradient));
2002 
2003   if (! end_seg)
2004     end_seg = gimp_gradient_segment_get_last (start_seg);
2005 
2006   /* Count number of segments in selection */
2007 
2008   num_segs = 0;
2009   seg      = start_seg;
2010 
2011   do
2012     {
2013       num_segs++;
2014       aseg = seg;
2015       seg  = seg->next;
2016     }
2017   while (aseg != end_seg);
2018 
2019   /* Calculate new segment length */
2020 
2021   left    = start_seg->left;
2022   right   = end_seg->right;
2023   seg_len = (right - left) / num_segs;
2024 
2025   /* Redistribute */
2026 
2027   seg = start_seg;
2028 
2029   for (i = 0; i < num_segs; i++)
2030     {
2031       seg->left   = left + i * seg_len;
2032       seg->right  = left + (i + 1) * seg_len;
2033       seg->middle = (seg->left + seg->right) / 2.0;
2034 
2035       seg = seg->next;
2036     }
2037 
2038   /* Fix endpoints to squish accumulative error */
2039 
2040   start_seg->left  = left;
2041   end_seg->right = right;
2042 
2043   gimp_data_thaw (GIMP_DATA (gradient));
2044 }
2045 
2046 gdouble
gimp_gradient_segment_range_move(GimpGradient * gradient,GimpGradientSegment * range_l,GimpGradientSegment * range_r,gdouble delta,gboolean control_compress)2047 gimp_gradient_segment_range_move (GimpGradient        *gradient,
2048                                   GimpGradientSegment *range_l,
2049                                   GimpGradientSegment *range_r,
2050                                   gdouble              delta,
2051                                   gboolean             control_compress)
2052 {
2053   gdouble              lbound, rbound;
2054   gint                 is_first, is_last;
2055   GimpGradientSegment *seg, *aseg;
2056 
2057   g_return_val_if_fail (GIMP_IS_GRADIENT (gradient), 0.0);
2058 
2059   gimp_data_freeze (GIMP_DATA (gradient));
2060 
2061   if (! range_r)
2062     range_r = gimp_gradient_segment_get_last (range_l);
2063 
2064   /* First or last segments in gradient? */
2065 
2066   is_first = (range_l->prev == NULL);
2067   is_last  = (range_r->next == NULL);
2068 
2069   /* Calculate drag bounds */
2070 
2071   if (! control_compress)
2072     {
2073       if (!is_first)
2074         lbound = range_l->prev->middle + EPSILON;
2075       else
2076         lbound = range_l->left + EPSILON;
2077 
2078       if (!is_last)
2079         rbound = range_r->next->middle - EPSILON;
2080       else
2081         rbound = range_r->right - EPSILON;
2082     }
2083   else
2084     {
2085       if (!is_first)
2086         lbound = range_l->prev->left + 2.0 * EPSILON;
2087       else
2088         lbound = range_l->left + EPSILON;
2089 
2090       if (!is_last)
2091         rbound = range_r->next->right - 2.0 * EPSILON;
2092       else
2093         rbound = range_r->right - EPSILON;
2094     }
2095 
2096   /* Fix the delta if necessary */
2097 
2098   if (delta < 0.0)
2099     {
2100       if (!is_first)
2101         {
2102           if (range_l->left + delta < lbound)
2103             delta = lbound - range_l->left;
2104         }
2105       else
2106         if (range_l->middle + delta < lbound)
2107           delta = lbound - range_l->middle;
2108     }
2109   else
2110     {
2111       if (!is_last)
2112         {
2113           if (range_r->right + delta > rbound)
2114             delta = rbound - range_r->right;
2115         }
2116       else
2117         if (range_r->middle + delta > rbound)
2118           delta = rbound - range_r->middle;
2119     }
2120 
2121   /* Move all the segments inside the range */
2122 
2123   seg = range_l;
2124 
2125   do
2126     {
2127       if (!((seg == range_l) && is_first))
2128         seg->left  += delta;
2129 
2130       seg->middle  += delta;
2131 
2132       if (!((seg == range_r) && is_last))
2133         seg->right += delta;
2134 
2135       /* Next */
2136 
2137       aseg = seg;
2138       seg  = seg->next;
2139     }
2140   while (aseg != range_r);
2141 
2142   /* Fix the segments that surround the range */
2143 
2144   if (!is_first)
2145     {
2146       if (! control_compress)
2147         range_l->prev->right = range_l->left;
2148       else
2149         gimp_gradient_segment_range_compress (gradient,
2150                                               range_l->prev, range_l->prev,
2151                                               range_l->prev->left, range_l->left);
2152     }
2153 
2154   if (!is_last)
2155     {
2156       if (! control_compress)
2157         range_r->next->left = range_r->right;
2158       else
2159         gimp_gradient_segment_range_compress (gradient,
2160                                               range_r->next, range_r->next,
2161                                               range_r->right, range_r->next->right);
2162     }
2163 
2164   gimp_data_thaw (GIMP_DATA (gradient));
2165 
2166   return delta;
2167 }
2168 
2169 
2170 /*  private functions  */
2171 
2172 static inline GimpGradientSegment *
gimp_gradient_get_segment_at_internal(GimpGradient * gradient,GimpGradientSegment * seg,gdouble pos)2173 gimp_gradient_get_segment_at_internal (GimpGradient        *gradient,
2174                                        GimpGradientSegment *seg,
2175                                        gdouble              pos)
2176 {
2177   /* handle FP imprecision at the edges of the gradient */
2178   pos = CLAMP (pos, 0.0, 1.0);
2179 
2180   if (! seg)
2181     seg = gradient->segments;
2182 
2183   if (pos >= seg->left)
2184     {
2185       while (seg->next && pos >= seg->right)
2186         seg = seg->next;
2187     }
2188   else
2189     {
2190       do
2191         seg = seg->prev;
2192       while (pos < seg->left);
2193     }
2194 
2195   return seg;
2196 }
2197 
2198 static void
gimp_gradient_get_flat_color(GimpContext * context,const GimpRGB * color,GimpGradientColor color_type,GimpRGB * flat_color)2199 gimp_gradient_get_flat_color (GimpContext       *context,
2200                               const GimpRGB     *color,
2201                               GimpGradientColor  color_type,
2202                               GimpRGB           *flat_color)
2203 {
2204   switch (color_type)
2205     {
2206     case GIMP_GRADIENT_COLOR_FIXED:
2207       *flat_color = *color;
2208       break;
2209 
2210     case GIMP_GRADIENT_COLOR_FOREGROUND:
2211     case GIMP_GRADIENT_COLOR_FOREGROUND_TRANSPARENT:
2212       gimp_context_get_foreground (context, flat_color);
2213 
2214       if (color_type == GIMP_GRADIENT_COLOR_FOREGROUND_TRANSPARENT)
2215         gimp_rgb_set_alpha (flat_color, 0.0);
2216       break;
2217 
2218     case GIMP_GRADIENT_COLOR_BACKGROUND:
2219     case GIMP_GRADIENT_COLOR_BACKGROUND_TRANSPARENT:
2220       gimp_context_get_background (context, flat_color);
2221 
2222       if (color_type == GIMP_GRADIENT_COLOR_BACKGROUND_TRANSPARENT)
2223         gimp_rgb_set_alpha (flat_color, 0.0);
2224       break;
2225     }
2226 }
2227 
2228 static inline gdouble
gimp_gradient_calc_linear_factor(gdouble middle,gdouble pos)2229 gimp_gradient_calc_linear_factor (gdouble middle,
2230                                   gdouble pos)
2231 {
2232   if (pos <= middle)
2233     {
2234       if (middle < EPSILON)
2235         return 0.0;
2236       else
2237         return 0.5 * pos / middle;
2238     }
2239   else
2240     {
2241       pos -= middle;
2242       middle = 1.0 - middle;
2243 
2244       if (middle < EPSILON)
2245         return 1.0;
2246       else
2247         return 0.5 + 0.5 * pos / middle;
2248     }
2249 }
2250 
2251 static inline gdouble
gimp_gradient_calc_curved_factor(gdouble middle,gdouble pos)2252 gimp_gradient_calc_curved_factor (gdouble middle,
2253                                   gdouble pos)
2254 {
2255   if (middle < EPSILON)
2256     return 1.0;
2257   else if (1.0 - middle < EPSILON)
2258     return 0.0;
2259 
2260   return exp (-G_LN2 * log (pos) / log (middle));
2261 }
2262 
2263 static inline gdouble
gimp_gradient_calc_sine_factor(gdouble middle,gdouble pos)2264 gimp_gradient_calc_sine_factor (gdouble middle,
2265                                 gdouble pos)
2266 {
2267   pos = gimp_gradient_calc_linear_factor (middle, pos);
2268 
2269   return (sin ((-G_PI / 2.0) + G_PI * pos) + 1.0) / 2.0;
2270 }
2271 
2272 static inline gdouble
gimp_gradient_calc_sphere_increasing_factor(gdouble middle,gdouble pos)2273 gimp_gradient_calc_sphere_increasing_factor (gdouble middle,
2274                                              gdouble pos)
2275 {
2276   pos = gimp_gradient_calc_linear_factor (middle, pos) - 1.0;
2277 
2278   /* Works for convex increasing and concave decreasing */
2279   return sqrt (1.0 - pos * pos);
2280 }
2281 
2282 static inline gdouble
gimp_gradient_calc_sphere_decreasing_factor(gdouble middle,gdouble pos)2283 gimp_gradient_calc_sphere_decreasing_factor (gdouble middle,
2284                                              gdouble pos)
2285 {
2286   pos = gimp_gradient_calc_linear_factor (middle, pos);
2287 
2288   /* Works for convex decreasing and concave increasing */
2289   return 1.0 - sqrt(1.0 - pos * pos);
2290 }
2291 
2292 static inline gdouble
gimp_gradient_calc_step_factor(gdouble middle,gdouble pos)2293 gimp_gradient_calc_step_factor (gdouble middle,
2294                                 gdouble pos)
2295 {
2296   return pos >= middle;
2297 }
2298