private void WritePath(Path path, byte[] pathPaintingOperator, PdfContentByte canvas)
        {
            if (path.IsEmpty())
            {
                return;
            }

            foreach (Subpath subpath in path.Subpaths)
            {
                WriteMoveTo(subpath.GetStartPoint(), canvas);

                foreach (IShape segment in subpath.GetSegments())
                {
                    if (segment is BezierCurve)
                    {
                        WriteBezierCurve((BezierCurve)segment, canvas);
                    }
                    else
                    {
                        WriteLine((Line)segment, canvas);
                    }
                }

                if (subpath.Closed)
                {
                    canvas.InternalBuffer.Append(h);
                }
            }

            if (pathPaintingOperator != null)
            {
                canvas.InternalBuffer.Append(pathPaintingOperator);
            }
        }
Esempio n. 2
0
 private void InitClippingPath()
 {
     /* For our purposes it is enough to initialize clipping path as arbitrary !non-empty! path.
      * In other cases, initially, it shall include the entire page as it stated in PDF spec. */
     newClippingPath = new Path();
     newClippingPath.MoveTo(30, 30);
     newClippingPath.LineTo(30, 40);
 }
Esempio n. 3
0
        private void WriteStroke(PdfContentByte canvas, Path path)
        {
            canvas.InternalBuffer.Append(q);

            IList <PdfObject> strokeColorOperands = cleanUpStrategy.Context.PeekStrokeColor();
            String            strokeOperatorStr   = strokeColorOperands[strokeColorOperands.Count - 1].ToString();

            // Below expression converts stroke color operator to its fill analogue.
            strokeColorOperands[strokeColorOperands.Count - 1] = new PdfLiteral(strokeOperatorStr.ToLower());
            WriteOperands(canvas, strokeColorOperands);

            WritePath(cleanUpStrategy.CurrentStrokePath, f, canvas);

            canvas.InternalBuffer.Append(Q);
        }
Esempio n. 4
0
        /**
         * @param fillingRule If the path is contour, pass any value.
         */

        private Path FilterCurrentPath(Matrix ctm, bool stroke, int fillingRule, float lineWidth, int lineCapStyle,
                                       int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern)
        {
            Path path = new Path(unfilteredCurrentPath.Subpaths);

            if (stroke)
            {
                return(filter.FilterStrokePath(path, ctm, lineWidth, lineCapStyle, lineJoinStyle,
                                               miterLimit, lineDashPattern));
            }
            else
            {
                return(filter.FilterFillPath(path, ctm, fillingRule));
            }
        }
Esempio n. 5
0
        public virtual Path RenderPath(PathPaintingRenderInfo renderInfo)
        {
            // If previous clipping is empty, then we shouldn't compute the new one
            // because their intersection is empty.
            if (newClippingPath.IsEmpty())
            {
                currentStrokePath = new Path();
                currentFillPath   = currentStrokePath;
                return(newClippingPath);
            }

            bool stroke = (renderInfo.Operation & PathPaintingRenderInfo.STROKE) != 0;
            bool fill   = (renderInfo.Operation & PathPaintingRenderInfo.FILL) != 0;

            float           lineWidth       = renderInfo.LineWidth;
            int             lineCapStyle    = renderInfo.LineCapStyle;
            int             lineJoinStyle   = renderInfo.LineJoinStyle;
            float           miterLimit      = renderInfo.MiterLimit;
            LineDashPattern lineDashPattern = renderInfo.LineDashPattern;

            if (stroke)
            {
                currentStrokePath = FilterCurrentPath(renderInfo.Ctm, true, -1,
                                                      lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (fill)
            {
                currentFillPath = FilterCurrentPath(renderInfo.Ctm, false, renderInfo.Rule,
                                                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (clipPath)
            {
                if (fill && renderInfo.Rule == clippingRule)
                {
                    newClippingPath = currentFillPath;
                }
                else
                {
                    newClippingPath = FilterCurrentPath(renderInfo.Ctm, false, clippingRule,
                                                        lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
                }
            }

            unfilteredCurrentPath = new Path();
            return(newClippingPath);
        }
        private void WritePath(String operatorStr, PdfContentByte canvas, PdfName strokeColorSpace)
        {
            if (nwFillOperators.Contains(operatorStr))
            {
                WritePath(cleanUpStrategy.CurrentFillPath, f, canvas);
            }
            else if (eoFillOperators.Contains(operatorStr))
            {
                WritePath(cleanUpStrategy.CurrentFillPath, eoF, canvas);
            }

            if (strokeOperators.Contains(operatorStr))
            {
                WriteStroke(canvas, cleanUpStrategy.CurrentStrokePath, strokeColorSpace);
            }

            if (cleanUpStrategy.Clipped)
            {
                if (!cleanUpStrategy.NewClipPath.IsEmpty())
                {
                    byte[] clippingOperator = (cleanUpStrategy.ClippingRule == PathPaintingRenderInfo.NONZERO_WINDING_RULE) ? W : eoW;
                    WritePath(cleanUpStrategy.NewClipPath, clippingOperator, canvas);
                }
                else
                {
                    // If the clipping path from the source document is cleaned (it happens when reduction
                    // area covers the path completely), then you should treat it as an empty set (no points
                    // are included in the path). Then the current clipping path (which is the intersection
                    // between previous clipping path and the new one) is also empty set, which means that
                    // there is no visible content at all. But at the same time as we removed the clipping
                    // path, the invisible content would become visible. So, to emulate the correct result,
                    // we would simply put a degenerate clipping path which consists of a single point at (0, 0).
                    Path degeneratePath = new Path();
                    degeneratePath.MoveTo(0, 0);
                    WritePath(degeneratePath, W, canvas);
                }
                canvas.InternalBuffer.Append(n);
                cleanUpStrategy.Clipped = false;
            }
        }
Esempio n. 7
0
        public virtual Path RenderPath(PathPaintingRenderInfo renderInfo)
        {
            bool stroke = (renderInfo.Operation & PathPaintingRenderInfo.STROKE) != 0;
            bool fill   = (renderInfo.Operation & PathPaintingRenderInfo.FILL) != 0;

            float           lineWidth       = renderInfo.LineWidth;
            int             lineCapStyle    = renderInfo.LineCapStyle;
            int             lineJoinStyle   = renderInfo.LineJoinStyle;
            float           miterLimit      = renderInfo.MiterLimit;
            LineDashPattern lineDashPattern = renderInfo.LineDashPattern;

            if (stroke)
            {
                currentStrokePath = FilterCurrentPath(renderInfo.Ctm, true, -1,
                                                      lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (fill)
            {
                currentFillPath = FilterCurrentPath(renderInfo.Ctm, false, renderInfo.Rule,
                                                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (clipPath)
            {
                if (fill && renderInfo.Rule == clippingRule)
                {
                    newClippingPath = currentFillPath;
                }
                else
                {
                    newClippingPath = FilterCurrentPath(renderInfo.Ctm, false, clippingRule,
                                                        lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
                }
            }

            unfilteredCurrentPath = new Path();
            return(newClippingPath);
        }
        protected internal virtual Path FilterStrokePath(Path path, Matrix ctm, float lineWidth, int lineCapStyle,
                                                int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            JoinType joinType = GetJoinType(lineJoinStyle);
            EndType endType = GetEndType(lineCapStyle);

            if (lineDashPattern != null) {
                if (IsZeroDash(lineDashPattern)) {
                    return new Path();
                }
                
                if (!IsSolid(lineDashPattern)) {
                    path = ApplyDashPattern(path, lineDashPattern);
                }
            }

            ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpProcessor.ArcTolerance * PdfCleanUpProcessor.FloatMultiplier);
            AddPath(offset, path, joinType, endType);

            PolyTree resultTree = new PolyTree();
            offset.Execute(ref resultTree, lineWidth * PdfCleanUpProcessor.FloatMultiplier / 2);

            return FilterFillPath(ConvertToPath(resultTree), ctm, PathPaintingRenderInfo.NONZERO_WINDING_RULE);
        }
Esempio n. 9
0
        private static IList<Point2D> GetPathApproximation(Path path) {
            IList<Point2D> approx = new List<Point2D>();

            foreach (Subpath subpath in path.Subpaths) {
                IList<Point2D> subpathApprox = subpath.GetPiecewiseLinearApproximation();
                Point2D prevPoint = null;

                foreach (Point2D approxPt in subpathApprox) {
                    if (!approxPt.Equals(prevPoint)) {
                        approx.Add(approxPt);
                        prevPoint = approxPt;
                    }
                }
            }

            return approx;
        }
Esempio n. 10
0
        /**
         * Converts specified degenerate subpaths to squares.
         * Note: the list of degenerate subpaths should contain at least 2 elements. Otherwise
         * we can't determine the direction which the rotation of each square depends on.
         *
         * @param squareWidth Width of each constructed square.
         * @param sourcePath The path which dash pattern applied to. Needed to calc rotation angle of each square.
         * @return {@link java.util.List} consisting of squares constructed on given degenerated subpaths.
         */
        private static IList<Subpath> ConvertToSquares(IList<Subpath> degenerateSubpaths, double squareWidth, Path sourcePath) {
            IList<Point2D> pathApprox = GetPathApproximation(sourcePath);

            if (pathApprox.Count < 2) {
                return new List<Subpath>();
            }

            IEnumerator<Point2D> approxIter = pathApprox.GetEnumerator();

            approxIter.MoveNext();
            Point2D approxPt1 = approxIter.Current;

            approxIter.MoveNext();
            Point2D approxPt2 = approxIter.Current;

            StandardLine line = new StandardLine(approxPt1, approxPt2);

            IList<Subpath> squares = new List<Subpath>(degenerateSubpaths.Count);
            float widthHalf = (float) squareWidth / 2;

            for (int i = 0; i < degenerateSubpaths.Count; ++i) {
                Point2D point = degenerateSubpaths[i].GetStartPoint();

                while (!line.Contains(point)) {
                    approxPt1 = approxPt2;

                    approxIter.MoveNext();
                    approxPt2 = approxIter.Current;

                    line = new StandardLine(approxPt1, approxPt2);
                }

                float slope = line.GetSlope();
                double angle;

                if (!float.IsPositiveInfinity(slope)) {
                    angle = Math.Atan(slope);
                } else {
                    angle = Math.PI / 2;
                }

                squares.Add(ConstructSquare(point, widthHalf, angle));
            }

            return squares;
        }
Esempio n. 11
0
        /**
         * Note: this method will close all unclosed subpaths of the passed path.
         *
         * @param fillingRule If the subpath is contour, pass any value.
         */
        protected internal Path FilterFillPath(Path path, Matrix ctm, int fillingRule) {
            path.CloseAllSubpaths();

            Clipper clipper = new Clipper();
            AddPath(clipper, path);

            foreach (Rectangle rectangle in rectangles) {
                Point2D[] transfRectVertices = TransformPoints(ctm, true, GetVertices(rectangle));
                AddRect(clipper, transfRectVertices, PolyType.ptClip);
            }

            PolyFillType fillType = PolyFillType.pftNonZero;

            if (fillingRule == PathPaintingRenderInfo.EVEN_ODD_RULE) {
                fillType = PolyFillType.pftEvenOdd;
            }

            PolyTree resultTree = new PolyTree();
            clipper.Execute(ClipType.ctDifference, resultTree, fillType, PolyFillType.pftNonZero);

            return ConvertToPath(resultTree);
        }
Esempio n. 12
0
        protected internal Path FilterStrokePath(Path sourcePath, Matrix ctm, float lineWidth, int lineCapStyle,
                                int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            Path path = sourcePath;
            JoinType joinType = GetJoinType(lineJoinStyle);
            EndType endType = GetEndType(lineCapStyle);

            if (lineDashPattern != null && !lineDashPattern.IsSolid()) {
                path = ApplyDashPattern(path, lineDashPattern);
            }

            ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpProcessor.ArcTolerance * PdfCleanUpProcessor.FloatMultiplier);
            IList<Subpath> degenerateSubpaths = AddPath(offset, path, joinType, endType);

            PolyTree resultTree = new PolyTree();
            offset.Execute(ref resultTree, lineWidth * PdfCleanUpProcessor.FloatMultiplier / 2);
            Path offsetedPath = ConvertToPath(resultTree);

            if (degenerateSubpaths.Count > 0) {
                if (endType == EndType.etOpenRound) {
                    IList<Subpath> circles = ConvertToCircles(degenerateSubpaths, lineWidth / 2);
                    offsetedPath.AddSubpaths(circles);
                } else if (endType == EndType.etOpenSquare && lineDashPattern != null) {
                    IList<Subpath> squares = ConvertToSquares(degenerateSubpaths, lineWidth, sourcePath);
                    offsetedPath.AddSubpaths(squares);
                }
            }

            return FilterFillPath(offsetedPath, ctm, PathPaintingRenderInfo.NONZERO_WINDING_RULE);
        }
        public virtual Path RenderPath(PathPaintingRenderInfo renderInfo) {
            // If previous clipping is empty, then we shouldn't compute the new one
            // because their intersection is empty.
            if (newClippingPath.IsEmpty()) {
                currentStrokePath = new Path();
                currentFillPath = currentStrokePath;
                return newClippingPath;
            }

            bool stroke = (renderInfo.Operation & PathPaintingRenderInfo.STROKE) != 0;
            bool fill = (renderInfo.Operation & PathPaintingRenderInfo.FILL) != 0;

            float lineWidth = renderInfo.LineWidth;
            int lineCapStyle = renderInfo.LineCapStyle;
            int lineJoinStyle = renderInfo.LineJoinStyle;
            float miterLimit = renderInfo.MiterLimit;
            LineDashPattern lineDashPattern = renderInfo.LineDashPattern;

            if (stroke) {
                currentStrokePath = FilterCurrentPath(renderInfo.Ctm, true, -1, 
                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (fill) {
                currentFillPath = FilterCurrentPath(renderInfo.Ctm, false, renderInfo.Rule, 
                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            } 
            
            if (clipPath) {
                if (fill && renderInfo.Rule == clippingRule) {
                    newClippingPath = currentFillPath;
                } else {
                    newClippingPath = FilterCurrentPath(renderInfo.Ctm, false, clippingRule, 
                        lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
                }
            }

            unfilteredCurrentPath = new Path();
            return newClippingPath;
        }
Esempio n. 14
0
        private static Path ApplyDashPattern(Path path, LineDashPattern lineDashPattern) {
            HashSet2<int> modifiedSubpaths = new HashSet2<int>(path.ReplaceCloseWithLine());
            Path dashedPath = new Path();
            int currentSubpath = 0;

            foreach (Subpath subpath in path.Subpaths) {
                IList<Point2D> subpathApprox = subpath.GetPiecewiseLinearApproximation();

                if (subpathApprox.Count > 1) {
                    dashedPath.MoveTo((float) subpathApprox[0].GetX(), (float) subpathApprox[0].GetY());
                    float remainingDist = 0;
                    bool remainingIsGap = false;

                    for (int i = 1; i < subpathApprox.Count; ++i) {
                        Point2D nextPoint = null;

                        if (remainingDist != 0) {
                            nextPoint = GetNextPoint(subpathApprox[i - 1], subpathApprox[i], remainingDist);
                            remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, remainingIsGap);
                        }

                        while ((Util.compare(remainingDist, 0) == 0) && !dashedPath.CurrentPoint.Equals(subpathApprox[i])) {
                            LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next();
                            nextPoint = GetNextPoint(nextPoint ?? subpathApprox[i - 1], subpathApprox[i], currentElem.Value);
                            remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, currentElem.IsGap);
                            remainingIsGap = currentElem.IsGap;
                        }
                    }

                    // If true, then the line closing the subpath was explicitly added (see Path.ReplaceCloseWithLine).
                    // This causes a loss of a visual effect of line join style parameter, so in this clause
                    // we simply add overlapping dash (or gap, no matter), which continues the last dash and equals to 
                    // the first dash (or gap) of the path.
                    if (modifiedSubpaths.Contains(currentSubpath)) {
                        lineDashPattern.Reset();
                        LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next();
                        Point2D nextPoint = GetNextPoint(subpathApprox[0], subpathApprox[1], currentElem.Value);
                        ApplyDash(dashedPath, subpathApprox[0], subpathApprox[1], nextPoint, currentElem.IsGap);
                    }
                }

                // According to PDF spec. line dash pattern should be restarted for each new subpath.
                lineDashPattern.Reset();
                ++currentSubpath;
            }

            return dashedPath;
        }
        private static void AddPath(ClipperOffset offset, Path path, JoinType joinType, EndType endType) {
            foreach (Subpath subpath in path.Subpaths) {
                if (!subpath.IsSinglePointClosed() && !subpath.IsSinglePointOpen()) {
                    EndType et;

                    if (subpath.Closed) {
                        // Offsetting is never used for path being filled
                        et = EndType.etClosedLine;
                    } else {
                        et = endType;
                    }

                    IList<Point2D> linearApproxPoints = subpath.GetPiecewiseLinearApproximation();
                    offset.AddPath(ConvertToIntPoints(linearApproxPoints), joinType, et);
                }
            }
        }
Esempio n. 16
0
        private static Path ConvertToPath(PolyTree result) {
            Path path = new Path();
            PolyNode node = result.GetFirst();

            while (node != null) {
                AddContour(path, node.Contour, !node.IsOpen);
                node = node.GetNext();
            }

            return path;
        }
Esempio n. 17
0
        /**
         * Adds all subpaths of the path to the {@link ClipperOffset} object with one
         * note: it doesn't add degenerate subpaths.
         *
         * @return {@link java.util.List} consisting of all degenerate subpaths of the path.
         */
        private static IList<Subpath> AddPath(ClipperOffset offset, Path path, JoinType joinType, EndType endType) {
            IList<Subpath> degenerateSubpaths = new List<Subpath>();

            foreach (Subpath subpath in path.Subpaths) {
                if (subpath.IsDegenerate()) {
                    degenerateSubpaths.Add(subpath);
                    continue;
                }

                if (!subpath.IsSinglePointClosed() && !subpath.IsSinglePointOpen()) {
                    EndType et;

                    if (subpath.Closed) {
                        // Offsetting is never used for path being filled
                        et = EndType.etClosedLine;
                    } else {
                        et = endType;
                    }

                    IList<Point2D> linearApproxPoints = subpath.GetPiecewiseLinearApproximation();
                    offset.AddPath(ConvertToIntPoints(linearApproxPoints), joinType, et);
                }
            }

            return degenerateSubpaths;
        }
 private void InitClippingPath() {
     /* For our purposes it is enough to initialize clipping path as arbitrary !non-empty! path.
        In other cases, initially, it shall include the entire page as it stated in PDF spec. */
     newClippingPath = new Path();
     newClippingPath.MoveTo(30, 30);
     newClippingPath.LineTo(30, 40);
 }
        public virtual Path RenderPath(PathPaintingRenderInfo renderInfo) {
            bool stroke = (renderInfo.Operation & PathPaintingRenderInfo.STROKE) != 0;
            bool fill = (renderInfo.Operation & PathPaintingRenderInfo.FILL) != 0;

            float lineWidth = renderInfo.LineWidth;
            int lineCapStyle = renderInfo.LineCapStyle;
            int lineJoinStyle = renderInfo.LineJoinStyle;
            float miterLimit = renderInfo.MiterLimit;
            LineDashPattern lineDashPattern = renderInfo.LineDashPattern;

            if (stroke) {
                currentStrokePath = FilterCurrentPath(renderInfo.Ctm, true, -1, 
                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            }

            if (fill) {
                currentFillPath = FilterCurrentPath(renderInfo.Ctm, false, renderInfo.Rule, 
                    lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
            } 
            
            if (clipPath) {
                if (fill && renderInfo.Rule == clippingRule) {
                    newClippingPath = currentFillPath;
                } else {
                    newClippingPath = FilterCurrentPath(renderInfo.Ctm, false, clippingRule, 
                        lineWidth, lineCapStyle, lineJoinStyle, miterLimit, lineDashPattern);
                }
            }

            unfilteredCurrentPath = new Path();
            return newClippingPath;
        }
        /**
         * @param fillingRule If the path is contour, pass any value.
         */

        private Path FilterCurrentPath(Matrix ctm, bool stroke, int fillingRule, float lineWidth, int lineCapStyle, 
                                       int lineJoinStyle, float miterLimit, LineDashPattern lineDashPattern) {
            Path path = new Path(unfilteredCurrentPath.Subpaths);

            if (stroke) {
                return filter.FilterStrokePath(path, ctm, lineWidth, lineCapStyle, lineJoinStyle,
                    miterLimit, lineDashPattern);
            } else {
                return filter.FilterFillPath(path, ctm, fillingRule);
            }
        }
Esempio n. 21
0
 private static void AddPath(Clipper clipper, Path path) {
     foreach (Subpath subpath in path.Subpaths) {
         if (!subpath.IsSinglePointClosed() && !subpath.IsSinglePointOpen()) {
             IList<Point2D> linearApproxPoints = subpath.GetPiecewiseLinearApproximation();
             clipper.AddPath(ConvertToIntPoints(linearApproxPoints), PolyType.ptSubject, subpath.Closed);
         }
     }
 }
        private void WritePath(Path path, byte[] pathPaintingOperator, PdfContentByte canvas) {
            if (path.IsEmpty()) {
                return;
            }

            foreach (Subpath subpath in path.Subpaths) {
                WriteMoveTo(subpath.GetStartPoint(), canvas);

                foreach (IShape segment in subpath.GetSegments()) {
                    if (segment is BezierCurve) {
                        WriteBezierCurve((BezierCurve) segment, canvas);
                    } else {
                        WriteLine((Line) segment, canvas);
                    }
                }

                if (subpath.Closed) {
                    canvas.InternalBuffer.Append(h);
                }
            }

            if (pathPaintingOperator != null) {
                canvas.InternalBuffer.Append(pathPaintingOperator);
            }
        }
Esempio n. 23
0
        private static void AddContour(Path path, List<IntPoint> contour, Boolean close) {
            IList<Point2D> floatContour = ConvertToFloatPoints(contour);

            Point2D point = floatContour[0];
            path.MoveTo((float) point.GetX(), (float) point.GetY());

            for (int i = 1; i < floatContour.Count; ++i) {
                point = floatContour[i];
                path.LineTo((float) point.GetX(), (float) point.GetY());
            }

            if (close) {
                path.CloseSubpath();
            }
        }
        private void WriteStroke(PdfContentByte canvas, Path path) {
            canvas.InternalBuffer.Append(q);

            IList<PdfObject> strokeColorOperands = cleanUpStrategy.Context.PeekStrokeColor();
            String strokeOperatorStr = strokeColorOperands[strokeColorOperands.Count - 1].ToString();
            // Below expression converts stroke color operator to its fill analogue.
            strokeColorOperands[strokeColorOperands.Count - 1] = new PdfLiteral(strokeOperatorStr.ToLower());
            WriteOperands(canvas, strokeColorOperands);

            WritePath(cleanUpStrategy.CurrentStrokePath, f, canvas);

            canvas.InternalBuffer.Append(Q);
        }
Esempio n. 25
0
        private static float ApplyDash(Path dashedPath, Point2D segStart, Point2D segEnd, Point2D dashTo, bool isGap) {
            float remainingDist = 0;

            if (!LiesOnSegment(segStart, segEnd, dashTo)) {
                remainingDist = (float) dashTo.Distance(segEnd);
                dashTo = segEnd;
            }

            if (isGap) {
                dashedPath.MoveTo((float) dashTo.GetX(), (float) dashTo.GetY());
            } else {
                dashedPath.LineTo((float) dashTo.GetX(), (float) dashTo.GetY());
            }

            return remainingDist;
        }
        private void WritePath(String operatorStr, PdfContentByte canvas, PdfName strokeColorSpace) {
            if (nwFillOperators.Contains(operatorStr)) {
                WritePath(cleanUpStrategy.CurrentFillPath, f, canvas);
            } else if (eoFillOperators.Contains(operatorStr)) {
                WritePath(cleanUpStrategy.CurrentFillPath, eoF, canvas);
            }

            if (strokeOperators.Contains(operatorStr)) {
                WriteStroke(canvas, cleanUpStrategy.CurrentStrokePath, strokeColorSpace);
            }

            if (cleanUpStrategy.Clipped) {
                if (!cleanUpStrategy.NewClipPath.IsEmpty()) {
                    byte[] clippingOperator = (cleanUpStrategy.ClippingRule == PathPaintingRenderInfo.NONZERO_WINDING_RULE) ? W : eoW;
                    WritePath(cleanUpStrategy.NewClipPath, clippingOperator, canvas);
                } else {
                    // If the clipping path from the source document is cleaned (it happens when reduction
                    // area covers the path completely), then you should treat it as an empty set (no points
                    // are included in the path). Then the current clipping path (which is the intersection
                    // between previous clipping path and the new one) is also empty set, which means that
                    // there is no visible content at all. But at the same time as we removed the clipping
                    // path, the invisible content would become visible. So, to emulate the correct result,
                    // we would simply put a degenerate clipping path which consists of a single point at (0, 0).
                    Path degeneratePath = new Path();
                    degeneratePath.MoveTo(0, 0);
                    WritePath(degeneratePath, W, canvas);
                }
                canvas.InternalBuffer.Append(n);
                cleanUpStrategy.Clipped = false;
            }
        }