1//========================================================================
2//
3// CairoOutputDev.h
4//
5// Copyright 2003 Glyph & Cog, LLC
6// Copyright 2004 Red Hat, INC
7//
8//========================================================================
9
10//========================================================================
11//
12// Modified under the Poppler project - http://poppler.freedesktop.org
13//
14// All changes made under the Poppler project to this file are licensed
15// under GPL version 2 or later
16//
17// Copyright (C) 2005-2008 Jeff Muizelaar <jeff@infidigm.net>
18// Copyright (C) 2005, 2006 Kristian Høgsberg <krh@redhat.com>
19// Copyright (C) 2005 Nickolay V. Shmyrev <nshmyrev@yandex.ru>
20// Copyright (C) 2006-2011, 2013 Carlos Garcia Campos <carlosgc@gnome.org>
21// Copyright (C) 2008, 2009, 2011-2017, 2022, 2023 Adrian Johnson <ajohnson@redneon.com>
22// Copyright (C) 2008 Michael Vrable <mvrable@cs.ucsd.edu>
23// Copyright (C) 2010-2013 Thomas Freitag <Thomas.Freitag@alfa.de>
24// Copyright (C) 2015 Suzuki Toshiya <mpsuzuki@hiroshima-u.ac.jp>
25// Copyright (C) 2016 Jason Crain <jason@aquaticape.us>
26// Copyright (C) 2018, 2019, 2021 Albert Astals Cid <aacid@kde.org>
27// Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
28// Copyright (C) 2020 Michal <sudolskym@gmail.com>
29// Copyright (C) 2021 Christian Persch <chpe@src.gnome.org>
30// Copyright (C) 2022 Marek Kasik <mkasik@redhat.com>
31//
32// To see a description of the changes please see the Changelog file that
33// came with your tarball or type make ChangeLog if you are building from git
34//
35//========================================================================
36
37#ifndef CAIROOUTPUTDEV_H
38#define CAIROOUTPUTDEV_H
39
40#include <unordered_set>
41
42#include <cairo-ft.h>
43#include "OutputDev.h"
44#include "TextOutputDev.h"
45#include "GfxState.h"
46#include "StructElement.h"
47#include "StructTreeRoot.h"
48#include "Annot.h"
49#include "Link.h"
50
51class PDFDoc;
52class GfxState;
53class GfxPath;
54class Gfx8BitFont;
55struct GfxRGB;
56class CairoFontEngine;
57class CairoFont;
58
59//------------------------------------------------------------------------
60
61//------------------------------------------------------------------------
62// CairoImage
63//------------------------------------------------------------------------
64class CairoImage
65{
66public:
67 // Constructor.
68 CairoImage(double x1, double y1, double x2, double y2);
69
70 // Destructor.
71 ~CairoImage();
72
73 CairoImage(const CairoImage &) = delete;
74 CairoImage &operator=(const CairoImage &) = delete;
75
76 // Set the image cairo surface
77 void setImage(cairo_surface_t *image);
78
79 // Get the image cairo surface
80 cairo_surface_t *getImage() const { return image; }
81
82 // Get the image rectangle
83 void getRect(double *xa1, double *ya1, double *xa2, double *ya2)
84 {
85 *xa1 = x1;
86 *ya1 = y1;
87 *xa2 = x2;
88 *ya2 = y2;
89 }
90
91private:
92 cairo_surface_t *image; // image cairo surface
93 double x1, y1; // upper left corner
94 double x2, y2; // lower right corner
95};
96
97//------------------------------------------------------------------------
98// CairoOutputDev
99//------------------------------------------------------------------------
100
101class CairoOutputDev : public OutputDev
102{
103public:
104 // Constructor.
105 CairoOutputDev();
106
107 // Destructor.
108 ~CairoOutputDev() override;
109
110 //----- get info about output device
111
112 // Does this device use upside-down coordinates?
113 // (Upside-down means (0,0) is the top left corner of the page.)
114 bool upsideDown() override { return true; }
115
116 // Does this device use drawChar() or drawString()?
117 bool useDrawChar() override { return true; }
118
119 // Does this device use tilingPatternFill()? If this returns false,
120 // tiling pattern fills will be reduced to a series of other drawing
121 // operations.
122 bool useTilingPatternFill() override { return true; }
123
124 // Does this device use functionShadedFill(), axialShadedFill(), and
125 // radialShadedFill()? If this returns false, these shaded fills
126 // will be reduced to a series of other drawing operations.
127#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
128 bool useShadedFills(int type) override { return type <= 7; }
129#else
130 bool useShadedFills(int type) override { return type > 1 && type < 4; }
131#endif
132
133 // Does this device use FillColorStop()?
134 bool useFillColorStop() override { return true; }
135
136 // Does this device use beginType3Char/endType3Char? Otherwise,
137 // text in Type 3 fonts will be drawn with drawChar/drawString.
138 bool interpretType3Chars() override { return false; }
139
140 // Does this device need to clip pages to the crop box even when the
141 // box is the crop box?
142 bool needClipToCropBox() override { return true; }
143
144 //----- initialization and control
145
146 // Start a page.
147 void startPage(int pageNum, GfxState *state, XRef *xref) override;
148
149 // End a page.
150 void endPage() override;
151
152 // Must be called before last call to endPage()
153 void emitStructTree();
154
155 void beginForm(Object *obj, Ref id) override;
156 void endForm(Object *obj, Ref id) override;
157
158 //----- save/restore graphics state
159 void saveState(GfxState *state) override;
160 void restoreState(GfxState *state) override;
161
162 //----- update graphics state
163 void updateAll(GfxState *state) override;
164 void setDefaultCTM(const double *ctm) override;
165 void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override;
166 void updateLineDash(GfxState *state) override;
167 void updateFlatness(GfxState *state) override;
168 void updateLineJoin(GfxState *state) override;
169 void updateLineCap(GfxState *state) override;
170 void updateMiterLimit(GfxState *state) override;
171 void updateLineWidth(GfxState *state) override;
172 void updateFillColor(GfxState *state) override;
173 void updateStrokeColor(GfxState *state) override;
174 void updateFillOpacity(GfxState *state) override;
175 void updateStrokeOpacity(GfxState *state) override;
176 void updateFillColorStop(GfxState *state, double offset) override;
177 void updateBlendMode(GfxState *state) override;
178
179 //----- update text state
180 void updateFont(GfxState *state) override;
181
182 //----- path painting
183 void stroke(GfxState *state) override;
184 void fill(GfxState *state) override;
185 void eoFill(GfxState *state) override;
186 void clipToStrokePath(GfxState *state) override;
187 bool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep) override;
188#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
189 bool functionShadedFill(GfxState *state, GfxFunctionShading *shading) override;
190#endif
191 bool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) override;
192 bool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading) override;
193 bool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) override;
194 bool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading) override;
195#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
196 bool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) override;
197 bool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading) override;
198#endif
199
200 //----- path clipping
201 void clip(GfxState *state) override;
202 void eoClip(GfxState *state) override;
203
204 //----- text drawing
205 void beginString(GfxState *state, const GooString *s) override;
206 void endString(GfxState *state) override;
207 void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, const Unicode *u, int uLen) override;
208 void beginActualText(GfxState *state, const GooString *text) override;
209 void endActualText(GfxState *state) override;
210
211 bool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, const Unicode *u, int uLen) override;
212 void endType3Char(GfxState *state) override;
213 void beginTextObject(GfxState *state) override;
214 void endTextObject(GfxState *state) override;
215
216 void beginMarkedContent(const char *name, Dict *properties) override;
217 void endMarkedContent(GfxState *state) override;
218
219 //----- image drawing
220 void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) override;
221 void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool inlineImg, double *baseMatrix) override;
222 void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) override;
223 void drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg);
224 void drawImageMaskRegular(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg);
225
226 void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) override;
227 void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
228 bool maskInterpolate) override;
229
230 void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, bool maskInvert, bool maskInterpolate) override;
231
232 //----- transparency groups and soft masks
233 void beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) override;
234 void endTransparencyGroup(GfxState * /*state*/) override;
235 void popTransparencyGroup();
236 void paintTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/) override;
237 void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) override;
238 void clearSoftMask(GfxState * /*state*/) override;
239
240 //----- Type 3 font operators
241 void type3D0(GfxState *state, double wx, double wy) override;
242 void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) override;
243
244 //----- special access
245
246 // Called to indicate that a new PDF document has been loaded.
247 void startDoc(PDFDoc *docA, CairoFontEngine *fontEngine = nullptr);
248
249 // Called to prepare this output dev for rendering CairoType3Font.
250 void startType3Render(GfxState *state, XRef *xref);
251
252 bool isReverseVideo() { return false; }
253
254 void setCairo(cairo_t *cr);
255 void setTextPage(TextPage *text);
256 void setPrinting(bool printingA)
257 {
258 printing = printingA;
259 needFontUpdate = true;
260 }
261 void copyAntialias(cairo_t *cr, cairo_t *source_cr);
262 void setLogicalStructure(bool logStruct) { this->logicalStruct = logStruct; }
263
264 enum Type3RenderType
265 {
266 Type3RenderNone,
267 Type3RenderMask,
268 Type3RenderColor
269 };
270 void setType3RenderType(Type3RenderType state) { t3_render_state = state; }
271 void getType3GlyphWidth(double *wx, double *wy)
272 {
273 *wx = t3_glyph_wx;
274 *wy = t3_glyph_wy;
275 }
276 bool hasType3GlyphBBox() { return t3_glyph_has_bbox; }
277 double *getType3GlyphBBox() { return t3_glyph_bbox; }
278 bool type3GlyphHasColor() { return t3_glyph_has_color; }
279
280protected:
281 void doPath(cairo_t *cairo, GfxState *state, const GfxPath *path);
282 cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface);
283 void getScaledSize(const cairo_matrix_t *matrix, int orig_width, int orig_height, int *scaledWidth, int *scaledHeight);
284 cairo_filter_t getFilterForSurface(cairo_surface_t *image, bool interpolate);
285 bool getStreamData(Stream *str, char **buffer, int *length);
286 void setMimeData(GfxState *state, Stream *str, Object *ref, GfxImageColorMap *colorMap, cairo_surface_t *image, int height);
287 void fillToStrokePathClip(GfxState *state);
288 void alignStrokeCoords(const GfxSubpath *subpath, int i, double *x, double *y);
289 AnnotLink *findLinkObject(const StructElement *elem);
290 void quadToCairoRect(AnnotQuadrilaterals *quads, int idx, double destPageHeight, cairo_rectangle_t *rect);
291 bool appendLinkDestRef(GooString *s, const LinkDest *dest);
292 void appendLinkDestXY(GooString *s, const LinkDest *dest, double destPageHeight);
293 bool beginLinkTag(AnnotLink *annotLink);
294 bool beginLink(const StructElement *linkElem);
295 void getStructElemAttributeString(const StructElement *elem);
296 int getContentElementStructParents(const StructElement *element);
297 bool checkIfStructElementNeeded(const StructElement *element);
298 void emitStructElement(const StructElement *elem);
299 void startFirstPage(int pageNum, GfxState *state, XRef *xrefA);
300#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0)
301 bool setMimeDataForJBIG2Globals(Stream *str, cairo_surface_t *image);
302#endif
303#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10)
304 bool setMimeDataForCCITTParams(Stream *str, cairo_surface_t *image, int height);
305#endif
306 static void textStringToQuotedUtf8(const GooString *text, GooString *s);
307 bool isPDF();
308
309 std::optional<GfxRGB> fill_color, stroke_color;
310 cairo_pattern_t *fill_pattern, *stroke_pattern;
311 double fill_opacity;
312 double stroke_opacity;
313 bool stroke_adjust;
314 bool adjusted_stroke_width;
315 bool align_stroke_coords;
316 std::shared_ptr<CairoFont> currentFont;
317 XRef *xref;
318
319 struct StrokePathClip
320 {
321 GfxPath *path;
322 cairo_matrix_t ctm;
323 double line_width;
324 double *dashes;
325 int dash_count;
326 double dash_offset;
327 cairo_line_cap_t cap;
328 cairo_line_join_t join;
329 double miter;
330 int ref_count;
331 } *strokePathClip;
332
333 PDFDoc *doc; // the current document
334
335 static FT_Library ft_lib;
336 static std::once_flag ft_lib_once_flag;
337
338 CairoFontEngine *fontEngine;
339 bool fontEngine_owner;
340
341 cairo_t *cairo;
342 cairo_matrix_t orig_matrix;
343 bool needFontUpdate; // set when the font needs to be updated
344 bool printing;
345 bool use_show_text_glyphs;
346 bool text_matrix_valid;
347 cairo_glyph_t *glyphs;
348 int glyphCount;
349 cairo_text_cluster_t *clusters;
350 int clusterCount;
351 char *utf8;
352 int utf8Count;
353 int utf8Max;
354 cairo_path_t *textClipPath;
355 bool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2)
356 Type3RenderType t3_render_state;
357 double t3_glyph_wx, t3_glyph_wy;
358 bool t3_glyph_has_bbox;
359 bool t3_glyph_has_color;
360 bool has_color;
361 double t3_glyph_bbox[4];
362 bool prescaleImages;
363 bool logicalStruct;
364 bool firstPage;
365 int pdfPageNum; // page number of the PDF file
366 int cairoPageNum; // page number in cairo output
367 std::vector<std::string> markedContentStack;
368 std::vector<Annot *> annotations;
369 std::set<std::string> emittedDestinations;
370 std::map<int, int> pdfPageToCairoPageMap;
371
372 TextPage *textPage; // text for the current page
373 ActualText *actualText;
374
375 cairo_pattern_t *group;
376 cairo_pattern_t *shape;
377 cairo_pattern_t *mask;
378 cairo_matrix_t mask_matrix;
379 cairo_t *cairo_shape;
380 int knockoutCount;
381 struct ColorSpaceStack
382 {
383 bool knockout;
384 GfxColorSpace *cs;
385 cairo_matrix_t group_matrix;
386 struct ColorSpaceStack *next;
387 } *groupColorSpaceStack;
388
389 struct SaveStateElement
390 {
391 // These patterns hold a reference
392 cairo_pattern_t *fill_pattern;
393 cairo_pattern_t *stroke_pattern;
394 double fill_opacity;
395 double stroke_opacity;
396 cairo_pattern_t *mask; // can be null
397 cairo_matrix_t mask_matrix;
398 Ref fontRef;
399 };
400 std::vector<SaveStateElement> saveStateStack;
401
402 std::map<Ref, std::map<std::string, std::unique_ptr<LinkDest>>> destsMap;
403 std::map<Ref, int> pdfPageRefToCairoPageNumMap;
404 std::vector<int> structParentsStack;
405 int currentStructParents;
406
407 struct StructParentsMcidHash
408 {
409 size_t operator()(std::pair<int, int> x) const { return x.first << 16 | x.second; }
410 };
411 std::unordered_set<std::pair<int, int>, StructParentsMcidHash> mcidEmitted; // <structParent, MCID>
412
413 std::unordered_set<const StructElement *> structElementNeeded;
414};
415
416//------------------------------------------------------------------------
417// CairoImageOutputDev
418//------------------------------------------------------------------------
419
420// XXX: this should ideally not inherit from CairoOutputDev but use it instead perhaps
421class CairoImageOutputDev : public CairoOutputDev
422{
423public:
424 // Constructor.
425 CairoImageOutputDev();
426
427 // Destructor.
428 ~CairoImageOutputDev() override;
429
430 //----- get info about output device
431
432 // Does this device use upside-down coordinates?
433 // (Upside-down means (0,0) is the top left corner of the page.)
434 bool upsideDown() override { return true; }
435
436 // Does this device use drawChar() or drawString()?
437 bool useDrawChar() override { return false; }
438
439 // Does this device use tilingPatternFill()? If this returns false,
440 // tiling pattern fills will be reduced to a series of other drawing
441 // operations.
442 bool useTilingPatternFill() override { return true; }
443
444 // Does this device use functionShadedFill(), axialShadedFill(), and
445 // radialShadedFill()? If this returns false, these shaded fills
446 // will be reduced to a series of other drawing operations.
447#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2)
448 bool useShadedFills(int type) override { return type <= 7; }
449#else
450 bool useShadedFills(int type) override { return type < 4; }
451#endif
452
453 // Does this device use FillColorStop()?
454 bool useFillColorStop() override { return false; }
455
456 // Does this device use beginType3Char/endType3Char? Otherwise,
457 // text in Type 3 fonts will be drawn with drawChar/drawString.
458 bool interpretType3Chars() override { return false; }
459
460 // Does this device need non-text content?
461 bool needNonText() override { return true; }
462
463 //----- save/restore graphics state
464 void saveState(GfxState *state) override { }
465 void restoreState(GfxState *state) override { }
466
467 //----- update graphics state
468 void updateAll(GfxState *state) override { }
469 void setDefaultCTM(const double *ctm) override { }
470 void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override { }
471 void updateLineDash(GfxState *state) override { }
472 void updateFlatness(GfxState *state) override { }
473 void updateLineJoin(GfxState *state) override { }
474 void updateLineCap(GfxState *state) override { }
475 void updateMiterLimit(GfxState *state) override { }
476 void updateLineWidth(GfxState *state) override { }
477 void updateFillColor(GfxState *state) override { }
478 void updateStrokeColor(GfxState *state) override { }
479 void updateFillOpacity(GfxState *state) override { }
480 void updateStrokeOpacity(GfxState *state) override { }
481 void updateBlendMode(GfxState *state) override { }
482
483 //----- update text state
484 void updateFont(GfxState *state) override { }
485
486 //----- path painting
487 void stroke(GfxState *state) override { }
488 void fill(GfxState *state) override { }
489 void eoFill(GfxState *state) override { }
490 void clipToStrokePath(GfxState *state) override { }
491 bool tilingPatternFill(GfxState *state, Gfx *gfx, Catalog *cat, GfxTilingPattern *tPat, const double *mat, int x0, int y0, int x1, int y1, double xStep, double yStep) override { return true; }
492 bool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) override { return true; }
493 bool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) override { return true; }
494
495 //----- path clipping
496 void clip(GfxState *state) override { }
497 void eoClip(GfxState *state) override { }
498
499 //----- image drawing
500 void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) override;
501 void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) override;
502 void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
503 bool maskInterpolate) override;
504 void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, bool maskInvert, bool maskInterpolate) override;
505 void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool inlineImg, double *baseMatrix) override;
506 void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) override { }
507
508 //----- transparency groups and soft masks
509 void beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) override { }
510 void endTransparencyGroup(GfxState * /*state*/) override { }
511 void paintTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/) override { }
512 void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) override { }
513 void clearSoftMask(GfxState * /*state*/) override { }
514
515 //----- Image list
516 // By default images are not rendred
517 void setImageDrawDecideCbk(bool (*cbk)(int img_id, void *data), void *data)
518 {
519 imgDrawCbk = cbk;
520 imgDrawCbkData = data;
521 }
522 // Iterate through list of images.
523 int getNumImages() const { return numImages; }
524 CairoImage *getImage(int i) const { return images[i]; }
525
526private:
527 void saveImage(CairoImage *image);
528 void getBBox(GfxState *state, int width, int height, double *x1, double *y1, double *x2, double *y2);
529
530 CairoImage **images;
531 int numImages;
532 int size;
533 bool (*imgDrawCbk)(int img_id, void *data);
534 void *imgDrawCbkData;
535};
536
537#endif
538

source code of poppler/poppler/CairoOutputDev.h