public CffGlyphParser(FontParser parser,FontFace font){
			
			Font=font;
			Parser=parser;
			ScaleRatio=1f/font.UnitsPerEmF;
			Stack=new CffStack();
		}
		public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs,int numMetrics){
			
			// Seek there:
			parser.Position=offset;
			
			// Get the glyph length:
			int numGlyphs=glyphs.Length;
		
			ushort advanceWidth=0;
			short leftSideBearing=0;
			
			// For each one..
			for (int i=0;i<numGlyphs;i++){
				
				// Monospaced fonts only have one entry:
				if (i<numMetrics){
					advanceWidth=parser.ReadUInt16();
					leftSideBearing=parser.ReadInt16();
				}
				
				Glyph glyph=glyphs[i];
				
				glyph.AdvanceWidth=(float)advanceWidth/font.UnitsPerEmF;
				glyph.LeftSideBearing=(float)leftSideBearing/font.UnitsPerEmF;
			}
			
			
		}
		public static void Load(FontParser parser,int offset,FontFace font,out int glyphCount){
			
			// Seek:
			parser.Position=offset;
			
			// Table version:
			float version=parser.ReadVersion();
			
			// Glyph count:
			glyphCount=parser.ReadUInt16();
			
			if (version == 1f){
				
				// Max points:
				parser.ReadUInt16();
				
				// Max contours:
				parser.ReadUInt16();
				
				// Max composite points:
				parser.ReadUInt16();
				
				// Max composite contours:
				parser.ReadUInt16();
				
				// Max zones:
				parser.ReadUInt16();
				
				// Max twilight points:
				parser.ReadUInt16();
				
				// Max storage:
				parser.ReadUInt16();
				
				// Max function defs:
				parser.ReadUInt16();
				
				// Max instruction defs:
				parser.ReadUInt16();
				
				// Max stack elements:
				parser.ReadUInt16();
				
				// Max instruction size:
				parser.ReadUInt16();
				
				// Max component elements:
				parser.ReadUInt16();
				
				// Max component depth:
				parser.ReadUInt16();
				
			}
			
		}
		public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs){
			
			// Seek:
			parser.Position=offset;
			
			// Check table version - 0 is current:
			if(parser.ReadUInt16()!=0){
				return;
			}
			
			// Skip ntables:
			parser.Position+=2;
			
			// Sub-table version - 0 is current:
			if(parser.ReadUInt16()!=0){
				return;
			}
			
			// Skip subTableLength, subTableCoverage:
			parser.Position+=4;
			
			// How many pairs?
			int pairCount=parser.ReadUInt16();
			
			// Skip searchRange, entrySelector, rangeShift.
			parser.Position+=6;
			
			float scaleFactor=1f/font.UnitsPerEmF;
			
			for(int i=0;i<pairCount;i++){
				
				// Get the glyph indices:
				int leftIndex=parser.ReadUInt16();
				int rightIndex=parser.ReadUInt16();
				
				// Get the kerning value:
				short value=parser.ReadInt16();
				
				// Push:
				Glyph right=glyphs[rightIndex];
				Glyph left=glyphs[leftIndex];
				
				if(right==null || left==null){
					continue;
				}
				
				right.AddKerningPair(left,(float)value * scaleFactor);
				
			}
			
		}
		public static Glyph[] Load(FontParser parser,int start,uint[] locations,FontFace font){
			
			// Get the vertical range of the font - it's the em size.
			float range=font.UnitsPerEmF;
			
			// The number of glyphs (last location is just used for computation purposes).
			int glyphCount=locations.Length-1;
			
			Glyph[] glyphs=new Glyph[glyphCount];
			font.ParserGlyphs=glyphs;
			
			// For each glyph..
			for(int i=0;i<glyphCount;i++){
				
				uint offset=locations[i];
				uint nextOffset=locations[i+1];
				
				if(offset!=nextOffset){
					
					// Seek there now:
					parser.Position=start+(int)offset;
					
					// Load it:
					glyphs[i]=ParseGlyph(parser,font,range);
					
				}else{
					
					glyphs[i]=new Glyph(font);
					
				}
				
			}
			
			if(Fonts.Preload){
				
				// Composite glyphs next.
				for(int i=0;i<glyphCount;i++){
					
					Glyph glyph=glyphs[i];
					
					if(glyph!=null){
						glyph.LoadFully(glyphs);
					}
					
				}
				
			}
			
			return glyphs;
			
		}
		public static void Load(FontParser parser,int offset,FontFace font,Glyph[] glyphs){
			
			// Seek:
			parser.Position=offset;
			
			//float scaleFactor=1f/font.UnitsPerEmF;
			
			// Look for kerning data.
			/*Glyph right=glyphs[rightIndex];
			Glyph left=glyphs[leftIndex];
			
			if(right==null || left==null){
				continue;
			}
			
			right.AddKerningPair(left,(float)value * scaleFactor);
			*/
			
		}
		/// <summary>Adds the given font face to this family.</summary>
		public void Add(FontFace font){
			
			font.DisableExtrude=DisableExtrude;
			
			// Grab the flags which represent the styling of this font:
			FontFaceFlags flags=font.StyleFlags;
			
			// Push:
			FontFaces[flags]=font;
			
			if(Regular==null || font.Regular){
				Regular=font;
			}
			
			bool italic=font.Italic;
			
			if(font.Bold && !italic){
				
				if(Bold==null){
					Bold=new List<FontFace>();
				}
				
				Bold.Add(font);
				
			}
			
			if(italic){
				
				if(Italics==null){
					Italics=new List<FontFace>();
				}
				
				Italics.Add(font);
				
			}
			
		}
Exemple #8
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.

            // -> Got to grab all tables for a particular "platform".
            // -> Prefer platform 3 (Microsoft, most common and best documented), then 0, then anything else.

            // So, first let's figure out which platform we'll be using.

            // Favourite platform so far:
            int selectedPlatform = -1;

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

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

                if (platformId == 0)
                {
                    // Great, got platform 0.
                    // Just halt there because we know this fonts got 0 so we'll use that.
                    selectedPlatform = 0;
                    break;
                }
                else if (platformId == 3)
                {
                    // Prefer 3 over others:
                    selectedPlatform = 3;
                }
                else if (selectedPlatform == -1)
                {
                    // Anything else (last resort):
                    selectedPlatform = platformId;
                }

                // Skip encoding ID and offset:
                parser.Position += 6;
            }

            if (selectedPlatform == -1)
            {
                // Empty table! Return.
                return(false);
            }

            // Round 2. This time, select all subtables of the favourite platform.
            // Then collect the offset and load it up.

            // Reset parser, skipping count and version:
            parser.Position = start + 4;

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

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

                Fonts.OnLogMessage("Font " + font.FamilyName + " cmap subtable. Platform ID: " + platformId + ", encoding ID: " + encodingId);
                                #else
                // And the encoding ID:
                parser.ReadUInt16();
                                #endif

                if (platformId == selectedPlatform)
                {
                    // Read offset:
                    int offset = (int)parser.ReadUInt32();

                    // Get position:
                    int position = parser.Position;

                    // Load the subtable now:
                    font.CharacterCount += LoadSubTable(parser, start + offset, font, glyphs);

                    // Reset parser:
                    parser.Position = position;
                }
                else
                {
                    // Skip offset:
                    parser.Position += 4;
                }
            }

            return(true);
        }
Exemple #9
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);
        }
        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();
            }
        }
Exemple #11
0
        public static bool Load(int version, FontParser parser, FontFace font)
        {
            // Load the V1/V2 header:
            ushort numTables;

            LoadHeader(version, parser, out numTables);

            if (version == 1)
            {
                MemoryStream ms = new MemoryStream(parser.Data);

                // Get the ZLIB compression helper:
                Compressor zLib = Compression.Get("zlib");

                // Read each table next.
                for (int i = 0; i < numTables; i++)
                {
                    string tag        = parser.ReadTag();
                    uint   offset     = parser.ReadUInt32();
                    uint   compLength = parser.ReadUInt32();
                    uint   origLength = parser.ReadUInt32();
                    parser.ReadUInt32();                     // origChecksum

                    // Cache position:
                    int pos = parser.Position;

                    if (compLength != origLength)
                    {
                        // Decompress the table now (zlib)

                        // Seek to table:
                        ms.Position = (int)offset;

                        // Decompressed data:
                        byte[] decompressedTable = new byte[(int)origLength];

                        // Decompress now into our target bytes:
                        zLib.Decompress(ms, decompressedTable);
                    }
                    else
                    {
                        // Ordinary table.
                        parser.HandleTable(tag, (int)offset, font);
                    }

                    // Restore position:
                    parser.Position = pos;
                }
            }
            else if (version == 2)
            {
                // Read each table entry next. The data here is compressed as one single block after the table meta.
                Woff2Table[] tableHeaders = new Woff2Table[numTables];
                int          offset       = 0;

                for (int i = 0; i < numTables; i++)
                {
                    // Read the table entry:
                    byte flags = parser.ReadByte();

                    string tag;

                    int tagFlag = (flags & 63);

                    if (tagFlag == 63)
                    {
                        tag = parser.ReadTag();
                    }
                    else
                    {
                        tag = TagLookup[tagFlag];
                    }

                    ulong origLength      = parser.ReadBase128();
                    ulong transformLength = 0;

                    int transformVersion = (flags >> 6);                   //0-3

                    if (tag == "glyf" || tag == "loca")
                    {
                        // transform length:
                        transformLength = parser.ReadBase128();
                    }

                    offset += (int)origLength;

                    tableHeaders[i] = new Woff2Table(tag, offset, (int)transformLength, transformVersion);
                }
            }

            // All ok:
            return(true);
        }
Exemple #12
0
 public CompositeGlyph(FontFace parent) : base(parent)
 {
 }
		/// <summary>Adds a ligature table to the font.</summary>
		public static void AddToFont(string name,FontParser parser,int tableOffset,FontFace font,LigatureLookupTable[] tables){
			
			int position=parser.Position;
			
			// Skip params (+2):
			parser.Position=tableOffset+2;
			
			// Index count:
			int count=parser.ReadUInt16();
			
			// For each one..
			for(int i=0;i<count;i++){
				
				// Grab the index:
				//int index=parser.ReadUInt16();
				
				// Grab the table:
				//LigatureLookupTable table=tables[index];
				
			}
			
			parser.Position=position;
			
		}
		public static bool Load(FontParser parser,int start,FontFace font,Glyph[] glyphs){
			
			// Seek there:
			parser.Position=start;
			
			// Read the version (and check if it's zero):
			if(parser.ReadUInt16()!=0){
				return false;
			}
			
			// Strangely the cmap table can have lots of tables inside it. For now we're looking for the common type 3 table.
			
			// Number of tables:
			int tableCount=parser.ReadUInt16();
			
			// Total characters in font:
			int characterCount=0;
			
			int offset=-1;
			int favour=0;
			
			for(int i = 0; i < tableCount; i += 1) {
				
				// Grab the platform ID:
				int platformId=parser.ReadUInt16();
				
				// And the encoding ID:
				int encodingId=parser.ReadUInt16();
				
				if(platformId==3 || platformId==0){
					
					if(encodingId==10){
						
						// Top favourite - most broad Unicode encoding.
						
						// Read offset:
						offset=(int)parser.ReadUInt32();
						
						break;
						
					}else if(encodingId==1 || encodingId==0){
						
						// Read offset:
						offset=(int)parser.ReadUInt32();
						
						// Mid-range favourite:
						favour=1;
						
						continue;
						
					}else if(favour==0){
						
						// Anything else we'll give a try:
						
						// Read offset (but don't break):
						offset=(int)parser.ReadUInt32();
						
						continue;
						
					}
					
				}
				
				// Skip offset:
				parser.Position+=4;
				
			}
			
			if(offset==-1){
				// We don't support this font :(
				return false;
			}
			
			// Seek to the cmap now:
			parser.Position=start+offset;
			
			// Check it's format 4:
			int format=parser.ReadUInt16();
		
			if(format>6){
				// We now have e.g. 12.0 - another short here:
				parser.Position+=2;
				
				// Size/ structure are both 4 byte ints now:
				parser.Position+=8;
				
			}else{
			
				// Size of the sub-table (map length, u16):
				parser.Position+=2;
				
				// Structure of the sub-table (map language, u16):
				parser.Position+=2;
				
			}
			
			switch(format){
				
				case 0:
				
				// Byte encoding table:
				
				for(int i=0;i<256;i++){
					
					int rByte=parser.ReadByte();
					
					Glyph glyph=glyphs[rByte];
					
					if(glyph!=null){
						characterCount++;
					
						glyph.AddCharcode(i);
					}
					
				}
				
				break;
				case 2:
				
				// The offset to the headers:
				int subOffset=parser.Position + (256 * 2);
				
				// For each high byte:
				for(int i=0;i<256;i++){
					
					// Read the index to the header and zero out the bottom 3 bits:
					int headerPosition=subOffset + (parser.ReadUInt16() & (~7));
					
					// Read the header:
					int firstCode=parser.ReadUInt16(ref headerPosition);
					int entryCount=parser.ReadUInt16(ref headerPosition);
					short idDelta=parser.ReadInt16(ref headerPosition);
					
					// Grab the current position:
					int pos=headerPosition;
					
					// Read the idRangeOffset - the last part of the header:
					pos+=parser.ReadUInt16(ref headerPosition);
					
					int maxCode=firstCode+entryCount;
					
					// Get the high byte value:
					int highByte=(i<<8);
					
					// For each low byte:
					for (int j=firstCode;j<maxCode;j++){
						
						// Get the full charcode (which might not actually exist yet):
						int charCode=highByte+j;
						
						// Read the base of the glyphIndex:
						int p=parser.ReadUInt16(ref pos);
						
						if(p==0){
							continue;
						}
						
						p=(p+idDelta) & 0xFFFF;
						
						if(p==0){
							continue;
						}
						
						Glyph glyph=glyphs[p];
						
						if(glyph!=null){
							
							characterCount++;
							
							glyph.AddCharcode(charCode);
							
						}
						
					}
				}
				
				break;
				case 4:
				
				// Segment count. It's doubled.
				int segCount=(parser.ReadUInt16() >> 1);
				
				// Search range, entry selector and range shift (don't need any):
				parser.Position+=6;
				
				int baseIndex=parser.Position;
				
				int endCountIndex=baseIndex;
				
				baseIndex+=2;
				
				int startCountIndex = baseIndex + segCount * 2;
				int idDeltaIndex = baseIndex + segCount * 4;
				int idRangeOffsetIndex = baseIndex + segCount * 6;
				
				for(int i = 0; i < segCount - 1; i ++){
					
					int endCount = parser.ReadUInt16(ref endCountIndex);
					int startCount = parser.ReadUInt16(ref startCountIndex);
					int idDelta = parser.ReadInt16(ref idDeltaIndex);
					int idRangeOffset = parser.ReadUInt16(ref idRangeOffsetIndex);
					
					for(int c = startCount; c <= endCount;c++){
						
						int glyphIndex;
						
						if(idRangeOffset != 0){
							
							// The idRangeOffset is relative to the current position in the idRangeOffset array.
							// Take the current offset in the idRangeOffset array.
							int glyphIndexOffset = (idRangeOffsetIndex - 2);
							
							// Add the value of the idRangeOffset, which will move us into the glyphIndex array.
							glyphIndexOffset += idRangeOffset;
							
							// Then add the character index of the current segment, multiplied by 2 for USHORTs.
							glyphIndexOffset += (c - startCount) * 2;
							
							glyphIndex=parser.ReadUInt16(ref glyphIndexOffset);
							
							if(glyphIndex!=0){
								glyphIndex = (glyphIndex + idDelta) & 0xFFFF;
							}
							
						}else{
							glyphIndex = (c + idDelta) & 0xFFFF;
						}
						
						// Add a charcode to the glyph now:
						Glyph glyph=glyphs[glyphIndex];
						
						if(glyph!=null){
							characterCount++;
						
							glyph.AddCharcode(c);
						}
					}
					
				}
				
				break;
				
				case 6:
				
				int firstCCode=parser.ReadUInt16();
				int entryCCount=parser.ReadUInt16();
				
				for(int i=0;i<entryCCount;i++){
					
					Glyph glyphC=glyphs[parser.ReadUInt16()];
					
					if(glyphC!=null){
					
						characterCount++;
						
						glyphC.AddCharcode(firstCCode+i);
					
					}
					
				}
				
				break;
				
				case 12:
				
				int groups=(int)parser.ReadUInt32();
				
				for(int i=0;i<groups;i++){
					int startCode=(int)parser.ReadUInt32();
					int endCode=(int)parser.ReadUInt32();
					int startGlyph=(int)parser.ReadUInt32();
					
					int count=(endCode - startCode);
					
					for(int j=0;j<=count;j++){
						
						int glyphIndex=(startGlyph+j);
						
						Glyph glyph=glyphs[glyphIndex];
						
						if(glyph!=null){
							
							characterCount++;
							
							glyph.AddCharcode(startCode+j);
							
						}
						
					}
				}
				
				break;
				
				default:
					Fonts.OnLogMessage("InfiniText does not currently support this font. If you need it, please contact us with this: Format: "+format);
				break;
			}
			
			font.CharacterCount=characterCount;
			
			return true;
			
		}
        public static void Load(FontParser parser, int offset, FontFace font)
        {
            // Seek there:
            parser.Position = offset;

            // Version:
            parser.ReadVersion();

            // Script list (directed by UI Language setting):
            int scriptList = parser.ReadUInt16();

            // Feature list:
            int featList = parser.ReadUInt16();

            // Lookup list:
            int lookList = parser.ReadUInt16();

            // Goto script list:
            int objectOffset = scriptList + offset;

            parser.Position = objectOffset;

            /*
             * // How many language scripts?
             * int scriptCount=parser.ReadUInt16();
             *
             * for(int i=0;i<scriptCount;i++){
             *
             *      // Read the script code:
             *      string scrName=parser.ReadString(4);
             *
             *      // And it's offset:
             *      int scriptOffset=parser.ReadUInt16()+objectOffset;
             *
             *      int retPosition=parser.Position;
             *
             *      // Seek and load it right away:
             *      parser.Position=scriptOffset;
             *
             *      // What's the default lang?
             *      int defaultLangOffset=parser.ReadUInt16();
             *
             *      // How many languages?
             *      int langCount=parser.ReadUInt16();
             *
             *      for(int l=0;l<langCount;l++){
             *
             *              // Read the lang code:
             *              string langName=parser.ReadString(4);
             *
             *              // And it's offset - points to list of features:
             *              int langOffset=parser.ReadUInt16()+objectOffset;
             *
             *      }
             *
             *      parser.Position=retPosition;
             *
             * }
             */

            // Goto lookup list:
            objectOffset = lookList + offset;

            // Seek there:
            parser.Position = objectOffset;

            // Load each one:
            int lookCount = parser.ReadUInt16();

            // Create:
            LigatureLookupTable[] lookupTables = new LigatureLookupTable[lookCount];

            for (int i = 0; i < lookCount; i++)
            {
                // Create the table:
                LigatureLookupTable table = new LigatureLookupTable();

                // Load it:
                int tableOffset = parser.ReadUInt16();

                // Cache the position:
                int seekPos = parser.Position;

                // Head over to the table:
                parser.Position = objectOffset + tableOffset;

                // Load it now:
                table.Load(parser);

                // Add to set:
                lookupTables[i] = table;

                // Restore position:
                parser.Position = seekPos;
            }

            // Goto feature list:
            objectOffset = featList + offset;

            parser.Position = objectOffset;

            // How many features? For now, "liga" is the main feature we're after here.
            int featureCount = parser.ReadUInt16();

            for (int i = 0; i < featureCount; i++)
            {
                // Read the feature code:
                string feature = parser.ReadString(4);

                // Table offset:
                int featTable = parser.ReadUInt16();

                switch (feature)
                {
                case "locl":
                case "liga":

                    AddToFont(feature, parser, featTable + objectOffset, font, lookupTables);

                    break;
                }
            }
        }
        /// <summary>Adds a ligature table to the font.</summary>
        public static void AddToFont(string name, FontParser parser, int tableOffset, FontFace font, LigatureLookupTable[] tables)
        {
            int position = parser.Position;

            // Skip params (+2):
            parser.Position = tableOffset + 2;

            // Index count:
            int count = parser.ReadUInt16();

            // For each one..
            for (int i = 0; i < count; i++)
            {
                // Grab the index:
                //int index=parser.ReadUInt16();

                // Grab the table:
                //LigatureLookupTable table=tables[index];
            }

            parser.Position = position;
        }
        public static void Load(FontParser parser, int offset, FontFace font, out int hmMetricCount)
        {
            // Seek there:
            parser.Position = offset;

            // Version:
            parser.ReadVersion();

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

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

            // Line gap:
            float lineGap = (float)parser.ReadInt16() / font.UnitsPerEmF;

            if (!Fonts.UseOS2Metrics || !parser.ReadOS2)
            {
                if (lineGap < 0f)
                {
                    lineGap = -lineGap;
                }

                float halfGap = lineGap / 2f;

                font.Ascender  = ascender + halfGap;
                font.Descender = halfGap - descender;

                font.LineGap = font.Ascender + font.Descender;
            }

            // Advance width max:
            font.MaxAdvanceWidth = (float)parser.ReadUInt16() / font.UnitsPerEmF;

            // Min left side bearing:
            font.MinLeftSideBearing = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // Min right side bearing:
            font.MinRightSideBearing = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // Max x extent:
            font.MaxXExtent = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // Caret slope rise:
            float caretRise = (float)parser.ReadInt16();

            // Caret slope run:
            float caretRun = (float)parser.ReadInt16();

            font.CaretAngle = (float)Math.Atan2(caretRise, caretRun);

            // Caret offset:
            font.CaretOffset = (float)parser.ReadInt16() / font.UnitsPerEmF;

            // Skip:
            parser.Position += 8;

            // Metric format:
            parser.ReadInt16();

            // Metric count:
            hmMetricCount = parser.ReadUInt16();
        }
        public static bool Load(FontParser parser, int offset, FontFace font, out int locFormatIndex)
        {
            // Seek there now:
            parser.Position = offset;

            // Version:
            parser.ReadVersion();

            // Revision:
            parser.ReadRevision();

            // Checksum adjustment:
            parser.ReadUInt32();

            // Magic number:
            if (parser.ReadUInt32() != 0x5F0F3CF5)
            {
                locFormatIndex = 0;

                return(false);
            }

            // Flags:
            parser.ReadUInt16();

            // Units per em:
            font.UnitsPerEm  = parser.ReadUInt16();
            font.UnitsPerEmF = (float)font.UnitsPerEm;

            // Skip created and modified:
            parser.ReadTime();
            parser.ReadTime();

            // X min:
            parser.ReadInt16();

            // Y min:
            parser.ReadInt16();

            // X max:
            parser.ReadInt16();

            // Y max:
            parser.ReadInt16();

            // Mac style:
            parser.ReadUInt16();

            // Lowest Rec PPEM:
            parser.ReadUInt16();

            // Font direction hint:
            parser.ReadInt16();

            // Index for the loc format:
            locFormatIndex = parser.ReadInt16();             // 50

            // Glyph data format:
            parser.ReadInt16();

            return(true);
        }
        public static void Load(FontParser parser, int offset, FontFace font, out int numberOfGlyphs)
        {
            // Seek:
            parser.Position = offset;

            // version
            float version = parser.ReadVersion();

            // Italic angle. For some reason it's inverted in the spec - negative means a slope to the right.
            int frac;
            int dec = parser.ReadFixed(out frac);

            if (frac != 0)
            {
                // Figure it out:
                float angle = (float)dec / (float)frac;

                // Apply it (un-inverted):
                font.SetItalicAngle(-angle);
            }

            // underlinePosition
            parser.ReadInt16();

            // underlineThickness
            parser.ReadInt16();

            // isFixedPitch
            parser.ReadUInt32();

            // minMemType42
            parser.ReadUInt32();

            // maxMemType42
            parser.ReadUInt32();

            // minMemType1
            parser.ReadUInt32();

            // maxMemType1
            parser.ReadUInt32();

            if (version == 2f)
            {
                numberOfGlyphs = parser.ReadUInt16();

                /*
                 * string[] glyphNames=new string[numberOfGlyphs];
                 *
                 * for (int i = 0; i < numberOfGlyphs; i++) {
                 *
                 *      // Read the index:
                 *      int index = parser.ReadUInt16();
                 *
                 *      if(index >= StandardNames.Length){
                 *
                 *              // Read the name:
                 *              glyphNames[i]=parser.ReadString(parser.ReadByte());
                 *
                 *      }else{
                 *
                 *              // Grab the std name:
                 *              glyphNames[i]=StandardNames[index];
                 *
                 *      }
                 *
                 * }
                 */
            }
            else if (version == 2.5f)
            {
                numberOfGlyphs = parser.ReadUInt16();

                /*
                 * byte[] offsets = new byte[numberOfGlyphs];
                 *
                 * for (int i = 0; i < post.numberOfGlyphs; i++){
                 *
                 *      offsets[i] = parser.ReadByte();
                 *
                 * }
                 */
            }
            else
            {
                numberOfGlyphs = -1;
            }
        }
//--------------------------------------
		public static void Load(FontParser parser,int offset,FontFace font){
			
			// Seek there:
			parser.Position=offset;
			
			// Version:
			parser.ReadVersion();
			
			// Script list (directed by UI Language setting):
			int scriptList=parser.ReadUInt16();
			
			// Feature list:
			int featList=parser.ReadUInt16();
			
			// Lookup list:
			int lookList=parser.ReadUInt16();
			
			// Goto script list:
			int objectOffset=scriptList+offset;
			
			parser.Position=objectOffset;
			
			/*
			// How many language scripts?
			int scriptCount=parser.ReadUInt16();
			
			for(int i=0;i<scriptCount;i++){
				
				// Read the script code:
				string scrName=parser.ReadString(4);
				
				// And it's offset:
				int scriptOffset=parser.ReadUInt16()+objectOffset;
				
				int retPosition=parser.Position;
				
				// Seek and load it right away:
				parser.Position=scriptOffset;
				
				// What's the default lang?
				int defaultLangOffset=parser.ReadUInt16();
				
				// How many languages?
				int langCount=parser.ReadUInt16();
				
				for(int l=0;l<langCount;l++){
					
					// Read the lang code:
					string langName=parser.ReadString(4);
					
					// And it's offset - points to list of features:
					int langOffset=parser.ReadUInt16()+objectOffset;
					
				}
				
				parser.Position=retPosition;
				
			}
			*/
			
			// Goto lookup list:
			objectOffset=lookList+offset;
			
			// Seek there:
			parser.Position=objectOffset;
			
			// Load each one:
			int lookCount=parser.ReadUInt16();
			
			// Create:
			LigatureLookupTable[] lookupTables=new LigatureLookupTable[lookCount];
			
			for(int i=0;i<lookCount;i++){
				
				// Create the table:
				LigatureLookupTable table=new LigatureLookupTable();
				
				// Load it:
				int tableOffset=parser.ReadUInt16();
				
				// Cache the position:
				int seekPos=parser.Position;
				
				// Head over to the table:
				parser.Position=objectOffset+tableOffset;
				
				// Load it now:
				table.Load(parser);
				
				// Add to set:
				lookupTables[i]=table;
				
				// Restore position:
				parser.Position=seekPos;
				
			}
			
			// Goto feature list:
			objectOffset=featList+offset;
			
			parser.Position=objectOffset;
			
			// How many features? For now, "liga" is the main feature we're after here.
			int featureCount=parser.ReadUInt16();
			
			for(int i=0;i<featureCount;i++){
				
				// Read the feature code:
				string feature=parser.ReadString(4);
				
				// Table offset:
				int featTable=parser.ReadUInt16();
				
				switch(feature){
					
					case "locl":
					case "liga":
						
						AddToFont(feature,parser,featTable+objectOffset,font,lookupTables);
						
					break;
					
				}
				
			}
			
		}
		public static void Load(FontParser parser,int offset,FontFace font,out int hmMetricCount){
			
			// Seek there:
			parser.Position=offset;
			
			// Version:
			parser.ReadVersion();
			
			// Ascender:
			float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Descender:
			float descender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Line gap:
			float lineGap=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			if(!Fonts.UseOS2Metrics || !parser.ReadOS2){
				
				if(lineGap<0f){
					lineGap=-lineGap;
				}
				
				float halfGap=lineGap/2f;
				
				font.Ascender=ascender + halfGap;
				font.Descender=halfGap-descender;
			
				font.LineGap=font.Ascender + font.Descender;
			
			}
			
			// Advance width max:
			font.MaxAdvanceWidth=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// Min left side bearing:
			font.MinLeftSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Min right side bearing:
			font.MinRightSideBearing=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Max x extent:
			font.MaxXExtent=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Caret slope rise:
			float caretRise=(float)parser.ReadInt16();
			
			// Caret slope run:
			float caretRun=(float)parser.ReadInt16();
			
			font.CaretAngle=(float)Math.Atan2(caretRise,caretRun);
			
			// Caret offset:
			font.CaretOffset=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// Skip:
			parser.Position += 8;
			
			// Metric format:
			parser.ReadInt16();
			
			// Metric count:
			hmMetricCount = parser.ReadUInt16();
			
		}
//--------------------------------------
		public static Glyph ParseGlyph(FontParser parser,FontFace font,float range){
			
			// How many contours has it got?
			int contourCount=parser.ReadInt16();
			
			// Skip bounds - we don't trust these too much, so we'll figure them out ourselves:
			parser.Position+=8;
			
			if(contourCount>0){
				// This glyph is not a composite.
				
				// Create the glyph:
				Glyph glyph=new Glyph(font);
				
				if(Fonts.Preload){
					
					LoadGlyph(glyph,contourCount,parser,range);
					
				}else{
					
					// Increase unloaded count:
					font.UnloadedGlyphs++;
					
					// Add position info:
					glyph.AddPathNode(new LoadMetaPoint(parser.Position,contourCount));
					
				}
				
				return glyph;
				
			}else if(contourCount==0){
				
				// Empty glyph e.g. space. Create the glyph:
				Glyph glyph=new Glyph(font);
				
				return glyph;
				
			}
			
			CompositeGlyph compGlyph=new CompositeGlyph(font);
			
			bool moreComponents=true;
			
			while(moreComponents){
			
				ushort cFlags=parser.ReadUInt16();
				ushort glyphIndex=parser.ReadUInt16();
				
				VectorTransform component=new VectorTransform(glyphIndex);
				
				if ((cFlags & 1) > 0) {
					// The arguments are words
					component.Dx = (float)parser.ReadInt16() / range;
					component.Dy = (float)parser.ReadInt16() / range;
				} else {
					// The arguments are bytes
					component.Dx = (float)parser.ReadByte()  / range;
					component.Dy = (float)parser.ReadByte()  / range;
				}
				
				if ((cFlags & 8) > 0) {
					// We have one scale
					component.XScale = component.YScale = parser.ReadF2Dot14();
				} else if ((cFlags & 64) > 0) {
					// We have an X / Y scale
					component.XScale = parser.ReadF2Dot14();
					component.YScale = parser.ReadF2Dot14();
				} else if ((cFlags & 128) > 0) {
					// We have a 2x2 transformation
					component.XScale = parser.ReadF2Dot14();
					component.Scale01 = parser.ReadF2Dot14();
					component.Scale10 = parser.ReadF2Dot14();
					component.YScale = parser.ReadF2Dot14();
				}
				
				// Push the component to the end:
				compGlyph.AddComponent(component);
				
				moreComponents = ((cFlags & 32)==32);
			}
			
			return compGlyph;
			
		}
		public CompositeGlyph(FontFace parent):base(parent){
			
		}
        /// <summary>Gets or creates the most suitable font face for the given style.</summary>
        public FontFace GetFace(int styleCode, int synthFlags)
        {
            // Style (italic, oblique etc):
            int style = (styleCode & FontFaceFlags.StyleMask);

            // Get the font weight:
            int weight = (styleCode & FontFaceFlags.WeightMask) >> 3;

            if (weight == 0)
            {
                // Regular:
                weight = 4;
            }

            // And the stretch mode:
            int stretch = (styleCode & FontFaceFlags.StretchMask) >> 7;

            if (stretch == 0)
            {
                // Medium stretch
                stretch = 5;
            }

            // Try getting the face:
            FontFace bestFace = Regular;

            // A linear search is actually optimal for most cases.
            // This is because the set is typically very small.

            // [Condensed][Weight][Italic]
            int bestMatch = 0;


            for (int i = 0; i < FontFaces.Count; i++)
            {
                // Current face:
                FontFace face = FontFaces[i];

                // We'll now figure out a match weighting.
                int matchWeight = 0;

                // First, we match by condensed:
                if (face.Stretch == stretch)
                {
                    // Direct match. 8 points awarded.
                    matchWeight = 8;
                }
                else
                {
                    // How close is it?
                    int stretchDiff = face.Stretch - stretch;

                    if (stretchDiff < 0)
                    {
                        stretchDiff = -stretchDiff;
                    }

                    // StretchDiff maxes out at 8. Award at most 8 points.
                    matchWeight = 8 - stretchDiff;
                }

                // Weight next.
                if (face.Weight == weight)
                {
                    // Direct match. 8 points awarded.
                    matchWeight += 8;
                }
                else
                {
                    // How close is it?
                    int weightDiff = face.Weight - weight;

                    if (weightDiff < 0)
                    {
                        weightDiff = -weightDiff;
                    }

                    // weightDiff maxes out at 8. Award at most 8 points.
                    matchWeight += 8 - weightDiff;
                }

                // Style.
                if (face.Style == style)
                {
                    // Direct match! 2 points awarded.
                    matchWeight += 2;
                }
                else
                {
                    // If it's the other of oblique/italic, award 1 point.
                    if (style != 0 && face.Style != 0)
                    {
                        matchWeight += 1;
                    }
                }

                if (matchWeight > bestMatch)
                {
                    // Got a new best!
                    bestMatch = matchWeight;
                    bestFace  = face;
                }

                if (matchWeight == 18)
                {
                    // Perfect match!
                    break;
                }
            }

            if (bestMatch != 18 && synthFlags != 0)
            {
                // Synthesize a face, deriving it from our best match.
                bestFace = bestFace.CreateSynthetic(style, weight, stretch);

                // Add it:
                Add(bestFace);
            }

            return(bestFace);
        }
		public static Glyph[] Load(FontParser parser,int offset,FontFace font){
			
			// Create the parser:
			CffGlyphParser cffParser=new CffGlyphParser(parser,font);
			cffParser.FullLoad=Fonts.Preload;
			font.CffParser=cffParser;
			
			// Seek, skipping the 4 byte header:
			parser.Position=offset+4;
			
			// Skip the name index:
			SkipIndex(parser);
			
			// Top dict index next (one entry only):
			Dictionary<int,List<int>> topDict=LoadDict(parser);
			
			// String index:
			SkipIndex(parser);
			
			// GSubr index:
			cffParser.GSubrs=LoadSubIndex(parser);
			
			// Figure out the bias:
			cffParser.GsubrsBias=GetBias(cffParser.GSubrs);
			
			// Read the private dict next - grab the info about where it is:
			List<int> privateDictInfo=topDict[18];
			
			// Get it's offset:
			int privateDictOffset=offset+privateDictInfo[1];
			
			// Seek there:
			parser.Position=privateDictOffset;
			
			// Load:
			Dictionary<int,List<int>> privateDict=ParseCFFDict(parser,privateDictInfo[0]);
			
			// Grab the default values:
			cffParser.DefaultWidthX=(float)ReadDict(privateDict,20);
			cffParser.NominalWidthX=(float)ReadDict(privateDict,21);
			
			// Grab the subrs offset. May be zero (or non-existant):
			int privateSubrs=ReadDict(privateDict,19);
			
			if(privateSubrs!=0){
				
				// We have a "subroutine" set. Get it's full offset and hop there:
				parser.Position=privateDictOffset+privateSubrs;
				
				// Load the set:
				cffParser.Subrs=LoadSubIndex(parser);
				
				// Figure out the bias/offset:
				cffParser.SubrsBias=GetBias(cffParser.Subrs);
				
			}
			
			// Seek to the char string table:
			parser.Position=offset+ReadDict(topDict,17);
			
			// Time to actually load the actual glyphs, wohoo! O.O
			return LoadIndex(parser,cffParser);
			
		}
		public static void Load(FontParser parser,int offset,FontFace font){
			
			// Got OS2:
			parser.ReadOS2=true;
			
			// Seek:
			parser.Position=offset;
			
			// version
			int version=parser.ReadUInt16();
			
			// xAvgCharWidth
			parser.ReadInt16();
			
			// usWeightClass
			int weight=parser.ReadUInt16();
			
			// usWidthClass
			parser.ReadUInt16();
			
			// fsType
			parser.ReadUInt16();
			
			// ySubscriptXSize
			parser.ReadInt16();
			
			// ySubscriptYSize
			parser.ReadInt16();
			
			// ySubscriptXOffset
			parser.ReadInt16();
			
			// ySubscriptYOffset
			parser.ReadInt16();
			
			// ySuperscriptXSize
			parser.ReadInt16();
			
			// ySuperscriptYSize
			parser.ReadInt16();
			
			// ySuperscriptXOffset
			parser.ReadInt16();
			
			// ySuperscriptYOffset
			parser.ReadInt16();
			
			// yStrikeoutSize
			font.StrikeSize=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// yStrikeoutPosition
			font.StrikeOffset=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sFamilyClass
			parser.ReadInt16();
			
			// panose:
			/*
			byte panose=new byte[10];
			
			for(int i=0;i<10;i++){
				panose[i]=parser.ReadByte();
			}
			*/
			parser.Position+=10;
			
			// ulUnicodeRange1
			parser.ReadUInt32();
			
			// ulUnicodeRange2
			parser.ReadUInt32();
			
			// ulUnicodeRange3
			parser.ReadUInt32();
			
			// ulUnicodeRange4
			parser.ReadUInt32();
			
			// achVendID
			parser.ReadTag();
			
			// fsSelection
			int type=parser.ReadUInt16();
			
			bool italic=((type&1)==1);
			// bool strikeout=((type&16)==16);
			// bool underscore=((type&2)==2);
			bool oblique=((type&512)==512);
			bool bold=((type&32)==32);
			bool regular=((type&64)==64);
			bool useTypo=((type&128)==128);
			
			if(!bold || regular){
				// Must be regular:
				weight=400;
			}else if(weight==0){
				weight=700;
			}
			
			font.SetFlags(italic || oblique,weight);
			
			// usFirstCharIndex
			parser.ReadUInt16();
			
			// usLastCharIndex
			parser.ReadUInt16();
			
			// sTypoAscender
			float ascender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sTypoDescender
			float descender=(float)parser.ReadInt16()/font.UnitsPerEmF;
			
			// sTypoLineGap
			float lineGap=((float)parser.ReadInt16()/font.UnitsPerEmF);
			
			// usWinAscent
			float wAscender=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// usWinDescent
			float wDescender=(float)parser.ReadUInt16()/font.UnitsPerEmF;
			
			// This is an awkward spec hack due to most windows programs
			// providing the wrong typo descender values.
		
			if(Fonts.UseOS2Metrics){
				
				if(useTypo){
					
					float halfGap=lineGap/2f;
				
					font.Ascender=ascender + halfGap;
					font.Descender=halfGap-descender;
					
					font.LineGap=font.Ascender + font.Descender;
					
				}else{
					font.Ascender=wAscender;
					font.Descender=wDescender;
					
					font.LineGap=font.Ascender + font.Descender;
				}
				
			}
			
			
			if (version >= 1){
				// ulCodePageRange1
				parser.ReadUInt32();
				
				// ulCodePageRange2
				parser.ReadUInt32();
			}
			
			if (version >= 2){
				// sxHeight
				parser.ReadInt16();
				
				// sCapHeight
				parser.ReadInt16();
				
				// usDefaultChar
				parser.ReadUInt16();
				
				// usBreakChar
				parser.ReadUInt16();
				
				// usMaxContent
				parser.ReadUInt16();
			}
			
			
		}
		public static Dictionary<string,string> Load(FontParser parser,int start,FontFace font){
			
			// Create the map:
			Dictionary<string,string> map=new Dictionary<string,string>();
			
			// Go there now:
			parser.Position=start;
			
			// Format:
			int format=parser.ReadUInt16();
			
			// Number of names:
			int count = parser.ReadUInt16();
			
			// String offset:
			int stringOffset = start + parser.ReadUInt16();
			
			int unknownCount = 0;
			
			for(int i=0;i<count;i++){
				
				// Platform ID:
				ushort platformID = parser.ReadUInt16();
				ushort encodingID = parser.ReadUInt16();
				ushort languageID = parser.ReadUInt16();
				ushort nameID = parser.ReadUInt16();
				string property = null;
				
				if(nameID<PropertyMap.Length){
					property=PropertyMap[nameID];
				}
				
				ushort byteLength = parser.ReadUInt16();
				ushort offset = parser.ReadUInt16();
				
				// platformID - encodingID - languageID standard combinations :
				// 1 - 0 - 0 : Macintosh, Roman, English
				// 3 - 1 - 0x409 : Windows, Unicode BMP (UCS-2), en-US
				
				if(platformID == 3 && encodingID == 1 && languageID == 0x409){
					
					int length = byteLength/2;
					char[] chars=new char[length];
				
					int index=stringOffset+offset;
					
					for(int j = 0; j < length; j++){
						
						chars[j] = (char)parser.ReadInt16(ref index);
						
					}
					
					string str = new string(chars);
					
					if(property!=null){
						map[property] = str;
					}else{
						unknownCount++;
						map["unknown"+unknownCount] = str;
					}
					
				}
				
			}
			
			// Next grab the name and family. Done last as we must know name before family.
			string name;
			map.TryGetValue("fullName",out name);
			
			string family;
			map.TryGetValue("fontFamily",out family);
			
			if(name==null){
				name="[Untitled font face]";
			}
			
			// Apply name first:
			font.Name=name;
			
			if(family==null){
				family="[Untitled font family]";
			}
			
			// Apply family name (which in turn creates the family instance):
			font.FamilyName=family;
			
			if(format==1){
				
				// Language tag count:
				parser.ReadUInt16();
				
			}
			
			return map;
			
		}
Exemple #30
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 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;
			}
			
		}
Exemple #34
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);
        }