Bug Summary

File:_build/../cdk-pixbuf/pixops/pixops.c
Warning:line 1210, column 23
The left operand of '+' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name pixops.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/_build -fcoverage-compilation-dir=/rootdir/_build -resource-dir /usr/lib/llvm-21/lib/clang/21 -I cdk-pixbuf/pixops/libpixops.a.p -I cdk-pixbuf/pixops -I ../cdk-pixbuf/pixops -I . -I .. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/libmount -I /usr/include/blkid -D _FILE_OFFSET_BITS=64 -D _POSIX_C_SOURCE=200809L -D _DEFAULT_SOURCE -D _XOPEN_SOURCE=700 -D HAVE_CONFIG_H=1 -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/15/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-checker deadcode.DeadStores -analyzer-checker security.ArrayBound -analyzer-checker unix.cstring.NotNullTerminated -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2026-06-05-220802-8580-1 -x c ../cdk-pixbuf/pixops/pixops.c
1/*
2 * Copyright (C) 2000 Red Hat, Inc
3 * mediaLib integration Copyright (c) 2001-2007 Sun Microsystems, Inc.
4 * All rights reserved. (Brian Cameron, Dmitriy Demin, James Cheng,
5 * Padraig O'Briain)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 */
20#include "config.h"
21#include <math.h>
22#include <glib.h>
23
24#include "../fallback-c89.c"
25#include "pixops.h"
26
27#define SUBSAMPLE_BITS4 4
28#define SUBSAMPLE(1 << 4) (1 << SUBSAMPLE_BITS4)
29#define SUBSAMPLE_MASK((1 << 4)-1) ((1 << SUBSAMPLE_BITS4)-1)
30#define SCALE_SHIFT16 16
31
32static void
33_pixops_scale_real (guchar *dest_buf,
34 int render_x0,
35 int render_y0,
36 int render_x1,
37 int render_y1,
38 int dest_rowstride,
39 int dest_channels,
40 gboolean dest_has_alpha,
41 const guchar *src_buf,
42 int src_width,
43 int src_height,
44 int src_rowstride,
45 int src_channels,
46 gboolean src_has_alpha,
47 double scale_x,
48 double scale_y,
49 PixopsInterpType interp_type);
50
51typedef struct _PixopsFilter PixopsFilter;
52typedef struct _PixopsFilterDimension PixopsFilterDimension;
53
54struct _PixopsFilterDimension
55{
56 int n;
57 double offset;
58 double *weights;
59};
60
61struct _PixopsFilter
62{
63 PixopsFilterDimension x;
64 PixopsFilterDimension y;
65 double overall_alpha;
66};
67
68typedef guchar *(*PixopsLineFunc) (int *weights, int n_x, int n_y,
69 guchar *dest, int dest_x, guchar *dest_end,
70 int dest_channels, int dest_has_alpha,
71 guchar **src, int src_channels,
72 gboolean src_has_alpha, int x_init,
73 int x_step, int src_width, int check_size,
74 guint32 color1, guint32 color2);
75typedef void (*PixopsPixelFunc) (guchar *dest, int dest_x, int dest_channels,
76 int dest_has_alpha, int src_has_alpha,
77 int check_size, guint32 color1,
78 guint32 color2,
79 guint r, guint g, guint b, guint a);
80
81#ifdef USE_MEDIALIB
82#include <stdlib.h>
83#include <dlfcn.h>
84#include <mlib_image.h>
85
86#ifdef HAVE_STRINGS_H
87#include <strings.h>
88#endif
89
90#ifdef HAVE_STRING_H
91#include <string.h>
92#endif
93
94#if defined(HAVE_SYS_SYSTEMINFO_H)
95#include <sys/systeminfo.h>
96#elif defined(HAVE_SYS_SYSINFO_H)
97#include <sys/sysinfo.h>
98#endif
99
100static void pixops_medialib_composite (guchar *dest_buf,
101 int dest_width,
102 int dest_height,
103 int dest_rowstride,
104 int dest_channels,
105 int dest_has_alpha,
106 const guchar *src_buf,
107 int src_width,
108 int src_height,
109 int src_rowstride,
110 int src_channels,
111 int src_has_alpha,
112 int dest_x,
113 int dest_y,
114 int dest_region_width,
115 int dest_region_height,
116 double offset_x,
117 double offset_y,
118 double scale_x,
119 double scale_y,
120 PixopsInterpType interp_type,
121 int overall_alpha);
122
123static void pixops_medialib_scale (guchar *dest_buf,
124 int dest_width,
125 int dest_height,
126 int dest_rowstride,
127 int dest_channels,
128 int dest_has_alpha,
129 const guchar *src_buf,
130 int src_width,
131 int src_height,
132 int src_rowstride,
133 int src_channels,
134 int src_has_alpha,
135 int dest_x,
136 int dest_y,
137 int dest_region_width,
138 int dest_region_height,
139 double offset_x,
140 double offset_y,
141 double scale_x,
142 double scale_y,
143 PixopsInterpType interp_type);
144
145typedef struct _mlInterp mlInterp;
146
147struct _mlInterp
148{
149 double tx;
150 double ty;
151 PixopsFilter po_filter;
152 void *interp_table;
153};
154
155static gboolean medialib_initialized = FALSE(0);
156static gboolean use_medialib = TRUE(!(0));
157
158/*
159 * Sun mediaLib(tm) support.
160 *
161 * http://www.sun.com/processors/vis/mlib.html
162 *
163 */
164static void
165_pixops_use_medialib ()
166{
167 char *mlib_version_string;
168 char sys_info[257];
169 long count;
170
171 medialib_initialized = TRUE(!(0));
172
173 if (getenv ("CDK_DISABLE_MEDIALIB"))
174 {
175 use_medialib = FALSE(0);
176 return;
177 }
178
179 /*
180 * The imaging functions we want to use were added in mediaLib version 2.
181 * So turn off mediaLib support if the user has an older version.
182 * mlib_version returns a string in this format:
183 *
184 * mediaLib:0210:20011101:v8plusa
185 * ^^^^^^^^ ^^^^ ^^^^^^^^ ^^^^^^^
186 * libname vers build ISALIST identifier
187 * date (in this case sparcv8plus+vis)
188 *
189 * The first 2 digits of the version are the major version. The 3rd digit
190 * is the minor version, and the 4th digit is the micro version. So the
191 * above string corresponds to version 2.1.0. In the following test we only
192 * care about the major version.
193 */
194 mlib_version_string = mlib_version ();
195
196 count = sysinfo (SI_ARCHITECTURE, &sys_info[0], 257);
197
198 if (count != -1)
199 {
200 if (strcmp (sys_info, "i386") == 0)
201 {
202 char *mlib_target_isa = &mlib_version_string[23];
203
204 /*
205 * For x86 processors mediaLib generic C implementation
206 * does not give any performance advantage so disable it
207 */
208 if (strncmp (mlib_target_isa, "sse", 3) != 0)
209 {
210 use_medialib = FALSE(0);
211 return;
212 }
213
214 /*
215 * For x86 processors use of libumem conflicts with
216 * mediaLib, so avoid using it.
217 */
218 if (dlsym (RTLD_PROBE, "umem_alloc") != NULL((void*)0))
219 {
220 use_medialib = FALSE(0);
221 return;
222 }
223 }
224 }
225 else
226 {
227 /* Failed to get system architecture, disable mediaLib anyway */
228 use_medialib = FALSE(0);
229 return;
230 }
231}
232#endif
233
234static int
235get_check_shift (int check_size)
236{
237 int check_shift = 0;
238 g_return_val_if_fail (check_size >= 0, 4)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_19
= 0; if (check_size >= 0) _g_boolean_var_19 = 1; _g_boolean_var_19
; }), 1))) { } else { g_return_if_fail_warning (((gchar*) 0),
((const char*) (__func__)), "check_size >= 0"); return (4
); } } while (0)
;
239
240 while (!(check_size & 1))
241 {
242 check_shift++;
243 check_size >>= 1;
244 }
245
246 return check_shift;
247}
248
249static void
250pixops_scale_nearest (guchar *dest_buf,
251 int render_x0,
252 int render_y0,
253 int render_x1,
254 int render_y1,
255 int dest_rowstride,
256 int dest_channels,
257 gboolean dest_has_alpha,
258 const guchar *src_buf,
259 int src_width,
260 int src_height,
261 int src_rowstride,
262 int src_channels,
263 gboolean src_has_alpha,
264 double scale_x,
265 double scale_y)
266{
267 gint64 i;
268 gint64 x;
269 gint64 x_step = (1 << SCALE_SHIFT16) / scale_x;
270 gint64 y_step = (1 << SCALE_SHIFT16) / scale_y;
271 gint64 xmax, xstart, xstop, x_pos, y_pos;
272 const guchar *p;
273
274#define INNER_LOOP(SRC_CHANNELS,DEST_CHANNELS,ASSIGN_PIXEL) \
275 xmax = x + (render_x1 - render_x0) * x_step; \
276 xstart = MIN (0, xmax)(((0) < (xmax)) ? (0) : (xmax)); \
277 xstop = MIN (src_width << SCALE_SHIFT, xmax)(((src_width << 16) < (xmax)) ? (src_width << 16
) : (xmax))
; \
278 p = src + (CLAMP (x, xstart, xstop)(((x) > (xstop)) ? (xstop) : (((x) < (xstart)) ? (xstart
) : (x)))
>> SCALE_SHIFT16) * SRC_CHANNELS; \
279 while (x < xstart) \
280 { \
281 ASSIGN_PIXEL; \
282 dest += DEST_CHANNELS; \
283 x += x_step; \
284 } \
285 while (x < xstop) \
286 { \
287 p = src + (x >> SCALE_SHIFT16) * SRC_CHANNELS; \
288 ASSIGN_PIXEL; \
289 dest += DEST_CHANNELS; \
290 x += x_step; \
291 } \
292 x_pos = x >> SCALE_SHIFT16; \
293 p = src + CLAMP (x_pos, 0, src_width - 1)(((x_pos) > (src_width - 1)) ? (src_width - 1) : (((x_pos)
< (0)) ? (0) : (x_pos)))
* SRC_CHANNELS; \
294 while (x < xmax) \
295 { \
296 ASSIGN_PIXEL; \
297 dest += DEST_CHANNELS; \
298 x += x_step; \
299 }
300
301 for (i = 0; i < (render_y1 - render_y0); i++)
302 {
303 const guchar *src;
304 guchar *dest;
305 y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT16;
306 y_pos = CLAMP (y_pos, 0, src_height - 1)(((y_pos) > (src_height - 1)) ? (src_height - 1) : (((y_pos
) < (0)) ? (0) : (y_pos)))
;
307 src = src_buf + (gsize)y_pos * src_rowstride;
308 dest = dest_buf + (gsize)i * dest_rowstride;
309
310 x = render_x0 * x_step + x_step / 2;
311
312 if (src_channels == 3)
313 {
314 if (dest_channels == 3)
315 {
316 INNER_LOOP (3, 3, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2]);
317 }
318 else
319 {
320 INNER_LOOP (3, 4, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2];dest[3]=0xff);
321 }
322 }
323 else if (src_channels == 4)
324 {
325 if (dest_channels == 3)
326 {
327 INNER_LOOP (4, 3, dest[0]=p[0];dest[1]=p[1];dest[2]=p[2]);
328 }
329 else
330 {
331 guint32 *p32;
332 INNER_LOOP(4, 4, p32=(guint32*)dest;*p32=*((guint32*)p));
333 }
334 }
335 }
336}
337
338static void
339pixops_composite_nearest (guchar *dest_buf,
340 int render_x0,
341 int render_y0,
342 int render_x1,
343 int render_y1,
344 int dest_rowstride,
345 int dest_channels,
346 gboolean dest_has_alpha,
347 const guchar *src_buf,
348 int src_width,
349 int src_height,
350 int src_rowstride,
351 int src_channels,
352 gboolean src_has_alpha,
353 double scale_x,
354 double scale_y,
355 int overall_alpha)
356{
357 gint64 i;
358 gint64 x;
359 gint64 x_step = (1 << SCALE_SHIFT16) / scale_x;
360 gint64 y_step = (1 << SCALE_SHIFT16) / scale_y;
361 gint64 xmax, xstart, xstop, x_pos, y_pos;
362 const guchar *p;
363 unsigned int a0;
364
365 for (i = 0; i < (render_y1 - render_y0); i++)
366 {
367 const guchar *src;
368 guchar *dest;
369 y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT16;
370 y_pos = CLAMP (y_pos, 0, src_height - 1)(((y_pos) > (src_height - 1)) ? (src_height - 1) : (((y_pos
) < (0)) ? (0) : (y_pos)))
;
371 src = src_buf + (gsize)y_pos * src_rowstride;
372 dest = dest_buf + (gsize)i * dest_rowstride;
373
374 x = render_x0 * x_step + x_step / 2;
375
376 INNER_LOOP(src_channels, dest_channels,
377 if (src_has_alpha)
378 a0 = (p[3] * overall_alpha) / 0xff;
379 else
380 a0 = overall_alpha;
381
382 switch (a0)
383 {
384 case 0:
385 break;
386 case 255:
387 dest[0] = p[0];
388 dest[1] = p[1];
389 dest[2] = p[2];
390 if (dest_has_alpha)
391 dest[3] = 0xff;
392 break;
393 default:
394 if (dest_has_alpha)
395 {
396 unsigned int w0 = 0xff * a0;
397 unsigned int w1 = (0xff - a0) * dest[3];
398 unsigned int w = w0 + w1;
399
400 dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
401 dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
402 dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
403 dest[3] = w / 0xff;
404 }
405 else
406 {
407 unsigned int a1 = 0xff - a0;
408 unsigned int tmp;
409
410 tmp = a0 * p[0] + a1 * dest[0] + 0x80;
411 dest[0] = (tmp + (tmp >> 8)) >> 8;
412 tmp = a0 * p[1] + a1 * dest[1] + 0x80;
413 dest[1] = (tmp + (tmp >> 8)) >> 8;
414 tmp = a0 * p[2] + a1 * dest[2] + 0x80;
415 dest[2] = (tmp + (tmp >> 8)) >> 8;
416 }
417 break;
418 }
419 );
420 }
421}
422
423static void
424pixops_composite_nearest_noscale (guchar *dest_buf,
425 int render_x0,
426 int render_y0,
427 int render_x1,
428 int render_y1,
429 int dest_rowstride,
430 int dest_channels,
431 gboolean dest_has_alpha,
432 const guchar *src_buf,
433 int src_width,
434 int src_height,
435 int src_rowstride,
436 int src_channels,
437 gboolean src_has_alpha,
438 int overall_alpha)
439{
440 gint64 i;
441 gint64 x;
442 gint64 xmax, xstart, xstop, y_pos;
443 const guchar *p;
444 unsigned int a0;
445
446#define INNER_LOOP_NOSCALE(SRC_CHANNELS,DEST_CHANNELS,ASSIGN_PIXEL) \
447 xmax = x + (render_x1 - render_x0); \
448 xstart = MIN (0, xmax)(((0) < (xmax)) ? (0) : (xmax)); \
449 xstop = MIN (src_width, xmax)(((src_width) < (xmax)) ? (src_width) : (xmax)); \
450 p = src + CLAMP (x, xstart, xstop)(((x) > (xstop)) ? (xstop) : (((x) < (xstart)) ? (xstart
) : (x)))
* SRC_CHANNELS; \
451 while (x < xstart) \
452 { \
453 ASSIGN_PIXEL; \
454 dest += DEST_CHANNELS; \
455 x++; \
456 } \
457 p = src + x * SRC_CHANNELS; \
458 while (x < xstop) \
459 { \
460 ASSIGN_PIXEL; \
461 dest += DEST_CHANNELS; \
462 x++; \
463 p += SRC_CHANNELS; \
464 } \
465 p = src + CLAMP (x, 0, src_width - 1)(((x) > (src_width - 1)) ? (src_width - 1) : (((x) < (0
)) ? (0) : (x)))
* SRC_CHANNELS; \
466 while (x < xmax) \
467 { \
468 ASSIGN_PIXEL; \
469 dest += DEST_CHANNELS; \
470 x++; \
471 }
472
473 for (i = 0; i < (render_y1 - render_y0); i++)
474 {
475 const guchar *src;
476 guchar *dest;
477 y_pos = i + render_y0;
478 y_pos = CLAMP (y_pos, 0, src_height - 1)(((y_pos) > (src_height - 1)) ? (src_height - 1) : (((y_pos
) < (0)) ? (0) : (y_pos)))
;
479 src = src_buf + (gsize)y_pos * src_rowstride;
480 dest = dest_buf + (gsize)i * dest_rowstride;
481
482 x = render_x0;
483
484 INNER_LOOP_NOSCALE(src_channels, dest_channels,
485 if (src_has_alpha)
486 a0 = (p[3] * overall_alpha) / 0xff;
487 else
488 a0 = overall_alpha;
489
490 switch (a0)
491 {
492 case 0:
493 break;
494 case 255:
495 dest[0] = p[0];
496 dest[1] = p[1];
497 dest[2] = p[2];
498 if (dest_has_alpha)
499 dest[3] = 0xff;
500 break;
501 default:
502 if (dest_has_alpha)
503 {
504 unsigned int w0 = 0xff * a0;
505 unsigned int w1 = (0xff - a0) * dest[3];
506 unsigned int w = w0 + w1;
507
508 dest[0] = (w0 * p[0] + w1 * dest[0]) / w;
509 dest[1] = (w0 * p[1] + w1 * dest[1]) / w;
510 dest[2] = (w0 * p[2] + w1 * dest[2]) / w;
511 dest[3] = w / 0xff;
512 }
513 else
514 {
515 unsigned int a1 = 0xff - a0;
516 unsigned int tmp;
517
518 tmp = a0 * p[0] + a1 * dest[0] + 0x80;
519 dest[0] = (tmp + (tmp >> 8)) >> 8;
520 tmp = a0 * p[1] + a1 * dest[1] + 0x80;
521 dest[1] = (tmp + (tmp >> 8)) >> 8;
522 tmp = a0 * p[2] + a1 * dest[2] + 0x80;
523 dest[2] = (tmp + (tmp >> 8)) >> 8;
524 }
525 break;
526 }
527 );
528 }
529}
530#undef INNER_LOOP_NOSCALE
531
532static void
533pixops_composite_color_nearest (guchar *dest_buf,
534 int render_x0,
535 int render_y0,
536 int render_x1,
537 int render_y1,
538 int dest_rowstride,
539 int dest_channels,
540 gboolean dest_has_alpha,
541 const guchar *src_buf,
542 int src_width,
543 int src_height,
544 int src_rowstride,
545 int src_channels,
546 gboolean src_has_alpha,
547 double scale_x,
548 double scale_y,
549 int overall_alpha,
550 int check_x,
551 int check_y,
552 int check_size,
553 guint32 color1,
554 guint32 color2)
555{
556 gint64 i, j;
557 gint64 x;
558 gint64 x_step = (1 << SCALE_SHIFT16) / scale_x;
559 gint64 y_step = (1 << SCALE_SHIFT16) / scale_y;
560 int r1, g1, b1, r2, g2, b2;
561 int check_shift = get_check_shift (check_size);
562 gint64 xmax, xstart, xstop, x_pos, y_pos;
563 const guchar *p;
564 unsigned int a0;
565
566 for (i = 0; i < (render_y1 - render_y0); i++)
567 {
568 const guchar *src;
569 guchar *dest;
570 y_pos = ((i + render_y0) * y_step + y_step / 2) >> SCALE_SHIFT16;
571 y_pos = CLAMP (y_pos, 0, src_height - 1)(((y_pos) > (src_height - 1)) ? (src_height - 1) : (((y_pos
) < (0)) ? (0) : (y_pos)))
;
572 src = src_buf + (gsize)y_pos * src_rowstride;
573 dest = dest_buf + (gsize)i * dest_rowstride;
574
575 x = render_x0 * x_step + x_step / 2;
576
577
578 if (((i + check_y) >> check_shift) & 1)
579 {
580 r1 = (color2 & 0xff0000) >> 16;
581 g1 = (color2 & 0xff00) >> 8;
582 b1 = color2 & 0xff;
583
584 r2 = (color1 & 0xff0000) >> 16;
585 g2 = (color1 & 0xff00) >> 8;
586 b2 = color1 & 0xff;
587 }
588 else
589 {
590 r1 = (color1 & 0xff0000) >> 16;
591 g1 = (color1 & 0xff00) >> 8;
592 b1 = color1 & 0xff;
593
594 r2 = (color2 & 0xff0000) >> 16;
595 g2 = (color2 & 0xff00) >> 8;
596 b2 = color2 & 0xff;
597 }
598
599 j = 0;
600 INNER_LOOP(src_channels, dest_channels,
601 if (src_has_alpha)
602 a0 = (p[3] * overall_alpha + 0xff) >> 8;
603 else
604 a0 = overall_alpha;
605
606 switch (a0)
607 {
608 case 0:
609 if (((j + check_x) >> check_shift) & 1)
610 {
611 dest[0] = r2;
612 dest[1] = g2;
613 dest[2] = b2;
614 }
615 else
616 {
617 dest[0] = r1;
618 dest[1] = g1;
619 dest[2] = b1;
620 }
621 break;
622 case 255:
623 dest[0] = p[0];
624 dest[1] = p[1];
625 dest[2] = p[2];
626 break;
627 default:
628 {
629 unsigned int tmp;
630 if (((j + check_x) >> check_shift) & 1)
631 {
632 tmp = ((int) p[0] - r2) * a0;
633 dest[0] = r2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
634 tmp = ((int) p[1] - g2) * a0;
635 dest[1] = g2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
636 tmp = ((int) p[2] - b2) * a0;
637 dest[2] = b2 + ((tmp + (tmp >> 8) + 0x80) >> 8);
638 }
639 else
640 {
641 tmp = ((int) p[0] - r1) * a0;
642 dest[0] = r1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
643 tmp = ((int) p[1] - g1) * a0;
644 dest[1] = g1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
645 tmp = ((int) p[2] - b1) * a0;
646 dest[2] = b1 + ((tmp + (tmp >> 8) + 0x80) >> 8);
647 }
648 }
649 break;
650 }
651
652 if (dest_channels == 4)
653 dest[3] = 0xff;
654
655 j++;
656 );
657 }
658}
659#undef INNER_LOOP
660
661static void
662composite_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
663 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
664 guint r, guint g, guint b, guint a)
665{
666 if (dest_has_alpha)
667 {
668 unsigned int w0 = a - (a >> 8);
669 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
670 unsigned int w = w0 + w1;
671
672 if (w != 0)
673 {
674 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
675 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
676 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
677 dest[3] = w / 0xff00;
678 }
679 else
680 {
681 dest[0] = 0;
682 dest[1] = 0;
683 dest[2] = 0;
684 dest[3] = 0;
685 }
686 }
687 else
688 {
689 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
690 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
691 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
692 }
693}
694
695static guchar *
696composite_line (int *weights, int n_x, int n_y,
697 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
698 guchar **src, int src_channels, gboolean src_has_alpha,
699 int x_init, int x_step, int src_width,
700 int check_size, guint32 color1, guint32 color2)
701{
702 int x = x_init;
703 int i, j;
704
705 while (dest < dest_end)
706 {
707 int x_scaled = x >> SCALE_SHIFT16;
708 unsigned int r = 0, g = 0, b = 0, a = 0;
709 int *pixel_weights;
710
711 pixel_weights = weights + ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * n_x * n_y;
712
713 for (i=0; i<n_y; i++)
714 {
715 guchar *q = src[i] + x_scaled * src_channels;
716 int *line_weights = pixel_weights + n_x * i;
717
718 for (j=0; j<n_x; j++)
719 {
720 unsigned int ta;
721
722 if (src_has_alpha)
723 ta = q[3] * line_weights[j];
724 else
725 ta = 0xff * line_weights[j];
726
727 r += ta * q[0];
728 g += ta * q[1];
729 b += ta * q[2];
730 a += ta;
731
732 q += src_channels;
733 }
734 }
735
736 if (dest_has_alpha)
737 {
738 unsigned int w0 = a - (a >> 8);
739 unsigned int w1 = ((0xff0000 - a) >> 8) * dest[3];
740 unsigned int w = w0 + w1;
741
742 if (w != 0)
743 {
744 dest[0] = (r - (r >> 8) + w1 * dest[0]) / w;
745 dest[1] = (g - (g >> 8) + w1 * dest[1]) / w;
746 dest[2] = (b - (b >> 8) + w1 * dest[2]) / w;
747 dest[3] = w / 0xff00;
748 }
749 else
750 {
751 dest[0] = 0;
752 dest[1] = 0;
753 dest[2] = 0;
754 dest[3] = 0;
755 }
756 }
757 else
758 {
759 dest[0] = (r + (0xff0000 - a) * dest[0]) / 0xff0000;
760 dest[1] = (g + (0xff0000 - a) * dest[1]) / 0xff0000;
761 dest[2] = (b + (0xff0000 - a) * dest[2]) / 0xff0000;
762 }
763
764 dest += dest_channels;
765 x += x_step;
766 }
767
768 return dest;
769}
770
771static guchar *
772composite_line_22_4a4 (int *weights, int n_x, int n_y,
773 guchar *dest, int dest_x, guchar *dest_end, int dest_channels, int dest_has_alpha,
774 guchar **src, int src_channels, gboolean src_has_alpha,
775 int x_init, int x_step, int src_width,
776 int check_size, guint32 color1, guint32 color2)
777{
778 int x = x_init;
779 guchar *src0 = src[0];
780 guchar *src1 = src[1];
781
782 g_return_val_if_fail (src_channels != 3, dest)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_20
= 0; if (src_channels != 3) _g_boolean_var_20 = 1; _g_boolean_var_20
; }), 1))) { } else { g_return_if_fail_warning (((gchar*) 0),
((const char*) (__func__)), "src_channels != 3"); return (dest
); } } while (0)
;
783 g_return_val_if_fail (src_has_alpha, dest)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_21
= 0; if (src_has_alpha) _g_boolean_var_21 = 1; _g_boolean_var_21
; }), 1))) { } else { g_return_if_fail_warning (((gchar*) 0),
((const char*) (__func__)), "src_has_alpha"); return (dest);
} } while (0)
;
784
785 while (dest < dest_end)
786 {
787 int x_scaled = x >> SCALE_SHIFT16;
788 unsigned int r, g, b, a, ta;
789 int *pixel_weights;
790 guchar *q0, *q1;
791 int w1, w2, w3, w4;
792
793 q0 = src0 + x_scaled * 4;
794 q1 = src1 + x_scaled * 4;
795
796 pixel_weights = (int *)((char *)weights +
797 ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4 - 4)) & (SUBSAMPLE_MASK((1 << 4)-1) << 4)));
798
799 w1 = pixel_weights[0];
800 w2 = pixel_weights[1];
801 w3 = pixel_weights[2];
802 w4 = pixel_weights[3];
803
804 a = w1 * q0[3];
805 r = a * q0[0];
806 g = a * q0[1];
807 b = a * q0[2];
808
809 ta = w2 * q0[7];
810 r += ta * q0[4];
811 g += ta * q0[5];
812 b += ta * q0[6];
813 a += ta;
814
815 ta = w3 * q1[3];
816 r += ta * q1[0];
817 g += ta * q1[1];
818 b += ta * q1[2];
819 a += ta;
820
821 ta = w4 * q1[7];
822 r += ta * q1[4];
823 g += ta * q1[5];
824 b += ta * q1[6];
825 a += ta;
826
827 dest[0] = ((0xff0000 - a) * dest[0] + r) >> 24;
828 dest[1] = ((0xff0000 - a) * dest[1] + g) >> 24;
829 dest[2] = ((0xff0000 - a) * dest[2] + b) >> 24;
830 dest[3] = a >> 16;
831
832 dest += 4;
833 x += x_step;
834 }
835
836 return dest;
837}
838
839static void
840composite_pixel_color (guchar *dest, int dest_x, int dest_channels,
841 int dest_has_alpha, int src_has_alpha, int check_size,
842 guint32 color1, guint32 color2, guint r, guint g,
843 guint b, guint a)
844{
845 int dest_r, dest_g, dest_b;
846 int check_shift = get_check_shift (check_size);
847
848 if ((dest_x >> check_shift) & 1)
849 {
850 dest_r = (color2 & 0xff0000) >> 16;
851 dest_g = (color2 & 0xff00) >> 8;
852 dest_b = color2 & 0xff;
853 }
854 else
855 {
856 dest_r = (color1 & 0xff0000) >> 16;
857 dest_g = (color1 & 0xff00) >> 8;
858 dest_b = color1 & 0xff;
859 }
860
861 dest[0] = ((0xff0000 - a) * dest_r + r) >> 24;
862 dest[1] = ((0xff0000 - a) * dest_g + g) >> 24;
863 dest[2] = ((0xff0000 - a) * dest_b + b) >> 24;
864
865 if (dest_has_alpha)
866 dest[3] = 0xff;
867 else if (dest_channels == 4)
868 dest[3] = a >> 16;
869}
870
871static guchar *
872composite_line_color (int *weights, int n_x, int n_y, guchar *dest,
873 int dest_x, guchar *dest_end, int dest_channels,
874 int dest_has_alpha, guchar **src, int src_channels,
875 gboolean src_has_alpha, int x_init, int x_step,
876 int src_width, int check_size, guint32 color1,
877 guint32 color2)
878{
879 int x = x_init;
880 int i, j;
881 int check_shift = get_check_shift (check_size);
882 int dest_r1, dest_g1, dest_b1;
883 int dest_r2, dest_g2, dest_b2;
884
885 g_return_val_if_fail (check_size != 0, dest)do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_22
= 0; if (check_size != 0) _g_boolean_var_22 = 1; _g_boolean_var_22
; }), 1))) { } else { g_return_if_fail_warning (((gchar*) 0),
((const char*) (__func__)), "check_size != 0"); return (dest
); } } while (0)
;
886
887 dest_r1 = (color1 & 0xff0000) >> 16;
888 dest_g1 = (color1 & 0xff00) >> 8;
889 dest_b1 = color1 & 0xff;
890
891 dest_r2 = (color2 & 0xff0000) >> 16;
892 dest_g2 = (color2 & 0xff00) >> 8;
893 dest_b2 = color2 & 0xff;
894
895 while (dest < dest_end)
896 {
897 int x_scaled = x >> SCALE_SHIFT16;
898 unsigned int r = 0, g = 0, b = 0, a = 0;
899 int *pixel_weights;
900
901 pixel_weights = weights + ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * n_x * n_y;
902
903 for (i=0; i<n_y; i++)
904 {
905 guchar *q = src[i] + x_scaled * src_channels;
906 int *line_weights = pixel_weights + n_x * i;
907
908 for (j=0; j<n_x; j++)
909 {
910 unsigned int ta;
911
912 if (src_has_alpha)
913 ta = q[3] * line_weights[j];
914 else
915 ta = 0xff * line_weights[j];
916
917 r += ta * q[0];
918 g += ta * q[1];
919 b += ta * q[2];
920 a += ta;
921
922 q += src_channels;
923 }
924 }
925
926 if ((dest_x >> check_shift) & 1)
927 {
928 dest[0] = ((0xff0000 - a) * dest_r2 + r) >> 24;
929 dest[1] = ((0xff0000 - a) * dest_g2 + g) >> 24;
930 dest[2] = ((0xff0000 - a) * dest_b2 + b) >> 24;
931 }
932 else
933 {
934 dest[0] = ((0xff0000 - a) * dest_r1 + r) >> 24;
935 dest[1] = ((0xff0000 - a) * dest_g1 + g) >> 24;
936 dest[2] = ((0xff0000 - a) * dest_b1 + b) >> 24;
937 }
938
939 if (dest_has_alpha)
940 dest[3] = 0xff;
941 else if (dest_channels == 4)
942 dest[3] = a >> 16;
943
944 dest += dest_channels;
945 x += x_step;
946 dest_x++;
947 }
948
949 return dest;
950}
951
952static void
953scale_pixel (guchar *dest, int dest_x, int dest_channels, int dest_has_alpha,
954 int src_has_alpha, int check_size, guint32 color1, guint32 color2,
955 guint r, guint g, guint b, guint a)
956{
957 if (src_has_alpha)
958 {
959 if (a == 0xff0000)
960 {
961 /* Division by a constant is converted into a multiplication by an optimizing C compiler */
962 dest[0] = r / 0xff0000;
963 dest[1] = g / 0xff0000;
964 dest[2] = b / 0xff0000;
965 dest[3] = 0xff0000 >> 16;
966 }
967 else if (a)
968 {
969 double a1 = 1.0 / a;
970 dest[0] = r * a1;
971 dest[1] = g * a1;
972 dest[2] = b * a1;
973 dest[3] = a >> 16;
974 }
975 else
976 {
977 dest[0] = 0;
978 dest[1] = 0;
979 dest[2] = 0;
980 dest[3] = 0;
981 }
982 }
983 else
984 {
985 dest[0] = (r + 0xffffff) >> 24;
986 dest[1] = (g + 0xffffff) >> 24;
987 dest[2] = (b + 0xffffff) >> 24;
988
989 if (dest_has_alpha)
990 dest[3] = 0xff;
991 }
992}
993
994static guchar *
995scale_line (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
996 guchar *dest_end, int dest_channels, int dest_has_alpha,
997 guchar **src, int src_channels, gboolean src_has_alpha, int x_init,
998 int x_step, int src_width, int check_size, guint32 color1,
999 guint32 color2)
1000{
1001 gint64 x = x_init;
1002 int i, j;
1003 const gint64 n_xy = n_x * n_y;
1004
1005 while (dest < dest_end)
1006 {
1007 int x_scaled = x >> SCALE_SHIFT16;
1008 int *pixel_weights;
1009
1010 pixel_weights = weights +
1011 ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * n_xy;
1012
1013 if (src_has_alpha)
1014 {
1015 unsigned int r = 0, g = 0, b = 0, a = 0;
1016 for (i = 0; i < n_y; i++)
1017 {
1018 guchar *q = src[i] + x_scaled * src_channels;
1019 int *line_weights = pixel_weights + n_x * i;
1020
1021 for (j = 0; j < n_x; j++)
1022 {
1023 unsigned int ta;
1024
1025 ta = q[3] * line_weights[j];
1026 r += ta * q[0];
1027 g += ta * q[1];
1028 b += ta * q[2];
1029 a += ta;
1030
1031 q += src_channels;
1032 }
1033 }
1034
1035 if (a == 0xff0000)
1036 {
1037 /* Division by a constant is converted into a multiplication by an optimizing C compiler */
1038 dest[0] = r / 0xff0000;
1039 dest[1] = g / 0xff0000;
1040 dest[2] = b / 0xff0000;
1041 dest[3] = 0xff0000 >> 16;
1042 }
1043 else if (a)
1044 {
1045 double a1 = 1.0 / a;
1046 dest[0] = r * a1;
1047 dest[1] = g * a1;
1048 dest[2] = b * a1;
1049 dest[3] = a >> 16;
1050 }
1051 else
1052 {
1053 dest[0] = 0;
1054 dest[1] = 0;
1055 dest[2] = 0;
1056 dest[3] = 0;
1057 }
1058 }
1059 else
1060 {
1061 unsigned int r = 0, g = 0, b = 0;
1062 for (i = 0; i < n_y; i++)
1063 {
1064 guchar *q = src[i] + x_scaled * src_channels;
1065 int *line_weights = pixel_weights + n_x * i;
1066
1067 for (j = 0; j < n_x; j++)
1068 {
1069 unsigned int ta = line_weights[j];
1070
1071 r += ta * q[0];
1072 g += ta * q[1];
1073 b += ta * q[2];
1074
1075 q += src_channels;
1076 }
1077 }
1078
1079 dest[0] = (r + 0xffff) >> 16;
1080 dest[1] = (g + 0xffff) >> 16;
1081 dest[2] = (b + 0xffff) >> 16;
1082
1083 if (dest_has_alpha)
1084 dest[3] = 0xff;
1085 }
1086
1087 dest += dest_channels;
1088
1089 x += x_step;
1090 }
1091
1092 return dest;
1093}
1094
1095
1096static guchar *
1097scale_line_22_33 (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
1098 guchar *dest_end, int dest_channels, int dest_has_alpha,
1099 guchar **src, int src_channels, gboolean src_has_alpha,
1100 int x_init, int x_step, int src_width,
1101 int check_size, guint32 color1, guint32 color2)
1102{
1103 int x = x_init;
1104 guchar *src0 = src[0];
1105 guchar *src1 = src[1];
1106
1107 while (dest < dest_end)
1108 {
1109 unsigned int r, g, b;
1110 int x_scaled = x >> SCALE_SHIFT16;
1111 int *pixel_weights;
1112 guchar *q0, *q1;
1113 int w1, w2, w3, w4;
1114
1115 q0 = src0 + x_scaled * 3;
1116 q1 = src1 + x_scaled * 3;
1117
1118 pixel_weights = weights +
1119 ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * 4;
1120
1121 w1 = pixel_weights[0];
1122 w2 = pixel_weights[1];
1123 w3 = pixel_weights[2];
1124 w4 = pixel_weights[3];
1125
1126 r = w1 * q0[0];
1127 g = w1 * q0[1];
1128 b = w1 * q0[2];
1129
1130 r += w2 * q0[3];
1131 g += w2 * q0[4];
1132 b += w2 * q0[5];
1133
1134 r += w3 * q1[0];
1135 g += w3 * q1[1];
1136 b += w3 * q1[2];
1137
1138 r += w4 * q1[3];
1139 g += w4 * q1[4];
1140 b += w4 * q1[5];
1141
1142 dest[0] = (r + 0x8000) >> 16;
1143 dest[1] = (g + 0x8000) >> 16;
1144 dest[2] = (b + 0x8000) >> 16;
1145
1146 dest += 3;
1147 x += x_step;
1148 }
1149
1150 return dest;
1151}
1152
1153static void
1154process_pixel (int *weights, int n_x, int n_y, guchar *dest, int dest_x,
1155 int dest_channels, int dest_has_alpha, guchar **src,
1156 int src_channels, gboolean src_has_alpha, int x_start,
1157 int src_width, int check_size, guint32 color1, guint32 color2,
1158 PixopsPixelFunc pixel_func)
1159{
1160 unsigned int r = 0, g = 0, b = 0, a = 0;
1161 int i, j;
1162
1163 for (i=0; i<n_y; i++)
1164 {
1165 int *line_weights = weights + n_x * i;
1166
1167 for (j=0; j<n_x; j++)
1168 {
1169 unsigned int ta;
1170 guchar *q;
1171
1172 if (x_start + j < 0)
1173 q = src[i];
1174 else if (x_start + j < src_width)
1175 q = src[i] + (x_start + j) * src_channels;
1176 else
1177 q = src[i] + (src_width - 1) * src_channels;
1178
1179 if (src_has_alpha)
1180 ta = q[3] * line_weights[j];
1181 else
1182 ta = 0xff * line_weights[j];
1183
1184 r += ta * q[0];
1185 g += ta * q[1];
1186 b += ta * q[2];
1187 a += ta;
1188 }
1189 }
1190
1191 (*pixel_func) (dest, dest_x, dest_channels, dest_has_alpha, src_has_alpha,
1192 check_size, color1, color2, r, g, b, a);
1193}
1194
1195static void
1196correct_total (int *weights,
1197 int n_x,
1198 int n_y,
1199 int total,
1200 double overall_alpha)
1201{
1202 int correction = (int)(0.5 + 65536 * overall_alpha) - total;
1203 int remaining, c, d, i;
1204
1205 if (correction != 0)
14
Assuming 'correction' is not equal to 0
15
Taking true branch
1206 {
1207 remaining = correction;
1208 for (d = 1, c = correction; c
15.1
'c' is not equal to 0
!= 0
&& remaining
15.2
'remaining' is not equal to 0
22.1
'remaining' is not equal to 0
!= 0; d++, c = correction / d)
16
Loop condition is true. Entering loop body
22
Assuming 'c' is not equal to 0
23
Loop condition is true. Entering loop body
1209 for (i = n_x * n_y - 1; i
23.1
'i' is >= 0
>= 0
&& c
17.1
'c' is not equal to 0
23.2
'c' is not equal to 0
!= 0 && remaining
17.2
'remaining' is not equal to 0
23.3
'remaining' is not equal to 0
!= 0; i--)
17
Assuming 'i' is >= 0
18
Loop condition is true. Entering loop body
21
Assuming 'i' is < 0
24
Loop condition is true. Entering loop body
1210 if (*(weights + i) + c >= 0)
19
Assuming the condition is false
20
Taking false branch
25
The left operand of '+' is a garbage value
1211 {
1212 *(weights + i) += c;
1213 remaining -= c;
1214 if ((0 < remaining && remaining < c) ||
1215 (0 > remaining && remaining > c))
1216 c = remaining;
1217 }
1218 }
1219}
1220
1221static int *
1222make_filter_table (PixopsFilter *filter)
1223{
1224 int i_offset, j_offset;
1225 int n_x = filter->x.n;
1226 int n_y = filter->y.n;
1227 int *weights;
1228
1229 /* check n_x doesn't overflow */
1230 if (G_MAXINT2147483647 / (SUBSAMPLE(1 << 4) * SUBSAMPLE(1 << 4)) < n_x)
1
Assuming the condition is false
2
Taking false branch
1231 return NULL((void*)0);
1232
1233 /* check n_y doesn't overflow */
1234 if (G_MAXINT2147483647 / (SUBSAMPLE(1 << 4) * SUBSAMPLE(1 << 4) * n_x) < n_y)
3
Assuming the condition is false
4
Taking false branch
1235 return NULL((void*)0);
1236
1237 weights = g_try_new (int, SUBSAMPLE * SUBSAMPLE * n_x * n_y)(int *) (__extension__ ({ gsize __n = (gsize) ((1 << 4)
* (1 << 4) * n_x * n_y); gsize __s = sizeof (int); gpointer
__p; if (__s == 1) __p = g_try_malloc (__n); else if (__builtin_constant_p
(__n) && (__s == 0 || __n <= (9223372036854775807L
*2UL+1UL) / __s)) __p = g_try_malloc (__n * __s); else __p =
g_try_malloc_n (__n, __s); __p; }))
;
5
Taking false branch
6
Storing uninitialized value
1238 if (!weights)
7
Assuming 'weights' is non-null
8
Taking false branch
1239 return NULL((void*)0); /* overflow, bail */
1240
1241 for (i_offset=0; i_offset < SUBSAMPLE(1 << 4); i_offset++)
9
Loop condition is true. Entering loop body
1242 for (j_offset=0; j_offset < SUBSAMPLE(1 << 4); j_offset++)
10
Loop condition is true. Entering loop body
1243 {
1244 double weight;
1245 int *pixel_weights = weights + ((i_offset*SUBSAMPLE(1 << 4)) + j_offset) * n_x * n_y;
1246 int total = 0;
1247 int i, j;
1248
1249 for (i=0; i < n_y; i++)
11
Assuming 'i' is >= 'n_y'
12
Loop condition is false. Execution continues on line 1261
1250 for (j=0; j < n_x; j++)
1251 {
1252 weight = filter->x.weights[(j_offset * n_x) + j] *
1253 filter->y.weights[(i_offset * n_y) + i] *
1254 filter->overall_alpha * 65536 + 0.5;
1255
1256 total += (int)weight;
1257
1258 *(pixel_weights + n_x * i + j) = weight;
1259 }
1260
1261 correct_total (pixel_weights, n_x, n_y, total, filter->overall_alpha);
13
Calling 'correct_total'
1262 }
1263
1264 return weights;
1265}
1266
1267static void
1268pixops_process (guchar *dest_buf,
1269 int render_x0,
1270 int render_y0,
1271 int render_x1,
1272 int render_y1,
1273 int dest_rowstride,
1274 int dest_channels,
1275 gboolean dest_has_alpha,
1276 const guchar *src_buf,
1277 int src_width,
1278 int src_height,
1279 int src_rowstride,
1280 int src_channels,
1281 gboolean src_has_alpha,
1282 double scale_x,
1283 double scale_y,
1284 int check_x,
1285 int check_y,
1286 int check_size,
1287 guint32 color1,
1288 guint32 color2,
1289 PixopsFilter *filter,
1290 PixopsLineFunc line_func,
1291 PixopsPixelFunc pixel_func)
1292{
1293 gint64 i, j;
1294 gint64 x, y; /* X and Y position in source (fixed_point) */
1295
1296 guchar **line_bufs;
1297 int *filter_weights;
1298
1299 gint64 x_step;
1300 gint64 y_step;
1301
1302 int check_shift;
1303 gint64 scaled_x_offset;
1304
1305 gint64 run_end_x;
1306 gint64 run_end_index;
1307
1308 x_step = (1 << SCALE_SHIFT16) / scale_x; /* X step in source (fixed point) */
1309 y_step = (1 << SCALE_SHIFT16) / scale_y; /* Y step in source (fixed point) */
1310
1311 if (x_step == 0 || y_step == 0)
1312 return; /* overflow, bail out */
1313
1314 filter_weights = make_filter_table (filter);
1315 if (!filter_weights)
1316 return; /* overflow, bail out */
1317
1318 line_bufs = g_new (guchar *, filter->y.n)(guchar * *) (__extension__ ({ gsize __n = (gsize) (filter->
y.n); gsize __s = sizeof (guchar *); gpointer __p; if (__s ==
1) __p = g_malloc (__n); else if (__builtin_constant_p (__n)
&& (__s == 0 || __n <= (9223372036854775807L *2UL
+1UL) / __s)) __p = g_malloc (__n * __s); else __p = g_malloc_n
(__n, __s); __p; }))
;
1319
1320 check_shift = check_size ? get_check_shift (check_size) : 0;
1321
1322 scaled_x_offset = floor (filter->x.offset * (1 << SCALE_SHIFT16));
1323
1324 /* Compute the index where we run off the end of the source buffer. The
1325 * furthest source pixel we access at index i is:
1326 *
1327 * ((render_x0 + i) * x_step + scaled_x_offset) >> SCALE_SHIFT + filter->x.n - 1
1328 *
1329 * So, run_end_index is the smallest i for which this pixel is src_width,
1330 * i.e, for which:
1331 *
1332 * (i + render_x0) * x_step >= ((src_width - filter->x.n + 1) << SCALE_SHIFT) - scaled_x_offset
1333 *
1334 */
1335#define MYDIV(a,b)((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b)) ((a) > 0 ? (a) / (b) : ((a) - (b) + 1) / (b)) /* Division so that -1/5 = -1 */
1336
1337 run_end_x = (((src_width - (gint64) filter->x.n + 1) << SCALE_SHIFT16) - scaled_x_offset);
1338 run_end_index = MYDIV (run_end_x + x_step - 1, x_step)((run_end_x + x_step - 1) > 0 ? (run_end_x + x_step - 1) /
(x_step) : ((run_end_x + x_step - 1) - (x_step) + 1) / (x_step
))
- render_x0;
1339 run_end_index = MIN (run_end_index, render_x1 - render_x0)(((run_end_index) < (render_x1 - render_x0)) ? (run_end_index
) : (render_x1 - render_x0))
;
1340
1341 y = render_y0 * y_step + floor (filter->y.offset * (1 << SCALE_SHIFT16));
1342 for (i = 0; i < (render_y1 - render_y0); i++)
1343 {
1344 int dest_x;
1345 int y_start = y >> SCALE_SHIFT16;
1346 int x_start;
1347 int *run_weights = filter_weights +
1348 ((y >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) *
1349 filter->x.n * filter->y.n * SUBSAMPLE(1 << 4);
1350 guchar *new_outbuf;
1351 guint32 tcolor1, tcolor2;
1352
1353 guchar *outbuf = dest_buf + (gsize)dest_rowstride * i;
1354 guchar *outbuf_end = outbuf + dest_channels * (render_x1 - render_x0);
1355
1356 if (((i + check_y) >> check_shift) & 1)
1357 {
1358 tcolor1 = color2;
1359 tcolor2 = color1;
1360 }
1361 else
1362 {
1363 tcolor1 = color1;
1364 tcolor2 = color2;
1365 }
1366
1367 for (j=0; j<filter->y.n; j++)
1368 {
1369 if (y_start < 0)
1370 line_bufs[j] = (guchar *)src_buf;
1371 else if (y_start < src_height)
1372 line_bufs[j] = (guchar *)src_buf + (gsize)src_rowstride * y_start;
1373 else
1374 line_bufs[j] = (guchar *)src_buf + (gsize)src_rowstride * (src_height - 1);
1375
1376 y_start++;
1377 }
1378
1379 dest_x = check_x;
1380 x = render_x0 * x_step + scaled_x_offset;
1381 x_start = x >> SCALE_SHIFT16;
1382
1383 while (x_start < 0 && outbuf < outbuf_end)
1384 {
1385 process_pixel (run_weights + ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
1386 outbuf, dest_x, dest_channels, dest_has_alpha,
1387 line_bufs, src_channels, src_has_alpha,
1388 x >> SCALE_SHIFT16, src_width,
1389 check_size, tcolor1, tcolor2, pixel_func);
1390
1391 x += x_step;
1392 x_start = x >> SCALE_SHIFT16;
1393 dest_x++;
1394 outbuf += dest_channels;
1395 }
1396
1397 new_outbuf = (*line_func) (run_weights, filter->x.n, filter->y.n,
1398 outbuf, dest_x, dest_buf + (gsize)dest_rowstride *
1399 i + run_end_index * dest_channels,
1400 dest_channels, dest_has_alpha,
1401 line_bufs, src_channels, src_has_alpha,
1402 x, x_step, src_width, check_size, tcolor1,
1403 tcolor2);
1404
1405 dest_x += (new_outbuf - outbuf) / dest_channels;
1406
1407 x = (dest_x - check_x + render_x0) * x_step + scaled_x_offset;
1408 outbuf = new_outbuf;
1409
1410 while (outbuf < outbuf_end)
1411 {
1412 process_pixel (run_weights + ((x >> (SCALE_SHIFT16 - SUBSAMPLE_BITS4)) & SUBSAMPLE_MASK((1 << 4)-1)) * (filter->x.n * filter->y.n), filter->x.n, filter->y.n,
1413 outbuf, dest_x, dest_channels, dest_has_alpha,
1414 line_bufs, src_channels, src_has_alpha,
1415 x >> SCALE_SHIFT16, src_width,
1416 check_size, tcolor1, tcolor2, pixel_func);
1417
1418 x += x_step;
1419 dest_x++;
1420 outbuf += dest_channels;
1421 }
1422
1423 y += y_step;
1424 }
1425
1426 g_free (line_bufs);
1427 g_free (filter_weights);
1428}
1429
1430/* Compute weights for reconstruction by replication followed by
1431 * sampling with a box filter
1432 */
1433static gboolean
1434tile_make_weights (PixopsFilterDimension *dim,
1435 double scale)
1436{
1437 int n = ceil (1 / scale + 1);
1438 double *pixel_weights;
1439 int offset;
1440 int i;
1441
1442 pixel_weights = g_try_malloc_n (sizeof (double) * SUBSAMPLE(1 << 4), n);
1443 if (pixel_weights == NULL((void*)0))
1444 return FALSE(0);
1445
1446 dim->n = n;
1447 dim->offset = 0;
1448 dim->weights = pixel_weights;
1449
1450 for (offset = 0; offset < SUBSAMPLE(1 << 4); offset++)
1451 {
1452 double x = (double)offset / SUBSAMPLE(1 << 4);
1453 double a = x + 1 / scale;
1454
1455 for (i = 0; i < n; i++)
1456 {
1457 if (i < x)
1458 {
1459 if (i + 1 > x)
1460 *(pixel_weights++) = (MIN (i + 1, a)(((i + 1) < (a)) ? (i + 1) : (a)) - x) * scale;
1461 else
1462 *(pixel_weights++) = 0;
1463 }
1464 else
1465 {
1466 if (a > i)
1467 *(pixel_weights++) = (MIN (i + 1, a)(((i + 1) < (a)) ? (i + 1) : (a)) - i) * scale;
1468 else
1469 *(pixel_weights++) = 0;
1470 }
1471 }
1472 }
1473
1474 return TRUE(!(0));
1475}
1476
1477/* Compute weights for a filter that, for minification
1478 * is the same as 'tiles', and for magnification, is bilinear
1479 * reconstruction followed by a sampling with a delta function.
1480 */
1481static gboolean
1482bilinear_magnify_make_weights (PixopsFilterDimension *dim,
1483 double scale)
1484{
1485 double *pixel_weights;
1486 int n;
1487 int offset;
1488 int i;
1489
1490 if (scale > 1.0) /* Linear */
1491 {
1492 n = 2;
1493 dim->offset = 0.5 * (1 / scale - 1);
1494 }
1495 else /* Tile */
1496 {
1497 n = ceil (1.0 + 1.0 / scale);
1498 dim->offset = 0.0;
1499 }
1500
1501 dim->n = n;
1502 dim->weights = g_try_malloc_n (sizeof (double) * SUBSAMPLE(1 << 4), n);
1503 if (dim->weights == NULL((void*)0))
1504 return FALSE(0);
1505
1506 pixel_weights = dim->weights;
1507
1508 for (offset=0; offset < SUBSAMPLE(1 << 4); offset++)
1509 {
1510 double x = (double)offset / SUBSAMPLE(1 << 4);
1511
1512 if (scale > 1.0) /* Linear */
1513 {
1514 for (i = 0; i < n; i++)
1515 *(pixel_weights++) = (((i == 0) ? (1 - x) : x) / scale) * scale;
1516 }
1517 else /* Tile */
1518 {
1519 double a = x + 1 / scale;
1520
1521 /* x
1522 * ---------|--.-|----|--.-|------- SRC
1523 * ------------|---------|--------- DEST
1524 */
1525 for (i = 0; i < n; i++)
1526 {
1527 if (i < x)
1528 {
1529 if (i + 1 > x)
1530 *(pixel_weights++) = (MIN (i + 1, a)(((i + 1) < (a)) ? (i + 1) : (a)) - x) * scale;
1531 else
1532 *(pixel_weights++) = 0;
1533 }
1534 else
1535 {
1536 if (a > i)
1537 *(pixel_weights++) = (MIN (i + 1, a)(((i + 1) < (a)) ? (i + 1) : (a)) - i) * scale;
1538 else
1539 *(pixel_weights++) = 0;
1540 }
1541 }
1542 }
1543 }
1544
1545 return TRUE(!(0));
1546}
1547
1548/* Computes the integral from b0 to b1 of
1549 *
1550 * f(x) = x; 0 <= x < 1
1551 * f(x) = 0; otherwise
1552 *
1553 * We combine two of these to compute the convolution of
1554 * a box filter with a triangular spike.
1555 */
1556static double
1557linear_box_half (double b0, double b1)
1558{
1559 double a0, a1;
1560 double x0, x1;
1561
1562 a0 = 0.;
1563 a1 = 1.;
1564
1565 if (a0 < b0)
1566 {
1567 if (a1 > b0)
1568 {
1569 x0 = b0;
1570 x1 = MIN (a1, b1)(((a1) < (b1)) ? (a1) : (b1));
1571 }
1572 else
1573 return 0;
1574 }
1575 else
1576 {
1577 if (b1 > a0)
1578 {
1579 x0 = a0;
1580 x1 = MIN (a1, b1)(((a1) < (b1)) ? (a1) : (b1));
1581 }
1582 else
1583 return 0;
1584 }
1585
1586 return 0.5 * (x1*x1 - x0*x0);
1587}
1588
1589/* Compute weights for reconstructing with bilinear
1590 * interpolation, then sampling with a box filter
1591 */
1592static gboolean
1593bilinear_box_make_weights (PixopsFilterDimension *dim,
1594 double scale)
1595{
1596 int n = ceil (1/scale + 3.0);
1597 double *pixel_weights;
1598 double w;
1599 int offset, i;
1600
1601 pixel_weights = g_malloc_n (sizeof (double) * SUBSAMPLE(1 << 4), n);
1602 if (pixel_weights == NULL((void*)0))
1603 return FALSE(0);
1604
1605 dim->offset = -1.0;
1606 dim->n = n;
1607 dim->weights = pixel_weights;
1608
1609 for (offset = 0; offset < SUBSAMPLE(1 << 4); offset++)
1610 {
1611 double x = (double)offset / SUBSAMPLE(1 << 4);
1612 double a = x + 1 / scale;
1613
1614 for (i = 0; i < n; i++)
1615 {
1616 w = linear_box_half (0.5 + i - a, 0.5 + i - x);
1617 w += linear_box_half (1.5 + x - i, 1.5 + a - i);
1618
1619 *(pixel_weights++) = w * scale;
1620 }
1621 }
1622
1623 return TRUE(!(0));
1624}
1625
1626static gboolean
1627make_weights (PixopsFilter *filter,
1628 PixopsInterpType interp_type,
1629 double scale_x,
1630 double scale_y)
1631{
1632 switch (interp_type)
1633 {
1634 case PIXOPS_INTERP_NEAREST:
1635 default:
1636 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "../cdk-pixbuf/pixops/pixops.c"
, 1636, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1637 return FALSE(0);
1638
1639 case PIXOPS_INTERP_TILES:
1640 if (!tile_make_weights (&filter->x, scale_x))
1641 return FALSE(0);
1642 if (!tile_make_weights (&filter->y, scale_y))
1643 {
1644 g_free (filter->x.weights);
1645 return FALSE(0);
1646 }
1647 return TRUE(!(0));
1648
1649 case PIXOPS_INTERP_BILINEAR:
1650 if (!bilinear_magnify_make_weights (&filter->x, scale_x))
1651 return FALSE(0);
1652 if (!bilinear_magnify_make_weights (&filter->y, scale_y))
1653 {
1654 g_free (filter->x.weights);
1655 return FALSE(0);
1656 }
1657 return TRUE(!(0));
1658
1659 case PIXOPS_INTERP_HYPER:
1660 if (!bilinear_box_make_weights (&filter->x, scale_x))
1661 return FALSE(0);
1662 if (!bilinear_box_make_weights (&filter->y, scale_y))
1663 {
1664 g_free (filter->x.weights);
1665 return FALSE(0);
1666 }
1667 return TRUE(!(0));
1668 }
1669}
1670
1671/* Two-step scaler begins */
1672
1673/* make_filter_table() bloats out in VM usage and consumes 100% CPU for
1674 * tens of seconds when downscaling by a large factor.
1675 * https://bugzilla.gnome.org/show_bug.cgi?id=80925
1676 * We work round this by doing extreme reductions in two steps.
1677 *
1678 * The excessive CPU usage is accompanied by an excessive RAM usage because
1679 * make_weights() allocates two arrays of weights proportional in size to
1680 * n_x = (1 / scale_x + 3) and n_y = (1 / scale_y + 3), then make_filter_table()
1681 * allocates and fills an array of SUBSAMPLE * SUBSAMPLE * n_x * n_y doubles.
1682 * Empirically, on machines with plenty of RAM, the execution time slopes upward
1683 * when n_filters > 1000.
1684 * SUBSAMPLE is 16 so each filter takes 16 x 16 doubles (8 bytes) = 2kb RAM.
1685 * Limiting it to 1000 filters limits the scaler's RAM consumption to about 2MB
1686 * which should be OK on machines with relatively little memory.
1687 *
1688 * CDK_INTER_BILINEAR, CDK_INTERP_TILES and CDK_INTER_HYPER all have
1689 * similar symptoms; only CDK_INTERP_NEAREST does not need this trick.
1690 **/
1691#define MAX_FILTERS1000 1000
1692
1693/* Check whether prescaling is necessary to avoid the bug */
1694static gboolean
1695need_to_prescale (double scale_x,
1696 double scale_y,
1697 PixopsInterpType interp_type)
1698{
1699 int n_x, n_y; /* See make_weights() */
1700
1701 /* The testsuite sets this to compare the results with and without it. */
1702 if (g_getenv ("CDK_PIXBUF_DISABLE_TWO_STEP_SCALER"))
1703 return FALSE(0);
1704
1705 /* Calculate the number of weights created in make_weights() */
1706 switch (interp_type) {
1707 case PIXOPS_INTERP_HYPER:
1708 n_x = ceil (1 / scale_x + 3);
1709 n_y = ceil (1 / scale_y + 3);
1710 break;
1711 case PIXOPS_INTERP_TILES:
1712 case PIXOPS_INTERP_BILINEAR:
1713 n_x = ceil (1 / scale_x + 1);
1714 n_y = ceil (1 / scale_y + 1);
1715 break;
1716 case PIXOPS_INTERP_NEAREST:
1717 /* Doesn't need the optimization */
1718 return FALSE(0);
1719 default:
1720 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "../cdk-pixbuf/pixops/pixops.c"
, 1720, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1721 }
1722
1723 /* Limit the number of filters created by make_filter_table(). */
1724 return (n_x * n_y > MAX_FILTERS1000);
1725}
1726
1727/* Prescale the source image.
1728 * If successful, it changes the source buffer's parameters to reflect the
1729 * half-scaled image and the scaling factors to reflect the scaling left to do.
1730 * It returns a pointer to the new image data or NULL, so that the caller knows
1731 * whether they have to free the temporary buffer or not.
1732 */
1733static guchar *
1734prescale (const guchar **src_bufp,
1735 int *src_widthp,
1736 int *src_heightp,
1737 int *src_rowstridep,
1738 int src_channels,
1739 gboolean src_has_alpha,
1740 double *scale_xp,
1741 double *scale_yp,
1742 PixopsInterpType interp_type)
1743{
1744 /* Give local names to parameters that may be modified */
1745 const guchar *src_buf = *src_bufp;
1746 int src_width = *src_widthp;
1747 int src_height = *src_heightp;
1748 int src_rowstride = *src_rowstridep;
1749 double scale_x = *scale_xp;
1750 double scale_y = *scale_yp;
1751
1752 /* How much we prescale each axis by */
1753 double prescale_x, prescale_y;
1754
1755 /* The prescaled image */
1756 int tmp_width, tmp_height;
1757 int tmp_rowstride;
1758 int tmp_channels;
1759 gboolean tmp_has_alpha;
1760 guchar *tmp_buf;
1761
1762 /* The time taken by make_filter_table() is roughly proportional to
1763 * 1/scale_x * 1/scale_y, i.e. to the area reduction factor, so we
1764 * reduce the image in two steps, each of which reduces the total area
1765 * by the same factor. */
1766 prescale_x = sqrt (scale_x);
1767 prescale_y = sqrt (scale_y);
1768
1769 /* Scale the whole source image into a top-left-aligned temporary pixbuf.
1770 * render_[xy][01] are done in the final scaling, not here, as they are
1771 * measured in the coordinate system of the scaled image. */
1772 tmp_width = lrint (src_width * prescale_x);
1773 tmp_height = lrint (src_height * prescale_y);
1774
1775 /* We are below the cdk_ interface, so create the temp image manually.
1776 * Code copied from cdk_pixbuf_new() */
1777 tmp_channels = src_channels;
1778 tmp_has_alpha = src_has_alpha;
1779 tmp_rowstride = ((tmp_width * tmp_channels) + 3) & ~3;
1780 tmp_buf = g_try_malloc_n (tmp_height, tmp_rowstride);
1781 if (!tmp_buf)
1782 return NULL((void*)0); /* Skip the prescaling */
1783
1784 /* Prescale to an intermediate size */
1785 _pixops_scale (tmp_buf, tmp_width, tmp_height, tmp_rowstride,
1786 tmp_channels, tmp_has_alpha, src_buf, src_width,
1787 src_height, src_rowstride, src_channels, src_has_alpha,
1788 0, 0, tmp_width, tmp_height, 0.0, 0.0,
1789 prescale_x, prescale_y,
1790 interp_type);
1791
1792 /* The second call to the scaler reads from the prescaled image */
1793 *src_bufp = tmp_buf;
1794 *src_widthp = tmp_width;
1795 *src_heightp = tmp_height;
1796 *src_rowstridep = tmp_rowstride;
1797
1798 /* Calculate how much scaling is left to do */
1799 *scale_xp /= prescale_x;
1800 *scale_yp /= prescale_y;
1801
1802 return tmp_buf;
1803}
1804/* End of two-step scaler */
1805
1806static void
1807_pixops_composite_color_real (guchar *dest_buf,
1808 int render_x0,
1809 int render_y0,
1810 int render_x1,
1811 int render_y1,
1812 int dest_rowstride,
1813 int dest_channels,
1814 gboolean dest_has_alpha,
1815 const guchar *src_buf,
1816 int src_width,
1817 int src_height,
1818 int src_rowstride,
1819 int src_channels,
1820 gboolean src_has_alpha,
1821 double scale_x,
1822 double scale_y,
1823 PixopsInterpType interp_type,
1824 int overall_alpha,
1825 int check_x,
1826 int check_y,
1827 int check_size,
1828 guint32 color1,
1829 guint32 color2)
1830{
1831 PixopsFilter filter;
1832 PixopsLineFunc line_func;
1833 guchar *tmp_buf = NULL((void*)0);
1834
1835 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_23
= 0; if (!(dest_channels == 3 && dest_has_alpha)) _g_boolean_var_23
= 1; _g_boolean_var_23; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(dest_channels == 3 && dest_has_alpha)"
); return; } } while (0)
;
1836 g_return_if_fail (!(src_channels == 3 && src_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_24
= 0; if (!(src_channels == 3 && src_has_alpha)) _g_boolean_var_24
= 1; _g_boolean_var_24; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(src_channels == 3 && src_has_alpha)"
); return; } } while (0)
;
1837
1838 if (scale_x == 0 || scale_y == 0)
1839 return;
1840
1841 if (interp_type == PIXOPS_INTERP_NEAREST)
1842 {
1843 pixops_composite_color_nearest (dest_buf, render_x0, render_y0,
1844 render_x1, render_y1, dest_rowstride,
1845 dest_channels, dest_has_alpha, src_buf,
1846 src_width, src_height, src_rowstride,
1847 src_channels, src_has_alpha, scale_x,
1848 scale_y, overall_alpha, check_x, check_y,
1849 check_size, color1, color2);
1850 return;
1851 }
1852
1853 if (need_to_prescale (scale_x, scale_y, interp_type))
1854 tmp_buf = prescale (&src_buf, &src_width, &src_height, &src_rowstride,
1855 src_channels, src_has_alpha,
1856 &scale_x, &scale_y, interp_type);
1857
1858 filter.overall_alpha = overall_alpha / 255.;
1859 if (!make_weights (&filter, interp_type, scale_x, scale_y))
1860 goto free_tmp;
1861
1862 line_func = composite_line_color;
1863
1864 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
1865 dest_rowstride, dest_channels, dest_has_alpha,
1866 src_buf, src_width, src_height, src_rowstride, src_channels,
1867 src_has_alpha, scale_x, scale_y, check_x, check_y, check_size, color1, color2,
1868 &filter, line_func, composite_pixel_color);
1869
1870 g_free (filter.x.weights);
1871 g_free (filter.y.weights);
1872free_tmp:
1873 g_free (tmp_buf);
1874}
1875
1876void
1877_pixops_composite_color (guchar *dest_buf,
1878 int dest_width,
1879 int dest_height,
1880 int dest_rowstride,
1881 int dest_channels,
1882 gboolean dest_has_alpha,
1883 const guchar *src_buf,
1884 int src_width,
1885 int src_height,
1886 int src_rowstride,
1887 int src_channels,
1888 gboolean src_has_alpha,
1889 int dest_x,
1890 int dest_y,
1891 int dest_region_width,
1892 int dest_region_height,
1893 double offset_x,
1894 double offset_y,
1895 double scale_x,
1896 double scale_y,
1897 PixopsInterpType interp_type,
1898 int overall_alpha,
1899 int check_x,
1900 int check_y,
1901 int check_size,
1902 guint32 color1,
1903 guint32 color2)
1904{
1905 guchar *new_dest_buf;
1906 int render_x0;
1907 int render_y0;
1908 int render_x1;
1909 int render_y1;
1910
1911 if (!src_has_alpha && overall_alpha == 255)
1912 {
1913 _pixops_scale (dest_buf, dest_width, dest_height, dest_rowstride,
1914 dest_channels, dest_has_alpha, src_buf, src_width,
1915 src_height, src_rowstride, src_channels, src_has_alpha,
1916 dest_x, dest_y, dest_region_width, dest_region_height,
1917 offset_x, offset_y, scale_x, scale_y, interp_type);
1918 return;
1919 }
1920
1921 new_dest_buf = dest_buf + dest_y * dest_rowstride + dest_x *
1922 dest_channels;
1923 render_x0 = dest_x - offset_x;
1924 render_y0 = dest_y - offset_y;
1925 render_x1 = dest_x + dest_region_width - offset_x;
1926 render_y1 = dest_y + dest_region_height - offset_y;
1927
1928 _pixops_composite_color_real (new_dest_buf, render_x0, render_y0, render_x1,
1929 render_y1, dest_rowstride, dest_channels,
1930 dest_has_alpha, src_buf, src_width,
1931 src_height, src_rowstride, src_channels,
1932 src_has_alpha, scale_x, scale_y,
1933 (PixopsInterpType)interp_type, overall_alpha,
1934 check_x, check_y, check_size, color1, color2);
1935}
1936
1937/**
1938 * _pixops_composite_real:
1939 * @dest_buf: pointer to location to store result
1940 * @render_x0: x0 of region of scaled source to store into @dest_buf
1941 * @render_y0: y0 of region of scaled source to store into @dest_buf
1942 * @render_x1: x1 of region of scaled source to store into @dest_buf
1943 * @render_y1: y1 of region of scaled source to store into @dest_buf
1944 * @dest_rowstride: rowstride of @dest_buf
1945 * @dest_channels: number of channels in @dest_buf
1946 * @dest_has_alpha: whether @dest_buf has alpha
1947 * @src_buf: pointer to source pixels
1948 * @src_width: width of source (used for clipping)
1949 * @src_height: height of source (used for clipping)
1950 * @src_rowstride: rowstride of source
1951 * @src_channels: number of channels in @src_buf
1952 * @src_has_alpha: whether @src_buf has alpha
1953 * @scale_x: amount to scale source by in X direction
1954 * @scale_y: amount to scale source by in Y direction
1955 * @interp_type: type of enumeration
1956 * @overall_alpha: overall alpha factor to multiply source by
1957 *
1958 * Scale source buffer by scale_x / scale_y, then composite a given rectangle
1959 * of the result into the destination buffer.
1960 **/
1961static void
1962_pixops_composite_real (guchar *dest_buf,
1963 int render_x0,
1964 int render_y0,
1965 int render_x1,
1966 int render_y1,
1967 int dest_rowstride,
1968 int dest_channels,
1969 gboolean dest_has_alpha,
1970 const guchar *src_buf,
1971 int src_width,
1972 int src_height,
1973 int src_rowstride,
1974 int src_channels,
1975 gboolean src_has_alpha,
1976 double scale_x,
1977 double scale_y,
1978 PixopsInterpType interp_type,
1979 int overall_alpha)
1980{
1981 PixopsFilter filter;
1982 PixopsLineFunc line_func;
1983 guchar *tmp_buf = NULL((void*)0);
1984
1985 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_25
= 0; if (!(dest_channels == 3 && dest_has_alpha)) _g_boolean_var_25
= 1; _g_boolean_var_25; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(dest_channels == 3 && dest_has_alpha)"
); return; } } while (0)
;
1986 g_return_if_fail (!(src_channels == 3 && src_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_26
= 0; if (!(src_channels == 3 && src_has_alpha)) _g_boolean_var_26
= 1; _g_boolean_var_26; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(src_channels == 3 && src_has_alpha)"
); return; } } while (0)
;
1987
1988 if (scale_x == 0 || scale_y == 0)
1989 return;
1990
1991 if (interp_type == PIXOPS_INTERP_NEAREST)
1992 {
1993 if (scale_x == 1.0 && scale_y == 1.0)
1994 pixops_composite_nearest_noscale (dest_buf, render_x0, render_y0, render_x1, render_y1,
1995 dest_rowstride, dest_channels, dest_has_alpha,
1996 src_buf, src_width, src_height, src_rowstride, src_channels,
1997 src_has_alpha, overall_alpha);
1998 else
1999 pixops_composite_nearest (dest_buf, render_x0, render_y0, render_x1, render_y1,
2000 dest_rowstride, dest_channels, dest_has_alpha,
2001 src_buf, src_width, src_height, src_rowstride, src_channels,
2002 src_has_alpha, scale_x, scale_y, overall_alpha);
2003 return;
2004 }
2005
2006 if (need_to_prescale (scale_x, scale_y, interp_type))
2007 tmp_buf = prescale (&src_buf, &src_width, &src_height, &src_rowstride,
2008 src_channels, src_has_alpha,
2009 &scale_x, &scale_y, interp_type);
2010
2011 filter.overall_alpha = overall_alpha / 255.;
2012 if (!make_weights (&filter, interp_type, scale_x, scale_y))
2013 goto free_tmp;
2014
2015 if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 4 &&
2016 src_channels == 4 && src_has_alpha && !dest_has_alpha)
2017 line_func = composite_line_22_4a4;
2018 else
2019 line_func = composite_line;
2020
2021 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
2022 dest_rowstride, dest_channels, dest_has_alpha,
2023 src_buf, src_width, src_height, src_rowstride, src_channels,
2024 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
2025 &filter, line_func, composite_pixel);
2026
2027 g_free (filter.x.weights);
2028 g_free (filter.y.weights);
2029free_tmp:
2030 g_free (tmp_buf);
2031}
2032
2033void
2034_pixops_composite (guchar *dest_buf,
2035 int dest_width,
2036 int dest_height,
2037 int dest_rowstride,
2038 int dest_channels,
2039 int dest_has_alpha,
2040 const guchar *src_buf,
2041 int src_width,
2042 int src_height,
2043 int src_rowstride,
2044 int src_channels,
2045 int src_has_alpha,
2046 int dest_x,
2047 int dest_y,
2048 int dest_region_width,
2049 int dest_region_height,
2050 double offset_x,
2051 double offset_y,
2052 double scale_x,
2053 double scale_y,
2054 PixopsInterpType interp_type,
2055 int overall_alpha)
2056{
2057 guchar *new_dest_buf;
2058 int render_x0;
2059 int render_y0;
2060 int render_x1;
2061 int render_y1;
2062
2063 if (!src_has_alpha && overall_alpha == 255)
2064 {
2065 _pixops_scale (dest_buf, dest_width, dest_height, dest_rowstride,
2066 dest_channels, dest_has_alpha, src_buf, src_width,
2067 src_height, src_rowstride, src_channels, src_has_alpha,
2068 dest_x, dest_y, dest_region_width, dest_region_height,
2069 offset_x, offset_y, scale_x, scale_y, interp_type);
2070 return;
2071 }
2072
2073#ifdef USE_MEDIALIB
2074 pixops_medialib_composite (dest_buf, dest_width, dest_height, dest_rowstride,
2075 dest_channels, dest_has_alpha, src_buf,
2076 src_width, src_height, src_rowstride,
2077 src_channels, src_has_alpha, dest_x, dest_y,
2078 dest_region_width, dest_region_height, offset_x,
2079 offset_y, scale_x, scale_y,
2080 (PixopsInterpType)interp_type, overall_alpha);
2081 return;
2082#endif
2083
2084 new_dest_buf = dest_buf + (gsize)dest_y * dest_rowstride + (gsize)dest_x * dest_channels;
2085 render_x0 = dest_x - offset_x;
2086 render_y0 = dest_y - offset_y;
2087 render_x1 = dest_x + dest_region_width - offset_x;
2088 render_y1 = dest_y + dest_region_height - offset_y;
2089
2090 _pixops_composite_real (new_dest_buf, render_x0, render_y0, render_x1,
2091 render_y1, dest_rowstride, dest_channels,
2092 dest_has_alpha, src_buf, src_width, src_height,
2093 src_rowstride, src_channels, src_has_alpha, scale_x,
2094 scale_y, (PixopsInterpType)interp_type,
2095 overall_alpha);
2096}
2097
2098#ifdef USE_MEDIALIB
2099static void
2100medialib_get_interpolation (mlInterp * ml_interp,
2101 PixopsInterpType interp_type,
2102 double scale_x,
2103 double scale_y,
2104 double overall_alpha)
2105{
2106 mlib_s32 leftPadding, topPadding;
2107 ml_interp->interp_table = NULL((void*)0);
2108
2109 /*
2110 * medialib 2.1 and later supports scaling with user-defined interpolation
2111 * tables, so this logic is used.
2112 *
2113 * bilinear_magnify_make_weights builds an interpolation table of size 2x2 if
2114 * the scale factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise. These map
2115 * most closely to MLIB_BILINEAR, which uses an interpolation table of size
2116 * 2x2.
2117 *
2118 * tile_make_weights builds an interpolation table of size 2x2 if the scale
2119 * factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise. These map most
2120 * closely to MLIB_BILINEAR, which uses an interpolation table of size 2x2.
2121 *
2122 * bilinear_box_make_weights builds an interpolation table of size 4x4 if the
2123 * scale factor >= 1.0 and "ceil (1.0 + 1.0/scale)" otherwise. These map most
2124 * closely to MLIB_BICUBIC, which uses an interpolation table of size 4x4.
2125 *
2126 * PIXOPS_INTERP_NEAREST calls pixops_scale_nearest which does not use an
2127 * interpolation table. This maps to MLIB_NEAREST.
2128 */
2129 switch (interp_type)
2130 {
2131 case PIXOPS_INTERP_BILINEAR:
2132 bilinear_magnify_make_weights (&(ml_interp->po_filter.x), scale_x);
2133 bilinear_magnify_make_weights (&(ml_interp->po_filter.y), scale_y);
2134 leftPadding = 0;
2135 topPadding = 0;
2136
2137 if (scale_x <= 1.0)
2138 ml_interp->tx = 0.5 * (1 - scale_x);
2139 else
2140 ml_interp->tx = 0.0;
2141
2142 if (scale_y <= 1.0)
2143 ml_interp->ty = 0.5 * (1 - scale_y);
2144 else
2145 ml_interp->ty = 0.0;
2146
2147 break;
2148
2149 case PIXOPS_INTERP_TILES:
2150 tile_make_weights (&(ml_interp->po_filter.x), scale_x);
2151 tile_make_weights (&(ml_interp->po_filter.y), scale_y);
2152 leftPadding = 0;
2153 topPadding = 0;
2154 ml_interp->tx = 0.5 * (1 - scale_x);
2155 ml_interp->ty = 0.5 * (1 - scale_y);
2156 break;
2157
2158 case PIXOPS_INTERP_HYPER:
2159 bilinear_box_make_weights (&(ml_interp->po_filter.x), scale_x);
2160 bilinear_box_make_weights (&(ml_interp->po_filter.y), scale_y);
2161 leftPadding = 1;
2162 topPadding = 1;
2163 ml_interp->tx = 0.5 * (1 - scale_x);
2164 ml_interp->ty = 0.5 * (1 - scale_y);
2165 break;
2166
2167 case PIXOPS_INTERP_NEAREST:
2168 default:
2169 /*
2170 * Note that this function should not be called in the
2171 * PIXOPS_INTERP_NEAREST case since it does not use an interpolation
2172 * table.
2173 */
2174 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "../cdk-pixbuf/pixops/pixops.c"
, 2174, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2175 break;
2176 }
2177
2178 /*
2179 * If overall_alpha is not 1.0, then multiply the vectors built by the
2180 * sqrt (overall_alpha). This will cause overall_alpha to get evenly
2181 * blended across both axis.
2182 *
2183 * Note there is no need to multiply the vectors built by the various
2184 * make-weight functions by sqrt (overall_alpha) since the make-weight
2185 * functions are called with overall_alpha hardcoded to 1.0.
2186 */
2187 if (overall_alpha != 1.0)
2188 {
2189 double sqrt_alpha = sqrt (overall_alpha);
2190 int i;
2191
2192 for (i=0; i < SUBSAMPLE(1 << 4) * ml_interp->po_filter.x.n; i++)
2193 ml_interp->po_filter.x.weights[i] *= sqrt_alpha;
2194 for (i=0; i < SUBSAMPLE(1 << 4) * ml_interp->po_filter.y.n; i++)
2195 ml_interp->po_filter.y.weights[i] *= sqrt_alpha;
2196 }
2197
2198 ml_interp->interp_table = (void *) mlib_ImageInterpTableCreate (MLIB_DOUBLE,
2199 ml_interp->po_filter.x.n, ml_interp->po_filter.y.n, leftPadding,
2200 topPadding, SUBSAMPLE_BITS4, SUBSAMPLE_BITS4, 8,
2201 ml_interp->po_filter.x.weights, ml_interp->po_filter.y.weights);
2202
2203 g_free (ml_interp->po_filter.x.weights);
2204 g_free (ml_interp->po_filter.y.weights);
2205}
2206
2207static void
2208pixops_medialib_composite (guchar *dest_buf,
2209 int dest_width,
2210 int dest_height,
2211 int dest_rowstride,
2212 int dest_channels,
2213 int dest_has_alpha,
2214 const guchar *src_buf,
2215 int src_width,
2216 int src_height,
2217 int src_rowstride,
2218 int src_channels,
2219 int src_has_alpha,
2220 int dest_x,
2221 int dest_y,
2222 int dest_region_width,
2223 int dest_region_height,
2224 double offset_x,
2225 double offset_y,
2226 double scale_x,
2227 double scale_y,
2228 PixopsInterpType interp_type,
2229 int overall_alpha)
2230{
2231 mlib_blend blend;
2232 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_27
= 0; if (!(dest_channels == 3 && dest_has_alpha)) _g_boolean_var_27
= 1; _g_boolean_var_27; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(dest_channels == 3 && dest_has_alpha)"
); return; } } while (0)
;
2233 g_return_if_fail (!(src_channels == 3 && src_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_28
= 0; if (!(src_channels == 3 && src_has_alpha)) _g_boolean_var_28
= 1; _g_boolean_var_28; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(src_channels == 3 && src_has_alpha)"
); return; } } while (0)
;
2234
2235 if (scale_x == 0 || scale_y == 0)
2236 return;
2237
2238 if (!medialib_initialized)
2239 _pixops_use_medialib ();
2240
2241 if (!use_medialib)
2242 {
2243 /* Use non-mediaLib version */
2244 _pixops_composite_real (dest_buf + (gsize)dest_y * dest_rowstride + (gsize)dest_x *
2245 dest_channels, dest_x - offset_x, dest_y -
2246 offset_y, dest_x + dest_region_width - offset_x,
2247 dest_y + dest_region_height - offset_y,
2248 dest_rowstride, dest_channels, dest_has_alpha,
2249 src_buf, src_width, src_height, src_rowstride,
2250 src_channels, src_has_alpha, scale_x, scale_y,
2251 interp_type, overall_alpha);
2252 }
2253 else
2254 {
2255 mlInterp ml_interp;
2256 mlib_image img_src, img_dest;
2257 double ml_offset_x, ml_offset_y;
2258
2259 if (!src_has_alpha && overall_alpha == 255 &&
2260 dest_channels <= src_channels)
2261 {
2262 pixops_medialib_scale (dest_buf, dest_region_width,
2263 dest_region_height, dest_rowstride,
2264 dest_channels, dest_has_alpha, src_buf,
2265 src_width, src_height, src_rowstride,
2266 src_channels, src_has_alpha, dest_x, dest_y,
2267 dest_region_width, dest_region_height,
2268 offset_x, offset_y, scale_x, scale_y,
2269 interp_type);
2270 return;
2271 }
2272
2273 mlib_ImageSetStruct (&img_src, MLIB_BYTE, src_channels,
2274 src_width, src_height, src_rowstride, src_buf);
2275
2276 if (dest_x == 0 && dest_y == 0 &&
2277 dest_width == dest_region_width &&
2278 dest_height == dest_region_height)
2279 {
2280 mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
2281 dest_width, dest_height, dest_rowstride,
2282 dest_buf);
2283 }
2284 else
2285 {
2286 mlib_u8 *data = dest_buf + (gsize)dest_y * dest_rowstride +
2287 (gsize)dest_x * dest_channels;
2288
2289 mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
2290 dest_region_width, dest_region_height,
2291 dest_rowstride, data);
2292 }
2293
2294 ml_offset_x = floor (offset_x) - dest_x;
2295 ml_offset_y = floor (offset_y) - dest_y;
2296
2297 if (interp_type == PIXOPS_INTERP_NEAREST)
2298 {
2299 blend = src_has_alpha ? MLIB_BLEND_CTK_SRC_OVER2 : MLIB_BLEND_CTK_SRC;
2300
2301 mlib_ImageZoomTranslateBlend (&img_dest,
2302 &img_src,
2303 scale_x,
2304 scale_y,
2305 ml_offset_x,
2306 ml_offset_y,
2307 MLIB_NEAREST,
2308 MLIB_EDGE_SRC_EXTEND_INDEF,
2309 blend,
2310 overall_alpha,
2311 1);
2312 }
2313 else
2314 {
2315 blend = src_has_alpha ? MLIB_BLEND_CTK_SRC_OVER : MLIB_BLEND_CTK_SRC;
2316
2317 if (interp_type == PIXOPS_INTERP_BILINEAR &&
2318 scale_x > 1.0 && scale_y > 1.0)
2319 {
2320 mlib_ImageZoomTranslateBlend (&img_dest,
2321 &img_src,
2322 scale_x,
2323 scale_y,
2324 ml_offset_x,
2325 ml_offset_y,
2326 MLIB_BILINEAR,
2327 MLIB_EDGE_SRC_EXTEND_INDEF,
2328 blend,
2329 overall_alpha,
2330 1);
2331 }
2332 else
2333 {
2334 medialib_get_interpolation (&ml_interp, interp_type, scale_x,
2335 scale_y, overall_alpha/255.0);
2336
2337 if (ml_interp.interp_table != NULL((void*)0))
2338 {
2339 mlib_ImageZoomTranslateTableBlend (&img_dest,
2340 &img_src,
2341 scale_x,
2342 scale_y,
2343 ml_offset_x + ml_interp.tx,
2344 ml_offset_y + ml_interp.ty,
2345 ml_interp.interp_table,
2346 MLIB_EDGE_SRC_EXTEND_INDEF,
2347 blend,
2348 1);
2349 mlib_ImageInterpTableDelete (ml_interp.interp_table);
2350 }
2351 else
2352 {
2353 /* Should not happen - Use non-mediaLib version */
2354 _pixops_composite_real (dest_buf + (gsize)dest_y * dest_rowstride +
2355 (gsize)dest_x * dest_channels,
2356 dest_x - offset_x, dest_y - offset_y,
2357 dest_x + dest_region_width - offset_x,
2358 dest_y + dest_region_height - offset_y,
2359 dest_rowstride, dest_channels,
2360 dest_has_alpha, src_buf, src_width,
2361 src_height, src_rowstride,
2362 src_channels, src_has_alpha, scale_x,
2363 scale_y, interp_type, overall_alpha);
2364 }
2365 }
2366 }
2367 }
2368}
2369#endif
2370
2371static void
2372_pixops_scale_real (guchar *dest_buf,
2373 int render_x0,
2374 int render_y0,
2375 int render_x1,
2376 int render_y1,
2377 int dest_rowstride,
2378 int dest_channels,
2379 gboolean dest_has_alpha,
2380 const guchar *src_buf,
2381 int src_width,
2382 int src_height,
2383 int src_rowstride,
2384 int src_channels,
2385 gboolean src_has_alpha,
2386 double scale_x,
2387 double scale_y,
2388 PixopsInterpType interp_type)
2389{
2390 PixopsFilter filter;
2391 PixopsLineFunc line_func;
2392 guchar *tmp_buf = NULL((void*)0); /* Temporary image for two-step scaling */
2393
2394 g_return_if_fail (!(dest_channels == 3 && dest_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_29
= 0; if (!(dest_channels == 3 && dest_has_alpha)) _g_boolean_var_29
= 1; _g_boolean_var_29; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(dest_channels == 3 && dest_has_alpha)"
); return; } } while (0)
;
2395 g_return_if_fail (!(src_channels == 3 && src_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_30
= 0; if (!(src_channels == 3 && src_has_alpha)) _g_boolean_var_30
= 1; _g_boolean_var_30; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(src_channels == 3 && src_has_alpha)"
); return; } } while (0)
;
2396 g_return_if_fail (!(src_has_alpha && !dest_has_alpha))do { if ((__builtin_expect (__extension__ ({ int _g_boolean_var_31
= 0; if (!(src_has_alpha && !dest_has_alpha)) _g_boolean_var_31
= 1; _g_boolean_var_31; }), 1))) { } else { g_return_if_fail_warning
(((gchar*) 0), ((const char*) (__func__)), "!(src_has_alpha && !dest_has_alpha)"
); return; } } while (0)
;
2397
2398 if (scale_x == 0 || scale_y == 0)
2399 return;
2400
2401 if (interp_type == PIXOPS_INTERP_NEAREST)
2402 {
2403 pixops_scale_nearest (dest_buf, render_x0, render_y0, render_x1,
2404 render_y1, dest_rowstride, dest_channels,
2405 dest_has_alpha, src_buf, src_width, src_height,
2406 src_rowstride, src_channels, src_has_alpha,
2407 scale_x, scale_y);
2408 return;
2409 }
2410
2411 if (need_to_prescale (scale_x, scale_y, interp_type))
2412 tmp_buf = prescale (&src_buf, &src_width, &src_height, &src_rowstride,
2413 src_channels, src_has_alpha,
2414 &scale_x, &scale_y, interp_type);
2415
2416 filter.overall_alpha = 1.0;
2417 if (!make_weights (&filter, interp_type, scale_x, scale_y))
2418 goto free_tmp;
2419
2420 if (filter.x.n == 2 && filter.y.n == 2 && dest_channels == 3 && src_channels == 3)
2421 line_func = scale_line_22_33;
2422 else
2423 line_func = scale_line;
2424
2425 pixops_process (dest_buf, render_x0, render_y0, render_x1, render_y1,
2426 dest_rowstride, dest_channels, dest_has_alpha,
2427 src_buf, src_width, src_height, src_rowstride, src_channels,
2428 src_has_alpha, scale_x, scale_y, 0, 0, 0, 0, 0,
2429 &filter, line_func, scale_pixel);
2430
2431 g_free (filter.x.weights);
2432 g_free (filter.y.weights);
2433free_tmp:
2434 g_free (tmp_buf);
2435}
2436
2437void
2438_pixops_scale (guchar *dest_buf,
2439 int dest_width,
2440 int dest_height,
2441 int dest_rowstride,
2442 int dest_channels,
2443 int dest_has_alpha,
2444 const guchar *src_buf,
2445 int src_width,
2446 int src_height,
2447 int src_rowstride,
2448 int src_channels,
2449 int src_has_alpha,
2450 int dest_x,
2451 int dest_y,
2452 int dest_region_width,
2453 int dest_region_height,
2454 double offset_x,
2455 double offset_y,
2456 double scale_x,
2457 double scale_y,
2458 PixopsInterpType interp_type)
2459{
2460 guchar *new_dest_buf;
2461 int render_x0;
2462 int render_y0;
2463 int render_x1;
2464 int render_y1;
2465
2466#ifdef USE_MEDIALIB
2467 pixops_medialib_scale (dest_buf, dest_width, dest_height, dest_rowstride,
2468 dest_channels, dest_has_alpha, src_buf, src_width,
2469 src_height, src_rowstride, src_channels,
2470 src_has_alpha, dest_x, dest_y, dest_region_width,
2471 dest_region_height, offset_x, offset_y, scale_x,
2472 scale_y, (PixopsInterpType)interp_type);
2473 return;
2474#endif
2475
2476 new_dest_buf = dest_buf + (gsize)dest_y * dest_rowstride + (gsize)dest_x * dest_channels;
2477 render_x0 = dest_x - offset_x;
2478 render_y0 = dest_y - offset_y;
2479 render_x1 = dest_x + dest_region_width - offset_x;
2480 render_y1 = dest_y + dest_region_height - offset_y;
2481
2482 _pixops_scale_real (new_dest_buf, render_x0, render_y0, render_x1,
2483 render_y1, dest_rowstride, dest_channels,
2484 dest_has_alpha, src_buf, src_width, src_height,
2485 src_rowstride, src_channels, src_has_alpha,
2486 scale_x, scale_y, (PixopsInterpType)interp_type);
2487}
2488
2489#ifdef USE_MEDIALIB
2490static void
2491pixops_medialib_scale (guchar *dest_buf,
2492 int dest_width,
2493 int dest_height,
2494 int dest_rowstride,
2495 int dest_channels,
2496 int dest_has_alpha,
2497 const guchar *src_buf,
2498 int src_width,
2499 int src_height,
2500 int src_rowstride,
2501 int src_channels,
2502 int src_has_alpha,
2503 int dest_x,
2504 int dest_y,
2505 int dest_region_width,
2506 int dest_region_height,
2507 double offset_x,
2508 double offset_y,
2509 double scale_x,
2510 double scale_y,
2511 PixopsInterpType interp_type)
2512{
2513 if (scale_x == 0 || scale_y == 0)
2514 return;
2515
2516 if (!medialib_initialized)
2517 _pixops_use_medialib ();
2518
2519 /*
2520 * We no longer support mediaLib 2.1 because it has a core dumping problem
2521 * in the mlib_ImageZoomTranslateTable function that has been corrected in
2522 * 2.2. Although the mediaLib_zoom function could be used, it does not
2523 * work properly if the source and destination images have different
2524 * values for "has_alpha" or "num_channels". The complicated if-logic
2525 * required to support both versions is not worth supporting
2526 * mediaLib 2.1 moving forward.
2527 */
2528 if (!use_medialib)
2529 {
2530 _pixops_scale_real (dest_buf + (gsize)dest_y * dest_rowstride + (gsize)dest_x *
2531 dest_channels, dest_x - offset_x, dest_y - offset_y,
2532 dest_x + dest_region_width - offset_x,
2533 dest_y + dest_region_height - offset_y,
2534 dest_rowstride, dest_channels, dest_has_alpha,
2535 src_buf, src_width, src_height, src_rowstride,
2536 src_channels, src_has_alpha, scale_x, scale_y,
2537 interp_type);
2538 }
2539 else
2540 {
2541 mlInterp ml_interp;
2542 mlib_image img_orig_src, img_src, img_dest;
2543 double ml_offset_x, ml_offset_y;
2544 guchar *tmp_buf = NULL((void*)0);
2545
2546 mlib_ImageSetStruct (&img_orig_src, MLIB_BYTE, src_channels, src_width,
2547 src_height, src_rowstride, src_buf);
2548
2549 if (dest_x == 0 && dest_y == 0 &&
2550 dest_width == dest_region_width &&
2551 dest_height == dest_region_height)
2552 {
2553 mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
2554 dest_width, dest_height, dest_rowstride,
2555 dest_buf);
2556 }
2557 else
2558 {
2559 mlib_u8 *data = dest_buf + (gsize)dest_y * dest_rowstride +
2560 (gsize)dest_x * dest_channels;
2561
2562 mlib_ImageSetStruct (&img_dest, MLIB_BYTE, dest_channels,
2563 dest_region_width, dest_region_height,
2564 dest_rowstride, data);
2565 }
2566
2567 ml_offset_x = floor (offset_x) - dest_x;
2568 ml_offset_y = floor (offset_y) - dest_y;
2569
2570 /*
2571 * Note that zoomTranslate and zoomTranslateTable are faster
2572 * than zoomTranslateBlend and zoomTranslateTableBlend. However
2573 * the faster functions only work in the following case:
2574 *
2575 * if (src_channels == dest_channels &&
2576 * (!src_alpha && interp_table != PIXOPS_INTERP_NEAREST))
2577 *
2578 * We use the faster versions if we can.
2579 *
2580 * Note when the interp_type is BILINEAR and the interpolation
2581 * table will be size 2x2 (when both x/y scale factors > 1.0),
2582 * then we do not bother building the interpolation table. In
2583 * this case we can just use MLIB_BILINEAR, which is faster than
2584 * using a specified interpolation table.
2585 */
2586 img_src = img_orig_src;
2587
2588 if (!src_has_alpha)
2589 {
2590 if (src_channels > dest_channels)
2591 {
2592 int channels = 3;
2593 int rowstride = (channels * src_width + 3) & ~3;
2594
2595 tmp_buf = g_malloc_n (src_rowstride, src_height);
2596
2597 if (src_buf != NULL((void*)0))
2598 {
2599 src_channels = channels;
2600 src_rowstride = rowstride;
2601
2602 mlib_ImageSetStruct (&img_src, MLIB_BYTE, src_channels,
2603 src_width, src_height, src_rowstride,
2604 tmp_buf);
2605 mlib_ImageChannelExtract (&img_src, &img_orig_src, 0xE);
2606 }
2607 }
2608 }
2609
2610 if (interp_type == PIXOPS_INTERP_NEAREST)
2611 {
2612 if (src_channels == dest_channels)
2613 {
2614 mlib_ImageZoomTranslate (&img_dest,
2615 &img_src,
2616 scale_x,
2617 scale_y,
2618 ml_offset_x,
2619 ml_offset_y,
2620 MLIB_NEAREST,
2621 MLIB_EDGE_SRC_EXTEND_INDEF);
2622 }
2623 else
2624 {
2625 mlib_ImageZoomTranslateBlend (&img_dest,
2626 &img_src,
2627 scale_x,
2628 scale_y,
2629 ml_offset_x,
2630 ml_offset_y,
2631 MLIB_NEAREST,
2632 MLIB_EDGE_SRC_EXTEND_INDEF,
2633 MLIB_BLEND_CTK_SRC,
2634 1.0,
2635 1);
2636 }
2637 }
2638 else if (src_channels == dest_channels && !src_has_alpha)
2639 {
2640 if (interp_type == PIXOPS_INTERP_BILINEAR &&
2641 scale_x > 1.0 && scale_y > 1.0)
2642 {
2643 mlib_ImageZoomTranslate (&img_dest,
2644 &img_src,
2645 scale_x,
2646 scale_y,
2647 ml_offset_x,
2648 ml_offset_y,
2649 MLIB_BILINEAR,
2650 MLIB_EDGE_SRC_EXTEND_INDEF);
2651 }
2652 else
2653 {
2654 medialib_get_interpolation (&ml_interp, interp_type,
2655 scale_x, scale_y, 1.0);
2656
2657 if (ml_interp.interp_table != NULL((void*)0))
2658 {
2659 mlib_ImageZoomTranslateTable (&img_dest,
2660 &img_src,
2661 scale_x,
2662 scale_y,
2663 ml_offset_x + ml_interp.tx,
2664 ml_offset_y + ml_interp.ty,
2665 ml_interp.interp_table,
2666 MLIB_EDGE_SRC_EXTEND_INDEF);
2667
2668 mlib_ImageInterpTableDelete (ml_interp.interp_table);
2669 }
2670 else
2671 {
2672 /* Should not happen. */
2673 mlib_filter ml_filter;
2674
2675 switch (interp_type)
2676 {
2677 case PIXOPS_INTERP_BILINEAR:
2678 ml_filter = MLIB_BILINEAR;
2679 break;
2680
2681 case PIXOPS_INTERP_TILES:
2682 ml_filter = MLIB_BILINEAR;
2683 break;
2684
2685 case PIXOPS_INTERP_HYPER:
2686 ml_filter = MLIB_BICUBIC;
2687 break;
2688 }
2689
2690 mlib_ImageZoomTranslate (&img_dest,
2691 &img_src,
2692 scale_x,
2693 scale_y,
2694 ml_offset_x,
2695 ml_offset_y,
2696 ml_filter,
2697 MLIB_EDGE_SRC_EXTEND_INDEF);
2698 }
2699 }
2700 }
2701
2702 /* Deal with case where src_channels != dest_channels || src_has_alpha */
2703 else if (interp_type == PIXOPS_INTERP_BILINEAR &&
2704 scale_x > 1.0 && scale_y > 1.0)
2705 {
2706 mlib_ImageZoomTranslateBlend (&img_dest,
2707 &img_src,
2708 scale_x,
2709 scale_y,
2710 ml_offset_x,
2711 ml_offset_y,
2712 MLIB_BILINEAR,
2713 MLIB_EDGE_SRC_EXTEND_INDEF,
2714 MLIB_BLEND_CTK_SRC,
2715 1.0,
2716 1);
2717 }
2718 else
2719 {
2720 medialib_get_interpolation (&ml_interp, interp_type,
2721 scale_x, scale_y, 1.0);
2722
2723 if (ml_interp.interp_table != NULL((void*)0))
2724 {
2725 mlib_ImageZoomTranslateTableBlend (&img_dest,
2726 &img_src,
2727 scale_x,
2728 scale_y,
2729 ml_offset_x + ml_interp.tx,
2730 ml_offset_y + ml_interp.ty,
2731 ml_interp.interp_table,
2732 MLIB_EDGE_SRC_EXTEND_INDEF,
2733 MLIB_BLEND_CTK_SRC,
2734 1);
2735 mlib_ImageInterpTableDelete (ml_interp.interp_table);
2736 }
2737 else
2738 {
2739 mlib_filter ml_filter;
2740
2741 switch (interp_type)
2742 {
2743 case PIXOPS_INTERP_BILINEAR:
2744 ml_filter = MLIB_BILINEAR;
2745 break;
2746
2747 case PIXOPS_INTERP_TILES:
2748 ml_filter = MLIB_BILINEAR;
2749 break;
2750
2751 case PIXOPS_INTERP_HYPER:
2752 ml_filter = MLIB_BICUBIC;
2753 break;
2754 }
2755
2756 mlib_ImageZoomTranslate (&img_dest,
2757 &img_src,
2758 scale_x,
2759 scale_y,
2760 ml_offset_x,
2761 ml_offset_y,
2762 ml_filter,
2763 MLIB_EDGE_SRC_EXTEND_INDEF);
2764 }
2765 }
2766
2767 if (tmp_buf != NULL((void*)0))
2768 g_free (tmp_buf);
2769 }
2770}
2771#endif