diff --git a/.gitmodules b/.gitmodules index 6bb1f137e06..035e5c4961c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -103,3 +103,6 @@ [submodule "src/support/css/rust-cssparser"] path = src/support/css/rust-cssparser url = https://github.com/mozilla-servo/rust-cssparser.git +[submodule "src/support/png/rust-png"] + path = src/support/png/rust-png + url = https://github.com/mozilla-servo/rust-png.git diff --git a/README.md b/README.md index 78a4092b3ff..8161466a76e 100644 --- a/README.md +++ b/README.md @@ -9,8 +9,7 @@ On OS X (homebrew): ``` sh brew install https://raw.github.com/Homebrew/homebrew-versions/master/autoconf213.rb -brew install automake libtool -brew install pkg-config +brew install automake libtool pkg-config libpng ``` On OS X (MacPorts): @@ -24,7 +23,7 @@ On Debian-based Linuxes: ``` sh sudo apt-get install autoconf2.13 curl freeglut3-dev libtool \ libfreetype6-dev libfontconfig1-dev libgl1-mesa-dri libglib2.0-dev \ - xorg-dev + xorg-dev libpng-dev ``` Servo builds its own copy of Rust, so there is no need to provide a Rust @@ -59,6 +58,7 @@ make && make check - `Ctrl-=` zooms in - `Backspace` goes backwards in the history - `Shift-Backspace` goes forwards in the history +- `Esc` exits servo ## Developing diff --git a/configure b/configure index 7a40b5020fa..f0c24ba25e6 100755 --- a/configure +++ b/configure @@ -422,6 +422,7 @@ CFG_SUBMODULES="\ support/spidermonkey/mozjs \ support/spidermonkey/rust-mozjs \ support/stb-image/rust-stb-image \ + support/png/rust-png \ support/wapcaplet/libwapcaplet \ support/wapcaplet/rust-wapcaplet" diff --git a/mk/check.mk b/mk/check.mk index 6bf902c9a14..b3a9a899ea8 100644 --- a/mk/check.mk +++ b/mk/check.mk @@ -1,5 +1,6 @@ define DEF_SUBMODULE_TEST_RULES # check target +.PHONY: check-$(1) check-$(1) : $$(DONE_$(1)) @$$(call E, make check: $(1)) @@ -31,20 +32,28 @@ DEPS_CHECK_TESTABLE = $(filter-out $(NO_TESTS),$(DEPS_CHECK_ALL)) DEPS_CHECK_TARGETS_ALL = $(addprefix check-,$(DEPS_CHECK_TESTABLE)) DEPS_CHECK_TARGETS_FAST = $(addprefix check-,$(filter-out $(SLOW_TESTS),$(DEPS_CHECK_TESTABLE))) -.PHONY: check $(DEPS_CHECK_TARGETS_ALL) +.PHONY: check-test +check-test: + echo $(DEPS_CHECK_TARGETS_ALL) +.PHONY: check check: $(DEPS_CHECK_TARGETS_FAST) check-servo tidy +.PHONY: check-all check-all: $(DEPS_CHECK_TARGETS_ALL) check-servo tidy +.PHONY: check-servo check-servo: servo-test ./servo-test $(TESTNAME) +.PHONY: check-ref check-ref: reftest ./reftest --source-dir=$(S)/src/test/html/ref --work-dir=src/test/html/ref $(TESTNAME) +.PHONY: check-content check-content: contenttest ./contenttest --source-dir=$(S)/src/test/html/content $(TESTNAME) +.PHONY: tidy tidy: python $(S)src/etc/tidy.py $(S)src diff --git a/src/components/gfx/opts.rs b/src/components/gfx/opts.rs index cba8d517587..456d37869c9 100644 --- a/src/components/gfx/opts.rs +++ b/src/components/gfx/opts.rs @@ -20,6 +20,7 @@ pub struct Opts { tile_size: uint, profiler_period: Option, exit_after_load: bool, + output_file: Option<~str>, } #[allow(non_implicitly_copyable_typarams)] @@ -48,10 +49,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { copy opt_match.free }; - if getopts::opt_present(&opt_match, "o") { - fail!(~"servo cannot treat 'o' option now.") - } - let render_backend = match getopts::opt_maybe_str(&opt_match, "r") { Some(backend_str) => { if backend_str == ~"direct2d" { @@ -90,6 +87,8 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { let exit_after_load = getopts::opt_present(&opt_match, "x"); + let output_file = getopts::opt_maybe_str(&opt_match, "o"); + Opts { urls: urls, render_backend: render_backend, @@ -97,5 +96,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts { tile_size: tile_size, profiler_period: profiler_period, exit_after_load: exit_after_load, + output_file: output_file, } } diff --git a/src/components/main/compositing/mod.rs b/src/components/main/compositing/mod.rs index d277c2f551e..fa9799210b5 100644 --- a/src/components/main/compositing/mod.rs +++ b/src/components/main/compositing/mod.rs @@ -24,6 +24,8 @@ use std::comm; use std::comm::{Chan, SharedChan, Port}; use std::num::Orderable; use std::task; +use std::uint; +use std::vec; use extra::uv_global_loop; use extra::timer; use geom::matrix::identity; @@ -35,6 +37,8 @@ use layers::layers::{ImageData, WithDataFn}; use layers::layers::{TextureLayerKind, TextureLayer, TextureManager}; use layers::rendergl; use layers::scene::Scene; +use opengles::gl2; +use png; use servo_util::{time, url}; use servo_util::time::profile; use servo_util::time::ProfilerChan; @@ -464,6 +468,8 @@ impl CompositorTask { }; let profiler_chan = self.profiler_chan.clone(); + let write_png = self.opts.output_file.is_some(); + let exit = self.opts.exit_after_load; let composite = || { do profile(time::CompositingCategory, profiler_chan.clone()) { debug!("compositor: compositing"); @@ -474,7 +480,40 @@ impl CompositorTask { rendergl::render_scene(context, scene); } + // Render to PNG. We must read from the back buffer (ie, before + // window.present()) as OpenGL ES 2 does not have glReadBuffer(). + if write_png { + let (width, height) = (window_size.width as uint, window_size.height as uint); + let path = Path(*self.opts.output_file.get_ref()); + let mut pixels = gl2::read_pixels(0, 0, + width as gl2::GLsizei, + height as gl2::GLsizei, + gl2::RGB, gl2::UNSIGNED_BYTE); + // flip image vertically (texture is upside down) + let orig_pixels = pixels.clone(); + let stride = width * 3; + for uint::range(0, height) |y| { + let dst_start = y * stride; + let src_start = (height - y - 1) * stride; + vec::bytes::copy_memory(pixels.mut_slice(dst_start, dst_start + stride), + orig_pixels.slice(src_start, src_start + stride), + stride); + } + let img = png::Image { + width: width as u32, + height: height as u32, + color_type: png::RGB8, + pixels: pixels, + }; + let res = png::store_png(&img, &path); + assert!(res.is_ok()); + + *done = true; + } + window.present(); + + if exit { *done = true; } }; // When the user scrolls, move the layer around. @@ -548,12 +587,6 @@ impl CompositorTask { *recomposite = true; } - if self.opts.exit_after_load { - do window.set_finished_callback || { - *done = true; - } - } - // Enter the main event loop. while !*done { // Check for new messages coming from the rendering task. diff --git a/src/components/main/servo.rc b/src/components/main/servo.rc index a009790daad..1f660764c93 100755 --- a/src/components/main/servo.rc +++ b/src/components/main/servo.rc @@ -21,6 +21,7 @@ extern mod js; extern mod layers; extern mod newcss (name = "css"); extern mod opengles; +extern mod png; extern mod script; extern mod servo_net (name = "net"); extern mod servo_msg (name = "msg"); diff --git a/src/support/azure/rust-azure b/src/support/azure/rust-azure index ae7c99be106..c6774cb3ebd 160000 --- a/src/support/azure/rust-azure +++ b/src/support/azure/rust-azure @@ -1 +1 @@ -Subproject commit ae7c99be106e5767b0384f16887579d55e222e71 +Subproject commit c6774cb3ebdb20b1736fa3e8b5e8348fefbc987f diff --git a/src/support/opengles/rust-opengles b/src/support/opengles/rust-opengles index 17bd4bbc049..b5cb5593f49 160000 --- a/src/support/opengles/rust-opengles +++ b/src/support/opengles/rust-opengles @@ -1 +1 @@ -Subproject commit 17bd4bbc04942e7de9eae76c0f8a76dfcb3dc9fc +Subproject commit b5cb5593f4938a578eebda56c905bbaff33efe66 diff --git a/src/support/png/rust-png b/src/support/png/rust-png new file mode 160000 index 00000000000..1d24ffad5ca --- /dev/null +++ b/src/support/png/rust-png @@ -0,0 +1 @@ +Subproject commit 1d24ffad5caed4c2b28240f78f3e036558a97912