mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Add WebRender integration to Servo.
WebRender is an experimental GPU accelerated rendering backend for Servo. The WebRender backend can be specified by running Servo with the -w option (otherwise the default rendering backend will be used). WebRender has many bugs, and missing features - but it is usable to browse most websites - please report any WebRender specific rendering bugs you encounter!
This commit is contained in:
parent
f7f0eea470
commit
c0531c312f
75 changed files with 2869 additions and 888 deletions
|
@ -69,6 +69,9 @@ features = ["plugins"]
|
|||
[dependencies.ipc-channel]
|
||||
git = "https://github.com/servo/ipc-channel"
|
||||
|
||||
[dependencies.webrender_traits]
|
||||
git = "https://github.com/glennw/webrender_traits"
|
||||
|
||||
[target.x86_64-apple-darwin.dependencies]
|
||||
core-foundation = "0.2"
|
||||
core-graphics = "0.2"
|
||||
|
|
|
@ -45,6 +45,7 @@ use util::linked_list::prepend_from;
|
|||
use util::opts;
|
||||
use util::print_tree::PrintTree;
|
||||
use util::range::Range;
|
||||
use webrender_traits::WebGLContextId;
|
||||
|
||||
pub use style::dom::OpaqueNode;
|
||||
|
||||
|
@ -641,7 +642,10 @@ impl StackingContext {
|
|||
layer_info: layer_info,
|
||||
last_child_layer_info: None,
|
||||
};
|
||||
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
|
||||
// webrender doesn't care about layers in the display list - it's handled internally.
|
||||
if !opts::get().use_webrender {
|
||||
StackingContextLayerCreator::add_layers_to_preserve_drawing_order(&mut stacking_context);
|
||||
}
|
||||
stacking_context
|
||||
}
|
||||
|
||||
|
@ -681,7 +685,8 @@ impl StackingContext {
|
|||
// TODO(gw): This is a hack to avoid running the DL optimizer
|
||||
// on 3d transformed tiles. We should have a better solution
|
||||
// than just disabling the opts here.
|
||||
if paint_context.layer_kind == LayerKind::HasTransform {
|
||||
if paint_context.layer_kind == LayerKind::HasTransform ||
|
||||
opts::get().use_webrender { // webrender takes care of all culling via aabb tree!
|
||||
self.draw_into_context(&self.display_list,
|
||||
paint_context,
|
||||
&transform,
|
||||
|
@ -775,6 +780,9 @@ struct StackingContextLayerCreator {
|
|||
|
||||
impl StackingContextLayerCreator {
|
||||
fn new() -> StackingContextLayerCreator {
|
||||
// webrender doesn't care about layers in the display list - it's handled internally.
|
||||
debug_assert!(!opts::get().use_webrender);
|
||||
|
||||
StackingContextLayerCreator {
|
||||
display_list_for_next_layer: None,
|
||||
next_layer_info: None,
|
||||
|
@ -969,6 +977,7 @@ pub enum DisplayItem {
|
|||
SolidColorClass(Box<SolidColorDisplayItem>),
|
||||
TextClass(Box<TextDisplayItem>),
|
||||
ImageClass(Box<ImageDisplayItem>),
|
||||
WebGLClass(Box<WebGLDisplayItem>),
|
||||
BorderClass(Box<BorderDisplayItem>),
|
||||
GradientClass(Box<GradientDisplayItem>),
|
||||
LineClass(Box<LineDisplayItem>),
|
||||
|
@ -976,6 +985,7 @@ pub enum DisplayItem {
|
|||
StackingContextClass(Arc<StackingContext>),
|
||||
LayeredItemClass(Box<LayeredItem>),
|
||||
NoopClass(Box<BaseDisplayItem>),
|
||||
IframeClass(Box<IframeDisplayItem>),
|
||||
}
|
||||
|
||||
/// Information common to all display items.
|
||||
|
@ -1236,6 +1246,20 @@ pub struct ImageDisplayItem {
|
|||
pub image_rendering: image_rendering::T,
|
||||
}
|
||||
|
||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||
pub struct WebGLDisplayItem {
|
||||
pub base: BaseDisplayItem,
|
||||
#[ignore_heap_size_of = "Defined in webrender_traits"]
|
||||
pub context_id: WebGLContextId,
|
||||
}
|
||||
|
||||
|
||||
/// Paints an iframe.
|
||||
#[derive(Clone, HeapSizeOf, Deserialize, Serialize)]
|
||||
pub struct IframeDisplayItem {
|
||||
pub base: BaseDisplayItem,
|
||||
pub iframe: PipelineId,
|
||||
}
|
||||
|
||||
/// Paints a gradient.
|
||||
#[derive(Clone, Deserialize, HeapSizeOf, Serialize)]
|
||||
|
@ -1450,6 +1474,10 @@ impl DisplayItem {
|
|||
image_item.image_rendering.clone());
|
||||
}
|
||||
|
||||
DisplayItem::WebGLClass(_) => {
|
||||
panic!("Shouldn't be here, WebGL display items are created just with webrender");
|
||||
}
|
||||
|
||||
DisplayItem::BorderClass(ref border) => {
|
||||
paint_context.draw_border(&border.base.bounds,
|
||||
&border.border_widths,
|
||||
|
@ -1499,6 +1527,7 @@ impl DisplayItem {
|
|||
DisplayItem::LayeredItemClass(_) => panic!("Found layered item during drawing."),
|
||||
|
||||
DisplayItem::NoopClass(_) => { }
|
||||
DisplayItem::IframeClass(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1507,6 +1536,7 @@ impl DisplayItem {
|
|||
DisplayItem::SolidColorClass(ref solid_color) => Some(&solid_color.base),
|
||||
DisplayItem::TextClass(ref text) => Some(&text.base),
|
||||
DisplayItem::ImageClass(ref image_item) => Some(&image_item.base),
|
||||
DisplayItem::WebGLClass(ref webgl_item) => Some(&webgl_item.base),
|
||||
DisplayItem::BorderClass(ref border) => Some(&border.base),
|
||||
DisplayItem::GradientClass(ref gradient) => Some(&gradient.base),
|
||||
DisplayItem::LineClass(ref line) => Some(&line.base),
|
||||
|
@ -1514,6 +1544,7 @@ impl DisplayItem {
|
|||
DisplayItem::LayeredItemClass(ref layered_item) => layered_item.item.base(),
|
||||
DisplayItem::NoopClass(ref base_item) => Some(base_item),
|
||||
DisplayItem::StackingContextClass(_) => None,
|
||||
DisplayItem::IframeClass(ref iframe) => Some(&iframe.base),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1563,6 +1594,7 @@ impl fmt::Debug for DisplayItem {
|
|||
solid_color.color.a),
|
||||
DisplayItem::TextClass(_) => "Text".to_owned(),
|
||||
DisplayItem::ImageClass(_) => "Image".to_owned(),
|
||||
DisplayItem::WebGLClass(_) => "WebGL".to_owned(),
|
||||
DisplayItem::BorderClass(_) => "Border".to_owned(),
|
||||
DisplayItem::GradientClass(_) => "Gradient".to_owned(),
|
||||
DisplayItem::LineClass(_) => "Line".to_owned(),
|
||||
|
@ -1571,6 +1603,7 @@ impl fmt::Debug for DisplayItem {
|
|||
DisplayItem::LayeredItemClass(ref layered_item) =>
|
||||
format!("LayeredItem({:?})", layered_item.item),
|
||||
DisplayItem::NoopClass(_) => "Noop".to_owned(),
|
||||
DisplayItem::IframeClass(_) => "Iframe".to_owned(),
|
||||
},
|
||||
self.bounds(),
|
||||
)
|
||||
|
|
|
@ -23,6 +23,7 @@ use text::shaping::ShaperMethods;
|
|||
use time;
|
||||
use unicode_script::Script;
|
||||
use util::cache::HashCache;
|
||||
use webrender_traits;
|
||||
|
||||
static TEXT_SHAPING_PERFORMANCE_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
|
||||
|
||||
|
@ -100,6 +101,7 @@ pub struct Font {
|
|||
pub shaper: Option<Shaper>,
|
||||
pub shape_cache: HashCache<ShapeCacheEntry, Arc<GlyphStore>>,
|
||||
pub glyph_advance_cache: HashCache<u32, FractionalPixel>,
|
||||
pub font_key: Option<webrender_traits::FontKey>,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
|
|
|
@ -24,12 +24,19 @@ use url::Url;
|
|||
use util::prefs;
|
||||
use util::str::LowercaseString;
|
||||
use util::thread::spawn_named;
|
||||
use webrender_traits;
|
||||
|
||||
/// A list of font templates that make up a given font family.
|
||||
struct FontTemplates {
|
||||
templates: Vec<FontTemplate>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct FontTemplateInfo {
|
||||
pub font_template: Arc<FontTemplateData>,
|
||||
pub font_key: Option<webrender_traits::FontKey>,
|
||||
}
|
||||
|
||||
impl FontTemplates {
|
||||
fn new() -> FontTemplates {
|
||||
FontTemplates {
|
||||
|
@ -73,7 +80,8 @@ impl FontTemplates {
|
|||
}
|
||||
}
|
||||
|
||||
let template = FontTemplate::new(identifier, maybe_data);
|
||||
let template = FontTemplate::new(identifier,
|
||||
maybe_data);
|
||||
self.templates.push(template);
|
||||
}
|
||||
}
|
||||
|
@ -91,7 +99,7 @@ pub enum Command {
|
|||
/// Reply messages sent from the font cache thread to the FontContext caller.
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub enum Reply {
|
||||
GetFontTemplateReply(Option<Arc<FontTemplateData>>),
|
||||
GetFontTemplateReply(Option<FontTemplateInfo>),
|
||||
}
|
||||
|
||||
/// The font cache thread itself. It maintains a list of reference counted
|
||||
|
@ -104,6 +112,8 @@ struct FontCache {
|
|||
web_families: HashMap<LowercaseString, FontTemplates>,
|
||||
font_context: FontContextHandle,
|
||||
resource_thread: ResourceThread,
|
||||
webrender_api: Option<webrender_traits::RenderApi>,
|
||||
webrender_fonts: HashMap<Atom, webrender_traits::FontKey>,
|
||||
}
|
||||
|
||||
fn populate_generic_fonts() -> HashMap<FontFamily, LowercaseString> {
|
||||
|
@ -285,24 +295,46 @@ impl FontCache {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_font_template_info(&mut self, template: Arc<FontTemplateData>) -> FontTemplateInfo {
|
||||
let webrender_fonts = &mut self.webrender_fonts;
|
||||
let font_key = self.webrender_api.as_ref().map(|webrender_api| {
|
||||
*webrender_fonts.entry(template.identifier.clone()).or_insert_with(|| {
|
||||
match (template.bytes_if_in_memory(), template.native_font()) {
|
||||
(Some(bytes), _) => webrender_api.add_raw_font(bytes),
|
||||
(None, Some(native_font)) => webrender_api.add_native_font(native_font),
|
||||
(None, None) => webrender_api.add_raw_font(template.bytes().clone()),
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
FontTemplateInfo {
|
||||
font_template: template,
|
||||
font_key: font_key,
|
||||
}
|
||||
}
|
||||
|
||||
fn find_font_template(&mut self, family: &FontFamily, desc: &FontTemplateDescriptor)
|
||||
-> Option<Arc<FontTemplateData>> {
|
||||
self.find_font_in_web_family(family, desc)
|
||||
-> Option<FontTemplateInfo> {
|
||||
let template = self.find_font_in_web_family(family, desc)
|
||||
.or_else(|| {
|
||||
let transformed_family = self.transform_family(family);
|
||||
self.find_font_in_local_family(&transformed_family, desc)
|
||||
})
|
||||
});
|
||||
|
||||
template.map(|template| {
|
||||
self.get_font_template_info(template)
|
||||
})
|
||||
}
|
||||
|
||||
fn last_resort_font_template(&mut self, desc: &FontTemplateDescriptor)
|
||||
-> Arc<FontTemplateData> {
|
||||
-> FontTemplateInfo {
|
||||
let last_resort = last_resort_font_families();
|
||||
|
||||
for family in &last_resort {
|
||||
let family = LowercaseString::new(family);
|
||||
let maybe_font_in_family = self.find_font_in_local_family(&family, desc);
|
||||
if let Some(family) = maybe_font_in_family {
|
||||
return family;
|
||||
return self.get_font_template_info(family)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,7 +350,8 @@ pub struct FontCacheThread {
|
|||
}
|
||||
|
||||
impl FontCacheThread {
|
||||
pub fn new(resource_thread: ResourceThread) -> FontCacheThread {
|
||||
pub fn new(resource_thread: ResourceThread,
|
||||
webrender_api: Option<webrender_traits::RenderApi>) -> FontCacheThread {
|
||||
let (chan, port) = ipc::channel().unwrap();
|
||||
|
||||
let channel_to_self = chan.clone();
|
||||
|
@ -334,6 +367,8 @@ impl FontCacheThread {
|
|||
web_families: HashMap::new(),
|
||||
font_context: FontContextHandle::new(),
|
||||
resource_thread: resource_thread,
|
||||
webrender_api: webrender_api,
|
||||
webrender_fonts: HashMap::new(),
|
||||
};
|
||||
|
||||
cache.refresh_local_families();
|
||||
|
@ -346,7 +381,7 @@ impl FontCacheThread {
|
|||
}
|
||||
|
||||
pub fn find_font_template(&self, family: FontFamily, desc: FontTemplateDescriptor)
|
||||
-> Option<Arc<FontTemplateData>> {
|
||||
-> Option<FontTemplateInfo> {
|
||||
|
||||
let (response_chan, response_port) = ipc::channel().unwrap();
|
||||
self.chan.send(Command::GetFontTemplate(family, desc, response_chan)).unwrap();
|
||||
|
@ -361,7 +396,7 @@ impl FontCacheThread {
|
|||
}
|
||||
|
||||
pub fn last_resort_font_template(&self, desc: FontTemplateDescriptor)
|
||||
-> Arc<FontTemplateData> {
|
||||
-> FontTemplateInfo {
|
||||
|
||||
let (response_chan, response_port) = ipc::channel().unwrap();
|
||||
self.chan.send(Command::GetLastResortFontTemplate(desc, response_chan)).unwrap();
|
||||
|
|
|
@ -28,6 +28,7 @@ use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
|
|||
use string_cache::Atom;
|
||||
use style::computed_values::{font_style, font_variant};
|
||||
use util::cache::HashCache;
|
||||
use webrender_traits;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "windows"))]
|
||||
fn create_scaled_font(template: &Arc<FontTemplateData>, pt_size: Au) -> ScaledFont {
|
||||
|
@ -105,9 +106,12 @@ impl FontContext {
|
|||
}
|
||||
|
||||
/// Create a font for use in layout calculations.
|
||||
fn create_layout_font(&self, template: Arc<FontTemplateData>,
|
||||
descriptor: FontTemplateDescriptor, pt_size: Au,
|
||||
variant: font_variant::T) -> Result<Font, ()> {
|
||||
fn create_layout_font(&self,
|
||||
template: Arc<FontTemplateData>,
|
||||
descriptor: FontTemplateDescriptor,
|
||||
pt_size: Au,
|
||||
variant: font_variant::T,
|
||||
font_key: Option<webrender_traits::FontKey>) -> Result<Font, ()> {
|
||||
// TODO: (Bug #3463): Currently we only support fake small-caps
|
||||
// painting. We should also support true small-caps (where the
|
||||
// font supports it) in the future.
|
||||
|
@ -133,6 +137,7 @@ impl FontContext {
|
|||
metrics: metrics,
|
||||
shape_cache: HashCache::new(),
|
||||
glyph_advance_cache: HashCache::new(),
|
||||
font_key: font_key,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -201,14 +206,15 @@ impl FontContext {
|
|||
}
|
||||
|
||||
if !cache_hit {
|
||||
let font_template = self.font_cache_thread.find_font_template(family.clone(),
|
||||
desc.clone());
|
||||
match font_template {
|
||||
Some(font_template) => {
|
||||
let layout_font = self.create_layout_font(font_template,
|
||||
let template_info = self.font_cache_thread.find_font_template(family.clone(),
|
||||
desc.clone());
|
||||
match template_info {
|
||||
Some(template_info) => {
|
||||
let layout_font = self.create_layout_font(template_info.font_template,
|
||||
desc.clone(),
|
||||
style.font_size,
|
||||
style.font_variant);
|
||||
style.font_variant,
|
||||
template_info.font_key);
|
||||
let font = match layout_font {
|
||||
Ok(layout_font) => {
|
||||
let layout_font = Rc::new(RefCell::new(layout_font));
|
||||
|
@ -250,11 +256,12 @@ impl FontContext {
|
|||
}
|
||||
|
||||
if !cache_hit {
|
||||
let font_template = self.font_cache_thread.last_resort_font_template(desc.clone());
|
||||
let layout_font = self.create_layout_font(font_template,
|
||||
let template_info = self.font_cache_thread.last_resort_font_template(desc.clone());
|
||||
let layout_font = self.create_layout_font(template_info.font_template,
|
||||
desc.clone(),
|
||||
style.font_size,
|
||||
style.font_variant);
|
||||
style.font_variant,
|
||||
template_info.font_key);
|
||||
match layout_font {
|
||||
Ok(layout_font) => {
|
||||
let layout_font = Rc::new(RefCell::new(layout_font));
|
||||
|
|
|
@ -75,6 +75,7 @@ extern crate unicode_script;
|
|||
extern crate url;
|
||||
#[macro_use]
|
||||
extern crate util;
|
||||
extern crate webrender_traits;
|
||||
|
||||
pub use paint_context::PaintContext;
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use string_cache::Atom;
|
||||
use webrender_traits::NativeFontHandle;
|
||||
|
||||
/// Platform specific font representation for Linux.
|
||||
/// The identifier is an absolute path, and the bytes
|
||||
|
@ -36,4 +37,22 @@ impl FontTemplateData {
|
|||
identifier: identifier,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a clone of the data in this font. This may be a hugely expensive
|
||||
/// operation (depending on the platform) which performs synchronous disk I/O
|
||||
/// and should never be done lightly.
|
||||
pub fn bytes(&self) -> Vec<u8> {
|
||||
self.bytes.clone()
|
||||
}
|
||||
|
||||
/// Returns a clone of the bytes in this font if they are in memory. This function never
|
||||
/// performs disk I/O.
|
||||
pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
|
||||
Some(self.bytes())
|
||||
}
|
||||
|
||||
/// Returns the native font that underlies this font template, if applicable.
|
||||
pub fn native_font(&self) -> Option<NativeFontHandle> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,12 @@ use core_text::font::CTFont;
|
|||
use serde::de::{Error, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::borrow::ToOwned;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Mutex;
|
||||
use string_cache::Atom;
|
||||
use url::Url;
|
||||
|
||||
/// Platform specific font representation for mac.
|
||||
/// The identifier is a PostScript font name. The
|
||||
|
@ -62,6 +65,39 @@ impl FontTemplateData {
|
|||
}
|
||||
ctfont.as_ref().map(|ctfont| (*ctfont).clone())
|
||||
}
|
||||
|
||||
/// Returns a clone of the data in this font. This may be a hugely expensive
|
||||
/// operation (depending on the platform) which performs synchronous disk I/O
|
||||
/// and should never be done lightly.
|
||||
pub fn bytes(&self) -> Vec<u8> {
|
||||
match self.bytes_if_in_memory() {
|
||||
Some(font_data) => return font_data,
|
||||
None => {}
|
||||
}
|
||||
|
||||
let path = Url::parse(&*self.ctfont()
|
||||
.expect("No Core Text font available!")
|
||||
.url()
|
||||
.expect("No URL for Core Text font!")
|
||||
.get_string()
|
||||
.to_string()).expect("Couldn't parse Core Text font URL!")
|
||||
.to_file_path()
|
||||
.expect("Core Text font didn't name a path!");
|
||||
let mut bytes = Vec::new();
|
||||
File::open(path).expect("Couldn't open font file!").read_to_end(&mut bytes).unwrap();
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Returns a clone of the bytes in this font if they are in memory. This function never
|
||||
/// performs disk I/O.
|
||||
pub fn bytes_if_in_memory(&self) -> Option<Vec<u8>> {
|
||||
self.font_data.clone()
|
||||
}
|
||||
|
||||
/// Returns the native font that underlies this font template, if applicable.
|
||||
pub fn native_font(&self) -> Option<CGFont> {
|
||||
self.ctfont().map(|ctfont| ctfont.copy_to_CGFont())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
@ -13,6 +13,7 @@ use std::sync::Arc;
|
|||
use text::glyph::{CharIndex, GlyphStore};
|
||||
use util::range::Range;
|
||||
use util::vec::{Comparator, FullBinarySearchMethods};
|
||||
use webrender_traits;
|
||||
|
||||
thread_local! {
|
||||
static INDEX_OF_FIRST_GLYPH_RUN_CACHE: Cell<Option<(*const TextRun, CharIndex, usize)>> =
|
||||
|
@ -27,6 +28,7 @@ pub struct TextRun {
|
|||
pub font_template: Arc<FontTemplateData>,
|
||||
pub actual_pt_size: Au,
|
||||
pub font_metrics: FontMetrics,
|
||||
pub font_key: Option<webrender_traits::FontKey>,
|
||||
/// The glyph runs that make up this text run.
|
||||
pub glyphs: Arc<Vec<GlyphRun>>,
|
||||
pub bidi_level: u8,
|
||||
|
@ -177,6 +179,7 @@ impl<'a> TextRun {
|
|||
text: Arc::new(text),
|
||||
font_metrics: font.metrics.clone(),
|
||||
font_template: font.handle.template(),
|
||||
font_key: font.font_key,
|
||||
actual_pt_size: font.actual_pt_size,
|
||||
glyphs: Arc::new(glyphs),
|
||||
bidi_level: bidi_level,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue