1 //========================================================================
2 //
3 // OutputDev.h
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2005 Jonathan Blandford <jrb@redhat.com>
17 // Copyright (C) 2006 Thorkild Stray <thorkild@ifi.uio.no>
18 // Copyright (C) 2007 Jeff Muizelaar <jeff@infidigm.net>
19 // Copyright (C) 2007, 2011, 2017, 2021 Adrian Johnson <ajohnson@redneon.com>
20 // Copyright (C) 2009-2013, 2015 Thomas Freitag <Thomas.Freitag@alfa.de>
21 // Copyright (C) 2009, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
22 // Copyright (C) 2009, 2012, 2013, 2018, 2019, 2021 Albert Astals Cid <aacid@kde.org>
23 // Copyright (C) 2010 Christian Feuersänger <cfeuersaenger@googlemail.com>
24 // Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it>
25 // Copyright (C) 2012 William Bader <williambader@hotmail.com>
26 // Copyright (C) 2017, 2018, 2020 Oliver Sander <oliver.sander@tu-dresden.de>
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) 2018 Adam Reichold <adam.reichold@t-online.de>
29 // Copyright (C) 2020 Philipp Knechtges <philipp-dev@knechtges.com>
30 //
31 // To see a description of the changes please see the Changelog file that
32 // came with your tarball or type make ChangeLog if you are building from git
33 //
34 //========================================================================
35 
36 #ifndef OUTPUTDEV_H
37 #define OUTPUTDEV_H
38 
39 #include "poppler-config.h"
40 #include "poppler_private_export.h"
41 #include "CharTypes.h"
42 #include "Object.h"
43 #include "PopplerCache.h"
44 #include "ProfileData.h"
45 #include "GfxState.h"
46 #include <memory>
47 #include <unordered_map>
48 #include <string>
49 
50 class Annot;
51 class Dict;
52 class GooString;
53 class Gfx;
54 class Stream;
55 class Links;
56 class AnnotLink;
57 class Catalog;
58 class Page;
59 class Function;
60 
61 //------------------------------------------------------------------------
62 // OutputDev
63 //------------------------------------------------------------------------
64 
65 class POPPLER_PRIVATE_EXPORT OutputDev
66 {
67 public:
68     // Constructor.
69     OutputDev();
70 
71     // Destructor.
72     virtual ~OutputDev();
73 
74     //----- get info about output device
75 
76     // Does this device use upside-down coordinates?
77     // (Upside-down means (0,0) is the top left corner of the page.)
78     virtual bool upsideDown() = 0;
79 
80     // Does this device use drawChar() or drawString()?
81     virtual bool useDrawChar() = 0;
82 
83     // Does this device use tilingPatternFill()?  If this returns false,
84     // tiling pattern fills will be reduced to a series of other drawing
85     // operations.
useTilingPatternFill()86     virtual bool useTilingPatternFill() { return false; }
87 
88     // Does this device support specific shading types?
89     // see gouraudTriangleShadedFill() and patchMeshShadedFill()
useShadedFills(int type)90     virtual bool useShadedFills(int type) { return false; }
91 
92     // Does this device use FillColorStop()?
useFillColorStop()93     virtual bool useFillColorStop() { return false; }
94 
95     // Does this device use drawForm()?  If this returns false,
96     // form-type XObjects will be interpreted (i.e., unrolled).
useDrawForm()97     virtual bool useDrawForm() { return false; }
98 
99     // Does this device use beginType3Char/endType3Char?  Otherwise,
100     // text in Type 3 fonts will be drawn with drawChar/drawString.
101     virtual bool interpretType3Chars() = 0;
102 
103     // Does this device need non-text content?
needNonText()104     virtual bool needNonText() { return true; }
105 
106     // Does this device require incCharCount to be called for text on
107     // non-shown layers?
needCharCount()108     virtual bool needCharCount() { return false; }
109 
110     // Does this device need to clip pages to the crop box even when the
111     // box is the crop box?
needClipToCropBox()112     virtual bool needClipToCropBox() { return false; }
113 
114     //----- initialization and control
115 
116     // Set default transform matrix.
117     virtual void setDefaultCTM(const double *ctm);
118 
119     // Check to see if a page slice should be displayed.  If this
120     // returns false, the page display is aborted.  Typically, an
121     // OutputDev will use some alternate means to display the page
122     // before returning false.
123     virtual bool checkPageSlice(Page *page, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, int sliceX, int sliceY, int sliceW, int sliceH, bool printing, bool (*abortCheckCbk)(void *data) = nullptr,
124                                 void *abortCheckCbkData = nullptr, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = nullptr, void *annotDisplayDecideCbkData = nullptr)
125     {
126         return true;
127     }
128 
129     // Start a page.
startPage(int pageNum,GfxState * state,XRef * xref)130     virtual void startPage(int pageNum, GfxState *state, XRef *xref) { }
131 
132     // End a page.
endPage()133     virtual void endPage() { }
134 
135     // Dump page contents to display.
dump()136     virtual void dump() { }
137 
initGfxState(GfxState * state)138     virtual void initGfxState(GfxState *state)
139     {
140 #ifdef USE_CMS
141         state->setDisplayProfile(displayprofile);
142 
143         auto invalidref = Ref::INVALID();
144         if (defaultGrayProfile) {
145             auto cs = new GfxICCBasedColorSpace(1, new GfxDeviceGrayColorSpace(), &invalidref);
146 
147             cs->setProfile(defaultGrayProfile);
148             cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
149             state->setDefaultGrayColorSpace(cs);
150         }
151 
152         if (defaultRGBProfile) {
153             auto cs = new GfxICCBasedColorSpace(3, new GfxDeviceRGBColorSpace(), &invalidref);
154 
155             cs->setProfile(defaultRGBProfile);
156             cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
157             state->setDefaultRGBColorSpace(cs);
158         }
159 
160         if (defaultCMYKProfile) {
161             auto cs = new GfxICCBasedColorSpace(4, new GfxDeviceCMYKColorSpace(), &invalidref);
162 
163             cs->setProfile(defaultCMYKProfile);
164             cs->buildTransforms(state); // needs to happen after state->setDisplayProfile has been called
165             state->setDefaultCMYKColorSpace(cs);
166         }
167 #endif
168     }
169 
170     //----- coordinate conversion
171 
172     // Convert between device and user coordinates.
173     virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy);
174     virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
175 
getDefCTM()176     const double *getDefCTM() const { return defCTM; }
getDefICTM()177     const double *getDefICTM() const { return defICTM; }
178 
179     //----- save/restore graphics state
saveState(GfxState *)180     virtual void saveState(GfxState * /*state*/) { }
restoreState(GfxState *)181     virtual void restoreState(GfxState * /*state*/) { }
182 
183     //----- update graphics state
184     virtual void updateAll(GfxState *state);
185 
186     // Update the Current Transformation Matrix (CTM), i.e., the new matrix
187     // given in m11, ..., m32 is combined with the current value of the CTM.
188     // At the same time, when this method is called, state->getCTM() already
189     // contains the correct new CTM, so one may as well replace the
190     // CTM of the renderer with that.
updateCTM(GfxState *,double,double,double,double,double,double)191     virtual void updateCTM(GfxState * /*state*/, double /*m11*/, double /*m12*/, double /*m21*/, double /*m22*/, double /*m31*/, double /*m32*/) { }
updateLineDash(GfxState *)192     virtual void updateLineDash(GfxState * /*state*/) { }
updateFlatness(GfxState *)193     virtual void updateFlatness(GfxState * /*state*/) { }
updateLineJoin(GfxState *)194     virtual void updateLineJoin(GfxState * /*state*/) { }
updateLineCap(GfxState *)195     virtual void updateLineCap(GfxState * /*state*/) { }
updateMiterLimit(GfxState *)196     virtual void updateMiterLimit(GfxState * /*state*/) { }
updateLineWidth(GfxState *)197     virtual void updateLineWidth(GfxState * /*state*/) { }
updateStrokeAdjust(GfxState *)198     virtual void updateStrokeAdjust(GfxState * /*state*/) { }
updateAlphaIsShape(GfxState *)199     virtual void updateAlphaIsShape(GfxState * /*state*/) { }
updateTextKnockout(GfxState *)200     virtual void updateTextKnockout(GfxState * /*state*/) { }
updateFillColorSpace(GfxState *)201     virtual void updateFillColorSpace(GfxState * /*state*/) { }
updateStrokeColorSpace(GfxState *)202     virtual void updateStrokeColorSpace(GfxState * /*state*/) { }
updateFillColor(GfxState *)203     virtual void updateFillColor(GfxState * /*state*/) { }
updateStrokeColor(GfxState *)204     virtual void updateStrokeColor(GfxState * /*state*/) { }
updateBlendMode(GfxState *)205     virtual void updateBlendMode(GfxState * /*state*/) { }
updateFillOpacity(GfxState *)206     virtual void updateFillOpacity(GfxState * /*state*/) { }
updateStrokeOpacity(GfxState *)207     virtual void updateStrokeOpacity(GfxState * /*state*/) { }
updatePatternOpacity(GfxState *)208     virtual void updatePatternOpacity(GfxState * /*state*/) { }
clearPatternOpacity(GfxState *)209     virtual void clearPatternOpacity(GfxState * /*state*/) { }
updateFillOverprint(GfxState *)210     virtual void updateFillOverprint(GfxState * /*state*/) { }
updateStrokeOverprint(GfxState *)211     virtual void updateStrokeOverprint(GfxState * /*state*/) { }
updateOverprintMode(GfxState *)212     virtual void updateOverprintMode(GfxState * /*state*/) { }
updateTransfer(GfxState *)213     virtual void updateTransfer(GfxState * /*state*/) { }
updateFillColorStop(GfxState *,double)214     virtual void updateFillColorStop(GfxState * /*state*/, double /*offset*/) { }
215 
216     //----- update text state
updateFont(GfxState *)217     virtual void updateFont(GfxState * /*state*/) { }
updateTextMat(GfxState *)218     virtual void updateTextMat(GfxState * /*state*/) { }
updateCharSpace(GfxState *)219     virtual void updateCharSpace(GfxState * /*state*/) { }
updateRender(GfxState *)220     virtual void updateRender(GfxState * /*state*/) { }
updateRise(GfxState *)221     virtual void updateRise(GfxState * /*state*/) { }
updateWordSpace(GfxState *)222     virtual void updateWordSpace(GfxState * /*state*/) { }
updateHorizScaling(GfxState *)223     virtual void updateHorizScaling(GfxState * /*state*/) { }
updateTextPos(GfxState *)224     virtual void updateTextPos(GfxState * /*state*/) { }
updateTextShift(GfxState *,double)225     virtual void updateTextShift(GfxState * /*state*/, double /*shift*/) { }
saveTextPos(GfxState *)226     virtual void saveTextPos(GfxState * /*state*/) { }
restoreTextPos(GfxState *)227     virtual void restoreTextPos(GfxState * /*state*/) { }
228 
229     //----- path painting
stroke(GfxState *)230     virtual void stroke(GfxState * /*state*/) { }
fill(GfxState *)231     virtual void fill(GfxState * /*state*/) { }
eoFill(GfxState *)232     virtual void eoFill(GfxState * /*state*/) { }
tilingPatternFill(GfxState *,Gfx *,Catalog *,GfxTilingPattern *,const double *,int,int,int,int,double,double)233     virtual 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*/)
234     {
235         return false;
236     }
functionShadedFill(GfxState *,GfxFunctionShading *)237     virtual bool functionShadedFill(GfxState * /*state*/, GfxFunctionShading * /*shading*/) { return false; }
axialShadedFill(GfxState *,GfxAxialShading *,double,double)238     virtual bool axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/, double /*tMin*/, double /*tMax*/) { return false; }
axialShadedSupportExtend(GfxState *,GfxAxialShading *)239     virtual bool axialShadedSupportExtend(GfxState * /*state*/, GfxAxialShading * /*shading*/) { return false; }
radialShadedFill(GfxState *,GfxRadialShading *,double,double)240     virtual bool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/, double /*sMin*/, double /*sMax*/) { return false; }
radialShadedSupportExtend(GfxState *,GfxRadialShading *)241     virtual bool radialShadedSupportExtend(GfxState * /*state*/, GfxRadialShading * /*shading*/) { return false; }
gouraudTriangleShadedFill(GfxState * state,GfxGouraudTriangleShading * shading)242     virtual bool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) { return false; }
patchMeshShadedFill(GfxState * state,GfxPatchMeshShading * shading)243     virtual bool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading) { return false; }
244 
245     //----- path clipping
246 
247     // Update the clipping path.  The new path is the intersection of the old path
248     // with the path given in 'state'.
249     // Additionally, set the clipping mode to the 'nonzero winding number rule'.
250     // That is, a point is inside the clipping region if its winding number
251     // with respect to the clipping path is nonzero.
clip(GfxState *)252     virtual void clip(GfxState * /*state*/) { }
253 
254     // Update the clipping path.  The new path is the intersection of the old path
255     // with the path given in 'state'.
256     // Additionally, set the clipping mode to the 'even-odd rule'.  That is, a point is
257     // inside the clipping region if a ray from it to infinity will cross the clipping
258     // path an odd number of times (disregarding the path orientation).
eoClip(GfxState *)259     virtual void eoClip(GfxState * /*state*/) { }
260 
261     // Update the clipping path.  Unlike for the previous two methods, the clipping region
262     // is not the region surrounded by the path in 'state', but rather the path itself,
263     // rendered with the current pen settings.
clipToStrokePath(GfxState *)264     virtual void clipToStrokePath(GfxState * /*state*/) { }
265 
266     //----- text drawing
beginStringOp(GfxState *)267     virtual void beginStringOp(GfxState * /*state*/) { }
endStringOp(GfxState *)268     virtual void endStringOp(GfxState * /*state*/) { }
beginString(GfxState *,const GooString *)269     virtual void beginString(GfxState * /*state*/, const GooString * /*s*/) { }
endString(GfxState *)270     virtual void endString(GfxState * /*state*/) { }
271 
272     // Draw one glyph at a specified position
273     //
274     // Arguments are:
275     // CharCode code: This is the character code in the content stream. It needs to be mapped back to a glyph index.
276     // int nBytes: The text strings in the content stream can consists of either 8-bit or 16-bit
277     //             character codes depending on the font. nBytes is the number of bytes in the character code.
278     // Unicode *u: The UCS-4 mapping used for text extraction (TextOutputDev).
279     // int uLen: The number of unicode entries in u.  Usually '1', for a single character,
280     //           but it may also have larger values, for example for ligatures.
drawChar(GfxState *,double,double,double,double,double,double,CharCode,int,const Unicode *,int)281     virtual 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*/) { }
drawString(GfxState *,const GooString *)282     virtual void drawString(GfxState * /*state*/, const GooString * /*s*/) { }
283     virtual bool beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/, double /*dx*/, double /*dy*/, CharCode /*code*/, const Unicode * /*u*/, int /*uLen*/);
endType3Char(GfxState *)284     virtual void endType3Char(GfxState * /*state*/) { }
beginTextObject(GfxState *)285     virtual void beginTextObject(GfxState * /*state*/) { }
endTextObject(GfxState *)286     virtual void endTextObject(GfxState * /*state*/) { }
incCharCount(int)287     virtual void incCharCount(int /*nChars*/) { }
beginActualText(GfxState *,const GooString *)288     virtual void beginActualText(GfxState * /*state*/, const GooString * /*text*/) { }
endActualText(GfxState *)289     virtual void endActualText(GfxState * /*state*/) { }
290 
291     //----- image drawing
292     // Draw an image mask.  An image mask is a one-bit-per-pixel image, where each pixel
293     // can only be 'fill color' or 'transparent'.
294     //
295     // If 'invert' is false, a sample value of 0 marks the page with the current color,
296     // and a 1 leaves the previous contents unchanged. If 'invert' is true, these meanings are reversed.
297     virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg);
298     virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool inlineImg, double *baseMatrix);
299     virtual void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix);
300     virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg);
301     virtual 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);
302     virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap,
303                                      bool maskInterpolate);
304 
305     //----- grouping operators
306 
307     virtual void endMarkedContent(GfxState *state);
308     virtual void beginMarkedContent(const char *name, Dict *properties);
309     virtual void markPoint(const char *name);
310     virtual void markPoint(const char *name, Dict *properties);
311 
312 #ifdef OPI_SUPPORT
313     //----- OPI functions
314     virtual void opiBegin(GfxState *state, Dict *opiDict);
315     virtual void opiEnd(GfxState *state, Dict *opiDict);
316 #endif
317 
318     //----- Type 3 font operators
type3D0(GfxState *,double,double)319     virtual void type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) { }
type3D1(GfxState *,double,double,double,double,double,double)320     virtual void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/, double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) { }
321 
322     //----- form XObjects
beginForm(Ref)323     virtual void beginForm(Ref /*id*/) { }
drawForm(Ref)324     virtual void drawForm(Ref /*id*/) { }
endForm(Ref)325     virtual void endForm(Ref /*id*/) { }
326 
327     //----- PostScript XObjects
psXObject(Stream *,Stream *)328     virtual void psXObject(Stream * /*psStream*/, Stream * /*level1Stream*/) { }
329 
330     //----- Profiling
331     void startProfile();
getProfileHash()332     std::unordered_map<std::string, ProfileData> *getProfileHash() const { return profileHash.get(); }
333     std::unique_ptr<std::unordered_map<std::string, ProfileData>> endProfile();
334 
335     //----- transparency groups and soft masks
checkTransparencyGroup(GfxState *,bool)336     virtual bool checkTransparencyGroup(GfxState * /*state*/, bool /*knockout*/) { return true; }
beginTransparencyGroup(GfxState *,const double *,GfxColorSpace *,bool,bool,bool)337     virtual void beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) { }
endTransparencyGroup(GfxState *)338     virtual void endTransparencyGroup(GfxState * /*state*/) { }
paintTransparencyGroup(GfxState *,const double *)339     virtual void paintTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/) { }
setSoftMask(GfxState *,const double *,bool,Function *,GfxColor *)340     virtual void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) { }
clearSoftMask(GfxState *)341     virtual void clearSoftMask(GfxState * /*state*/) { }
342 
343     //----- links
processLink(AnnotLink *)344     virtual void processLink(AnnotLink * /*link*/) { }
345 
346 #if 1 //~tmp: turn off anti-aliasing temporarily
getVectorAntialias()347     virtual bool getVectorAntialias() { return false; }
setVectorAntialias(bool)348     virtual void setVectorAntialias(bool /*vaa*/) { }
349 #endif
350 
351 #ifdef USE_CMS
setDisplayProfile(const GfxLCMSProfilePtr & profile)352     void setDisplayProfile(const GfxLCMSProfilePtr &profile) { displayprofile = profile; }
getDisplayProfile()353     GfxLCMSProfilePtr getDisplayProfile() const { return displayprofile; }
setDefaultGrayProfile(const GfxLCMSProfilePtr & profile)354     void setDefaultGrayProfile(const GfxLCMSProfilePtr &profile) { defaultGrayProfile = profile; }
getDefaultGrayProfile()355     GfxLCMSProfilePtr getDefaultGrayProfile() const { return defaultGrayProfile; }
setDefaultRGBProfile(const GfxLCMSProfilePtr & profile)356     void setDefaultRGBProfile(const GfxLCMSProfilePtr &profile) { defaultRGBProfile = profile; }
getDefaultRGBProfile()357     GfxLCMSProfilePtr getDefaultRGBProfile() const { return defaultRGBProfile; }
setDefaultCMYKProfile(const GfxLCMSProfilePtr & profile)358     void setDefaultCMYKProfile(const GfxLCMSProfilePtr &profile) { defaultCMYKProfile = profile; }
getDefaultCMYKProfile()359     GfxLCMSProfilePtr getDefaultCMYKProfile() const { return defaultCMYKProfile; }
360 
getIccColorSpaceCache()361     PopplerCache<Ref, GfxICCBasedColorSpace> *getIccColorSpaceCache() { return &iccColorSpaceCache; }
362 #endif
363 
364 private:
365     double defCTM[6]; // default coordinate transform matrix
366     double defICTM[6]; // inverse of default CTM
367     std::unique_ptr<std::unordered_map<std::string, ProfileData>> profileHash;
368 
369 #ifdef USE_CMS
370     GfxLCMSProfilePtr displayprofile;
371     GfxLCMSProfilePtr defaultGrayProfile;
372     GfxLCMSProfilePtr defaultRGBProfile;
373     GfxLCMSProfilePtr defaultCMYKProfile;
374 
375     PopplerCache<Ref, GfxICCBasedColorSpace> iccColorSpaceCache;
376 #endif
377 };
378 
379 #endif
380