diff options
Diffstat (limited to 'src/gui/painting/qgrayraster.c')
-rw-r--r-- | src/gui/painting/qgrayraster.c | 236 |
1 files changed, 101 insertions, 135 deletions
diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c index 0143e9b602..3c222c49e1 100644 --- a/src/gui/painting/qgrayraster.c +++ b/src/gui/painting/qgrayraster.c @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only /***************************************************************************/ /* */ @@ -187,6 +151,7 @@ typedef ptrdiff_t QT_FT_PtrDist; #include <stdlib.h> #include <stdio.h> +#include <assert.h> #define QT_FT_UNUSED( x ) (void) x @@ -216,11 +181,8 @@ typedef ptrdiff_t QT_FT_PtrDist; #define PIXEL_BITS 8 #define ONE_PIXEL ( 1L << PIXEL_BITS ) -#define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) -#define SUBPIXELS( x ) ( (TPos)(x) * ONE_PIXEL ) -#define FLOOR( x ) ( (x) & -ONE_PIXEL ) -#define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) -#define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) +#define TRUNC( x ) (TCoord)( (x) >> PIXEL_BITS ) +#define FRACT( x ) (TCoord)( (x) & ( ONE_PIXEL - 1 ) ) #if PIXEL_BITS >= 6 #define UPSCALE( x ) ( (x) * ( ONE_PIXEL >> 6 ) ) @@ -548,17 +510,13 @@ QT_FT_END_STMNT TPos x2, TCoord y2 ) { - TCoord ex1, ex2, fx1, fx2, delta, mod; - int p, first, dx; + TCoord ex1, ex2, fx1, fx2, first, dy, delta, mod; + TPos p, dx; int incr; - dx = x2 - x1; - ex1 = TRUNC( x1 ); ex2 = TRUNC( x2 ); - fx1 = (TCoord)( x1 - SUBPIXELS( ex1 ) ); - fx2 = (TCoord)( x2 - SUBPIXELS( ex2 ) ); /* trivial case. Happens often */ if ( y1 == y2 ) @@ -567,26 +525,27 @@ QT_FT_END_STMNT return; } + fx1 = FRACT( x1 ); + fx2 = FRACT( x2 ); + /* everything is located in a single cell. That is easy! */ /* */ if ( ex1 == ex2 ) - { - delta = y2 - y1; - ras.area += (TArea)( fx1 + fx2 ) * delta; - ras.cover += delta; - return; - } + goto End; /* ok, we'll have to render a run of adjacent cells on the same */ /* scanline... */ /* */ - p = ( ONE_PIXEL - fx1 ) * ( y2 - y1 ); - first = ONE_PIXEL; - incr = 1; + dx = x2 - x1; + dy = y2 - y1; - if ( dx < 0 ) + if ( dx > 0 ) { - p = fx1 * ( y2 - y1 ); + p = ( ONE_PIXEL - fx1 ) * dy; + first = ONE_PIXEL; + incr = 1; + } else { + p = fx1 * dy; first = 0; incr = -1; dx = -dx; @@ -596,42 +555,42 @@ QT_FT_END_STMNT ras.area += (TArea)( fx1 + first ) * delta; ras.cover += delta; - - ex1 += incr; + y1 += delta; + ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); - y1 += delta; if ( ex1 != ex2 ) { TCoord lift, rem; - p = ONE_PIXEL * ( y2 - y1 + delta ); + p = ONE_PIXEL * dy; QT_FT_DIV_MOD( TCoord, p, dx, lift, rem ); - mod -= (int)dx; - - while ( ex1 != ex2 ) + do { delta = lift; mod += rem; - if ( mod >= 0 ) + if ( mod >= (TCoord)dx ) { mod -= (TCoord)dx; delta++; } - ras.area += (TArea)ONE_PIXEL * delta; + ras.area += (TArea)( ONE_PIXEL * delta ); ras.cover += delta; y1 += delta; ex1 += incr; gray_set_cell( RAS_VAR_ ex1, ey ); - } + } while ( ex1 != ex2 ); } + fx1 = ONE_PIXEL - first; - delta = y2 - y1; - ras.area += (TArea)( fx2 + ONE_PIXEL - first ) * delta; - ras.cover += delta; + End: + dy = y2 - y1; + + ras.area += (TArea)( ( fx1 + fx2 ) * dy ); + ras.cover += dy; } @@ -643,25 +602,21 @@ QT_FT_END_STMNT gray_render_line( RAS_ARG_ TPos to_x, TPos to_y ) { - TCoord ey1, ey2, fy1, fy2, mod; - TPos dx, dy, x, x2; - int p, first; - int delta, rem, lift, incr; - + TCoord ey1, ey2, fy1, fy2, first, delta, mod; + TPos p, dx, dy, x, x2; + int incr; ey1 = TRUNC( ras.y ); ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ - fy1 = (TCoord)( ras.y - SUBPIXELS( ey1 ) ); - fy2 = (TCoord)( to_y - SUBPIXELS( ey2 ) ); - - dx = to_x - ras.x; - dy = to_y - ras.y; /* perform vertical clipping */ if ( ( ey1 >= ras.max_ey && ey2 >= ras.max_ey ) || ( ey1 < ras.min_ey && ey2 < ras.min_ey ) ) goto End; + fy1 = FRACT( ras.y ); + fy2 = FRACT( to_y ); + /* everything is on a single scanline */ if ( ey1 == ey2 ) { @@ -669,23 +624,31 @@ QT_FT_END_STMNT goto End; } + dx = to_x - ras.x; + dy = to_y - ras.y; + /* vertical line - avoid calling gray_render_scanline */ if ( dx == 0 ) { TCoord ex = TRUNC( ras.x ); - TCoord two_fx = (TCoord)( ( ras.x - SUBPIXELS( ex ) ) << 1 ); + TCoord two_fx = FRACT( ras.x ) << 1; TPos area, max_ey1; - first = ONE_PIXEL; - if ( dy < 0 ) + if ( dy > 0) + { + first = ONE_PIXEL; + } + else + { first = 0; + } - delta = (int)( first - fy1 ); + delta = first - fy1; ras.area += (TArea)two_fx * delta; ras.cover += delta; - delta = (int)( first + first - ONE_PIXEL ); + delta = first + first - ONE_PIXEL; area = (TArea)two_fx * delta; max_ey1 = ras.count_ey + ras.min_ey; if (dy < 0) { @@ -738,11 +701,13 @@ QT_FT_END_STMNT } /* ok, we have to render several scanlines */ - p = ( ONE_PIXEL - fy1 ) * dx; - first = ONE_PIXEL; - incr = 1; - - if ( dy < 0 ) + if ( dy > 0) + { + p = ( ONE_PIXEL - fy1 ) * dx; + first = ONE_PIXEL; + incr = 1; + } + else { p = fy1 * dx; first = 0; @@ -750,13 +715,9 @@ QT_FT_END_STMNT dy = -dy; } - delta = (int)( p / dy ); - mod = (int)( p % dy ); - if ( mod < 0 ) - { - delta--; - mod += (TCoord)dy; - } + /* the fractional part of x-delta is mod/dy. It is essential to */ + /* keep track of its accumulation for accurate rendering. */ + QT_FT_DIV_MOD( TCoord, p, dy, delta, mod ); x = ras.x + delta; gray_render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, (TCoord)first ); @@ -766,34 +727,36 @@ QT_FT_END_STMNT if ( ey1 != ey2 ) { - p = ONE_PIXEL * dx; - QT_FT_DIV_MOD( int, p, dy, lift, rem ); - mod -= (int)dy; + TCoord lift, rem; - while ( ey1 != ey2 ) + + p = ONE_PIXEL * dx; + QT_FT_DIV_MOD( TCoord, p, dy, lift, rem ); + + do { delta = lift; mod += rem; - if ( mod >= 0 ) + if ( mod >= (TCoord)dy ) { - mod -= (int)dy; + mod -= (TCoord)dy; delta++; } x2 = x + delta; - gray_render_scanline( RAS_VAR_ ey1, x, - (TCoord)( ONE_PIXEL - first ), x2, - (TCoord)first ); + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + x2, first ); x = x2; ey1 += incr; gray_set_cell( RAS_VAR_ TRUNC( x ), ey1 ); - } + } while ( ey1 != ey2 ); } - gray_render_scanline( RAS_VAR_ ey1, x, - (TCoord)( ONE_PIXEL - first ), to_x, - fy2 ); + gray_render_scanline( RAS_VAR_ ey1, + x, ONE_PIXEL - first, + to_x, fy2 ); End: ras.x = to_x; @@ -828,8 +791,8 @@ QT_FT_END_STMNT dx = to_x - ras.x; dy = to_y - ras.y; - fx1 = ras.x - SUBPIXELS( ex1 ); - fy1 = ras.y - SUBPIXELS( ey1 ); + fx1 = FRACT( ras.x ); + fy1 = FRACT( ras.y ); if ( ex1 == ex2 && ey1 == ey2 ) /* inside one cell */ ; @@ -926,8 +889,8 @@ QT_FT_END_STMNT } while ( ex1 != ex2 || ey1 != ey2 ); } - fx2 = to_x - SUBPIXELS( ex2 ); - fy2 = to_y - SUBPIXELS( ey2 ); + fx2 = FRACT( to_x ); + fy2 = FRACT( to_y ); ras.cover += ( fy2 - fy1 ); ras.area += ( fy2 - fy1 ) * ( fx1 + fx2 ); @@ -1103,7 +1066,7 @@ QT_FT_END_STMNT L = QT_FT_HYPOT( dx_, dy_ ); /* Avoid possible arithmetic overflow below by splitting. */ - if ( L > 32767 ) + if ( L >= (1 << 23) ) goto Split; /* Max deviation may be as much as (s/L) * 3/4 (if Hain's v = 1). */ @@ -1253,13 +1216,13 @@ QT_FT_END_STMNT y += (TCoord)ras.min_ey; x += (TCoord)ras.min_ex; - /* QT_FT_Span.x is a 16-bit short, so limit our coordinates appropriately */ - if ( x >= 32767 ) - x = 32767; + /* QT_FT_Span.x is an int, so limit our coordinates appropriately */ + if ( x >= (1 << 23) ) + x = (1 << 23) - 1; - /* QT_FT_Span.y is a 16-bit short, so limit our coordinates appropriately */ - if ( y >= 32767 ) - y = 32767; + /* QT_FT_Span.y is an int, so limit our coordinates appropriately */ + if ( y >= (1 << 23) ) + y = (1 << 23) - 1; if ( coverage ) { @@ -1273,10 +1236,10 @@ QT_FT_END_STMNT span = ras.gray_spans + count - 1; if ( count > 0 && span->y == y && - (int)span->x + span->len == (int)x && + span->x + span->len == x && span->coverage == coverage ) { - span->len = (unsigned short)( span->len + acount ); + span->len = span->len + acount; return; } @@ -1319,9 +1282,9 @@ QT_FT_END_STMNT span++; /* add a gray span to the current list */ - span->x = (short)x; - span->len = (unsigned short)acount; - span->y = (short)y; + span->x = x; + span->len = acount; + span->y = y; span->coverage = (unsigned char)coverage; ras.num_gray_spans++; @@ -1839,8 +1802,11 @@ QT_FT_END_STMNT if ( !raster || !raster->buffer || !raster->buffer_size ) return ErrRaster_Invalid_Argument; - if ( raster->worker ) - raster->worker->skip_spans = params->skip_spans; + /* Should always be non-null, it is set by raster_reset() which is always */ + /* called with a non-null pool, and a pool_size >= MINIMUM_POOL_SIZE. */ + assert(raster->worker); + + raster->worker->skip_spans = params->skip_spans; /* If raster object and raster buffer are allocated, but */ /* raster size isn't of the minimum size, indicate out of */ @@ -1897,10 +1863,10 @@ QT_FT_END_STMNT } else { - ras.clip_box.xMin = -32768L; - ras.clip_box.yMin = -32768L; - ras.clip_box.xMax = 32767L; - ras.clip_box.yMax = 32767L; + ras.clip_box.xMin = -(1 << 23); + ras.clip_box.yMin = -(1 << 23); + ras.clip_box.xMax = (1 << 23) - 1; + ras.clip_box.yMax = (1 << 23) - 1; } gray_init_cells( worker, raster->buffer, raster->buffer_size ); |