/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ extern crate euclid; extern crate gleam; extern crate glutin; extern crate webrender; extern crate winit; use gleam::gl; use glutin::NotCurrent; use std::fs::File; use std::io::Read; use webrender::api::*; use webrender::api::units::*; use webrender::render_api::*; use webrender::DebugFlags; use winit::dpi::LogicalSize; struct Notifier { events_proxy: winit::EventsLoopProxy, } impl Notifier { fn new(events_proxy: winit::EventsLoopProxy) -> Notifier { Notifier { events_proxy } } } impl RenderNotifier for Notifier { fn clone(&self) -> Box { Box::new(Notifier { events_proxy: self.events_proxy.clone(), }) } fn wake_up(&self, _composite_needed: bool) { #[cfg(not(target_os = "android"))] let _ = self.events_proxy.wakeup(); } fn new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool, _render_time: Option) { self.wake_up(composite_needed); } } struct Window { events_loop: winit::EventsLoop, //TODO: share events loop? context: Option>, renderer: webrender::Renderer, name: &'static str, pipeline_id: PipelineId, document_id: DocumentId, epoch: Epoch, api: RenderApi, font_instance_key: FontInstanceKey, } impl Window { fn new(name: &'static str, clear_color: ColorF) -> Self { let events_loop = winit::EventsLoop::new(); let window_builder = winit::WindowBuilder::new() .with_title(name) .with_multitouch() .with_dimensions(LogicalSize::new(800., 600.)); let context = glutin::ContextBuilder::new() .with_gl(glutin::GlRequest::GlThenGles { opengl_version: (3, 2), opengles_version: (3, 0), }) .build_windowed(window_builder, &events_loop) .unwrap(); let context = unsafe { context.make_current().unwrap() }; let gl = match context.get_api() { glutin::Api::OpenGl => unsafe { gl::GlFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) }, glutin::Api::OpenGlEs => unsafe { gl::GlesFns::load_with(|symbol| context.get_proc_address(symbol) as *const _) }, glutin::Api::WebGl => unimplemented!(), }; let device_pixel_ratio = context.window().get_hidpi_factor() as f32; let opts = webrender::RendererOptions { device_pixel_ratio, clear_color: Some(clear_color), ..webrender::RendererOptions::default() }; let device_size = { let size = context .window() .get_inner_size() .unwrap() .to_physical(device_pixel_ratio as f64); DeviceIntSize::new(size.width as i32, size.height as i32) }; let notifier = Box::new(Notifier::new(events_loop.create_proxy())); let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap(); let mut api = sender.create_api(); let document_id = api.add_document(device_size); let epoch = Epoch(0); let pipeline_id = PipelineId(0, 0); let mut txn = Transaction::new(); let font_key = api.generate_font_key(); let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf"); txn.add_raw_font(font_key, font_bytes, 0); let font_instance_key = api.generate_font_instance_key(); txn.add_font_instance(font_instance_key, font_key, 32.0, None, None, Vec::new()); api.send_transaction(document_id, txn); Window { events_loop, context: Some(unsafe { context.make_not_current().unwrap() }), renderer, name, epoch, pipeline_id, document_id, api, font_instance_key, } } fn tick(&mut self) -> bool { let mut do_exit = false; let my_name = &self.name; let renderer = &mut self.renderer; let api = &mut self.api; self.events_loop.poll_events(|global_event| match global_event { winit::Event::WindowEvent { event, .. } => match event { winit::WindowEvent::CloseRequested | winit::WindowEvent::KeyboardInput { input: winit::KeyboardInput { virtual_keycode: Some(winit::VirtualKeyCode::Escape), .. }, .. } => { do_exit = true } winit::WindowEvent::KeyboardInput { input: winit::KeyboardInput { state: winit::ElementState::Pressed, virtual_keycode: Some(winit::VirtualKeyCode::P), .. }, .. } => { println!("set flags {}", my_name); api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG)) } _ => {} } _ => {} }); if do_exit { return true } let context = unsafe { self.context.take().unwrap().make_current().unwrap() }; let device_pixel_ratio = context.window().get_hidpi_factor() as f32; let device_size = { let size = context .window() .get_inner_size() .unwrap() .to_physical(device_pixel_ratio as f64); DeviceIntSize::new(size.width as i32, size.height as i32) }; let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio); let mut txn = Transaction::new(); let mut builder = DisplayListBuilder::new(self.pipeline_id); let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id); let bounds = LayoutRect::new(LayoutPoint::zero(), layout_size); builder.push_simple_stacking_context( bounds.origin, space_and_clip.spatial_id, PrimitiveFlags::IS_BACKFACE_VISIBLE, ); builder.push_rect( &CommonItemProperties::new( LayoutRect::new( LayoutPoint::new(100.0, 200.0), LayoutSize::new(100.0, 200.0), ), space_and_clip, ), LayoutRect::new( LayoutPoint::new(100.0, 200.0), LayoutSize::new(100.0, 200.0), ), ColorF::new(0.0, 1.0, 0.0, 1.0)); let text_bounds = LayoutRect::new( LayoutPoint::new(100.0, 50.0), LayoutSize::new(700.0, 200.0) ); let glyphs = vec![ GlyphInstance { index: 48, point: LayoutPoint::new(100.0, 100.0), }, GlyphInstance { index: 68, point: LayoutPoint::new(150.0, 100.0), }, GlyphInstance { index: 80, point: LayoutPoint::new(200.0, 100.0), }, GlyphInstance { index: 82, point: LayoutPoint::new(250.0, 100.0), }, GlyphInstance { index: 81, point: LayoutPoint::new(300.0, 100.0), }, GlyphInstance { index: 3, point: LayoutPoint::new(350.0, 100.0), }, GlyphInstance { index: 86, point: LayoutPoint::new(400.0, 100.0), }, GlyphInstance { index: 79, point: LayoutPoint::new(450.0, 100.0), }, GlyphInstance { index: 72, point: LayoutPoint::new(500.0, 100.0), }, GlyphInstance { index: 83, point: LayoutPoint::new(550.0, 100.0), }, GlyphInstance { index: 87, point: LayoutPoint::new(600.0, 100.0), }, GlyphInstance { index: 17, point: LayoutPoint::new(650.0, 100.0), }, ]; builder.push_text( &CommonItemProperties::new( text_bounds, space_and_clip, ), text_bounds, &glyphs, self.font_instance_key, ColorF::new(1.0, 1.0, 0.0, 1.0), None, ); builder.pop_stacking_context(); txn.set_display_list( self.epoch, None, layout_size, builder.finalize(), true, ); txn.set_root_pipeline(self.pipeline_id); txn.generate_frame(0); api.send_transaction(self.document_id, txn); renderer.update(); renderer.render(device_size, 0).unwrap(); context.swap_buffers().ok(); self.context = Some(unsafe { context.make_not_current().unwrap() }); false } fn deinit(self) { self.renderer.deinit(); } } fn main() { let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0)); let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0)); loop { if win1.tick() { break; } if win2.tick() { break; } } win1.deinit(); win2.deinit(); } fn load_file(name: &str) -> Vec { let mut file = File::open(name).unwrap(); let mut buffer = vec![]; file.read_to_end(&mut buffer).unwrap(); buffer }