Skip to content

Commit

Permalink
Rework Size handling
Browse files Browse the repository at this point in the history
This removes the `DPR` stuff due to it being redundant.
  • Loading branch information
kchibisov committed Dec 3, 2023
1 parent 62f0393 commit 5bbf429
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 67 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Changed

- `Size` now uses 3 floating point digits precision instead of rounding to 0.5.
- `Size` now uses 6 floating point digits precision instead of rounding to 0.5.
- Add `Size::from_px`, `Size::as_px`, `Size::as_pt`, `Size::change_px`, and `Size::scale`.
- Remove `Rasterizer::update_dpr`; users should scale font themselves.

## 0.5.2

Expand Down
15 changes: 5 additions & 10 deletions src/darwin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,11 @@ impl Descriptor {
pub struct CoreTextRasterizer {
fonts: HashMap<FontKey, Font>,
keys: HashMap<(FontDesc, Size), FontKey>,
device_pixel_ratio: f32,
}

impl crate::Rasterize for CoreTextRasterizer {
fn new(device_pixel_ratio: f32) -> Result<CoreTextRasterizer, Error> {
Ok(CoreTextRasterizer { fonts: HashMap::new(), keys: HashMap::new(), device_pixel_ratio })
fn new() -> Result<CoreTextRasterizer, Error> {
Ok(CoreTextRasterizer { fonts: HashMap::new(), keys: HashMap::new() })
}

/// Get metrics for font specified by FontKey.
Expand All @@ -118,7 +117,7 @@ impl crate::Rasterize for CoreTextRasterizer {
}

fn load_font(&mut self, desc: &FontDesc, size: Size) -> Result<FontKey, Error> {
let scaled_size = Size::new(size.as_f32_pts() * self.device_pixel_ratio);
let scaled_size = Size::new(size.as_pt());
self.keys.get(&(desc.to_owned(), scaled_size)).map(|k| Ok(*k)).unwrap_or_else(|| {
let font = self.get_font(desc, size)?;
let key = FontKey::next();
Expand Down Expand Up @@ -156,10 +155,6 @@ impl crate::Rasterize for CoreTextRasterizer {
fn kerning(&mut self, _left: GlyphKey, _right: GlyphKey) -> (f32, f32) {
(0., 0.)
}

fn update_dpr(&mut self, device_pixel_ratio: f32) {
self.device_pixel_ratio = device_pixel_ratio;
}
}

impl CoreTextRasterizer {
Expand All @@ -173,7 +168,7 @@ impl CoreTextRasterizer {
for descriptor in descriptors {
if descriptor.style_name == style {
// Found the font we want.
let scaled_size = f64::from(size.as_f32_pts()) * f64::from(self.device_pixel_ratio);
let scaled_size = f64::from(size.as_pt());
let font = descriptor.to_font(scaled_size, true);
return Ok(font);
}
Expand All @@ -191,7 +186,7 @@ impl CoreTextRasterizer {
) -> Result<Font, Error> {
let bold = weight == Weight::Bold;
let italic = slant != Slant::Normal;
let scaled_size = f64::from(size.as_f32_pts()) * f64::from(self.device_pixel_ratio);
let scaled_size = f64::from(size.as_pt());

let descriptors = descriptors_for_family(&desc.name[..]);
for descriptor in descriptors {
Expand Down
22 changes: 6 additions & 16 deletions src/directwrite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ struct Font {
pub struct DirectWriteRasterizer {
fonts: HashMap<FontKey, Font>,
keys: HashMap<FontDesc, FontKey>,
device_pixel_ratio: f32,
available_fonts: FontCollection,
fallback_sequence: Option<FontFallback>,
}
Expand All @@ -48,7 +47,7 @@ impl DirectWriteRasterizer {
character: char,
glyph_index: u16,
) -> Result<RasterizedGlyph, Error> {
let em_size = em_size(size);
let em_size = f32::from(size.as_px());

let glyph_run = DWRITE_GLYPH_RUN {
fontFace: unsafe { face.as_ptr() },
Expand All @@ -63,13 +62,13 @@ impl DirectWriteRasterizer {

let rendering_mode = face.get_recommended_rendering_mode_default_params(
em_size,
self.device_pixel_ratio,
1.,
dwrote::DWRITE_MEASURING_MODE_NATURAL,
);

let glyph_analysis = GlyphRunAnalysis::create(
&glyph_run,
self.device_pixel_ratio,
1.,
None,
rendering_mode,
dwrote::DWRITE_MEASURING_MODE_NATURAL,
Expand Down Expand Up @@ -136,11 +135,10 @@ impl DirectWriteRasterizer {
}

impl crate::Rasterize for DirectWriteRasterizer {
fn new(device_pixel_ratio: f32) -> Result<DirectWriteRasterizer, Error> {
fn new() -> Result<DirectWriteRasterizer, Error> {
Ok(DirectWriteRasterizer {
fonts: HashMap::new(),
keys: HashMap::new(),
device_pixel_ratio,
available_fonts: FontCollection::system(),
fallback_sequence: FontFallback::get_system_fallback(),
})
Expand All @@ -150,7 +148,7 @@ impl crate::Rasterize for DirectWriteRasterizer {
let face = &self.get_loaded_font(key)?.face;
let vmetrics = face.metrics().metrics0();

let scale = em_size(size) * self.device_pixel_ratio / f32::from(vmetrics.designUnitsPerEm);
let scale = f32::from(size.as_px()) / f32::from(vmetrics.designUnitsPerEm);

let underline_position = f32::from(vmetrics.underlinePosition) * scale;
let underline_thickness = f32::from(vmetrics.underlineThickness) * scale;
Expand Down Expand Up @@ -252,17 +250,9 @@ impl crate::Rasterize for DirectWriteRasterizer {
}
}

fn kerning(&mut self, left: GlyphKey, right: GlyphKey) -> (f32, f32) {
fn kerning(&mut self, _left: GlyphKey, _right: GlyphKey) -> (f32, f32) {
(0., 0.)
}

fn update_dpr(&mut self, device_pixel_ratio: f32) {
self.device_pixel_ratio = device_pixel_ratio;
}
}

fn em_size(size: Size) -> f32 {
size.as_f32_pts() * (96.0 / 72.0)
}

impl From<dwrote::Font> for Font {
Expand Down
14 changes: 3 additions & 11 deletions src/ft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ impl fmt::Debug for FaceLoadingProperties {
pub struct FreeTypeRasterizer {
loader: FreeTypeLoader,
fallback_lists: HashMap<FontKey, FallbackList>,
device_pixel_ratio: f32,

/// Rasterizer creation time stamp to delay lazy font config updates
/// in `Rasterizer::load_font`.
Expand Down Expand Up @@ -133,11 +132,10 @@ impl IntoF32 for i64 {
}

impl Rasterize for FreeTypeRasterizer {
fn new(device_pixel_ratio: f32) -> Result<FreeTypeRasterizer, Error> {
fn new() -> Result<FreeTypeRasterizer, Error> {
Ok(FreeTypeRasterizer {
loader: FreeTypeLoader::new()?,
fallback_lists: HashMap::new(),
device_pixel_ratio,
creation_timestamp: Some(Instant::now()),
})
}
Expand Down Expand Up @@ -204,9 +202,7 @@ impl Rasterize for FreeTypeRasterizer {
let font_key = self.face_for_glyph(glyph_key);
let face = &self.loader.faces[&font_key];
let index = face.ft_face.get_char_index(glyph_key.character as usize);
let pixelsize = face
.non_scalable
.unwrap_or_else(|| glyph_key.size.as_f32_pts() * self.device_pixel_ratio * 96. / 72.);
let pixelsize = face.non_scalable.unwrap_or_else(|| glyph_key.size.as_px() as f32);

if !face.colored_bitmap {
face.ft_face.set_char_size(to_freetype_26_6(pixelsize), 0, 0, 0)?;
Expand Down Expand Up @@ -308,10 +304,6 @@ impl Rasterize for FreeTypeRasterizer {

(from_freetype_26_6(kerning.x), from_freetype_26_6(kerning.y))
}

fn update_dpr(&mut self, device_pixel_ratio: f32) {
self.device_pixel_ratio = device_pixel_ratio;
}
}

impl From<Slant> for fc::Slant {
Expand Down Expand Up @@ -342,7 +334,7 @@ impl FreeTypeRasterizer {
/// Load a font face according to `FontDesc`.
fn get_face(&mut self, desc: &FontDesc, size: Size) -> Result<FontKey, Error> {
// Adjust for DPR.
let size = f64::from(size.as_f32_pts() * self.device_pixel_ratio * 96. / 72.);
let size = f64::from(size.as_pt() * 96. / 72.);

let config = fc::Config::get_current();
let mut pattern = Pattern::new();
Expand Down
62 changes: 33 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#![deny(clippy::all, clippy::if_not_else, clippy::enum_glob_use)]

use std::fmt::{self, Display, Formatter};
use std::ops::{Add, Mul};
use std::sync::atomic::{AtomicUsize, Ordering};

#[cfg(not(any(target_os = "macos", windows)))]
Expand Down Expand Up @@ -101,47 +100,55 @@ pub struct GlyphKey {
pub size: Size,
}

/// Max font size in PT.
const MAX_FONT_PT_SIZE: f32 = 4000.;

/// Font size stored as base and fraction.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Size(i32);
pub struct Size(u32);

impl Size {
/// Create a new `Size` from a f32 size in points.
///
/// The font size is automatically clamped to supported range of [1.; 4000.] pt.
pub fn new(size: f32) -> Size {
Size((size * Size::factor()) as i32)
let size = size.clamp(1., MAX_FONT_PT_SIZE);
Size((size * Self::factor()) as u32)
}

/// Scale factor between font "Size" type and point size.
#[inline]
pub fn factor() -> f32 {
1000.
/// Create a new `Size` from px.
///
/// The value will be clamped to the pt range of [`Size::new`].
pub fn from_px(size: u16) -> Self {
let pt = size as f32 * 72. / 96.;
Size::new(pt)
}

/// Get the f32 size in points.
pub fn as_f32_pts(self) -> f32 {
(f64::from(self.0) / Size::factor() as f64) as f32
/// Change font size in px by the given amount.
pub fn change_px(self, delta: i32) -> Self {
let new_size = (self.as_px() as i32 + delta).clamp(1, u16::MAX as i32) as u16;
Size::from_px(new_size)
}
}

impl<T: Into<Size>> Add<T> for Size {
type Output = Size;

fn add(self, other: T) -> Size {
Size(self.0.saturating_add(other.into().0))
/// Scale font size by the given amount.
pub fn scale(self, scale: f32) -> Self {
Self::new(self.as_pt() * scale)
}
}

impl<T: Into<Size>> Mul<T> for Size {
type Output = Size;
/// Get size in `px`.
pub fn as_px(self) -> u16 {
(self.as_pt() * 96. / 72.).trunc() as u16
}

fn mul(self, other: T) -> Size {
Size(self.0 * other.into().0)
/// Get the size in `pt`.
pub fn as_pt(self) -> f32 {
(f64::from(self.0) / Size::factor() as f64) as f32
}
}

impl From<f32> for Size {
fn from(float: f32) -> Size {
Size::new(float)
/// Scale factor between font "Size" type and point size.
#[inline]
fn factor() -> f32 {
1_000_000.
}
}

Expand Down Expand Up @@ -231,7 +238,7 @@ impl Display for Error {

pub trait Rasterize {
/// Create a new Rasterizer.
fn new(device_pixel_ratio: f32) -> Result<Self, Error>
fn new() -> Result<Self, Error>
where
Self: Sized;

Expand All @@ -244,9 +251,6 @@ pub trait Rasterize {
/// Rasterize the glyph described by `GlyphKey`..
fn get_glyph(&mut self, _: GlyphKey) -> Result<RasterizedGlyph, Error>;

/// Update the Rasterizer's DPI factor.
fn update_dpr(&mut self, device_pixel_ratio: f32);

/// Kerning between two characters.
fn kerning(&mut self, left: GlyphKey, right: GlyphKey) -> (f32, f32);
}

0 comments on commit 5bbf429

Please sign in to comment.