1use lazy_static::lazy_static;
14use pathfinder_geometry::rect::RectI;
15use pathfinder_geometry::vector::Vector2I;
16use std::cmp;
17use std::fmt;
18
19use crate::utils;
20
21lazy_static! {
22 static ref BITMAP_1BPP_TO_8BPP_LUT: [[u8; 8]; 256] = {
23 let mut lut = [[0; 8]; 256];
24 for byte in 0..0x100 {
25 let mut value = [0; 8];
26 for bit in 0..8 {
27 if (byte & (0x80 >> bit)) != 0 {
28 value[bit] = 0xff;
29 }
30 }
31 lut[byte] = value
32 }
33 lut
34 };
35}
36
37pub struct Canvas {
39 pub pixels: Vec<u8>,
41 pub size: Vector2I,
43 pub stride: usize,
45 pub format: Format,
47}
48
49impl Canvas {
50 #[inline]
56 pub fn new(size: Vector2I, format: Format) -> Canvas {
57 Canvas::with_stride(
58 size,
59 size.x() as usize * format.bytes_per_pixel() as usize,
60 format,
61 )
62 }
63
64 pub fn with_stride(size: Vector2I, stride: usize, format: Format) -> Canvas {
69 Canvas {
70 pixels: vec![0; stride * size.y() as usize],
71 size,
72 stride,
73 format,
74 }
75 }
76
77 #[allow(dead_code)]
78 pub(crate) fn blit_from_canvas(&mut self, src: &Canvas) {
79 self.blit_from(
80 Vector2I::default(),
81 &src.pixels,
82 src.size,
83 src.stride,
84 src.format,
85 )
86 }
87
88 #[allow(dead_code)]
89 pub(crate) fn blit_from(
90 &mut self,
91 dst_point: Vector2I,
92 src_bytes: &[u8],
93 src_size: Vector2I,
94 src_stride: usize,
95 src_format: Format,
96 ) {
97 let dst_rect = RectI::new(dst_point, src_size);
98 let dst_rect = dst_rect.intersection(RectI::new(Vector2I::default(), self.size));
99 let dst_rect = match dst_rect {
100 Some(dst_rect) => dst_rect,
101 None => return,
102 };
103
104 match (self.format, src_format) {
105 (Format::A8, Format::A8)
106 | (Format::Rgb24, Format::Rgb24)
107 | (Format::Rgba32, Format::Rgba32) => {
108 self.blit_from_with::<BlitMemcpy>(dst_rect, src_bytes, src_stride, src_format)
109 }
110 (Format::A8, Format::Rgb24) => {
111 self.blit_from_with::<BlitRgb24ToA8>(dst_rect, src_bytes, src_stride, src_format)
112 }
113 (Format::Rgb24, Format::A8) => {
114 self.blit_from_with::<BlitA8ToRgb24>(dst_rect, src_bytes, src_stride, src_format)
115 }
116 (Format::Rgb24, Format::Rgba32) => self
117 .blit_from_with::<BlitRgba32ToRgb24>(dst_rect, src_bytes, src_stride, src_format),
118 (Format::Rgba32, Format::Rgb24) => self
119 .blit_from_with::<BlitRgb24ToRgba32>(dst_rect, src_bytes, src_stride, src_format),
120 (Format::Rgba32, Format::A8) | (Format::A8, Format::Rgba32) => unimplemented!(),
121 }
122 }
123
124 #[allow(dead_code)]
125 pub(crate) fn blit_from_bitmap_1bpp(
126 &mut self,
127 dst_point: Vector2I,
128 src_bytes: &[u8],
129 src_size: Vector2I,
130 src_stride: usize,
131 ) {
132 if self.format != Format::A8 {
133 unimplemented!()
134 }
135
136 let dst_rect = RectI::new(dst_point, src_size);
137 let dst_rect = dst_rect.intersection(RectI::new(Vector2I::default(), self.size));
138 let dst_rect = match dst_rect {
139 Some(dst_rect) => dst_rect,
140 None => return,
141 };
142
143 let size = dst_rect.size();
144
145 let dest_bytes_per_pixel = self.format.bytes_per_pixel() as usize;
146 let dest_row_stride = size.x() as usize * dest_bytes_per_pixel;
147 let src_row_stride = utils::div_round_up(size.x() as usize, 8);
148
149 for y in 0..size.y() {
150 let (dest_row_start, src_row_start) = (
151 (y + dst_rect.origin_y()) as usize * self.stride
152 + dst_rect.origin_x() as usize * dest_bytes_per_pixel,
153 y as usize * src_stride,
154 );
155 let dest_row_end = dest_row_start + dest_row_stride;
156 let src_row_end = src_row_start + src_row_stride;
157 let dest_row_pixels = &mut self.pixels[dest_row_start..dest_row_end];
158 let src_row_pixels = &src_bytes[src_row_start..src_row_end];
159 for x in 0..src_row_stride {
160 let pattern = &BITMAP_1BPP_TO_8BPP_LUT[src_row_pixels[x] as usize];
161 let dest_start = x * 8;
162 let dest_end = cmp::min(dest_start + 8, dest_row_stride);
163 let src = &pattern[0..(dest_end - dest_start)];
164 dest_row_pixels[dest_start..dest_end].clone_from_slice(src);
165 }
166 }
167 }
168
169 fn blit_from_with<B: Blit>(
170 &mut self,
171 rect: RectI,
172 src_bytes: &[u8],
173 src_stride: usize,
174 src_format: Format,
175 ) {
176 let src_bytes_per_pixel = src_format.bytes_per_pixel() as usize;
177 let dest_bytes_per_pixel = self.format.bytes_per_pixel() as usize;
178
179 for y in 0..rect.height() {
180 let (dest_row_start, src_row_start) = (
181 (y + rect.origin_y()) as usize * self.stride
182 + rect.origin_x() as usize * dest_bytes_per_pixel,
183 y as usize * src_stride,
184 );
185 let dest_row_end = dest_row_start + rect.width() as usize * dest_bytes_per_pixel;
186 let src_row_end = src_row_start + rect.width() as usize * src_bytes_per_pixel;
187 let dest_row_pixels = &mut self.pixels[dest_row_start..dest_row_end];
188 let src_row_pixels = &src_bytes[src_row_start..src_row_end];
189 B::blit(dest_row_pixels, src_row_pixels)
190 }
191 }
192}
193
194impl fmt::Debug for Canvas {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 f.debug_struct("Canvas")
197 .field("pixels", &self.pixels.len()) .field("size", &self.size)
199 .field("stride", &self.stride)
200 .field("format", &self.format)
201 .finish()
202 }
203}
204
205#[derive(Clone, Copy, Debug, PartialEq)]
207pub enum Format {
208 Rgba32,
210 Rgb24,
212 A8,
214}
215
216impl Format {
217 #[inline]
219 pub fn bits_per_pixel(self) -> u8 {
220 match self {
221 Format::Rgba32 => 32,
222 Format::Rgb24 => 24,
223 Format::A8 => 8,
224 }
225 }
226
227 #[inline]
229 pub fn components_per_pixel(self) -> u8 {
230 match self {
231 Format::Rgba32 => 4,
232 Format::Rgb24 => 3,
233 Format::A8 => 1,
234 }
235 }
236
237 #[inline]
239 pub fn bits_per_component(self) -> u8 {
240 self.bits_per_pixel() / self.components_per_pixel()
241 }
242
243 #[inline]
245 pub fn bytes_per_pixel(self) -> u8 {
246 self.bits_per_pixel() / 8
247 }
248}
249
250#[derive(Clone, Copy, Debug, PartialEq)]
252pub enum RasterizationOptions {
253 Bilevel,
255 GrayscaleAa,
257 SubpixelAa,
259}
260
261trait Blit {
262 fn blit(dest: &mut [u8], src: &[u8]);
263}
264
265struct BlitMemcpy;
266
267impl Blit for BlitMemcpy {
268 #[inline]
269 fn blit(dest: &mut [u8], src: &[u8]) {
270 dest.clone_from_slice(src)
271 }
272}
273
274struct BlitRgb24ToA8;
275
276impl Blit for BlitRgb24ToA8 {
277 #[inline]
278 fn blit(dest: &mut [u8], src: &[u8]) {
279 for (dest, src) in dest.iter_mut().zip(src.chunks(3)) {
281 *dest = src[1]
282 }
283 }
284}
285
286struct BlitA8ToRgb24;
287
288impl Blit for BlitA8ToRgb24 {
289 #[inline]
290 fn blit(dest: &mut [u8], src: &[u8]) {
291 for (dest, src) in dest.chunks_mut(3).zip(src.iter()) {
292 dest[0] = *src;
293 dest[1] = *src;
294 dest[2] = *src;
295 }
296 }
297}
298
299struct BlitRgba32ToRgb24;
300
301impl Blit for BlitRgba32ToRgb24 {
302 #[inline]
303 fn blit(dest: &mut [u8], src: &[u8]) {
304 for (dest, src) in dest.chunks_mut(3).zip(src.chunks(4)) {
306 dest.copy_from_slice(&src[0..3])
307 }
308 }
309}
310
311struct BlitRgb24ToRgba32;
312
313impl Blit for BlitRgb24ToRgba32 {
314 fn blit(dest: &mut [u8], src: &[u8]) {
315 for (dest, src) in dest.chunks_mut(4).zip(src.chunks(3)) {
316 dest[0] = src[0];
317 dest[1] = src[1];
318 dest[2] = src[2];
319 dest[3] = 255;
320 }
321 }
322}