mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Format component compositing #21373
This commit is contained in:
parent
1ee3deea27
commit
e4cd04399e
5 changed files with 363 additions and 255 deletions
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.embedder_coordinates.framebuffer,
|
self.webrender_document,
|
||||||
self.embedder_coordinates.viewport,
|
self.embedder_coordinates.framebuffer,
|
||||||
self.embedder_coordinates.hidpi_factor.get());
|
self.embedder_coordinates.viewport,
|
||||||
|
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);
|
||||||
|
@ -720,7 +746,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
warn!("Sending event to constellation failed ({}).", e);
|
warn!("Sending event to constellation failed ({}).", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(cursor) = CursorKind::from_u8(item.tag.1 as _).ok() {
|
if let Some(cursor) = CursorKind::from_u8(item.tag.1 as _).ok() {
|
||||||
let msg = ConstellationMsg::SetCursor(cursor);
|
let msg = ConstellationMsg::SetCursor(cursor);
|
||||||
if let Err(e) = self.constellation_chan.send(msg) {
|
if let Err(e) = self.constellation_chan.send(msg) {
|
||||||
warn!("Sending event to constellation failed ({}).", e);
|
warn!("Sending event to constellation failed ({}).", e);
|
||||||
|
@ -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(
|
||||||
event_type: TouchEventType,
|
&mut self,
|
||||||
identifier: TouchId,
|
event_type: TouchEventType,
|
||||||
location: DevicePoint) {
|
identifier: TouchId,
|
||||||
|
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(
|
||||||
delta: ScrollLocation,
|
&mut self,
|
||||||
cursor: DeviceIntPoint,
|
delta: ScrollLocation,
|
||||||
phase: TouchEventType) {
|
cursor: DeviceIntPoint,
|
||||||
|
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(
|
||||||
scroll_location: ScrollLocation,
|
&mut self,
|
||||||
cursor: DeviceIntPoint) {
|
scroll_location: ScrollLocation,
|
||||||
|
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(
|
||||||
scroll_location: ScrollLocation,
|
&mut self,
|
||||||
cursor: DeviceIntPoint) {
|
scroll_location: ScrollLocation,
|
||||||
|
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,21 +939,23 @@ 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()) /
|
||||||
.to_untyped();
|
self.scale)
|
||||||
let calculated_delta = webrender_api::LayoutVector2D::from_untyped(&scaled_delta);
|
.to_untyped();
|
||||||
ScrollLocation::Delta(calculated_delta)
|
let calculated_delta =
|
||||||
|
webrender_api::LayoutVector2D::from_untyped(&scaled_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.
|
||||||
sl @ ScrollLocation::Start | sl @ ScrollLocation::End => sl,
|
sl @ ScrollLocation::Start | sl @ ScrollLocation::End => sl,
|
||||||
|
@ -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,10 +984,10 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let animation_state = if pipeline_ids.is_empty() {
|
let animation_state = if pipeline_ids.is_empty() {
|
||||||
|
@ -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
|
||||||
|
@ -1047,14 +1087,17 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
|
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
|
||||||
magnification: magnification,
|
magnification: magnification,
|
||||||
scroll_location: ScrollLocation::Delta(TypedVector2D::zero()), // TODO: Scroll to keep the center in view?
|
scroll_location: ScrollLocation::Delta(TypedVector2D::zero()), // TODO: Scroll to keep the center in view?
|
||||||
cursor: TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
|
cursor: TypedPoint2D::new(-1, -1), // Make sure this hits the base layer.
|
||||||
event_count: 1,
|
event_count: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
||||||
debug!("compositor: compositing");
|
ProfilerCategory::Compositing,
|
||||||
|
None,
|
||||||
|
self.time_profiler_chan.clone(),
|
||||||
|
|| {
|
||||||
|
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 {
|
||||||
|
@ -1233,7 +1288,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
if let Some(pipeline) = self.pipeline(*id) {
|
if let Some(pipeline) = self.pipeline(*id) {
|
||||||
// and inform the layout thread with the measured paint time.
|
// and inform the layout thread with the measured paint time.
|
||||||
let msg = LayoutControlMsg::PaintMetric(epoch, paint_time);
|
let msg = LayoutControlMsg::PaintMetric(epoch, paint_time);
|
||||||
if let Err(e) = pipeline.layout_chan.send(msg) {
|
if let Err(e) = pipeline.layout_chan.send(msg) {
|
||||||
warn!("Sending PaintMetric message to layout failed ({}).", e);
|
warn!("Sending PaintMetric message to layout failed ({}).", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1395,44 +1455,47 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
||||||
let flag = match option {
|
let flag = match option {
|
||||||
WebRenderDebugOption::Profiler => {
|
WebRenderDebugOption::Profiler => {
|
||||||
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()
|
||||||
Ok(_) => true,
|
.map(|dir| dir.join("capture_webrender").join(&capture_id))
|
||||||
Err(err) => {
|
.ok()
|
||||||
eprintln!("Unable to create path '{:?}' for capture: {:?}", &val, err);
|
}).find(|val| match create_dir_all(&val) {
|
||||||
false
|
Ok(_) => true,
|
||||||
}
|
Err(err) => {
|
||||||
}
|
eprintln!("Unable to create path '{:?}' for capture: {:?}", &val, err);
|
||||||
|
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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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::DEPTH_COMPONENT24,
|
gl::RENDERBUFFER,
|
||||||
width.get() as gl::GLsizei,
|
gl::DEPTH_COMPONENT24,
|
||||||
height.get() as gl::GLsizei);
|
width.get() as gl::GLsizei,
|
||||||
gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
|
height.get() as gl::GLsizei,
|
||||||
gl::DEPTH_ATTACHMENT,
|
);
|
||||||
gl::RENDERBUFFER,
|
gl.framebuffer_renderbuffer(
|
||||||
depth_rb);
|
gl::FRAMEBUFFER,
|
||||||
|
gl::DEPTH_ATTACHMENT,
|
||||||
|
gl::RENDERBUFFER,
|
||||||
|
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);
|
||||||
|
@ -88,10 +116,9 @@ pub fn draw_img(
|
||||||
for y in 0..height {
|
for y in 0..height {
|
||||||
let dst_start = y * stride;
|
let dst_start = y * stride;
|
||||||
let src_start = (height - y - 1) * stride;
|
let src_start = (height - y - 1) * stride;
|
||||||
let src_slice = &orig_pixels[src_start .. src_start + stride];
|
let src_slice = &orig_pixels[src_start..src_start + stride];
|
||||||
(&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!")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,22 +82,25 @@ impl TouchHandler {
|
||||||
self.active_touch_points.push(point);
|
self.active_touch_points.push(point);
|
||||||
|
|
||||||
self.state = match self.state {
|
self.state = match self.state {
|
||||||
Nothing => WaitingForScript,
|
Nothing => WaitingForScript,
|
||||||
Touching | Panning => Pinching,
|
Touching | Panning => Pinching,
|
||||||
WaitingForScript => WaitingForScript,
|
WaitingForScript => WaitingForScript,
|
||||||
DefaultPrevented => DefaultPrevented,
|
DefaultPrevented => DefaultPrevented,
|
||||||
Pinching | MultiTouch => MultiTouch,
|
Pinching | MultiTouch => MultiTouch,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
|
@ -103,21 +109,19 @@ impl TouchHandler {
|
||||||
let delta = point - old_point;
|
let delta = point - old_point;
|
||||||
|
|
||||||
if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
if delta.x.abs() > TOUCH_PAN_MIN_SCREEN_PX ||
|
||||||
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
delta.y.abs() > TOUCH_PAN_MIN_SCREEN_PX
|
||||||
{
|
{
|
||||||
self.state = Panning;
|
self.state = Panning;
|
||||||
TouchAction::Scroll(delta)
|
TouchAction::Scroll(delta)
|
||||||
} 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,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue