if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) { if (checkBounds && (dhnd.yMin > Y1 || dhnd.yMax <= Y1 || dhnd.xMin > X1 || dhnd.xMax <= X1)) { return; } dhnd.drawPixel(X1, Y1); } pixelInfo[3] = X1; pixelInfo[4] = Y1; } void PROCESS_POINT(int fX, int fY, boolean checkBounds, int[] pixelInfo) { int _X = fX>> MDP_PREC; int _Y = fY>> MDP_PREC; if (checkBounds && (dhnd.yMin > _Y || dhnd.yMax <= _Y || dhnd.xMin > _X || dhnd.xMax <= _X)) return; /* * (_X,_Y) should be inside boundaries * * assert(dhnd.yMin <= _Y && * dhnd.yMax > _Y && * dhnd.xMin <= _X && * dhnd.xMax > _X); * */ if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = _X; pixelInfo[2] = _Y; pixelInfo[3] = _X; pixelInfo[4] = _Y; dhnd.drawPixel(_X, _Y); } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4]) && (_X != pixelInfo[1] || _Y != pixelInfo[2])) { dhnd.drawPixel(_X, _Y); pixelInfo[3] = _X; pixelInfo[4] = _Y; } } /* 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 * moveTo/close of the path * 1 - there are drawn pixels * * pixelInfo[1,2] - first pixel of the path * between moveTo/close of the * path * * pixelInfo[3,4] - last drawn pixel between * moveTo/close of the path * * checkBounds - flag showing necessity of checking the clip * */ public void processFixedLine(int x1, int y1, int x2, int y2, int[] pixelInfo, boolean checkBounds, boolean endSubPath) { /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */ int c = ((x1 ^ x2) | (y1 ^ y2)); int rx1, ry1, rx2, ry2; if ((c & MDP_W_MASK) == 0) { /* Checking for the segments with integer coordinates having * the same start and end points */ if (c == 0) { PROCESS_POINT(x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT, checkBounds, pixelInfo); } return; } if (x1 == x2 || y1 == y2) { rx1 = x1 + MDP_HALF_MULT; rx2 = x2 + MDP_HALF_MULT; ry1 = y1 + MDP_HALF_MULT; ry2 = y2 + MDP_HALF_MULT; } else { /* Neither dx nor dy can be zero because of the check above */ int dx = x2 - x1; int dy = y2 - y1; /* Floor of x1, y1, x2, y2 */ int fx1 = x1 & MDP_W_MASK; int fy1 = y1 & MDP_W_MASK; int fx2 = x2 & MDP_W_MASK; int fy2 = y2 & MDP_W_MASK; /* Processing first endpoint */ if (fx1 == x1 || fy1 == y1) { /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 * will not affect the result */ rx1 = x1 + MDP_HALF_MULT; ry1 = y1 + MDP_HALF_MULT; } else { /* Boundary at the direction from (x1,y1) to (x2,y2) */ int bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1; int by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1; /* intersection with column bx1 */ int cross = y1 + ((bx1 - x1)*dy)/dx; if (cross >= fy1 && cross <= fy1 + MDP_MULT) { rx1 = bx1; ry1 = cross + MDP_HALF_MULT; } else { /* intersection with row by1 */ cross = x1 + ((by1 - y1)*dx)/dy; rx1 = cross + MDP_HALF_MULT; ry1 = by1; } } /* Processing second endpoint */ if (fx2 == x2 || fy2 == y2) { /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 * will not affect the result */ rx2 = x2 + MDP_HALF_MULT; ry2 = y2 + MDP_HALF_MULT; } else { /* Boundary at the direction from (x2,y2) to (x1,y1) */ int bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2; int by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2; /* intersection with column bx2 */ int cross = y2 + ((bx2 - x2)*dy)/dx; if (cross >= fy2 && cross <= fy2 + MDP_MULT) { rx2 = bx2; ry2 = cross + MDP_HALF_MULT; } else { /* intersection with row by2 */ cross = x2 + ((by2 - y2)*dx)/dy; rx2 = cross + MDP_HALF_MULT; ry2 = by2; } } } PROCESS_LINE(rx1, ry1, rx2, ry2, checkBounds, pixelInfo); } } /* 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 DrawMonotonicQuad in the * ProcessGeneralPath.c */ private static void DrawMonotonicQuad(ProcessHandler hnd, float[] coords, boolean checkBounds, int[] pixelInfo) { int x0 = (int)(coords[0]*MDP_MULT); int y0 = (int)(coords[1]*MDP_MULT); int xe = (int)(coords[4]*MDP_MULT); int ye = (int)(coords[5]*MDP_MULT); /* Extracting fractional part of coordinates of first control point */ int px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; int py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; /* Setting default amount of steps */ int count = DF_QUAD_COUNT; /* Setting default shift for preparing to the midpoint rounding */ int shift = DF_QUAD_SHIFT; int ax = (int)((coords[0] - 2*coords[2] + coords[4])*QUAD_A_MDP_MULT); int ay = (int)((coords[1] - 2*coords[3] + coords[5])*QUAD_A_MDP_MULT); int bx = (int)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT); int by = (int)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT); int ddpx = 2*ax; int ddpy = 2*ay; int dpx = ax + bx; int dpy = ay + by; int x1, y1; int x2 = x0; int y2 = y0; int maxDD = Math.max(Math.abs(ddpx),Math.abs(ddpy)); int dx = xe - x0; int dy = ye - y0; int x0w = x0 & MDP_W_MASK; int y0w = y0 & MDP_W_MASK; /* Perform decreasing step in 2 times if slope of the first 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) { dpx = (dpx<<1) - ax; dpy = (dpy<<1) - ay; count <<= 1; maxDD >>= 2; px <<=2; py <<=2; shift += 2; } while(count-- > 1) { px += dpx; py += dpy; dpx += ddpx; dpy += ddpy; x1 = x2; y1 = y2; x2 = x0w + (px >> shift); y2 = y0w + (py >> shift); /* 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 DrawCubic already splitted into the * monotonic in X and Y pieces */ /* Bounding x2 by xe */ if (((xe-x2)^dx) < 0) { x2 = xe; } /* Bounding y2 by ye */ if (((ye-y2)^dy) < 0) { y2 = ye; } hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds, false); } /* We are performing one step less than necessary and use actual * (xe,ye) endpoint of the curve instead of calculated. This prevent us * from running above the curve endpoint due to the accumulated errors * during the iterations. */ hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds, false); } /* * 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 */ private static void ProcessMonotonicQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo) { float[] coords1 = new float[6]; float tx, ty; float xMin, yMin, xMax, yMax; xMin = xMax = coords[0]; yMin = yMax = coords[1]; for (int i = 2; i < 6; i += 2) { xMin = (xMin > coords[i])? coords[i] : xMin; xMax = (xMax < coords[i])? coords[i] : xMax; yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin; yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax; } if (hnd.clipMode == PH_MODE_DRAW_CLIP) { /* In case of drawing we could just skip curves which are * completely out of bounds */ if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax || hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) { return; } } else { /* In case of filling we could skip curves which are above, * below and behind the right boundary of the visible area */ if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax || hnd.dhnd.xMaxf < xMin) { return; } /* We could clamp x coordinates to the corresponding boundary * if the curve is completely behind the left one */ if (hnd.dhnd.xMinf > xMax) { coords[0] = coords[2] = coords[4] = hnd.dhnd.xMinf; } } if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) { coords1[4] = coords[4]; coords1[5] = coords[5]; coords1[2] = (coords[2] + coords[4])/2.0f; coords1[3] = (coords[3] + coords[5])/2.0f; coords[2] = (coords[0] + coords[2])/2.0f; coords[3] = (coords[1] + coords[3])/2.0f; coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f; coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f; ProcessMonotonicQuad(hnd, coords, pixelInfo); ProcessMonotonicQuad(hnd, coords1, pixelInfo); } else { DrawMonotonicQuad(hnd, coords, /* Set checkBounds parameter if curve intersects * boundary of the visible area. We know that the * curve is visible, so the check is pretty * simple */ hnd.dhnd.xMinf >= xMin || hnd.dhnd.xMaxf <= xMax || hnd.dhnd.yMinf >= yMin || hnd.dhnd.yMaxf <= yMax, pixelInfo); } } /* * 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 */ private static void ProcessQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo) { /* Temporary array for holding parameters corresponding to the extreme * in X and Y points */ double params[] = new double[2]; int cnt = 0; 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. */ if ((coords[0] > coords[2] || coords[2] > coords[4]) && (coords[0] < coords[2] || coords[2] < coords[4])) { /* Searching for extreme points of the X(t) function by solving * dX(t) * ---- = 0 equation * dt */ double ax = coords[0] - 2*coords[2] + coords[4]; if (ax != 0) { /* Calculating root of the following equation * ax*t + bx = 0 */ double bx = coords[0] - coords[2]; param = bx/ax; if (param < 1.0 && param > 0.0) { params[cnt++] = param; } } } /* 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. */ if ((coords[1] > coords[3] || coords[3] > coords[5]) && (coords[1] < coords[3] || coords[3] < coords[5])) { /* Searching for extreme points of the Y(t) function by solving * dY(t) * ----- = 0 equation * dt */ double ay = coords[1] - 2*coords[3] + coords[5]; if (ay != 0) { /* Calculating root of the following equation * ay*t + by = 0 */ double by = coords[1] - coords[3]; param = by/ay; if (param < 1.0 && param > 0.0) { if (cnt > 0) { /* Inserting parameter only if it differs from * already stored */ if (params[0] > param) { params[cnt++] = params[0]; params[0] = param; } else if (params[0] < param) { params[cnt++] = param; } } else { params[cnt++] = param; } } } } /* Processing obtained monotonic parts */ switch(cnt) { case 0: break; case 1: ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, (float)params[0]); break; case 2: ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, (float)params[0]); param = params[1] - params[0]; if (param > 0) { ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, /* Scale parameter to match with * rest of the curve */ (float)(param/(1.0 - params[0]))); } break; } ProcessMonotonicQuad(hnd,coords,pixelInfo); } /* * 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 */ private static void ProcessFirstMonotonicPartOfQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo, float t) { float[] coords1 = new float[6]; coords1[0] = coords[0]; coords1[1] = coords[1]; coords1[2] = coords[0] + t*(coords[2] - coords[0]); coords1[3] = coords[1] + t*(coords[3] - coords[1]); coords[2] = coords[2] + t*(coords[4] - coords[2]); coords[3] = coords[3] + t*(coords[5] - coords[3]); coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]); coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]); ProcessMonotonicQuad(hnd, coords1, pixelInfo); } /* 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. See comments to the DrawMonotonicCubic in the * ProcessGeneralPath.c */ private static void DrawMonotonicCubic(ProcessHandler hnd, float[] coords, boolean checkBounds, int[] pixelInfo) { int x0 = (int)(coords[0]*MDP_MULT); int y0 = (int)(coords[1]*MDP_MULT); int xe = (int)(coords[6]*MDP_MULT); int ye = (int)(coords[7]*MDP_MULT); /* Extracting fractional part of coordinates of first control point */ int px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; int py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;Lines 501–1000 of 2128. Previous lines Load more
if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) { if (checkBounds && (dhnd.yMin > Y1 || dhnd.yMax <= Y1 || dhnd.xMin > X1 || dhnd.xMax <= X1)) { return; } dhnd.drawPixel(X1, Y1); } pixelInfo[3] = X1; pixelInfo[4] = Y1; } void PROCESS_POINT(int fX, int fY, boolean checkBounds, int[] pixelInfo) { int _X = fX>> MDP_PREC; int _Y = fY>> MDP_PREC; if (checkBounds && (dhnd.yMin > _Y || dhnd.yMax <= _Y || dhnd.xMin > _X || dhnd.xMax <= _X)) return; /* * (_X,_Y) should be inside boundaries * * assert(dhnd.yMin <= _Y && * dhnd.yMax > _Y && * dhnd.xMin <= _X && * dhnd.xMax > _X); * */ if (pixelInfo[0] == 0) { pixelInfo[0] = 1; pixelInfo[1] = _X; pixelInfo[2] = _Y; pixelInfo[3] = _X; pixelInfo[4] = _Y; dhnd.drawPixel(_X, _Y); } else if ((_X != pixelInfo[3] || _Y != pixelInfo[4]) && (_X != pixelInfo[1] || _Y != pixelInfo[2])) { dhnd.drawPixel(_X, _Y); pixelInfo[3] = _X; pixelInfo[4] = _Y; } } /* 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 * moveTo/close of the path * 1 - there are drawn pixels * * pixelInfo[1,2] - first pixel of the path * between moveTo/close of the * path * * pixelInfo[3,4] - last drawn pixel between * moveTo/close of the path * * checkBounds - flag showing necessity of checking the clip * */ public void processFixedLine(int x1, int y1, int x2, int y2, int[] pixelInfo, boolean checkBounds, boolean endSubPath) { /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */ int c = ((x1 ^ x2) | (y1 ^ y2)); int rx1, ry1, rx2, ry2; if ((c & MDP_W_MASK) == 0) { /* Checking for the segments with integer coordinates having * the same start and end points */ if (c == 0) { PROCESS_POINT(x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT, checkBounds, pixelInfo); } return; } if (x1 == x2 || y1 == y2) { rx1 = x1 + MDP_HALF_MULT; rx2 = x2 + MDP_HALF_MULT; ry1 = y1 + MDP_HALF_MULT; ry2 = y2 + MDP_HALF_MULT; } else { /* Neither dx nor dy can be zero because of the check above */ int dx = x2 - x1; int dy = y2 - y1; /* Floor of x1, y1, x2, y2 */ int fx1 = x1 & MDP_W_MASK; int fy1 = y1 & MDP_W_MASK; int fx2 = x2 & MDP_W_MASK; int fy2 = y2 & MDP_W_MASK; /* Processing first endpoint */ if (fx1 == x1 || fy1 == y1) { /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 * will not affect the result */ rx1 = x1 + MDP_HALF_MULT; ry1 = y1 + MDP_HALF_MULT; } else { /* Boundary at the direction from (x1,y1) to (x2,y2) */ int bx1 = (x1 < x2) ? fx1 + MDP_MULT : fx1; int by1 = (y1 < y2) ? fy1 + MDP_MULT : fy1; /* intersection with column bx1 */ int cross = y1 + ((bx1 - x1)*dy)/dx; if (cross >= fy1 && cross <= fy1 + MDP_MULT) { rx1 = bx1; ry1 = cross + MDP_HALF_MULT; } else { /* intersection with row by1 */ cross = x1 + ((by1 - y1)*dx)/dy; rx1 = cross + MDP_HALF_MULT; ry1 = by1; } } /* Processing second endpoint */ if (fx2 == x2 || fy2 == y2) { /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 * will not affect the result */ rx2 = x2 + MDP_HALF_MULT; ry2 = y2 + MDP_HALF_MULT; } else { /* Boundary at the direction from (x2,y2) to (x1,y1) */ int bx2 = (x1 > x2) ? fx2 + MDP_MULT : fx2; int by2 = (y1 > y2) ? fy2 + MDP_MULT : fy2; /* intersection with column bx2 */ int cross = y2 + ((bx2 - x2)*dy)/dx; if (cross >= fy2 && cross <= fy2 + MDP_MULT) { rx2 = bx2; ry2 = cross + MDP_HALF_MULT; } else { /* intersection with row by2 */ cross = x2 + ((by2 - y2)*dx)/dy; rx2 = cross + MDP_HALF_MULT; ry2 = by2; } } } PROCESS_LINE(rx1, ry1, rx2, ry2, checkBounds, pixelInfo); } } /* 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 DrawMonotonicQuad in the * ProcessGeneralPath.c */ private static void DrawMonotonicQuad(ProcessHandler hnd, float[] coords, boolean checkBounds, int[] pixelInfo) { int x0 = (int)(coords[0]*MDP_MULT); int y0 = (int)(coords[1]*MDP_MULT); int xe = (int)(coords[4]*MDP_MULT); int ye = (int)(coords[5]*MDP_MULT); /* Extracting fractional part of coordinates of first control point */ int px = (x0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; int py = (y0 & (~MDP_W_MASK)) << DF_QUAD_SHIFT; /* Setting default amount of steps */ int count = DF_QUAD_COUNT; /* Setting default shift for preparing to the midpoint rounding */ int shift = DF_QUAD_SHIFT; int ax = (int)((coords[0] - 2*coords[2] + coords[4])*QUAD_A_MDP_MULT); int ay = (int)((coords[1] - 2*coords[3] + coords[5])*QUAD_A_MDP_MULT); int bx = (int)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT); int by = (int)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT); int ddpx = 2*ax; int ddpy = 2*ay; int dpx = ax + bx; int dpy = ay + by; int x1, y1; int x2 = x0; int y2 = y0; int maxDD = Math.max(Math.abs(ddpx),Math.abs(ddpy)); int dx = xe - x0; int dy = ye - y0; int x0w = x0 & MDP_W_MASK; int y0w = y0 & MDP_W_MASK; /* Perform decreasing step in 2 times if slope of the first 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) { dpx = (dpx<<1) - ax; dpy = (dpy<<1) - ay; count <<= 1; maxDD >>= 2; px <<=2; py <<=2; shift += 2; } while(count-- > 1) { px += dpx; py += dpy; dpx += ddpx; dpy += ddpy; x1 = x2; y1 = y2; x2 = x0w + (px >> shift); y2 = y0w + (py >> shift); /* 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 DrawCubic already splitted into the * monotonic in X and Y pieces */ /* Bounding x2 by xe */ if (((xe-x2)^dx) < 0) { x2 = xe; } /* Bounding y2 by ye */ if (((ye-y2)^dy) < 0) { y2 = ye; } hnd.processFixedLine(x1, y1, x2, y2, pixelInfo, checkBounds, false); } /* We are performing one step less than necessary and use actual * (xe,ye) endpoint of the curve instead of calculated. This prevent us * from running above the curve endpoint due to the accumulated errors * during the iterations. */ hnd.processFixedLine(x2, y2, xe, ye, pixelInfo, checkBounds, false); } /* * 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 */ private static void ProcessMonotonicQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo) { float[] coords1 = new float[6]; float tx, ty; float xMin, yMin, xMax, yMax; xMin = xMax = coords[0]; yMin = yMax = coords[1]; for (int i = 2; i < 6; i += 2) { xMin = (xMin > coords[i])? coords[i] : xMin; xMax = (xMax < coords[i])? coords[i] : xMax; yMin = (yMin > coords[i + 1])? coords[i + 1] : yMin; yMax = (yMax < coords[i + 1])? coords[i + 1] : yMax; } if (hnd.clipMode == PH_MODE_DRAW_CLIP) { /* In case of drawing we could just skip curves which are * completely out of bounds */ if (hnd.dhnd.xMaxf < xMin || hnd.dhnd.xMinf > xMax || hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax) { return; } } else { /* In case of filling we could skip curves which are above, * below and behind the right boundary of the visible area */ if (hnd.dhnd.yMaxf < yMin || hnd.dhnd.yMinf > yMax || hnd.dhnd.xMaxf < xMin) { return; } /* We could clamp x coordinates to the corresponding boundary * if the curve is completely behind the left one */ if (hnd.dhnd.xMinf > xMax) { coords[0] = coords[2] = coords[4] = hnd.dhnd.xMinf; } } if (xMax - xMin > MAX_QUAD_SIZE || yMax - yMin > MAX_QUAD_SIZE) { coords1[4] = coords[4]; coords1[5] = coords[5]; coords1[2] = (coords[2] + coords[4])/2.0f; coords1[3] = (coords[3] + coords[5])/2.0f; coords[2] = (coords[0] + coords[2])/2.0f; coords[3] = (coords[1] + coords[3])/2.0f; coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f; coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f; ProcessMonotonicQuad(hnd, coords, pixelInfo); ProcessMonotonicQuad(hnd, coords1, pixelInfo); } else { DrawMonotonicQuad(hnd, coords, /* Set checkBounds parameter if curve intersects * boundary of the visible area. We know that the * curve is visible, so the check is pretty * simple */ hnd.dhnd.xMinf >= xMin || hnd.dhnd.xMaxf <= xMax || hnd.dhnd.yMinf >= yMin || hnd.dhnd.yMaxf <= yMax, pixelInfo); } } /* * 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 */ private static void ProcessQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo) { /* Temporary array for holding parameters corresponding to the extreme * in X and Y points */ double params[] = new double[2]; int cnt = 0; 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. */ if ((coords[0] > coords[2] || coords[2] > coords[4]) && (coords[0] < coords[2] || coords[2] < coords[4])) { /* Searching for extreme points of the X(t) function by solving * dX(t) * ---- = 0 equation * dt */ double ax = coords[0] - 2*coords[2] + coords[4]; if (ax != 0) { /* Calculating root of the following equation * ax*t + bx = 0 */ double bx = coords[0] - coords[2]; param = bx/ax; if (param < 1.0 && param > 0.0) { params[cnt++] = param; } } } /* 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. */ if ((coords[1] > coords[3] || coords[3] > coords[5]) && (coords[1] < coords[3] || coords[3] < coords[5])) { /* Searching for extreme points of the Y(t) function by solving * dY(t) * ----- = 0 equation * dt */ double ay = coords[1] - 2*coords[3] + coords[5]; if (ay != 0) { /* Calculating root of the following equation * ay*t + by = 0 */ double by = coords[1] - coords[3]; param = by/ay; if (param < 1.0 && param > 0.0) { if (cnt > 0) { /* Inserting parameter only if it differs from * already stored */ if (params[0] > param) { params[cnt++] = params[0]; params[0] = param; } else if (params[0] < param) { params[cnt++] = param; } } else { params[cnt++] = param; } } } } /* Processing obtained monotonic parts */ switch(cnt) { case 0: break; case 1: ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, (float)params[0]); break; case 2: ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, (float)params[0]); param = params[1] - params[0]; if (param > 0) { ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, /* Scale parameter to match with * rest of the curve */ (float)(param/(1.0 - params[0]))); } break; } ProcessMonotonicQuad(hnd,coords,pixelInfo); } /* * 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 */ private static void ProcessFirstMonotonicPartOfQuad(ProcessHandler hnd, float[] coords, int[] pixelInfo, float t) { float[] coords1 = new float[6]; coords1[0] = coords[0]; coords1[1] = coords[1]; coords1[2] = coords[0] + t*(coords[2] - coords[0]); coords1[3] = coords[1] + t*(coords[3] - coords[1]); coords[2] = coords[2] + t*(coords[4] - coords[2]); coords[3] = coords[3] + t*(coords[5] - coords[3]); coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]); coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]); ProcessMonotonicQuad(hnd, coords1, pixelInfo); } /* 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. See comments to the DrawMonotonicCubic in the * ProcessGeneralPath.c */ private static void DrawMonotonicCubic(ProcessHandler hnd, float[] coords, boolean checkBounds, int[] pixelInfo) { int x0 = (int)(coords[0]*MDP_MULT); int y0 = (int)(coords[1]*MDP_MULT); int xe = (int)(coords[6]*MDP_MULT); int ye = (int)(coords[7]*MDP_MULT); /* Extracting fractional part of coordinates of first control point */ int px = (x0 & (~MDP_W_MASK)) << DF_CUB_SHIFT; int py = (y0 & (~MDP_W_MASK)) << DF_CUB_SHIFT;