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 app_units;
6 extern crate euclid;
7 extern crate gleam;
8 extern crate glutin;
9 extern crate webrender;
10 
11 use app_units::Au;
12 use gleam::gl;
13 use glutin::GlContext;
14 use std::fs::File;
15 use std::io::Read;
16 use webrender::api::*;
17 
18 struct Notifier {
19     events_proxy: glutin::EventsLoopProxy,
20 }
21 
22 impl Notifier {
new(events_proxy: glutin::EventsLoopProxy) -> Notifier23     fn new(events_proxy: glutin::EventsLoopProxy) -> Notifier {
24         Notifier { events_proxy }
25     }
26 }
27 
28 impl RenderNotifier for Notifier {
clone(&self) -> Box<RenderNotifier>29     fn clone(&self) -> Box<RenderNotifier> {
30         Box::new(Notifier {
31             events_proxy: self.events_proxy.clone(),
32         })
33     }
34 
wake_up(&self)35     fn wake_up(&self) {
36         #[cfg(not(target_os = "android"))]
37         let _ = self.events_proxy.wakeup();
38     }
39 
new_document_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool)40     fn new_document_ready(&self, _: DocumentId, _scrolled: bool, _composite_needed: bool) {
41         self.wake_up();
42     }
43 }
44 
45 struct Window {
46     events_loop: glutin::EventsLoop, //TODO: share events loop?
47     window: glutin::GlWindow,
48     renderer: webrender::Renderer,
49     name: &'static str,
50     pipeline_id: PipelineId,
51     document_id: DocumentId,
52     epoch: Epoch,
53     api: RenderApi,
54     font_instance_key: FontInstanceKey,
55 }
56 
57 impl Window {
new(name: &'static str, clear_color: ColorF) -> Self58     fn new(name: &'static str, clear_color: ColorF) -> Self {
59         let events_loop = glutin::EventsLoop::new();
60         let context_builder = glutin::ContextBuilder::new()
61             .with_gl(glutin::GlRequest::GlThenGles {
62                 opengl_version: (3, 2),
63                 opengles_version: (3, 0),
64             });
65         let window_builder = glutin::WindowBuilder::new()
66             .with_title(name)
67             .with_multitouch()
68             .with_dimensions(800, 600);
69         let window = glutin::GlWindow::new(window_builder, context_builder, &events_loop)
70             .unwrap();
71 
72         unsafe {
73             window.make_current().ok();
74         }
75 
76         let gl = match window.get_api() {
77             glutin::Api::OpenGl => unsafe {
78                 gl::GlFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
79             },
80             glutin::Api::OpenGlEs => unsafe {
81                 gl::GlesFns::load_with(|symbol| window.get_proc_address(symbol) as *const _)
82             },
83             glutin::Api::WebGl => unimplemented!(),
84         };
85 
86         let device_pixel_ratio = window.hidpi_factor();
87 
88         let opts = webrender::RendererOptions {
89             debug: true,
90             device_pixel_ratio,
91             clear_color: Some(clear_color),
92             ..webrender::RendererOptions::default()
93         };
94 
95         let framebuffer_size = {
96             let (width, height) = window.get_inner_size().unwrap();
97             DeviceUintSize::new(width, height)
98         };
99         let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
100         let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts).unwrap();
101         let api = sender.create_api();
102         let document_id = api.add_document(framebuffer_size, 0);
103 
104         let epoch = Epoch(0);
105         let pipeline_id = PipelineId(0, 0);
106         let mut resources = ResourceUpdates::new();
107 
108         let font_key = api.generate_font_key();
109         let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
110         resources.add_raw_font(font_key, font_bytes, 0);
111 
112         let font_instance_key = api.generate_font_instance_key();
113         resources.add_font_instance(font_instance_key, font_key, Au::from_px(32), None, None, Vec::new());
114 
115         let mut txn = Transaction::new();
116         txn.update_resources(resources);
117         api.send_transaction(document_id, txn);
118 
119         Window {
120             events_loop,
121             window,
122             renderer,
123             name,
124             epoch,
125             pipeline_id,
126             document_id,
127             api,
128             font_instance_key,
129         }
130     }
131 
tick(&mut self) -> bool132     fn tick(&mut self) -> bool {
133         unsafe {
134             self.window.make_current().ok();
135         }
136         let mut do_exit = false;
137         let my_name = &self.name;
138         let renderer = &mut self.renderer;
139 
140         self.events_loop.poll_events(|global_event| match global_event {
141             glutin::Event::WindowEvent { event, .. } => match event {
142                 glutin::WindowEvent::Closed |
143                 glutin::WindowEvent::KeyboardInput {
144                     input: glutin::KeyboardInput {
145                         virtual_keycode: Some(glutin::VirtualKeyCode::Escape),
146                         ..
147                     },
148                     ..
149                 } => {
150                     do_exit = true
151                 }
152                 glutin::WindowEvent::KeyboardInput {
153                     input: glutin::KeyboardInput {
154                         state: glutin::ElementState::Pressed,
155                         virtual_keycode: Some(glutin::VirtualKeyCode::P),
156                         ..
157                     },
158                     ..
159                 } => {
160                     println!("toggle flags {}", my_name);
161                     renderer.toggle_debug_flags(webrender::DebugFlags::PROFILER_DBG);
162                 }
163                 _ => {}
164             }
165             _ => {}
166         });
167         if do_exit {
168             return true
169         }
170 
171         let framebuffer_size = {
172             let (width, height) = self.window.get_inner_size().unwrap();
173             DeviceUintSize::new(width, height)
174         };
175         let device_pixel_ratio = self.window.hidpi_factor();
176         let layout_size = framebuffer_size.to_f32() / euclid::TypedScale::new(device_pixel_ratio);
177         let mut txn = Transaction::new();
178         let mut builder = DisplayListBuilder::new(self.pipeline_id, layout_size);
179 
180         let bounds = LayoutRect::new(LayoutPoint::zero(), builder.content_size());
181         let info = LayoutPrimitiveInfo::new(bounds);
182         builder.push_stacking_context(
183             &info,
184             ScrollPolicy::Scrollable,
185             None,
186             TransformStyle::Flat,
187             None,
188             MixBlendMode::Normal,
189             Vec::new(),
190         );
191 
192         let info = LayoutPrimitiveInfo::new(LayoutRect::new(
193             LayoutPoint::new(100.0, 100.0),
194             LayoutSize::new(100.0, 200.0)
195         ));
196         builder.push_rect(&info, ColorF::new(0.0, 1.0, 0.0, 1.0));
197 
198         let text_bounds = LayoutRect::new(
199             LayoutPoint::new(100.0, 50.0),
200             LayoutSize::new(700.0, 200.0)
201         );
202         let glyphs = vec![
203             GlyphInstance {
204                 index: 48,
205                 point: LayoutPoint::new(100.0, 100.0),
206             },
207             GlyphInstance {
208                 index: 68,
209                 point: LayoutPoint::new(150.0, 100.0),
210             },
211             GlyphInstance {
212                 index: 80,
213                 point: LayoutPoint::new(200.0, 100.0),
214             },
215             GlyphInstance {
216                 index: 82,
217                 point: LayoutPoint::new(250.0, 100.0),
218             },
219             GlyphInstance {
220                 index: 81,
221                 point: LayoutPoint::new(300.0, 100.0),
222             },
223             GlyphInstance {
224                 index: 3,
225                 point: LayoutPoint::new(350.0, 100.0),
226             },
227             GlyphInstance {
228                 index: 86,
229                 point: LayoutPoint::new(400.0, 100.0),
230             },
231             GlyphInstance {
232                 index: 79,
233                 point: LayoutPoint::new(450.0, 100.0),
234             },
235             GlyphInstance {
236                 index: 72,
237                 point: LayoutPoint::new(500.0, 100.0),
238             },
239             GlyphInstance {
240                 index: 83,
241                 point: LayoutPoint::new(550.0, 100.0),
242             },
243             GlyphInstance {
244                 index: 87,
245                 point: LayoutPoint::new(600.0, 100.0),
246             },
247             GlyphInstance {
248                 index: 17,
249                 point: LayoutPoint::new(650.0, 100.0),
250             },
251         ];
252 
253         let info = LayoutPrimitiveInfo::new(text_bounds);
254         builder.push_text(
255             &info,
256             &glyphs,
257             self.font_instance_key,
258             ColorF::new(1.0, 1.0, 0.0, 1.0),
259             None,
260         );
261 
262         builder.pop_stacking_context();
263 
264         txn.set_display_list(
265             self.epoch,
266             None,
267             layout_size,
268             builder.finalize(),
269             true,
270         );
271         txn.set_root_pipeline(self.pipeline_id);
272         txn.generate_frame();
273         self.api.send_transaction(self.document_id, txn);
274 
275         renderer.update();
276         renderer.render(framebuffer_size).unwrap();
277         self.window.swap_buffers().ok();
278 
279         false
280     }
281 
deinit(self)282     fn deinit(self) {
283         self.renderer.deinit();
284     }
285 }
286 
main()287 fn main() {
288     let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0));
289     let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0));
290 
291     loop {
292         if win1.tick() {
293             break;
294         }
295         if win2.tick() {
296             break;
297         }
298     }
299 
300     win1.deinit();
301     win2.deinit();
302 }
303 
load_file(name: &str) -> Vec<u8>304 fn load_file(name: &str) -> Vec<u8> {
305     let mut file = File::open(name).unwrap();
306     let mut buffer = vec![];
307     file.read_to_end(&mut buffer).unwrap();
308     buffer
309 }
310