blob: fc91ad1838abf9a087e64cd00bb3f66dd810438f [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QFONTENGINE_P_H
#define QFONTENGINE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtGui/private/qtguiglobal_p.h>
#include "QtCore/qatomic.h"
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qhashfunctions.h>
#include "private/qtextengine_p.h"
#include "private/qfont_p.h"
QT_BEGIN_NAMESPACE
class QPainterPath;
class QFontEngineGlyphCache;
struct QGlyphLayout;
#define MAKE_TAG(ch1, ch2, ch3, ch4) (\
(((quint32)(ch1)) << 24) | \
(((quint32)(ch2)) << 16) | \
(((quint32)(ch3)) << 8) | \
((quint32)(ch4)) \
)
// ### this only used in getPointInOutline(), refactor it and then remove these magic numbers
enum HB_Compat_Error {
Err_Ok = 0x0000,
Err_Not_Covered = 0xFFFF,
Err_Invalid_Argument = 0x1A66,
Err_Invalid_SubTable_Format = 0x157F,
Err_Invalid_SubTable = 0x1570
};
typedef void (*qt_destroy_func_t) (void *user_data);
typedef bool (*qt_get_font_table_func_t) (void *user_data, uint tag, uchar *buffer, uint *length);
class Q_GUI_EXPORT QFontEngine
{
public:
enum Type {
Box,
Multi,
// MS Windows types
Win,
// Apple Mac OS types
Mac,
// QWS types
Freetype,
QPF1,
QPF2,
Proxy,
DirectWrite,
TestFontEngine = 0x1000
};
enum GlyphFormat {
Format_None,
Format_Render = Format_None,
Format_Mono,
Format_A8,
Format_A32,
Format_ARGB
};
enum ShaperFlag {
DesignMetrics = 0x0002,
GlyphIndicesOnly = 0x0004
};
Q_DECLARE_FLAGS(ShaperFlags, ShaperFlag)
/* Used with the Freetype font engine. */
struct Glyph {
Glyph() = default;
~Glyph() { delete [] data; }
short linearAdvance = 0;
unsigned short width = 0;
unsigned short height = 0;
short x = 0;
short y = 0;
short advance = 0;
signed char format = 0;
uchar *data = nullptr;
private:
Q_DISABLE_COPY(Glyph)
};
virtual ~QFontEngine();
inline Type type() const { return m_type; }
// all of these are in unscaled metrics if the engine supports uncsaled metrics,
// otherwise in design metrics
struct Properties {
QByteArray postscriptName;
QByteArray copyright;
QRectF boundingBox;
QFixed emSquare;
QFixed ascent;
QFixed descent;
QFixed leading;
QFixed italicAngle;
QFixed capHeight;
QFixed lineWidth;
};
virtual Properties properties() const;
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics);
QByteArray getSfntTable(uint tag) const;
virtual bool getSfntTableData(uint tag, uchar *buffer, uint *length) const;
struct FaceId {
FaceId() : index(0), encoding(0) {}
QByteArray filename;
QByteArray uuid;
int index;
int encoding;
};
virtual FaceId faceId() const { return FaceId(); }
enum SynthesizedFlags {
SynthesizedItalic = 0x1,
SynthesizedBold = 0x2,
SynthesizedStretch = 0x4
};
virtual int synthesized() const { return 0; }
virtual bool supportsSubPixelPositions() const { return false; }
virtual QFixed subPixelPositionForX(QFixed x) const;
virtual QFixed emSquareSize() const { return ascent(); }
/* returns 0 as glyph index for non existent glyphs */
virtual glyph_t glyphIndex(uint ucs4) const = 0;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const = 0;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const {}
virtual void doKerning(QGlyphLayout *, ShaperFlags) const;
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
QPainterPath *path, QTextItem::RenderFlags flags);
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions);
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags);
void addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags);
/**
* Create a qimage with the alpha values for the glyph.
* Returns an image indexed_8 with index values ranging from 0=fully transparent to 255=opaque
*/
// ### Refactor this into a smaller and more flexible API.
virtual QImage alphaMapForGlyph(glyph_t);
virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition);
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t);
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color = QColor());
virtual Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
virtual bool hasInternalCaching() const { return false; }
virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/)
{
return boundingBox(glyph, matrix);
}
virtual void removeGlyphFromCache(glyph_t);
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) = 0;
virtual glyph_metrics_t boundingBox(glyph_t glyph) = 0;
virtual glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix);
glyph_metrics_t tightBoundingBox(const QGlyphLayout &glyphs);
virtual QFixed ascent() const = 0;
virtual QFixed capHeight() const = 0;
virtual QFixed descent() const = 0;
virtual QFixed leading() const = 0;
virtual QFixed xHeight() const;
virtual QFixed averageCharWidth() const;
virtual QFixed lineThickness() const;
virtual QFixed underlinePosition() const;
virtual qreal maxCharWidth() const = 0;
virtual qreal minLeftBearing() const;
virtual qreal minRightBearing() const;
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = nullptr, qreal *rightBearing = nullptr);
inline bool canRender(uint ucs4) const { return glyphIndex(ucs4) != 0; }
virtual bool canRender(const QChar *str, int len) const;
virtual bool supportsTransformation(const QTransform &transform) const;
virtual int glyphCount() const;
virtual int glyphMargin(GlyphFormat format) { return format == Format_A32 ? 2 : 0; }
virtual QFontEngine *cloneWithSize(qreal /*pixelSize*/) const { return nullptr; }
virtual Qt::HANDLE handle() const;
void *harfbuzzFont() const;
void *harfbuzzFace() const;
bool supportsScript(QChar::Script script) const;
inline static bool scriptRequiresOpenType(QChar::Script script)
{
return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
|| script == QChar::Script_Khmer || script == QChar::Script_Nko);
}
virtual int getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints);
void clearGlyphCache(const void *key);
void setGlyphCache(const void *key, QFontEngineGlyphCache *data);
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform, const QColor &color = QColor()) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily);
virtual bool hasUnreliableGlyphOutline() const;
virtual bool expectsGammaCorrectedBlending() const;
enum HintStyle {
HintNone,
HintLight,
HintMedium,
HintFull
};
virtual void setDefaultHintStyle(HintStyle) { }
enum SubpixelAntialiasingType {
Subpixel_None,
Subpixel_RGB,
Subpixel_BGR,
Subpixel_VRGB,
Subpixel_VBGR
};
private:
const Type m_type;
public:
QAtomicInt ref;
QFontDef fontDef;
class Holder { // replace by std::unique_ptr once available
void *ptr;
qt_destroy_func_t destroy_func;
public:
Holder() : ptr(nullptr), destroy_func(nullptr) {}
explicit Holder(void *p, qt_destroy_func_t d) : ptr(p), destroy_func(d) {}
~Holder() { if (ptr && destroy_func) destroy_func(ptr); }
Holder(Holder &&other) noexcept
: ptr(other.ptr),
destroy_func(other.destroy_func)
{
other.ptr = nullptr;
other.destroy_func = nullptr;
}
Holder &operator=(Holder &&other) noexcept
{ swap(other); return *this; }
void swap(Holder &other) noexcept
{
qSwap(ptr, other.ptr);
qSwap(destroy_func, other.destroy_func);
}
void *get() const noexcept { return ptr; }
void *release() noexcept {
void *result = ptr;
ptr = nullptr;
destroy_func = nullptr;
return result;
}
void reset() noexcept { Holder().swap(*this); }
qt_destroy_func_t get_deleter() const noexcept { return destroy_func; }
bool operator!() const noexcept { return !ptr; }
};
mutable Holder font_; // \ NOTE: Declared before m_glyphCaches, so font_, face_
mutable Holder face_; // / are destroyed _after_ m_glyphCaches is destroyed.
struct FaceData {
void *user_data;
qt_get_font_table_func_t get_font_table;
} faceData;
uint cache_cost; // amount of mem used in bytes by the font
uint fsType : 16;
bool symbol;
bool isSmoothlyScalable;
struct KernPair {
uint left_right;
QFixed adjust;
inline bool operator<(const KernPair &other) const
{
return left_right < other.left_right;
}
};
QVector<KernPair> kerning_pairs;
void loadKerningPairs(QFixed scalingFactor);
GlyphFormat glyphFormat;
int m_subPixelPositionCount; // Number of positions within a single pixel for this cache
inline QVariant userData() const { return m_userData; }
protected:
explicit QFontEngine(Type type);
QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false);
inline void setUserData(const QVariant &userData) { m_userData = userData; }
QFixed calculatedCapHeight() const;
private:
struct GlyphCacheEntry {
GlyphCacheEntry();
GlyphCacheEntry(const GlyphCacheEntry &);
~GlyphCacheEntry();
GlyphCacheEntry &operator=(const GlyphCacheEntry &);
QExplicitlySharedDataPointer<QFontEngineGlyphCache> cache;
bool operator==(const GlyphCacheEntry &other) const { return cache == other.cache; }
};
typedef std::list<GlyphCacheEntry> GlyphCaches;
mutable QHash<const void *, GlyphCaches> m_glyphCaches;
private:
QVariant m_userData;
mutable qreal m_minLeftBearing;
mutable qreal m_minRightBearing;
};
Q_DECLARE_TYPEINFO(QFontEngine::KernPair, Q_PRIMITIVE_TYPE);
Q_DECLARE_OPERATORS_FOR_FLAGS(QFontEngine::ShaperFlags)
inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId &f2)
{
return f1.index == f2.index && f1.encoding == f2.encoding && f1.filename == f2.filename && f1.uuid == f2.uuid;
}
inline uint qHash(const QFontEngine::FaceId &f, uint seed = 0)
noexcept(noexcept(qHash(f.filename)))
{
QtPrivate::QHashCombine hash;
seed = hash(seed, f.filename);
seed = hash(seed, f.uuid);
seed = hash(seed, f.index);
seed = hash(seed, f.encoding);
return seed;
}
class QGlyph;
class QFontEngineBox : public QFontEngine
{
public:
QFontEngineBox(int size);
~QFontEngineBox();
virtual glyph_t glyphIndex(uint ucs4) const override;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
void draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &si);
virtual void addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags) override;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
virtual QFontEngine *cloneWithSize(qreal pixelSize) const override;
virtual QFixed ascent() const override;
virtual QFixed capHeight() const override;
virtual QFixed descent() const override;
virtual QFixed leading() const override;
virtual qreal maxCharWidth() const override;
virtual qreal minLeftBearing() const override { return 0; }
virtual qreal minRightBearing() const override { return 0; }
virtual QImage alphaMapForGlyph(glyph_t) override;
virtual bool canRender(const QChar *string, int len) const override;
inline int size() const { return _size; }
protected:
explicit QFontEngineBox(Type type, int size);
private:
friend class QFontPrivate;
int _size;
};
class Q_GUI_EXPORT QFontEngineMulti : public QFontEngine
{
public:
explicit QFontEngineMulti(QFontEngine *engine, int script, const QStringList &fallbackFamilies = QStringList());
~QFontEngineMulti();
virtual glyph_t glyphIndex(uint ucs4) const override;
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, ShaperFlags flags) const override;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
virtual void recalcAdvances(QGlyphLayout *, ShaperFlags) const override;
virtual void doKerning(QGlyphLayout *, ShaperFlags) const override;
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags) override;
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = nullptr, qreal *rightBearing = nullptr) override;
virtual QFixed ascent() const override;
virtual QFixed capHeight() const override;
virtual QFixed descent() const override;
virtual QFixed leading() const override;
virtual QFixed xHeight() const override;
virtual QFixed averageCharWidth() const override;
virtual QImage alphaMapForGlyph(glyph_t) override;
virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override;
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t) override;
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
virtual QFixed lineThickness() const override;
virtual QFixed underlinePosition() const override;
virtual qreal maxCharWidth() const override;
virtual qreal minLeftBearing() const override;
virtual qreal minRightBearing() const override;
virtual bool canRender(const QChar *string, int len) const override;
inline int fallbackFamilyCount() const { return m_fallbackFamilies.size(); }
inline QString fallbackFamilyAt(int at) const { return m_fallbackFamilies.at(at); }
void setFallbackFamiliesList(const QStringList &fallbackFamilies);
static uchar highByte(glyph_t glyph); // Used for determining engine
inline QFontEngine *engine(int at) const
{ Q_ASSERT(at < m_engines.size()); return m_engines.at(at); }
void ensureEngineAt(int at);
static QFontEngine *createMultiFontEngine(QFontEngine *fe, int script);
protected:
virtual void ensureFallbackFamiliesQueried();
virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const;
virtual QFontEngine *loadEngine(int at);
private:
QVector<QFontEngine *> m_engines;
QStringList m_fallbackFamilies;
const int m_script;
bool m_fallbackFamiliesQueried;
};
class QTestFontEngine : public QFontEngineBox
{
public:
QTestFontEngine(int size);
};
QT_END_NAMESPACE
#endif // QFONTENGINE_P_H