1 // SPDX-License-Identifier: GPL-2.0-or-later 2 #ifndef EXTENSION_INTERNAL_CAIRO_RENDER_CONTEXT_H_SEEN 3 #define EXTENSION_INTERNAL_CAIRO_RENDER_CONTEXT_H_SEEN 4 5 /** \file 6 * Declaration of CairoRenderContext, a class used for rendering with Cairo. 7 */ 8 /* 9 * Authors: 10 * Miklos Erdelyi <erdelyim@gmail.com> 11 * 12 * Copyright (C) 2006 Miklos Erdelyi 13 * 14 * Released under GNU GPL v2+, read the file 'COPYING' for more information. 15 */ 16 17 #include "extension/extension.h" 18 #include <set> 19 #include <string> 20 21 #include <2geom/forward.h> 22 #include <2geom/affine.h> 23 24 #include "style-internal.h" // SPIEnum 25 26 #include <cairo.h> 27 28 class SPClipPath; 29 class SPMask; 30 31 typedef struct _PangoFont PangoFont; 32 typedef struct _PangoLayout PangoLayout; 33 34 namespace Inkscape { 35 class Pixbuf; 36 37 namespace Extension { 38 namespace Internal { 39 40 class CairoRenderer; 41 class CairoRenderContext; 42 struct CairoRenderState; 43 struct CairoGlyphInfo; 44 45 // Holds info for rendering a glyph 46 struct CairoGlyphInfo { 47 unsigned long index; 48 double x; 49 double y; 50 }; 51 52 struct CairoRenderState { 53 unsigned int merge_opacity : 1; // whether fill/stroke opacity can be mul'd with item opacity 54 unsigned int need_layer : 1; // whether object is masked, clipped, and/or has a non-zero opacity 55 unsigned int has_overflow : 1; 56 unsigned int parent_has_userspace : 1; // whether the parent's ctm should be applied 57 float opacity; 58 bool has_filtereffect; 59 Geom::Affine item_transform; // this item's item->transform, for correct clipping 60 61 SPClipPath *clip_path; 62 SPMask* mask; 63 64 Geom::Affine transform; // the CTM 65 }; 66 67 // Metadata to set on the cairo surface (if the surface supports it) 68 struct CairoRenderContextMetadata { 69 Glib::ustring title = ""; 70 Glib::ustring author = ""; 71 Glib::ustring subject = ""; 72 Glib::ustring keywords = ""; 73 Glib::ustring copyright = ""; 74 Glib::ustring creator = ""; 75 Glib::ustring cdate = ""; // currently unused 76 Glib::ustring mdate = ""; // currently unused 77 }; 78 79 class CairoRenderContext { 80 friend class CairoRenderer; 81 public: 82 CairoRenderContext *cloneMe() const; 83 CairoRenderContext *cloneMe(double width, double height) const; 84 bool finish(bool finish_surface = true); 85 86 CairoRenderer *getRenderer() const; 87 cairo_t *getCairoContext() const; 88 89 enum CairoRenderMode { 90 RENDER_MODE_NORMAL, 91 RENDER_MODE_CLIP 92 }; 93 94 enum CairoClipMode { 95 CLIP_MODE_PATH, 96 CLIP_MODE_MASK 97 }; 98 99 bool setImageTarget(cairo_format_t format); 100 bool setPdfTarget(gchar const *utf8_fn); 101 bool setPsTarget(gchar const *utf8_fn); 102 /** Set the cairo_surface_t from an external source */ 103 bool setSurfaceTarget(cairo_surface_t *surface, bool is_vector, cairo_matrix_t *ctm=nullptr); 104 105 void setPSLevel(unsigned int level); 106 void setEPS(bool eps); 107 unsigned int getPSLevel(); 108 void setPDFLevel(unsigned int level); 109 void setTextToPath(bool texttopath); 110 bool getTextToPath(); 111 void setOmitText(bool omittext); 112 bool getOmitText(); 113 void setFilterToBitmap(bool filtertobitmap); 114 bool getFilterToBitmap(); 115 void setBitmapResolution(int resolution); 116 int getBitmapResolution(); 117 118 /** Creates the cairo_surface_t for the context with the 119 given width, height and with the currently set target 120 surface type. Also sets supported metadata on the surface. */ 121 bool setupSurface(double width, double height); 122 123 cairo_surface_t *getSurface(); 124 125 /** Saves the contents of the context to a PNG file. */ 126 bool saveAsPng(const char *file_name); 127 128 /** On targets supporting multiple pages, sends subsequent rendering to a new page*/ 129 void newPage(); 130 131 /* Render/clip mode setting/query */ 132 void setRenderMode(CairoRenderMode mode); 133 CairoRenderMode getRenderMode() const; 134 void setClipMode(CairoClipMode mode); 135 CairoClipMode getClipMode() const; 136 137 void addPathVector(Geom::PathVector const &pv); 138 void setPathVector(Geom::PathVector const &pv); 139 140 void pushLayer(); 141 void popLayer(cairo_operator_t composite = CAIRO_OPERATOR_CLEAR); 142 143 void tagBegin(const char* link); 144 void tagEnd(); 145 146 /* Graphics state manipulation */ 147 void pushState(); 148 void popState(); 149 CairoRenderState *getCurrentState() const; 150 CairoRenderState *getParentState() const; 151 void setStateForStyle(SPStyle const *style); 152 153 void transform(Geom::Affine const &transform); 154 void setTransform(Geom::Affine const &transform); 155 Geom::Affine getTransform() const; 156 Geom::Affine getParentTransform() const; 157 158 /* Clipping methods */ 159 void addClipPath(Geom::PathVector const &pv, SPIEnum<SPWindRule> const *fill_rule); 160 void addClippingRect(double x, double y, double width, double height); 161 162 /* Rendering methods */ 163 enum CairoPaintOrder { 164 STROKE_OVER_FILL, 165 FILL_OVER_STROKE, 166 FILL_ONLY, 167 STROKE_ONLY 168 }; 169 170 bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox, CairoPaintOrder order = STROKE_OVER_FILL); 171 bool renderImage(Inkscape::Pixbuf *pb, 172 Geom::Affine const &image_transform, SPStyle const *style); 173 bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix, 174 std::vector<CairoGlyphInfo> const &glyphtext, SPStyle const *style); 175 176 /* More general rendering methods will have to be added (like fill, stroke) */ 177 178 protected: 179 CairoRenderContext(CairoRenderer *renderer); 180 virtual ~CairoRenderContext(); 181 182 enum CairoOmitTextPageState { 183 EMPTY, 184 GRAPHIC_ON_TOP, 185 NEW_PAGE_ON_GRAPHIC 186 }; 187 188 float _width; 189 float _height; 190 unsigned short _dpi; 191 unsigned int _pdf_level; 192 unsigned int _ps_level; 193 bool _eps; 194 bool _is_texttopath; 195 bool _is_omittext; 196 bool _is_filtertobitmap; 197 int _bitmapresolution; 198 199 FILE *_stream; 200 201 unsigned int _is_valid : 1; 202 unsigned int _vector_based_target : 1; 203 204 cairo_t *_cr; // Cairo context 205 cairo_surface_t *_surface; 206 cairo_surface_type_t _target; 207 cairo_format_t _target_format; 208 PangoLayout *_layout; 209 210 unsigned int _clip_rule : 8; 211 unsigned int _clip_winding_failed : 1; 212 213 std::vector<CairoRenderState *> _state_stack; 214 CairoRenderState *_state; // the current state 215 216 CairoRenderer *_renderer; 217 218 CairoRenderMode _render_mode; 219 CairoClipMode _clip_mode; 220 221 CairoOmitTextPageState _omittext_state; 222 223 CairoRenderContextMetadata _metadata; 224 225 cairo_pattern_t *_createPatternForPaintServer(SPPaintServer const *const paintserver, 226 Geom::OptRect const &pbox, float alpha); 227 cairo_pattern_t *_createPatternPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox); 228 cairo_pattern_t *_createHatchPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox); 229 230 unsigned int _showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoGlyphInfo> const &glyphtext, bool is_stroke); 231 232 bool _finishSurfaceSetup(cairo_surface_t *surface, cairo_matrix_t *ctm = nullptr); 233 void _setSurfaceMetadata(cairo_surface_t *surface); 234 235 void _setFillStyle(SPStyle const *style, Geom::OptRect const &pbox); 236 void _setStrokeStyle(SPStyle const *style, Geom::OptRect const &pbox); 237 238 void _initCairoMatrix(cairo_matrix_t *matrix, Geom::Affine const &transform); 239 void _concatTransform(cairo_t *cr, double xx, double yx, double xy, double yy, double x0, double y0); 240 void _concatTransform(cairo_t *cr, Geom::Affine const &transform); 241 242 void _prepareRenderGraphic(); 243 void _prepareRenderText(); 244 245 std::map<gpointer, cairo_font_face_t *> font_table; 246 static void font_data_free(gpointer data); 247 248 CairoRenderState *_createState(); 249 }; 250 251 } /* namespace Internal */ 252 } /* namespace Extension */ 253 } /* namespace Inkscape */ 254 255 #endif /* !EXTENSION_INTERNAL_CAIRO_RENDER_CONTEXT_H_SEEN */ 256 257 /* 258 Local Variables: 259 mode:c++ 260 c-file-style:"stroustrup" 261 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) 262 indent-tabs-mode:nil 263 fill-column:99 264 End: 265 */ 266 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : 267