1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /** @file
3 * TODO: insert short description here
4 *//*
5 * Authors: see git history
6 *
7 * Copyright (C) 2018 Authors
8 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
9 */
10 /*
11 */
12
13 #include <glibmm/i18n.h>
14
15 #include <xml/repr.h>
16 #include "display/curve.h"
17 #include "sp-shape.h"
18 #include "sp-text.h"
19 #include "sp-use.h"
20 #include "style.h"
21 #include "document.h"
22 #include "sp-title.h"
23 #include "sp-desc.h"
24
25 #include "sp-flowregion.h"
26
27 #include "livarot/Path.h"
28 #include "livarot/Shape.h"
29
30
31 static void GetDest(SPObject* child,Shape **computed);
32
33
SPFlowregion()34 SPFlowregion::SPFlowregion() : SPItem() {
35 }
36
~SPFlowregion()37 SPFlowregion::~SPFlowregion() {
38 for (auto & it : this->computed) {
39 delete it;
40 }
41 }
42
child_added(Inkscape::XML::Node * child,Inkscape::XML::Node * ref)43 void SPFlowregion::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) {
44 SPItem::child_added(child, ref);
45
46 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
47 }
48
49 /* fixme: hide (Lauris) */
50
remove_child(Inkscape::XML::Node * child)51 void SPFlowregion::remove_child(Inkscape::XML::Node * child) {
52 SPItem::remove_child(child);
53
54 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
55 }
56
57
update(SPCtx * ctx,unsigned int flags)58 void SPFlowregion::update(SPCtx *ctx, unsigned int flags) {
59 SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx);
60 SPItemCtx cctx = *ictx;
61
62 unsigned childflags = flags;
63 if (flags & SP_OBJECT_MODIFIED_FLAG) {
64 childflags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
65 }
66 childflags &= SP_OBJECT_MODIFIED_CASCADE;
67
68 std::vector<SPObject*>l;
69
70 for (auto& child: children) {
71 sp_object_ref(&child);
72 l.push_back(&child);
73 }
74
75 for (auto child:l) {
76 g_assert(child != nullptr);
77 SPItem *item = dynamic_cast<SPItem *>(child);
78
79 if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
80 if (item) {
81 SPItem const &chi = *item;
82 cctx.i2doc = chi.transform * ictx->i2doc;
83 cctx.i2vp = chi.transform * ictx->i2vp;
84 child->updateDisplay((SPCtx *)&cctx, childflags);
85 } else {
86 child->updateDisplay(ctx, childflags);
87 }
88 }
89
90 sp_object_unref(child);
91 }
92
93 SPItem::update(ctx, flags);
94
95 this->UpdateComputed();
96 }
97
UpdateComputed()98 void SPFlowregion::UpdateComputed()
99 {
100 for (auto & it : computed) {
101 delete it;
102 }
103 computed.clear();
104
105 for (auto& child: children) {
106 Shape *shape = nullptr;
107 GetDest(&child, &shape);
108 computed.push_back(shape);
109 }
110 }
111
modified(guint flags)112 void SPFlowregion::modified(guint flags) {
113 if (flags & SP_OBJECT_MODIFIED_FLAG) {
114 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
115 }
116
117 flags &= SP_OBJECT_MODIFIED_CASCADE;
118
119 std::vector<SPObject *>l;
120
121 for (auto& child: children) {
122 sp_object_ref(&child);
123 l.push_back(&child);
124 }
125
126 for (auto child:l) {
127 g_assert(child != nullptr);
128
129 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
130 child->emitModified(flags);
131 }
132
133 sp_object_unref(child);
134 }
135 }
136
write(Inkscape::XML::Document * xml_doc,Inkscape::XML::Node * repr,guint flags)137 Inkscape::XML::Node *SPFlowregion::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
138 if (flags & SP_OBJECT_WRITE_BUILD) {
139 if ( repr == nullptr ) {
140 repr = xml_doc->createElement("svg:flowRegion");
141 }
142
143 std::vector<Inkscape::XML::Node *> l;
144 for (auto& child: children) {
145 if ( !dynamic_cast<SPTitle *>(&child) && !dynamic_cast<SPDesc *>(&child) ) {
146 Inkscape::XML::Node *crepr = child.updateRepr(xml_doc, nullptr, flags);
147
148 if (crepr) {
149 l.push_back(crepr);
150 }
151 }
152 }
153
154 for (auto i = l.rbegin(); i != l.rend(); ++i) {
155 repr->addChild(*i, nullptr);
156 Inkscape::GC::release(*i);
157 }
158
159 for (auto& child: children) {
160 if ( !dynamic_cast<SPTitle *>(&child) && !dynamic_cast<SPDesc *>(&child) ) {
161 child.updateRepr(flags);
162 }
163 }
164 }
165
166 SPItem::write(xml_doc, repr, flags);
167
168 this->UpdateComputed(); // copied from update(), see LP Bug 1339305
169
170 return repr;
171 }
172
displayName() const173 const char* SPFlowregion::displayName() const {
174 // TRANSLATORS: "Flow region" is an area where text is allowed to flow
175 return _("Flow Region");
176 }
177
SPFlowregionExclude()178 SPFlowregionExclude::SPFlowregionExclude() : SPItem() {
179 this->computed = nullptr;
180 }
181
~SPFlowregionExclude()182 SPFlowregionExclude::~SPFlowregionExclude() {
183 if (this->computed) {
184 delete this->computed;
185 this->computed = nullptr;
186 }
187 }
188
child_added(Inkscape::XML::Node * child,Inkscape::XML::Node * ref)189 void SPFlowregionExclude::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) {
190 SPItem::child_added(child, ref);
191
192 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
193 }
194
195 /* fixme: hide (Lauris) */
196
remove_child(Inkscape::XML::Node * child)197 void SPFlowregionExclude::remove_child(Inkscape::XML::Node * child) {
198 SPItem::remove_child(child);
199
200 this->requestModified(SP_OBJECT_MODIFIED_FLAG);
201 }
202
203
update(SPCtx * ctx,unsigned int flags)204 void SPFlowregionExclude::update(SPCtx *ctx, unsigned int flags) {
205 SPItemCtx *ictx = reinterpret_cast<SPItemCtx *>(ctx);
206 SPItemCtx cctx = *ictx;
207
208 SPItem::update(ctx, flags);
209
210 if (flags & SP_OBJECT_MODIFIED_FLAG) {
211 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
212 }
213
214 flags &= SP_OBJECT_MODIFIED_CASCADE;
215
216 std::vector<SPObject *> l;
217
218 for (auto& child: children) {
219 sp_object_ref(&child);
220 l.push_back(&child);
221 }
222
223 for(auto child:l) {
224 g_assert(child != nullptr);
225
226 if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
227 SPItem *item = dynamic_cast<SPItem *>(child);
228 if (item) {
229 SPItem const &chi = *item;
230 cctx.i2doc = chi.transform * ictx->i2doc;
231 cctx.i2vp = chi.transform * ictx->i2vp;
232 child->updateDisplay((SPCtx *)&cctx, flags);
233 } else {
234 child->updateDisplay(ctx, flags);
235 }
236 }
237
238 sp_object_unref(child);
239 }
240
241 this->UpdateComputed();
242 }
243
244
UpdateComputed()245 void SPFlowregionExclude::UpdateComputed()
246 {
247 if (computed) {
248 delete computed;
249 computed = nullptr;
250 }
251
252 for (auto& child: children) {
253 GetDest(&child, &computed);
254 }
255 }
256
modified(guint flags)257 void SPFlowregionExclude::modified(guint flags) {
258 if (flags & SP_OBJECT_MODIFIED_FLAG) {
259 flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
260 }
261
262 flags &= SP_OBJECT_MODIFIED_CASCADE;
263
264 std::vector<SPObject*> l;
265
266 for (auto& child: children) {
267 sp_object_ref(&child);
268 l.push_back(&child);
269 }
270
271 for (auto child:l) {
272 g_assert(child != nullptr);
273
274 if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
275 child->emitModified(flags);
276 }
277
278 sp_object_unref(child);
279 }
280 }
281
write(Inkscape::XML::Document * xml_doc,Inkscape::XML::Node * repr,guint flags)282 Inkscape::XML::Node *SPFlowregionExclude::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
283 if (flags & SP_OBJECT_WRITE_BUILD) {
284 if ( repr == nullptr ) {
285 repr = xml_doc->createElement("svg:flowRegionExclude");
286 }
287
288 std::vector<Inkscape::XML::Node *> l;
289
290 for (auto& child: children) {
291 Inkscape::XML::Node *crepr = child.updateRepr(xml_doc, nullptr, flags);
292
293 if (crepr) {
294 l.push_back(crepr);
295 }
296 }
297
298 for (auto i = l.rbegin(); i != l.rend(); ++i) {
299 repr->addChild(*i, nullptr);
300 Inkscape::GC::release(*i);
301 }
302
303 } else {
304 for (auto& child: children) {
305 child.updateRepr(flags);
306 }
307 }
308
309 SPItem::write(xml_doc, repr, flags);
310
311 return repr;
312 }
313
displayName() const314 const char* SPFlowregionExclude::displayName() const {
315 /* TRANSLATORS: A region "cut out of" a flow region; text is not allowed to flow inside the
316 * flow excluded region. flowRegionExclude in SVG 1.2: see
317 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegion-elem and
318 * http://www.w3.org/TR/2004/WD-SVG12-20041027/flow.html#flowRegionExclude-elem. */
319 return _("Flow Excluded Region");
320 }
321
UnionShape(Shape * & base_shape,Shape const * add_shape)322 static void UnionShape(Shape *&base_shape, Shape const *add_shape)
323 {
324 if (base_shape == nullptr)
325 base_shape = new Shape;
326
327 if (base_shape->hasEdges() == false) {
328 base_shape->Copy(const_cast<Shape *>(add_shape));
329 } else if (add_shape->hasEdges()) {
330 Shape *temp = new Shape;
331 temp->Booleen(const_cast<Shape *>(add_shape), base_shape, bool_op_union);
332 delete base_shape;
333 base_shape = temp;
334 }
335 }
336
GetDest(SPObject * child,Shape ** computed)337 static void GetDest(SPObject* child,Shape **computed)
338 {
339 auto item = dynamic_cast<SPItem *>(child);
340 if (item == nullptr)
341 return;
342
343 std::unique_ptr<SPCurve> curve;
344 Geom::Affine tr_mat;
345
346 SPObject* u_child = child;
347 SPUse *use = dynamic_cast<SPUse *>(item);
348 if ( use ) {
349 u_child = use->child;
350 tr_mat = use->getRelativeTransform(child->parent);
351 } else {
352 tr_mat = item->transform;
353 }
354 SPShape *shape = dynamic_cast<SPShape *>(u_child);
355 if ( shape ) {
356 if (!shape->curve()) {
357 shape->set_shape();
358 }
359 curve = SPCurve::copy(shape->curve());
360 } else {
361 SPText *text = dynamic_cast<SPText *>(u_child);
362 if ( text ) {
363 curve = text->getNormalizedBpath();
364 }
365 }
366
367 if ( curve ) {
368 Path* temp=new Path;
369 temp->LoadPathVector(curve->get_pathvector(), tr_mat, true);
370 Shape* n_shp=new Shape;
371 temp->Convert(0.25);
372 temp->Fill(n_shp,0);
373 Shape* uncross=new Shape;
374 SPStyle* style = u_child->style;
375 if ( style && style->fill_rule.computed == SP_WIND_RULE_EVENODD ) {
376 uncross->ConvertToShape(n_shp,fill_oddEven);
377 } else {
378 uncross->ConvertToShape(n_shp,fill_nonZero);
379 }
380 UnionShape(*computed, uncross);
381 delete uncross;
382 delete n_shp;
383 delete temp;
384 }
385 }
386
387 /*
388 Local Variables:
389 mode:c++
390 c-file-style:"stroustrup"
391 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
392 indent-tabs-mode:nil
393 fill-column:99
394 End:
395 */
396 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
397