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 void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs,int numMetrics){
			
			// Seek there:
			parser.Position=offset;
			
			// Get the glyph length:
			int numGlyphs=glyphs.Length;
		
			ushort advanceWidth=0;
			short leftSideBearing=0;
			
			// For each one..
			for (int i=0;i<numGlyphs;i++){
				
				// Monospaced fonts only have one entry:
				if (i<numMetrics){
					advanceWidth=parser.ReadUInt16();
					leftSideBearing=parser.ReadInt16();
				}
				
				Glyph glyph=glyphs[i];
				
				glyph.AdvanceWidth=(float)advanceWidth/font.UnitsPerEmF;
				glyph.LeftSideBearing=(float)leftSideBearing/font.UnitsPerEmF;
			}
			
			
		}
		public static 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;
			
		}
		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 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)
        {
            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();
        }
		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 void Load(FontParser parser){
			
			// Format:
			int format=parser.ReadUInt16();
			
			switch(format){
				
				case 1:
					
					
					
				break;
				
				case 2:
					
					
					
				break;
				
			}
			
		}
		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 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;
			
		}
		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;
				
			}
			
		}
		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);
			}
			
		}
		public static Glyph ParseGlyph(FontParser parser,FontFace font,float range){
			
			// How many contours has it got?
			int contourCount=parser.ReadInt16();
			
			// Skip bounds - we don't trust these too much, so we'll figure them out ourselves:
			parser.Position+=8;
			
			if(contourCount>0){
				// This glyph is not a composite.
				
				// Create the glyph:
				Glyph glyph=new Glyph(font);
				
				if(Fonts.Preload){
					
					LoadGlyph(glyph,contourCount,parser,range);
					
				}else{
					
					// Increase unloaded count:
					font.UnloadedGlyphs++;
					
					// Add position info:
					glyph.AddPathNode(new LoadMetaPoint(parser.Position,contourCount));
					
				}
				
				return glyph;
				
			}else if(contourCount==0){
				
				// Empty glyph e.g. space. Create the glyph:
				Glyph glyph=new Glyph(font);
				
				return glyph;
				
			}
			
			CompositeGlyph compGlyph=new CompositeGlyph(font);
			
			bool moreComponents=true;
			
			while(moreComponents){
			
				ushort cFlags=parser.ReadUInt16();
				ushort glyphIndex=parser.ReadUInt16();
				
				VectorTransform component=new VectorTransform(glyphIndex);
				
				if ((cFlags & 1) > 0) {
					// The arguments are words
					component.Dx = (float)parser.ReadInt16() / range;
					component.Dy = (float)parser.ReadInt16() / range;
				} else {
					// The arguments are bytes
					component.Dx = (float)parser.ReadByte()  / range;
					component.Dy = (float)parser.ReadByte()  / range;
				}
				
				if ((cFlags & 8) > 0) {
					// We have one scale
					component.XScale = component.YScale = parser.ReadF2Dot14();
				} else if ((cFlags & 64) > 0) {
					// We have an X / Y scale
					component.XScale = parser.ReadF2Dot14();
					component.YScale = parser.ReadF2Dot14();
				} else if ((cFlags & 128) > 0) {
					// We have a 2x2 transformation
					component.XScale = parser.ReadF2Dot14();
					component.Scale01 = parser.ReadF2Dot14();
					component.Scale10 = parser.ReadF2Dot14();
					component.YScale = parser.ReadF2Dot14();
				}
				
				// Push the component to the end:
				compGlyph.AddComponent(component);
				
				moreComponents = ((cFlags & 32)==32);
			}
			
			return compGlyph;
			
		}
		public static void Load(FontParser parser,int offset,FontFace font){
			
			// Got OS2:
			parser.ReadOS2=true;
			
			// Seek:
			parser.Position=offset;
			
			// version
			int version=parser.ReadUInt16();
			
			// xAvgCharWidth
			parser.ReadInt16();
			
			// usWeightClass
			int weight=parser.ReadUInt16();
			
			// usWidthClass
			parser.ReadUInt16();
			
			// fsType
			parser.ReadUInt16();
			
			// ySubscriptXSize
			parser.ReadInt16();
			
			// ySubscriptYSize
			parser.ReadInt16();
			
			// ySubscriptXOffset
			parser.ReadInt16();
			
			// ySubscriptYOffset
			parser.ReadInt16();
			
			// ySuperscriptXSize
			parser.ReadInt16();
			
			// ySuperscriptYSize
			parser.ReadInt16();
			
			// ySuperscriptXOffset
			parser.ReadInt16();
			
			// ySuperscriptYOffset
			parser.ReadInt16();
			
			// yStrikeoutSize
			font.StrikeSize=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// yStrikeoutPosition
			font.StrikeOffset=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sFamilyClass
			parser.ReadInt16();
			
			// panose:
			/*
			byte panose=new byte[10];
			
			for(int i=0;i<10;i++){
				panose[i]=parser.ReadByte();
			}
			*/
			parser.Position+=10;
			
			// ulUnicodeRange1
			parser.ReadUInt32();
			
			// ulUnicodeRange2
			parser.ReadUInt32();
			
			// ulUnicodeRange3
			parser.ReadUInt32();
			
			// ulUnicodeRange4
			parser.ReadUInt32();
			
			// achVendID
			parser.ReadTag();
			
			// fsSelection
			int type=parser.ReadUInt16();
			
			bool italic=((type&1)==1);
			// bool strikeout=((type&16)==16);
			// bool underscore=((type&2)==2);
			bool oblique=((type&512)==512);
			bool bold=((type&32)==32);
			bool regular=((type&64)==64);
			bool useTypo=((type&128)==128);
			
			if(!bold || regular){
				// Must be regular:
				weight=400;
			}else if(weight==0){
				weight=700;
			}
			
			font.SetFlags(italic || oblique,weight);
			
			// usFirstCharIndex
			parser.ReadUInt16();
			
			// usLastCharIndex
			parser.ReadUInt16();
			
			// sTypoAscender
			float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sTypoDescender
			float descender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sTypoLineGap
			float lineGap=((float)parser.ReadInt16()/font.UnitsPerEmF);
			
			// usWinAscent
			float wAscender=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// usWinDescent
			float wDescender=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// This is an awkward spec hack due to most windows programs
			// providing the wrong typo descender values.
		
			if(Fonts.UseOS2Metrics){
				
				if(useTypo){
					
					float halfGap=lineGap/2f;
				
					font.Ascender=ascender + halfGap;
					font.Descender=halfGap-descender;
					
					font.LineGap=font.Ascender + font.Descender;
					
				}else{
					font.Ascender=wAscender;
					font.Descender=wDescender;
					
					font.LineGap=font.Ascender + font.Descender;
				}
				
			}
			
			
			if (version >= 1){
				// ulCodePageRange1
				parser.ReadUInt32();
				
				// ulCodePageRange2
				parser.ReadUInt32();
			}
			
			if (version >= 2){
				// sxHeight
				parser.ReadInt16();
				
				// sCapHeight
				parser.ReadInt16();
				
				// usDefaultChar
				parser.ReadUInt16();
				
				// usBreakChar
				parser.ReadUInt16();
				
				// usMaxContent
				parser.ReadUInt16();
			}
			
			
		}
		public static Dictionary<string,string> Load(FontParser parser,int start,FontFace font){
			
			// Create the map:
			Dictionary<string,string> map=new Dictionary<string,string>();
			
			// Go there now:
			parser.Position=start;
			
			// Format:
			int format=parser.ReadUInt16();
			
			// Number of names:
			int count = parser.ReadUInt16();
			
			// String offset:
			int stringOffset = start + parser.ReadUInt16();
			
			int unknownCount = 0;
			
			for(int i=0;i<count;i++){
				
				// Platform ID:
				ushort platformID = parser.ReadUInt16();
				ushort encodingID = parser.ReadUInt16();
				ushort languageID = parser.ReadUInt16();
				ushort nameID = parser.ReadUInt16();
				string property = null;
				
				if(nameID<PropertyMap.Length){
					property=PropertyMap[nameID];
				}
				
				ushort byteLength = parser.ReadUInt16();
				ushort offset = parser.ReadUInt16();
				
				// platformID - encodingID - languageID standard combinations :
				// 1 - 0 - 0 : Macintosh, Roman, English
				// 3 - 1 - 0x409 : Windows, Unicode BMP (UCS-2), en-US
				
				if(platformID == 3 && encodingID == 1 && languageID == 0x409){
					
					int length = byteLength/2;
					char[] chars=new char[length];
				
					int index=stringOffset+offset;
					
					for(int j = 0; j < length; j++){
						
						chars[j] = (char)parser.ReadInt16(ref index);
						
					}
					
					string str = new string(chars);
					
					if(property!=null){
						map[property] = str;
					}else{
						unknownCount++;
						map["unknown"+unknownCount] = str;
					}
					
				}
				
			}
			
			// Next grab the name and family. Done last as we must know name before family.
			string name;
			map.TryGetValue("fullName",out name);
			
			string family;
			map.TryGetValue("fontFamily",out family);
			
			if(name==null){
				name="[Untitled font face]";
			}
			
			// Apply name first:
			font.Name=name;
			
			if(family==null){
				family="[Untitled font family]";
			}
			
			// Apply family name (which in turn creates the family instance):
			font.FamilyName=family;
			
			if(format==1){
				
				// Language tag count:
				parser.ReadUInt16();
				
			}
			
			return map;
			
		}
		public static 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();
			
		}
		/// <summary>Adds a ligature table to the font.</summary>
		public static void AddToFont(string name,FontParser parser,int tableOffset,FontFace font,LigatureLookupTable[] tables){
			
			int position=parser.Position;
			
			// Skip params (+2):
			parser.Position=tableOffset+2;
			
			// Index count:
			int count=parser.ReadUInt16();
			
			// For each one..
			for(int i=0;i<count;i++){
				
				// Grab the index:
				//int index=parser.ReadUInt16();
				
				// Grab the table:
				//LigatureLookupTable table=tables[index];
				
			}
			
			parser.Position=position;
			
		}
		public static void Load(FontParser parser,int offset,FontFace font){
			
			// 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 bool Load(FontParser parser,int offset,FontFace font,out int locFormatIndex){
			
			// Seek there now:
			parser.Position=offset;
			
			// Version:
			parser.ReadVersion();
			
			// Revision:
			parser.ReadRevision();
			
			// Checksum adjustment:
			parser.ReadUInt32();
			
			// Magic number:
			if(parser.ReadUInt32()!=0x5F0F3CF5){
				
				locFormatIndex=0;
				
				return false;
				
			}
			
			// Flags:
			parser.ReadUInt16();
			
			// Units per em:
			font.UnitsPerEm = parser.ReadUInt16();
			font.UnitsPerEmF = (float)font.UnitsPerEm;
			
			// Skip created and modified:
			parser.ReadTime();
			parser.ReadTime();
			
			// X min:
			parser.ReadInt16();
			
			// Y min:
			parser.ReadInt16();
			
			// X max:
			parser.ReadInt16();
			
			// Y max:
			parser.ReadInt16();
			
			// Mac style:
			parser.ReadUInt16();
			
			// Lowest Rec PPEM:
			parser.ReadUInt16();
			
			// Font direction hint:
			parser.ReadInt16();
			
			// Index for the loc format:
			locFormatIndex = parser.ReadInt16(); // 50
			
			// Glyph data format:
			parser.ReadInt16();
			
			return true;
			
		}
//--------------------------------------
		public static void Load(FontParser parser,int offset,FontFace font,out int numberOfGlyphs){
			
			// Seek:
			parser.Position=offset;
			
			// version
			float version=parser.ReadVersion();
			
			// Italic angle. For some reason it's inverted in the spec - negative means a slope to the right.
			int frac;
			int dec=parser.ReadFixed(out frac);
			
			if(frac!=0){
				
				// Figure it out:
				float angle=(float)dec/(float)frac;
				
				// Apply it (un-inverted):
				font.SetItalicAngle(-angle);
				
			}
			
			// underlinePosition
			parser.ReadInt16();
			
			// underlineThickness
			parser.ReadInt16();
			
			// isFixedPitch
			parser.ReadUInt32();
			
			// minMemType42
			parser.ReadUInt32();
			
			// maxMemType42
			parser.ReadUInt32();
			
			// minMemType1
			parser.ReadUInt32();
			
			// maxMemType1
			parser.ReadUInt32();
			
			if(version==2f){
				
				numberOfGlyphs = parser.ReadUInt16();
				
				/*
				string[] glyphNames=new string[numberOfGlyphs];
				
				for (int i = 0; i < numberOfGlyphs; i++) {
					
					// Read the index:
					int index = parser.ReadUInt16();
					
					if(index >= StandardNames.Length){
						
						// Read the name:
						glyphNames[i]=parser.ReadString(parser.ReadByte());
						
					}else{
						
						// Grab the std name:
						glyphNames[i]=StandardNames[index];
						
					}
					
				}
				*/
				
			}else if(version==2.5f){
				numberOfGlyphs = parser.ReadUInt16();
				
				/*
				byte[] offsets = new byte[numberOfGlyphs];
				
				for (int i = 0; i < post.numberOfGlyphs; i++){
					
					offsets[i] = parser.ReadByte();
					
				}
				*/
			}else{
				numberOfGlyphs=-1;
			}
			
		}
		public static 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;
			
		}