зеркало из https://github.com/mozilla/gecko-dev.git
328 строки
9.9 KiB
Rust
328 строки
9.9 KiB
Rust
/* 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<dyn RenderNotifier> {
|
|
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<u64>) {
|
|
self.wake_up(composite_needed);
|
|
}
|
|
}
|
|
|
|
struct Window {
|
|
events_loop: winit::EventsLoop, //TODO: share events loop?
|
|
context: Option<glutin::WindowedContext<NotCurrent>>,
|
|
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<u8> {
|
|
let mut file = File::open(name).unwrap();
|
|
let mut buffer = vec![];
|
|
file.read_to_end(&mut buffer).unwrap();
|
|
buffer
|
|
}
|