| // Copyright 2021 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use std::{any::TypeId, rc::Rc}; |
| |
| use crate::{ |
| animation::{KeyedObject, KeyedProperty, LinearAnimation}, |
| artboard::Artboard, |
| backboard::Backboard, |
| component::Component, |
| core::{self, BinaryReader, Core, Object}, |
| importers::{ |
| ArtboardImporter, ImportStack, ImportStackObject, KeyedObjectImporter, |
| KeyedPropertyImporter, LinearAnimationImporter, |
| }, |
| runtime_header::RuntimeHeader, |
| status_code::StatusCode, |
| }; |
| |
| /// Major version number supported by the runtime. |
| const MAJOR_VERSION: u32 = 7; |
| /// Minor version number supported by the runtime. |
| const _MINOR_VERSION: u32 = 0; |
| |
| #[derive(Clone, Copy, Debug, Eq, PartialEq)] |
| pub enum ImportError { |
| /// Indicates that the Rive file is not supported by this runtime. |
| UnsupportedVersion, |
| /// Indicates that the there is a formatting problem in the file itself. |
| Malformed, |
| } |
| |
| fn read_runtime_object( |
| reader: &mut BinaryReader<'_>, |
| header: &RuntimeHeader, |
| objects: &mut Vec<Rc<dyn Core>>, |
| ) -> Option<(Object, TypeId)> { |
| let id = core::get_type_id(reader.read_var_u64()? as u16)?; |
| let (core, object) = <dyn Core>::from_type_id(id)?; |
| objects.push(Rc::clone(&core)); |
| |
| loop { |
| let property_key = reader.read_var_u64()? as u16; |
| if property_key == 0 { |
| break; |
| } |
| |
| if !core.write(property_key, reader) { |
| // todo!("try to find core property keys"); |
| |
| match header.property_file_id(property_key as u32)? { |
| 0 => { |
| reader.read_var_u64()?; |
| } |
| 1 => { |
| reader.read_string()?; |
| } |
| 2 => { |
| reader.read_f32()?; |
| } |
| 3 => { |
| reader.read_u32()?; |
| } |
| _ => return None, |
| } |
| } |
| } |
| |
| Some((object, id)) |
| } |
| |
| #[derive(Debug)] |
| pub struct File { |
| backboard: Object<Backboard>, |
| artboards: Vec<Object<Artboard>>, |
| // TODO(https://fxbug.dev/42165549) |
| #[allow(unused)] |
| objects: Vec<Rc<dyn Core>>, |
| } |
| |
| impl File { |
| pub fn import(reader: &mut BinaryReader<'_>) -> Result<Self, ImportError> { |
| let header = RuntimeHeader::read(reader).ok_or(ImportError::Malformed)?; |
| |
| if header.major_version() != MAJOR_VERSION { |
| return Err(ImportError::UnsupportedVersion); |
| } |
| |
| Self::read(reader, &header).ok_or(ImportError::Malformed) |
| } |
| |
| fn read(reader: &mut BinaryReader<'_>, header: &RuntimeHeader) -> Option<Self> { |
| let mut objects = Vec::new(); |
| let mut import_stack = ImportStack::default(); |
| let mut backboard_option = None; |
| let mut artboards = Vec::new(); |
| |
| while !reader.reached_end() { |
| let (object, id) = read_runtime_object(reader, header, &mut objects)?; |
| |
| let stack_object: Option<Box<dyn ImportStackObject>> = |
| if let Some(artboard) = object.try_cast::<Artboard>() { |
| Some(Box::new(ArtboardImporter::new(artboard))) |
| } else if let Some(animation) = object.try_cast::<LinearAnimation>() { |
| Some(Box::new(LinearAnimationImporter::new(animation))) |
| } else if let Some(keyed_object) = object.try_cast::<KeyedObject>() { |
| Some(Box::new(KeyedObjectImporter::new(keyed_object))) |
| } else if let Some(keyed_property) = object.try_cast::<KeyedProperty>() { |
| let importer = import_stack |
| .latest::<LinearAnimationImporter>(TypeId::of::<LinearAnimation>())?; |
| Some(Box::new(KeyedPropertyImporter::new(importer.animation(), keyed_property))) |
| } else { |
| None |
| }; |
| |
| if import_stack.make_latest(id, stack_object) != StatusCode::Ok { |
| return None; |
| } |
| |
| if object.as_ref().import(object.clone(), &import_stack) == StatusCode::Ok { |
| if let Some(backboard) = object.try_cast::<Backboard>() { |
| backboard_option = Some(backboard); |
| } |
| |
| if let Some(artboard) = object.try_cast::<Artboard>() { |
| artboards.push(artboard); |
| } |
| } |
| } |
| |
| if import_stack.resolve() != StatusCode::Ok { |
| return None; |
| } |
| |
| Some(Self { backboard: backboard_option?, artboards, objects }) |
| } |
| |
| pub fn backboard(&self) -> Object<Backboard> { |
| self.backboard.clone() |
| } |
| |
| pub fn artboard(&self) -> Option<Object<Artboard>> { |
| self.artboards.get(0).cloned() |
| } |
| |
| pub fn get_artboard(&self, name: &str) -> Option<Object<Artboard>> { |
| self.artboards |
| .iter() |
| .find(|artboard| artboard.cast::<Component>().as_ref().name() == name) |
| .cloned() |
| } |
| |
| pub fn artboards(&self) -> impl Iterator<Item = &Object<Artboard>> { |
| self.artboards.iter() |
| } |
| } |