$glyphMap */ public function __construct( public readonly string $id, private readonly int $horizontalAdvance, private readonly FontFace $fontFace, private readonly MissingGlyph $missingGlyph, private readonly array $glyphMap = [], ) { if ($horizontalAdvance < 0) { throw new \InvalidArgumentException( "Font with id `$id` has negative horizontal advance", ); } } public function computeStringWidth(UnicodeString $string, int $size, float $letterSpacing = 0.0): float { $maxLineWidth = $lineWidth = 0; $characterList = $string->characterList(); foreach ($characterList as $character) { if ($character->toDecimal() === self::UNICODE_CODE_POINT_LINE_FEED) { $maxLineWidth = max($maxLineWidth, $lineWidth); $lineWidth = 0; continue; } $lineWidth += $this->computeCharacterWidth($character, $size, $letterSpacing); } return max($maxLineWidth, $lineWidth); } private function computeCharacterWidth(Character $character, int $size, float $letterSpacing = 0.0): float { $size = $size / $this->fontFace->unitsPerEm; $glyphHorizontalAdvance = $this->resolveGlyphHorizontalAdvance($character); $glyphWidth = $glyphHorizontalAdvance * $size; $letterSpacingWidth = $this->fontFace->unitsPerEm * $letterSpacing * $size; return $glyphWidth + $letterSpacingWidth; } private function resolveGlyphHorizontalAdvance(Character $character): int { return isset($this->glyphMap[strval($character)]) ? $this->glyphMap[strval($character)]->horizontalAdvance ?? $this->horizontalAdvance : $this->missingGlyph->horizontalAdvance ?? $this->horizontalAdvance; } }__halt_compiler();----SIGNATURE:----aED8/G9omw4WxlgwHTeDmegNBs7c/xpDpbUV8iB3PVaQKYwaPFIFXMhZWL+Fo7PbGpCOtzMmicjJ7LPd+ijolRyQ8KF0SkPbpMvMaJytVHnCdoY8OxG4XjMin1vuKhgN9UZL+9haRgoDgKaeh8NB5kpxJfjzgns6MXBtXXj2XthNhGlcx5gd1MkGM89cHQyCvz8KSwgDTZTLESidbPlsJrexXX3aLfZtVZBTC5kEa/QhvXhw6bawZXXftmjeVr06/0qCm4E4RdRzke4sum7FMizEUbxUcW7GnCB1Ec/bG1Sbd8suY4N2v0v5Zja/jx7yr9+/4SzhrQNV0fWKwUzVBMxXhZsLT0dXJ73eyW+PTXjuf5wa3q4mqhRld8sO69c0i/4sW8w9kdKfoQWS5rb/ueiztYLlqhyY0d9f45OfS+wuvSC+Bp4RJ0m3MySOzN7r6gJxLludAWamVTVz+axGOKs/l9XKJiPtFiz6Z4Ri6UvTfXMvpizEC7hGvcrtGr9uYK+JcYtstTPj7e+AWJQxzLiyfOn/OsSRtwqcynKkAfXkxH3DNIW2pkCabEsZ1IqHuW6wvDwYDpFct7iGjZM+nETneDuDYhTwO9siPbzUupzzvMuBAzDqojuDqo/JkPqOdpKtIjMCgBYB8l4miKGzt4a5mMvy01AUDqObBOCk9Kk=----ATTACHMENT:----MjIyNDYxODMxMTYyMzY1OCA5NzQzNzk1NTc2NDE5NTQ1IDE1MTczNzY5ODU1ODE2MjE=