rive_rs/
file.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::any::TypeId;
6use std::rc::Rc;
7
8use crate::animation::{KeyedObject, KeyedProperty, LinearAnimation};
9use crate::artboard::Artboard;
10use crate::backboard::Backboard;
11use crate::component::Component;
12use crate::core::{self, BinaryReader, Core, Object};
13use crate::importers::{
14    ArtboardImporter, ImportStack, ImportStackObject, KeyedObjectImporter, KeyedPropertyImporter,
15    LinearAnimationImporter,
16};
17use crate::runtime_header::RuntimeHeader;
18use crate::status_code::StatusCode;
19
20/// Major version number supported by the runtime.
21const MAJOR_VERSION: u32 = 7;
22/// Minor version number supported by the runtime.
23const _MINOR_VERSION: u32 = 0;
24
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26pub enum ImportError {
27    /// Indicates that the Rive file is not supported by this runtime.
28    UnsupportedVersion,
29    /// Indicates that the there is a formatting problem in the file itself.
30    Malformed,
31}
32
33fn read_runtime_object(
34    reader: &mut BinaryReader<'_>,
35    header: &RuntimeHeader,
36    objects: &mut Vec<Rc<dyn Core>>,
37) -> Option<(Object, TypeId)> {
38    let id = core::get_type_id(reader.read_var_u64()? as u16)?;
39    let (core, object) = <dyn Core>::from_type_id(id)?;
40    objects.push(Rc::clone(&core));
41
42    loop {
43        let property_key = reader.read_var_u64()? as u16;
44        if property_key == 0 {
45            break;
46        }
47
48        if !core.write(property_key, reader) {
49            // todo!("try to find core property keys");
50
51            match header.property_file_id(property_key as u32)? {
52                0 => {
53                    reader.read_var_u64()?;
54                }
55                1 => {
56                    reader.read_string()?;
57                }
58                2 => {
59                    reader.read_f32()?;
60                }
61                3 => {
62                    reader.read_u32()?;
63                }
64                _ => return None,
65            }
66        }
67    }
68
69    Some((object, id))
70}
71
72#[derive(Debug)]
73pub struct File {
74    backboard: Object<Backboard>,
75    artboards: Vec<Object<Artboard>>,
76    // TODO(https://fxbug.dev/42165549)
77    #[allow(unused)]
78    objects: Vec<Rc<dyn Core>>,
79}
80
81impl File {
82    pub fn import(reader: &mut BinaryReader<'_>) -> Result<Self, ImportError> {
83        let header = RuntimeHeader::read(reader).ok_or(ImportError::Malformed)?;
84
85        if header.major_version() != MAJOR_VERSION {
86            return Err(ImportError::UnsupportedVersion);
87        }
88
89        Self::read(reader, &header).ok_or(ImportError::Malformed)
90    }
91
92    fn read(reader: &mut BinaryReader<'_>, header: &RuntimeHeader) -> Option<Self> {
93        let mut objects = Vec::new();
94        let mut import_stack = ImportStack::default();
95        let mut backboard_option = None;
96        let mut artboards = Vec::new();
97
98        while !reader.reached_end() {
99            let (object, id) = read_runtime_object(reader, header, &mut objects)?;
100
101            let stack_object: Option<Box<dyn ImportStackObject>> =
102                if let Some(artboard) = object.try_cast::<Artboard>() {
103                    Some(Box::new(ArtboardImporter::new(artboard)))
104                } else if let Some(animation) = object.try_cast::<LinearAnimation>() {
105                    Some(Box::new(LinearAnimationImporter::new(animation)))
106                } else if let Some(keyed_object) = object.try_cast::<KeyedObject>() {
107                    Some(Box::new(KeyedObjectImporter::new(keyed_object)))
108                } else if let Some(keyed_property) = object.try_cast::<KeyedProperty>() {
109                    let importer = import_stack
110                        .latest::<LinearAnimationImporter>(TypeId::of::<LinearAnimation>())?;
111                    Some(Box::new(KeyedPropertyImporter::new(importer.animation(), keyed_property)))
112                } else {
113                    None
114                };
115
116            if import_stack.make_latest(id, stack_object) != StatusCode::Ok {
117                return None;
118            }
119
120            if object.as_ref().import(object.clone(), &import_stack) == StatusCode::Ok {
121                if let Some(backboard) = object.try_cast::<Backboard>() {
122                    backboard_option = Some(backboard);
123                }
124
125                if let Some(artboard) = object.try_cast::<Artboard>() {
126                    artboards.push(artboard);
127                }
128            }
129        }
130
131        if import_stack.resolve() != StatusCode::Ok {
132            return None;
133        }
134
135        Some(Self { backboard: backboard_option?, artboards, objects })
136    }
137
138    pub fn backboard(&self) -> Object<Backboard> {
139        self.backboard.clone()
140    }
141
142    pub fn artboard(&self) -> Option<Object<Artboard>> {
143        self.artboards.get(0).cloned()
144    }
145
146    pub fn get_artboard(&self, name: &str) -> Option<Object<Artboard>> {
147        self.artboards
148            .iter()
149            .find(|artboard| artboard.cast::<Component>().as_ref().name() == name)
150            .cloned()
151    }
152
153    pub fn artboards(&self) -> impl Iterator<Item = &Object<Artboard>> {
154        self.artboards.iter()
155    }
156}