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