@@ -839,7 +839,11 @@ fn image_format_from_external_content(format: image::ImageFormat) -> Option<Imag
image::ImageFormat::Bmp => Some(ImageFormat::Bmp),
image::ImageFormat::Tiff => Some(ImageFormat::Tiff),
image::ImageFormat::Ico => Some(ImageFormat::Ico),
- _ => None,
+ image::ImageFormat::Pnm => Some(ImageFormat::Pnm),
+ _ => {
+ debug_panic!("An unhandled image format: {format:?}");
+ None
+ }
}
}
@@ -2001,17 +2001,21 @@ impl ImageFormat {
}
}
- /// Returns the ImageFormat for the given mime type
+ /// Returns the ImageFormat for the given mime type, including known aliases.
pub fn from_mime_type(mime_type: &str) -> Option<Self> {
+ use strum::IntoEnumIterator;
+ Self::iter()
+ .find(|format| format.mime_type() == mime_type)
+ .or_else(|| Self::from_mime_type_alias(mime_type))
+ }
+
+ /// Non-canonical mime types that some producers use in the wild.
+ /// Unlike `mime_type()` which returns the single canonical form,
+ /// these are legacy or shortened variants we still need to recognize.
+ fn from_mime_type_alias(mime_type: &str) -> Option<Self> {
match mime_type {
- "image/png" => Some(Self::Png),
- "image/jpeg" | "image/jpg" => Some(Self::Jpeg),
- "image/webp" => Some(Self::Webp),
- "image/gif" => Some(Self::Gif),
- "image/svg+xml" => Some(Self::Svg),
- "image/bmp" => Some(Self::Bmp),
- "image/tiff" | "image/tif" => Some(Self::Tiff),
- "image/ico" => Some(Self::Ico),
+ "image/jpg" => Some(Self::Jpeg),
+ "image/tif" => Some(Self::Tiff),
_ => None,
}
}
@@ -48,6 +48,7 @@ use x11rb::{
};
use gpui::{ClipboardItem, Image, ImageFormat, hash};
+use strum::IntoEnumIterator;
type Result<T, E = Error> = std::result::Result<T, E>;
@@ -989,14 +990,8 @@ impl Clipboard {
self.inner.write(data, selection, wait)
}
- #[allow(unused)]
- pub(crate) fn set_image(
- &self,
- image: Image,
- selection: ClipboardKind,
- wait: WaitConfig,
- ) -> Result<()> {
- let format = match image.format {
+ fn image_format_atom(&self, format: ImageFormat) -> Atom {
+ match format {
ImageFormat::Png => self.inner.atoms.PNG__MIME,
ImageFormat::Jpeg => self.inner.atoms.JPEG_MIME,
ImageFormat::Webp => self.inner.atoms.WEBP_MIME,
@@ -1006,7 +1001,17 @@ impl Clipboard {
ImageFormat::Tiff => self.inner.atoms.TIFF_MIME,
ImageFormat::Ico => self.inner.atoms.ICO__MIME,
ImageFormat::Pnm => self.inner.atoms.PNM__MIME,
- };
+ }
+ }
+
+ #[allow(unused)]
+ pub(crate) fn set_image(
+ &self,
+ image: Image,
+ selection: ClipboardKind,
+ wait: WaitConfig,
+ ) -> Result<()> {
+ let format = self.image_format_atom(image.format);
let data = vec![ClipboardData {
bytes: image.bytes,
format: self.inner.atoms.PNG__MIME,
@@ -1015,28 +1020,11 @@ impl Clipboard {
}
pub(crate) fn get_any(&self, selection: ClipboardKind) -> Result<ClipboardItem> {
- const IMAGE_FORMAT_COUNT: usize = 7;
- let image_format_atoms: [Atom; IMAGE_FORMAT_COUNT] = [
- self.inner.atoms.PNG__MIME,
- self.inner.atoms.JPEG_MIME,
- self.inner.atoms.WEBP_MIME,
- self.inner.atoms.GIF__MIME,
- self.inner.atoms.SVG__MIME,
- self.inner.atoms.BMP__MIME,
- self.inner.atoms.TIFF_MIME,
- ];
- let image_formats: [ImageFormat; IMAGE_FORMAT_COUNT] = [
- ImageFormat::Png,
- ImageFormat::Jpeg,
- ImageFormat::Webp,
- ImageFormat::Gif,
- ImageFormat::Svg,
- ImageFormat::Bmp,
- ImageFormat::Tiff,
- ];
+ let image_entries = ImageFormat::iter()
+ .map(|format| (self.image_format_atom(format), format))
+ .collect::<Vec<_>>();
- const TEXT_FORMAT_COUNT: usize = 6;
- let text_format_atoms: [Atom; TEXT_FORMAT_COUNT] = [
+ let text_format_atoms: &[Atom] = &[
self.inner.atoms.UTF8_STRING,
self.inner.atoms.UTF8_MIME_0,
self.inner.atoms.UTF8_MIME_1,
@@ -1045,17 +1033,11 @@ impl Clipboard {
self.inner.atoms.TEXT_MIME_UNKNOWN,
];
- let atom_none: Atom = AtomEnum::NONE.into();
-
- const FORMAT_ATOM_COUNT: usize = TEXT_FORMAT_COUNT + IMAGE_FORMAT_COUNT;
-
- let mut format_atoms: [Atom; FORMAT_ATOM_COUNT] = [atom_none; FORMAT_ATOM_COUNT];
-
// image formats first, as they are more specific, and read will return the first
// format that the contents can be converted to
- format_atoms[0..IMAGE_FORMAT_COUNT].copy_from_slice(&image_format_atoms);
- format_atoms[IMAGE_FORMAT_COUNT..].copy_from_slice(&text_format_atoms);
- debug_assert!(!format_atoms.contains(&atom_none));
+ let mut format_atoms = Vec::with_capacity(image_entries.len() + text_format_atoms.len());
+ format_atoms.extend(image_entries.iter().map(|(atom, _)| *atom));
+ format_atoms.extend_from_slice(text_format_atoms);
let result = self.inner.read(&format_atoms, selection)?;
@@ -1064,7 +1046,7 @@ impl Clipboard {
self.inner.atom_name(result.format)
);
- for (format_atom, image_format) in image_format_atoms.into_iter().zip(image_formats) {
+ for (format_atom, image_format) in image_entries {
if result.format == format_atom {
let bytes = result.bytes;
let id = hash(&bytes);