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);
			}
			
		}
Beispiel #2
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;
                }
            }
        }
Beispiel #3
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);
            }
        }