package d2isometricimg

import (
	
	
	

	
	
	

	
	
)

func ( *nativeSurfaceSVGWriter) ( d2scene.AssetID) (*fontface.ParsedFace, error) {
	if  := .fonts[];  != nil {
		return , nil
	}
	,  := .doc.Assets[].(d2scene.FontAsset)
	if ! {
		return nil, fmt.Errorf("native SVG missing font asset %q", )
	}
	if len(.fonts) >= 96 || len(.Data) > 64<<20 {
		return nil, fmt.Errorf("native SVG font assets exceed limit")
	}
	, ,  := fontface.RegisteredBundledFace(.Data, .FaceIndex)
	if  != nil {
		return nil, 
	}
	if ! {
		, ,  = fontface.RegisteredBundledNotoColorEmoji(.Data, .FaceIndex)
		if  != nil {
			return nil, 
		}
	}
	var  *fontface.ParsedFace
	if  {
		,  = .CloneReadOnly()
	} else {
		,  = fontface.ParseFace(.Data, .FaceIndex)
	}
	if  == nil {
		.fonts[] = 
	}
	return , 
}

func ( *nativeSurfaceSVGWriter) ( d2scene.TextRun,  int) string {
	if !.admit() {
		return ""
	}
	,  := .font(.Font.Asset)
	if  != nil {
		.err = 
		return ""
	}
	 := fixed.Int26_6(math.Round(.Font.Size * 64))
	if  <= 0 {
		.err = fmt.Errorf("native SVG has invalid text size")
		return ""
	}
	 := .Glyphs
	 := 0.
	if len() == 0 && .Text != "" {
		 := append([]d2scene.AssetID{.Font.Asset}, .Fallbacks...)
		var  []fontface.ShapeFace
		 := map[d2scene.AssetID]bool{}
		for ,  := range  {
			if [] {
				continue
			}
			[] = true
			,  := .font()
			if  != nil {
				.err = 
				return ""
			}
			 = append(, fontface.ShapeFace{ID: string(), Face: })
		}
		var  fontface.ShapingWorkspace
		,  := .ShapeTextTransient(.ctx, .Text, , , fontface.ShapeLimits{Runes: maxLabelRunes, Faces: 8, CoverageChecks: 8000000, Runs: 200000, Glyphs: 1000000})
		if  != nil {
			.err = 
			return ""
		}
		 = .Advance
		for ,  := range .Glyphs {
			 = append(, d2scene.Glyph{ID: .ID, Empty: .Empty, Asset: d2scene.AssetID([.Face].ID), Position: d2scene.Point{X: .PositionX, Y: .PositionY}, Advance: .Advance})
		}
	} else {
		for ,  := range  {
			 = max(, .Position.X+.Advance)
		}
	}
	if len() > maxLabelRunes {
		.err = fmt.Errorf("native SVG exceeds glyph count")
		return ""
	}
	 := 0.
	if .Anchor == d2scene.AnchorMiddle {
		 = - / 2
	}
	if .Anchor == d2scene.AnchorEnd {
		 = -
	}
	var  strings.Builder
	for ,  := range  {
		if .Empty {
			continue
		}
		if  := .ctx.Err();  != nil {
			.err = 
			return ""
		}
		 := .Asset
		if  == "" {
			 = .Font.Asset
		}
		,  := .font()
		if  != nil {
			.err = 
			return ""
		}
		 := d2scene.Point{X: .Origin.X +  + .Position.X, Y: .Origin.Y + .Position.Y}
		if .IsBundledNotoColorEmoji() {
			, ,  := .CompileBundledNotoColorEmojiCOLRv1Plan(.ID)
			if  != nil {
				.err = 
				return ""
			}
			if  {
				.append(&, .colorGlyph(, , , .Font.Size, +1))
				continue
			}
		}
		, ,  := .COLR0GlyphLayers(.ID)
		if  != nil {
			.err = 
			return ""
		}
		if  {
			for ,  := range  {
				 := .Fill
				if !.Foreground {
					 = d2scene.SolidPaint{Color: .Color}
				}
				.append(&, .glyph(, .GlyphID, , , , nil, +1))
			}
			continue
		}
		.append(&, .glyph(, .ID, , , .Fill, .Stroke, +1))
	}
	if (.Underline || .Strike) &&  > 0 {
		var  sfnt.Buffer
		,  := .Outline.Metrics(&, , font.HintingNone)
		if  != nil {
			.err = 
			return ""
		}
		 := .transform.MaxScale()
		 := max(.Font.Size/16, 1/max(1e-12, ))
		 := func( float64) {
			.append(&, .primitive(d2scene.Rect{Box: d2scene.Box{X: .Origin.X + , Y: , Width: , Height: }, Fill: .Fill}, +1))
		}
		if .Underline {
			(.Origin.Y + max(.Font.Size/12, float64(.Descent)/64*.25))
		}
		if .Strike {
			 := float64(.XHeight) / 64
			if  <= 0 {
				 = .Font.Size * .5
			}
			(.Origin.Y - /2 - /2)
		}
	}
	return .String()
}

func nativeSVGGlyphPath( *fontface.ParsedFace,  uint32,  fixed.Int26_6,  d2scene.Point) (d2scene.Path, error) {
	if  == 0 ||  > math.MaxUint16 || int() >= .Outline.NumGlyphs() {
		return d2scene.Path{}, fmt.Errorf("native SVG has invalid glyph ID %d", )
	}
	var  sfnt.Buffer
	,  := .Outline.LoadGlyph(&, sfnt.GlyphIndex(), , nil)
	if  != nil {
		return d2scene.Path{}, fmt.Errorf("native SVG glyph %d outline: %w", , )
	}
	 := d2scene.Path{}
	 := func( fixed.Point26_6) d2scene.Point {
		return d2scene.Point{X: .X + float64(.X)/64, Y: .Y + float64(.Y)/64}
	}
	 := false
	for ,  := range  {
		, ,  := (.Args[0]), (.Args[1]), (.Args[2])
		switch .Op {
		case sfnt.SegmentOpMoveTo:
			if  {
				.Commands = append(.Commands, d2scene.ClosePath())
			}
			.Commands = append(.Commands, d2scene.MoveTo(.X, .Y))
			 = true
		case sfnt.SegmentOpLineTo:
			.Commands = append(.Commands, d2scene.LineTo(.X, .Y))
		case sfnt.SegmentOpQuadTo:
			.Commands = append(.Commands, d2scene.QuadraticTo(.X, .Y, .X, .Y))
		case sfnt.SegmentOpCubeTo:
			.Commands = append(.Commands, d2scene.CubicTo(.X, .Y, .X, .Y, .X, .Y))
		}
	}
	if  {
		.Commands = append(.Commands, d2scene.ClosePath())
	}
	return , nil
}

type nativeSVGFontGlyph struct {
	face *fontface.ParsedFace
	id   uint32
	ppem fixed.Int26_6
}

// Reuse exact font curves across rich-text runs. Position and source paint
// belong to the use, while each font/glyph/size outline is serialized once.
func ( *nativeSurfaceSVGWriter) ( *fontface.ParsedFace,  uint32,  fixed.Int26_6) string {
	if .glyphs == nil {
		.glyphs = make(map[nativeSVGFontGlyph]string)
	}
	 := nativeSVGFontGlyph{face: , id: , ppem: }
	if  := .glyphs[];  != "" {
		return 
	}
	,  := nativeSVGGlyphPath(, , , d2scene.Point{})
	if  != nil {
		.err = 
		return ""
	}
	 := .id("glyph")
	.def("<path" + nativeSVGAttr("id", ) + nativeSVGAttr("d", .path()) + "/>")
	.glyphs[] = 
	return 
}

func ( *nativeSurfaceSVGWriter) ( *fontface.ParsedFace,  uint32,  fixed.Int26_6,  d2scene.Point,  d2scene.Paint,  *d2scene.Stroke,  int) string {
	if !.admit() {
		return ""
	}
	 := func( d2scene.Paint) bool {
		switch .(type) {
		case nil, d2scene.SolidPaint, *d2scene.SolidPaint:
			return true
		}
		return false
	}
	if !() ||  != nil && !(.Paint) {
		// Absolute paint coordinates must retain their relationship to a glyph.
		,  := nativeSVGGlyphPath(, , , )
		if  != nil {
			.err = 
			return ""
		}
		.Fill, .Stroke = , 
		return .primitive(, +1)
	}
	 := .glyphDefinition(, , )
	if .err != nil {
		return ""
	}
	return "<use" + nativeSVGAttr("href", "#"+) + nativeSVGAttr("transform", "translate("+nativeSVGNumber(.X)+" "+nativeSVGNumber(.Y)+")") + .style(, , +1) + "/>"
}