Backed out 5 changesets (bug 1866429, bug 1866421, bug 1865046, bug 1866462, bug...
[gecko.git] / gfx / wr / examples / multiwindow.rs
blob2f2ff02b462a552890759a8a0570560ae928b125
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 extern crate euclid;
6 extern crate gleam;
7 extern crate glutin;
8 extern crate webrender;
9 extern crate winit;
11 use gleam::gl;
12 use glutin::NotCurrent;
13 use std::fs::File;
14 use std::io::Read;
15 use webrender::api::*;
16 use webrender::api::units::*;
17 use webrender::render_api::*;
18 use webrender::DebugFlags;
19 use winit::dpi::LogicalSize;
20 use winit::platform::run_return::EventLoopExtRunReturn;
22 struct Notifier {
23     events_proxy: winit::event_loop::EventLoopProxy<()>,
26 impl Notifier {
27     fn new(events_proxy: winit::event_loop::EventLoopProxy<()>) -> Notifier {
28         Notifier { events_proxy }
29     }
32 impl RenderNotifier for Notifier {
33     fn clone(&self) -> Box<dyn RenderNotifier> {
34         Box::new(Notifier {
35             events_proxy: self.events_proxy.clone(),
36         })
37     }
39     fn wake_up(&self, _composite_needed: bool) {
40         #[cfg(not(target_os = "android"))]
41         let _ = self.events_proxy.send_event(());
42     }
44     fn new_frame_ready(&self,
45                        _: DocumentId,
46                        _scrolled: bool,
47                        composite_needed: bool,
48                        _: FramePublishId) {
49         self.wake_up(composite_needed);
50     }
53 struct Window {
54     events_loop: winit::event_loop::EventLoop<()>, //TODO: share events loop?
55     context: Option<glutin::WindowedContext<NotCurrent>>,
56     renderer: webrender::Renderer,
57     name: &'static str,
58     pipeline_id: PipelineId,
59     document_id: DocumentId,
60     epoch: Epoch,
61     api: RenderApi,
62     font_instance_key: FontInstanceKey,
65 impl Window {
66     fn new(name: &'static str, clear_color: ColorF) -> Self {
67         let events_loop = winit::event_loop::EventLoop::new();
68         let window_builder = winit::window::WindowBuilder::new()
69             .with_title(name)
70             .with_inner_size(LogicalSize::new(800. as f64, 600. as f64));
71         let context = glutin::ContextBuilder::new()
72             .with_gl(glutin::GlRequest::GlThenGles {
73                 opengl_version: (3, 2),
74                 opengles_version: (3, 0),
75             })
76             .build_windowed(window_builder, &events_loop)
77             .unwrap();
79         let context = unsafe { context.make_current().unwrap() };
81         let gl = match context.get_api() {
82             glutin::Api::OpenGl => unsafe {
83                 gl::GlFns::load_with(|symbol| context.get_proc_address(symbol) as *const _)
84             },
85             glutin::Api::OpenGlEs => unsafe {
86                 gl::GlesFns::load_with(|symbol| context.get_proc_address(symbol) as *const _)
87             },
88             glutin::Api::WebGl => unimplemented!(),
89         };
91         let opts = webrender::WebRenderOptions {
92             clear_color,
93             ..webrender::WebRenderOptions::default()
94         };
96         let device_size = {
97             let size = context
98                 .window()
99                 .inner_size();
100             DeviceIntSize::new(size.width as i32, size.height as i32)
101         };
102         let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
103         let (renderer, sender) = webrender::create_webrender_instance(gl.clone(), notifier, opts, None).unwrap();
104         let mut api = sender.create_api();
105         let document_id = api.add_document(device_size);
107         let epoch = Epoch(0);
108         let pipeline_id = PipelineId(0, 0);
109         let mut txn = Transaction::new();
111         let font_key = api.generate_font_key();
112         let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
113         txn.add_raw_font(font_key, font_bytes, 0);
115         let font_instance_key = api.generate_font_instance_key();
116         txn.add_font_instance(font_instance_key, font_key, 32.0, None, None, Vec::new());
118         api.send_transaction(document_id, txn);
120         Window {
121             events_loop,
122             context: Some(unsafe { context.make_not_current().unwrap() }),
123             renderer,
124             name,
125             epoch,
126             pipeline_id,
127             document_id,
128             api,
129             font_instance_key,
130         }
131     }
133     fn tick(&mut self) -> bool {
134         let mut do_exit = false;
135         let my_name = &self.name;
136         let renderer = &mut self.renderer;
137         let api = &mut self.api;
139         self.events_loop.run_return(|global_event, _elwt, control_flow| {
140             *control_flow = winit::event_loop::ControlFlow::Exit;
141             match global_event {
142                 winit::event::Event::WindowEvent { event, .. } => match event {
143                     winit::event::WindowEvent::CloseRequested |
144                     winit::event::WindowEvent::KeyboardInput {
145                         input: winit::event::KeyboardInput {
146                             virtual_keycode: Some(winit::event::VirtualKeyCode::Escape),
147                             ..
148                         },
149                         ..
150                     } => {
151                         do_exit = true
152                     }
153                     winit::event::WindowEvent::KeyboardInput {
154                         input: winit::event::KeyboardInput {
155                             state: winit::event::ElementState::Pressed,
156                             virtual_keycode: Some(winit::event::VirtualKeyCode::P),
157                             ..
158                         },
159                         ..
160                     } => {
161                         println!("set flags {}", my_name);
162                         api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG))
163                     }
164                     _ => {}
165                 }
166                 _ => {}
167             }
168         });
169         if do_exit {
170             return true
171         }
173         let context = unsafe { self.context.take().unwrap().make_current().unwrap() };
174         let device_pixel_ratio = context.window().scale_factor() as f32;
175         let device_size = {
176             let size = context
177                 .window()
178                 .inner_size();
179             DeviceIntSize::new(size.width as i32, size.height as i32)
180         };
181         let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
182         let mut txn = Transaction::new();
183         let mut builder = DisplayListBuilder::new(self.pipeline_id);
184         let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id);
185         builder.begin();
187         let bounds = LayoutRect::from_size(layout_size);
188         builder.push_simple_stacking_context(
189             bounds.min,
190             space_and_clip.spatial_id,
191             PrimitiveFlags::IS_BACKFACE_VISIBLE,
192         );
194         builder.push_rect(
195             &CommonItemProperties::new(
196                 LayoutRect::from_origin_and_size(
197                     LayoutPoint::new(100.0, 200.0),
198                     LayoutSize::new(100.0, 200.0),
199                 ),
200                 space_and_clip,
201             ),
202             LayoutRect::from_origin_and_size(
203                 LayoutPoint::new(100.0, 200.0),
204                 LayoutSize::new(100.0, 200.0),
205             ),
206             ColorF::new(0.0, 1.0, 0.0, 1.0));
208         let text_bounds = LayoutRect::from_origin_and_size(
209             LayoutPoint::new(100.0, 50.0),
210             LayoutSize::new(700.0, 200.0)
211         );
212         let glyphs = vec![
213             GlyphInstance {
214                 index: 48,
215                 point: LayoutPoint::new(100.0, 100.0),
216             },
217             GlyphInstance {
218                 index: 68,
219                 point: LayoutPoint::new(150.0, 100.0),
220             },
221             GlyphInstance {
222                 index: 80,
223                 point: LayoutPoint::new(200.0, 100.0),
224             },
225             GlyphInstance {
226                 index: 82,
227                 point: LayoutPoint::new(250.0, 100.0),
228             },
229             GlyphInstance {
230                 index: 81,
231                 point: LayoutPoint::new(300.0, 100.0),
232             },
233             GlyphInstance {
234                 index: 3,
235                 point: LayoutPoint::new(350.0, 100.0),
236             },
237             GlyphInstance {
238                 index: 86,
239                 point: LayoutPoint::new(400.0, 100.0),
240             },
241             GlyphInstance {
242                 index: 79,
243                 point: LayoutPoint::new(450.0, 100.0),
244             },
245             GlyphInstance {
246                 index: 72,
247                 point: LayoutPoint::new(500.0, 100.0),
248             },
249             GlyphInstance {
250                 index: 83,
251                 point: LayoutPoint::new(550.0, 100.0),
252             },
253             GlyphInstance {
254                 index: 87,
255                 point: LayoutPoint::new(600.0, 100.0),
256             },
257             GlyphInstance {
258                 index: 17,
259                 point: LayoutPoint::new(650.0, 100.0),
260             },
261         ];
263         builder.push_text(
264             &CommonItemProperties::new(
265                 text_bounds,
266                 space_and_clip,
267             ),
268             text_bounds,
269             &glyphs,
270             self.font_instance_key,
271             ColorF::new(1.0, 1.0, 0.0, 1.0),
272             None,
273         );
275         builder.pop_stacking_context();
277         txn.set_display_list(
278             self.epoch,
279             builder.end(),
280         );
281         txn.set_root_pipeline(self.pipeline_id);
282         txn.generate_frame(0, RenderReasons::empty());
283         api.send_transaction(self.document_id, txn);
285         renderer.update();
286         renderer.render(device_size, 0).unwrap();
287         context.swap_buffers().ok();
289         self.context = Some(unsafe { context.make_not_current().unwrap() });
291         false
292     }
294     fn deinit(self) {
295         self.renderer.deinit();
296     }
299 fn main() {
300     let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0));
301     let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0));
303     loop {
304         if win1.tick() {
305             break;
306         }
307         if win2.tick() {
308             break;
309         }
310     }
312     win1.deinit();
313     win2.deinit();
316 fn load_file(name: &str) -> Vec<u8> {
317     let mut file = File::open(name).unwrap();
318     let mut buffer = vec![];
319     file.read_to_end(&mut buffer).unwrap();
320     buffer