package fontface

import (
	
	
	
	
	
	

	gotextfont 
	
	
	
	
)

const (
	maxParsedFontFaces  = 256
	maxCOLR0GlyphLayers = 1_024
)

var errShapingParserPanic = errors.New("shaping font parser panicked")

var errColorGlyphLookupPanic = errors.New("color glyph table lookup panicked")

type shapingCollectionParser func(gotextfont.Resource) ([]*gotextfont.Face, error)

// FaceCountLimitError reports a collection rejected before the shaping parser
// constructs one Face per entry.
type FaceCountLimitError struct {
	Count int
	Limit int
}

func ( *FaceCountLimitError) () string {
	return fmt.Sprintf("font collection face count %d exceeds limit %d", .Count, .Limit)
}

// Collection parses one font source with both libraries used by the
// raster text pipeline. A source is accepted only when outline lookup and
// HarfBuzz-compatible shaping agree on its face topology.
type Collection struct {
	outline *opentype.Collection
	shaping []*gotextfont.Face
	digest  [sha256.Size]byte
}

// parsedFaceSource is parser-issued provenance bound to the exact outline,
// shaping face, and immutable shaping font selected from one source. Keeping
// this unexported prevents sibling renderer packages from authorizing a
// synthesized ParsedFace by copying a digest into an exported field.
type parsedFaceSource struct {
	digest         [sha256.Size]byte
	outline        *sfnt.Font
	shaping        *gotextfont.Face
	shapingFont    *gotextfont.Font
	bundledOutline bool
}

// ParsedFace is one matching outline/shaping face. The Shaping face owns
// mutable lookup caches and must not be shared across concurrent renders.
type ParsedFace struct {
	Outline *sfnt.Font
	Shaping *gotextfont.Face
	source  parsedFaceSource
}

// BundledFaceSource is an authenticated, package-owned clone source. Its
// parser state is not exposed.
type BundledFaceSource struct {
	face *ParsedFace
}

// BundledNotoColorEmojiSource preserves the specific name used by the bundled
// emoji resolver and its authenticated color-paint and coverage APIs.
type BundledNotoColorEmojiSource = BundledFaceSource

func ( *BundledFaceSource) () (*ParsedFace, error) {
	if  == nil || .face == nil || !.face.hasParsedSourceComponents() {
		return nil, fmt.Errorf("bundled font clone source is unavailable")
	}
	return .face, nil
}

// Outline returns the immutable sfnt reader for this authenticated source.
// sfnt.Font has no mutable exported state; callers supply their own Buffer for
// every operation, so the reader may safely be shared by concurrent renders.
func ( *BundledFaceSource) () (*sfnt.Font, error) {
	,  := .parsed()
	if  != nil {
		return nil, 
	}
	return .Outline, nil
}

// IsBundledNotoColorEmoji reports whether this source is D2's authenticated
// color-emoji font without exposing its parser face.
func ( *BundledFaceSource) () bool {
	,  := .parsed()
	return  == nil && .IsBundledNotoColorEmoji()
}

// COLR0GlyphLayers resolves immutable COLRv0 table data without allocating a
// mutable go-text Face clone. Returned layers are detached value records.
func ( *BundledFaceSource) ( uint32) ([]ColorGlyphLayer, bool, error) {
	,  := .parsed()
	if  != nil {
		return nil, false, 
	}
	return .COLR0GlyphLayers()
}

// CompileBundledNotoColorEmojiCOLRv1Plan compiles an immutable renderer plan
// through the authenticated package-private color tables.
func ( *BundledFaceSource) ( uint32) (*COLRv1Plan, bool, error) {
	,  := .parsed()
	if  != nil {
		return nil, false, 
	}
	return .CompileBundledNotoColorEmojiCOLRv1Plan()
}

// GlyphRenderBounds reads glyph paint bounds without constructing per-Face
// shaping caches.
func ( *BundledFaceSource) ( uint32,  fixed.Int26_6) (fixed.Rectangle26_6, bool, error) {
	,  := .parsed()
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	return .GlyphRenderBounds(, )
}

// GlyphDataKind reports only the diagnostic category of a glyph. Keeping the
// table-backed GlyphData value private prevents callers from retaining or
// modifying parser-owned slices while still preserving renderer errors.
func ( *BundledFaceSource) ( uint32) (string, error) {
	,  := .parsed()
	if  != nil {
		return "", 
	}
	return glyphDataKind(.Shaping.GlyphData(gotextfont.GID())), nil
}

func glyphDataKind( gotextfont.GlyphData) string {
	switch .(type) {
	case gotextfont.GlyphOutline:
		return "outline"
	case gotextfont.GlyphColor:
		return "color"
	case gotextfont.GlyphBitmap:
		return "bitmap"
	case gotextfont.GlyphSVG:
		return "SVG"
	case nil:
		return "missing"
	default:
		return "non-outline"
	}
}

// CloneReadOnly returns independent shaping caches while sharing go-text's
// documented read-only Font. It is for renderer-owned faces whose parsed table
// fields are never reassigned by the caller.
func ( *BundledFaceSource) () (*ParsedFace, error) {
	,  := .parsed()
	if  != nil {
		return nil, 
	}
	 := new(ParsedFace)
	if  := .CloneInto();  != nil {
		return nil, 
	}
	return , nil
}

// CloneReadOnlyInto is CloneReadOnly with caller-owned result storage.
func ( *BundledFaceSource) ( *ParsedFace) error {
	,  := .parsed()
	if  != nil {
		return 
	}
	return .CloneInto()
}

// SupportsRenderableRune checks exact bundled-font coverage without mutating a
// shaping face cache, so one registered source can serve concurrent resolvers.
// The fixed ordinary D2 fonts contain only authenticated outline glyphs, so a
// matching non-zero cmap entry is sufficient. The bundled color-emoji source
// additionally validates its supported COLR paint path.
func ( *BundledFaceSource) ( rune) (bool, error) {
	,  := .parsed()
	if  != nil {
		return false, 
	}
	,  := .Shaping.Font.NominalGlyph()
	if ! ||  == 0 {
		return false, nil
	}
	var  sfnt.Buffer
	,  := .Outline.GlyphIndex(&, )
	if  != nil ||  == 0 || uint32() != uint32() {
		return false, nil
	}
	if !.hasParsedSource(bundledNotoColorEmojiCOLRv1SHA256) {
		return true, nil
	}
	, ,  := .CompileBundledNotoColorEmojiCOLRv1Plan(uint32())
	if  != nil {
		return false, 
	}
	if  {
		return .Clip != nil && .Clip.XMin < .Clip.XMax && .Clip.YMin < .Clip.YMax, nil
	}
	, ,  := .COLR0GlyphLayers(uint32())
	if  != nil {
		return false, 
	}
	if  {
		for ,  := range  {
			if ,  := .Outline.LoadGlyph(&, sfnt.GlyphIndex(.GlyphID), fixed.I(1_000), nil);  != nil {
				return false, fmt.Errorf("load COLRv0 layer glyph %d: %w", .GlyphID, )
			}
		}
		return true, nil
	}
	if ,  := .Outline.LoadGlyph(&, , fixed.I(1_000), nil);  != nil {
		return false, nil
	}
	return true, nil
}

// ColorGlyphLayer is one foreground or palette-colored outline in a COLRv0
// glyph. Layers are returned in paint order.
type ColorGlyphLayer struct {
	GlyphID    uint32
	Color      color.NRGBA
	Foreground bool
}

func parseFaceCollection( []byte) (*Collection, error) {
	return ParseFaceCollectionWithLimit(, maxParsedFontFaces)
}

// ParseFaceCollectionWithLimit inspects the cheap sfnt collection directory
// first and rejects excessive face counts before go-text eagerly constructs
// its per-face parser state.
func ( []byte,  int) (*Collection, error) {
	 = min(, maxParsedFontFaces)
	return parseFaceCollectionWithLimitUsingParser(, , gotextfont.ParseTTC)
}

func parseFaceCollectionWithLimitUsingParser( []byte,  int,  shapingCollectionParser) (*Collection, error) {
	,  := parseFaceCollectionWithLimitUsingParserAndDigest(, , , [sha256.Size]byte{})
	if  != nil {
		return nil, 
	}
	if len() == bundledNotoColorEmojiCOLRv1Size {
		.digest = sha256.Sum256()
	}
	return , nil
}

func parseFaceCollectionWithLimitUsingParserAndDigest( []byte,  int,  shapingCollectionParser,  [sha256.Size]byte) (*Collection, error) {
	if len() == 0 {
		return nil, fmt.Errorf("empty font data")
	}
	if  <= 0 {
		return nil, fmt.Errorf("font face limit must be positive")
	}
	,  := opentype.ParseCollection()
	if  != nil {
		return nil, fmt.Errorf("parse TrueType/OpenType font: %w", )
	}
	if .NumFonts() >  {
		return nil, &FaceCountLimitError{Count: .NumFonts(), Limit: }
	}
	,  := parseShapingCollection(bytes.NewReader(), )
	if  != nil {
		return nil, fmt.Errorf("parse shaping font: %w", )
	}
	if .NumFonts() != len() {
		return nil, fmt.Errorf("font parser face-count mismatch: outline=%d shaping=%d", .NumFonts(), len())
	}
	return &Collection{outline: , shaping: , digest: }, nil
}

// Contain go-text parser panics caused by malformed or unsupported external
// font bytes so they become ordinary parse failures instead of terminating an
// export.
func parseShapingCollection( gotextfont.Resource,  shapingCollectionParser) ( []*gotextfont.Face,  error) {
	if  == nil {
		return nil, fmt.Errorf("nil shaping font parser")
	}
	defer func() {
		if recover() != nil {
			 = nil
			 = errShapingParserPanic
		}
	}()
	return ()
}

// NumFaces reports the number of matching outline and shaping faces.
func ( *Collection) () int {
	if  == nil {
		return 0
	}
	return len(.shaping)
}

// Face returns one parser-authenticated face by zero-based index.
func ( *Collection) ( int) (*ParsedFace, error) {
	if  == nil ||  < 0 ||  >= .NumFaces() {
		return nil, fmt.Errorf("load font face %d: collection has %d faces", , .NumFaces())
	}
	,  := .outline.Font()
	if  != nil {
		return nil, fmt.Errorf("load outline font face %d: %w", , )
	}
	return newParsedFace(, .shaping[], .digest), nil
}

func newParsedFace( *sfnt.Font,  *gotextfont.Face,  [sha256.Size]byte) *ParsedFace {
	 := &ParsedFace{Outline: , Shaping: }
	if  != nil &&  != nil && .Font != nil {
		.source = parsedFaceSource{digest: , outline: , shaping: , shapingFont: .Font}
	}
	return 
}

// Clone returns a face with fresh shaping caches while preserving provenance
// only when this value still contains the exact parser-selected components.
// It is safe to use the resulting face independently in another render.
func ( *ParsedFace) () (*ParsedFace, error) {
	if  == nil || .Outline == nil || .Shaping == nil || .Shaping.Font == nil {
		return nil, fmt.Errorf("nil parsed font face")
	}
	 := new(ParsedFace)
	if  := .CloneInto();  != nil {
		return nil, 
	}
	return , nil
}

// CloneInto is Clone with caller-owned result storage.
func ( *ParsedFace) ( *ParsedFace) error {
	if  == nil || .Outline == nil || .Shaping == nil || .Shaping.Font == nil {
		return fmt.Errorf("nil parsed font face")
	}
	if  == nil {
		return fmt.Errorf("nil parsed font face clone destination")
	}
	,  := .Outline, .Shaping.Font
	, ,  := .source.digest, .source.bundledOutline, .hasParsedSourceComponents()
	 := gotextfont.NewFace()
	 := ParsedFace{Outline: , Shaping: }
	if  {
		.source = parsedFaceSource{
			digest: , outline: , shaping: , shapingFont: , bundledOutline: ,
		}
	}
	* = 
	return nil
}

func ( *ParsedFace) () bool {
	return  != nil && .source.outline != nil && .Outline == .source.outline && .Shaping == .source.shaping && .Shaping != nil && .Shaping.Font == .source.shapingFont
}

func ( *ParsedFace) ( [sha256.Size]byte) bool {
	return  != ([sha256.Size]byte{}) && .hasParsedSourceComponents() && .source.digest == 
}

// IsBundledNotoColorEmoji reports whether this face retains parser-issued
// provenance for D2's exact bundled color-emoji resource.
func ( *ParsedFace) () bool {
	return .hasParsedSource(bundledNotoColorEmojiCOLRv1SHA256)
}

// ParseFace parses one face from a TrueType, OpenType, or collection resource.
func ( []byte,  uint16) (*ParsedFace, error) {
	,  := parseFaceCollection()
	if  != nil {
		return nil, 
	}
	,  := .Face(int())
	if  != nil {
		return nil, 
	}
	if .IsBundledNotoColorEmoji() {
		if ,  := registerAuthenticatedBundledNotoColorEmoji(, .digest);  != nil {
			return nil, 
		}
	}
	return , nil
}

// SupportsRenderableRune reports whether both parsers select the same non-zero
// glyph and the raster pipeline can paint its base outline, COLRv0/CPAL layers,
// or an authenticated bundled COLRv1 plan. Empty outline glyphs are valid:
// spaces and spacing format controls can intentionally paint no contour while
// still contributing advance.
func ( *ParsedFace) ( rune) (bool, error) {
	if  == nil || .Outline == nil || .Shaping == nil {
		return false, fmt.Errorf("nil parsed font face")
	}
	if .hasParsedSourceComponents() && .source.bundledOutline {
		,  := .Shaping.Font.NominalGlyph()
		if ! ||  == 0 {
			return false, nil
		}
		var  sfnt.Buffer
		,  := .Outline.GlyphIndex(&, )
		return  == nil &&  != 0 && uint32() == uint32(), nil
	}
	,  := .Shaping.NominalGlyph()
	if ! ||  == 0 {
		return false, nil
	}
	var  sfnt.Buffer
	,  := .Outline.GlyphIndex(&, )
	if  != nil ||  == 0 || uint32() != uint32() {
		return false, nil
	}
	, ,  := .trustedCOLRv1Plan(uint32())
	if  != nil {
		return false, 
	}
	if  {
		return .Clip != nil && .Clip.XMin < .Clip.XMax && .Clip.YMin < .Clip.YMax, nil
	}
	return supportsRenderableRune(.Outline, .Shaping, )
}

// trustedCOLRv1Plan authenticates the one bundled COLRv1 resource before
// examining its paint graph. ParsedFace values synthesized by sibling packages
// lack parser-issued provenance and therefore follow the conservative
// outline/COLRv0 path.
func ( *ParsedFace) ( uint32) (*COLRv1Plan, bool, error) {
	if !.hasParsedSource(bundledNotoColorEmojiCOLRv1SHA256) {
		return nil, false, nil
	}
	return .CompileBundledNotoColorEmojiCOLRv1Plan()
}

// supportsRenderableRune applies the digest-neutral coverage predicate used
// when no ParsedFace source provenance is available. It intentionally admits
// only outlines and COLRv0/CPAL layers.
func supportsRenderableRune( *sfnt.Font,  *gotextfont.Face,  rune) (bool, error) {
	if  == nil ||  == nil {
		return false, fmt.Errorf("nil outline or shaping face")
	}
	,  := .NominalGlyph()
	if ! ||  == 0 {
		return false, nil
	}
	var  sfnt.Buffer
	,  := .GlyphIndex(&, )
	if  != nil ||  == 0 || uint32() != uint32() {
		return false, nil
	}
	 := &ParsedFace{Outline: , Shaping: }
	, ,  := .COLR0GlyphLayers(uint32())
	if  != nil {
		return false, 
	}
	if  {
		for ,  := range  {
			if ,  := .LoadGlyph(&, sfnt.GlyphIndex(.GlyphID), fixed.I(1_000), nil);  != nil {
				return false, fmt.Errorf("load COLRv0 layer glyph %d: %w", .GlyphID, )
			}
		}
		return true, nil
	}
	if ,  := .LoadGlyph(&, , fixed.I(1_000), nil);  != nil {
		return false, nil
	}
	return true, nil
}

// COLR0GlyphLayers returns the default-palette layers for one supported
// COLRv0 glyph. A false second result means the glyph should use its ordinary
// outline; this preserves outline fallback for other color-font formats.
func ( *ParsedFace) ( uint32) ([]ColorGlyphLayer, bool, error) {
	if  == nil || .Outline == nil || .Shaping == nil {
		return nil, false, fmt.Errorf("nil parsed font face")
	}
	if  == 0 ||  > math.MaxUint16 || int() >= .Outline.NumGlyphs() {
		return nil, false, fmt.Errorf("glyph ID %d is out of range", )
	}
	if .Shaping.COLR == nil {
		return nil, false, nil
	}
	, ,  := searchCOLRPaint(.Shaping.COLR, tables.GlyphID())
	if  != nil {
		return nil, false, 
	}
	if ! {
		return nil, false, nil
	}
	return .resolveColorPaint(, )
}

func ( *ParsedFace) ( uint32,  tables.PaintTable) ([]ColorGlyphLayer, bool, error) {
	,  := .(tables.PaintColrLayersResolved)
	if ! {
		var  sfnt.Buffer
		,  := .Outline.LoadGlyph(&, sfnt.GlyphIndex(), fixed.I(1_000), nil)
		if  != nil {
			return nil, false, fmt.Errorf("load fallback outline for color glyph %d: %w", , )
		}
		if len() == 0 {
			return nil, false, fmt.Errorf("color glyph %d uses unsupported COLRv1 paint without an outline fallback", )
		}
		return nil, false, nil
	}
	if len() == 0 {
		return nil, true, fmt.Errorf("COLRv0 glyph %d has no layers", )
	}
	if len(.Shaping.CPAL) == 0 {
		return nil, true, fmt.Errorf("COLRv0 glyph %d has no CPAL palette", )
	}
	,  := validateCOLR0Layers(, .Shaping.CPAL[0], .Outline.NumGlyphs())
	if  != nil {
		return nil, true, fmt.Errorf("COLRv0 glyph %d: %w", , )
	}
	return , true, nil
}

// searchCOLRPaint contains malformed-table panics from go-text's COLRv0 layer
// slice lookup. Font bytes are untrusted, so a corrupt FirstLayerIndex or
// NumLayers must fail one export rather than terminate the process.
func searchCOLRPaint( *tables.COLR1,  tables.GlyphID) ( tables.PaintTable,  bool,  error) {
	if  == nil {
		return nil, false, nil
	}
	defer func() {
		if recover() != nil {
			 = nil
			 = false
			 = errColorGlyphLookupPanic
		}
	}()
	,  = .Search()
	return , , nil
}

// GlyphRenderBounds returns paint bounds in the same fixed-point coordinate
// system as sfnt.LoadGlyph. Authenticated COLRv1 glyphs use their static COLR
// clip box; all other faces use outlines or COLRv0 layers.
func ( *ParsedFace) ( uint32,  fixed.Int26_6) (fixed.Rectangle26_6, bool, error) {
	if  == nil || .Outline == nil || .Shaping == nil {
		return fixed.Rectangle26_6{}, false, fmt.Errorf("nil parsed font face")
	}
	if  <= 0 {
		return fixed.Rectangle26_6{}, false, fmt.Errorf("glyph size must be positive")
	}
	, ,  := .trustedCOLRv1Plan()
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	if  {
		if .Clip == nil {
			return fixed.Rectangle26_6{}, false, fmt.Errorf("trusted COLRv1 glyph %d has no static clip box", )
		}
		return colrv1ClipBounds(.Clip, .Outline.UnitsPerEm(), )
	}
	, ,  := .COLR0GlyphLayers()
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	if ! {
		var  sfnt.Buffer
		,  := .Outline.LoadGlyph(&, sfnt.GlyphIndex(), , nil)
		if  != nil {
			return fixed.Rectangle26_6{}, false, fmt.Errorf("load outline glyph %d: %w", , )
		}
		return .Bounds(), len() != 0, nil
	}

	var  sfnt.Buffer
	var  fixed.Rectangle26_6
	 := false
	for ,  := range  {
		,  := .Outline.LoadGlyph(&, sfnt.GlyphIndex(.GlyphID), , nil)
		if  != nil {
			return fixed.Rectangle26_6{}, false, fmt.Errorf("load COLRv0 layer glyph %d: %w", .GlyphID, )
		}
		if len() == 0 {
			continue
		}
		if  {
			 = .Union(.Bounds())
		} else {
			 = .Bounds()
			 = true
		}
	}
	return , , nil
}

func colrv1ClipBounds( *COLRv1ClipBox,  sfnt.Units,  fixed.Int26_6) (fixed.Rectangle26_6, bool, error) {
	if  == nil ||  == 0 {
		return fixed.Rectangle26_6{}, false, fmt.Errorf("invalid COLRv1 clip bounds")
	}
	if !finiteCOLRv1(.XMin) || !finiteCOLRv1(.YMin) || !finiteCOLRv1(.XMax) || !finiteCOLRv1(.YMax) || .XMin >= .XMax || .YMin >= .YMax {
		return fixed.Rectangle26_6{}, false, fmt.Errorf("invalid COLRv1 clip bounds")
	}
	 := float64() / float64()
	 := func( float64) (fixed.Int26_6, error) {
		 *= 
		if !finiteCOLRv1() ||  > float64(math.MaxInt32) ||  < float64(math.MinInt32) {
			return 0, fmt.Errorf("COLRv1 clip bounds exceed fixed-point range")
		}
		return fixed.Int26_6(math.Round()), nil
	}
	,  := (.XMin)
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	// COLR clip coordinates are Y-up, while sfnt.LoadGlyph and shaped ink
	// bounds are Y-down. Reflect the extrema around the baseline.
	,  := (-.YMax)
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	,  := (.XMax)
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	,  := (-.YMin)
	if  != nil {
		return fixed.Rectangle26_6{}, false, 
	}
	if  >=  ||  >=  {
		return fixed.Rectangle26_6{}, false, fmt.Errorf("COLRv1 clip bounds collapse at requested size")
	}
	return fixed.Rectangle26_6{Min: fixed.Point26_6{X: , Y: }, Max: fixed.Point26_6{X: , Y: }}, true, nil
}

func finiteCOLRv1( float64) bool { return !math.IsNaN() && !math.IsInf(, 0) }

func validateCOLR0Layers( []tables.Layer,  []tables.ColorRecord,  int) ([]ColorGlyphLayer, error) {
	if  <= 0 {
		return nil, fmt.Errorf("font has no glyphs")
	}
	if len() == 0 {
		return nil, fmt.Errorf("glyph has no layers")
	}
	if len() > maxCOLR0GlyphLayers {
		return nil, fmt.Errorf("layer count %d exceeds limit %d", len(), maxCOLR0GlyphLayers)
	}
	 := make([]ColorGlyphLayer, 0, len())
	for ,  := range  {
		if int(.GlyphID) >=  {
			return nil, fmt.Errorf("layer %d glyph ID %d is out of range", , .GlyphID)
		}
		 := ColorGlyphLayer{GlyphID: uint32(.GlyphID)}
		if .PaletteIndex == math.MaxUint16 {
			.Foreground = true
		} else {
			if int(.PaletteIndex) >= len() {
				return nil, fmt.Errorf("layer %d palette index %d is out of range", , .PaletteIndex)
			}
			 := [.PaletteIndex]
			.Color = color.NRGBA{R: .Red, G: .Green, B: .Blue, A: .Alpha}
		}
		 = append(, )
	}
	return , nil
}