freetype-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [Devel] PCL issues and feature requests


From: Ian Brown
Subject: RE: [Devel] PCL issues and feature requests
Date: Mon, 9 Jul 2001 09:24:07 +0200

Hi Werner,
        It's difficult to contribute the code for a number of reasons:

1. It's wrapped up with code subject to Non-Disclosure agreements.
2. without the entire PCL interpreter it doesn't make much sense.

The code is pretty small though (about 100 lines max) and due to the
way it is downloaded, probably belongs in the application and not
the library. For those interested, this is how PCL does true-type:

1. A 'font header' is read. The data for this command is a true type file
with the tables: cvt, fpgm, gdir, head, hhea, hmtx, maxp, prep. gdir
is a PCL specific table ... it is empty on download, the interpreter
uses it.

When I get this command, I rename the gdir table to loca. I also add a
cmap and a glyf table.

2. A number of download character commands are read. The data segment
for each command contains the glyf data for this character, the character
code and the glyph number.

Each time I get a character download, I update the cmap, loca and gylf tables.
I then delete the face if it exists.

3. Some text is printed.

I create the face if it does not exist and render the text as normal.

I have included the code I use for step 2 below (this is the only complex code,
step one is simple directory manipulation. Use it for reference, but do not use
it directly.

----------------------------------------------

The thing to note is that steps 2 and 3 are repeated ... ie the characters are downloaded
on demand. This means that every time we have a new character, we need to re-read the font.
I think this is a read performance slug ... it would be nice if there was an interface to
say 're-read the loca table'.

----------------------------------------------

The thing with the missing tables is that to keep the printer stream small,
PCL omits the tables it doesn't need. These include the 'name' and
the 'post' tables. Now, because these are marked as obligitory in the
spec., freetype refuses to load the font from memory if these tables do
not exist ... even though it doesn't actually use them !
The easiest interface I think would be to have a 'liberal' flag ...
by this I mean you can set a library property that allows it to treat
any tables that the spec requires but freetype does not as optional.

Ian Brown
PrintSoft Systems GmbH

----------------------------------------------
Sample code to read a download character:

/*
note:
~~~~
        The font is optionally created everytime we draw a character with the following code:

        if (!m_ft_face){
                error = FT_New_Memory_Face(m_ft_library, m_tt_data, m_tt_data_size, 0, &m_ft_face);
        }
*/
/** Add a glyph to the font. */
void PCLFontDefinition::AddTTCharacter(unsigned char* pGlyfData, int cdata_size, int glyph_id, int char_id)
{
        // This is a little more difficult than it needs to be.
        // The glyph descriptions in the glyf table need to be consequtive. This is because the
        // size of a glyph is found by differencing the offset of the glyph and the offset of the
        // following glyph as found in the loca table.

//      TRACE2("Adding TT character 0x%x, glyph_id 0x%x\n", char_id, glyph_id);
        if (char_id > 0 && char_id < 256){
                // Make the entry in the character map table.
                unsigned char* pCMAP = m_tt_data + m_cmap_table_offset + 22 + char_id*2;
                pCMAP[0] = (unsigned char)(glyph_id / 256); pCMAP[1] = (unsigned char)(glyph_id);

                // Add the Glyph data to the glyf table.
                unsigned char* pGlyfDir = m_tt_data + 12 + (16 * m_glyf_table_no);
                int glyf_table_size = (pGlyfDir[13] << 16) + (pGlyfDir[14] << 8) + pGlyfDir[15];
                if (m_glyf_table_offset + glyf_table_size + cdata_size + 16 > m_tt_data_size){
                        // We need to allocate some more space !
                        int new_tt_data_size = m_glyf_table_offset + glyf_table_size + 10 * cdata_size + 4;
                        unsigned char* new_tt_data = new unsigned char[new_tt_data_size];
                        memcpy(new_tt_data, m_tt_data, m_tt_data_size);
                        delete[] m_tt_data;
                        m_tt_data = new_tt_data;
                        m_tt_data_size = new_tt_data_size;
                        pGlyfDir = m_tt_data + 12 + (16 * m_glyf_table_no);
                }
                // Find out where this glyph needs to go. Scan the 'loca' table to see where the
                // following glyph is.
                unsigned char* pLocaSlot = m_tt_data + m_loca_table_offset + glyph_id*4;
                unsigned int offset_to_insert_at = (pLocaSlot[0] << 24) + (pLocaSlot[1] << 16) + (pLocaSlot[2] << 8) + pLocaSlot[3];

                int cur_glyph_id = glyph_id;
                while (0 == offset_to_insert_at && cur_glyph_id < m_max_tt_glyphs){
                        pLocaSlot += 4; ++cur_glyph_id;
                        offset_to_insert_at = (pLocaSlot[0] << 24) + (pLocaSlot[1] << 16) + (pLocaSlot[2] << 8) + pLocaSlot[3];

                }
                if (0 == offset_to_insert_at){
                        // This is the highest glyph number currently added, so add to the end of the glyf data.
                        offset_to_insert_at = glyf_table_size;

                        // We make sure that no glyph is actually inserted at offset 0 ... if we do not do this then we cannot easily

                        // detect from the loca table whether it points to a glyph or not.
                        if (0 == offset_to_insert_at){
                                glyf_table_size += 4;
                                offset_to_insert_at = 4;
                        }
                }
                // Shift the glyph data above offset_to_insert_at up to create a hole for the new glyph data.
                int bytes_to_copy = glyf_table_size - offset_to_insert_at;
                int padded_cdata_size = (cdata_size + 3) & ~3;
                if (bytes_to_copy > 0){
                        memmove(m_tt_data + m_glyf_table_offset + offset_to_insert_at + padded_cdata_size, m_tt_data + m_glyf_table_offset + offset_to_insert_at, bytes_to_copy);

                }
               
                // Add the new glyph data to the glyph table.
                memcpy(m_tt_data + m_glyf_table_offset + offset_to_insert_at, pGlyfData, cdata_size);
                if (padded_cdata_size > cdata_size){
                        // Zero the padding bytes if there are any.
                        memset(m_tt_data + m_glyf_table_offset + offset_to_insert_at + cdata_size, 0, padded_cdata_size - cdata_size);

                }
                glyf_table_size += padded_cdata_size;
                // update the table size in the table directory.
                pGlyfDir[13] = (unsigned char)(glyf_table_size >> 16);
                pGlyfDir[14] = (unsigned char)(glyf_table_size >> 8);
                pGlyfDir[15] = (unsigned char)(glyf_table_size);
               
                // update the loca table entry for this glyph.
                pLocaSlot = m_tt_data + m_loca_table_offset + glyph_id*4;
                pLocaSlot[0] = (unsigned char)(offset_to_insert_at >> 24);
                pLocaSlot[1] = (unsigned char)(offset_to_insert_at >> 16);
                pLocaSlot[2] = (unsigned char)(offset_to_insert_at >> 8);
                pLocaSlot[3] = (unsigned char)(offset_to_insert_at);
                int glyf_end_offset = offset_to_insert_at + padded_cdata_size;
                pLocaSlot[4] = (unsigned char)(glyf_end_offset >> 24);
                pLocaSlot[5] = (unsigned char)(glyf_end_offset >> 16);
                pLocaSlot[6] = (unsigned char)(glyf_end_offset >> 8);
                pLocaSlot[7] = (unsigned char)(glyf_end_offset);

                // need to adjust and following loca offsets by adding padded_cdata_size if we shifted any data up.
                if (bytes_to_copy > 0){
                        pLocaSlot += 8;
                        for (int gid = glyph_id +2; gid <= m_max_tt_glyphs; ++gid, pLocaSlot += 4){
                                unsigned int offset = (pLocaSlot[0] << 24) + (pLocaSlot[1] << 16) + (pLocaSlot[2] << 8) + pLocaSlot[3];

                                if (offset != 0){
                                        offset += padded_cdata_size;
                                        pLocaSlot[0] = (unsigned char)(offset >> 24);
                                        pLocaSlot[1] = (unsigned char)(offset >> 16);
                                        pLocaSlot[2] = (unsigned char)(offset >> 8);
                                        pLocaSlot[3] = (unsigned char)(offset);
                                }
                        }
                }
                // Because we have changed the loca table, we need to re-read the font data.
                if (m_ft_face){
                        FT_Done_Face(m_ft_face);
                        m_ft_face = NULL;
                }

        } else {
                TRACE0("*** Invalid character code ! ***\n");
        }
}


reply via email to

[Prev in Thread] Current Thread [Next in Thread]