/// <summary> /// Creates an instance of a class that implements the FontTable interface. /// </summary> /// <param name="tableName"> /// One of the pre-defined TrueType tables from the <see cref="TableNames"/> class. /// </param> /// <returns> /// A subclass of <see cref="FontTable"/> that is capable of parsing /// a TrueType table. /// </returns> /// <exception cref="ArgumentException"> /// If a class capable of parsing <i>tableName</i> is not available. /// </exception> public static FontTable Make(string tableName, FontFileReader reader) { DirectoryEntry entry = reader.GetDictionaryEntry(tableName); switch (tableName) { case TableNames.Head: return new HeaderTable(entry); case TableNames.Hhea: return new HorizontalHeaderTable(entry); case TableNames.Hmtx: return new HorizontalMetricsTable(entry); case TableNames.Maxp: return new MaximumProfileTable(entry); case TableNames.Loca: return new IndexToLocationTable(entry); case TableNames.Glyf: return new GlyfDataTable(entry); case TableNames.Cvt: return new ControlValueTable(entry); case TableNames.Prep: return new ControlValueProgramTable(entry); case TableNames.Fpgm: return new FontProgramTable(entry); case TableNames.Post: return new PostTable(entry); case TableNames.Os2: return new OS2Table(entry); case TableNames.Name: return new NameTable(entry); case TableNames.Kern: return new KerningTable(entry); default: throw new ArgumentException("Unrecognised table name '" + tableName + "'", "tableName"); } }
/// <summary> /// Reads the contents of the "hmtx" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Obtain number of horizonal metrics from 'hhea' table int numberOfHMetrics = reader.GetHorizontalHeaderTable().HMetricCount; // Obtain glyph count from 'maxp' table int numGlyphs = reader.GetMaximumProfileTable().GlyphCount; // Metrics might not be supplied for each glyph. For example, if // the font is monospaced the hMetrics array will only contain a // single entry int metricsSize = (numGlyphs > numberOfHMetrics) ? numGlyphs : numberOfHMetrics; metrics = new ArrayList(metricsSize); for (int i = 0; i < numberOfHMetrics; i++) { metrics.Add(new HorizontalMetric( stream.ReadUShort(), stream.ReadShort())); } // Fill in missing widths if (numberOfHMetrics < metricsSize) { HorizontalMetric lastHMetric = (HorizontalMetric) metrics[metrics.Count - 1]; for (int i = numberOfHMetrics; i < numGlyphs; i++) { metrics.Add( new HorizontalMetric(lastHMetric.AdvanceWidth, stream.ReadShort())); } } }
/// <summary> /// Reads the contents of the "maxp" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // These two fields are common to versions 0.5 and 1.0 versionNo = stream.ReadFixed(); numGlyphs = stream.ReadUShort(); // Version 1.0 of this table contains more data if (versionNo == 0x00010000) { maxPoints = stream.ReadUShort(); maxContours = stream.ReadUShort(); maxCompositePoints = stream.ReadUShort(); maxCompositeContours = stream.ReadUShort(); maxZones = stream.ReadUShort(); maxTwilightPoints = stream.ReadUShort(); maxStorage = stream.ReadUShort(); maxFunctionDefs = stream.ReadUShort(); maxInstructionDefs = stream.ReadUShort(); maxStackElements = stream.ReadUShort(); maxSizeOfInstructions = stream.ReadUShort(); maxComponentElements = stream.ReadUShort(); maxComponentDepth = stream.ReadUShort(); } }
/// <summary> /// Reads the contents of the "hmtx" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Obtain number of horizonal metrics from 'hhea' table int numberOfHMetrics = reader.GetHorizontalHeaderTable().HMetricCount; // Obtain glyph count from 'maxp' table int numGlyphs = reader.GetMaximumProfileTable().GlyphCount; // Metrics might not be supplied for each glyph. For example, if // the font is monospaced the hMetrics array will only contain a // single entry int metricsSize = (numGlyphs > numberOfHMetrics) ? numGlyphs : numberOfHMetrics; metrics = new List <HorizontalMetric>();//(metricsSize); for (int i = 0; i < numberOfHMetrics; i++) { metrics.Add(new HorizontalMetric(stream.ReadUShort(), stream.ReadShort())); } // Fill in missing widths if (numberOfHMetrics < metricsSize) { HorizontalMetric lastHMetric = metrics[metrics.Count - 1]; for (int i = numberOfHMetrics; i < numGlyphs; i++) { metrics.Add( new HorizontalMetric(lastHMetric.AdvanceWidth, stream.ReadShort())); } } }
/// <summary> /// Reads the contents of the "loca" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Glyph offsets can be stored in either short of long format bool isShortFormat = reader.GetHeaderTable().IsShortFormat; // Number of glyphs including extra entry int glyphCount = reader.GetMaximumProfileTable().GlyphCount + 1; offsets = new ArrayList(glyphCount); for (int i = 0; i < glyphCount; i++) { offsets.Insert(i, (isShortFormat) ? (uint) (stream.ReadUShort() << 1) : stream.ReadULong()); } }
/// <summary> /// Creates an instance of a class that implements the FontTable interface. /// </summary> /// <param name="tableName"> /// One of the pre-defined TrueType tables from the <see cref="TableNames"/> class. /// </param> /// <returns> /// A subclass of <see cref="FontTable"/> that is capable of parsing /// a TrueType table. /// </returns> /// <exception cref="ArgumentException"> /// If a class capable of parsing <i>tableName</i> is not available. /// </exception> public static FontTable Make(string tableName, FontFileReader reader) { DirectoryEntry entry = reader.GetDictionaryEntry(tableName); switch (tableName) { case TableNames.Head: return(new HeaderTable(entry)); case TableNames.Hhea: return(new HorizontalHeaderTable(entry)); case TableNames.Hmtx: return(new HorizontalMetricsTable(entry)); case TableNames.Maxp: return(new MaximumProfileTable(entry)); case TableNames.Loca: return(new IndexToLocationTable(entry)); case TableNames.Glyf: return(new GlyfDataTable(entry)); case TableNames.Cvt: return(new ControlValueTable(entry)); case TableNames.Prep: return(new ControlValueProgramTable(entry)); case TableNames.Fpgm: return(new FontProgramTable(entry)); case TableNames.Post: return(new PostTable(entry)); case TableNames.Os2: return(new OS2Table(entry)); case TableNames.Name: return(new NameTable(entry)); case TableNames.Kern: return(new KerningTable(entry)); default: throw new ArgumentException("Unrecognised table name '" + tableName + "'", "tableName"); } }
/// <summary> /// Reads the contents of the "kern" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Skip version field stream.Skip(PrimitiveSizes.UShort); // Number of subtables int numTables = stream.ReadUShort(); for (int i = 0; i < numTables; i++) { // Another pesky version field stream.Skip(PrimitiveSizes.UShort); // Length of the subtable, in bytes (including header). ushort length = stream.ReadUShort(); // Type of information is contained in this table. ushort coverage = stream.ReadUShort(); // Only interested in horiztonal kerning values in format 0 if ((coverage & HoriztonalMask) == 1 && (coverage & MinimumMask) == 0 && ((coverage >> 8) == 0)) { // The number of kerning pairs in the table. int numPairs = stream.ReadUShort(); hasKerningInfo = true; pairs = new KerningPairs(numPairs); // Skip pointless shit stream.Skip(3 * PrimitiveSizes.UShort); for (int j = 0; j < numPairs; j++) { pairs.Add( stream.ReadUShort(), // Left glyph index stream.ReadUShort(), // Right glyph index stream.ReadFWord()); // Kerning amount } } else { stream.Skip(length - 3 * PrimitiveSizes.UShort); } } }
/// <summary> /// Reads the contents of the "os/2" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; version = stream.ReadUShort(); avgCharWidth = stream.ReadShort(); usWeightClass = stream.ReadUShort(); usWidthClass = stream.ReadUShort(); // According to the OpenType spec, bit 0 must be zero. fsType = (ushort)(stream.ReadUShort() & ~1); subscriptXSize = stream.ReadShort(); subscriptYSize = stream.ReadShort(); subscriptXOffset = stream.ReadShort(); subscriptYOffset = stream.ReadShort(); superscriptXSize = stream.ReadShort(); superscriptYSize = stream.ReadShort(); superscriptXOffset = stream.ReadShort(); superscriptYOffset = stream.ReadShort(); strikeoutSize = stream.ReadShort(); strikeoutPosition = stream.ReadShort(); short familyClass = stream.ReadShort(); classID = (byte)(familyClass >> 8); subclassID = (byte)(familyClass & 255); stream.Read(panose, 0, panose.Length); unicodeRange1 = stream.ReadULong(); unicodeRange2 = stream.ReadULong(); unicodeRange3 = stream.ReadULong(); unicodeRange4 = stream.ReadULong(); vendorID[0] = stream.ReadChar(); vendorID[1] = stream.ReadChar(); vendorID[2] = stream.ReadChar(); vendorID[3] = stream.ReadChar(); fsSelection = stream.ReadUShort(); usFirstCharIndex = stream.ReadUShort(); usLastCharIndex = stream.ReadUShort(); typoAscender = stream.ReadShort(); typoDescender = stream.ReadShort(); typoLineGap = stream.ReadShort(); usWinAscent = stream.ReadUShort(); usWinDescent = stream.ReadUShort(); codePageRange1 = stream.ReadULong(); codePageRange2 = stream.ReadULong(); sxHeight = stream.ReadShort(); sCapHeight = stream.ReadShort(); usDefaultChar = stream.ReadUShort(); usBreakChar = stream.ReadUShort(); usMaxContext = stream.ReadUShort(); }
/// <summary> /// Reads the contents of the "loca" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Glyph offsets can be stored in either short of long format bool isShortFormat = reader.GetHeaderTable().IsShortFormat; // Number of glyphs including extra entry int glyphCount = reader.GetMaximumProfileTable().GlyphCount + 1; offsets = new ArrayList(glyphCount); for (int i = 0; i < glyphCount; i++) { offsets.Insert(i, (isShortFormat) ? (uint)(stream.ReadUShort() << 1) : stream.ReadULong()); } }
/// <summary> /// Reads the contents of the "post" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; version = stream.ReadFixed(); // The italic angle is stored in the stupid fixed field format. italicAngle = (float)stream.ReadFixed() / 65536.0f; underlinePosition = stream.ReadFWord(); underlineThickness = stream.ReadFWord(); fixedPitch = stream.ReadULong(); minMemType42 = stream.ReadULong(); maxMemType42 = stream.ReadULong(); minMemType1 = stream.ReadULong(); maxMemType1 = stream.ReadULong(); }
/// <summary> /// Reads the contents of the "name" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Ignore format selector field stream.ReadUShort(); // Number of name records int numRecords = stream.ReadUShort(); // Offset to start of string storage (from start of table). storageOffset = stream.ReadUShort(); for (int i = 0; i < numRecords; i++) { int platformID = stream.ReadUShort(); int encodingID = stream.ReadUShort(); int languageID = stream.ReadUShort(); int nameID = stream.ReadUShort(); int length = stream.ReadUShort(); int stringOffset = stream.ReadUShort(); // Only interested in name records for Microsoft platform, // Unicode encoding and US English language. if (platformID == MicrosoftPlatformID && (encodingID == SymbolEncoding || encodingID == UnicodeEncoding) && languageID == EnglishAmericanLanguage) { switch (nameID) { case FamilyNameID: familyName = ReadString(stream, stringOffset, length); break; case FullNameID: fullName = ReadString(stream, stringOffset, length); break; } if (familyName != String.Empty && fullName != String.Empty) { break; } } } }
/// <summary> /// Reads the contents of the "kern" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; // Skip version field stream.Skip(PrimitiveSizes.UShort); // Number of subtables int numTables = stream.ReadUShort(); for (int i = 0; i < numTables; i++) { // Another pesky version field stream.Skip(PrimitiveSizes.UShort); // Length of the subtable, in bytes (including header). ushort length = stream.ReadUShort(); // Type of information is contained in this table. ushort coverage = stream.ReadUShort(); // Only interested in horiztonal kerning values in format 0 if ((coverage & HoriztonalMask) == 1 && (coverage & MinimumMask) == 0 && ((coverage >> 8) == 0)) { // The number of kerning pairs in the table. int numPairs = stream.ReadUShort(); hasKerningInfo = true; pairs = new KerningPairs(numPairs); // Skip pointless shit stream.Skip(3*PrimitiveSizes.UShort); for (int j = 0; j < numPairs; j++) { pairs.Add( stream.ReadUShort(), // Left glyph index stream.ReadUShort(), // Right glyph index stream.ReadFWord()); // Kerning amount } } else { stream.Skip(length - 3*PrimitiveSizes.UShort); } } }
/// <summary> /// Reads the contents of the "glyf" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { GlyphReader builder = new GlyphReader(reader); foreach (int index in reader.IndexMappings.GlyphIndices) { Glyph glyph = builder.ReadGlyph(index); glyphDescriptions[glyph.Index] = glyph; // Parse child glyphs if (glyph.IsComposite) { foreach (int subsetIndex in glyph.Children) { if (this[subsetIndex] == null) { int glyphIndex = reader.IndexMappings.GetGlyphIndex(subsetIndex); this[subsetIndex] = builder.ReadGlyph(glyphIndex); } } } } }
/// <summary> /// Reads the contents of the "head" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; versionNo = stream.ReadFixed(); fontRevision = stream.ReadFixed(); checkSumAdjustment = stream.ReadULong(); magicNumber = stream.ReadULong(); flags = stream.ReadUShort(); unitsPermEm = stream.ReadUShort(); // Some fonts have dodgy date offsets that cause AddSeconds to throw an exception createDate = GetDate(stream.ReadLongDateTime()); updateDate = GetDate(stream.ReadLongDateTime()); xMin = stream.ReadShort(); yMin = stream.ReadShort(); xMax = stream.ReadShort(); yMax = stream.ReadShort(); macStyle = stream.ReadUShort(); lowestRecPPEM = stream.ReadUShort(); fontDirectionHint = stream.ReadShort(); indexToLocFormat = stream.ReadShort(); glyphDataFormat = stream.ReadShort(); }
/// <summary> /// Reads the contents of the "hhea" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; versionNo = stream.ReadFixed(); ascender = stream.ReadFWord(); decender = stream.ReadFWord(); lineGap = stream.ReadFWord(); advanceWidthMax = stream.ReadUFWord(); minLeftSideBearing = stream.ReadFWord(); minRightSideBearing = stream.ReadFWord(); xMaxExtent = stream.ReadFWord(); caretSlopeRise = stream.ReadShort(); caretSlopeRun = stream.ReadShort(); caretOffset = stream.ReadShort(); stream.ReadShort(); stream.ReadShort(); stream.ReadShort(); stream.ReadShort(); metricDataFormat = stream.ReadShort(); numberOfHMetrics = stream.ReadUShort(); }
internal GdiFontMetrics(GdiDeviceContent dc, GdiFont currentFont) { if (dc.Handle == IntPtr.Zero) { throw new ArgumentNullException("dc", "Handle to device context cannot be null"); } if (dc.GetCurrentObject(GdiDcObject.Font) == IntPtr.Zero) { throw new ArgumentException("dc", "No font selected into supplied device context"); } this.dc = dc; this.currentFont = currentFont; // FontFileReader requires the font facename because the font may exist in // a TrueType collection. StringBuilder builder = new StringBuilder(255); LibWrapper.GetTextFace(dc.Handle, builder.Capacity, builder); faceName = builder.ToString(); ranges = new GdiUnicodeRanges(dc); reader = new FontFileReader(new MemoryStream(GetFontData()), faceName); converter = new PdfUnitConverter(EmSquare); // After we have cached the font data, we can safely delete the resource currentFont.Dispose(); }
/// <summary> /// Reads the contents of the "os/2" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; version = stream.ReadUShort(); avgCharWidth = stream.ReadShort(); usWeightClass = stream.ReadUShort(); usWidthClass = stream.ReadUShort(); // According to the OpenType spec, bit 0 must be zero. fsType = (ushort) (stream.ReadUShort() & ~1); subscriptXSize = stream.ReadShort(); subscriptYSize = stream.ReadShort(); subscriptXOffset = stream.ReadShort(); subscriptYOffset = stream.ReadShort(); superscriptXSize = stream.ReadShort(); superscriptYSize = stream.ReadShort(); superscriptXOffset = stream.ReadShort(); superscriptYOffset = stream.ReadShort(); strikeoutSize = stream.ReadShort(); strikeoutPosition = stream.ReadShort(); short familyClass = stream.ReadShort(); classID = (byte) (familyClass >> 8); subclassID = (byte) (familyClass & 255); stream.Read(panose, 0, panose.Length); unicodeRange1 = stream.ReadULong(); unicodeRange2 = stream.ReadULong(); unicodeRange3 = stream.ReadULong(); unicodeRange4 = stream.ReadULong(); vendorID[0] = stream.ReadChar(); vendorID[1] = stream.ReadChar(); vendorID[2] = stream.ReadChar(); vendorID[3] = stream.ReadChar(); fsSelection = stream.ReadUShort(); usFirstCharIndex = stream.ReadUShort(); usLastCharIndex = stream.ReadUShort(); typoAscender = stream.ReadShort(); typoDescender = stream.ReadShort(); typoLineGap = stream.ReadShort(); usWinAscent = stream.ReadUShort(); usWinDescent = stream.ReadUShort(); codePageRange1 = stream.ReadULong(); codePageRange2 = stream.ReadULong(); sxHeight = stream.ReadShort(); sCapHeight = stream.ReadShort(); usDefaultChar = stream.ReadUShort(); usBreakChar = stream.ReadUShort(); usMaxContext = stream.ReadUShort(); }
/// <summary> /// Gets an instance of an <see cref="FontTable"/> implementation that is /// capable of parsing the table identified by <b>tab</b>. /// </summary> /// <returns></returns> internal FontTable MakeTable(FontFileReader reader) { return FontTableFactory.Make(TableName, reader); }
/// <summary> /// Reads the contents of the "hhea" table from the current position /// in the supplied stream. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; versionNo = stream.ReadFixed(); ascender = stream.ReadFWord(); decender = stream.ReadFWord(); lineGap = stream.ReadFWord(); advanceWidthMax = stream.ReadUFWord(); minLeftSideBearing = stream.ReadFWord(); minRightSideBearing = stream.ReadFWord(); xMaxExtent = stream.ReadFWord(); caretSlopeRise = stream.ReadShort(); caretSlopeRun = stream.ReadShort(); caretOffset = stream.ReadShort(); // TODO: Check these 4 fields are all 0 stream.ReadShort(); stream.ReadShort(); stream.ReadShort(); stream.ReadShort(); metricDataFormat = stream.ReadShort(); numberOfHMetrics = stream.ReadUShort(); }
/// <summary> /// Creates a new instance of the FontSubset class. /// </summary> /// <param name="reader">TrueType font parser.</param> public FontSubset(FontFileReader reader) { this.reader = reader; }
/// <summary> /// Gets an instance of an <see cref="FontTable"/> implementation that is /// capable of parsing the table identified by <b>tab</b>. /// </summary> /// <returns></returns> internal FontTable MakeTable(FontFileReader reader) { return(FontTableFactory.Make(TableName, reader)); }
/// <summary> /// Reads the contents of the "post" table from the supplied stream /// at the current position. /// </summary> /// <param name="reader"></param> protected internal override void Read(FontFileReader reader) { FontFileStream stream = reader.Stream; version = stream.ReadFixed(); // The italic angle is stored in the stupid fixed field format. italicAngle = (float) stream.ReadFixed()/65536.0f; underlinePosition = stream.ReadFWord(); underlineThickness = stream.ReadFWord(); fixedPitch = stream.ReadULong(); minMemType42 = stream.ReadULong(); maxMemType42 = stream.ReadULong(); minMemType1 = stream.ReadULong(); maxMemType1 = stream.ReadULong(); }
/// <summary> /// Reads the contents of a table from the current position in /// the supplied stream. /// </summary> /// <param name="reader"></param> /// <exception cref="ArgumentException"> /// If the supplied stream does not contain enough data. /// </exception> protected internal abstract void Read(FontFileReader reader);