Skip to content

Commit

Permalink
Adding net crate (#123)
Browse files Browse the repository at this point in the history
* Adding async netcode

* Restructuring of the components

* Fixing screenshot example.

* Refactor some of the net api

* Parse stylsheets on the fetch thread.

* Make it possible to insert stylesheets at the correct position for unordered loading

* improve  net api

* Use an request method provided by Handler instead of GET

* improve non_blocking provider

* Workaround for css loading

* Remove workaround

* Reset inline nodes

* Reduce size of Resource

* Merge main into net

* Moving to dynamic dispatch, adding callback, adding traits crate, removing sync provider

(im sorry)

* fmt, clippy and some git weirdness

* Small api teaks

* Fixing double borrow introduced with #132

* Basic font-face support

* fmt

* Merge main into net, i hope this can get merged

* git
git

* typo + remove html-escape from dioxus-blitz

* Fix screenshot.rs

---------

Co-authored-by: GitButler <[email protected]>
  • Loading branch information
kokoISnoTarget and gitbutler-client authored Sep 17, 2024
1 parent 57dd0a9 commit 023b2f6
Show file tree
Hide file tree
Showing 17 changed files with 530 additions and 228 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# members = ["packages/dom"]
# members = ["packages/blitz", "packages/dom", "packages/dioxus-blitz"]
# exclude = ["packages/blitz", "packages/dioxus-blitz"]
members = ["packages/blitz", "packages/dom", "packages/dioxus-blitz"]
members = ["packages/blitz", "packages/dom", "packages/dioxus-blitz", "packages/net", "packages/traits"]
resolver = "2"

[workspace.dependencies]
Expand Down Expand Up @@ -55,6 +55,8 @@ incremental = false
# mozbuild = "0.1.0"
blitz = { path = "./packages/blitz" }
blitz-dom = { path = "./packages/dom" }
blitz-net = { path = "./packages/net" }
blitz-traits = { path = "./packages/traits" }
comrak = { git = "https://github.com/nicoburns/comrak", branch = "tasklist-class", default-features = false, features = ["syntect"] }
png = { version = "0.17" }
dioxus-blitz = { path = "./packages/dioxus-blitz" }
Expand Down
32 changes: 30 additions & 2 deletions examples/screenshot.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
//! Load first CLI argument as a url. Fallback to google.com if no CLI argument is provided.

use blitz::render_to_buffer;
use blitz_dom::util::Resource;
use blitz_dom::{HtmlDocument, Viewport};
use blitz_net::{MpscCallback, Provider};
use blitz_traits::net::{SharedCallback, SharedProvider};
use reqwest::Url;
use std::sync::Arc;
use std::{
fs::File,
io::Write,
path::{Path, PathBuf},
time::Instant,
};
use tokio::runtime::Handle;

const USER_AGENT: &str = "Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/81.0";

Expand Down Expand Up @@ -46,13 +51,36 @@ async fn main() {
.and_then(|arg| arg.parse().ok())
.unwrap_or(1200);

let (mut recv, callback) = MpscCallback::new();
let net = Arc::new(Provider::new(
Handle::current(),
Arc::new(callback) as SharedCallback<Resource>,
));

timer.time("Setup document prerequisites");

// Create HtmlDocument
let mut document = HtmlDocument::from_html(&html, Some(url.clone()), Vec::new());
let mut document = HtmlDocument::from_html(
&html,
Some(url.clone()),
Vec::new(),
Arc::clone(&net) as SharedProvider<Resource>,
);

timer.time("Parsed document");

document
.as_mut()
.set_viewport(Viewport::new(width * scale, height * scale, scale as f32));

timer.time("Created document (+ fetched assets)");
while let Some(res) = recv.recv().await {
document.as_mut().load_resource(res);
if net.is_empty() {
break;
}
}

timer.time("Fetched assets");

// Compute style, layout, etc for HtmlDocument
document.as_mut().resolve();
Expand Down
2 changes: 2 additions & 0 deletions packages/dioxus-blitz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ style = { workspace = true }
tracing = { workspace = true, optional = true }
blitz = { path = "../blitz" }
blitz-dom = { path = "../dom" }
blitz-net = { path = "../net" }
blitz-traits = { path = "../traits" }
url = { version = "2.5.0", features = ["serde"] }
ureq = "2.9"
rustc-hash = "1.1.0"
Expand Down
11 changes: 6 additions & 5 deletions packages/dioxus-blitz/src/documents/dioxus_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use rustc_hash::FxHashMap;
use style::{
data::{ElementData, ElementStyles},
properties::{style_structs::Font, ComputedValues},
stylesheets::Origin,
};

use super::event_handler::{NativeClickData, NativeConverter, NativeFormData};
Expand Down Expand Up @@ -269,7 +270,7 @@ impl DioxusDocument {
root_node.children.push(html_element_id);

// Include default and user-specified stylesheets
doc.add_stylesheet(DEFAULT_CSS);
doc.add_user_agent_stylesheet(DEFAULT_CSS);

let state = DioxusState::create(&mut doc);
let mut doc = Self {
Expand Down Expand Up @@ -492,7 +493,8 @@ impl WriteMutations for MutationWriter<'_> {
let parent = self.doc.get_node(parent).unwrap();
if let NodeData::Element(ref element) = parent.raw_dom_data {
if element.name.local.as_ref() == "style" {
self.doc.add_stylesheet(value);
let sheet = self.doc.make_stylesheet(value, Origin::Author);
self.doc.add_stylesheet_for_node(sheet, parent.id);
}
}
}
Expand Down Expand Up @@ -617,16 +619,15 @@ impl WriteMutations for MutationWriter<'_> {
// todo: this is very inefficient for inline styles - lots of string cloning going on
let changed = text.content != value;
text.content = value.to_string();
let contents = text.content.clone();

if let Some(parent) = node.parent {
// if the text is the child of a style element, we want to put the style into the stylesheet cache
let parent = self.doc.get_node(parent).unwrap();
if let NodeData::Element(ref element) = parent.raw_dom_data {
// Only set stylsheets if the text content has *changed* - we need to unload
if changed && element.name.local.as_ref() == "style" {
self.doc.add_stylesheet(value);
self.doc.remove_stylehsheet(&contents);
let sheet = self.doc.make_stylesheet(value, Origin::Author);
self.doc.add_stylesheet_for_node(sheet, parent.id);
}
}
}
Expand Down
104 changes: 82 additions & 22 deletions packages/dioxus-blitz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,29 @@ mod menu;
#[cfg(feature = "accessibility")]
mod accessibility;

use crate::application::Application;
pub use crate::documents::DioxusDocument;
pub use crate::waker::BlitzEvent;
use crate::waker::BlitzWindowEvent;
use crate::window::View;
pub use crate::window::WindowConfig;
use blitz_dom::util::Resource;
use blitz_dom::{DocumentLike, HtmlDocument};
use blitz_net::Provider;
use blitz_traits::net::SharedCallback;
use dioxus::prelude::{ComponentFunction, Element, VirtualDom};
use std::ops::DerefMut;
use std::sync::{Arc, Mutex};
use tokio::runtime::Runtime;
use url::Url;
use winit::event_loop::EventLoopProxy;
use winit::window::WindowId;
use winit::{
dpi::LogicalSize,
event_loop::{ControlFlow, EventLoop},
window::Window,
};

use crate::application::Application;
use crate::window::View;

pub use crate::documents::DioxusDocument;
pub use crate::waker::BlitzEvent;
pub use crate::window::WindowConfig;

pub mod exports {
pub use dioxus;
}
Expand Down Expand Up @@ -67,7 +74,14 @@ pub fn launch_cfg_with_props<P: Clone + 'static, M: 'static>(
let vdom = VirtualDom::new_with_props(root, props);
let document = DioxusDocument::new(vdom);

launch_with_document(document)
// Turn on the runtime and enter it
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();

let _guard = rt.enter();
launch_with_document(document, rt, None)
}

pub fn launch_url(url: &str) {
Expand Down Expand Up @@ -99,11 +113,25 @@ pub fn launch_static_html(html: &str) {
}

pub fn launch_static_html_cfg(html: &str, cfg: Config) {
let document = HtmlDocument::from_html(html, cfg.base_url, cfg.stylesheets);
launch_with_document(document)
// Turn on the runtime and enter it
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();

let _guard = rt.enter();

let net_callback = Arc::new(Callback::new());
let net = Provider::new(
rt.handle().clone(),
Arc::clone(&net_callback) as SharedCallback<Resource>,
);

let document = HtmlDocument::from_html(html, cfg.base_url, cfg.stylesheets, Arc::new(net));
launch_with_document(document, rt, Some(net_callback));
}

fn launch_with_document(doc: impl DocumentLike) {
fn launch_with_document(doc: impl DocumentLike, rt: Runtime, net_callback: Option<Arc<Callback>>) {
let mut window_attrs = Window::default_attributes();
if !cfg!(all(target_os = "android", target_os = "ios")) {
window_attrs.inner_size = Some(
Expand All @@ -114,20 +142,12 @@ fn launch_with_document(doc: impl DocumentLike) {
.into(),
);
}
let window = WindowConfig::new(doc);
let window = WindowConfig::new(doc, net_callback);

launch_with_window(window)
launch_with_window(window, rt)
}

fn launch_with_window<Doc: DocumentLike + 'static>(window: WindowConfig<Doc>) {
// Turn on the runtime and enter it
let rt = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();

let _guard = rt.enter();

fn launch_with_window<Doc: DocumentLike + 'static>(window: WindowConfig<Doc>, rt: Runtime) {
// Build an event loop for the application
let mut ev_builder = EventLoop::<BlitzEvent>::with_user_event();
#[cfg(target_os = "android")]
Expand Down Expand Up @@ -182,3 +202,43 @@ pub fn set_android_app(app: android_activity::AndroidApp) {
pub fn current_android_app(app: android_activity::AndroidApp) -> AndroidApp {
ANDROID_APP.get().unwrap().clone()
}

pub struct Callback(Mutex<CallbackInner>);
enum CallbackInner {
Window(WindowId, EventLoopProxy<BlitzEvent>),
Queue(Vec<Resource>),
}
impl Callback {
fn new() -> Self {
Self(Mutex::new(CallbackInner::Queue(Vec::new())))
}
fn init(self: Arc<Self>, window_id: WindowId, proxy: &EventLoopProxy<BlitzEvent>) {
let old = std::mem::replace(
self.0.lock().unwrap().deref_mut(),
CallbackInner::Window(window_id, proxy.clone()),
);
match old {
CallbackInner::Window(..) => {}
CallbackInner::Queue(mut queue) => queue
.drain(..)
.for_each(|res| Self::send_event(&window_id, proxy, res)),
}
}
fn send_event(window_id: &WindowId, proxy: &EventLoopProxy<BlitzEvent>, data: Resource) {
proxy
.send_event(BlitzEvent::Window {
window_id: *window_id,
data: BlitzWindowEvent::ResourceLoad(data),
})
.unwrap()
}
}
impl blitz_traits::net::Callback for Callback {
type Data = Resource;
fn call(self: Arc<Self>, data: Self::Data) {
match self.0.lock().unwrap().deref_mut() {
CallbackInner::Window(wid, proxy) => Self::send_event(wid, proxy, data),
CallbackInner::Queue(queue) => queue.push(data),
}
}
}
12 changes: 10 additions & 2 deletions packages/dioxus-blitz/src/waker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ use winit::{event_loop::EventLoopProxy, window::WindowId};
#[cfg(feature = "accessibility")]
use accesskit_winit::Event as AccessibilityEvent;
use accesskit_winit::WindowEvent as AccessibilityWindowEvent;
use blitz_dom::util::Resource;

#[derive(Debug, Clone)]
pub enum BlitzEvent {
Window {
window_id: WindowId,
data: BlitzWindowEvent,
},

/// A hotreload event, basically telling us to update our templates.
#[cfg(all(
feature = "hot-reload",
Expand All @@ -22,6 +22,14 @@ pub enum BlitzEvent {
))]
HotReloadEvent(dioxus_hot_reload::HotReloadMsg),
}
impl From<(WindowId, Resource)> for BlitzEvent {
fn from((window_id, resource): (WindowId, Resource)) -> Self {
BlitzEvent::Window {
window_id,
data: BlitzWindowEvent::ResourceLoad(resource),
}
}
}

#[cfg(feature = "accessibility")]
impl From<AccessibilityEvent> for BlitzEvent {
Expand All @@ -37,7 +45,7 @@ impl From<AccessibilityEvent> for BlitzEvent {
#[derive(Debug, Clone)]
pub enum BlitzWindowEvent {
Poll,

ResourceLoad(Resource),
/// An accessibility event from `accesskit`.
#[cfg(feature = "accessibility")]
Accessibility(Arc<AccessibilityWindowEvent>),
Expand Down
26 changes: 22 additions & 4 deletions packages/dioxus-blitz/src/window.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::accessibility::AccessibilityState;
use crate::stylo_to_winit;
use crate::waker::{create_waker, BlitzEvent, BlitzWindowEvent};
use crate::{stylo_to_winit, Callback};
use blitz::{Devtools, Renderer};
use blitz_dom::events::{EventData, RendererEvent};
use blitz_dom::{DocumentLike, Viewport};
Expand All @@ -22,18 +22,28 @@ use crate::menu::init_menu;
pub struct WindowConfig<Doc: DocumentLike> {
doc: Doc,
attributes: WindowAttributes,
callback: Option<Arc<Callback>>,
}

impl<Doc: DocumentLike> WindowConfig<Doc> {
pub fn new(doc: Doc) -> Self {
pub fn new(doc: Doc, callback: Option<Arc<Callback>>) -> Self {
WindowConfig {
doc,
attributes: Window::default_attributes(),
callback,
}
}

pub fn with_attributes(doc: Doc, attributes: WindowAttributes) -> Self {
WindowConfig { doc, attributes }
pub fn with_attributes(
doc: Doc,
attributes: WindowAttributes,
callback: Option<Arc<Callback>>,
) -> Self {
WindowConfig {
doc,
attributes,
callback,
}
}
}

Expand Down Expand Up @@ -75,6 +85,10 @@ impl<Doc: DocumentLike> View<Doc> {
) -> Self {
let winit_window = Arc::from(event_loop.create_window(config.attributes).unwrap());

if let Some(callback) = config.callback {
callback.init(winit_window.id(), proxy);
}

// TODO: make this conditional on text input focus
winit_window.set_ime_allowed(true);

Expand Down Expand Up @@ -237,6 +251,10 @@ impl<Doc: DocumentLike> View<Doc> {
BlitzWindowEvent::Poll => {
self.poll();
}
BlitzWindowEvent::ResourceLoad(resource) => {
self.dom.as_mut().load_resource(resource);
self.request_redraw();
}
#[cfg(feature = "accessibility")]
BlitzWindowEvent::Accessibility(accessibility_event) => {
match &*accessibility_event {
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ default = ["tracing"]
tracing = ["dep:tracing"]

[dependencies]
blitz-traits = { path = "../traits" }
style = { workspace = true, features = ["servo"] }
selectors = { workspace = true }
style_config = { workspace = true }
Expand All @@ -26,7 +27,6 @@ string_cache = "0.8.7"
html-escape = "0.2.13"
url = { version = "2.5.0", features = ["serde"] }
data-url = "0.3.1"
ureq = "2.9"
image = "0.25.2"
winit = { version = "0.30.4", default-features = false }
usvg = "0.42.0"
Loading

0 comments on commit 023b2f6

Please sign in to comment.