Text drawing using FreeType library

This commit is contained in:
Jakub Melka
2019-04-07 19:39:29 +02:00
parent 1694d310a8
commit 51b2ccacec
100 changed files with 37664 additions and 121 deletions

View File

@@ -91,6 +91,20 @@ unix {
}
# Link to freetype library
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../FreeType/ -lfreetype
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../FreeType/ -lfreetype
else:unix: LIBS += -L$$PWD/FreeType/ -lfreetype
INCLUDEPATH += $$PWD/../FreeType/include
DEPENDPATH += $$PWD/../FreeType/include
freetype_lib.files = $$PWD/../FreeType/freetype.dll
freetype_lib.path = $$OUT_PWD
INSTALLS += freetype_lib
CONFIG += force_debug_info

View File

@@ -20,6 +20,14 @@
#include "pdfparser.h"
#include "pdfnametounicode.h"
#include <ft2build.h>
#include <freetype/freetype.h>
#include <freetype/ftglyph.h>
#include <freetype/fterrors.h>
#include <freetype/ftoutln.h>
#include <QMutex>
namespace pdf
{
@@ -29,8 +37,271 @@ PDFFont::PDFFont(FontDescriptor fontDescriptor) :
}
/// Implementation of the PDFRealizedFont class using PIMPL pattern
class PDFRealizedFontImpl
{
public:
explicit PDFRealizedFontImpl();
~PDFRealizedFontImpl();
/// Fills the text sequence by interpreting byte array according font data and
/// produces glyphs for the font.
/// \param byteArray Array of bytes to be interpreted
/// \param textSequence Text sequence to be filled
void fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence);
private:
friend class PDFRealizedFont;
static constexpr const PDFReal FORMAT_26_6_MULTIPLIER = 1 / 64.0;
struct Glyph
{
QPainterPath glyph;
PDFReal advance;
};
static int outlineMoveTo(const FT_Vector* to, void* user);
static int outlineLineTo(const FT_Vector* to, void* user);
static int outlineConicTo(const FT_Vector* control, const FT_Vector* to, void* user);
static int outlineCubicTo(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user);
/// Get glyph for unicode character. Throws exception, if glyph can't be found.
const Glyph& getGlyphForUnicode(QChar character);
/// Function checks, if error occured, and if yes, then exception is thrown
static void checkFreeTypeError(FT_Error error);
/// Mutex for accessing the glyph data
QMutex m_mutex;
/// Glyph cache, must be protected by the mutex above
std::map<QChar, Glyph> m_glyphCache;
/// For embedded fonts, this byte array contains embedded font data
QByteArray m_embeddedFontData;
/// Instance of FreeType library assigned to this font
FT_Library m_library;
/// Face of the font
FT_Face m_face;
/// Pixel size of the font
PDFReal m_pixelSize;
/// Parent font
const PDFFont* m_parentFont;
/// True, if font is embedded
bool m_isEmbedded;
/// True, if font has vertical writing system
bool m_isVertical;
};
PDFRealizedFontImpl::PDFRealizedFontImpl() :
m_library(nullptr),
m_face(nullptr),
m_pixelSize(0.0),
m_parentFont(nullptr),
m_isEmbedded(false),
m_isVertical(false)
{
}
PDFRealizedFontImpl::~PDFRealizedFontImpl()
{
if (m_face)
{
FT_Done_Face(m_face);
m_face = nullptr;
}
if (m_library)
{
FT_Done_FreeType(m_library);
m_library = nullptr;
}
}
void PDFRealizedFontImpl::fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence)
{
switch (m_parentFont->getFontType())
{
case FontType::Type1:
case FontType::TrueType:
{
// We can use encoding
QString text = m_parentFont->getTextUsingEncoding(byteArray);
textSequence.items.reserve(textSequence.items.size() + text.size());
for (const QChar& character : text)
{
const Glyph& glyph = getGlyphForUnicode(character);
textSequence.items.emplace_back(&glyph.glyph, character, glyph.advance);
}
break;
}
default:
{
// Unhandled font type
Q_ASSERT(false);
break;
}
}
}
int PDFRealizedFontImpl::outlineMoveTo(const FT_Vector* to, void* user)
{
Glyph* glyph = reinterpret_cast<Glyph*>(user);
glyph->glyph.moveTo(to->x * FORMAT_26_6_MULTIPLIER, to->y * FORMAT_26_6_MULTIPLIER);
return 0;
}
int PDFRealizedFontImpl::outlineLineTo(const FT_Vector* to, void* user)
{
Glyph* glyph = reinterpret_cast<Glyph*>(user);
glyph->glyph.lineTo(to->x * FORMAT_26_6_MULTIPLIER, to->y * FORMAT_26_6_MULTIPLIER);
return 0;
}
int PDFRealizedFontImpl::outlineConicTo(const FT_Vector* control, const FT_Vector* to, void* user)
{
Glyph* glyph = reinterpret_cast<Glyph*>(user);
glyph->glyph.cubicTo(control->x * FORMAT_26_6_MULTIPLIER, control->y * FORMAT_26_6_MULTIPLIER, control->x * FORMAT_26_6_MULTIPLIER, control->y * FORMAT_26_6_MULTIPLIER, to->x * FORMAT_26_6_MULTIPLIER, to->y * FORMAT_26_6_MULTIPLIER);
return 0;
}
int PDFRealizedFontImpl::outlineCubicTo(const FT_Vector* control1, const FT_Vector* control2, const FT_Vector* to, void* user)
{
Glyph* glyph = reinterpret_cast<Glyph*>(user);
glyph->glyph.cubicTo(control1->x * FORMAT_26_6_MULTIPLIER, control1->y * FORMAT_26_6_MULTIPLIER, control2->x * FORMAT_26_6_MULTIPLIER, control2->y * FORMAT_26_6_MULTIPLIER, to->x * FORMAT_26_6_MULTIPLIER, to->y * FORMAT_26_6_MULTIPLIER);
return 0;
}
const PDFRealizedFontImpl::Glyph& PDFRealizedFontImpl::getGlyphForUnicode(QChar character)
{
QMutexLocker lock(&m_mutex);
// First look into cache
auto it = m_glyphCache.find(character);
if (it != m_glyphCache.cend())
{
return it->second;
}
FT_UInt glyphIndex = FT_Get_Char_Index(m_face, character.unicode());
if (glyphIndex)
{
Glyph glyph;
FT_Outline_Funcs interface;
interface.delta = 0;
interface.shift = 0;
interface.move_to = PDFRealizedFontImpl::outlineMoveTo;
interface.line_to = PDFRealizedFontImpl::outlineLineTo;
interface.conic_to = PDFRealizedFontImpl::outlineConicTo;
interface.cubic_to = PDFRealizedFontImpl::outlineCubicTo;
checkFreeTypeError(FT_Load_Glyph(m_face, glyphIndex, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING));
checkFreeTypeError(FT_Outline_Decompose(&m_face->glyph->outline, &interface, &glyph));
glyph.glyph.closeSubpath();
glyph.advance = !m_isVertical ? m_face->glyph->advance.x : m_face->glyph->advance.y;
glyph.advance *= FORMAT_26_6_MULTIPLIER;
m_glyphCache[character] = qMove(glyph);
return m_glyphCache[character];
}
else
{
throw PDFParserException(PDFTranslationContext::tr("Glyph for unicode character '%1' not found.").arg(character));
}
static Glyph dummy;
return dummy;
}
void PDFRealizedFontImpl::checkFreeTypeError(FT_Error error)
{
if (error)
{
QString message;
if (const char* errorString = FT_Error_String(error))
{
message = QString::fromLatin1(errorString);
}
throw PDFParserException(PDFTranslationContext::tr("FreeType error code %1: message").arg(error).arg(message));
}
}
PDFRealizedFont::~PDFRealizedFont()
{
delete m_impl;
}
void PDFRealizedFont::fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence)
{
m_impl->fillTextSequence(byteArray, textSequence);
}
bool PDFRealizedFont::isHorizontalWritingSystem() const
{
return !m_impl->m_isVertical;
}
PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(const PDFFont* font, PDFReal pixelSize)
{
PDFRealizedFontPointer result;
std::unique_ptr<PDFRealizedFontImpl> implPtr(new PDFRealizedFontImpl());
PDFRealizedFontImpl* impl = implPtr.get();
impl->m_parentFont = font;
const FontDescriptor* descriptor = font->getFontDescriptor();
if (descriptor->isEmbedded())
{
PDFRealizedFontImpl::checkFreeTypeError(FT_Init_FreeType(&impl->m_library));
if (!descriptor->fontFile.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile;
}
else if (!descriptor->fontFile2.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile2;
}
else if (!descriptor->fontFile3.isEmpty())
{
impl->m_embeddedFontData = descriptor->fontFile3;
}
// At this time, embedded font data should not be empty!
Q_ASSERT(!impl->m_embeddedFontData.isEmpty());
PDFRealizedFontImpl::checkFreeTypeError(FT_New_Memory_Face(impl->m_library, reinterpret_cast<const FT_Byte*>(impl->m_embeddedFontData.constData()), impl->m_embeddedFontData.size(), 0, &impl->m_face));
PDFRealizedFontImpl::checkFreeTypeError(FT_Select_Charmap(impl->m_face, FT_ENCODING_UNICODE));
PDFRealizedFontImpl::checkFreeTypeError(FT_Set_Pixel_Sizes(impl->m_face, 0, qRound(pixelSize)));
impl->m_isVertical = impl->m_face->face_flags & FT_FACE_FLAG_VERTICAL;
impl->m_isEmbedded = true;
result.reset(new PDFRealizedFont(implPtr.release()));
}
else
{
// TODO: Support non-embedded fonts
throw PDFParserException(PDFTranslationContext::tr("Only embedded fonts are supported."));
}
return result;
}
PDFFontPointer PDFFont::createFont(const PDFObject& object, const PDFDocument* document)
{
// TODO: Create font cache for realized fonts
const PDFObject& dereferencedFontDictionary = document->getObject(object);
if (!dereferencedFontDictionary.isDictionary())
{
@@ -326,9 +597,13 @@ PDFSimpleFont::PDFSimpleFont(FontDescriptor fontDescriptor,
}
QRawFont PDFSimpleFont::getRealizedFont(PDFReal fontSize) const
PDFRealizedFontPointer PDFSimpleFont::getRealizedFont(PDFReal fontSize) const
{
// TODO: Fix font creation to use also embedded fonts, font descriptor, etc.
// TODO: Remove QRawFont
return PDFRealizedFont::createRealizedFont(this, fontSize);
/*
QRawFont rawFont;
if (m_fontDescriptor.isEmbedded())
@@ -362,7 +637,7 @@ QRawFont PDFSimpleFont::getRealizedFont(PDFReal fontSize) const
rawFont = QRawFont::fromFont(font, QFontDatabase::Any);
}
return rawFont;
return rawFont;*/
}
QString PDFSimpleFont::getTextUsingEncoding(const QByteArray& byteArray) const

View File

@@ -41,6 +41,27 @@ enum class TextRenderingMode
Clip = 7
};
/// Item of the text sequence (either single character, or advance)
struct TextSequenceItem
{
inline explicit TextSequenceItem() = default;
inline explicit TextSequenceItem(const QPainterPath* glyph, QChar character, PDFReal advance) : glyph(glyph), character(character), advance(advance) { }
inline explicit TextSequenceItem(PDFReal advance) : character(), advance(advance) { }
inline bool isCharacter() const { return !character.isNull(); }
inline bool isAdvance() const { return advance != 0.0; }
inline bool isNull() const { return !isCharacter() && !isAdvance(); }
const QPainterPath* glyph = nullptr;
QChar character;
PDFReal advance = 0;
};
struct TextSequence
{
std::vector<TextSequenceItem> items;
};
constexpr bool isTextRenderingModeFilled(TextRenderingMode mode)
{
switch (mode)
@@ -169,6 +190,38 @@ class PDFFont;
using PDFFontPointer = QSharedPointer<PDFFont>;
class PDFRealizedFont;
class PDFRealizedFontImpl;
using PDFRealizedFontPointer = QSharedPointer<PDFRealizedFont>;
/// Font, which has fixed pixel size. It is programmed as PIMPL, because we need
/// to remove FreeType types from the interface (so we do not include FreeType in the interface).
class PDFRealizedFont
{
public:
~PDFRealizedFont();
/// Fills the text sequence by interpreting byte array according font data and
/// produces glyphs for the font.
/// \param byteArray Array of bytes to be interpreted
/// \param textSequence Text sequence to be filled
void fillTextSequence(const QByteArray& byteArray, TextSequence& textSequence);
/// Return true, if we have horizontal writing system
bool isHorizontalWritingSystem() const;
/// Creates new realized font from the standard font. If font can't be created,
/// then exception is thrown.
static PDFRealizedFontPointer createRealizedFont(const PDFFont* font, PDFReal pixelSize);
private:
/// Constructs new realized font
explicit PDFRealizedFont(PDFRealizedFontImpl* impl) : m_impl(impl) { }
PDFRealizedFontImpl* m_impl;
};
/// Base class representing font in the PDF file
class PDFFont
{
@@ -182,7 +235,7 @@ public:
/// Realizes the font (physical materialization of the font using pixel size,
/// if font can't be realized, then empty QRawFont is returned).
/// \param fontSize Size of the font
virtual QRawFont getRealizedFont(PDFReal fontSize) const = 0;
virtual PDFRealizedFontPointer getRealizedFont(PDFReal fontSize) const = 0;
/// Returns text using the font encoding
/// \param byteArray Byte array with encoded string
@@ -215,7 +268,7 @@ public:
encoding::EncodingTable encoding);
virtual ~PDFSimpleFont() override = default;
virtual QRawFont getRealizedFont(PDFReal fontSize) const override;
virtual PDFRealizedFontPointer getRealizedFont(PDFReal fontSize) const override;
virtual QString getTextUsingEncoding(const QByteArray& byteArray) const override;
protected:

View File

@@ -1626,8 +1626,19 @@ void PDFPageContentProcessor::operatorTextShowTextString(PDFOperandString text)
{
if (m_graphicState.getTextFont())
{
QString textDecoded = m_graphicState.getTextFont()->getTextUsingEncoding(text.string);
drawText(TextSequence::fromString(textDecoded));
// Get the realized font
const PDFRealizedFontPointer& realizedFont = getRealizedFont();
if (!realizedFont)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid font, text can't be printed."));
}
TextSequence textSequence;
// We use simple heuristic to ensure reallocation doesn't occur too often
textSequence.items.reserve(m_operands.size());
realizedFont->fillTextSequence(text.string, textSequence);
drawText(textSequence);
}
else
{
@@ -1658,6 +1669,13 @@ void PDFPageContentProcessor::operatorTextShowTextIndividualSpacing()
// We use simple heuristic to ensure reallocation doesn't occur too often
textSequence.items.reserve(m_operands.size() * 4);
// Get the realized font
const PDFRealizedFontPointer& realizedFont = getRealizedFont();
if (!realizedFont)
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Invalid font, text can't be printed."));
}
for (size_t i = 1, lastIndex = m_operands.size() - 1; i < lastIndex; ++i)
{
switch (m_operands[i].type)
@@ -1676,8 +1694,7 @@ void PDFPageContentProcessor::operatorTextShowTextIndividualSpacing()
case PDFLexicalAnalyzer::TokenType::String:
{
QString string = m_graphicState.getTextFont()->getTextUsingEncoding(m_operands[i].data.toByteArray());
std::transform(string.cbegin(), string.cend(), std::back_inserter(textSequence.items), [](const QChar character) { return TextSequenceItem(character); });
realizedFont->fillTextSequence(m_operands[i].data.toByteArray(), textSequence);
break;
}
@@ -1721,10 +1738,89 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
return;
}
const QRawFont& font = getRealizedFont();
if (font.isValid())
const PDFRealizedFontPointer& font = getRealizedFont();
if (font)
{
std::vector<QChar> chars;
const PDFReal fontSize = m_graphicState.getTextFontSize();
const PDFReal horizontalScaling = m_graphicState.getTextHorizontalScaling() * 0.01; // Horizontal scaling is in percents
const PDFReal characterSpacing = m_graphicState.getTextCharacterSpacing();
const PDFReal wordSpacing = m_graphicState.getTextWordSpacing();
const PDFReal textRise = m_graphicState.getTextRise();
const TextRenderingMode textRenderingMode = m_graphicState.getTextRenderingMode();
const bool fill = isTextRenderingModeFilled(textRenderingMode);
const bool stroke = isTextRenderingModeStroked(textRenderingMode);
const bool clipped = isTextRenderingModeClipped(textRenderingMode);
// TODO: Add Text Clipping
// TODO: Pouzit pravdepodobne sirky z widths array?
// Detect horizontal writing system
const bool isHorizontalWritingSystem = font->isHorizontalWritingSystem();
// Calculate text rendering matrix
QMatrix adjustMatrix(horizontalScaling, 0.0, 0.0, 1.0, 0.0, textRise);
QMatrix textMatrix = m_graphicState.getTextMatrix();
QMatrix fontMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0);
size_t characterIndex = 0;
for (const TextSequenceItem& item : textSequence.items)
{
PDFReal displacementX = 0.0;
PDFReal displacementY = 0.0;
if (item.isCharacter())
{
QChar character = item.character;
QPointF advance = isHorizontalWritingSystem ? QPointF(item.advance, 0) : QPointF(0, item.advance);
// First, compute the advance
const PDFReal additionalAdvance = (character == QChar(QChar::Space)) ? wordSpacing : characterSpacing;
if (isHorizontalWritingSystem)
{
advance.rx() += additionalAdvance;
}
else
{
advance.ry() += additionalAdvance;
}
advance.rx() *= horizontalScaling;
// Then get the glyph path and paint it
if (item.glyph)
{
QPainterPath glyphPath = fontMatrix.map(*item.glyph);
if (!glyphPath.isEmpty())
{
QMatrix textRenderingMatrix = textMatrix * adjustMatrix;
QPainterPath transformedGlyph = textRenderingMatrix.map(glyphPath);
performPathPainting(transformedGlyph, stroke, fill, transformedGlyph.fillRule());
}
}
displacementX = advance.x();
displacementY = advance.y();
++characterIndex;
}
else if (item.isAdvance())
{
if (horizontalScaling)
{
displacementX = -item.advance * 0.001 * fontSize * horizontalScaling;
}
else
{
displacementY = -item.advance * 0.001 * fontSize;
}
}
textMatrix.translate(displacementX, displacementY);
}
m_graphicState.setTextMatrix(textMatrix);
updateGraphicState();
/*std::vector<QChar> chars;
chars.reserve(textSequence.items.size());
for (const TextSequenceItem& item : textSequence.items)
{
@@ -1748,80 +1844,7 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
advances.resize(numGlyphs, QPointF());
if (font.advancesForGlyphIndexes(glyphIndices.data(), advances.data(), numGlyphs, QRawFont::SeparateAdvances | QRawFont::UseDesignMetrics))
{
const PDFReal fontSize = m_graphicState.getTextFontSize();
const PDFReal horizontalScaling = m_graphicState.getTextHorizontalScaling() * 0.01; // Horizontal scaling is in percents
const PDFReal characterSpacing = m_graphicState.getTextCharacterSpacing();
const PDFReal wordSpacing = m_graphicState.getTextWordSpacing();
const PDFReal textRise = m_graphicState.getTextRise();
const TextRenderingMode textRenderingMode = m_graphicState.getTextRenderingMode();
const bool fill = isTextRenderingModeFilled(textRenderingMode);
const bool stroke = isTextRenderingModeStroked(textRenderingMode);
const bool clipped = isTextRenderingModeClipped(textRenderingMode);
// TODO: Add Text Clipping
// TODO: Pouzit pravdepodobne sirky z widths array?
// Detect horizontal writing system
const bool isHorizontalWritingSystem = std::any_of(advances.cbegin(), advances.cend(), [](const QPointF& point) { return !qFuzzyIsNull(point.x()); });
// Calculate text rendering matrix
QMatrix adjustMatrix(horizontalScaling, 0.0, 0.0, 1.0, 0.0, textRise);
QMatrix textMatrix = m_graphicState.getTextMatrix();
QMatrix fontMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0);
size_t characterIndex = 0;
for (const TextSequenceItem& item : textSequence.items)
{
PDFReal displacementX = 0.0;
PDFReal displacementY = 0.0;
if (item.isCharacter())
{
QChar character = item.character;
QPointF advance = advances[characterIndex];
// First, compute the advance
const PDFReal additionalAdvance = (character == QChar(QChar::Space)) ? wordSpacing : characterSpacing;
if (isHorizontalWritingSystem)
{
advance.rx() += additionalAdvance;
}
else
{
advance.ry() += additionalAdvance;
}
advance.rx() *= horizontalScaling;
// Then get the glyph path and paint it
QPainterPath glyphPath = fontMatrix.map(font.pathForGlyph(glyphIndices[characterIndex]));
if (!glyphPath.isEmpty())
{
QMatrix textRenderingMatrix = textMatrix * adjustMatrix;
QPainterPath transformedGlyph = textRenderingMatrix.map(glyphPath);
performPathPainting(transformedGlyph, stroke, fill, transformedGlyph.fillRule());
}
displacementX = advance.x();
displacementY = advance.y();
++characterIndex;
}
else if (item.isAdvance())
{
if (horizontalScaling)
{
displacementX = -item.advance * 0.001 * fontSize * horizontalScaling;
}
else
{
displacementY = -item.advance * 0.001 * fontSize;
}
}
textMatrix.translate(displacementX, displacementY);
}
m_graphicState.setTextMatrix(textMatrix);
updateGraphicState();
}
else
{
@@ -1831,7 +1854,7 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
else
{
throw PDFRendererException(RenderErrorType::Error, PDFTranslationContext::tr("Cant convert unicode to glyph indices, text can't be printed."));
}
}*/
}
else
{
@@ -1839,14 +1862,14 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
}
}
QRawFont PDFPageContentProcessor::getRealizedFontImpl() const
PDFRealizedFontPointer PDFPageContentProcessor::getRealizedFontImpl() const
{
if (m_graphicState.getTextFont())
{
return m_graphicState.getTextFont()->getRealizedFont(m_graphicState.getTextFontSize());
}
return QRawFont();
return PDFRealizedFontPointer();
}
PDFPageContentProcessor::PDFPageContentProcessorState::PDFPageContentProcessorState() :
@@ -2126,12 +2149,4 @@ void PDFPageContentProcessor::PDFPageContentProcessorState::setTextCharacterSpac
}
}
PDFPageContentProcessor::TextSequence PDFPageContentProcessor::TextSequence::fromString(const QString& string)
{
TextSequence result;
result.items.reserve(string.size());
std::transform(string.cbegin(), string.cend(), std::back_inserter(result.items), [](const QChar character) { return TextSequenceItem(character); });
return result;
}
} // namespace pdf

View File

@@ -350,28 +350,6 @@ protected:
StateFlags m_stateFlags;
};
/// Item of the text sequence (either single character, or advance)
struct TextSequenceItem
{
inline explicit TextSequenceItem() = default;
inline explicit TextSequenceItem(QChar character) : character(character), advance(0) { }
inline explicit TextSequenceItem(PDFReal advance) : character(), advance(advance) { }
inline bool isCharacter() const { return !character.isNull(); }
inline bool isAdvance() const { return advance != 0.0; }
inline bool isNull() const { return !isCharacter() && !isAdvance(); }
QChar character;
PDFReal advance = 0;
};
struct TextSequence
{
static TextSequence fromString(const QString& string);
std::vector<TextSequenceItem> items;
};
enum class ProcessOrder
{
BeforeOperation,
@@ -593,10 +571,10 @@ private:
void drawText(const TextSequence& textSequence);
/// Returns realized font
const QRawFont& getRealizedFont() { return m_realizedFont.get(this, &PDFPageContentProcessor::getRealizedFontImpl); }
const PDFRealizedFontPointer& getRealizedFont() { return m_realizedFont.get(this, &PDFPageContentProcessor::getRealizedFontImpl); }
/// Returns realized font (or empty font, if font can't be realized)
QRawFont getRealizedFontImpl() const;
PDFRealizedFontPointer getRealizedFontImpl() const;
const PDFPage* m_page;
const PDFDocument* m_document;
@@ -627,7 +605,7 @@ private:
int m_textBeginEndState;
/// Actually realized physical font
PDFCachedItem<QRawFont> m_realizedFont;
PDFCachedItem<PDFRealizedFontPointer> m_realizedFont;
};
} // namespace pdf