mirror of
https://github.com/typst/typst
synced 2025-08-16 07:58:32 +08:00
Compare commits
6 Commits
6b6a7e5a16
...
874f8183d8
Author | SHA1 | Date | |
---|---|---|---|
|
874f8183d8 | ||
|
9a6268050f | ||
|
e2a022ac7b | ||
|
3044bb0c76 | ||
|
97430912ce | ||
|
1197092a03 |
211
Cargo.lock
generated
211
Cargo.lock
generated
@ -136,6 +136,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
|
||||
|
||||
[[package]]
|
||||
name = "biblatex"
|
||||
version = "0.10.0"
|
||||
@ -244,6 +250,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.11"
|
||||
@ -471,6 +483,35 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie_store"
|
||||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9"
|
||||
dependencies = [
|
||||
"cookie",
|
||||
"document-features",
|
||||
"idna",
|
||||
"indexmap 2.7.1",
|
||||
"log",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"time",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.4"
|
||||
@ -572,6 +613,16 @@ version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a"
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
|
||||
dependencies = [
|
||||
"pem-rfc7468",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deranged"
|
||||
version = "0.3.11"
|
||||
@ -624,6 +675,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "document-features"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
|
||||
dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "downcast-rs"
|
||||
version = "1.2.1"
|
||||
@ -677,16 +737,6 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_proxy"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a5019be18538406a43b5419a5501461f0c8b49ea7dfda0cfc32f4e51fc44be1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
@ -970,6 +1020,23 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
|
||||
|
||||
[[package]]
|
||||
name = "httpdate"
|
||||
version = "1.0.3"
|
||||
@ -1507,6 +1574,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.12"
|
||||
@ -1853,6 +1926,15 @@ dependencies = [
|
||||
"ryu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pem-rfc7468"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@ -2228,6 +2310,24 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
|
||||
dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.19"
|
||||
@ -2455,6 +2555,17 @@ version = "1.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
|
||||
[[package]]
|
||||
name = "socks"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
@ -3008,7 +3119,6 @@ version = "0.13.1"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"ecow",
|
||||
"env_proxy",
|
||||
"fastrand",
|
||||
"flate2",
|
||||
"fontdb",
|
||||
@ -3373,18 +3483,37 @@ checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47"
|
||||
|
||||
[[package]]
|
||||
name = "ureq"
|
||||
version = "2.12.1"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d"
|
||||
checksum = "b7a3e9af6113ecd57b8c63d3cd76a385b2e3881365f1f489e54f49801d0c83ea"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"cookie_store",
|
||||
"der",
|
||||
"flate2",
|
||||
"log",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"rustls-pemfile",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"url",
|
||||
"socks",
|
||||
"ureq-proto",
|
||||
"utf-8",
|
||||
"webpki-root-certs 0.26.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ureq-proto"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fadf18427d33828c311234884b7ba2afb57143e6e7e69fda7ee883b624661e36"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -3426,6 +3555,12 @@ dependencies = [
|
||||
"xmlwriter",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utf-8"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||
|
||||
[[package]]
|
||||
name = "utf16_iter"
|
||||
version = "1.0.5"
|
||||
@ -3603,12 +3738,46 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "0.26.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e"
|
||||
dependencies = [
|
||||
"webpki-root-certs 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-root-certs"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01a83f7e1a9f8712695c03eabe9ed3fbca0feff0152f33f12593e5a6303cb1a4"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
@ -3618,6 +3787,12 @@ dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
@ -3895,6 +4070,12 @@ dependencies = [
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
|
||||
[[package]]
|
||||
name = "zerotrie"
|
||||
version = "0.1.3"
|
||||
|
@ -54,7 +54,6 @@ csv = "1"
|
||||
ctrlc = "3.4.1"
|
||||
dirs = "6"
|
||||
ecow = { version = "0.2", features = ["serde"] }
|
||||
env_proxy = "0.4"
|
||||
fastrand = "2.3"
|
||||
flate2 = "1"
|
||||
fontdb = { version = "0.23", default-features = false }
|
||||
@ -133,7 +132,7 @@ unicode-script = "0.5"
|
||||
unicode-normalization = "0.1.24"
|
||||
unicode-segmentation = "1"
|
||||
unscanny = "0.1"
|
||||
ureq = { version = "2", default-features = false, features = ["native-tls", "gzip", "json"] }
|
||||
ureq = { version = "3", default-features = false, features = ["native-tls", "gzip", "json", "socks-proxy"] }
|
||||
usvg = { version = "0.45", default-features = false, features = ["text"] }
|
||||
utf8_iter = "1.0.4"
|
||||
walkdir = "2"
|
||||
|
@ -145,10 +145,10 @@ impl Release {
|
||||
};
|
||||
|
||||
match downloader.download(&url) {
|
||||
Ok(response) => response.into_json().map_err(|err| {
|
||||
Ok(mut response) => response.body_mut().read_json().map_err(|err| {
|
||||
eco_format!("failed to parse release information ({err})")
|
||||
}),
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
Err(ureq::Error::StatusCode(404)) => {
|
||||
bail!("release not found (searched at {url})")
|
||||
}
|
||||
Err(err) => bail!("failed to download release ({err})"),
|
||||
@ -175,7 +175,7 @@ impl Release {
|
||||
&mut PrintDownload("release"),
|
||||
) {
|
||||
Ok(data) => data,
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
Err(ureq::Error::StatusCode(404)) => {
|
||||
bail!("asset not found (searched for {})", asset.name);
|
||||
}
|
||||
Err(err) => bail!("failed to download asset ({err})"),
|
||||
|
@ -109,10 +109,7 @@ fn handle(
|
||||
styles.chain(&style),
|
||||
Region::new(Size::splat(Abs::inf()), Axes::splat(false)),
|
||||
)?;
|
||||
output.push(HtmlNode::Frame(HtmlFrame {
|
||||
inner: frame,
|
||||
text_size: styles.resolve(TextElem::size),
|
||||
}));
|
||||
output.push(HtmlNode::Frame(HtmlFrame::new(frame, styles)));
|
||||
} else {
|
||||
engine.sink.warn(warning!(
|
||||
child.span(),
|
||||
|
@ -2,10 +2,11 @@ use std::fmt::{self, Debug, Display, Formatter};
|
||||
|
||||
use ecow::{EcoString, EcoVec};
|
||||
use typst_library::diag::{bail, HintedStrResult, StrResult};
|
||||
use typst_library::foundations::{cast, Dict, Repr, Str};
|
||||
use typst_library::foundations::{cast, Dict, Repr, Str, StyleChain};
|
||||
use typst_library::introspection::{Introspector, Tag};
|
||||
use typst_library::layout::{Abs, Frame};
|
||||
use typst_library::model::DocumentInfo;
|
||||
use typst_library::text::TextElem;
|
||||
use typst_syntax::Span;
|
||||
use typst_utils::{PicoStr, ResolvedPicoStr};
|
||||
|
||||
@ -279,3 +280,10 @@ pub struct HtmlFrame {
|
||||
/// consistently.
|
||||
pub text_size: Abs,
|
||||
}
|
||||
|
||||
impl HtmlFrame {
|
||||
/// Wraps a laid-out frame.
|
||||
pub fn new(inner: Frame, styles: StyleChain) -> Self {
|
||||
Self { inner, text_size: styles.resolve(TextElem::size) }
|
||||
}
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ fn write_children(w: &mut Writer, element: &HtmlElement) -> SourceResult<()> {
|
||||
let pretty_inside = allows_pretty_inside(element.tag)
|
||||
&& element.children.iter().any(|node| match node {
|
||||
HtmlNode::Element(child) => wants_pretty_around(child.tag),
|
||||
HtmlNode::Frame(_) => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
@ -305,14 +306,6 @@ fn write_escape(w: &mut Writer, c: char) -> StrResult<()> {
|
||||
|
||||
/// Encode a laid out frame into the writer.
|
||||
fn write_frame(w: &mut Writer, frame: &HtmlFrame) {
|
||||
// FIXME: This string replacement is obviously a hack.
|
||||
let svg = typst_svg::svg_frame(&frame.inner).replace(
|
||||
"<svg class",
|
||||
&format!(
|
||||
"<svg style=\"overflow: visible; width: {}em; height: {}em;\" class",
|
||||
frame.inner.width() / frame.text_size,
|
||||
frame.inner.height() / frame.text_size,
|
||||
),
|
||||
);
|
||||
let svg = typst_svg::svg_html_frame(&frame.inner, frame.text_size);
|
||||
w.buf.push_str(&svg);
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ typst-timing = { workspace = true }
|
||||
typst-utils = { workspace = true }
|
||||
dirs = { workspace = true, optional = true }
|
||||
ecow = { workspace = true }
|
||||
env_proxy = { workspace = true, optional = true }
|
||||
fastrand = { workspace = true, optional = true }
|
||||
flate2 = { workspace = true, optional = true }
|
||||
fontdb = { workspace = true, optional = true }
|
||||
@ -41,7 +40,7 @@ default = ["fonts", "packages"]
|
||||
fonts = ["dep:fontdb", "fontdb/memmap", "fontdb/fontconfig"]
|
||||
|
||||
# Add generic downloading utilities
|
||||
downloads = ["dep:env_proxy", "dep:native-tls", "dep:ureq", "dep:openssl"]
|
||||
downloads = ["dep:native-tls", "dep:ureq", "dep:openssl"]
|
||||
|
||||
# Add package downloading utilities, implies `downloads`
|
||||
packages = ["downloads", "dep:dirs", "dep:flate2", "dep:tar", "dep:fastrand"]
|
||||
|
@ -13,9 +13,8 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use ecow::EcoString;
|
||||
use native_tls::{Certificate, TlsConnector};
|
||||
use once_cell::sync::OnceCell;
|
||||
use ureq::Response;
|
||||
use ureq::tls::{Certificate, RootCerts, TlsProvider};
|
||||
|
||||
/// Manages progress reporting for downloads.
|
||||
pub trait Progress {
|
||||
@ -57,7 +56,7 @@ pub struct DownloadState {
|
||||
pub struct Downloader {
|
||||
user_agent: EcoString,
|
||||
cert_path: Option<PathBuf>,
|
||||
cert: OnceCell<Certificate>,
|
||||
cert: OnceCell<Certificate<'static>>,
|
||||
}
|
||||
|
||||
impl Downloader {
|
||||
@ -82,7 +81,10 @@ impl Downloader {
|
||||
}
|
||||
|
||||
/// Crates a new downloader with the given user agent and certificate.
|
||||
pub fn with_cert(user_agent: impl Into<EcoString>, cert: Certificate) -> Self {
|
||||
pub fn with_cert(
|
||||
user_agent: impl Into<EcoString>,
|
||||
cert: Certificate<'static>,
|
||||
) -> Self {
|
||||
Self {
|
||||
user_agent: user_agent.into(),
|
||||
cert_path: None,
|
||||
@ -96,7 +98,7 @@ impl Downloader {
|
||||
/// - Returns `None` if `--cert` and `TYPST_CERT` are not set.
|
||||
/// - Returns `Some(Ok(cert))` if the certificate was loaded successfully.
|
||||
/// - Returns `Some(Err(err))` if an error occurred while loading the certificate.
|
||||
pub fn cert(&self) -> Option<io::Result<&Certificate>> {
|
||||
pub fn cert(&self) -> Option<io::Result<&Certificate<'static>>> {
|
||||
self.cert_path.as_ref().map(|path| {
|
||||
self.cert.get_or_try_init(|| {
|
||||
let pem = std::fs::read(path)?;
|
||||
@ -107,31 +109,34 @@ impl Downloader {
|
||||
|
||||
/// Download binary data from the given url.
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn download(&self, url: &str) -> Result<ureq::Response, ureq::Error> {
|
||||
let mut builder = ureq::AgentBuilder::new();
|
||||
let mut tls = TlsConnector::builder();
|
||||
pub fn download(
|
||||
&self,
|
||||
url: &str,
|
||||
) -> Result<ureq::http::Response<ureq::Body>, ureq::Error> {
|
||||
let mut builder = ureq::config::Config::builder();
|
||||
|
||||
// Set user agent.
|
||||
builder = builder.user_agent(&self.user_agent);
|
||||
|
||||
// Get the network proxy config from the environment and apply it.
|
||||
if let Some(proxy) = env_proxy::for_url_str(url)
|
||||
.to_url()
|
||||
.and_then(|url| ureq::Proxy::new(url).ok())
|
||||
{
|
||||
builder = builder.proxy(proxy);
|
||||
}
|
||||
|
||||
// Apply a custom CA certificate if present.
|
||||
if let Some(cert) = self.cert() {
|
||||
tls.add_root_certificate(cert?.clone());
|
||||
}
|
||||
let maybe_cert = self.cert().transpose()?.cloned().map_or(
|
||||
RootCerts::PlatformVerifier,
|
||||
|cert| {
|
||||
let certs = vec![cert];
|
||||
RootCerts::Specific(Arc::new(certs))
|
||||
},
|
||||
);
|
||||
|
||||
// Configure native TLS.
|
||||
let connector = tls.build().map_err(io::Error::other)?;
|
||||
builder = builder.tls_connector(Arc::new(connector));
|
||||
let tls_config = ureq::tls::TlsConfig::builder()
|
||||
.provider(TlsProvider::NativeTls)
|
||||
.root_certs(maybe_cert);
|
||||
|
||||
builder.build().get(url).call()
|
||||
builder = builder.tls_config(tls_config.build());
|
||||
|
||||
let agent = ureq::Agent::new_with_config(builder.build());
|
||||
|
||||
agent.get(url).call()
|
||||
}
|
||||
|
||||
/// Download binary data from the given url and report its progress.
|
||||
@ -170,7 +175,7 @@ const SAMPLES: usize = 5;
|
||||
/// over a websocket and reports its progress.
|
||||
struct RemoteReader<'p> {
|
||||
/// The reader returned by the ureq::Response.
|
||||
reader: Box<dyn Read + Send + Sync + 'static>,
|
||||
reader: ureq::BodyReader<'static>,
|
||||
/// The download state, holding download metadata for progress reporting.
|
||||
state: DownloadState,
|
||||
/// The instant at which progress was last reported.
|
||||
@ -184,13 +189,18 @@ impl<'p> RemoteReader<'p> {
|
||||
///
|
||||
/// The 'Content-Length' header is used as a size hint for read
|
||||
/// optimization, if present.
|
||||
fn from_response(response: Response, progress: &'p mut dyn Progress) -> Self {
|
||||
fn from_response(
|
||||
response: ureq::http::Response<ureq::Body>,
|
||||
progress: &'p mut dyn Progress,
|
||||
) -> Self {
|
||||
let content_len: Option<usize> = response
|
||||
.header("Content-Length")
|
||||
.headers()
|
||||
.get("Content-Length")
|
||||
.and_then(|header| header.to_str().ok())
|
||||
.and_then(|header| header.parse().ok());
|
||||
|
||||
Self {
|
||||
reader: response.into_reader(),
|
||||
reader: response.into_body().into_reader(),
|
||||
last_progress: None,
|
||||
state: DownloadState {
|
||||
content_len,
|
||||
|
@ -150,10 +150,10 @@ impl PackageStorage {
|
||||
.get_or_try_init(|| {
|
||||
let url = format!("{DEFAULT_REGISTRY}/{DEFAULT_NAMESPACE}/index.json");
|
||||
match self.downloader.download(&url) {
|
||||
Ok(response) => response.into_json().map_err(|err| {
|
||||
Ok(mut response) => response.body_mut().read_json().map_err(|err| {
|
||||
eco_format!("failed to parse package index: {err}")
|
||||
}),
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
Err(ureq::Error::StatusCode(404)) => {
|
||||
bail!("failed to fetch package index (not found)")
|
||||
}
|
||||
Err(err) => bail!("failed to fetch package index ({err})"),
|
||||
@ -181,7 +181,7 @@ impl PackageStorage {
|
||||
|
||||
let data = match self.downloader.download_with_progress(&url, progress) {
|
||||
Ok(data) => data,
|
||||
Err(ureq::Error::Status(404, _)) => {
|
||||
Err(ureq::Error::StatusCode(404)) => {
|
||||
if let Ok(version) = self.determine_latest_version(&spec.versionless()) {
|
||||
return Err(PackageError::VersionNotFound(spec.clone(), version));
|
||||
} else {
|
||||
|
@ -45,6 +45,30 @@ pub fn svg_frame(frame: &Frame) -> String {
|
||||
renderer.finalize()
|
||||
}
|
||||
|
||||
/// Export a frame into an SVG suitable for embedding into HTML.
|
||||
#[typst_macros::time(name = "svg html frame")]
|
||||
pub fn svg_html_frame(frame: &Frame, text_size: Abs) -> String {
|
||||
let mut renderer = SVGRenderer::with_options(xmlwriter::Options {
|
||||
indent: xmlwriter::Indent::None,
|
||||
..Default::default()
|
||||
});
|
||||
renderer.write_header_with_custom_attrs(frame.size(), |xml| {
|
||||
xml.write_attribute("class", "typst-frame");
|
||||
xml.write_attribute_fmt(
|
||||
"style",
|
||||
format_args!(
|
||||
"overflow: visible; width: {}em; height: {}em;",
|
||||
frame.width() / text_size,
|
||||
frame.height() / text_size,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
let state = State::new(frame.size(), Transform::identity());
|
||||
renderer.render_frame(state, Transform::identity(), frame);
|
||||
renderer.finalize()
|
||||
}
|
||||
|
||||
/// Export a document with potentially multiple pages into a single SVG file.
|
||||
///
|
||||
/// The padding will be added around and between the individual frames.
|
||||
@ -158,8 +182,13 @@ impl State {
|
||||
impl SVGRenderer {
|
||||
/// Create a new SVG renderer with empty glyph and clip path.
|
||||
fn new() -> Self {
|
||||
Self::with_options(Default::default())
|
||||
}
|
||||
|
||||
/// Create a new SVG renderer with the given configuration.
|
||||
fn with_options(options: xmlwriter::Options) -> Self {
|
||||
SVGRenderer {
|
||||
xml: XmlWriter::new(xmlwriter::Options::default()),
|
||||
xml: XmlWriter::new(options),
|
||||
glyphs: Deduplicator::new('g'),
|
||||
clip_paths: Deduplicator::new('c'),
|
||||
gradient_refs: Deduplicator::new('g'),
|
||||
@ -170,11 +199,22 @@ impl SVGRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Write the SVG header, including the `viewBox` and `width` and `height`
|
||||
/// attributes.
|
||||
/// Write the default SVG header, including a `typst-doc` class, the
|
||||
/// `viewBox` and `width` and `height` attributes.
|
||||
fn write_header(&mut self, size: Size) {
|
||||
self.write_header_with_custom_attrs(size, |xml| {
|
||||
xml.write_attribute("class", "typst-doc");
|
||||
});
|
||||
}
|
||||
|
||||
/// Write the SVG header with additional attributes and standard attributes.
|
||||
fn write_header_with_custom_attrs(
|
||||
&mut self,
|
||||
size: Size,
|
||||
write_custom_attrs: impl FnOnce(&mut XmlWriter),
|
||||
) {
|
||||
self.xml.start_element("svg");
|
||||
self.xml.write_attribute("class", "typst-doc");
|
||||
write_custom_attrs(&mut self.xml);
|
||||
self.xml.write_attribute_fmt(
|
||||
"viewBox",
|
||||
format_args!("0 0 {} {}", size.x.to_pt(), size.y.to_pt()),
|
||||
|
11
tests/ref/html/html-frame.html
Normal file
11
tests/ref/html/html-frame.html
Normal file
@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<p>A rectangle:</p>
|
||||
<svg class="typst-frame" style="overflow: visible; width: 4.5em; height: 3em;" viewBox="0 0 45 30" width="45pt" height="30pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:h5="http://www.w3.org/1999/xhtml"><g><g transform="translate(-0 -0)"><path class="typst-shape" fill="none" stroke="#000000" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" d="M 0 0 L 0 30 L 45 30 L 45 0 Z "/></g></g></svg>
|
||||
</body>
|
||||
</html>
|
@ -1,5 +1,6 @@
|
||||
// No proper HTML tests here yet because we don't want to test SVG export just
|
||||
// yet. We'll definitely add tests at some point.
|
||||
--- html-frame html ---
|
||||
A rectangle:
|
||||
#html.frame(rect())
|
||||
|
||||
--- html-frame-in-layout ---
|
||||
// Ensure that HTML frames are transparent in layout. This is less important for
|
||||
|
Loading…
x
Reference in New Issue
Block a user