Skip to content

Commit

Permalink
Rasterize glyphs using white on black (or viceversa) depending on bri…
Browse files Browse the repository at this point in the history
…ghtness
  • Loading branch information
as-cii committed Nov 11, 2024
1 parent 93ab6ad commit a80ff28
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 34 deletions.
6 changes: 6 additions & 0 deletions crates/gpui/src/color.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,12 @@ impl Hsla {
self.a == 0.0
}

/// Returns true if the color is considered "light", false otherwise.
/// A color is considered light if its lightness value is greater than 0.5.
pub fn is_light(&self) -> bool {
self.l > 0.5
}

/// Blends `other` on top of `self` based on `other`'s alpha value. The resulting color is a combination of `self`'s and `other`'s colors.
///
/// If `other`'s alpha value is 1.0 or greater, `other` color is fully opaque, thus `other` is returned as the output color.
Expand Down
110 changes: 76 additions & 34 deletions crates/gpui/src/platform/mac/text_system.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::open_type::apply_features_and_fallbacks;
use crate::{
point, px, size, Bounds, DevicePixels, Font, FontFallbacks, FontFeatures, FontId, FontMetrics,
FontRun, FontStyle, FontWeight, GlyphId, LineLayout, Pixels, PlatformTextSystem, Point,
Expand All @@ -13,10 +14,13 @@ use core_foundation::{
string::CFString,
};
use core_graphics::{
base::{kCGImageAlphaPremultipliedLast, CGGlyph},
base::{
kCGBitmapByteOrder32Little, kCGImageAlphaNoneSkipLast, kCGImageAlphaPremultipliedLast,
CGGlyph,
},
color_space::CGColorSpace,
context::CGContext,
display::CGPoint,
context::{CGBlendMode, CGContext, CGTextDrawingMode},
display::{CGPoint, CGRect, CGSize},
};
use core_text::{
font::CTFont,
Expand Down Expand Up @@ -44,11 +48,6 @@ use pathfinder_geometry::{
use smallvec::SmallVec;
use std::{borrow::Cow, char, cmp, convert::TryFrom, sync::Arc};

use super::open_type::apply_features_and_fallbacks;

#[allow(non_upper_case_globals)]
const kCGImageAlphaOnly: u32 = 7;

pub(crate) struct MacTextSystem(RwLock<MacTextSystemState>);

#[derive(Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -359,30 +358,63 @@ impl MacTextSystemState {
}
let bitmap_size = bitmap_size;

let mut bytes;
let cx;
if params.is_emoji {
bytes = vec![0; bitmap_size.width.0 as usize * 4 * bitmap_size.height.0 as usize];
cx = CGContext::create_bitmap_context(
Some(bytes.as_mut_ptr() as *mut _),
bitmap_size.width.0 as usize,
bitmap_size.height.0 as usize,
8,
bitmap_size.width.0 as usize * 4,
&CGColorSpace::create_device_rgb(),
kCGImageAlphaPremultipliedLast,
);
let color_type = if params.is_emoji {
kCGImageAlphaPremultipliedLast
} else {
bytes = vec![0; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize];
cx = CGContext::create_bitmap_context(
Some(bytes.as_mut_ptr() as *mut _),
bitmap_size.width.0 as usize,
bitmap_size.height.0 as usize,
8,
bitmap_size.width.0 as usize,
&CGColorSpace::create_device_gray(),
kCGImageAlphaOnly,
kCGImageAlphaNoneSkipLast
};
let mut bytes =
vec![0; bitmap_size.width.0 as usize * 4 * bitmap_size.height.0 as usize];
let cx = CGContext::create_bitmap_context(
Some(bytes.as_mut_ptr() as *mut _),
bitmap_size.width.0 as usize,
bitmap_size.height.0 as usize,
8,
bitmap_size.width.0 as usize * 4,
&CGColorSpace::create_device_rgb(),
kCGBitmapByteOrder32Little | color_type,
);
cx.set_allows_font_subpixel_positioning(true);
cx.set_should_subpixel_position_fonts(true);
cx.set_allows_font_subpixel_quantization(false);
cx.set_should_subpixel_quantize_fonts(false);
if !params.is_emoji {
cx.set_should_smooth_fonts(true);
cx.set_should_antialias(true);

let background_color;
let foreground_color;
if params.is_light {
background_color = [0., 0., 0.];
foreground_color = [1., 1., 1.];
} else {
background_color = [1., 1., 1.];
foreground_color = [0., 0., 0.];
}

cx.set_blend_mode(CGBlendMode::Copy);
cx.set_rgb_fill_color(
background_color[0],
background_color[1],
background_color[2],
1.,
);
cx.fill_rect(CGRect {
origin: CGPoint { x: 0.0, y: 0.0 },
size: CGSize {
width: bitmap_size.width.0 as CGFloat,
height: bitmap_size.height.0 as CGFloat,
},
});
cx.set_blend_mode(CGBlendMode::Normal);

cx.set_rgb_fill_color(
foreground_color[0],
foreground_color[1],
foreground_color[2],
1.,
);
cx.set_text_drawing_mode(CGTextDrawingMode::CGTextFill);
}

// Move the origin to bottom left and account for scaling, this
Expand All @@ -399,10 +431,7 @@ impl MacTextSystemState {
let subpixel_shift = params
.subpixel_variant
.map(|v| v as f32 / SUBPIXEL_VARIANTS as f32);
cx.set_allows_font_subpixel_positioning(true);
cx.set_should_subpixel_position_fonts(true);
cx.set_allows_font_subpixel_quantization(false);
cx.set_should_subpixel_quantize_fonts(false);

self.fonts[params.font_id.0]
.native_font()
.clone_with_font_size(f32::from(params.font_size) as CGFloat)
Expand All @@ -424,6 +453,19 @@ impl MacTextSystemState {
pixel[1] = (pixel[1] as f32 / a) as u8;
pixel[2] = (pixel[2] as f32 / a) as u8;
}
} else {
let mut index = 0;
bytes.retain_mut(|value| {
index += 1;
if index % 4 == 0 {
if !params.is_light {
*value = 255 - *value;
}
true
} else {
false
}
});
}

Ok((bitmap_size, bytes))
Expand Down
2 changes: 2 additions & 0 deletions crates/gpui/src/text_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ pub(crate) struct RenderGlyphParams {
pub(crate) subpixel_variant: Point<u8>,
pub(crate) scale_factor: f32,
pub(crate) is_emoji: bool,
pub(crate) is_light: bool,
}

impl Eq for RenderGlyphParams {}
Expand All @@ -669,6 +670,7 @@ impl Hash for RenderGlyphParams {
self.subpixel_variant.hash(state);
self.scale_factor.to_bits().hash(state);
self.is_emoji.hash(state);
self.is_light.hash(state);
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/gpui/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2447,6 +2447,7 @@ impl<'a> WindowContext<'a> {
subpixel_variant,
scale_factor,
is_emoji: false,
is_light: color.is_light(),
};

let raster_bounds = self.text_system().raster_bounds(&params)?;
Expand Down Expand Up @@ -2511,6 +2512,7 @@ impl<'a> WindowContext<'a> {
subpixel_variant: Default::default(),
scale_factor,
is_emoji: true,
is_light: false,
};

let raster_bounds = self.text_system().raster_bounds(&params)?;
Expand Down

0 comments on commit a80ff28

Please sign in to comment.