summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNelson Benítez León <nbenitezl@gmail.com>2024-04-06 21:50:24 +0100
committerAlbert Astals Cid <aacid@kde.org>2025-01-08 23:36:12 +0000
commiteac3e60144d63581fe71be405a4de64af75a8563 (patch)
tree8538030c64bc28273844876a8e7dc49715a7b8bb
parent0ea8b3dc20b84a035e29ced11e2c45e088a7653d (diff)
avoid _render_type3_glyph() stopping subsequent rendering
When _render_type3_glyph() fails it returns CAIRO_STATUS_USER_FONT_ERROR causing the cairo surface to be set in error state and this is never cleared. This prevents further rendering of subsequent content, while other PDF applications are able to handle this error condition more gracefully, omitting only the character or at most the font, with the remainder of the document showing up fine. So let's do the same and change the returned error into a logging message but return success from _render_type3_glyph() Also included is a fix for a pdftocairo bug: If a character isn't in /CharProcs at all, then pdftocairo displays it as the first /CharProcs entry (because CairoType3Font::create initializes the codeToGID array to 0). All other programs I tested will display it as a space or nothing. Patch from Jeffrey Morlan Fixes issue #1478
-rw-r--r--poppler/CairoFontEngine.cc22
-rw-r--r--poppler/CairoFontEngine.h2
-rw-r--r--poppler/CairoOutputDev.cc13
3 files changed, 25 insertions, 12 deletions
diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc
index 75ae72bd..816c7ee2 100644
--- a/poppler/CairoFontEngine.cc
+++ b/poppler/CairoFontEngine.cc
@@ -61,6 +61,8 @@
#include "Gfx.h"
#include "Page.h"
+#define EMPTY_ARRAY (-1)
+
//------------------------------------------------------------------------
// CairoFont
//------------------------------------------------------------------------
@@ -85,16 +87,19 @@ cairo_font_face_t *CairoFont::getFontFace()
return cairo_font_face;
}
-unsigned long CairoFont::getGlyph(CharCode code, const Unicode *u, int uLen)
+std::optional<unsigned long> CairoFont::getGlyph(CharCode code, const Unicode *u, int uLen)
{
FT_UInt gid;
if (code < codeToGID.size()) {
+ if (codeToGID[code] == EMPTY_ARRAY) {
+ return std::nullopt;
+ }
gid = (FT_UInt)codeToGID[code];
} else {
gid = (FT_UInt)code;
}
- return gid;
+ return { gid };
}
double CairoFont::getSubstitutionCorrection(const std::shared_ptr<GfxFont> &gfxFont)
@@ -433,11 +438,13 @@ static cairo_status_t _render_type3_glyph(cairo_scaled_font_t *scaled_font, unsi
charProcs = std::static_pointer_cast<Gfx8BitFont>(info->font)->getCharProcs();
if (!charProcs) {
- return CAIRO_STATUS_USER_FONT_ERROR;
+ // error already logged by Gfx8BitFont constructor
+ return CAIRO_STATUS_SUCCESS;
}
- if ((int)glyph >= charProcs->getLength()) {
- return CAIRO_STATUS_USER_FONT_ERROR;
+ if (glyph >= (unsigned)charProcs->getLength()) {
+ error(errSyntaxError, -1, "Type3 character not in /CharProcs");
+ return CAIRO_STATUS_SUCCESS;
}
mat = info->font->getFontMatrix();
@@ -466,7 +473,8 @@ static cairo_status_t _render_type3_glyph(cairo_scaled_font_t *scaled_font, unsi
output_dev->setType3RenderType(color ? CairoOutputDev::Type3RenderColor : CairoOutputDev::Type3RenderMask);
charProc = charProcs->getVal(glyph);
if (!charProc.isStream()) {
- return CAIRO_STATUS_USER_FONT_ERROR;
+ error(errSyntaxError, -1, "Type3 character /{0:s} value not a stream", charProcs->getKey(glyph));
+ return CAIRO_STATUS_SUCCESS;
}
Object charProcResObject = charProc.streamGetDict()->lookup("Resources");
if (charProcResObject.isDict()) {
@@ -553,7 +561,7 @@ CairoType3Font *CairoType3Font::create(const std::shared_ptr<GfxFont> &gfxFont,
char **enc = std::static_pointer_cast<Gfx8BitFont>(gfxFont)->getEncoding();
codeToGID.resize(256);
for (int i = 0; i < 256; ++i) {
- codeToGID[i] = 0;
+ codeToGID[i] = EMPTY_ARRAY;
if (charProcs && (name = enc[i])) {
for (int j = 0; j < charProcs->getLength(); j++) {
if (strcmp(name, charProcs->getKey(j)) == 0) {
diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h
index 07604d93..a26f8262 100644
--- a/poppler/CairoFontEngine.h
+++ b/poppler/CairoFontEngine.h
@@ -55,7 +55,7 @@ public:
virtual bool matches(Ref &other, bool printing);
cairo_font_face_t *getFontFace();
- unsigned long getGlyph(CharCode code, const Unicode *u, int uLen);
+ std::optional<unsigned long> getGlyph(CharCode code, const Unicode *u, int uLen);
double getSubstitutionCorrection(const std::shared_ptr<GfxFont> &gfxFont);
bool isSubstitute() { return substitute; }
diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc
index c2345cb9..d91c9876 100644
--- a/poppler/CairoOutputDev.cc
+++ b/poppler/CairoOutputDev.cc
@@ -1902,11 +1902,16 @@ void CairoOutputDev::beginString(GfxState *state, const GooString *s)
void CairoOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, const Unicode *u, int uLen)
{
+ std::optional<int> glyphIndex;
+
if (currentFont) {
- glyphs[glyphCount].index = currentFont->getGlyph(code, u, uLen);
- glyphs[glyphCount].x = x - originX;
- glyphs[glyphCount].y = y - originY;
- glyphCount++;
+ glyphIndex = currentFont->getGlyph(code, u, uLen);
+ if (glyphIndex) {
+ glyphs[glyphCount].index = *glyphIndex;
+ glyphs[glyphCount].x = x - originX;
+ glyphs[glyphCount].y = y - originY;
+ glyphCount++;
+ }
if (use_show_text_glyphs) {
const UnicodeMap *utf8Map = globalParams->getUtf8Map();
if (utf8Max - utf8Count < uLen * 6) {