diff options
author | Nelson Benítez León <nbenitezl@gmail.com> | 2024-04-06 21:50:24 +0100 |
---|---|---|
committer | Albert Astals Cid <aacid@kde.org> | 2025-01-08 23:36:12 +0000 |
commit | eac3e60144d63581fe71be405a4de64af75a8563 (patch) | |
tree | 8538030c64bc28273844876a8e7dc49715a7b8bb | |
parent | 0ea8b3dc20b84a035e29ced11e2c45e088a7653d (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.cc | 22 | ||||
-rw-r--r-- | poppler/CairoFontEngine.h | 2 | ||||
-rw-r--r-- | poppler/CairoOutputDev.cc | 13 |
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) { |