RenderPath renders a path to the canvas using a style and a transformation matrix.
(path *canvas.Path, style canvas.Style, m canvas.Matrix)
| 102 | |
| 103 | // RenderPath renders a path to the canvas using a style and a transformation matrix. |
| 104 | func (r *PDF) RenderPath(path *canvas.Path, style canvas.Style, m canvas.Matrix) { |
| 105 | // PDFs don't support the arcs joiner, miter joiner (not clipped), or miter joiner (clipped) with non-bevel fallback |
| 106 | strokeUnsupported := false |
| 107 | if _, ok := style.StrokeJoiner.(canvas.ArcsJoiner); ok { |
| 108 | strokeUnsupported = true |
| 109 | } else if miter, ok := style.StrokeJoiner.(canvas.MiterJoiner); ok { |
| 110 | if math.IsNaN(miter.Limit) { |
| 111 | strokeUnsupported = true |
| 112 | } else if _, ok := miter.GapJoiner.(canvas.BevelJoiner); !ok { |
| 113 | strokeUnsupported = true |
| 114 | } |
| 115 | } |
| 116 | if !strokeUnsupported { |
| 117 | if m.IsSimilarity() { |
| 118 | scale := math.Sqrt(math.Abs(m.Det())) |
| 119 | style.StrokeWidth *= scale |
| 120 | style.DashOffset, style.Dashes = canvas.ScaleDash(style.StrokeWidth, style.DashOffset, style.Dashes) |
| 121 | } else { |
| 122 | strokeUnsupported = true |
| 123 | } |
| 124 | } |
| 125 | |
| 126 | // PDFs don't support connecting first and last dashes if path is closed, so we move the start of the path if this is the case |
| 127 | // TODO: closing dashes |
| 128 | //if style.DashesClose { |
| 129 | // strokeUnsupported = true |
| 130 | //} |
| 131 | |
| 132 | closed := false |
| 133 | data := path.Copy().Transform(m).ToPDF() |
| 134 | if 1 < len(data) && data[len(data)-1] == 'h' { |
| 135 | data = data[:len(data)-2] |
| 136 | closed = true |
| 137 | } |
| 138 | |
| 139 | if !style.HasStroke() || !strokeUnsupported { |
| 140 | if style.HasFill() && !style.HasStroke() { |
| 141 | r.w.SetFill(style.Fill, m) |
| 142 | r.w.Write([]byte(" ")) |
| 143 | r.w.Write([]byte(data)) |
| 144 | r.w.Write([]byte(" f")) |
| 145 | if style.FillRule == canvas.EvenOdd { |
| 146 | r.w.Write([]byte("*")) |
| 147 | } |
| 148 | } else if !style.HasFill() && style.HasStroke() { |
| 149 | r.w.SetStroke(style.Stroke, m) |
| 150 | r.w.SetLineWidth(style.StrokeWidth) |
| 151 | r.w.SetLineCap(style.StrokeCapper) |
| 152 | r.w.SetLineJoin(style.StrokeJoiner) |
| 153 | r.w.SetDashes(style.DashOffset, style.Dashes) |
| 154 | r.w.Write([]byte(" ")) |
| 155 | r.w.Write([]byte(data)) |
| 156 | if closed { |
| 157 | r.w.Write([]byte(" s")) |
| 158 | } else { |
| 159 | r.w.Write([]byte(" S")) |
| 160 | } |
| 161 | } else if style.HasFill() && style.HasStroke() { |
nothing calls this directly
no test coverage detected