feat: validate gradient color stops

This commit is contained in:
melsonic 2025-04-16 00:22:55 +05:30
parent 9fe52cf8b2
commit 8bbdac7c18
No known key found for this signature in database
GPG key ID: DFA426742F621CD7
2 changed files with 38 additions and 16 deletions

View file

@ -1069,9 +1069,10 @@ func renderDoubleOval(tl *geo.Point, width, height float64, fill, fillStroke, st
return renderOval(tl, width, height, fill, fillStroke, stroke, style, inlineTheme) + renderOval(innerTL, width-10, height-10, fill, "", stroke, style, inlineTheme) return renderOval(tl, width, height, fill, fillStroke, stroke, style, inlineTheme) + renderOval(innerTL, width-10, height-10, fill, "", stroke, style, inlineTheme)
} }
func defineGradients(writer io.Writer, cssGradient string) { func defineGradients(writer io.Writer, cssGradient string) error {
gradient, _ := color.ParseGradient(cssGradient) gradient, err := color.ParseGradient(cssGradient)
fmt.Fprint(writer, fmt.Sprintf(`<defs>%s</defs>`, color.GradientToSVG(gradient))) fmt.Fprint(writer, fmt.Sprintf(`<defs>%s</defs>`, color.GradientToSVG(gradient)))
return err
} }
func defineShadowFilter(writer io.Writer) { func defineShadowFilter(writer io.Writer) {
@ -2278,28 +2279,42 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
} }
if color.IsGradient(diagram.Root.Fill) { if color.IsGradient(diagram.Root.Fill) {
defineGradients(buf, diagram.Root.Fill) if err := defineGradients(buf, diagram.Root.Fill); err != nil {
return nil, err
}
} }
if color.IsGradient(diagram.Root.Stroke) { if color.IsGradient(diagram.Root.Stroke) {
defineGradients(buf, diagram.Root.Stroke) if err := defineGradients(buf, diagram.Root.Stroke); err != nil {
return nil, err
}
} }
for _, s := range diagram.Shapes { for _, s := range diagram.Shapes {
if color.IsGradient(s.Fill) { if color.IsGradient(s.Fill) {
defineGradients(buf, s.Fill) if err := defineGradients(buf, s.Fill); err != nil {
return nil, err
}
} }
if color.IsGradient(s.Stroke) { if color.IsGradient(s.Stroke) {
defineGradients(buf, s.Stroke) if err := defineGradients(buf, s.Stroke); err != nil {
return nil, err
}
} }
if color.IsGradient(s.Color) { if color.IsGradient(s.Color) {
defineGradients(buf, s.Color) if err := defineGradients(buf, s.Color); err != nil {
return nil, err
}
} }
} }
for _, c := range diagram.Connections { for _, c := range diagram.Connections {
if color.IsGradient(c.Stroke) { if color.IsGradient(c.Stroke) {
defineGradients(buf, c.Stroke) if err := defineGradients(buf, c.Stroke); err != nil {
return nil, err
}
} }
if color.IsGradient(c.Fill) { if color.IsGradient(c.Fill) {
defineGradients(buf, c.Fill) if err := defineGradients(buf, c.Fill); err != nil {
return nil, err
}
} }
} }

View file

@ -9,6 +9,8 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"github.com/mazznoer/csscolorparser"
) )
type Gradient struct { type Gradient struct {
@ -46,23 +48,26 @@ func ParseGradient(cssGradient string) (Gradient, error) {
} }
firstParam := strings.TrimSpace(paramList[0]) firstParam := strings.TrimSpace(paramList[0])
var err error
if gradient.Type == "linear" && (strings.HasSuffix(firstParam, "deg") || strings.HasPrefix(firstParam, "to ")) { if gradient.Type == "linear" && (strings.HasSuffix(firstParam, "deg") || strings.HasPrefix(firstParam, "to ")) {
gradient.Direction = firstParam gradient.Direction = firstParam
colorStops := paramList[1:] colorStops := paramList[1:]
if len(colorStops) == 0 { if len(colorStops) == 0 {
return Gradient{}, errors.New("no color stops in gradient") return Gradient{}, errors.New("no color stops in gradient")
} }
gradient.ColorStops = parseColorStops(colorStops) gradient.ColorStops, err = parseColorStops(colorStops)
} else if gradient.Type == "radial" && (firstParam == "circle" || firstParam == "ellipse") { } else if gradient.Type == "radial" && (firstParam == "circle" || firstParam == "ellipse") {
gradient.Direction = firstParam gradient.Direction = firstParam
colorStops := paramList[1:] colorStops := paramList[1:]
if len(colorStops) == 0 { if len(colorStops) == 0 {
return Gradient{}, errors.New("no color stops in gradient") return Gradient{}, errors.New("no color stops in gradient")
} }
gradient.ColorStops = parseColorStops(colorStops) gradient.ColorStops, err = parseColorStops(colorStops)
} else { } else {
gradient.ColorStops = parseColorStops(paramList) gradient.ColorStops, err = parseColorStops(paramList)
}
if err != nil {
return Gradient{}, err
} }
gradient.ID = UniqueGradientID(cssGradient) gradient.ID = UniqueGradientID(cssGradient)
@ -97,12 +102,14 @@ func splitParams(params string) []string {
return parts return parts
} }
func parseColorStops(params []string) []ColorStop { func parseColorStops(params []string) ([]ColorStop, error) {
var colorStops []ColorStop var colorStops []ColorStop
for _, p := range params { for _, p := range params {
p = strings.TrimSpace(p) p = strings.TrimSpace(p)
parts := strings.Fields(p) parts := strings.Fields(p)
if _, err := csscolorparser.Parse(parts[0]); err != nil {
return nil, fmt.Errorf("%s is not a valid color format", parts[0])
}
switch len(parts) { switch len(parts) {
case 1: case 1:
colorStops = append(colorStops, ColorStop{Color: parts[0]}) colorStops = append(colorStops, ColorStop{Color: parts[0]})
@ -112,7 +119,7 @@ func parseColorStops(params []string) []ColorStop {
continue continue
} }
} }
return colorStops return colorStops, nil
} }
func GradientToSVG(gradient Gradient) string { func GradientToSVG(gradient Gradient) string {