Beispiel #1
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);
        }
Beispiel #2
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);
        }
Beispiel #3
0
        public static Dictionary <int, List <int> > ParseCFFDict(FontParser parser, int length)
        {
            // Create the results set:
            Dictionary <int, List <int> > results = new Dictionary <int, List <int> >();

            // Our first values set:
            List <int> values = new List <int>();

            // Note that rather awkwardly the key comes *after* the set of values.

            int max = parser.Position + length;

            // While there's more data..
            while (parser.Position < max)
            {
                // Read the state byte:
                int state = parser.ReadByte();

                if (state < 22)
                {
                    if (state == 12)
                    {
                        // 2 byte key code.
                        state = 1200 + parser.ReadByte();
                    }

                    // Push values:
                    results[state] = values;

                    // Clear:
                    values = new List <int>();
                }
                else
                {
                    // Read the operand:
                    int operand = ParseOperand(parser, state);

                    // Push:
                    values.Add(operand);
                }
            }

            return(results);
        }
		private static Glyph[] LoadIndex(FontParser parser,CffGlyphParser cffParser){
			
			// Read the index which contains a bunch of char strings.
			// Each charstring is a postscript glyph definition.
			
			// How many are in here?
			int count=parser.ReadUInt16();
			
			if(count==0){
				
				return null;
				
			}
			
			// Create the offset set:
			int[] offsets=new int[count+1];
			
			// Read the offset size:
			int offsetSize=parser.ReadByte();
			
			// Read each offset:
			for(int i=0;i<=count;i++){
				
				// Read the current offset:
				offsets[i]=parser.ReadOffset(offsetSize);
				
			}
		
			// Grab the object offset, minus one as their not zero based:
			int objectOffset=parser.Position-1;
			
			// Create the glyph set:
			Glyph[] glyphs=new Glyph[offsets.Length-1];
			
			// For each one..
			for(int i=0;i<glyphs.Length;i++){
				
				// Get the (relative) indices:
				int startIndex=offsets[i];
				int length=offsets[i+1]-startIndex;
				
				// Load the glyph now, which starts at startIndex+objectOffset:
				Glyph glyph=cffParser.LoadGlyph(startIndex+objectOffset,length);
				
				// Add to the set:
				glyphs[i]=glyph;
				
			}
			
			// Seek over the table:
			parser.Position=objectOffset+offsets[count];
			
			return glyphs;
			
		}
Beispiel #5
0
        private static Glyph[] LoadIndex(FontParser parser, CffGlyphParser cffParser)
        {
            // Read the index which contains a bunch of char strings.
            // Each charstring is a postscript glyph definition.

            // How many are in here?
            int count = parser.ReadUInt16();

            if (count == 0)
            {
                return(null);
            }

            // Create the offset set:
            int[] offsets = new int[count + 1];

            // Read the offset size:
            int offsetSize = parser.ReadByte();

            // Read each offset:
            for (int i = 0; i <= count; i++)
            {
                // Read the current offset:
                offsets[i] = parser.ReadOffset(offsetSize);
            }

            // Grab the object offset, minus one as their not zero based:
            int objectOffset = parser.Position - 1;

            // Create the glyph set:
            Glyph[] glyphs = new Glyph[offsets.Length - 1];

            // For each one..
            for (int i = 0; i < glyphs.Length; i++)
            {
                // Get the (relative) indices:
                int startIndex = offsets[i];
                int length     = offsets[i + 1] - startIndex;

                // Load the glyph now, which starts at startIndex+objectOffset:
                Glyph glyph = cffParser.LoadGlyph(startIndex + objectOffset, length);

                // Add to the set:
                glyphs[i] = glyph;
            }

            // Seek over the table:
            parser.Position = objectOffset + offsets[count];

            return(glyphs);
        }
Beispiel #6
0
        private static CffSubPosition[] LoadSubIndex(FontParser parser)
        {
            // How many are in here?
            int count = parser.ReadUInt16();

            if (count == 0)
            {
                return(null);
            }

            // Create the offset set:
            int[] offsets = new int[count + 1];

            // Read the offset size:
            int offsetSize = parser.ReadByte();

            // Read each offset:
            for (int i = 0; i <= count; i++)
            {
                // Read the current offset:
                offsets[i] = parser.ReadOffset(offsetSize);
            }

            // Minus one as their not zero based:
            int objectOffset = parser.Position - 1;

            // Seek over the table:
            parser.Position = objectOffset + offsets[count];

            // Create the result set:
            CffSubPosition[] results = new CffSubPosition[offsets.Length - 1];

            // For each one..
            for (int i = 0; i < results.Length; i++)
            {
                // Get the (relative) indices:
                int startIndex = offsets[i];
                int length     = offsets[i + 1] - startIndex;

                // Load the glyph now, which starts at startIndex+objectOffset:
                results[i] = new CffSubPosition(startIndex + objectOffset, length);
            }

            return(results);
        }
Beispiel #7
0
        private static Dictionary <int, List <int> > LoadDict(FontParser parser)
        {
            // How many are in here?
            int count = parser.ReadUInt16();

            if (count == 0)
            {
                return(null);
            }

            // Read the offset size:
            int offsetSize = parser.ReadByte();

            // Grab the position:
            int position = parser.Position;

            // Find where the data starts:
            int objectOffset = position + ((count + 1) * offsetSize) - 1;

            // Read two only:
            int firstOffset  = parser.ReadOffset(offsetSize);
            int secondOffset = parser.ReadOffset(offsetSize);

            // Seek to the location:
            parser.Position = firstOffset + objectOffset;

            // Parse the dictionary now:
            Dictionary <int, List <int> > set = ParseCFFDict(parser, secondOffset - firstOffset);

            // Return:
            parser.Position = position;

            // Skip the rest:
            parser.Position += offsetSize * count;

            // Read the last offset:
            secondOffset = parser.ReadOffset(offsetSize);

            // Seek there, minus one as their not zero based:
            parser.Position += secondOffset - 1;

            return(set);
        }
Beispiel #8
0
        private static void SkipIndex(FontParser parser)
        {
            // How many are in here?
            int count = parser.ReadUInt16();

            if (count > 0)
            {
                // Read the offset size:
                int offsetSize = parser.ReadByte();

                // Skip count offsets:
                parser.Position += offsetSize * count;

                // Read the last offset:
                int lastOffset = parser.ReadOffset(offsetSize);

                // Seek there, minus one as their not zero based:
                parser.Position += lastOffset - 1;
            }
        }
		private static void SkipIndex(FontParser parser){
			
			// How many are in here?
			int count=parser.ReadUInt16();
			
			if(count>0){
				
				// Read the offset size:
				int offsetSize=parser.ReadByte();
				
				// Skip count offsets:
				parser.Position+=offsetSize*count;
				
				// Read the last offset:
				int lastOffset=parser.ReadOffset(offsetSize);
				
				// Seek there, minus one as their not zero based:
				parser.Position+=lastOffset-1;
				
			}
			
		}
Beispiel #10
0
        private static void LoadGlyph(Glyph glyph, int contourCount, FontParser parser, float range)
        {
            // The contour count (tiny set):
            ushort[] endPointIndices = new ushort[contourCount];

            // Load each endpoint:
            for (int i = 0; i < contourCount; i++)
            {
                endPointIndices[i] = parser.ReadUInt16();
            }

            // How big is the instruction block?
            int instructionLength = parser.ReadUInt16();

            // And skip it!
            parser.Position += instructionLength;

            // How many coordinates?
            int numberOfCoordinates = endPointIndices[endPointIndices.Length - 1] + 1;

            // Create the flag set:
            byte[] flags = new byte[numberOfCoordinates];

            // For each one..
            for (int i = 0; i < numberOfCoordinates; i++)
            {
                byte flag = parser.ReadByte();

                flags[i] = flag;

                // If bit 3 is set, we repeat this flag n times, where n is the next byte.
                if ((flag & 8) > 0)
                {
                    int repeatCount = parser.ReadByte();

                    for (int j = 0; j < repeatCount; j += 1)
                    {
                        i++;
                        flags[i] = flag;
                    }
                }
            }

            if (endPointIndices.Length > 0)
            {
                // X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0.
                if (numberOfCoordinates > 0)
                {
                    // Current coord:
                    int coord = 0;

                    // Coord index:
                    int coordIndex = 0;

                    // The coord set:
                    float[] coords = new float[numberOfCoordinates * 2];

                    // Load X coords:
                    for (int i = 0; i < numberOfCoordinates; i++)
                    {
                        byte flag = flags[i];

                        coord = LoadGlyphCoordinate(parser, flag, coord, 2, 16);

                        coords[coordIndex] = (float)coord / range;

                        coordIndex += 2;
                    }

                    // Reset shared vars:
                    coord      = 0;
                    coordIndex = 1;

                    // Load Y coords:
                    for (int i = 0; i < numberOfCoordinates; i++)
                    {
                        byte flag = flags[i];

                        coord = LoadGlyphCoordinate(parser, flag, coord, 4, 32);

                        coords[coordIndex] = (float)coord / range;

                        coordIndex += 2;
                    }

                    int[] orderedEnds = new int[endPointIndices.Length];
                    int   currentEnd  = 0;

                    for (int i = 0; i < numberOfCoordinates; i++)
                    {
                        // Grab the flag:
                        byte flag = flags[i];

                        // On curve flag - Control point otherwise:
                        flag = (byte)(flag & 1);

                        // Last point of the current contour?

                        // For each end point index (tiny set - better than hash):
                        for (int e = endPointIndices.Length - 1; e >= 0; e--)
                        {
                            if (endPointIndices[e] == i)
                            {
                                orderedEnds[currentEnd] = i;

                                currentEnd++;

                                break;
                            }
                        }

                        // Update the flag - it's now just a 1 or 0:
                        flags[i] = flag;
                    }

                    // Reset shared index again:
                    coordIndex = 0;

                    // Create our temp holders of point info:
                    GlyphPoint firstPointRaw   = new GlyphPoint(flags, coords);
                    GlyphPoint lastPointRaw    = new GlyphPoint(flags, coords);
                    GlyphPoint prevPointRaw    = new GlyphPoint(flags, coords);
                    GlyphPoint currentPointRaw = new GlyphPoint(flags, coords);
                    GlyphPoint controlPoint    = new GlyphPoint(flags, coords);

                    // For each contour..
                    for (int i = 0; i < contourCount; i++)
                    {
                        int pointOffset = 0;

                        // Get the indices of the first/last points on this contour.
                        int firstIndex = 0;
                        int lastIndex  = orderedEnds[i];

                        if (i != 0)
                        {
                            firstIndex = orderedEnds[i - 1] + 1;
                        }

                        GlyphPoint firstPoint = firstPointRaw;
                        firstPoint.Set(firstIndex);

                        GlyphPoint lastPoint = lastPointRaw;
                        lastPoint.Set(lastIndex);

                        if (firstPoint.OnCurve)
                        {
                            // No control point:
                            controlPoint.Active = false;

                            // The first point will be consumed by the moveTo command so skip it:
                            pointOffset = 1;
                        }
                        else
                        {
                            if (lastPoint.OnCurve)
                            {
                                // If the first point is off-curve and the last point is on-curve,
                                // start at the last point.
                                firstPoint = lastPoint;
                            }
                            else
                            {
                                // If both first and last points are off-curve, start at their middle.

                                firstPoint.X = (firstPoint.X + lastPoint.X) / 2f;
                                firstPoint.Y = (firstPoint.Y + lastPoint.Y) / 2f;
                            }

                            controlPoint.Set(firstPoint);
                        }

                        glyph.MoveTo(firstPoint.X, firstPoint.Y);

                        int contourStart = firstIndex + pointOffset;

                        for (int j = contourStart; j <= lastIndex; j++)
                        {
                            // Setup the previous point:
                            GlyphPoint prevPoint;

                            if (j == firstIndex)
                            {
                                prevPoint = firstPoint;
                            }
                            else
                            {
                                prevPoint = prevPointRaw;
                                prevPoint.Set(j - 1);
                            }

                            // Setup the current point:
                            GlyphPoint pt = currentPointRaw;
                            pt.Set(j);

                            if (prevPoint.OnCurve && pt.OnCurve)
                            {
                                // Just a line here:
                                glyph.LineTo(pt.X, pt.Y);
                            }
                            else if (prevPoint.OnCurve && !pt.OnCurve)
                            {
                                controlPoint.Set(pt);
                            }
                            else if (!prevPoint.OnCurve && !pt.OnCurve)
                            {
                                float midPointX = (prevPoint.X + pt.X) / 2f;
                                float midPointY = (prevPoint.Y + pt.Y) / 2f;

                                glyph.QuadraticCurveTo(prevPoint.X, prevPoint.Y, midPointX, midPointY);
                                controlPoint.Set(pt);
                            }
                            else if (!prevPoint.OnCurve && pt.OnCurve)
                            {
                                // Previous point off-curve, this point on-curve.
                                glyph.QuadraticCurveTo(controlPoint.X, controlPoint.Y, pt.X, pt.Y);

                                controlPoint.Active = false;
                            }
                        }

                        if (firstPoint != lastPoint)
                        {
                            // Close the path.

                            if (controlPoint.Active)
                            {
                                // Still got a spare control point:
                                glyph.QuadraticCurveTo(controlPoint.X, controlPoint.Y, firstPoint.X, firstPoint.Y);
                            }

                            // Just a normal close:
                            glyph.ClosePath();
                        }
                    }
                }
            }

            if (glyph.Font.WindingUnknown)
            {
                // Find the winding now:
                glyph.Font.FindWinding(glyph);
            }
        }
		private static CffSubPosition[] LoadSubIndex(FontParser parser){
			
			// How many are in here?
			int count=parser.ReadUInt16();
			
			if(count==0){
				
				return null;
				
			}
			
			// Create the offset set:
			int[] offsets=new int[count+1];
			
			// Read the offset size:
			int offsetSize=parser.ReadByte();
			
			// Read each offset:
			for(int i=0;i<=count;i++){
				
				// Read the current offset:
				offsets[i]=parser.ReadOffset(offsetSize);
				
			}
			
			// Minus one as their not zero based:
			int objectOffset=parser.Position-1;
			
			// Seek over the table:
			parser.Position=objectOffset+offsets[count];
		
			// Create the result set:
			CffSubPosition[] results=new CffSubPosition[offsets.Length-1];
			
			// For each one..
			for(int i=0;i<results.Length;i++){
				
				// Get the (relative) indices:
				int startIndex=offsets[i];
				int length=offsets[i+1]-startIndex;
				
				// Load the glyph now, which starts at startIndex+objectOffset:
				results[i]=new CffSubPosition(startIndex+objectOffset,length);
				
			}
		
			return results;
			
		}
Beispiel #12
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;
                }
            }
        }
		public static Dictionary<int,List<int>> ParseCFFDict(FontParser parser,int length){
			
			// Create the results set:
			Dictionary<int,List<int>> results=new Dictionary<int,List<int>>();
			
			// Our first values set:
			List<int> values=new List<int>();
			
			// Note that rather awkwardly the key comes *after* the set of values.
			
			int max=parser.Position+length;
			
			// While there's more data..
			while(parser.Position<max){
				
				// Read the state byte:
				int state=parser.ReadByte();
				
				if(state<22){
					
					if(state==12){
						// 2 byte key code.
						state=1200+parser.ReadByte();
					}
					
					// Push values:
					results[state]=values;
					
					// Clear:
					values=new List<int>();
				
				}else{
					
					// Read the operand:
					int operand=ParseOperand(parser,state);
					
					// Push:
					values.Add(operand);
					
				}
				
			}
			
			return results;
			
		}
Beispiel #14
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);
        }
Beispiel #15
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;
		}
Beispiel #17
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);
        }
		private static void LoadGlyph(Glyph glyph,int contourCount,FontParser parser,float range){
			
			// The contour count (tiny set):
			ushort[] endPointIndices=new ushort[contourCount];
			
			// Load each endpoint:
			for(int i=0;i<contourCount;i++){
				
				endPointIndices[i]=parser.ReadUInt16();
				
			}
			
			// How big is the instruction block?
			int instructionLength=parser.ReadUInt16();
			
			// And skip it!
			parser.Position+=instructionLength;
			
			// How many coordinates?
			int numberOfCoordinates=endPointIndices[endPointIndices.Length-1]+1;
			
			// Create the flag set:
			byte[] flags=new byte[numberOfCoordinates];
			
			// For each one..
			for (int i = 0; i < numberOfCoordinates;i++) {
				
				byte flag=parser.ReadByte();
				
				flags[i]=flag;
				
				// If bit 3 is set, we repeat this flag n times, where n is the next byte.
				if((flag&8)>0){
					int repeatCount = parser.ReadByte();
					
					for (int j = 0; j < repeatCount; j += 1) {
						i++;
						flags[i]=flag;
					}
				}
				
			}
			
			if (endPointIndices.Length > 0) {
				
				// X/Y coordinates are relative to the previous point, except for the first point which is relative to 0,0.
				if (numberOfCoordinates > 0){
					
					// Current coord:
					int coord=0;
					
					// Coord index:
					int coordIndex=0;
					
					// The coord set:
					float[] coords=new float[numberOfCoordinates*2];
					
					// Load X coords:
					for (int i = 0; i < numberOfCoordinates; i++) {
						byte flag = flags[i];
						
						coord = LoadGlyphCoordinate(parser,flag,coord,2,16);
						
						coords[coordIndex]=(float)coord/range;
						
						coordIndex+=2;
						
					}
					
					// Reset shared vars:
					coord=0;
					coordIndex=1;
					
					// Load Y coords:
					for (int i = 0; i < numberOfCoordinates; i++) {
						byte flag = flags[i];
						
						coord = LoadGlyphCoordinate(parser,flag,coord,4,32);
						
						coords[coordIndex]=(float)coord/range;
						
						coordIndex+=2;
						
					}
					
					int[] orderedEnds=new int[endPointIndices.Length];
					int currentEnd=0;
					
					for (int i = 0; i < numberOfCoordinates; i++) {
						
						// Grab the flag:
						byte flag=flags[i];
						
						// On curve flag - Control point otherwise:
						flag=(byte)(flag&1);
						
						// Last point of the current contour?
						
						// For each end point index (tiny set - better than hash):
						for(int e=endPointIndices.Length-1;e>=0;e--){
							
							if(endPointIndices[e]==i){
								
								orderedEnds[currentEnd]=i;
								
								currentEnd++;
								
								break;
							}
							
						}
						
						// Update the flag - it's now just a 1 or 0:
						flags[i]=flag;
						
					}
					
					// Reset shared index again:
					coordIndex=0;
					
					// Create our temp holders of point info:
					GlyphPoint firstPointRaw=new GlyphPoint(flags,coords);
					GlyphPoint lastPointRaw=new GlyphPoint(flags,coords);
					GlyphPoint prevPointRaw=new GlyphPoint(flags,coords);
					GlyphPoint currentPointRaw=new GlyphPoint(flags,coords);
					GlyphPoint controlPoint=new GlyphPoint(flags,coords);
					
					// For each contour..
					for(int i=0;i<contourCount;i++){
						
						int pointOffset=0;
						
						// Get the indices of the first/last points on this contour.
						int firstIndex=0;
						int lastIndex=orderedEnds[i];
						
						if(i!=0){
							firstIndex=orderedEnds[i-1]+1;
						}
						
						GlyphPoint firstPoint=firstPointRaw;
						firstPoint.Set(firstIndex);
						
						GlyphPoint lastPoint=lastPointRaw;
						lastPoint.Set(lastIndex);
						
						if(firstPoint.OnCurve){
							
							// No control point:
							controlPoint.Active=false;
							
							// The first point will be consumed by the moveTo command so skip it:
							pointOffset=1;
							
						}else{
							
							if(lastPoint.OnCurve){
								
								// If the first point is off-curve and the last point is on-curve,
								// start at the last point.
								firstPoint=lastPoint;
								
							}else{
								// If both first and last points are off-curve, start at their middle.
								
								firstPoint.X=(firstPoint.X+lastPoint.X)/2f;
								firstPoint.Y=(firstPoint.Y+lastPoint.Y)/2f;
								
							}
							
							controlPoint.Set(firstPoint);
							
						}
						
						glyph.MoveTo(firstPoint.X,firstPoint.Y);
						
						int contourStart=firstIndex+pointOffset;
						
						for(int j=contourStart;j<=lastIndex;j++){
							
							// Setup the previous point:
							GlyphPoint prevPoint;
							
							if(j==firstIndex){
								prevPoint=firstPoint;
							}else{
								prevPoint=prevPointRaw;
								prevPoint.Set(j-1);
							}
							
							// Setup the current point:
							GlyphPoint pt=currentPointRaw;
							pt.Set(j);
							
							if(prevPoint.OnCurve && pt.OnCurve) {
								
								// Just a line here:
								glyph.LineTo(pt.X,pt.Y);
								
							}else if (prevPoint.OnCurve && !pt.OnCurve){
								
								controlPoint.Set(pt);
								
							}else if(!prevPoint.OnCurve && !pt.OnCurve){
								
								float midPointX=(prevPoint.X+pt.X)/2f;
								float midPointY=(prevPoint.Y+pt.Y)/2f;
								
								glyph.QuadraticCurveTo(prevPoint.X,prevPoint.Y,midPointX,midPointY);
								controlPoint.Set(pt);
								
							}else if(!prevPoint.OnCurve && pt.OnCurve){
								
								// Previous point off-curve, this point on-curve.
								glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,pt.X,pt.Y);
								
								controlPoint.Active=false;
								
							}
							
						}
						
						if(firstPoint!=lastPoint){
							// Close the path.
							
							if(controlPoint.Active){
								
								// Still got a spare control point:
								glyph.QuadraticCurveTo(controlPoint.X,controlPoint.Y,firstPoint.X,firstPoint.Y);
								
							}
							
							// Just a normal close:
							glyph.ClosePath();
							
						}
						
					}
					
				}
				
			}
			
			if(glyph.Font.WindingUnknown){
				// Find the winding now:
				glyph.Font.FindWinding(glyph);
			}
			
		}
		public static 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;
			
		}
		private static Dictionary<int,List<int>> LoadDict(FontParser parser){
			
			// How many are in here?
			int count=parser.ReadUInt16();
			
			if(count==0){
				
				return null;
				
			}
			
			// Read the offset size:
			int offsetSize=parser.ReadByte();
			
			// Grab the position:
			int position=parser.Position;
			
			// Find where the data starts:
			int objectOffset=position+((count+1)*offsetSize)-1;
			
			// Read two only:
			int firstOffset=parser.ReadOffset(offsetSize);
			int secondOffset=parser.ReadOffset(offsetSize);
			
			// Seek to the location:
			parser.Position=firstOffset+objectOffset;
			
			// Parse the dictionary now:
			Dictionary<int,List<int>> set=ParseCFFDict(parser,secondOffset-firstOffset);
			
			// Return:
			parser.Position=position;
			
			// Skip the rest:
			parser.Position+=offsetSize*count;
			
			// Read the last offset:
			secondOffset=parser.ReadOffset(offsetSize);
			
			// Seek there, minus one as their not zero based:
			parser.Position+=secondOffset-1;
			
			return set;
			
		}
Beispiel #23
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);
        }