-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Image #4200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Image #4200
Changes from all commits
5a4e0bf
7254350
ee7daa5
9eaa66b
6178c8e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,9 +32,170 @@ | |
| let hash = ResourceHash::from(data.as_ref()); | ||
| self.registry.push_source_back(&resource_id, DataSource::Embedded); | ||
| self.registry.resolve(&resource_id, hash); | ||
| responses.add(ResourceStorageMessage::Store { data }); | ||
| responses.add_front(ResourceStorageMessage::Store { data }); | ||
| } | ||
| ResourceMessage::AddFont { resource_id, font } => { | ||
| let style = fonts.font_catalog.find_font_style_in_catalog(&font); | ||
| let style_name = style.map(|style| style.to_named_style()).unwrap_or_else(|| font.font_style.clone()); | ||
| self.registry.push_source_back(&resource_id, DataSource::Embedded); | ||
| self.registry.push_source_back( | ||
| &resource_id, | ||
| DataSource::Font { | ||
| family: font.font_family, | ||
| style: Some(style_name), | ||
| }, | ||
| ); | ||
| responses.add(ResourceMessage::Resolve { resource_id }); | ||
| } | ||
| ResourceMessage::ResolveAll => { | ||
| let unresolved_ids: Vec<ResourceId> = self.registry.unresolved().map(|info| info.id).collect(); | ||
| for id in unresolved_ids { | ||
| if self.pending_resolves.contains(&id) { | ||
| continue; | ||
| } | ||
| responses.add(ResourceMessage::Resolve { resource_id: id }); | ||
| } | ||
| } | ||
| ResourceMessage::Resolve { resource_id } => { | ||
| if self.pending_resolves.contains(&resource_id) { | ||
| log::warn!("Already pending resolve for {resource_id}; skipping"); | ||
| return; | ||
| } | ||
| let Some(info) = self.registry.info(&resource_id) else { | ||
| log::error!("Resolve for {resource_id}: no registry entry"); | ||
| return; | ||
| }; | ||
| if info.hash.is_some() { | ||
| log::warn!("Resource {resource_id} already resolved"); | ||
| return; | ||
| } | ||
|
|
||
| self.pending_resolves.insert(resource_id); | ||
|
|
||
| let font_catalog = fonts.font_catalog.clone(); | ||
|
|
||
| let sources = info | ||
| .sources | ||
| .iter() | ||
| .map(|source| match source { | ||
| DataSource::Font { family, style } => { | ||
| let font = match style { | ||
| Some(style) => Font::new(family.clone(), style.clone()), | ||
| None => Font::new_with_default_style(family.clone()), | ||
| }; | ||
| let hash = fonts.cached_hash(&font); | ||
| (source.clone(), hash) | ||
| } | ||
| source => (source.clone(), None), | ||
| }) | ||
| .collect::<Vec<(DataSource, Option<ResourceHash>)>>(); | ||
|
Comment on lines
+73
to
+91
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When resolving a resource, if the resource is already cached locally (i.e., let sources = info
.sources
.iter()
.map(|source| match source {
DataSource::Font { family, style } => {
let font = match style {
Some(style) => Font::new(family.clone(), style.clone()),
None => Font::new_with_default_style(family.clone()),
};
let hash = fonts.cached_hash(&font);
(source.clone(), hash)
}
source => (source.clone(), None),
})
.collect::<Vec<(DataSource, Option<ResourceHash>)>>();
if let Some((source, Some(hash))) = sources.iter().find(|(_, hash)| hash.is_some()) {
responses.add(ResourceMessage::Resolved { resource_id, source: source.clone(), hash: *hash });
return;
}
self.pending_resolves.insert(resource_id);
let font_catalog = fonts.font_catalog.clone(); |
||
|
|
||
| async fn resolve_to_message(document_id: DocumentId, resource_id: ResourceId, source: DataSource, url: Url, client: &Client) -> Option<Message> { | ||
| let result = client.fetch(url.clone()).await; | ||
| match result { | ||
| Some(data) => { | ||
| let hash = ResourceHash::from(data.as_ref()); | ||
| Some(Message::Batched { | ||
| messages: Box::new([ | ||
| PortfolioMessage::DocumentPassMessage { | ||
| document_id, | ||
| message: ResourceMessage::Resolved { resource_id, source, hash }.into(), | ||
| } | ||
| .into(), | ||
| ResourceStorageMessage::Store { data: Arc::from(data) }.into(), | ||
| ]), | ||
| }) | ||
| } | ||
| None => { | ||
| log::warn!("Failed to fetch resource {resource_id} from {url}"); | ||
| None | ||
| } | ||
| } | ||
| } | ||
|
|
||
| responses.add(NetworkMessage::request(async move |client| { | ||
| let mut loaded_catalog = None; | ||
| let mut response: Option<Message> = None; | ||
| for (source, hash) in sources { | ||
| if let Some(hash) = hash { | ||
| response = Some(ResourceMessage::Resolved { resource_id, source, hash }.into()); | ||
| break; | ||
| } | ||
|
|
||
| match &source { | ||
| DataSource::Embedded => continue, | ||
| DataSource::Url(url) => { | ||
| response = resolve_to_message(document_id, resource_id, source.clone(), url.clone(), &client).await; | ||
| } | ||
| DataSource::Font { family, style } => { | ||
| let font = match style { | ||
| Some(style) => Font::new(family.clone(), style.clone()), | ||
| None => Font::new_with_default_style(family.clone()), | ||
| }; | ||
|
|
||
| if font_catalog.is_empty() && loaded_catalog.as_ref().is_none() { | ||
| loaded_catalog = FontCatalog::load_from_api(&client).await; | ||
| } | ||
|
|
||
| let url = loaded_catalog.as_ref().and_then(|catalog| catalog.download_url(&font)).or_else(|| font_catalog.download_url(&font)); | ||
|
|
||
| if let Some(url) = url { | ||
| let Ok(url) = Url::parse(&url) else { | ||
| log::warn!("Invalid URL {url} for font resource {resource_id}"); | ||
| continue; | ||
| }; | ||
| response = resolve_to_message(document_id, resource_id, source.clone(), url, &client).await; | ||
| } else { | ||
| log::warn!("No download URL found for font resource {resource_id}"); | ||
| } | ||
| } | ||
| } | ||
| if response.is_some() { | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| let mut response = response.unwrap_or_else(|| { | ||
| log::error!("Resolve for {resource_id}: all sources exhausted"); | ||
| PortfolioMessage::DocumentPassMessage { | ||
| document_id, | ||
| message: ResourceMessage::ResolveFailed { resource_id }.into(), | ||
| } | ||
| .into() | ||
| }); | ||
|
|
||
| if let Some(catalog) = loaded_catalog.take() { | ||
| response = Message::Batched { | ||
| messages: Box::new([response, FontsMessage::CatalogLoaded { catalog }.into()]), | ||
| }; | ||
| } | ||
|
|
||
| response | ||
| })) | ||
| } | ||
| ResourceMessage::Resolved { resource_id, source, hash } => { | ||
| self.pending_resolves.remove(&resource_id); | ||
| if self.registry.info(&resource_id).is_none() { | ||
| // Resource was removed from registry after the fetch started. | ||
| return; | ||
| } | ||
|
|
||
| self.registry.resolve(&resource_id, hash); | ||
|
|
||
| if let DataSource::Font { family, style } = source { | ||
| let font = match style { | ||
| Some(style) => Font::new(family, style), | ||
| None => Font::new_with_default_style(family), | ||
| }; | ||
| responses.add(FontsMessage::ResourceResolved { font, hash }); | ||
| } | ||
|
|
||
| responses.add(NodeGraphMessage::RunDocumentGraph); | ||
| } | ||
| ResourceMessage::ResolveFailed { resource_id } => { | ||
| self.pending_resolves.remove(&resource_id); | ||
| } | ||
| ResourceMessage::AddFont { resource_id, font } => { | ||
|
Check failure on line 198 in editor/src/messages/portfolio/document/resource/resource_message_handler.rs
|
||
| let style = fonts.font_catalog.find_font_style_in_catalog(&font); | ||
| let style_name = style.map(|style| style.to_named_style()).unwrap_or_else(|| font.font_style.clone()); | ||
| self.registry.push_source_back(&resource_id, DataSource::Embedded); | ||
|
|
@@ -47,7 +208,7 @@ | |
| ); | ||
| responses.add(ResourceMessage::Resolve { resource_id }); | ||
| } | ||
| ResourceMessage::ResolveAll => { | ||
|
Check failure on line 211 in editor/src/messages/portfolio/document/resource/resource_message_handler.rs
|
||
| let unresolved_ids: Vec<ResourceId> = self.registry.unresolved().map(|info| info.id).collect(); | ||
| for id in unresolved_ids { | ||
| if self.pending_resolves.contains(&id) { | ||
|
|
@@ -56,7 +217,7 @@ | |
| responses.add(ResourceMessage::Resolve { resource_id: id }); | ||
| } | ||
| } | ||
| ResourceMessage::Resolve { resource_id } => { | ||
|
Check failure on line 220 in editor/src/messages/portfolio/document/resource/resource_message_handler.rs
|
||
| if self.pending_resolves.contains(&resource_id) { | ||
| log::warn!("Already pending resolve for {resource_id}; skipping"); | ||
| return; | ||
|
|
@@ -173,7 +334,7 @@ | |
| response | ||
| })) | ||
| } | ||
| ResourceMessage::Resolved { resource_id, source, hash } => { | ||
|
Check failure on line 337 in editor/src/messages/portfolio/document/resource/resource_message_handler.rs
|
||
| self.pending_resolves.remove(&resource_id); | ||
| if self.registry.info(&resource_id).is_none() { | ||
| // Resource was removed from registry after the fetch started. | ||
|
|
@@ -192,7 +353,7 @@ | |
|
|
||
| responses.add(NodeGraphMessage::RunDocumentGraph); | ||
| } | ||
| ResourceMessage::ResolveFailed { resource_id } => { | ||
|
Check failure on line 356 in editor/src/messages/portfolio/document/resource/resource_message_handler.rs
|
||
| self.pending_resolves.remove(&resource_id); | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Decoding the entire image using
::image::load_from_memory_with_formatjust to retrieve its dimensions is highly inefficient, especially for large embedded SVG images. Consider using::image::Readerwithinto_dimensions()to parse only the image header and extract the width and height without decoding the full pixel data.