Honor vertical subpixel positions
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
bc977fc873
commit
5f3dbb05d6
4 changed files with 28 additions and 19 deletions
|
@ -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,
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue