Example #1
0
            // generate a new table from the cached data

            public override OTTable GenerateTable()
            {
                // create a Motorola Byte Order buffer for the new table

                MBOBuffer newbuf = new MBOBuffer(54);


                // populate the buffer

                newbuf.SetFixed(m_TableVersion, (uint)Table_head.FieldOffsets.TableVersionNumber);
                newbuf.SetFixed(m_fontRevision, (uint)Table_head.FieldOffsets.fontRevision);
                newbuf.SetUint(m_checkSumAdjustment, (uint)Table_head.FieldOffsets.checkSumAdjustment);
                newbuf.SetUint(m_magicNumber, (uint)Table_head.FieldOffsets.magicNumber);
                newbuf.SetUshort(m_flags, (uint)Table_head.FieldOffsets.flags);
                newbuf.SetUshort(m_unitsPerEm, (uint)Table_head.FieldOffsets.unitsPerEm);
                newbuf.SetLong(m_created, (uint)Table_head.FieldOffsets.created);
                newbuf.SetLong(m_modified, (uint)Table_head.FieldOffsets.modified);
                newbuf.SetShort(m_xMin, (uint)Table_head.FieldOffsets.xMin);
                newbuf.SetShort(m_yMin, (uint)Table_head.FieldOffsets.yMin);
                newbuf.SetShort(m_xMax, (uint)Table_head.FieldOffsets.xMax);
                newbuf.SetShort(m_yMax, (uint)Table_head.FieldOffsets.yMax);
                newbuf.SetUshort(m_macStyle, (uint)Table_head.FieldOffsets.macStyle);
                newbuf.SetUshort(m_lowestRecPPEM, (uint)Table_head.FieldOffsets.lowestRecPPEM);
                newbuf.SetShort(m_fontDirectionHint, (uint)Table_head.FieldOffsets.fontDirectionHint);
                newbuf.SetShort(m_indexToLocFormat, (uint)Table_head.FieldOffsets.indexToLocFormat);
                newbuf.SetShort(m_glyphDataFormat, (uint)Table_head.FieldOffsets.glyphDataFormat);


                // put the buffer into a Table_head object and return it

                Table_head headTable = new Table_head("head", newbuf);

                return(headTable);
            }
Example #2
0
 protected int Format(OTFont fontOwner)
 {
     // sets format without validating it
     if (this.m_format == Table_loca.ValueInvalid)
     {
         Table_head headTable = (Table_head)fontOwner.GetTable("head");
         if (headTable != null)
         {
             this.m_format = headTable.indexToLocFormat;
         }
     }
     return(this.m_format);
 }
Example #3
0
        /// <summary>Get modified date from "name" table, or <c>1/1/1904</c> if
        /// no "name" table yet.</summary>
        public DateTime GetFontModifiedDate()
        {
            // default to Jan 1, 1904 if unavailable
            DateTime dt = new DateTime(1904, 1, 1);

            try
            {
                Table_head headTable = (Table_head)GetTable("head");
                if (headTable != null)
                {
                    dt = headTable.GetModifiedDateTime();
                }
            }
            catch
            {
            }

            return(dt);
        }
Example #4
0
            // constructor

            public head_cache(Table_head OwnerTable)
            {
                // copy the data from the owner table's MBOBuffer
                // and store it in the cache variables
                m_TableVersion       = OwnerTable.TableVersionNumber;
                m_fontRevision       = OwnerTable.fontRevision;
                m_checkSumAdjustment = OwnerTable.checkSumAdjustment;
                m_magicNumber        = OwnerTable.magicNumber;
                m_flags             = OwnerTable.flags;
                m_unitsPerEm        = OwnerTable.unitsPerEm;
                m_created           = OwnerTable.created;
                m_modified          = OwnerTable.modified;
                m_xMin              = OwnerTable.xMin;
                m_yMin              = OwnerTable.yMin;
                m_xMax              = OwnerTable.xMax;
                m_yMax              = OwnerTable.yMax;
                m_macStyle          = OwnerTable.macStyle;
                m_lowestRecPPEM     = OwnerTable.lowestRecPPEM;
                m_fontDirectionHint = OwnerTable.fontDirectionHint;
                m_indexToLocFormat  = OwnerTable.indexToLocFormat;
                m_glyphDataFormat   = OwnerTable.glyphDataFormat;
            }
Example #5
0
        public virtual OTTable CreateTableObject(OTTag tag, MBOBuffer buf)
        {
            OTTable table = null;

            string sName = GetUnaliasedTableName(tag);

            switch (sName)
            {
            case "BASE": table = new Table_BASE(tag, buf); break;

            case "CFF ": table = new Table_CFF(tag, buf); break;

            case "cmap": table = new Table_cmap(tag, buf); break;

            case "cvt ": table = new Table_cvt(tag, buf); break;

            case "DSIG": table = new Table_DSIG(tag, buf); break;

            case "EBDT": table = new Table_EBDT(tag, buf); break;

            case "EBLC": table = new Table_EBLC(tag, buf); break;

            case "EBSC": table = new Table_EBSC(tag, buf); break;

            case "fpgm": table = new Table_fpgm(tag, buf); break;

            case "gasp": table = new Table_gasp(tag, buf); break;

            case "GDEF": table = new Table_GDEF(tag, buf); break;

            case "glyf": table = new Table_glyf(tag, buf); break;

            case "GPOS": table = new Table_GPOS(tag, buf); break;

            case "GSUB": table = new Table_GSUB(tag, buf); break;

            case "hdmx": table = new Table_hdmx(tag, buf); break;

            case "head": table = new Table_head(tag, buf); break;

            case "hhea": table = new Table_hhea(tag, buf); break;

            case "hmtx": table = new Table_hmtx(tag, buf); break;

            case "JSTF": table = new Table_JSTF(tag, buf); break;

            case "kern": table = new Table_kern(tag, buf); break;

            case "loca": table = new Table_loca(tag, buf); break;

            case "LTSH": table = new Table_LTSH(tag, buf); break;

            case "maxp": table = new Table_maxp(tag, buf); break;

            case "name": table = new Table_name(tag, buf); break;

            case "OS/2": table = new Table_OS2(tag, buf); break;

            case "PCLT": table = new Table_PCLT(tag, buf); break;

            case "post": table = new Table_post(tag, buf); break;

            case "prep": table = new Table_prep(tag, buf); break;

            case "VDMX": table = new Table_VDMX(tag, buf); break;

            case "vhea": table = new Table_vhea(tag, buf); break;

            case "vmtx": table = new Table_vmtx(tag, buf); break;

            case "VORG": table = new Table_VORG(tag, buf); break;

            //case "Zapf": table = new Table_Zapf(tag, buf); break;
            default: table = new Table__Unknown(tag, buf); break;
            }

            return(table);
        }
Example #6
0
        public virtual OTTable CreateTableObject(OTTag tag, MBOBuffer buf)
        {
            OTTable table = null;

            string sName = GetUnaliasedTableName(tag);

            switch (sName)
            {
                case "BASE": table = new Table_BASE(tag, buf); break;
                case "CFF ": table = new Table_CFF(tag, buf); break;
                case "cmap": table = new Table_cmap(tag, buf); break;
                case "cvt ": table = new Table_cvt(tag, buf); break;
                case "DSIG": table = new Table_DSIG(tag, buf); break;
                case "EBDT": table = new Table_EBDT(tag, buf); break;
                case "EBLC": table = new Table_EBLC(tag, buf); break;
                case "EBSC": table = new Table_EBSC(tag, buf); break;
                case "fpgm": table = new Table_fpgm(tag, buf); break;
                case "gasp": table = new Table_gasp(tag, buf); break;
                case "GDEF": table = new Table_GDEF(tag, buf); break;
                case "glyf": table = new Table_glyf(tag, buf); break;
                case "GPOS": table = new Table_GPOS(tag, buf); break;
                case "GSUB": table = new Table_GSUB(tag, buf); break;
                case "hdmx": table = new Table_hdmx(tag, buf); break;
                case "head": table = new Table_head(tag, buf); break;
                case "hhea": table = new Table_hhea(tag, buf); break;
                case "hmtx": table = new Table_hmtx(tag, buf); break;
                case "JSTF": table = new Table_JSTF(tag, buf); break;
                case "kern": table = new Table_kern(tag, buf); break;
                case "loca": table = new Table_loca(tag, buf); break;
                case "LTSH": table = new Table_LTSH(tag, buf); break;
                case "maxp": table = new Table_maxp(tag, buf); break;
                case "name": table = new Table_name(tag, buf); break;
                case "OS/2": table = new Table_OS2(tag, buf); break;
                case "PCLT": table = new Table_PCLT(tag, buf); break;
                case "post": table = new Table_post(tag, buf); break;
                case "prep": table = new Table_prep(tag, buf); break;
                case "VDMX": table = new Table_VDMX(tag, buf); break;
                case "vhea": table = new Table_vhea(tag, buf); break;
                case "vmtx": table = new Table_vmtx(tag, buf); break;
                case "VORG": table = new Table_VORG(tag, buf); break;
                //case "Zapf": table = new Table_Zapf(tag, buf); break;
                default: table = new Table__Unknown(tag, buf); break;
            }

            return table;
        }
Example #7
0
        /// <summary>Write a TTC (TT Collection) to a disk file.</summary>
        public static bool WriteTTCFile(FileStream fs, OTFont[] fonts)
        {
            bool bRet = true;


            // build the TTC header

            OTTag TTCtag         = (OTTag)"ttcf";
            uint  version        = 0x00020000;
            uint  DirectoryCount = (uint)fonts.Length;

            uint [] TableDirectory = new uint[fonts.Length];
            uint    ulDsigTag      = 0;
            uint    ulDsigLength   = 0;
            uint    ulDsigOffset   = 0;

            uint TTCHeaderLen = 12 + DirectoryCount * 4 + 12; // length of version 2.0 header


            // build an array of offset tables
            OffsetTable[] otArr = new OffsetTable[fonts.Length];
            for (int iFont = 0; iFont < fonts.Length; iFont++)
            {
                otArr[iFont] = new OffsetTable(new OTFixed(1, 0), fonts[iFont].GetNumTables());
            }

            // build an array of head tables that will contain the updated modified field and font checksum
            Table_head[] arrHeadTables = new Table_head[fonts.Length];
            for (int i = 0; i < fonts.Length; i++)
            {
                // get the cache
                Table_head            headTable = (Table_head)fonts[i].GetTable("head");
                Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                // set the 'modified' field to the current date
                DateTime dt = DateTime.Now;
                headCache.modified = headTable.DateTimeToSecondsSince1904(dt);

                // generate a new table and add it to the array
                Table_head newHead = (Table_head)headCache.GenerateTable();
                arrHeadTables[i] = newHead;
            }



            // build a list of directory entries for each font

            long FilePos = TTCHeaderLen;

            for (int iFont = 0; iFont < fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();
                TableDirectory[iFont] = (uint)FilePos;
                FilePos += 12 + numTables * 16;

                uint PrevFilePos = 0;
                for (ushort i = 0; i < numTables; i++)
                {
                    OTTable table = fonts[iFont].GetTable(i);
                    OTTag   tag   = table.m_tag;

                    if ((string)tag == "head")
                    {
                        table = arrHeadTables[iFont];
                    }

                    // check if this table is a duplicate of a table in a previous font

                    PrevFilePos = 0;
                    if (iFont > 0)
                    {
                        for (int iPrevFont = 0; iPrevFont < iFont; iPrevFont++)
                        {
                            for (int iTable = 0; iTable < fonts[iPrevFont].GetNumTables(); iTable++)
                            {
                                OTTable PrevTable = fonts[iPrevFont].GetTable(table.m_tag);
                                if (PrevTable != null)
                                {
                                    if (MBOBuffer.BinaryEqual(table.m_bufTable, PrevTable.m_bufTable))
                                    {
                                        // get the file position for the previous table
                                        for (int iDe = 0; iDe < otArr[iPrevFont].DirectoryEntries.Count; iDe++)
                                        {
                                            DirectoryEntry dePrev = (DirectoryEntry)otArr[iPrevFont].DirectoryEntries[iDe];
                                            if (dePrev.tag == table.m_tag)
                                            {
                                                PrevFilePos = dePrev.offset;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }


                    // build a new directory entry

                    DirectoryEntry de = new DirectoryEntry();
                    de.tag      = new OTTag(tag.GetBytes());
                    de.checkSum = table.CalcChecksum();
                    de.length   = table.GetLength();
                    if (PrevFilePos != 0)
                    {
                        de.offset = (uint)PrevFilePos;
                    }
                    else
                    {
                        de.offset = (uint)FilePos;
                        FilePos  += table.GetBuffer().GetPaddedLength();
                    }

                    otArr[iFont].DirectoryEntries.Add(de);
                }


                // sort the directory entries

                if (numTables > 1)
                {
                    for (int i = 0; i < numTables - 1; i++)
                    {
                        for (int j = i + 1; j < numTables; j++)
                        {
                            if (((DirectoryEntry)otArr[iFont].DirectoryEntries[i]).tag > ((DirectoryEntry)otArr[iFont].DirectoryEntries[j]).tag)
                            {
                                DirectoryEntry temp = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                                otArr[iFont].DirectoryEntries[i] = (DirectoryEntry)otArr[iFont].DirectoryEntries[j];
                                otArr[iFont].DirectoryEntries[j] = temp;
                            }
                        }
                    }
                }
            }


            // update each font's checksum in the head table

            for (int iFont = 0; iFont < fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();

                // calculate the checksum
                uint sum = 0;
                sum += otArr[iFont].CalcOffsetTableChecksum();
                sum += otArr[iFont].CalcDirectoryEntriesChecksum();
                for (ushort i = 0; i < numTables; i++)
                {
                    DirectoryEntry de    = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    OTTable        table = fonts[iFont].GetTable(de.tag);
                    if ((string)de.tag == "head")
                    {
                        table = arrHeadTables[iFont];
                    }
                    sum += table.CalcChecksum();
                }

                // get the cache
                Table_head            headTable = arrHeadTables[iFont];
                Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                // set the checkSumAdujustment field
                headCache.checkSumAdjustment = 0xb1b0afba - sum;

                // generate a new table and replace the head table in the array of head tables
                Table_head newHead = (Table_head)headCache.GenerateTable();
                arrHeadTables[iFont] = newHead;
            }



            // write the TTC header

            WriteUint32MBO(fs, (uint)TTCtag);
            WriteUint32MBO(fs, version);
            WriteUint32MBO(fs, DirectoryCount);
            for (int i = 0; i < fonts.Length; i++)
            {
                WriteUint32MBO(fs, TableDirectory[i]);
            }
            WriteUint32MBO(fs, ulDsigTag);
            WriteUint32MBO(fs, ulDsigLength);
            WriteUint32MBO(fs, ulDsigOffset);


            // write out each font

            for (int iFont = 0; iFont < fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();

                // write the offset table

                fs.Write(otArr[iFont].m_buf.GetBuffer(), 0, (int)otArr[iFont].m_buf.GetLength());


                // write the directory entries

                for (int i = 0; i < numTables; i++)
                {
                    DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    fs.Write(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength());
                }


                // write out each table unless a shared version has been written

                for (ushort i = 0; i < numTables; i++)
                {
                    DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    if (fs.Position == de.offset)
                    {
                        OTTable table = fonts[iFont].GetTable(de.tag);
                        if ((string)table.m_tag == "head")
                        {
                            table = arrHeadTables[iFont];
                        }
                        fs.Write(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength());
                    }
                }
            }


            return(bRet);
        }
Example #8
0
        /// <summary>Write a single OTF to a disk file, with tables in
        /// proper order, checksums set, etc.
        /// </summary>
        public static bool WriteSfntFile(FileStream fs, OTFont font)
        {
            bool bRet = true;


            OTFixed     sfntVersion = new OTFixed(1, 0);
            ushort      numTables   = font.GetNumTables();
            OffsetTable ot          = new OffsetTable(sfntVersion, numTables);


            // order tables in fastfont order

            string [] arrOrderedNames = null;
            string [] ttNames         =
            {
                "head", "hhea", "maxp", "OS/2", "hmtx", "LTSH", "VDMX", "hdmx", "cmap", "fpgm",
                "prep", "cvt ", "loca", "glyf", "kern", "name", "post", "gasp", "PCLT"
            };
            string [] psNames =
            {
                "head", "hhea", "maxp", "OS/2", "name", "cmap", "post", "CFF "
            };

            if (font.ContainsTrueTypeOutlines())
            {
                arrOrderedNames = ttNames;
            }
            else if (font.ContainsPostScriptOutlines())
            {
                arrOrderedNames = psNames;
            }

            OTTable[] OrderedTables = new OTTable[numTables];
            for (ushort i = 0; i < numTables; i++)
            {
                OrderedTables[i] = font.GetTable(i);
            }

            if (arrOrderedNames != null)
            {
                ushort curpos = 0;
                for (int iName = 0; iName < arrOrderedNames.Length; iName++)
                {
                    for (ushort i = curpos; i < numTables; i++)
                    {
                        if (arrOrderedNames[iName] == (string)OrderedTables[i].m_tag)
                        {
                            OTTable temp = OrderedTables[curpos];
                            OrderedTables[curpos] = OrderedTables[i];
                            OrderedTables[i]      = temp;
                            curpos++;
                            break;
                        }
                    }
                }
            }


            // update the modified date in the head table

            for (int i = 0; i < OrderedTables.Length; i++)
            {
                if ((string)OrderedTables[i].m_tag == "head")
                {
                    // get the cache
                    Table_head            headTable = (Table_head)OrderedTables[i];
                    Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                    // set the 'modified' field to the current date and time
                    DateTime dt = DateTime.Now;
                    headCache.modified = headTable.DateTimeToSecondsSince1904(dt);

                    // generate a new table and replace the head table in the list of ordered tables
                    Table_head newHead = (Table_head)headCache.GenerateTable();
                    OrderedTables[i] = newHead;

                    break;
                }
            }


            // build a list of directory entries

            long TableFilePos = 12 + numTables * 16;

            for (ushort i = 0; i < numTables; i++)
            {
                OTTable table = OrderedTables[i];
                OTTag   tag   = table.m_tag;

                // build a new directory entry
                DirectoryEntry de = new DirectoryEntry();
                de.tag      = new OTTag(tag.GetBytes());
                de.checkSum = table.CalcChecksum();
                de.offset   = (uint)TableFilePos;
                de.length   = table.GetLength();

                ot.DirectoryEntries.Add(de);

                TableFilePos += table.GetBuffer().GetPaddedLength();
            }


            // sort the directory entries

            if (numTables > 1)
            {
                for (int i = 0; i < numTables - 1; i++)
                {
                    for (int j = i + 1; j < numTables; j++)
                    {
                        if (((DirectoryEntry)(ot.DirectoryEntries[i])).tag > ((DirectoryEntry)(ot.DirectoryEntries[j])).tag)
                        {
                            DirectoryEntry temp = (DirectoryEntry)ot.DirectoryEntries[i];
                            ot.DirectoryEntries[i] = (DirectoryEntry)ot.DirectoryEntries[j];
                            ot.DirectoryEntries[j] = temp;
                        }
                    }
                }
            }


            // update the font checksum in the head table

            for (int i = 0; i < OrderedTables.Length; i++)
            {
                if ((string)OrderedTables[i].m_tag == "head")
                {
                    // calculate the checksum
                    uint sum = 0;
                    sum += ot.CalcOffsetTableChecksum();
                    sum += ot.CalcDirectoryEntriesChecksum();
                    for (int j = 0; j < OrderedTables.Length; j++)
                    {
                        sum += OrderedTables[j].CalcChecksum();
                    }

                    // get the cache
                    Table_head            headTable = (Table_head)OrderedTables[i];
                    Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                    // set the checkSumAdujustment field
                    headCache.checkSumAdjustment = 0xb1b0afba - sum;

                    // generate a new table and replace the head table in the list of ordered tables
                    Table_head newHead = (Table_head)headCache.GenerateTable();
                    OrderedTables[i] = newHead;

                    break;
                }
            }


            // write the offset table

            fs.Write(ot.m_buf.GetBuffer(), 0, (int)ot.m_buf.GetLength());


            // write the directory entries

            for (int i = 0; i < numTables; i++)
            {
                DirectoryEntry de = (DirectoryEntry)ot.DirectoryEntries[i];
                fs.Write(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength());
            }


            // write the tables

            for (ushort i = 0; i < numTables; i++)
            {
                OTTable table = OrderedTables[i];

                fs.Write(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength());
            }


            return(bRet);
        }
Example #9
0
            // generate a new table from the cached data

            public override OTTable GenerateTable()
            {
                // create a Motorola Byte Order buffer for the new table

                MBOBuffer newbuf = new MBOBuffer(54);


                // populate the buffer
                
                newbuf.SetFixed (m_TableVersion,       (uint)Table_head.FieldOffsets.TableVersionNumber);
                newbuf.SetFixed (m_fontRevision,       (uint)Table_head.FieldOffsets.fontRevision);
                newbuf.SetUint  (m_checkSumAdjustment, (uint)Table_head.FieldOffsets.checkSumAdjustment);
                newbuf.SetUint  (m_magicNumber,        (uint)Table_head.FieldOffsets.magicNumber);
                newbuf.SetUshort(m_flags,              (uint)Table_head.FieldOffsets.flags);
                newbuf.SetUshort(m_unitsPerEm,         (uint)Table_head.FieldOffsets.unitsPerEm);
                newbuf.SetLong  (m_created,            (uint)Table_head.FieldOffsets.created);
                newbuf.SetLong  (m_modified,           (uint)Table_head.FieldOffsets.modified);
                newbuf.SetShort (m_xMin,               (uint)Table_head.FieldOffsets.xMin);
                newbuf.SetShort (m_yMin,               (uint)Table_head.FieldOffsets.yMin);
                newbuf.SetShort (m_xMax,               (uint)Table_head.FieldOffsets.xMax);
                newbuf.SetShort (m_yMax,               (uint)Table_head.FieldOffsets.yMax);
                newbuf.SetUshort(m_macStyle,           (uint)Table_head.FieldOffsets.macStyle);
                newbuf.SetUshort(m_lowestRecPPEM,      (uint)Table_head.FieldOffsets.lowestRecPPEM);
                newbuf.SetShort (m_fontDirectionHint,  (uint)Table_head.FieldOffsets.fontDirectionHint);
                newbuf.SetShort (m_indexToLocFormat,   (uint)Table_head.FieldOffsets.indexToLocFormat);
                newbuf.SetShort (m_glyphDataFormat,    (uint)Table_head.FieldOffsets.glyphDataFormat);


                // put the buffer into a Table_head object and return it

                Table_head headTable = new Table_head("head", newbuf);

                return headTable;
            }
Example #10
0
            // constructor

            public head_cache(Table_head OwnerTable)
            {
                // copy the data from the owner table's MBOBuffer
                // and store it in the cache variables
                m_TableVersion       = OwnerTable.TableVersionNumber;
                m_fontRevision       = OwnerTable.fontRevision;
                m_checkSumAdjustment = OwnerTable.checkSumAdjustment;
                m_magicNumber        = OwnerTable.magicNumber;
                m_flags              = OwnerTable.flags;
                m_unitsPerEm         = OwnerTable.unitsPerEm;
                m_created            = OwnerTable.created;
                m_modified           = OwnerTable.modified;
                m_xMin               = OwnerTable.xMin;
                m_yMin               = OwnerTable.yMin;
                m_xMax               = OwnerTable.xMax;
                m_yMax               = OwnerTable.yMax;
                m_macStyle           = OwnerTable.macStyle;
                m_lowestRecPPEM      = OwnerTable.lowestRecPPEM;
                m_fontDirectionHint  = OwnerTable.fontDirectionHint;
                m_indexToLocFormat   = OwnerTable.indexToLocFormat;
                m_glyphDataFormat    = OwnerTable.glyphDataFormat;
            }
Example #11
0
        /// <summary>Write a TTC (TT Collection) to a disk file.</summary>
        public static bool WriteTTCFile(FileStream fs, OTFont[] fonts)
        {
            bool bRet = true;

            // build the TTC header

            OTTag TTCtag = (OTTag)"ttcf";
            uint version = 0x00020000;
            uint DirectoryCount = (uint)fonts.Length;
            uint [] TableDirectory = new uint[fonts.Length];
            uint ulDsigTag    = 0;
            uint ulDsigLength = 0;
            uint ulDsigOffset = 0;

            uint TTCHeaderLen = 12 + DirectoryCount * 4 + 12; // length of version 2.0 header

            // build an array of offset tables
            OffsetTable[] otArr = new OffsetTable[fonts.Length];
            for (int iFont=0; iFont<fonts.Length; iFont++)
            {
                otArr[iFont] = new OffsetTable(new OTFixed(1,0), fonts[iFont].GetNumTables());
            }

            // build an array of head tables that will contain the updated modified field and font checksum
            Table_head[] arrHeadTables = new Table_head[fonts.Length];
            for (int i=0; i<fonts.Length; i++)
            {
                // get the cache
                Table_head headTable = (Table_head)fonts[i].GetTable("head");
                Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                // set the 'modified' field to the current date
                DateTime dt = DateTime.Now;
                headCache.modified = headTable.DateTimeToSecondsSince1904(dt);

                // generate a new table and add it to the array
                Table_head newHead = (Table_head)headCache.GenerateTable();
                arrHeadTables[i] = newHead;
            }

            // build a list of directory entries for each font

            long FilePos = TTCHeaderLen;

            for (int iFont = 0; iFont<fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();
                TableDirectory[iFont] = (uint)FilePos;
                FilePos += 12 + numTables*16;

                uint PrevFilePos = 0;
                for (ushort i=0; i<numTables; i++)
                {
                    OTTable table = fonts[iFont].GetTable(i);
                    OTTag tag = table.m_tag;

                    if ((string)tag == "head")
                    {
                        table = arrHeadTables[iFont];
                    }

                    // check if this table is a duplicate of a table in a previous font

                    PrevFilePos = 0;
                    if (iFont > 0)
                    {
                        for (int iPrevFont=0; iPrevFont<iFont; iPrevFont++)
                        {
                            for (int iTable=0; iTable<fonts[iPrevFont].GetNumTables(); iTable++)
                            {
                                OTTable PrevTable = fonts[iPrevFont].GetTable(table.m_tag);
                                if (PrevTable != null)
                                {
                                    if (MBOBuffer.BinaryEqual(table.m_bufTable, PrevTable.m_bufTable))
                                    {
                                        // get the file position for the previous table
                                        for (int iDe=0; iDe<otArr[iPrevFont].DirectoryEntries.Count; iDe++)
                                        {
                                            DirectoryEntry dePrev = (DirectoryEntry)otArr[iPrevFont].DirectoryEntries[iDe];
                                            if (dePrev.tag == table.m_tag)
                                            {
                                                PrevFilePos = dePrev.offset;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // build a new directory entry

                    DirectoryEntry de = new DirectoryEntry();
                    de.tag = new OTTag(tag.GetBytes());
                    de.checkSum = table.CalcChecksum();
                    de.length = table.GetLength();
                    if (PrevFilePos != 0)
                    {
                        de.offset = (uint)PrevFilePos;
                    }
                    else
                    {
                        de.offset = (uint)FilePos;
                        FilePos += table.GetBuffer().GetPaddedLength();
                    }

                    otArr[iFont].DirectoryEntries.Add(de);
                }

                // sort the directory entries

                if (numTables > 1)
                {
                    for (int i=0; i<numTables-1; i++)
                    {
                        for (int j=i+1; j<numTables; j++)
                        {
                            if (((DirectoryEntry)otArr[iFont].DirectoryEntries[i]).tag > ((DirectoryEntry)otArr[iFont].DirectoryEntries[j]).tag)
                            {
                                DirectoryEntry temp = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                                otArr[iFont].DirectoryEntries[i] = (DirectoryEntry)otArr[iFont].DirectoryEntries[j];
                                otArr[iFont].DirectoryEntries[j] = temp;
                            }
                        }
                    }
                }
            }

            // update each font's checksum in the head table

            for (int iFont=0; iFont<fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();

                // calculate the checksum
                uint sum = 0;
                sum += otArr[iFont].CalcOffsetTableChecksum();
                sum += otArr[iFont].CalcDirectoryEntriesChecksum();
                for (ushort i=0; i<numTables; i++)
                {
                    DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    OTTable table = fonts[iFont].GetTable(de.tag);
                    if ((string)de.tag == "head")
                    {
                        table = arrHeadTables[iFont];
                    }
                    sum += table.CalcChecksum();
                }

                // get the cache
                Table_head headTable = arrHeadTables[iFont];
                Table_head.head_cache headCache = (Table_head.head_cache)headTable.GetCache();

                // set the checkSumAdujustment field
                headCache.checkSumAdjustment = 0xb1b0afba - sum;

                // generate a new table and replace the head table in the array of head tables
                Table_head newHead = (Table_head)headCache.GenerateTable();
                arrHeadTables[iFont] = newHead;

            }

            // write the TTC header

            WriteUint32MBO(fs, (uint)TTCtag);
            WriteUint32MBO(fs, version);
            WriteUint32MBO(fs, DirectoryCount);
            for (int i=0; i<fonts.Length; i++)
            {
                WriteUint32MBO(fs, TableDirectory[i]);
            }
            WriteUint32MBO(fs, ulDsigTag);
            WriteUint32MBO(fs, ulDsigLength);
            WriteUint32MBO(fs, ulDsigOffset);

            // write out each font

            for (int iFont=0; iFont<fonts.Length; iFont++)
            {
                ushort numTables = fonts[iFont].GetNumTables();

                // write the offset table

                fs.Write(otArr[iFont].m_buf.GetBuffer(), 0, (int)otArr[iFont].m_buf.GetLength());

                // write the directory entries

                for (int i=0; i<numTables; i++)
                {
                    DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    fs.Write(de.m_buf.GetBuffer(), 0, (int)de.m_buf.GetLength());
                }

                // write out each table unless a shared version has been written

                for (ushort i=0; i<numTables; i++)
                {
                    DirectoryEntry de = (DirectoryEntry)otArr[iFont].DirectoryEntries[i];
                    if (fs.Position == de.offset)
                    {
                        OTTable table = fonts[iFont].GetTable(de.tag);
                        if ((string)table.m_tag == "head")
                        {
                            table = arrHeadTables[iFont];
                        }
                        fs.Write(table.m_bufTable.GetBuffer(), 0, (int)table.GetBuffer().GetPaddedLength());
                    }
                }

            }

            return bRet;
        }