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
21 struct Notifier {
22 events_proxy: winit::EventsLoopProxy,
23 }
24
25 impl Notifier {
new(events_proxy: winit::EventsLoopProxy) -> Notifier26 fn new(events_proxy: winit::EventsLoopProxy) -> Notifier {
27 Notifier { events_proxy }
28 }
29 }
30
31 impl RenderNotifier for Notifier {
clone(&self) -> Box<dyn RenderNotifier>32 fn clone(&self) -> Box<dyn RenderNotifier> {
33 Box::new(Notifier {
34 events_proxy: self.events_proxy.clone(),
35 })
36 }
37
wake_up(&self, _composite_needed: bool)38 fn wake_up(&self, _composite_needed: bool) {
39 #[cfg(not(target_os = "android"))]
40 let _ = self.events_proxy.wakeup();
41 }
42
new_frame_ready(&self, _: DocumentId, _scrolled: bool, composite_needed: bool, _render_time: Option<u64>)43 fn new_frame_ready(&self,
44 _: DocumentId,
45 _scrolled: bool,
46 composite_needed: bool,
47 _render_time: Option<u64>) {
48 self.wake_up(composite_needed);
49 }
50 }
51
52 struct Window {
53 events_loop: winit::EventsLoop, //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 {
new(name: &'static str, clear_color: ColorF) -> Self65 fn new(name: &'static str, clear_color: ColorF) -> Self {
66 let events_loop = winit::EventsLoop::new();
67 let window_builder = winit::WindowBuilder::new()
68 .with_title(name)
69 .with_multitouch()
70 .with_dimensions(LogicalSize::new(800., 600.));
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();
78
79 let context = unsafe { context.make_current().unwrap() };
80
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 };
90
91 let device_pixel_ratio = context.window().get_hidpi_factor() as f32;
92
93 let opts = webrender::RendererOptions {
94 clear_color,
95 ..webrender::RendererOptions::default()
96 };
97
98 let device_size = {
99 let size = context
100 .window()
101 .get_inner_size()
102 .unwrap()
103 .to_physical(device_pixel_ratio as f64);
104 DeviceIntSize::new(size.width as i32, size.height as i32)
105 };
106 let notifier = Box::new(Notifier::new(events_loop.create_proxy()));
107 let (renderer, sender) = webrender::Renderer::new(gl.clone(), notifier, opts, None).unwrap();
108 let mut api = sender.create_api();
109 let document_id = api.add_document(device_size);
110
111 let epoch = Epoch(0);
112 let pipeline_id = PipelineId(0, 0);
113 let mut txn = Transaction::new();
114
115 let font_key = api.generate_font_key();
116 let font_bytes = load_file("../wrench/reftests/text/FreeSans.ttf");
117 txn.add_raw_font(font_key, font_bytes, 0);
118
119 let font_instance_key = api.generate_font_instance_key();
120 txn.add_font_instance(font_instance_key, font_key, 32.0, None, None, Vec::new());
121
122 api.send_transaction(document_id, txn);
123
124 Window {
125 events_loop,
126 context: Some(unsafe { context.make_not_current().unwrap() }),
127 renderer,
128 name,
129 epoch,
130 pipeline_id,
131 document_id,
132 api,
133 font_instance_key,
134 }
135 }
136
tick(&mut self) -> bool137 fn tick(&mut self) -> bool {
138 let mut do_exit = false;
139 let my_name = &self.name;
140 let renderer = &mut self.renderer;
141 let api = &mut self.api;
142
143 self.events_loop.poll_events(|global_event| match global_event {
144 winit::Event::WindowEvent { event, .. } => match event {
145 winit::WindowEvent::CloseRequested |
146 winit::WindowEvent::KeyboardInput {
147 input: winit::KeyboardInput {
148 virtual_keycode: Some(winit::VirtualKeyCode::Escape),
149 ..
150 },
151 ..
152 } => {
153 do_exit = true
154 }
155 winit::WindowEvent::KeyboardInput {
156 input: winit::KeyboardInput {
157 state: winit::ElementState::Pressed,
158 virtual_keycode: Some(winit::VirtualKeyCode::P),
159 ..
160 },
161 ..
162 } => {
163 println!("set flags {}", my_name);
164 api.send_debug_cmd(DebugCommand::SetFlags(DebugFlags::PROFILER_DBG))
165 }
166 _ => {}
167 }
168 _ => {}
169 });
170 if do_exit {
171 return true
172 }
173
174 let context = unsafe { self.context.take().unwrap().make_current().unwrap() };
175 let device_pixel_ratio = context.window().get_hidpi_factor() as f32;
176 let device_size = {
177 let size = context
178 .window()
179 .get_inner_size()
180 .unwrap()
181 .to_physical(device_pixel_ratio as f64);
182 DeviceIntSize::new(size.width as i32, size.height as i32)
183 };
184 let layout_size = device_size.to_f32() / euclid::Scale::new(device_pixel_ratio);
185 let mut txn = Transaction::new();
186 let mut builder = DisplayListBuilder::new(self.pipeline_id);
187 let space_and_clip = SpaceAndClipInfo::root_scroll(self.pipeline_id);
188
189 let bounds = LayoutRect::from_size(layout_size);
190 builder.push_simple_stacking_context(
191 bounds.min,
192 space_and_clip.spatial_id,
193 PrimitiveFlags::IS_BACKFACE_VISIBLE,
194 );
195
196 builder.push_rect(
197 &CommonItemProperties::new(
198 LayoutRect::from_origin_and_size(
199 LayoutPoint::new(100.0, 200.0),
200 LayoutSize::new(100.0, 200.0),
201 ),
202 space_and_clip,
203 ),
204 LayoutRect::from_origin_and_size(
205 LayoutPoint::new(100.0, 200.0),
206 LayoutSize::new(100.0, 200.0),
207 ),
208 ColorF::new(0.0, 1.0, 0.0, 1.0));
209
210 let text_bounds = LayoutRect::from_origin_and_size(
211 LayoutPoint::new(100.0, 50.0),
212 LayoutSize::new(700.0, 200.0)
213 );
214 let glyphs = vec![
215 GlyphInstance {
216 index: 48,
217 point: LayoutPoint::new(100.0, 100.0),
218 },
219 GlyphInstance {
220 index: 68,
221 point: LayoutPoint::new(150.0, 100.0),
222 },
223 GlyphInstance {
224 index: 80,
225 point: LayoutPoint::new(200.0, 100.0),
226 },
227 GlyphInstance {
228 index: 82,
229 point: LayoutPoint::new(250.0, 100.0),
230 },
231 GlyphInstance {
232 index: 81,
233 point: LayoutPoint::new(300.0, 100.0),
234 },
235 GlyphInstance {
236 index: 3,
237 point: LayoutPoint::new(350.0, 100.0),
238 },
239 GlyphInstance {
240 index: 86,
241 point: LayoutPoint::new(400.0, 100.0),
242 },
243 GlyphInstance {
244 index: 79,
245 point: LayoutPoint::new(450.0, 100.0),
246 },
247 GlyphInstance {
248 index: 72,
249 point: LayoutPoint::new(500.0, 100.0),
250 },
251 GlyphInstance {
252 index: 83,
253 point: LayoutPoint::new(550.0, 100.0),
254 },
255 GlyphInstance {
256 index: 87,
257 point: LayoutPoint::new(600.0, 100.0),
258 },
259 GlyphInstance {
260 index: 17,
261 point: LayoutPoint::new(650.0, 100.0),
262 },
263 ];
264
265 builder.push_text(
266 &CommonItemProperties::new(
267 text_bounds,
268 space_and_clip,
269 ),
270 text_bounds,
271 &glyphs,
272 self.font_instance_key,
273 ColorF::new(1.0, 1.0, 0.0, 1.0),
274 None,
275 );
276
277 builder.pop_stacking_context();
278
279 txn.set_display_list(
280 self.epoch,
281 None,
282 layout_size,
283 builder.finalize(),
284 true,
285 );
286 txn.set_root_pipeline(self.pipeline_id);
287 txn.generate_frame(0);
288 api.send_transaction(self.document_id, txn);
289
290 renderer.update();
291 renderer.render(device_size, 0).unwrap();
292 context.swap_buffers().ok();
293
294 self.context = Some(unsafe { context.make_not_current().unwrap() });
295
296 false
297 }
298
deinit(self)299 fn deinit(self) {
300 self.renderer.deinit();
301 }
302 }
303
main()304 fn main() {
305 let mut win1 = Window::new("window1", ColorF::new(0.3, 0.0, 0.0, 1.0));
306 let mut win2 = Window::new("window2", ColorF::new(0.0, 0.3, 0.0, 1.0));
307
308 loop {
309 if win1.tick() {
310 break;
311 }
312 if win2.tick() {
313 break;
314 }
315 }
316
317 win1.deinit();
318 win2.deinit();
319 }
320
load_file(name: &str) -> Vec<u8>321 fn load_file(name: &str) -> Vec<u8> {
322 let mut file = File::open(name).unwrap();
323 let mut buffer = vec![];
324 file.read_to_end(&mut buffer).unwrap();
325 buffer
326 }
327