public CffGlyphParser(FontParser parser,FontFace font){ Font=font; Parser=parser; ScaleRatio=1f/font.UnitsPerEmF; Stack=new CffStack(); }
public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs,int numMetrics){ // Seek there: parser.Position=offset; // Get the glyph length: int numGlyphs=glyphs.Length; ushort advanceWidth=0; short leftSideBearing=0; // For each one.. for (int i=0;i<numGlyphs;i++){ // Monospaced fonts only have one entry: if (i<numMetrics){ advanceWidth=parser.ReadUInt16(); leftSideBearing=parser.ReadInt16(); } Glyph glyph=glyphs[i]; glyph.AdvanceWidth=(float)advanceWidth/font.UnitsPerEmF; glyph.LeftSideBearing=(float)leftSideBearing/font.UnitsPerEmF; } }
public static void Load(FontParser parser,int offset,FontFace font,out int glyphCount){ // Seek: parser.Position=offset; // Table version: float version=parser.ReadVersion(); // Glyph count: glyphCount=parser.ReadUInt16(); if (version == 1f){ // Max points: parser.ReadUInt16(); // Max contours: parser.ReadUInt16(); // Max composite points: parser.ReadUInt16(); // Max composite contours: parser.ReadUInt16(); // Max zones: parser.ReadUInt16(); // Max twilight points: parser.ReadUInt16(); // Max storage: parser.ReadUInt16(); // Max function defs: parser.ReadUInt16(); // Max instruction defs: parser.ReadUInt16(); // Max stack elements: parser.ReadUInt16(); // Max instruction size: parser.ReadUInt16(); // Max component elements: parser.ReadUInt16(); // Max component depth: parser.ReadUInt16(); } }
public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs){ // Seek: parser.Position=offset; // Check table version - 0 is current: if(parser.ReadUInt16()!=0){ return; } // Skip ntables: parser.Position+=2; // Sub-table version - 0 is current: if(parser.ReadUInt16()!=0){ return; } // Skip subTableLength, subTableCoverage: parser.Position+=4; // How many pairs? int pairCount=parser.ReadUInt16(); // Skip searchRange, entrySelector, rangeShift. parser.Position+=6; float scaleFactor=1f/font.UnitsPerEmF; for(int i=0;i<pairCount;i++){ // Get the glyph indices: int leftIndex=parser.ReadUInt16(); int rightIndex=parser.ReadUInt16(); // Get the kerning value: short value=parser.ReadInt16(); // Push: Glyph right=glyphs[rightIndex]; Glyph left=glyphs[leftIndex]; if(right==null || left==null){ continue; } right.AddKerningPair(left,(float)value * scaleFactor); } }
public static Glyph[] Load(FontParser parser,int start,uint[] locations,FontFace font){ // Get the vertical range of the font - it's the em size. float range=font.UnitsPerEmF; // The number of glyphs (last location is just used for computation purposes). int glyphCount=locations.Length-1; Glyph[] glyphs=new Glyph[glyphCount]; font.ParserGlyphs=glyphs; // For each glyph.. for(int i=0;i<glyphCount;i++){ uint offset=locations[i]; uint nextOffset=locations[i+1]; if(offset!=nextOffset){ // Seek there now: parser.Position=start+(int)offset; // Load it: glyphs[i]=ParseGlyph(parser,font,range); }else{ glyphs[i]=new Glyph(font); } } if(Fonts.Preload){ // Composite glyphs next. for(int i=0;i<glyphCount;i++){ Glyph glyph=glyphs[i]; if(glyph!=null){ glyph.LoadFully(glyphs); } } } return glyphs; }
public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs){ // Seek: parser.Position=offset; //float scaleFactor=1f/font.UnitsPerEmF; // Look for kerning data. /*Glyph right=glyphs[rightIndex]; Glyph left=glyphs[leftIndex]; if(right==null || left==null){ continue; } right.AddKerningPair(left,(float)value * scaleFactor); */ }
/// <summary>Adds the given font face to this family.</summary> public void Add(FontFace font){ font.DisableExtrude=DisableExtrude; // Grab the flags which represent the styling of this font: FontFaceFlags flags=font.StyleFlags; // Push: FontFaces[flags]=font; if(Regular==null || font.Regular){ Regular=font; } bool italic=font.Italic; if(font.Bold && !italic){ if(Bold==null){ Bold=new List<FontFace>(); } Bold.Add(font); } if(italic){ if(Italics==null){ Italics=new List<FontFace>(); } Italics.Add(font); } }
public static bool Load(FontParser parser, int start, FontFace font, Glyph[] glyphs) { // Seek there: parser.Position = start; // Read the version (and check if it's zero): if (parser.ReadUInt16() != 0) { return(false); } // Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table. // -> Got to grab all tables for a particular "platform". // -> Prefer platform 3 (Microsoft, most common and best documented), then 0, then anything else. // So, first let's figure out which platform we'll be using. // Favourite platform so far: int selectedPlatform = -1; // Number of tables: int tableCount = parser.ReadUInt16(); for (int i = 0; i < tableCount; i += 1) { // Grab the platform ID: int platformId = parser.ReadUInt16(); if (platformId == 0) { // Great, got platform 0. // Just halt there because we know this fonts got 0 so we'll use that. selectedPlatform = 0; break; } else if (platformId == 3) { // Prefer 3 over others: selectedPlatform = 3; } else if (selectedPlatform == -1) { // Anything else (last resort): selectedPlatform = platformId; } // Skip encoding ID and offset: parser.Position += 6; } if (selectedPlatform == -1) { // Empty table! Return. return(false); } // Round 2. This time, select all subtables of the favourite platform. // Then collect the offset and load it up. // Reset parser, skipping count and version: parser.Position = start + 4; // For each table.. for (int i = 0; i < tableCount; i += 1) { // Grab the platform ID: int platformId = parser.ReadUInt16(); #if INFINITEXT_DEBUG // And the encoding ID: int encodingId = parser.ReadUInt16(); Fonts.OnLogMessage("Font " + font.FamilyName + " cmap subtable. Platform ID: " + platformId + ", encoding ID: " + encodingId); #else // And the encoding ID: parser.ReadUInt16(); #endif if (platformId == selectedPlatform) { // Read offset: int offset = (int)parser.ReadUInt32(); // Get position: int position = parser.Position; // Load the subtable now: font.CharacterCount += LoadSubTable(parser, start + offset, font, glyphs); // Reset parser: parser.Position = position; } else { // Skip offset: parser.Position += 4; } } return(true); }
private static int LoadSubTable(FontParser parser, int start, FontFace font, Glyph[] glyphs) { // Total characters in subtable: int characterCount = 0; // Seek to the cmap now: parser.Position = start; // Check it's format 4: int format = parser.ReadUInt16(); #if INFINITEXT_DEBUG Fonts.OnLogMessage("Cmap subtable format: " + format); #endif if (format > 13) { // We now have e.g. 14.0 - ulong here ("Length"): parser.Position += 4; } else if (format > 6) { // We now have e.g. 12.0 - another short here (reserved): parser.Position += 2; // Length and language are both 4 byte ints now: parser.Position += 8; } else { // Size of the sub-table (map length, u16): parser.Position += 2; // Structure of the sub-table (map language, u16): parser.Position += 2; } switch (format) { case 0: // Byte encoding table: for (int i = 0; i < 256; i++) { int rByte = parser.ReadByte(); Glyph glyph = glyphs[rByte]; if (glyph != null) { characterCount++; glyph.AddCharcode(i); } } break; case 2: // The offset to the headers: int subOffset = parser.Position + (256 * 2); // For each high byte: for (int i = 0; i < 256; i++) { // Read the index to the header and zero out the bottom 3 bits: int headerPosition = subOffset + (parser.ReadUInt16() & (~7)); // Read the header: int firstCode = parser.ReadUInt16(ref headerPosition); int entryCount = parser.ReadUInt16(ref headerPosition); short idDelta = parser.ReadInt16(ref headerPosition); // Grab the current position: int pos = headerPosition; // Read the idRangeOffset - the last part of the header: pos += parser.ReadUInt16(ref headerPosition); int maxCode = firstCode + entryCount; // Get the high byte value: int highByte = (i << 8); // For each low byte: for (int j = firstCode; j < maxCode; j++) { // Get the full charcode (which might not actually exist yet): int charCode = highByte + j; // Read the base of the glyphIndex: int p = parser.ReadUInt16(ref pos); if (p == 0) { continue; } p = (p + idDelta) & 0xFFFF; if (p == 0) { continue; } Glyph glyph = glyphs[p]; if (glyph != null) { characterCount++; glyph.AddCharcode(charCode); } } } break; case 4: // Segment count. It's doubled. int segCount = (parser.ReadUInt16() >> 1); // Search range, entry selector and range shift (don't need any): parser.Position += 6; int baseIndex = parser.Position; int endCountIndex = baseIndex; baseIndex += 2; int startCountIndex = baseIndex + segCount * 2; int idDeltaIndex = baseIndex + segCount * 4; int idRangeOffsetIndex = baseIndex + segCount * 6; for (int i = 0; i < segCount - 1; i++) { int endCount = parser.ReadUInt16(ref endCountIndex); int startCount = parser.ReadUInt16(ref startCountIndex); int idDelta = parser.ReadInt16(ref idDeltaIndex); int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex); for (int c = startCount; c <= endCount; c++) { int glyphIndex; if (idRangeOffset != 0) { // The idRangeOffset is relative to the current position in the idRangeOffset array. // Take the current offset in the idRangeOffset array. int glyphIndexOffset = (idRangeOffsetIndex - 2); // Add the value of the idRangeOffset, which will move us into the glyphIndex array. glyphIndexOffset += idRangeOffset; // Then add the character index of the current segment, multiplied by 2 for USHORTs. glyphIndexOffset += (c - startCount) * 2; glyphIndex = parser.ReadUInt16(ref glyphIndexOffset); if (glyphIndex != 0) { glyphIndex = (glyphIndex + idDelta) & 0xFFFF; } } else { glyphIndex = (c + idDelta) & 0xFFFF; } // Add a charcode to the glyph now: Glyph glyph = glyphs[glyphIndex]; if (glyph != null) { characterCount++; glyph.AddCharcode(c); } } } break; case 6: int firstCCode = parser.ReadUInt16(); int entryCCount = parser.ReadUInt16(); for (int i = 0; i < entryCCount; i++) { Glyph glyphC = glyphs[parser.ReadUInt16()]; if (glyphC != null) { characterCount++; glyphC.AddCharcode(firstCCode + i); } } break; case 10: // Trimmed array. Similar to format 6. int startCharCode = parser.ReadUInt16(); int numChars = parser.ReadUInt16(); for (int i = 0; i < numChars; i++) { Glyph glyphC = glyphs[parser.ReadUInt16()]; if (glyphC != null) { characterCount++; glyphC.AddCharcode(startCharCode + i); } } break; case 12: // Segmented coverage. // Mapping of 1 charcode to 1 glyph. "Segmented" because it can come in blocks called groups. int groups = (int)parser.ReadUInt32(); // For each group of glyphs.. for (int i = 0; i < groups; i++) { // Start/end charcode: int startCode = (int)parser.ReadUInt32(); int endCode = (int)parser.ReadUInt32(); // Start glyph ID: int startGlyph = (int)parser.ReadUInt32(); int count = (endCode - startCode); // For each glyph/charcode pair.. for (int j = 0; j <= count; j++) { // Get the glyph: int glyphIndex = (startGlyph + j); Glyph glyph = glyphs[glyphIndex]; if (glyph != null) { characterCount++; // Charcode is.. glyph.AddCharcode(startCode + j); } } } break; case 13: // Many to one. Same format as #12 but the meaning is a bit different. // How many groups? int glyphCount = (int)parser.ReadUInt32(); for (int i = 0; i < glyphCount; i++) { int startCode = (int)parser.ReadUInt32(); int endCode = (int)parser.ReadUInt32(); int glyphID = (int)parser.ReadUInt32(); // Get the glyph: Glyph glyph = glyphs[glyphID]; if (glyph != null) { int count = (endCode - startCode); // For each charcode.. for (int j = 0; j <= count; j++) { characterCount++; // Hook up glyph to this charcode: glyph.AddCharcode(startCode + j); } } } break; case 14: Fonts.OnLogMessage("InfiniText partially supports part of the font '" + font.Family.Name + "' - this is harmless. Search for this message for more."); // This font contains a format 14 CMAP Table. // Format 14 is "Unicode variation selectors" - essentially different versions of the same character. // E.g. a text Emoji character and a graphical one. // In a text system like InfiniText, that just means we must map a bunch of different charcodes // to the same glyph. // .. I Think! As usual, the OpenType spec doesn't make too much sense. // However, it appears to be entirely optional. // So, approx implementation is below, however getting the utf32 code point from the variation + base character // is completely undocumented - my best guess unfortunately threw errors. // See the commented out block below! break; /* * * case 14: * * // How many var selector records? * int records=(int)parser.ReadUInt32(); * * for(int i=0;i<records;i++){ * * // variation selector: * int varSelector=(int)parser.ReadUInt24(); * * // Offsets: * int defaultUVSOffset=(int)parser.ReadUInt32(); * int nonDefaultUVSOffset=(int)parser.ReadUInt32(); * * // Grab parser position: * int position=parser.Position; * * // Got a ref to a default style table? * if(defaultUVSOffset!=0){ * * // Yep! The UVS is simply a list of "base" characters, each with ranges of available charcodes. * // [BaseCharCode][The extended part. Each of these comes from the range.] * // The actual glyph is the one that we get by directly looking up each of the base characters. * * // Seek to the table: * parser.Position=start+defaultUVSOffset; * * // Read the unicode value ranges count: * int numUniRangesCount=(int)parser.ReadUInt32(); * * // For each one.. * for(int m=0;m<numUniRangesCount;m++){ * * // Read the base charcode: * int baseCharcode=(int)parser.ReadUInt24(); * * // Read the size of the range: * byte rangeSize=parser.ReadByte(); * * for(int c=0;c<=rangeSize;c++){ * * // Fetch the base glyph: * Glyph glyph=font.GetGlyphDirect(baseCharcode); * * if(glyph!=null){ * * // Combine baseCharcode with varSelector next to form the variation (of "glyph"). * * // Get the full charcode (this is incorrect!): * // int charcode=char.ConvertToUtf32((char)baseCharcode,(char)varSelector); * * // Add: * //glyph.AddCharcode(charcode); * * } * * // Move baseCharcode along: * baseCharcode++; * * } * * } * * // Restore parser: * parser.Position=position; * * } * * // Got a ref to a non-default style table? * if(nonDefaultUVSOffset!=0){ * * // Yep! The UVS is simply a list of "base" characters, each with ranges of available charcodes. * // [BaseCharCode][The extended part. Each of these comes from the range.] * // This time though, the glyph to use is directly specified * // (that's what gives it the "non-default" property). * * // Seek to the table: * parser.Position=start+nonDefaultUVSOffset; * * // Read the number of mappings: * int numMappings=(int)parser.ReadUInt32(); * * // For each one.. * for(int m=0;m<numMappings;m++){ * * // Read the base charcode: * int baseCharcode=(int)parser.ReadUInt24(); * * // Read glyph ID: * int glyphID=(int)parser.ReadUInt16(); * * // Get the glyph: * Glyph glyph=glyphs[glyphID]; * * if(glyph!=null){ * * // Combine baseCharcode with varSelector next to form the variation (of "glyph"). * * // Get the full charcode (this is incorrect!): * // int charcode=char.ConvertToUtf32((char)baseCharcode,(char)varSelector); * * // Add: * //glyph.AddCharcode(charcode); * * } * * } * * // Restore parser: * parser.Position=position; * * } * * } * * break; * */ default: Fonts.OnLogMessage("InfiniText does not currently support part of this font. If you need it, please contact us with this: Format: " + format); break; } return(characterCount); }
public static void Load(FontParser parser, int offset, FontFace font) { // Seek: parser.Position = offset; // version int version = parser.ReadUInt16(); // xAvgCharWidth parser.ReadInt16(); // usWeightClass int weight = parser.ReadUInt16(); // usWidthClass int stretch = parser.ReadUInt16(); // fsType parser.ReadUInt16(); // ySubscriptXSize parser.ReadInt16(); // ySubscriptYSize parser.ReadInt16(); // ySubscriptXOffset parser.ReadInt16(); // ySubscriptYOffset parser.ReadInt16(); // ySuperscriptXSize parser.ReadInt16(); // ySuperscriptYSize parser.ReadInt16(); // ySuperscriptXOffset parser.ReadInt16(); // ySuperscriptYOffset parser.ReadInt16(); // yStrikeoutSize font.StrikeSize = (float)parser.ReadInt16() / font.UnitsPerEmF; // yStrikeoutPosition font.StrikeOffset = (float)parser.ReadInt16() / font.UnitsPerEmF; // sFamilyClass parser.ReadInt16(); // panose: /* * byte panose=new byte[10]; * * for(int i=0;i<10;i++){ * panose[i]=parser.ReadByte(); * } */ parser.Position += 10; // ulUnicodeRange1 parser.ReadUInt32(); // ulUnicodeRange2 parser.ReadUInt32(); // ulUnicodeRange3 parser.ReadUInt32(); // ulUnicodeRange4 parser.ReadUInt32(); // achVendID parser.ReadTag(); // fsSelection int type = parser.ReadUInt16(); bool italic = ((type & 1) == 1); // bool strikeout=((type&16)==16); // bool underscore=((type&2)==2); bool oblique = ((type & 512) == 512); bool bold = ((type & 32) == 32); bool regular = ((type & 64) == 64); bool useTypo = ((type & 128) == 128); if (!bold || regular) { // Must be regular: weight = 400; } else if (weight == 0) { weight = 700; } int styleCode = 0; if (italic) { styleCode = FontFaceFlags.Italic; } else if (oblique) { styleCode = FontFaceFlags.Oblique; } font.SetFlags(styleCode, weight, stretch); // usFirstCharIndex parser.ReadUInt16(); // usLastCharIndex parser.ReadUInt16(); // sTypoAscender float ascender = (float)parser.ReadInt16() / font.UnitsPerEmF; // sTypoDescender float descender = (float)parser.ReadInt16() / font.UnitsPerEmF; // sTypoLineGap float lineGap = ((float)parser.ReadInt16() / font.UnitsPerEmF); // We'll now always use OS/2 unless this table isn't present, in which case HHEA takes over. // (The W3C suggested approach). if (Fonts.AlwaysUseTypo || useTypo) { // Apply as-is: font.Ascender = ascender; font.Descender = -descender; font.LineGap = lineGap; // Remove internal leading if there is one: float internalLeading = (ascender - descender) - 1f; if (internalLeading != 0f) { // Add to lineGap: font.Ascender -= internalLeading; font.LineGap += internalLeading; } // Skip windows ascent/descent parser.Position += 4; } else { // usWinAscent parser.usWinAscent = (float)parser.ReadUInt16() / font.UnitsPerEmF; // usWinDescent parser.usWinDescent = (float)parser.ReadUInt16() / font.UnitsPerEmF; } if (version >= 1) { // ulCodePageRange1 parser.ReadUInt32(); // ulCodePageRange2 parser.ReadUInt32(); } if (version >= 2) { // sxHeight parser.ReadInt16(); // sCapHeight parser.ReadInt16(); // usDefaultChar parser.ReadUInt16(); // usBreakChar parser.ReadUInt16(); // usMaxContent parser.ReadUInt16(); } }
public static bool Load(int version, FontParser parser, FontFace font) { // Load the V1/V2 header: ushort numTables; LoadHeader(version, parser, out numTables); if (version == 1) { MemoryStream ms = new MemoryStream(parser.Data); // Get the ZLIB compression helper: Compressor zLib = Compression.Get("zlib"); // Read each table next. for (int i = 0; i < numTables; i++) { string tag = parser.ReadTag(); uint offset = parser.ReadUInt32(); uint compLength = parser.ReadUInt32(); uint origLength = parser.ReadUInt32(); parser.ReadUInt32(); // origChecksum // Cache position: int pos = parser.Position; if (compLength != origLength) { // Decompress the table now (zlib) // Seek to table: ms.Position = (int)offset; // Decompressed data: byte[] decompressedTable = new byte[(int)origLength]; // Decompress now into our target bytes: zLib.Decompress(ms, decompressedTable); } else { // Ordinary table. parser.HandleTable(tag, (int)offset, font); } // Restore position: parser.Position = pos; } } else if (version == 2) { // Read each table entry next. The data here is compressed as one single block after the table meta. Woff2Table[] tableHeaders = new Woff2Table[numTables]; int offset = 0; for (int i = 0; i < numTables; i++) { // Read the table entry: byte flags = parser.ReadByte(); string tag; int tagFlag = (flags & 63); if (tagFlag == 63) { tag = parser.ReadTag(); } else { tag = TagLookup[tagFlag]; } ulong origLength = parser.ReadBase128(); ulong transformLength = 0; int transformVersion = (flags >> 6); //0-3 if (tag == "glyf" || tag == "loca") { // transform length: transformLength = parser.ReadBase128(); } offset += (int)origLength; tableHeaders[i] = new Woff2Table(tag, offset, (int)transformLength, transformVersion); } } // All ok: return(true); }
public CompositeGlyph(FontFace parent) : base(parent) { }
/// <summary>Adds a ligature table to the font.</summary> public static void AddToFont(string name,FontParser parser,int tableOffset,FontFace font,LigatureLookupTable[] tables){ int position=parser.Position; // Skip params (+2): parser.Position=tableOffset+2; // Index count: int count=parser.ReadUInt16(); // For each one.. for(int i=0;i<count;i++){ // Grab the index: //int index=parser.ReadUInt16(); // Grab the table: //LigatureLookupTable table=tables[index]; } parser.Position=position; }
public static bool Load(FontParser parser,int start,FontFace font,Glyph[] glyphs){ // Seek there: parser.Position=start; // Read the version (and check if it's zero): if(parser.ReadUInt16()!=0){ return false; } // Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table. // Number of tables: int tableCount=parser.ReadUInt16(); // Total characters in font: int characterCount=0; int offset=-1; int favour=0; for(int i = 0; i < tableCount; i += 1) { // Grab the platform ID: int platformId=parser.ReadUInt16(); // And the encoding ID: int encodingId=parser.ReadUInt16(); if(platformId==3 || platformId==0){ if(encodingId==10){ // Top favourite - most broad Unicode encoding. // Read offset: offset=(int)parser.ReadUInt32(); break; }else if(encodingId==1 || encodingId==0){ // Read offset: offset=(int)parser.ReadUInt32(); // Mid-range favourite: favour=1; continue; }else if(favour==0){ // Anything else we'll give a try: // Read offset (but don't break): offset=(int)parser.ReadUInt32(); continue; } } // Skip offset: parser.Position+=4; } if(offset==-1){ // We don't support this font :( return false; } // Seek to the cmap now: parser.Position=start+offset; // Check it's format 4: int format=parser.ReadUInt16(); if(format>6){ // We now have e.g. 12.0 - another short here: parser.Position+=2; // Size/ structure are both 4 byte ints now: parser.Position+=8; }else{ // Size of the sub-table (map length, u16): parser.Position+=2; // Structure of the sub-table (map language, u16): parser.Position+=2; } switch(format){ case 0: // Byte encoding table: for(int i=0;i<256;i++){ int rByte=parser.ReadByte(); Glyph glyph=glyphs[rByte]; if(glyph!=null){ characterCount++; glyph.AddCharcode(i); } } break; case 2: // The offset to the headers: int subOffset=parser.Position + (256 * 2); // For each high byte: for(int i=0;i<256;i++){ // Read the index to the header and zero out the bottom 3 bits: int headerPosition=subOffset + (parser.ReadUInt16() & (~7)); // Read the header: int firstCode=parser.ReadUInt16(ref headerPosition); int entryCount=parser.ReadUInt16(ref headerPosition); short idDelta=parser.ReadInt16(ref headerPosition); // Grab the current position: int pos=headerPosition; // Read the idRangeOffset - the last part of the header: pos+=parser.ReadUInt16(ref headerPosition); int maxCode=firstCode+entryCount; // Get the high byte value: int highByte=(i<<8); // For each low byte: for (int j=firstCode;j<maxCode;j++){ // Get the full charcode (which might not actually exist yet): int charCode=highByte+j; // Read the base of the glyphIndex: int p=parser.ReadUInt16(ref pos); if(p==0){ continue; } p=(p+idDelta) & 0xFFFF; if(p==0){ continue; } Glyph glyph=glyphs[p]; if(glyph!=null){ characterCount++; glyph.AddCharcode(charCode); } } } break; case 4: // Segment count. It's doubled. int segCount=(parser.ReadUInt16() >> 1); // Search range, entry selector and range shift (don't need any): parser.Position+=6; int baseIndex=parser.Position; int endCountIndex=baseIndex; baseIndex+=2; int startCountIndex = baseIndex + segCount * 2; int idDeltaIndex = baseIndex + segCount * 4; int idRangeOffsetIndex = baseIndex + segCount * 6; for(int i = 0; i < segCount - 1; i ++){ int endCount = parser.ReadUInt16(ref endCountIndex); int startCount = parser.ReadUInt16(ref startCountIndex); int idDelta = parser.ReadInt16(ref idDeltaIndex); int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex); for(int c = startCount; c <= endCount;c++){ int glyphIndex; if(idRangeOffset != 0){ // The idRangeOffset is relative to the current position in the idRangeOffset array. // Take the current offset in the idRangeOffset array. int glyphIndexOffset = (idRangeOffsetIndex - 2); // Add the value of the idRangeOffset, which will move us into the glyphIndex array. glyphIndexOffset += idRangeOffset; // Then add the character index of the current segment, multiplied by 2 for USHORTs. glyphIndexOffset += (c - startCount) * 2; glyphIndex=parser.ReadUInt16(ref glyphIndexOffset); if(glyphIndex!=0){ glyphIndex = (glyphIndex + idDelta) & 0xFFFF; } }else{ glyphIndex = (c + idDelta) & 0xFFFF; } // Add a charcode to the glyph now: Glyph glyph=glyphs[glyphIndex]; if(glyph!=null){ characterCount++; glyph.AddCharcode(c); } } } break; case 6: int firstCCode=parser.ReadUInt16(); int entryCCount=parser.ReadUInt16(); for(int i=0;i<entryCCount;i++){ Glyph glyphC=glyphs[parser.ReadUInt16()]; if(glyphC!=null){ characterCount++; glyphC.AddCharcode(firstCCode+i); } } break; case 12: int groups=(int)parser.ReadUInt32(); for(int i=0;i<groups;i++){ int startCode=(int)parser.ReadUInt32(); int endCode=(int)parser.ReadUInt32(); int startGlyph=(int)parser.ReadUInt32(); int count=(endCode - startCode); for(int j=0;j<=count;j++){ int glyphIndex=(startGlyph+j); Glyph glyph=glyphs[glyphIndex]; if(glyph!=null){ characterCount++; glyph.AddCharcode(startCode+j); } } } break; default: Fonts.OnLogMessage("InfiniText does not currently support this font. If you need it, please contact us with this: Format: "+format); break; } font.CharacterCount=characterCount; return true; }
public static void Load(FontParser parser, int offset, FontFace font) { // Seek there: parser.Position = offset; // Version: parser.ReadVersion(); // Script list (directed by UI Language setting): int scriptList = parser.ReadUInt16(); // Feature list: int featList = parser.ReadUInt16(); // Lookup list: int lookList = parser.ReadUInt16(); // Goto script list: int objectOffset = scriptList + offset; parser.Position = objectOffset; /* * // How many language scripts? * int scriptCount=parser.ReadUInt16(); * * for(int i=0;i<scriptCount;i++){ * * // Read the script code: * string scrName=parser.ReadString(4); * * // And it's offset: * int scriptOffset=parser.ReadUInt16()+objectOffset; * * int retPosition=parser.Position; * * // Seek and load it right away: * parser.Position=scriptOffset; * * // What's the default lang? * int defaultLangOffset=parser.ReadUInt16(); * * // How many languages? * int langCount=parser.ReadUInt16(); * * for(int l=0;l<langCount;l++){ * * // Read the lang code: * string langName=parser.ReadString(4); * * // And it's offset - points to list of features: * int langOffset=parser.ReadUInt16()+objectOffset; * * } * * parser.Position=retPosition; * * } */ // Goto lookup list: objectOffset = lookList + offset; // Seek there: parser.Position = objectOffset; // Load each one: int lookCount = parser.ReadUInt16(); // Create: LigatureLookupTable[] lookupTables = new LigatureLookupTable[lookCount]; for (int i = 0; i < lookCount; i++) { // Create the table: LigatureLookupTable table = new LigatureLookupTable(); // Load it: int tableOffset = parser.ReadUInt16(); // Cache the position: int seekPos = parser.Position; // Head over to the table: parser.Position = objectOffset + tableOffset; // Load it now: table.Load(parser); // Add to set: lookupTables[i] = table; // Restore position: parser.Position = seekPos; } // Goto feature list: objectOffset = featList + offset; parser.Position = objectOffset; // How many features? For now, "liga" is the main feature we're after here. int featureCount = parser.ReadUInt16(); for (int i = 0; i < featureCount; i++) { // Read the feature code: string feature = parser.ReadString(4); // Table offset: int featTable = parser.ReadUInt16(); switch (feature) { case "locl": case "liga": AddToFont(feature, parser, featTable + objectOffset, font, lookupTables); break; } } }
/// <summary>Adds a ligature table to the font.</summary> public static void AddToFont(string name, FontParser parser, int tableOffset, FontFace font, LigatureLookupTable[] tables) { int position = parser.Position; // Skip params (+2): parser.Position = tableOffset + 2; // Index count: int count = parser.ReadUInt16(); // For each one.. for (int i = 0; i < count; i++) { // Grab the index: //int index=parser.ReadUInt16(); // Grab the table: //LigatureLookupTable table=tables[index]; } parser.Position = position; }
public static void Load(FontParser parser, int offset, FontFace font, out int hmMetricCount) { // Seek there: parser.Position = offset; // Version: parser.ReadVersion(); // Ascender: float ascender = (float)parser.ReadInt16() / font.UnitsPerEmF; // Descender: float descender = (float)parser.ReadInt16() / font.UnitsPerEmF; // Line gap: float lineGap = (float)parser.ReadInt16() / font.UnitsPerEmF; if (!Fonts.UseOS2Metrics || !parser.ReadOS2) { if (lineGap < 0f) { lineGap = -lineGap; } float halfGap = lineGap / 2f; font.Ascender = ascender + halfGap; font.Descender = halfGap - descender; font.LineGap = font.Ascender + font.Descender; } // Advance width max: font.MaxAdvanceWidth = (float)parser.ReadUInt16() / font.UnitsPerEmF; // Min left side bearing: font.MinLeftSideBearing = (float)parser.ReadInt16() / font.UnitsPerEmF; // Min right side bearing: font.MinRightSideBearing = (float)parser.ReadInt16() / font.UnitsPerEmF; // Max x extent: font.MaxXExtent = (float)parser.ReadInt16() / font.UnitsPerEmF; // Caret slope rise: float caretRise = (float)parser.ReadInt16(); // Caret slope run: float caretRun = (float)parser.ReadInt16(); font.CaretAngle = (float)Math.Atan2(caretRise, caretRun); // Caret offset: font.CaretOffset = (float)parser.ReadInt16() / font.UnitsPerEmF; // Skip: parser.Position += 8; // Metric format: parser.ReadInt16(); // Metric count: hmMetricCount = parser.ReadUInt16(); }
public static bool Load(FontParser parser, int offset, FontFace font, out int locFormatIndex) { // Seek there now: parser.Position = offset; // Version: parser.ReadVersion(); // Revision: parser.ReadRevision(); // Checksum adjustment: parser.ReadUInt32(); // Magic number: if (parser.ReadUInt32() != 0x5F0F3CF5) { locFormatIndex = 0; return(false); } // Flags: parser.ReadUInt16(); // Units per em: font.UnitsPerEm = parser.ReadUInt16(); font.UnitsPerEmF = (float)font.UnitsPerEm; // Skip created and modified: parser.ReadTime(); parser.ReadTime(); // X min: parser.ReadInt16(); // Y min: parser.ReadInt16(); // X max: parser.ReadInt16(); // Y max: parser.ReadInt16(); // Mac style: parser.ReadUInt16(); // Lowest Rec PPEM: parser.ReadUInt16(); // Font direction hint: parser.ReadInt16(); // Index for the loc format: locFormatIndex = parser.ReadInt16(); // 50 // Glyph data format: parser.ReadInt16(); return(true); }
public static void Load(FontParser parser, int offset, FontFace font, out int numberOfGlyphs) { // Seek: parser.Position = offset; // version float version = parser.ReadVersion(); // Italic angle. For some reason it's inverted in the spec - negative means a slope to the right. int frac; int dec = parser.ReadFixed(out frac); if (frac != 0) { // Figure it out: float angle = (float)dec / (float)frac; // Apply it (un-inverted): font.SetItalicAngle(-angle); } // underlinePosition parser.ReadInt16(); // underlineThickness parser.ReadInt16(); // isFixedPitch parser.ReadUInt32(); // minMemType42 parser.ReadUInt32(); // maxMemType42 parser.ReadUInt32(); // minMemType1 parser.ReadUInt32(); // maxMemType1 parser.ReadUInt32(); if (version == 2f) { numberOfGlyphs = parser.ReadUInt16(); /* * string[] glyphNames=new string[numberOfGlyphs]; * * for (int i = 0; i < numberOfGlyphs; i++) { * * // Read the index: * int index = parser.ReadUInt16(); * * if(index >= StandardNames.Length){ * * // Read the name: * glyphNames[i]=parser.ReadString(parser.ReadByte()); * * }else{ * * // Grab the std name: * glyphNames[i]=StandardNames[index]; * * } * * } */ } else if (version == 2.5f) { numberOfGlyphs = parser.ReadUInt16(); /* * byte[] offsets = new byte[numberOfGlyphs]; * * for (int i = 0; i < post.numberOfGlyphs; i++){ * * offsets[i] = parser.ReadByte(); * * } */ } else { numberOfGlyphs = -1; } }
//--------------------------------------
public static void Load(FontParser parser,int offset,FontFace font){ // Seek there: parser.Position=offset; // Version: parser.ReadVersion(); // Script list (directed by UI Language setting): int scriptList=parser.ReadUInt16(); // Feature list: int featList=parser.ReadUInt16(); // Lookup list: int lookList=parser.ReadUInt16(); // Goto script list: int objectOffset=scriptList+offset; parser.Position=objectOffset; /* // How many language scripts? int scriptCount=parser.ReadUInt16(); for(int i=0;i<scriptCount;i++){ // Read the script code: string scrName=parser.ReadString(4); // And it's offset: int scriptOffset=parser.ReadUInt16()+objectOffset; int retPosition=parser.Position; // Seek and load it right away: parser.Position=scriptOffset; // What's the default lang? int defaultLangOffset=parser.ReadUInt16(); // How many languages? int langCount=parser.ReadUInt16(); for(int l=0;l<langCount;l++){ // Read the lang code: string langName=parser.ReadString(4); // And it's offset - points to list of features: int langOffset=parser.ReadUInt16()+objectOffset; } parser.Position=retPosition; } */ // Goto lookup list: objectOffset=lookList+offset; // Seek there: parser.Position=objectOffset; // Load each one: int lookCount=parser.ReadUInt16(); // Create: LigatureLookupTable[] lookupTables=new LigatureLookupTable[lookCount]; for(int i=0;i<lookCount;i++){ // Create the table: LigatureLookupTable table=new LigatureLookupTable(); // Load it: int tableOffset=parser.ReadUInt16(); // Cache the position: int seekPos=parser.Position; // Head over to the table: parser.Position=objectOffset+tableOffset; // Load it now: table.Load(parser); // Add to set: lookupTables[i]=table; // Restore position: parser.Position=seekPos; } // Goto feature list: objectOffset=featList+offset; parser.Position=objectOffset; // How many features? For now, "liga" is the main feature we're after here. int featureCount=parser.ReadUInt16(); for(int i=0;i<featureCount;i++){ // Read the feature code: string feature=parser.ReadString(4); // Table offset: int featTable=parser.ReadUInt16(); switch(feature){ case "locl": case "liga": AddToFont(feature,parser,featTable+objectOffset,font,lookupTables); break; } } }
public static void Load(FontParser parser,int offset,FontFace font,out int hmMetricCount){ // Seek there: parser.Position=offset; // Version: parser.ReadVersion(); // Ascender: float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF; // Descender: float descender=(float)parser.ReadInt16()/font.UnitsPerEmF; // Line gap: float lineGap=(float)parser.ReadInt16()/font.UnitsPerEmF; if(!Fonts.UseOS2Metrics || !parser.ReadOS2){ if(lineGap<0f){ lineGap=-lineGap; } float halfGap=lineGap/2f; font.Ascender=ascender + halfGap; font.Descender=halfGap-descender; font.LineGap=font.Ascender + font.Descender; } // Advance width max: font.MaxAdvanceWidth=(float)parser.ReadUInt16()/font.UnitsPerEmF; // Min left side bearing: font.MinLeftSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF; // Min right side bearing: font.MinRightSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF; // Max x extent: font.MaxXExtent=(float)parser.ReadInt16()/font.UnitsPerEmF; // Caret slope rise: float caretRise=(float)parser.ReadInt16(); // Caret slope run: float caretRun=(float)parser.ReadInt16(); font.CaretAngle=(float)Math.Atan2(caretRise,caretRun); // Caret offset: font.CaretOffset=(float)parser.ReadInt16()/font.UnitsPerEmF; // Skip: parser.Position += 8; // Metric format: parser.ReadInt16(); // Metric count: hmMetricCount = parser.ReadUInt16(); }
public static Glyph ParseGlyph(FontParser parser,FontFace font,float range){ // How many contours has it got? int contourCount=parser.ReadInt16(); // Skip bounds - we don't trust these too much, so we'll figure them out ourselves: parser.Position+=8; if(contourCount>0){ // This glyph is not a composite. // Create the glyph: Glyph glyph=new Glyph(font); if(Fonts.Preload){ LoadGlyph(glyph,contourCount,parser,range); }else{ // Increase unloaded count: font.UnloadedGlyphs++; // Add position info: glyph.AddPathNode(new LoadMetaPoint(parser.Position,contourCount)); } return glyph; }else if(contourCount==0){ // Empty glyph e.g. space. Create the glyph: Glyph glyph=new Glyph(font); return glyph; } CompositeGlyph compGlyph=new CompositeGlyph(font); bool moreComponents=true; while(moreComponents){ ushort cFlags=parser.ReadUInt16(); ushort glyphIndex=parser.ReadUInt16(); VectorTransform component=new VectorTransform(glyphIndex); if ((cFlags & 1) > 0) { // The arguments are words component.Dx = (float)parser.ReadInt16() / range; component.Dy = (float)parser.ReadInt16() / range; } else { // The arguments are bytes component.Dx = (float)parser.ReadByte() / range; component.Dy = (float)parser.ReadByte() / range; } if ((cFlags & 8) > 0) { // We have one scale component.XScale = component.YScale = parser.ReadF2Dot14(); } else if ((cFlags & 64) > 0) { // We have an X / Y scale component.XScale = parser.ReadF2Dot14(); component.YScale = parser.ReadF2Dot14(); } else if ((cFlags & 128) > 0) { // We have a 2x2 transformation component.XScale = parser.ReadF2Dot14(); component.Scale01 = parser.ReadF2Dot14(); component.Scale10 = parser.ReadF2Dot14(); component.YScale = parser.ReadF2Dot14(); } // Push the component to the end: compGlyph.AddComponent(component); moreComponents = ((cFlags & 32)==32); } return compGlyph; }
public CompositeGlyph(FontFace parent):base(parent){ }
/// <summary>Gets or creates the most suitable font face for the given style.</summary> public FontFace GetFace(int styleCode, int synthFlags) { // Style (italic, oblique etc): int style = (styleCode & FontFaceFlags.StyleMask); // Get the font weight: int weight = (styleCode & FontFaceFlags.WeightMask) >> 3; if (weight == 0) { // Regular: weight = 4; } // And the stretch mode: int stretch = (styleCode & FontFaceFlags.StretchMask) >> 7; if (stretch == 0) { // Medium stretch stretch = 5; } // Try getting the face: FontFace bestFace = Regular; // A linear search is actually optimal for most cases. // This is because the set is typically very small. // [Condensed][Weight][Italic] int bestMatch = 0; for (int i = 0; i < FontFaces.Count; i++) { // Current face: FontFace face = FontFaces[i]; // We'll now figure out a match weighting. int matchWeight = 0; // First, we match by condensed: if (face.Stretch == stretch) { // Direct match. 8 points awarded. matchWeight = 8; } else { // How close is it? int stretchDiff = face.Stretch - stretch; if (stretchDiff < 0) { stretchDiff = -stretchDiff; } // StretchDiff maxes out at 8. Award at most 8 points. matchWeight = 8 - stretchDiff; } // Weight next. if (face.Weight == weight) { // Direct match. 8 points awarded. matchWeight += 8; } else { // How close is it? int weightDiff = face.Weight - weight; if (weightDiff < 0) { weightDiff = -weightDiff; } // weightDiff maxes out at 8. Award at most 8 points. matchWeight += 8 - weightDiff; } // Style. if (face.Style == style) { // Direct match! 2 points awarded. matchWeight += 2; } else { // If it's the other of oblique/italic, award 1 point. if (style != 0 && face.Style != 0) { matchWeight += 1; } } if (matchWeight > bestMatch) { // Got a new best! bestMatch = matchWeight; bestFace = face; } if (matchWeight == 18) { // Perfect match! break; } } if (bestMatch != 18 && synthFlags != 0) { // Synthesize a face, deriving it from our best match. bestFace = bestFace.CreateSynthetic(style, weight, stretch); // Add it: Add(bestFace); } return(bestFace); }
public static Glyph[] Load(FontParser parser,int offset,FontFace font){ // Create the parser: CffGlyphParser cffParser=new CffGlyphParser(parser,font); cffParser.FullLoad=Fonts.Preload; font.CffParser=cffParser; // Seek, skipping the 4 byte header: parser.Position=offset+4; // Skip the name index: SkipIndex(parser); // Top dict index next (one entry only): Dictionary<int,List<int>> topDict=LoadDict(parser); // String index: SkipIndex(parser); // GSubr index: cffParser.GSubrs=LoadSubIndex(parser); // Figure out the bias: cffParser.GsubrsBias=GetBias(cffParser.GSubrs); // Read the private dict next - grab the info about where it is: List<int> privateDictInfo=topDict[18]; // Get it's offset: int privateDictOffset=offset+privateDictInfo[1]; // Seek there: parser.Position=privateDictOffset; // Load: Dictionary<int,List<int>> privateDict=ParseCFFDict(parser,privateDictInfo[0]); // Grab the default values: cffParser.DefaultWidthX=(float)ReadDict(privateDict,20); cffParser.NominalWidthX=(float)ReadDict(privateDict,21); // Grab the subrs offset. May be zero (or non-existant): int privateSubrs=ReadDict(privateDict,19); if(privateSubrs!=0){ // We have a "subroutine" set. Get it's full offset and hop there: parser.Position=privateDictOffset+privateSubrs; // Load the set: cffParser.Subrs=LoadSubIndex(parser); // Figure out the bias/offset: cffParser.SubrsBias=GetBias(cffParser.Subrs); } // Seek to the char string table: parser.Position=offset+ReadDict(topDict,17); // Time to actually load the actual glyphs, wohoo! O.O return LoadIndex(parser,cffParser); }
public static void Load(FontParser parser,int offset,FontFace font){ // Got OS2: parser.ReadOS2=true; // Seek: parser.Position=offset; // version int version=parser.ReadUInt16(); // xAvgCharWidth parser.ReadInt16(); // usWeightClass int weight=parser.ReadUInt16(); // usWidthClass parser.ReadUInt16(); // fsType parser.ReadUInt16(); // ySubscriptXSize parser.ReadInt16(); // ySubscriptYSize parser.ReadInt16(); // ySubscriptXOffset parser.ReadInt16(); // ySubscriptYOffset parser.ReadInt16(); // ySuperscriptXSize parser.ReadInt16(); // ySuperscriptYSize parser.ReadInt16(); // ySuperscriptXOffset parser.ReadInt16(); // ySuperscriptYOffset parser.ReadInt16(); // yStrikeoutSize font.StrikeSize=(float)parser.ReadInt16()/font.UnitsPerEmF; // yStrikeoutPosition font.StrikeOffset=(float)parser.ReadInt16()/font.UnitsPerEmF; // sFamilyClass parser.ReadInt16(); // panose: /* byte panose=new byte[10]; for(int i=0;i<10;i++){ panose[i]=parser.ReadByte(); } */ parser.Position+=10; // ulUnicodeRange1 parser.ReadUInt32(); // ulUnicodeRange2 parser.ReadUInt32(); // ulUnicodeRange3 parser.ReadUInt32(); // ulUnicodeRange4 parser.ReadUInt32(); // achVendID parser.ReadTag(); // fsSelection int type=parser.ReadUInt16(); bool italic=((type&1)==1); // bool strikeout=((type&16)==16); // bool underscore=((type&2)==2); bool oblique=((type&512)==512); bool bold=((type&32)==32); bool regular=((type&64)==64); bool useTypo=((type&128)==128); if(!bold || regular){ // Must be regular: weight=400; }else if(weight==0){ weight=700; } font.SetFlags(italic || oblique,weight); // usFirstCharIndex parser.ReadUInt16(); // usLastCharIndex parser.ReadUInt16(); // sTypoAscender float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF; // sTypoDescender float descender=(float)parser.ReadInt16()/font.UnitsPerEmF; // sTypoLineGap float lineGap=((float)parser.ReadInt16()/font.UnitsPerEmF); // usWinAscent float wAscender=(float)parser.ReadUInt16()/font.UnitsPerEmF; // usWinDescent float wDescender=(float)parser.ReadUInt16()/font.UnitsPerEmF; // This is an awkward spec hack due to most windows programs // providing the wrong typo descender values. if(Fonts.UseOS2Metrics){ if(useTypo){ float halfGap=lineGap/2f; font.Ascender=ascender + halfGap; font.Descender=halfGap-descender; font.LineGap=font.Ascender + font.Descender; }else{ font.Ascender=wAscender; font.Descender=wDescender; font.LineGap=font.Ascender + font.Descender; } } if (version >= 1){ // ulCodePageRange1 parser.ReadUInt32(); // ulCodePageRange2 parser.ReadUInt32(); } if (version >= 2){ // sxHeight parser.ReadInt16(); // sCapHeight parser.ReadInt16(); // usDefaultChar parser.ReadUInt16(); // usBreakChar parser.ReadUInt16(); // usMaxContent parser.ReadUInt16(); } }
public static Dictionary<string,string> Load(FontParser parser,int start,FontFace font){ // Create the map: Dictionary<string,string> map=new Dictionary<string,string>(); // Go there now: parser.Position=start; // Format: int format=parser.ReadUInt16(); // Number of names: int count = parser.ReadUInt16(); // String offset: int stringOffset = start + parser.ReadUInt16(); int unknownCount = 0; for(int i=0;i<count;i++){ // Platform ID: ushort platformID = parser.ReadUInt16(); ushort encodingID = parser.ReadUInt16(); ushort languageID = parser.ReadUInt16(); ushort nameID = parser.ReadUInt16(); string property = null; if(nameID<PropertyMap.Length){ property=PropertyMap[nameID]; } ushort byteLength = parser.ReadUInt16(); ushort offset = parser.ReadUInt16(); // platformID - encodingID - languageID standard combinations : // 1 - 0 - 0 : Macintosh, Roman, English // 3 - 1 - 0x409 : Windows, Unicode BMP (UCS-2), en-US if(platformID == 3 && encodingID == 1 && languageID == 0x409){ int length = byteLength/2; char[] chars=new char[length]; int index=stringOffset+offset; for(int j = 0; j < length; j++){ chars[j] = (char)parser.ReadInt16(ref index); } string str = new string(chars); if(property!=null){ map[property] = str; }else{ unknownCount++; map["unknown"+unknownCount] = str; } } } // Next grab the name and family. Done last as we must know name before family. string name; map.TryGetValue("fullName",out name); string family; map.TryGetValue("fontFamily",out family); if(name==null){ name="[Untitled font face]"; } // Apply name first: font.Name=name; if(family==null){ family="[Untitled font family]"; } // Apply family name (which in turn creates the family instance): font.FamilyName=family; if(format==1){ // Language tag count: parser.ReadUInt16(); } return map; }
public static bool Load(FontParser parser, int start, FontFace font, Glyph[] glyphs) { // Seek there: parser.Position = start; // Read the version (and check if it's zero): if (parser.ReadUInt16() != 0) { return(false); } // Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table. // Number of tables: int tableCount = parser.ReadUInt16(); // Total characters in font: int characterCount = 0; int offset = -1; int favour = 0; for (int i = 0; i < tableCount; i += 1) { // Grab the platform ID: int platformId = parser.ReadUInt16(); // And the encoding ID: int encodingId = parser.ReadUInt16(); if (platformId == 3 || platformId == 0) { if (encodingId == 10) { // Top favourite - most broad Unicode encoding. // Read offset: offset = (int)parser.ReadUInt32(); break; } else if (encodingId == 1 || encodingId == 0) { // Read offset: offset = (int)parser.ReadUInt32(); // Mid-range favourite: favour = 1; continue; } else if (favour == 0) { // Anything else we'll give a try: // Read offset (but don't break): offset = (int)parser.ReadUInt32(); continue; } } // Skip offset: parser.Position += 4; } if (offset == -1) { // We don't support this font :( return(false); } // Seek to the cmap now: parser.Position = start + offset; // Check it's format 4: int format = parser.ReadUInt16(); if (format > 6) { // We now have e.g. 12.0 - another short here: parser.Position += 2; // Size/ structure are both 4 byte ints now: parser.Position += 8; } else { // Size of the sub-table (map length, u16): parser.Position += 2; // Structure of the sub-table (map language, u16): parser.Position += 2; } switch (format) { case 0: // Byte encoding table: for (int i = 0; i < 256; i++) { int rByte = parser.ReadByte(); Glyph glyph = glyphs[rByte]; if (glyph != null) { characterCount++; glyph.AddCharcode(i); } } break; case 2: // The offset to the headers: int subOffset = parser.Position + (256 * 2); // For each high byte: for (int i = 0; i < 256; i++) { // Read the index to the header and zero out the bottom 3 bits: int headerPosition = subOffset + (parser.ReadUInt16() & (~7)); // Read the header: int firstCode = parser.ReadUInt16(ref headerPosition); int entryCount = parser.ReadUInt16(ref headerPosition); short idDelta = parser.ReadInt16(ref headerPosition); // Grab the current position: int pos = headerPosition; // Read the idRangeOffset - the last part of the header: pos += parser.ReadUInt16(ref headerPosition); int maxCode = firstCode + entryCount; // Get the high byte value: int highByte = (i << 8); // For each low byte: for (int j = firstCode; j < maxCode; j++) { // Get the full charcode (which might not actually exist yet): int charCode = highByte + j; // Read the base of the glyphIndex: int p = parser.ReadUInt16(ref pos); if (p == 0) { continue; } p = (p + idDelta) & 0xFFFF; if (p == 0) { continue; } Glyph glyph = glyphs[p]; if (glyph != null) { characterCount++; glyph.AddCharcode(charCode); } } } break; case 4: // Segment count. It's doubled. int segCount = (parser.ReadUInt16() >> 1); // Search range, entry selector and range shift (don't need any): parser.Position += 6; int baseIndex = parser.Position; int endCountIndex = baseIndex; baseIndex += 2; int startCountIndex = baseIndex + segCount * 2; int idDeltaIndex = baseIndex + segCount * 4; int idRangeOffsetIndex = baseIndex + segCount * 6; for (int i = 0; i < segCount - 1; i++) { int endCount = parser.ReadUInt16(ref endCountIndex); int startCount = parser.ReadUInt16(ref startCountIndex); int idDelta = parser.ReadInt16(ref idDeltaIndex); int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex); for (int c = startCount; c <= endCount; c++) { int glyphIndex; if (idRangeOffset != 0) { // The idRangeOffset is relative to the current position in the idRangeOffset array. // Take the current offset in the idRangeOffset array. int glyphIndexOffset = (idRangeOffsetIndex - 2); // Add the value of the idRangeOffset, which will move us into the glyphIndex array. glyphIndexOffset += idRangeOffset; // Then add the character index of the current segment, multiplied by 2 for USHORTs. glyphIndexOffset += (c - startCount) * 2; glyphIndex = parser.ReadUInt16(ref glyphIndexOffset); if (glyphIndex != 0) { glyphIndex = (glyphIndex + idDelta) & 0xFFFF; } } else { glyphIndex = (c + idDelta) & 0xFFFF; } // Add a charcode to the glyph now: Glyph glyph = glyphs[glyphIndex]; if (glyph != null) { characterCount++; glyph.AddCharcode(c); } } } break; case 6: int firstCCode = parser.ReadUInt16(); int entryCCount = parser.ReadUInt16(); for (int i = 0; i < entryCCount; i++) { Glyph glyphC = glyphs[parser.ReadUInt16()]; if (glyphC != null) { characterCount++; glyphC.AddCharcode(firstCCode + i); } } break; case 12: int groups = (int)parser.ReadUInt32(); for (int i = 0; i < groups; i++) { int startCode = (int)parser.ReadUInt32(); int endCode = (int)parser.ReadUInt32(); int startGlyph = (int)parser.ReadUInt32(); int count = (endCode - startCode); for (int j = 0; j <= count; j++) { int glyphIndex = (startGlyph + j); Glyph glyph = glyphs[glyphIndex]; if (glyph != null) { characterCount++; glyph.AddCharcode(startCode + j); } } } break; default: Fonts.OnLogMessage("InfiniText does not currently support this font. If you need it, please contact us with this: Format: " + format); break; } font.CharacterCount = characterCount; return(true); }
public static bool Load(FontParser parser,int offset,FontFace font,out int locFormatIndex){ // Seek there now: parser.Position=offset; // Version: parser.ReadVersion(); // Revision: parser.ReadRevision(); // Checksum adjustment: parser.ReadUInt32(); // Magic number: if(parser.ReadUInt32()!=0x5F0F3CF5){ locFormatIndex=0; return false; } // Flags: parser.ReadUInt16(); // Units per em: font.UnitsPerEm = parser.ReadUInt16(); font.UnitsPerEmF = (float)font.UnitsPerEm; // Skip created and modified: parser.ReadTime(); parser.ReadTime(); // X min: parser.ReadInt16(); // Y min: parser.ReadInt16(); // X max: parser.ReadInt16(); // Y max: parser.ReadInt16(); // Mac style: parser.ReadUInt16(); // Lowest Rec PPEM: parser.ReadUInt16(); // Font direction hint: parser.ReadInt16(); // Index for the loc format: locFormatIndex = parser.ReadInt16(); // 50 // Glyph data format: parser.ReadInt16(); return true; }
public static void Load(FontParser parser,int offset,FontFace font,out int numberOfGlyphs){ // Seek: parser.Position=offset; // version float version=parser.ReadVersion(); // Italic angle. For some reason it's inverted in the spec - negative means a slope to the right. int frac; int dec=parser.ReadFixed(out frac); if(frac!=0){ // Figure it out: float angle=(float)dec/(float)frac; // Apply it (un-inverted): font.SetItalicAngle(-angle); } // underlinePosition parser.ReadInt16(); // underlineThickness parser.ReadInt16(); // isFixedPitch parser.ReadUInt32(); // minMemType42 parser.ReadUInt32(); // maxMemType42 parser.ReadUInt32(); // minMemType1 parser.ReadUInt32(); // maxMemType1 parser.ReadUInt32(); if(version==2f){ numberOfGlyphs = parser.ReadUInt16(); /* string[] glyphNames=new string[numberOfGlyphs]; for (int i = 0; i < numberOfGlyphs; i++) { // Read the index: int index = parser.ReadUInt16(); if(index >= StandardNames.Length){ // Read the name: glyphNames[i]=parser.ReadString(parser.ReadByte()); }else{ // Grab the std name: glyphNames[i]=StandardNames[index]; } } */ }else if(version==2.5f){ numberOfGlyphs = parser.ReadUInt16(); /* byte[] offsets = new byte[numberOfGlyphs]; for (int i = 0; i < post.numberOfGlyphs; i++){ offsets[i] = parser.ReadByte(); } */ }else{ numberOfGlyphs=-1; } }
public static Glyph ParseGlyph(FontParser parser, FontFace font, float range) { // How many contours has it got? int contourCount = parser.ReadInt16(); // Skip bounds - we don't trust these too much, so we'll figure them out ourselves: parser.Position += 8; if (contourCount > 0) { // This glyph is not a composite. // Create the glyph: Glyph glyph = new Glyph(font); if (Fonts.Preload) { LoadGlyph(glyph, contourCount, parser, range); } else { // Increase unloaded count: font.UnloadedGlyphs++; // Add position info: glyph.AddPathNode(new LoadMetaPoint(parser.Position, contourCount)); } return(glyph); } else if (contourCount == 0) { // Empty glyph e.g. space. Create the glyph: Glyph glyph = new Glyph(font); return(glyph); } CompositeGlyph compGlyph = new CompositeGlyph(font); bool moreComponents = true; while (moreComponents) { ushort cFlags = parser.ReadUInt16(); ushort glyphIndex = parser.ReadUInt16(); VectorTransform component = new VectorTransform(glyphIndex); if ((cFlags & 1) > 0) { // The arguments are words component.Dx = (float)parser.ReadInt16() / range; component.Dy = (float)parser.ReadInt16() / range; } else { // The arguments are bytes component.Dx = (float)parser.ReadByte() / range; component.Dy = (float)parser.ReadByte() / range; } if ((cFlags & 8) > 0) { // We have one scale component.XScale = component.YScale = parser.ReadF2Dot14(); } else if ((cFlags & 64) > 0) { // We have an X / Y scale component.XScale = parser.ReadF2Dot14(); component.YScale = parser.ReadF2Dot14(); } else if ((cFlags & 128) > 0) { // We have a 2x2 transformation component.XScale = parser.ReadF2Dot14(); component.Scale01 = parser.ReadF2Dot14(); component.Scale10 = parser.ReadF2Dot14(); component.YScale = parser.ReadF2Dot14(); } // Push the component to the end: compGlyph.AddComponent(component); moreComponents = ((cFlags & 32) == 32); } return(compGlyph); }