Format component compositing #21373

This commit is contained in:
kingdido999 2018-08-31 08:19:22 +08:00
parent 1ee3deea27
commit e4cd04399e
5 changed files with 363 additions and 255 deletions

View file

@ -10,24 +10,33 @@ use std::io::{Read, Write};
use std::path::Path; use std::path::Path;
fn main() { fn main() {
let lockfile_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("..").join("..").join("Cargo.lock"); let lockfile_path = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap())
let revision_file_path = Path::new(&env::var_os("OUT_DIR").unwrap()).join("webrender_revision.rs"); .join("..")
.join("..")
.join("Cargo.lock");
let revision_file_path =
Path::new(&env::var_os("OUT_DIR").unwrap()).join("webrender_revision.rs");
let mut lockfile = String::new(); let mut lockfile = String::new();
File::open(lockfile_path).expect("Cannot open lockfile") File::open(lockfile_path)
.expect("Cannot open lockfile")
.read_to_string(&mut lockfile) .read_to_string(&mut lockfile)
.expect("Failed to read lockfile"); .expect("Failed to read lockfile");
match toml::from_str::<toml::value::Table>(&lockfile) { match toml::from_str::<toml::value::Table>(&lockfile) {
Ok(result) => { Ok(result) => {
let packages = result.get("package").expect("Cargo lockfile should contain package list"); let packages = result
.get("package")
.expect("Cargo lockfile should contain package list");
match *packages { match *packages {
toml::Value::Array(ref arr) => { toml::Value::Array(ref arr) => {
let source = arr let source = arr
.iter() .iter()
.find(|pkg| pkg.get("name").and_then(|name| name.as_str()).unwrap_or("") == "webrender") .find(|pkg| {
.and_then(|pkg| pkg.get("source").and_then(|source| source.as_str())) pkg.get("name").and_then(|name| name.as_str()).unwrap_or("") ==
"webrender"
}).and_then(|pkg| pkg.get("source").and_then(|source| source.as_str()))
.unwrap_or("unknown"); .unwrap_or("unknown");
let parsed: Vec<&str> = source.split("#").collect(); let parsed: Vec<&str> = source.split("#").collect();
@ -36,9 +45,9 @@ fn main() {
let mut revision_module_file = File::create(&revision_file_path).unwrap(); let mut revision_module_file = File::create(&revision_file_path).unwrap();
write!(&mut revision_module_file, "{}", format!("\"{}\"", revision)).unwrap(); write!(&mut revision_module_file, "{}", format!("\"{}\"", revision)).unwrap();
}, },
_ => panic!("Cannot find package definitions in lockfile") _ => panic!("Cannot find package definitions in lockfile"),
} }
}, },
Err(e) => panic!(e) Err(e) => panic!(e),
} }
} }

View file

@ -43,7 +43,6 @@ use webrender_api::{self, DeviceIntPoint, DevicePoint, HitTestFlags, HitTestResu
use webrender_api::{LayoutVector2D, ScrollLocation}; use webrender_api::{LayoutVector2D, ScrollLocation};
use windowing::{self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods}; use windowing::{self, EmbedderCoordinates, MouseWindowEvent, WebRenderDebugOption, WindowMethods};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
enum UnableToComposite { enum UnableToComposite {
WindowUnprepared, WindowUnprepared,
@ -251,7 +250,7 @@ enum CompositeTarget {
WindowAndPng, WindowAndPng,
/// Compose to a PNG, write it to disk, and then exit the browser (used for reftests) /// Compose to a PNG, write it to disk, and then exit the browser (used for reftests)
PngFile PngFile,
} }
#[derive(Clone)] #[derive(Clone)]
@ -273,7 +272,8 @@ impl webrender_api::RenderNotifier for RenderNotifier {
} }
fn wake_up(&self) { fn wake_up(&self) {
self.compositor_proxy.recomposite(CompositingReason::NewWebRenderFrame); self.compositor_proxy
.recomposite(CompositingReason::NewWebRenderFrame);
} }
fn new_frame_ready( fn new_frame_ready(
@ -284,7 +284,8 @@ impl webrender_api::RenderNotifier for RenderNotifier {
_render_time_ns: Option<u64>, _render_time_ns: Option<u64>,
) { ) {
if scrolled { if scrolled {
self.compositor_proxy.send(Msg::NewScrollFrameReady(composite_needed)); self.compositor_proxy
.send(Msg::NewScrollFrameReady(composite_needed));
} else { } else {
self.wake_up(); self.wake_up();
} }
@ -295,7 +296,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn new(window: Rc<Window>, state: InitialCompositorState) -> Self { fn new(window: Rc<Window>, state: InitialCompositorState) -> Self {
let composite_target = match opts::get().output_file { let composite_target = match opts::get().output_file {
Some(_) => CompositeTarget::PngFile, Some(_) => CompositeTarget::PngFile,
None => CompositeTarget::Window None => CompositeTarget::Window,
}; };
IOCompositor { IOCompositor {
@ -372,7 +373,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// Tell the profiler, memory profiler, and scrolling timer to shut down. // Tell the profiler, memory profiler, and scrolling timer to shut down.
if let Ok((sender, receiver)) = ipc::channel() { if let Ok((sender, receiver)) = ipc::channel() {
self.time_profiler_chan.send(time::ProfilerMsg::Exit(sender)); self.time_profiler_chan
.send(time::ProfilerMsg::Exit(sender));
let _ = receiver.recv(); let _ = receiver.recv();
} }
@ -383,33 +385,33 @@ impl<Window: WindowMethods> IOCompositor<Window> {
match (msg, self.shutdown_state) { match (msg, self.shutdown_state) {
(_, ShutdownState::FinishedShuttingDown) => { (_, ShutdownState::FinishedShuttingDown) => {
error!("compositor shouldn't be handling messages after shutting down"); error!("compositor shouldn't be handling messages after shutting down");
return false return false;
} },
(Msg::ShutdownComplete, _) => { (Msg::ShutdownComplete, _) => {
self.finish_shutting_down(); self.finish_shutting_down();
return false; return false;
} },
(Msg::ChangeRunningAnimationsState(pipeline_id, animation_state), (
ShutdownState::NotShuttingDown) => { Msg::ChangeRunningAnimationsState(pipeline_id, animation_state),
ShutdownState::NotShuttingDown,
) => {
self.change_running_animations_state(pipeline_id, animation_state); self.change_running_animations_state(pipeline_id, animation_state);
} },
(Msg::SetFrameTree(frame_tree), (Msg::SetFrameTree(frame_tree), ShutdownState::NotShuttingDown) => {
ShutdownState::NotShuttingDown) => {
self.set_frame_tree(&frame_tree); self.set_frame_tree(&frame_tree);
self.send_viewport_rects(); self.send_viewport_rects();
} },
(Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => { (Msg::Recomposite(reason), ShutdownState::NotShuttingDown) => {
self.composition_request = CompositionRequest::CompositeNow(reason) self.composition_request = CompositionRequest::CompositeNow(reason)
} },
(Msg::TouchEventProcessed(result), ShutdownState::NotShuttingDown) => { (Msg::TouchEventProcessed(result), ShutdownState::NotShuttingDown) => {
self.touch_handler.on_event_processed(result); self.touch_handler.on_event_processed(result);
} },
(Msg::CreatePng(reply), ShutdownState::NotShuttingDown) => { (Msg::CreatePng(reply), ShutdownState::NotShuttingDown) => {
let res = self.composite_specific_target(CompositeTarget::WindowAndPng); let res = self.composite_specific_target(CompositeTarget::WindowAndPng);
@ -420,15 +422,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
if let Err(e) = reply.send(img) { if let Err(e) = reply.send(img) {
warn!("Sending reply to create png failed ({}).", e); warn!("Sending reply to create png failed ({}).", e);
} }
} },
(Msg::ViewportConstrained(pipeline_id, constraints), (
ShutdownState::NotShuttingDown) => { Msg::ViewportConstrained(pipeline_id, constraints),
ShutdownState::NotShuttingDown,
) => {
self.constrain_viewport(pipeline_id, constraints); self.constrain_viewport(pipeline_id, constraints);
} },
(Msg::IsReadyToSaveImageReply(is_ready), ShutdownState::NotShuttingDown) => { (Msg::IsReadyToSaveImageReply(is_ready), ShutdownState::NotShuttingDown) => {
assert_eq!(self.ready_to_save_state, ReadyState::WaitingForConstellationReply); assert_eq!(
self.ready_to_save_state,
ReadyState::WaitingForConstellationReply
);
if is_ready { if is_ready {
self.ready_to_save_state = ReadyState::ReadyToSaveImage; self.ready_to_save_state = ReadyState::ReadyToSaveImage;
if opts::get().is_running_problem_test { if opts::get().is_running_problem_test {
@ -441,34 +448,38 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
} }
self.composite_if_necessary(CompositingReason::Headless); self.composite_if_necessary(CompositingReason::Headless);
} },
(Msg::PipelineVisibilityChanged(pipeline_id, visible), ShutdownState::NotShuttingDown) => { (
Msg::PipelineVisibilityChanged(pipeline_id, visible),
ShutdownState::NotShuttingDown,
) => {
self.pipeline_details(pipeline_id).visible = visible; self.pipeline_details(pipeline_id).visible = visible;
if visible { if visible {
self.process_animations(); self.process_animations();
} }
} },
(Msg::PipelineExited(pipeline_id, sender), _) => { (Msg::PipelineExited(pipeline_id, sender), _) => {
debug!("Compositor got pipeline exited: {:?}", pipeline_id); debug!("Compositor got pipeline exited: {:?}", pipeline_id);
self.remove_pipeline_root_layer(pipeline_id); self.remove_pipeline_root_layer(pipeline_id);
let _ = sender.send(()); let _ = sender.send(());
} },
(Msg::NewScrollFrameReady(recomposite_needed), ShutdownState::NotShuttingDown) => { (Msg::NewScrollFrameReady(recomposite_needed), ShutdownState::NotShuttingDown) => {
self.waiting_for_results_of_scroll = false; self.waiting_for_results_of_scroll = false;
if recomposite_needed { if recomposite_needed {
self.composition_request = CompositionRequest::CompositeNow( self.composition_request = CompositionRequest::CompositeNow(
CompositingReason::NewWebRenderScrollFrame); CompositingReason::NewWebRenderScrollFrame,
} );
} }
},
(Msg::Dispatch(func), ShutdownState::NotShuttingDown) => { (Msg::Dispatch(func), ShutdownState::NotShuttingDown) => {
// The functions sent here right now are really dumb, so they can't panic. // The functions sent here right now are really dumb, so they can't panic.
// But if we start running more complex code here, we should really catch panic here. // But if we start running more complex code here, we should really catch panic here.
func(); func();
} },
(Msg::LoadComplete(_), ShutdownState::NotShuttingDown) => { (Msg::LoadComplete(_), ShutdownState::NotShuttingDown) => {
// If we're painting in headless mode, schedule a recomposite. // If we're painting in headless mode, schedule a recomposite.
@ -479,30 +490,30 @@ impl<Window: WindowMethods> IOCompositor<Window> {
(Msg::PendingPaintMetric(pipeline_id, epoch), _) => { (Msg::PendingPaintMetric(pipeline_id, epoch), _) => {
self.pending_paint_metrics.insert(pipeline_id, epoch); self.pending_paint_metrics.insert(pipeline_id, epoch);
} },
(Msg::GetClientWindow(req), ShutdownState::NotShuttingDown) => { (Msg::GetClientWindow(req), ShutdownState::NotShuttingDown) => {
if let Err(e) = req.send(self.embedder_coordinates.window) { if let Err(e) = req.send(self.embedder_coordinates.window) {
warn!("Sending response to get client window failed ({}).", e); warn!("Sending response to get client window failed ({}).", e);
} }
} },
(Msg::GetScreenSize(req), ShutdownState::NotShuttingDown) => { (Msg::GetScreenSize(req), ShutdownState::NotShuttingDown) => {
if let Err(e) = req.send(self.embedder_coordinates.screen) { if let Err(e) = req.send(self.embedder_coordinates.screen) {
warn!("Sending response to get screen size failed ({}).", e); warn!("Sending response to get screen size failed ({}).", e);
} }
} },
(Msg::GetScreenAvailSize(req), ShutdownState::NotShuttingDown) => { (Msg::GetScreenAvailSize(req), ShutdownState::NotShuttingDown) => {
if let Err(e) = req.send(self.embedder_coordinates.screen_avail) { if let Err(e) = req.send(self.embedder_coordinates.screen_avail) {
warn!("Sending response to get screen avail size failed ({}).", e); warn!("Sending response to get screen avail size failed ({}).", e);
} }
} },
// When we are shutting_down, we need to avoid performing operations // When we are shutting_down, we need to avoid performing operations
// such as Paint that may crash because we have begun tearing down // such as Paint that may crash because we have begun tearing down
// the rest of our resources. // the rest of our resources.
(_, ShutdownState::ShuttingDown) => {} (_, ShutdownState::ShuttingDown) => {},
} }
true true
@ -522,42 +533,53 @@ impl<Window: WindowMethods> IOCompositor<Window> {
if visible { if visible {
self.composite_if_necessary(CompositingReason::Animation); self.composite_if_necessary(CompositingReason::Animation);
} }
} },
AnimationState::AnimationCallbacksPresent => { AnimationState::AnimationCallbacksPresent => {
let visible = self.pipeline_details(pipeline_id).visible; let visible = self.pipeline_details(pipeline_id).visible;
self.pipeline_details(pipeline_id).animation_callbacks_running = true; self.pipeline_details(pipeline_id)
.animation_callbacks_running = true;
if visible { if visible {
self.tick_animations_for_pipeline(pipeline_id); self.tick_animations_for_pipeline(pipeline_id);
} }
} },
AnimationState::NoAnimationsPresent => { AnimationState::NoAnimationsPresent => {
self.pipeline_details(pipeline_id).animations_running = false; self.pipeline_details(pipeline_id).animations_running = false;
} },
AnimationState::NoAnimationCallbacksPresent => { AnimationState::NoAnimationCallbacksPresent => {
self.pipeline_details(pipeline_id).animation_callbacks_running = false; self.pipeline_details(pipeline_id)
} .animation_callbacks_running = false;
},
} }
} }
fn pipeline_details(&mut self, pipeline_id: PipelineId) -> &mut PipelineDetails { fn pipeline_details(&mut self, pipeline_id: PipelineId) -> &mut PipelineDetails {
if !self.pipeline_details.contains_key(&pipeline_id) { if !self.pipeline_details.contains_key(&pipeline_id) {
self.pipeline_details.insert(pipeline_id, PipelineDetails::new()); self.pipeline_details
.insert(pipeline_id, PipelineDetails::new());
} }
self.pipeline_details.get_mut(&pipeline_id).expect("Insert then get failed!") self.pipeline_details
.get_mut(&pipeline_id)
.expect("Insert then get failed!")
} }
pub fn pipeline(&self, pipeline_id: PipelineId) -> Option<&CompositionPipeline> { pub fn pipeline(&self, pipeline_id: PipelineId) -> Option<&CompositionPipeline> {
match self.pipeline_details.get(&pipeline_id) { match self.pipeline_details.get(&pipeline_id) {
Some(ref details) => details.pipeline.as_ref(), Some(ref details) => details.pipeline.as_ref(),
None => { None => {
warn!("Compositor layer has an unknown pipeline ({:?}).", pipeline_id); warn!(
"Compositor layer has an unknown pipeline ({:?}).",
pipeline_id
);
None None
} },
} }
} }
fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) { fn set_frame_tree(&mut self, frame_tree: &SendableFrameTree) {
debug!("Setting the frame tree for pipeline {}", frame_tree.pipeline.id); debug!(
"Setting the frame tree for pipeline {}",
frame_tree.pipeline.id
);
self.root_pipeline = Some(frame_tree.pipeline.clone()); self.root_pipeline = Some(frame_tree.pipeline.clone());
@ -565,7 +587,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut txn = webrender_api::Transaction::new(); let mut txn = webrender_api::Transaction::new();
txn.set_root_pipeline(pipeline_id); txn.set_root_pipeline(pipeline_id);
txn.generate_frame(); txn.generate_frame();
self.webrender_api.send_transaction(self.webrender_document, txn); self.webrender_api
.send_transaction(self.webrender_document, txn);
self.create_pipeline_details_for_frame_tree(&frame_tree); self.create_pipeline_details_for_frame_tree(&frame_tree);
@ -589,10 +612,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn send_window_size(&self, size_type: WindowSizeType) { fn send_window_size(&self, size_type: WindowSizeType) {
let dppx = self.page_zoom * self.embedder_coordinates.hidpi_factor; let dppx = self.page_zoom * self.embedder_coordinates.hidpi_factor;
self.webrender_api.set_window_parameters(self.webrender_document, self.webrender_api.set_window_parameters(
self.webrender_document,
self.embedder_coordinates.framebuffer, self.embedder_coordinates.framebuffer,
self.embedder_coordinates.viewport, self.embedder_coordinates.viewport,
self.embedder_coordinates.hidpi_factor.get()); self.embedder_coordinates.hidpi_factor.get(),
);
let initial_viewport = self.embedder_coordinates.viewport.size.to_f32() / dppx; let initial_viewport = self.embedder_coordinates.viewport.size.to_f32() / dppx;
@ -601,9 +626,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
initial_viewport: initial_viewport, initial_viewport: initial_viewport,
}; };
let top_level_browsing_context_id = self.root_pipeline.as_ref().map(|pipeline| { let top_level_browsing_context_id = self
pipeline.top_level_browsing_context_id .root_pipeline
}); .as_ref()
.map(|pipeline| pipeline.top_level_browsing_context_id);
let msg = ConstellationMsg::WindowSize(top_level_browsing_context_id, data, size_type); let msg = ConstellationMsg::WindowSize(top_level_browsing_context_id, data, size_type);
@ -624,7 +650,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
if self.embedder_coordinates.viewport == old_coords.viewport && if self.embedder_coordinates.viewport == old_coords.viewport &&
self.embedder_coordinates.framebuffer == old_coords.framebuffer { self.embedder_coordinates.framebuffer == old_coords.framebuffer
{
return; return;
} }
@ -634,11 +661,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) { pub fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) {
if opts::get().convert_mouse_to_touch { if opts::get().convert_mouse_to_touch {
match mouse_window_event { match mouse_window_event {
MouseWindowEvent::Click(_, _) => {} MouseWindowEvent::Click(_, _) => {},
MouseWindowEvent::MouseDown(_, p) => self.on_touch_down(TouchId(0), p), MouseWindowEvent::MouseDown(_, p) => self.on_touch_down(TouchId(0), p),
MouseWindowEvent::MouseUp(_, p) => self.on_touch_up(TouchId(0), p), MouseWindowEvent::MouseUp(_, p) => self.on_touch_up(TouchId(0), p),
} }
return return;
} }
self.dispatch_mouse_window_event_class(mouse_window_event); self.dispatch_mouse_window_event_class(mouse_window_event);
@ -687,15 +714,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.webrender_document, self.webrender_document,
None, None,
world_cursor, world_cursor,
HitTestFlags::empty() HitTestFlags::empty(),
) )
} }
pub fn on_mouse_window_move_event_class(&mut self, cursor: DevicePoint) { pub fn on_mouse_window_move_event_class(&mut self, cursor: DevicePoint) {
if opts::get().convert_mouse_to_touch { if opts::get().convert_mouse_to_touch {
self.on_touch_move(TouchId(0), cursor); self.on_touch_move(TouchId(0), cursor);
return return;
} }
self.dispatch_mouse_window_move_event_class(cursor); self.dispatch_mouse_window_move_event_class(cursor);
@ -733,8 +759,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
&self, &self,
event_type: TouchEventType, event_type: TouchEventType,
identifier: TouchId, identifier: TouchId,
point: DevicePoint) point: DevicePoint,
{ ) {
let results = self.hit_test_at_point(point); let results = self.hit_test_at_point(point);
if let Some(item) = results.items.first() { if let Some(item) = results.items.first() {
let event = TouchEvent( let event = TouchEvent(
@ -751,10 +777,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
} }
pub fn on_touch_event(&mut self, pub fn on_touch_event(
&mut self,
event_type: TouchEventType, event_type: TouchEventType,
identifier: TouchId, identifier: TouchId,
location: DevicePoint) { location: DevicePoint,
) {
match event_type { match event_type {
TouchEventType::Down => self.on_touch_down(identifier, location), TouchEventType::Down => self.on_touch_down(identifier, location),
TouchEventType::Move => self.on_touch_move(identifier, location), TouchEventType::Move => self.on_touch_move(identifier, location),
@ -770,28 +798,25 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn on_touch_move(&mut self, identifier: TouchId, point: DevicePoint) { fn on_touch_move(&mut self, identifier: TouchId, point: DevicePoint) {
match self.touch_handler.on_touch_move(identifier, point) { match self.touch_handler.on_touch_move(identifier, point) {
TouchAction::Scroll(delta) => { TouchAction::Scroll(delta) => self.on_scroll_window_event(
self.on_scroll_window_event( ScrollLocation::Delta(LayoutVector2D::from_untyped(&delta.to_untyped())),
ScrollLocation::Delta( point.cast(),
LayoutVector2D::from_untyped(&delta.to_untyped())
), ),
point.cast()
)
}
TouchAction::Zoom(magnification, scroll_delta) => { TouchAction::Zoom(magnification, scroll_delta) => {
let cursor = TypedPoint2D::new(-1, -1); // Make sure this hits the base layer. let cursor = TypedPoint2D::new(-1, -1); // Make sure this hits the base layer.
self.pending_scroll_zoom_events.push(ScrollZoomEvent { self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: magnification, magnification: magnification,
scroll_location: ScrollLocation::Delta(webrender_api::LayoutVector2D::from_untyped( scroll_location: ScrollLocation::Delta(
&scroll_delta.to_untyped())), webrender_api::LayoutVector2D::from_untyped(&scroll_delta.to_untyped()),
),
cursor: cursor, cursor: cursor,
event_count: 1, event_count: 1,
}); });
} },
TouchAction::DispatchEvent => { TouchAction::DispatchEvent => {
self.send_touch_event(TouchEventType::Move, identifier, point); self.send_touch_event(TouchEventType::Move, identifier, point);
} },
_ => {} _ => {},
} }
} }
@ -818,24 +843,24 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.dispatch_mouse_window_event_class(MouseWindowEvent::Click(button, p)); self.dispatch_mouse_window_event_class(MouseWindowEvent::Click(button, p));
} }
pub fn on_scroll_event(&mut self, pub fn on_scroll_event(
&mut self,
delta: ScrollLocation, delta: ScrollLocation,
cursor: DeviceIntPoint, cursor: DeviceIntPoint,
phase: TouchEventType) { phase: TouchEventType,
) {
match phase { match phase {
TouchEventType::Move => self.on_scroll_window_event(delta, cursor), TouchEventType::Move => self.on_scroll_window_event(delta, cursor),
TouchEventType::Up | TouchEventType::Cancel => { TouchEventType::Up | TouchEventType::Cancel => {
self.on_scroll_end_window_event(delta, cursor); self.on_scroll_end_window_event(delta, cursor);
} },
TouchEventType::Down => { TouchEventType::Down => {
self.on_scroll_start_window_event(delta, cursor); self.on_scroll_start_window_event(delta, cursor);
} },
} }
} }
fn on_scroll_window_event(&mut self, fn on_scroll_window_event(&mut self, scroll_location: ScrollLocation, cursor: DeviceIntPoint) {
scroll_location: ScrollLocation,
cursor: DeviceIntPoint) {
self.in_scroll_transaction = Some(Instant::now()); self.in_scroll_transaction = Some(Instant::now());
self.pending_scroll_zoom_events.push(ScrollZoomEvent { self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0, magnification: 1.0,
@ -845,9 +870,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}); });
} }
fn on_scroll_start_window_event(&mut self, fn on_scroll_start_window_event(
&mut self,
scroll_location: ScrollLocation, scroll_location: ScrollLocation,
cursor: DeviceIntPoint) { cursor: DeviceIntPoint,
) {
self.scroll_in_progress = true; self.scroll_in_progress = true;
self.pending_scroll_zoom_events.push(ScrollZoomEvent { self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0, magnification: 1.0,
@ -857,9 +884,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}); });
} }
fn on_scroll_end_window_event(&mut self, fn on_scroll_end_window_event(
&mut self,
scroll_location: ScrollLocation, scroll_location: ScrollLocation,
cursor: DeviceIntPoint) { cursor: DeviceIntPoint,
) {
self.scroll_in_progress = false; self.scroll_in_progress = false;
self.pending_scroll_zoom_events.push(ScrollZoomEvent { self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0, magnification: 1.0,
@ -884,19 +913,20 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// disregard other pending events and exit the loop. // disregard other pending events and exit the loop.
last_combined_event = Some(scroll_event); last_combined_event = Some(scroll_event);
break; break;
} },
}; };
match &mut last_combined_event { match &mut last_combined_event {
last_combined_event @ &mut None => { last_combined_event @ &mut None => {
*last_combined_event = Some(ScrollZoomEvent { *last_combined_event = Some(ScrollZoomEvent {
magnification: scroll_event.magnification, magnification: scroll_event.magnification,
scroll_location: ScrollLocation::Delta(webrender_api::LayoutVector2D::from_untyped( scroll_location: ScrollLocation::Delta(
&this_delta.to_untyped())), webrender_api::LayoutVector2D::from_untyped(&this_delta.to_untyped()),
),
cursor: this_cursor, cursor: this_cursor,
event_count: 1, event_count: 1,
}) })
} },
&mut Some(ref mut last_combined_event) => { &mut Some(ref mut last_combined_event) => {
// Mac OS X sometimes delivers scroll events out of vsync during a // Mac OS X sometimes delivers scroll events out of vsync during a
// fling. This causes events to get bunched up occasionally, causing // fling. This causes events to get bunched up occasionally, causing
@ -909,20 +939,22 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let new_event_count = let new_event_count =
TypedScale::new(last_combined_event.event_count as f32); TypedScale::new(last_combined_event.event_count as f32);
last_combined_event.scroll_location = ScrollLocation::Delta( last_combined_event.scroll_location = ScrollLocation::Delta(
(delta * old_event_count + this_delta) / (delta * old_event_count + this_delta) / new_event_count,
new_event_count); );
} }
last_combined_event.magnification *= scroll_event.magnification; last_combined_event.magnification *= scroll_event.magnification;
} },
} }
} }
if let Some(combined_event) = last_combined_event { if let Some(combined_event) = last_combined_event {
let scroll_location = match combined_event.scroll_location { let scroll_location = match combined_event.scroll_location {
ScrollLocation::Delta(delta) => { ScrollLocation::Delta(delta) => {
let scaled_delta = (TypedVector2D::from_untyped(&delta.to_untyped()) / self.scale) let scaled_delta = (TypedVector2D::from_untyped(&delta.to_untyped()) /
self.scale)
.to_untyped(); .to_untyped();
let calculated_delta = webrender_api::LayoutVector2D::from_untyped(&scaled_delta); let calculated_delta =
webrender_api::LayoutVector2D::from_untyped(&scaled_delta);
ScrollLocation::Delta(calculated_delta) ScrollLocation::Delta(calculated_delta)
}, },
// Leave ScrollLocation unchanged if it is Start or End location. // Leave ScrollLocation unchanged if it is Start or End location.
@ -938,7 +970,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
txn.set_pinch_zoom(webrender_api::ZoomFactor::new(self.pinch_zoom_level())); txn.set_pinch_zoom(webrender_api::ZoomFactor::new(self.pinch_zoom_level()));
} }
txn.generate_frame(); txn.generate_frame();
self.webrender_api.send_transaction(self.webrender_document, txn); self.webrender_api
.send_transaction(self.webrender_document, txn);
self.waiting_for_results_of_scroll = true self.waiting_for_results_of_scroll = true
} }
@ -951,9 +984,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn process_animations(&mut self) { fn process_animations(&mut self) {
let mut pipeline_ids = vec![]; let mut pipeline_ids = vec![];
for (pipeline_id, pipeline_details) in &self.pipeline_details { for (pipeline_id, pipeline_details) in &self.pipeline_details {
if (pipeline_details.animations_running || if (pipeline_details.animations_running || pipeline_details.animation_callbacks_running) &&
pipeline_details.animation_callbacks_running) && pipeline_details.visible
pipeline_details.visible { {
pipeline_ids.push(*pipeline_id); pipeline_ids.push(*pipeline_id);
} }
} }
@ -969,7 +1002,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
fn tick_animations_for_pipeline(&mut self, pipeline_id: PipelineId) { fn tick_animations_for_pipeline(&mut self, pipeline_id: PipelineId) {
let animation_callbacks_running = self.pipeline_details(pipeline_id).animation_callbacks_running; let animation_callbacks_running = self
.pipeline_details(pipeline_id)
.animation_callbacks_running;
if animation_callbacks_running { if animation_callbacks_running {
let msg = ConstellationMsg::TickAnimation(pipeline_id, AnimationTickType::Script); let msg = ConstellationMsg::TickAnimation(pipeline_id, AnimationTickType::Script);
if let Err(e) = self.constellation_chan.send(msg) { if let Err(e) = self.constellation_chan.send(msg) {
@ -988,9 +1023,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
fn constrain_viewport(&mut self, pipeline_id: PipelineId, constraints: ViewportConstraints) { fn constrain_viewport(&mut self, pipeline_id: PipelineId, constraints: ViewportConstraints) {
let is_root = self.root_pipeline.as_ref().map_or(false, |root_pipeline| { let is_root = self
root_pipeline.id == pipeline_id .root_pipeline
}); .as_ref()
.map_or(false, |root_pipeline| root_pipeline.id == pipeline_id);
if is_root { if is_root {
self.viewport_zoom = constraints.initial_zoom; self.viewport_zoom = constraints.initial_zoom;
@ -1006,7 +1042,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
None => match opts::get().output_file { None => match opts::get().output_file {
Some(_) => TypedScale::new(1.0), Some(_) => TypedScale::new(1.0),
None => self.embedder_coordinates.hidpi_factor, None => self.embedder_coordinates.hidpi_factor,
} },
} }
} }
@ -1027,8 +1063,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
pub fn on_zoom_window_event(&mut self, magnification: f32) { pub fn on_zoom_window_event(&mut self, magnification: f32) {
self.page_zoom = TypedScale::new((self.page_zoom.get() * magnification) self.page_zoom = TypedScale::new(
.max(MIN_ZOOM).min(MAX_ZOOM)); (self.page_zoom.get() * magnification)
.max(MIN_ZOOM)
.min(MAX_ZOOM),
);
self.update_zoom_transform(); self.update_zoom_transform();
self.send_window_size(WindowSizeType::Resize); self.send_window_size(WindowSizeType::Resize);
self.update_page_zoom_for_webrender(); self.update_page_zoom_for_webrender();
@ -1039,7 +1078,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut txn = webrender_api::Transaction::new(); let mut txn = webrender_api::Transaction::new();
txn.set_page_zoom(page_zoom); txn.set_page_zoom(page_zoom);
self.webrender_api.send_transaction(self.webrender_document, txn); self.webrender_api
.send_transaction(self.webrender_document, txn);
} }
/// Simulate a pinch zoom /// Simulate a pinch zoom
@ -1054,7 +1094,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn send_viewport_rects(&self) { fn send_viewport_rects(&self) {
let mut scroll_states_per_pipeline = HashMap::new(); let mut scroll_states_per_pipeline = HashMap::new();
for scroll_layer_state in self.webrender_api.get_scroll_node_state(self.webrender_document) { for scroll_layer_state in self
.webrender_api
.get_scroll_node_state(self.webrender_document)
{
let scroll_state = ScrollState { let scroll_state = ScrollState {
scroll_id: scroll_layer_state.id, scroll_id: scroll_layer_state.id,
scroll_offset: scroll_layer_state.scroll_offset.to_untyped(), scroll_offset: scroll_layer_state.scroll_offset.to_untyped(),
@ -1105,8 +1148,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut pipeline_epochs = HashMap::new(); let mut pipeline_epochs = HashMap::new();
for (id, _) in &self.pipeline_details { for (id, _) in &self.pipeline_details {
let webrender_pipeline_id = id.to_webrender(); let webrender_pipeline_id = id.to_webrender();
if let Some(webrender_api::Epoch(epoch)) = self.webrender if let Some(webrender_api::Epoch(epoch)) =
.current_epoch(webrender_pipeline_id) { self.webrender.current_epoch(webrender_pipeline_id)
{
let epoch = Epoch(epoch); let epoch = Epoch(epoch);
pipeline_epochs.insert(*id, epoch); pipeline_epochs.insert(*id, epoch);
} }
@ -1120,12 +1164,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
self.ready_to_save_state = ReadyState::WaitingForConstellationReply; self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
Err(NotReadyToPaint::JustNotifiedConstellation) Err(NotReadyToPaint::JustNotifiedConstellation)
} },
ReadyState::WaitingForConstellationReply => { ReadyState::WaitingForConstellationReply => {
// If waiting on a reply from the constellation to the last // If waiting on a reply from the constellation to the last
// query if the image is stable, then assume not ready yet. // query if the image is stable, then assume not ready yet.
Err(NotReadyToPaint::WaitingOnConstellation) Err(NotReadyToPaint::WaitingOnConstellation)
} },
ReadyState::ReadyToSaveImage => { ReadyState::ReadyToSaveImage => {
// Constellation has replied at some point in the past // Constellation has replied at some point in the past
// that the current output image is stable and ready // that the current output image is stable and ready
@ -1137,7 +1181,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
self.ready_to_save_state = ReadyState::Unknown; self.ready_to_save_state = ReadyState::Unknown;
Ok(()) Ok(())
} },
} }
} }
@ -1149,7 +1193,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.start_shutting_down(); self.start_shutting_down();
}, },
Err(e) => if opts::get().is_running_problem_test { Err(e) => if opts::get().is_running_problem_test {
if e != UnableToComposite::NotReadyToPaintImage(NotReadyToPaint::WaitingOnConstellation) { if e != UnableToComposite::NotReadyToPaintImage(
NotReadyToPaint::WaitingOnConstellation,
) {
println!("not ready to composite: {:?}", e); println!("not ready to composite: {:?}", e);
} }
}, },
@ -1161,13 +1207,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
/// for some reason. If CompositeTarget is Window or Png no image data is returned; /// for some reason. If CompositeTarget is Window or Png no image data is returned;
/// in the latter case the image is written directly to a file. If CompositeTarget /// in the latter case the image is written directly to a file. If CompositeTarget
/// is WindowAndPng Ok(Some(png::Image)) is returned. /// is WindowAndPng Ok(Some(png::Image)) is returned.
fn composite_specific_target(&mut self, fn composite_specific_target(
target: CompositeTarget) &mut self,
-> Result<Option<Image>, UnableToComposite> { target: CompositeTarget,
) -> Result<Option<Image>, UnableToComposite> {
let width = self.embedder_coordinates.framebuffer.width_typed(); let width = self.embedder_coordinates.framebuffer.width_typed();
let height = self.embedder_coordinates.framebuffer.height_typed(); let height = self.embedder_coordinates.framebuffer.height_typed();
if !self.window.prepare_for_composite(width, height) { if !self.window.prepare_for_composite(width, height) {
return Err(UnableToComposite::WindowUnprepared) return Err(UnableToComposite::WindowUnprepared);
} }
self.webrender.update(); self.webrender.update();
@ -1183,34 +1230,40 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// all active animations to complete. // all active animations to complete.
if self.animations_active() { if self.animations_active() {
self.process_animations(); self.process_animations();
return Err(UnableToComposite::NotReadyToPaintImage(NotReadyToPaint::AnimationsActive)); return Err(UnableToComposite::NotReadyToPaintImage(
NotReadyToPaint::AnimationsActive,
));
} }
if let Err(result) = self.is_ready_to_paint_image_output() { if let Err(result) = self.is_ready_to_paint_image_output() {
return Err(UnableToComposite::NotReadyToPaintImage(result)) return Err(UnableToComposite::NotReadyToPaintImage(result));
} }
} }
let rt_info = match target { let rt_info = match target {
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]
CompositeTarget::Window => { CompositeTarget::Window => gl::RenderTargetInfo::default(),
gl::RenderTargetInfo::default()
}
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]
CompositeTarget::WindowAndPng | CompositeTarget::WindowAndPng | CompositeTarget::PngFile => {
CompositeTarget::PngFile => {
gl::initialize_png(&*self.window.gl(), width, height) gl::initialize_png(&*self.window.gl(), width, height)
} },
#[cfg(not(feature = "gleam"))] #[cfg(not(feature = "gleam"))]
_ => () _ => (),
}; };
profile(ProfilerCategory::Compositing, None, self.time_profiler_chan.clone(), || { profile(
ProfilerCategory::Compositing,
None,
self.time_profiler_chan.clone(),
|| {
debug!("compositor: compositing"); debug!("compositor: compositing");
// Paint the scene. // Paint the scene.
// TODO(gw): Take notice of any errors the renderer returns! // TODO(gw): Take notice of any errors the renderer returns!
self.webrender.render(self.embedder_coordinates.framebuffer).ok(); self.webrender
}); .render(self.embedder_coordinates.framebuffer)
.ok();
},
);
// If there are pending paint metrics, we check if any of the painted epochs is // If there are pending paint metrics, we check if any of the painted epochs is
// one of the ones that the paint metrics recorder is expecting . In that case, // one of the ones that the paint metrics recorder is expecting . In that case,
@ -1222,7 +1275,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
// For each pending paint metrics pipeline id // For each pending paint metrics pipeline id
for (id, pending_epoch) in &self.pending_paint_metrics { for (id, pending_epoch) in &self.pending_paint_metrics {
// we get the last painted frame id from webrender // we get the last painted frame id from webrender
if let Some(webrender_api::Epoch(epoch)) = self.webrender.current_epoch(id.to_webrender()) { if let Some(webrender_api::Epoch(epoch)) =
self.webrender.current_epoch(id.to_webrender())
{
// and check if it is the one the layout thread is expecting, // and check if it is the one the layout thread is expecting,
let epoch = Epoch(epoch); let epoch = Epoch(epoch);
if *pending_epoch != epoch { if *pending_epoch != epoch {
@ -1256,27 +1311,31 @@ impl<Window: WindowMethods> IOCompositor<Window> {
bytes: ipc::IpcSharedMemory::from_bytes(&*img), bytes: ipc::IpcSharedMemory::from_bytes(&*img),
id: None, id: None,
}) })
} },
#[cfg(feature = "gleam")] #[cfg(feature = "gleam")]
CompositeTarget::PngFile => { CompositeTarget::PngFile => {
let gl = &*self.window.gl(); let gl = &*self.window.gl();
profile(ProfilerCategory::ImageSaving, None, self.time_profiler_chan.clone(), || { profile(
match opts::get().output_file.as_ref() { ProfilerCategory::ImageSaving,
None,
self.time_profiler_chan.clone(),
|| match opts::get().output_file.as_ref() {
Some(path) => match File::create(path) { Some(path) => match File::create(path) {
Ok(mut file) => { Ok(mut file) => {
let img = gl::draw_img(gl, rt_info, width, height); let img = gl::draw_img(gl, rt_info, width, height);
let dynamic_image = DynamicImage::ImageRgb8(img); let dynamic_image = DynamicImage::ImageRgb8(img);
if let Err(e) = dynamic_image.write_to(&mut file, ImageFormat::PNG) { if let Err(e) = dynamic_image.write_to(&mut file, ImageFormat::PNG)
{
error!("Failed to save {} ({}).", path, e); error!("Failed to save {} ({}).", path, e);
} }
}, },
Err(e) => error!("Failed to create {} ({}).", path, e), Err(e) => error!("Failed to create {} ({}).", path, e),
}, },
None => error!("No file specified."), None => error!("No file specified."),
} },
}); );
None None
} },
#[cfg(not(feature = "gleam"))] #[cfg(not(feature = "gleam"))]
_ => None, _ => None,
}; };
@ -1301,7 +1360,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
self.composition_request = CompositionRequest::CompositeNow(reason) self.composition_request = CompositionRequest::CompositeNow(reason)
} else if opts::get().is_running_problem_test { } else if opts::get().is_running_problem_test {
println!("composition_request is already {:?}", self.composition_request); println!(
"composition_request is already {:?}",
self.composition_request
);
} }
} }
@ -1315,17 +1377,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let mut found_recomposite_msg = false; let mut found_recomposite_msg = false;
while let Some(msg) = self.port.try_recv_compositor_msg() { while let Some(msg) = self.port.try_recv_compositor_msg() {
match msg { match msg {
Msg::Recomposite(_) if found_recomposite_msg => {} Msg::Recomposite(_) if found_recomposite_msg => {},
Msg::Recomposite(_) => { Msg::Recomposite(_) => {
found_recomposite_msg = true; found_recomposite_msg = true;
compositor_messages.push(msg) compositor_messages.push(msg)
} },
_ => compositor_messages.push(msg), _ => compositor_messages.push(msg),
} }
} }
for msg in compositor_messages { for msg in compositor_messages {
if !self.handle_browser_message(msg) { if !self.handle_browser_message(msg) {
return false return false;
} }
} }
true true
@ -1342,10 +1404,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
} }
match self.composition_request { match self.composition_request {
CompositionRequest::NoCompositingNecessary => {} CompositionRequest::NoCompositingNecessary => {},
CompositionRequest::CompositeNow(_) => { CompositionRequest::CompositeNow(_) => self.composite(),
self.composite()
}
} }
if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll { if !self.pending_scroll_zoom_events.is_empty() && !self.waiting_for_results_of_scroll {
@ -1368,10 +1428,10 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let keep_going = self.handle_browser_message(msg); let keep_going = self.handle_browser_message(msg);
if need_recomposite { if need_recomposite {
self.composite(); self.composite();
break break;
} }
if !keep_going { if !keep_going {
break break;
} }
} }
} }
@ -1397,42 +1457,45 @@ impl<Window: WindowMethods> IOCompositor<Window> {
webrender::DebugFlags::PROFILER_DBG | webrender::DebugFlags::PROFILER_DBG |
webrender::DebugFlags::GPU_TIME_QUERIES | webrender::DebugFlags::GPU_TIME_QUERIES |
webrender::DebugFlags::GPU_SAMPLE_QUERIES webrender::DebugFlags::GPU_SAMPLE_QUERIES
} },
WebRenderDebugOption::TextureCacheDebug => { WebRenderDebugOption::TextureCacheDebug => webrender::DebugFlags::TEXTURE_CACHE_DBG,
webrender::DebugFlags::TEXTURE_CACHE_DBG WebRenderDebugOption::RenderTargetDebug => webrender::DebugFlags::RENDER_TARGET_DBG,
}
WebRenderDebugOption::RenderTargetDebug => {
webrender::DebugFlags::RENDER_TARGET_DBG
}
}; };
flags.toggle(flag); flags.toggle(flag);
self.webrender.set_debug_flags(flags); self.webrender.set_debug_flags(flags);
let mut txn = webrender_api::Transaction::new(); let mut txn = webrender_api::Transaction::new();
txn.generate_frame(); txn.generate_frame();
self.webrender_api.send_transaction(self.webrender_document, txn); self.webrender_api
.send_transaction(self.webrender_document, txn);
} }
pub fn capture_webrender(&mut self) { pub fn capture_webrender(&mut self) {
let capture_id = now().to_timespec().sec.to_string(); let capture_id = now().to_timespec().sec.to_string();
let available_path = [env::current_dir(), Ok(env::temp_dir())].iter() let available_path = [env::current_dir(), Ok(env::temp_dir())]
.filter_map(|val| val.as_ref().map(|dir| dir.join("capture_webrender").join(&capture_id)).ok()) .iter()
.find(|val| { .filter_map(|val| {
match create_dir_all(&val) { val.as_ref()
.map(|dir| dir.join("capture_webrender").join(&capture_id))
.ok()
}).find(|val| match create_dir_all(&val) {
Ok(_) => true, Ok(_) => true,
Err(err) => { Err(err) => {
eprintln!("Unable to create path '{:?}' for capture: {:?}", &val, err); eprintln!("Unable to create path '{:?}' for capture: {:?}", &val, err);
false false
} },
}
}); });
match available_path { match available_path {
Some(capture_path) => { Some(capture_path) => {
let revision_file_path = capture_path.join("wr.txt"); let revision_file_path = capture_path.join("wr.txt");
debug!("Trying to save webrender capture under {:?}", &revision_file_path); debug!(
self.webrender_api.save_capture(capture_path, webrender_api::CaptureBits::all()); "Trying to save webrender capture under {:?}",
&revision_file_path
);
self.webrender_api
.save_capture(capture_path, webrender_api::CaptureBits::all());
match File::create(revision_file_path) { match File::create(revision_file_path) {
Ok(mut file) => { Ok(mut file) => {
@ -1440,11 +1503,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
if let Err(err) = write!(&mut file, "{}", revision) { if let Err(err) = write!(&mut file, "{}", revision) {
eprintln!("Unable to write webrender revision: {:?}", err) eprintln!("Unable to write webrender revision: {:?}", err)
} }
} },
Err(err) => eprintln!("Capture triggered, creating webrender revision info skipped: {:?}", err) Err(err) => eprintln!(
"Capture triggered, creating webrender revision info skipped: {:?}",
err
),
} }
}, },
None => eprintln!("Unable to locate path to save captures") None => eprintln!("Unable to locate path to save captures"),
} }
} }
} }

View file

@ -20,7 +20,6 @@ use style_traits::viewport::ViewportConstraints;
use webrender; use webrender;
use webrender_api::{self, DeviceIntPoint, DeviceUintSize}; use webrender_api::{self, DeviceIntPoint, DeviceUintSize};
/// Sends messages to the compositor. /// Sends messages to the compositor.
pub struct CompositorProxy { pub struct CompositorProxy {
pub sender: Sender<Msg>, pub sender: Sender<Msg>,
@ -48,7 +47,7 @@ impl Clone for CompositorProxy {
/// The port that the compositor receives messages on. /// The port that the compositor receives messages on.
pub struct CompositorReceiver { pub struct CompositorReceiver {
pub receiver: Receiver<Msg> pub receiver: Receiver<Msg>,
} }
impl CompositorReceiver { impl CompositorReceiver {

View file

@ -2,12 +2,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use gleam::gl; use gleam::gl;
use image::RgbImage; use image::RgbImage;
use servo_geometry::DeviceUintLength; use servo_geometry::DeviceUintLength;
#[derive(Default)] #[derive(Default)]
pub struct RenderTargetInfo { pub struct RenderTargetInfo {
framebuffer_ids: Vec<gl::GLuint>, framebuffer_ids: Vec<gl::GLuint>,
@ -16,7 +14,9 @@ pub struct RenderTargetInfo {
} }
pub fn initialize_png( pub fn initialize_png(
gl: &gl::Gl, width: DeviceUintLength, height: DeviceUintLength gl: &gl::Gl,
width: DeviceUintLength,
height: DeviceUintLength,
) -> RenderTargetInfo { ) -> RenderTargetInfo {
let framebuffer_ids = gl.gen_framebuffers(1); let framebuffer_ids = gl.gen_framebuffers(1);
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]); gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]);
@ -24,27 +24,53 @@ pub fn initialize_png(
let texture_ids = gl.gen_textures(1); let texture_ids = gl.gen_textures(1);
gl.bind_texture(gl::TEXTURE_2D, texture_ids[0]); gl.bind_texture(gl::TEXTURE_2D, texture_ids[0]);
gl.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGB as gl::GLint, width.get() as gl::GLsizei, gl.tex_image_2d(
height.get() as gl::GLsizei, 0, gl::RGB, gl::UNSIGNED_BYTE, None); gl::TEXTURE_2D,
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as gl::GLint); 0,
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as gl::GLint); gl::RGB as gl::GLint,
width.get() as gl::GLsizei,
height.get() as gl::GLsizei,
0,
gl::RGB,
gl::UNSIGNED_BYTE,
None,
);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_MAG_FILTER,
gl::NEAREST as gl::GLint,
);
gl.tex_parameter_i(
gl::TEXTURE_2D,
gl::TEXTURE_MIN_FILTER,
gl::NEAREST as gl::GLint,
);
gl.framebuffer_texture_2d(gl::FRAMEBUFFER, gl::COLOR_ATTACHMENT0, gl::TEXTURE_2D, gl.framebuffer_texture_2d(
texture_ids[0], 0); gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::TEXTURE_2D,
texture_ids[0],
0,
);
gl.bind_texture(gl::TEXTURE_2D, 0); gl.bind_texture(gl::TEXTURE_2D, 0);
let renderbuffer_ids = gl.gen_renderbuffers(1); let renderbuffer_ids = gl.gen_renderbuffers(1);
let depth_rb = renderbuffer_ids[0]; let depth_rb = renderbuffer_ids[0];
gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb); gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
gl.renderbuffer_storage(gl::RENDERBUFFER, gl.renderbuffer_storage(
gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24, gl::DEPTH_COMPONENT24,
width.get() as gl::GLsizei, width.get() as gl::GLsizei,
height.get() as gl::GLsizei); height.get() as gl::GLsizei,
gl.framebuffer_renderbuffer(gl::FRAMEBUFFER, );
gl.framebuffer_renderbuffer(
gl::FRAMEBUFFER,
gl::DEPTH_ATTACHMENT, gl::DEPTH_ATTACHMENT,
gl::RENDERBUFFER, gl::RENDERBUFFER,
depth_rb); depth_rb,
);
RenderTargetInfo { RenderTargetInfo {
framebuffer_ids, framebuffer_ids,
@ -70,10 +96,12 @@ pub fn draw_img(
gl.bind_vertex_array(0); gl.bind_vertex_array(0);
let mut pixels = gl.read_pixels( let mut pixels = gl.read_pixels(
0, 0, 0,
0,
width as gl::GLsizei, width as gl::GLsizei,
height as gl::GLsizei, height as gl::GLsizei,
gl::RGB, gl::UNSIGNED_BYTE, gl::RGB,
gl::UNSIGNED_BYTE,
); );
gl.bind_framebuffer(gl::FRAMEBUFFER, 0); gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
@ -92,6 +120,5 @@ pub fn draw_img(
(&mut pixels[dst_start..dst_start + stride]).clone_from_slice(&src_slice[..stride]); (&mut pixels[dst_start..dst_start + stride]).clone_from_slice(&src_slice[..stride]);
} }
RgbImage::from_raw(width as u32, height as u32, pixels) RgbImage::from_raw(width as u32, height as u32, pixels).expect("Flipping image failed!")
.expect("Flipping image failed!")
} }

View file

@ -19,12 +19,15 @@ pub struct TouchHandler {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct TouchPoint { pub struct TouchPoint {
pub id: TouchId, pub id: TouchId,
pub point: TypedPoint2D<f32, DevicePixel> pub point: TypedPoint2D<f32, DevicePixel>,
} }
impl TouchPoint { impl TouchPoint {
pub fn new(id: TouchId, point: TypedPoint2D<f32, DevicePixel>) -> Self { pub fn new(id: TouchId, point: TypedPoint2D<f32, DevicePixel>) -> Self {
TouchPoint { id: id, point: point } TouchPoint {
id: id,
point: point,
}
} }
} }
@ -87,14 +90,17 @@ impl TouchHandler {
}; };
} }
pub fn on_touch_move(&mut self, id: TouchId, point: TypedPoint2D<f32, DevicePixel>) pub fn on_touch_move(
-> TouchAction { &mut self,
id: TouchId,
point: TypedPoint2D<f32, DevicePixel>,
) -> TouchAction {
let idx = match self.active_touch_points.iter_mut().position(|t| t.id == id) { let idx = match self.active_touch_points.iter_mut().position(|t| t.id == id) {
Some(i) => i, Some(i) => i,
None => { None => {
warn!("Got a touchmove event for a non-active touch point"); warn!("Got a touchmove event for a non-active touch point");
return TouchAction::NoAction; return TouchAction::NoAction;
} },
}; };
let old_point = self.active_touch_points[idx].point; let old_point = self.active_touch_points[idx].point;
@ -110,14 +116,12 @@ impl TouchHandler {
} else { } else {
TouchAction::NoAction TouchAction::NoAction
} }
} },
Panning => { Panning => {
let delta = point - old_point; let delta = point - old_point;
TouchAction::Scroll(delta) TouchAction::Scroll(delta)
} },
DefaultPrevented => { DefaultPrevented => TouchAction::DispatchEvent,
TouchAction::DispatchEvent
}
Pinching => { Pinching => {
let (d0, c0) = self.pinch_distance_and_center(); let (d0, c0) = self.pinch_distance_and_center();
self.active_touch_points[idx].point = point; self.active_touch_points[idx].point = point;
@ -127,7 +131,7 @@ impl TouchHandler {
let scroll_delta = c1 - c0 * TypedScale::new(magnification); let scroll_delta = c1 - c0 * TypedScale::new(magnification);
TouchAction::Zoom(magnification, scroll_delta) TouchAction::Zoom(magnification, scroll_delta)
} },
WaitingForScript => TouchAction::NoAction, WaitingForScript => TouchAction::NoAction,
MultiTouch => TouchAction::NoAction, MultiTouch => TouchAction::NoAction,
Nothing => unreachable!(), Nothing => unreachable!(),
@ -141,15 +145,18 @@ impl TouchHandler {
action action
} }
pub fn on_touch_up(&mut self, id: TouchId, _point: TypedPoint2D<f32, DevicePixel>) pub fn on_touch_up(
-> TouchAction { &mut self,
id: TouchId,
_point: TypedPoint2D<f32, DevicePixel>,
) -> TouchAction {
match self.active_touch_points.iter().position(|t| t.id == id) { match self.active_touch_points.iter().position(|t| t.id == id) {
Some(i) => { Some(i) => {
self.active_touch_points.swap_remove(i); self.active_touch_points.swap_remove(i);
} },
None => { None => {
warn!("Got a touch up event for a non-active touch point"); warn!("Got a touch up event for a non-active touch point");
} },
} }
match self.state { match self.state {
Touching => { Touching => {
@ -157,21 +164,21 @@ impl TouchHandler {
// FIXME: Don't send a click if preventDefault is called on the touchend event. // FIXME: Don't send a click if preventDefault is called on the touchend event.
self.state = Nothing; self.state = Nothing;
TouchAction::Click TouchAction::Click
} },
Nothing | Panning => { Nothing | Panning => {
self.state = Nothing; self.state = Nothing;
TouchAction::NoAction TouchAction::NoAction
} },
Pinching => { Pinching => {
self.state = Panning; self.state = Panning;
TouchAction::NoAction TouchAction::NoAction
} },
WaitingForScript | DefaultPrevented | MultiTouch => { WaitingForScript | DefaultPrevented | MultiTouch => {
if self.active_touch_points.is_empty() { if self.active_touch_points.is_empty() {
self.state = Nothing; self.state = Nothing;
} }
TouchAction::NoAction TouchAction::NoAction
} },
} }
} }
@ -179,25 +186,25 @@ impl TouchHandler {
match self.active_touch_points.iter().position(|t| t.id == id) { match self.active_touch_points.iter().position(|t| t.id == id) {
Some(i) => { Some(i) => {
self.active_touch_points.swap_remove(i); self.active_touch_points.swap_remove(i);
} },
None => { None => {
warn!("Got a touchcancel event for a non-active touch point"); warn!("Got a touchcancel event for a non-active touch point");
return; return;
} },
} }
match self.state { match self.state {
Nothing => {} Nothing => {},
Touching | Panning => { Touching | Panning => {
self.state = Nothing; self.state = Nothing;
} },
Pinching => { Pinching => {
self.state = Panning; self.state = Panning;
} },
WaitingForScript | DefaultPrevented | MultiTouch => { WaitingForScript | DefaultPrevented | MultiTouch => {
if self.active_touch_points.is_empty() { if self.active_touch_points.is_empty() {
self.state = Nothing; self.state = Nothing;
} }
} },
} }
} }
@ -209,7 +216,7 @@ impl TouchHandler {
1 => Touching, 1 => Touching,
2 => Pinching, 2 => Pinching,
_ => MultiTouch, _ => MultiTouch,
} },
} }
} }
} }