package d2isometricimg

import (
	
	
	
	

	
)

// Vector surface retention is scoped to one serial export. PNG/GIF rendering
// does not retain scene documents or incur any vector serialization work.
type nativeVectorKey struct{}
type nativeVectorRegistry struct {
	surfaces map[*image.RGBA]*nativeVectorSurface
}
type nativeVectorSurface struct {
	document        *d2scene.Document
	inkCoverage     *nativeVectorSurface
	coverageOpacity float64
	capBackground   *color.NRGBA
	capPaint        d2scene.Paint
}

// A solid cap's source viewport includes its centered stroke. Its retained
// fill therefore stops just inside the physical cap, while geometric rim ink
// follows the cap itself. Fill that opaque substrate before its source paint;
// the cap's mesh clip, material lighting and opacity still apply once outside.
// Keep the registry document and other uses of the source texture unchanged.
func nativeVectorSolidCap( *nativeVectorSurface,  color.NRGBA) *nativeVectorSurface {
	if  == nil || .A != 255 {
		return 
	}
	 := *
	.capBackground = &
	return &
}

func nativeVectorContext( context.Context) context.Context {
	if  == nil {
		 = context.Background()
	}
	return context.WithValue(, nativeVectorKey{}, &nativeVectorRegistry{surfaces: make(map[*image.RGBA]*nativeVectorSurface)})
}

func nativeVectorEnabled( context.Context) bool {
	if  == nil {
		return false
	}
	,  := .Value(nativeVectorKey{}).(*nativeVectorRegistry)
	return 
}

func retainNativeVectorSurface( context.Context,  *image.RGBA,  *d2scene.Document) error {
	if  == nil {
		return nil
	}
	,  := .Value(nativeVectorKey{}).(*nativeVectorRegistry)
	if ! ||  == nil ||  == nil {
		return nil
	}
	if  := .Err();  != nil {
		return 
	}
	if len(.surfaces) >= 100000 {
		return fmt.Errorf("native SVG exceeds 100000 retained surfaces")
	}
	 := *
	if .LogicalWidth <= 0 || .LogicalHeight <= 0 {
		.LogicalWidth, .LogicalHeight = float64(.Bounds().Dx()), float64(.Bounds().Dy())
	}
	.surfaces[] = &nativeVectorSurface{document: &}
	return nil
}

func nativeVectorForTexture( context.Context,  *image.RGBA) *nativeVectorSurface {
	if  == nil {
		return nil
	}
	if ,  := .Value(nativeVectorKey{}).(*nativeVectorRegistry);  {
		return .surfaces[]
	}
	return nil
}

// Match an RGBA compositing step performed after a document was rasterized:
// background first, followed by the document, with one object-opacity fade.
func retainStyledNativeVectorSurface( context.Context,  *image.RGBA,  *d2scene.Document,  d2scene.Paint,  float64) error {
	if !nativeVectorEnabled() {
		return nil
	}
	 := *
	,  := nativeVectorViewport(&)
	if  != nil {
		return 
	}
	 := d2scene.NewNode(nil)
	.Transform = d2scene.Scale(.LogicalWidth, .LogicalHeight).Mul()
	.Children = []*d2scene.Node{.Root}
	 := d2scene.NewNode(nil)
	.Opacity = 
	 := d2scene.Box{Width: .LogicalWidth, Height: .LogicalHeight}
	if  != nil {
		.Children = append(.Children, d2scene.NewNode(d2scene.Rect{Box: , Fill: }))
	}
	.Children = append(.Children, )
	.Root, .ViewBox = , 
	.ViewportFit = d2scene.ViewportStretch
	return retainNativeVectorSurface(, , &)
}

func nativeVectorViewport( *d2scene.Document) (d2scene.Matrix, error) {
	 := d2scene.AspectRatio{Align: d2scene.AlignNone}
	if .ViewportFit == d2scene.ViewportMeet {
		.Align = d2scene.AlignXMinYMin
		if .ViewportAlign == d2scene.ViewportAlignXMidYMid {
			.Align = d2scene.AlignXMidYMid
		}
	}
	,  := .LogicalWidth, .LogicalHeight
	if !captionFinite() || !captionFinite() ||  <= 0 ||  <= 0 {
		return d2scene.Matrix{}, fmt.Errorf("native SVG surface has invalid dimensions")
	}
	,  := d2scene.AspectRatioMatrix(.ViewBox, d2scene.Box{Width: , Height: }, )
	if  != nil {
		return d2scene.Matrix{}, fmt.Errorf("native SVG surface has invalid viewport: %w", )
	}
	return d2scene.Scale(1/, 1/).Mul(), nil
}

// Match the border-label opening without baking its antialiased pixels into
// SVG. Both rectangles live in the source document's coordinate system.
func nativeVectorAperture( *nativeVectorSurface,  d2scene.Box) {
	if .Width <= 0 || .Height <= 0 {
		return
	}
	 := d2scene.NewNode(nil)
	.Children = []*d2scene.Node{.document.Root}
	 := d2scene.Path{FillRule: d2scene.EvenOdd}
	for ,  := range []d2scene.Box{.document.ViewBox, } {
		.Commands = append(.Commands, d2scene.MoveTo(.X, .Y), d2scene.LineTo(.X+.Width, .Y), d2scene.LineTo(.X+.Width, .Y+.Height), d2scene.LineTo(.X, .Y+.Height), d2scene.ClosePath())
	}
	.Clip = &d2scene.Clip{Path: , Transform: d2scene.Identity()}
	.document.Root = 
}