示例#1
0
        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;
            }
        }
示例#2
0
 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);
			
		}
示例#7
0
        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;
			
		}
示例#9
0
        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);
        }
示例#10
0
        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;
			
		}
示例#13
0
        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();
            }
        }
示例#14
0
        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);
            }
        }
示例#15
0
        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);
				
			}
			
		}
示例#18
0
        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;
			
		}
示例#20
0
        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);
        }
示例#21
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);
     }
 }
示例#22
0
        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);
        }
示例#23
0
        /// <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);
            }
        }
示例#24
0
        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);
        }
示例#25
0
        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);
			*/
			
		}
示例#27
0
        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);
        }
示例#28
0
        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;
            }
        }
示例#30
0
        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;
				
			}
			
		}
示例#35
0
        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;
        }
示例#36
0
        /// <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;
		}
示例#39
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;
			
		}
示例#43
0
        public static FontFace Load(byte[] data)
        {
            FontParser parser = new FontParser(data);

            return(Load(parser));
        }
示例#44
0
        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();
			
		}
示例#49
0
        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;
			
		}
示例#51
0
//--------------------------------------
		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;
			
		}
示例#55
0
        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));
        }
示例#56
0
        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;
			
		}