Ejemplo n.º 1
0
        private byte[] BuildHmtxTable()
        {
            MemoryStream bos = new MemoryStream();

            HorizontalHeaderTable  h  = ttf.HorizontalHeader;
            HorizontalMetricsTable hm = ttf.HorizontalMetrics;

            Bytes.Buffer input = ttf.OriginalData;

            // more info: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hmtx.html
            int lastgid = h.NumberOfHMetrics - 1;
            // true if lastgid input not in the set: we'll need its width (but not its left side bearing) later
            bool needLastGidWidth = false;

            if (glyphIds.LastOrDefault() > lastgid && !glyphIds.Contains(lastgid))
            {
                needLastGidWidth = true;
            }

            try
            {
                long isResult = input.Skip(hm.Offset);

                if (isResult.CompareTo(hm.Offset) != 0)
                {
                    Debug.WriteLine($"debug: Tried skipping {hm.Offset} bytes but only {isResult} bytes skipped");
                }

                long lastOffset = 0;
                foreach (int glyphId in glyphIds)
                {
                    // offset in original file
                    long offset;
                    if (glyphId <= lastgid)
                    {
                        // copy width and lsb
                        offset     = glyphId * 4L;
                        lastOffset = CopyBytes(input, bos, offset, lastOffset, 4);
                    }
                    else
                    {
                        if (needLastGidWidth)
                        {
                            // one time only: copy width from lastgid, whose width applies
                            // to all later glyphs
                            needLastGidWidth = false;
                            offset           = lastgid * 4L;
                            lastOffset       = CopyBytes(input, bos, offset, lastOffset, 2);

                            // then go on with lsb from actual glyph (lsb are individual even in monotype fonts)
                        }

                        // copy lsb only, as we are beyond numOfHMetrics
                        offset     = h.NumberOfHMetrics * 4L + (glyphId - h.NumberOfHMetrics) * 2L;
                        lastOffset = CopyBytes(input, bos, offset, lastOffset, 2);
                    }
                }

                return(bos.ToArray());
            }
            finally
            {
                input.Dispose();
            }
        }
Ejemplo n.º 2
0
        /**
         * Resolve compound glyph references.
         */
        private void AddCompoundReferences()
        {
            if (hasAddedCompoundReferences)
            {
                return;
            }
            hasAddedCompoundReferences = true;

            bool hasNested;

            do
            {
                GlyphTable   g             = ttf.Glyph;
                long[]       offsets       = ttf.IndexToLocation.Offsets;
                Bytes.Buffer input         = ttf.OriginalData;
                ISet <int>   glyphIdsToAdd = null;
                try
                {
                    long isResult = input.Skip(g.Offset);

                    if (isResult.CompareTo(g.Offset) != 0)
                    {
                        Debug.WriteLine($"debug: Tried skipping {g.Offset} bytes but skipped only {isResult} bytes");
                    }

                    long lastOff = 0L;
                    foreach (int glyphId in glyphIds)
                    {
                        long offset = offsets[glyphId];
                        long len    = offsets[glyphId + 1] - offset;
                        isResult = input.Skip(offset - lastOff);

                        if (isResult.CompareTo(offset - lastOff) != 0)
                        {
                            Debug.WriteLine($"debug: Tried skipping {(offset - lastOff)} bytes but skipped only {isResult} bytes");
                        }

                        sbyte[] buf = new sbyte[(int)len];
                        isResult = input.Read(buf);

                        if (isResult.CompareTo(len) != 0)
                        {
                            Debug.WriteLine($"debug: Tried reading {len} bytes but only {isResult} bytes read");
                        }

                        // rewrite glyphIds for compound glyphs
                        if (buf.Length >= 2 && buf[0] == -1 && buf[1] == -1)
                        {
                            int off = 2 * 5;
                            int flags;
                            do
                            {
                                flags = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff;
                                off  += 2;
                                int ogid = (buf[off] & 0xff) << 8 | buf[off + 1] & 0xff;
                                if (!glyphIds.Contains(ogid))
                                {
                                    if (glyphIdsToAdd == null)
                                    {
                                        glyphIdsToAdd = new HashSet <int>();
                                    }
                                    glyphIdsToAdd.Add(ogid);
                                }
                                off += 2;
                                // ARG_1_AND_2_ARE_WORDS
                                if ((flags & 1 << 0) != 0)
                                {
                                    off += 2 * 2;
                                }
                                else
                                {
                                    off += 2;
                                }
                                // WE_HAVE_A_TWO_BY_TWO
                                if ((flags & 1 << 7) != 0)
                                {
                                    off += 2 * 4;
                                }
                                // WE_HAVE_AN_X_AND_Y_SCALE
                                else if ((flags & 1 << 6) != 0)
                                {
                                    off += 2 * 2;
                                }
                                // WE_HAVE_A_SCALE
                                else if ((flags & 1 << 3) != 0)
                                {
                                    off += 2;
                                }
                            }while ((flags & 1 << 5) != 0); // MORE_COMPONENTS
                        }
                        lastOff = offsets[glyphId + 1];
                    }
                }
                finally
                {
                    input.Dispose();
                }
                if (glyphIdsToAdd != null)
                {
                    glyphIds.AddAll(glyphIdsToAdd);
                }
                hasNested = glyphIdsToAdd != null;
            }while (hasNested);
        }