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 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 // 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 CAIROOUTPUTDEV_H 37 #define CAIROOUTPUTDEV_H 38 39 #include <cairo-ft.h> 40 #include "OutputDev.h" 41 #include "TextOutputDev.h" 42 #include "GfxState.h" 43 44 class PDFDoc; 45 class GfxState; 46 class GfxPath; 47 class Gfx8BitFont; 48 struct GfxRGB; 49 class CairoFontEngine; 50 class CairoFont; 51 52 //------------------------------------------------------------------------ 53 54 //------------------------------------------------------------------------ 55 // CairoImage 56 //------------------------------------------------------------------------ 57 class CairoImage 58 { 59 public: 60 // Constructor. 61 CairoImage(double x1, double y1, double x2, double y2); 62 63 // Destructor. 64 ~CairoImage(); 65 66 CairoImage(const CairoImage &) = delete; 67 CairoImage &operator=(const CairoImage &) = delete; 68 69 // Set the image cairo surface 70 void setImage(cairo_surface_t *image); 71 72 // Get the image cairo surface getImage()73 cairo_surface_t *getImage() const { return image; } 74 75 // Get the image rectangle getRect(double * xa1,double * ya1,double * xa2,double * ya2)76 void getRect(double *xa1, double *ya1, double *xa2, double *ya2) 77 { 78 *xa1 = x1; 79 *ya1 = y1; 80 *xa2 = x2; 81 *ya2 = y2; 82 } 83 84 private: 85 cairo_surface_t *image; // image cairo surface 86 double x1, y1; // upper left corner 87 double x2, y2; // lower right corner 88 }; 89 90 //------------------------------------------------------------------------ 91 // CairoOutputDev 92 //------------------------------------------------------------------------ 93 94 class CairoOutputDev : public OutputDev 95 { 96 public: 97 // Constructor. 98 CairoOutputDev(); 99 100 // Destructor. 101 ~CairoOutputDev() override; 102 103 //----- get info about output device 104 105 // Does this device use upside-down coordinates? 106 // (Upside-down means (0,0) is the top left corner of the page.) upsideDown()107 bool upsideDown() override { return true; } 108 109 // Does this device use drawChar() or drawString()? useDrawChar()110 bool useDrawChar() override { return true; } 111 112 // Does this device use tilingPatternFill()? If this returns false, 113 // tiling pattern fills will be reduced to a series of other drawing 114 // operations. useTilingPatternFill()115 bool useTilingPatternFill() override { return true; } 116 117 // Does this device use functionShadedFill(), axialShadedFill(), and 118 // radialShadedFill()? If this returns false, these shaded fills 119 // will be reduced to a series of other drawing operations. 120 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) useShadedFills(int type)121 bool useShadedFills(int type) override { return type <= 7; } 122 #else useShadedFills(int type)123 bool useShadedFills(int type) override { return type > 1 && type < 4; } 124 #endif 125 126 // Does this device use FillColorStop()? useFillColorStop()127 bool useFillColorStop() override { return true; } 128 129 // Does this device use beginType3Char/endType3Char? Otherwise, 130 // text in Type 3 fonts will be drawn with drawChar/drawString. interpretType3Chars()131 bool interpretType3Chars() override { return false; } 132 133 // Does this device need to clip pages to the crop box even when the 134 // box is the crop box? needClipToCropBox()135 bool needClipToCropBox() override { return true; } 136 137 //----- initialization and control 138 139 // Start a page. 140 void startPage(int pageNum, GfxState *state, XRef *xref) override; 141 142 // End a page. 143 void endPage() override; 144 145 //----- save/restore graphics state 146 void saveState(GfxState *state) override; 147 void restoreState(GfxState *state) override; 148 149 //----- update graphics state 150 void updateAll(GfxState *state) override; 151 void setDefaultCTM(const double *ctm) override; 152 void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override; 153 void updateLineDash(GfxState *state) override; 154 void updateFlatness(GfxState *state) override; 155 void updateLineJoin(GfxState *state) override; 156 void updateLineCap(GfxState *state) override; 157 void updateMiterLimit(GfxState *state) override; 158 void updateLineWidth(GfxState *state) override; 159 void updateFillColor(GfxState *state) override; 160 void updateStrokeColor(GfxState *state) override; 161 void updateFillOpacity(GfxState *state) override; 162 void updateStrokeOpacity(GfxState *state) override; 163 void updateFillColorStop(GfxState *state, double offset) override; 164 void updateBlendMode(GfxState *state) override; 165 166 //----- update text state 167 void updateFont(GfxState *state) override; 168 169 //----- path painting 170 void stroke(GfxState *state) override; 171 void fill(GfxState *state) override; 172 void eoFill(GfxState *state) override; 173 void clipToStrokePath(GfxState *state) override; 174 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; 175 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) 176 bool functionShadedFill(GfxState *state, GfxFunctionShading *shading) override; 177 #endif 178 bool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) override; 179 bool axialShadedSupportExtend(GfxState *state, GfxAxialShading *shading) override; 180 bool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) override; 181 bool radialShadedSupportExtend(GfxState *state, GfxRadialShading *shading) override; 182 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) 183 bool gouraudTriangleShadedFill(GfxState *state, GfxGouraudTriangleShading *shading) override; 184 bool patchMeshShadedFill(GfxState *state, GfxPatchMeshShading *shading) override; 185 #endif 186 187 //----- path clipping 188 void clip(GfxState *state) override; 189 void eoClip(GfxState *state) override; 190 191 //----- text drawing 192 void beginString(GfxState *state, const GooString *s) override; 193 void endString(GfxState *state) override; 194 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; 195 void beginActualText(GfxState *state, const GooString *text) override; 196 void endActualText(GfxState *state) override; 197 198 bool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, const Unicode *u, int uLen) override; 199 void endType3Char(GfxState *state) override; 200 void beginTextObject(GfxState *state) override; 201 void endTextObject(GfxState *state) override; 202 203 //----- image drawing 204 void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) override; 205 void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool inlineImg, double *baseMatrix) override; 206 void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) override; 207 void drawImageMaskPrescaled(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg); 208 void drawImageMaskRegular(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg); 209 210 void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) override; 211 void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap, 212 bool maskInterpolate) override; 213 214 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; 215 216 //----- transparency groups and soft masks 217 void beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) override; 218 void endTransparencyGroup(GfxState * /*state*/) override; 219 void popTransparencyGroup(); 220 void paintTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/) override; 221 void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) override; 222 void clearSoftMask(GfxState * /*state*/) override; 223 224 //----- Type 3 font operators 225 void type3D0(GfxState *state, double wx, double wy) override; 226 void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) override; 227 228 //----- special access 229 230 // Called to indicate that a new PDF document has been loaded. 231 void startDoc(PDFDoc *docA, CairoFontEngine *fontEngine = nullptr); 232 isReverseVideo()233 bool isReverseVideo() { return false; } 234 235 void setCairo(cairo_t *cr); 236 void setTextPage(TextPage *text); setPrinting(bool printingA)237 void setPrinting(bool printingA) 238 { 239 printing = printingA; 240 needFontUpdate = true; 241 } 242 void copyAntialias(cairo_t *cr, cairo_t *source_cr); 243 setInType3Char(bool inType3CharA)244 void setInType3Char(bool inType3CharA) { inType3Char = inType3CharA; } getType3GlyphWidth(double * wx,double * wy)245 void getType3GlyphWidth(double *wx, double *wy) 246 { 247 *wx = t3_glyph_wx; 248 *wy = t3_glyph_wy; 249 } hasType3GlyphBBox()250 bool hasType3GlyphBBox() { return t3_glyph_has_bbox; } getType3GlyphBBox()251 double *getType3GlyphBBox() { return t3_glyph_bbox; } 252 253 protected: 254 void doPath(cairo_t *cairo, GfxState *state, const GfxPath *path); 255 cairo_surface_t *downscaleSurface(cairo_surface_t *orig_surface); 256 void getScaledSize(const cairo_matrix_t *matrix, int orig_width, int orig_height, int *scaledWidth, int *scaledHeight); 257 cairo_filter_t getFilterForSurface(cairo_surface_t *image, bool interpolate); 258 bool getStreamData(Stream *str, char **buffer, int *length); 259 void setMimeData(GfxState *state, Stream *str, Object *ref, GfxImageColorMap *colorMap, cairo_surface_t *image, int height); 260 void fillToStrokePathClip(GfxState *state); 261 void alignStrokeCoords(const GfxSubpath *subpath, int i, double *x, double *y); 262 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 14, 0) 263 bool setMimeDataForJBIG2Globals(Stream *str, cairo_surface_t *image); 264 #endif 265 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 10) 266 bool setMimeDataForCCITTParams(Stream *str, cairo_surface_t *image, int height); 267 #endif 268 269 GfxRGB fill_color, stroke_color; 270 cairo_pattern_t *fill_pattern, *stroke_pattern; 271 double fill_opacity; 272 double stroke_opacity; 273 bool stroke_adjust; 274 bool adjusted_stroke_width; 275 bool align_stroke_coords; 276 CairoFont *currentFont; 277 XRef *xref; 278 279 struct StrokePathClip 280 { 281 GfxPath *path; 282 cairo_matrix_t ctm; 283 double line_width; 284 double *dashes; 285 int dash_count; 286 double dash_offset; 287 cairo_line_cap_t cap; 288 cairo_line_join_t join; 289 double miter; 290 int ref_count; 291 } * strokePathClip; 292 293 PDFDoc *doc; // the current document 294 295 static FT_Library ft_lib; 296 static std::once_flag ft_lib_once_flag; 297 298 CairoFontEngine *fontEngine; 299 bool fontEngine_owner; 300 301 cairo_t *cairo; 302 cairo_matrix_t orig_matrix; 303 bool needFontUpdate; // set when the font needs to be updated 304 bool printing; 305 bool use_show_text_glyphs; 306 bool text_matrix_valid; 307 cairo_glyph_t *glyphs; 308 int glyphCount; 309 cairo_text_cluster_t *clusters; 310 int clusterCount; 311 char *utf8; 312 int utf8Count; 313 int utf8Max; 314 cairo_path_t *textClipPath; 315 bool inUncoloredPattern; // inside a uncolored pattern (PaintType = 2) 316 bool inType3Char; // inside a Type 3 CharProc 317 double t3_glyph_wx, t3_glyph_wy; 318 bool t3_glyph_has_bbox; 319 double t3_glyph_bbox[4]; 320 bool prescaleImages; 321 322 TextPage *textPage; // text for the current page 323 ActualText *actualText; 324 325 cairo_pattern_t *group; 326 cairo_pattern_t *shape; 327 cairo_pattern_t *mask; 328 cairo_matrix_t mask_matrix; 329 cairo_t *cairo_shape; 330 int knockoutCount; 331 struct ColorSpaceStack 332 { 333 bool knockout; 334 GfxColorSpace *cs; 335 cairo_matrix_t group_matrix; 336 struct ColorSpaceStack *next; 337 } * groupColorSpaceStack; 338 339 struct MaskStack 340 { 341 cairo_pattern_t *mask; 342 cairo_matrix_t mask_matrix; 343 struct MaskStack *next; 344 } * maskStack; 345 }; 346 347 //------------------------------------------------------------------------ 348 // CairoImageOutputDev 349 //------------------------------------------------------------------------ 350 351 // XXX: this should ideally not inherit from CairoOutputDev but use it instead perhaps 352 class CairoImageOutputDev : public CairoOutputDev 353 { 354 public: 355 // Constructor. 356 CairoImageOutputDev(); 357 358 // Destructor. 359 ~CairoImageOutputDev() override; 360 361 //----- get info about output device 362 363 // Does this device use upside-down coordinates? 364 // (Upside-down means (0,0) is the top left corner of the page.) upsideDown()365 bool upsideDown() override { return true; } 366 367 // Does this device use drawChar() or drawString()? useDrawChar()368 bool useDrawChar() override { return false; } 369 370 // Does this device use tilingPatternFill()? If this returns false, 371 // tiling pattern fills will be reduced to a series of other drawing 372 // operations. useTilingPatternFill()373 bool useTilingPatternFill() override { return true; } 374 375 // Does this device use functionShadedFill(), axialShadedFill(), and 376 // radialShadedFill()? If this returns false, these shaded fills 377 // will be reduced to a series of other drawing operations. 378 #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 11, 2) useShadedFills(int type)379 bool useShadedFills(int type) override { return type <= 7; } 380 #else useShadedFills(int type)381 bool useShadedFills(int type) override { return type < 4; } 382 #endif 383 384 // Does this device use FillColorStop()? useFillColorStop()385 bool useFillColorStop() override { return false; } 386 387 // Does this device use beginType3Char/endType3Char? Otherwise, 388 // text in Type 3 fonts will be drawn with drawChar/drawString. interpretType3Chars()389 bool interpretType3Chars() override { return false; } 390 391 // Does this device need non-text content? needNonText()392 bool needNonText() override { return true; } 393 394 //----- save/restore graphics state saveState(GfxState * state)395 void saveState(GfxState *state) override { } restoreState(GfxState * state)396 void restoreState(GfxState *state) override { } 397 398 //----- update graphics state updateAll(GfxState * state)399 void updateAll(GfxState *state) override { } setDefaultCTM(const double * ctm)400 void setDefaultCTM(const double *ctm) override { } updateCTM(GfxState * state,double m11,double m12,double m21,double m22,double m31,double m32)401 void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) override { } updateLineDash(GfxState * state)402 void updateLineDash(GfxState *state) override { } updateFlatness(GfxState * state)403 void updateFlatness(GfxState *state) override { } updateLineJoin(GfxState * state)404 void updateLineJoin(GfxState *state) override { } updateLineCap(GfxState * state)405 void updateLineCap(GfxState *state) override { } updateMiterLimit(GfxState * state)406 void updateMiterLimit(GfxState *state) override { } updateLineWidth(GfxState * state)407 void updateLineWidth(GfxState *state) override { } updateFillColor(GfxState * state)408 void updateFillColor(GfxState *state) override { } updateStrokeColor(GfxState * state)409 void updateStrokeColor(GfxState *state) override { } updateFillOpacity(GfxState * state)410 void updateFillOpacity(GfxState *state) override { } updateStrokeOpacity(GfxState * state)411 void updateStrokeOpacity(GfxState *state) override { } updateBlendMode(GfxState * state)412 void updateBlendMode(GfxState *state) override { } 413 414 //----- update text state updateFont(GfxState * state)415 void updateFont(GfxState *state) override { } 416 417 //----- path painting stroke(GfxState * state)418 void stroke(GfxState *state) override { } fill(GfxState * state)419 void fill(GfxState *state) override { } eoFill(GfxState * state)420 void eoFill(GfxState *state) override { } clipToStrokePath(GfxState * state)421 void clipToStrokePath(GfxState *state) override { } tilingPatternFill(GfxState * state,Gfx * gfx,Catalog * cat,GfxTilingPattern * tPat,const double * mat,int x0,int y0,int x1,int y1,double xStep,double yStep)422 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; } axialShadedFill(GfxState * state,GfxAxialShading * shading,double tMin,double tMax)423 bool axialShadedFill(GfxState *state, GfxAxialShading *shading, double tMin, double tMax) override { return true; } radialShadedFill(GfxState * state,GfxRadialShading * shading,double sMin,double sMax)424 bool radialShadedFill(GfxState *state, GfxRadialShading *shading, double sMin, double sMax) override { return true; } 425 426 //----- path clipping clip(GfxState * state)427 void clip(GfxState *state) override { } eoClip(GfxState * state)428 void eoClip(GfxState *state) override { } 429 430 //----- image drawing 431 void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool interpolate, bool inlineImg) override; 432 void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, const int *maskColors, bool inlineImg) override; 433 void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap, 434 bool maskInterpolate) override; 435 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; 436 void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, bool invert, bool inlineImg, double *baseMatrix) override; unsetSoftMaskFromImageMask(GfxState * state,double * baseMatrix)437 void unsetSoftMaskFromImageMask(GfxState *state, double *baseMatrix) override { } 438 439 //----- transparency groups and soft masks beginTransparencyGroup(GfxState *,const double *,GfxColorSpace *,bool,bool,bool)440 void beginTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/, GfxColorSpace * /*blendingColorSpace*/, bool /*isolated*/, bool /*knockout*/, bool /*forSoftMask*/) override { } endTransparencyGroup(GfxState *)441 void endTransparencyGroup(GfxState * /*state*/) override { } paintTransparencyGroup(GfxState *,const double *)442 void paintTransparencyGroup(GfxState * /*state*/, const double * /*bbox*/) override { } setSoftMask(GfxState *,const double *,bool,Function *,GfxColor *)443 void setSoftMask(GfxState * /*state*/, const double * /*bbox*/, bool /*alpha*/, Function * /*transferFunc*/, GfxColor * /*backdropColor*/) override { } clearSoftMask(GfxState *)444 void clearSoftMask(GfxState * /*state*/) override { } 445 446 //----- Image list 447 // By default images are not rendred setImageDrawDecideCbk(bool (* cbk)(int img_id,void * data),void * data)448 void setImageDrawDecideCbk(bool (*cbk)(int img_id, void *data), void *data) 449 { 450 imgDrawCbk = cbk; 451 imgDrawCbkData = data; 452 } 453 // Iterate through list of images. getNumImages()454 int getNumImages() const { return numImages; } getImage(int i)455 CairoImage *getImage(int i) const { return images[i]; } 456 457 private: 458 void saveImage(CairoImage *image); 459 void getBBox(GfxState *state, int width, int height, double *x1, double *y1, double *x2, double *y2); 460 461 CairoImage **images; 462 int numImages; 463 int size; 464 bool (*imgDrawCbk)(int img_id, void *data); 465 void *imgDrawCbkData; 466 }; 467 468 #endif 469