示例#1
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();
        }
示例#2
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;
            }
        }
示例#3
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 void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs,int numMetrics){
			
			// Seek there:
			parser.Position=offset;
			
			// Get the glyph length:
			int numGlyphs=glyphs.Length;
		
			ushort advanceWidth=0;
			short leftSideBearing=0;
			
			// For each one..
			for (int i=0;i<numGlyphs;i++){
				
				// Monospaced fonts only have one entry:
				if (i<numMetrics){
					advanceWidth=parser.ReadUInt16();
					leftSideBearing=parser.ReadInt16();
				}
				
				Glyph glyph=glyphs[i];
				
				glyph.AdvanceWidth=(float)advanceWidth/font.UnitsPerEmF;
				glyph.LeftSideBearing=(float)leftSideBearing/font.UnitsPerEmF;
			}
			
			
		}
        public static void Load(FontParser parser, int offset, FontFace font, 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){
			
			// 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);
				
			}
			
		}
示例#7
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);
        }
		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 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 bool Load(FontParser parser,int start,FontFace font,Glyph[] glyphs){
			
			// Seek there:
			parser.Position=start;
			
			// Read the version (and check if it's zero):
			if(parser.ReadUInt16()!=0){
				return false;
			}
			
			// Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table.
			
			// Number of tables:
			int tableCount=parser.ReadUInt16();
			
			// Total characters in font:
			int characterCount=0;
			
			int offset=-1;
			int favour=0;
			
			for(int i = 0; i < tableCount; i += 1) {
				
				// Grab the platform ID:
				int platformId=parser.ReadUInt16();
				
				// And the encoding ID:
				int encodingId=parser.ReadUInt16();
				
				if(platformId==3 || platformId==0){
					
					if(encodingId==10){
						
						// Top favourite - most broad Unicode encoding.
						
						// Read offset:
						offset=(int)parser.ReadUInt32();
						
						break;
						
					}else if(encodingId==1 || encodingId==0){
						
						// Read offset:
						offset=(int)parser.ReadUInt32();
						
						// Mid-range favourite:
						favour=1;
						
						continue;
						
					}else if(favour==0){
						
						// Anything else we'll give a try:
						
						// Read offset (but don't break):
						offset=(int)parser.ReadUInt32();
						
						continue;
						
					}
					
				}
				
				// Skip offset:
				parser.Position+=4;
				
			}
			
			if(offset==-1){
				// We don't support this font :(
				return false;
			}
			
			// Seek to the cmap now:
			parser.Position=start+offset;
			
			// Check it's format 4:
			int format=parser.ReadUInt16();
		
			if(format>6){
				// We now have e.g. 12.0 - another short here:
				parser.Position+=2;
				
				// Size/ structure are both 4 byte ints now:
				parser.Position+=8;
				
			}else{
			
				// Size of the sub-table (map length, u16):
				parser.Position+=2;
				
				// Structure of the sub-table (map language, u16):
				parser.Position+=2;
				
			}
			
			switch(format){
				
				case 0:
				
				// Byte encoding table:
				
				for(int i=0;i<256;i++){
					
					int rByte=parser.ReadByte();
					
					Glyph glyph=glyphs[rByte];
					
					if(glyph!=null){
						characterCount++;
					
						glyph.AddCharcode(i);
					}
					
				}
				
				break;
				case 2:
				
				// The offset to the headers:
				int subOffset=parser.Position + (256 * 2);
				
				// For each high byte:
				for(int i=0;i<256;i++){
					
					// Read the index to the header and zero out the bottom 3 bits:
					int headerPosition=subOffset + (parser.ReadUInt16() & (~7));
					
					// Read the header:
					int firstCode=parser.ReadUInt16(ref headerPosition);
					int entryCount=parser.ReadUInt16(ref headerPosition);
					short idDelta=parser.ReadInt16(ref headerPosition);
					
					// Grab the current position:
					int pos=headerPosition;
					
					// Read the idRangeOffset - the last part of the header:
					pos+=parser.ReadUInt16(ref headerPosition);
					
					int maxCode=firstCode+entryCount;
					
					// Get the high byte value:
					int highByte=(i<<8);
					
					// For each low byte:
					for (int j=firstCode;j<maxCode;j++){
						
						// Get the full charcode (which might not actually exist yet):
						int charCode=highByte+j;
						
						// Read the base of the glyphIndex:
						int p=parser.ReadUInt16(ref pos);
						
						if(p==0){
							continue;
						}
						
						p=(p+idDelta) & 0xFFFF;
						
						if(p==0){
							continue;
						}
						
						Glyph glyph=glyphs[p];
						
						if(glyph!=null){
							
							characterCount++;
							
							glyph.AddCharcode(charCode);
							
						}
						
					}
				}
				
				break;
				case 4:
				
				// Segment count. It's doubled.
				int segCount=(parser.ReadUInt16() >> 1);
				
				// Search range, entry selector and range shift (don't need any):
				parser.Position+=6;
				
				int baseIndex=parser.Position;
				
				int endCountIndex=baseIndex;
				
				baseIndex+=2;
				
				int startCountIndex = baseIndex + segCount * 2;
				int idDeltaIndex = baseIndex + segCount * 4;
				int idRangeOffsetIndex = baseIndex + segCount * 6;
				
				for(int i = 0; i < segCount - 1; i ++){
					
					int endCount = parser.ReadUInt16(ref endCountIndex);
					int startCount = parser.ReadUInt16(ref startCountIndex);
					int idDelta = parser.ReadInt16(ref idDeltaIndex);
					int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex);
					
					for(int c = startCount; c <= endCount;c++){
						
						int glyphIndex;
						
						if(idRangeOffset != 0){
							
							// The idRangeOffset is relative to the current position in the idRangeOffset array.
							// Take the current offset in the idRangeOffset array.
							int glyphIndexOffset = (idRangeOffsetIndex - 2);
							
							// Add the value of the idRangeOffset, which will move us into the glyphIndex array.
							glyphIndexOffset += idRangeOffset;
							
							// Then add the character index of the current segment, multiplied by 2 for USHORTs.
							glyphIndexOffset += (c - startCount) * 2;
							
							glyphIndex=parser.ReadUInt16(ref glyphIndexOffset);
							
							if(glyphIndex!=0){
								glyphIndex = (glyphIndex + idDelta) & 0xFFFF;
							}
							
						}else{
							glyphIndex = (c + idDelta) & 0xFFFF;
						}
						
						// Add a charcode to the glyph now:
						Glyph glyph=glyphs[glyphIndex];
						
						if(glyph!=null){
							characterCount++;
						
							glyph.AddCharcode(c);
						}
					}
					
				}
				
				break;
				
				case 6:
				
				int firstCCode=parser.ReadUInt16();
				int entryCCount=parser.ReadUInt16();
				
				for(int i=0;i<entryCCount;i++){
					
					Glyph glyphC=glyphs[parser.ReadUInt16()];
					
					if(glyphC!=null){
					
						characterCount++;
						
						glyphC.AddCharcode(firstCCode+i);
					
					}
					
				}
				
				break;
				
				case 12:
				
				int groups=(int)parser.ReadUInt32();
				
				for(int i=0;i<groups;i++){
					int startCode=(int)parser.ReadUInt32();
					int endCode=(int)parser.ReadUInt32();
					int startGlyph=(int)parser.ReadUInt32();
					
					int count=(endCode - startCode);
					
					for(int j=0;j<=count;j++){
						
						int glyphIndex=(startGlyph+j);
						
						Glyph glyph=glyphs[glyphIndex];
						
						if(glyph!=null){
							
							characterCount++;
							
							glyph.AddCharcode(startCode+j);
							
						}
						
					}
				}
				
				break;
				
				default:
					Fonts.OnLogMessage("InfiniText does not currently support this font. If you need it, please contact us with this: Format: "+format);
				break;
			}
			
			font.CharacterCount=characterCount;
			
			return true;
			
		}
		public static void Load(FontParser parser,int offset,FontFace font,out int hmMetricCount){
			
			// Seek there:
			parser.Position=offset;
			
			// Version:
			parser.ReadVersion();
			
			// Ascender:
			float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Descender:
			float descender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Line gap:
			float lineGap=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			if(!Fonts.UseOS2Metrics || !parser.ReadOS2){
				
				if(lineGap<0f){
					lineGap=-lineGap;
				}
				
				float halfGap=lineGap/2f;
				
				font.Ascender=ascender + halfGap;
				font.Descender=halfGap-descender;
			
				font.LineGap=font.Ascender + font.Descender;
			
			}
			
			// Advance width max:
			font.MaxAdvanceWidth=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// Min left side bearing:
			font.MinLeftSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Min right side bearing:
			font.MinRightSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Max x extent:
			font.MaxXExtent=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Caret slope rise:
			float caretRise=(float)parser.ReadInt16();
			
			// Caret slope run:
			float caretRun=(float)parser.ReadInt16();
			
			font.CaretAngle=(float)Math.Atan2(caretRise,caretRun);
			
			// Caret offset:
			font.CaretOffset=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Skip:
			parser.Position += 8;
			
			// Metric format:
			parser.ReadInt16();
			
			// Metric count:
			hmMetricCount = parser.ReadUInt16();
			
		}
		public static 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 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;
			
		}
示例#14
0
        public static bool Load(FontParser parser, int start, FontFace font, Glyph[] glyphs)
        {
            // Seek there:
            parser.Position = start;

            // Read the version (and check if it's zero):
            if (parser.ReadUInt16() != 0)
            {
                return(false);
            }

            // Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table.

            // Number of tables:
            int tableCount = parser.ReadUInt16();

            // Total characters in font:
            int characterCount = 0;

            int offset = -1;
            int favour = 0;

            for (int i = 0; i < tableCount; i += 1)
            {
                // Grab the platform ID:
                int platformId = parser.ReadUInt16();

                // And the encoding ID:
                int encodingId = parser.ReadUInt16();

                if (platformId == 3 || platformId == 0)
                {
                    if (encodingId == 10)
                    {
                        // Top favourite - most broad Unicode encoding.

                        // Read offset:
                        offset = (int)parser.ReadUInt32();

                        break;
                    }
                    else if (encodingId == 1 || encodingId == 0)
                    {
                        // Read offset:
                        offset = (int)parser.ReadUInt32();

                        // Mid-range favourite:
                        favour = 1;

                        continue;
                    }
                    else if (favour == 0)
                    {
                        // Anything else we'll give a try:

                        // Read offset (but don't break):
                        offset = (int)parser.ReadUInt32();

                        continue;
                    }
                }

                // Skip offset:
                parser.Position += 4;
            }

            if (offset == -1)
            {
                // We don't support this font :(
                return(false);
            }

            // Seek to the cmap now:
            parser.Position = start + offset;

            // Check it's format 4:
            int format = parser.ReadUInt16();

            if (format > 6)
            {
                // We now have e.g. 12.0 - another short here:
                parser.Position += 2;

                // Size/ structure are both 4 byte ints now:
                parser.Position += 8;
            }
            else
            {
                // Size of the sub-table (map length, u16):
                parser.Position += 2;

                // Structure of the sub-table (map language, u16):
                parser.Position += 2;
            }

            switch (format)
            {
            case 0:

                // Byte encoding table:

                for (int i = 0; i < 256; i++)
                {
                    int rByte = parser.ReadByte();

                    Glyph glyph = glyphs[rByte];

                    if (glyph != null)
                    {
                        characterCount++;

                        glyph.AddCharcode(i);
                    }
                }

                break;

            case 2:

                // The offset to the headers:
                int subOffset = parser.Position + (256 * 2);

                // For each high byte:
                for (int i = 0; i < 256; i++)
                {
                    // Read the index to the header and zero out the bottom 3 bits:
                    int headerPosition = subOffset + (parser.ReadUInt16() & (~7));

                    // Read the header:
                    int   firstCode  = parser.ReadUInt16(ref headerPosition);
                    int   entryCount = parser.ReadUInt16(ref headerPosition);
                    short idDelta    = parser.ReadInt16(ref headerPosition);

                    // Grab the current position:
                    int pos = headerPosition;

                    // Read the idRangeOffset - the last part of the header:
                    pos += parser.ReadUInt16(ref headerPosition);

                    int maxCode = firstCode + entryCount;

                    // Get the high byte value:
                    int highByte = (i << 8);

                    // For each low byte:
                    for (int j = firstCode; j < maxCode; j++)
                    {
                        // Get the full charcode (which might not actually exist yet):
                        int charCode = highByte + j;

                        // Read the base of the glyphIndex:
                        int p = parser.ReadUInt16(ref pos);

                        if (p == 0)
                        {
                            continue;
                        }

                        p = (p + idDelta) & 0xFFFF;

                        if (p == 0)
                        {
                            continue;
                        }

                        Glyph glyph = glyphs[p];

                        if (glyph != null)
                        {
                            characterCount++;

                            glyph.AddCharcode(charCode);
                        }
                    }
                }

                break;

            case 4:

                // Segment count. It's doubled.
                int segCount = (parser.ReadUInt16() >> 1);

                // Search range, entry selector and range shift (don't need any):
                parser.Position += 6;

                int baseIndex = parser.Position;

                int endCountIndex = baseIndex;

                baseIndex += 2;

                int startCountIndex    = baseIndex + segCount * 2;
                int idDeltaIndex       = baseIndex + segCount * 4;
                int idRangeOffsetIndex = baseIndex + segCount * 6;

                for (int i = 0; i < segCount - 1; i++)
                {
                    int endCount      = parser.ReadUInt16(ref endCountIndex);
                    int startCount    = parser.ReadUInt16(ref startCountIndex);
                    int idDelta       = parser.ReadInt16(ref idDeltaIndex);
                    int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex);

                    for (int c = startCount; c <= endCount; c++)
                    {
                        int glyphIndex;

                        if (idRangeOffset != 0)
                        {
                            // The idRangeOffset is relative to the current position in the idRangeOffset array.
                            // Take the current offset in the idRangeOffset array.
                            int glyphIndexOffset = (idRangeOffsetIndex - 2);

                            // Add the value of the idRangeOffset, which will move us into the glyphIndex array.
                            glyphIndexOffset += idRangeOffset;

                            // Then add the character index of the current segment, multiplied by 2 for USHORTs.
                            glyphIndexOffset += (c - startCount) * 2;

                            glyphIndex = parser.ReadUInt16(ref glyphIndexOffset);

                            if (glyphIndex != 0)
                            {
                                glyphIndex = (glyphIndex + idDelta) & 0xFFFF;
                            }
                        }
                        else
                        {
                            glyphIndex = (c + idDelta) & 0xFFFF;
                        }

                        // Add a charcode to the glyph now:
                        Glyph glyph = glyphs[glyphIndex];

                        if (glyph != null)
                        {
                            characterCount++;

                            glyph.AddCharcode(c);
                        }
                    }
                }

                break;

            case 6:

                int firstCCode  = parser.ReadUInt16();
                int entryCCount = parser.ReadUInt16();

                for (int i = 0; i < entryCCount; i++)
                {
                    Glyph glyphC = glyphs[parser.ReadUInt16()];

                    if (glyphC != null)
                    {
                        characterCount++;

                        glyphC.AddCharcode(firstCCode + i);
                    }
                }

                break;

            case 12:

                int groups = (int)parser.ReadUInt32();

                for (int i = 0; i < groups; i++)
                {
                    int startCode  = (int)parser.ReadUInt32();
                    int endCode    = (int)parser.ReadUInt32();
                    int startGlyph = (int)parser.ReadUInt32();

                    int count = (endCode - startCode);

                    for (int j = 0; j <= count; j++)
                    {
                        int glyphIndex = (startGlyph + j);

                        Glyph glyph = glyphs[glyphIndex];

                        if (glyph != null)
                        {
                            characterCount++;

                            glyph.AddCharcode(startCode + j);
                        }
                    }
                }

                break;

            default:
                Fonts.OnLogMessage("InfiniText does not currently support this font. If you need it, please contact us with this: Format: " + format);
                break;
            }

            font.CharacterCount = characterCount;

            return(true);
        }
		public static int ParseOperand(FontParser parser,int b0){
			
			if(b0==28){
				return parser.ReadInt16();
			}
			
			if(b0==29){
				return parser.ReadInt32();
			}
			
			if(b0==30){
				// A floating point value which we really don't need - skipping!
				
				while(true){
					byte b=parser.ReadByte();
					int n1 = b >> 4;
					int n2 = b & 15;

					if (n1 ==15 || n2==15) {
						break;
					}
					
				}
				
				return 0;
			}
			
			if (b0 >= 32 && b0 <= 246) {
				return b0 - 139;
			}
			
			if (b0 >= 247 && b0 <= 250) {
				return (b0 - 247) * 256 + parser.ReadByte() + 108;
			}
			
			if (b0 >= 251 && b0 <= 254) {
				return -(b0 - 251) * 256 - parser.ReadByte() - 108;
			}
			
			return 0;
		}
        public 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();
        }
示例#17
0
        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;
            }
        }
示例#18
0
        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 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;
			
		}
示例#20
0
        public static void Load(FontParser parser, int offset, FontFace font)
        {
            // Seek:
            parser.Position = offset;

            // version
            int version = parser.ReadUInt16();

            // xAvgCharWidth
            parser.ReadInt16();

            // usWeightClass
            int weight = parser.ReadUInt16();

            // usWidthClass
            int stretch = parser.ReadUInt16();

            // fsType
            parser.ReadUInt16();

            // ySubscriptXSize
            parser.ReadInt16();

            // ySubscriptYSize
            parser.ReadInt16();

            // ySubscriptXOffset
            parser.ReadInt16();

            // ySubscriptYOffset
            parser.ReadInt16();

            // ySuperscriptXSize
            parser.ReadInt16();

            // ySuperscriptYSize
            parser.ReadInt16();

            // ySuperscriptXOffset
            parser.ReadInt16();

            // ySuperscriptYOffset
            parser.ReadInt16();

            // yStrikeoutSize
            font.StrikeSize = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // yStrikeoutPosition
            font.StrikeOffset = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // sFamilyClass
            parser.ReadInt16();

            // panose:

            /*
             * byte panose=new byte[10];
             *
             * for(int i=0;i<10;i++){
             *      panose[i]=parser.ReadByte();
             * }
             */
            parser.Position += 10;

            // ulUnicodeRange1
            parser.ReadUInt32();

            // ulUnicodeRange2
            parser.ReadUInt32();

            // ulUnicodeRange3
            parser.ReadUInt32();

            // ulUnicodeRange4
            parser.ReadUInt32();

            // achVendID
            parser.ReadTag();

            // fsSelection
            int type = parser.ReadUInt16();

            bool italic = ((type & 1) == 1);
            // bool strikeout=((type&16)==16);
            // bool underscore=((type&2)==2);
            bool oblique = ((type & 512) == 512);
            bool bold    = ((type & 32) == 32);
            bool regular = ((type & 64) == 64);
            bool useTypo = ((type & 128) == 128);

            if (!bold || regular)
            {
                // Must be regular:
                weight = 400;
            }
            else if (weight == 0)
            {
                weight = 700;
            }

            int styleCode = 0;

            if (italic)
            {
                styleCode = FontFaceFlags.Italic;
            }
            else if (oblique)
            {
                styleCode = FontFaceFlags.Oblique;
            }

            font.SetFlags(styleCode, weight, stretch);

            // usFirstCharIndex
            parser.ReadUInt16();

            // usLastCharIndex
            parser.ReadUInt16();

            // sTypoAscender
            float ascender = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // sTypoDescender
            float descender = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // sTypoLineGap
            float lineGap = ((float)parser.ReadInt16() / font.UnitsPerEmF);

            // We'll now always use OS/2 unless this table isn't present, in which case HHEA takes over.
            // (The W3C suggested approach).
            if (Fonts.AlwaysUseTypo || useTypo)
            {
                // Apply as-is:
                font.Ascender  = ascender;
                font.Descender = -descender;
                font.LineGap   = lineGap;

                // Remove internal leading if there is one:
                float internalLeading = (ascender - descender) - 1f;

                if (internalLeading != 0f)
                {
                    // Add to lineGap:
                    font.Ascender -= internalLeading;
                    font.LineGap  += internalLeading;
                }

                // Skip windows ascent/descent
                parser.Position += 4;
            }
            else
            {
                // usWinAscent
                parser.usWinAscent = (float)parser.ReadUInt16() / font.UnitsPerEmF;

                // usWinDescent
                parser.usWinDescent = (float)parser.ReadUInt16() / font.UnitsPerEmF;
            }

            if (version >= 1)
            {
                // ulCodePageRange1
                parser.ReadUInt32();

                // ulCodePageRange2
                parser.ReadUInt32();
            }

            if (version >= 2)
            {
                // sxHeight
                parser.ReadInt16();

                // sCapHeight
                parser.ReadInt16();

                // usDefaultChar
                parser.ReadUInt16();

                // usBreakChar
                parser.ReadUInt16();

                // usMaxContent
                parser.ReadUInt16();
            }
        }
示例#21
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();
            }
        }
示例#22
0
        private static int LoadSubTable(FontParser parser, int start, FontFace font, Glyph[] glyphs)
        {
            // Total characters in subtable:
            int characterCount = 0;

            // Seek to the cmap now:
            parser.Position = start;

            // Check it's format 4:
            int format = parser.ReadUInt16();

                        #if INFINITEXT_DEBUG
            Fonts.OnLogMessage("Cmap subtable format: " + format);
                        #endif

            if (format > 13)
            {
                // We now have e.g. 14.0 - ulong here ("Length"):
                parser.Position += 4;
            }
            else if (format > 6)
            {
                // We now have e.g. 12.0 - another short here (reserved):
                parser.Position += 2;

                // Length and language are both 4 byte ints now:
                parser.Position += 8;
            }
            else
            {
                // Size of the sub-table (map length, u16):
                parser.Position += 2;

                // Structure of the sub-table (map language, u16):
                parser.Position += 2;
            }

            switch (format)
            {
            case 0:

                // Byte encoding table:

                for (int i = 0; i < 256; i++)
                {
                    int rByte = parser.ReadByte();

                    Glyph glyph = glyphs[rByte];

                    if (glyph != null)
                    {
                        characterCount++;

                        glyph.AddCharcode(i);
                    }
                }

                break;

            case 2:

                // The offset to the headers:
                int subOffset = parser.Position + (256 * 2);

                // For each high byte:
                for (int i = 0; i < 256; i++)
                {
                    // Read the index to the header and zero out the bottom 3 bits:
                    int headerPosition = subOffset + (parser.ReadUInt16() & (~7));

                    // Read the header:
                    int   firstCode  = parser.ReadUInt16(ref headerPosition);
                    int   entryCount = parser.ReadUInt16(ref headerPosition);
                    short idDelta    = parser.ReadInt16(ref headerPosition);

                    // Grab the current position:
                    int pos = headerPosition;

                    // Read the idRangeOffset - the last part of the header:
                    pos += parser.ReadUInt16(ref headerPosition);

                    int maxCode = firstCode + entryCount;

                    // Get the high byte value:
                    int highByte = (i << 8);

                    // For each low byte:
                    for (int j = firstCode; j < maxCode; j++)
                    {
                        // Get the full charcode (which might not actually exist yet):
                        int charCode = highByte + j;

                        // Read the base of the glyphIndex:
                        int p = parser.ReadUInt16(ref pos);

                        if (p == 0)
                        {
                            continue;
                        }

                        p = (p + idDelta) & 0xFFFF;

                        if (p == 0)
                        {
                            continue;
                        }

                        Glyph glyph = glyphs[p];

                        if (glyph != null)
                        {
                            characterCount++;

                            glyph.AddCharcode(charCode);
                        }
                    }
                }

                break;

            case 4:

                // Segment count. It's doubled.
                int segCount = (parser.ReadUInt16() >> 1);

                // Search range, entry selector and range shift (don't need any):
                parser.Position += 6;

                int baseIndex = parser.Position;

                int endCountIndex = baseIndex;

                baseIndex += 2;

                int startCountIndex    = baseIndex + segCount * 2;
                int idDeltaIndex       = baseIndex + segCount * 4;
                int idRangeOffsetIndex = baseIndex + segCount * 6;

                for (int i = 0; i < segCount - 1; i++)
                {
                    int endCount      = parser.ReadUInt16(ref endCountIndex);
                    int startCount    = parser.ReadUInt16(ref startCountIndex);
                    int idDelta       = parser.ReadInt16(ref idDeltaIndex);
                    int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex);

                    for (int c = startCount; c <= endCount; c++)
                    {
                        int glyphIndex;

                        if (idRangeOffset != 0)
                        {
                            // The idRangeOffset is relative to the current position in the idRangeOffset array.
                            // Take the current offset in the idRangeOffset array.
                            int glyphIndexOffset = (idRangeOffsetIndex - 2);

                            // Add the value of the idRangeOffset, which will move us into the glyphIndex array.
                            glyphIndexOffset += idRangeOffset;

                            // Then add the character index of the current segment, multiplied by 2 for USHORTs.
                            glyphIndexOffset += (c - startCount) * 2;

                            glyphIndex = parser.ReadUInt16(ref glyphIndexOffset);

                            if (glyphIndex != 0)
                            {
                                glyphIndex = (glyphIndex + idDelta) & 0xFFFF;
                            }
                        }
                        else
                        {
                            glyphIndex = (c + idDelta) & 0xFFFF;
                        }

                        // Add a charcode to the glyph now:
                        Glyph glyph = glyphs[glyphIndex];

                        if (glyph != null)
                        {
                            characterCount++;

                            glyph.AddCharcode(c);
                        }
                    }
                }

                break;

            case 6:

                int firstCCode  = parser.ReadUInt16();
                int entryCCount = parser.ReadUInt16();

                for (int i = 0; i < entryCCount; i++)
                {
                    Glyph glyphC = glyphs[parser.ReadUInt16()];

                    if (glyphC != null)
                    {
                        characterCount++;

                        glyphC.AddCharcode(firstCCode + i);
                    }
                }

                break;

            case 10:

                // Trimmed array. Similar to format 6.

                int startCharCode = parser.ReadUInt16();
                int numChars      = parser.ReadUInt16();

                for (int i = 0; i < numChars; i++)
                {
                    Glyph glyphC = glyphs[parser.ReadUInt16()];

                    if (glyphC != null)
                    {
                        characterCount++;

                        glyphC.AddCharcode(startCharCode + i);
                    }
                }

                break;

            case 12:

                // Segmented coverage.
                // Mapping of 1 charcode to 1 glyph. "Segmented" because it can come in blocks called groups.

                int groups = (int)parser.ReadUInt32();

                // For each group of glyphs..
                for (int i = 0; i < groups; i++)
                {
                    // Start/end charcode:
                    int startCode = (int)parser.ReadUInt32();
                    int endCode   = (int)parser.ReadUInt32();

                    // Start glyph ID:
                    int startGlyph = (int)parser.ReadUInt32();

                    int count = (endCode - startCode);

                    // For each glyph/charcode pair..
                    for (int j = 0; j <= count; j++)
                    {
                        // Get the glyph:
                        int glyphIndex = (startGlyph + j);

                        Glyph glyph = glyphs[glyphIndex];

                        if (glyph != null)
                        {
                            characterCount++;

                            // Charcode is..
                            glyph.AddCharcode(startCode + j);
                        }
                    }
                }

                break;

            case 13:

                // Many to one. Same format as #12 but the meaning is a bit different.

                // How many groups?
                int glyphCount = (int)parser.ReadUInt32();

                for (int i = 0; i < glyphCount; i++)
                {
                    int startCode = (int)parser.ReadUInt32();
                    int endCode   = (int)parser.ReadUInt32();
                    int glyphID   = (int)parser.ReadUInt32();

                    // Get the glyph:
                    Glyph glyph = glyphs[glyphID];

                    if (glyph != null)
                    {
                        int count = (endCode - startCode);

                        // For each charcode..
                        for (int j = 0; j <= count; j++)
                        {
                            characterCount++;

                            // Hook up glyph to this charcode:
                            glyph.AddCharcode(startCode + j);
                        }
                    }
                }

                break;

            case 14:

                Fonts.OnLogMessage("InfiniText partially supports part of the font '" + font.Family.Name + "' - this is harmless. Search for this message for more.");

                // This font contains a format 14 CMAP Table.
                // Format 14 is "Unicode variation selectors" - essentially different versions of the same character.
                // E.g. a text Emoji character and a graphical one.
                // In a text system like InfiniText, that just means we must map a bunch of different charcodes
                // to the same glyph.

                // .. I Think! As usual, the OpenType spec doesn't make too much sense.
                // However, it appears to be entirely optional.

                // So, approx implementation is below, however getting the utf32 code point from the variation + base character
                // is completely undocumented - my best guess unfortunately threw errors.

                // See the commented out block below!

                break;

            /*
             *
             * case 14:
             *
             * // How many var selector records?
             * int records=(int)parser.ReadUInt32();
             *
             * for(int i=0;i<records;i++){
             *
             *      // variation selector:
             *      int varSelector=(int)parser.ReadUInt24();
             *
             *      // Offsets:
             *      int defaultUVSOffset=(int)parser.ReadUInt32();
             *      int nonDefaultUVSOffset=(int)parser.ReadUInt32();
             *
             *      // Grab parser position:
             *      int position=parser.Position;
             *
             *      // Got a ref to a default style table?
             *      if(defaultUVSOffset!=0){
             *
             *              // Yep! The UVS is simply a list of "base" characters, each with ranges of available charcodes.
             *              // [BaseCharCode][The extended part. Each of these comes from the range.]
             *              // The actual glyph is the one that we get by directly looking up each of the base characters.
             *
             *              // Seek to the table:
             *              parser.Position=start+defaultUVSOffset;
             *
             *              // Read the unicode value ranges count:
             *              int numUniRangesCount=(int)parser.ReadUInt32();
             *
             *              // For each one..
             *              for(int m=0;m<numUniRangesCount;m++){
             *
             *                      // Read the base charcode:
             *                      int baseCharcode=(int)parser.ReadUInt24();
             *
             *                      // Read the size of the range:
             *                      byte rangeSize=parser.ReadByte();
             *
             *                      for(int c=0;c<=rangeSize;c++){
             *
             *                              // Fetch the base glyph:
             *                              Glyph glyph=font.GetGlyphDirect(baseCharcode);
             *
             *                              if(glyph!=null){
             *
             *                                      // Combine baseCharcode with varSelector next to form the variation (of "glyph").
             *
             *                                      // Get the full charcode (this is incorrect!):
             *                                      // int charcode=char.ConvertToUtf32((char)baseCharcode,(char)varSelector);
             *
             *                                      // Add:
             *                                      //glyph.AddCharcode(charcode);
             *
             *                              }
             *
             *                              // Move baseCharcode along:
             *                              baseCharcode++;
             *
             *                      }
             *
             *              }
             *
             *              // Restore parser:
             *              parser.Position=position;
             *
             *      }
             *
             *      // Got a ref to a non-default style table?
             *      if(nonDefaultUVSOffset!=0){
             *
             *              // Yep! The UVS is simply a list of "base" characters, each with ranges of available charcodes.
             *              // [BaseCharCode][The extended part. Each of these comes from the range.]
             *              // This time though, the glyph to use is directly specified
             *              // (that's what gives it the "non-default" property).
             *
             *              // Seek to the table:
             *              parser.Position=start+nonDefaultUVSOffset;
             *
             *              // Read the number of mappings:
             *              int numMappings=(int)parser.ReadUInt32();
             *
             *              // For each one..
             *              for(int m=0;m<numMappings;m++){
             *
             *                      // Read the base charcode:
             *                      int baseCharcode=(int)parser.ReadUInt24();
             *
             *                      // Read glyph ID:
             *                      int glyphID=(int)parser.ReadUInt16();
             *
             *                      // Get the glyph:
             *                      Glyph glyph=glyphs[glyphID];
             *
             *                      if(glyph!=null){
             *
             *                              // Combine baseCharcode with varSelector next to form the variation (of "glyph").
             *
             *                              // Get the full charcode (this is incorrect!):
             *                              // int charcode=char.ConvertToUtf32((char)baseCharcode,(char)varSelector);
             *
             *                              // Add:
             *                              //glyph.AddCharcode(charcode);
             *
             *                      }
             *
             *              }
             *
             *              // Restore parser:
             *              parser.Position=position;
             *
             *      }
             *
             * }
             *
             * break;
             *
             */

            default:
                Fonts.OnLogMessage("InfiniText does not currently support part of this font. If you need it, please contact us with this: Format: " + format);
                break;
            }

            return(characterCount);
        }
示例#23
0
        private void Parse(int start, int codeLength)
        {
            // Seek there now:
            Parser.Position = start;

            // Where should the parser quit?
            int max = start + codeLength;

            float          c1x;
            float          c1y;
            float          c2x;
            float          c2y;
            int            subIndex;
            CffSubPosition subCode;

            // For each bytecode..
            while (Parser.Position < max)
            {
                // Grab the byte:
                byte v = Parser.ReadByte();

                switch (v)
                {
                case 1:                         // hstem
                    ParseStems();
                    break;

                case 3:                         // vstem
                    ParseStems();
                    break;

                case 4:                         // vmoveto

                    if (Stack.Length > 1 && !HasWidth)
                    {
                        Width    = Stack.Shift() + NominalWidthX;
                        HasWidth = true;
                    }

                    Y += Stack.Shift();

                    Glyph.ClosePath();

                    // Move:
                    Glyph.MoveTo(X * ScaleRatio, Y * ScaleRatio);

                    break;

                case 5:                         // rlineto

                    while (Stack.Length > 0)
                    {
                        X += Stack.Shift();
                        Y += Stack.Shift();

                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 6:                         // hlineto

                    while (Stack.Length > 0)
                    {
                        X += Stack.Shift();
                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);

                        if (Stack.Empty)
                        {
                            break;
                        }

                        Y += Stack.Shift();
                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 7:                         // vlineto

                    while (Stack.Length > 0)
                    {
                        Y += Stack.Shift();
                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);

                        if (Stack.Length == 0)
                        {
                            break;
                        }

                        X += Stack.Shift();
                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 8:                         // rrcurveto

                    while (Stack.Length > 0)
                    {
                        c1x = X + Stack.Shift();
                        c1y = Y + Stack.Shift();
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x + Stack.Shift();
                        Y   = c2y + Stack.Shift();
                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 10:                         // callsubr

                    subIndex = (int)Stack.Pop() + SubrsBias;
                    subCode  = Subrs[subIndex];

                    if (subCode != null)
                    {
                        // Cache the position:
                        subIndex = Parser.Position;

                        // Parse:
                        Parse(subCode.Position, subCode.Length);

                        // Re-apply:
                        Parser.Position = subIndex;
                    }

                    break;

                case 11:                         // return
                    return;

                case 12:                         // escape
                    v = Parser.ReadByte();
                    break;

                case 14:                         // endchar

                    if (Stack.Length > 0 && !HasWidth)
                    {
                        Width    = Stack.Shift() + NominalWidthX;
                        HasWidth = true;
                    }

                    // Close the glyph:
                    Glyph.ClosePath();

                    break;

                case 18:                         // hstemhm
                    ParseStems();
                    break;

                case 19:                         // hintmask
                case 20:                         // cntrmask
                    ParseStems();
                    Parser.Position += (NStems + 7) >> 3;
                    break;

                case 21:                         // rmoveto

                    if (Stack.Length > 2 && !HasWidth)
                    {
                        Width    = Stack.Shift() + NominalWidthX;
                        HasWidth = true;
                    }

                    X += Stack.Shift();
                    Y += Stack.Shift();

                    Glyph.ClosePath();

                    // Move now:
                    Glyph.MoveTo(X * ScaleRatio, Y * ScaleRatio);

                    break;

                case 22:                         // hmoveto

                    if (Stack.Length > 1 && !HasWidth)
                    {
                        Width    = Stack.Shift() + NominalWidthX;
                        HasWidth = true;
                    }

                    X += Stack.Shift();

                    Glyph.ClosePath();

                    // Move now:
                    Glyph.MoveTo(X * ScaleRatio, Y * ScaleRatio);

                    break;

                case 23:                         // vstemhm
                    ParseStems();
                    break;

                case 24:                         // rcurveline

                    while (Stack.Length > 2)
                    {
                        c1x = X + Stack.Shift();
                        c1y = Y + Stack.Shift();
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x + Stack.Shift();
                        Y   = c2y + Stack.Shift();

                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    X += Stack.Shift();
                    Y += Stack.Shift();
                    Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);

                    break;

                case 25:                         // rlinecurve

                    while (Stack.Length > 6)
                    {
                        X += Stack.Shift();
                        Y += Stack.Shift();
                        Glyph.LineTo(X * ScaleRatio, Y * ScaleRatio);
                    }

                    c1x = X + Stack.Shift();
                    c1y = Y + Stack.Shift();
                    c2x = c1x + Stack.Shift();
                    c2y = c1y + Stack.Shift();
                    X   = c2x + Stack.Shift();
                    Y   = c2y + Stack.Shift();
                    Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);

                    break;

                case 26:                         // vvcurveto

                    if (Stack.IsOdd)
                    {
                        X += Stack.Shift();
                    }

                    while (Stack.Length > 0)
                    {
                        c1x = X;
                        c1y = Y + Stack.Shift();
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x;
                        Y   = c2y + Stack.Shift();

                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 27:                         // hhcurveto

                    if (Stack.IsOdd)
                    {
                        Y += Stack.Shift();
                    }

                    while (Stack.Length > 0)
                    {
                        c1x = X + Stack.Shift();
                        c1y = Y;
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x + Stack.Shift();
                        Y   = c2y;

                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 28:                         // shortint

                    Stack.Push(Parser.ReadInt16());

                    break;

                case 29:                         // callgsubr

                    subIndex = (int)Stack.Pop() + GsubrsBias;
                    subCode  = GSubrs[subIndex];

                    if (subCode != null)
                    {
                        // Cache the position:
                        subIndex = Parser.Position;

                        // Parse:
                        Parse(subCode.Position, subCode.Length);

                        // Re-apply:
                        Parser.Position = subIndex;
                    }

                    break;

                case 30:                         // vhcurveto

                    while (Stack.Length > 0)
                    {
                        c1x = X;
                        c1y = Y + Stack.Shift();
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x + Stack.Shift();
                        Y   = c2y + (Stack.Length == 1?Stack.Shift():0);
                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);

                        if (Stack.Empty)
                        {
                            break;
                        }

                        c1x = X + Stack.Shift();
                        c1y = Y;
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        Y   = c2y + Stack.Shift();
                        X   = c2x + (Stack.Length == 1?Stack.Shift():0);
                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                case 31:                         // hvcurveto

                    while (Stack.Length > 0)
                    {
                        c1x = X + Stack.Shift();
                        c1y = Y;
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        Y   = c2y + Stack.Shift();
                        X   = c2x + (Stack.Length == 1 ? Stack.Shift() : 0);
                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);

                        if (Stack.Empty)
                        {
                            break;
                        }

                        c1x = X;
                        c1y = Y + Stack.Shift();
                        c2x = c1x + Stack.Shift();
                        c2y = c1y + Stack.Shift();
                        X   = c2x + Stack.Shift();
                        Y   = c2y + (Stack.Length == 1?Stack.Shift():0);

                        Glyph.CurveTo(c1x * ScaleRatio, c1y * ScaleRatio, c2x * ScaleRatio, c2y * ScaleRatio, X * ScaleRatio, Y * ScaleRatio);
                    }

                    break;

                default:

                    if (v < 32)
                    {
                        // Faulty operator.
                        return;
                    }
                    else if (v < 247)
                    {
                        Stack.Push(v - 139);
                    }
                    else if (v < 251)
                    {
                        Stack.Push((v - 247) * 256 + Parser.ReadByte() + 108);
                    }
                    else if (v < 255)
                    {
                        Stack.Push(-(v - 251) * 256 - Parser.ReadByte() - 108);
                    }
                    else
                    {
                        Stack.Push((float)Parser.ReadInt32() / 65536f);
                    }

                    break;
                }
            }
        }
示例#24
0
        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 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;
			}
			
		}
示例#26
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);
        }