Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
95
third-party/vendor/ttf-parser-0.15.2/examples/font-info.rs
vendored
Normal file
95
third-party/vendor/ttf-parser-0.15.2/examples/font-info.rs
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
fn main() {
|
||||
let args: Vec<_> = std::env::args().collect();
|
||||
if args.len() != 2 {
|
||||
println!("Usage:\n\tfont-info font.ttf");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let font_data = std::fs::read(&args[1]).unwrap();
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
let face = match ttf_parser::Face::from_slice(&font_data, 0) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprint!("Error: {}.", e);
|
||||
std::process::exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
let family_name = face.names().into_iter()
|
||||
.find(|name| name.name_id == ttf_parser::name_id::FULL_NAME && name.is_unicode())
|
||||
.and_then(|name| name.to_string());
|
||||
|
||||
let post_script_name = face.names().into_iter()
|
||||
.find(|name| name.name_id == ttf_parser::name_id::POST_SCRIPT_NAME && name.is_unicode())
|
||||
.and_then(|name| name.to_string());
|
||||
|
||||
println!("Family name: {:?}", family_name);
|
||||
println!("PostScript name: {:?}", post_script_name);
|
||||
println!("Units per EM: {:?}", face.units_per_em());
|
||||
println!("Ascender: {}", face.ascender());
|
||||
println!("Descender: {}", face.descender());
|
||||
println!("Line gap: {}", face.line_gap());
|
||||
println!("Global bbox: {:?}", face.global_bounding_box());
|
||||
println!("Number of glyphs: {}", face.number_of_glyphs());
|
||||
println!("Underline: {:?}", face.underline_metrics());
|
||||
println!("X height: {:?}", face.x_height());
|
||||
println!("Weight: {:?}", face.weight());
|
||||
println!("Width: {:?}", face.width());
|
||||
println!("Regular: {}", face.is_regular());
|
||||
println!("Italic: {}", face.is_italic());
|
||||
println!("Bold: {}", face.is_bold());
|
||||
println!("Oblique: {}", face.is_oblique());
|
||||
println!("Strikeout: {:?}", face.strikeout_metrics());
|
||||
println!("Subscript: {:?}", face.subscript_metrics());
|
||||
println!("Superscript: {:?}", face.superscript_metrics());
|
||||
println!("Variable: {:?}", face.is_variable());
|
||||
|
||||
#[cfg(feature = "opentype-layout")] {
|
||||
if let Some(ref table) = face.tables().gpos {
|
||||
print_opentype_layout("positioning", table);
|
||||
}
|
||||
|
||||
if let Some(ref table) = face.tables().gsub {
|
||||
print_opentype_layout("substitution", table);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "variable-fonts")] {
|
||||
if face.is_variable() {
|
||||
println!("Variation axes:");
|
||||
for axis in face.variation_axes() {
|
||||
println!(" {} {}..{}, default {}",
|
||||
axis.tag, axis.min_value, axis.max_value, axis.def_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("Elapsed: {}us", now.elapsed().as_micros());
|
||||
}
|
||||
|
||||
fn print_opentype_layout(name: &str, table: &ttf_parser::opentype_layout::LayoutTable) {
|
||||
println!("OpenType {}:", name);
|
||||
println!(" Scripts:");
|
||||
for script in table.scripts {
|
||||
println!(" {}", script.tag);
|
||||
|
||||
if script.languages.is_empty() {
|
||||
println!(" No languages");
|
||||
continue;
|
||||
}
|
||||
|
||||
println!(" Languages:");
|
||||
for lang in script.languages {
|
||||
println!(" {}", lang.tag);
|
||||
}
|
||||
}
|
||||
|
||||
let mut features: Vec<_> = table.features.into_iter().map(|f| f.tag).collect();
|
||||
features.dedup();
|
||||
println!(" Features:");
|
||||
for feature in features {
|
||||
println!(" {}", feature);
|
||||
}
|
||||
}
|
||||
292
third-party/vendor/ttf-parser-0.15.2/examples/font2svg.rs
vendored
Normal file
292
third-party/vendor/ttf-parser-0.15.2/examples/font2svg.rs
vendored
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
use std::path::PathBuf;
|
||||
use std::io::Write;
|
||||
|
||||
use ttf_parser as ttf;
|
||||
|
||||
const FONT_SIZE: f64 = 128.0;
|
||||
const COLUMNS: u32 = 100;
|
||||
|
||||
const HELP: &str = "\
|
||||
Usage:
|
||||
font2svg font.ttf out.svg
|
||||
font2svg --variations 'wght:500;wdth:200' font.ttf out.svg
|
||||
";
|
||||
|
||||
struct Args {
|
||||
#[allow(dead_code)] variations: Vec<ttf::Variation>,
|
||||
ttf_path: PathBuf,
|
||||
svg_path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = match parse_args() {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("Error: {}.", e);
|
||||
print!("{}", HELP);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = process(args) {
|
||||
eprintln!("Error: {}.", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_args() -> Result<Args, Box<dyn std::error::Error>> {
|
||||
let mut args = pico_args::Arguments::from_env();
|
||||
|
||||
if args.contains(["-h", "--help"]) {
|
||||
print!("{}", HELP);
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
let variations = args.opt_value_from_fn("--variations", parse_variations)?;
|
||||
let free = args.finish();
|
||||
if free.len() != 2 {
|
||||
return Err("invalid number of arguments".into());
|
||||
}
|
||||
|
||||
Ok(Args {
|
||||
variations: variations.unwrap_or_default(),
|
||||
ttf_path: PathBuf::from(&free[0]),
|
||||
svg_path: PathBuf::from(&free[1]),
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_variations(s: &str) -> Result<Vec<ttf::Variation>, &'static str> {
|
||||
let mut variations = Vec::new();
|
||||
for part in s.split(';') {
|
||||
let mut iter = part.split(':');
|
||||
|
||||
let axis = iter.next().ok_or("failed to parse a variation")?;
|
||||
let axis = ttf::Tag::from_bytes_lossy(axis.as_bytes());
|
||||
|
||||
let value = iter.next().ok_or("failed to parse a variation")?;
|
||||
let value: f32 = value.parse().map_err(|_| "failed to parse a variation")?;
|
||||
|
||||
variations.push(ttf::Variation { axis, value });
|
||||
}
|
||||
|
||||
Ok(variations)
|
||||
}
|
||||
|
||||
fn process(args: Args) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let font_data = std::fs::read(&args.ttf_path)?;
|
||||
|
||||
// Exclude IO operations.
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut face = ttf::Face::from_slice(&font_data, 0)?;
|
||||
if face.is_variable() {
|
||||
#[cfg(feature = "variable-fonts")] {
|
||||
for variation in args.variations {
|
||||
face.set_variation(variation.axis, variation.value)
|
||||
.ok_or("failed to create variation coordinates")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let units_per_em = face.units_per_em();
|
||||
let scale = FONT_SIZE / units_per_em as f64;
|
||||
|
||||
let cell_size = face.height() as f64 * FONT_SIZE / units_per_em as f64;
|
||||
let rows = (face.number_of_glyphs() as f64 / COLUMNS as f64).ceil() as u32;
|
||||
|
||||
let mut svg = xmlwriter::XmlWriter::with_capacity(
|
||||
face.number_of_glyphs() as usize * 512,
|
||||
xmlwriter::Options::default(),
|
||||
);
|
||||
svg.start_element("svg");
|
||||
svg.write_attribute("xmlns", "http://www.w3.org/2000/svg");
|
||||
svg.write_attribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
|
||||
svg.write_attribute_fmt(
|
||||
"viewBox",
|
||||
format_args!("{} {} {} {}", 0, 0, cell_size * COLUMNS as f64, cell_size * rows as f64),
|
||||
);
|
||||
|
||||
draw_grid(face.number_of_glyphs(), cell_size, &mut svg);
|
||||
|
||||
let mut path_buf = String::with_capacity(256);
|
||||
let mut row = 0;
|
||||
let mut column = 0;
|
||||
for id in 0..face.number_of_glyphs() {
|
||||
let x = column as f64 * cell_size;
|
||||
let y = row as f64 * cell_size;
|
||||
|
||||
svg.start_element("text");
|
||||
svg.write_attribute("x", &(x + 2.0));
|
||||
svg.write_attribute("y", &(y + cell_size - 4.0));
|
||||
svg.write_attribute("font-size", "36");
|
||||
svg.write_attribute("fill", "gray");
|
||||
svg.write_text_fmt(format_args!("{}", &id));
|
||||
svg.end_element();
|
||||
|
||||
if let Some(img) = face.glyph_raster_image(ttf::GlyphId(id), std::u16::MAX) {
|
||||
svg.start_element("image");
|
||||
svg.write_attribute("x", &(x + 2.0 + img.x as f64));
|
||||
svg.write_attribute("y", &(y - img.y as f64));
|
||||
svg.write_attribute("width", &img.width);
|
||||
svg.write_attribute("height", &img.height);
|
||||
svg.write_attribute_raw("xlink:href", |buf| {
|
||||
buf.extend_from_slice(b"data:image/png;base64, ");
|
||||
|
||||
let mut enc = base64::write::EncoderWriter::new(buf, base64::STANDARD);
|
||||
enc.write_all(img.data).unwrap();
|
||||
enc.finish().unwrap();
|
||||
});
|
||||
svg.end_element();
|
||||
} else if let Some(img) = face.glyph_svg_image(ttf::GlyphId(id)) {
|
||||
svg.start_element("image");
|
||||
svg.write_attribute("x", &(x + 2.0));
|
||||
svg.write_attribute("y", &(y + cell_size));
|
||||
svg.write_attribute("width", &cell_size);
|
||||
svg.write_attribute("height", &cell_size);
|
||||
svg.write_attribute_raw("xlink:href", |buf| {
|
||||
buf.extend_from_slice(b"data:image/svg+xml;base64, ");
|
||||
|
||||
let mut enc = base64::write::EncoderWriter::new(buf, base64::STANDARD);
|
||||
enc.write_all(img).unwrap();
|
||||
enc.finish().unwrap();
|
||||
});
|
||||
svg.end_element();
|
||||
} else {
|
||||
glyph_to_path(
|
||||
x,
|
||||
y,
|
||||
&face,
|
||||
ttf::GlyphId(id),
|
||||
cell_size,
|
||||
scale,
|
||||
&mut svg,
|
||||
&mut path_buf,
|
||||
);
|
||||
}
|
||||
|
||||
column += 1;
|
||||
if column == COLUMNS {
|
||||
column = 0;
|
||||
row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
println!("Elapsed: {}ms", now.elapsed().as_micros() as f64 / 1000.0);
|
||||
|
||||
std::fs::write(&args.svg_path, &svg.end_document())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_grid(
|
||||
n_glyphs: u16,
|
||||
cell_size: f64,
|
||||
svg: &mut xmlwriter::XmlWriter,
|
||||
) {
|
||||
let columns = COLUMNS;
|
||||
let rows = (n_glyphs as f64 / columns as f64).ceil() as u32;
|
||||
|
||||
let width = columns as f64 * cell_size;
|
||||
let height = rows as f64 * cell_size;
|
||||
|
||||
svg.start_element("path");
|
||||
svg.write_attribute("fill", "none");
|
||||
svg.write_attribute("stroke", "black");
|
||||
svg.write_attribute("stroke-width", "5");
|
||||
|
||||
let mut path = String::with_capacity(256);
|
||||
|
||||
use std::fmt::Write;
|
||||
let mut x = 0.0;
|
||||
for _ in 0..=columns {
|
||||
write!(&mut path, "M {} {} L {} {} ", x, 0.0, x, height).unwrap();
|
||||
x += cell_size;
|
||||
}
|
||||
|
||||
let mut y = 0.0;
|
||||
for _ in 0..=rows {
|
||||
write!(&mut path, "M {} {} L {} {} ", 0.0, y, width, y).unwrap();
|
||||
y += cell_size;
|
||||
}
|
||||
|
||||
path.pop();
|
||||
|
||||
svg.write_attribute("d", &path);
|
||||
svg.end_element();
|
||||
}
|
||||
|
||||
fn glyph_to_path(
|
||||
x: f64,
|
||||
y: f64,
|
||||
face: &ttf::Face,
|
||||
glyph_id: ttf::GlyphId,
|
||||
cell_size: f64,
|
||||
scale: f64,
|
||||
svg: &mut xmlwriter::XmlWriter,
|
||||
path_buf: &mut String,
|
||||
) {
|
||||
path_buf.clear();
|
||||
let mut builder = Builder(path_buf);
|
||||
let bbox = match face.outline_glyph(glyph_id, &mut builder) {
|
||||
Some(v) => v,
|
||||
None => return,
|
||||
};
|
||||
if !path_buf.is_empty() {
|
||||
path_buf.pop(); // remove trailing space
|
||||
}
|
||||
|
||||
let bbox_w = (bbox.x_max as f64 - bbox.x_min as f64) * scale;
|
||||
let dx = (cell_size - bbox_w) / 2.0;
|
||||
let y = y + cell_size + face.descender() as f64 * scale;
|
||||
|
||||
let transform = format!("matrix({} 0 0 {} {} {})", scale, -scale, x + dx, y);
|
||||
|
||||
svg.start_element("path");
|
||||
svg.write_attribute("d", path_buf);
|
||||
svg.write_attribute("transform", &transform);
|
||||
svg.end_element();
|
||||
|
||||
{
|
||||
let bbox_h = (bbox.y_max as f64 - bbox.y_min as f64) * scale;
|
||||
let bbox_x = x + dx + bbox.x_min as f64 * scale;
|
||||
let bbox_y = y - bbox.y_max as f64 * scale;
|
||||
|
||||
svg.start_element("rect");
|
||||
svg.write_attribute("x", &bbox_x);
|
||||
svg.write_attribute("y", &bbox_y);
|
||||
svg.write_attribute("width", &bbox_w);
|
||||
svg.write_attribute("height", &bbox_h);
|
||||
svg.write_attribute("fill", "none");
|
||||
svg.write_attribute("stroke", "green");
|
||||
svg.end_element();
|
||||
}
|
||||
}
|
||||
|
||||
struct Builder<'a>(&'a mut String);
|
||||
|
||||
impl ttf::OutlineBuilder for Builder<'_> {
|
||||
fn move_to(&mut self, x: f32, y: f32) {
|
||||
use std::fmt::Write;
|
||||
write!(self.0, "M {} {} ", x, y).unwrap()
|
||||
}
|
||||
|
||||
fn line_to(&mut self, x: f32, y: f32) {
|
||||
use std::fmt::Write;
|
||||
write!(self.0, "L {} {} ", x, y).unwrap()
|
||||
}
|
||||
|
||||
fn quad_to(&mut self, x1: f32, y1: f32, x: f32, y: f32) {
|
||||
use std::fmt::Write;
|
||||
write!(self.0, "Q {} {} {} {} ", x1, y1, x, y).unwrap()
|
||||
}
|
||||
|
||||
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x: f32, y: f32) {
|
||||
use std::fmt::Write;
|
||||
write!(self.0, "C {} {} {} {} {} {} ", x1, y1, x2, y2, x, y).unwrap()
|
||||
}
|
||||
|
||||
fn close(&mut self) {
|
||||
self.0.push_str("Z ")
|
||||
}
|
||||
}
|
||||
18
third-party/vendor/ttf-parser-0.15.2/examples/wasm/README.md
vendored
Normal file
18
third-party/vendor/ttf-parser-0.15.2/examples/wasm/README.md
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# ttf-parser as a WebAssembly module
|
||||
|
||||
## Build
|
||||
|
||||
```sh
|
||||
rustup target add wasm32-unknown-unknown
|
||||
|
||||
cargo build --target wasm32-unknown-unknown --release --manifest-path ../../c-api/Cargo.toml
|
||||
cp ../../c-api/target/wasm32-unknown-unknown/release/ttfparser.wasm .
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
You can use any webserver that can serve `index.html`. Here is a Python example:
|
||||
|
||||
```sh
|
||||
python -m http.server
|
||||
```
|
||||
BIN
third-party/vendor/ttf-parser-0.15.2/examples/wasm/TTC.ttc
vendored
Normal file
BIN
third-party/vendor/ttf-parser-0.15.2/examples/wasm/TTC.ttc
vendored
Normal file
Binary file not shown.
67
third-party/vendor/ttf-parser-0.15.2/examples/wasm/index.html
vendored
Normal file
67
third-party/vendor/ttf-parser-0.15.2/examples/wasm/index.html
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<h2>ttf-parser in WebAssembly</h2>
|
||||
<p><small>(supports font files drag and drop)</small></p>
|
||||
<p><span id="fileName">TTC.ttc</span>:</p>
|
||||
<p><code>ttfp_fonts_in_collection():</code> <code id="fontsInCollection"></code></p>
|
||||
<p><code>ttfp_is_variable():</code> <code id="isVariable"></code></p>
|
||||
<p><code>ttfp_get_weight():</code> <code id="fontWeight"></code></p>
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
let wasm;
|
||||
|
||||
function update(fontBlob) {
|
||||
const exports = wasm.instance.exports;
|
||||
|
||||
// How our heaped is structured, as ttf-parser doesn't allocate anything
|
||||
// it is all ours and we can decide how to use it
|
||||
const heapStart = exports.__heap_base.value;
|
||||
const fontHandlerAddress = heapStart;
|
||||
const fontHandlerLength = exports.ttfp_face_size_of();
|
||||
const fontDataAddress = heapStart + fontHandlerLength;
|
||||
const fontDataLength = fontBlob.length;
|
||||
|
||||
// Copy the fetched blob into WebAssembly machine
|
||||
const heapu8 = new Uint8Array(exports.memory.buffer);
|
||||
heapu8.set(fontBlob, fontDataAddress);
|
||||
|
||||
fontsInCollection.textContent = exports.ttfp_fonts_in_collection(fontDataAddress, fontDataLength);
|
||||
|
||||
// Create font handler
|
||||
exports.ttfp_face_init(fontDataAddress, fontDataLength, 0/*face index*/, fontHandlerAddress);
|
||||
|
||||
isVariable.textContent = exports.ttfp_is_variable(fontHandlerAddress);
|
||||
fontWeight.textContent = exports.ttfp_get_weight(fontHandlerAddress);
|
||||
}
|
||||
|
||||
fetch('ttfparser.wasm').then(x => x.arrayBuffer()).then(WebAssembly.instantiate).then(result => {
|
||||
wasm = result;
|
||||
// Extend wasm machine heap once now that we are here, each page is 64kb
|
||||
wasm.instance.exports.memory.grow(400);
|
||||
|
||||
// Could be done in parallel using Promise.all
|
||||
fetch('TTC.ttc').then(x => x.arrayBuffer()).then(result => {
|
||||
update(new Uint8Array(result));
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener('dragover', e => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
}, false);
|
||||
document.addEventListener('dragleave', e => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
}, false);
|
||||
document.addEventListener('drop', e => {
|
||||
e.stopPropagation(); e.preventDefault();
|
||||
handleFontUpdate(e.dataTransfer.files[0]);
|
||||
});
|
||||
// document.addEventListener('paste', e => {
|
||||
// handleFontUpdate(e.clipboardData.files[0]);
|
||||
// });
|
||||
function handleFontUpdate(file) {
|
||||
if (!file) return;
|
||||
fileName.textContent = file.name;
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => update(new Uint8Array(reader.result)));
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue