1// Copyright 2016 Google Inc.
2// Copyright 2020 Yevhenii Reizner
3//
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6
7use crate::{BlendMode, Color, LengthU32, Paint, PixmapRef, PremultipliedColorU8, Shader};
8use crate::{ALPHA_U8_OPAQUE, ALPHA_U8_TRANSPARENT};
9
10use crate::alpha_runs::AlphaRun;
11use crate::blitter::{Blitter, Mask};
12use crate::color::AlphaU8;
13use crate::geom::ScreenIntRect;
14use crate::mask::SubMaskRef;
15use crate::math::LENGTH_U32_ONE;
16use crate::pipeline::{self, RasterPipeline, RasterPipelineBuilder};
17use crate::pixmap::SubPixmapMut;
18
19pub struct RasterPipelineBlitter<'a, 'b: 'a> {
20 mask: Option<SubMaskRef<'a>>,
21 pixmap_src: PixmapRef<'a>,
22 pixmap: &'a mut SubPixmapMut<'b>,
23 memset2d_color: Option<PremultipliedColorU8>,
24 blit_anti_h_rp: RasterPipeline,
25 blit_rect_rp: RasterPipeline,
26 blit_mask_rp: RasterPipeline,
27 is_mask: bool,
28}
29
30impl<'a, 'b: 'a> RasterPipelineBlitter<'a, 'b> {
31 pub fn new(
32 paint: &Paint<'a>,
33 mask: Option<SubMaskRef<'a>>,
34 pixmap: &'a mut SubPixmapMut<'b>,
35 ) -> Option<Self> {
36 // Make sure that `mask` has the same size as `pixmap`.
37 if let Some(mask) = mask {
38 if mask.size.width() != pixmap.size.width()
39 || mask.size.height() != pixmap.size.height()
40 {
41 log::warn!("Pixmap and Mask are expected to have the same size");
42 return None;
43 }
44 }
45
46 // Fast-reject.
47 // This is basically SkInterpretXfermode().
48 match paint.blend_mode {
49 // `Destination` keep the pixmap unchanged. Nothing to do here.
50 BlendMode::Destination => return None,
51 BlendMode::DestinationIn if paint.shader.is_opaque() && paint.is_solid_color() => {
52 return None
53 }
54 _ => {}
55 }
56
57 // We can strength-reduce SourceOver into Source when opaque.
58 let mut blend_mode = paint.blend_mode;
59 if paint.shader.is_opaque() && blend_mode == BlendMode::SourceOver && mask.is_none() {
60 blend_mode = BlendMode::Source;
61 }
62
63 // When we're drawing a constant color in Source mode, we can sometimes just memset.
64 let mut memset2d_color = None;
65 if paint.is_solid_color() && blend_mode == BlendMode::Source && mask.is_none() {
66 // Unlike Skia, our shader cannot be constant.
67 // Therefore there is no need to run a raster pipeline to get shader's color.
68 if let Shader::SolidColor(ref color) = paint.shader {
69 memset2d_color = Some(color.premultiply().to_color_u8());
70 }
71 };
72
73 // Clear is just a transparent color memset.
74 if blend_mode == BlendMode::Clear && !paint.anti_alias && mask.is_none() {
75 blend_mode = BlendMode::Source;
76 memset2d_color = Some(PremultipliedColorU8::TRANSPARENT);
77 }
78
79 let blit_anti_h_rp = {
80 let mut p = RasterPipelineBuilder::new();
81 p.set_force_hq_pipeline(paint.force_hq_pipeline);
82 if !paint.shader.push_stages(&mut p) {
83 return None;
84 }
85
86 if mask.is_some() {
87 p.push(pipeline::Stage::MaskU8);
88 }
89
90 if blend_mode.should_pre_scale_coverage() {
91 p.push(pipeline::Stage::Scale1Float);
92 p.push(pipeline::Stage::LoadDestination);
93 if let Some(blend_stage) = blend_mode.to_stage() {
94 p.push(blend_stage);
95 }
96 } else {
97 p.push(pipeline::Stage::LoadDestination);
98 if let Some(blend_stage) = blend_mode.to_stage() {
99 p.push(blend_stage);
100 }
101
102 p.push(pipeline::Stage::Lerp1Float);
103 }
104
105 p.push(pipeline::Stage::Store);
106
107 p.compile()
108 };
109
110 let blit_rect_rp = {
111 let mut p = RasterPipelineBuilder::new();
112 p.set_force_hq_pipeline(paint.force_hq_pipeline);
113 if !paint.shader.push_stages(&mut p) {
114 return None;
115 }
116
117 if mask.is_some() {
118 p.push(pipeline::Stage::MaskU8);
119 }
120
121 if blend_mode == BlendMode::SourceOver && mask.is_none() {
122 // TODO: ignore when dither_rate is non-zero
123 p.push(pipeline::Stage::SourceOverRgba);
124 } else {
125 if blend_mode != BlendMode::Source {
126 p.push(pipeline::Stage::LoadDestination);
127 if let Some(blend_stage) = blend_mode.to_stage() {
128 p.push(blend_stage);
129 }
130 }
131
132 p.push(pipeline::Stage::Store);
133 }
134
135 p.compile()
136 };
137
138 let blit_mask_rp = {
139 let mut p = RasterPipelineBuilder::new();
140 p.set_force_hq_pipeline(paint.force_hq_pipeline);
141 if !paint.shader.push_stages(&mut p) {
142 return None;
143 }
144
145 if mask.is_some() {
146 p.push(pipeline::Stage::MaskU8);
147 }
148
149 if blend_mode.should_pre_scale_coverage() {
150 p.push(pipeline::Stage::ScaleU8);
151 p.push(pipeline::Stage::LoadDestination);
152 if let Some(blend_stage) = blend_mode.to_stage() {
153 p.push(blend_stage);
154 }
155 } else {
156 p.push(pipeline::Stage::LoadDestination);
157 if let Some(blend_stage) = blend_mode.to_stage() {
158 p.push(blend_stage);
159 }
160
161 p.push(pipeline::Stage::LerpU8);
162 }
163
164 p.push(pipeline::Stage::Store);
165
166 p.compile()
167 };
168
169 let pixmap_src = match paint.shader {
170 Shader::Pattern(ref patt) => patt.pixmap,
171 // Just a dummy one.
172 _ => PixmapRef::from_bytes(&[0, 0, 0, 0], 1, 1).unwrap(),
173 };
174
175 Some(RasterPipelineBlitter {
176 mask,
177 pixmap_src,
178 pixmap,
179 memset2d_color,
180 blit_anti_h_rp,
181 blit_rect_rp,
182 blit_mask_rp,
183 is_mask: false,
184 })
185 }
186
187 pub fn new_mask(pixmap: &'a mut SubPixmapMut<'b>) -> Option<Self> {
188 let color = Color::WHITE.premultiply();
189
190 let memset2d_color = Some(color.to_color_u8());
191
192 let blit_anti_h_rp = {
193 let mut p = RasterPipelineBuilder::new();
194 p.push_uniform_color(color);
195 p.push(pipeline::Stage::LoadDestinationU8);
196 p.push(pipeline::Stage::Lerp1Float);
197 p.push(pipeline::Stage::StoreU8);
198 p.compile()
199 };
200
201 let blit_rect_rp = {
202 let mut p = RasterPipelineBuilder::new();
203 p.push_uniform_color(color);
204 p.push(pipeline::Stage::StoreU8);
205 p.compile()
206 };
207
208 let blit_mask_rp = {
209 let mut p = RasterPipelineBuilder::new();
210 p.push_uniform_color(color);
211 p.push(pipeline::Stage::LoadDestinationU8);
212 p.push(pipeline::Stage::LerpU8);
213 p.push(pipeline::Stage::StoreU8);
214 p.compile()
215 };
216
217 Some(RasterPipelineBlitter {
218 mask: None,
219 pixmap_src: PixmapRef::from_bytes(&[0, 0, 0, 0], 1, 1).unwrap(),
220 pixmap,
221 memset2d_color,
222 blit_anti_h_rp,
223 blit_rect_rp,
224 blit_mask_rp,
225 is_mask: true,
226 })
227 }
228}
229
230impl Blitter for RasterPipelineBlitter<'_, '_> {
231 fn blit_h(&mut self, x: u32, y: u32, width: LengthU32) {
232 let r = ScreenIntRect::from_xywh_safe(x, y, width, LENGTH_U32_ONE);
233 self.blit_rect(&r);
234 }
235
236 fn blit_anti_h(&mut self, mut x: u32, y: u32, aa: &mut [AlphaU8], runs: &mut [AlphaRun]) {
237 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
238
239 let mut aa_offset = 0;
240 let mut run_offset = 0;
241 let mut run_opt = runs[0];
242 while let Some(run) = run_opt {
243 let width = LengthU32::from(run);
244
245 match aa[aa_offset] {
246 ALPHA_U8_TRANSPARENT => {}
247 ALPHA_U8_OPAQUE => {
248 self.blit_h(x, y, width);
249 }
250 alpha => {
251 self.blit_anti_h_rp.ctx.current_coverage = alpha as f32 * (1.0 / 255.0);
252
253 let rect = ScreenIntRect::from_xywh_safe(x, y, width, LENGTH_U32_ONE);
254 self.blit_anti_h_rp.run(
255 &rect,
256 pipeline::AAMaskCtx::default(),
257 mask_ctx,
258 self.pixmap_src,
259 self.pixmap,
260 );
261 }
262 }
263
264 x += width.get();
265 run_offset += usize::from(run.get());
266 aa_offset += usize::from(run.get());
267 run_opt = runs[run_offset];
268 }
269 }
270
271 fn blit_v(&mut self, x: u32, y: u32, height: LengthU32, alpha: AlphaU8) {
272 let bounds = ScreenIntRect::from_xywh_safe(x, y, LENGTH_U32_ONE, height);
273
274 let mask = Mask {
275 image: [alpha, alpha],
276 bounds,
277 row_bytes: 0, // so we reuse the 1 "row" for all of height
278 };
279
280 self.blit_mask(&mask, &bounds);
281 }
282
283 fn blit_anti_h2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
284 let bounds = ScreenIntRect::from_xywh(x, y, 2, 1).unwrap();
285
286 let mask = Mask {
287 image: [alpha0, alpha1],
288 bounds,
289 row_bytes: 2,
290 };
291
292 self.blit_mask(&mask, &bounds);
293 }
294
295 fn blit_anti_v2(&mut self, x: u32, y: u32, alpha0: AlphaU8, alpha1: AlphaU8) {
296 let bounds = ScreenIntRect::from_xywh(x, y, 1, 2).unwrap();
297
298 let mask = Mask {
299 image: [alpha0, alpha1],
300 bounds,
301 row_bytes: 1,
302 };
303
304 self.blit_mask(&mask, &bounds);
305 }
306
307 fn blit_rect(&mut self, rect: &ScreenIntRect) {
308 if let Some(c) = self.memset2d_color {
309 if self.is_mask {
310 for y in 0..rect.height() {
311 let start = self
312 .pixmap
313 .offset(rect.x() as usize, (rect.y() + y) as usize);
314 let end = start + rect.width() as usize;
315 self.pixmap.data[start..end]
316 .iter_mut()
317 .for_each(|p| *p = c.alpha());
318 }
319 } else {
320 for y in 0..rect.height() {
321 let start = self
322 .pixmap
323 .offset(rect.x() as usize, (rect.y() + y) as usize);
324 let end = start + rect.width() as usize;
325 self.pixmap.pixels_mut()[start..end]
326 .iter_mut()
327 .for_each(|p| *p = c);
328 }
329 }
330
331 return;
332 }
333
334 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
335
336 self.blit_rect_rp.run(
337 rect,
338 pipeline::AAMaskCtx::default(),
339 mask_ctx,
340 self.pixmap_src,
341 self.pixmap,
342 );
343 }
344
345 fn blit_mask(&mut self, mask: &Mask, clip: &ScreenIntRect) {
346 let aa_mask_ctx = pipeline::AAMaskCtx {
347 pixels: mask.image,
348 stride: mask.row_bytes,
349 shift: (mask.bounds.left() + mask.bounds.top() * mask.row_bytes) as usize,
350 };
351
352 let mask_ctx = self.mask.map(|c| c.mask_ctx()).unwrap_or_default();
353
354 self.blit_mask_rp
355 .run(clip, aa_mask_ctx, mask_ctx, self.pixmap_src, self.pixmap);
356 }
357}
358