// SPDX-License-Identifier: Unlicense OR BSD-3-Clause

package font

import (
	

	ot 
	
)

type gID = tables.GlyphID

func ( *Font) ( GID,  uint16) (,  int32,  bool) {
	// harfbuzz seems not to implement this feature
	return 0, 0, false
}

// GlyphName returns the name of the given glyph, or an empty
// string if the glyph is invalid or has no name.
func ( *Font) ( GID) string {
	if  := .post.names;  != nil {
		if  := .glyphName();  != "" {
			return 
		}
	}
	if .cff != nil {
		return .cff.GlyphName()
	}
	return ""
}

// Upem returns the units per em of the font file.
// This value is only relevant for scalable fonts.
func ( *Font) () uint16 { return .upem }

var (
	metricsTagHorizontalAscender  = ot.MustNewTag("hasc")
	metricsTagHorizontalDescender = ot.MustNewTag("hdsc")
	metricsTagHorizontalLineGap   = ot.MustNewTag("hlgp")
	metricsTagVerticalAscender    = ot.MustNewTag("vasc")
	metricsTagVerticalDescender   = ot.MustNewTag("vdsc")
	metricsTagVerticalLineGap     = ot.MustNewTag("vlgp")
)

func fixAscenderDescender( float32,  Tag) float32 {
	if  == metricsTagHorizontalAscender ||  == metricsTagVerticalAscender {
		return float32(math.Abs(float64()))
	}
	if  == metricsTagHorizontalDescender ||  == metricsTagVerticalDescender {
		return float32(-math.Abs(float64()))
	}
	return 
}

func ( *Font) ( Tag,  []VarCoord) (float32, bool) {
	 := .mvar.getVar(, )
	switch  {
	case metricsTagHorizontalAscender:
		if .os2.useTypoMetrics {
			return fixAscenderDescender(float32(.os2.sTypoAscender)+, ), true
		} else if .hhea != nil {
			return fixAscenderDescender(float32(.hhea.Ascender)+, ), true
		}

	case metricsTagHorizontalDescender:
		if .os2.useTypoMetrics {
			return fixAscenderDescender(float32(.os2.sTypoDescender)+, ), true
		} else if .hhea != nil {
			return fixAscenderDescender(float32(.hhea.Descender)+, ), true
		}
	case metricsTagHorizontalLineGap:
		if .os2.useTypoMetrics {
			return fixAscenderDescender(float32(.os2.sTypoLineGap)+, ), true
		} else if .hhea != nil {
			return fixAscenderDescender(float32(.hhea.LineGap)+, ), true
		}
	case metricsTagVerticalAscender:
		if .vhea != nil {
			return fixAscenderDescender(float32(.vhea.Ascender)+, ), true
		}
	case metricsTagVerticalDescender:
		if .vhea != nil {
			return fixAscenderDescender(float32(.vhea.Descender)+, ), true
		}
	case metricsTagVerticalLineGap:
		if .vhea != nil {
			return fixAscenderDescender(float32(.vhea.LineGap)+, ), true
		}
	}
	return 0, false
}

// FontHExtents returns the extents of the font for horizontal text, or false
// it not available, in font units.
func ( *Face) () (FontExtents, bool) {
	var (
		           FontExtents
		, ,  bool
	)
	.Ascender,  = .Font.getPositionCommon(metricsTagHorizontalAscender, .coords)
	.Descender,  = .Font.getPositionCommon(metricsTagHorizontalDescender, .coords)
	.LineGap,  = .Font.getPositionCommon(metricsTagHorizontalLineGap, .coords)
	return ,  &&  && 
}

// FontVExtents is the same as `FontHExtents`, but for vertical text.
func ( *Face) () (FontExtents, bool) {
	var (
		           FontExtents
		, ,  bool
	)
	.Ascender,  = .Font.getPositionCommon(metricsTagVerticalAscender, .coords)
	.Descender,  = .Font.getPositionCommon(metricsTagVerticalDescender, .coords)
	.LineGap,  = .Font.getPositionCommon(metricsTagVerticalLineGap, .coords)
	return ,  &&  && 
}

var (
	tagStrikeoutSize      = ot.MustNewTag("strs")
	tagStrikeoutOffset    = ot.MustNewTag("stro")
	tagUnderlineSize      = ot.MustNewTag("unds")
	tagUnderlineOffset    = ot.MustNewTag("undo")
	tagSuperscriptYSize   = ot.MustNewTag("spys")
	tagSuperscriptXOffset = ot.MustNewTag("spxo")
	tagSubscriptYSize     = ot.MustNewTag("sbys")
	tagSubscriptYOffset   = ot.MustNewTag("sbyo")
	tagSubscriptXOffset   = ot.MustNewTag("sbxo")
	tagXHeight            = ot.MustNewTag("xhgt")
	tagCapHeight          = ot.MustNewTag("cpht")
)

// return the height from baseline (in font units)
func ( *Face) ( rune) float32 {
	,  := .NominalGlyph()
	if ! {
		return 0
	}
	,  := .GlyphExtents()
	if ! {
		return 0
	}
	return .YBearing
}

// LineMetric returns the metric identified by `metric` (in fonts units).
func ( *Face) ( LineMetric) float32 {
	switch  {
	case UnderlinePosition:
		return .post.underlinePosition + .mvar.getVar(tagUnderlineOffset, .coords)
	case UnderlineThickness:
		return .post.underlineThickness + .mvar.getVar(tagUnderlineSize, .coords)
	case StrikethroughPosition:
		return float32(.os2.yStrikeoutPosition) + .mvar.getVar(tagStrikeoutOffset, .coords)
	case StrikethroughThickness:
		return float32(.os2.yStrikeoutSize) + .mvar.getVar(tagStrikeoutSize, .coords)
	case SuperscriptEmYSize:
		return float32(.os2.ySuperscriptYSize) + .mvar.getVar(tagSuperscriptYSize, .coords)
	case SuperscriptEmXOffset:
		return float32(.os2.ySuperscriptXOffset) + .mvar.getVar(tagSuperscriptXOffset, .coords)
	case SubscriptEmYSize:
		return float32(.os2.ySubscriptYSize) + .mvar.getVar(tagSubscriptYSize, .coords)
	case SubscriptEmYOffset:
		return float32(.os2.ySubscriptYOffset) + .mvar.getVar(tagSubscriptYOffset, .coords)
	case SubscriptEmXOffset:
		return float32(.os2.ySubscriptXOffset) + .mvar.getVar(tagSubscriptXOffset, .coords)
	case CapHeight:
		if .os2.version < 2 {
			// sCapHeight may be set equal to the top of the unscaled and unhinted glyph
			// bounding box of the glyph encoded at U+0048 (LATIN CAPITAL LETTER H).
			return .runeHeight('H')
		}
		return float32(.os2.sCapHeight) + .mvar.getVar(tagCapHeight, .coords)
	case XHeight:
		if .os2.version < 2 {
			// sxHeight equal to the top of the unscaled and unhinted glyph bounding box
			// of the glyph encoded at U+0078 (LATIN SMALL LETTER X).
			return .runeHeight('x')
		}
		return float32(.os2.sxHeigh) + .mvar.getVar(tagXHeight, .coords)
	default:
		return 0
	}
}

// NominalGlyph returns the glyph used to represent the given rune,
// or false if not found.
// Note that it only looks into the cmap, without taking account substitutions
// nor variation selectors.
func ( *Font) ( rune) (GID, bool) { return .Cmap.Lookup() }

// VariationGlyph retrieves the glyph ID for a specified Unicode code point
// followed by a specified Variation Selector code point, or false if not found
func ( *Font) (,  rune) (GID, bool) {
	,  := .cmapVar.GetGlyphVariant(, )
	switch  {
	case VariantNotFound:
		return 0, false
	case VariantFound:
		return , true
	default: // VariantUseDefault
		return .NominalGlyph()
	}
}

// do not take into account variations
func ( *Font) ( gID,  tables.Hmtx,  bool) int16 {
	/* If `table` is empty, it means we don't have the metrics table
	 * for this direction: return default advance.  Otherwise, it means that the
	 * glyph index is out of bound: return zero. */
	if .IsEmpty() {
		if  {
			return int16(.upem)
		}
		return int16(.upem / 2)
	}

	return .Advance()
}

func clamp( float32) float32 {
	if  < 0 {
		 = 0
	}
	return 
}

func ( *Face) ( gID,  bool) float32 {
	,  := .getGlyfPoints(, false)
	if  {
		return clamp([phantomTop].Y - [phantomBottom].Y)
	}
	return clamp([phantomRight].X - [phantomLeft].X)
}

func ( *Face) ( GID) float32 {
	 := .getBaseAdvance(gID(), .hmtx, false)
	if !.isVar() {
		return float32()
	}
	if .hvar != nil {
		return float32() + .hvar.AdvanceDelta(gID(), .coords)
	}
	return .getGlyphAdvanceVar(gID(), false)
}

// return `true` is the font is variable and `Coords` is valid
func ( *Face) () bool {
	return len(.coords) != 0 && len(.coords) == len(.Font.fvar)
}

// HasVerticalMetrics returns true if a the 'vmtx' table is present.
// If not, client should avoid calls to [VerticalAdvance], which will returns a
// defaut value.
func ( *Font) () bool { return !.vmtx.IsEmpty() }

func ( *Face) ( GID) float32 {
	// return the opposite of the advance from the font
	 := .getBaseAdvance(gID(), .vmtx, true)
	if !.isVar() {
		return -float32()
	}
	if .vvar != nil {
		return -float32() - .vvar.AdvanceDelta(gID(), .coords)
	}
	return -.getGlyphAdvanceVar(gID(), true)
}

func ( *Font) (GID) (,  int32,  bool) {
	// zero is the right value here
	return 0, 0, true
}

func ( *Face) ( GID) (,  float32) {
	// First, set the x value to half the advance width.
	 = .HorizontalAdvance() / 2

	// If there is VORG, always use it. It uses VVAR for variations if necessary.
	if .vorg != nil {
		 = float32(.vorg.YOrigin(gID()))
		if .isVar() && .vvar != nil {
			 += .vvar.VorgDelta(gID(), .coords)
		}
		return , 
	}

	// If and only if `vmtx` is present and it's a `glyf` font,
	// we use the top phantom point, deduced from vmtx,glyf[,gvar].
	if !.vmtx.IsEmpty() && .glyf != nil {
		 = .getVOriginWithVar(gID())
		return , 
	}

	// Otherwise, use glyph extents to center the glyph vertically.
	// If getting glyph extents failed, just use the font ascender.
	,  := .FontHExtents()
	 := .Ascender - .Descender

	if ,  := .getExtentsFromGlyf(gID());  {
		 :=  - -.Height
		 = .YBearing + float32(int()/2)
		return , 
	}

	 = .Ascender
	return , 
}

func ( *Face) ( gID) float32 {
	if int() >= .nGlyphs {
		return 0
	}
	,  := .getGlyfPoints(, false)
	return [phantomTop].Y
}

func ( *Face) ( gID) (GlyphExtents, bool) {
	if int() >= len(.glyf) {
		return GlyphExtents{}, false
	}
	if .isVar() { // we have to compute the outline points and apply variations
		,  := .getGlyfPoints(, true)
		return , true
	}
	return getGlyphExtents(.glyf[], .hmtx, ), true
}

func ( *Font) ( gID, ,  uint16) (GlyphExtents, bool) {
	 := .bitmap.chooseStrike(, )
	if  == nil || .ppemX == 0 || .ppemY == 0 {
		return GlyphExtents{}, false
	}
	 := .findTable()
	if  == nil {
		return GlyphExtents{}, false
	}
	 := .image()
	if  == nil {
		return GlyphExtents{}, false
	}
	 := GlyphExtents{
		XBearing: float32(.metrics.BearingX),
		YBearing: float32(.metrics.BearingY),
		Width:    float32(.metrics.Width),
		Height:   -float32(.metrics.Height),
	}

	/* convert to font units. */
	 := float32(.upem) / float32(.ppemX)
	 := float32(.upem) / float32(.ppemY)
	.XBearing *= 
	.YBearing *= 
	.Width *= 
	.Height *= 
	return , true
}

func ( *Font) ( gID, ,  uint16) (GlyphExtents, bool) {
	 := .sbix.chooseStrike(, )
	if  == nil || .Ppem == 0 {
		return GlyphExtents{}, false
	}
	 := strikeGlyph(, , 0)
	if .GraphicType == 0 {
		return GlyphExtents{}, false
	}
	,  := bitmapGlyphExtents()

	/* convert to font units. */
	 := float32(.upem) / float32(.Ppem)
	.XBearing *= 
	.YBearing *= 
	.Width *= 
	.Height *= 
	return , 
}

func ( *Font) ( gID) (GlyphExtents, bool) {
	if .cff == nil {
		return GlyphExtents{}, false
	}
	, ,  := .cff.LoadGlyph()
	if  != nil {
		return GlyphExtents{}, false
	}
	return .ToExtents(), true
}

func ( *Face) ( gID) (GlyphExtents, bool) {
	if .cff2 == nil {
		return GlyphExtents{}, false
	}
	, ,  := .cff2.LoadGlyph(, .coords)
	if  != nil {
		return GlyphExtents{}, false
	}
	return .ToExtents(), true
}

func ( *Face) ( GID) (GlyphExtents, bool) {
	,  := .getExtentsFromSbix(gID(), .xPpem, .yPpem)
	if  {
		return , 
	}
	,  = .getExtentsFromBitmap(gID(), .xPpem, .yPpem)
	if  {
		return , 
	}
	,  = .getExtentsFromGlyf(gID())
	if  {
		return , 
	}
	,  = .getExtentsFromCff2(gID())
	if  {
		return , 
	}
	,  = .getExtentsFromCff1(gID())
	return , 
}