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