mirror of https://github.com/JakubMelka/PDF4QT.git
Font cache
This commit is contained in:
parent
51b2ccacec
commit
90767ddfa5
|
@ -30,7 +30,13 @@ PDFDrawSpaceController::PDFDrawSpaceController(QObject* parent) :
|
|||
m_document(nullptr),
|
||||
m_pageLayoutMode(PageLayout::OneColumn),
|
||||
m_verticalSpacingMM(5.0),
|
||||
m_horizontalSpacingMM(1.0)
|
||||
m_horizontalSpacingMM(1.0),
|
||||
m_fontCache(FONT_CACHE_LIMIT, REALIZED_FONT_CACHE_LIMIT)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
PDFDrawSpaceController::~PDFDrawSpaceController()
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -40,6 +46,7 @@ void PDFDrawSpaceController::setDocument(const PDFDocument* document)
|
|||
if (document != m_document)
|
||||
{
|
||||
m_document = document;
|
||||
m_fontCache.setDocument(document);
|
||||
recalculate();
|
||||
}
|
||||
}
|
||||
|
@ -343,6 +350,11 @@ PDFDrawWidgetProxy::PDFDrawWidgetProxy(QObject* parent) :
|
|||
connect(m_controller, &PDFDrawSpaceController::drawSpaceChanged, this, &PDFDrawWidgetProxy::update);
|
||||
}
|
||||
|
||||
PDFDrawWidgetProxy::~PDFDrawWidgetProxy()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void PDFDrawWidgetProxy::setDocument(const PDFDocument* document)
|
||||
{
|
||||
m_controller->setDocument(document);
|
||||
|
@ -533,7 +545,7 @@ void PDFDrawWidgetProxy::draw(QPainter* painter, QRect rect)
|
|||
// Clear the page space by white color
|
||||
painter->fillRect(placedRect, Qt::white);
|
||||
|
||||
PDFRenderer renderer(m_controller->getDocument());
|
||||
PDFRenderer renderer(m_controller->getDocument(), m_controller->getFontCache());
|
||||
QList<PDFRenderError> errors = renderer.render(painter, placedRect, item.pageIndex);
|
||||
|
||||
if (!errors.empty())
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "pdfglobal.h"
|
||||
#include "pdfdocument.h"
|
||||
#include "pdfrenderer.h"
|
||||
#include "pdffont.h"
|
||||
|
||||
#include <QRectF>
|
||||
#include <QObject>
|
||||
|
@ -43,6 +44,7 @@ class PDFDrawSpaceController : public QObject
|
|||
|
||||
public:
|
||||
explicit PDFDrawSpaceController(QObject* parent);
|
||||
virtual ~PDFDrawSpaceController() override;
|
||||
|
||||
/// Sets the document and recalculates the draw space. Document can be nullptr,
|
||||
/// in that case, draw space is cleared.
|
||||
|
@ -88,6 +90,9 @@ public:
|
|||
/// Returns the document
|
||||
const PDFDocument* getDocument() const { return m_document; }
|
||||
|
||||
/// Returns the font cache
|
||||
const PDFFontCache* getFontCache() const { return &m_fontCache; }
|
||||
|
||||
signals:
|
||||
void drawSpaceChanged();
|
||||
|
||||
|
@ -109,6 +114,9 @@ private:
|
|||
|
||||
using BlockItems = std::vector<LayoutBlock>;
|
||||
|
||||
static constexpr size_t FONT_CACHE_LIMIT = 32;
|
||||
static constexpr size_t REALIZED_FONT_CACHE_LIMIT = 128;
|
||||
|
||||
const PDFDocument* m_document;
|
||||
|
||||
PageLayout m_pageLayoutMode;
|
||||
|
@ -116,6 +124,9 @@ private:
|
|||
BlockItems m_blockItems;
|
||||
PDFReal m_verticalSpacingMM;
|
||||
PDFReal m_horizontalSpacingMM;
|
||||
|
||||
/// Font cache
|
||||
PDFFontCache m_fontCache;
|
||||
};
|
||||
|
||||
/// This is a proxy class to draw space controller using widget. We have two spaces, pixel space
|
||||
|
@ -126,6 +137,7 @@ class PDFFORQTLIBSHARED_EXPORT PDFDrawWidgetProxy : public QObject
|
|||
|
||||
public:
|
||||
explicit PDFDrawWidgetProxy(QObject* parent);
|
||||
virtual ~PDFDrawWidgetProxy() override;
|
||||
|
||||
/// Sets the document and updates the draw space. Document can be nullptr,
|
||||
/// in that case, draw space is cleared.
|
||||
|
|
|
@ -91,7 +91,7 @@ private:
|
|||
PDFReal m_pixelSize;
|
||||
|
||||
/// Parent font
|
||||
const PDFFont* m_parentFont;
|
||||
PDFFontPointer m_parentFont;
|
||||
|
||||
/// True, if font is embedded
|
||||
bool m_isEmbedded;
|
||||
|
@ -253,7 +253,7 @@ bool PDFRealizedFont::isHorizontalWritingSystem() const
|
|||
return !m_impl->m_isVertical;
|
||||
}
|
||||
|
||||
PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(const PDFFont* font, PDFReal pixelSize)
|
||||
PDFRealizedFontPointer PDFRealizedFont::createRealizedFont(PDFFontPointer font, PDFReal pixelSize)
|
||||
{
|
||||
PDFRealizedFontPointer result;
|
||||
std::unique_ptr<PDFRealizedFontImpl> implPtr(new PDFRealizedFontImpl());
|
||||
|
@ -597,12 +597,12 @@ PDFSimpleFont::PDFSimpleFont(FontDescriptor fontDescriptor,
|
|||
|
||||
}
|
||||
|
||||
PDFRealizedFontPointer PDFSimpleFont::getRealizedFont(PDFReal fontSize) const
|
||||
PDFRealizedFontPointer PDFSimpleFont::getRealizedFont(PDFFontPointer font, PDFReal fontSize) const
|
||||
{
|
||||
// TODO: Fix font creation to use also embedded fonts, font descriptor, etc.
|
||||
// TODO: Remove QRawFont
|
||||
|
||||
return PDFRealizedFont::createRealizedFont(this, fontSize);
|
||||
return PDFRealizedFont::createRealizedFont(font, fontSize);
|
||||
/*
|
||||
QRawFont rawFont;
|
||||
|
||||
|
@ -678,4 +678,69 @@ FontType PDFTrueTypeFont::getFontType() const
|
|||
return FontType::TrueType;
|
||||
}
|
||||
|
||||
void PDFFontCache::setDocument(const PDFDocument* document)
|
||||
{
|
||||
QMutexLocker lock(&m_mutex);
|
||||
if (m_document != document)
|
||||
{
|
||||
m_document = document;
|
||||
m_fontCache.clear();
|
||||
m_realizedFontCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
PDFFontPointer PDFFontCache::getFont(const PDFObject& fontObject) const
|
||||
{
|
||||
if (fontObject.isReference())
|
||||
{
|
||||
// Font is object reference. Look in the cache, if we have it, then return it.
|
||||
|
||||
QMutexLocker lock(&m_mutex);
|
||||
PDFObjectReference reference = fontObject.getReference();
|
||||
|
||||
auto it = m_fontCache.find(reference);
|
||||
if (it == m_fontCache.cend())
|
||||
{
|
||||
// We must create the font
|
||||
PDFFontPointer font = PDFFont::createFont(fontObject, m_document);
|
||||
|
||||
if (m_fontCache.size() >= m_fontCacheLimit)
|
||||
{
|
||||
// We have exceeded the cache limit. Clear the cache.
|
||||
m_fontCache.clear();
|
||||
}
|
||||
|
||||
it = m_fontCache.insert(std::make_pair(reference, qMove(font))).first;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Object is not a reference. Create font directly and return it.
|
||||
return PDFFont::createFont(fontObject, m_document);
|
||||
}
|
||||
}
|
||||
|
||||
PDFRealizedFontPointer PDFFontCache::getRealizedFont(const PDFFontPointer& font, PDFReal size) const
|
||||
{
|
||||
Q_ASSERT(font);
|
||||
|
||||
QMutexLocker lock(&m_mutex);
|
||||
auto it = m_realizedFontCache.find(std::make_pair(font, size));
|
||||
if (it == m_realizedFontCache.cend())
|
||||
{
|
||||
// We must create the realized font
|
||||
PDFRealizedFontPointer realizedFont = font->getRealizedFont(font, size);
|
||||
|
||||
if (m_realizedFontCache.size() >= m_realizedFontCacheLimit)
|
||||
{
|
||||
m_realizedFontCache.clear();
|
||||
}
|
||||
|
||||
it = m_realizedFontCache.insert(std::make_pair(std::make_pair(font, size), qMove(realizedFont))).first;
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
} // namespace pdf
|
||||
|
|
|
@ -213,7 +213,7 @@ public:
|
|||
|
||||
/// 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);
|
||||
static PDFRealizedFontPointer createRealizedFont(PDFFontPointer font, PDFReal pixelSize);
|
||||
|
||||
private:
|
||||
/// Constructs new realized font
|
||||
|
@ -235,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 PDFRealizedFontPointer getRealizedFont(PDFReal fontSize) const = 0;
|
||||
virtual PDFRealizedFontPointer getRealizedFont(PDFFontPointer font, PDFReal fontSize) const = 0;
|
||||
|
||||
/// Returns text using the font encoding
|
||||
/// \param byteArray Byte array with encoded string
|
||||
|
@ -268,7 +268,7 @@ public:
|
|||
encoding::EncodingTable encoding);
|
||||
virtual ~PDFSimpleFont() override = default;
|
||||
|
||||
virtual PDFRealizedFontPointer getRealizedFont(PDFReal fontSize) const override;
|
||||
virtual PDFRealizedFontPointer getRealizedFont(PDFFontPointer font, PDFReal fontSize) const override;
|
||||
virtual QString getTextUsingEncoding(const QByteArray& byteArray) const override;
|
||||
|
||||
protected:
|
||||
|
@ -312,6 +312,43 @@ public:
|
|||
virtual FontType getFontType() const override;
|
||||
};
|
||||
|
||||
/// Font cache which caches both fonts, and realized fonts. Cache has individual limit
|
||||
/// for fonts, and realized fonts.
|
||||
class PDFFontCache
|
||||
{
|
||||
public:
|
||||
inline explicit PDFFontCache(size_t fontCacheLimit, size_t realizedFontCacheLimit) :
|
||||
m_fontCacheLimit(fontCacheLimit),
|
||||
m_realizedFontCacheLimit(realizedFontCacheLimit),
|
||||
m_document(nullptr)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// Sets the document to the cache. Whole cache is cleared.
|
||||
/// \param document Document to be setted
|
||||
void setDocument(const PDFDocument* document);
|
||||
|
||||
/// Retrieves font from the cache. If font can't be accessed or created,
|
||||
/// then exception is thrown.
|
||||
/// \param fontObject Font object
|
||||
PDFFontPointer getFont(const PDFObject& fontObject) const;
|
||||
|
||||
/// Retrieves realized font from the cache. If realized font can't be accessed or created,
|
||||
/// then exception is thrown.
|
||||
/// \param font Font, which should be realized
|
||||
/// \param size Size of the font (in pixels)
|
||||
PDFRealizedFontPointer getRealizedFont(const PDFFontPointer& font, PDFReal size) const;
|
||||
|
||||
private:
|
||||
const size_t m_fontCacheLimit;
|
||||
const size_t m_realizedFontCacheLimit;
|
||||
mutable QMutex m_mutex;
|
||||
const PDFDocument* m_document;
|
||||
mutable std::map<PDFObjectReference, PDFFontPointer> m_fontCache;
|
||||
mutable std::map<std::pair<PDFFontPointer, PDFReal>, PDFRealizedFontPointer> m_realizedFontCache;
|
||||
};
|
||||
|
||||
} // namespace pdf
|
||||
|
||||
#endif // PDFFONT_H
|
||||
|
|
|
@ -149,9 +149,10 @@ static constexpr const std::pair<const char*, PDFPageContentProcessor::Operator>
|
|||
{ "EX", PDFPageContentProcessor::Operator::CompatibilityEnd }
|
||||
};
|
||||
|
||||
PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document) :
|
||||
PDFPageContentProcessor::PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document, const PDFFontCache* fontCache) :
|
||||
m_page(page),
|
||||
m_document(document),
|
||||
m_fontCache(fontCache),
|
||||
m_colorSpaceDictionary(nullptr),
|
||||
m_fontDictionary(nullptr),
|
||||
m_textBeginEndState(0)
|
||||
|
@ -1532,7 +1533,7 @@ void PDFPageContentProcessor::operatorTextSetFontAndFontSize(PDFOperandName font
|
|||
{
|
||||
try
|
||||
{
|
||||
PDFFontPointer font = PDFFont::createFont(m_fontDictionary->get(fontName.name), m_document);
|
||||
PDFFontPointer font = m_fontCache->getFont(m_fontDictionary->get(fontName.name));
|
||||
|
||||
m_graphicState.setTextFont(qMove(font));
|
||||
m_graphicState.setTextFontSize(fontSize);
|
||||
|
@ -1759,7 +1760,6 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
|
|||
// 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)
|
||||
|
@ -1787,7 +1787,7 @@ void PDFPageContentProcessor::drawText(const TextSequence& textSequence)
|
|||
// Then get the glyph path and paint it
|
||||
if (item.glyph)
|
||||
{
|
||||
QPainterPath glyphPath = fontMatrix.map(*item.glyph);
|
||||
const QPainterPath& glyphPath = *item.glyph;
|
||||
if (!glyphPath.isEmpty())
|
||||
{
|
||||
QMatrix textRenderingMatrix = textMatrix * adjustMatrix;
|
||||
|
@ -1866,7 +1866,7 @@ PDFRealizedFontPointer PDFPageContentProcessor::getRealizedFontImpl() const
|
|||
{
|
||||
if (m_graphicState.getTextFont())
|
||||
{
|
||||
return m_graphicState.getTextFont()->getRealizedFont(m_graphicState.getTextFontSize());
|
||||
return m_fontCache->getRealizedFont(m_graphicState.getTextFont(), m_graphicState.getTextFontSize());
|
||||
}
|
||||
|
||||
return PDFRealizedFontPointer();
|
||||
|
|
|
@ -56,7 +56,7 @@ private:
|
|||
class PDFPageContentProcessor
|
||||
{
|
||||
public:
|
||||
explicit PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document);
|
||||
explicit PDFPageContentProcessor(const PDFPage* page, const PDFDocument* document, const PDFFontCache* fontCache);
|
||||
virtual ~PDFPageContentProcessor();
|
||||
|
||||
enum class Operator
|
||||
|
@ -578,6 +578,7 @@ private:
|
|||
|
||||
const PDFPage* m_page;
|
||||
const PDFDocument* m_document;
|
||||
const PDFFontCache* m_fontCache;
|
||||
const PDFDictionary* m_colorSpaceDictionary;
|
||||
const PDFDictionary* m_fontDictionary;
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace pdf
|
|||
{
|
||||
|
||||
|
||||
PDFPainter::PDFPainter(QPainter* painter, PDFRenderer::Features features, QMatrix pagePointToDevicePointMatrix, const PDFPage* page, const PDFDocument* document) :
|
||||
PDFPageContentProcessor(page, document),
|
||||
PDFPainter::PDFPainter(QPainter* painter, PDFRenderer::Features features, QMatrix pagePointToDevicePointMatrix, const PDFPage* page, const PDFDocument* document, const PDFFontCache* fontCache) :
|
||||
PDFPageContentProcessor(page, document, fontCache),
|
||||
m_painter(painter),
|
||||
m_features(features),
|
||||
m_pagePointToDevicePointMatrix(pagePointToDevicePointMatrix)
|
||||
|
|
|
@ -34,7 +34,18 @@ class PDFPainter : public PDFPageContentProcessor
|
|||
{
|
||||
public:
|
||||
/// Constructs new PDFPainter object, with default parameters.
|
||||
explicit PDFPainter(QPainter* painter, PDFRenderer::Features features, QMatrix pagePointToDevicePointMatrix, const PDFPage* page, const PDFDocument* document);
|
||||
/// \param painter Painter, on which page content is drawn
|
||||
/// \param features Features of the painter
|
||||
/// \param pagePointToDevicePointMatrix Matrix, which translates page points to device points
|
||||
/// \param page Page, which will be drawn
|
||||
/// \param document Document owning the page
|
||||
/// \param fontCache Font cache
|
||||
explicit PDFPainter(QPainter* painter,
|
||||
PDFRenderer::Features features,
|
||||
QMatrix pagePointToDevicePointMatrix,
|
||||
const PDFPage* page,
|
||||
const PDFDocument* document,
|
||||
const PDFFontCache* fontCache);
|
||||
virtual ~PDFPainter() override;
|
||||
|
||||
protected:
|
||||
|
|
|
@ -22,8 +22,9 @@
|
|||
namespace pdf
|
||||
{
|
||||
|
||||
PDFRenderer::PDFRenderer(const PDFDocument* document) :
|
||||
PDFRenderer::PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCache) :
|
||||
m_document(document),
|
||||
m_fontCache(fontCache),
|
||||
m_features(Antialiasing | TextAntialiasing)
|
||||
{
|
||||
Q_ASSERT(document);
|
||||
|
@ -54,7 +55,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QRectF& recta
|
|||
matrix.translate(rectangle.left(), rectangle.bottom());
|
||||
matrix.scale(rectangle.width() / mediaBox.width(), -rectangle.height() / mediaBox.height());
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document);
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ QList<PDFRenderError> PDFRenderer::render(QPainter* painter, const QMatrix& matr
|
|||
const PDFPage* page = catalog->getPage(pageIndex);
|
||||
Q_ASSERT(page);
|
||||
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document);
|
||||
PDFPainter processor(painter, m_features, matrix, page, m_document, m_fontCache);
|
||||
return processor.processContents();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ class QPainter;
|
|||
|
||||
namespace pdf
|
||||
{
|
||||
class PDFFontCache;
|
||||
|
||||
enum RenderErrorType
|
||||
{
|
||||
|
@ -49,7 +50,7 @@ struct PDFRenderError
|
|||
class PDFRenderer
|
||||
{
|
||||
public:
|
||||
explicit PDFRenderer(const PDFDocument* document);
|
||||
explicit PDFRenderer(const PDFDocument* document, const PDFFontCache* fontCache);
|
||||
|
||||
enum Feature
|
||||
{
|
||||
|
@ -75,6 +76,7 @@ public:
|
|||
|
||||
private:
|
||||
const PDFDocument* m_document;
|
||||
const PDFFontCache* m_fontCache;
|
||||
Features m_features;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue