Honor vertical subpixel positions

Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
Antonio Scandurra 2021-03-24 18:35:48 +01:00
parent bc977fc873
commit 5f3dbb05d6
4 changed files with 28 additions and 19 deletions

View file

@ -3,7 +3,7 @@ use crate::{
geometry::{ geometry::{
rect::{RectF, RectI}, rect::{RectF, RectI},
transform2d::Transform2F, transform2d::Transform2F,
vector::{vec2f, vec2i}, vector::{vec2f, vec2i, Vector2F},
}, },
platform, platform,
text_layout::{Glyph, Line, Run}, text_layout::{Glyph, Line, Run},
@ -71,12 +71,12 @@ impl platform::FontSystem for FontSystem {
font_id: FontId, font_id: FontId,
font_size: f32, font_size: f32,
glyph_id: GlyphId, glyph_id: GlyphId,
horizontal_shift: f32, subpixel_shift: Vector2F,
scale_factor: f32, scale_factor: f32,
) -> Option<(RectI, Vec<u8>)> { ) -> Option<(RectI, Vec<u8>)> {
self.0 self.0
.read() .read()
.rasterize_glyph(font_id, font_size, glyph_id, horizontal_shift, scale_factor) .rasterize_glyph(font_id, font_size, glyph_id, subpixel_shift, scale_factor)
} }
fn layout_str( fn layout_str(
@ -126,7 +126,7 @@ impl FontSystemState {
font_id: FontId, font_id: FontId,
font_size: f32, font_size: f32,
glyph_id: GlyphId, glyph_id: GlyphId,
horizontal_shift: f32, subpixel_shift: Vector2F,
scale_factor: f32, scale_factor: f32,
) -> Option<(RectI, Vec<u8>)> { ) -> Option<(RectI, Vec<u8>)> {
let font = &self.fonts[font_id.0]; let font = &self.fonts[font_id.0];
@ -145,7 +145,7 @@ impl FontSystemState {
None None
} else { } else {
// Make room for subpixel variants. // Make room for subpixel variants.
let bounds = RectI::new(bounds.origin(), bounds.size() + vec2i(1, 0)); let bounds = RectI::new(bounds.origin(), bounds.size() + vec2i(1, 1));
let mut pixels = vec![0; bounds.width() as usize * bounds.height() as usize]; let mut pixels = vec![0; bounds.width() as usize * bounds.height() as usize];
let ctx = CGContext::create_bitmap_context( let ctx = CGContext::create_bitmap_context(
Some(pixels.as_mut_ptr() as *mut _), Some(pixels.as_mut_ptr() as *mut _),
@ -175,8 +175,8 @@ impl FontSystemState {
ctx.show_glyphs_at_positions( ctx.show_glyphs_at_positions(
&[glyph_id as CGGlyph], &[glyph_id as CGGlyph],
&[CGPoint::new( &[CGPoint::new(
(horizontal_shift / scale_factor) as CGFloat, (subpixel_shift.x() / scale_factor) as CGFloat,
0.0, (subpixel_shift.y() / scale_factor) as CGFloat,
)], )],
); );

View file

@ -272,7 +272,7 @@ impl Renderer {
glyph.font_id, glyph.font_id,
glyph.font_size, glyph.font_size,
glyph.id, glyph.id,
glyph.origin.x(), glyph.origin,
scene.scale_factor(), scene.scale_factor(),
) { ) {
sprites_by_atlas sprites_by_atlas

View file

@ -2,7 +2,7 @@ use crate::{
fonts::{FontId, GlyphId}, fonts::{FontId, GlyphId},
geometry::{ geometry::{
rect::RectI, rect::RectI,
vector::{vec2i, Vector2F, Vector2I}, vector::{vec2f, vec2i, Vector2F, Vector2I},
}, },
platform, platform,
}; };
@ -16,7 +16,7 @@ struct GlyphDescriptor {
font_id: FontId, font_id: FontId,
font_size: OrderedFloat<f32>, font_size: OrderedFloat<f32>,
glyph_id: GlyphId, glyph_id: GlyphId,
subpixel_variant: u8, subpixel_variant: (u8, u8),
} }
#[derive(Clone)] #[derive(Clone)]
@ -60,18 +60,22 @@ impl SpriteCache {
font_id: FontId, font_id: FontId,
font_size: f32, font_size: f32,
glyph_id: GlyphId, glyph_id: GlyphId,
target_x: f32, target_position: Vector2F,
scale_factor: f32, scale_factor: f32,
) -> Option<GlyphSprite> { ) -> Option<GlyphSprite> {
const SUBPIXEL_VARIANTS: u8 = 4; const SUBPIXEL_VARIANTS: u8 = 4;
let target_x = target_x * scale_factor; let target_position = target_position * scale_factor;
let fonts = &self.fonts; let fonts = &self.fonts;
let atlasses = &mut self.atlasses; let atlasses = &mut self.atlasses;
let atlas_size = self.atlas_size; let atlas_size = self.atlas_size;
let device = &self.device; let device = &self.device;
let subpixel_variant = let subpixel_variant = (
(target_x.fract() * SUBPIXEL_VARIANTS as f32).round() as u8 % SUBPIXEL_VARIANTS; (target_position.x().fract() * SUBPIXEL_VARIANTS as f32).round() as u8
% SUBPIXEL_VARIANTS,
(target_position.y().fract() * SUBPIXEL_VARIANTS as f32).round() as u8
% SUBPIXEL_VARIANTS,
);
self.glyphs self.glyphs
.entry(GlyphDescriptor { .entry(GlyphDescriptor {
font_id, font_id,
@ -80,12 +84,15 @@ impl SpriteCache {
subpixel_variant, subpixel_variant,
}) })
.or_insert_with(|| { .or_insert_with(|| {
let horizontal_shift = subpixel_variant as f32 / SUBPIXEL_VARIANTS as f32; let subpixel_shift = vec2f(
subpixel_variant.0 as f32 / SUBPIXEL_VARIANTS as f32,
subpixel_variant.1 as f32 / SUBPIXEL_VARIANTS as f32,
);
let (glyph_bounds, mask) = fonts.rasterize_glyph( let (glyph_bounds, mask) = fonts.rasterize_glyph(
font_id, font_id,
font_size, font_size,
glyph_id, glyph_id,
horizontal_shift, subpixel_shift,
scale_factor, scale_factor,
)?; )?;
assert!(glyph_bounds.width() < atlas_size.x()); assert!(glyph_bounds.width() < atlas_size.x());
@ -102,8 +109,10 @@ impl SpriteCache {
bounds bounds
}); });
let mut offset = glyph_bounds.origin().to_f32(); // Snap sprite to pixel grid.
offset.set_x(offset.x() - target_x.fract()); let offset = glyph_bounds.origin().to_f32()
- vec2f(target_position.x().fract(), target_position.y().fract());
Some(GlyphSprite { Some(GlyphSprite {
atlas_id: atlasses.len() - 1, atlas_id: atlasses.len() - 1,
atlas_origin: atlas_bounds.origin(), atlas_origin: atlas_bounds.origin(),

View file

@ -78,7 +78,7 @@ pub trait FontSystem: Send + Sync {
font_id: FontId, font_id: FontId,
font_size: f32, font_size: f32,
glyph_id: GlyphId, glyph_id: GlyphId,
horizontal_shift: f32, subpixel_shift: Vector2F,
scale_factor: f32, scale_factor: f32,
) -> Option<(RectI, Vec<u8>)>; ) -> Option<(RectI, Vec<u8>)>;
fn layout_str(&self, text: &str, font_size: f32, runs: &[(Range<usize>, FontId)]) -> Line; fn layout_str(&self, text: &str, font_size: f32, runs: &[(Range<usize>, FontId)]) -> Line;