1use super::*;
2
3#[inline]
15pub(super) fn active_fb<'a>(
16 base_fb: &'a mut Framebuffer,
17 layer_stack: &'a mut Vec<LayerEntry>,
18) -> &'a mut Framebuffer {
19 if let Some(top) = layer_stack.last_mut() {
20 &mut top.fb
21 } else {
22 base_fb
23 }
24}
25
26pub(super) fn composite_framebuffers(
46 dst: &mut Framebuffer,
47 src: &Framebuffer,
48 dest_x: i32,
49 dest_y: i32,
50 alpha: f64,
51 clip: Option<(f64, f64, f64, f64)>,
52) {
53 let src_w = src.width() as i32;
54 let src_h = src.height() as i32;
55 let dst_w = dst.width() as i32;
56 let dst_h = dst.height() as i32;
57
58 let (cx1, cy1, cx2, cy2) = match clip {
63 Some((cx, cy, cw, ch)) => (
64 cx.floor() as i32,
65 cy.floor() as i32,
66 (cx + cw).ceil() as i32,
67 (cy + ch).ceil() as i32,
68 ),
69 None => (0, 0, dst_w, dst_h),
70 };
71
72 let src_px = src.pixels();
73 let dst_px = dst.pixels_mut();
74
75 for sy in 0..src_h {
76 let dy = dest_y + sy;
77 if dy < 0 || dy >= dst_h || dy < cy1 || dy >= cy2 {
78 continue;
79 }
80 for sx in 0..src_w {
81 let dx = dest_x + sx;
82 if dx < 0 || dx >= dst_w || dx < cx1 || dx >= cx2 {
83 continue;
84 }
85 let si = ((sy * src_w + sx) * 4) as usize;
86 let di = ((dy * dst_w + dx) * 4) as usize;
87 let layer_alpha = alpha.clamp(0.0, 1.0) as f32;
88 let sa = (src_px[si + 3] as f32 / 255.0) * layer_alpha;
89 if sa < 1e-4 {
90 continue;
91 } let inv_sa = 1.0 - sa;
93 for k in 0..4 {
95 let s = src_px[si + k] as f32 * layer_alpha;
96 let d = dst_px[di + k] as f32;
97 dst_px[di + k] = (s + d * inv_sa).round().clamp(0.0, 255.0) as u8;
98 }
99 }
100 }
101}
102
103pub(crate) fn rasterize_fill(
110 fb: &mut Framebuffer,
111 path: &mut PathStorage,
112 color: &agg_rust::color::Rgba8,
113 mode: CompOp,
114 clip: Option<(f64, f64, f64, f64)>,
115 fill_rule: FillRule,
116 transform: &TransAffine,
117) {
118 let w = fb.width();
119 let h = fb.height();
120 let stride = (w * 4) as i32;
121 let mut ra = RowAccessor::new();
122 unsafe { ra.attach(fb.pixels_mut().as_mut_ptr(), w, h, stride) };
123 let pf = PixfmtRgba32CompOp::new_with_op(&mut ra, mode);
124 let mut rb = RendererBase::new(pf);
125 apply_clip(&mut rb, clip);
126
127 let mut ras = RasterizerScanlineAa::new();
128 ras.filling_rule(to_agg_fill_rule(fill_rule));
129 let mut sl = ScanlineU8::new();
130 let mut curves = ConvCurve::new(path);
131 let mut transformed = ConvTransform::new(&mut curves, transform.clone());
132 ras.add_path(&mut transformed, 0);
133 render_scanlines_aa_solid(&mut ras, &mut sl, &mut rb, color);
134}
135
136fn to_agg_fill_rule(rule: FillRule) -> FillingRule {
137 match rule {
138 FillRule::NonZero => FillingRule::NonZero,
139 FillRule::EvenOdd => FillingRule::EvenOdd,
140 }
141}
142
143pub(crate) fn rasterize_stroke(
144 fb: &mut Framebuffer,
145 path: &mut PathStorage,
146 color: &agg_rust::color::Rgba8,
147 width: f64,
148 join: LineJoin,
149 cap: LineCap,
150 miter_limit: f64,
151 dashes: &[f64],
152 dash_offset: f64,
153 mode: CompOp,
154 clip: Option<(f64, f64, f64, f64)>,
155 transform: &TransAffine,
156) {
157 let mut curves = ConvCurve::new(path);
158 if dashes.is_empty() {
159 rasterize_stroke_source(
160 fb,
161 &mut curves,
162 color,
163 width,
164 join,
165 cap,
166 miter_limit,
167 mode,
168 clip,
169 transform,
170 );
171 } else {
172 let mut dash = ConvDash::new(&mut curves);
173 configure_dashes(&mut dash, dashes, dash_offset);
174 rasterize_stroke_source(
175 fb,
176 dash,
177 color,
178 width,
179 join,
180 cap,
181 miter_limit,
182 mode,
183 clip,
184 transform,
185 );
186 }
187}
188
189fn rasterize_stroke_source<VS: VertexSource>(
190 fb: &mut Framebuffer,
191 source: VS,
192 color: &agg_rust::color::Rgba8,
193 width: f64,
194 join: LineJoin,
195 cap: LineCap,
196 miter_limit: f64,
197 mode: CompOp,
198 clip: Option<(f64, f64, f64, f64)>,
199 transform: &TransAffine,
200) {
201 let w = fb.width();
202 let h = fb.height();
203 let stride = (w * 4) as i32;
204 let mut ra = RowAccessor::new();
205 unsafe { ra.attach(fb.pixels_mut().as_mut_ptr(), w, h, stride) };
206 let pf = PixfmtRgba32CompOp::new_with_op(&mut ra, mode);
207 let mut rb = RendererBase::new(pf);
208 apply_clip(&mut rb, clip);
209
210 let mut ras = RasterizerScanlineAa::new();
211 let mut sl = ScanlineU8::new();
212 let mut stroke = ConvStroke::new(source);
213 stroke.set_width(width);
214 stroke.set_line_join(join);
215 stroke.set_line_cap(cap);
216 stroke.set_miter_limit(miter_limit);
217 let mut transformed = ConvTransform::new(&mut stroke, transform.clone());
218 ras.add_path(&mut transformed, 0);
219 render_scanlines_aa_solid(&mut ras, &mut sl, &mut rb, color);
220}
221
222fn configure_dashes<VS: VertexSource>(dash: &mut ConvDash<VS>, dashes: &[f64], dash_offset: f64) {
223 let mut chunks = dashes.chunks_exact(2);
224 for pair in &mut chunks {
225 dash.add_dash(pair[0], pair[1]);
226 }
227 if let Some(&last) = chunks.remainder().first() {
228 dash.add_dash(last, last);
229 }
230 dash.dash_start(dash_offset);
231}
232
233impl crate::draw_ctx::DrawCtx for GfxCtx<'_> {
238 fn set_fill_color(&mut self, c: crate::color::Color) {
239 self.set_fill_color(c)
240 }
241 fn set_fill_linear_gradient(&mut self, gradient: crate::draw_ctx::LinearGradientPaint) {
242 self.set_fill_linear_gradient(gradient)
243 }
244 fn set_fill_radial_gradient(&mut self, gradient: crate::draw_ctx::RadialGradientPaint) {
245 self.set_fill_radial_gradient(gradient)
246 }
247 fn set_fill_pattern(&mut self, pattern: crate::draw_ctx::PatternPaint) {
248 self.set_fill_pattern(pattern)
249 }
250 fn supports_fill_linear_gradient(&self) -> bool {
251 true
252 }
253 fn supports_fill_radial_gradient(&self) -> bool {
254 true
255 }
256 fn supports_fill_pattern(&self) -> bool {
257 true
258 }
259 fn set_stroke_color(&mut self, c: crate::color::Color) {
260 self.set_stroke_color(c)
261 }
262 fn set_stroke_linear_gradient(&mut self, gradient: crate::draw_ctx::LinearGradientPaint) {
263 self.set_stroke_linear_gradient(gradient)
264 }
265 fn set_stroke_radial_gradient(&mut self, gradient: crate::draw_ctx::RadialGradientPaint) {
266 self.set_stroke_radial_gradient(gradient)
267 }
268 fn set_stroke_pattern(&mut self, pattern: crate::draw_ctx::PatternPaint) {
269 self.set_stroke_pattern(pattern)
270 }
271 fn supports_stroke_linear_gradient(&self) -> bool {
272 true
273 }
274 fn supports_stroke_radial_gradient(&self) -> bool {
275 true
276 }
277 fn supports_stroke_pattern(&self) -> bool {
278 true
279 }
280 fn set_line_width(&mut self, w: f64) {
281 self.set_line_width(w)
282 }
283 fn set_line_join(&mut self, j: agg_rust::math_stroke::LineJoin) {
284 self.set_line_join(j)
285 }
286 fn set_line_cap(&mut self, c: agg_rust::math_stroke::LineCap) {
287 self.set_line_cap(c)
288 }
289 fn set_miter_limit(&mut self, limit: f64) {
290 self.set_miter_limit(limit)
291 }
292 fn set_line_dash(&mut self, dashes: &[f64], offset: f64) {
293 self.set_line_dash(dashes, offset)
294 }
295 fn set_fill_rule(&mut self, rule: crate::draw_ctx::FillRule) {
296 self.set_fill_rule(rule)
297 }
298 fn set_blend_mode(&mut self, m: agg_rust::comp_op::CompOp) {
299 self.set_blend_mode(m)
300 }
301 fn set_global_alpha(&mut self, a: f64) {
302 self.set_global_alpha(a)
303 }
304 fn set_font(&mut self, f: Arc<crate::text::Font>) {
305 self.set_font(f)
306 }
307 fn set_font_size(&mut self, s: f64) {
308 self.set_font_size(s)
309 }
310 fn clip_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
311 self.clip_rect(x, y, w, h)
312 }
313 fn reset_clip(&mut self) {
314 self.reset_clip()
315 }
316 fn clip_path(&mut self) {
317 self.clip_path()
318 }
319 fn supports_clip_path(&self) -> bool {
320 true
321 }
322 fn clear(&mut self, c: crate::color::Color) {
323 self.clear(c)
324 }
325 fn begin_path(&mut self) {
326 self.begin_path()
327 }
328 fn move_to(&mut self, x: f64, y: f64) {
329 self.move_to(x, y)
330 }
331 fn line_to(&mut self, x: f64, y: f64) {
332 self.line_to(x, y)
333 }
334 fn cubic_to(&mut self, cx1: f64, cy1: f64, cx2: f64, cy2: f64, x: f64, y: f64) {
335 self.cubic_to(cx1, cy1, cx2, cy2, x, y)
336 }
337 fn quad_to(&mut self, cx: f64, cy: f64, x: f64, y: f64) {
338 self.quad_to(cx, cy, x, y)
339 }
340 fn arc_to(&mut self, cx: f64, cy: f64, r: f64, a1: f64, a2: f64, ccw: bool) {
341 self.arc_to(cx, cy, r, a1, a2, ccw)
342 }
343 fn circle(&mut self, cx: f64, cy: f64, r: f64) {
344 self.circle(cx, cy, r)
345 }
346 fn rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
347 self.rect(x, y, w, h)
348 }
349 fn rounded_rect(&mut self, x: f64, y: f64, w: f64, h: f64, r: f64) {
350 self.rounded_rect(x, y, w, h, r)
351 }
352 fn close_path(&mut self) {
353 self.close_path()
354 }
355 fn fill(&mut self) {
356 self.fill()
357 }
358 fn stroke(&mut self) {
359 self.stroke()
360 }
361 fn fill_and_stroke(&mut self) {
362 self.fill_and_stroke()
363 }
364
365 fn draw_triangles_aa(
366 &mut self,
367 vertices: &[[f32; 3]],
368 indices: &[u32],
369 color: crate::color::Color,
370 ) {
371 let saved_fill = self.state.fill_color;
379 self.set_fill_color(color);
380 let n_tris = indices.len() / 3;
381 for t in 0..n_tris {
382 let i0 = indices[t * 3] as usize;
383 let i1 = indices[t * 3 + 1] as usize;
384 let i2 = indices[t * 3 + 2] as usize;
385 if i0 >= vertices.len() || i1 >= vertices.len() || i2 >= vertices.len() {
386 continue;
387 }
388 let v0 = vertices[i0];
389 let v1 = vertices[i1];
390 let v2 = vertices[i2];
391 self.begin_path();
392 self.move_to(v0[0] as f64, v0[1] as f64);
393 self.line_to(v1[0] as f64, v1[1] as f64);
394 self.line_to(v2[0] as f64, v2[1] as f64);
395 self.close_path();
396 self.fill();
397 }
398 self.set_fill_color(saved_fill);
399 }
400 fn fill_text(&mut self, t: &str, x: f64, y: f64) {
401 self.fill_text(t, x, y)
402 }
403 fn fill_text_gsv(&mut self, t: &str, x: f64, y: f64, s: f64) {
404 self.fill_text_gsv(t, x, y, s)
405 }
406 fn measure_text(&self, t: &str) -> Option<crate::text::TextMetrics> {
407 self.measure_text(t)
408 }
409 fn transform(&self) -> agg_rust::trans_affine::TransAffine {
410 self.transform()
411 }
412 fn root_transform(&self) -> agg_rust::trans_affine::TransAffine {
413 let mut t = self.transform();
414 for layer in self.layer_stack.iter().rev() {
415 t.premultiply(&agg_rust::trans_affine::TransAffine::new_translation(
416 layer.origin_x,
417 layer.origin_y,
418 ));
419 }
420 t
421 }
422 fn save(&mut self) {
423 self.save()
424 }
425 fn restore(&mut self) {
426 self.restore()
427 }
428 fn translate(&mut self, tx: f64, ty: f64) {
429 self.translate(tx, ty)
430 }
431 fn rotate(&mut self, r: f64) {
432 self.rotate(r)
433 }
434 fn scale(&mut self, sx: f64, sy: f64) {
435 self.scale(sx, sy)
436 }
437 fn set_transform(&mut self, m: agg_rust::trans_affine::TransAffine) {
438 self.set_transform(m)
439 }
440 fn reset_transform(&mut self) {
441 self.reset_transform()
442 }
443 fn push_layer(&mut self, w: f64, h: f64) {
444 self.push_layer(w, h)
445 }
446 fn supports_compositing_layers(&self) -> bool {
447 true
448 }
449 fn push_layer_with_alpha(&mut self, w: f64, h: f64, alpha: f64) {
450 self.push_layer_with_alpha(w, h, alpha)
451 }
452 fn pop_layer(&mut self) {
453 self.pop_layer()
454 }
455
456 fn has_image_blit(&self) -> bool {
457 true
458 }
459
460 fn draw_image_rgba_arc(
461 &mut self,
462 data: &Arc<Vec<u8>>,
463 img_w: u32,
464 img_h: u32,
465 dst_x: f64,
466 dst_y: f64,
467 dst_w: f64,
468 dst_h: f64,
469 ) {
470 self.draw_image_rgba(data.as_slice(), img_w, img_h, dst_x, dst_y, dst_w, dst_h);
473 }
474
475 fn draw_lcd_backbuffer_arc(
476 &mut self,
477 color: &Arc<Vec<u8>>,
478 alpha: &Arc<Vec<u8>>,
479 _content_version: u64,
480 w: u32,
481 h: u32,
482 dst_x: f64,
483 dst_y: f64,
484 _dst_w: f64,
485 _dst_h: f64,
486 ) {
487 if w == 0 || h == 0 {
498 return;
499 }
500 let w_u = w as usize;
501 let h_u = h as usize;
502 if color.len() < w_u * h_u * 3 || alpha.len() < w_u * h_u * 3 {
503 return;
504 }
505
506 let t = &self.state.transform;
507 let sx = (dst_x * t.sx + dst_y * t.shx + t.tx).round() as i32;
508 let sy = (dst_x * t.shy + dst_y * t.sy + t.ty).round() as i32;
509 let ga = self.state.global_alpha.clamp(0.0, 1.0) as f32;
514 let clip = self.state.clip;
518 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
519 let fw = fb.width() as i32;
520 let fh = fb.height() as i32;
521 let (cx1, cy1, cx2, cy2) = match clip {
522 Some((cx, cy, cw, ch)) => (
523 cx.floor() as i32,
524 cy.floor() as i32,
525 (cx + cw).ceil() as i32,
526 (cy + ch).ceil() as i32,
527 ),
528 None => (0, 0, fw, fh),
529 };
530 let fw_u = fw as usize;
531 let pixels = fb.pixels_mut();
532
533 for src_y in 0..h_u {
534 let dy = sy + (h_u - 1 - src_y) as i32;
537 if dy < 0 || dy >= fh || dy < cy1 || dy >= cy2 {
538 continue;
539 }
540 let dy_u = dy as usize;
541 for src_x in 0..w_u {
542 let dx = sx + src_x as i32;
543 if dx < 0 || dx >= fw || dx < cx1 || dx >= cx2 {
544 continue;
545 }
546 let ci = (src_y * w_u + src_x) * 3;
547
548 let sa_r = (alpha[ci] as f32 / 255.0) * ga;
549 let sa_g = (alpha[ci + 1] as f32 / 255.0) * ga;
550 let sa_b = (alpha[ci + 2] as f32 / 255.0) * ga;
551 if sa_r == 0.0 && sa_g == 0.0 && sa_b == 0.0 {
552 continue;
553 }
554
555 let sc_r = (color[ci] as f32 / 255.0) * ga;
556 let sc_g = (color[ci + 1] as f32 / 255.0) * ga;
557 let sc_b = (color[ci + 2] as f32 / 255.0) * ga;
558
559 let di = (dy_u * fw_u + dx as usize) * 4;
560 let dc_r = pixels[di] as f32 / 255.0;
567 let dc_g = pixels[di + 1] as f32 / 255.0;
568 let dc_b = pixels[di + 2] as f32 / 255.0;
569 let da = pixels[di + 3] as f32 / 255.0;
570
571 let rc_r = sc_r + dc_r * (1.0 - sa_r);
572 let rc_g = sc_g + dc_g * (1.0 - sa_g);
573 let rc_b = sc_b + dc_b * (1.0 - sa_b);
574 let src_a_max = sa_r.max(sa_g).max(sa_b);
575 let ra = src_a_max + da * (1.0 - src_a_max);
576
577 pixels[di] = (rc_r * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
578 pixels[di + 1] = (rc_g * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
579 pixels[di + 2] = (rc_b * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
580 pixels[di + 3] = (ra * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
581 }
582 }
583 }
584
585 fn has_lcd_mask_composite(&self) -> bool {
586 true
587 }
588
589 fn draw_lcd_mask(
590 &mut self,
591 mask: &[u8],
592 mask_w: u32,
593 mask_h: u32,
594 src_color: Color,
595 dst_x: f64,
596 dst_y: f64,
597 ) {
598 if mask.len() < (mask_w as usize) * (mask_h as usize) * 3 {
603 return;
604 }
605 let t = &self.state.transform;
606 let sx = dst_x * t.sx + dst_y * t.shx + t.tx;
607 let sy = dst_x * t.shy + dst_y * t.sy + t.ty;
608 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
609 let fw = fb.width();
610 let fh = fb.height();
611 let origin_x = sx.round() as i32;
612 let origin_y = sy.round() as i32;
613
614 let sa = src_color.a.clamp(0.0, 1.0);
615 let sr = src_color.r.clamp(0.0, 1.0);
616 let sg = src_color.g.clamp(0.0, 1.0);
617 let sb = src_color.b.clamp(0.0, 1.0);
618 let fw_i = fw as i32;
619 let fh_i = fh as i32;
620 let mw_i = mask_w as i32;
621 let mh_i = mask_h as i32;
622 let pixels = fb.pixels_mut();
623
624 for my in 0..mh_i {
625 let dy = origin_y + my;
628 if dy < 0 || dy >= fh_i {
629 continue;
630 }
631 for mx in 0..mw_i {
632 let dx = origin_x + mx;
633 if dx < 0 || dx >= fw_i {
634 continue;
635 }
636 let mi = ((my * mw_i + mx) * 3) as usize;
637 let cr = (mask[mi] as f32 / 255.0) * sa;
640 let cg = (mask[mi + 1] as f32 / 255.0) * sa;
641 let cb = (mask[mi + 2] as f32 / 255.0) * sa;
642 if cr == 0.0 && cg == 0.0 && cb == 0.0 {
643 continue;
644 }
645 let di = ((dy * fw_i + dx) * 4) as usize;
646 let dr = pixels[di] as f32 / 255.0;
647 let dg = pixels[di + 1] as f32 / 255.0;
648 let db = pixels[di + 2] as f32 / 255.0;
649 let rr = sr * cr + dr * (1.0 - cr);
650 let rg = sg * cg + dg * (1.0 - cg);
651 let rbb = sb * cb + db * (1.0 - cb);
652 pixels[di] = (rr * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
653 pixels[di + 1] = (rg * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
654 pixels[di + 2] = (rbb * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
655 }
659 }
660 }
661
662 fn draw_image_rgba(
663 &mut self,
664 data: &[u8],
665 img_w: u32,
666 img_h: u32,
667 dst_x: f64,
668 dst_y: f64,
669 dst_w: f64,
670 dst_h: f64,
671 ) {
672 if img_w == 0 || img_h == 0 || dst_w < 1.0 || dst_h < 1.0 {
675 return;
676 }
677
678 let out_w = dst_w.round() as u32;
679 let out_h = dst_h.round() as u32;
680 let mut scaled = crate::framebuffer::Framebuffer::new(out_w, out_h);
681
682 let px = scaled.pixels_mut();
688 for dy in 0..out_h {
689 for dx in 0..out_w {
690 let sx = (dx as f64 / out_w as f64 * img_w as f64) as u32;
691 let sy_img = ((1.0 - (dy as f64 + 0.5) / out_h as f64) * img_h as f64)
693 .floor()
694 .clamp(0.0, (img_h - 1) as f64) as u32;
695 let si = ((sy_img * img_w + sx) * 4) as usize;
696 let di = ((dy * out_w + dx) * 4) as usize;
697 if si + 3 < data.len() && di + 3 < px.len() {
698 let a = data[si + 3] as u32;
699 if a == 255 {
700 px[di] = data[si];
701 px[di + 1] = data[si + 1];
702 px[di + 2] = data[si + 2];
703 px[di + 3] = 255;
704 } else {
705 px[di] = (((data[si] as u32) * a + 127) / 255) as u8;
707 px[di + 1] = (((data[si + 1] as u32) * a + 127) / 255) as u8;
708 px[di + 2] = (((data[si + 2] as u32) * a + 127) / 255) as u8;
709 px[di + 3] = a as u8;
710 }
711 }
712 }
713 }
714
715 let (tx, ty) = {
717 let t = self.transform();
718 (t.tx, t.ty)
719 };
720 let screen_x = (tx + dst_x).round() as i32;
721 let screen_y = (ty + dst_y).round() as i32;
722 let ga = self.state.global_alpha;
727 let clip = self.state.clip;
733 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
734 composite_framebuffers(fb, &scaled, screen_x, screen_y, ga, clip);
735 }
736}
737
738pub(crate) fn apply_clip<PF: agg_rust::pixfmt_rgba::PixelFormat>(
740 rb: &mut RendererBase<PF>,
741 clip: Option<(f64, f64, f64, f64)>,
742) {
743 if let Some((x, y, w, h)) = clip {
744 let x1 = x.floor() as i32;
745 let y1 = y.floor() as i32;
746 let x2 = (x + w).ceil() as i32 - 1;
747 let y2 = (y + h).ceil() as i32 - 1;
748 rb.clip_box_i(x1, y1, x2, y2);
749 }
750}