FskErr FskFramePolygon( UInt32 nPts, const FskFixedPoint2D *pts, FskFixed strokeWidth, FskFixed jointSharpness, const FskColorSource *frameColor, const FskFixedMatrix3x2 *M, UInt32 quality, FskConstRectangle clipRect, FskBitmap dstBM ) { FskErr err; const FskColorSource *frameFillColors[2]; if (frameColor->dashCycles != 0) /* Do special processing for dashed lines: @@@ should have endcap spec for dashes */ return FrameDashedPolyLine(nPts, pts, strokeWidth, jointSharpness, kFskLineEndCapClosed|kFskLineEndCapButt, frameColor, M, quality, clipRect, dstBM); if (M) strokeWidth = ScaleStrokeWidth(strokeWidth, M); if ( (strokeWidth <= FIXED_ONE) && (frameColor->type == kFskColorSourceTypeConstant) ) { if (quality == 0) { FskConstColorRGB frColor = (FskConstColorRGB)(void*)(&(((const FskColorSourceConstant*)(void*)frameColor)->color)); err = FrameJaggyNarrowPolyLine( nPts, pts, 1, frColor, M, clipRect, dstBM); } else { frameFillColors[0] = frameColor; frameFillColors[1] = NULL; err = FskAAPolygonContours(1, &nPts, pts, FIXED_ONE, frameFillColors, -1, M, clipRect, dstBM); } } else { FskGrowableFixedPoint2DArray pgon = NULL; UInt32 n; FskFixedPoint2D *p; BAIL_IF_ERR(err = FskWidePolyLineToPolygon(nPts, pts, strokeWidth, jointSharpness, kFskLineEndCapClosed, M, &pgon)); BAIL_IF_ZERO((n = FskGrowableFixedPoint2DArrayGetItemCount(pgon)), err, kFskErrNothingRendered); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayGetPointerToItem(pgon, 0, (void**)(void*)(&p))); if (quality == 0) { err = FillJaggyPolygonContours(1, &n, p, frameColor, kFskFillRuleNonZero, NULL, clipRect, dstBM); } else { frameFillColors[0] = NULL; frameFillColors[1] = frameColor; err = FskAAPolygonContours( 1, &n, p, -1, frameFillColors, kFskFillRuleNonZero, NULL, clipRect, dstBM); } bail: if (pgon != NULL) FskGrowableFixedPoint2DArrayDispose(pgon); } return err; }
FskErr FskWidePolyLineToPolygon( UInt32 nPts, const FskFixedPoint2D *pts, FskFixed strokeWidth, FskFixed jointSharpness, UInt32 endCaps, const FskFixedMatrix3x2 *M, FskGrowableFixedPoint2DArray *polygonHandle ) { FskErr err; FskGrowableFixedPoint2DArray poly, back = NULL; SInt32 n; const FskFixedPoint2D *p0, *p1; FskFixedPoint2D pt; LineSeg seg0, seg1; MakeEndCap endCap; MakeJoin join; BAIL_IF_TRUE((jointSharpness < 0), err, kFskErrInvalidParameter); BAIL_IF_NULL(polygonHandle, err, kFskErrInvalidParameter); /* Select the join proc */ if (jointSharpness < FIXED_ONE) { /* Rounded */ join = RoundedJoin; n = nPts * 8; } else if (jointSharpness == FIXED_ONE) { /* Beveled */ join = BeveledJoin; n = nPts * 3; } else { /* Mitered */ join = MiteredJoin; n = nPts * 2; seg0.sinMiterLimit = seg1.sinMiterLimit = FskFixDiv(FRACT_ONE, jointSharpness); } /* Convert closed 2 point polylines into open ones with compatible endcaps */ if ((nPts == 2) && ((endCaps & kFskLineEndCapClosed) != 0)) { endCaps = (jointSharpness < FIXED_ONE) ? kFskLineEndCapRound : kFskLineEndCapButt; } /* Make sure a polygon is allocated */ if (*polygonHandle == NULL) { BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayNew(n, polygonHandle)); } else { BAIL_IF_ERR(err = FskGrowableFixedPoint2DArraySetItemCount(*polygonHandle, 0)); } poly = *polygonHandle; BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayNew(n, &back)); seg0.strokeWidth = seg1.strokeWidth = strokeWidth; /* Generate the polygon from the polyline description */ switch (endCaps) { case kFskLineEndCapRound: endCap = RoundEndCap; seg0.arcRelTol = seg1.arcRelTol = FskFracSqrt(FskFixedNDiv(LINEAR_TOLERANCE, strokeWidth, 31)); goto openLine; case kFskLineEndCapSquare: endCap = SquareEndCap; goto openLine; case kFskLineEndCapButt: endCap = ButtEndCap; openLine: p0 = pts; p1 = p0 + 1; for (n = nPts - 2; !InitLineSeg(p0, p1, M, &seg0) && (n > 0); p1++, n--) ; /* Get the first nondegenerate segment */ BAIL_IF_ERR(err = (*endCap)(&seg0, 0, poly)); seg1 = seg0; /* This should take care of the case with just 2 points */ for (p0 = p1++; n-- > 0; p0 = p1++) { if (InitLineSeg(p0, p1, M, &seg1)) { BAIL_IF_ERR(err = (*join)(&seg0, &seg1, poly, back)); seg0 = seg1; /* Only shift nondegenerate segments */ } } BAIL_IF_ERR(err = (*endCap)(&seg1, 1, poly)); break; case kFskLineEndCapClosed: // case kFskLineEndCapClosed|kFskLineEndCapRound: // round == 0 case kFskLineEndCapClosed|kFskLineEndCapSquare: case kFskLineEndCapClosed|kFskLineEndCapButt: p0 = pts + nPts - 2; p1 = p0 + 1; for (n = nPts; !InitLineSeg(p0, p1, M, &seg0) && (n > 0); p0--, n--) ; /* Nondegenerate segment coming in to the last point */ for (p0 = p1, p1 = pts; n-- > 0; p0 = p1++) { if (InitLineSeg(p0, p1, M, &seg1)) { BAIL_IF_ERR(err = (*join)(&seg0, &seg1, poly, back)); seg0 = seg1; /* Only shift nondegenerate segments */ } } BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayGetItem(poly, 0, &pt)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem(poly, &pt)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayGetItem(back, 0, &pt)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendItem(back, &pt)); break; } n = FskGrowableFixedPoint2DArrayGetItemCount(back); FskGrowableFixedPoint2DArrayGetConstPointerToItem(back, 0, (const void**)(const void*)(&p1)); BAIL_IF_ERR(err = FskGrowableFixedPoint2DArrayAppendReversedItems(poly, p1, n)); bail: if (back != NULL) FskGrowableFixedPoint2DArrayDispose(back); return err; }