1
//! The `pattern` element.
2

            
3
use markup5ever::{expanded_name, local_name, namespace_url, 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
1000204
#[derive(Clone, Default)]
29
struct Common {
30
500102
    units: Option<PatternUnits>,
31
500102
    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
500102
    vbox: Option<Option<ViewBox>>,
37
500102
    preserve_aspect_ratio: Option<AspectRatio>,
38
500102
    transform: Option<TransformAttribute>,
39
500102
    x: Option<Length<Horizontal>>,
40
500102
    y: Option<Length<Vertical>>,
41
500102
    width: Option<ULength<Horizontal>>,
42
500102
    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
500035
#[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
500035
    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
112
#[derive(Default)]
123
pub struct Pattern {
124
56
    common: Common,
125
56
    fallback: Option<NodeId>,
126
}
127

            
128
impl ElementTrait for Pattern {
129
56
    fn set_attributes(&mut self, attrs: &Attributes, session: &Session) {
130
332
        for (attr, value) in attrs.iter() {
131
474
            match attr.expanded() {
132
                expanded_name!("", "patternUnits") => {
133
37
                    set_attribute(&mut self.common.units, attr.parse(value), session)
134
                }
135
                expanded_name!("", "patternContentUnits") => {
136
6
                    set_attribute(&mut self.common.content_units, attr.parse(value), session);
137
                }
138
                expanded_name!("", "viewBox") => {
139
11
                    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
                expanded_name!("", "patternTransform") => {
149
12
                    set_attribute(&mut self.common.transform, attr.parse(value), session);
150
                }
151
210
                ref a if is_href(a) => {
152
12
                    let mut href = None;
153
12
                    set_attribute(
154
                        &mut href,
155
12
                        NodeId::parse(value).map(Some).attribute(attr.clone()),
156
                        session,
157
                    );
158
12
                    set_href(a, &mut self.fallback, href);
159
12
                }
160
                expanded_name!("", "x") => {
161
29
                    set_attribute(&mut self.common.x, attr.parse(value), session)
162
                }
163
                expanded_name!("", "y") => {
164
30
                    set_attribute(&mut self.common.y, attr.parse(value), session)
165
                }
166
                expanded_name!("", "width") => {
167
42
                    set_attribute(&mut self.common.width, attr.parse(value), session)
168
                }
169
                expanded_name!("", "height") => {
170
43
                    set_attribute(&mut self.common.height, attr.parse(value), session)
171
                }
172
                _ => (),
173
            }
174
276
        }
175
56
    }
176
}
177

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

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

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

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

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

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

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

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

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

            
284
1500121
        if node.children().any(|child| child.is_element()) {
285
500037
            UnresolvedChildren::WithChildren(weak)
286
        } else {
287
9
            UnresolvedChildren::Unresolved
288
        }
289
500046
    }
290

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

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

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

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

            
309
500039
        match *self {
310
4
            Unresolved => ResolvedEmpty,
311
500035
            _ => (*self).clone(),
312
        }
313
500039
    }
314

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
416
500034
        Some(UserSpacePattern {
417
            width,
418
            height,
419
500034
            transform: pattern_transform,
420
            coord_transform,
421
500034
            content_transform,
422
500034
            opacity: self.opacity,
423
500034
            node_with_children,
424
        })
425
500038
    }
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
500024
    pub fn acquire_pattern_node(
434
        &self,
435
        acquired_nodes: &mut AcquiredNodes<'_>,
436
    ) -> Result<AcquiredNode, AcquireError> {
437
500024
        acquired_nodes.acquire_ref(&self.node_with_children)
438
500024
    }
439
}
440

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

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

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

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

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

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

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

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

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

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

            
506
500038
        Ok(pattern.into_resolved(opacity))
507
500039
    }
508
}
509

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

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

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

            
519
    #[test]
520
2
    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

            
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
2
    }
531
}