Merge pull request #431 from pcwalton/refactor-compositor

Refactor compositor
This commit is contained in:
Jack Moffitt 2013-05-09 15:15:21 -07:00
commit cdc99a8572
38 changed files with 510 additions and 484 deletions

View file

@ -168,21 +168,28 @@ DONE_servo_util = $(B)src/servo-util/libservoutil.dummy
DEPS_servo_util = $(CRATE_servo_util) $(SRC_servo_util) $(DONE_SUBMODULES)
RFLAGS_servo_gfx = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util
RFLAGS_servo_net = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util
SRC_servo_net = $(call rwildcard,$(S)src/servo-net/,*.rs)
CRATE_servo_net = $(S)src/servo-net/servo_net.rc
DONE_servo_net = $(B)src/servo-net/libservonet.dummy
DEPS_servo_net = $(CRATE_servo_net) $(SRC_servo_net) $(DONE_SUBMODULES) $(DONE_servo_util)
RFLAGS_servo_gfx = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-util -L $(B)src/servo-net
SRC_servo_gfx = $(call rwildcard,$(S)src/servo-gfx/,*.rs)
CRATE_servo_gfx = $(S)src/servo-gfx/servo_gfx.rc
DONE_servo_gfx = $(B)src/servo-gfx/libservogfx.dummy
DEPS_servo_gfx = $(CRATE_servo_gfx) $(SRC_servo_gfx) $(DONE_SUBMODULES) $(DONE_servo_util)
DEPS_servo_gfx = $(CRATE_servo_gfx) $(SRC_servo_gfx) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_net)
RFLAGS_servo = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-gfx -L $(B)src/servo-util
RFLAGS_servo = $(strip $(CFG_RUSTC_FLAGS)) $(addprefix -L $(B)src/,$(DEPS_SUBMODULES)) -L $(B)src/servo-gfx -L $(B)src/servo-util -L $(B)src/servo-net
WEBIDL_servo = $(call rwildcard,$(S)src/servo/,*.webidl)
AUTOGEN_SRC_servo = $(patsubst %.webidl, %Binding.rs, $(WEBIDL_servo))
SRC_servo = $(call rwildcard,$(S)src/servo/,*.rs) $(AUTOGEN_SRC_servo)
CRATE_servo = $(S)src/servo/servo.rc
DEPS_servo = $(CRATE_servo) $(SRC_servo) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_gfx)
DEPS_servo = $(CRATE_servo) $(SRC_servo) $(DONE_SUBMODULES) $(DONE_servo_util) $(DONE_servo_gfx) $(DONE_servo_net)
# rules that depend on having correct meta-target vars (DEPS_CLEAN, DEPS_servo, etc)
include $(S)mk/check.mk
@ -197,6 +204,9 @@ all: servo package
$(DONE_servo_util): $(DEPS_servo_util)
$(RUSTC) $(RFLAGS_servo_util) -o $@ $< && touch $@
$(DONE_servo_net): $(DEPS_servo_net)
$(RUSTC) $(RFLAGS_servo_net) -o $@ $< && touch $@
$(DONE_servo_gfx): $(DEPS_servo_gfx)
$(RUSTC) $(RFLAGS_servo_gfx) -o $@ $< && touch $@

1
configure vendored
View file

@ -419,6 +419,7 @@ do
done
make_dir ${CFG_BUILD_DIR}src/servo-util
make_dir ${CFG_BUILD_DIR}src/servo-net
make_dir ${CFG_BUILD_DIR}src/servo-gfx
make_dir src/test/ref
make_dir src/rust

View file

@ -21,10 +21,8 @@ pub struct LayerBufferSet {
buffers: ~[LayerBuffer]
}
/**
The interface used to by the renderer to aquire draw targets for
each rendered frame and submit them to be drawn to the display
*/
/// The interface used to by the renderer to acquire draw targets for each rendered frame and
/// submit them to be drawn to the display.
pub trait Compositor {
fn begin_drawing(&self, next_dt: comm::Chan<LayerBufferSet>);
fn draw(&self, next_dt: comm::Chan<LayerBufferSet>, +draw_me: LayerBufferSet);

View file

@ -4,15 +4,15 @@
use color::{Color, rgb};
use geometry::Au;
use image::base::Image;
use render_context::RenderContext;
use text::SendableTextRun;
use servo_util::range::Range;
use clone_arc = std::arc::clone;
use geom::Rect;
use geom::Point2D;
use std::arc::ARC;
use servo_net::image::base::Image;
use servo_util::range::Range;
struct DisplayItemData {
bounds : Rect<Au>, // TODO: whose coordinate system should this use?

View file

@ -1,28 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use core::io::WriterUtil;
use surface;
fn encode(writer: @io::Writer, surface: &surface::ImageSurface) {
assert!(surface.format == surface::fo_rgba_8888);
writer.write_u8(0u8); // identsize
writer.write_u8(0u8); // colourmaptype
writer.write_u8(2u8); // imagetype
writer.write_le_u16(0u16); // colourmapstart
writer.write_le_u16(0u16); // colourmaplength
writer.write_u8(16u8); // colourmapbits
writer.write_le_u16(0u16); // xstart
writer.write_le_u16(0u16); // ystart
writer.write_le_u16(surface.size.width as u16); // width
writer.write_le_u16(surface.size.height as u16); // height
writer.write_u8(32u8); // bits
writer.write_u8(0x30u8); // descriptor
writer.write(surface.buffer);
}

View file

@ -10,17 +10,11 @@ use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBacke
pub struct Opts {
urls: ~[~str],
render_mode: RenderMode,
render_backend: BackendType,
n_render_threads: uint,
tile_size: uint,
}
pub enum RenderMode {
Screen,
Png(~str)
}
#[allow(non_implicitly_copyable_typarams)]
pub fn from_cmdline_args(args: &[~str]) -> Opts {
use std::getopts;
@ -45,11 +39,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
copy opt_match.free
};
let render_mode = match getopts::opt_maybe_str(&opt_match, ~"o") {
Some(output_file) => Png(output_file),
None => Screen,
};
let render_backend = match getopts::opt_maybe_str(&opt_match, ~"r") {
Some(backend_str) => {
if backend_str == ~"direct2d" {
@ -81,7 +70,6 @@ pub fn from_cmdline_args(args: &[~str]) -> Opts {
Opts {
urls: urls,
render_mode: render_mode,
render_backend: render_backend,
n_render_threads: n_render_threads,
tile_size: tile_size,

View file

@ -5,7 +5,6 @@
use compositor::LayerBuffer;
use font_context::FontContext;
use geometry::Au;
use image::base::Image;
use opts::Opts;
use azure::azure_hl::{B8G8R8A8, Color, ColorPattern, DrawOptions};
@ -15,6 +14,7 @@ use core::libc::types::common::c99::uint16_t;
use geom::point::Point2D;
use geom::rect::Rect;
use geom::size::Size2D;
use servo_net::image::base::Image;
use std::arc;
use std::arc::ARC;

View file

@ -11,13 +11,13 @@ use geom::matrix2d::Matrix2D;
use opts::Opts;
use render_context::RenderContext;
use render_layers::{RenderLayer, render_layers};
use resource::util::spawn_listener;
use servo_util::time::time;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::task::SingleThreaded;
use std::task_pool::TaskPool;
use servo_net::util::spawn_listener;
use servo_util::time::time;
pub enum Msg {
RenderMsg(RenderLayer),

View file

@ -13,6 +13,7 @@ extern mod geom;
extern mod http_client;
extern mod stb_image;
extern mod std;
extern mod servo_net;
extern mod servo_util (name = "servo_util");
// Eventually we would like the shaper to be pluggable, as many operating systems have their own
@ -57,22 +58,7 @@ pub mod opts;
#[path="platform/mod.rs"]
pub mod platform;
// Images
pub mod image {
pub mod base;
pub mod holder;
}
// Text
#[path = "text/mod.rs"]
pub mod text;
// FIXME: Blech. This does not belong in the GFX module.
pub mod resource {
pub mod file_loader;
pub mod http_loader;
pub mod image_cache_task;
pub mod local_image_cache;
pub mod resource_task;
pub mod util;
}

View file

@ -2,16 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use core::task::spawn;
use resource::resource_task::{Payload, Done, LoaderTask};
use core::io::{file_reader, ReaderUtil};
use resource_task::{Done, LoaderTask, Payload};
use core::io::{ReaderUtil, file_reader};
use core::task;
static READ_SIZE: uint = 1024;
pub fn factory() -> LoaderTask {
let f: LoaderTask = |url, progress_chan| {
assert!(url.scheme == ~"file");
do spawn {
assert!("file" == url.scheme);
do task::spawn {
// FIXME: Resolve bug prevents us from moving the path out of the URL.
match file_reader(&Path(url.path)) {
Ok(reader) => {

View file

@ -2,18 +2,19 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use resource_task::{Payload, Done, LoaderTask};
use core::comm::SharedChan;
use core::task::spawn;
use resource::resource_task::{Payload, Done, LoaderTask};
use core::task;
use http_client::uv_http_request;
use http_client;
use http_client::{uv_http_request};
pub fn factory() -> LoaderTask {
let f: LoaderTask = |url, progress_chan| {
assert!(url.scheme == ~"http");
let progress_chan = SharedChan::new(progress_chan);
do spawn {
do task::spawn {
debug!("http_loader: requesting via http: %?", url.clone());
let mut request = uv_http_request(url.clone());
let errored = @mut false;

View file

@ -20,7 +20,6 @@ pub fn test_image_bin() -> ~[u8] {
}
pub fn load_from_memory(buffer: &[u8]) -> Option<Image> {
// Can't remember why we do this. Maybe it's what cairo wants
static FORCE_DEPTH: uint = 4;

View file

@ -3,21 +3,20 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use image::base::Image;
use resource::image_cache_task::{ImageReady, ImageNotReady, ImageFailed};
use resource::local_image_cache::LocalImageCache;
use image_cache_task::{ImageReady, ImageNotReady, ImageFailed};
use local_image_cache::LocalImageCache;
use core::util::replace;
use geom::size::Size2D;
use std::net::url::Url;
use std::arc::{ARC, clone, get};
// FIXME: Nasty coupling to resource here. This should probably be factored out into an interface
// and use dependency injection.
// FIXME: Nasty coupling here This will be a problem if we want to factor out image handling from
// the network stack. This should probably be factored out into an interface and use dependency
// injection.
/** A struct to store image data. The image will be loaded once, the
first time it is requested, and an arc will be stored. Clones of
this arc are given out on demand.
*/
/// A struct to store image data. The image will be loaded once the first time it is requested,
/// and an ARC will be stored. Clones of this ARC are given out on demand.
pub struct ImageHolder {
url: Url,
image: Option<ARC<~Image>>,
@ -46,18 +45,16 @@ pub impl ImageHolder {
holder
}
/**
This version doesn't perform any computation, but may be stale w.r.t.
newly-available image data that determines size.
The intent is that the impure version is used during layout when
dimensions are used for computing layout.
*/
/// This version doesn't perform any computation, but may be stale w.r.t. newly-available image
/// data that determines size.
///
/// The intent is that the impure version is used during layout when dimensions are used for
/// computing layout.
fn size(&self) -> Size2D<int> {
self.cached_size
}
/** Query and update current image size */
/// Query and update the current image size.
fn get_size(&mut self) -> Option<Size2D<int>> {
debug!("get_size() %?", self.url);
match self.get_image() {
@ -103,3 +100,4 @@ pub impl ImageHolder {
return result;
}
}

View file

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Before After
Before After

View file

@ -3,46 +3,46 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use image::base::{Image, load_from_memory};
use resource::resource_task;
use resource::resource_task::ResourceTask;
use resource_task;
use resource_task::ResourceTask;
use servo_util::url::{UrlMap, url_map};
use clone_arc = std::arc::clone;
use core::cell::Cell;
use core::comm::{Chan, Port, SharedChan, stream};
use core::task::spawn;
use core::to_str::ToStr;
use core::util::replace;
use std::arc::ARC;
use std::net::url::Url;
use core::cell::Cell;
pub enum Msg {
/// Tell the cache that we may need a particular image soon. Must be posted
/// before Decode
pub Prefetch(Url),
Prefetch(Url),
// FIXME: We can probably get rid of this Cell now
/// Used be the prefetch tasks to post back image binaries
priv StorePrefetchedImageData(Url, Result<Cell<~[u8]>, ()>),
/// Tell the cache to decode an image. Must be posted before GetImage/WaitForImage
pub Decode(Url),
Decode(Url),
/// Used by the decoder tasks to post decoded images back to the cache
priv StoreImage(Url, Option<ARC<~Image>>),
/// Request an Image object for a URL. If the image is not is not immediately
/// available then ImageNotReady is returned.
pub GetImage(Url, Chan<ImageResponseMsg>),
GetImage(Url, Chan<ImageResponseMsg>),
/// Wait for an image to become available (or fail to load).
pub WaitForImage(Url, Chan<ImageResponseMsg>),
WaitForImage(Url, Chan<ImageResponseMsg>),
/// For testing
priv OnMsg(~fn(msg: &Msg)),
/// Clients must wait for a response before shutting down the ResourceTask
pub Exit(Chan<()>)
Exit(Chan<()>),
}
pub enum ImageResponseMsg {
@ -54,9 +54,9 @@ pub enum ImageResponseMsg {
impl ImageResponseMsg {
fn clone(&self) -> ImageResponseMsg {
match *self {
ImageReady(ref img) => ImageReady(clone_arc(img)),
ImageNotReady => ImageNotReady,
ImageFailed => ImageFailed
ImageReady(ref img) => ImageReady(clone_arc(img)),
ImageNotReady => ImageNotReady,
ImageFailed => ImageFailed,
}
}
}
@ -65,17 +65,16 @@ impl Eq for ImageResponseMsg {
fn eq(&self, other: &ImageResponseMsg) -> bool {
// FIXME: Bad copies
match (self.clone(), other.clone()) {
(ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"),
(ImageNotReady, ImageNotReady) => true,
(ImageFailed, ImageFailed) => true,
(ImageReady(*), ImageReady(*)) => fail!(~"unimplemented comparison"),
(ImageNotReady, ImageNotReady) => true,
(ImageFailed, ImageFailed) => true,
(ImageReady(*), _)
| (ImageNotReady, _)
| (ImageFailed, _) => false
(ImageReady(*), _) | (ImageNotReady, _) | (ImageFailed, _) => false
}
}
fn ne(&self, other: &ImageResponseMsg) -> bool {
return !(*self).eq(other);
!(*self).eq(other)
}
}
@ -87,9 +86,8 @@ pub fn ImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
ImageCacheTask_(resource_task, default_decoder_factory)
}
pub fn ImageCacheTask_(resource_task: ResourceTask,
decoder_factory: DecoderFactory)
-> ImageCacheTask {
pub fn ImageCacheTask_(resource_task: ResourceTask, decoder_factory: DecoderFactory)
-> ImageCacheTask {
// FIXME: Doing some dancing to avoid copying decoder_factory, our test
// version of which contains an uncopyable type which rust will currently
// copy unsoundly
@ -140,7 +138,7 @@ fn SyncImageCacheTask(resource_task: ResourceTask) -> ImageCacheTask {
}
}
return SharedChan::new(chan);
SharedChan::new(chan)
}
struct ImageCache {
@ -175,9 +173,7 @@ enum AfterPrefetch {
#[allow(non_implicitly_copyable_typarams)]
impl ImageCache {
pub fn run(&mut self) {
let mut msg_handlers: ~[~fn(msg: &Msg)] = ~[];
loop {
@ -397,26 +393,12 @@ impl ImageCache {
priv fn get_image(&self, url: Url, response: Chan<ImageResponseMsg>) {
match self.get_state(copy url) {
Init => fail!(~"request for image before prefetch"),
Prefetching(DoDecode) => {
response.send(ImageNotReady);
}
Prefetching(DoNotDecode)
| Prefetched(*) => fail!(~"request for image before decode"),
Decoding => {
response.send(ImageNotReady)
}
Decoded(image) => {
response.send(ImageReady(clone_arc(image)));
}
Failed => {
response.send(ImageFailed);
}
Init => fail!(~"request for image before prefetch"),
Prefetching(DoDecode) => response.send(ImageNotReady),
Prefetching(DoNotDecode) | Prefetched(*) => fail!(~"request for image before decode"),
Decoding => response.send(ImageNotReady),
Decoded(image) => response.send(ImageReady(clone_arc(image))),
Failed => response.send(ImageFailed),
}
}
@ -505,7 +487,6 @@ fn mock_resource_task(on_load: ~fn(resource: Chan<resource_task::ProgressMsg>))
#[test]
fn should_exit_on_request() {
let mock_resource_task = mock_resource_task(|_response| () );
let image_cache_task = ImageCacheTask(mock_resource_task);
@ -518,7 +499,6 @@ fn should_exit_on_request() {
#[test]
#[should_fail]
fn should_fail_if_unprefetched_image_is_requested() {
let mock_resource_task = mock_resource_task(|_response| () );
let image_cache_task = ImageCacheTask(mock_resource_task);
@ -552,7 +532,6 @@ fn should_request_url_from_resource_task_on_prefetch() {
#[test]
#[should_fail]
fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
let mock_resource_task = mock_resource_task(|_response| () );
let image_cache_task = ImageCacheTask(mock_resource_task);
@ -565,7 +544,6 @@ fn should_fail_if_requesting_decode_of_an_unprefetched_image() {
#[test]
#[should_fail]
fn should_fail_if_requesting_image_before_requesting_decode() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Done(result::Ok(())));
};
@ -606,7 +584,6 @@ fn should_not_request_url_from_resource_task_on_multiple_prefetches() {
#[test]
fn should_return_image_not_ready_if_data_has_not_arrived() {
let (wait_chan, wait_port) = pipes::stream();
let mock_resource_task = do mock_resource_task |response| {
@ -632,7 +609,6 @@ fn should_return_image_not_ready_if_data_has_not_arrived() {
#[test]
fn should_return_decoded_image_data_if_data_has_arrived() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(())));
@ -670,7 +646,6 @@ fn should_return_decoded_image_data_if_data_has_arrived() {
#[test]
fn should_return_decoded_image_data_for_multiple_requests() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(())));
@ -710,7 +685,6 @@ fn should_return_decoded_image_data_for_multiple_requests() {
#[test]
fn should_not_request_image_from_resource_task_if_image_is_already_available() {
let image_bin_sent = comm::Port();
let image_bin_sent_chan = image_bin_sent.chan();
@ -755,7 +729,6 @@ fn should_not_request_image_from_resource_task_if_image_is_already_available() {
#[test]
fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
let image_bin_sent = comm::Port();
let image_bin_sent_chan = image_bin_sent.chan();
@ -802,7 +775,6 @@ fn should_not_request_image_from_resource_task_if_image_fetch_already_failed() {
#[test]
fn should_return_failed_if_image_bin_cannot_be_fetched() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Payload(test_image_bin()));
// ERROR fetching image
@ -841,7 +813,6 @@ fn should_return_failed_if_image_bin_cannot_be_fetched() {
#[test]
fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_fetched() {
let mock_resource_task = do mock_resource_task |response | {
response.send(resource_task::Payload(test_image_bin()));
// ERROR fetching image
@ -888,7 +859,6 @@ fn should_return_failed_for_multiple_get_image_requests_if_image_bin_cannot_be_f
#[test]
fn should_return_not_ready_if_image_is_still_decoding() {
let (wait_to_decode_chan, wait_to_decode_port) = pipes::stream();
let mock_resource_task = do mock_resource_task |response| {
@ -943,7 +913,6 @@ fn should_return_not_ready_if_image_is_still_decoding() {
#[test]
fn should_return_failed_if_image_decode_fails() {
let mock_resource_task = do mock_resource_task |response| {
// Bogus data
response.send(resource_task::Payload(~[]));
@ -984,7 +953,6 @@ fn should_return_failed_if_image_decode_fails() {
#[test]
fn should_return_image_on_wait_if_image_is_already_loaded() {
let mock_resource_task = do mock_resource_task |response| {
response.send(resource_task::Payload(test_image_bin()));
response.send(resource_task::Done(result::Ok(())));
@ -1022,7 +990,6 @@ fn should_return_image_on_wait_if_image_is_already_loaded() {
#[test]
fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
let (wait_chan, wait_port) = pipes::stream();
let mock_resource_task = do mock_resource_task |response| {
@ -1053,7 +1020,6 @@ fn should_return_image_on_wait_if_image_is_not_yet_loaded() {
#[test]
fn should_return_image_failed_on_wait_if_image_fails_to_load() {
let (wait_chan, wait_port) = pipes::stream();
let mock_resource_task = do mock_resource_task |response| {
@ -1105,3 +1071,4 @@ fn sync_cache_should_wait_for_images() {
image_cache_task.exit();
mock_resource_task.send(resource_task::Exit);
}

View file

@ -8,12 +8,13 @@ extra message traffic, it also avoids waiting on the same image
multiple times and thus triggering reflows multiple times.
*/
use image_cache_task::{Decode, GetImage, ImageCacheTask, ImageFailed, ImageNotReady, ImageReady};
use image_cache_task::{ImageResponseMsg, Prefetch, WaitForImage};
use clone_arc = std::arc::clone;
use std::net::url::Url;
use core::comm::Port;
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg, Prefetch, Decode, GetImage};
use resource::image_cache_task::{ WaitForImage, ImageReady, ImageNotReady, ImageFailed};
use servo_util::url::{UrlMap, url_map};
use std::net::url::Url;
pub fn LocalImageCache(image_cache_task: ImageCacheTask) -> LocalImageCache {
LocalImageCache {

View file

@ -2,17 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*!
//! A task that takes a URL and streams back the binary data.
A task that takes a URL and streams back the binary data
*/
use file_loader;
use http_loader;
use core::cell::Cell;
use core::comm::{Chan, Port, SharedChan};
use resource::util::spawn_listener;
use std::net::url::{Url, to_str};
use super::{file_loader, http_loader};
use util::spawn_listener;
pub enum ControlMsg {
/// Request the data associated with a particular URL

View file

@ -0,0 +1,33 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[link(name = "servo_net",
vers = "0.1",
uuid = "69c2b7b7-0d7d-4514-a48a-0eed61476039",
url = "http://servo.org/")];
#[crate_type = "lib"];
extern mod geom;
extern mod http_client;
extern mod servo_util;
extern mod stb_image;
extern mod std;
/// Image handling.
///
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
/// However, image handling is generally very integrated with the network stack (especially where
/// caching is involved) and as a result it must live in here.
pub mod image {
pub mod base;
pub mod holder;
}
pub mod file_loader;
pub mod http_loader;
pub mod image_cache_task;
pub mod local_image_cache;
pub mod resource_task;
pub mod util;

View file

@ -2,11 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use ShareGlContext = sharegl::platform::Context;
use compositing::resize_rate_limiter::ResizeRateLimiter;
use dom::event::Event;
use platform::resize_rate_limiter::ResizeRateLimiter;
use platform::{Application, Window};
use windowing::{ApplicationMethods, WindowMethods};
use azure::azure_hl::{BackendType, B8G8R8A8, DataSourceSurface, DrawTarget, SourceSurfaceMethods};
use core::cell::Cell;
use core::comm::{Chan, SharedChan, Port};
use core::util;
use geom::matrix::identity;
@ -15,65 +17,40 @@ use geom::rect::Rect;
use geom::size::Size2D;
use gfx::compositor::{Compositor, LayerBuffer, LayerBufferSet};
use gfx::opts::Opts;
use servo_util::time;
use core::cell::Cell;
use glut::glut;
use layers;
use sharegl;
use sharegl::ShareGlContext;
use sharegl::base::ShareContext;
use servo_util::time;
pub struct OSMain {
mod resize_rate_limiter;
/// The implementation of the layers-based compositor.
#[deriving(Clone)]
pub struct CompositorImpl {
chan: SharedChan<Msg>
}
impl Clone for OSMain {
fn clone(&self) -> OSMain {
OSMain {
chan: self.chan.clone()
impl CompositorImpl {
/// Creates a new compositor instance.
pub fn new(dom_event_chan: SharedChan<Event>, opts: Opts) -> CompositorImpl {
let dom_event_chan = Cell(dom_event_chan);
let chan: Chan<Msg> = do on_osmain |port| {
debug!("preparing to enter main loop");
mainloop(port, dom_event_chan.take(), &opts);
};
CompositorImpl {
chan: SharedChan::new(chan)
}
}
}
// FIXME: Move me over to opts.rs.
enum Mode {
GlutMode,
ShareMode
}
enum Window {
GlutWindow(glut::Window),
ShareWindow(ShareGlContext)
}
/// Messages to the compositor.
pub enum Msg {
BeginDrawing(comm::Chan<LayerBufferSet>),
Draw(comm::Chan<LayerBufferSet>, LayerBufferSet),
AddKeyHandler(comm::Chan<()>),
BeginDrawing(Chan<LayerBufferSet>),
Draw(Chan<LayerBufferSet>, LayerBufferSet),
AddKeyHandler(Chan<()>),
Exit
}
pub fn OSMain(dom_event_chan: comm::SharedChan<Event>, opts: Opts) -> OSMain {
let dom_event_chan = Cell(dom_event_chan);
OSMain {
chan: SharedChan::new(on_osmain::<Msg>(|po| {
let po = Cell(po);
do platform::runmain {
debug!("preparing to enter main loop");
// FIXME: Use the servo options.
let mode;
match os::getenv("SERVO_SHARE") {
Some(_) => mode = ShareMode,
None => mode = GlutMode
}
mainloop(mode, po.take(), dom_event_chan.take(), &opts);
}
}))
}
}
/// Azure surface wrapping to work with the layers infrastructure.
struct AzureDrawTargetImageData {
draw_target: DrawTarget,
@ -82,8 +59,12 @@ struct AzureDrawTargetImageData {
}
impl layers::layers::ImageData for AzureDrawTargetImageData {
fn size(&self) -> Size2D<uint> { self.size }
fn stride(&self) -> uint { self.data_source_surface.stride() as uint }
fn size(&self) -> Size2D<uint> {
self.size
}
fn stride(&self) -> uint {
self.data_source_surface.stride() as uint
}
fn format(&self) -> layers::layers::Format {
// FIXME: This is not always correct. We should query the Azure draw target for the format.
layers::layers::ARGB32Format
@ -95,33 +76,20 @@ impl layers::layers::ImageData for AzureDrawTargetImageData {
}
}
fn mainloop(mode: Mode,
po: Port<Msg>,
dom_event_chan: SharedChan<Event>,
opts: &Opts) {
fn mainloop(po: Port<Msg>, dom_event_chan: SharedChan<Event>, opts: &Opts) {
let key_handlers: @mut ~[Chan<()>] = @mut ~[];
let window;
match mode {
GlutMode => {
glut::init();
glut::init_display_mode(glut::DOUBLE);
let glut_window = glut::create_window(~"Servo");
glut::reshape_window(glut_window, 800, 600);
window = GlutWindow(glut_window);
}
ShareMode => {
let size = Size2D(800, 600);
let share_context: ShareGlContext = sharegl::base::ShareContext::new(size);
io::println(fmt!("Sharing ID is %d", share_context.id()));
window = ShareWindow(share_context);
}
}
let app: Application = ApplicationMethods::new();
let window: @mut Window = WindowMethods::new(&app);
let surfaces = @mut SurfaceSet(opts.render_backend);
let context = layers::rendergl::init_render_context();
// Create an initial layer tree.
//
// TODO: There should be no initial layer tree until the renderer creates one from the display
// list. This is only here because we don't have that logic in the renderer yet.
let root_layer = @mut layers::layers::ContainerLayer();
let original_layer_transform;
{
@ -137,19 +105,17 @@ fn mainloop(mode: Mode,
}
let scene = @layers::scene::Scene(layers::layers::ContainerLayerKind(root_layer),
Size2D(800.0, 600.0),
identity());
let scene = @mut layers::scene::Scene(layers::layers::ContainerLayerKind(root_layer),
Size2D(800.0, 600.0),
identity());
let done = @mut false;
let resize_rate_limiter = @mut ResizeRateLimiter(dom_event_chan);
let check_for_messages: @fn() = || {
// Periodically check if content responded to our last resize event
resize_rate_limiter.check_resize_response();
// Handle messages
//#debug("osmain: peeking");
while po.peek() {
match po.recv() {
AddKeyHandler(key_ch) => key_handlers.push(key_ch),
@ -195,9 +161,7 @@ fn mainloop(mode: Mode,
common.next_sibling
}
}
Some(_) => {
fail!(~"found unexpected layer kind")
}
Some(_) => fail!(~"found unexpected layer kind"),
};
// Set the layer's transform.
@ -216,70 +180,39 @@ fn mainloop(mode: Mode,
}
};
let adjust_for_window_resizing: @fn() = || {
let window_width = glut::get(glut::WindowWidth) as uint;
let window_height = glut::get(glut::WindowHeight) as uint;
// FIXME: Cross-crate struct mutability is broken.
let size: &mut Size2D<f32>;
unsafe { size = cast::transmute(&scene.size); }
*size = Size2D(window_width as f32, window_height as f32);
};
let composite: @fn() = || {
//#debug("osmain: drawing to screen");
do window.set_composite_callback {
do time::time(~"compositing") {
adjust_for_window_resizing();
// Adjust the layer dimensions as necessary to correspond to the size of the window.
scene.size = window.size();
// Render the scene.
layers::rendergl::render_scene(context, scene);
}
glut::swap_buffers();
glut::post_redisplay();
};
window.present();
}
match window {
GlutWindow(window) => {
do glut::reshape_func(window) |width, height| {
debug!("osmain: window resized to %d,%d", width as int, height as int);
check_for_messages();
resize_rate_limiter.window_resized(width as uint, height as uint);
//composite();
}
do window.set_resize_callback |width, height| {
debug!("osmain: window resized to %ux%u", width, height);
resize_rate_limiter.window_resized(width, height);
}
do glut::display_func() {
//debug!("osmain: display func");
check_for_messages();
composite();
}
// Enter the main event loop.
while !*done {
// Check for new messages coming from the rendering task.
check_for_messages();
while !*done {
//#debug("osmain: running GLUT check loop");
glut::check_loop();
}
}
ShareWindow(share_context) => {
loop {
check_for_messages();
do time::time(~"compositing") {
layers::rendergl::render_scene(context, scene);
}
share_context.flush();
}
}
// Check for messages coming from the windowing system.
window.check_loop();
}
}
/**
Implementation to allow the osmain channel to be used as a graphics
compositor for the renderer
*/
impl Compositor for OSMain {
fn begin_drawing(&self, next_dt: comm::Chan<LayerBufferSet>) {
/// Implementation of the abstract `Compositor` interface.
impl Compositor for CompositorImpl {
fn begin_drawing(&self, next_dt: Chan<LayerBufferSet>) {
self.chan.send(BeginDrawing(next_dt))
}
fn draw(&self, next_dt: comm::Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
fn draw(&self, next_dt: Chan<LayerBufferSet>, draw_me: LayerBufferSet) {
self.chan.send(Draw(next_dt, draw_me))
}
}
@ -289,7 +222,7 @@ struct SurfaceSet {
back: Surface,
}
fn lend_surface(surfaces: &mut SurfaceSet, receiver: comm::Chan<LayerBufferSet>) {
fn lend_surface(surfaces: &mut SurfaceSet, receiver: Chan<LayerBufferSet>) {
// We are in a position to lend out the surface?
assert!(surfaces.front.have);
// Ok then take it
@ -343,11 +276,16 @@ fn Surface(backend: BackendType) -> Surface {
rect: Rect(Point2D(0u, 0u), Size2D(800u, 600u)),
stride: 800 * 4
};
let layer_buffer_set = LayerBufferSet { buffers: ~[ layer_buffer ] };
Surface { layer_buffer_set: layer_buffer_set, have: true }
let layer_buffer_set = LayerBufferSet {
buffers: ~[ layer_buffer ]
};
Surface {
layer_buffer_set: layer_buffer_set,
have: true
}
}
/// A function for spawning into the platform's main thread
/// A function for spawning into the platform's main thread.
fn on_osmain<T: Owned>(f: ~fn(po: Port<T>)) -> Chan<T> {
let (setup_po, setup_ch) = comm::stream();
do task::task().sched_mode(task::PlatformThread).spawn {
@ -358,10 +296,3 @@ fn on_osmain<T: Owned>(f: ~fn(po: Port<T>)) -> Chan<T> {
setup_po.recv()
}
// #[cfg(target_os = "linux")]
mod platform {
pub fn runmain(f: &fn()) {
f()
}
}

View file

@ -17,15 +17,13 @@ use layout::layout_task;
use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::either;
use core::io::{println, read_whole_file};
use core::io::read_whole_file;
use core::pipes::select2i;
use core::ptr::null;
use core::task::{SingleThreaded, task};
use core::util::replace;
use dom;
use geom::size::Size2D;
use gfx::resource::image_cache_task::ImageCacheTask;
use gfx::resource::resource_task::ResourceTask;
use html;
use js::JSVAL_NULL;
use js::global::{global_class, debug_fns};
@ -34,6 +32,8 @@ use js::jsapi::JSContext;
use js::jsapi::bindgen::{JS_CallFunctionValue, JS_GetContextPrivate};
use js::rust::{Compartment, Cx};
use jsrt = js::rust::rt;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::tree::TreeNodeRef;
use std::net::url::Url;
use url_to_str = std::net::url::to_str;

View file

@ -68,7 +68,7 @@ pub fn create(cx: *JSContext, node: &mut AbstractNode) -> jsobj {
}
pub unsafe fn unwrap(obj: *JSObject) -> AbstractNode {
let raw = unsafe { utils::unwrap::<*mut Node>(obj) };
let raw = utils::unwrap::<*mut Node>(obj);
AbstractNode::from_raw(raw)
}

View file

@ -2,34 +2,34 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositing::CompositorImpl;
use content::content_task::{ContentTask, ExecuteMsg, ParseMsg};
use content::content_task;
use dom::event::Event;
use layout::layout_task;
use layout::layout_task::LayoutTask;
use resource::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use resource::resource_task::ResourceTask;
use resource::resource_task;
use util::task::spawn_listener;
use core::cell::Cell;
use core::comm::{Port, Chan};
use gfx::compositor::Compositor;
use core::comm::{Chan, Port, SharedChan};
use gfx::opts::Opts;
use gfx::render_task::RenderTask;
use gfx::render_task;
use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
use servo_net::resource_task::ResourceTask;
use servo_net::resource_task;
use std::net::url::Url;
pub type EngineTask = Chan<Msg>;
pub enum Msg {
LoadURLMsg(Url),
LoadUrlMsg(Url),
ExitMsg(Chan<()>)
}
pub struct Engine<C> {
pub struct Engine {
request_port: Port<Msg>,
compositor: C,
compositor: CompositorImpl,
render_task: RenderTask,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
@ -37,39 +37,42 @@ pub struct Engine<C> {
content_task: ContentTask
}
pub fn Engine<C:Compositor + Owned + Clone>(compositor: C,
opts: &Opts,
dom_event_port: comm::Port<Event>,
dom_event_chan: comm::SharedChan<Event>,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask)
-> EngineTask {
let dom_event_port = Cell(dom_event_port);
let dom_event_chan = Cell(dom_event_chan);
impl Engine {
pub fn start(compositor: CompositorImpl,
opts: &Opts,
dom_event_port: Port<Event>,
dom_event_chan: SharedChan<Event>,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask)
-> EngineTask {
let dom_event_port = Cell(dom_event_port);
let dom_event_chan = Cell(dom_event_chan);
let opts = Cell(copy *opts);
do spawn_listener::<Msg> |request| {
let render_task = RenderTask(compositor.clone(), opts.with_ref(|o| copy *o));
let layout_task = LayoutTask(render_task.clone(), image_cache_task.clone(), opts.take());
let content_task = ContentTask(layout_task.clone(),
dom_event_port.take(),
dom_event_chan.take(),
resource_task.clone(),
image_cache_task.clone());
let opts = Cell(copy *opts);
do spawn_listener::<Msg> |request| {
let render_task = RenderTask(compositor.clone(), opts.with_ref(|o| copy *o));
Engine {
request_port: request,
compositor: compositor.clone(),
render_task: render_task,
resource_task: resource_task.clone(),
image_cache_task: image_cache_task.clone(),
layout_task: layout_task,
content_task: content_task
}.run();
let opts = opts.take();
let layout_task = LayoutTask(render_task.clone(), image_cache_task.clone(), opts);
let content_task = ContentTask(layout_task.clone(),
dom_event_port.take(),
dom_event_chan.take(),
resource_task.clone(),
image_cache_task.clone());
Engine {
request_port: request,
compositor: compositor.clone(),
render_task: render_task,
resource_task: resource_task.clone(),
image_cache_task: image_cache_task.clone(),
layout_task: layout_task,
content_task: content_task,
}.run()
}
}
}
impl<C:Compositor + Owned + Clone> Engine<C> {
fn run(&self) {
while self.handle_request(self.request_port.recv()) {
// Go on...
@ -78,30 +81,30 @@ impl<C:Compositor + Owned + Clone> Engine<C> {
fn handle_request(&self, request: Msg) -> bool {
match request {
LoadURLMsg(url) => {
if url.path.ends_with(".js") {
self.content_task.send(ExecuteMsg(url))
} else {
self.content_task.send(ParseMsg(url))
LoadUrlMsg(url) => {
if url.path.ends_with(".js") {
self.content_task.send(ExecuteMsg(url))
} else {
self.content_task.send(ParseMsg(url))
}
return true
}
return true;
}
ExitMsg(sender) => {
self.content_task.send(content_task::ExitMsg);
self.layout_task.send(layout_task::ExitMsg);
let (response_port, response_chan) = comm::stream();
ExitMsg(sender) => {
self.content_task.send(content_task::ExitMsg);
self.layout_task.send(layout_task::ExitMsg);
self.render_task.send(render_task::ExitMsg(response_chan));
response_port.recv();
let (response_port, response_chan) = comm::stream();
self.image_cache_task.exit();
self.resource_task.send(resource_task::Exit);
self.render_task.send(render_task::ExitMsg(response_chan));
response_port.recv();
sender.send(());
return false;
}
self.image_cache_task.exit();
self.resource_task.send(resource_task::Exit);
sender.send(());
return false
}
}
}
}

View file

@ -2,17 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*!
Some little helpers for hooking up the HTML parser with the CSS parser
*/
use resource::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};
/// Some little helpers for hooking up the HTML parser with the CSS parser.
use core::cell::Cell;
use core::comm::Port;
use core::str;
use newcss::stylesheet::Stylesheet;
use newcss::util::DataStream;
use servo_net::resource_task::{ResourceTask, ProgressMsg, Load, Payload, Done};
use std::net::url::Url;
/// Where a style sheet comes from.

View file

@ -6,15 +6,15 @@ use dom::element::*;
use dom::node::{AbstractNode, Comment, Doctype, Element, ElementNodeTypeId, Node, Text};
use html::cssparse::{InlineProvenance, StylesheetProvenance, UrlProvenance, spawn_css_parser};
use newcss::stylesheet::Stylesheet;
use resource::image_cache_task::ImageCacheTask;
use resource::image_cache_task;
use resource::resource_task::{Done, Load, Payload, ResourceTask};
use util::task::spawn_conversation;
use core::cell::Cell;
use core::comm::{Chan, Port, SharedChan};
use core::str::eq_slice;
use hubbub::hubbub;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::image_cache_task;
use servo_net::resource_task::{Done, Load, Payload, ResourceTask};
use servo_util::tree::TreeUtils;
use servo_util::url::make_url;
use std::net::url::Url;

View file

@ -127,8 +127,7 @@ impl BlockLayout for FlowContext {
assert!(self.starts_block_flow());
let mut remaining_width = self.with_imm_node(|this| this.position.size.width);
let mut _right_used = Au(0);
let mut left_used = Au(0);
let left_used = Au(0);
// Let the box consume some width. It will return the amount remaining for its children.
do self.with_block_box |box| {

View file

@ -19,16 +19,15 @@ use geom::{Point2D, Rect, Size2D};
use gfx::display_list::{DisplayItem, DisplayList};
use gfx::font::{FontStyle, FontWeight300};
use gfx::geometry::Au;
use gfx::image::holder::ImageHolder;
use gfx::resource::local_image_cache::LocalImageCache;
use gfx;
use newcss::color::{Color, rgb};
use newcss::color::rgb;
use newcss::complete::CompleteStyle;
use newcss::units::{Cursive, Em, Fantasy, Length, Monospace, Pt, Px, SansSerif, Serif};
use newcss::values::{CSSBorderWidthLength, CSSBorderWidthMedium};
use newcss::values::{CSSFontFamilyFamilyName, CSSFontFamilyGenericFamily};
use newcss::values::{CSSFontSizeLength, CSSFontStyleItalic, CSSFontStyleNormal};
use newcss::values::{CSSFontStyleOblique, CSSTextAlign};
use servo_net::image::holder::ImageHolder;
use servo_net::local_image_cache::LocalImageCache;
use servo_util::range::*;
use std::arc;
use std::cmp::FuzzyEq;

View file

@ -10,8 +10,7 @@ use dom::node::{ElementNodeTypeId, TextNodeTypeId};
use layout::block::BlockFlowData;
use layout::box::{GenericRenderBoxClass, ImageRenderBox, ImageRenderBoxClass, RenderBox};
use layout::box::{RenderBoxBase, RenderBoxType, RenderBox_Generic, RenderBox_Image};
use layout::box::{RenderBox_Text, TextRenderBox, UnscannedTextRenderBox};
use layout::box::{UnscannedTextRenderBoxClass};
use layout::box::{RenderBox_Text, UnscannedTextRenderBox, UnscannedTextRenderBoxClass};
use layout::context::LayoutContext;
use layout::debug::{BoxedMutDebugMethods, DebugMethods};
use layout::flow::{AbsoluteFlow, BlockFlow, FloatFlow, Flow_Absolute, Flow_Block, Flow_Float};
@ -20,7 +19,6 @@ use layout::flow::{FlowContextType, FlowData, InlineBlockFlow, InlineFlow, RootF
use layout::inline::{InlineFlowData, InlineLayout};
use layout::root::RootFlowData;
use gfx::image::holder::ImageHolder;
use newcss::values::{CSSDisplay, CSSDisplayBlock, CSSDisplayInline, CSSDisplayInlineBlock};
use newcss::values::{CSSDisplayNone};
use servo_util::range::Range;
@ -461,7 +459,7 @@ pub impl LayoutTreeBuilder {
let result = match ty {
RenderBox_Generic => GenericRenderBoxClass(@mut base),
RenderBox_Text => UnscannedTextRenderBoxClass(@mut UnscannedTextRenderBox::new(base)),
RenderBox_Image => self.make_image_box(layout_ctx, node, flow_context, base),
RenderBox_Image => self.make_image_box(layout_ctx, node, base),
};
debug!("LayoutTreeBuilder: created box: %s", result.debug_str());
result
@ -470,7 +468,6 @@ pub impl LayoutTreeBuilder {
fn make_image_box(&mut self,
layout_ctx: &LayoutContext,
node: AbstractNode,
flow_context: FlowContext,
base: RenderBoxBase)
-> RenderBox {
assert!(node.is_image_element());

View file

@ -2,14 +2,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Data needed by the layout task.
use geom::rect::Rect;
use gfx::font_context::FontContext;
use gfx::geometry::Au;
use gfx::resource::local_image_cache::LocalImageCache;
use servo_net::local_image_cache::LocalImageCache;
use std::net::url::Url;
/* Represents layout task context. */
/// Data needed by the layout task.
pub struct LayoutContext {
font_ctx: @mut FontContext,
image_cache: @mut LocalImageCache,

View file

@ -17,7 +17,6 @@ use core::util;
use geom::{Point2D, Rect, Size2D};
use gfx::display_list::DisplayList;
use gfx::geometry::Au;
use gfx::image::holder;
use gfx::text::text_run::TextRun;
use gfx::text::util::*;
use newcss::values::{CSSTextAlignCenter, CSSTextAlignJustify, CSSTextAlignLeft};
@ -674,7 +673,7 @@ impl InlineFlowData {
let width = Au::from_px(size.get_or_default(Size2D(0, 0)).width);
image_box.base.position.size.width = width;
}
TextRenderBoxClass(text_box) => {
TextRenderBoxClass(_) => {
// Text boxes are preinitialized.
}
GenericRenderBoxClass(generic_box) => {

View file

@ -15,8 +15,6 @@ use layout::context::LayoutContext;
use layout::debug::{BoxedMutDebugMethods, DebugMethods};
use layout::display_list_builder::{DisplayListBuilder, FlowDisplayListBuilderMethods};
use layout::flow::FlowContext;
use resource::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use resource::local_image_cache::LocalImageCache;
use util::task::spawn_listener;
use util::time::time;
@ -34,6 +32,8 @@ use gfx::render_task::{RenderMsg, RenderTask};
use newcss::select::SelectCtx;
use newcss::stylesheet::Stylesheet;
use newcss::types::OriginAuthor;
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::LocalImageCache;
use servo_util::tree::TreeUtils;
use std::net::url::Url;

View file

@ -1,5 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

View file

@ -0,0 +1,92 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A windowing implementation using GLUT.
///
/// GLUT is a very old and bare-bones toolkit. However, it has good cross-platform support, at
/// least on desktops. It is designed for testing Servo without the need of a UI.
use windowing::{ApplicationMethods, CompositeCallback, ResizeCallback, WindowMethods};
use geom::size::Size2D;
use glut::glut::{DOUBLE, WindowHeight, WindowWidth};
use glut::glut;
/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;
impl ApplicationMethods for Application {
pub fn new() -> Application {
glut::init();
glut::init_display_mode(DOUBLE);
Application
}
}
/// The type of a window.
pub struct Window {
glut_window: glut::Window,
composite_callback: Option<CompositeCallback>,
resize_callback: Option<ResizeCallback>,
}
impl WindowMethods<Application> for Window {
/// Creates a new window.
pub fn new(_: &Application) -> @mut Window {
// Create the GLUT window.
let glut_window = glut::create_window(~"Servo");
glut::reshape_window(glut_window, 800, 600);
// Create our window object.
let window = @mut Window {
glut_window: glut_window,
composite_callback: None,
resize_callback: None,
};
// Register event handlers.
do glut::reshape_func(window.glut_window) |width, height| {
match window.resize_callback {
None => {}
Some(callback) => callback(width as uint, height as uint),
}
};
do glut::display_func {
// FIXME(pcwalton): This will not work with multiple windows.
match window.composite_callback {
None => {}
Some(callback) => callback(),
}
};
window
}
/// Returns the size of the window.
pub fn size(&self) -> Size2D<f32> {
Size2D(glut::get(WindowWidth) as f32, glut::get(WindowHeight) as f32)
}
/// Presents the window to the screen (perhaps by page flipping).
pub fn present(&mut self) {
glut::swap_buffers();
glut::post_redisplay();
}
/// Registers a callback to run when a composite event occurs.
pub fn set_composite_callback(&mut self, new_composite_callback: CompositeCallback) {
self.composite_callback = Some(new_composite_callback)
}
/// Registers a callback to run when a resize event occurs.
pub fn set_resize_callback(&mut self, new_resize_callback: ResizeCallback) {
self.resize_callback = Some(new_resize_callback)
}
/// Spins the event loop.
pub fn check_loop(@mut self) {
glut::check_loop()
}
}

View file

@ -0,0 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! A windowing implementation using shared OpenGL textures.
///
/// In this setup, Servo renders to an OpenGL texture and uses IPC to share that texture with
/// another application. It also uses IPC to handle events.
///
/// This is designed for sandboxing scenarios which the OpenGL graphics driver is either sandboxed
/// along with the Servo process or trusted. If the OpenGL driver itself is untrusted, then this
/// windowing implementation is not appropriate.
use windowing::{CompositeCallback, ResizeCallback};
use geom::size::Size2D;
use sharegl::base::ShareContext;
use sharegl::platform::Context;
/// A structure responsible for setting up and tearing down the entire windowing system.
pub struct Application;
impl ApplicationMethods for Application {
pub fn new() -> Application {
Application
}
}
/// The type of a window.
pub struct Window(Context);
impl WindowingMethods<Application> for Window {
/// Creates a new window.
pub fn new(_: &Application) -> @mut Window {
let share_context: Context = ShareContext::new(Size2D(800, 600));
println(fmt!("Sharing ID is %d", share_context.id()));
@mut Window(share_context)
}
/// Returns the size of the window.
pub fn size(&mut self) -> Size2D<f32> {
Size2D(800.0, 600.0)
}
/// Presents the window to the screen (perhaps by page flipping).
pub fn present(&mut self) {
(*self).flush();
}
/// Registers a callback to run when a composite event occurs.
pub fn set_composite_callback(&mut self, _: CompositeCallback) {}
/// Registers a callback to run when a resize event occurs.
pub fn set_resize_callback(&mut self, _: ResizeCallback) {}
/// Returns the next event.
pub fn check_loop(@mut self) {}
}

18
src/servo/platform/mod.rs Normal file
View file

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Platform-specific functionality for Servo.
#[cfg(not(shared_gl_windowing))]
pub use platform::common::glut_windowing::{Application, Window};
#[cfg(shared_gl_windowing)]
pub use platform::common::shared_gl_windowing::{Application, Window};
pub mod common {
#[cfg(not(shared_gl_windowing))]
pub mod glut_windowing;
#[cfg(shared_gl_windowing)]
pub mod shared_gl_windowing;
}

View file

@ -11,19 +11,18 @@
#[license = "MPL"];
#[crate_type = "lib"];
#[legacy_records];
extern mod azure;
extern mod geom;
extern mod gfx (name = "servo_gfx");
extern mod servo_util (name = "servo_util");
extern mod glut;
extern mod http_client;
extern mod hubbub;
extern mod js;
extern mod layers;
extern mod opengles;
extern mod newcss (name = "css");
extern mod opengles;
extern mod servo_net;
extern mod servo_util (name = "servo_util");
extern mod sharegl;
extern mod stb_image;
extern mod std;
@ -33,16 +32,21 @@ extern mod core_graphics;
#[cfg(target_os="macos")]
extern mod core_text;
use engine::{Engine, LoadURLMsg};
use platform::osmain::{AddKeyHandler, OSMain};
use compositing::{AddKeyHandler, CompositorImpl};
use engine::{Engine, LoadUrlMsg};
pub use gfx::opts::{Opts, Png, Screen}; // FIXME: Do we really want "Screen" and "Png" visible?
pub use gfx::resource;
pub use gfx::resource::image_cache_task::ImageCacheTask;
pub use gfx::resource::resource_task::ResourceTask;
use core::comm::SharedChan;
use gfx::opts;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
pub use gfx::opts::Opts;
pub use gfx::text;
pub use servo_util::url::make_url;
#[path="compositing/mod.rs"]
pub mod compositing;
pub mod content {
pub mod content_task;
}
@ -117,65 +121,50 @@ pub mod html {
pub mod hubbub_html_parser;
}
pub mod platform {
pub mod base;
pub mod osmain;
priv mod resize_rate_limiter;
}
pub mod windowing;
#[path="platform/mod.rs"]
pub mod platform;
#[path = "util/mod.rs"]
pub mod util;
fn main() {
let args = os::args();
run(&gfx::opts::from_cmdline_args(args))
run(&opts::from_cmdline_args(os::args()))
}
#[allow(non_implicitly_copyable_typarams)]
fn run(opts: &Opts) {
match &opts.render_mode {
&Screen => run_pipeline_screen(opts),
&Png(ref outfile) => {
assert!(!opts.urls.is_empty());
if opts.urls.len() > 1u {
fail!(~"servo asks that you stick to a single URL in PNG output mode")
}
run_pipeline_png(opts, *outfile)
}
}
}
fn run_pipeline_screen(opts: &Opts) {
let (dom_event_port, dom_event_chan) = comm::stream();
let dom_event_chan = comm::SharedChan::new(dom_event_chan);
let dom_event_chan = SharedChan::new(dom_event_chan);
// The platform event handler thread
let osmain = OSMain(dom_event_chan.clone(), copy *opts);
let compositor = CompositorImpl::new(dom_event_chan.clone(), copy *opts);
// Send each file to render then wait for keypress
let (keypress_from_osmain, keypress_to_engine) = comm::stream();
osmain.chan.send(AddKeyHandler(keypress_to_engine));
let (keypress_from_compositor, keypress_to_engine) = comm::stream();
compositor.chan.send(AddKeyHandler(keypress_to_engine));
// Create a servo instance
let resource_task = ResourceTask();
let image_cache_task = ImageCacheTask(resource_task.clone());
let engine_task = Engine(osmain.clone(),
opts,
dom_event_port,
dom_event_chan,
resource_task,
image_cache_task);
let engine_task = Engine::start(compositor.clone(),
opts,
dom_event_port,
dom_event_chan,
resource_task,
image_cache_task);
for opts.urls.each |filename| {
let url = make_url(copy *filename, None);
debug!("master: Sending url `%s`", url.to_str());
engine_task.send(LoadURLMsg(url));
debug!("master: Waiting for keypress");
match keypress_from_osmain.try_recv() {
Some(*) => { }
None => { error!("keypress stream closed unexpectedly") }
};
debug!("master: Sending url `%s`", url.to_str());
engine_task.send(LoadUrlMsg(url));
debug!("master: Waiting for keypress");
match keypress_from_compositor.try_recv() {
Some(*) => {}
None => error!("keypress stream closed unexpectedly"),
}
}
// Shut everything down
@ -184,46 +173,6 @@ fn run_pipeline_screen(opts: &Opts) {
engine_task.send(engine::ExitMsg(exit_chan));
exit_response_from_engine.recv();
osmain.chan.send(platform::osmain::Exit);
compositor.chan.send(compositing::Exit);
}
fn run_pipeline_png(_opts: &Opts, _outfile: &str) {
fail!(~"PNG compositor is broken");
}
#[cfg(broken)]
fn run_pipeline_png(url: ~str, outfile: &str) {
// Use a PNG encoder as the graphics compositor
use gfx::png_compositor;
use png_compositor::PngCompositor;
use io::{Writer, buffered_file_writer};
use resource::resource_task::ResourceTask;
use resource::image_cache_task::SyncImageCacheTask;
listen(|pngdata_from_compositor| {
let (dom_event_port, dom_event_chan) = comm::stream();
let dom_event_chan = comm::SharedChan(dom_event_chan);
let compositor = PngCompositor(pngdata_from_compositor);
let resource_task = ResourceTask();
// For the PNG pipeline we are using a synchronous image task so that all images will be
// fulfilled before the first paint.
let image_cache_task = SyncImageCacheTask(resource_task);
let engine_task = Engine(copy compositor,
dom_event_port,
dom_event_chan,
resource_task,
image_cache_task);
engine_task.send(LoadURLMsg(make_url(copy url, None)));
match buffered_file_writer(&Path(outfile)) {
Ok(writer) => writer.write(pngdata_from_compositor.recv()),
Err(e) => fail!(e)
}
let (exit_chan, exit_response_from_engine) = comm::stream();
engine_task.send(engine::ExitMsg(exit_chan));
exit_response_from_engine.recv();
compositor.send(png_compositor::Exit);
})
}

34
src/servo/windowing.rs Normal file
View file

@ -0,0 +1,34 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
use geom::size::Size2D;
/// Type of the function that is called when the screen is to be redisplayed.
pub type CompositeCallback = @fn();
/// Type of the function that is called when the window is resized.
pub type ResizeCallback = @fn(uint, uint);
/// Methods for an abstract Application.
pub trait ApplicationMethods {
fn new() -> Self;
}
pub trait WindowMethods<A> {
/// Creates a new window.
pub fn new(app: &A) -> @mut Self;
/// Returns the size of the window.
pub fn size(&self) -> Size2D<f32>;
/// Presents the window to the screen (perhaps by page flipping).
pub fn present(&mut self);
/// Registers a callback to run when a composite event occurs.
pub fn set_composite_callback(&mut self, new_composite_callback: CompositeCallback);
/// Registers a callback to run when a resize event occurs.
pub fn set_resize_callback(&mut self, new_resize_callback: ResizeCallback);
/// Spins the event loop.
pub fn check_loop(@mut self);
}