/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "j2d_md.h"
#include "java_awt_geom_PathIterator.h"
#include "ProcessPath.h"
/*
* This framework performs filling and drawing of paths with sub-pixel
* precision. Also, it performs clipping by the specified view area.
*
* Drawing of the shapes is performed not pixel by pixel but segment by segment
* except several pixels near endpoints of the drawn line. This approach saves
* lot's of cpu cycles especially in case of large primitives (like ovals with
* sizes more than 50) and helps in achieving appropriate visual quality. Also,
* such method of drawing is useful for the accelerated pipelines where
* overhead of the per-pixel drawing could eliminate all benefits of the
* hardware acceleration.
*
* Filling of the path was taken from
*
* [Graphics Gems, edited by Andrew S Glassner. Academic Press 1990,
* ISBN 0-12-286165-5 (Concave polygon scan conversion), 87-91]
*
* and modified to work with sub-pixel precision and non-continuous paths.
* It's also speeded up by using hash table by rows of the filled objects.
*
* Here is high level scheme showing the rendering process:
*
* doDrawPath doFillPath
* \ /
* ProcessPath
* |
* CheckPathSegment
* |
* --------+------
* | |
* | |
* | |
* _->ProcessCurve |
* / / | |
* \___/ | |
* | |
* DrawCurve ProcessLine
* \ /
* \ /
* \ /
* \ /
* ------+------
* (filling) / \ (drawing)
* / \
* Clipping and Clipping
* clamping \
* | \
* StoreFixedLine ProcessFixedLine
* | / \
* | / \
* FillPolygon PROCESS_LINE PROCESS_POINT
*
*
*
* CheckPathSegment - rough checking and skipping path's segments in case of
* invalid or huge coordinates of the control points to
* avoid calculation problems with NaNs and values close
* to the FLT_MAX
*
* ProcessCurve - (ProcessQuad, ProcessCubic) Splitting the curve into
* monotonic parts having appropriate size (calculated as
* boundary box of the control points)
*
* DrawMonotonicCurve - (DrawMonotonicQuad, DrawMonotonicCubic) flattening
* monotonic curve using adaptive forward differencing
*
* StoreFixedLine - storing segment from the flattened path to the
* FillData structure. Performing clipping and clamping if
* necessary.
*
* PROCESS_LINE, PROCESS_POINT - Helpers for calling appropriate primitive from
* DrawHandler structure
*
* ProcessFixedLine - Drawing line segment with subpixel precision.
*
*/
do { \
\
/* Checking bounds and clipping if necessary. \
* REMIND: It's temporary solution to avoid OOB in rendering code. \
* Current approach uses float equations which are unreliable for \
* clipping and makes assumptions about the line biases of the \
* rendering algorithm. Also, clipping code should be moved down \
* into only those output renderers that need it. \
*/ \
if (checkBounds) { \
if (res == CRES_INVISIBLE) break; \
if (res == CRES_INVISIBLE) break; \
if (res == CRES_INVISIBLE) break; \
if (res == CRES_INVISIBLE) break; \
} \
\
/* Handling lines having just one pixel */ \
if (pixelInfo[0] == 0) { \
pixelInfo[0] = 1; \
} \
break; \
} \
\
if (pixelInfo[0] && \
{ \
} \
\
\
if (pixelInfo[0] == 0) { \
pixelInfo[0] = 1; \
} \
\
/* Switch on last pixel of the line if it was already \
* drawn during rendering of the previous segments \
*/ \
{ \
} \
} while(0)
do { \
if (checkBounds && \
/* \
* (_X,_Y) should be inside boundaries \
* \
* assert(hnd->dhnd->yMin <= _Y && \
* hnd->dhnd->yMax > _Y && \
* hnd->dhnd->xMin <= _X && \
* hnd->dhnd->xMax > _X); \
* \
*/ \
if (pixelInfo[0] == 0) { \
pixelInfo[0] = 1; \
} \
} while(0)
/*
* Constants for the forward differencing
* of the cubic and quad curves
*/
/* Maximum size of the cubic curve (calculated as the size of the bounding box
* of the control points) which could be rendered without splitting
*/
/* Maximum size of the quad curve (calculated as the size of the bounding box
* of the control points) which could be rendered without splitting
*/
/* Default power of 2 steps used in the forward differencing. Here DF prefix
* stands for DeFault. Constants below are used as initial values for the
* adaptive forward differencing algorithm.
*/
/* Shift of the current point of the curve for preparing to the midpoint
* rounding
*/
/* Default amount of steps of the forward differencing */
/* Default boundary constants used to check the necessity of the restepping */
/* Multiplyers for the coefficients of the polynomial form of the cubic and
* quad curves representation
*/
/* Boundaries used for clipping large path segments (those are inside
*/
do { \
if ((X) < (LBND)) { \
(X) = (LBND); \
} else if ((X) > UBND) { \
(X) = (UBND); \
} \
} while(0)
/* Following constants are used for providing open boundaries of the intervals
*/
/* Calculation boundary. It is used for switching to the more slow but allowing
* larger input values method of calculation of the initial values of the scan
* converted line segments inside the FillPolygon.
*/
/* Clipping macros for drawing and filling algorithms */
enum {
};
do { \
jdouble t; \
res = CRES_NOT_CLIPPED; \
res = CRES_INVISIBLE; \
break; \
}; \
res = CRES_MIN_CLIPPED; \
t = (LINE_MIN); \
} else { \
res = CRES_INVISIBLE; \
break; \
}; \
res = CRES_MAX_CLIPPED; \
t = (LINE_MAX); \
} \
} \
} while (0)
/* Following macro is used for clipping and clumping filled shapes.
* An example of this process is shown on the picture below:
* ----+ ----+
* |/ | |/ |
* + | + |
* /| | I |
* / | | I |
* | | | ===> I |
* \ | | I |
* \| | I |
* + | + |
* |\ | |\ |
* | ----+ | ----+
* boundary boundary
*
* We can only perform clipping in case of right side of the output area
* because all segments passed out the right boundary don't influence on the
* result of scan conversion algorithm (it correctly handles half open
* contours).
*
*/
do { \
if (res == CRES_MIN_CLIPPED) { \
} else if (res == CRES_MAX_CLIPPED) { \
res = CRES_MAX_CLIPPED; \
} else if (res == CRES_INVISIBLE) { \
res = CRES_INVISIBLE; \
} else { \
res = CRES_NOT_CLIPPED; \
} \
} \
} while (0)
/* Following macro is used for solving quadratic equations:
* A*t^2 + B*t + C = 0
* in (0,1) range. That means we put to the RES the only roots which
* belongs to the (0,1) range. Note: 0 and 1 are not included.
* See solveQuadratic method in
* for more info about calculations
*/
do { \
double param; \
if ((A) != 0) { \
/* Calculating roots of the following equation \
* A*t^2 + B*t + C = 0 \
*/ \
double d = (B)*(B) - 4*(A)*(C); \
double q; \
if (d < 0) { \
break; \
} \
d = sqrt(d); \
/* For accuracy, calculate one root using: \
* (-B +/- d) / 2*A \
* and the other using: \
* 2*C / (-B +/- d) \
* Choose the sign of the +/- so that B+D gets larger \
* in magnitude \
*/ \
if ((B) < 0) { \
d = -d; \
} \
q = ((B) + d) / -2.0; \
param = q/(A); \
} \
if (d == 0 || q == 0) { \
break; \
} \
param = (C)/q; \
} \
} else { \
/* Calculating root of the following equation \
* B*t + C = 0 \
*/ \
if ((B) == 0) { \
break; \
} \
param = -(C)/(B); \
} \
} \
} while(0)
/* Drawing line with subpixel endpoints
*
* (x1, y1), (x2, y2) - fixed point coordinates of the endpoints
* with MDP_PREC bits for the fractional part
*
* pixelInfo - structure which keeps drawing info for avoiding
* multiple drawing at the same position on the
* screen (required for the XOR mode of drawing)
*
* pixelInfo[0] - state of the drawing
* 0 - no pixel drawn between
* 1 - there are drawn pixels
*
* pixelInfo[1,2] - first pixel of the path
* path
*
* pixelInfo[3,4] - last drawn pixel between
*
* checkBounds - flag showing necessity of checking the clip
*
*/
{
/* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */
if ((c & MDP_W_MASK) == 0) {
/* Checking for the segments with integer coordinates having
* the same start and end points
*/
if (c == 0) {
}
return;
}
} else {
/* Neither dx nor dy can be zero because of the check above */
/* Floor of x1, y1, x2, y2 */
/* Processing first endpoint */
/* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 will not
* affect the result
*/
} else {
/* Boundary at the direction from (x1,y1) to (x2,y2) */
/* intersection with column bx1 */
} else {
/* intersection with row by1 */
}
}
/* Processing second endpoint */
/* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 will not
* affect the result
*/
} else {
/* Boundary at the direction from (x2,y2) to (x1,y1) */
/* intersection with column bx2 */
} else {
/* intersection with row by2 */
}
}
}
}
/* Performing drawing of the monotonic in X and Y quadratic curves with sizes
* less than MAX_QUAD_SIZE by using forward differencing method of calculation.
* See comments to the DrawMonotonicCubic.
*/
{
/* Extracting fractional part of coordinates of first control point */
/* Setting default amount of steps */
/* Setting default shift for preparing to the midpoint rounding */
/* Perform decreasing step in 2 times if slope of the second forward
* difference changes too quickly (more than a pixel per step in X or Y
* direction). We can perform adjusting of the step size before the
* rendering loop because the curvature of the quad curve remains the same
* along all the curve
*/
while (maxDD > DF_QUAD_DEC_BND) {
count <<= 1;
maxDD >>= 2;
px <<=2;
py <<=2;
shift += 2;
}
while(count-- > 1) {
/* Checking that we are not running out of the endpoint and bounding
* violating coordinate. The check is pretty simple because the curve
* passed to the DrawMonotonicQuad already splitted into the monotonic
* in X and Y pieces
*/
/* Bounding x2 by xe */
}
/* Bounding y2 by ye */
}
}
/* We are performing one step less than necessary and use actual (xe,ye)
* curve's endpoint instead of calculated. This prevent us from accumulated
* errors at the last point.
*/
}
/*
* Checking size of the quad curves and split them if necessary.
* Calling DrawMonotonicQuad for the curves of the appropriate size.
* Note: coords array could be changed
*/
/* In case of drawing we could just skip curves which are completely
* out of bounds
*/
return;
}
} else {
/* In case of filling we could skip curves which are above,
* below and behind the right boundary of the visible area
*/
{
return;
}
/* We could clamp x coordinates to the corresponding boundary
* if the curve is completely behind the left one
*/
}
}
} else {
/* Set checkBounds parameter if curve intersects
* boundary of the visible area. We know that the
* curve is visible, so the check is pretty simple
*/
}
}
/*
* Bite the piece of the quadratic curve from start point till the point
* corresponding to the specified parameter then call ProcessQuad for the
* bitten part.
* Note: coords array will be changed
*/
{
}
/*
* Split quadratic curve into monotonic in X and Y parts. Calling
* ProcessMonotonicQuad for each monotonic piece of the curve.
* Note: coords array could be changed
*/
/* Temporary array for holding parameters corresponding to the extreme in X
* and Y points. The values are inside the (0,1) range (0 and 1 excluded)
* and in ascending order.
*/
double param;
/* Simple check for monotonicity in X before searching for the extreme
* points of the X(t) function. We first check if the curve is monotonic
* in X by seeing if all of the X coordinates are strongly ordered.
*/
{
/* Searching for extreme points of the X(t) function by solving
* dX(t)
* ---- = 0 equation
* dt
*/
if (ax != 0) {
/* Calculating root of the following equation
* ax*t + bx = 0
*/
}
}
}
/* Simple check for monotonicity in Y before searching for the extreme
* points of the Y(t) function. We first check if the curve is monotonic
* in Y by seeing if all of the Y coordinates are strongly ordered.
*/
{
/* Searching for extreme points of the Y(t) function by solving
* dY(t)
* ----- = 0 equation
* dt
*/
if (ay != 0) {
/* Calculating root of the following equation
* ay*t + by = 0
*/
if (cnt > 0) {
/* Inserting parameter only if it differs from
* already stored
*/
}
} else {
}
}
}
}
/* Processing obtained monotonic parts */
switch(cnt) {
case 0:
break;
case 1:
break;
case 2:
if (param > 0) {
/* Scale parameter to match with rest of the curve */
}
break;
}
}
/*
* Performing drawing of the monotonic in X and Y cubic curves with sizes less
* than MAX_CUB_SIZE by using forward differencing method of calculation.
*
* Here is some math used in the code below.
*
* If we express the parametric equation for the coordinates as
* simple polynomial:
*
* V(t) = a * t^3 + b * t^2 + c * t + d
*
* The equations for how we derive these polynomial coefficients
* from the Bezier control points can be found in the method comments
* for the CubicCurve.fillEqn Java method.
*
* From this polynomial, we can derive the forward differences to
* allow us to calculate V(t+K) from V(t) as follows:
*
* 1) V1(0)
* = V(K)-V(0)
* = aK^3 + bK^2 + cK + d - d
* = aK^3 + bK^2 + cK
*
* 2) V1(K)
* = V(2K)-V(K)
* = 8aK^3 + 4bK^2 + 2cK + d - aK^3 - bK^2 - cK - d
* = 7aK^3 + 3bK^2 + cK
*
* 3) V1(2K)
* = V(3K)-V(2K)
* = 27aK^3 + 9bK^2 + 3cK + d - 8aK^3 - 4bK^2 - 2cK - d
* = 19aK^3 + 5bK^2 + cK
*
* 4) V2(0)
* = V1(K) - V1(0)
* = 7aK^3 + 3bK^2 + cK - aK^3 - bK^2 - cK
* = 6aK^3 + 2bK^2
*
* 5) V2(K)
* = V1(2K) - V1(K)
* = 19aK^3 + 5bK^2 + cK - 7aK^3 - 3bK^2 - cK
* = 12aK^3 + 2bK^2
*
* 6) V3(0)
* = V2(K) - V2(0)
* = 12aK^3 + 2bK^2 - 6aK^3 - 2bK^2
* = 6aK^3
*
* Note that if we continue on to calculate V1(3K), V2(2K) and
* V3(K) we will see that V3(K) == V3(0) so we need at most
* 3 cascading forward differences to step through the cubic
* curve.
*
* Note, b coefficient calculating in the DrawCubic is actually twice the b
* coefficient seen above. It's been done for the better accuracy.
*
* In our case, initialy K is chosen as 1/(2^DF_CUB_STEPS) this value is taken
* with FWD_PREC bits precision. This means that we should do 2^DF_CUB_STEPS
* steps to pass through all the curve.
*
* On each step we examine how far we are stepping by examining our first(V1)
* and second (V2) order derivatives and verifying that they are met following
* conditions:
*
* abs(V2) <= DF_CUB_DEC_BND
* abs(V1) > DF_CUB_INC_BND
*
* So, ensures that we step through the curve more slowly when its curvature is
* high and faster when its curvature is lower. If the step size needs
* adjustment we adjust it so that we step either twice as fast, or twice as
* slow until our step size is within range. This modifies our stepping
* variables as follows:
*
* Decreasing step size
*
* V3 = oV3/8
* V2 = oV2/4 - V3
* V1 = (oV1 - V2)/2
*
* Here V1-V3 stands for new values of the forward differencies and oV1 - oV3
* for the old ones
*
* Using the equations above it's easy to calculating stepping variables for
* the increasing step size:
*
* V1 = 2*oV1 + oV2
* V2 = 4*oV2 + 4*oV3
* V3 = 8*oV3
*
* And then for not to running out of 32 bit precision we are performing 3 bit
* shift of the forward differencing precision (keeping in shift variable) in
* left or right direction depending on what is happening (decreasing or
* increasing). So, all oV1 - oV3 variables should be thought as appropriately
* shifted in regard to the V1 - V3.
*
* Taking all of the above into account we will have following:
*
* Decreasing step size:
*
* shift = shift + 3
* V3 keeps the same
* V2 = 2*oV2 - V3
* V1 = 4*oV1 - V2/2
*
* Increasing step size:
*
* shift = shift - 3
* V1 = oV1/4 + oV2/8
* V2 = oV2/2 + oV3/2
* V3 keeps the same
*
*/
{
/* Extracting fractional part of coordinates of first control point */
/* Setting default boundary values for checking first and second forward
* difference for the necessity of the restepping. See comments to the
* boundary values in ProcessQuad for more info.
*/
/* Setting default amount of steps */
/* Setting default shift for preparing to the midpoint rounding */
/* Calculating whole part of the first point of the curve */
while (count > 0) {
/* Perform decreasing step in 2 times if necessary */
while (
/* The code below is an optimized version of the checks:
* abs(ddpx) > decStepBnd1 ||
* abs(ddpy) > decStepBnd1
*/
{
count <<=1;
decStepBnd1 <<=3;
decStepBnd2 <<=3;
incStepBnd1 <<=3;
incStepBnd2 <<=3;
px <<=3;
py <<=3;
shift += 3;
}
/* Perform increasing step in 2 times if necessary.
* Note: we could do it only in even steps
*/
/* The code below is an optimized version of the check:
* abs(dpx) <= incStepBnd1 &&
* abs(dpy) <= incStepBnd1
*/
{
count >>=1;
decStepBnd1 >>=3;
decStepBnd2 >>=3;
incStepBnd1 >>=3;
incStepBnd2 >>=3;
px >>=3;
py >>=3;
shift -= 3;
}
count--;
/* We are performing one step less than necessary and use actual
* (xe,ye) endpoint of the curve instead of calculated. This prevent
* us from accumulated errors at the last point.
*/
if (count) {
/* Checking that we are not running out of the endpoint and
* bounding violating coordinate. The check is pretty simple
* because the curve passed to the DrawMonotonicCubic already
* splitted into the monotonic in X and Y pieces
*/
/* Bounding x2 by xe */
}
/* Bounding y2 by ye */
}
} else {
}
}
}
/*
* Checking size of the cubic curves and split them if necessary.
* Calling DrawMonotonicCubic for the curves of the appropriate size.
* Note: coords array could be changed
*/
/* In case of drawing we could just skip curves which are completely
* out of bounds
*/
return;
}
} else {
/* In case of filling we could skip curves which are above,
* below and behind the right boundary of the visible area
*/
{
return;
}
/* We could clamp x coordinates to the corresponding boundary
* if the curve is completely behind the left one
*/
}
}
} else {
/* Set checkBounds parameter if curve intersects
* boundary of the visible area. We know that the
* curve is visible, so the check is pretty simple
*/
}
}
/*
* Bite the piece of the cubic curve from start point till the point
* corresponding to the specified parameter then call ProcessMonotonicCubic for
* the bitten part.
* Note: coords array will be changed
*/
jfloat t)
{
}
/*
* Split cubic curve into monotonic in X and Y parts. Calling ProcessCubic for
* each monotonic piece of the curve.
*
* Note: coords array could be changed
*/
{
/* Temporary array for holding parameters corresponding to the extreme in X
* and Y points. The values are inside the (0,1) range (0 and 1 excluded)
* and in ascending order.
*/
/* Simple check for monotonicity in X before searching for the extreme
* points of the X(t) function. We first check if the curve is monotonic in
* X by seeing if all of the X coordinates are strongly ordered.
*/
{
/* Searching for extreme points of the X(t) function by solving
* dX(t)
* ---- = 0 equation
* dt
*/
}
/* Simple check for monotonicity in Y before searching for the extreme
* points of the Y(t) function. We first check if the curve is monotonic in
* Y by seeing if all of the Y coordinates are strongly ordered.
*/
{
/* Searching for extreme points of the Y(t) function by solving
* dY(t)
* ----- = 0 equation
* dt
*/
}
if (cnt > 0) {
/* Sorting parameter values corresponding to the extremum points of
* the curve. We are using insertion sort because of tiny size of the
* array.
*/
jint j;
for(i = 1; i < cnt; i++) {
}
}
/* Processing obtained monotonic parts */
for (i = 1; i < cnt; i++) {
if (param > 0) {
/* Scale parameter to match with rest of the curve */
}
}
}
}
if (res == CRES_INVISIBLE) return;
if (res == CRES_INVISIBLE) return;
if (res == CRES_INVISIBLE) return;
if (res == CRES_INVISIBLE) return;
clipped, /* enable boundary checking in case
of clipping to avoid entering
out of bounds which could
happens during rounding
*/
lastClipped /* Notify pProcessFixedLine that
this is the end of the
subpath (because of exiting
out of boundaries)
*/
);
} else {
/* Clamping starting from first vertex of the the processed segment
*/
/* Clamping only by left boundary */
if (res == CRES_MIN_CLIPPED) {
} else if (res == CRES_INVISIBLE) {
return;
}
/* Clamping starting from last vertex of the the processed segment
*/
/* Checking if there was a clip by right boundary */
/* Clamping only by left boundary */
if (res == CRES_MIN_CLIPPED) {
}
}
}
{
int i, index = 0;
pixelInfo[0] = 0;
/* Adding support of the KEY_STROKE_CONTROL rendering hint.
* Now we are supporting two modes: "pixels at centers" and
* "pixels at corners".
* First one is disabled by default but could be enabled by setting
* VALUE_STROKE_PURE to the rendering hint. It means that pixel at the
* screen (x,y) has (x + 0.5, y + 0.5) float coordinates.
*
* Second one is enabled by default and means straightforward mapping
* (x,y) --> (x,y)
*
*/
closeCoord[0] = -0.5f;
transXf -= 0.5;
transYf -= 0.5;
} else {
closeCoord[0] = 0.0f;
}
/* Adjusting boundaries to the capabilities of the ProcessPath code */
/* Setting up fractional clipping box
*
* We are using following float -> int mapping:
*
* xi = floor(xf + 0.5)
*
* So, fractional values that hit the [xmin, xmax) integer interval will be
* situated inside the [xmin-0.5, xmax - 0.5) fractional interval. We are
* using EPSF constant to provide that upper boundary is not included.
*/
for (i = 0; i < numTypes; i++) {
switch (types[i]) {
/* Performing closing of the unclosed segments */
if (subpathStarted & !skip) {
if (tCoords[0] != closeCoord[0] ||
{
}
}
}
/* Checking SEG_MOVETO coordinates if they are out of the
* [LOWER_BND, UPPER_BND] range. This check also handles
* NaN and Infinity values. Skipping next path segment in
* case of invalid data.
*/
{
closeCoord[0] = tCoords[0];
} else {
}
} else {
return JNI_FALSE;
}
break;
/* Checking SEG_LINETO coordinates if they are out of the
* [LOWER_BND, UPPER_BND] range. This check also handles
* NaN and Infinity values. Ignoring current path segment
* in case of invalid data. If segment is skipped its
* endpoint (if valid) is used to begin new subpath.
*/
{
if (skip) {
} else {
}
}
} else {
return JNI_FALSE;
}
break;
/* Checking SEG_QUADTO coordinates if they are out of the
* [LOWER_BND, UPPER_BND] range. This check also handles
* NaN and Infinity values. Ignoring current path segment
* in case of invalid endpoints's data. Equivalent to
* the SEG_LINETO if endpoint coordinates are valid but
* there are invalid data among other coordinates
*/
{
if (skip) {
} else {
{
} else {
}
}
}
} else {
return JNI_FALSE;
}
break;
/* Checking SEG_CUBICTO coordinates if they are out of the
* [LOWER_BND, UPPER_BND] range. This check also handles
* NaN and Infinity values. Ignoring current path segment
* in case of invalid endpoints's data. Equivalent to
* the SEG_LINETO if endpoint coordinates are valid but
* there are invalid data among other coordinates
*/
{
if (skip) {
} else {
{
} else {
}
}
}
} else {
return JNI_FALSE;
}
break;
if (subpathStarted && !skip) {
if (tCoords[0] != closeCoord[0] ||
{
/* Storing last path's point for using in
* following segments without initial moveTo
*/
tCoords[0] = closeCoord[0];
}
}
break;
}
}
/* Performing closing of the unclosed segments */
if (subpathStarted & !skip) {
if (tCoords[0] != closeCoord[0] ||
{
}
}
}
return JNI_TRUE;
}
* out of memory error and don't leak earlier allocated data
*/
struct _Edge;
typedef struct _Point {
jint x;
jint y;
} Point;
typedef struct _Edge {
jint x;
Point* p;
} Edge;
/* Size of the default buffer in the FillData structure. This buffer is
* replaced with heap allocated in case of large paths.
*/
/* Following structure accumulates points of the non-continuous flattened
* path during iteration through the origin path's segments . The end
* of the each subpath is marked as lastPoint flag set at the last point
*/
typedef struct {
} FillData;
do { \
} while(0)
do { \
} else { \
} \
} \
_pnts->x = X; \
_pnts->y = Y; \
if (_size) { \
} else { \
} \
} while(0)
do { \
} \
} while(0)
do { \
} while(0)
/* Bubble sorting in the ascending order of the linked list. This
* implementation stops processing the list if there were no changes during the
* previous pass.
*
* LIST - ptr to the ptr to the first element of the list
* ETYPE - type of the element in the list
* NEXT - accessor to the next field in the list element
* GET_LKEY - accessor to the key of the list element
*/
do { \
/* r precedes p and s points to the node up to which comparisons \
* are to be made */ \
r = p = *LIST; \
q = NEXT(p); \
wasSwap = 0; \
while ( p != s ) { \
wasSwap = 1; \
if ( p == *LIST ) { \
NEXT(q) = p ; \
*LIST = q ; \
r = q ; \
} else { \
NEXT(q) = p ; \
NEXT(r) = q ; \
r = q ; \
} \
} else { \
r = p ; \
p = NEXT(p); \
} \
q = NEXT(p); \
if ( q == s ) s = p ; \
} \
} \
} while(0);
/* Accessors for the Edge structure to work with LBUBBLE_SORT */
#define GET_ACTIVE_KEY(a) (a->x)
*/
do { \
if (prevp) { \
} else { \
} \
if (nextp) { \
} \
} while(0);
do { \
/* Skipping horizontal segments */ \
break; \
} else { \
} else { /* pnt->y > np->y */ \
} \
\
/* We need to worry only about dX because dY is in */\
/* denominator and abs(dy) < MDP_MULT (cy is a first */\
/* scanline of the scan converted segment and we subtract */\
/* y coordinate of the nearest segment's end from it to */\
/* obtain dy) */\
} else { \
} \
} \
if (head) { \
} \
nact++; \
} while(0);
jint n;
/* Because of support of the KEY_STROKE_CONTROL hint we are performing
* shift of the coordinates at the higher level
*/
// TODO creating lists using fake first element to avoid special casing of
// the first element in the list (which otherwise should be performed in each
// list operation)
/* Winding counter */
/* Calculating mask to be applied to the winding counter */
if (n <=1) return;
for (k = 0; k < hashSize; k++) {
}
/* Creating double linked list (prev, next links) describing path order and
* hash table with points which fall between scanlines. nextByY link is
* used for the points which are between same scanlines. Scanlines are
* passed through the centers of the pixels.
*/
}
nact = 0;
activeList = NULL;
for (y=hashOffset + MDP_MULT,k = 0;
{
/* pt->y should be inside hashed interval
* assert(y-MDP_MULT <= pt->y && pt->y < y);
*/
}
}
}
}
}
if (!activeList) continue;
/* We could not use O(N) Radix sort here because in most cases list of
* edges almost sorted. So, bubble sort (O(N^2))is working much
* better. Note, in case of array of edges Shell sort is more
* efficient.
*/
/* Correction of the back links in the double linked edge list */
while (curEdge) {
}
counter = 0;
drawing = 0;
drawing = 1;
}
}
drawing = 0;
}
}
/* Performing drawing till the right boundary (for correct rendering
* shapes clipped at the right side)
*/
}
}
}
/* There is no need to round line coordinates to the forward differencing
* precision anymore. Such a rounding was used for preventing the curve go
* out the endpoint (this sometimes does not help). The problem was fixed
* in the forward differencing loops.
*/
if (checkBounds) {
/* This function is used only for filling shapes, so there is no
* check for the type of clipping
*/
if (res == CRES_INVISIBLE) return;
if (res == CRES_INVISIBLE) return;
/* Clamping starting from first vertex of the the processed segment */
/* Clamping only by left boundary */
if (res == CRES_MIN_CLIPPED) {
} else if (res == CRES_INVISIBLE) {
return;
}
/* Clamping starting from last vertex of the the processed segment */
/* Checking if there was a clip by right boundary */
/* Clamping only by left boundary */
if (res == CRES_MIN_CLIPPED) {
}
return;
}
/* Adding first point of the line only in case of empty or just finished
* path
*/
}
if (endSubPath) {
}
}
if (!FD_IS_EMPTY(pfd)) {
}
}
}
{
{
NULL,
};
/* Initialization of the following fields in the declaration of the hnd
* above causes warnings on sun studio compiler with -xc99=%none option
* applied (this option means compliance with C90 standard instead of C99)
*/
if (!res) {
return JNI_FALSE;
}
return JNI_TRUE;
}
void (*pProcessEndSubPath)(ProcessHandler*),
{
{
NULL,
NULL,
};
/* Initialization of the following fields in the declaration of the hnd
* above causes warnings on sun studio compiler with -xc99=%none option
* applied (this option means compliance with C90 standard instead of C99)
*/
}