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 clear(&mut self, c: crate::color::Color) {
317 self.clear(c)
318 }
319 fn begin_path(&mut self) {
320 self.begin_path()
321 }
322 fn move_to(&mut self, x: f64, y: f64) {
323 self.move_to(x, y)
324 }
325 fn line_to(&mut self, x: f64, y: f64) {
326 self.line_to(x, y)
327 }
328 fn cubic_to(&mut self, cx1: f64, cy1: f64, cx2: f64, cy2: f64, x: f64, y: f64) {
329 self.cubic_to(cx1, cy1, cx2, cy2, x, y)
330 }
331 fn quad_to(&mut self, cx: f64, cy: f64, x: f64, y: f64) {
332 self.quad_to(cx, cy, x, y)
333 }
334 fn arc_to(&mut self, cx: f64, cy: f64, r: f64, a1: f64, a2: f64, ccw: bool) {
335 self.arc_to(cx, cy, r, a1, a2, ccw)
336 }
337 fn circle(&mut self, cx: f64, cy: f64, r: f64) {
338 self.circle(cx, cy, r)
339 }
340 fn rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
341 self.rect(x, y, w, h)
342 }
343 fn rounded_rect(&mut self, x: f64, y: f64, w: f64, h: f64, r: f64) {
344 self.rounded_rect(x, y, w, h, r)
345 }
346 fn close_path(&mut self) {
347 self.close_path()
348 }
349 fn fill(&mut self) {
350 self.fill()
351 }
352 fn stroke(&mut self) {
353 self.stroke()
354 }
355 fn fill_and_stroke(&mut self) {
356 self.fill_and_stroke()
357 }
358
359 fn draw_triangles_aa(
360 &mut self,
361 vertices: &[[f32; 3]],
362 indices: &[u32],
363 color: crate::color::Color,
364 ) {
365 let saved_fill = self.state.fill_color;
373 self.set_fill_color(color);
374 let n_tris = indices.len() / 3;
375 for t in 0..n_tris {
376 let i0 = indices[t * 3] as usize;
377 let i1 = indices[t * 3 + 1] as usize;
378 let i2 = indices[t * 3 + 2] as usize;
379 if i0 >= vertices.len() || i1 >= vertices.len() || i2 >= vertices.len() {
380 continue;
381 }
382 let v0 = vertices[i0];
383 let v1 = vertices[i1];
384 let v2 = vertices[i2];
385 self.begin_path();
386 self.move_to(v0[0] as f64, v0[1] as f64);
387 self.line_to(v1[0] as f64, v1[1] as f64);
388 self.line_to(v2[0] as f64, v2[1] as f64);
389 self.close_path();
390 self.fill();
391 }
392 self.set_fill_color(saved_fill);
393 }
394 fn fill_text(&mut self, t: &str, x: f64, y: f64) {
395 self.fill_text(t, x, y)
396 }
397 fn fill_text_gsv(&mut self, t: &str, x: f64, y: f64, s: f64) {
398 self.fill_text_gsv(t, x, y, s)
399 }
400 fn measure_text(&self, t: &str) -> Option<crate::text::TextMetrics> {
401 self.measure_text(t)
402 }
403 fn transform(&self) -> agg_rust::trans_affine::TransAffine {
404 self.transform()
405 }
406 fn root_transform(&self) -> agg_rust::trans_affine::TransAffine {
407 let mut t = self.transform();
408 for layer in self.layer_stack.iter().rev() {
409 t.premultiply(&agg_rust::trans_affine::TransAffine::new_translation(
410 layer.origin_x,
411 layer.origin_y,
412 ));
413 }
414 t
415 }
416 fn save(&mut self) {
417 self.save()
418 }
419 fn restore(&mut self) {
420 self.restore()
421 }
422 fn translate(&mut self, tx: f64, ty: f64) {
423 self.translate(tx, ty)
424 }
425 fn rotate(&mut self, r: f64) {
426 self.rotate(r)
427 }
428 fn scale(&mut self, sx: f64, sy: f64) {
429 self.scale(sx, sy)
430 }
431 fn set_transform(&mut self, m: agg_rust::trans_affine::TransAffine) {
432 self.set_transform(m)
433 }
434 fn reset_transform(&mut self) {
435 self.reset_transform()
436 }
437 fn push_layer(&mut self, w: f64, h: f64) {
438 self.push_layer(w, h)
439 }
440 fn supports_compositing_layers(&self) -> bool {
441 true
442 }
443 fn push_layer_with_alpha(&mut self, w: f64, h: f64, alpha: f64) {
444 self.push_layer_with_alpha(w, h, alpha)
445 }
446 fn pop_layer(&mut self) {
447 self.pop_layer()
448 }
449
450 fn has_image_blit(&self) -> bool {
451 true
452 }
453
454 fn draw_image_rgba_arc(
455 &mut self,
456 data: &Arc<Vec<u8>>,
457 img_w: u32,
458 img_h: u32,
459 dst_x: f64,
460 dst_y: f64,
461 dst_w: f64,
462 dst_h: f64,
463 ) {
464 self.draw_image_rgba(data.as_slice(), img_w, img_h, dst_x, dst_y, dst_w, dst_h);
467 }
468
469 fn draw_lcd_backbuffer_arc(
470 &mut self,
471 color: &Arc<Vec<u8>>,
472 alpha: &Arc<Vec<u8>>,
473 _content_version: u64,
474 w: u32,
475 h: u32,
476 dst_x: f64,
477 dst_y: f64,
478 _dst_w: f64,
479 _dst_h: f64,
480 ) {
481 if w == 0 || h == 0 {
492 return;
493 }
494 let w_u = w as usize;
495 let h_u = h as usize;
496 if color.len() < w_u * h_u * 3 || alpha.len() < w_u * h_u * 3 {
497 return;
498 }
499
500 let t = &self.state.transform;
501 let sx = (dst_x * t.sx + dst_y * t.shx + t.tx).round() as i32;
502 let sy = (dst_x * t.shy + dst_y * t.sy + t.ty).round() as i32;
503 let ga = self.state.global_alpha.clamp(0.0, 1.0) as f32;
508 let clip = self.state.clip;
512 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
513 let fw = fb.width() as i32;
514 let fh = fb.height() as i32;
515 let (cx1, cy1, cx2, cy2) = match clip {
516 Some((cx, cy, cw, ch)) => (
517 cx.floor() as i32,
518 cy.floor() as i32,
519 (cx + cw).ceil() as i32,
520 (cy + ch).ceil() as i32,
521 ),
522 None => (0, 0, fw, fh),
523 };
524 let fw_u = fw as usize;
525 let pixels = fb.pixels_mut();
526
527 for src_y in 0..h_u {
528 let dy = sy + (h_u - 1 - src_y) as i32;
531 if dy < 0 || dy >= fh || dy < cy1 || dy >= cy2 {
532 continue;
533 }
534 let dy_u = dy as usize;
535 for src_x in 0..w_u {
536 let dx = sx + src_x as i32;
537 if dx < 0 || dx >= fw || dx < cx1 || dx >= cx2 {
538 continue;
539 }
540 let ci = (src_y * w_u + src_x) * 3;
541
542 let sa_r = (alpha[ci] as f32 / 255.0) * ga;
543 let sa_g = (alpha[ci + 1] as f32 / 255.0) * ga;
544 let sa_b = (alpha[ci + 2] as f32 / 255.0) * ga;
545 if sa_r == 0.0 && sa_g == 0.0 && sa_b == 0.0 {
546 continue;
547 }
548
549 let sc_r = (color[ci] as f32 / 255.0) * ga;
550 let sc_g = (color[ci + 1] as f32 / 255.0) * ga;
551 let sc_b = (color[ci + 2] as f32 / 255.0) * ga;
552
553 let di = (dy_u * fw_u + dx as usize) * 4;
554 let dc_r = pixels[di] as f32 / 255.0;
561 let dc_g = pixels[di + 1] as f32 / 255.0;
562 let dc_b = pixels[di + 2] as f32 / 255.0;
563 let da = pixels[di + 3] as f32 / 255.0;
564
565 let rc_r = sc_r + dc_r * (1.0 - sa_r);
566 let rc_g = sc_g + dc_g * (1.0 - sa_g);
567 let rc_b = sc_b + dc_b * (1.0 - sa_b);
568 let src_a_max = sa_r.max(sa_g).max(sa_b);
569 let ra = src_a_max + da * (1.0 - src_a_max);
570
571 pixels[di] = (rc_r * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
572 pixels[di + 1] = (rc_g * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
573 pixels[di + 2] = (rc_b * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
574 pixels[di + 3] = (ra * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
575 }
576 }
577 }
578
579 fn has_lcd_mask_composite(&self) -> bool {
580 true
581 }
582
583 fn draw_lcd_mask(
584 &mut self,
585 mask: &[u8],
586 mask_w: u32,
587 mask_h: u32,
588 src_color: Color,
589 dst_x: f64,
590 dst_y: f64,
591 ) {
592 if mask.len() < (mask_w as usize) * (mask_h as usize) * 3 {
597 return;
598 }
599 let t = &self.state.transform;
600 let sx = dst_x * t.sx + dst_y * t.shx + t.tx;
601 let sy = dst_x * t.shy + dst_y * t.sy + t.ty;
602 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
603 let fw = fb.width();
604 let fh = fb.height();
605 let origin_x = sx.round() as i32;
606 let origin_y = sy.round() as i32;
607
608 let sa = src_color.a.clamp(0.0, 1.0);
609 let sr = src_color.r.clamp(0.0, 1.0);
610 let sg = src_color.g.clamp(0.0, 1.0);
611 let sb = src_color.b.clamp(0.0, 1.0);
612 let fw_i = fw as i32;
613 let fh_i = fh as i32;
614 let mw_i = mask_w as i32;
615 let mh_i = mask_h as i32;
616 let pixels = fb.pixels_mut();
617
618 for my in 0..mh_i {
619 let dy = origin_y + my;
622 if dy < 0 || dy >= fh_i {
623 continue;
624 }
625 for mx in 0..mw_i {
626 let dx = origin_x + mx;
627 if dx < 0 || dx >= fw_i {
628 continue;
629 }
630 let mi = ((my * mw_i + mx) * 3) as usize;
631 let cr = (mask[mi] as f32 / 255.0) * sa;
634 let cg = (mask[mi + 1] as f32 / 255.0) * sa;
635 let cb = (mask[mi + 2] as f32 / 255.0) * sa;
636 if cr == 0.0 && cg == 0.0 && cb == 0.0 {
637 continue;
638 }
639 let di = ((dy * fw_i + dx) * 4) as usize;
640 let dr = pixels[di] as f32 / 255.0;
641 let dg = pixels[di + 1] as f32 / 255.0;
642 let db = pixels[di + 2] as f32 / 255.0;
643 let rr = sr * cr + dr * (1.0 - cr);
644 let rg = sg * cg + dg * (1.0 - cg);
645 let rbb = sb * cb + db * (1.0 - cb);
646 pixels[di] = (rr * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
647 pixels[di + 1] = (rg * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
648 pixels[di + 2] = (rbb * 255.0 + 0.5).clamp(0.0, 255.0) as u8;
649 }
653 }
654 }
655
656 fn draw_image_rgba(
657 &mut self,
658 data: &[u8],
659 img_w: u32,
660 img_h: u32,
661 dst_x: f64,
662 dst_y: f64,
663 dst_w: f64,
664 dst_h: f64,
665 ) {
666 if img_w == 0 || img_h == 0 || dst_w < 1.0 || dst_h < 1.0 {
669 return;
670 }
671
672 let out_w = dst_w.round() as u32;
673 let out_h = dst_h.round() as u32;
674 let mut scaled = crate::framebuffer::Framebuffer::new(out_w, out_h);
675
676 let px = scaled.pixels_mut();
682 for dy in 0..out_h {
683 for dx in 0..out_w {
684 let sx = (dx as f64 / out_w as f64 * img_w as f64) as u32;
685 let sy_img = ((1.0 - (dy as f64 + 0.5) / out_h as f64) * img_h as f64)
687 .floor()
688 .clamp(0.0, (img_h - 1) as f64) as u32;
689 let si = ((sy_img * img_w + sx) * 4) as usize;
690 let di = ((dy * out_w + dx) * 4) as usize;
691 if si + 3 < data.len() && di + 3 < px.len() {
692 let a = data[si + 3] as u32;
693 if a == 255 {
694 px[di] = data[si];
695 px[di + 1] = data[si + 1];
696 px[di + 2] = data[si + 2];
697 px[di + 3] = 255;
698 } else {
699 px[di] = (((data[si] as u32) * a + 127) / 255) as u8;
701 px[di + 1] = (((data[si + 1] as u32) * a + 127) / 255) as u8;
702 px[di + 2] = (((data[si + 2] as u32) * a + 127) / 255) as u8;
703 px[di + 3] = a as u8;
704 }
705 }
706 }
707 }
708
709 let (tx, ty) = {
711 let t = self.transform();
712 (t.tx, t.ty)
713 };
714 let screen_x = (tx + dst_x).round() as i32;
715 let screen_y = (ty + dst_y).round() as i32;
716 let ga = self.state.global_alpha;
721 let clip = self.state.clip;
727 let fb = active_fb(&mut self.base_fb, &mut self.layer_stack);
728 composite_framebuffers(fb, &scaled, screen_x, screen_y, ga, clip);
729 }
730}
731
732pub(crate) fn apply_clip<PF: agg_rust::pixfmt_rgba::PixelFormat>(
734 rb: &mut RendererBase<PF>,
735 clip: Option<(f64, f64, f64, f64)>,
736) {
737 if let Some((x, y, w, h)) = clip {
738 let x1 = x.floor() as i32;
739 let y1 = y.floor() as i32;
740 let x2 = (x + w).ceil() as i32 - 1;
741 let y2 = (y + h).ceil() as i32 - 1;
742 rb.clip_box_i(x1, y1, x2, y2);
743 }
744}