1
//! The `pattern` element.
2

            
3
use markup5ever::{expanded_name, local_name, ns};
4

            
5
use crate::coord_units;
6
use crate::coord_units::CoordUnits;
7

            
8
use crate::aspect_ratio::*;
9
use crate::document::{AcquiredNode, AcquiredNodes, NodeId, NodeStack};
10
use crate::drawing_ctx::Viewport;
11
use crate::element::{set_attribute, ElementData, ElementTrait};
12
use crate::error::*;
13
use crate::href::{is_href, set_href};
14
use crate::length::*;
15
use crate::node::{Node, NodeBorrow, WeakNode};
16
use crate::parsers::ParseValue;
17
use crate::rect::Rect;
18
use crate::rsvg_log;
19
use crate::session::Session;
20
use crate::transform::{Transform, TransformAttribute};
21
use crate::unit_interval::UnitInterval;
22
use crate::viewbox::*;
23
use crate::xml::Attributes;
24

            
25
coord_units!(PatternUnits, CoordUnits::ObjectBoundingBox);
26
coord_units!(PatternContentUnits, CoordUnits::UserSpaceOnUse);
27

            
28
#[derive(Clone, Default)]
29
struct Common {
30
    units: Option<PatternUnits>,
31
    content_units: Option<PatternContentUnits>,
32
    // This Option<Option<ViewBox>> is a bit strange.  We want a field
33
    // with value None to mean, "this field isn't resolved yet".  However,
34
    // the vbox can very well be *not* specified in the SVG file.
35
    // In that case, the fully resolved pattern will have a .vbox=Some(None) value.
36
    vbox: Option<Option<ViewBox>>,
37
    preserve_aspect_ratio: Option<AspectRatio>,
38
    transform: Option<TransformAttribute>,
39
    x: Option<Length<Horizontal>>,
40
    y: Option<Length<Vertical>>,
41
    width: Option<ULength<Horizontal>>,
42
    height: Option<ULength<Vertical>>,
43
}
44

            
45
/// State used during the pattern resolution process
46
///
47
/// This is the current node's pattern information, plus the fallback
48
/// that should be used in case that information is not complete for a
49
/// resolved pattern yet.
50
struct Unresolved {
51
    pattern: UnresolvedPattern,
52
    fallback: Option<NodeId>,
53
}
54

            
55
/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
56
#[derive(Clone)]
57
enum UnresolvedChildren {
58
    /// Points back to the original Pattern if it had no usable children
59
    Unresolved,
60

            
61
    /// Points back to the original Pattern, as no pattern in the
62
    /// chain of fallbacks had usable children.  This only gets returned
63
    /// by resolve_from_defaults().
64
    ResolvedEmpty,
65

            
66
    /// Points back to the Pattern that had usable children.
67
    WithChildren(WeakNode),
68
}
69

            
70
/// Keeps track of which Pattern provided a non-empty set of children during pattern resolution
71
#[derive(Clone)]
72
enum Children {
73
    Empty,
74

            
75
    /// Points back to the Pattern that had usable children
76
    WithChildren(WeakNode),
77
}
78

            
79
/// Main structure used during pattern resolution.  For unresolved
80
/// patterns, we store all fields as `Option<T>` - if `None`, it means
81
/// that the field is not specified; if `Some(T)`, it means that the
82
/// field was specified.
83
struct UnresolvedPattern {
84
    common: Common,
85

            
86
    // Point back to our corresponding node, or to the fallback node which has children.
87
    // If the value is None, it means we are fully resolved and didn't find any children
88
    // among the fallbacks.
89
    children: UnresolvedChildren,
90
}
91

            
92
#[derive(Clone)]
93
pub struct ResolvedPattern {
94
    units: PatternUnits,
95
    content_units: PatternContentUnits,
96
    vbox: Option<ViewBox>,
97
    preserve_aspect_ratio: AspectRatio,
98
    transform: TransformAttribute,
99
    x: Length<Horizontal>,
100
    y: Length<Vertical>,
101
    width: ULength<Horizontal>,
102
    height: ULength<Vertical>,
103
    opacity: UnitInterval,
104

            
105
    // Link to the node whose children are the pattern's resolved children.
106
    children: Children,
107
}
108

            
109
/// Pattern normalized to user-space units.
110
pub struct UserSpacePattern {
111
    pub width: f64,
112
    pub height: f64,
113
    pub transform: Transform,
114
    pub coord_transform: Transform,
115
    pub content_transform: Transform,
116
    pub opacity: UnitInterval,
117

            
118
    // This one is private so the caller has to go through fn acquire_pattern_node()
119
    node_with_children: Node,
120
}
121

            
122
#[derive(Default)]
123
pub struct Pattern {
124
    common: Common,
125
    fallback: Option<NodeId>,
126
}
127

            
128
impl ElementTrait for Pattern {
129
1027
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
130
5112
        for (attr, value) in attrs.iter() {
131
5111
            match attr.expanded() {
132
                expanded_name!("", "patternUnits") => {
133
684
                    set_attribute(&mut self.common.units, attr.parse(value), session)
134
                }
135
114
                expanded_name!("", "patternContentUnits") => {
136
114
                    set_attribute(&mut self.common.content_units, attr.parse(value), session);
137
114
                }
138
                expanded_name!("", "viewBox") => {
139
190
                    set_attribute(&mut self.common.vbox, attr.parse(value), session)
140
                }
141
                expanded_name!("", "preserveAspectRatio") => {
142
                    set_attribute(
143
                        &mut self.common.preserve_aspect_ratio,
144
                        attr.parse(value),
145
                        session,
146
                    );
147
                }
148
228
                expanded_name!("", "patternTransform") => {
149
228
                    set_attribute(&mut self.common.transform, attr.parse(value), session);
150
228
                }
151
3895
                ref a if is_href(a) => {
152
228
                    let mut href = None;
153
228
                    set_attribute(
154
228
                        &mut href,
155
228
                        NodeId::parse(value).map(Some).attribute(attr.clone()),
156
228
                        session,
157
228
                    );
158
228
                    set_href(a, &mut self.fallback, href);
159
228
                }
160
                expanded_name!("", "x") => {
161
532
                    set_attribute(&mut self.common.x, attr.parse(value), session)
162
                }
163
                expanded_name!("", "y") => {
164
551
                    set_attribute(&mut self.common.y, attr.parse(value), session)
165
                }
166
                expanded_name!("", "width") => {
167
779
                    set_attribute(&mut self.common.width, attr.parse(value), session)
168
                }
169
                expanded_name!("", "height") => {
170
798
                    set_attribute(&mut self.common.height, attr.parse(value), session)
171
                }
172
1007
                _ => (),
173
            }
174
        }
175
1027
    }
176
}
177

            
178
impl UnresolvedPattern {
179
9500703
    fn into_resolved(self, opacity: UnitInterval) -> ResolvedPattern {
180
9500703
        assert!(self.is_resolved());
181

            
182
9500703
        ResolvedPattern {
183
9500703
            units: self.common.units.unwrap(),
184
9500703
            content_units: self.common.content_units.unwrap(),
185
9500703
            vbox: self.common.vbox.unwrap(),
186
9500703
            preserve_aspect_ratio: self.common.preserve_aspect_ratio.unwrap(),
187
9500703
            transform: self.common.transform.unwrap(),
188
9500703
            x: self.common.x.unwrap(),
189
9500703
            y: self.common.y.unwrap(),
190
9500703
            width: self.common.width.unwrap(),
191
9500703
            height: self.common.height.unwrap(),
192
9500703
            opacity,
193
9500703

            
194
9500703
            children: self.children.to_resolved(),
195
9500703
        }
196
9500703
    }
197

            
198
19001540
    fn is_resolved(&self) -> bool {
199
19001540
        self.common.units.is_some()
200
19001217
            && self.common.content_units.is_some()
201
9500818
            && self.common.vbox.is_some()
202
9500704
            && self.common.preserve_aspect_ratio.is_some()
203
9500704
            && self.common.transform.is_some()
204
9500704
            && self.common.x.is_some()
205
9500704
            && self.common.y.is_some()
206
9500704
            && self.common.width.is_some()
207
9500704
            && self.common.height.is_some()
208
9500704
            && self.children.is_resolved()
209
19001540
    }
210

            
211
114
    fn resolve_from_fallback(&self, fallback: &UnresolvedPattern) -> UnresolvedPattern {
212
114
        let units = self.common.units.or(fallback.common.units);
213
114
        let content_units = self.common.content_units.or(fallback.common.content_units);
214
114
        let vbox = self.common.vbox.or(fallback.common.vbox);
215
114
        let preserve_aspect_ratio = self
216
114
            .common
217
114
            .preserve_aspect_ratio
218
114
            .or(fallback.common.preserve_aspect_ratio);
219
114
        let transform = self.common.transform.or(fallback.common.transform);
220
114
        let x = self.common.x.or(fallback.common.x);
221
114
        let y = self.common.y.or(fallback.common.y);
222
114
        let width = self.common.width.or(fallback.common.width);
223
114
        let height = self.common.height.or(fallback.common.height);
224
114
        let children = self.children.resolve_from_fallback(&fallback.children);
225
114

            
226
114
        UnresolvedPattern {
227
114
            common: Common {
228
114
                units,
229
114
                content_units,
230
114
                vbox,
231
114
                preserve_aspect_ratio,
232
114
                transform,
233
114
                x,
234
114
                y,
235
114
                width,
236
114
                height,
237
114
            },
238
114
            children,
239
114
        }
240
114
    }
241

            
242
9500704
    fn resolve_from_defaults(&self) -> UnresolvedPattern {
243
9500704
        let units = self.common.units.or_else(|| Some(PatternUnits::default()));
244
9500704
        let content_units = self
245
9500704
            .common
246
9500704
            .content_units
247
9500704
            .or_else(|| Some(PatternContentUnits::default()));
248
9500704
        let vbox = self.common.vbox.or(Some(None));
249
9500704
        let preserve_aspect_ratio = self
250
9500704
            .common
251
9500704
            .preserve_aspect_ratio
252
9500704
            .or_else(|| Some(AspectRatio::default()));
253
9500704
        let transform = self
254
9500704
            .common
255
9500704
            .transform
256
9500704
            .or_else(|| Some(TransformAttribute::default()));
257
9500704
        let x = self.common.x.or_else(|| Some(Default::default()));
258
9500704
        let y = self.common.y.or_else(|| Some(Default::default()));
259
9500704
        let width = self.common.width.or_else(|| Some(Default::default()));
260
9500704
        let height = self.common.height.or_else(|| Some(Default::default()));
261
9500704
        let children = self.children.resolve_from_defaults();
262
9500704

            
263
9500704
        UnresolvedPattern {
264
9500704
            common: Common {
265
9500704
                units,
266
9500704
                content_units,
267
9500704
                vbox,
268
9500704
                preserve_aspect_ratio,
269
9500704
                transform,
270
9500704
                x,
271
9500704
                y,
272
9500704
                width,
273
9500704
                height,
274
9500704
            },
275
9500704
            children,
276
9500704
        }
277
9500704
    }
278
}
279

            
280
impl UnresolvedChildren {
281
9500837
    fn from_node(node: &Node) -> UnresolvedChildren {
282
9500837
        let weak = node.downgrade();
283
9500837

            
284
19001426
        if node.children().any(|child| child.is_element()) {
285
9500703
            UnresolvedChildren::WithChildren(weak)
286
        } else {
287
134
            UnresolvedChildren::Unresolved
288
        }
289
9500837
    }
290

            
291
19001407
    fn is_resolved(&self) -> bool {
292
19001407
        !matches!(*self, UnresolvedChildren::Unresolved)
293
19001407
    }
294

            
295
114
    fn resolve_from_fallback(&self, fallback: &UnresolvedChildren) -> UnresolvedChildren {
296
        use UnresolvedChildren::*;
297

            
298
114
        match (self, fallback) {
299
            (&Unresolved, &Unresolved) => Unresolved,
300
76
            (WithChildren(wc), _) => WithChildren(wc.clone()),
301
38
            (_, WithChildren(wc)) => WithChildren(wc.clone()),
302
            (_, _) => unreachable!(),
303
        }
304
114
    }
305

            
306
9500704
    fn resolve_from_defaults(&self) -> UnresolvedChildren {
307
        use UnresolvedChildren::*;
308

            
309
9500704
        match *self {
310
39
            Unresolved => ResolvedEmpty,
311
9500665
            _ => (*self).clone(),
312
        }
313
9500704
    }
314

            
315
9500703
    fn to_resolved(&self) -> Children {
316
        use UnresolvedChildren::*;
317

            
318
9500703
        assert!(self.is_resolved());
319

            
320
9500703
        match *self {
321
38
            ResolvedEmpty => Children::Empty,
322
9500665
            WithChildren(ref wc) => Children::WithChildren(wc.clone()),
323
            _ => unreachable!(),
324
        }
325
9500703
    }
326
}
327

            
328
342
fn nonempty_rect(bbox: &Option<Rect>) -> Option<Rect> {
329
323
    match *bbox {
330
19
        None => None,
331
323
        Some(r) if r.is_empty() => None,
332
323
        Some(r) => Some(r),
333
    }
334
342
}
335

            
336
impl ResolvedPattern {
337
9500703
    fn node_with_children(&self) -> Option<Node> {
338
9500703
        match self.children {
339
            // This means we didn't find any children among the fallbacks,
340
            // so there is nothing to render.
341
38
            Children::Empty => None,
342

            
343
9500665
            Children::WithChildren(ref wc) => Some(wc.upgrade().unwrap()),
344
        }
345
9500703
    }
346

            
347
9500665
    fn get_rect(&self, params: &NormalizeParams) -> Rect {
348
9500665
        let x = self.x.to_user(params);
349
9500665
        let y = self.y.to_user(params);
350
9500665
        let w = self.width.to_user(params);
351
9500665
        let h = self.height.to_user(params);
352
9500665

            
353
9500665
        Rect::new(x, y, x + w, y + h)
354
9500665
    }
355

            
356
9500703
    pub fn to_user_space(
357
9500703
        &self,
358
9500703
        object_bbox: &Option<Rect>,
359
9500703
        viewport: &Viewport,
360
9500703
        values: &NormalizeValues,
361
9500703
    ) -> Option<UserSpacePattern> {
362
9500703
        let node_with_children = self.node_with_children()?;
363

            
364
9500665
        let viewport = viewport.with_units(self.units.0);
365
9500665
        let params = NormalizeParams::from_values(values, &viewport);
366
9500665

            
367
9500665
        let rect = self.get_rect(&params);
368

            
369
        // Create the pattern coordinate system
370
9500665
        let (width, height, coord_transform) = match self.units {
371
            PatternUnits(CoordUnits::ObjectBoundingBox) => {
372
247
                let bbrect = nonempty_rect(object_bbox)?;
373
228
                (
374
228
                    rect.width() * bbrect.width(),
375
228
                    rect.height() * bbrect.height(),
376
228
                    Transform::new_translate(
377
228
                        bbrect.x0 + rect.x0 * bbrect.width(),
378
228
                        bbrect.y0 + rect.y0 * bbrect.height(),
379
228
                    ),
380
228
                )
381
            }
382
9500418
            PatternUnits(CoordUnits::UserSpaceOnUse) => (
383
9500418
                rect.width(),
384
9500418
                rect.height(),
385
9500418
                Transform::new_translate(rect.x0, rect.y0),
386
9500418
            ),
387
        };
388

            
389
9500646
        let pattern_transform = self.transform.to_transform();
390
9500646

            
391
9500646
        let coord_transform = coord_transform.post_transform(&pattern_transform);
392

            
393
        // Create the pattern contents coordinate system
394
9500646
        let content_transform = if let Some(vbox) = self.vbox {
395
            // If there is a vbox, use that
396
171
            let r = self
397
171
                .preserve_aspect_ratio
398
171
                .compute(&vbox, &Rect::from_size(width, height));
399
171

            
400
171
            let sw = r.width() / vbox.width();
401
171
            let sh = r.height() / vbox.height();
402
171
            let x = r.x0 - vbox.x0 * sw;
403
171
            let y = r.y0 - vbox.y0 * sh;
404
171

            
405
171
            Transform::new_scale(sw, sh).pre_translate(x, y)
406
        } else {
407
9500475
            match self.content_units {
408
                PatternContentUnits(CoordUnits::ObjectBoundingBox) => {
409
95
                    let bbrect = nonempty_rect(object_bbox)?;
410
95
                    Transform::new_scale(bbrect.width(), bbrect.height())
411
                }
412
9500380
                PatternContentUnits(CoordUnits::UserSpaceOnUse) => Transform::identity(),
413
            }
414
        };
415

            
416
9500646
        Some(UserSpacePattern {
417
9500646
            width,
418
9500646
            height,
419
9500646
            transform: pattern_transform,
420
9500646
            coord_transform,
421
9500646
            content_transform,
422
9500646
            opacity: self.opacity,
423
9500646
            node_with_children,
424
9500646
        })
425
9500703
    }
426
}
427

            
428
impl UserSpacePattern {
429
    /// Gets the `<pattern>` node that contains the children to be drawn for the pattern's contents.
430
    ///
431
    /// This has to go through [AcquiredNodes] to catch circular references among
432
    /// patterns and their children.
433
9500456
    pub fn acquire_pattern_node(
434
9500456
        &self,
435
9500456
        acquired_nodes: &mut AcquiredNodes<'_>,
436
9500456
    ) -> Result<AcquiredNode, AcquireError> {
437
9500456
        acquired_nodes.acquire_ref(&self.node_with_children)
438
9500456
    }
439
}
440

            
441
impl Pattern {
442
9500837
    fn get_unresolved(&self, node: &Node) -> Unresolved {
443
9500837
        let pattern = UnresolvedPattern {
444
9500837
            common: self.common.clone(),
445
9500837
            children: UnresolvedChildren::from_node(node),
446
9500837
        };
447
9500837

            
448
9500837
        Unresolved {
449
9500837
            pattern,
450
9500837
            fallback: self.fallback.clone(),
451
9500837
        }
452
9500837
    }
453

            
454
9500722
    pub fn resolve(
455
9500722
        &self,
456
9500722
        node: &Node,
457
9500722
        acquired_nodes: &mut AcquiredNodes<'_>,
458
9500722
        opacity: UnitInterval,
459
9500722
        session: &Session,
460
9500722
    ) -> Result<ResolvedPattern, AcquireError> {
461
9500722
        let Unresolved {
462
9500722
            mut pattern,
463
9500722
            mut fallback,
464
9500722
        } = self.get_unresolved(node);
465
9500722

            
466
9500722
        let mut stack = NodeStack::new();
467

            
468
9500836
        while !pattern.is_resolved() {
469
9500836
            if let Some(ref node_id) = fallback {
470
209
                match acquired_nodes.acquire(node_id) {
471
133
                    Ok(acquired) => {
472
133
                        let acquired_node = acquired.get();
473
133

            
474
133
                        if stack.contains(acquired_node) {
475
                            return Err(AcquireError::CircularReference(acquired_node.clone()));
476
133
                        }
477
133

            
478
133
                        match *acquired_node.borrow_element_data() {
479
114
                            ElementData::Pattern(ref p) => {
480
114
                                let unresolved = p.get_unresolved(acquired_node);
481
114
                                pattern = pattern.resolve_from_fallback(&unresolved.pattern);
482
114
                                fallback = unresolved.fallback;
483
114

            
484
114
                                stack.push(acquired_node);
485
114
                            }
486
19
                            _ => return Err(AcquireError::InvalidLinkType(node_id.clone())),
487
                        }
488
                    }
489

            
490
                    Err(AcquireError::MaxReferencesExceeded) => {
491
                        return Err(AcquireError::MaxReferencesExceeded)
492
                    }
493

            
494
76
                    Err(e) => {
495
76
                        rsvg_log!(session, "Stopping pattern resolution: {}", e);
496
76
                        pattern = pattern.resolve_from_defaults();
497
76
                        break;
498
                    }
499
                }
500
            } else {
501
9500627
                pattern = pattern.resolve_from_defaults();
502
9500627
                break;
503
            }
504
        }
505

            
506
9500703
        Ok(pattern.into_resolved(opacity))
507
9500722
    }
508
}
509

            
510
#[cfg(test)]
511
mod tests {
512
    use super::*;
513

            
514
    use markup5ever::{ns, QualName};
515

            
516
    use crate::borrow_element_as;
517
    use crate::node::NodeData;
518

            
519
    #[test]
520
1
    fn pattern_resolved_from_defaults_is_really_resolved() {
521
1
        let node = Node::new(NodeData::new_element(
522
1
            &Session::default(),
523
1
            &QualName::new(None, ns!(svg), local_name!("pattern")),
524
1
            Attributes::new(),
525
1
        ));
526
1

            
527
1
        let unresolved = borrow_element_as!(node, Pattern).get_unresolved(&node);
528
1
        let pattern = unresolved.pattern.resolve_from_defaults();
529
1
        assert!(pattern.is_resolved());
530
1
    }
531
}