# frozen_string_literal: truerequire'stringio'require'pathname'require_relative'ttfunk/aggregate'require_relative'ttfunk/directory'require_relative'ttfunk/resource_file'require_relative'ttfunk/collection'require_relative'ttfunk/ttf_encoder'require_relative'ttfunk/encoded_string'require_relative'ttfunk/placeholder'require_relative'ttfunk/otf_encoder'require_relative'ttfunk/sci_form'require_relative'ttfunk/bit_field'require_relative'ttfunk/bin_utils'require_relative'ttfunk/sub_table'require_relative'ttfunk/min'require_relative'ttfunk/max'require_relative'ttfunk/sum'require_relative'ttfunk/one_based_array'# TTFunk is a TrueType and OpenType font library written in pure ruby. It# supports both parsing and encoding of fonts. Also provides limited font# subsetting.## It supports a veriety of SFNT-based formats:# * TrueType fonts (ttf)# * OpenType fonts (otf), with both TrueType and CFF glyph outlines# * DFont resources (dfont)# * TrueType Collections (ttc)## While not all TrueType and OpenType tables are implemented the most common# ones are.moduleTTFunk# TTFunk-specific exceptionsclassError<StandardError;end# File represents an individual font. It can represents both TrueType and# OpenType fonts.classFile# Raw content of the font.# @return [String]attr_reader:contents# Font tables directory.# @return [TTFunk::Directory]attr_reader:directory# Open font file## @overload open(io)# @param io [IO] IO to read font content from. IO position and binmode# might change.# @return [TTFunk::File]# @overload open(path)# @param path [String, Pathname] Path to file to read the font from.# @return [TTFunk::File]defself.open(io_or_path)new(verify_and_read(io_or_path))end# Load a font from a resource file.## @param file [String, Pathname] Path to the resource file.# @param which [Integer, String] index or name of the font to load# @return [TTFunk::File]]defself.from_dfont(file,which=0)new(ResourceFile.open(file){|dfont|dfont['sfnt',which]})end# Load a font from a TrueType collection.## @overload from_ttc(io, which = 0)# @param file [IO] IO to read the collection from.# @param which [Integer] index of the font to load# @return [TTFunk::File]# @overload from_ttc(file_path, which = 0)# @param file_path [String, Pathname] Path to the resource file.# @param which [Integer] index of the font to load# @return [TTFunk::File]defself.from_ttc(file,which=0)Collection.open(file){|ttc|ttc[which]}end# Turn a path or IO into an IO convenient for TTFunk. The resulting IO is# going to be in bin mode and its position set to the beginning.## @overload verify_and_open(io)# @param io [IO] IO to prepare. Its position and binmode might# change.# @return [io]# @overload verify_and_open(path)# @param path [String, Pathname] path of the file to turn into an IO.# @return [IO] newly opened IO for the path# @deprecated This method might retain open files for longer than necessary.# @see .verify_and_readdefself.verify_and_open(io_or_path)# File or IOifio_or_path.respond_to?(:rewind)io=io_or_path# Rewind if the object we're passed is an IO, so that multiple embeds of# the same IO object will workio.rewind# read the file as binary so the size is calculated correctly# guard binmode because some objects acting io-like don't implement itio.binmodeifio.respond_to?(:binmode)returnioend# String or Pathnameio_or_path=Pathname.new(io_or_path)raiseArgumentError,"#{io_or_path} not found"unlessio_or_path.file?io_or_path.open('rb')end# Read contents of a path or IO.## @overload verify_and_read(io)# @param io [IO] IO to read from. Its position and binmode might# change. IO is read from the beginning regardless of its initial# position.# @return [String]# @overload verify_and_read(path)# @param path [String, Pathname] path of the file to read.# @return [String]defself.verify_and_read(io_or_path)# File or IOifio_or_path.respond_to?(:rewind)io=io_or_path# Rewind if the object we're passed is an IO, so that multiple embeds of# the same IO object will workio.rewind# read the file as binary so the size is calculated correctly# guard binmode because some objects acting io-like don't implement itio.binmodeifio.respond_to?(:binmode)returnio.readend# String or Pathnameio_or_path=Pathname.new(io_or_path)raiseArgumentError,"#{io_or_path} not found"unlessio_or_path.file?io_or_path.binreadend# @param contents [String] binary string containg the font data# @param offset [Integer] offset at which the font data startsdefinitialize(contents,offset=0)@contents=StringIO.new(contents)@directory=Directory.new(@contents,offset)end# Glyphs ascent as defined for in the font.## @return [Integer]defascent@ascent||=(os2.exists?&&os2.ascent&&os2.ascent.nonzero?)||horizontal_header.ascentend# Glyphs descent as defined in the font.## @return [Integer]defdescent@descent||=(os2.exists?&&os2.descent&&os2.descent.nonzero?)||horizontal_header.descentend# Line gap as defined in the font.## @return [Integer]defline_gap@line_gap||=(os2.exists?&&os2.line_gap&&os2.line_gap.nonzero?)||horizontal_header.line_gapend# Glyps bounding box as defined in the font.## @return [Array(Integer, Integer, Integer, Integer)]defbbox[header.x_min,header.y_min,header.x_max,header.y_max]end# Font directory entry for the table with the provided tag.## @param tag [String] table tab# @return [Hash, nil]defdirectory_info(tag)directory.tables[tag.to_s]end# Font Header (`head`) table## @return [TTFunk::Table::Head, nil]defheader@header||=TTFunk::Table::Head.new(self)end# Character to Glyph Index Mapping (`cmap`) table## @return [TTFunk::Tbale::Cmap, nil]defcmap@cmap||=TTFunk::Table::Cmap.new(self)end# Horizontal Header (`hhea`) table## @return [TTFunk::Table::Hhea, nil]defhorizontal_header@horizontal_header||=TTFunk::Table::Hhea.new(self)end# Horizontal Metrics (`hmtx`) table## @return [TTFunk::Table::Hmtx, nil]defhorizontal_metrics@horizontal_metrics||=TTFunk::Table::Hmtx.new(self)end# Maximum Profile (`maxp`) table## @return [TTFunk::Table::Maxp, nil]defmaximum_profile@maximum_profile||=TTFunk::Table::Maxp.new(self)end# Kerning (`kern`) table## @return [TTFunk::Table::Kern, nil]defkerning@kerning||=TTFunk::Table::Kern.new(self)end# Naming (`name`) table## @return [TTFunk::Table::Name, nil]defname@name||=TTFunk::Table::Name.new(self)end# OS/2 and Windows Metrics (`OS/2`) table## @return [TTFunk::Table:OS2, nil]defos2@os2||=TTFunk::Table::OS2.new(self)end# PostScript (`post`) table## @return [TTFunk::Table::Post, nil]defpostscript@postscript||=TTFunk::Table::Post.new(self)end# Index to Location (`loca`) table## @return [TTFunk::Table::Loca, nil]defglyph_locations@glyph_locations||=TTFunk::Table::Loca.new(self)end# Glyph Data (`glyf`) table## @return [TTFunk::Table::Glyf, nil]defglyph_outlines@glyph_outlines||=TTFunk::Table::Glyf.new(self)end# Standard Bitmap Graphics (`sbix`) table## @return [TTFunk::Table::Sbix, nil]defsbix@sbix||=TTFunk::Table::Sbix.new(self)end# Compact Font Format (`CFF `) table## @return [Table::Table::Cff, nil]defcff@cff||=TTFunk::Table::Cff.new(self)end# Vertical Origin (`VORG`) table## @return [TTFunk::Table::Vorg, nil]defvertical_origins@vertical_origins||=ifdirectory.tables.include?(TTFunk::Table::Vorg::TAG)TTFunk::Table::Vorg.new(self)endend# Digital Signature (`DSIG`) table## @return [TTFunk::Table::Dsig, nil]defdigital_signature@digital_signature||=ifdirectory.tables.include?(TTFunk::Table::Dsig::TAG)TTFunk::Table::Dsig.new(self)endend# Find glyph by its index.## @return [TTFunk::Table::Cff::Charstring] if it's a CFF-based OpenType font# @return [TTFunk::Table::Glyf::Simple, TTFunk::Table::Glyf::Compound]# if it's a TrueType fontdeffind_glyph(glyph_id)ifcff.exists?cff.top_index[0].charstrings_index[glyph_id].glyphelseglyph_outlines.for(glyph_id)endendendendrequire_relative'ttfunk/table/cff'require_relative'ttfunk/table/cmap'require_relative'ttfunk/table/dsig'require_relative'ttfunk/table/glyf'require_relative'ttfunk/table/head'require_relative'ttfunk/table/hhea'require_relative'ttfunk/table/hmtx'require_relative'ttfunk/table/kern'require_relative'ttfunk/table/loca'require_relative'ttfunk/table/maxp'require_relative'ttfunk/table/name'require_relative'ttfunk/table/os2'require_relative'ttfunk/table/post'require_relative'ttfunk/table/sbix'require_relative'ttfunk/table/vorg'