Exemplo n.º 1
0
        public static void ComposeGlyphs(int glyphIndex, int startPoint, ref Matrix3x2 transform, List<PointF> basePoints, List<int> baseContours, BaseGlyph[] glyphTable)
        {
            var glyph = glyphTable[glyphIndex];
            var simple = glyph as SimpleGlyph;
            if (simple != null)
            {
                foreach (var endpoint in simple.ContourEndpoints)
                    baseContours.Add(endpoint + startPoint);
                foreach (var point in simple.Points)
                    basePoints.Add(new PointF(Vector2.TransformNormal((Vector2)point, transform), point.Type));
            }
            else
            {
                // otherwise, we have a composite glyph
                var composite = (CompositeGlyph)glyph;
                foreach (var subglyph in composite.Subglyphs)
                {
                    // if we have a scale, update the local transform
                    var local = transform;
                    bool haveScale = (subglyph.Flags & (CompositeGlyphFlags.HaveScale | CompositeGlyphFlags.HaveXYScale | CompositeGlyphFlags.HaveTransform)) != 0;
                    if (haveScale)
                        local = transform * subglyph.Transform;

                    // recursively compose the subglyph into our lists
                    int currentPoints = basePoints.Count;
                    ComposeGlyphs(subglyph.Index, currentPoints, ref local, basePoints, baseContours, glyphTable);

                    // calculate the offset for the subglyph. we have to do offsetting after composing all subglyphs,
                    // because we might need to find the offset based on previously composed points by index
                    Vector2 offset;
                    if ((subglyph.Flags & CompositeGlyphFlags.ArgsAreXYValues) != 0)
                    {
                        offset = (Vector2)new Point((FUnit)subglyph.Arg1, (FUnit)subglyph.Arg2);
                        if (haveScale && (subglyph.Flags & CompositeGlyphFlags.ScaledComponentOffset) != 0)
                            offset = Vector2.TransformNormal(offset, local);
                        else
                            offset = Vector2.TransformNormal(offset, transform);

                        // if the RoundXYToGrid flag is set, round the offset components
                        if ((subglyph.Flags & CompositeGlyphFlags.RoundXYToGrid) != 0)
                            offset = new Vector2((float)Math.Round(offset.X), (float)Math.Round(offset.Y));
                    }
                    else
                    {
                        // if the offsets are not given in FUnits, then they are point indices
                        // in the currently composed base glyph that we should match up
                        var p1 = basePoints[(int)((uint)subglyph.Arg1 + startPoint)];
                        var p2 = basePoints[(int)((uint)subglyph.Arg2 + currentPoints)];
                        offset = p1.P - p2.P;
                    }

                    // translate all child points
                    if (offset != Vector2.Zero)
                    {
                        for (int i = currentPoints; i < basePoints.Count; i++)
                            basePoints[i] = basePoints[i].Offset(offset);
                    }
                }
            }
        }
Exemplo n.º 2
0
        public static void ReadGlyph(
            DataReader reader, int glyphIndex, int recursionDepth,
            BaseGlyph[] glyphTable, uint glyfOffset, uint glyfLength, uint* loca
        )
        {
            // check if this glyph has already been loaded; this can happen
            // if we're recursively loading subglyphs as part of a composite
            if (glyphTable[glyphIndex] != null)
                return;

            // prevent bad font data from causing infinite recursion
            if (recursionDepth > MaxRecursion)
                throw new InvalidFontException("Bad font data; infinite composite recursion.");

            // check if this glyph doesn't have any actual data
            GlyphHeader header;
            var offset = loca[glyphIndex];
            if ((glyphIndex < glyphTable.Length - 1 && offset == loca[glyphIndex + 1]) || offset >= glyfLength)
            {
                // this is an empty glyph, so synthesize a header
                header = default(GlyphHeader);
            }
            else
            {
                // seek to the right spot and load the header
                reader.Seek(glyfOffset + loca[glyphIndex]);
                header = new GlyphHeader
                {
                    ContourCount = reader.ReadInt16BE(),
                    MinX = reader.ReadInt16BE(),
                    MinY = reader.ReadInt16BE(),
                    MaxX = reader.ReadInt16BE(),
                    MaxY = reader.ReadInt16BE()
                };

                if (header.ContourCount < -1 || header.ContourCount > MaxContours)
                    throw new InvalidFontException("Invalid number of contours for glyph.");
            }

            if (header.ContourCount > 0)
            {
                // positive contours means a simple glyph
                glyphTable[glyphIndex] = ReadSimpleGlyph(reader, header.ContourCount);
            }
            else if (header.ContourCount == -1)
            {
                // -1 means composite glyph
                var composite = ReadCompositeGlyph(reader);
                var subglyphs = composite.Subglyphs;

                // read each subglyph recrusively
                for (int i = 0; i < subglyphs.Length; i++)
                    ReadGlyph(reader, subglyphs[i].Index, recursionDepth + 1, glyphTable, glyfOffset, glyfLength, loca);

                glyphTable[glyphIndex] = composite;
            }
            else
            {
                // no data, so synthesize an empty glyph
                glyphTable[glyphIndex] = new SimpleGlyph
                {
                    Points = new Point[0],
                    ContourEndpoints = new int[0]
                };
            }

            // save bounding box
            var glyph = glyphTable[glyphIndex];
            glyph.MinX = header.MinX;
            glyph.MinY = header.MinY;
            glyph.MaxX = header.MaxX;
            glyph.MaxY = header.MaxY;
        }