From e993346289e624494c070cd0fa604d0227fc2427 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 8 Dec 2017 01:29:16 -0500 Subject: [PATCH] determine whether a font has bitmaps only when fetching glyphs --- Cargo.lock | 8 +- webrender/Cargo.toml | 2 +- webrender/res/ps_text_run.glsl | 17 +++- webrender/src/glyph_rasterizer.rs | 30 ++++--- webrender/src/platform/macos/font.rs | 64 +++++++------- webrender/src/platform/unix/font.rs | 53 ++++++------ webrender/src/platform/windows/font.rs | 110 ++++++++++++++----------- webrender/src/prim_store.rs | 3 +- webrender/src/renderer.rs | 5 +- webrender/src/resource_cache.rs | 8 +- webrender/src/tiling.rs | 34 ++++---- webrender_api/Cargo.toml | 2 +- webrender_api/src/font.rs | 4 +- 13 files changed, 176 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2734156364..e93ed9ae34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,7 +995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "webrender" -version = "0.56.0" +version = "0.56.1" dependencies = [ "angle 0.5.0 (git+https://github.com/servo/angle?branch=servo)", "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1026,13 +1026,13 @@ dependencies = [ "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "thread_profiler 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "webrender_api 0.56.0", + "webrender_api 0.56.1", "ws 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webrender_api" -version = "0.56.0" +version = "0.56.1" dependencies = [ "app_units 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "bincode 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1083,7 +1083,7 @@ dependencies = [ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-glutin 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "webrender 0.56.0", + "webrender 0.56.1", "yaml-rust 0.3.4 (git+https://github.com/vvuk/yaml-rust)", ] diff --git a/webrender/Cargo.toml b/webrender/Cargo.toml index 0b492bce74..2f8d010bd9 100644 --- a/webrender/Cargo.toml +++ b/webrender/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webrender" -version = "0.56.0" +version = "0.56.1" authors = ["Glenn Watson "] license = "MPL-2.0" repository = "https://github.com/servo/webrender" diff --git a/webrender/res/ps_text_run.glsl b/webrender/res/ps_text_run.glsl index bead00fe07..83e8605583 100644 --- a/webrender/res/ps_text_run.glsl +++ b/webrender/res/ps_text_run.glsl @@ -17,7 +17,8 @@ flat varying vec4 vUvBorder; #define MODE_SUBPX_BG_PASS0 4 #define MODE_SUBPX_BG_PASS1 5 #define MODE_SUBPX_BG_PASS2 6 -#define MODE_COLOR_BITMAP 7 +#define MODE_BITMAP 7 +#define MODE_COLOR_BITMAP 8 VertexInfo write_text_vertex(vec2 clamped_local_pos, RectWithSize local_clip_rect, @@ -59,9 +60,20 @@ void main(void) { int glyph_index = prim.user_data0; int resource_address = prim.user_data1; + int subpx_dir; + switch (uMode) { + case MODE_BITMAP: + case MODE_COLOR_BITMAP: + subpx_dir = SUBPX_DIR_NONE; + break; + default: + subpx_dir = text.subpx_dir; + break; + } + Glyph glyph = fetch_glyph(prim.specific_prim_address, glyph_index, - text.subpx_dir); + subpx_dir); GlyphResource res = fetch_glyph_resource(resource_address); #ifdef WR_FEATURE_GLYPH_TRANSFORM @@ -125,6 +137,7 @@ void main(void) { case MODE_ALPHA: case MODE_SUBPX_PASS1: case MODE_SUBPX_BG_PASS2: + case MODE_BITMAP: vColor = text.color; break; case MODE_SUBPX_CONST_COLOR: diff --git a/webrender/src/glyph_rasterizer.rs b/webrender/src/glyph_rasterizer.rs index d6305ff569..3de945ecff 100644 --- a/webrender/src/glyph_rasterizer.rs +++ b/webrender/src/glyph_rasterizer.rs @@ -180,17 +180,19 @@ impl FontInstance { } } - pub fn get_glyph_format(&self, color_bitmaps: bool) -> GlyphFormat { + pub fn get_alpha_glyph_format(&self) -> GlyphFormat { + if self.transform.is_identity() { GlyphFormat::Alpha } else { GlyphFormat::TransformedAlpha } + } + + pub fn get_subpixel_glyph_format(&self) -> GlyphFormat { + if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel } + } + + #[allow(dead_code)] + pub fn get_glyph_format(&self) -> GlyphFormat { match self.render_mode { - FontRenderMode::Mono | FontRenderMode::Alpha => { - if self.transform.is_identity() { GlyphFormat::Alpha } else { GlyphFormat::TransformedAlpha } - } - FontRenderMode::Subpixel => { - if self.transform.is_identity() { GlyphFormat::Subpixel } else { GlyphFormat::TransformedSubpixel } - } - FontRenderMode::Bitmap => { - if color_bitmaps { GlyphFormat::ColorBitmap } else { GlyphFormat::Alpha } - } + FontRenderMode::Mono | FontRenderMode::Alpha => self.get_alpha_glyph_format(), + FontRenderMode::Subpixel => self.get_subpixel_glyph_format(), } } @@ -209,11 +211,13 @@ impl FontInstance { } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] +#[allow(dead_code)] pub enum GlyphFormat { Alpha, TransformedAlpha, Subpixel, TransformedSubpixel, + Bitmap, ColorBitmap, } @@ -453,12 +457,6 @@ impl GlyphRasterizer { .get_glyph_dimensions(font, glyph_key) } - pub fn is_bitmap_font(&self, font: &FontInstance) -> bool { - self.font_contexts - .lock_shared_context() - .is_bitmap_font(font) - } - pub fn get_glyph_index(&mut self, font_key: FontKey, ch: char) -> Option { self.font_contexts .lock_shared_context() diff --git a/webrender/src/platform/macos/font.rs b/webrender/src/platform/macos/font.rs index b67200bb8a..83d7c211fb 100644 --- a/webrender/src/platform/macos/font.rs +++ b/webrender/src/platform/macos/font.rs @@ -22,7 +22,7 @@ use core_text; use core_text::font::{CTFont, CTFontRef}; use core_text::font_descriptor::{kCTFontDefaultOrientation, kCTFontColorGlyphsTrait}; use gamma_lut::{ColorLut, GammaLut}; -use glyph_rasterizer::{FontInstance, RasterizedGlyph}; +use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph}; use internal_types::FastHashMap; use std::collections::hash_map::Entry; use std::sync::Arc; @@ -259,6 +259,11 @@ fn new_ct_font_with_variations(cg_font: &CGFont, size: f64, variations: &[FontVa } } +fn is_bitmap_font(ct_font: &CTFont) -> bool { + let traits = ct_font.symbolic_traits(); + (traits & kCTFontColorGlyphsTrait) != 0 +} + impl FontContext { pub fn new() -> FontContext { debug!("Test for subpixel AA support: {}", supports_subpixel_aa()); @@ -351,7 +356,8 @@ impl FontContext { self.get_ct_font(font.font_key, font.size, &font.variations) .and_then(|ref ct_font| { let glyph = key.index as CGGlyph; - let (x_offset, y_offset) = font.get_subpx_offset(key); + let bitmap = is_bitmap_font(ct_font); + let (x_offset, y_offset) = if bitmap { (0.0, 0.0) } else { font.get_subpx_offset(key) }; let metrics = get_glyph_metrics(ct_font, None, glyph, x_offset, y_offset, 0.0); if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 { None @@ -404,22 +410,12 @@ impl FontContext { } } - pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool { - match self.get_ct_font(font.font_key, font.size, &font.variations) { - Some(ref ct_font) => { - let traits = ct_font.symbolic_traits(); - (traits & kCTFontColorGlyphsTrait) != 0 - } - None => false, - } - } - pub fn prepare_font(font: &mut FontInstance) { match font.render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => { - // In mono/bitmap modes the color of the font is irrelevant. + FontRenderMode::Mono => { + // In mono mode the color of the font is irrelevant. font.color = ColorU::new(255, 255, 255, 255); - // Subpixel positioning is disabled in mono and bitmap modes. + // Subpixel positioning is disabled in mono mode. font.subpx_dir = SubpixelDirection::None; } FontRenderMode::Alpha => { @@ -457,8 +453,9 @@ impl FontContext { None => return None, }; + let bitmap = is_bitmap_font(&ct_font); let shape = font.transform.pre_scale(y_scale.recip() as f32, y_scale.recip() as f32); - let transform = if shape.is_identity() { + let transform = if bitmap || shape.is_identity() { None } else { Some(CGAffineTransform { @@ -470,16 +467,18 @@ impl FontContext { ty: 0.0 }) }; + let glyph = key.index as CGGlyph; - let (x_offset, y_offset) = font.get_subpx_offset(key); - let extra_strikes = font.get_extra_strikes(x_scale); + let (x_offset, y_offset) = if bitmap { (0.0, 0.0) } else { font.get_subpx_offset(key) }; + let (strike_scale, pixel_step) = if bitmap { (y_scale, 1.0) } else { (x_scale, y_scale / x_scale) }; + let extra_strikes = font.get_extra_strikes(strike_scale); let metrics = get_glyph_metrics( &ct_font, transform.as_ref(), glyph, x_offset, y_offset, - extra_strikes as f64 * y_scale / x_scale, + extra_strikes as f64 * pixel_step, ); if metrics.rasterized_width == 0 || metrics.rasterized_height == 0 { return None; @@ -507,14 +506,10 @@ impl FontContext { // subpixel AA at all (which we need it to do in both Subpixel and // Alpha+smoothing mode). But little-endian is what we want anyway, so // this works out nicely. - let context_flags = match font.render_mode { - FontRenderMode::Subpixel | FontRenderMode::Alpha | - FontRenderMode::Mono => { - kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst - } - FontRenderMode::Bitmap => { - kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst - } + let context_flags = if bitmap { + kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst + } else { + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst }; let mut cg_context = CGContext::create_bitmap_context( @@ -552,7 +547,9 @@ impl FontContext { // the "Alpha without smoothing" and Mono modes. let use_white_on_black = should_use_white_on_black(font.color); let use_font_smoothing = font.flags.contains(FontInstanceFlags::FONT_SMOOTHING); - let (antialias, smooth, text_color, bg_color, bg_alpha, invert) = + let (antialias, smooth, text_color, bg_color, bg_alpha, invert) = if bitmap { + (true, false, 0.0, 0.0, 0.0, false) + } else { match (font.render_mode, use_font_smoothing) { (FontRenderMode::Subpixel, _) | (FontRenderMode::Alpha, true) => if use_white_on_black { @@ -562,8 +559,8 @@ impl FontContext { }, (FontRenderMode::Alpha, false) => (true, false, 0.0, 1.0, 1.0, true), (FontRenderMode::Mono, _) => (false, false, 0.0, 1.0, 1.0, true), - (FontRenderMode::Bitmap, _) => (true, false, 0.0, 0.0, 0.0, false), - }; + } + }; // These are always true in Gecko, even for non-AA fonts cg_context.set_allows_font_subpixel_positioning(true); @@ -606,7 +603,6 @@ impl FontContext { if extra_strikes > 0 { let strikes = 1 + extra_strikes; - let pixel_step = y_scale / x_scale; let glyphs = vec![glyph; strikes]; let origins = (0..strikes) .map(|i| CGPoint { x: draw_origin.x + i as f64 * pixel_step, y: draw_origin.y }) @@ -618,7 +614,7 @@ impl FontContext { let mut rasterized_pixels = cg_context.data().to_vec(); - if font.render_mode != FontRenderMode::Bitmap { + if !bitmap { // We rendered text into an opaque surface. The code below needs to // ignore the current value of each pixel's alpha channel. But it's // allowed to write to the alpha channel, because we're done calling @@ -670,8 +666,8 @@ impl FontContext { top: metrics.rasterized_ascent as f32, width: metrics.rasterized_width, height: metrics.rasterized_height, - scale: 1.0, - format: font.get_glyph_format(true), + scale: if bitmap { y_scale.recip() as f32 } else { 1.0 }, + format: if bitmap { GlyphFormat::ColorBitmap } else { font.get_glyph_format() }, bytes: rasterized_pixels, }) } diff --git a/webrender/src/platform/unix/font.rs b/webrender/src/platform/unix/font.rs index d059662756..2d0e0a40a4 100644 --- a/webrender/src/platform/unix/font.rs +++ b/webrender/src/platform/unix/font.rs @@ -16,8 +16,8 @@ use freetype::freetype::{FT_Fixed, FT_Matrix, FT_Set_Transform}; use freetype::freetype::{FT_LOAD_COLOR, FT_LOAD_DEFAULT, FT_LOAD_FORCE_AUTOHINT}; use freetype::freetype::{FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, FT_LOAD_NO_AUTOHINT}; use freetype::freetype::{FT_LOAD_NO_BITMAP, FT_LOAD_NO_HINTING, FT_LOAD_VERTICAL_LAYOUT}; -use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES, FT_Err_Cannot_Render_Glyph}; -use glyph_rasterizer::{FontInstance, RasterizedGlyph}; +use freetype::freetype::{FT_FACE_FLAG_SCALABLE, FT_FACE_FLAG_FIXED_SIZES}; +use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph}; use internal_types::FastHashMap; use std::{cmp, mem, ptr, slice}; use std::cmp::max; @@ -185,16 +185,15 @@ impl FontContext { load_flags |= FT_LOAD_COLOR; load_flags |= FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH; + let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0)); let req_size = font.size.to_f64_px(); - let mut result = if font.render_mode == FontRenderMode::Bitmap { - if (load_flags & FT_LOAD_NO_BITMAP) != 0 { - FT_Error(FT_Err_Cannot_Render_Glyph as i32) - } else { - unsafe { FT_Set_Transform(face.face, ptr::null_mut(), ptr::null_mut()) }; - self.choose_bitmap_size(face.face, req_size) - } + let face_flags = unsafe { (*face.face).face_flags }; + let mut result = if (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 && + (face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0 && + (load_flags & FT_LOAD_NO_BITMAP) == 0 { + unsafe { FT_Set_Transform(face.face, ptr::null_mut(), ptr::null_mut()) }; + self.choose_bitmap_size(face.face, req_size * y_scale) } else { - let (x_scale, y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0)); let shape = font.transform.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32); let mut ft_shape = FT_Matrix { xx: (shape.scale_x * 65536.0) as FT_Fixed, @@ -273,8 +272,7 @@ impl FontContext { let padding = match font.render_mode { FontRenderMode::Subpixel => (self.lcd_extra_pixels * 64) as FT_Pos, FontRenderMode::Alpha | - FontRenderMode::Mono | - FontRenderMode::Bitmap => 0 as FT_Pos, + FontRenderMode::Mono => 0 as FT_Pos, }; // Offset the bounding box by subpixel positioning. @@ -377,17 +375,6 @@ impl FontContext { slot.and_then(|slot| self.get_glyph_dimensions_impl(slot, font, key, true)) } - pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool { - debug_assert!(self.faces.contains_key(&font.font_key)); - let face = self.faces.get(&font.font_key).unwrap(); - let face_flags = unsafe { (*face.face).face_flags }; - // If the face has embedded bitmaps, they should only be used if either - // embedded bitmaps are explicitly requested or if the face has no outline. - (face_flags & (FT_FACE_FLAG_FIXED_SIZES as FT_Long)) != 0 && - (font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) || - (face_flags & (FT_FACE_FLAG_SCALABLE as FT_Long)) == 0) - } - fn choose_bitmap_size(&self, face: FT_Face, requested_size: f64) -> FT_Error { let mut best_dist = unsafe { *(*face).available_sizes.offset(0) }.y_ppem as f64 / 64.0 - requested_size; let mut best_size = 0; @@ -407,10 +394,10 @@ impl FontContext { pub fn prepare_font(font: &mut FontInstance) { match font.render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => { - // In mono/bitmap modes the color of the font is irrelevant. + FontRenderMode::Mono => { + // In mono mode the color of the font is irrelevant. font.color = ColorU::new(0xFF, 0xFF, 0xFF, 0xFF); - // Subpixel positioning is disabled in mono and bitmap modes. + // Subpixel positioning is disabled in mono mode. font.subpx_dir = SubpixelDirection::None; } FontRenderMode::Alpha | FontRenderMode::Subpixel => { @@ -460,7 +447,7 @@ impl FontContext { } let render_mode = match (font.render_mode, font.subpx_dir) { (FontRenderMode::Mono, _) => FT_Render_Mode::FT_RENDER_MODE_MONO, - (FontRenderMode::Alpha, _) | (FontRenderMode::Bitmap, _) => FT_Render_Mode::FT_RENDER_MODE_NORMAL, + (FontRenderMode::Alpha, _) => FT_Render_Mode::FT_RENDER_MODE_NORMAL, (FontRenderMode::Subpixel, SubpixelDirection::Vertical) => FT_Render_Mode::FT_RENDER_MODE_LCD_V, (FontRenderMode::Subpixel, _) => FT_Render_Mode::FT_RENDER_MODE_LCD, }; @@ -545,7 +532,7 @@ impl FontContext { }; let mut final_buffer = vec![0; (actual_width * actual_height * 4) as usize]; - // Extract the final glyph from FT format into RGBA8 format, which is + // Extract the final glyph from FT format into BGRA8 format, which is // what WR expects. let subpixel_bgr = font.flags.contains(FontInstanceFlags::SUBPIXEL_BGR); let mut src_row = bitmap.buffer; @@ -635,13 +622,21 @@ impl FontContext { _ => {} } + let glyph_format = match (pixel_mode, format) { + (FT_Pixel_Mode::FT_PIXEL_MODE_LCD, _) | + (FT_Pixel_Mode::FT_PIXEL_MODE_LCD_V, _) => font.get_subpixel_glyph_format(), + (FT_Pixel_Mode::FT_PIXEL_MODE_BGRA, _) => GlyphFormat::ColorBitmap, + (_, FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP) => GlyphFormat::Bitmap, + _ => font.get_alpha_glyph_format(), + }; + Some(RasterizedGlyph { left: left as f32, top: top as f32, width: actual_width as u32, height: actual_height as u32, scale, - format: font.get_glyph_format(pixel_mode == FT_Pixel_Mode::FT_PIXEL_MODE_BGRA), + format: glyph_format, bytes: final_buffer, }) } diff --git a/webrender/src/platform/windows/font.rs b/webrender/src/platform/windows/font.rs index 519c3c22f9..2f71d61645 100644 --- a/webrender/src/platform/windows/font.rs +++ b/webrender/src/platform/windows/font.rs @@ -6,7 +6,7 @@ use api::{FontInstanceFlags, FontKey, FontRenderMode}; use api::{ColorU, GlyphDimensions, GlyphKey, SubpixelDirection}; use dwrote; use gamma_lut::{ColorLut, GammaLut}; -use glyph_rasterizer::{FontInstance, RasterizedGlyph}; +use glyph_rasterizer::{FontInstance, GlyphFormat, RasterizedGlyph}; use internal_types::FastHashMap; use std::collections::hash_map::Entry; use std::sync::Arc; @@ -34,7 +34,6 @@ unsafe impl Send for FontContext {} fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TYPE { match render_mode { FontRenderMode::Mono => dwrote::DWRITE_TEXTURE_ALIASED_1x1, - FontRenderMode::Bitmap | FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_TEXTURE_CLEARTYPE_3x1, } @@ -42,12 +41,13 @@ fn dwrite_texture_type(render_mode: FontRenderMode) -> dwrote::DWRITE_TEXTURE_TY fn dwrite_measure_mode( font: &FontInstance, + bitmaps: bool, ) -> dwrote::DWRITE_MEASURING_MODE { - if font.flags.contains(FontInstanceFlags::FORCE_GDI) { + if bitmaps || font.flags.contains(FontInstanceFlags::FORCE_GDI) { dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC } else { match font.render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC, + FontRenderMode::Mono => dwrote::DWRITE_MEASURING_MODE_GDI_CLASSIC, FontRenderMode::Alpha | FontRenderMode::Subpixel => dwrote::DWRITE_MEASURING_MODE_NATURAL, } } @@ -58,12 +58,12 @@ fn dwrite_render_mode( font: &FontInstance, em_size: f32, measure_mode: dwrote::DWRITE_MEASURING_MODE, + bitmaps: bool, ) -> dwrote::DWRITE_RENDERING_MODE { let dwrite_render_mode = match font.render_mode { - FontRenderMode::Bitmap => dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC, FontRenderMode::Mono => dwrote::DWRITE_RENDERING_MODE_ALIASED, FontRenderMode::Alpha | FontRenderMode::Subpixel => { - if font.flags.contains(FontInstanceFlags::FORCE_GDI) { + if bitmaps || font.flags.contains(FontInstanceFlags::FORCE_GDI) { dwrote::DWRITE_RENDERING_MODE_GDI_CLASSIC } else { font_face.get_recommended_rendering_mode_default_params(em_size, 1.0, measure_mode) @@ -79,6 +79,13 @@ fn dwrite_render_mode( dwrite_render_mode } +fn is_bitmap_font(font: &FontInstance) -> bool { + // If bitmaps are requested, then treat as a bitmap font to disable transforms. + // If mono AA is requested, let that take priority over using bitmaps. + font.render_mode != FontRenderMode::Mono && + font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) +} + impl FontContext { pub fn new() -> FontContext { // These are the default values we use in Gecko. @@ -176,6 +183,9 @@ impl FontContext { &mut self, font: &FontInstance, key: &GlyphKey, + size: f32, + transform: Option, + bitmaps: bool, ) -> dwrote::GlyphRunAnalysis { let face = self.get_font_face(font); let glyph = key.index as u16; @@ -185,9 +195,6 @@ impl FontContext { ascenderOffset: 0.0, }; - let (.., y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0)); - let size = (font.size.to_f64_px() * y_scale) as f32; - let glyph_run = dwrote::DWRITE_GLYPH_RUN { fontFace: unsafe { face.as_ptr() }, fontEmSize: size, // size in DIPs (1/96", same as CSS pixels) @@ -199,29 +206,19 @@ impl FontContext { bidiLevel: 0, }; - let dwrite_measure_mode = dwrite_measure_mode(font); + let dwrite_measure_mode = dwrite_measure_mode(font, bitmaps); let dwrite_render_mode = dwrite_render_mode( face, font, size, dwrite_measure_mode, + bitmaps, ); - let (x_offset, y_offset) = font.get_subpx_offset(key); - let shape = font.transform.pre_scale(y_scale.recip() as f32, y_scale.recip() as f32); - let transform = dwrote::DWRITE_MATRIX { - m11: shape.scale_x, - m12: shape.skew_y, - m21: shape.skew_x, - m22: shape.scale_y, - dx: x_offset as f32, - dy: y_offset as f32, - }; - dwrote::GlyphRunAnalysis::create( &glyph_run, 1.0, - Some(transform), + transform, dwrite_render_mode, dwrite_measure_mode, 0.0, @@ -235,17 +232,16 @@ impl FontContext { indices.first().map(|idx| *idx as u32) } - // TODO: Pipe GlyphOptions into glyph_dimensions too pub fn get_glyph_dimensions( &mut self, font: &FontInstance, key: &GlyphKey, ) -> Option { - // Probably have to default to something else here. - let render_mode = FontRenderMode::Subpixel; - let analysis = self.create_glyph_analysis(font, key); + let size = font.size.to_f32_px(); + let bitmaps = is_bitmap_font(font); + let analysis = self.create_glyph_analysis(font, key, size, None, bitmaps); - let texture_type = dwrite_texture_type(render_mode); + let texture_type = dwrite_texture_type(font.render_mode); let bounds = analysis.get_alpha_texture_bounds(texture_type); @@ -262,7 +258,7 @@ impl FontContext { face.get_design_glyph_metrics(&[key.index as u16], false) .first() .map(|metrics| { - let em_size = font.size.to_f32_px() / 16.; + let em_size = size / 16.; let design_units_per_pixel = face.metrics().designUnitsPerEm as f32 / 16. as f32; let scaled_design_units_to_pixels = em_size / design_units_per_pixel; let advance = metrics.advanceWidth as f32 * scaled_design_units_to_pixels; @@ -278,9 +274,14 @@ impl FontContext { } // DWrite ClearType gives us values in RGB, but WR expects BGRA. - fn convert_to_bgra(&self, pixels: &[u8], render_mode: FontRenderMode) -> Vec { - match render_mode { - FontRenderMode::Mono => { + fn convert_to_bgra( + &self, + pixels: &[u8], + render_mode: FontRenderMode, + bitmaps: bool, + ) -> Vec { + match (render_mode, bitmaps) { + (FontRenderMode::Mono, _) => { let mut bgra_pixels: Vec = vec![0; pixels.len() * 4]; for i in 0 .. pixels.len() { let alpha = pixels[i]; @@ -291,7 +292,7 @@ impl FontContext { } bgra_pixels } - FontRenderMode::Alpha | FontRenderMode::Bitmap => { + (FontRenderMode::Alpha, _) | (_, true) => { let length = pixels.len() / 3; let mut bgra_pixels: Vec = vec![0; length * 4]; for i in 0 .. length { @@ -304,7 +305,7 @@ impl FontContext { } bgra_pixels } - FontRenderMode::Subpixel => { + (FontRenderMode::Subpixel, false) => { let length = pixels.len() / 3; let mut bgra_pixels: Vec = vec![0; length * 4]; for i in 0 .. length { @@ -318,19 +319,12 @@ impl FontContext { } } - pub fn is_bitmap_font(&mut self, font: &FontInstance) -> bool { - // If bitmaps are requested, then treat as a bitmap font to disable transforms. - // If mono AA is requested, let that take priority over using bitmaps. - font.render_mode != FontRenderMode::Mono && - font.flags.contains(FontInstanceFlags::EMBEDDED_BITMAPS) - } - pub fn prepare_font(font: &mut FontInstance) { match font.render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => { - // In mono/bitmap modes the color of the font is irrelevant. + FontRenderMode::Mono => { + // In mono mode the color of the font is irrelevant. font.color = ColorU::new(255, 255, 255, 255); - // Subpixel positioning is disabled in mono and bitmap modes. + // Subpixel positioning is disabled in mono mode. font.subpx_dir = SubpixelDirection::None; } FontRenderMode::Alpha => { @@ -347,7 +341,25 @@ impl FontContext { font: &FontInstance, key: &GlyphKey, ) -> Option { - let analysis = self.create_glyph_analysis(font, key); + let (.., y_scale) = font.transform.compute_scale().unwrap_or((1.0, 1.0)); + let size = (font.size.to_f64_px() * y_scale) as f32; + let bitmaps = is_bitmap_font(font); + let transform = if bitmaps { + None + } else { + let (x_offset, y_offset) = font.get_subpx_offset(key); + let shape = font.transform.pre_scale(y_scale.recip() as f32, y_scale.recip() as f32); + Some(dwrote::DWRITE_MATRIX { + m11: shape.scale_x, + m12: shape.skew_y, + m21: shape.skew_x, + m22: shape.scale_y, + dx: x_offset as f32, + dy: y_offset as f32, + }) + }; + + let analysis = self.create_glyph_analysis(font, key, size, transform, bitmaps); let texture_type = dwrite_texture_type(font.render_mode); let bounds = analysis.get_alpha_texture_bounds(texture_type); @@ -361,12 +373,12 @@ impl FontContext { } let pixels = analysis.create_alpha_texture(texture_type, bounds); - let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode); + let mut bgra_pixels = self.convert_to_bgra(&pixels, font.render_mode, bitmaps); let lut_correction = match font.render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => &self.gdi_gamma_lut, + FontRenderMode::Mono => &self.gdi_gamma_lut, FontRenderMode::Alpha | FontRenderMode::Subpixel => { - if font.flags.contains(FontInstanceFlags::FORCE_GDI) { + if bitmaps || font.flags.contains(FontInstanceFlags::FORCE_GDI) { &self.gdi_gamma_lut } else { &self.gamma_lut @@ -380,8 +392,8 @@ impl FontContext { top: -bounds.top as f32, width, height, - scale: 1.0, - format: font.get_glyph_format(false), + scale: if bitmaps { y_scale.recip() as f32 } else { 1.0 }, + format: if bitmaps { GlyphFormat::Bitmap } else { font.get_glyph_format() }, bytes: bgra_pixels, }) } diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 8e30d9c4e5..818dbb45d4 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -751,8 +751,7 @@ impl TextRunPrimitiveCpu { ) -> FontInstance { let mut font = self.font.clone(); font.size = font.size.scale_by(device_pixel_ratio); - if font.render_mode != FontRenderMode::Bitmap && - rasterization_kind == RasterizationSpace::Screen { + if rasterization_kind == RasterizationSpace::Screen { if transform.has_perspective_component() || !transform.has_2d_inverse() { font.render_mode = font.render_mode.limit_by(FontRenderMode::Alpha); } else { diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index ae74eaeb33..b9ec728f67 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -281,7 +281,8 @@ enum TextShaderMode { SubpixelWithBgColorPass0 = 4, SubpixelWithBgColorPass1 = 5, SubpixelWithBgColorPass2 = 6, - ColorBitmap = 7, + Bitmap = 7, + ColorBitmap = 8, } impl Into for TextShaderMode { @@ -297,6 +298,7 @@ impl From for TextShaderMode { GlyphFormat::Subpixel | GlyphFormat::TransformedSubpixel => { panic!("Subpixel glyph formats must be handled separately."); } + GlyphFormat::Bitmap => TextShaderMode::Bitmap, GlyphFormat::ColorBitmap => TextShaderMode::ColorBitmap, } } @@ -1251,6 +1253,7 @@ impl TextShader { match glyph_format { GlyphFormat::Alpha | GlyphFormat::Subpixel | + GlyphFormat::Bitmap | GlyphFormat::ColorBitmap => { match transform_kind { TransformedRectKind::AxisAligned => { diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index 36d0a8cc83..e916503c95 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -4,7 +4,7 @@ use api::{AddFont, BlobImageData, BlobImageResources, ResourceUpdate, ResourceUpdates}; use api::{BlobImageDescriptor, BlobImageError, BlobImageRenderer, BlobImageRequest}; -use api::{ColorF, FontRenderMode}; +use api::ColorF; use api::{DevicePoint, DeviceUintRect, DeviceUintSize}; use api::{Epoch, FontInstanceKey, FontKey, FontTemplate}; use api::{ExternalImageData, ExternalImageType}; @@ -354,8 +354,7 @@ impl ResourceCache { bg_color, .. } = options.unwrap_or_default(); - assert!(render_mode != FontRenderMode::Bitmap); - let mut instance = FontInstance::new( + let instance = FontInstance::new( font_key, glyph_size, ColorF::new(0.0, 0.0, 0.0, 1.0), @@ -366,9 +365,6 @@ impl ResourceCache { platform_options, variations, ); - if self.glyph_rasterizer.is_bitmap_font(&instance) { - instance.render_mode = instance.render_mode.limit_by(FontRenderMode::Bitmap); - } self.resources.font_instances .write() .unwrap() diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index b780d5e7aa..979736dde5 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -4,7 +4,7 @@ use api::{BorderRadiusKind, ClipId, ColorF, DeviceIntPoint, ImageKey}; use api::{DeviceIntRect, DeviceIntSize, device_length, DeviceUintPoint, DeviceUintRect, DeviceUintSize}; -use api::{DocumentLayer, ExternalImageType, FilterOp, FontRenderMode}; +use api::{DocumentLayer, ExternalImageType, FilterOp}; use api::{ImageFormat, ImageRendering}; use api::{LayerRect, MixBlendMode, PipelineId}; use api::{TileOffset, YuvColorSpace, YuvFormat}; @@ -106,21 +106,8 @@ impl AlphaBatchHelpers for PrimitiveStore { transform_kind == TransformedRectKind::Complex; match metadata.prim_kind { - PrimitiveKind::TextRun => { - let font = &self.cpu_text_runs[metadata.cpu_prim_index.0].font; - match font.render_mode { - FontRenderMode::Subpixel => { - if font.bg_color.a != 0 { - BlendMode::SubpixelWithBgColor - } else { - BlendMode::SubpixelConstantTextColor(font.color.into()) - } - } - FontRenderMode::Alpha | - FontRenderMode::Mono | - FontRenderMode::Bitmap => BlendMode::PremultipliedAlpha, - } - }, + // Can only resolve the TextRun's blend mode once glyphs are fetched. + PrimitiveKind::TextRun => BlendMode::PremultipliedAlpha, PrimitiveKind::Border | PrimitiveKind::Image | PrimitiveKind::YuvImage | @@ -599,6 +586,21 @@ fn add_to_batch( TransformBatchKind::TextRun(glyph_format), ); + let blend_mode = match glyph_format { + GlyphFormat::Subpixel | + GlyphFormat::TransformedSubpixel => { + if text_cpu.font.bg_color.a != 0 { + BlendMode::SubpixelWithBgColor + } else { + BlendMode::SubpixelConstantTextColor(text_cpu.font.color.into()) + } + } + GlyphFormat::Alpha | + GlyphFormat::TransformedAlpha | + GlyphFormat::Bitmap | + GlyphFormat::ColorBitmap => BlendMode::PremultipliedAlpha, + }; + let key = BatchKey::new(kind, blend_mode, textures); let batch = batch_list.get_suitable_batch(key, item_bounding_rect); diff --git a/webrender_api/Cargo.toml b/webrender_api/Cargo.toml index 5fb3ebcf27..d01799f082 100644 --- a/webrender_api/Cargo.toml +++ b/webrender_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "webrender_api" -version = "0.56.0" +version = "0.56.1" authors = ["Glenn Watson "] license = "MPL-2.0" repository = "https://github.com/servo/webrender" diff --git a/webrender_api/src/font.rs b/webrender_api/src/font.rs index 0b87109f4e..53e814dfa7 100644 --- a/webrender_api/src/font.rs +++ b/webrender_api/src/font.rs @@ -93,7 +93,6 @@ pub enum FontRenderMode { Mono = 0, Alpha, Subpixel, - Bitmap, } #[repr(u32)] @@ -130,7 +129,6 @@ impl FontRenderMode { // Combine two font render modes such that the lesser amount of AA limits the AA of the result. pub fn limit_by(self, other: FontRenderMode) -> FontRenderMode { match (self, other) { - (FontRenderMode::Bitmap, _) | (_, FontRenderMode::Bitmap) => FontRenderMode::Bitmap, (FontRenderMode::Subpixel, _) | (_, FontRenderMode::Mono) => other, _ => self, } @@ -141,7 +139,7 @@ impl SubpixelDirection { // Limit the subpixel direction to what is supported by the render mode. pub fn limit_by(self, render_mode: FontRenderMode) -> SubpixelDirection { match render_mode { - FontRenderMode::Mono | FontRenderMode::Bitmap => SubpixelDirection::None, + FontRenderMode::Mono => SubpixelDirection::None, FontRenderMode::Alpha | FontRenderMode::Subpixel => self, } }