Merge 30ade60ee7
into bd4e943597
This commit is contained in:
commit
e087894c74
4 changed files with 33 additions and 93 deletions
|
@ -15,11 +15,6 @@ use std::{
|
||||||
rc::{Rc, Weak},
|
rc::{Rc, Weak},
|
||||||
sync::Arc,
|
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.
|
/// TestPlatform implements the Platform trait for use in tests.
|
||||||
pub(crate) struct TestPlatform {
|
pub(crate) struct TestPlatform {
|
||||||
|
@ -36,8 +31,6 @@ pub(crate) struct TestPlatform {
|
||||||
screen_capture_sources: RefCell<Vec<TestScreenCaptureSource>>,
|
screen_capture_sources: RefCell<Vec<TestScreenCaptureSource>>,
|
||||||
pub opened_url: RefCell<Option<String>>,
|
pub opened_url: RefCell<Option<String>>,
|
||||||
pub text_system: Arc<dyn PlatformTextSystem>,
|
pub text_system: Arc<dyn PlatformTextSystem>,
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
bitmap_factory: std::mem::ManuallyDrop<IWICImagingFactory>,
|
|
||||||
weak: Weak<Self>,
|
weak: Weak<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,16 +85,6 @@ pub(crate) struct TestPrompts {
|
||||||
|
|
||||||
impl TestPlatform {
|
impl TestPlatform {
|
||||||
pub fn new(executor: BackgroundExecutor, foreground_executor: ForegroundExecutor) -> Rc<Self> {
|
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);
|
let text_system = Arc::new(NoopTextSystem);
|
||||||
|
|
||||||
Rc::new_cyclic(|weak| TestPlatform {
|
Rc::new_cyclic(|weak| TestPlatform {
|
||||||
|
@ -117,8 +100,6 @@ impl TestPlatform {
|
||||||
current_primary_item: Mutex::new(None),
|
current_primary_item: Mutex::new(None),
|
||||||
weak: weak.clone(),
|
weak: weak.clone(),
|
||||||
opened_url: Default::default(),
|
opened_url: Default::default(),
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
bitmap_factory,
|
|
||||||
text_system,
|
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;
|
struct TestKeyboardLayout;
|
||||||
|
|
||||||
impl PlatformKeyboardLayout for TestKeyboardLayout {
|
impl PlatformKeyboardLayout for TestKeyboardLayout {
|
||||||
|
|
|
@ -15,7 +15,6 @@ use windows::{
|
||||||
DirectWrite::*,
|
DirectWrite::*,
|
||||||
Dxgi::Common::*,
|
Dxgi::Common::*,
|
||||||
Gdi::{IsRectEmpty, LOGFONTW},
|
Gdi::{IsRectEmpty, LOGFONTW},
|
||||||
Imaging::*,
|
|
||||||
},
|
},
|
||||||
System::SystemServices::LOCALE_NAME_MAX_LENGTH,
|
System::SystemServices::LOCALE_NAME_MAX_LENGTH,
|
||||||
UI::WindowsAndMessaging::*,
|
UI::WindowsAndMessaging::*,
|
||||||
|
@ -40,7 +39,6 @@ pub(crate) struct DirectWriteTextSystem(RwLock<DirectWriteState>);
|
||||||
struct DirectWriteComponent {
|
struct DirectWriteComponent {
|
||||||
locale: String,
|
locale: String,
|
||||||
factory: IDWriteFactory5,
|
factory: IDWriteFactory5,
|
||||||
bitmap_factory: AgileReference<IWICImagingFactory>,
|
|
||||||
in_memory_loader: IDWriteInMemoryFontFileLoader,
|
in_memory_loader: IDWriteInMemoryFontFileLoader,
|
||||||
builder: IDWriteFontSetBuilder1,
|
builder: IDWriteFontSetBuilder1,
|
||||||
text_renderer: Arc<TextRendererWrapper>,
|
text_renderer: Arc<TextRendererWrapper>,
|
||||||
|
@ -76,11 +74,10 @@ struct FontIdentifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectWriteComponent {
|
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
|
// todo: ideally this would not be a large unsafe block but smaller isolated ones for easier auditing
|
||||||
unsafe {
|
unsafe {
|
||||||
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?;
|
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?;
|
||||||
let bitmap_factory = AgileReference::new(bitmap_factory)?;
|
|
||||||
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
|
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
|
||||||
// Windows 10 Creators Update, which consequently requires the entire
|
// Windows 10 Creators Update, which consequently requires the entire
|
||||||
// `DirectWriteTextSystem` to run on `win10 1703`+.
|
// `DirectWriteTextSystem` to run on `win10 1703`+.
|
||||||
|
@ -117,7 +114,6 @@ impl DirectWriteComponent {
|
||||||
Ok(DirectWriteComponent {
|
Ok(DirectWriteComponent {
|
||||||
locale,
|
locale,
|
||||||
factory,
|
factory,
|
||||||
bitmap_factory,
|
|
||||||
in_memory_loader,
|
in_memory_loader,
|
||||||
builder,
|
builder,
|
||||||
text_renderer,
|
text_renderer,
|
||||||
|
@ -212,11 +208,8 @@ impl GPUState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DirectWriteTextSystem {
|
impl DirectWriteTextSystem {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(gpu_context: &DirectXDevices) -> Result<Self> {
|
||||||
gpu_context: &DirectXDevices,
|
let components = DirectWriteComponent::new(gpu_context)?;
|
||||||
bitmap_factory: &IWICImagingFactory,
|
|
||||||
) -> Result<Self> {
|
|
||||||
let components = DirectWriteComponent::new(bitmap_factory, gpu_context)?;
|
|
||||||
let system_font_collection = unsafe {
|
let system_font_collection = unsafe {
|
||||||
let mut result = std::mem::zeroed();
|
let mut result = std::mem::zeroed();
|
||||||
components
|
components
|
||||||
|
@ -782,8 +775,8 @@ impl DirectWriteState {
|
||||||
rendering_mode,
|
rendering_mode,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
DWRITE_MEASURING_MODE_NATURAL,
|
||||||
grid_fit_mode,
|
grid_fit_mode,
|
||||||
// We're using cleartype not grayscale for monochrome is because it provides better quality
|
// Use grayscale antialiasing for consistent quality across all color combinations
|
||||||
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
|
DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
|
||||||
baseline_origin_x,
|
baseline_origin_x,
|
||||||
baseline_origin_y,
|
baseline_origin_y,
|
||||||
)
|
)
|
||||||
|
@ -794,8 +787,8 @@ impl DirectWriteState {
|
||||||
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
|
fn raster_bounds(&self, params: &RenderGlyphParams) -> Result<Bounds<DevicePixels>> {
|
||||||
let glyph_analysis = self.create_glyph_run_analysis(params)?;
|
let glyph_analysis = self.create_glyph_run_analysis(params)?;
|
||||||
|
|
||||||
let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1)? };
|
let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1)? };
|
||||||
// Some glyphs cannot be drawn with ClearType, such as bitmap fonts. In that case
|
// 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.
|
// GetAlphaTextureBounds() supposedly returns an empty RECT, but I haven't tested that yet.
|
||||||
if !unsafe { IsRectEmpty(&bounds) }.as_bool() {
|
if !unsafe { IsRectEmpty(&bounds) }.as_bool() {
|
||||||
Ok(Bounds {
|
Ok(Bounds {
|
||||||
|
@ -871,49 +864,25 @@ impl DirectWriteState {
|
||||||
params: &RenderGlyphParams,
|
params: &RenderGlyphParams,
|
||||||
glyph_bounds: Bounds<DevicePixels>,
|
glyph_bounds: Bounds<DevicePixels>,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let mut bitmap_data =
|
// Use single-channel grayscale data directly from DirectWrite
|
||||||
vec![0u8; glyph_bounds.size.width.0 as usize * glyph_bounds.size.height.0 as usize * 3];
|
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)?;
|
let glyph_analysis = self.create_glyph_run_analysis(params)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
glyph_analysis.CreateAlphaTexture(
|
glyph_analysis.CreateAlphaTexture(
|
||||||
// We're using cleartype not grayscale for monochrome is because it provides better quality
|
DWRITE_TEXTURE_ALIASED_1x1,
|
||||||
DWRITE_TEXTURE_CLEARTYPE_3x1,
|
|
||||||
&RECT {
|
&RECT {
|
||||||
left: glyph_bounds.origin.x.0,
|
left: glyph_bounds.origin.x.0,
|
||||||
top: glyph_bounds.origin.y.0,
|
top: glyph_bounds.origin.y.0,
|
||||||
right: glyph_bounds.size.width.0 + glyph_bounds.origin.x.0,
|
right: glyph_bounds.size.width.0 + glyph_bounds.origin.x.0,
|
||||||
bottom: glyph_bounds.size.height.0 + glyph_bounds.origin.y.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()?;
|
Ok(grayscale_data)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rasterize_color(
|
fn rasterize_color(
|
||||||
|
@ -981,25 +950,24 @@ impl DirectWriteState {
|
||||||
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
|
DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC,
|
||||||
DWRITE_MEASURING_MODE_NATURAL,
|
DWRITE_MEASURING_MODE_NATURAL,
|
||||||
DWRITE_GRID_FIT_MODE_DEFAULT,
|
DWRITE_GRID_FIT_MODE_DEFAULT,
|
||||||
DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE,
|
DWRITE_TEXT_ANTIALIAS_MODE_GRAYSCALE,
|
||||||
baseline_origin_x,
|
baseline_origin_x,
|
||||||
baseline_origin_y,
|
baseline_origin_y,
|
||||||
)
|
)
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let color_bounds =
|
let color_bounds =
|
||||||
unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1) }?;
|
unsafe { color_analysis.GetAlphaTextureBounds(DWRITE_TEXTURE_ALIASED_1x1) }?;
|
||||||
|
|
||||||
let color_size = size(
|
let color_size = size(
|
||||||
color_bounds.right - color_bounds.left,
|
color_bounds.right - color_bounds.left,
|
||||||
color_bounds.bottom - color_bounds.top,
|
color_bounds.bottom - color_bounds.top,
|
||||||
);
|
);
|
||||||
if color_size.width > 0 && color_size.height > 0 {
|
if color_size.width > 0 && color_size.height > 0 {
|
||||||
let mut alpha_data =
|
let mut alpha_data = vec![0u8; (color_size.width * color_size.height) as usize];
|
||||||
vec![0u8; (color_size.width * color_size.height * 3) as usize];
|
|
||||||
unsafe {
|
unsafe {
|
||||||
color_analysis.CreateAlphaTexture(
|
color_analysis.CreateAlphaTexture(
|
||||||
DWRITE_TEXTURE_CLEARTYPE_3x1,
|
DWRITE_TEXTURE_ALIASED_1x1,
|
||||||
&color_bounds,
|
&color_bounds,
|
||||||
&mut alpha_data,
|
&mut alpha_data,
|
||||||
)
|
)
|
||||||
|
@ -1016,8 +984,8 @@ impl DirectWriteState {
|
||||||
};
|
};
|
||||||
let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
|
let bounds = bounds(point(color_bounds.left, color_bounds.top), color_size);
|
||||||
let alpha_data = alpha_data
|
let alpha_data = alpha_data
|
||||||
.chunks_exact(3)
|
.iter()
|
||||||
.flat_map(|chunk| [chunk[0], chunk[1], chunk[2], 255])
|
.flat_map(|&alpha| [255, 255, 255, alpha])
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
glyph_layers.push(GlyphLayerTexture::new(
|
glyph_layers.push(GlyphLayerTexture::new(
|
||||||
&self.components.gpu_state,
|
&self.components.gpu_state,
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
ffi::OsStr,
|
ffi::OsStr,
|
||||||
mem::ManuallyDrop,
|
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
@ -18,10 +17,7 @@ use windows::{
|
||||||
UI::ViewManagement::UISettings,
|
UI::ViewManagement::UISettings,
|
||||||
Win32::{
|
Win32::{
|
||||||
Foundation::*,
|
Foundation::*,
|
||||||
Graphics::{
|
Graphics::Gdi::*,
|
||||||
Gdi::*,
|
|
||||||
Imaging::{CLSID_WICImagingFactory, IWICImagingFactory},
|
|
||||||
},
|
|
||||||
Security::Credentials::*,
|
Security::Credentials::*,
|
||||||
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
|
System::{Com::*, LibraryLoader::*, Ole::*, SystemInformation::*, Threading::*},
|
||||||
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
UI::{Input::KeyboardAndMouse::*, Shell::*, WindowsAndMessaging::*},
|
||||||
|
@ -41,7 +37,6 @@ pub(crate) struct WindowsPlatform {
|
||||||
foreground_executor: ForegroundExecutor,
|
foreground_executor: ForegroundExecutor,
|
||||||
text_system: Arc<DirectWriteTextSystem>,
|
text_system: Arc<DirectWriteTextSystem>,
|
||||||
windows_version: WindowsVersion,
|
windows_version: WindowsVersion,
|
||||||
bitmap_factory: ManuallyDrop<IWICImagingFactory>,
|
|
||||||
drop_target_helper: IDropTargetHelper,
|
drop_target_helper: IDropTargetHelper,
|
||||||
validation_number: usize,
|
validation_number: usize,
|
||||||
main_thread_id_win32: u32,
|
main_thread_id_win32: u32,
|
||||||
|
@ -101,12 +96,8 @@ impl WindowsPlatform {
|
||||||
let foreground_executor = ForegroundExecutor::new(dispatcher);
|
let foreground_executor = ForegroundExecutor::new(dispatcher);
|
||||||
let directx_devices = DirectXDevices::new(disable_direct_composition)
|
let directx_devices = DirectXDevices::new(disable_direct_composition)
|
||||||
.context("Unable to init directx devices.")?;
|
.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(
|
let text_system = Arc::new(
|
||||||
DirectWriteTextSystem::new(&directx_devices, &bitmap_factory)
|
DirectWriteTextSystem::new(&directx_devices)
|
||||||
.context("Error creating DirectWriteTextSystem")?,
|
.context("Error creating DirectWriteTextSystem")?,
|
||||||
);
|
);
|
||||||
let drop_target_helper: IDropTargetHelper = unsafe {
|
let drop_target_helper: IDropTargetHelper = unsafe {
|
||||||
|
@ -128,7 +119,6 @@ impl WindowsPlatform {
|
||||||
text_system,
|
text_system,
|
||||||
disable_direct_composition,
|
disable_direct_composition,
|
||||||
windows_version,
|
windows_version,
|
||||||
bitmap_factory,
|
|
||||||
drop_target_helper,
|
drop_target_helper,
|
||||||
validation_number,
|
validation_number,
|
||||||
main_thread_id_win32,
|
main_thread_id_win32,
|
||||||
|
@ -716,7 +706,6 @@ impl Platform for WindowsPlatform {
|
||||||
impl Drop for WindowsPlatform {
|
impl Drop for WindowsPlatform {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
ManuallyDrop::drop(&mut self.bitmap_factory);
|
|
||||||
OleUninitialize();
|
OleUninitialize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1098,6 +1098,18 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI
|
||||||
|
|
||||||
float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target {
|
float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target {
|
||||||
float sample = t_sprite.Sample(s_sprite, input.tile_position).r;
|
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);
|
return float4(input.color.rgb, input.color.a * sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue