Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions crates/moon-gpui/src/gpu_canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,14 @@ pub struct GpuFrameInfo {
pub now: Instant,
/// Canvas bounds in logical pixels.
pub bounds: Bounds<Pixels>,
/// Window scale factor used to convert logical pixels to device pixels.
/// Effective window scale factor, the platform factor times the content zoom: `bounds`
/// times this is the canvas in device pixels.
pub scale_factor: f32,
/// The window's content zoom folded into `scale_factor`. A canvas that must keep device
/// density (a chart whose lines and captions should not follow UI zoom) sizes its own
/// geometry by `scale_factor / content_zoom` while still filling `bounds` times
/// `scale_factor` device pixels.
pub content_zoom: f32,
/// Whether the platform currently expects a present to be possible.
pub presentable: bool,
}
Expand Down Expand Up @@ -148,6 +154,9 @@ struct GpuCanvasRetainedTextCacheKey {
bounds: Bounds<Pixels>,
content_mask: ContentMask<ScaledPixels>,
scale_factor_bits: u32,
/// Keyed beside the combined factor: a consumer that keeps device density sizes by
/// `scale_factor / content_zoom`, which a zoom change offset by a DPI change leaves unchanged.
content_zoom_bits: u32,
background_appearance: WindowBackgroundAppearance,
subpixel_rendering_supported: bool,
text_rendering_mode: TextRenderingMode,
Expand Down Expand Up @@ -528,6 +537,7 @@ pub struct GpuCanvasTextContext<'a> {
pub(crate) sprite_atlas: Arc<dyn PlatformAtlas>,
pub(crate) bounds: Bounds<Pixels>,
pub(crate) scale_factor: f32,
pub(crate) content_zoom: f32,
pub(crate) content_mask: ContentMask<ScaledPixels>,
pub(crate) background_appearance: WindowBackgroundAppearance,
pub(crate) subpixel_rendering_supported: bool,
Expand All @@ -545,6 +555,7 @@ impl<'a> GpuCanvasTextContext<'a> {
sprite_atlas: Arc<dyn PlatformAtlas>,
bounds: Bounds<Pixels>,
scale_factor: f32,
content_zoom: f32,
content_mask: ContentMask<ScaledPixels>,
background_appearance: WindowBackgroundAppearance,
subpixel_rendering_supported: bool,
Expand All @@ -559,6 +570,7 @@ impl<'a> GpuCanvasTextContext<'a> {
sprite_atlas,
bounds,
scale_factor,
content_zoom,
content_mask,
background_appearance,
subpixel_rendering_supported,
Expand All @@ -581,11 +593,18 @@ impl<'a> GpuCanvasTextContext<'a> {
self.bounds
}

/// Window scale factor used for the current frame.
/// Effective window scale factor for the current frame: the platform factor times the
/// content zoom. Logical text metrics and origins times this are device pixels.
pub fn scale_factor(&self) -> f32 {
self.scale_factor
}

/// The window's content zoom folded into [`Self::scale_factor`]; see
/// [`GpuFrameInfo::content_zoom`].
pub fn content_zoom(&self) -> f32 {
self.content_zoom
}

/// Effective text clip in scaled/device pixels.
pub fn content_mask(&self) -> ContentMask<ScaledPixels> {
self.content_mask
Expand Down Expand Up @@ -621,6 +640,7 @@ impl<'a> GpuCanvasTextContext<'a> {
bounds: self.bounds,
content_mask: self.content_mask,
scale_factor_bits: self.scale_factor.to_bits(),
content_zoom_bits: self.content_zoom.to_bits(),
background_appearance: self.background_appearance,
subpixel_rendering_supported: self.subpixel_rendering_supported,
text_rendering_mode: self.text_rendering_mode,
Expand All @@ -633,6 +653,7 @@ impl<'a> GpuCanvasTextContext<'a> {
self.sprite_atlas.clone(),
self.bounds,
self.scale_factor,
self.content_zoom,
self.content_mask,
self.background_appearance,
self.subpixel_rendering_supported,
Expand Down
32 changes: 30 additions & 2 deletions crates/moon-gpui/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1261,9 +1261,19 @@ impl PlatformInputHandler {
.ok();
}

/// The platform-space bounds of a UTF-16 range, or `None` when the handler has none.
///
/// Every platform layer positions its IME candidate window from this (and from
/// [`Self::selected_bounds`]), so the content-space bounds the handler reports are multiplied
/// by the window's content zoom here, once, rather than in each platform.
pub fn bounds_for_range(&mut self, range_utf16: Range<usize>) -> Option<Bounds<Pixels>> {
self.cx
.update(|window, cx| self.handler.bounds_for_range(range_utf16, window, cx))
.update(|window, cx| {
let zoom = window.content_zoom();
self.handler
.bounds_for_range(range_utf16, window, cx)
.map(|bounds| bounds.map(|c| c * zoom))
})
.ok()
.flatten()
}
Expand Down Expand Up @@ -1312,14 +1322,24 @@ impl PlatformInputHandler {
}
}

/// The platform-space bounds the IME candidate window should sit beside, or `None`.
///
/// Content-space bounds from the handler, multiplied by the window's content zoom like
/// [`Self::bounds_for_range`].
pub fn selected_bounds(&mut self, window: &mut Window, cx: &mut App) -> Option<Bounds<Pixels>> {
let zoom = window.content_zoom();
let marked_range = self.handler.marked_text_range(window, cx);
let selection = self.handler.selected_text_range(true, window, cx)?;
Self::compute_ime_candidate_bounds(marked_range, &selection, |range| {
self.handler.bounds_for_range(range, window, cx)
})
.map(|bounds| bounds.map(|c| c * zoom))
}

/// [`Self::selected_bounds`] for a caller without the window in hand.
///
/// Composed from [`Self::bounds_for_range`], which already converts to platform space, so
/// nothing is multiplied again here.
pub fn ime_candidate_bounds(&mut self) -> Option<Bounds<Pixels>> {
let marked_range = self.marked_text_range();
let selection = self.selected_text_range(true)?;
Expand All @@ -1329,9 +1349,17 @@ impl PlatformInputHandler {
}

#[allow(unused)]
/// The character under a platform-space point, or `None`.
///
/// The point arrives in the platform's logical pixels and is divided by the content zoom
/// before the handler, which lays text out in content space, sees it.
pub fn character_index_for_point(&mut self, point: Point<Pixels>) -> Option<usize> {
self.cx
.update(|window, cx| self.handler.character_index_for_point(point, window, cx))
.update(|window, cx| {
let zoom = window.content_zoom();
self.handler
.character_index_for_point(point.map(|c| c / zoom), window, cx)
})
.ok()
.flatten()
}
Expand Down
Loading
Loading