diff --git a/toonz/sources/common/tvrender/tfont_qt.cpp b/toonz/sources/common/tvrender/tfont_qt.cpp new file mode 100644 index 0000000..dfb68c7 --- /dev/null +++ b/toonz/sources/common/tvrender/tfont_qt.cpp @@ -0,0 +1,462 @@ + + +// character_manager.cpp: implementation of the TFont class +// for FreeType 2. +// +////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "tpixelgr.h" +#include "tfont.h" +#include "tstroke.h" +#include "tcurves.h" +#include "traster.h" +#include "tmathutil.h" +#include "tvectorimage.h" +using namespace std; + +//============================================================================= + +struct TFont::Impl { + bool m_hasKerning; + int m_hasVertical; + QFont m_font; + // XXX:cache a QFontMetrics m_metrics; ? + // XXX:cache a QRawFont m_raw; ? + + // KerningPairs m_kerningPairs; + + Impl(const QString &family, const QString &style, int size); + ~Impl(); + + // void getChar(); +}; + +//----------------------------------------------------------------------------- + +TFont::TFont(const wstring family, const wstring face, int size) { + m_pimpl = new Impl(QString::fromStdWString(family), + QString::fromStdWString(face), size); +} + +//----------------------------------------------------------------------------- + +TFont::~TFont() { delete m_pimpl; } + +//----------------------------------------------------------------------------- + +TFont::Impl::Impl(const QString &family, const QString &style, int size) { + m_font = QFont(family, size); + m_font.setStyleName(style); +} + +//----------------------------------------------------------------------------- + +TFont::Impl::~Impl() {} + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- + +TPoint TFont::drawChar(TVectorImageP &image, wchar_t charcode, + wchar_t nextCharCode) const { + QRawFont raw(QRawFont::fromFont(m_pimpl->m_font)); + + QChar chars[2] = {charcode, nextCharCode}; + quint32 indices[2]; + int count = 2; + + if (!raw.glyphIndexesForChars(chars, 2, indices, &count) || count < 1) + return TPoint(0, 0); + QPainterPath path = raw.pathForGlyph(indices[0]); + + // empty glyph, nothing to do + if (path.elementCount() < 1) return getDistance(charcode, nextCharCode); + + // force closing the last path + if (path.elementAt(path.elementCount() - 1).type != QPainterPath::MoveToElement) { + path.moveTo(0.0, 0.0); + } + + int i, n = path.elementCount(); + int strokes = 0; + std::vector points; + + TThickPoint pts[4]; + int nCubicPts = 0; + + for (i = 0; i < n; i++) { + QPainterPath::Element e = path.elementAt(i); + e.y = -e.y; + + switch (e.type) { + case QPainterPath::MoveToElement: + if (!points.empty()) { + if (points.back() != points.front()) { + points.push_back(0.5 * (points.back() + points.front())); + points.push_back(points.front()); + } + + TStroke *stroke = new TStroke(points); + stroke->setSelfLoop(true); + image->addStroke(stroke); + strokes++; + points.clear(); + } + points.push_back(TThickPoint(e.x, e.y, 0)); + break; + case QPainterPath::LineToElement: { + TThickPoint p0 = points.back(); + TThickPoint p1 = TThickPoint(e.x, e.y, 0); + points.push_back((p0 + p1) * 0.5); + points.push_back(p1); + break; + } + case QPainterPath::CurveToElement: + pts[0] = points.back(); + pts[1] = TThickPoint(e.x, e.y, 0); + nCubicPts = 2; + break; + case QPainterPath::CurveToDataElement: + pts[nCubicPts++] = TThickPoint(e.x, e.y, 0); + if (nCubicPts == 4) { + vector chunkArray; + computeQuadraticsFromCubic(pts[0], pts[1], pts[2], pts[3], 0.09, + chunkArray); + + for (int j = 0; j < chunkArray.size(); j++) { + points.push_back(chunkArray[j]->getP1()); + points.push_back(chunkArray[j]->getP2()); + } + nCubicPts = 0; + } + break; + } + } + + if (strokes > 1) image->group(0, strokes); + + return getDistance(charcode, nextCharCode); +} + +//----------------------------------------------------------------------------- + +TPoint TFont::drawChar(TRasterGR8P &outImage, TPoint &unused, wchar_t charcode, + wchar_t nextCharCode) const { + QRawFont raw(QRawFont::fromFont(m_pimpl->m_font)); + + QChar chars[2] = {charcode, nextCharCode}; + quint32 indices[2]; + int count = 2; + + if (!raw.glyphIndexesForChars(chars, 2, indices, &count) || count < 1) { + return TPoint(0, 0); + } + + QImage image(raw.alphaMapForGlyph(indices[0], QRawFont::PixelAntialiasing)); + + if (image.format() != QImage::Format_Indexed8) + throw TException(L"bad QImage format " + image.format()); + + int height = image.height(); + int width = image.width(); + + outImage = TRasterGR8P(width, height); + +#if 0 + TPixelGR8 bgp; + bgp.value = 255; + outImage->fill(bgp); +#endif + void *data = outImage->getRawData(); + + memcpy(data, image.bits(), image.byteCount()); + + return getDistance(charcode, nextCharCode); +} + +//----------------------------------------------------------------------------- + +TPoint TFont::drawChar(TRasterCM32P &outImage, TPoint &unused, int inkId, + wchar_t charcode, wchar_t nextCharCode) const { + TRasterGR8P grayAppImage; + this->drawChar(grayAppImage, unused, charcode, nextCharCode); + + int lx = grayAppImage->getLx(); + int ly = grayAppImage->getLy(); + + outImage = TRasterCM32P(lx, ly); + + assert(TPixelCM32::getMaxTone() == 255); + TPixelCM32 bgColor(0, 0, TPixelCM32::getMaxTone()); + grayAppImage->lock(); + outImage->lock(); + int ty = 0; + for (int gy = ly - 1; gy >= 0; --gy, ++ty) { + TPixelGR8 *srcPix = grayAppImage->pixels(gy); + TPixelCM32 *tarPix = outImage->pixels(ty); + for (int x = 0; x < lx; ++x) { + int tone = srcPix->value; + + if (tone == 255) + *tarPix = bgColor; + else + *tarPix = TPixelCM32(inkId, 0, tone); + + ++srcPix; + ++tarPix; + } + } + grayAppImage->unlock(); + outImage->unlock(); + + return getDistance(charcode, nextCharCode); +} + +//----------------------------------------------------------------------------- + +TPoint TFont::getDistance(wchar_t firstChar, wchar_t secondChar) const { + QRawFont raw(QRawFont::fromFont(m_pimpl->m_font)); + QChar chars[2] = {firstChar, secondChar}; + quint32 indices[2]; + QPointF advances[2]; + int count = 2; + + if (!raw.glyphIndexesForChars(chars, 2, indices, &count) || count != 2) { + return TPoint(0, 0); + } + + if (!raw.advancesForGlyphIndexes(indices, advances, 2, QRawFont::KernedAdvances)) { + return TPoint(0, 0); + } + + int advance = (int)(advances[0].x()); + + return TPoint(advance, 0); +} + +//----------------------------------------------------------------------------- + +int TFont::getMaxHeight() const { + QFontMetrics metrics(m_pimpl->m_font); + return metrics.ascent() - metrics.descent(); +} + +//----------------------------------------------------------------------------- + +int TFont::getMaxWidth() const { + QFontMetrics metrics(m_pimpl->m_font); + return metrics.maxWidth(); +} +//----------------------------------------------------------------------------- + +int TFont::getLineAscender() const { + QFontMetrics metrics(m_pimpl->m_font); + return metrics.ascent(); +} + +//----------------------------------------------------------------------------- + +int TFont::getLineDescender() const { + QFontMetrics metrics(m_pimpl->m_font); + return metrics.descent(); +} + +//----------------------------------------------------------------------------- + +bool TFont::hasKerning() const { return m_pimpl->m_font.kerning(); } + +//----------------------------------------------------------------------------- + +bool TFont::hasVertical() const { + // FIXME + return false; +} + +//----------------------------------------------------------------------------- + +//============================================================================= +//==================== TFontManager ===================================== +//============================================================================= + +//--------------------------------------------------------- + +struct TFontManager::Impl { + QFontDatabase *m_qfontdb; + bool m_loaded; + + TFont *m_currentFont; + wstring m_currentFamily; + wstring m_currentTypeface; + int m_size; + + // this option is set by library user when he wants to write vertically. + // In this implementation, if m_vertical is true and the font + // has the @-version, the library use it. + bool m_vertical; + + Impl() + : m_qfontdb(NULL) + , m_loaded(false) + , m_currentFont(0) + , m_size(0) + , m_vertical(false) {} + ~Impl() { delete m_qfontdb; } +}; + +//--------------------------------------------------------- + +TFontManager::TFontManager() { m_pimpl = new TFontManager::Impl(); } + +//--------------------------------------------------------- + +TFontManager::~TFontManager() { delete m_pimpl; } + +//--------------------------------------------------------- + +TFontManager *TFontManager::instance() { + static TFontManager theManager; + return &theManager; +} + +//--------------------------------------------------------- + +void TFontManager::loadFontNames() { + if (m_pimpl->m_loaded) return; + + m_pimpl->m_qfontdb = new QFontDatabase; + + if (m_pimpl->m_qfontdb->families().empty()) throw TFontLibraryLoadingError(); + + m_pimpl->m_loaded = true; +} + +//--------------------------------------------------------- + +void TFontManager::setFamily(const wstring family) { + if (m_pimpl->m_currentFamily == family) return; + + QString qFamily = QString::fromStdWString(family); + QStringList families = m_pimpl->m_qfontdb->families(); + if (!families.contains(qFamily)) throw TFontCreationError(); + + m_pimpl->m_currentFamily = family; + + // XXX: if current style is not valid for family, reset it? + // doing so asserts when chosing a font in the GUI +#if 0 + QStringList styles = m_pimpl->m_qfontdb->styles(qFamily); + if (styles.contains(QString::fromStdWString(m_pimpl->m_currentTypeface))) { + m_pimpl->m_currentTypeface = L""; + } +#endif + delete m_pimpl->m_currentFont; + m_pimpl->m_currentFont = new TFont( + m_pimpl->m_currentFamily, m_pimpl->m_currentTypeface, m_pimpl->m_size); +} + +//--------------------------------------------------------- + +void TFontManager::setTypeface(const wstring typeface) { + if (m_pimpl->m_currentTypeface == typeface) return; + + QString qTypeface = QString::fromStdWString(typeface); + QStringList styles = m_pimpl->m_qfontdb->styles( + QString::fromStdWString(m_pimpl->m_currentFamily)); + if (!styles.contains(qTypeface)) { + throw TFontCreationError(); + } + + m_pimpl->m_currentTypeface = typeface; + + delete m_pimpl->m_currentFont; + m_pimpl->m_currentFont = new TFont( + m_pimpl->m_currentFamily, m_pimpl->m_currentTypeface, m_pimpl->m_size); +} + +//--------------------------------------------------------- + +void TFontManager::setSize(int size) { + if (m_pimpl->m_size == size) return; + m_pimpl->m_size = size; + delete m_pimpl->m_currentFont; + m_pimpl->m_currentFont = new TFont( + m_pimpl->m_currentFamily, m_pimpl->m_currentTypeface, m_pimpl->m_size); +} + +//--------------------------------------------------------- + +wstring TFontManager::getCurrentFamily() const { + return m_pimpl->m_currentFamily; +} + +//--------------------------------------------------------- + +wstring TFontManager::getCurrentTypeface() const { + return m_pimpl->m_currentTypeface; +} + +//--------------------------------------------------------- + +TFont *TFontManager::getCurrentFont() { + if (m_pimpl->m_currentFont) { + return m_pimpl->m_currentFont; + } + + if (!m_pimpl->m_currentFont) { + loadFontNames(); + } + + assert(!m_pimpl->m_qfontdb->families().empty()); + setFamily(m_pimpl->m_qfontdb->families().first().toStdWString()); + + return m_pimpl->m_currentFont; +} + +//--------------------------------------------------------- + +void TFontManager::getAllFamilies(vector &families) const { + QStringList qFamilies = m_pimpl->m_qfontdb->families(); + + families.clear(); + families.reserve(qFamilies.count()); + + QStringList::const_iterator it = qFamilies.begin(); + for (; it != qFamilies.end(); ++it) { + families.push_back(it->toStdWString()); + } +} + +//--------------------------------------------------------- + +void TFontManager::getAllTypefaces(vector &typefaces) const { + typefaces.clear(); + + QStringList qStyles = m_pimpl->m_qfontdb->styles( + QString::fromStdWString(m_pimpl->m_currentFamily)); + + if (qStyles.empty()) return; + + typefaces.reserve(qStyles.count()); + QStringList::const_iterator it_typeface = qStyles.begin(); + for (; it_typeface != qStyles.end(); ++it_typeface) { + typefaces.push_back(it_typeface->toStdWString()); + } +} + +//--------------------------------------------------------- + +void TFontManager::setVertical(bool vertical) {} + +//---------------------------------------------------------