From 572d505037caa703ef9752ebea96e607e55fe791 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 4 May 2012 22:59:19 -0700 Subject: [PATCH] Add a PNG graphics sink --- src/servo/gfx/pngsink.rs | 122 +++++++++++++++++++++++++++++++++++++++ src/servo/servo.rc | 1 + 2 files changed, 123 insertions(+) create mode 100644 src/servo/gfx/pngsink.rs diff --git a/src/servo/gfx/pngsink.rs b/src/servo/gfx/pngsink.rs new file mode 100644 index 00000000000..8f3f8e4b229 --- /dev/null +++ b/src/servo/gfx/pngsink.rs @@ -0,0 +1,122 @@ +#[doc = " +A graphics sink that renders to PNG format buffers + +Each time the renderer renders a frame the bufsink will output a +`[u8]` containing the frame in PNG format. +"]; + +export msg, pngsink; + +import azure::cairo; +import azure_bg = azure::bindgen; +import azure::AzDrawTargetRef; +import cairo_bg = cairo::bindgen; + +enum msg { + begin_drawing(chan), + draw(chan, AzDrawTargetRef), + exit +} + +impl pngsink of renderer::sink for chan { + fn begin_drawing(next_dt: chan) { + self.send(begin_drawing(next_dt)) + } + fn draw(next_dt: chan, draw_me: AzDrawTargetRef) { + self.send(draw(next_dt, draw_me)) + } +} + +fn pngsink(output: chan<[u8]>) -> chan { + task::spawn_listener:: { |po| + + let cairo_surf = cairo_bg::cairo_image_surface_create( + cairo::CAIRO_FORMAT_ARGB32, 800 as libc::c_int, 600 as libc::c_int + ); + assert cairo_surf.is_not_null(); + + let draw_target = azure_bg::AzCreateDrawTargetForCairoSurface(cairo_surf); + assert draw_target.is_not_null(); + + loop { + alt po.recv() { + begin_drawing(sender) { + sender.send(draw_target); + } + draw(sender, dt) { + do_draw(sender, dt, output, cairo_surf); + } + exit { break } + } + } + + azure_bg::AzReleaseDrawTarget(draw_target); + cairo_bg::cairo_surface_destroy(cairo_surf); + } +} + +fn do_draw(sender: chan, + dt: AzDrawTargetRef, + output: comm::chan<[u8]>, + cairo_surf: *cairo::cairo_surface_t) { + + import libc::*; + + listen {|data_ch| + + crust fn write_fn(closure: *c_void, + data: *c_uchar, + len: c_uint) + + -> cairo::cairo_status_t unsafe { + + let p: *chan<[u8]> = unsafe::reinterpret_cast(closure); + let data_ch = *p; + + // Convert from *c_uchar to *u8 + let data = unsafe::reinterpret_cast(data); + let len = len as uint; + // Copy to a vector + let data = vec::unsafe::from_buf(data, len); + data_ch.send(data); + + ret cairo::CAIRO_STATUS_SUCCESS; + } + + let closure = ptr::addr_of(data_ch); + + unsafe { + cairo_bg::cairo_surface_write_to_png_stream( + cairo_surf, write_fn, unsafe::reinterpret_cast(closure)); + } + + // Collect the entire image into a single vector + let mut result = []; + while data_ch.peek() { + result += data_ch.recv(); + } + + // Send the PNG image away + output.send(result); + } + // Send the next draw target to the renderer + sender.send(dt); +} + +#[test] +fn sanity_check() { + + listen {|ch| + + let sink = pngsink(ch); + let renderer = renderer::renderer(sink); + + let dlist = []; + renderer.send(renderer::render(dlist)); + listen {|resp| + renderer.send(renderer::exit(resp)); + resp.recv(); + } + sink.send(exit) + } +} \ No newline at end of file diff --git a/src/servo/servo.rc b/src/servo/servo.rc index a2f25852963..37175d56bbb 100755 --- a/src/servo/servo.rc +++ b/src/servo/servo.rc @@ -19,6 +19,7 @@ mod gfx { mod geom; mod surface; mod renderer; + mod pngsink; } mod image {