Coverage Report

Created: 2026-02-26 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/qtbase/src/gui/painting/qimagescale.cpp
Line
Count
Source
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// Copyright (C) 2004, 2005 Daniel M. Duley., (C) Carsten Haitzler and various contributors., (C) Willem Monsuwe <willem@stack.nl>
3
// SPDX-License-Identifier: BSD-2-Clause AND Imlib2
4
// Qt-Security score:significant reason:default
5
#include <private/qimagescale_p.h>
6
#include <private/qdrawhelper_p.h>
7
#include <private/qimage_p.h>
8
9
#include "qimage.h"
10
#include "qcolor.h"
11
#include "qrgba64_p.h"
12
#include "qrgbafloat.h"
13
14
QT_BEGIN_NAMESPACE
15
16
/*
17
 * Copyright (C) 2004, 2005 Daniel M. Duley
18
 *
19
 * Redistribution and use in source and binary forms, with or without
20
 * modification, are permitted provided that the following conditions
21
 * are met:
22
 *
23
 * 1. Redistributions of source code must retain the above copyright
24
 *    notice, this list of conditions and the following disclaimer.
25
 * 2. Redistributions in binary form must reproduce the above copyright
26
 *    notice, this list of conditions and the following disclaimer in the
27
 *    documentation and/or other materials provided with the distribution.
28
 *
29
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
30
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
33
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 */
41
42
/* OTHER CREDITS:
43
 *
44
 * This is the normal smoothscale method, based on Imlib2's smoothscale.
45
 *
46
 * Originally I took the algorithm used in NetPBM and Qt and added MMX/3dnow
47
 * optimizations. It ran in about 1/2 the time as Qt. Then I ported Imlib's
48
 * C algorithm and it ran at about the same speed as my MMX optimized one...
49
 * Finally I ported Imlib's MMX version and it ran in less than half the
50
 * time as my MMX algorithm, (taking only a quarter of the time Qt does).
51
 * After further optimization it seems to run at around 1/6th.
52
 *
53
 * Changes include formatting, namespaces and other C++'ings, removal of old
54
 * #ifdef'ed code, and removal of unneeded border calculation code.
55
 * Later the code has been refactored, an SSE4.1 optimizated path have been
56
 * added instead of the removed MMX assembler, and scaling of clipped area
57
 * removed, and an RGBA64 version written
58
 *
59
 * Imlib2 is (C) Carsten Haitzler and various contributors. The MMX code
60
 * is by Willem Monsuwe <willem@stack.nl>. All other modifications are
61
 * (C) Daniel M. Duley.
62
 */
63
64
65
namespace QImageScale {
66
    static const unsigned int** qimageCalcYPoints(const unsigned int *src, int sw, int sh, int dh);
67
    static int* qimageCalcXPoints(int sw, int dw);
68
    static int* qimageCalcApoints(int s, int d, int up);
69
    static QImageScaleInfo* qimageFreeScaleInfo(QImageScaleInfo *isi);
70
    static QImageScaleInfo *qimageCalcScaleInfo(const QImage &img, int sw, int sh, int dw, int dh, char aa);
71
}
72
73
using namespace QImageScale;
74
75
//
76
// Code ported from Imlib...
77
//
78
79
static const unsigned int** QImageScale::qimageCalcYPoints(const unsigned int *src,
80
                                                           int sw, int sh, int dh)
81
1.91k
{
82
1.91k
    const unsigned int **p;
83
1.91k
    int j = 0, rv = 0;
84
1.91k
    qint64 val, inc;
85
86
1.91k
    if (dh < 0) {
87
0
        dh = -dh;
88
0
        rv = 1;
89
0
    }
90
1.91k
    p = new const unsigned int* [dh+1];
91
92
1.91k
    int up = qAbs(dh) >= sh;
93
1.91k
    val = up ? 0x8000 * sh / dh - 0x8000 : 0;
94
1.91k
    inc = (((qint64)sh) << 16) / dh;
95
145k
    for (int i = 0; i < dh; i++) {
96
143k
        p[j++] = src + qMax(0LL, val >> 16) * sw;
97
143k
        val += inc;
98
143k
    }
99
1.91k
    if (rv) {
100
0
        for (int i = dh / 2; --i >= 0; ) {
101
0
            const unsigned int *tmp = p[i];
102
0
            p[i] = p[dh - i - 1];
103
0
            p[dh - i - 1] = tmp;
104
0
        }
105
0
    }
106
1.91k
    return(p);
107
1.91k
}
108
109
static int* QImageScale::qimageCalcXPoints(int sw, int dw)
110
1.91k
{
111
1.91k
    int *p, j = 0, rv = 0;
112
1.91k
    qint64 val, inc;
113
114
1.91k
    if (dw < 0) {
115
0
        dw = -dw;
116
0
        rv = 1;
117
0
    }
118
1.91k
    p = new int[dw+1];
119
120
1.91k
    int up = qAbs(dw) >= sw;
121
1.91k
    val = up ? 0x8000 * sw / dw - 0x8000 : 0;
122
1.91k
    inc = (((qint64)sw) << 16) / dw;
123
174k
    for (int i = 0; i < dw; i++) {
124
172k
        p[j++] = qMax(0LL, val >> 16);
125
172k
        val += inc;
126
172k
    }
127
128
1.91k
    if (rv) {
129
0
        for (int i = dw / 2; --i >= 0; ) {
130
0
            int tmp = p[i];
131
0
            p[i] = p[dw - i - 1];
132
0
            p[dw - i - 1] = tmp;
133
0
        }
134
0
    }
135
1.91k
   return p;
136
1.91k
}
137
138
static int* QImageScale::qimageCalcApoints(int s, int d, int up)
139
3.83k
{
140
3.83k
    int *p, j = 0, rv = 0;
141
142
3.83k
    if (d < 0) {
143
0
        rv = 1;
144
0
        d = -d;
145
0
    }
146
3.83k
    p = new int[d];
147
148
3.83k
    if (up) {
149
        /* scaling up */
150
28
        qint64 val = 0x8000 * s / d - 0x8000;
151
28
        qint64 inc = (((qint64)s) << 16) / d;
152
2.46k
        for (int i = 0; i < d; i++) {
153
2.44k
            int pos = val >> 16;
154
2.44k
            if (pos < 0)
155
0
                p[j++] = 0;
156
2.44k
            else if (pos >= (s - 1))
157
28
                p[j++] = 0;
158
2.41k
            else
159
2.41k
                p[j++] = (val >> 8) - ((val >> 8) & 0xffffff00);
160
2.44k
            val += inc;
161
2.44k
        }
162
3.80k
    } else {
163
        /* scaling down */
164
3.80k
        qint64 val = 0;
165
3.80k
        qint64 inc = (((qint64)s) << 16) / d;
166
3.80k
        int Cp = (((d << 14) + s - 1) / s);
167
318k
        for (int i = 0; i < d; i++) {
168
314k
            int ap = ((0x10000 - (val & 0xffff)) * Cp) >> 16;
169
314k
            p[j] = ap | (Cp << 16);
170
314k
            j++;
171
314k
            val += inc;
172
314k
        }
173
3.80k
    }
174
3.83k
    if (rv) {
175
0
        int tmp;
176
0
        for (int i = d / 2; --i >= 0; ) {
177
0
            tmp = p[i];
178
0
            p[i] = p[d - i - 1];
179
0
            p[d - i - 1] = tmp;
180
0
        }
181
0
    }
182
3.83k
    return p;
183
3.83k
}
184
185
static QImageScaleInfo* QImageScale::qimageFreeScaleInfo(QImageScaleInfo *isi)
186
1.91k
{
187
1.91k
    if (isi) {
188
1.91k
        delete[] isi->xpoints;
189
1.91k
        delete[] isi->ypoints;
190
1.91k
        delete[] isi->xapoints;
191
1.91k
        delete[] isi->yapoints;
192
1.91k
        delete isi;
193
1.91k
    }
194
1.91k
    return nullptr;
195
1.91k
}
196
197
static QImageScaleInfo* QImageScale::qimageCalcScaleInfo(const QImage &img,
198
                                                         int sw, int sh,
199
                                                         int dw, int dh, char aa)
200
1.91k
{
201
1.91k
    QImageScaleInfo *isi;
202
1.91k
    int scw, sch;
203
204
1.91k
    scw = dw * qlonglong(img.width()) / sw;
205
1.91k
    sch = dh * qlonglong(img.height()) / sh;
206
207
1.91k
    isi = new QImageScaleInfo;
208
1.91k
    if (!isi)
209
0
        return nullptr;
210
1.91k
    isi->sh = sh;
211
1.91k
    isi->sw = sw;
212
213
1.91k
    isi->xup_yup = (qAbs(dw) >= sw) + ((qAbs(dh) >= sh) << 1);
214
215
1.91k
    isi->xpoints = qimageCalcXPoints(img.width(), scw);
216
1.91k
    if (!isi->xpoints)
217
0
        return qimageFreeScaleInfo(isi);
218
1.91k
    isi->ypoints = qimageCalcYPoints((const unsigned int *)img.scanLine(0),
219
1.91k
                                     img.bytesPerLine() / 4, img.height(), sch);
220
1.91k
    if (!isi->ypoints)
221
0
        return qimageFreeScaleInfo(isi);
222
1.91k
    if (aa) {
223
1.91k
        isi->xapoints = qimageCalcApoints(img.width(), scw, isi->xup_yup & 1);
224
1.91k
        if (!isi->xapoints)
225
0
            return qimageFreeScaleInfo(isi);
226
1.91k
        isi->yapoints = qimageCalcApoints(img.height(), sch, isi->xup_yup & 2);
227
1.91k
        if (!isi->yapoints)
228
0
            return qimageFreeScaleInfo(isi);
229
1.91k
    }
230
1.91k
    return isi;
231
1.91k
}
232
233
234
static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
235
                                             int dw, int dh, int dow, int sow);
236
237
static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
238
                                             int dw, int dh, int dow, int sow);
239
240
static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest,
241
                                         int dw, int dh, int dow, int sow);
242
243
#if defined(QT_COMPILER_SUPPORTS_SSE4_1)
244
template<bool RGB>
245
void qt_qimageScaleAARGBA_up_x_down_y_sse4(QImageScaleInfo *isi, unsigned int *dest,
246
                                           int dw, int dh, int dow, int sow);
247
template<bool RGB>
248
void qt_qimageScaleAARGBA_down_x_up_y_sse4(QImageScaleInfo *isi, unsigned int *dest,
249
                                           int dw, int dh, int dow, int sow);
250
template<bool RGB>
251
void qt_qimageScaleAARGBA_down_xy_sse4(QImageScaleInfo *isi, unsigned int *dest,
252
                                       int dw, int dh, int dow, int sow);
253
#endif
254
255
#if defined(QT_COMPILER_SUPPORTS_LSX)
256
template<bool RGB>
257
void qt_qimageScaleAARGBA_up_x_down_y_lsx(QImageScaleInfo *isi, unsigned int *dest,
258
                                          int dw, int dh, int dow, int sow);
259
template<bool RGB>
260
void qt_qimageScaleAARGBA_down_x_up_y_lsx(QImageScaleInfo *isi, unsigned int *dest,
261
                                          int dw, int dh, int dow, int sow);
262
template<bool RGB>
263
void qt_qimageScaleAARGBA_down_xy_lsx(QImageScaleInfo *isi, unsigned int *dest,
264
                                      int dw, int dh, int dow, int sow);
265
#endif
266
267
#if defined(__ARM_NEON__)
268
template<bool RGB>
269
void qt_qimageScaleAARGBA_up_x_down_y_neon(QImageScaleInfo *isi, unsigned int *dest,
270
                                           int dw, int dh, int dow, int sow);
271
template<bool RGB>
272
void qt_qimageScaleAARGBA_down_x_up_y_neon(QImageScaleInfo *isi, unsigned int *dest,
273
                                           int dw, int dh, int dow, int sow);
274
template<bool RGB>
275
void qt_qimageScaleAARGBA_down_xy_neon(QImageScaleInfo *isi, unsigned int *dest,
276
                                       int dw, int dh, int dow, int sow);
277
#endif
278
279
static void qt_qimageScaleAARGBA_up_xy(QImageScaleInfo *isi, unsigned int *dest,
280
                                       int dw, int dh, int dow, int sow)
281
0
{
282
0
    const unsigned int **ypoints = isi->ypoints;
283
0
    int *xpoints = isi->xpoints;
284
0
    int *xapoints = isi->xapoints;
285
0
    int *yapoints = isi->yapoints;
286
287
    /* go through every scanline in the output buffer */
288
0
    auto scaleSection = [&] (int yStart, int yEnd) {
289
0
        for (int y = yStart; y < yEnd; ++y) {
290
            /* calculate the source line we'll scan from */
291
0
            const unsigned int *sptr = ypoints[y];
292
0
            unsigned int *dptr = dest + (y * dow);
293
0
            const int yap = yapoints[y];
294
0
            if (yap > 0) {
295
0
                for (int x = 0; x < dw; x++) {
296
0
                    const unsigned int *pix = sptr + xpoints[x];
297
0
                    const int xap = xapoints[x];
298
0
                    if (xap > 0)
299
0
                        *dptr = interpolate_4_pixels(pix, pix + sow, xap, yap);
300
0
                    else
301
0
                        *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - yap, pix[sow], yap);
302
0
                    dptr++;
303
0
                }
304
0
            } else {
305
0
                for (int x = 0; x < dw; x++) {
306
0
                    const unsigned int *pix = sptr + xpoints[x];
307
0
                    const int xap = xapoints[x];
308
0
                    if (xap > 0)
309
0
                        *dptr = INTERPOLATE_PIXEL_256(pix[0], 256 - xap, pix[1], xap);
310
0
                    else
311
0
                        *dptr = pix[0];
312
0
                    dptr++;
313
0
                }
314
0
            }
315
0
        }
316
0
    };
317
0
    multithread_pixels_function(isi, dh, scaleSection);
318
0
}
319
320
/* scale by area sampling - with alpha */
321
static void qt_qimageScaleAARGBA(QImageScaleInfo *isi, unsigned int *dest,
322
                                 int dw, int dh, int dow, int sow)
323
0
{
324
    /* scaling up both ways */
325
0
    if (isi->xup_yup == 3) {
326
0
        qt_qimageScaleAARGBA_up_xy(isi, dest, dw, dh, dow, sow);
327
0
    }
328
    /* if we're scaling down vertically */
329
0
    else if (isi->xup_yup == 1) {
330
0
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
331
0
        if (qCpuHasFeature(SSE4_1))
332
0
            qt_qimageScaleAARGBA_up_x_down_y_sse4<false>(isi, dest, dw, dh, dow, sow);
333
0
        else
334
#elif defined(QT_COMPILER_SUPPORTS_LSX)
335
        if (qCpuHasFeature(LSX))
336
            qt_qimageScaleAARGBA_up_x_down_y_lsx<false>(isi, dest, dw, dh, dow, sow);
337
        else
338
#elif defined(__ARM_NEON__)
339
        if (qCpuHasFeature(NEON))
340
            qt_qimageScaleAARGBA_up_x_down_y_neon<false>(isi, dest, dw, dh, dow, sow);
341
        else
342
#endif
343
0
        qt_qimageScaleAARGBA_up_x_down_y(isi, dest, dw, dh, dow, sow);
344
0
    }
345
    /* if we're scaling down horizontally */
346
0
    else if (isi->xup_yup == 2) {
347
0
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
348
0
        if (qCpuHasFeature(SSE4_1))
349
0
            qt_qimageScaleAARGBA_down_x_up_y_sse4<false>(isi, dest, dw, dh, dow, sow);
350
0
        else
351
#elif defined(QT_COMPILER_SUPPORTS_LSX)
352
        if (qCpuHasFeature(LSX))
353
            qt_qimageScaleAARGBA_down_x_up_y_lsx<false>(isi, dest, dw, dh, dow, sow);
354
        else
355
#elif defined(__ARM_NEON__)
356
        if (qCpuHasFeature(NEON))
357
            qt_qimageScaleAARGBA_down_x_up_y_neon<false>(isi, dest, dw, dh, dow, sow);
358
        else
359
#endif
360
0
        qt_qimageScaleAARGBA_down_x_up_y(isi, dest, dw, dh, dow, sow);
361
0
    }
362
    /* if we're scaling down horizontally & vertically */
363
0
    else {
364
0
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
365
0
        if (qCpuHasFeature(SSE4_1))
366
0
            qt_qimageScaleAARGBA_down_xy_sse4<false>(isi, dest, dw, dh, dow, sow);
367
0
        else
368
#elif defined(QT_COMPILER_SUPPORTS_LSX)
369
        if (qCpuHasFeature(LSX))
370
            qt_qimageScaleAARGBA_down_xy_lsx<false>(isi, dest, dw, dh, dow, sow);
371
        else
372
#elif defined(__ARM_NEON__)
373
        if (qCpuHasFeature(NEON))
374
            qt_qimageScaleAARGBA_down_xy_neon<false>(isi, dest, dw, dh, dow, sow);
375
        else
376
#endif
377
0
        qt_qimageScaleAARGBA_down_xy(isi, dest, dw, dh, dow, sow);
378
0
    }
379
0
}
380
381
inline static void qt_qimageScaleAARGBA_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b, int &a)
382
0
{
383
0
    r = qRed(*pix)   * xyap;
384
0
    g = qGreen(*pix) * xyap;
385
0
    b = qBlue(*pix)  * xyap;
386
0
    a = qAlpha(*pix) * xyap;
387
0
    int j;
388
0
    for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) {
389
0
        pix += step;
390
0
        r += qRed(*pix)   * Cxy;
391
0
        g += qGreen(*pix) * Cxy;
392
0
        b += qBlue(*pix)  * Cxy;
393
0
        a += qAlpha(*pix) * Cxy;
394
0
    }
395
0
    pix += step;
396
0
    r += qRed(*pix)   * j;
397
0
    g += qGreen(*pix) * j;
398
0
    b += qBlue(*pix)  * j;
399
0
    a += qAlpha(*pix) * j;
400
0
}
401
402
static void qt_qimageScaleAARGBA_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
403
                                             int dw, int dh, int dow, int sow)
404
0
{
405
0
    const unsigned int **ypoints = isi->ypoints;
406
0
    int *xpoints = isi->xpoints;
407
0
    int *xapoints = isi->xapoints;
408
0
    int *yapoints = isi->yapoints;
409
410
    /* go through every scanline in the output buffer */
411
0
    auto scaleSection = [&] (int yStart, int yEnd) {
412
0
        for (int y = yStart; y < yEnd; ++y) {
413
0
            int Cy = yapoints[y] >> 16;
414
0
            int yap = yapoints[y] & 0xffff;
415
416
0
            unsigned int *dptr = dest + (y * dow);
417
0
            for (int x = 0; x < dw; x++) {
418
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
419
0
                int r, g, b, a;
420
0
                qt_qimageScaleAARGBA_helper(sptr, yap, Cy, sow, r, g, b, a);
421
422
0
                int xap = xapoints[x];
423
0
                if (xap > 0) {
424
0
                    int rr, gg, bb, aa;
425
0
                    qt_qimageScaleAARGBA_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
426
427
0
                    r = r * (256 - xap);
428
0
                    g = g * (256 - xap);
429
0
                    b = b * (256 - xap);
430
0
                    a = a * (256 - xap);
431
0
                    r = (r + (rr * xap)) >> 8;
432
0
                    g = (g + (gg * xap)) >> 8;
433
0
                    b = (b + (bb * xap)) >> 8;
434
0
                    a = (a + (aa * xap)) >> 8;
435
0
                }
436
0
                *dptr++ = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
437
0
            }
438
0
        }
439
0
    };
440
0
    multithread_pixels_function(isi, dh, scaleSection);
441
0
}
442
443
static void qt_qimageScaleAARGBA_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
444
                                             int dw, int dh, int dow, int sow)
445
0
{
446
0
    const unsigned int **ypoints = isi->ypoints;
447
0
    int *xpoints = isi->xpoints;
448
0
    int *xapoints = isi->xapoints;
449
0
    int *yapoints = isi->yapoints;
450
451
    /* go through every scanline in the output buffer */
452
0
    auto scaleSection = [&] (int yStart, int yEnd) {
453
0
        for (int y = yStart; y < yEnd; ++y) {
454
0
            unsigned int *dptr = dest + (y * dow);
455
0
            for (int x = 0; x < dw; x++) {
456
0
                int Cx = xapoints[x] >> 16;
457
0
                int xap = xapoints[x] & 0xffff;
458
459
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
460
0
                int r, g, b, a;
461
0
                qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, r, g, b, a);
462
463
0
                int yap = yapoints[y];
464
0
                if (yap > 0) {
465
0
                    int rr, gg, bb, aa;
466
0
                    qt_qimageScaleAARGBA_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
467
468
0
                    r = r * (256 - yap);
469
0
                    g = g * (256 - yap);
470
0
                    b = b * (256 - yap);
471
0
                    a = a * (256 - yap);
472
0
                    r = (r + (rr * yap)) >> 8;
473
0
                    g = (g + (gg * yap)) >> 8;
474
0
                    b = (b + (bb * yap)) >> 8;
475
0
                    a = (a + (aa * yap)) >> 8;
476
0
                }
477
0
                *dptr = qRgba(r >> 14, g >> 14, b >> 14, a >> 14);
478
0
                dptr++;
479
0
            }
480
0
        }
481
0
    };
482
0
    multithread_pixels_function(isi, dh, scaleSection);
483
0
}
484
485
static void qt_qimageScaleAARGBA_down_xy(QImageScaleInfo *isi, unsigned int *dest,
486
                                         int dw, int dh, int dow, int sow)
487
0
{
488
0
    const unsigned int **ypoints = isi->ypoints;
489
0
    int *xpoints = isi->xpoints;
490
0
    int *xapoints = isi->xapoints;
491
0
    int *yapoints = isi->yapoints;
492
493
0
    auto scaleSection = [&] (int yStart, int yEnd) {
494
0
        for (int y = yStart; y < yEnd; ++y) {
495
0
            int Cy = (yapoints[y]) >> 16;
496
0
            int yap = (yapoints[y]) & 0xffff;
497
498
0
            unsigned int *dptr = dest + (y * dow);
499
0
            for (int x = 0; x < dw; x++) {
500
0
                int Cx = xapoints[x] >> 16;
501
0
                int xap = xapoints[x] & 0xffff;
502
503
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
504
0
                int rx, gx, bx, ax;
505
0
                qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
506
507
0
                int r = ((rx>>4) * yap);
508
0
                int g = ((gx>>4) * yap);
509
0
                int b = ((bx>>4) * yap);
510
0
                int a = ((ax>>4) * yap);
511
512
0
                int j;
513
0
                for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
514
0
                    sptr += sow;
515
0
                    qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
516
0
                    r += ((rx>>4) * Cy);
517
0
                    g += ((gx>>4) * Cy);
518
0
                    b += ((bx>>4) * Cy);
519
0
                    a += ((ax>>4) * Cy);
520
0
                }
521
0
                sptr += sow;
522
0
                qt_qimageScaleAARGBA_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
523
524
0
                r += ((rx>>4) * j);
525
0
                g += ((gx>>4) * j);
526
0
                b += ((bx>>4) * j);
527
0
                a += ((ax>>4) * j);
528
529
0
                *dptr = qRgba(r >> 24, g >> 24, b >> 24, a >> 24);
530
0
                dptr++;
531
0
            }
532
0
        }
533
0
    };
534
0
    multithread_pixels_function(isi, dh, scaleSection);
535
0
}
536
537
#if QT_CONFIG(raster_64bit)
538
static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest,
539
                                             int dw, int dh, int dow, int sow);
540
541
static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
542
                                             int dw, int dh, int dow, int sow);
543
544
static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
545
                                         int dw, int dh, int dow, int sow);
546
547
static void qt_qimageScaleRgba64_up_xy(QImageScaleInfo *isi, QRgba64 *dest,
548
                                       int dw, int dh, int dow, int sow)
549
0
{
550
0
    const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints;
551
0
    int *xpoints = isi->xpoints;
552
0
    int *xapoints = isi->xapoints;
553
0
    int *yapoints = isi->yapoints;
554
555
0
    auto scaleSection = [&] (int yStart, int yEnd) {
556
0
        for (int y = yStart; y < yEnd; ++y) {
557
0
            const QRgba64 *sptr = ypoints[y];
558
0
            QRgba64 *dptr = dest + (y * dow);
559
0
            const int yap = yapoints[y];
560
0
            if (yap > 0) {
561
0
                for (int x = 0; x < dw; x++) {
562
0
                    const QRgba64 *pix = sptr + xpoints[x];
563
0
                    const int xap = xapoints[x];
564
0
                    if (xap > 0)
565
0
                        *dptr = interpolate_4_pixels_rgb64(pix, pix + sow, xap * 256, yap * 256);
566
0
                    else
567
0
                        *dptr = interpolate256(pix[0], 256 - yap, pix[sow], yap);
568
0
                    dptr++;
569
0
                }
570
0
            } else {
571
0
                for (int x = 0; x < dw; x++) {
572
0
                    const QRgba64 *pix = sptr + xpoints[x];
573
0
                    const int xap = xapoints[x];
574
0
                    if (xap > 0)
575
0
                        *dptr = interpolate256(pix[0], 256 - xap, pix[1], xap);
576
0
                    else
577
0
                        *dptr = pix[0];
578
0
                    dptr++;
579
0
                }
580
0
            }
581
0
        }
582
0
    };
583
0
    multithread_pixels_function(isi, dh, scaleSection);
584
0
}
585
586
void qt_qimageScaleRgba64(QImageScaleInfo *isi, QRgba64 *dest,
587
                          int dw, int dh, int dow, int sow)
588
0
{
589
0
    if (isi->xup_yup == 3)
590
0
        qt_qimageScaleRgba64_up_xy(isi, dest, dw, dh, dow, sow);
591
0
    else if (isi->xup_yup == 1)
592
0
        qt_qimageScaleRgba64_up_x_down_y(isi, dest, dw, dh, dow, sow);
593
0
    else if (isi->xup_yup == 2)
594
0
        qt_qimageScaleRgba64_down_x_up_y(isi, dest, dw, dh, dow, sow);
595
0
    else
596
0
        qt_qimageScaleRgba64_down_xy(isi, dest, dw, dh, dow, sow);
597
0
}
598
599
inline static void qt_qimageScaleRgba64_helper(const QRgba64 *pix, int xyap, int Cxy, int step, qint64 &r, qint64 &g, qint64 &b, qint64 &a)
600
0
{
601
0
    r = pix->red()   * xyap;
602
0
    g = pix->green() * xyap;
603
0
    b = pix->blue()  * xyap;
604
0
    a = pix->alpha() * xyap;
605
0
    int j;
606
0
    for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){
607
0
        pix += step;
608
0
        r += pix->red()   * Cxy;
609
0
        g += pix->green() * Cxy;
610
0
        b += pix->blue()  * Cxy;
611
0
        a += pix->alpha() * Cxy;
612
0
    }
613
0
    pix += step;
614
0
    r += pix->red()   * j;
615
0
    g += pix->green() * j;
616
0
    b += pix->blue()  * j;
617
0
    a += pix->alpha() * j;
618
0
}
619
620
static void qt_qimageScaleRgba64_up_x_down_y(QImageScaleInfo *isi, QRgba64 *dest,
621
                                             int dw, int dh, int dow, int sow)
622
0
{
623
0
    const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints;
624
0
    int *xpoints = isi->xpoints;
625
0
    int *xapoints = isi->xapoints;
626
0
    int *yapoints = isi->yapoints;
627
628
0
    auto scaleSection = [&] (int yStart, int yEnd) {
629
0
        for (int y = yStart; y < yEnd; ++y) {
630
0
            int Cy = (yapoints[y]) >> 16;
631
0
            int yap = (yapoints[y]) & 0xffff;
632
633
0
            QRgba64 *dptr = dest + (y * dow);
634
0
            for (int x = 0; x < dw; x++) {
635
0
                const QRgba64 *sptr = ypoints[y] + xpoints[x];
636
0
                qint64 r, g, b, a;
637
0
                qt_qimageScaleRgba64_helper(sptr, yap, Cy, sow, r, g, b, a);
638
639
0
                int xap = xapoints[x];
640
0
                if (xap > 0) {
641
0
                    qint64 rr, gg, bb, aa;
642
0
                    qt_qimageScaleRgba64_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
643
644
0
                    r = r * (256 - xap);
645
0
                    g = g * (256 - xap);
646
0
                    b = b * (256 - xap);
647
0
                    a = a * (256 - xap);
648
0
                    r = (r + (rr * xap)) >> 8;
649
0
                    g = (g + (gg * xap)) >> 8;
650
0
                    b = (b + (bb * xap)) >> 8;
651
0
                    a = (a + (aa * xap)) >> 8;
652
0
                }
653
0
                *dptr++ = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
654
0
            }
655
0
        }
656
0
    };
657
0
    multithread_pixels_function(isi, dh, scaleSection);
658
0
}
659
660
static void qt_qimageScaleRgba64_down_x_up_y(QImageScaleInfo *isi, QRgba64 *dest,
661
                                             int dw, int dh, int dow, int sow)
662
0
{
663
0
    const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints;
664
0
    int *xpoints = isi->xpoints;
665
0
    int *xapoints = isi->xapoints;
666
0
    int *yapoints = isi->yapoints;
667
668
0
    auto scaleSection = [&] (int yStart, int yEnd) {
669
0
        for (int y = yStart; y < yEnd; ++y) {
670
0
            QRgba64 *dptr = dest + (y * dow);
671
0
            for (int x = 0; x < dw; x++) {
672
0
                int Cx = xapoints[x] >> 16;
673
0
                int xap = xapoints[x] & 0xffff;
674
675
0
                const QRgba64 *sptr = ypoints[y] + xpoints[x];
676
0
                qint64 r, g, b, a;
677
0
                qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, r, g, b, a);
678
679
0
                int yap = yapoints[y];
680
0
                if (yap > 0) {
681
0
                    qint64 rr, gg, bb, aa;
682
0
                    qt_qimageScaleRgba64_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
683
684
0
                    r = r * (256 - yap);
685
0
                    g = g * (256 - yap);
686
0
                    b = b * (256 - yap);
687
0
                    a = a * (256 - yap);
688
0
                    r = (r + (rr * yap)) >> 8;
689
0
                    g = (g + (gg * yap)) >> 8;
690
0
                    b = (b + (bb * yap)) >> 8;
691
0
                    a = (a + (aa * yap)) >> 8;
692
0
                }
693
0
                *dptr = qRgba64(r >> 14, g >> 14, b >> 14, a >> 14);
694
0
                dptr++;
695
0
            }
696
0
        }
697
0
    };
698
0
    multithread_pixels_function(isi, dh, scaleSection);
699
0
}
700
701
static void qt_qimageScaleRgba64_down_xy(QImageScaleInfo *isi, QRgba64 *dest,
702
                                         int dw, int dh, int dow, int sow)
703
0
{
704
0
    const QRgba64 **ypoints = (const QRgba64 **)isi->ypoints;
705
0
    int *xpoints = isi->xpoints;
706
0
    int *xapoints = isi->xapoints;
707
0
    int *yapoints = isi->yapoints;
708
709
0
    auto scaleSection = [&] (int yStart, int yEnd) {
710
0
        for (int y = yStart; y < yEnd; ++y) {
711
0
            int Cy = (yapoints[y]) >> 16;
712
0
            int yap = (yapoints[y]) & 0xffff;
713
714
0
            QRgba64 *dptr = dest + (y * dow);
715
0
            for (int x = 0; x < dw; x++) {
716
0
                int Cx = xapoints[x] >> 16;
717
0
                int xap = xapoints[x] & 0xffff;
718
719
0
                const QRgba64 *sptr = ypoints[y] + xpoints[x];
720
0
                qint64 rx, gx, bx, ax;
721
0
                qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
722
723
0
                qint64 r = rx * yap;
724
0
                qint64 g = gx * yap;
725
0
                qint64 b = bx * yap;
726
0
                qint64 a = ax * yap;
727
0
                int j;
728
0
                for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
729
0
                    sptr += sow;
730
0
                    qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
731
0
                    r += rx * Cy;
732
0
                    g += gx * Cy;
733
0
                    b += bx * Cy;
734
0
                    a += ax * Cy;
735
0
                }
736
0
                sptr += sow;
737
0
                qt_qimageScaleRgba64_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
738
0
                r += rx * j;
739
0
                g += gx * j;
740
0
                b += bx * j;
741
0
                a += ax * j;
742
743
0
                *dptr = qRgba64(r >> 28, g >> 28, b >> 28, a >> 28);
744
0
                dptr++;
745
0
            }
746
0
        }
747
0
    };
748
0
    multithread_pixels_function(isi, dh, scaleSection);
749
0
}
750
#endif
751
752
#if QT_CONFIG(raster_fp)
753
static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
754
                                             int dw, int dh, int dow, int sow);
755
756
static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
757
                                             int dw, int dh, int dow, int sow);
758
759
static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
760
                                         int dw, int dh, int dow, int sow);
761
762
static void qt_qimageScaleRgbaFP_up_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
763
                                       int dw, int dh, int dow, int sow)
764
0
{
765
0
    const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
766
0
    int *xpoints = isi->xpoints;
767
0
    int *xapoints = isi->xapoints;
768
0
    int *yapoints = isi->yapoints;
769
770
0
    auto scaleSection = [&] (int yStart, int yEnd) {
771
0
        for (int y = yStart; y < yEnd; ++y) {
772
0
            const QRgbaFloat32 *sptr = ypoints[y];
773
0
            QRgbaFloat32 *dptr = dest + (y * dow);
774
0
            const int yap = yapoints[y];
775
0
            if (yap > 0) {
776
0
                for (int x = 0; x < dw; x++) {
777
0
                    const QRgbaFloat32 *pix = sptr + xpoints[x];
778
0
                    const int xap = xapoints[x];
779
0
                    if (xap > 0)
780
0
                        *dptr = interpolate_4_pixels_rgba32f(pix, pix + sow, xap * 256, yap * 256);
781
0
                    else
782
0
                        *dptr = interpolate_rgba32f(pix[0], 256 - yap, pix[sow], yap);
783
0
                    dptr++;
784
0
                }
785
0
            } else {
786
0
                for (int x = 0; x < dw; x++) {
787
0
                    const QRgbaFloat32 *pix = sptr + xpoints[x];
788
0
                    const int xap = xapoints[x];
789
0
                    if (xap > 0)
790
0
                        *dptr = interpolate_rgba32f(pix[0], 256 - xap, pix[1], xap);
791
0
                    else
792
0
                        *dptr = pix[0];
793
0
                    dptr++;
794
0
                }
795
0
            }
796
0
        }
797
0
    };
798
0
    multithread_pixels_function(isi, dh, scaleSection);
799
0
}
800
801
void qt_qimageScaleRgbaFP(QImageScaleInfo *isi, QRgbaFloat32 *dest,
802
                          int dw, int dh, int dow, int sow)
803
0
{
804
0
    if (isi->xup_yup == 3)
805
0
        qt_qimageScaleRgbaFP_up_xy(isi, dest, dw, dh, dow, sow);
806
0
    else if (isi->xup_yup == 1)
807
0
        qt_qimageScaleRgbaFP_up_x_down_y(isi, dest, dw, dh, dow, sow);
808
0
    else if (isi->xup_yup == 2)
809
0
        qt_qimageScaleRgbaFP_down_x_up_y(isi, dest, dw, dh, dow, sow);
810
0
    else
811
0
        qt_qimageScaleRgbaFP_down_xy(isi, dest, dw, dh, dow, sow);
812
0
}
813
814
inline static void qt_qimageScaleRgbaFP_helper(const QRgbaFloat32 *pix, int xyap, int Cxy, int step, float &r, float &g, float &b, float &a)
815
0
{
816
0
    constexpr float f = (1.0f / float(1<<14));
817
0
    const float xyapf = xyap * f;
818
0
    const float Cxyf = Cxy * f;
819
0
    r = pix->red()   * xyapf;
820
0
    g = pix->green() * xyapf;
821
0
    b = pix->blue()  * xyapf;
822
0
    a = pix->alpha() * xyapf;
823
0
    int j;
824
0
    for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy ){
825
0
        pix += step;
826
0
        r += pix->red()   * Cxyf;
827
0
        g += pix->green() * Cxyf;
828
0
        b += pix->blue()  * Cxyf;
829
0
        a += pix->alpha() * Cxyf;
830
0
    }
831
0
    pix += step;
832
0
    const float jf = j * f;
833
0
    r += pix->red()   * jf;
834
0
    g += pix->green() * jf;
835
0
    b += pix->blue()  * jf;
836
0
    a += pix->alpha() * jf;
837
0
}
838
839
static void qt_qimageScaleRgbaFP_up_x_down_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
840
                                             int dw, int dh, int dow, int sow)
841
0
{
842
0
    const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
843
0
    int *xpoints = isi->xpoints;
844
0
    int *xapoints = isi->xapoints;
845
0
    int *yapoints = isi->yapoints;
846
847
0
    auto scaleSection = [&] (int yStart, int yEnd) {
848
0
        for (int y = yStart; y < yEnd; ++y) {
849
0
            int Cy = (yapoints[y]) >> 16;
850
0
            int yap = (yapoints[y]) & 0xffff;
851
852
0
            QRgbaFloat32 *dptr = dest + (y * dow);
853
0
            for (int x = 0; x < dw; x++) {
854
0
                const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
855
0
                float r, g, b, a;
856
0
                qt_qimageScaleRgbaFP_helper(sptr, yap, Cy, sow, r, g, b, a);
857
858
0
                int xap = xapoints[x];
859
0
                float xapf = xap * (1.f / 256.f);
860
0
                if (xap > 0) {
861
0
                    float rr, gg, bb, aa;
862
0
                    qt_qimageScaleRgbaFP_helper(sptr + 1, yap, Cy, sow, rr, gg, bb, aa);
863
864
0
                    r = (r * (1.0f - xapf) + (rr * xapf));
865
0
                    g = (g * (1.0f - xapf) + (gg * xapf));
866
0
                    b = (b * (1.0f - xapf) + (bb * xapf));
867
0
                    a = (a * (1.0f - xapf) + (aa * xapf));
868
0
                }
869
0
                *dptr++ = QRgbaFloat32{r, g, b, a};
870
0
            }
871
0
        }
872
0
    };
873
0
    multithread_pixels_function(isi, dh, scaleSection);
874
0
}
875
876
static void qt_qimageScaleRgbaFP_down_x_up_y(QImageScaleInfo *isi, QRgbaFloat32 *dest,
877
                                             int dw, int dh, int dow, int sow)
878
0
{
879
0
    const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
880
0
    int *xpoints = isi->xpoints;
881
0
    int *xapoints = isi->xapoints;
882
0
    int *yapoints = isi->yapoints;
883
884
0
    auto scaleSection = [&] (int yStart, int yEnd) {
885
0
        for (int y = yStart; y < yEnd; ++y) {
886
0
            QRgbaFloat32 *dptr = dest + (y * dow);
887
0
            for (int x = 0; x < dw; x++) {
888
0
                int Cx = xapoints[x] >> 16;
889
0
                int xap = xapoints[x] & 0xffff;
890
891
0
                const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
892
0
                float r, g, b, a;
893
0
                qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, r, g, b, a);
894
895
0
                int yap = yapoints[y];
896
0
                float yapf = yap * (1.f / 256.f);
897
0
                if (yap > 0) {
898
0
                    float rr, gg, bb, aa;
899
0
                    qt_qimageScaleRgbaFP_helper(sptr + sow, xap, Cx, 1, rr, gg, bb, aa);
900
901
0
                    r = (r * (1.0f - yapf) + (rr * yapf));
902
0
                    g = (g * (1.0f - yapf) + (gg * yapf));
903
0
                    b = (b * (1.0f - yapf) + (bb * yapf));
904
0
                    a = (a * (1.0f - yapf) + (aa * yapf));
905
0
                }
906
0
                *dptr++ = QRgbaFloat32{r, g, b, a};
907
0
            }
908
0
        }
909
0
    };
910
0
    multithread_pixels_function(isi, dh, scaleSection);
911
0
}
912
913
static void qt_qimageScaleRgbaFP_down_xy(QImageScaleInfo *isi, QRgbaFloat32 *dest,
914
                                         int dw, int dh, int dow, int sow)
915
0
{
916
0
    const QRgbaFloat32 **ypoints = (const QRgbaFloat32 **)isi->ypoints;
917
0
    int *xpoints = isi->xpoints;
918
0
    int *xapoints = isi->xapoints;
919
0
    int *yapoints = isi->yapoints;
920
921
0
    auto scaleSection = [&] (int yStart, int yEnd) {
922
0
        constexpr float f = 1.f / float(1 << 14);
923
0
        for (int y = yStart; y < yEnd; ++y) {
924
0
            int Cy = (yapoints[y]) >> 16;
925
0
            int yap = (yapoints[y]) & 0xffff;
926
927
0
            QRgbaFloat32 *dptr = dest + (y * dow);
928
0
            for (int x = 0; x < dw; x++) {
929
0
                int Cx = xapoints[x] >> 16;
930
0
                int xap = xapoints[x] & 0xffff;
931
932
0
                const QRgbaFloat32 *sptr = ypoints[y] + xpoints[x];
933
0
                float rx, gx, bx, ax;
934
0
                qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
935
936
0
                const float yapf = yap * f;
937
0
                const float Cyf = Cy * f;
938
0
                float r = rx * yapf;
939
0
                float g = gx * yapf;
940
0
                float b = bx * yapf;
941
0
                float a = ax * yapf;
942
0
                int j;
943
0
                for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
944
0
                    sptr += sow;
945
0
                    qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
946
0
                    r += rx * Cyf;
947
0
                    g += gx * Cyf;
948
0
                    b += bx * Cyf;
949
0
                    a += ax * Cyf;
950
0
                }
951
0
                sptr += sow;
952
0
                qt_qimageScaleRgbaFP_helper(sptr, xap, Cx, 1, rx, gx, bx, ax);
953
0
                const float jf = j * f;
954
0
                r += rx * jf;
955
0
                g += gx * jf;
956
0
                b += bx * jf;
957
0
                a += ax * jf;
958
959
0
                *dptr++ = QRgbaFloat32{r, g, b, a};
960
0
            }
961
0
        }
962
0
    };
963
0
    multithread_pixels_function(isi, dh, scaleSection);
964
0
}
965
#endif
966
967
static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
968
                                            int dw, int dh, int dow, int sow);
969
970
static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
971
                                            int dw, int dh, int dow, int sow);
972
973
static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest,
974
                                        int dw, int dh, int dow, int sow);
975
976
/* scale by area sampling - IGNORE the ALPHA byte*/
977
static void qt_qimageScaleAARGB(QImageScaleInfo *isi, unsigned int *dest,
978
                                int dw, int dh, int dow, int sow)
979
1.91k
{
980
    /* scaling up both ways */
981
1.91k
    if (isi->xup_yup == 3) {
982
0
        qt_qimageScaleAARGBA_up_xy(isi, dest, dw, dh, dow, sow);
983
0
    }
984
    /* if we're scaling down vertically */
985
1.91k
    else if (isi->xup_yup == 1) {
986
13
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
987
13
        if (qCpuHasFeature(SSE4_1))
988
13
            qt_qimageScaleAARGBA_up_x_down_y_sse4<true>(isi, dest, dw, dh, dow, sow);
989
0
        else
990
#elif defined QT_COMPILER_SUPPORTS_LSX
991
        if (qCpuHasFeature(LSX))
992
            qt_qimageScaleAARGBA_up_x_down_y_lsx<true>(isi, dest, dw, dh, dow, sow);
993
        else
994
#elif defined(__ARM_NEON__)
995
        if (qCpuHasFeature(NEON))
996
            qt_qimageScaleAARGBA_up_x_down_y_neon<true>(isi, dest, dw, dh, dow, sow);
997
        else
998
#endif
999
0
        qt_qimageScaleAARGB_up_x_down_y(isi, dest, dw, dh, dow, sow);
1000
13
    }
1001
    /* if we're scaling down horizontally */
1002
1.90k
    else if (isi->xup_yup == 2) {
1003
15
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
1004
15
        if (qCpuHasFeature(SSE4_1))
1005
15
            qt_qimageScaleAARGBA_down_x_up_y_sse4<true>(isi, dest, dw, dh, dow, sow);
1006
0
        else
1007
#elif defined QT_COMPILER_SUPPORTS_LSX
1008
        if (qCpuHasFeature(LSX))
1009
            qt_qimageScaleAARGBA_down_x_up_y_lsx<true>(isi, dest, dw, dh, dow, sow);
1010
        else
1011
#elif defined(__ARM_NEON__)
1012
        if (qCpuHasFeature(NEON))
1013
            qt_qimageScaleAARGBA_down_x_up_y_neon<true>(isi, dest, dw, dh, dow, sow);
1014
        else
1015
#endif
1016
0
        qt_qimageScaleAARGB_down_x_up_y(isi, dest, dw, dh, dow, sow);
1017
15
    }
1018
    /* if we're scaling down horizontally & vertically */
1019
1.89k
    else {
1020
1.89k
#ifdef QT_COMPILER_SUPPORTS_SSE4_1
1021
1.89k
        if (qCpuHasFeature(SSE4_1))
1022
1.89k
            qt_qimageScaleAARGBA_down_xy_sse4<true>(isi, dest, dw, dh, dow, sow);
1023
0
        else
1024
#elif defined QT_COMPILER_SUPPORTS_LSX
1025
        if (qCpuHasFeature(LSX))
1026
            qt_qimageScaleAARGBA_down_xy_lsx<true>(isi, dest, dw, dh, dow, sow);
1027
        else
1028
#elif defined(__ARM_NEON__)
1029
        if (qCpuHasFeature(NEON))
1030
            qt_qimageScaleAARGBA_down_xy_neon<true>(isi, dest, dw, dh, dow, sow);
1031
        else
1032
#endif
1033
0
        qt_qimageScaleAARGB_down_xy(isi, dest, dw, dh, dow, sow);
1034
1.89k
    }
1035
1.91k
}
1036
1037
1038
inline static void qt_qimageScaleAARGB_helper(const unsigned int *pix, int xyap, int Cxy, int step, int &r, int &g, int &b)
1039
0
{
1040
0
    r = qRed(*pix)   * xyap;
1041
0
    g = qGreen(*pix) * xyap;
1042
0
    b = qBlue(*pix)  * xyap;
1043
0
    int j;
1044
0
    for (j = (1 << 14) - xyap; j > Cxy; j -= Cxy) {
1045
0
        pix += step;
1046
0
        r += qRed(*pix)   * Cxy;
1047
0
        g += qGreen(*pix) * Cxy;
1048
0
        b += qBlue(*pix)  * Cxy;
1049
0
    }
1050
0
    pix += step;
1051
0
    r += qRed(*pix)   * j;
1052
0
    g += qGreen(*pix) * j;
1053
0
    b += qBlue(*pix)  * j;
1054
0
}
1055
1056
static void qt_qimageScaleAARGB_up_x_down_y(QImageScaleInfo *isi, unsigned int *dest,
1057
                                            int dw, int dh, int dow, int sow)
1058
0
{
1059
0
    const unsigned int **ypoints = isi->ypoints;
1060
0
    int *xpoints = isi->xpoints;
1061
0
    int *xapoints = isi->xapoints;
1062
0
    int *yapoints = isi->yapoints;
1063
1064
    /* go through every scanline in the output buffer */
1065
0
    auto scaleSection = [&] (int yStart, int yEnd) {
1066
0
        for (int y = yStart; y < yEnd; ++y) {
1067
0
            int Cy = yapoints[y] >> 16;
1068
0
            int yap = yapoints[y] & 0xffff;
1069
1070
0
            unsigned int *dptr = dest + (y * dow);
1071
0
            for (int x = 0; x < dw; x++) {
1072
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
1073
0
                int r, g, b;
1074
0
                qt_qimageScaleAARGB_helper(sptr, yap, Cy, sow, r, g, b);
1075
1076
0
                int xap = xapoints[x];
1077
0
                if (xap > 0) {
1078
0
                    int rr, bb, gg;
1079
0
                    qt_qimageScaleAARGB_helper(sptr + 1, yap, Cy, sow, rr, gg, bb);
1080
1081
0
                    r = r * (256 - xap);
1082
0
                    g = g * (256 - xap);
1083
0
                    b = b * (256 - xap);
1084
0
                    r = (r + (rr * xap)) >> 8;
1085
0
                    g = (g + (gg * xap)) >> 8;
1086
0
                    b = (b + (bb * xap)) >> 8;
1087
0
                }
1088
0
                *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
1089
0
            }
1090
0
        }
1091
0
    };
1092
0
    multithread_pixels_function(isi, dh, scaleSection);
1093
0
}
1094
1095
static void qt_qimageScaleAARGB_down_x_up_y(QImageScaleInfo *isi, unsigned int *dest,
1096
                                            int dw, int dh, int dow, int sow)
1097
0
{
1098
0
    const unsigned int **ypoints = isi->ypoints;
1099
0
    int *xpoints = isi->xpoints;
1100
0
    int *xapoints = isi->xapoints;
1101
0
    int *yapoints = isi->yapoints;
1102
1103
    /* go through every scanline in the output buffer */
1104
0
    auto scaleSection = [&] (int yStart, int yEnd) {
1105
0
        for (int y = yStart; y < yEnd; ++y) {
1106
0
            unsigned int *dptr = dest + (y * dow);
1107
0
            for (int x = 0; x < dw; x++) {
1108
0
                int Cx = xapoints[x] >> 16;
1109
0
                int xap = xapoints[x] & 0xffff;
1110
1111
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
1112
0
                int r, g, b;
1113
0
                qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, r, g, b);
1114
1115
0
                int yap = yapoints[y];
1116
0
                if (yap > 0) {
1117
0
                    int rr, bb, gg;
1118
0
                    qt_qimageScaleAARGB_helper(sptr + sow, xap, Cx, 1, rr, gg, bb);
1119
1120
0
                    r = r * (256 - yap);
1121
0
                    g = g * (256 - yap);
1122
0
                    b = b * (256 - yap);
1123
0
                    r = (r + (rr * yap)) >> 8;
1124
0
                    g = (g + (gg * yap)) >> 8;
1125
0
                    b = (b + (bb * yap)) >> 8;
1126
0
                }
1127
0
                *dptr++ = qRgb(r >> 14, g >> 14, b >> 14);
1128
0
            }
1129
0
        }
1130
0
    };
1131
0
    multithread_pixels_function(isi, dh, scaleSection);
1132
0
}
1133
1134
static void qt_qimageScaleAARGB_down_xy(QImageScaleInfo *isi, unsigned int *dest,
1135
                                        int dw, int dh, int dow, int sow)
1136
0
{
1137
0
    const unsigned int **ypoints = isi->ypoints;
1138
0
    int *xpoints = isi->xpoints;
1139
0
    int *xapoints = isi->xapoints;
1140
0
    int *yapoints = isi->yapoints;
1141
1142
0
    auto scaleSection = [&] (int yStart, int yEnd) {
1143
0
        for (int y = yStart; y < yEnd; ++y) {
1144
0
            int Cy = yapoints[y] >> 16;
1145
0
            int yap = yapoints[y] & 0xffff;
1146
1147
0
            unsigned int *dptr = dest + (y * dow);
1148
0
            for (int x = 0; x < dw; x++) {
1149
0
                int Cx = xapoints[x] >> 16;
1150
0
                int xap = xapoints[x] & 0xffff;
1151
1152
0
                const unsigned int *sptr = ypoints[y] + xpoints[x];
1153
0
                int rx, gx, bx;
1154
0
                qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
1155
1156
0
                int r = (rx >> 4) * yap;
1157
0
                int g = (gx >> 4) * yap;
1158
0
                int b = (bx >> 4) * yap;
1159
1160
0
                int j;
1161
0
                for (j = (1 << 14) - yap; j > Cy; j -= Cy) {
1162
0
                    sptr += sow;
1163
0
                    qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
1164
1165
0
                    r += (rx >> 4) * Cy;
1166
0
                    g += (gx >> 4) * Cy;
1167
0
                    b += (bx >> 4) * Cy;
1168
0
                }
1169
0
                sptr += sow;
1170
0
                qt_qimageScaleAARGB_helper(sptr, xap, Cx, 1, rx, gx, bx);
1171
1172
0
                r += (rx >> 4) * j;
1173
0
                g += (gx >> 4) * j;
1174
0
                b += (bx >> 4) * j;
1175
1176
0
                *dptr = qRgb(r >> 24, g >> 24, b >> 24);
1177
0
                dptr++;
1178
0
            }
1179
0
        }
1180
0
    };
1181
0
    multithread_pixels_function(isi, dh, scaleSection);
1182
0
}
1183
1184
QImage qSmoothScaleImage(const QImage &src, int dw, int dh)
1185
1.91k
{
1186
1.91k
    QImage buffer;
1187
1.91k
    if (src.isNull() || dw <= 0 || dh <= 0)
1188
0
        return buffer;
1189
1190
1.91k
    int w = src.width();
1191
1.91k
    int h = src.height();
1192
1.91k
    QImageScaleInfo *scaleinfo =
1193
1.91k
        qimageCalcScaleInfo(src, w, h, dw, dh, true);
1194
1.91k
    if (!scaleinfo)
1195
0
        return buffer;
1196
1197
1.91k
    buffer = QImage(dw, dh, src.format());
1198
1.91k
    if (buffer.isNull()) {
1199
0
        qWarning("QImage: out of memory, returning null");
1200
0
        qimageFreeScaleInfo(scaleinfo);
1201
0
        return QImage();
1202
0
    }
1203
1204
1.91k
#if QT_CONFIG(raster_fp)
1205
1.91k
    if (qt_fpColorPrecision(src.format()))
1206
0
        qt_qimageScaleRgbaFP(scaleinfo, (QRgbaFloat32 *)buffer.scanLine(0),
1207
0
                             dw, dh, dw, src.bytesPerLine() / 16);
1208
1.91k
    else
1209
1.91k
#endif
1210
1.91k
#if QT_CONFIG(raster_64bit)
1211
1.91k
    if (src.depth() > 32)
1212
0
        qt_qimageScaleRgba64(scaleinfo, (QRgba64 *)buffer.scanLine(0),
1213
0
                             dw, dh, dw, src.bytesPerLine() / 8);
1214
1.91k
    else
1215
1.91k
#endif
1216
1.91k
    if (src.hasAlphaChannel() || src.format() == QImage::Format_CMYK8888)
1217
0
        qt_qimageScaleAARGBA(scaleinfo, (unsigned int *)buffer.scanLine(0),
1218
0
                             dw, dh, dw, src.bytesPerLine() / 4);
1219
1.91k
    else
1220
1.91k
        qt_qimageScaleAARGB(scaleinfo, (unsigned int *)buffer.scanLine(0),
1221
1.91k
                            dw, dh, dw, src.bytesPerLine() / 4);
1222
1223
1.91k
    qimageFreeScaleInfo(scaleinfo);
1224
1.91k
    return buffer;
1225
1.91k
}
1226
1227
QT_END_NAMESPACE