Vendor things

This commit is contained in:
John Doty 2024-03-08 11:03:01 -08:00
parent 5deceec006
commit 977e3c17e5
19434 changed files with 10682014 additions and 0 deletions

View file

@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"4991589f97c0b45b6a65669ac834c1e36b63b6fc27aa3cdd8efad8ab018c94c7","Cargo.toml":"ec6f15394241acb2d0118504e9797130c0324d4ceff46218ce31f1a2ed856850","LICENSE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","README.md":"da6bee2fc99fc8f96283e3382d85330569b59b97960558aed28a665c2bac7ba1","src/codepoint_ids.rs":"dad69e55584e9b3a9c28d13c6b9fe50e0190e3bd9966662a6532e361d2efb7a4","src/err.rs":"cf565d2c68afc5261b46d707d760636d9ac9c8a55b2653024544ccbb2c035572","src/font.rs":"a586cb6d71e99b8ffd0f6a80be2278841cfc12f65b30cfaa6c342a2131e46d74","src/font_arc.rs":"791d0fd55cf13624577a77d63fc398f890f143b97df34763e8daed900d4d6344","src/glyph.rs":"02017141b7f5a6982494f6a708e6f843d4be8da784b9322ba585e4416fcc0b9e","src/lib.rs":"b5f6926f64887d85b74ef5e9f4a797d67777df19688d7ccd582fc0d848d76efd","src/nostd_float.rs":"2bcf37dbc84b917a118cf3675161090f022bba7662e07dbfe7f0db4bfa2a1452","src/outlined.rs":"5c9ca46a8af0cef450d209b3a0d56ca3128ece7280b4c93599ef9ee421c64872","src/scale.rs":"c712fb8388b9f86ea20f50f86a5d9b83448905816fdf908f3d4586d78f206c94","src/ttfp.rs":"3a9fe6ba373db0a0b93b41986f4a45d0eb5a92bf59c61d6cd20b009562beda63","src/ttfp/outliner.rs":"e4ef3695155e5da8ab7260eeac5ac3e9e5f2d64d588a5ee625571e0eed63154c","src/ttfp/variable.rs":"ee1293438364f60fbc40829dbec33d2d0a884e3e8173cb68aa282c9f0a9e822e","src/variable.rs":"48d3b514f22b279e4b5ca82776167b954856f4419759446c98a3d32d17ce3b20"},"package":"80179d7dd5d7e8c285d67c4a1e652972a92de7475beddfb92028c76463b13225"}

View file

@ -0,0 +1,95 @@
# v0.2.23
* Update _ttf-parser_ to `0.20`.
# 0.2.22
* Add `v2::GlyphImage` and `Font::glyph_raster_image2` to expose width and height info.
* Deprecate `Font::glyph_raster_image` & `GlyphImage`.
* Improve `OutlinedGlyph::draw` documentation.
# 0.2.21
* Update _ttf-parser_ to `0.19`.
* Add `GlyphImageFormat` variants `BitmapMono`, `BitmapMonoPacked`, `BitmapGray2`, `BitmapGray2Packed`,
`BitmapGray4`, `BitmapGray4Packed`, `BitmapGray8`, `BitmapPremulBgra32`.
* `Font::h_advance_unscaled`, `h_side_bearing_unscaled`, `v_advance_unscaled`, `v_side_bearing_unscaled`
and related `ScaleFont` methods now return `0.0` if the font does not define that value.
Previously calls would panic when fonts lacked support.
* Use edition 2021.
# 0.2.20
* Add `FontVec::as_slice`, `FontVec::into_vec`.
# 0.2.19
* Update _ttf-parser_ to `0.18`.
# 0.2.18
* Update _ttf-parser_ to `0.17`.
# 0.2.17
* Add `VariableFont` trait implemented by `FontRef` & `FontVec`.
Provides `variations` & `set_variation` functions.
* Add default enabled feature `variable-fonts`.
# 0.2.16
* Add `Font::pt_to_px_scale` to ease converting point size to `PxScale`.
* Add `PxScale::round`.
# 0.2.15
* Fix some font outlines by always trying to "close" them at the end. Fixes _Cantarell-VF.otf_ outlining.
# 0.2.14
* Update _ttf-parser_ to `0.15`.
# 0.2.13
* Update _ttf-parser_ to `0.14`.
# 0.2.12
* Update _owned-ttf-parser_ to `0.13.2`.
* Pre-parse cmap & kern subtables on all `Font` variants at initialization. This provides
much faster `glyph_id` & `kern` method performance, results in 25-30% faster layout
benchmark performance.
# 0.2.11
* `Font::outline` will return `None` for rare invalid/empty glyph bounds instead of panicking.
* Add `Font::glyph_raster_image` for color emoji fonts.
# 0.2.10
* Update _ttf-parser_ to `0.12`.
# 0.2.9
* Update _ttf-parser_ to `0.11`.
# 0.2.8
* Add fallback bounding box calculation for malformed font glyphs with zero sized boxes.
* Update _ttf-parser_ to `0.10`.
# 0.2.7
* Update _ttf-parser_ to `0.9`.
# 0.2.6
* Add `Font::codepoint_ids` method for iterating over `(GlyphId, char)` pairs.
* Clarify documentation.
# 0.2.5
* Add `Font::units_per_em` + documentation on unscaled font units.
* Update _ttf-parser_ to `0.8`.
# 0.2.4
* Update _ttf-parser_ to `0.7` adding CID font support.
# 0.2.3
* Add `v_advance` & `v_side_bearing` methods to `ScaleFont` + `_unscaled` variants to `Font`.
# 0.2.2
* Add `Font::glyph_bounds` method, similar to glyph_brush's `glyph_bounds` but for a single glyph.
* Rename `OutlinedGlyph::bounds` to `OutlinedGlyph::px_bounds` for clarity.
# 0.2.1
* Update _ttf-parser_ to `0.6`.
# 0.2
* Add `_unscaled` suffix to `Font` trait methods that deal with unscaled metrics.
This helps distinguish `ScaleFont`'s scaled metrics and can avoid unintended behaviour.
* Rename "libm-math" -> "libm" for consistency with _ab_glyph_rasterizer_.
# 0.1
* Implement fast glyph layout, outline & drawing primitives.

56
third-party/vendor/ab_glyph/Cargo.toml vendored Normal file
View file

@ -0,0 +1,56 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
name = "ab_glyph"
version = "0.2.23"
authors = ["Alex Butler <alexheretic@gmail.com>"]
description = "API for loading, scaling, positioning and rasterizing OpenType font glyphs."
readme = "README.md"
keywords = [
"text",
"ttf",
"truetype",
"otf",
"opentype",
]
license = "Apache-2.0"
repository = "https://github.com/alexheretic/ab-glyph"
[dependencies.ab_glyph_rasterizer]
version = "0.1.2"
default-features = false
[dependencies.libm]
version = "0.2.1"
optional = true
[dependencies.owned_ttf_parser]
version = "0.20"
default-features = false
[dev-dependencies]
[features]
default = [
"std",
"variable-fonts",
]
libm = [
"dep:libm",
"ab_glyph_rasterizer/libm",
]
std = [
"owned_ttf_parser/default",
"ab_glyph_rasterizer/default",
]
variable-fonts = ["owned_ttf_parser/variable-fonts"]

176
third-party/vendor/ab_glyph/LICENSE vendored Normal file
View file

@ -0,0 +1,176 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

42
third-party/vendor/ab_glyph/README.md vendored Normal file
View file

@ -0,0 +1,42 @@
ab_glyph
[![crates.io](https://img.shields.io/crates/v/ab_glyph.svg)](https://crates.io/crates/ab_glyph)
[![Documentation](https://docs.rs/ab_glyph/badge.svg)](https://docs.rs/ab_glyph)
========
Fast API for loading, scaling, positioning and rasterizing OpenType font glyphs.
```rust
use ab_glyph::{FontRef, Font, Glyph, point};
let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
// Get a glyph for 'q' with a scale & position.
let q_glyph: Glyph = font.glyph_id('q').with_scale_and_position(24.0, point(100.0, 0.0));
// Draw it.
if let Some(q) = font.outline_glyph(q_glyph) {
q.draw(|x, y, c| { /* draw pixel `(x, y)` with coverage: `c` */ });
}
```
## no_std
no_std environments are supported using `alloc` & [`libm`](https://github.com/rust-lang/libm).
```toml
ab_glyph = { default-features = false, features = ["libm"] }
```
## Comparison with [`rusttype`](https://gitlab.redox-os.org/redox-os/rusttype)
ab_glyph is a rewrite of rusttype made after I added .otf support for the latter and saw some performance issue's
with the rusttype API.
ab_glyph is a more focussed API concentrating on high performance for both .ttf & .otf fonts.
When laying out glyphs into paragraph, ab_glyph is faster than rusttype using .ttf fonts &
**much** faster for .otf fonts.
```
group ab-glyph rusttype 0.9
----- -------- ------------
layout_a_sentence (exo2-ttf) 1.00 11.1±0.08µs 1.56 17.3±0.14µs
layout_a_sentence (exo2-otf) 1.00 11.1±0.12µs 8.85 98.1±1.17µs
```
_Note: Numbers from May-2020 benchmarks, ab-glyph performance is also expected to have improved since then_.

View file

@ -0,0 +1,24 @@
use crate::GlyphId;
use alloc::boxed::Box;
use core::{fmt, iter};
pub struct CodepointIdIter<'a> {
pub(crate) inner: Box<dyn Iterator<Item = (GlyphId, char)> + 'a>,
}
impl<'a> Iterator for CodepointIdIter<'a> {
type Item = (GlyphId, char);
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl iter::FusedIterator for CodepointIdIter<'_> {}
impl fmt::Debug for CodepointIdIter<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "CodepointIdIter")
}
}

14
third-party/vendor/ab_glyph/src/err.rs vendored Normal file
View file

@ -0,0 +1,14 @@
use core::fmt;
/// Invalid font data error.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InvalidFont;
impl fmt::Display for InvalidFont {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "InvalidFont")
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidFont {}

318
third-party/vendor/ab_glyph/src/font.rs vendored Normal file
View file

@ -0,0 +1,318 @@
use crate::{
point, v2, Glyph, GlyphId, Outline, OutlinedGlyph, PxScale, PxScaleFont, Rect, ScaleFont,
};
/// Functionality required from font data.
///
/// See also [`FontArc`](struct.FontArc.html), [`FontRef`](struct.FontRef.html)
/// and [`FontVec`](struct.FontVec.html).
///
/// ## Units
///
/// Units of unscaled accessors are "font units", which is an arbitrary unit
/// defined by the font. See [`Font::units_per_em`].
///
/// ab_glyph uses a non-standard scale [`PxScale`] which is the pixel height
/// of the text. See [`Font::pt_to_px_scale`] to convert standard point sizes.
pub trait Font {
/// Get the size of the font unit
///
/// This returns "font units per em", where 1em is a base unit of font scale
/// (typically the width of a capital 'M').
///
/// Returns `None` in case the font unit size exceeds the expected range.
/// See [`Face::units_per_em`](https://docs.rs/ttf-parser/latest/ttf_parser/struct.Face.html#method.units_per_em).
///
/// May be used to calculate [`PxScale`] from pt size, see [`Font::pt_to_px_scale`].
fn units_per_em(&self) -> Option<f32>;
/// Converts pt units into [`PxScale`].
///
/// Note: To handle a screen scale factor multiply it to the `pt_size` argument.
///
/// Returns `None` in case the [`Font::units_per_em`] unit size exceeds the expected range.
///
/// ## Point size (pt)
///
/// Font sizes are typically specified in "points". According to the modern
/// standard, 1pt = 1/72in. The "point size" of a font is the number of points
/// per em.
///
/// The DPI (dots-per-inch) of a screen depends on the screen in question;
/// 96 DPI is often considered the "standard". For high-DPI displays the
/// DPI may be specified directly or one may multiply 96 by a scale-factor.
///
/// Thus, for example, a 10pt font on a 96 pixels-per-inch display has
/// 10 / 72 * 96 = 13.333... pixels-per-em. If we divide this number by
/// `units_per_em` we then get a scaling factor: pixels-per-font-unit.
///
/// Note however that since [`PxScale`] values are relative to the text height,
/// one further step is needed: multiply by [`Font::height_unscaled`].
fn pt_to_px_scale(&self, pt_size: f32) -> Option<PxScale> {
let px_per_em = pt_size * (96.0 / 72.0);
let units_per_em = self.units_per_em()?;
let height = self.height_unscaled();
Some(PxScale::from(px_per_em * height / units_per_em))
}
/// Unscaled glyph ascent.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn ascent_unscaled(&self) -> f32;
/// Unscaled glyph descent.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn descent_unscaled(&self) -> f32;
/// Unscaled height `ascent - descent`.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
#[inline]
fn height_unscaled(&self) -> f32 {
self.ascent_unscaled() - self.descent_unscaled()
}
/// Unscaled line gap.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn line_gap_unscaled(&self) -> f32;
/// Lookup a `GlyphId` matching a given `char`.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn glyph_id(&self, c: char) -> GlyphId;
/// Unscaled horizontal advance for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn h_advance_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled horizontal side bearing for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled vertical advance for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn v_advance_unscaled(&self, id: GlyphId) -> f32;
/// Unscaled vertical side bearing for a given glyph id.
///
/// Returns `0.0` if the font does not define this value.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32;
/// Returns additional unscaled kerning to apply for a particular pair of glyph ids.
///
/// Scaling can be done with [as_scaled](trait.Font.html#method.as_scaled).
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32;
/// Compute unscaled glyph outline curves & bounding box.
fn outline(&self, id: GlyphId) -> Option<Outline>;
/// The number of glyphs present in this font. Glyph identifiers for this
/// font will always be in the range `0..self.glyph_count()`
fn glyph_count(&self) -> usize;
/// Returns an iterator of all distinct `(GlyphId, char)` pairs. Not ordered.
///
/// # Example
/// ```
/// # use ab_glyph::{Font, FontRef, GlyphId};
/// # use std::collections::HashMap;
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// // Iterate over pairs, each id will appear at most once.
/// let mut codepoint_ids = font.codepoint_ids();
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(408), '\r')));
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(1), ' ')));
/// assert_eq!(codepoint_ids.next(), Some((GlyphId(75), '!')));
///
/// // Build a lookup map for all ids
/// let map: HashMap<_, _> = font.codepoint_ids().collect();
/// assert_eq!(map.get(&GlyphId(75)), Some(&'!'));
/// # assert_eq!(map.len(), 908);
/// # Ok(()) }
/// ```
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_>;
/// Returns a pre-rendered image of the glyph.
///
/// This is normally only present when an outline is not sufficient to describe the glyph, such
/// as emojis (particularly color ones). The `pixel_size` parameter is in pixels per em, and will be
/// used to select between multiple possible images (if present); the returned image will
/// likely not match this value, requiring you to scale it to match the target resolution.
/// To get the largest image use `u16::MAX`.
#[allow(deprecated)]
#[deprecated(
since = "0.2.22",
note = "Deprecated in favor of `glyph_raster_image2`"
)]
fn glyph_raster_image(&self, id: GlyphId, pixel_size: u16) -> Option<crate::GlyphImage> {
self.glyph_raster_image2(id, pixel_size)
.map(|i| crate::GlyphImage {
origin: i.origin,
scale: i.pixels_per_em.into(),
data: i.data,
format: i.format,
})
}
/// Returns a pre-rendered image of the glyph.
///
/// This is normally only present when an outline is not sufficient to describe the glyph, such
/// as emojis (particularly color ones). The `pixel_size` parameter is in pixels per em, and will be
/// used to select between multiple possible images (if present); the returned image will
/// likely not match this value, requiring you to scale it to match the target resolution.
/// To get the largest image use `u16::MAX`.
fn glyph_raster_image2(&self, id: GlyphId, pixel_size: u16) -> Option<v2::GlyphImage>;
/// Returns the layout bounds of this glyph. These are different to the outline `px_bounds()`.
///
/// Horizontally: Glyph position +/- h_advance/h_side_bearing.
/// Vertically: Glyph position +/- ascent/descent.
#[inline]
fn glyph_bounds(&self, glyph: &Glyph) -> Rect
where
Self: Sized,
{
let sf = self.as_scaled(glyph.scale);
let pos = glyph.position;
Rect {
min: point(pos.x - sf.h_side_bearing(glyph.id), pos.y - sf.ascent()),
max: point(pos.x + sf.h_advance(glyph.id), pos.y - sf.descent()),
}
}
/// Compute glyph outline ready for drawing.
#[inline]
fn outline_glyph(&self, glyph: Glyph) -> Option<OutlinedGlyph>
where
Self: Sized,
{
let outline = self.outline(glyph.id)?;
let scale_factor = self.as_scaled(glyph.scale).scale_factor();
Some(OutlinedGlyph::new(glyph, outline, scale_factor))
}
/// Construct a [`PxScaleFontRef`](struct.PxScaleFontRef.html) by associating with the
/// given pixel `scale`.
///
/// # Example
/// ```
/// # use ab_glyph::{Font, FontRef, PxScale, ScaleFont};
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.descent_unscaled(), -201.0);
///
/// assert_eq!(font.as_scaled(24.0).descent(), -4.02);
/// assert_eq!(font.as_scaled(50.0).descent(), -8.375);
/// # Ok(()) }
/// ```
#[inline]
fn as_scaled<S: Into<PxScale>>(&self, scale: S) -> PxScaleFont<&'_ Self>
where
Self: Sized,
{
PxScaleFont {
font: self,
scale: scale.into(),
}
}
/// Move into a [`PxScaleFont`](struct.PxScaleFont.html) associated with the
/// given pixel `scale`.
#[inline]
fn into_scaled<S: Into<PxScale>>(self, scale: S) -> PxScaleFont<Self>
where
Self: core::marker::Sized,
{
PxScaleFont {
font: self,
scale: scale.into(),
}
}
}
impl<F: Font> Font for &F {
#[inline]
fn units_per_em(&self) -> Option<f32> {
(*self).units_per_em()
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
(*self).ascent_unscaled()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
(*self).descent_unscaled()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
(*self).line_gap_unscaled()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
(*self).glyph_id(c)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
(*self).h_advance_unscaled(id)
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
(*self).h_side_bearing_unscaled(id)
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
(*self).v_advance_unscaled(id)
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
(*self).v_side_bearing_unscaled(id)
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
(*self).kern_unscaled(first, second)
}
#[inline]
fn outline(&self, glyph: GlyphId) -> Option<Outline> {
(*self).outline(glyph)
}
#[inline]
fn glyph_count(&self) -> usize {
(*self).glyph_count()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
(*self).codepoint_ids()
}
#[inline]
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
(*self).glyph_raster_image2(id, size)
}
}

View file

@ -0,0 +1,162 @@
use crate::{v2, Font, FontRef, FontVec, GlyphId, InvalidFont, Outline};
use alloc::sync::Arc;
use core::fmt;
/// `Font` implementor that wraps another concrete `Font + 'static` type storing in an `Arc`.
///
/// Provides convenient type erasure & cheap clones (particularly for `FontVec`).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontArc};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontArc::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
#[derive(Clone)]
pub struct FontArc(Arc<dyn Font + Send + Sync + 'static>);
impl FontArc {
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// # let font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// # let font_vec = FontVec::try_from_vec(font_data)?;
/// let font_arc = FontArc::new(font_vec);
/// # Ok(()) }
/// ```
#[inline]
pub fn new<F: Font + Send + Sync + 'static>(font: F) -> Self {
Self(Arc::new(font))
}
/// Creates an `FontArc` from owned data.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontArc::try_from_vec(owned_font_data)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec(data: Vec<u8>) -> Result<Self, InvalidFont> {
Ok(FontVec::try_from_vec(data)?.into())
}
/// Creates an `FontArc` from a byte-slice.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font = FontArc::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice(data: &'static [u8]) -> Result<Self, InvalidFont> {
Ok(FontRef::try_from_slice(data)?.into())
}
}
impl fmt::Debug for FontArc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontArc")
}
}
impl Font for FontArc {
#[inline]
fn units_per_em(&self) -> Option<f32> {
self.0.units_per_em()
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
self.0.ascent_unscaled()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
self.0.descent_unscaled()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
self.0.line_gap_unscaled()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
self.0.glyph_id(c)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0.h_advance_unscaled(id)
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0.h_side_bearing_unscaled(id)
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0.v_advance_unscaled(id)
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0.v_side_bearing_unscaled(id)
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
self.0.kern_unscaled(first, second)
}
#[inline]
fn outline(&self, glyph: GlyphId) -> Option<Outline> {
self.0.outline(glyph)
}
#[inline]
fn glyph_count(&self) -> usize {
self.0.glyph_count()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
self.0.codepoint_ids()
}
#[inline]
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
self.0.glyph_raster_image2(id, size)
}
}
impl From<FontVec> for FontArc {
#[inline]
fn from(font: FontVec) -> Self {
Self::new(font)
}
}
impl From<FontRef<'static>> for FontArc {
#[inline]
fn from(font: FontRef<'static>) -> Self {
Self::new(font)
}
}
impl From<Arc<dyn Font + Send + Sync + 'static>> for FontArc {
#[inline]
fn from(font: Arc<dyn Font + Send + Sync + 'static>) -> Self {
Self(font)
}
}

171
third-party/vendor/ab_glyph/src/glyph.rs vendored Normal file
View file

@ -0,0 +1,171 @@
use crate::{Point, PxScale};
/// Glyph id.
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef, GlyphId};
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// let q_id: GlyphId = font.glyph_id('q');
/// # Ok(()) }
/// ```
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GlyphId(pub u16);
impl GlyphId {
/// Construct a `Glyph` with given scale & position.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let glyph = font.glyph_id('z').with_scale_and_position(24.0, point(100.0, 0.0));
/// ```
#[inline]
pub fn with_scale_and_position<S: Into<PxScale>, P: Into<Point>>(
self,
scale: S,
position: P,
) -> Glyph {
Glyph {
id: self,
scale: scale.into(),
position: position.into(),
}
}
/// Construct a `Glyph` with given scale and position `point(0.0, 0.0)`.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let glyph = font.glyph_id('w').with_scale(48.0);
/// ```
#[inline]
pub fn with_scale<S: Into<PxScale>>(self, scale: S) -> Glyph {
self.with_scale_and_position(scale, Point::default())
}
}
/// A glyph with pixel scale & position.
#[derive(Clone, Debug, PartialEq, PartialOrd)]
pub struct Glyph {
/// Glyph id.
pub id: GlyphId,
/// Pixel scale of this glyph.
pub scale: PxScale,
/// Position of this glyph.
pub position: Point,
}
/// Old version of [`v2::GlyphImage`].
#[deprecated(since = "0.2.22", note = "Deprecated in favor of `v2::GlyphImage`")]
#[derive(Debug, Clone)]
pub struct GlyphImage<'a> {
/// Offset of the image from the normal origin (top at the baseline plus
/// ascent), measured in pixels at the image's current scale.
pub origin: Point,
/// Current scale of the image in pixels per em.
pub scale: f32,
/// Raw image data, not a bitmap in the case of [`GlyphImageFormat::Png`] format.
pub data: &'a [u8],
/// Format of the raw data.
pub format: GlyphImageFormat,
}
pub mod v2 {
use crate::{GlyphImageFormat, Point};
/// A pre-rendered image of a glyph, usually used for emojis or other glyphs
/// that can't be represented only using an outline.
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct GlyphImage<'a> {
/// Offset of the image from the normal origin (top at the baseline plus
/// ascent), measured in pixels at the image's current scale.
pub origin: Point,
/// Image width.
///
/// It doesn't guarantee that this value is the same as set in the `data` in the case of
/// [`GlyphImageFormat::Png`] format.
pub width: u16,
/// Image height.
///
/// It doesn't guarantee that this value is the same as set in the `data` in the case of
/// [`GlyphImageFormat::Png`] format.
pub height: u16,
/// Pixels per em of the selected strike.
pub pixels_per_em: u16,
/// Raw image data, see [`format`](GlyphImageFormat).
pub data: &'a [u8],
/// Format of the raw [`data`](Self::data).
pub format: GlyphImageFormat,
}
}
/// Valid formats for a [`GlyphImage`].
// Possible future formats: SVG, JPEG, TIFF
#[non_exhaustive]
#[derive(Debug, Clone)]
pub enum GlyphImageFormat {
Png,
/// A monochrome bitmap.
///
/// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte. 1 corresponds
/// to black, and 0 to white.
BitmapMono,
/// A packed monochrome bitmap.
///
/// The most significant bit of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding. 1
/// corresponds to black, and 0 to white.
BitmapMonoPacked,
/// A grayscale bitmap with 2 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte.
BitmapGray2,
/// A packed grayscale bitmap with 2 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding.
BitmapGray2Packed,
/// A grayscale bitmap with 4 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. The data for each row is padded to a byte
/// boundary, so the next row begins with the most significant bit of a new byte.
BitmapGray4,
/// A packed grayscale bitmap with 4 bits per pixel.
///
/// The most significant bits of the first byte corresponds to the top-left pixel, proceeding
/// through succeeding bits moving left to right. Data is tightly packed with no padding.
BitmapGray4Packed,
/// A grayscale bitmap with 8 bits per pixel.
///
/// The first byte corresponds to the top-left pixel, proceeding through succeeding bytes
/// moving left to right.
BitmapGray8,
/// A color bitmap with 32 bits per pixel.
///
/// The first group of four bytes corresponds to the top-left pixel, proceeding through
/// succeeding pixels moving left to right. Each byte corresponds to a color channel and the
/// channels within a pixel are in blue, green, red, alpha order. Color values are
/// pre-multiplied by the alpha. For example, the color "full-green with half translucency"
/// is encoded as `\x00\x80\x00\x80`, and not `\x00\xFF\x00\x80`.
BitmapPremulBgra32,
}

54
third-party/vendor/ab_glyph/src/lib.rs vendored Normal file
View file

@ -0,0 +1,54 @@
//! API for loading, scaling, positioning and rasterizing OpenType font glyphs.
//!
//! # Example
//! ```
//! use ab_glyph::{point, Font, FontRef, Glyph};
//!
//! # fn main() -> Result<(), ab_glyph::InvalidFont> {
//! let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
//!
//! // Get a glyph for 'q' with a scale & position.
//! let q_glyph: Glyph = font
//! .glyph_id('q')
//! .with_scale_and_position(24.0, point(100.0, 0.0));
//!
//! // Draw it.
//! if let Some(q) = font.outline_glyph(q_glyph) {
//! q.draw(|x, y, c| { /* draw pixel `(x, y)` with coverage: `c` */ });
//! }
//! # Ok(()) }
//! ```
#![warn(missing_debug_implementations)]
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
mod codepoint_ids;
mod err;
mod font;
#[cfg(feature = "std")]
mod font_arc;
mod glyph;
#[cfg(all(feature = "libm", not(feature = "std")))]
mod nostd_float;
mod outlined;
mod scale;
mod ttfp;
#[cfg(feature = "variable-fonts")]
mod variable;
#[cfg(feature = "std")]
pub use crate::font_arc::*;
#[allow(deprecated)]
pub use crate::{
codepoint_ids::*,
err::*,
font::*,
glyph::*,
outlined::*,
scale::*,
ttfp::{FontRef, FontVec},
};
pub use ab_glyph_rasterizer::{point, Point};
#[cfg(feature = "variable-fonts")]
pub use variable::*;

View file

@ -0,0 +1,41 @@
/// Basic required float operations.
pub(crate) trait FloatExt {
fn floor(self) -> Self;
fn ceil(self) -> Self;
fn sqrt(self) -> Self;
fn round(self) -> Self;
fn abs(self) -> Self;
fn trunc(self) -> Self;
fn fract(self) -> Self;
}
impl FloatExt for f32 {
#[inline]
fn floor(self) -> Self {
libm::floorf(self)
}
#[inline]
fn ceil(self) -> Self {
libm::ceilf(self)
}
#[inline]
fn sqrt(self) -> Self {
libm::sqrtf(self)
}
#[inline]
fn round(self) -> Self {
libm::roundf(self)
}
#[inline]
fn abs(self) -> Self {
libm::fabsf(self)
}
#[inline]
fn trunc(self) -> Self {
libm::truncf(self)
}
#[inline]
fn fract(self) -> Self {
self - self.trunc()
}
}

View file

@ -0,0 +1,176 @@
#[cfg(all(feature = "libm", not(feature = "std")))]
use crate::nostd_float::FloatExt;
use crate::{point, Glyph, Point, PxScaleFactor};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// A "raw" collection of outline curves for a glyph, unscaled & unpositioned.
#[derive(Clone, Debug)]
pub struct Outline {
/// Unscaled bounding box.
pub bounds: Rect,
/// Unscaled & unpositioned outline curves.
pub curves: Vec<OutlineCurve>,
}
impl Outline {
/// Convert unscaled bounds into pixel bounds at a given scale & position.
pub fn px_bounds(&self, scale_factor: PxScaleFactor, position: Point) -> Rect {
let Rect { min, max } = self.bounds;
// Use subpixel fraction in floor/ceil rounding to elimate rounding error
// from identical subpixel positions
let (x_trunc, x_fract) = (position.x.trunc(), position.x.fract());
let (y_trunc, y_fract) = (position.y.trunc(), position.y.fract());
Rect {
min: point(
(min.x * scale_factor.horizontal + x_fract).floor() + x_trunc,
(min.y * -scale_factor.vertical + y_fract).floor() + y_trunc,
),
max: point(
(max.x * scale_factor.horizontal + x_fract).ceil() + x_trunc,
(max.y * -scale_factor.vertical + y_fract).ceil() + y_trunc,
),
}
}
}
/// A glyph that has been outlined at a scale & position.
#[derive(Clone, Debug)]
pub struct OutlinedGlyph {
glyph: Glyph,
// Pixel scale bounds.
px_bounds: Rect,
// Scale factor
scale_factor: PxScaleFactor,
// Raw outline
outline: Outline,
}
impl OutlinedGlyph {
/// Constructs an `OutlinedGlyph` from the source `Glyph`, pixel bounds
/// & relatively positioned outline curves.
#[inline]
pub fn new(glyph: Glyph, outline: Outline, scale_factor: PxScaleFactor) -> Self {
// work this out now as it'll usually be used more than once
let px_bounds = outline.px_bounds(scale_factor, glyph.position);
Self {
glyph,
px_bounds,
scale_factor,
outline,
}
}
/// Glyph info.
#[inline]
pub fn glyph(&self) -> &Glyph {
&self.glyph
}
#[deprecated = "Renamed to `px_bounds`"]
#[doc(hidden)]
pub fn bounds(&self) -> Rect {
self.px_bounds()
}
/// Conservative whole number pixel bounding box for this glyph.
#[inline]
pub fn px_bounds(&self) -> Rect {
self.px_bounds
}
/// Draw this glyph outline using a pixel & coverage handling function.
///
/// The callback will be called for each `(x, y)` pixel coordinate inside the bounds
/// with a coverage value indicating how much the glyph covered that pixel.
///
/// A coverage value of `0.0` means the pixel is totally uncoverred by the glyph.
/// A value of `1.0` or greater means fully coverred.
pub fn draw<O: FnMut(u32, u32, f32)>(&self, o: O) {
use ab_glyph_rasterizer::Rasterizer;
let h_factor = self.scale_factor.horizontal;
let v_factor = -self.scale_factor.vertical;
let offset = self.glyph.position - self.px_bounds.min;
let (w, h) = (
self.px_bounds.width() as usize,
self.px_bounds.height() as usize,
);
let scale_up = |&Point { x, y }| point(x * h_factor, y * v_factor);
self.outline
.curves
.iter()
.fold(Rasterizer::new(w, h), |mut rasterizer, curve| match curve {
OutlineCurve::Line(p0, p1) => {
// eprintln!("r.draw_line({:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset);
rasterizer.draw_line(scale_up(p0) + offset, scale_up(p1) + offset);
rasterizer
}
OutlineCurve::Quad(p0, p1, p2) => {
// eprintln!("r.draw_quad({:?}, {:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset, scale_up(p2) + offset);
rasterizer.draw_quad(
scale_up(p0) + offset,
scale_up(p1) + offset,
scale_up(p2) + offset,
);
rasterizer
}
OutlineCurve::Cubic(p0, p1, p2, p3) => {
// eprintln!("r.draw_cubic({:?}, {:?}, {:?}, {:?});",
// scale_up(p0) + offset, scale_up(p1) + offset, scale_up(p2) + offset, scale_up(p3) + offset);
rasterizer.draw_cubic(
scale_up(p0) + offset,
scale_up(p1) + offset,
scale_up(p2) + offset,
scale_up(p3) + offset,
);
rasterizer
}
})
.for_each_pixel_2d(o);
}
}
impl AsRef<Glyph> for OutlinedGlyph {
#[inline]
fn as_ref(&self) -> &Glyph {
self.glyph()
}
}
/// Glyph outline primitives.
#[derive(Clone, Debug)]
pub enum OutlineCurve {
/// Straight line from `.0` to `.1`.
Line(Point, Point),
/// Quadratic Bézier curve from `.0` to `.2` using `.1` as the control.
Quad(Point, Point, Point),
/// Cubic Bézier curve from `.0` to `.3` using `.1` as the control at the beginning of the
/// curve and `.2` at the end of the curve.
Cubic(Point, Point, Point, Point),
}
/// A rectangle, with top-left corner at `min`, and bottom-right corner at `max`.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct Rect {
pub min: Point,
pub max: Point,
}
impl Rect {
#[inline]
pub fn width(&self) -> f32 {
self.max.x - self.min.x
}
#[inline]
pub fn height(&self) -> f32 {
self.max.y - self.min.y
}
}

270
third-party/vendor/ab_glyph/src/scale.rs vendored Normal file
View file

@ -0,0 +1,270 @@
#[cfg(all(feature = "libm", not(feature = "std")))]
use crate::nostd_float::FloatExt;
use crate::{Font, Glyph, GlyphId, OutlinedGlyph, Rect};
/// Pixel scale.
///
/// This is the pixel-height of text.
///
/// Usually one uses `x == y`, but one may use a different ratio to stretch a
/// font horizontally or vertically.
///
/// To convert pt size into pixel-scale see [`Font::pt_to_px_scale`].
///
/// # Example
/// ```
/// use ab_glyph::PxScale;
///
/// let uniform_scale_24px = PxScale::from(24.0);
/// ```
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct PxScale {
/// Horizontal scale in pixels.
pub x: f32,
/// Vertical scale in pixels.
///
/// By definition, this is the pixel-height of a font.
pub y: f32,
}
impl PxScale {
/// Returns a `PxScale` with both x & y scale values set to the nearest integer.
#[inline]
pub fn round(self) -> Self {
Self {
x: self.x.round(),
y: self.y.round(),
}
}
}
impl From<f32> for PxScale {
/// Uniform scaling where x & y are the same.
#[inline]
fn from(s: f32) -> Self {
PxScale { x: s, y: s }
}
}
/// 2D scale factors for use with unscaled metrics.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct PxScaleFactor {
pub horizontal: f32,
pub vertical: f32,
}
/// A [`Font`](trait.Font.html) with an associated pixel scale. This can be used to provide
/// pixel scale values for glyph advances, heights etc.
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef, PxScale, ScaleFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// // Associate the font with a scale of 45px
/// let scaled_font = font.as_scaled(PxScale::from(45.0));
///
/// assert_eq!(scaled_font.height(), 45.0);
/// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b')), 21.225);
///
/// // Replace associated scale with another
/// let scaled_font = scaled_font.with_scale(180.0);
///
/// assert_eq!(scaled_font.height(), 180.0);
/// assert_eq!(scaled_font.h_advance(scaled_font.glyph_id('b')), 84.9);
/// # Ok(()) }
/// ```
pub trait ScaleFont<F: Font> {
/// Returns the pixel scale associated with this font.
fn scale(&self) -> PxScale;
/// Returns a font reference.
fn font(&self) -> &F;
/// Scale factor for unscaled font horizontal values.
#[inline]
fn h_scale_factor(&self) -> f32 {
self.scale().x / self.font().height_unscaled()
}
/// Scale factor for unscaled font vertical values.
#[inline]
fn v_scale_factor(&self) -> f32 {
self.scale().y / self.font().height_unscaled()
}
#[inline]
fn scale_factor(&self) -> PxScaleFactor {
PxScaleFactor {
horizontal: self.h_scale_factor(),
vertical: self.v_scale_factor(),
}
}
/// Pixel scaled glyph ascent.
#[inline]
fn ascent(&self) -> f32 {
self.v_scale_factor() * self.font().ascent_unscaled()
}
/// Pixel scaled glyph descent.
#[inline]
fn descent(&self) -> f32 {
self.v_scale_factor() * self.font().descent_unscaled()
}
/// Pixel scaled height `ascent - descent`.
///
/// By definition of [`PxScale`], this is `self.scale().y`.
#[inline]
fn height(&self) -> f32 {
self.scale().y
}
/// Pixel scaled line gap.
#[inline]
fn line_gap(&self) -> f32 {
self.v_scale_factor() * self.font().line_gap_unscaled()
}
/// Lookup a `GlyphId` matching a given `char`.
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
self.font().glyph_id(c)
}
/// Construct a [`Glyph`](struct.Glyph.html) with the font's pixel scale at
/// position `point(0.0, 0.0)`.
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf")).unwrap();
/// let scaled_font = font.as_scaled(50.0);
///
/// let a1 = scaled_font.scaled_glyph('a');
/// let a2 = font.glyph_id('a').with_scale(50.0); // equivalent
///
/// # assert_eq!(a1.id, a2.id);
/// assert_eq!(a1.scale, PxScale::from(50.0));
/// assert_eq!(a1.position, point(0.0, 0.0));
/// ```
#[inline]
fn scaled_glyph(&self, c: char) -> Glyph {
self.font().glyph_id(c).with_scale(self.scale())
}
/// Pixel scaled horizontal advance for a given glyph.
#[inline]
fn h_advance(&self, id: GlyphId) -> f32 {
self.h_scale_factor() * self.font().h_advance_unscaled(id)
}
/// Pixel scaled horizontal side bearing for a given glyph.
#[inline]
fn h_side_bearing(&self, id: GlyphId) -> f32 {
self.h_scale_factor() * self.font().h_side_bearing_unscaled(id)
}
/// Pixel scaled vertical advance for a given glyph.
#[inline]
fn v_advance(&self, id: GlyphId) -> f32 {
self.v_scale_factor() * self.font().v_advance_unscaled(id)
}
/// Pixel scaled vertical side bearing for a given glyph.
#[inline]
fn v_side_bearing(&self, id: GlyphId) -> f32 {
self.v_scale_factor() * self.font().v_side_bearing_unscaled(id)
}
/// Returns additional pixel scaled kerning to apply for a particular pair of glyphs.
#[inline]
fn kern(&self, first: GlyphId, second: GlyphId) -> f32 {
self.h_scale_factor() * self.font().kern_unscaled(first, second)
}
/// Returns the layout bounds of this glyph. These are different to the outline `px_bounds()`.
///
/// Horizontally: Glyph position +/- h_advance/h_side_bearing.
/// Vertically: Glyph position +/- ascent/descent.
///
/// Note this method does not make use of the associated scale, as `Glyph`
/// already includes one of it's own.
#[inline]
fn glyph_bounds(&self, glyph: &Glyph) -> Rect {
self.font().glyph_bounds(glyph)
}
/// The number of glyphs present in this font. Glyph identifiers for this
/// font will always be in the range `0..self.glyph_count()`
#[inline]
fn glyph_count(&self) -> usize {
self.font().glyph_count()
}
/// Returns an iterator of all distinct `(GlyphId, char)` pairs. Not ordered.
///
/// Same as [`Font::codepoint_ids`](trait.Font.html#tymethod.codepoint_ids).
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_>;
/// Compute glyph outline ready for drawing.
///
/// Note this method does not make use of the associated scale, as `Glyph`
/// already includes one of it's own.
#[inline]
fn outline_glyph(&self, glyph: Glyph) -> Option<OutlinedGlyph> {
self.font().outline_glyph(glyph)
}
}
impl<F: Font, SF: ScaleFont<F>> ScaleFont<F> for &SF {
#[inline]
fn scale(&self) -> PxScale {
(*self).scale()
}
#[inline]
fn font(&self) -> &F {
(*self).font()
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
(*self).codepoint_ids()
}
}
/// A [`Font`](trait.Font.html) and an associated pixel scale.
#[derive(Clone, Copy, Debug)]
pub struct PxScaleFont<F> {
pub font: F,
pub scale: PxScale,
}
impl<F> PxScaleFont<F> {
#[inline]
pub fn with_scale<S: Into<PxScale>>(mut self, scale: S) -> Self {
self.scale = scale.into();
self
}
}
impl<F: Font> ScaleFont<F> for PxScaleFont<F> {
#[inline]
fn scale(&self) -> PxScale {
self.scale
}
#[inline]
fn font(&self) -> &F {
&self.font
}
#[inline]
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
self.font.codepoint_ids()
}
}

349
third-party/vendor/ab_glyph/src/ttfp.rs vendored Normal file
View file

@ -0,0 +1,349 @@
//! ttf-parser crate specific code. ttf-parser types should not be leaked publicly.
mod outliner;
#[cfg(feature = "variable-fonts")]
mod variable;
use crate::{point, v2, Font, GlyphId, GlyphImageFormat, InvalidFont, Outline, Rect};
use alloc::boxed::Box;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
use owned_ttf_parser::{self as ttfp, AsFaceRef};
impl From<GlyphId> for ttfp::GlyphId {
#[inline]
fn from(id: GlyphId) -> Self {
Self(id.0)
}
}
/// Font data handle stored as a `&[u8]` + parsed data.
/// See [`Font`](trait.Font.html) for more methods.
///
/// Also see the owned version [`FontVec`](struct.FontVec.html).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontRef};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
#[derive(Clone)]
pub struct FontRef<'font>(ttfp::PreParsedSubtables<'font, ttfp::Face<'font>>);
impl fmt::Debug for FontRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontRef")
}
}
impl<'font> FontRef<'font> {
/// Creates an `FontRef` from a byte-slice.
///
/// For font collections see
/// [`FontRef::try_from_slice_and_index`](#method.try_from_slice_and_index).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Exo2-Light.otf"))?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice(data: &'font [u8]) -> Result<Self, InvalidFont> {
Self::try_from_slice_and_index(data, 0)
}
/// Creates an `FontRef` from byte-slice.
///
/// You can set index for font collections. For simple fonts use `0` or
/// [`FontRef::try_from_slice`](#method.try_from_slice).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// let font =
/// FontRef::try_from_slice_and_index(include_bytes!("../../dev/fonts/Exo2-Light.otf"), 0)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_slice_and_index(data: &'font [u8], index: u32) -> Result<Self, InvalidFont> {
Ok(Self(ttfp::PreParsedSubtables::from(
ttfp::Face::parse(data, index).map_err(|_| InvalidFont)?,
)))
}
}
/// Font data handle stored in a `Vec<u8>` + parsed data.
/// See [`Font`](trait.Font.html) for more methods.
///
/// Also see [`FontRef`](struct.FontRef.html).
///
/// # Example
/// ```
/// use ab_glyph::{Font, FontVec};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
///
/// assert_eq!(font.glyph_id('s'), ab_glyph::GlyphId(56));
/// # Ok(()) }
/// ```
pub struct FontVec(ttfp::PreParsedSubtables<'static, ttfp::OwnedFace>);
impl fmt::Debug for FontVec {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FontVec")
}
}
impl FontVec {
/// Creates an `FontVec` from owned data.
///
/// For font collections see
/// [`FontVec::try_from_vec_and_index`](#method.try_from_vec_and_index).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec(data: Vec<u8>) -> Result<Self, InvalidFont> {
Self::try_from_vec_and_index(data, 0)
}
/// Creates an `FontVec` from owned data.
///
/// You can set index for font collections. For simple fonts use `0` or
/// [`FontVec::try_from_vec`](#method.try_from_vec).
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font = FontVec::try_from_vec_and_index(owned_font_data, 0)?;
/// # Ok(()) }
/// ```
#[inline]
pub fn try_from_vec_and_index(data: Vec<u8>, index: u32) -> Result<Self, InvalidFont> {
Ok(Self(ttfp::PreParsedSubtables::from(
ttfp::OwnedFace::from_vec(data, index).map_err(|_| InvalidFont)?,
)))
}
/// Extracts a slice containing the data passed into e.g. [`FontVec::try_from_vec`].
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font_data_clone = owned_font_data.clone();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// assert_eq!(font.as_slice(), font_data_clone);
/// # Ok(()) }
/// ```
#[inline]
pub fn as_slice(&self) -> &[u8] {
self.0.face.as_slice()
}
/// Unwraps the data passed into e.g. [`FontVec::try_from_vec`].
///
/// # Example
/// ```
/// # use ab_glyph::*;
/// # fn main() -> Result<(), InvalidFont> {
/// # let owned_font_data = include_bytes!("../../dev/fonts/Exo2-Light.otf").to_vec();
/// let font_data_clone = owned_font_data.clone();
/// let font = FontVec::try_from_vec(owned_font_data)?;
/// assert_eq!(font.into_vec(), font_data_clone);
/// # Ok(()) }
/// ```
pub fn into_vec(self) -> Vec<u8> {
self.0.face.into_vec()
}
}
/// Implement `Font` for `Self(AsFontRef)` types.
macro_rules! impl_font {
($font:ty) => {
impl Font for $font {
#[inline]
fn units_per_em(&self) -> Option<f32> {
// TODO unwrap signature when making next breaking change
Some(self.0.as_face_ref().units_per_em().into())
}
#[inline]
fn ascent_unscaled(&self) -> f32 {
self.0.as_face_ref().ascender().into()
}
#[inline]
fn descent_unscaled(&self) -> f32 {
self.0.as_face_ref().descender().into()
}
#[inline]
fn line_gap_unscaled(&self) -> f32 {
self.0.as_face_ref().line_gap().into()
}
#[inline]
fn glyph_id(&self, c: char) -> GlyphId {
// Note: Using `PreParsedSubtables` method for better performance.
let index = self.0.glyph_index(c).map(|id| id.0).unwrap_or(0);
GlyphId(index)
}
#[inline]
fn h_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_hor_advance(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn h_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_hor_side_bearing(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn v_advance_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_ver_advance(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn v_side_bearing_unscaled(&self, id: GlyphId) -> f32 {
self.0
.as_face_ref()
.glyph_ver_side_bearing(id.into())
.unwrap_or_default()
.into()
}
#[inline]
fn kern_unscaled(&self, first: GlyphId, second: GlyphId) -> f32 {
// Note: Using `PreParsedSubtables` method for better performance.
self.0
.glyphs_hor_kerning(first.into(), second.into())
.map(f32::from)
.unwrap_or_default()
}
fn outline(&self, id: GlyphId) -> Option<Outline> {
let mut outliner = outliner::OutlineCurveBuilder::default();
let ttfp::Rect {
x_min,
x_max,
y_min,
y_max,
} = self
.0
.as_face_ref()
.outline_glyph(id.into(), &mut outliner)
// invalid bounds are treated as having no outline
.filter(|b| b.x_min < b.x_max && b.y_min < b.y_max)?;
let curves = outliner.take_outline();
let bounds = Rect {
min: point(x_min.into(), y_max.into()),
max: point(x_max.into(), y_min.into()),
};
Some(Outline { bounds, curves })
}
#[inline]
fn glyph_count(&self) -> usize {
self.0.as_face_ref().number_of_glyphs() as _
}
fn codepoint_ids(&self) -> crate::CodepointIdIter<'_> {
let face_ref = self.0.as_face_ref();
#[cfg(feature = "std")]
let mut used_indices =
std::collections::HashSet::with_capacity(face_ref.number_of_glyphs() as _);
#[cfg(not(feature = "std"))]
let mut used_indices = alloc::collections::BTreeSet::new();
let inner = Box::new(
face_ref
.tables()
.cmap
.iter()
.flat_map(|c| c.subtables)
.filter(|s| s.is_unicode())
.flat_map(move |subtable| {
let mut pairs = Vec::new();
subtable.codepoints(|c| {
if let Ok(ch) = char::try_from(c) {
if let Some(idx) = subtable.glyph_index(c).filter(|i| i.0 > 0) {
if used_indices.insert(idx.0) {
pairs.push((GlyphId(idx.0), ch));
}
}
}
});
pairs
}),
);
crate::CodepointIdIter { inner }
}
fn glyph_raster_image2(&self, id: GlyphId, size: u16) -> Option<v2::GlyphImage> {
use GlyphImageFormat::*;
let img = self.0.as_face_ref().glyph_raster_image(id.into(), size)?;
Some(v2::GlyphImage {
origin: point(img.x.into(), img.y.into()),
width: img.width,
height: img.height,
pixels_per_em: img.pixels_per_em,
data: img.data,
format: match img.format {
ttfp::RasterImageFormat::PNG => Png,
ttfp::RasterImageFormat::BitmapMono => BitmapMono,
ttfp::RasterImageFormat::BitmapMonoPacked => BitmapMonoPacked,
ttfp::RasterImageFormat::BitmapGray2 => BitmapGray2,
ttfp::RasterImageFormat::BitmapGray2Packed => BitmapGray2Packed,
ttfp::RasterImageFormat::BitmapGray4 => BitmapGray4,
ttfp::RasterImageFormat::BitmapGray4Packed => BitmapGray4Packed,
ttfp::RasterImageFormat::BitmapGray8 => BitmapGray8,
ttfp::RasterImageFormat::BitmapPremulBgra32 => BitmapPremulBgra32,
},
})
}
}
};
}
impl_font!(FontRef<'_>);
impl_font!(FontVec);

View file

@ -0,0 +1,65 @@
use crate::{point, OutlineCurve, Point};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Debug, Default)]
pub(crate) struct OutlineCurveBuilder {
last: Point,
last_move: Option<Point>,
outline: Vec<OutlineCurve>,
}
impl OutlineCurveBuilder {
#[inline]
pub(crate) fn take_outline(mut self) -> Vec<OutlineCurve> {
// some font glyphs implicitly close, e.g. Cantarell-VF.otf
owned_ttf_parser::OutlineBuilder::close(&mut self);
self.outline
}
}
impl owned_ttf_parser::OutlineBuilder for OutlineCurveBuilder {
#[inline]
fn move_to(&mut self, x: f32, y: f32) {
// eprintln!("M {x} {y}");
self.last = point(x, y);
self.last_move = Some(self.last);
}
#[inline]
fn line_to(&mut self, x1: f32, y1: f32) {
// eprintln!("L {x1} {y1}");
let p1 = point(x1, y1);
self.outline.push(OutlineCurve::Line(self.last, p1));
self.last = p1;
}
#[inline]
fn quad_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32) {
// eprintln!("Q {x1} {y1}");
let p1 = point(x1, y1);
let p2 = point(x2, y2);
self.outline.push(OutlineCurve::Quad(self.last, p1, p2));
self.last = p2;
}
#[inline]
fn curve_to(&mut self, x1: f32, y1: f32, x2: f32, y2: f32, x3: f32, y3: f32) {
// eprintln!("C {x1} {y1} {x3} {y3}");
let p1 = point(x1, y1);
let p2 = point(x2, y2);
let p3 = point(x3, y3);
self.outline
.push(OutlineCurve::Cubic(self.last, p1, p2, p3));
self.last = p3;
}
#[inline]
fn close(&mut self) {
// eprintln!("Z");
if let Some(m) = self.last_move.take() {
self.outline.push(OutlineCurve::Line(self.last, m));
}
}
}

View file

@ -0,0 +1,63 @@
use crate::{FontRef, FontVec, VariableFont, VariationAxis};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use owned_ttf_parser::{self as ttfp, AsFaceRef, FaceMut};
impl VariableFont for FontRef<'_> {
fn set_variation(&mut self, axis: &[u8; 4], value: f32) -> bool {
let tag = ttfp::Tag::from_bytes(axis);
// TODO remove existence check in next breaking version
let exists = self
.0
.as_face_ref()
.variation_axes()
.into_iter()
.any(|axis| axis.tag == tag);
if exists {
self.0.set_variation(tag, value);
}
exists
}
fn variations(&self) -> Vec<VariationAxis> {
variations(self.0.as_face_ref())
}
}
impl VariableFont for FontVec {
fn set_variation(&mut self, axis: &[u8; 4], value: f32) -> bool {
self.0
.set_variation(ttfp::Tag::from_bytes(axis), value)
.is_some()
}
fn variations(&self) -> Vec<VariationAxis> {
variations(self.0.as_face_ref())
}
}
fn variations(face: &ttfp::Face<'_>) -> Vec<VariationAxis> {
face.variation_axes()
.into_iter()
.map(|axis| {
#[cfg(feature = "std")]
let name = face.names().into_iter().find_map(|n| {
if n.name_id == axis.name_id {
n.to_string()
} else {
None
}
});
#[cfg(not(feature = "std"))]
let name = None;
VariationAxis {
tag: axis.tag.to_bytes(),
name,
min_value: axis.min_value,
default_value: axis.def_value,
max_value: axis.max_value,
hidden: axis.hidden,
}
})
.collect()
}

View file

@ -0,0 +1,67 @@
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
/// Logic for variable fonts.
///
/// Requires feature `variable-fonts` (enabled by default).
pub trait VariableFont {
/// Sets a variation axis coordinate value by it's tag.
///
/// Returns false if there is no such axis tag.
///
/// # Example
/// ```
/// use ab_glyph::{FontRef, VariableFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let mut font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Cantarell-VF.otf"))?;
///
/// // set weight to 600
/// assert!(font.set_variation(b"wght", 600.0));
///
/// // no such variation tag "foob" so return false
/// assert!(!font.set_variation(b"foob", 200.0));
/// # Ok(()) }
/// ```
fn set_variation(&mut self, tag: &[u8; 4], value: f32) -> bool;
/// Returns variation axes.
///
/// # Example
/// ```
/// use ab_glyph::{FontRef, VariableFont};
///
/// # fn main() -> Result<(), ab_glyph::InvalidFont> {
/// let font = FontRef::try_from_slice(include_bytes!("../../dev/fonts/Cantarell-VF.otf"))?;
/// let var = &font.variations()[0];
/// # eprintln!("{var:#?}");
///
/// assert_eq!(var.tag, *b"wght");
/// assert_eq!(var.name.as_deref(), Some("Weight"));
/// assert!((var.min_value - 100.0).abs() < f32::EPSILON);
/// assert!((var.default_value - 400.0).abs() < f32::EPSILON);
/// assert!((var.max_value - 800.0).abs() < f32::EPSILON);
/// assert!(!var.hidden);
/// # Ok(()) }
/// ```
fn variations(&self) -> Vec<VariationAxis>;
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct VariationAxis {
/// Tag identifying the design variation for the axis.
pub tag: [u8; 4],
/// Unicode name.
pub name: Option<String>,
/// The minimum coordinate value for the axis.
pub min_value: f32,
/// The default coordinate value for the axis.
pub default_value: f32,
/// The maximum coordinate value for the axis.
pub max_value: f32,
/// Whether the axis should be exposed directly in user interfaces.
pub hidden: bool,
}