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 CffGlyphParser(FontParser parser, FontFace font) { Font = font; Parser = parser; ScaleRatio = 1f / font.UnitsPerEmF; Stack = new CffStack(); }
/// <summary>Called when all glyphs in this font face have been loaded up. /// Note that this may occur very late or, more likely never, when glyphs are loaded on demand.</summary> public void AllGlyphsLoaded() { CffParser = null; Parser = null; UnloadedGlyphs = 0; ParserGlyphs = null; }
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; } }
/// <summary>Used when delaying the loading of a glyph. This results in rapid startup.</summary> public static void LoadFully(Glyph glyph,FontParser parser,LoadMetaPoint meta){ parser.Position=meta.Start; LoadGlyph(glyph,meta.Length,parser,glyph.Font.UnitsPerEmF); }
public static int LoadGlyphCoordinate(FontParser parser, byte flag, int previousValue, int shortVectorBitMask, int sameBitMask) { int v; if ((flag & shortVectorBitMask) > 0) { // The coordinate is 1 byte long. v = parser.ReadByte(); // The "same" bit is re-used for short values to signify the sign of the value. if ((flag & sameBitMask) == 0) { v = -v; } v = previousValue + v; } else { // The coordinate is 2 bytes long. // If the same bit is set, the coordinate is the same as the previous coordinate. if ((flag & sameBitMask) > 0) { v = previousValue; } else { // Parse the coordinate as a signed 16-bit delta value. v = previousValue + parser.ReadInt16(); } } return(v); }
public static uint[] Load(FontParser parser,int offset,int numGlyphs,bool shortVersion){ // Seek there now: parser.Position=offset; // Extra entry is used for computing the length of the last glyph, thus +1. int length=numGlyphs+1; // Create the output set: uint[] locations=new uint[length]; // For each one.. for(int i=0;i<length;i++){ if(shortVersion){ locations[i]=(uint)(parser.ReadUInt16()*2); }else{ locations[i]=parser.ReadUInt32(); } } return locations; }
public static uint[] Load(FontParser parser, int offset, int numGlyphs, bool shortVersion) { // Seek there now: parser.Position = offset; // Extra entry is used for computing the length of the last glyph, thus +1. int length = numGlyphs + 1; // Create the output set: uint[] locations = new uint[length]; // For each one.. for (int i = 0; i < length; i++) { if (shortVersion) { locations[i] = (uint)(parser.ReadUInt16() * 2); } else { locations[i] = parser.ReadUInt32(); } } return(locations); }
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 (lineGap < 0f) { // Negative line gaps are treated as meaning 0. lineGap = 0f; } parser.HheaAscender = ascender; parser.HheaDescender = descender; parser.HheaLineGap = lineGap; // 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 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(); } }
private static Glyph[] LoadIndex(FontParser parser,CffGlyphParser cffParser){ // Read the index which contains a bunch of char strings. // Each charstring is a postscript glyph definition. // How many are in here? int count=parser.ReadUInt16(); if(count==0){ return null; } // Create the offset set: int[] offsets=new int[count+1]; // Read the offset size: int offsetSize=parser.ReadByte(); // Read each offset: for(int i=0;i<=count;i++){ // Read the current offset: offsets[i]=parser.ReadOffset(offsetSize); } // Grab the object offset, minus one as their not zero based: int objectOffset=parser.Position-1; // Create the glyph set: Glyph[] glyphs=new Glyph[offsets.Length-1]; // For each one.. for(int i=0;i<glyphs.Length;i++){ // Get the (relative) indices: int startIndex=offsets[i]; int length=offsets[i+1]-startIndex; // Load the glyph now, which starts at startIndex+objectOffset: Glyph glyph=cffParser.LoadGlyph(startIndex+objectOffset,length); // Add to the set: glyphs[i]=glyph; } // Seek over the table: parser.Position=objectOffset+offsets[count]; return glyphs; }
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); } }
private static Glyph[] LoadIndex(FontParser parser, CffGlyphParser cffParser) { // Read the index which contains a bunch of char strings. // Each charstring is a postscript glyph definition. // How many are in here? int count = parser.ReadUInt16(); if (count == 0) { return(null); } // Create the offset set: int[] offsets = new int[count + 1]; // Read the offset size: int offsetSize = parser.ReadByte(); // Read each offset: for (int i = 0; i <= count; i++) { // Read the current offset: offsets[i] = parser.ReadOffset(offsetSize); } // Grab the object offset, minus one as their not zero based: int objectOffset = parser.Position - 1; // Create the glyph set: Glyph[] glyphs = new Glyph[offsets.Length - 1]; // For each one.. for (int i = 0; i < glyphs.Length; i++) { // Get the (relative) indices: int startIndex = offsets[i]; int length = offsets[i + 1] - startIndex; // Load the glyph now, which starts at startIndex+objectOffset: Glyph glyph = cffParser.LoadGlyph(startIndex + objectOffset, length); // Add to the set: glyphs[i] = glyph; } // Seek over the table: parser.Position = objectOffset + offsets[count]; return(glyphs); }
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; // 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 FontFace Load(FontParser parser) { // Create the font: FontFace font = new FontFace(); if (Load(parser, font, true)) { return(font); } else { return(null); } }
private static CffSubPosition[] LoadSubIndex(FontParser parser){ // How many are in here? int count=parser.ReadUInt16(); if(count==0){ return null; } // Create the offset set: int[] offsets=new int[count+1]; // Read the offset size: int offsetSize=parser.ReadByte(); // Read each offset: for(int i=0;i<=count;i++){ // Read the current offset: offsets[i]=parser.ReadOffset(offsetSize); } // Minus one as their not zero based: int objectOffset=parser.Position-1; // Seek over the table: parser.Position=objectOffset+offsets[count]; // Create the result set: CffSubPosition[] results=new CffSubPosition[offsets.Length-1]; // For each one.. for(int i=0;i<results.Length;i++){ // Get the (relative) indices: int startIndex=offsets[i]; int length=offsets[i+1]-startIndex; // Load the glyph now, which starts at startIndex+objectOffset: results[i]=new CffSubPosition(startIndex+objectOffset,length); } return results; }
public static int ParseOperand(FontParser parser, int b0) { if (b0 == 28) { return(parser.ReadInt16()); } if (b0 == 29) { return(parser.ReadInt32()); } if (b0 == 30) { // A floating point value which we really don't need - skipping! while (true) { byte b = parser.ReadByte(); int n1 = b >> 4; int n2 = b & 15; if (n1 == 15 || n2 == 15) { break; } } return(0); } if (b0 >= 32 && b0 <= 246) { return(b0 - 139); } if (b0 >= 247 && b0 <= 250) { return((b0 - 247) * 256 + parser.ReadByte() + 108); } if (b0 >= 251 && b0 <= 254) { return(-(b0 - 251) * 256 - parser.ReadByte() - 108); } return(0); }
public override void Load(FontParser parser, ushort fmt, int start) { if (fmt == 1) { ReadCoverage(parser, start); DeltaGlyphId = parser.ReadUInt16(); } else if (fmt == 2) { ReadCoverage(parser, start); } else { Fail(fmt); } }
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); }
/// <summary>Creates a fontface from the given data. Only actually loads it on first glyph request.</summary> public static FontFace DeferredLoad(byte[] data) { // Create the parser: FontParser parser = new FontParser(data); // Create the font: FontFace font = new FontFace(); if (Load(parser, font, false)) { return(font); } else { return(null); } }
private static CffSubPosition[] LoadSubIndex(FontParser parser) { // How many are in here? int count = parser.ReadUInt16(); if (count == 0) { return(null); } // Create the offset set: int[] offsets = new int[count + 1]; // Read the offset size: int offsetSize = parser.ReadByte(); // Read each offset: for (int i = 0; i <= count; i++) { // Read the current offset: offsets[i] = parser.ReadOffset(offsetSize); } // Minus one as their not zero based: int objectOffset = parser.Position - 1; // Seek over the table: parser.Position = objectOffset + offsets[count]; // Create the result set: CffSubPosition[] results = new CffSubPosition[offsets.Length - 1]; // For each one.. for (int i = 0; i < results.Length; i++) { // Get the (relative) indices: int startIndex = offsets[i]; int length = offsets[i + 1] - startIndex; // Load the glyph now, which starts at startIndex+objectOffset: results[i] = new CffSubPosition(startIndex + objectOffset, length); } return(results); }
public static Dictionary <int, List <int> > ParseCFFDict(FontParser parser, int length) { // Create the results set: Dictionary <int, List <int> > results = new Dictionary <int, List <int> >(); // Our first values set: List <int> values = new List <int>(); // Note that rather awkwardly the key comes *after* the set of values. int max = parser.Position + length; // While there's more data.. while (parser.Position < max) { // Read the state byte: int state = parser.ReadByte(); if (state < 22) { if (state == 12) { // 2 byte key code. state = 1200 + parser.ReadByte(); } // Push values: results[state] = values; // Clear: values = new List <int>(); } else { // Read the operand: int operand = ParseOperand(parser, state); // Push: values.Add(operand); } } return(results); }
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); */ }
private static Dictionary <int, List <int> > LoadDict(FontParser parser) { // How many are in here? int count = parser.ReadUInt16(); if (count == 0) { return(null); } // Read the offset size: int offsetSize = parser.ReadByte(); // Grab the position: int position = parser.Position; // Find where the data starts: int objectOffset = position + ((count + 1) * offsetSize) - 1; // Read two only: int firstOffset = parser.ReadOffset(offsetSize); int secondOffset = parser.ReadOffset(offsetSize); // Seek to the location: parser.Position = firstOffset + objectOffset; // Parse the dictionary now: Dictionary <int, List <int> > set = ParseCFFDict(parser, secondOffset - firstOffset); // Return: parser.Position = position; // Skip the rest: parser.Position += offsetSize * count; // Read the last offset: secondOffset = parser.ReadOffset(offsetSize); // Seek there, minus one as their not zero based: parser.Position += secondOffset - 1; return(set); }
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); */ }
public void Load(FontParser parser) { // Format: int format = parser.ReadUInt16(); switch (format) { case 1: break; case 2: break; } }
private static void SkipIndex(FontParser parser) { // How many are in here? int count = parser.ReadUInt16(); if (count > 0) { // Read the offset size: int offsetSize = parser.ReadByte(); // Skip count offsets: parser.Position += offsetSize * count; // Read the last offset: int lastOffset = parser.ReadOffset(offsetSize); // Seek there, minus one as their not zero based: parser.Position += lastOffset - 1; } }
public void Load(FontParser parser){ int start=parser.Position; // Table type: parser.ReadUInt16(); parser.ReadUInt16(); int count=parser.ReadUInt16(); // create the set: Substitutions=new Dictionary<int,List<LigatureSubstitution>>(); // For each one.. for(int i=0;i<count;i++){ // Get the offset: int offset=parser.ReadUInt16(); // Create the substitution entry: LigatureSubstitution substitution=new LigatureSubstitution(); // Get the current position: int position=parser.Position; // Hop there: parser.Position=start+offset; // Load it: substitution.Load(parser); // Go back: parser.Position=position; } // Extra flags: parser.ReadUInt16(); }
/// <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 void Load(FontParser parser) { int start = parser.Position; // Table type: parser.ReadUInt16(); parser.ReadUInt16(); int count = parser.ReadUInt16(); // create the set: Substitutions = new Dictionary <int, List <LigatureSubstitution> >(); // For each one.. for (int i = 0; i < count; i++) { // Get the offset: int offset = parser.ReadUInt16(); // Create the substitution entry: LigatureSubstitution substitution = new LigatureSubstitution(); // Get the current position: int position = parser.Position; // Hop there: parser.Position = start + offset; // Load it: substitution.Load(parser); // Go back: parser.Position = position; } // Extra flags: parser.ReadUInt16(); }
public void Load(FontParser parser){ // Format: int format=parser.ReadUInt16(); switch(format){ case 1: break; case 2: break; } }
public void ReadCoverage(FontParser parser, int start) { ushort offset = parser.ReadUInt16(); int pos = parser.Position; // Go there: parser.Position = offset + start; /* * ushort fmt=parser.ReadUInt16(); * ushort count=parser.ReadUInt16(); * * if(fmt==1){ * * for (int i = 0; i < count; i++) { * * // Just the glyphID: * ushort glyphID=parser.ReadUInt16(); * * } * * }else{ * * for (int i = 0; i < count; i++) { * * ushort start=parser.ReadUInt16(); * ushort end=parser.ReadUInt16(); * ushort index=parser.ReadUInt16(); * * } * * } */ // Restore: parser.Position = pos; }
/// <summary>Loads the WOFF header. Only useful thing from this for us is the number of tables.</summary> public static void LoadHeader(int version, FontParser parser, out ushort numTables) { // - Woff header - parser.Position += 4; // Flavour (uint) parser.Position += 4; // Length (uint) numTables = parser.ReadUInt16(); parser.Position += 2; // Reserved (ushort) parser.Position += 4; // Total size (uint) if (version == 2) // It's a shame this was put above the actual declared version { parser.Position += 4; // Total compressed size (uint) } parser.Position += 2; // Version major (ushort) parser.Position += 2; // Version minor (ushort) parser.Position += 4; // meta Offset (uint) parser.Position += 4; // meta Length (uint) parser.Position += 4; // meta Orig Length (uint) parser.Position += 4; // priv offset (uint) parser.Position += 4; // priv Length (uint) }
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 int ParseOperand(FontParser parser,int b0){ if(b0==28){ return parser.ReadInt16(); } if(b0==29){ return parser.ReadInt32(); } if(b0==30){ // A floating point value which we really don't need - skipping! while(true){ byte b=parser.ReadByte(); int n1 = b >> 4; int n2 = b & 15; if (n1 ==15 || n2==15) { break; } } return 0; } if (b0 >= 32 && b0 <= 246) { return b0 - 139; } if (b0 >= 247 && b0 <= 250) { return (b0 - 247) * 256 + parser.ReadByte() + 108; } if (b0 >= 251 && b0 <= 254) { return -(b0 - 251) * 256 - parser.ReadByte() - 108; } return 0; }
public LookupList(FontParser parser, int position) { Parser = parser; Offset = position; }
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 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 int LoadGlyphCoordinate(FontParser parser,byte flag,int previousValue,int shortVectorBitMask,int sameBitMask){ int v; if((flag&shortVectorBitMask)>0){ // The coordinate is 1 byte long. v = parser.ReadByte(); // The "same" bit is re-used for short values to signify the sign of the value. if ((flag & sameBitMask) == 0) { v = -v; } v = previousValue + v; } else { // The coordinate is 2 bytes long. // If the same bit is set, the coordinate is the same as the previous coordinate. if ((flag & sameBitMask) > 0) { v = previousValue; } else { // Parse the coordinate as a signed 16-bit delta value. v = previousValue + parser.ReadInt16(); } } return v; }
public static FontFace Load(byte[] data) { FontParser parser = new FontParser(data); return(Load(parser)); }
public static bool ReadTables(FontParser parser, FontFace font) { int hmMetricCount = 0; if (parser.HheaOffset != 0) { // Hhea table: HheaTables.Load(parser, parser.HheaOffset, font, out hmMetricCount); } Glyph[] glyphs = null; if (parser.GlyfOffset != 0 && parser.LocaOffset != 0) { bool shortVersion = (parser.IndexToLocFormat == 0); // Load a loca table (temporary): uint[] locaTable = LocaTables.Load(parser, parser.LocaOffset, parser.GlyphCount, shortVersion); // Load the glyph set: glyphs = GlyfTables.Load(parser, parser.GlyfOffset, locaTable, font); HmtxTables.Load(parser, parser.HmtxOffset, font, glyphs, hmMetricCount); } else if (parser.CffOffset != 0) { if (parser.PostOffset != 0) { // Post table: int postGlyphCount; PostTables.Load(parser, parser.PostOffset, font, out postGlyphCount); if (parser.GlyphCount == 0 && postGlyphCount != -1) { parser.GlyphCount = postGlyphCount; } } // Load the CFF (PostScript glyph) table: glyphs = CffTables.Load(parser, parser.CffOffset, font); } else { // Unrecognised/ bad font. return(false); } if (parser.KernOffset != 0) { // Kerning table: KerningTables.Load(parser, parser.KernOffset, font, glyphs); } else if (parser.GposOffset != 0) { // GPOS table (also kerning data): GposTables.Load(parser, parser.GposOffset, font, glyphs); } // Finally, the character map: if (parser.CmapOffset != 0) { // Load a charmap: CharMapTables.Load(parser, parser.CmapOffset, font, glyphs); } if (Fonts.Preload) { font.AllGlyphsLoaded(); } return(true); }
private static void LoadGlyph(Glyph glyph,int contourCount,FontParser parser,float range){ // The contour count (tiny set): ushort[] endPointIndices=new ushort[contourCount]; // Load each endpoint: for(int i=0;i<contourCount;i++){ endPointIndices[i]=parser.ReadUInt16(); } // How big is the instruction block? int instructionLength=parser.ReadUInt16(); // And skip it! parser.Position+=instructionLength; // How many coordinates? int numberOfCoordinates=endPointIndices[endPointIndices.Length-1]+1; // Create the flag set: byte[] flags=new byte[numberOfCoordinates]; // For each one.. for (int i = 0; i < numberOfCoordinates;i++) { byte flag=parser.ReadByte(); flags[i]=flag; // If bit 3 is set, we repeat this flag n times, where n is the next byte. if((flag&8)>0){ int repeatCount = parser.ReadByte(); for (int j = 0; j < repeatCount; j += 1) { i++; flags[i]=flag; } } } if (endPointIndices.Length > 0) { // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0. if (numberOfCoordinates > 0){ // Current coord: int coord=0; // Coord index: int coordIndex=0; // The coord set: float[] coords=new float[numberOfCoordinates*2]; // Load X coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser,flag,coord,2,16); coords[coordIndex]=(float)coord/range; coordIndex+=2; } // Reset shared vars: coord=0; coordIndex=1; // Load Y coords: for (int i = 0; i < numberOfCoordinates; i++) { byte flag = flags[i]; coord = LoadGlyphCoordinate(parser,flag,coord,4,32); coords[coordIndex]=(float)coord/range; coordIndex+=2; } int[] orderedEnds=new int[endPointIndices.Length]; int currentEnd=0; for (int i = 0; i < numberOfCoordinates; i++) { // Grab the flag: byte flag=flags[i]; // On curve flag - Control point otherwise: flag=(byte)(flag&1); // Last point of the current contour? // For each end point index (tiny set - better than hash): for(int e=endPointIndices.Length-1;e>=0;e--){ if(endPointIndices[e]==i){ orderedEnds[currentEnd]=i; currentEnd++; break; } } // Update the flag - it's now just a 1 or 0: flags[i]=flag; } // Reset shared index again: coordIndex=0; // Create our temp holders of point info: GlyphPoint firstPointRaw=new GlyphPoint(flags,coords); GlyphPoint lastPointRaw=new GlyphPoint(flags,coords); GlyphPoint prevPointRaw=new GlyphPoint(flags,coords); GlyphPoint currentPointRaw=new GlyphPoint(flags,coords); GlyphPoint controlPoint=new GlyphPoint(flags,coords); // For each contour.. for(int i=0;i<contourCount;i++){ int pointOffset=0; // Get the indices of the first/last points on this contour. int firstIndex=0; int lastIndex=orderedEnds[i]; if(i!=0){ firstIndex=orderedEnds[i-1]+1; } GlyphPoint firstPoint=firstPointRaw; firstPoint.Set(firstIndex); GlyphPoint lastPoint=lastPointRaw; lastPoint.Set(lastIndex); if(firstPoint.OnCurve){ // No control point: controlPoint.Active=false; // The first point will be consumed by the moveTo command so skip it: pointOffset=1; }else{ if(lastPoint.OnCurve){ // If the first point is off-curve and the last point is on-curve, // start at the last point. firstPoint=lastPoint; }else{ // If both first and last points are off-curve, start at their middle. firstPoint.X=(firstPoint.X+lastPoint.X)/2f; firstPoint.Y=(firstPoint.Y+lastPoint.Y)/2f; } controlPoint.Set(firstPoint); } glyph.MoveTo(firstPoint.X,firstPoint.Y); int contourStart=firstIndex+pointOffset; for(int j=contourStart;j<=lastIndex;j++){ // Setup the previous point: GlyphPoint prevPoint; if(j==firstIndex){ prevPoint=firstPoint; }else{ prevPoint=prevPointRaw; prevPoint.Set(j-1); } // Setup the current point: GlyphPoint pt=currentPointRaw; pt.Set(j); if(prevPoint.OnCurve && pt.OnCurve) { // Just a line here: glyph.LineTo(pt.X,pt.Y); }else if (prevPoint.OnCurve && !pt.OnCurve){ controlPoint.Set(pt); }else if(!prevPoint.OnCurve && !pt.OnCurve){ float midPointX=(prevPoint.X+pt.X)/2f; float midPointY=(prevPoint.Y+pt.Y)/2f; glyph.QuadraticCurveTo(prevPoint.X,prevPoint.Y,midPointX,midPointY); controlPoint.Set(pt); }else if(!prevPoint.OnCurve && pt.OnCurve){ // Previous point off-curve, this point on-curve. glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,pt.X,pt.Y); controlPoint.Active=false; } } if(firstPoint!=lastPoint){ // Close the path. if(controlPoint.Active){ // Still got a spare control point: glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,firstPoint.X,firstPoint.Y); } // Just a normal close: glyph.ClosePath(); } } } } if(glyph.Font.WindingUnknown){ // Find the winding now: glyph.Font.FindWinding(glyph); } }
private static Dictionary<int,List<int>> LoadDict(FontParser parser){ // How many are in here? int count=parser.ReadUInt16(); if(count==0){ return null; } // Read the offset size: int offsetSize=parser.ReadByte(); // Grab the position: int position=parser.Position; // Find where the data starts: int objectOffset=position+((count+1)*offsetSize)-1; // Read two only: int firstOffset=parser.ReadOffset(offsetSize); int secondOffset=parser.ReadOffset(offsetSize); // Seek to the location: parser.Position=firstOffset+objectOffset; // Parse the dictionary now: Dictionary<int,List<int>> set=ParseCFFDict(parser,secondOffset-firstOffset); // Return: parser.Position=position; // Skip the rest: parser.Position+=offsetSize*count; // Read the last offset: secondOffset=parser.ReadOffset(offsetSize); // Seek there, minus one as their not zero based: parser.Position+=secondOffset-1; return set; }
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,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, FontFace font, bool full) { font.RequiresLoad = !full; font.Parser = parser; // Read the version: int dec; int version = parser.ReadFixed(out dec); if (version == 1 && dec == 0) { // TTF outline format. } else { // Reset to start: parser.Position = 0; // OpenType. Read the tag (right at the start): string openTypeVersion = parser.ReadTag(); if (openTypeVersion == "OTTO") { // CFF outline format. } else { // Unsupported format. return(false); } } // Table count: int numTables = parser.ReadUInt16(); // Move to p12: parser.Position = 12; for (int i = 0; i < numTables; i++) { // Read the tables tag: string tag = parser.ReadTag(); // Move parser along: parser.Position += 4; // Read the offset: int offset = (int)parser.ReadUInt32(); // Grab the position - this allows the tables to mess it up: int basePosition = parser.Position; switch (tag) { case "cmap": parser.CmapOffset = offset; break; case "head": // Load the header: if (!HeaderTables.Load(parser, offset, font, out parser.IndexToLocFormat)) { return(false); } break; case "hhea": parser.HheaOffset = offset; break; case "hmtx": parser.HmtxOffset = offset; break; case "maxp": // Maxp table: MaxpTables.Load(parser, offset, font, out parser.GlyphCount); break; case "name": // General meta: NameTables.Load(parser, offset, font); break; case "OS/2": // OS2 table: OS2Tables.Load(parser, offset, font); break; case "post": // Postscript info table: parser.PostOffset = offset; break; case "glyf": parser.GlyfOffset = offset; break; case "loca": parser.LocaOffset = offset; break; case "GSUB": // Gsub(stitute) table. Ligatures fall through here. GsubTables.Load(parser, offset, font); break; case "CFF ": parser.CffOffset = offset; break; case "kern": parser.KernOffset = offset; break; case "GPOS": parser.GposOffset = offset; break; } // Skip meta: parser.Position = basePosition + 4; } if (full) { return(ReadTables(parser, font)); } return(true); }
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 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; }
/// <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 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 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; } }
private static void SkipIndex(FontParser parser){ // How many are in here? int count=parser.ReadUInt16(); if(count>0){ // Read the offset size: int offsetSize=parser.ReadByte(); // Skip count offsets: parser.Position+=offsetSize*count; // Read the last offset: int lastOffset=parser.ReadOffset(offsetSize); // Seek there, minus one as their not zero based: parser.Position+=lastOffset-1; } }
public static Dictionary<int,List<int>> ParseCFFDict(FontParser parser,int length){ // Create the results set: Dictionary<int,List<int>> results=new Dictionary<int,List<int>>(); // Our first values set: List<int> values=new List<int>(); // Note that rather awkwardly the key comes *after* the set of values. int max=parser.Position+length; // While there's more data.. while(parser.Position<max){ // Read the state byte: int state=parser.ReadByte(); if(state<22){ if(state==12){ // 2 byte key code. state=1200+parser.ReadByte(); } // Push values: results[state]=values; // Clear: values=new List<int>(); }else{ // Read the operand: int operand=ParseOperand(parser,state); // Push: values.Add(operand); } } return results; }