diff --git a/alacritty/src/config/window.rs b/alacritty/src/config/window.rs index 507a4f2c..f181289a 100644 --- a/alacritty/src/config/window.rs +++ b/alacritty/src/config/window.rs @@ -85,9 +85,9 @@ impl WindowConfig { } #[inline] - pub fn padding(&self, dpr: f64) -> (f32, f32) { - let padding_x = (f32::from(self.padding.x) * dpr as f32).floor(); - let padding_y = (f32::from(self.padding.y) * dpr as f32).floor(); + pub fn padding(&self, scale_factor: f64) -> (f32, f32) { + let padding_x = (f32::from(self.padding.x) * scale_factor as f32).floor(); + let padding_y = (f32::from(self.padding.y) * scale_factor as f32).floor(); (padding_x, padding_y) } diff --git a/alacritty/src/display/mod.rs b/alacritty/src/display/mod.rs index c58ded5d..dda32b0f 100644 --- a/alacritty/src/display/mod.rs +++ b/alacritty/src/display/mod.rs @@ -5,7 +5,6 @@ use std::convert::TryFrom; use std::fmt::{self, Formatter}; #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] use std::sync::atomic::Ordering; -use std::time::Instant; use std::{cmp, mem}; use glutin::dpi::PhysicalSize; @@ -223,26 +222,29 @@ impl Display { #[cfg(all(feature = "x11", not(any(target_os = "macos", windows))))] let is_x11 = event_loop.is_x11(); - // Guess DPR based on first monitor. On Wayland the initial frame always renders at a DPR - // of 1. - let estimated_dpr = if cfg!(any(target_os = "macos", windows)) || is_x11 { + // Guess scale_factor based on first monitor. On Wayland the initial frame always renders at + // a scale factor of 1. + let estimated_scale_factor = if cfg!(any(target_os = "macos", windows)) || is_x11 { event_loop.available_monitors().next().map(|m| m.scale_factor()).unwrap_or(1.) } else { 1. }; // Guess the target window dimensions. - let mut rasterizer = Rasterizer::new(estimated_dpr as f32, config.font.use_thin_strokes)?; - let metrics = GlyphCache::static_metrics(&mut rasterizer, config.font.clone())?; + debug!("Loading \"{}\" font", &config.font.normal().family); + let font = &config.font; + let rasterizer = Rasterizer::new(estimated_scale_factor as f32, font.use_thin_strokes)?; + let mut glyph_cache = GlyphCache::new(rasterizer, font)?; + let metrics = glyph_cache.font_metrics(); let (cell_width, cell_height) = compute_cell_size(config, &metrics); // Guess the target window size if the user has specified the number of lines/columns. let dimensions = config.window.dimensions(); let estimated_size = dimensions.map(|dimensions| { - window_size(config, dimensions, cell_width, cell_height, estimated_dpr) + window_size(config, dimensions, cell_width, cell_height, estimated_scale_factor) }); - debug!("Estimated DPR: {}", estimated_dpr); + debug!("Estimated scaling factor: {}", estimated_scale_factor); debug!("Estimated window size: {:?}", estimated_size); debug!("Estimated cell size: {} x {}", cell_width, cell_height); @@ -256,26 +258,34 @@ impl Display { wayland_event_queue, )?; - info!("Device pixel ratio: {}", window.dpr); - rasterizer.update_dpr(window.dpr as f32); - // Create renderer. let mut renderer = QuadRenderer::new()?; - let (glyph_cache, cell_width, cell_height) = - Self::new_glyph_cache(rasterizer, &mut renderer, config)?; + let scale_factor = window.scale_factor; + info!("Display scale factor: {}", scale_factor); - if let Some(dimensions) = dimensions { - if (estimated_dpr - window.dpr).abs() < f64::EPSILON { - info!("Estimated DPR correctly, skipping resize"); - } else { - // Resize the window again if the DPR was not estimated correctly. - let size = window_size(config, dimensions, cell_width, cell_height, window.dpr); - window.set_inner_size(size); - } + // If the scaling factor changed update the glyph cache and mark for resize. + let should_resize = (estimated_scale_factor - window.scale_factor).abs() > f64::EPSILON; + let (cell_width, cell_height) = if should_resize { + Self::update_glyph_cache(&mut renderer, &mut glyph_cache, scale_factor, config, font) + } else { + (cell_width, cell_height) + }; + + // Load font common glyphs to accelerate rendering. + debug!("Filling glyph cache with common glyphs"); + renderer.with_loader(|mut api| { + glyph_cache.load_common_glyphs(&mut api); + }); + + if let Some(dimensions) = dimensions.filter(|_| should_resize) { + // Resize the window again if the scale factor was not estimated correctly. + let size = + window_size(config, dimensions, cell_width, cell_height, window.scale_factor); + window.set_inner_size(size); } - let padding = config.window.padding(window.dpr); + let padding = config.window.padding(window.scale_factor); let viewport_size = window.inner_size(); // Create new size with at least one column and row. @@ -362,49 +372,22 @@ impl Display { }) } - fn new_glyph_cache( - rasterizer: Rasterizer, - renderer: &mut QuadRenderer, - config: &UiConfig, - ) -> Result<(GlyphCache, f32, f32), Error> { - let font = config.font.clone(); - - // Initialize glyph cache. - let glyph_cache = { - info!("Initializing glyph cache..."); - let init_start = Instant::now(); - - let cache = - renderer.with_loader(|mut api| GlyphCache::new(rasterizer, &font, &mut api))?; - - let stop = init_start.elapsed(); - let stop_f = stop.as_secs() as f64 + f64::from(stop.subsec_nanos()) / 1_000_000_000f64; - info!("... finished initializing glyph cache in {}s", stop_f); - - cache - }; - - // Need font metrics to resize the window properly. This suggests to me the - // font metrics should be computed before creating the window in the first - // place so that a resize is not needed. - let (cw, ch) = compute_cell_size(config, &glyph_cache.font_metrics()); - - Ok((glyph_cache, cw, ch)) - } - /// Update font size and cell dimensions. /// /// This will return a tuple of the cell width and height. - fn update_glyph_cache(&mut self, config: &UiConfig, font: &Font) -> (f32, f32) { - let cache = &mut self.glyph_cache; - let dpr = self.window.dpr; - - self.renderer.with_loader(|mut api| { - let _ = cache.update_font_size(font, dpr, &mut api); + fn update_glyph_cache( + renderer: &mut QuadRenderer, + glyph_cache: &mut GlyphCache, + scale_factor: f64, + config: &UiConfig, + font: &Font, + ) -> (f32, f32) { + renderer.with_loader(|mut api| { + let _ = glyph_cache.update_font_size(font, scale_factor, &mut api); }); // Compute new cell sizes. - compute_cell_size(config, &self.glyph_cache.font_metrics()) + compute_cell_size(config, &glyph_cache.font_metrics()) } /// Clear glyph cache. @@ -436,7 +419,14 @@ impl Display { // Update font size and cell dimensions. if let Some(font) = pending_update.font() { - let cell_dimensions = self.update_glyph_cache(config, font); + let scale_factor = self.window.scale_factor; + let cell_dimensions = Self::update_glyph_cache( + &mut self.renderer, + &mut self.glyph_cache, + scale_factor, + config, + font, + ); cell_width = cell_dimensions.0; cell_height = cell_dimensions.1; @@ -451,7 +441,7 @@ impl Display { height = dimensions.height as f32; } - let padding = config.window.padding(self.window.dpr); + let padding = config.window.padding(self.window.scale_factor); self.size_info = SizeInfo::new( width, @@ -1021,9 +1011,9 @@ fn window_size( dimensions: Dimensions, cell_width: f32, cell_height: f32, - dpr: f64, + scale_factor: f64, ) -> PhysicalSize { - let padding = config.window.padding(dpr); + let padding = config.window.padding(scale_factor); let grid_width = cell_width * dimensions.columns.0.max(MIN_COLUMNS) as f32; let grid_height = cell_height * dimensions.lines.max(MIN_SCREEN_LINES) as f32; diff --git a/alacritty/src/display/window.rs b/alacritty/src/display/window.rs index 712b4ac9..222e52b0 100644 --- a/alacritty/src/display/window.rs +++ b/alacritty/src/display/window.rs @@ -151,8 +151,8 @@ pub struct Window { #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] pub wayland_surface: Option>, - /// Cached DPR for quickly scaling pixel sizes. - pub dpr: f64, + /// Cached scale factor for quickly scaling pixel sizes. + pub scale_factor: f64, /// Current window title. title: String, @@ -219,7 +219,7 @@ impl Window { None }; - let dpr = windowed_context.window().scale_factor(); + let scale_factor = windowed_context.window().scale_factor(); Ok(Self { current_mouse_cursor, @@ -230,7 +230,7 @@ impl Window { should_draw: Arc::new(AtomicBool::new(true)), #[cfg(all(feature = "wayland", not(any(target_os = "macos", windows))))] wayland_surface, - dpr, + scale_factor, }) } diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 6885415f..1fd42fe6 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -83,7 +83,7 @@ impl From for GlutinEvent<'_, Event> { /// Alacritty events. #[derive(Debug, Clone)] pub enum EventType { - DprChanged(f64, (u32, u32)), + ScaleFactorChanged(f64, (u32, u32)), Terminal(TerminalEvent), ConfigReload(PathBuf), Message(Message), @@ -1026,17 +1026,17 @@ impl input::Processor> { pub fn handle_event(&mut self, event: GlutinEvent<'_, Event>) { match event { GlutinEvent::UserEvent(Event { payload, .. }) => match payload { - EventType::DprChanged(scale_factor, (width, height)) => { + EventType::ScaleFactorChanged(scale_factor, (width, height)) => { let display_update_pending = &mut self.ctx.display.pending_update; - // Push current font to update its DPR. + // Push current font to update its scale factor. let font = self.ctx.config.font.clone(); display_update_pending.set_font(font.with_size(*self.ctx.font_size)); // Resize to event's dimensions, since no resize event is emitted on Wayland. display_update_pending.set_dimensions(PhysicalSize::new(width, height)); - self.ctx.window().dpr = scale_factor; + self.ctx.window().scale_factor = scale_factor; *self.ctx.dirty = true; }, EventType::SearchNext => self.ctx.goto_match(None), diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 51bd3fc5..f1b4a138 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -923,14 +923,14 @@ impl> Processor { /// Handle automatic scrolling when selecting above/below the window. fn update_selection_scrolling(&mut self, mouse_y: i32) { - let dpr = self.ctx.window().dpr; + let scale_factor = self.ctx.window().scale_factor; let size = self.ctx.size_info(); let window_id = self.ctx.window().id(); let scheduler = self.ctx.scheduler_mut(); // Scale constants by DPI. - let min_height = (MIN_SELECTION_SCROLLING_HEIGHT * dpr) as i32; - let step = (SELECTION_SCROLLING_STEP * dpr) as i32; + let min_height = (MIN_SELECTION_SCROLLING_HEIGHT * scale_factor) as i32; + let step = (SELECTION_SCROLLING_STEP * scale_factor) as i32; // Compute the height of the scrolling areas. let end_top = max(min_height, size.padding_y() as i32); diff --git a/alacritty/src/renderer/mod.rs b/alacritty/src/renderer/mod.rs index e7878b6d..4aa562ad 100644 --- a/alacritty/src/renderer/mod.rs +++ b/alacritty/src/renderer/mod.rs @@ -156,14 +156,7 @@ pub struct GlyphCache { } impl GlyphCache { - pub fn new( - mut rasterizer: Rasterizer, - font: &Font, - loader: &mut L, - ) -> Result - where - L: LoadGlyph, - { + pub fn new(mut rasterizer: Rasterizer, font: &Font) -> Result { let (regular, bold, italic, bold_italic) = Self::compute_font_keys(font, &mut rasterizer)?; // Need to load at least one glyph for the face before calling metrics. @@ -173,7 +166,7 @@ impl GlyphCache { let metrics = rasterizer.metrics(regular, font.size())?; - let mut cache = Self { + Ok(Self { cache: HashMap::default(), rasterizer, font_size: font.size(), @@ -185,11 +178,7 @@ impl GlyphCache { glyph_offset: font.glyph_offset, metrics, builtin_box_drawing: font.builtin_box_drawing, - }; - - cache.load_common_glyphs(loader); - - Ok(cache) + }) } fn load_glyphs_for_font(&mut self, font: FontKey, loader: &mut L) { @@ -358,11 +347,11 @@ impl GlyphCache { pub fn update_font_size( &mut self, font: &Font, - dpr: f64, + scale_factor: f64, loader: &mut L, ) -> Result<(), crossfont::Error> { // Update dpi scaling. - self.rasterizer.update_dpr(dpr as f32); + self.rasterizer.update_dpr(scale_factor as f32); self.font_offset = font.offset; // Recompute font keys. @@ -376,7 +365,7 @@ impl GlyphCache { })?; let metrics = self.rasterizer.metrics(regular, font.size())?; - info!("Font size changed to {:?} with DPR of {}", font.size(), dpr); + info!("Font size changed to {:?} with scale factor of {}", font.size(), scale_factor); self.font_size = font.size(); self.font_key = regular; @@ -396,24 +385,12 @@ impl GlyphCache { } /// Prefetch glyphs that are almost guaranteed to be loaded anyways. - fn load_common_glyphs(&mut self, loader: &mut L) { + pub fn load_common_glyphs(&mut self, loader: &mut L) { self.load_glyphs_for_font(self.font_key, loader); self.load_glyphs_for_font(self.bold_key, loader); self.load_glyphs_for_font(self.italic_key, loader); self.load_glyphs_for_font(self.bold_italic_key, loader); } - - /// Calculate font metrics without access to a glyph cache. - pub fn static_metrics( - rasterizer: &mut crossfont::Rasterizer, - font: Font, - ) -> Result { - let regular_desc = GlyphCache::make_desc(font.normal(), Slant::Normal, Weight::Normal); - let regular = Self::load_regular_font(rasterizer, ®ular_desc, font.size())?; - rasterizer.get_glyph(GlyphKey { font_key: regular, character: 'm', size: font.size() })?; - - rasterizer.metrics(regular, font.size()) - } } // NOTE: These flags must be in sync with their usage in the text.*.glsl shaders. diff --git a/alacritty/src/window_context.rs b/alacritty/src/window_context.rs index 6af46e03..c9b27ed6 100644 --- a/alacritty/src/window_context.rs +++ b/alacritty/src/window_context.rs @@ -242,13 +242,14 @@ impl WindowContext { }, // Continue to process all pending events. GlutinEvent::RedrawEventsCleared => (), - // Remap DPR change event to remove the lifetime. + // Remap scale_factor change event to remove the lifetime. GlutinEvent::WindowEvent { event: WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size }, window_id, } => { let size = (new_inner_size.width, new_inner_size.height); - let event = Event::new(EventType::DprChanged(scale_factor, size), window_id); + let event = + Event::new(EventType::ScaleFactorChanged(scale_factor, size), window_id); self.event_queue.push(event.into()); return; },