summaryrefslogtreecommitdiffstats
path: root/src/object/sp-pattern.h
blob: e7b36a0f60c54a2f39d464bc409b8e569fd5e420 (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
// SPDX-License-Identifier: GPL-2.0-or-later
/** @file
 * SVG <pattern> implementation
 *//*
 * Author:
 *   Lauris Kaplinski <lauris@kaplinski.com>
 *   Abhishek Sharma
 *
 * Copyright (C) 2002 Lauris Kaplinski
 *
 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
 */

#ifndef SEEN_SP_PATTERN_H
#define SEEN_SP_PATTERN_H

#include <memory>
#include <vector>
#include <cstddef>
#include <glibmm/ustring.h>
#include <sigc++/connection.h>

#include "svg/svg-length.h"
#include "sp-paint-server.h"
#include "uri-references.h"
#include "viewbox.h"
#include "display/drawing-item-ptr.h"

class SPPattern;
class SPItem;

namespace Inkscape {
namespace XML {
class Node;
} // namespace XML
} // namespace Inkscape

class SPPatternReference
    : public Inkscape::URIReference
{
public:
    SPPatternReference(SPPattern *owner);
    SPPattern *getObject() const;

protected:
    bool _acceptObject(SPObject *obj) const override;
};

class SPPattern final
    : public SPPaintServer
    , public SPViewBox
{
public:
    enum PatternUnits
    {
        UNITS_USERSPACEONUSE,
        UNITS_OBJECTBOUNDINGBOX
    };

    SPPattern();
    ~SPPattern() override;
    int tag() const override { return tag_of<decltype(*this)>; }

    // Reference (href)
    Glib::ustring href;
    SPPatternReference ref;

    double x() const;
    double y() const;
    double width() const;
    double height() const;
    Geom::OptRect viewbox() const;
    SPPattern::PatternUnits patternUnits() const;
    SPPattern::PatternUnits patternContentUnits() const;
    Geom::Affine const &getTransform() const;
    SPPattern const *rootPattern() const;
    SPPattern *rootPattern();
    const Geom::Affine& get_this_transform() const;

    SPPattern *clone_if_necessary(SPItem *item, char const *property);
    void transform_multiply(Geom::Affine postmul, bool set);

    /**
     * @brief create a new pattern in XML tree
     * @return created pattern id
     */
    static char const *produce(std::vector<Inkscape::XML::Node*> const &reprs, Geom::Rect const &bounds,
                               SPDocument *document, Geom::Affine const &transform, Geom::Affine const &move);

    bool isValid() const override;

protected:
    void build(SPDocument *doc, Inkscape::XML::Node *repr) override;
    void release() override;
    void set(SPAttr key, char const *value) override;
    void update(SPCtx *ctx, unsigned flags) override;
    void modified(unsigned flags) override;

    void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) override;
    void remove_child(Inkscape::XML::Node* child) override;
    void order_changed(Inkscape::XML::Node *child, Inkscape::XML::Node *old_ref, Inkscape::XML::Node *new_ref) override;

    Inkscape::DrawingPattern *show(Inkscape::Drawing &drawing, unsigned key, Geom::OptRect const &bbox) override;
    void hide(unsigned key) override;
    void setBBox(unsigned key, Geom::OptRect const &bbox) override;

private:
    bool _hasItemChildren() const;

    SPPattern *_chain() const;

    /**
     * Count how many times pattern is used by the styles of o and its descendants
     */
    unsigned _countHrefs(SPObject *o) const;

    /**
     * Gets called when the pattern is reattached to another <pattern>
     */
    void _onRefChanged(SPObject *old_ref, SPObject *ref);

    /**
     * Gets called when the referenced <pattern> is changed
     */
    void _onRefModified(SPObject *ref, unsigned flags);

    /* patternUnits and patternContentUnits attribute */
    PatternUnits _pattern_units : 1;
    bool _pattern_units_set : 1;
    PatternUnits _pattern_content_units : 1;
    bool _pattern_content_units_set : 1;
    /* patternTransform attribute */
    Geom::Affine _pattern_transform;
    bool _pattern_transform_set : 1;
    /* Tile rectangle */
    SVGLength _x;
    SVGLength _y;
    SVGLength _width;
    SVGLength _height;

    sigc::connection _modified_connection;

    /**
     * The pattern at the end of the href chain, currently tasked with keeping our DrawingPattern
     * up to date. When 'shown' is deleted, our DrawingPattern will be unattached from it and 'shown'
     * will be nulled. Later (asynchronously), 'shown' will be re-resolved to another Pattern and our
     * DrawingPattern will be re-attached to that.
     */
    SPPattern *shown;
    sigc::connection shown_released_connection;
    void set_shown(SPPattern *new_shown);

    /**
     * Drawing items belonging to other patterns with this pattern at the end of their href chain.
     * They will be updated in sync with this pattern's children.
     */
    struct AttachedView
    {
        Inkscape::DrawingPattern *drawingitem;
        unsigned key;
    };
    std::vector<AttachedView> attached_views;
    void attach_view(Inkscape::DrawingPattern *di, unsigned key);
    void unattach_view(Inkscape::DrawingPattern *di);

    struct View
    {
        DrawingItemPtr<Inkscape::DrawingPattern> drawingitem;
        Geom::OptRect bbox;
        unsigned key;
        View(DrawingItemPtr<Inkscape::DrawingPattern> drawingitem, Geom::OptRect const &bbox, unsigned key);
    };
    std::vector<View> views;
    void update_view(View &v);
};

#endif // SEEN_SP_PATTERN_H

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