[fondue-commits] [SCM] Fondue Font Editor branch, master, updated. f602a45688c78ea6a94078a3ffdb41d0e7e20c59
Eugeniy Meshcheryakov
eugen at debian.org
Thu Aug 30 19:34:57 UTC 2007
The branch, master has been updated
via f602a45688c78ea6a94078a3ffdb41d0e7e20c59 (commit)
from 885121fe2a3d91ccca86282712fd4423efe7f97d (commit)
- Shortlog ------------------------------------------------------------
f602a45 Add some primitive ttf export capability
Summary of changes:
gui/mainwindow.cxx | 30 +++
gui/mainwindow.h | 2 +
nongui/nongui.rules | 6 +-
nongui/ttfwriter.cxx | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++
nongui/ttfwriter.h | 53 +++++
5 files changed, 641 insertions(+), 2 deletions(-)
-----------------------------------------------------------------------
Details of changes:
commit f602a45688c78ea6a94078a3ffdb41d0e7e20c59
Author: Eugeniy Meshcheryakov <eugen at debian.org>
Date: Thu Aug 30 21:34:44 2007 +0200
Add some primitive ttf export capability
Created ttf file does not contain all required tables.
It is enough for ttx, but not for fntsample or fontforge.
It is not possible to export fonts that contain glyphs with
both contours and references.
Complex glyphs are exported as empty glyphs.
Some tables contain invalid values.
diff --git a/gui/mainwindow.cxx b/gui/mainwindow.cxx
index 940beed..c6ea988 100644
--- a/gui/mainwindow.cxx
+++ b/gui/mainwindow.cxx
@@ -34,6 +34,7 @@
#include "unicodeproxymodel.h"
#include "cvtmodel.h"
#include "cvteditor.h"
+#include "ttfwriter.h"
#include "config.h"
@@ -78,6 +79,9 @@ void MainWindow::createActions()
saveAsAction = new QAction("Save &As...", this);
connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
+ exportTTFAction = new QAction("Export As TTF...", this);
+ connect(exportTTFAction, SIGNAL(triggered()), this, SLOT(exportTTF()));
+
cellSizeGroup = new QActionGroup(this);
for (int i = 0; i < 5; i++) {
int size = (i + 2) * 16;
@@ -102,12 +106,14 @@ void MainWindow::createActions()
saveAction->setEnabled(false);
saveAsAction->setEnabled(false);
+ exportTTFAction->setEnabled(false);
editPrepAction->setEnabled(false);
editFpgmAction->setEnabled(false);
editCvtAction->setEnabled(false);
connect(this, SIGNAL(documentAvailable(bool)), saveAction, SLOT(setEnabled(bool)));
connect(this, SIGNAL(documentAvailable(bool)), saveAsAction, SLOT(setEnabled(bool)));
+ connect(this, SIGNAL(documentAvailable(bool)), exportTTFAction, SLOT(setEnabled(bool)));
connect(this, SIGNAL(documentAvailable(bool)), editPrepAction, SLOT(setEnabled(bool)));
connect(this, SIGNAL(documentAvailable(bool)), editFpgmAction, SLOT(setEnabled(bool)));
connect(this, SIGNAL(documentAvailable(bool)), editCvtAction, SLOT(setEnabled(bool)));
@@ -119,6 +125,7 @@ void MainWindow::createMenus()
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addAction(saveAsAction);
+ fileMenu->addAction(exportTTFAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
@@ -279,6 +286,29 @@ bool MainWindow::saveAs()
return saveFile(fileName);
}
+bool MainWindow::exportTTF()
+{
+ QString fileName = QFileDialog::getSaveFileName(this, 0, 0, "TrueType Font File (*.ttf)");
+ if (fileName.isEmpty())
+ return false;
+ QFile file(fileName);
+ if (!file.open(QFile::WriteOnly | QFile::Truncate)) {
+ QMessageBox::warning(this, "Fondue", QString("Cannot write file %1:\n%2")
+ .arg(fileName)
+ .arg(file.errorString()));
+ return false;
+ }
+
+ Q_ASSERT(m_doc);
+ TTFWriter writer(m_doc);
+ if (!writer.write(&file)) {
+ QMessageBox::warning(this, "Fondue", QString("Cannot export to TrueType."));
+ return false;
+ }
+ file.close();
+ return true;
+}
+
void MainWindow::editPrep()
{
#if 0
diff --git a/gui/mainwindow.h b/gui/mainwindow.h
index b30e91d..8e9ea2f 100644
--- a/gui/mainwindow.h
+++ b/gui/mainwindow.h
@@ -42,6 +42,7 @@ public slots:
void open();
bool save();
bool saveAs();
+ bool exportTTF();
void editPrep();
void editFpgm();
@@ -87,6 +88,7 @@ private:
QAction *openAction;
QAction *saveAction;
QAction *saveAsAction;
+ QAction *exportTTFAction;
QActionGroup *cellSizeGroup;
QAction *cellSizeActions[5];
diff --git a/nongui/nongui.rules b/nongui/nongui.rules
index 3996943..0d48576 100644
--- a/nongui/nongui.rules
+++ b/nongui/nongui.rules
@@ -6,7 +6,8 @@ libfonduenongui_a_SOURCES = \
nongui/fontdocumentwriter.cxx \
nongui/fontdocument.cxx \
nongui/ttfencode.cxx \
- nongui/cvtmodel.cxx
+ nongui/cvtmodel.cxx \
+ nongui/ttfwriter.cxx
nodist_libfonduenongui_a_SOURCES = \
nongui/decodertable.tbl.cxx \
@@ -37,7 +38,8 @@ noinst_HEADERS += \
nongui/lookup.h \
nongui/script.h \
nongui/ttfencode.h \
- nongui/cvtmodel.h
+ nongui/cvtmodel.h \
+ nongui/ttfwriter.h
EXTRA_DIST += \
nongui/decodertable.xsl \
diff --git a/nongui/ttfwriter.cxx b/nongui/ttfwriter.cxx
new file mode 100644
index 0000000..7eba457
--- /dev/null
+++ b/nongui/ttfwriter.cxx
@@ -0,0 +1,552 @@
+/* Copyright (C) 2007 ÐвгенÑй ÐеÑеÑÑков <eugen at debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "ttfwriter.h"
+#include <QDebug>
+#include <QIODevice>
+#include <QtEndian>
+#include "cvtentry.h"
+#include "fontdocument.h"
+#include <QBuffer>
+#include "ttfencode.h"
+#include "contour.h"
+
+static inline quint32 makeTag(unsigned char a, unsigned char b,
+ unsigned char c, unsigned char d)
+{
+ return (a << 24) + (b << 16) + (c << 8) + d;
+}
+
+TTFWriter::TTFWriter(const FontDocument *doc) : m_doc(doc)
+{
+ Q_ASSERT(m_doc);
+}
+
+template <typename T>
+static bool writeBigEndian(QIODevice *dev, T v)
+{
+ Q_ASSERT(dev);
+ T be = qToBigEndian(v);
+ return dev->write((const char *)&be, sizeof(T)) == sizeof(T);
+}
+
+static quint32 tableChecksum(const QByteArray &table)
+{
+ quint32 sum = 0;
+ Q_ASSERT(table.size() % 4 == 0);
+ int nWords = table.size() / 4;
+ const quint32 *tableData = (const quint32 *)table.constData();
+ for (int i = 0; i < nWords; i++)
+ sum += qFromBigEndian(tableData[i]);
+ return sum;
+}
+
+bool TTFWriter::write(QIODevice *dev)
+{
+ Q_ASSERT(dev);
+ QByteArray output;
+ QBuffer buf(&output);
+
+ if (!writeCvt()) {
+ qDebug() << "writeCvt failed";
+ goto fail;
+ }
+ if (!writeFpgm()) {
+ qDebug() << "writeFpgm failed";
+ goto fail;
+ }
+ if (!writePrep()) {
+ qDebug() << "writePrep failed";
+ goto fail;
+ }
+ if (!writeGlyphs()) {
+ qDebug() << "writeGlyphs failed";
+ goto fail;
+ }
+ if (!writeMaxp()) {
+ qDebug() << "writeMaxp failed";
+ goto fail;
+ }
+ if (!writeHead()) {
+ qDebug() << "writeHead failed";
+ goto fail;
+ }
+ if (!writeCmap()) {
+ qDebug() << "writeCmap failed";
+ goto fail;
+ }
+ if (!writeName()) {
+ qDebug() << "writeName failed";
+ goto fail;
+ }
+ if (!writePost()) {
+ qDebug() << "writePost failed";
+ goto fail;
+ }
+ {
+ // TODO other tables, check order
+ buf.open(QBuffer::WriteOnly);
+
+ quint16 searchRange = 0;
+ quint16 nTables = tables.size();
+ for (int i = nTables / 2; i; i /= 2)
+ searchRange++;
+ quint16 entrySelector = 0;
+ for (int i = searchRange / 2; i; i /= 2)
+ entrySelector++;
+ searchRange *= 16;
+ quint16 rangeShift = nTables * 16 - searchRange;
+
+ bool ret = true;
+ ret = ret && writeBigEndian(&buf, (quint32)0x00010000); // Version aka scaler type
+ ret = ret && writeBigEndian(&buf, nTables); // Number of tables
+ ret = ret && writeBigEndian(&buf, searchRange);
+ ret = ret && writeBigEndian(&buf, entrySelector);
+ ret = ret && writeBigEndian(&buf, rangeShift);
+ if (!ret)
+ return false;
+
+ int offset = buf.pos() + 4 * 4 * nTables; // beginning of tables data
+ int headOffset = 0; // offset of head table, needed for checksum calculation
+ // write tables directory
+ QMapIterator<quint32, QByteArray> i(tables);
+ qDebug("Looking for: %04X", makeTag('h', 'e', 'a', 'd'));
+ while (i.hasNext()) {
+ i.next();
+ qDebug("Table tag: %04X", i.key());
+ if (i.key() == makeTag('h', 'e', 'a', 'd'))
+ headOffset = offset;
+ ret = true;
+ ret = ret && writeBigEndian(&buf, i.key()); // Table tag
+ ret = ret && writeBigEndian(&buf, tableChecksum(i.value()));
+ ret = ret && writeBigEndian(&buf, (quint32)offset);
+ ret = ret && writeBigEndian(&buf, tableLengths[i.key()]); // real length of a table
+ if (!ret)
+ return false;
+ offset += i.value().size();
+ }
+ Q_ASSERT(headOffset);
+ // write tables
+ i.toFront();
+ while (i.hasNext()) {
+ i.next();
+ if (buf.write(i.value()) != i.value().size())
+ return false;
+ }
+ // calculate checksum and write it into head table
+ buf.close();
+ quint32 ckSum = 0xB1B0AFBA - tableChecksum(output);
+ buf.open(QBuffer::WriteOnly);
+ buf.seek(headOffset + 8); // checksum field of head table
+ if (!writeBigEndian(&buf, ckSum))
+ return false;
+ buf.close();
+
+ if (dev->write(output) != output.size())
+ return false;
+
+ return true;
+ }
+fail:
+ return false;
+}
+
+bool TTFWriter::writeCvt()
+{
+ int ret = true;
+
+ const QVector<CVTEntry> &cvt = m_doc->cvt();
+ if (!cvt.isEmpty()) {
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ foreach (const CVTEntry &ent, cvt) {
+ ret = ret && writeBigEndian(&buffer, ent.value());
+ }
+
+ buffer.close();
+ if (ret)
+ appendTable(makeTag('c', 'v', 't', ' '), tbl);
+ }
+ return ret;
+}
+
+bool TTFWriter::writeFpgm()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ TTInstructionsEncoder encoder(m_doc->fpgm());
+ bool ret = encoder.encode(&buffer);
+ if (!ret)
+ return false;
+ buffer.close();
+ if (!tbl.isEmpty())
+ appendTable(makeTag('f', 'p', 'g', 'm'), tbl);
+ return true;
+}
+
+bool TTFWriter::writePrep()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ TTInstructionsEncoder encoder(m_doc->prep());
+ bool ret = encoder.encode(&buffer);
+ if (!ret)
+ return false;
+ buffer.close();
+
+ if (!tbl.isEmpty())
+ appendTable(makeTag('p', 'r', 'e', 'p'), tbl);
+ return true;
+}
+
+bool TTFWriter::writeGlyphs()
+{
+ QByteArray glyfTbl;
+ QBuffer glyfBuffer(&glyfTbl);
+ QByteArray locaTbl;
+ QBuffer locaBuffer(&locaTbl);
+
+ glyfBuffer.open(QBuffer::WriteOnly);
+ locaBuffer.open(QBuffer::WriteOnly);
+
+ // FIXME using 32-bit version of loca table
+ // write offset of .notdef glyph
+ if (!writeBigEndian(&locaBuffer, (quint32)0))
+ return false;
+ // TODO move .notdef to the begining of the font
+
+ // TODO skip glyphs that only have color
+ foreach (const Glyph *g, m_doc->glyphs()) {
+ int nContours = 0;
+ int nRefs = 0;
+
+ // write offset of the glyphs into loca table
+ if (!writeBigEndian(&locaBuffer, (quint32)glyfBuffer.pos()))
+ return false;
+
+ // is glyph simple, composite, empty or invalid?
+ foreach (QVariant v, g->content) {
+ if (v.canConvert<Contour>())
+ nContours++;
+ else
+ nRefs++;
+ }
+ if (nContours && nRefs) {
+ qDebug() << "Invalid glyph found:" << g->objectName();
+ return false; // glyph is invalid
+ }
+
+ bool ret = true;
+ if (nRefs)
+ ret = writeCompositeGlyph(&glyfBuffer, g);
+ else if (nContours)
+ ret = writeSimpleGlyph(&glyfBuffer, g);
+ if (!ret)
+ return false;
+ }
+
+ if (!writeBigEndian(&locaBuffer, (quint32)glyfBuffer.pos()))
+ return false;
+
+ glyfBuffer.close();
+ locaBuffer.close();
+
+ appendTable(makeTag('l', 'o', 'c', 'a'), locaTbl);
+ appendTable(makeTag('g', 'l', 'y', 'f'), glyfTbl);
+ return true;
+}
+
+bool TTFWriter::writeCompositeGlyph(QIODevice *dev, const Glyph *g)
+{
+ // XXX TODO ignore composite glyphs for now
+ Q_UNUSED(dev);
+ Q_UNUSED(g);
+ return true;
+}
+
+static bool computeMinMax(const QList<QVariant> &content,
+ qint16 &xMin, qint16 &xMax, qint16 &yMin, qint16 &yMax)
+{
+ if (!content.size()) {
+ xMin = xMax = yMin = yMax = 0;
+ return true;
+ }
+ Contour c = content.at(0).value<Contour>();
+ if (!c.size())
+ return false; // empty contours are not allowed
+ xMin = xMax = (qint16)c.at(0).x();
+ yMin = yMax = (qint16)c.at(0).y();
+
+ foreach (QVariant v, content) {
+ Q_ASSERT(v.canConvert<Contour>());
+ c = v.value<Contour>();
+ if (c.isOpen())
+ return false; // not allowed
+ if (!c.size())
+ return false;
+ foreach (const GlyphPoint &pt, c) {
+ qint16 x = (qint16)pt.x();
+ qint16 y = (qint16)pt.y();
+ if (xMin > x) xMin = x;
+ if (xMax < x) xMax = x;
+ if (yMin > y) yMin = y;
+ if (yMax < y) yMax = y;
+ }
+ }
+ return true;
+}
+
+#define TTFLAG_ON_CURVE 1
+
+bool TTFWriter::writeSimpleGlyph(QIODevice *dev, const Glyph *g)
+{
+ qint16 nContours = g->content.size();
+ qint16 xMin, xMax, yMin, yMax;
+ if (!computeMinMax(g->content, xMin, xMax, yMin, yMax)) {
+ qDebug() << "computeMinMax failed:" << g->objectName();
+ return false;
+ }
+ bool ret = writeBigEndian(dev, nContours);
+ ret = ret && writeBigEndian(dev, xMin);
+ ret = ret && writeBigEndian(dev, yMin);
+ ret = ret && writeBigEndian(dev, xMax);
+ ret = ret && writeBigEndian(dev, yMax);
+ if (!ret)
+ return false;
+ // write endpoints of contours
+ int nPoints = 0;
+ foreach (QVariant v, g->content) {
+ Contour c = v.value<Contour>();
+ nPoints += c.size();
+ if (!writeBigEndian(dev, (qint16)(nPoints - 1)))
+ return false;
+ }
+ // write instructions, if any
+ QByteArray insts;
+ if (!g->instructions().isEmpty()) {
+ // TODO check if instructions are valid
+ QBuffer instsBuf(&insts);
+ instsBuf.open(QBuffer::WriteOnly);
+ TTInstructionsEncoder encoder(g->instructions());
+ if (!encoder.encode(&instsBuf)) {
+ qDebug() << "Bad instructions for glyph" << g->objectName();
+ return false;
+ }
+ instsBuf.close();
+ }
+ if (!writeBigEndian(dev, (quint16)insts.size())) // number of instructions...
+ return false;
+ if (dev->write(insts) != insts.size()) // ...and instructions itself
+ return false;
+ // write flags
+ // TODO optimize those flags
+ foreach (QVariant v, g->content) {
+ Contour c = v.value<Contour>();
+ foreach (const GlyphPoint &pt, c) {
+ char flags = 0;
+ if (pt.on())
+ flags |= TTFLAG_ON_CURVE;
+ if (!dev->putChar(flags))
+ return false;
+ }
+ }
+ // write coordiantes
+ // all coordinates are 16-bit for now
+ // start with x-coordinates
+ foreach (QVariant v, g->content) {
+ qint16 prev = 0;
+ Contour c = v.value<Contour>();
+ // XXX FIXME coordinates should be relative!
+ foreach (const GlyphPoint &pt, c) {
+ qint16 thisPoint = (qint16)pt.x();
+ if (!writeBigEndian<qint16>(dev, thisPoint - prev))
+ return false;
+ prev = thisPoint;
+ }
+ }
+ // and y-coordinates
+ foreach (QVariant v, g->content) {
+ qint16 prev = 0;
+ Contour c = v.value<Contour>();
+ foreach (const GlyphPoint &pt, c) {
+ qint16 thisPoint = (qint16)pt.y();
+ if (!writeBigEndian<qint16>(dev, thisPoint - prev))
+ return false;
+ prev = thisPoint;
+ }
+ }
+ return true;
+}
+
+void TTFWriter::appendTable(quint32 tag, QByteArray &table)
+{
+ tableLengths[tag] = table.size();
+
+ // table size must be multiple of 4
+ if (table.size() % 4) {
+ int size = table.size();
+ for (int i = 0; i < (4 - size % 4); i++)
+ table.append('\0');
+ }
+ tables[tag] = table;
+}
+
+bool TTFWriter::writeMaxp()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ bool ret = true;
+ ret = ret && writeBigEndian(&buffer, (qint32)0x00010000); // Table version
+ ret = ret && writeBigEndian(&buffer, (qint16)(m_doc->glyphs().size() + 1)); // number of glyphs // FIXME +1 is for .notdef
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max number of points in non-composite glyph
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max number of contours in non-composite glyph
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max number of points in composite glyph
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max number of contours in composite glyph
+ ret = ret && writeBigEndian(&buffer, (qint16)2); // Max number of zones
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max number of points in Z0
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max storage
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Number of FDEFs
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Number of IDEFs
+ ret = ret && writeBigEndian(&buffer, (qint16)1000); // FIXME Max stack depth
+ ret = ret && writeBigEndian(&buffer, (qint16)10000); // FIXME Max size of instructions
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max top-level components
+ ret = ret && writeBigEndian(&buffer, (qint16)100); // FIXME Max levels of recursion
+ buffer.close();
+
+ if (ret)
+ appendTable(makeTag('m', 'a', 'x', 'p'), tbl);
+
+ return ret;
+}
+
+bool TTFWriter::writeHead()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ bool ret = true;
+ ret = ret && writeBigEndian(&buffer, (qint32)0x00010000); // Version number
+ ret = ret && writeBigEndian(&buffer, (qint32)0); // FIXME Font revision
+ ret = ret && writeBigEndian(&buffer, (qint32)0); // Check sum - will be set to real value later
+ ret = ret && writeBigEndian(&buffer, (qint32)0x5F0F3CF5); // Magic number
+ ret = ret && writeBigEndian(&buffer, (qint16)0x1F); // Flags TODO use symbolic names
+ ret = ret && writeBigEndian(&buffer, (qint16)2048); // FIXME Units per em
+ ret = ret && writeBigEndian(&buffer, Q_INT64_C(0)); // FIXME Creation time
+ ret = ret && writeBigEndian(&buffer, Q_INT64_C(0)); // FIXME Modification time
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME xMin
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME yMin
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME xMax
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME yMax
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME Mac style
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // FIXME Smallest readable size in pixels
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // Font direction hint
+ ret = ret && writeBigEndian(&buffer, (qint16)1); // loca format; 1 - long
+ ret = ret && writeBigEndian(&buffer, (qint16)0); // Glyph data format
+ buffer.close();
+
+ if (ret)
+ appendTable(makeTag('h', 'e', 'a', 'd'), tbl);
+
+ return ret;
+}
+
+bool TTFWriter::writeCmap()
+{
+ // XXX TODO writes minimal cmap
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+ buffer.open(QBuffer::WriteOnly);
+
+ bool ret = true;
+ // Table header
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // Version
+ ret = ret && writeBigEndian(&buffer, (quint16)1); // FIXME Number of subtables
+
+ // Subtables
+ ret = ret && writeBigEndian(&buffer, (quint16)3); // Platform ID, 3 - MS
+ ret = ret && writeBigEndian(&buffer, (quint16)1); // Encoding ID, 1 - Unicode
+ ret = ret && writeBigEndian(&buffer, (quint32)12); // FIXME offset of cmap
+ // Type 4 cmap
+ ret = ret && writeBigEndian(&buffer, (quint16)4); // cmap format
+ ret = ret && writeBigEndian(&buffer, (quint16)24); // FIXME Length
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // Language
+ ret = ret && writeBigEndian(&buffer, (quint16)2); // FIXME 2 * SegCount
+ ret = ret && writeBigEndian(&buffer, (quint16)4); // FIXME Search range
+ ret = ret && writeBigEndian(&buffer, (quint16)1); // FIXME Entry selector
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // FIXME Range shift
+ ret = ret && writeBigEndian(&buffer, (quint16)0xFFFF); // End code
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // Reserved
+ ret = ret && writeBigEndian(&buffer, (quint16)0xFFFF); // Start code
+ ret = ret && writeBigEndian(&buffer, (quint16)1); // FIXME ID delta
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // FIXME ID range offset
+ buffer.close();
+ if (ret)
+ appendTable(makeTag('c', 'm', 'a', 'p'), tbl);
+ return ret;
+}
+
+bool TTFWriter::writeName()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+
+ buffer.open(QBuffer::WriteOnly);
+ bool ret = true;
+ // TODO
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // Format
+ ret = ret && writeBigEndian(&buffer, (quint16)0); // FIXME Count
+ ret = ret && writeBigEndian(&buffer, (quint16)6); // FIXME Offset to strings
+ // records - skipped
+ // strings - skipped
+ buffer.close();
+
+ if (ret)
+ appendTable(makeTag('n', 'a', 'm', 'e'), tbl);
+ return ret;
+}
+
+bool TTFWriter::writePost()
+{
+ QByteArray tbl;
+ QBuffer buffer(&tbl);
+
+ buffer.open(QBuffer::WriteOnly);
+ // TODO write real post table, or not?
+ bool ret = true;
+ ret = ret && writeBigEndian(&buffer, (quint32)0x00030000); // FIXME Table format, 3 - no names
+ ret = ret && writeBigEndian(&buffer, (quint32)(m_doc->italicAngle() * 0x10000)); // Italic angle
+ ret = ret && writeBigEndian(&buffer, (qint16)m_doc->underlinePosition()); // Underline position
+ ret = ret && writeBigEndian(&buffer, (qint16)m_doc->underlineThickness()); // Underline thickness
+ ret = ret && writeBigEndian(&buffer, (quint32)0); // Fixed pitch, 0 - no
+ ret = ret && writeBigEndian(&buffer, (quint32)0); // Min mem type42 - unknown
+ ret = ret && writeBigEndian(&buffer, (quint32)0); // Max mem type42 - unknown
+ ret = ret && writeBigEndian(&buffer, (quint32)0); // Min mem type1 - unknown
+ ret = ret && writeBigEndian(&buffer, (quint32)0); // Max mem type1 - unknown
+ buffer.close();
+
+ if (ret)
+ appendTable(makeTag('p', 'o', 's', 't'), tbl);
+ return ret;
+}
diff --git a/gui/ttihighlighter.h b/nongui/ttfwriter.h
similarity index 55%
copy from gui/ttihighlighter.h
copy to nongui/ttfwriter.h
index d13180b..3c1d403 100644
--- a/gui/ttihighlighter.h
+++ b/nongui/ttfwriter.h
@@ -14,30 +14,40 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef TTIHIGHLIGHTER_H
-#define TTIHIGHLIGHTER_H
-#include <QSyntaxHighlighter>
+#ifndef TTFWRITER_H
+#define TTFWRITER_H
+#include <QMap>
+#include <QByteArray>
+#include <QHash>
-class QRegExp;
+class FontDocument;
+class QIODevice;
+class Glyph;
-class TTIHighlighter : public QSyntaxHighlighter
-{
- Q_OBJECT
+class TTFWriter {
public:
- TTIHighlighter(QTextDocument *parent = 0);
-protected:
- void highlightBlock(const QString &text);
+ TTFWriter(const FontDocument *doc);
+ bool write(QIODevice *dev);
private:
- struct HighlightingRule
- {
- QRegExp pattern;
- Qt::CaseSensitivity cs;
- QTextCharFormat format;
- };
+ bool writeCvt();
+ bool writeFpgm();
+ bool writePrep();
+ bool writeGlyphs();
+ bool writeMaxp();
+ bool writeHead();
+ bool writeCmap();
+ bool writeName();
+ bool writePost();
- QVector<HighlightingRule> highlightingRules;
+ bool writeCompositeGlyph(QIODevice *dev, const Glyph *g);
+ bool writeSimpleGlyph(QIODevice *dev, const Glyph *g);
- static const char* const instructions[];
+ void appendTable(quint32 tag, QByteArray &table);
+
+ const FontDocument *m_doc;
+
+ QMap<quint32, QByteArray> tables;
+ QHash<quint32, quint32> tableLengths;
};
#endif
--
Fondue Font Editor
More information about the fondue-commits
mailing list