1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-26 14:54:16 +03:00

CellAttributes: split color into thin/fat components

The common palette indices are in the main cell attributes.
Using true color will allocate fat storage.

This allows reducing the Cell size from 32 -> 24 across the
implementation of storing 10 bpc color (it peaked at 40 in
the last couple of commits).
This commit is contained in:
Wez Furlong 2021-07-10 15:32:26 -07:00
parent 47839adf95
commit 4e99edf6f5

View File

@ -1,5 +1,5 @@
//! Model a cell in the terminal display //! Model a cell in the terminal display
use crate::color::ColorAttribute; use crate::color::{ColorAttribute, PaletteIndex};
pub use crate::escape::osc::Hyperlink; pub use crate::escape::osc::Hyperlink;
use crate::image::ImageCell; use crate::image::ImageCell;
#[cfg(feature = "use_serde")] #[cfg(feature = "use_serde")]
@ -8,6 +8,28 @@ use std::mem;
use std::sync::Arc; use std::sync::Arc;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
enum SmallColor {
Default,
PaletteIndex(PaletteIndex),
}
impl Default for SmallColor {
fn default() -> Self {
Self::Default
}
}
impl Into<ColorAttribute> for SmallColor {
fn into(self) -> ColorAttribute {
match self {
Self::Default => ColorAttribute::Default,
Self::PaletteIndex(idx) => ColorAttribute::PaletteIndex(idx),
}
}
}
/// Holds the attributes for a cell. /// Holds the attributes for a cell.
/// Most style attributes are stored internally as part of a bitfield /// Most style attributes are stored internally as part of a bitfield
/// to reduce per-cell overhead. /// to reduce per-cell overhead.
@ -18,9 +40,9 @@ use unicode_width::UnicodeWidthStr;
pub struct CellAttributes { pub struct CellAttributes {
attributes: u16, attributes: u16,
/// The foreground color /// The foreground color
foreground: ColorAttribute, foreground: SmallColor,
/// The background color /// The background color
background: ColorAttribute, background: SmallColor,
/// Relatively rarely used attributes spill over to a heap /// Relatively rarely used attributes spill over to a heap
/// allocated struct in order to keep CellAttributes /// allocated struct in order to keep CellAttributes
/// smaller in the common case. /// smaller in the common case.
@ -58,6 +80,8 @@ struct FatAttributes {
/// The color of the underline. If None, then /// The color of the underline. If None, then
/// the foreground color is to be used /// the foreground color is to be used
underline_color: ColorAttribute, underline_color: ColorAttribute,
foreground: ColorAttribute,
background: ColorAttribute,
} }
/// Define getter and setter for the attributes bitfield. /// Define getter and setter for the attributes bitfield.
@ -227,21 +251,75 @@ impl CellAttributes {
/// Set the foreground color for the cell to that specified /// Set the foreground color for the cell to that specified
pub fn set_foreground<C: Into<ColorAttribute>>(&mut self, foreground: C) -> &mut Self { pub fn set_foreground<C: Into<ColorAttribute>>(&mut self, foreground: C) -> &mut Self {
self.foreground = foreground.into(); let foreground: ColorAttribute = foreground.into();
match foreground {
ColorAttribute::Default => {
self.foreground = SmallColor::Default;
if let Some(fat) = self.fat.as_mut() {
fat.foreground = ColorAttribute::Default;
}
self.deallocate_fat_attributes_if_none();
}
ColorAttribute::PaletteIndex(idx) => {
self.foreground = SmallColor::PaletteIndex(idx);
if let Some(fat) = self.fat.as_mut() {
fat.foreground = ColorAttribute::Default;
}
self.deallocate_fat_attributes_if_none();
}
foreground => {
self.foreground = SmallColor::Default;
self.allocate_fat_attributes();
self.fat.as_mut().unwrap().foreground = foreground;
}
}
self self
} }
pub fn foreground(&self) -> ColorAttribute { pub fn foreground(&self) -> ColorAttribute {
self.foreground if let Some(fat) = self.fat.as_ref() {
if fat.foreground != ColorAttribute::Default {
return fat.foreground;
}
}
self.foreground.into()
} }
pub fn set_background<C: Into<ColorAttribute>>(&mut self, background: C) -> &mut Self { pub fn set_background<C: Into<ColorAttribute>>(&mut self, background: C) -> &mut Self {
self.background = background.into(); let background: ColorAttribute = background.into();
match background {
ColorAttribute::Default => {
self.background = SmallColor::Default;
if let Some(fat) = self.fat.as_mut() {
fat.background = ColorAttribute::Default;
}
self.deallocate_fat_attributes_if_none();
}
ColorAttribute::PaletteIndex(idx) => {
self.background = SmallColor::PaletteIndex(idx);
if let Some(fat) = self.fat.as_mut() {
fat.background = ColorAttribute::Default;
}
self.deallocate_fat_attributes_if_none();
}
background => {
self.background = SmallColor::Default;
self.allocate_fat_attributes();
self.fat.as_mut().unwrap().background = background;
}
}
self self
} }
pub fn background(&self) -> ColorAttribute { pub fn background(&self) -> ColorAttribute {
self.background if let Some(fat) = self.fat.as_ref() {
if fat.background != ColorAttribute::Default {
return fat.background;
}
}
self.background.into()
} }
fn allocate_fat_attributes(&mut self) { fn allocate_fat_attributes(&mut self) {
@ -250,6 +328,8 @@ impl CellAttributes {
hyperlink: None, hyperlink: None,
image: None, image: None,
underline_color: ColorAttribute::Default, underline_color: ColorAttribute::Default,
foreground: ColorAttribute::Default,
background: ColorAttribute::Default,
})); }));
} }
} }
@ -262,6 +342,8 @@ impl CellAttributes {
fat.image.is_none() fat.image.is_none()
&& fat.hyperlink.is_none() && fat.hyperlink.is_none()
&& fat.underline_color == ColorAttribute::Default && fat.underline_color == ColorAttribute::Default
&& fat.foreground == ColorAttribute::Default
&& fat.background == ColorAttribute::Default
}) })
.unwrap_or(false); .unwrap_or(false);
if deallocate { if deallocate {
@ -640,8 +722,8 @@ mod test {
fn memory_usage() { fn memory_usage() {
assert_eq!(std::mem::size_of::<crate::color::RgbColor>(), 4); assert_eq!(std::mem::size_of::<crate::color::RgbColor>(), 4);
assert_eq!(std::mem::size_of::<ColorAttribute>(), 8); assert_eq!(std::mem::size_of::<ColorAttribute>(), 8);
assert_eq!(std::mem::size_of::<CellAttributes>(), 32); assert_eq!(std::mem::size_of::<CellAttributes>(), 16);
assert_eq!(std::mem::size_of::<Cell>(), 40); assert_eq!(std::mem::size_of::<Cell>(), 24);
assert_eq!(std::mem::size_of::<Vec<u8>>(), 24); assert_eq!(std::mem::size_of::<Vec<u8>>(), 24);
assert_eq!(std::mem::size_of::<char>(), 4); assert_eq!(std::mem::size_of::<char>(), 4);
assert_eq!(std::mem::size_of::<TeenyString>(), 8); assert_eq!(std::mem::size_of::<TeenyString>(), 8);