summaryrefslogtreecommitdiffstats
path: root/src/extension/internal/pdfinput/svg-builder.h
blob: e91febd71761f9da47f9ed7ece81841a76db40e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
// SPDX-License-Identifier: GPL-2.0-or-later
#ifndef SEEN_EXTENSION_INTERNAL_PDFINPUT_SVGBUILDER_H
#define SEEN_EXTENSION_INTERNAL_PDFINPUT_SVGBUILDER_H

/*
 * Authors:
 *   miklos erdelyi
 *
 * Copyright (C) 2007 Authors
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"  // only include where actually required!
#endif

#ifdef HAVE_POPPLER
#include "poppler-transition-api.h"

class SPDocument;
namespace Inkscape {
    namespace XML {
        struct Document;
        class Node;
    }
}

#include <2geom/point.h>
#include <2geom/affine.h>
#include <glibmm/ustring.h>

#include "CharTypes.h"
class Function;
class GfxState;
struct GfxColor;
class GfxColorSpace;
struct GfxRGB;
class GfxPath;
class GfxPattern;
class GfxTilingPattern;
class GfxShading;
class GfxFont;
class GfxImageColorMap;
class Stream;
class XRef;

class SPCSSAttr;

#include <vector>
#include <glib.h>

namespace Inkscape {
namespace Extension {
namespace Internal {

struct SvgTransparencyGroup;

/**
 * Holds information about the current softmask and group depth for use of libpoppler.
 * Could be later used to store other graphics state parameters so that we could
 * emit only the differences in style settings from the parent state.
 */
struct SvgGraphicsState {
    Inkscape::XML::Node *softmask; // Points to current softmask node
    int group_depth;    // Depth of nesting groups at this level
};

/**
 * Holds information about glyphs added by PdfParser which haven't been added
 * to the document yet.
 */
struct SvgGlyph {
    Geom::Point position;    // Absolute glyph coords
    Geom::Point text_position; // Absolute glyph coords in text space
    double dx;  // X advance value
    double dy;  // Y advance value
    double rise;    // Text rise parameter
    Glib::ustring code;   // UTF-8 coded character
    bool is_space;

    bool style_changed;  // Set to true if style has to be reset
    SPCSSAttr *style;
    int render_mode;    // Text render mode
    const char *font_specification;   // Pointer to current font specification
};

/**
 * Builds the inner SVG representation using libpoppler from the calls of PdfParser.
 */
class SvgBuilder {
public:
    SvgBuilder(SPDocument *document, gchar *docname, XRef *xref);
    SvgBuilder(SvgBuilder *parent, Inkscape::XML::Node *root);
    virtual ~SvgBuilder();

    // Property setting
    void setDocumentSize(double width, double height);  // Document size in px
    void setAsLayer(char *layer_name=nullptr);
    void setGroupOpacity(double opacity);
    Inkscape::XML::Node *getPreferences() {
        return _preferences;
    }
    void pushPage();

    // Handling the node stack
    Inkscape::XML::Node *pushGroup();
    Inkscape::XML::Node *popGroup();
    Inkscape::XML::Node *getContainer();    // Returns current group node

    // Path adding
    void addPath(GfxState *state, bool fill, bool stroke, bool even_odd=false);
    void addShadedFill(GfxShading *shading, double *matrix, GfxPath *path, bool even_odd=false);

    // Image handling
    void addImage(GfxState *state, Stream *str, int width, int height,
                  GfxImageColorMap *color_map, bool interpolate, int *mask_colors);
    void addImageMask(GfxState *state, Stream *str, int width, int height,
                      bool invert, bool interpolate);
    void addMaskedImage(GfxState *state, Stream *str, int width, int height,
                        GfxImageColorMap *color_map, bool interpolate,
                        Stream *mask_str, int mask_width, int mask_height,
                        bool invert_mask, bool mask_interpolate);
    void addSoftMaskedImage(GfxState *state, Stream *str, int width, int height,
                            GfxImageColorMap *color_map, bool interpolate,
                            Stream *mask_str, int mask_width, int mask_height,
                            GfxImageColorMap *mask_color_map, bool mask_interpolate);

    // Transparency group and soft mask handling
    void pushTransparencyGroup(GfxState *state, double *bbox,
                               GfxColorSpace *blending_color_space,
                               bool isolated, bool knockout,
                               bool for_softmask);
    void popTransparencyGroup(GfxState *state);
    void paintTransparencyGroup(GfxState *state, double *bbox);
    void setSoftMask(GfxState *state, double *bbox, bool alpha,
                     Function *transfer_func, GfxColor *backdrop_color);
    void clearSoftMask(GfxState *state);

    // Text handling
    void beginString(GfxState *state);
    void endString(GfxState *state);
    void addChar(GfxState *state, double x, double y,
                 double dx, double dy,
                 double originX, double originY,
                 CharCode code, int nBytes, Unicode const *u, int uLen);
    void beginTextObject(GfxState *state);
    void endTextObject(GfxState *state);

    bool isPatternTypeSupported(GfxPattern *pattern);

    // State manipulation
    void saveState();
    void restoreState();
    void updateStyle(GfxState *state);
    void updateFont(GfxState *state);
    void updateTextPosition(double tx, double ty);
    void updateTextShift(GfxState *state, double shift);
    void updateTextMatrix(GfxState *state);

    // Clipping
    void clip(GfxState *state, bool even_odd=false);
    void setClipPath(GfxState *state, bool even_odd=false);

    // Transforming
    void setTransform(double c0, double c1, double c2, double c3, double c4,
                      double c5);
    void setTransform(double const *transform);
    bool getTransform(double *transform);

private:
    void _init();

    // Pattern creation
    gchar *_createPattern(GfxPattern *pattern, GfxState *state, bool is_stroke=false);
    gchar *_createGradient(GfxShading *shading, double *matrix, bool for_shading=false);
    void _addStopToGradient(Inkscape::XML::Node *gradient, double offset,
                            GfxRGB *color, double opacity);
    bool _addGradientStops(Inkscape::XML::Node *gradient, GfxShading *shading,
                           _POPPLER_CONST Function *func);
    gchar *_createTilingPattern(GfxTilingPattern *tiling_pattern, GfxState *state,
                                bool is_stroke=false);
    // Image/mask creation
    Inkscape::XML::Node *_createImage(Stream *str, int width, int height,
                                      GfxImageColorMap *color_map, bool interpolate,
                                      int *mask_colors, bool alpha_only=false,
                                      bool invert_alpha=false);
    Inkscape::XML::Node *_createMask(double width, double height);
    // Style setting
    SPCSSAttr *_setStyle(GfxState *state, bool fill, bool stroke, bool even_odd=false);
    void _setStrokeStyle(SPCSSAttr *css, GfxState *state);
    void _setFillStyle(SPCSSAttr *css, GfxState *state, bool even_odd);
    void _setBlendMode(Inkscape::XML::Node *node, GfxState *state);
    void _flushText();    // Write buffered text into doc

    std::string _BestMatchingFont(std::string PDFname);

    // Handling of node stack
    Inkscape::XML::Node *pushNode(const char* name);
    Inkscape::XML::Node *popNode();
    std::vector<Inkscape::XML::Node *> _node_stack;
    std::vector<int> _group_depth;    // Depth of nesting groups
    SvgTransparencyGroup *_transp_group_stack;  // Transparency group stack
    std::vector<SvgGraphicsState> _state_stack;

    SPCSSAttr *_font_style;          // Current font style
    const char *_font_specification;
    double _font_scaling;
    bool _need_font_update;
    Geom::Affine _text_matrix;
    Geom::Point _text_position;
    std::vector<SvgGlyph> _glyphs;   // Added characters
    bool _in_text_object;   // Whether we are inside a text object
    bool _invalidated_style;
    GfxState *_current_state;
    std::vector<std::string> _availableFontNames; // Full names, used for matching font names (Bug LP #179589).

    bool _is_top_level;  // Whether this SvgBuilder is the top-level one
    SPDocument *_doc;
    gchar *_docname;    // Basename of the URI from which this document is created
    XRef *_xref;    // Cross-reference table from the PDF doc we're converting from
    Inkscape::XML::Document *_xml_doc;
    Inkscape::XML::Node *_root;  // Root node from the point of view of this SvgBuilder
    Inkscape::XML::Node *_container; // Current container (group/pattern/mask)
    Inkscape::XML::Node *_preferences;  // Preferences container node
    double _width;       // Document size in px
    double _height;       // Document size in px
    double _ttm[6]; ///< temporary transform matrix
    bool _ttm_is_set;
    
    Inkscape::XML::Node *_nv = nullptr; // XML NameView xml
    Inkscape::XML::Node *_page = nullptr; // XML Page definition
    int _page_num = 0; // Are we on a page
    double _page_left = 0 ; // Move to the left for more pages
    double _page_top = 0 ; // Move to the top (maybe)
    bool _page_offset = false;
};


} // namespace Internal
} // namespace Extension
} // namespace Inkscape

#endif // HAVE_POPPLER

#endif // SEEN_EXTENSION_INTERNAL_PDFINPUT_SVGBUILDER_H

/*
  Local Variables:
  mode:c++
  c-file-style:"stroustrup"
  c-file-offsets:((innamespace . 0)(inline-open . 0))
  indent-tabs-mode:nil
  fill-column:99
  End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :