diff -ur poppler-23.09.0/glib/demo/render.c poppler-23.09.0.patched/glib/demo/render.c --- poppler-23.09.0/glib/demo/render.c 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/glib/demo/render.c 2023-11-30 18:01:41.000547101 +0100 @@ -79,12 +79,15 @@ static void pgd_render_start(GtkButton *button, PgdRenderDemo *demo) { PopplerPage *page; + gboolean subpixel_rendering; gdouble page_width, page_height; gdouble width, height; gint x, y; gchar *str; GTimer *timer; cairo_t *cr; + cairo_font_options_t *fo; + page = poppler_document_get_page(demo->doc, demo->page); if (!page) { @@ -114,6 +117,21 @@ demo->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create(demo->surface); + fo = cairo_font_options_create (); + cairo_get_font_options (cr, fo); + + subpixel_rendering = poppler_page_support_subpixel_rendering (page); + printf("subpixel_rendering %d\n", subpixel_rendering); + if (subpixel_rendering) { + cairo_set_source_rgb (cr, 1., 1., 1.); + cairo_paint (cr); + cairo_font_options_set_antialias (fo, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_font_options_set_subpixel_order (fo, CAIRO_SUBPIXEL_ORDER_RGB); + } + + cairo_set_font_options (cr, fo); + cairo_font_options_destroy (fo); + cairo_save(cr); switch (demo->rotate) { case 90: @@ -144,9 +162,11 @@ } cairo_restore(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER); - cairo_set_source_rgb(cr, 1., 1., 1.); - cairo_paint(cr); + if (!subpixel_rendering) { + cairo_set_operator(cr, CAIRO_OPERATOR_DEST_OVER); + cairo_set_source_rgb(cr, 1., 1., 1.); + cairo_paint(cr); + } g_timer_stop(timer); diff -ur poppler-23.09.0/glib/poppler-page.cc poppler-23.09.0.patched/glib/poppler-page.cc --- poppler-23.09.0/glib/poppler-page.cc 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/glib/poppler-page.cc 2023-11-30 18:07:07.875433617 +0100 @@ -2572,3 +2572,13 @@ return g_list_reverse(attributes); } + +gboolean +poppler_page_support_subpixel_rendering (PopplerPage *page) +{ + CairoOutputDev *output_dev; + g_return_val_if_fail (POPPLER_IS_PAGE (page), FALSE); + + output_dev = page->document->output_dev; + return page->page->supportSubpixelRendering(output_dev); +} diff -ur poppler-23.09.0/glib/poppler-page.h poppler-23.09.0.patched/glib/poppler-page.h --- poppler-23.09.0/glib/poppler-page.h 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/glib/poppler-page.h 2023-11-30 18:09:23.142489921 +0100 @@ -112,6 +112,8 @@ POPPLER_PUBLIC GList *poppler_page_get_text_attributes_for_area(PopplerPage *page, PopplerRectangle *area); +gboolean poppler_page_support_subpixel_rendering (PopplerPage *page); + /* A rectangle on a page, with coordinates in PDF points. */ #define POPPLER_TYPE_RECTANGLE (poppler_rectangle_get_type()) /** diff -ur poppler-23.09.0/poppler/CairoFontEngine.cc poppler-23.09.0.patched/poppler/CairoFontEngine.cc --- poppler-23.09.0/poppler/CairoFontEngine.cc 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/CairoFontEngine.cc 2023-11-30 18:20:21.686158628 +0100 @@ -114,7 +114,7 @@ cairo_matrix_t m; cairo_matrix_init_identity(&m); cairo_font_options_t *options = cairo_font_options_create(); - cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_NONE); + cairo_font_options_set_hint_style(options, CAIRO_HINT_STYLE_SLIGHT); cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF); cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options); @@ -186,7 +186,7 @@ } } - font_face.cairo_font_face = cairo_ft_font_face_create_for_ft_face(resource->face, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP); + font_face.cairo_font_face = cairo_ft_font_face_create_for_ft_face(resource->face, FT_LOAD_TARGET_LIGHT | FT_LOAD_NO_BITMAP); if (cairo_font_face_set_user_data(font_face.cairo_font_face, &ft_cairo_key, resource, _ft_done_face)) { cairo_font_face_destroy(font_face.cairo_font_face); _ft_done_face(resource); diff -ur poppler-23.09.0/poppler/CairoOutputDev.cc poppler-23.09.0.patched/poppler/CairoOutputDev.cc --- poppler-23.09.0/poppler/CairoOutputDev.cc 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/CairoOutputDev.cc 2023-11-30 18:16:28.287237879 +0100 @@ -223,6 +223,13 @@ } if (c != nullptr) { cairo = cairo_reference(c); + { + cairo_font_options_t *options = cairo_font_options_create (); + cairo_get_font_options (cairo, options); + cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_SUBPIXEL); + cairo_set_font_options (cairo, options); + cairo_font_options_destroy (options); + } /* save the initial matrix so that we can use it for type3 fonts. */ // XXX: is this sufficient? could we miss changes to the matrix somehow? cairo_get_matrix(cairo, &orig_matrix); @@ -1519,6 +1526,7 @@ void CairoOutputDev::endString(GfxState *state) { int render; + GfxFontType fontType; if (!currentFont) { return; @@ -1544,6 +1552,18 @@ render = 0; } + fontType = state->getFont()->getType(); + // Do not enable subpixel rendering for type3 font + // For some reason it does not work + if (fontType == fontType3) { + cairo_save(cairo); + cairo_font_options_t *fo; + fo = cairo_font_options_create (); + cairo_get_font_options (cairo, fo); + cairo_font_options_set_antialias (fo, CAIRO_ANTIALIAS_DEFAULT); + cairo_set_font_options (cairo, fo); + } + if (!(render & 1)) { LOG(printf("fill string\n")); cairo_set_source(cairo, fill_pattern); @@ -1596,6 +1616,10 @@ } finish: + // pair with the previous cairo_save to disable subpixel rendering for type3 fonts + if (fontType == fontType3) { + cairo_restore(cairo); + } gfree(glyphs); glyphs = nullptr; if (use_show_text_glyphs) { diff -ur poppler-23.09.0/poppler/Gfx.cc poppler-23.09.0.patched/poppler/Gfx.cc --- poppler-23.09.0/poppler/Gfx.cc 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/Gfx.cc 2023-11-30 18:22:28.913389896 +0100 @@ -4603,6 +4603,47 @@ error(errSyntaxError, getPos(), "Bad image parameters"); } +bool Gfx::checkNormalBlendModeOnly(Object *str) { + printf("check blender mode start\n"); + Object args[maxArgs]; + int numArgs; + bool onlyNormalBlendMode; + Parser myParser(xref, str, false); + + numArgs = 0; + onlyNormalBlendMode = true; + + Object obj = myParser.getObj(); + while (!obj.isEOF()) { + if (obj.isCmd()) { + const char* cmd = obj.getCmd(); + + if (strcmp(cmd, "gs") == 0) { + GfxBlendMode mode; + Object obj1 = res->lookupGState(args[0].getName()); + if (!obj1.isNull()) { + Object obj2 = obj1.dictLookup("BM"); + if (!obj2.isNull()) { + if (state->parseBlendMode(&obj2, &mode)) { + printf("check blend mode: %d\n", mode); + onlyNormalBlendMode &= (mode == gfxBlendNormal); + } + } + } + } + + numArgs = 0; + } else if (numArgs < maxArgs) { + args[numArgs++] = obj.copy(); + } + + obj = myParser.getObj(); + } + + return onlyNormalBlendMode; +} + + bool Gfx::checkTransparencyGroup(Dict *resDict) { // check the effect of compositing objects as a group: diff -ur poppler-23.09.0/poppler/Gfx.h poppler-23.09.0.patched/poppler/Gfx.h --- poppler-23.09.0/poppler/Gfx.h 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/Gfx.h 2023-11-30 18:07:07.887433355 +0100 @@ -190,6 +190,9 @@ // Get the current graphics state object. GfxState *getState() { return state; } + // Check whether a stream only contains normal blend mode (to enable subpixel rendering) + bool checkNormalBlendModeOnly(Object *str); + bool checkTransparencyGroup(Dict *resDict); void drawForm(Object *str, Dict *resDict, const double *matrix, const double *bbox, bool transpGroup = false, bool softMask = false, GfxColorSpace *blendingColorSpace = nullptr, bool isolated = false, bool knockout = false, diff -ur poppler-23.09.0/poppler/Page.cc poppler-23.09.0.patched/poppler/Page.cc --- poppler-23.09.0/poppler/Page.cc 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/Page.cc 2023-11-30 18:23:43.977756338 +0100 @@ -344,6 +344,19 @@ return dict ? dict->copy(xrefA) : nullptr; } +bool Page::supportSubpixelRendering(OutputDev *out) { + bool supported = false; + PDFRectangle box; + + Object obj = contents.fetch(xref); + if (!obj.isNull()) { + Gfx gfx(doc, out, attrs->getResourceDict(), &box, nullptr); + supported = gfx.checkNormalBlendModeOnly(&obj); + } + + return supported; +} + void Page::replaceXRef(XRef *xrefA) { Dict *pageDict = pageObj.getDict()->copy(xrefA); diff -ur poppler-23.09.0/poppler/Page.h poppler-23.09.0.patched/poppler/Page.h --- poppler-23.09.0/poppler/Page.h 2023-09-05 23:15:14.000000000 +0200 +++ poppler-23.09.0.patched/poppler/Page.h 2023-11-30 18:07:07.887433355 +0100 @@ -178,6 +178,9 @@ Object *getResourceDictObject(); Dict *getResourceDictCopy(XRef *xrefA); + // Whether the content in this page supports subpixel rendering (lcdfilter) + bool supportSubpixelRendering(OutputDev *out); + // Get annotations array. Object getAnnotsObject(XRef *xrefA = nullptr) { return annotsObj.fetch(xrefA ? xrefA : xref); } // Add a new annotation to the page