Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/vcl/source/fontsubset/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 31 kB image not shown  

Quelle  ttcr.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


/*
 * TrueTypeCreator method implementation
 */


#include <iomanip>
#include <assert.h>

#include <sal/log.hxx>

#include "ttcr.hxx"
#include <string.h>

namespace vcl
{

/*
 * Private Data Types
 */


struct TableEntry {
    sal_uInt32 tag;
    sal_uInt32 length;
    sal_uInt8  *data;
};

/*- Data access macros for data stored in big-endian or little-endian format */
static sal_Int16 GetInt16( const sal_uInt8* ptr, sal_uInt32 offset)
{
    assert(ptr != nullptr);
    sal_Int16 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
    return t;
}

static sal_uInt16 GetUInt16( const sal_uInt8* ptr, sal_uInt32 offset)
{
    assert(ptr != nullptr);
    sal_uInt16 t = (ptr+offset)[0] << 8 | (ptr+offset)[1];
    return t;
}

static void PutInt16(sal_Int16 val, sal_uInt8 *ptr, sal_uInt32 offset)
{
    assert(ptr != nullptr);

    ptr[offset] = static_cast<sal_uInt8>((val >> 8) & 0xFF);
    ptr[offset+1] = static_cast<sal_uInt8>(val & 0xFF);
}

static void PutUInt16(sal_uInt16 val, sal_uInt8 *ptr, sal_uInt32 offset)
{
    assert(ptr != nullptr);

    ptr[offset] = static_cast<sal_uInt8>((val >> 8) & 0xFF);
    ptr[offset+1] = static_cast<sal_uInt8>(val & 0xFF);
}

static void PutUInt32(sal_uInt32 val, sal_uInt8 *ptr, sal_uInt32 offset)
{
    assert(ptr != nullptr);

    ptr[offset]   = static_cast<sal_uInt8>((val >> 24) & 0xFF);
    ptr[offset+1] = static_cast<sal_uInt8>((val >> 16) & 0xFF);
    ptr[offset+2] = static_cast<sal_uInt8>((val >> 8) & 0xFF);
    ptr[offset+3] = static_cast<sal_uInt8>(val & 0xFF);
}

static int TableEntryCompareF(const void *l, const void *r)
{
    sal_uInt32 const ltag(static_cast<TableEntry const*>(l)->tag);
    sal_uInt32 const rtag(static_cast<TableEntry const*>(r)->tag);
    return (ltag == rtag) ? 0 : (ltag < rtag) ? -1 : 1;
}

namespace {
struct NameRecordCompareF
{
    bool operator()(const NameRecord& l, const NameRecord& r) const
    {
        if (l.platformID != r.platformID) {
            return l.platformID < r.platformID;
        } else if (l.encodingID != r.encodingID) {
            return l.encodingID < r.encodingID;
        } else if (l.languageID != r.languageID) {
            return l.languageID < r.languageID;
        } else if (l.nameID != r.nameID) {
            return l.nameID < r.nameID;
        }
        return false;
    }
};
}

static sal_uInt32 CheckSum(sal_uInt32 *ptr, sal_uInt32 length)
{
    sal_uInt32 sum = 0;
    sal_uInt32 *endptr = ptr + ((length + 3) & sal_uInt32(~3)) / 4;

    while (ptr < endptr) sum += *ptr++;

    return sum;
}

/*
 * Public functions
 */


TrueTypeCreator::TrueTypeCreator(sal_uInt32 _tag)
{
    this->m_tag = _tag;
}

void TrueTypeCreator::AddTable(std::unique_ptr<TrueTypeTable> table)
{
    if (table != nullptr) {
        this->m_tables.push_back(std::move(table));
    }
}

void TrueTypeCreator::RemoveTable(sal_uInt32 tableTag)
{
    for (auto it = this->m_tables.begin(); it != this->m_tables.end(); )
    {
        if ((*it)->m_tag == tableTag)
        {
            it = this->m_tables.erase(it);
        }
        else
            ++it;
    }
}

SFErrCodes TrueTypeCreator::StreamToMemory(std::vector<sal_uInt8>& rOutBuffer)
{
    sal_uInt16 searchRange=1, entrySelector=0, rangeShift;
    sal_uInt32 s, offset, checkSumAdjustment = 0;
    sal_uInt32 *p;
    sal_uInt8 *head = nullptr;     /* saved pointer to the head table data for checkSumAdjustment calculation */

    if (this->m_tables.empty())
        return SFErrCodes::TtFormat;

    ProcessTables();

    /* ProcessTables() adds 'loca' and 'hmtx' */

    sal_uInt16 numTables = this->m_tables.size();

    std::unique_ptr<TableEntry[]> te(new TableEntry[numTables]);

    int teIdx = 0;
    for (auto const & e : this->m_tables)
    {
        e->GetRawData(&te[teIdx]);
        ++teIdx;
    }

    qsort(te.get(), numTables, sizeof(TableEntry), TableEntryCompareF);

    do {
        searchRange *= 2;
        entrySelector++;
    } while (searchRange <= numTables);

    searchRange *= 8;
    entrySelector--;
    rangeShift = numTables * 16 - searchRange;

    s = offset = 12 + 16 * numTables;

    for (int i = 0; i < numTables; ++i) {
        s += (te[i].length + 3) & sal_uInt32(~3);
        /* if ((te[i].length & 3) != 0) s += (4 - (te[i].length & 3)) & 3; */
    }

    rOutBuffer.resize(s);
    sal_uInt8* ttf = rOutBuffer.data();

    /* Offset Table */
    PutUInt32(this->m_tag, ttf, 0);
    PutUInt16(numTables, ttf, 4);
    PutUInt16(searchRange, ttf, 6);
    PutUInt16(entrySelector, ttf, 8);
    PutUInt16(rangeShift, ttf, 10);

    /* Table Directory */
    for (int i = 0; i < numTables; ++i) {
        PutUInt32(te[i].tag, ttf + 12, 16 * i);
        PutUInt32(CheckSum(reinterpret_cast<sal_uInt32 *>(te[i].data), te[i].length), ttf + 12, 16 * i + 4);
        PutUInt32(offset, ttf + 12, 16 * i + 8);
        PutUInt32(te[i].length, ttf + 12, 16 * i + 12);

        if (te[i].tag == T_head) {
            head = ttf + offset;
        }

        memcpy(ttf+offset, te[i].data, (te[i].length + 3) & sal_uInt32(~3) );
        offset += (te[i].length + 3) & sal_uInt32(~3);
        /* if ((te[i].length & 3) != 0) offset += (4 - (te[i].length & 3)) & 3; */
    }

    te.reset();

    p = reinterpret_cast<sal_uInt32 *>(ttf);
    for (int i = 0; i < static_cast<int>(s) / 4; ++i) checkSumAdjustment += p[i];
    PutUInt32(0xB1B0AFBA - checkSumAdjustment, head, 8);

    return SFErrCodes::Ok;
}

/*
 * TrueTypeTable private methods
 */


/*    Table         data points to
 * --------------------------------------------
 *    generic       tdata_generic struct
 *    'head'        HEAD_Length bytes of memory
 *    'hhea'        HHEA_Length bytes of memory
 *    'loca'        tdata_loca struct
 *    'maxp'        MAXP_Version1Length bytes of memory
 *    'glyf'        list of GlyphData structs (defined in sft.h)
 *    'name'        list of NameRecord structs (defined in sft.h)
 *    'post'        tdata_post struct
 *
 */


#define CMAP_SUBTABLE_INIT 10
#define CMAP_SUBTABLE_INCR 10

namespace {

struct CmapSubTable {
    sal_uInt32  id;                         /* subtable ID (platform/encoding ID)    */
    std::vector<std::pair<sal_uInt32, sal_uInt32>> mappings;  /* character to glyph mapping array */
};

}

struct table_cmap {
    sal_uInt32 n;                           /* number of used CMAP sub-tables       */
    sal_uInt32 m;                           /* number of allocated CMAP sub-tables  */
    std::unique_ptr<CmapSubTable[]> s;      /* sorted array of sub-tables           */
};

struct tdata_loca {
    sal_uInt32 nbytes;                      /* number of bytes in loca table */
    std::unique_ptr<sal_uInt8[]> ptr;       /* pointer to the data */
};

/* allocate memory for a TT table */
static std::unique_ptr<sal_uInt8[]> ttmalloc(sal_uInt32 nbytes)
{
    sal_uInt32 n = (nbytes + 3) & sal_uInt32(~3);
    return std::make_unique<sal_uInt8[]>(n);
}

TrueTypeTable::~TrueTypeTable() {}

TrueTypeTableGeneric::~TrueTypeTableGeneric()
{
}

TrueTypeTableHead::~TrueTypeTableHead()
{
}

TrueTypeTableHhea::~TrueTypeTableHhea()
{
}

TrueTypeTableLoca::~TrueTypeTableLoca()
{
}

TrueTypeTableMaxp::~TrueTypeTableMaxp()
{
}

TrueTypeTableGlyf::~TrueTypeTableGlyf()
{
}

TrueTypeTableCmap::~TrueTypeTableCmap()
{
}

TrueTypeTableName::~TrueTypeTableName()
{
}

TrueTypeTablePost::~TrueTypeTablePost()
{
    if (m_format == 0x00030000) {
        /* do nothing */
    } else {
        SAL_WARN("vcl.fonts""Unsupported format of a 'post' table: "
                << std::setfill('0')
                << std::setw(8)
                << std::hex
                << std::uppercase
                << static_cast<int>(m_format) << ".");
    }
}


int TrueTypeTableGeneric::GetRawData(TableEntry* te)
{
    te->data = this->m_ptr.get();
    te->length = this->m_nbytes;
    te->tag = this->m_tag;

    return TTCR_OK;
}

int TrueTypeTableHead::GetRawData(TableEntry* te)
{
    te->length = HEAD_Length;
    te->data = this->m_head.get();
    te->tag = T_head;

    return TTCR_OK;
}

int TrueTypeTableHhea::GetRawData(TableEntry* te)
{
    te->length = HHEA_Length;
    te->data = this->m_hhea.get();
    te->tag = T_hhea;

    return TTCR_OK;
}

int TrueTypeTableLoca::GetRawData(TableEntry* te)
{
    assert(this->m_loca != nullptr);

    if (m_loca->nbytes == 0) return TTCR_ZEROGLYPHS;

    te->data = m_loca->ptr.get();
    te->length = m_loca->nbytes;
    te->tag = T_loca;

    return TTCR_OK;
}

int TrueTypeTableMaxp::GetRawData(TableEntry* te)
{
    te->length = MAXP_Version1Length;
    te->data = this->m_maxp.get();
    te->tag = T_maxp;

    return TTCR_OK;
}

int TrueTypeTableGlyf::GetRawData(TableEntry* te)
{
    sal_uInt32 n, nbytes = 0;
    /* sal_uInt16 curID = 0;    */               /* to check if glyph IDs are sequential and start from zero */

    te->data = nullptr;
    te->length = 0;
    te->tag = 0;

    if (m_list.empty()) return TTCR_ZEROGLYPHS;

    for (const std::unique_ptr<GlyphData>& pGlyph : m_list)
    {
        /* if (((GlyphData *) listCurrent(l))->glyphID != curID++) return TTCR_GLYPHSEQ; */
        nbytes += pGlyph->nbytes;
    }

    m_rawdata = ttmalloc(nbytes);

    auto p = m_rawdata.get();
    for (const std::unique_ptr<GlyphData>& pGlyph : m_list)
    {
        n = pGlyph->nbytes;
        if (n != 0) {
            memcpy(p, pGlyph->ptr.get(), n);
            p += n;
        }
    }

    te->length = nbytes;
    te->data = m_rawdata.get();
    te->tag = T_glyf;

    return TTCR_OK;
}

/* cmap packers */
static std::unique_ptr<sal_uInt8[]> PackCmapType0(CmapSubTable const *s, sal_uInt32 *length)
{
    std::unique_ptr<sal_uInt8[]> ptr(new sal_uInt8[262]);
    sal_uInt8 *p = ptr.get() + 6;

    PutUInt16(0, ptr.get(), 0);
    PutUInt16(262, ptr.get(), 2);
    PutUInt16(0, ptr.get(), 4);

    for (sal_uInt32 i = 0; i < 256; i++) {
        sal_uInt16 g = 0;
        for (const auto& [ch, glyph] : s->mappings) {
            if (ch == i) {
                g = static_cast<sal_uInt16>(glyph);
            }
        }
        p[i] = static_cast<sal_uInt8>(g);
    }
    *length = 262;
    return ptr;
}

static std::unique_ptr<sal_uInt8[]> PackCmapType6(CmapSubTable const *s, sal_uInt32 *length)
{
    std::unique_ptr<sal_uInt8[]> ptr(new sal_uInt8[s->mappings.size()*2 + 10]);
    sal_uInt8 *p = ptr.get() + 10;

    PutUInt16(6, ptr.get(), 0);
    PutUInt16(static_cast<sal_uInt16>(s->mappings.size()*2+10), ptr.get(), 2);
    PutUInt16(0, ptr.get(), 4);
    PutUInt16(0, ptr.get(), 6);
    PutUInt16(static_cast<sal_uInt16>(s->mappings.size()), ptr.get(), 8 );

    for (size_t i = 0; i < s->mappings.size(); i++) {
        sal_uInt16 g = 0;
        for (const auto& [ch, glyph] : s->mappings) {
            if (ch == i) {
                g = static_cast<sal_uInt16>(glyph);
            }
        }
        PutUInt16( g, p, 2*i );
    }
    *length = s->mappings.size()*2+10;
    return ptr;
}

/* XXX it only handles Format 0 encoding tables */
static std::unique_ptr<sal_uInt8[]> PackCmap(CmapSubTable const *s, sal_uInt32 *length)
{
    if (s->mappings.back().second > 0xff)
        return PackCmapType6(s, length);
    else
        return PackCmapType0(s, length);
}

int TrueTypeTableCmap::GetRawData(TableEntry* te)
{
    sal_uInt32 i;
    sal_uInt32 tlen = 0;
    sal_uInt32 l;
    sal_uInt32 cmapsize;
    sal_uInt8 *cmap;
    sal_uInt32 coffset;

    assert(m_cmap);
    assert(m_cmap->n != 0);

    std::unique_ptr<std::unique_ptr<sal_uInt8[]>[]> subtables(new std::unique_ptr<sal_uInt8[]>[m_cmap->n]);
    std::unique_ptr<sal_uInt32[]> sizes(new sal_uInt32[m_cmap->n]);

    for (i = 0; i < m_cmap->n; i++) {
        subtables[i] = PackCmap(m_cmap->s.get()+i, &l);
        sizes[i] = l;
        tlen += l;
    }

    cmapsize = tlen + 4 + 8 * m_cmap->n;
    this->m_rawdata = ttmalloc(cmapsize);
    cmap = this->m_rawdata.get();

    PutUInt16(0, cmap, 0);
    PutUInt16(static_cast<sal_uInt16>(m_cmap->n), cmap, 2);
    coffset = 4 + m_cmap->n * 8;

    for (i = 0; i < m_cmap->n; i++) {
        PutUInt16(static_cast<sal_uInt16>(m_cmap->s[i].id >> 16), cmap + 4, i * 8);
        PutUInt16(static_cast<sal_uInt16>(m_cmap->s[i].id & 0xFF), cmap + 4, 2 + i * 8);
        PutUInt32(coffset, cmap + 4, 4 + i * 8);
        memcpy(cmap + coffset, subtables[i].get(), sizes[i]);
        subtables[i].reset();
        coffset += sizes[i];
    }

    subtables.reset();
    sizes.reset();

    te->data = cmap;
    te->length = cmapsize;
    te->tag = T_cmap;

    return TTCR_OK;
}

int TrueTypeTableName::GetRawData(TableEntry* te)
{
    sal_Int16 i=0, n;                          /* number of Name Records */
    int stringLen = 0;
    sal_uInt8 *p1, *p2;

    te->data = nullptr;
    te->length = 0;
    te->tag = 0;

    if ((n = static_cast<sal_Int16>(m_list.size())) == 0) return TTCR_NONAMES;

    std::vector<NameRecord> nr = m_list;

    for (const NameRecord & rName : m_list)
        stringLen += rName.sptr.size();

    if (stringLen > 65535) {
        return TTCR_NAMETOOLONG;
    }

    std::sort(nr.begin(), nr.end(), NameRecordCompareF());

    int nameLen = stringLen + 12 * n + 6;
    std::unique_ptr<sal_uInt8[]> name = ttmalloc(nameLen);

    PutUInt16(0, name.get(), 0);
    PutUInt16(n, name.get(), 2);
    PutUInt16(static_cast<sal_uInt16>(6 + 12 * n), name.get(), 4);

    p1 = name.get() + 6;
    p2 = p1 + 12 * n;

    for (i = 0; i < n; i++) {
        PutUInt16(nr[i].platformID, p1, 0);
        PutUInt16(nr[i].encodingID, p1, 2);
        PutUInt16(static_cast<sal_uInt16>(nr[i].languageID), p1, 4);
        PutUInt16(nr[i].nameID, p1, 6);
        PutUInt16(nr[i].sptr.size(), p1, 8);
        PutUInt16(static_cast<sal_uInt16>(p2 - (name.get() + 6 + 12 * n)), p1, 10);
        if (nr[i].sptr.size()) {
            memcpy(p2, nr[i].sptr.data(), nr[i].sptr.size());
        }
        /* {int j; for(j=0; j<nr[i].slen; j++) printf("%c", nr[i].sptr[j]); printf("\n"); }; */
        p2 += nr[i].sptr.size();
        p1 += 12;
    }

    nr.clear();
    this->m_rawdata = std::move(name);

    te->data = this->m_rawdata.get();
    te->length = static_cast<sal_uInt16>(nameLen);
    te->tag = T_name;

    /*{int j; for(j=0; j<nameLen; j++) printf("%c", name[j]); }; */

    return TTCR_OK;
}

int TrueTypeTablePost::GetRawData(TableEntry* te)
{
    std::unique_ptr<sal_uInt8[]> post;
    sal_uInt32 postLen = 0;
    int ret;

    this->m_rawdata.reset();

    if (m_format == 0x00030000) {
        postLen = 32;
        post = ttmalloc(postLen);
        PutUInt32(0x00030000, post.get(), 0);
        PutUInt32(m_italicAngle, post.get(), 4);
        PutUInt16(m_underlinePosition, post.get(), 8);
        PutUInt16(m_underlineThickness, post.get(), 10);
        PutUInt16(static_cast<sal_uInt16>(m_isFixedPitch), post.get(), 12);
        ret = TTCR_OK;
    } else {
        SAL_WARN("vcl.fonts""Unrecognized format of a post table: "
                << std::setfill('0')
                << std::setw(8)
                << std::hex
                << std::uppercase
                << static_cast<int>(m_format) << ".");
        ret = TTCR_POSTFORMAT;
    }

    this->m_rawdata = std::move(post);
    te->data = this->m_rawdata.get();
    te->length = postLen;
    te->tag = T_post;

    return ret;
}

/*
 * TrueTypeTable public methods
 */


/* Note: Type42 fonts only need these tables:
 *        head, hhea, loca, maxp, cvt, prep, glyf, hmtx, fpgm
 *
 * Microsoft required tables
 *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post, OS/2
 *
 * Apple required tables
 *        cmap, glyf, head, hhea, hmtx, loca, maxp, name, post
 *
 */


TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag,
                                sal_uInt32 nbytes,
                                const sal_uInt8* ptr)
    : TrueTypeTable(tag),
    m_nbytes(nbytes)
{
    if (nbytes) {
        m_ptr = ttmalloc(nbytes);
        memcpy(m_ptr.get(), ptr, nbytes);
    }
}

TrueTypeTableGeneric::TrueTypeTableGeneric(sal_uInt32 tag,
                                sal_uInt32 nbytes,
                                std::unique_ptr<sal_uInt8[]> ptr)
    : TrueTypeTable(tag),
    m_nbytes(nbytes)
{
    if (nbytes) {
        m_ptr = std::move(ptr);
    }
}

TrueTypeTableHead::TrueTypeTableHead(sal_uInt32 fontRevision,
                                     sal_uInt16 flags,
                                     sal_uInt16 unitsPerEm,
                                     const sal_uInt8* created,
                                     sal_uInt16 macStyle,
                                     sal_uInt16 lowestRecPPEM,
                                     sal_Int16  fontDirectionHint)
    : TrueTypeTable(T_head)
    , m_head(ttmalloc(HEAD_Length))
{
    assert(created != nullptr);

    sal_uInt8* ptr = m_head.get();

    PutUInt32(0x00010000, ptr, 0);             /* version */
    PutUInt32(fontRevision, ptr, 4);
    PutUInt32(0x5F0F3CF5, ptr, 12);            /* magic number */
    PutUInt16(flags, ptr, 16);
    PutUInt16(unitsPerEm, ptr, 18);
    memcpy(ptr+20, created, 8);                   /* Created Long Date */
    memset(ptr+28, 0, 8);                         /* Modified Long Date */
    PutUInt16(macStyle, ptr, 44);
    PutUInt16(lowestRecPPEM, ptr, 46);
    PutUInt16(fontDirectionHint, ptr, 48);
    PutUInt16(0, ptr, 52);                     /* glyph data format: 0 */
}

TrueTypeTableHhea::TrueTypeTableHhea(sal_Int16  ascender,
                                     sal_Int16  descender,
                                     sal_Int16  linegap,
                                     sal_Int16  caretSlopeRise,
                                     sal_Int16  caretSlopeRun)
    : TrueTypeTable(T_hhea),
    m_hhea(ttmalloc(HHEA_Length))
{
    sal_uInt8* ptr = m_hhea.get();

    PutUInt32(0x00010000, ptr, 0);             /* version */
    PutUInt16(ascender, ptr, 4);
    PutUInt16(descender, ptr, 6);
    PutUInt16(linegap, ptr, 8);
    PutUInt16(caretSlopeRise, ptr, 18);
    PutUInt16(caretSlopeRun, ptr, 20);
    PutUInt16(0, ptr, 22);                     /* reserved 1 */
    PutUInt16(0, ptr, 24);                     /* reserved 2 */
    PutUInt16(0, ptr, 26);                     /* reserved 3 */
    PutUInt16(0, ptr, 28);                     /* reserved 4 */
    PutUInt16(0, ptr, 30);                     /* reserved 5 */
    PutUInt16(0, ptr, 32);                     /* metricDataFormat */
}

TrueTypeTableLoca::TrueTypeTableLoca()
    : TrueTypeTable(T_loca),
    m_loca(new tdata_loca)
{
    this->m_loca->nbytes = 0;
    this->m_loca->ptr = nullptr;
}

TrueTypeTableMaxp::TrueTypeTableMaxp( const sal_uInt8* maxp, int size)
    : TrueTypeTable(T_maxp)
{
    this->m_maxp = ttmalloc(MAXP_Version1Length);

    if (maxp && size == MAXP_Version1Length) {
        memcpy(this->m_maxp.get(), maxp, MAXP_Version1Length);
    }
}

TrueTypeTableGlyf::TrueTypeTableGlyf()
    : TrueTypeTable(T_glyf)
{
}

TrueTypeTableCmap::TrueTypeTableCmap()
    : TrueTypeTable(T_cmap)
    , m_cmap(new table_cmap)
{
    m_cmap->n = 0;
    m_cmap->m = CMAP_SUBTABLE_INIT;
    m_cmap->s.reset(new CmapSubTable[CMAP_SUBTABLE_INIT]);
}

TrueTypeTableName::TrueTypeTableName(std::vector<NameRecord> nr)
    : TrueTypeTable(T_name)
    , m_list(std::move(nr))
{
}

TrueTypeTablePost::TrueTypeTablePost(sal_Int32 format,
                                     sal_Int32 italicAngle,
                                     sal_Int16 underlinePosition,
                                     sal_Int16 underlineThickness,
                                     sal_uInt32 isFixedPitch)
    : TrueTypeTable(T_post)
{
    assert(format == 0x00030000);                 /* Only format 3.0 is supported at this time */

    m_format = format;
    m_italicAngle = italicAngle;
    m_underlinePosition = underlinePosition;
    m_underlineThickness = underlineThickness;
    m_isFixedPitch = isFixedPitch;
}

void TrueTypeTableCmap::cmapAdd(sal_uInt32 id, sal_uInt32 c, sal_uInt32 g)
{
    sal_uInt32 i, found;
    CmapSubTable *s;

    assert(m_cmap);
    s = m_cmap->s.get(); assert(s != nullptr);

    found = 0;

    for (i = 0; i < m_cmap->n; i++) {
        if (s[i].id == id) {
            found = 1;
            break;
        }
    }

    if (!found) {
        if (m_cmap->n == m_cmap->m) {
            std::unique_ptr<CmapSubTable[]> tmp(new CmapSubTable[m_cmap->m + CMAP_SUBTABLE_INCR]);
            for (sal_uInt32 j = 0; j != m_cmap->m; ++j) {
                tmp[j] = std::move(s[j]);
            }
            m_cmap->m += CMAP_SUBTABLE_INCR;
            s = tmp.get();
            m_cmap->s = std::move(tmp);
        }

        for (i = 0; i < m_cmap->n; i++) {
            if (s[i].id > id) break;
        }

        if (i < m_cmap->n) {
            for (sal_uInt32 j = m_cmap->n; j != i; --j) {
                s[j + 1] = std::move(s[j]);
            }
        }

        m_cmap->n++;

        s[i].id = id;
    }

    s[i].mappings.emplace_back(c, g);
}

sal_uInt32 TrueTypeTableGlyf::glyfAdd(std::unique_ptr<GlyphData> glyphdata, AbstractTrueTypeFont *fnt)
{
    sal_uInt32 currentID;
    int ret, n, ncomponents;

    if (!glyphdata) return sal_uInt32(~0);

    std::vector< sal_uInt32 > glyphlist;

    ncomponents = GetTTGlyphComponents(fnt, glyphdata->glyphID, glyphlist);

    if (m_list.size() > 0) {
        ret = n = m_list.back()->newID + 1;
    } else {
        ret = n = 0;
    }
    glyphdata->newID = n++;
    m_list.push_back(std::move(glyphdata));

    if (ncomponents > 1 && glyphlist.size() > 1 )
    {
        std::vector< sal_uInt32 >::const_iterator it = glyphlist.begin();
        ++it;
        /* glyphData->glyphID is always the first glyph on the list */
        do
        {
            int found = 0;
            currentID = *it;
            /* XXX expensive! should be rewritten with sorted arrays! */
            for (const std::unique_ptr<GlyphData>& pGlyph : m_list)
            {
                if (pGlyph->glyphID == currentID) {
                    found = 1;
                    break;
                }
            }

            if (!found) {
                std::unique_ptr<GlyphData> gd = GetTTRawGlyphData(fnt, currentID);
                gd->newID = n++;
                m_list.push_back(std::move(gd));
            }
        } while( ++it != glyphlist.end() );
    }

    return ret;
}

TrueTypeTable *TrueTypeCreator::FindTable(sal_uInt32 tableTag)
{
    for (const std::unique_ptr<TrueTypeTable>& p : this->m_tables)
        if (p->m_tag == tableTag) {
            return p.get();
        }

    return nullptr;
}

/* This function processes all the tables and synchronizes them before creating
 * the output TrueType stream.
 *
 * *** It adds two TrueType tables to the font: 'loca' and 'hmtx' ***
 *
 * It does:
 *
 * - Re-numbers glyph IDs and creates 'glyf', 'loca', and 'hmtx' tables.
 * - Calculates xMin, yMin, xMax, and yMax and stores values in 'head' table.
 * - Stores indexToLocFormat in 'head'
 * - updates 'maxp' table
 * - Calculates advanceWidthMax, minLSB, minRSB, xMaxExtent and numberOfHMetrics
 *   in 'hhea' table
 *
 */

void TrueTypeCreator::ProcessTables()
{
    TrueTypeTableHhea *hhea = nullptr;
    TrueTypeTableMaxp *maxp = nullptr;
    TrueTypeTableHead *head = nullptr;
    std::unique_ptr<TrueTypeTableLoca> loca;
    TrueTypeTableGlyf *glyf = nullptr;
    sal_uInt32 nGlyphs, locaLen = 0, glyfLen = 0;
    sal_Int16 xMin = 0, yMin = 0, xMax = 0, yMax = 0;
    sal_uInt32 i = 0;
    sal_Int16 indexToLocFormat;
    std::unique_ptr<sal_uInt8[]> hmtxPtr;
    sal_uInt8 *hheaPtr;
    sal_uInt32 hmtxSize;
    sal_uInt8 *p1, *p2;
    sal_uInt16 maxPoints = 0, maxContours = 0, maxCompositePoints = 0, maxCompositeContours = 0;
    int nlsb = 0;
    std::unique_ptr<sal_uInt32[]> gid;   /* array of old glyphIDs */

    glyf = static_cast<TrueTypeTableGlyf*>(FindTable(T_glyf));
    std::vector<std::unique_ptr<GlyphData>>& glyphlist = glyf->m_list;
    nGlyphs = glyphlist.size();
    if (!nGlyphs)
    {
        SAL_WARN("vcl.fonts""no glyphs found in ProcessTables");
        return;
    }
    gid.reset(new sal_uInt32[nGlyphs]);

    RemoveTable(T_loca);
    RemoveTable(T_hmtx);

    /* XXX Need to make sure that composite glyphs do not break during glyph renumbering */

    for (const std::unique_ptr<GlyphData>& gd : glyphlist)
    {
        glyfLen += gd->nbytes;
        /* XXX if (gd->nbytes & 1) glyfLen++; */

        assert(gd->newID == i);
        gid[i++] = gd->glyphID;
        /* gd->glyphID = i++; */

        /* printf("IDs: %d %d.\n", gd->glyphID, gd->newID); */

        if (gd->nbytes >= 10) {
            sal_Int16 z = GetInt16(gd->ptr.get(), 2);
            if (z < xMin) xMin = z;

            z = GetInt16(gd->ptr.get(), 4);
            if (z < yMin) yMin = z;

            z = GetInt16(gd->ptr.get(), 6);
            if (z > xMax) xMax = z;

            z = GetInt16(gd->ptr.get(), 8);
            if (z > yMax) yMax = z;
        }

        if (!gd->compflag) {                                /* non-composite glyph */
            if (gd->npoints > maxPoints) maxPoints = gd->npoints;
            if (gd->ncontours > maxContours) maxContours = gd->ncontours;
        } else {                                            /* composite glyph */
            if (gd->npoints > maxCompositePoints) maxCompositePoints = gd->npoints;
            if (gd->ncontours > maxCompositeContours) maxCompositeContours = gd->ncontours;
        }

    }

    indexToLocFormat = (glyfLen / 2 > 0xFFFF) ? 1 : 0;
    locaLen = indexToLocFormat ?  (nGlyphs + 1) << 2 : (nGlyphs + 1) << 1;

    std::unique_ptr<sal_uInt8[]> glyfPtr = ttmalloc(glyfLen);
    std::unique_ptr<sal_uInt8[]> locaPtr = ttmalloc(locaLen);
    std::unique_ptr<TTSimpleGlyphMetrics[]> met(new TTSimpleGlyphMetrics[nGlyphs]);
    i = 0;

    p1 = glyfPtr.get();
    p2 = locaPtr.get();
    for (const std::unique_ptr<GlyphData>& gd : glyphlist)
    {
        if (gd->compflag && gd->nbytes > 10) {    /* re-number all components */
            sal_uInt16 flags, index;
            sal_uInt8 *ptr = gd->ptr.get() + 10;
            size_t nRemaining = gd->nbytes - 10;
            do {
                if (nRemaining < 4)
                {
                    SAL_WARN("vcl.fonts""truncated font");
                    break;
                }
                flags = GetUInt16(ptr, 0);
                index = GetUInt16(ptr, 2);

                /* XXX use the sorted array of old to new glyphID mapping and do a binary search */
                sal_uInt32 j;
                for (j = 0; j < nGlyphs; j++) {
                    if (gid[j] == index) {
                        break;
                    }
                }
                /* printf("X: %d -> %d.\n", index, j); */

                PutUInt16(static_cast<sal_uInt16>(j), ptr, 2);

                ptr += 4;
                nRemaining -= 4;

                sal_uInt32 nAdvance = 0;
                if (flags & ARG_1_AND_2_ARE_WORDS) {
                    nAdvance += 4;
                } else {
                    nAdvance += 2;
                }

                if (flags & WE_HAVE_A_SCALE) {
                    nAdvance += 2;
                } else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
                    nAdvance += 4;
                } else if (flags & WE_HAVE_A_TWO_BY_TWO) {
                    nAdvance += 8;
                }

                if (nRemaining < nAdvance)
                {
                    SAL_WARN("vcl.fonts""truncated font");
                    break;
                }

                ptr += nAdvance;
                nRemaining -= nAdvance;

            } while (flags & MORE_COMPONENTS);
        }

        if (gd->nbytes != 0) {
            memcpy(p1, gd->ptr.get(), gd->nbytes);
        }
        if (indexToLocFormat == 1) {
            PutUInt32(p1 - glyfPtr.get(), p2, 0);
            p2 += 4;
        } else {
            PutUInt16(static_cast<sal_uInt16>((p1 - glyfPtr.get()) >> 1), p2, 0);
            p2 += 2;
        }
        p1 += gd->nbytes;

        /* fill the array of metrics */
        met[i].adv = gd->aw;
        met[i].sb  = gd->lsb;
        i++;
    }

    gid.reset();

    if (indexToLocFormat == 1) {
        PutUInt32(p1 - glyfPtr.get(), p2, 0);
    } else {
        PutUInt16(static_cast<sal_uInt16>((p1 - glyfPtr.get()) >> 1), p2, 0);
    }

    glyf->m_rawdata = std::move(glyfPtr);

    loca.reset(new TrueTypeTableLoca());
    loca->m_loca->ptr = std::move(locaPtr);
    loca->m_loca->nbytes = locaLen;

    AddTable(std::move(loca));

    head = static_cast<TrueTypeTableHead*>(FindTable(T_head));
    sal_uInt8* const pHeadData = head->m_head.get();
    PutInt16(xMin, pHeadData, HEAD_xMin_offset);
    PutInt16(yMin, pHeadData, HEAD_yMin_offset);
    PutInt16(xMax, pHeadData, HEAD_xMax_offset);
    PutInt16(yMax, pHeadData, HEAD_yMax_offset);
    PutInt16(indexToLocFormat, pHeadData, HEAD_indexToLocFormat_offset);

    maxp = static_cast<TrueTypeTableMaxp*>(FindTable(T_maxp));

    sal_uInt8* const pMaxpData = maxp->m_maxp.get();
    PutUInt16(static_cast<sal_uInt16>(nGlyphs), pMaxpData, MAXP_numGlyphs_offset);
    PutUInt16(maxPoints, pMaxpData, MAXP_maxPoints_offset);
    PutUInt16(maxContours, pMaxpData, MAXP_maxContours_offset);
    PutUInt16(maxCompositePoints, pMaxpData, MAXP_maxCompositePoints_offset);
    PutUInt16(maxCompositeContours, pMaxpData, MAXP_maxCompositeContours_offset);

    /*
     * Generate an htmx table and update hhea table
     */

    hhea = static_cast<TrueTypeTableHhea*>(FindTable(T_hhea)); assert(hhea != nullptr);
    hheaPtr = hhea->m_hhea.get();
    if (nGlyphs > 2) {
        for (i = nGlyphs - 1; i > 0; i--) {
            if (met[i].adv != met[i-1].adv) break;
        }
        nlsb = nGlyphs - 1 - i;
    }
    hmtxSize = (nGlyphs - nlsb) * 4 + nlsb * 2;
    hmtxPtr = ttmalloc(hmtxSize);
    p1 = hmtxPtr.get();

    for (i = 0; i < nGlyphs; i++) {
        if (i < nGlyphs - nlsb) {
            PutUInt16(met[i].adv, p1, 0);
            PutUInt16(met[i].sb, p1, 2);
            p1 += 4;
        } else {
            PutUInt16(met[i].sb, p1, 0);
            p1 += 2;
        }
    }

    AddTable(std::make_unique<TrueTypeTableGeneric>(T_hmtx, hmtxSize, std::move(hmtxPtr)));
    PutUInt16(static_cast<sal_uInt16>(nGlyphs - nlsb), hheaPtr, 34);
}

/**
 * TrueTypeCreator destructor. It calls destructors for all TrueTypeTables added to it.
 */

TrueTypeCreator::~TrueTypeCreator()
{
}

// namespace vcl

#ifdef TEST_TTCR
static sal_uInt32 mkTag(sal_uInt8 a, sal_uInt8 b, sal_uInt8 c, sal_uInt8 d) {
    return (a << 24) | (b << 16) | (c << 8) | d;
}

int main()
{
    TrueTypeCreator *ttcr;
    sal_uInt8 *t1, *t2, *t3, *t4, *t5, *t6;

    TrueTypeCreatorNewEmpty(mkTag('t','r','u','e'), &ttcr);

    t1 = malloc(1000); memset(t1, 'a', 1000);
    t2 = malloc(2000); memset(t2, 'b', 2000);
    t3 = malloc(3000); memset(t3, 'c', 3000);
    t4 = malloc(4000); memset(t4, 'd', 4000);
    t5 = malloc(5000); memset(t5, 'e', 5000);
    t6 = malloc(6000); memset(t6, 'f', 6000);

    AddTable(ttcr, TrueTypeTableNew(T_maxp, 1000, t1));
    AddTable(ttcr, TrueTypeTableNew(T_OS2, 2000, t2));
    AddTable(ttcr, TrueTypeTableNew(T_cmap, 3000, t3));
    AddTable(ttcr, TrueTypeTableNew(T_loca, 4000, t4));
    AddTable(ttcr, TrueTypeTableNew(T_hhea, 5000, t5));
    AddTable(ttcr, TrueTypeTableNew(T_glyf, 6000, t6));

    free(t1);
    free(t2);
    free(t3);
    free(t4);
    free(t5);
    free(t6);

    StreamToFile(ttcr, "ttcrout.ttf");

    TrueTypeCreatorDispose(ttcr);
    return 0;
}
#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=92 G=92

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.