This commit is contained in:
James Tucker 2025-08-26 16:02:01 -04:00 committed by GitHub
commit e087894c74
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 33 additions and 93 deletions

View file

@ -15,11 +15,6 @@ use std::{
rc::{Rc, Weak},
sync::Arc,
};
#[cfg(target_os = "windows")]
use windows::Win32::{
Graphics::Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
System::Com::{CLSCTX_INPROC_SERVER, CoCreateInstance},
};
/// TestPlatform implements the Platform trait for use in tests.
pub(crate) struct TestPlatform {
@ -36,8 +31,6 @@ pub(crate) struct TestPlatform {
screen_capture_sources: RefCell<Vec<TestScreenCaptureSource>>,
pub opened_url: RefCell<Option<String>>,
pub text_system: Arc<dyn PlatformTextSystem>,
#[cfg(target_os = "windows")]
bitmap_factory: std::mem::ManuallyDrop<IWICImagingFactory>,
weak: Weak<Self>,
}
@ -92,16 +85,6 @@ pub(crate) struct TestPrompts {
impl TestPlatform {
pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Rc<Self> {
#[cfg(target_os = "windows")]
let bitmap_factory = unsafe {
windows::Win32::System::Ole::OleInitialize(None)
.expect("unable to initialize Windows OLE");
std::mem::ManuallyDrop::new(
CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)
.expect("Error creating bitmap factory."),
)
};
let text_system = Arc::new(NoopTextSystem);
Rc::new_cyclic(|weak| TestPlatform {
@ -117,8 +100,6 @@ impl TestPlatform {
current_primary_item: Mutex::new(None),
weak: weak.clone(),
opened_url: Default::default(),
#[cfg(target_os = "windows")]
bitmap_factory,
text_system,
})
}
@ -440,16 +421,6 @@ impl TestScreenCaptureSource {
}
}
#[cfg(target_os = "windows")]
impl Drop for TestPlatform {
fn drop(&mut self) {
unsafe {
std::mem::ManuallyDrop::drop(&mut self.bitmap_factory);
windows::Win32::System::Ole::OleUninitialize();
}
}
}
struct TestKeyboardLayout;
impl PlatformKeyboardLayout for TestKeyboardLayout {

View file

@ -15,7 +15,6 @@ use windows::{
DirectWrite::*,
Dxgi::Common::*,
Gdi::{IsRectEmpty, LOGFONTW},
Imaging::*,
},
System::SystemServices::LOCALE_NAME_MAX_LENGTH,
UI::WindowsAndMessaging::*,
@ -40,7 +39,6 @@ pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>);
struct DirectWriteComponent {
locale: String,
factory: IDWriteFactory5,
bitmap_factory: AgileReference<IWICImagingFactory>,
in_memory_loader: IDWriteInMemoryFontFileLoader,
builder: IDWriteFontSetBuilder1,
text_renderer: Arc<TextRendererWrapper>,
@ -76,11 +74,10 @@ struct FontIdentifier {
}
impl DirectWriteComponent {
pub fn new(bitmap_factory: &IWICImagingFactory, gpu_context: &DirectXDevices) -> Result<Self> {
pub fn new(gpu_context: &DirectXDevices) -> Result<Self> {
// todo: ideally this would not be a large unsafe block but smaller isolated ones for easier auditing
unsafe {
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?;
let bitmap_factory = AgileReference::new(bitmap_factory)?;
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
// Windows 10 Creators Update, which consequently requires the entire
// `DirectWriteTextSystem` to run on `win10 1703`+.
@ -117,7 +114,6 @@ impl DirectWriteComponent {
Ok(DirectWriteComponent {
locale,
factory,
bitmap_factory,
in_memory_loader,
builder,
text_renderer,
@ -212,11 +208,8 @@ impl GPUState {
}
impl DirectWriteTextSystem {
pub(crate) fn new(
gpu_context: &DirectXDevices,
bitmap_factory: &IWICImagingFactory,
) -> Result<Self> {
let components = DirectWriteComponent::new(bitmap_factory, gpu_context)?;
pub(crate) fn new(gpu_context: &DirectXDevices) -> Result<Self> {
let components = DirectWriteComponent::new(gpu_context)?;
let system_font_collection = unsafe {
let mut result = std::mem::zeroed();
components
@ -782,8 +775,8 @@ impl DirectWriteState {
rendering_mode,
DWRITE_MEASURING_MODE_NATURAL,
grid_fit_mode,
// We're using cleartype not grayscale for monochrome is because it provides better quality
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
// Use grayscale antialiasing for consistent quality across all color combinations
DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
baseline_origin_x,
baseline_origin_y,
)
@ -794,8 +787,8 @@ impl DirectWriteState {
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
let glyph_analysis = self.create_glyph_run_analysis(params)?;
let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1)? };
// Some glyphs cannot be drawn with ClearType, such as bitmap fonts. In that case
let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1)? };
// Some glyphs cannot be drawn with antialiasing, such as bitmap fonts. In that case
// GetAlphaTextureBounds() supposedly returns an empty RECT, but I haven't tested that yet.
if !unsafe { IsRectEmpty(&bounds) }.as_bool() {
Ok(Bounds {
@ -871,49 +864,25 @@ impl DirectWriteState {
params: &RenderGlyphParams,
glyph_bounds: Bounds<DevicePixels>,
) -> Result<Vec<u8>> {
let mut bitmap_data =
vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize * 3];
// Use single-channel grayscale data directly from DirectWrite
let mut grayscale_data =
vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize];
let glyph_analysis = self.create_glyph_run_analysis(params)?;
unsafe {
glyph_analysis.CreateAlphaTexture(
// We're using cleartype not grayscale for monochrome is because it provides better quality
DWRITE_TEXTURE_CLEARTYPE_3x1,
DWRITE_TEXTURE_ALIASED_1x1,
&RECT {
left: glyph_bounds.origin.x.0,
top: glyph_bounds.origin.y.0,
right: glyph_bounds.size.width.0 + glyph_bounds.origin.x.0,
bottom: glyph_bounds.size.height.0 + glyph_bounds.origin.y.0,
},
&mut bitmap_data,
&mut grayscale_data,
)?;
}
let bitmap_factory = self.components.bitmap_factory.resolve()?;
let bitmap = unsafe {
bitmap_factory.CreateBitmapFromMemory(
glyph_bounds.size.width.0 as u32,
glyph_bounds.size.height.0 as u32,
&GUID_WICPixelFormat24bppRGB,
glyph_bounds.size.width.0 as u32 * 3,
&bitmap_data,
)
}?;
let grayscale_bitmap =
unsafe { WICConvertBitmapSource(&GUID_WICPixelFormat8bppGray, &bitmap) }?;
let mut bitmap_data =
vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize];
unsafe {
grayscale_bitmap.CopyPixels(
std::ptr::null() as _,
glyph_bounds.size.width.0 as u32,
&mut bitmap_data,
)
}?;
Ok(bitmap_data)
Ok(grayscale_data)
}
fn rasterize_color(
@ -981,25 +950,24 @@ impl DirectWriteState {
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
DWRITE_MEASURING_MODE_NATURAL,
DWRITE_GRID_FIT_MODE_DEFAULT,
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
baseline_origin_x,
baseline_origin_y,
)
}?;
let color_bounds =
unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1) }?;
unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1) }?;
let color_size = size(
color_bounds.right - color_bounds.left,
color_bounds.bottom - color_bounds.top,
);
if color_size.width > 0 && color_size.height > 0 {
let mut alpha_data =
vec![0u8; (color_size.width * color_size.height * 3) as usize];
let mut alpha_data = vec![0u8; (color_size.width * color_size.height) as usize];
unsafe {
color_analysis.CreateAlphaTexture(
DWRITE_TEXTURE_CLEARTYPE_3x1,
DWRITE_TEXTURE_ALIASED_1x1,
&color_bounds,
&mut alpha_data,
)
@ -1016,8 +984,8 @@ impl DirectWriteState {
};
let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
let alpha_data = alpha_data
.chunks_exact(3)
.flat_map(|chunk| [chunk[0], chunk[1], chunk[2], 255])
.iter()
.flat_map(|&alpha| [255, 255, 255, alpha])
.collect::<Vec<_>>();
glyph_layers.push(GlyphLayerTexture::new(
&self.components.gpu_state,

View file

@ -1,7 +1,6 @@
use std::{
cell::RefCell,
ffi::OsStr,
mem::ManuallyDrop,
path::{Path, PathBuf},
rc::Rc,
sync::Arc,
@ -18,10 +17,7 @@ use windows::{
UI::ViewManagement::UISettings,
Win32::{
Foundation::*,
Graphics::{
Gdi::*,
Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
},
Graphics::Gdi::*,
Security::Credentials::*,
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
@ -41,7 +37,6 @@ pub(crate) struct WindowsPlatform {
foreground_executor: ForegroundExecutor,
text_system: Arc<DirectWriteTextSystem>,
windows_version: WindowsVersion,
bitmap_factory: ManuallyDrop<IWICImagingFactory>,
drop_target_helper: IDropTargetHelper,
validation_number: usize,
main_thread_id_win32: u32,
@ -101,12 +96,8 @@ impl WindowsPlatform {
let foreground_executor = ForegroundExecutor::new(dispatcher);
let directx_devices = DirectXDevices::new(disable_direct_composition)
.context("Unable to init directx devices.")?;
let bitmap_factory = ManuallyDrop::new(unsafe {
CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)
.context("Error creating bitmap factory.")?
});
let text_system = Arc::new(
DirectWriteTextSystem::new(&directx_devices, &bitmap_factory)
DirectWriteTextSystem::new(&directx_devices)
.context("Error creating DirectWriteTextSystem")?,
);
let drop_target_helper: IDropTargetHelper = unsafe {
@ -128,7 +119,6 @@ impl WindowsPlatform {
text_system,
disable_direct_composition,
windows_version,
bitmap_factory,
drop_target_helper,
validation_number,
main_thread_id_win32,
@ -716,7 +706,6 @@ impl Platform for WindowsPlatform {
impl Drop for WindowsPlatform {
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.bitmap_factory);
OleUninitialize();
}
}

View file

@ -1098,6 +1098,18 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI
float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target {
float sample = t_sprite.Sample(s_sprite, input.tile_position).r;
float textLuminance = dot(input.color.rgb, float3(0.2126, 0.7152, 0.0722));
bool isLightText = textLuminance > 0.5;
if (isLightText) {
// Stronger gamma correction - try values from 0.4 to 0.6
sample = pow(sample, 0.45);
// More aggressive bias to strengthen thin features
sample = saturate(sample * 1.2 - 0.1);
}
return float4(input.color.rgb, input.color.a * sample);
}