checkpoint

This commit is contained in:
Junkui Zhang 2025-07-31 17:27:06 +08:00
parent a1001079ba
commit 30f6699b56

View file

@ -707,11 +707,18 @@ impl DirectWriteState {
}
}
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
fn create_glyph_run_analysis(
&self,
params: &RenderGlyphParams,
advance: f32,
offset: DWRITE_GLYPH_OFFSET,
baseline_origin_x: f32,
baseline_origin_y: f32,
) -> Result<IDWriteGlyphRunAnalysis> {
let font = &self.fonts[params.font_id.0];
let glyph_id = [params.glyph_id.0 as u16];
let advance = [0.0f32];
let offset = [DWRITE_GLYPH_OFFSET::default()];
let advance = [advance];
let offset = [offset];
let glyph_run = DWRITE_GLYPH_RUN {
fontFace: unsafe { std::mem::transmute_copy(&font.font_face) },
fontEmSize: params.font_size.0,
@ -722,10 +729,6 @@ impl DirectWriteState {
isSideways: BOOL(0),
bidiLevel: 0,
};
let baseline_origin_x = 0.0;
let baseline_origin_y = 0.0;
let transform = DWRITE_MATRIX {
m11: params.scale_factor,
m12: 0.0,
@ -740,10 +743,10 @@ impl DirectWriteState {
unsafe {
font.font_face.GetRecommendedRenderingMode(
params.font_size.0,
// Is this correct?
1.0,
1.0,
Some(&transform),
// The dpi here seems that it has the same effect with `Some(&transform)`
params.scale_factor,
params.scale_factor,
None,
false,
DWRITE_OUTLINE_THRESHOLD_ANTIALIASED,
DWRITE_MEASURING_MODE_NATURAL,
@ -769,12 +772,19 @@ impl DirectWriteState {
antialias_mode,
baseline_origin_x,
baseline_origin_y,
)?
};
)
}?;
Ok(glyph_analysis)
}
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
let glyph_analysis =
self.create_glyph_run_analysis(params, 0.0, DWRITE_GLYPH_OFFSET::default(), 0.0, 0.0)?;
if params.is_emoji {
let bounds =
unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1)? };
// If it's empty, retry with grayscale AA.
if !unsafe { IsRectEmpty(&bounds) }.as_bool() {
return Ok(Bounds {
origin: point((bounds.left as i32).into(), (bounds.top as i32).into()),
@ -826,24 +836,6 @@ impl DirectWriteState {
anyhow::bail!("glyph bounds are empty");
}
let font_info = &self.fonts[params.font_id.0];
let glyph_id = [params.glyph_id.0 as u16];
let advance = [glyph_bounds.size.width.0 as f32];
let offset = [DWRITE_GLYPH_OFFSET {
advanceOffset: -glyph_bounds.origin.x.0 as f32 / params.scale_factor,
ascenderOffset: glyph_bounds.origin.y.0 as f32 / params.scale_factor,
}];
let glyph_run = DWRITE_GLYPH_RUN {
fontFace: ManuallyDrop::new(Some(font_info.font_face.cast()?)),
fontEmSize: params.font_size.0,
glyphCount: 1,
glyphIndices: glyph_id.as_ptr(),
glyphAdvances: advance.as_ptr(),
glyphOffsets: offset.as_ptr(),
isSideways: BOOL(0),
bidiLevel: 0,
};
// Add an extra pixel when the subpixel variant isn't zero to make room for anti-aliasing.
let mut bitmap_size = glyph_bounds.size;
if params.subpixel_variant.x > 0 {
@ -860,6 +852,31 @@ impl DirectWriteState {
let baseline_origin_x = subpixel_shift.x / params.scale_factor;
let baseline_origin_y = subpixel_shift.y / params.scale_factor;
let glyph_analysis = self.create_glyph_run_analysis(
params,
glyph_bounds.size.width.0 as f32,
DWRITE_GLYPH_OFFSET::default(),
baseline_origin_x,
baseline_origin_y,
)?;
let font = &self.fonts[params.font_id.0];
let glyph_id = [params.glyph_id.0 as u16];
let advance = [glyph_bounds.size.width.0 as f32];
let offset = [DWRITE_GLYPH_OFFSET {
advanceOffset: -glyph_bounds.origin.x.0 as f32 / params.scale_factor,
ascenderOffset: glyph_bounds.origin.y.0 as f32 / params.scale_factor,
}];
let glyph_run = DWRITE_GLYPH_RUN {
fontFace: unsafe { std::mem::transmute_copy(&font.font_face) },
fontEmSize: params.font_size.0,
glyphCount: 1,
glyphIndices: glyph_id.as_ptr(),
glyphAdvances: advance.as_ptr(),
glyphOffsets: offset.as_ptr(),
isSideways: BOOL(0),
bidiLevel: 0,
};
let transform = DWRITE_MATRIX {
m11: params.scale_factor,
m12: 0.0,
@ -869,74 +886,26 @@ impl DirectWriteState {
dy: 0.0,
};
let rendering_mode = if params.is_emoji {
DWRITE_RENDERING_MODE1_NATURAL
} else {
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC
};
let measuring_mode = DWRITE_MEASURING_MODE_NATURAL;
let glyph_analysis = unsafe {
self.components.factory.CreateGlyphRunAnalysis(
&glyph_run,
Some(&transform),
rendering_mode,
measuring_mode,
DWRITE_GRID_FIT_MODE_DEFAULT,
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
baseline_origin_x,
baseline_origin_y,
)?
};
let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1;
let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? };
let texture_width = (texture_bounds.right - texture_bounds.left) as u32;
let texture_height = (texture_bounds.bottom - texture_bounds.top) as u32;
if texture_width == 0 || texture_height == 0 {
return Ok((
bitmap_size,
vec![
0u8;
bitmap_size.width.0 as usize
* bitmap_size.height.0 as usize
* if params.is_emoji { 4 } else { 1 }
],
));
}
let mut bitmap_data: Vec<u8>;
if params.is_emoji {
if let Ok(color) = self.rasterize_color(
&glyph_run,
rendering_mode,
measuring_mode,
&transform,
point(baseline_origin_x, baseline_origin_y),
bitmap_size,
) {
bitmap_data = color;
} else {
let monochrome = Self::rasterize_monochrome(
&glyph_analysis,
bitmap_size,
size(texture_width, texture_height),
&texture_bounds,
)?;
let monochrome =
Self::rasterize_monochrome(&glyph_analysis, glyph_bounds.origin, bitmap_size)?;
bitmap_data = monochrome
.into_iter()
.flat_map(|pixel| [0, 0, 0, pixel])
.collect::<Vec<_>>();
}
} else {
bitmap_data = Self::rasterize_monochrome(
&glyph_analysis,
bitmap_size,
size(texture_width, texture_height),
&texture_bounds,
)?;
bitmap_data =
Self::rasterize_monochrome(&glyph_analysis, glyph_bounds.origin, bitmap_size)?;
}
Ok((bitmap_size, bitmap_data))
@ -944,56 +913,31 @@ impl DirectWriteState {
fn rasterize_monochrome(
glyph_analysis: &IDWriteGlyphRunAnalysis,
origin: Point<DevicePixels>,
bitmap_size: Size<DevicePixels>,
texture_size: Size<u32>,
texture_bounds: &RECT,
) -> Result<Vec<u8>> {
let mut bitmap_data =
vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize];
let mut alpha_data = vec![0u8; (texture_size.width * texture_size.height * 3) as usize];
unsafe {
glyph_analysis.CreateAlphaTexture(
DWRITE_TEXTURE_CLEARTYPE_3x1,
texture_bounds,
&mut alpha_data,
DWRITE_TEXTURE_ALIASED_1x1,
&RECT {
left: origin.x.0,
top: origin.y.0,
right: bitmap_size.width.0 + origin.x.0,
bottom: bitmap_size.height.0 + origin.y.0,
},
&mut bitmap_data,
)?;
}
// Convert ClearType RGB data to grayscale and place in bitmap
let offset_x = texture_bounds.left.max(0) as usize;
let offset_y = texture_bounds.top.max(0) as usize;
for y in 0..texture_size.height as usize {
for x in 0..texture_size.width as usize {
let bitmap_x = offset_x + x;
let bitmap_y = offset_y + y;
if bitmap_x < bitmap_size.width.0 as usize
&& bitmap_y < bitmap_size.height.0 as usize
{
let texture_idx = (y * texture_size.width as usize + x) * 3;
let bitmap_idx = bitmap_y * bitmap_size.width.0 as usize + bitmap_x;
if texture_idx + 2 < alpha_data.len() && bitmap_idx < bitmap_data.len() {
let max_value = alpha_data[texture_idx]
.max(alpha_data[texture_idx + 1])
.max(alpha_data[texture_idx + 2]);
bitmap_data[bitmap_idx] = max_value;
}
}
}
}
Ok(bitmap_data)
}
fn rasterize_color(
&self,
glyph_run: &DWRITE_GLYPH_RUN,
rendering_mode: DWRITE_RENDERING_MODE1,
measuring_mode: DWRITE_MEASURING_MODE,
transform: &DWRITE_MATRIX,
baseline_origin: Point<f32>,
bitmap_size: Size<DevicePixels>,
@ -1005,7 +949,7 @@ impl DirectWriteState {
glyph_run,
None,
DWRITE_GLYPH_IMAGE_FORMATS_COLR,
measuring_mode,
DWRITE_MEASURING_MODE_NATURAL,
Some(transform),
0,
)
@ -1021,8 +965,8 @@ impl DirectWriteState {
self.components.factory.CreateGlyphRunAnalysis(
&color_run.Base.glyphRun as *const _,
Some(transform),
rendering_mode,
measuring_mode,
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
DWRITE_MEASURING_MODE_NATURAL,
DWRITE_GRID_FIT_MODE_DEFAULT,
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
baseline_origin.x,