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