in shiny/iconvg/upgrade.go [337:491]
func upgradeDrawing(u *upgrader, v1 buffer, v0 buffer) (uf upgradeFunc, newV1 buffer, newV0 buffer, retErr error) {
u.verbs = u.verbs[:0]
u.args = u.args[:0]
coords := [3][2]float32{}
pen := [2]float32{}
prevSmoothType := smoothTypeNone
prevSmoothPoint := [2]float32{}
// Handle the implicit M after a "Start path" styling op.
v0, retErr = decodeCoordinates(pen[:2], nil, v0)
if retErr != nil {
return nil, nil, nil, retErr
}
u.verbs = append(u.verbs, upgradeVerbMoveTo)
u.args = append(u.args, pen)
startingPoint := pen
for len(v0) > 0 {
switch opcode := v0[0]; {
case opcode < 0xc0: // LineTo, QuadTo, CubeTo.
nCoordPairs, nReps, relative, smoothType := 0, 1+int(opcode&0x0f), false, smoothTypeNone
switch opcode >> 4 {
case 0x00, 0x01: // "L (absolute lineTo)"
nCoordPairs = 1
nReps = 1 + int(opcode&0x1f)
case 0x02, 0x03: // "l (relative lineTo)"
nCoordPairs = 1
nReps = 1 + int(opcode&0x1f)
relative = true
case 0x04: // "T (absolute smooth quadTo)"
nCoordPairs = 1
smoothType = smoothTypeQuad
case 0x05: // "t (relative smooth quadTo)"
nCoordPairs = 1
relative = true
smoothType = smoothTypeQuad
case 0x06: // "Q (absolute quadTo)"
nCoordPairs = 2
case 0x07: // "q (relative quadTo)"
nCoordPairs = 2
relative = true
case 0x08: // "S (absolute smooth cubeTo)"
nCoordPairs = 2
smoothType = smoothTypeCube
case 0x09: // "s (relative smooth cubeTo)"
nCoordPairs = 2
relative = true
smoothType = smoothTypeCube
case 0x0a: // "C (absolute cubeTo)"
nCoordPairs = 3
case 0x0b: // "c (relative cubeTo)"
nCoordPairs = 3
relative = true
}
v0 = v0[1:]
for i := 0; i < nReps; i++ {
smoothIndex := 0
if smoothType != smoothTypeNone {
smoothIndex = 1
if smoothType != prevSmoothType {
coords[0][0] = pen[0]
coords[0][1] = pen[1]
} else {
coords[0][0] = (2 * pen[0]) - prevSmoothPoint[0]
coords[0][1] = (2 * pen[1]) - prevSmoothPoint[1]
}
}
allCoords := coords[:smoothIndex+nCoordPairs]
explicitCoords := allCoords[smoothIndex:]
v0, retErr = decodeCoordinatePairs(explicitCoords, nil, v0)
if retErr != nil {
return nil, nil, nil, retErr
}
if relative {
for c := range explicitCoords {
explicitCoords[c][0] += pen[0]
explicitCoords[c][1] += pen[1]
}
}
u.verbs = append(u.verbs, uint8(len(allCoords)))
u.args = append(u.args, allCoords...)
pen = allCoords[len(allCoords)-1]
if len(allCoords) == 2 {
prevSmoothPoint = allCoords[0]
prevSmoothType = smoothTypeQuad
} else if len(allCoords) == 3 {
prevSmoothPoint = allCoords[1]
prevSmoothType = smoothTypeCube
} else {
prevSmoothType = smoothTypeNone
}
}
case opcode < 0xe0: // ArcTo.
v1, v0, retErr = u.upgradeArcs(&pen, v1, v0)
if retErr != nil {
return nil, nil, nil, retErr
}
prevSmoothType = smoothTypeNone
default: // Other drawing opcodes.
v0 = v0[1:]
switch opcode {
case 0xe1: // "z (closePath); end path"
goto endPath
case 0xe2, 0xe3: // "z (closePath); M (absolute/relative moveTo)"
v0, retErr = decodeCoordinatePairs(coords[:1], nil, v0)
if retErr != nil {
return nil, nil, nil, retErr
}
if opcode == 0xe2 {
pen[0] = coords[0][0]
pen[1] = coords[0][1]
} else {
pen[0] += coords[0][0]
pen[1] += coords[0][1]
}
u.verbs = append(u.verbs, upgradeVerbMoveTo)
u.args = append(u.args, pen)
default:
tmp := [1]float32{}
v0, retErr = decodeCoordinates(tmp[:1], nil, v0)
if retErr != nil {
return nil, nil, nil, retErr
}
switch opcode {
case 0xe6: // "H (absolute horizontal lineTo)"
pen[0] = tmp[0]
case 0xe7: // "h (relative horizontal lineTo)"
pen[0] += tmp[0]
case 0xe8: // "V (absolute vertical lineTo)"
pen[1] = tmp[0]
case 0xe9: // "v (relative vertical lineTo)"
pen[1] += tmp[0]
default:
return nil, nil, nil, errUnsupportedDrawingOpcode
}
u.verbs = append(u.verbs, upgradeVerbLineTo)
u.args = append(u.args, pen)
}
prevSmoothType = smoothTypeNone
}
}
endPath:
v1, retErr = u.finishDrawing(v1, startingPoint)
return upgradeStyling, v1, v0, retErr
}