Bug 1471874 - Update webrender to commit 34a498f7e46c385a189299e7369e204e1cb2060c. r=Gankro
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 04 Jul 2018 10:56:35 -0400
changeset 424999 17c971ee792ce4aa038929306829e1ccba5ee0e6
parent 424998 e672ba38c0a4750468a2927be9ffa88bac4b002d
child 425000 860f77039bdf01e87ee2af958948e71448027e74
push id104959
push userkgupta@mozilla.com
push dateWed, 04 Jul 2018 14:56:57 +0000
treeherdermozilla-inbound@860f77039bdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGankro
bugs1471874
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1471874 - Update webrender to commit 34a498f7e46c385a189299e7369e204e1cb2060c. r=Gankro
gfx/webrender/src/display_list_flattener.rs
gfx/webrender/src/glyph_rasterizer/mod.rs
gfx/webrender/src/platform/macos/font.rs
gfx/webrender/src/platform/unix/font.rs
gfx/webrender/src/platform/windows/font.rs
gfx/webrender/src/prim_store.rs
gfx/webrender/src/resource_cache.rs
gfx/webrender_api/src/font.rs
gfx/webrender_bindings/revision.txt
gfx/wrench/src/wrench.rs
gfx/wrench/src/yaml_frame_reader.rs
--- a/gfx/webrender/src/display_list_flattener.rs
+++ b/gfx/webrender/src/display_list_flattener.rs
@@ -1827,16 +1827,17 @@ impl<'a> DisplayListFlattener<'a> {
 
             let prim_font = FontInstance::new(
                 font_instance.font_key,
                 font_instance.size,
                 *text_color,
                 font_instance.bg_color,
                 render_mode,
                 flags,
+                font_instance.synthetic_italics,
                 font_instance.platform_options,
                 font_instance.variations.clone(),
             );
             TextRunPrimitiveCpu::new(
                 prim_font,
                 run_offset,
                 glyph_range,
                 Vec::new(),
--- a/gfx/webrender/src/glyph_rasterizer/mod.rs
+++ b/gfx/webrender/src/glyph_rasterizer/mod.rs
@@ -1,16 +1,16 @@
 /* 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/. */
 
 use api::{ColorF, ColorU, DevicePoint};
 use api::{FontInstanceFlags, FontInstancePlatformOptions};
 use api::{FontKey, FontRenderMode, FontTemplate, FontVariation};
-use api::{GlyphIndex, GlyphDimensions};
+use api::{GlyphIndex, GlyphDimensions, SyntheticItalics};
 use api::{LayoutPoint, LayoutToWorldTransform, WorldPoint};
 use app_units::Au;
 use euclid::approxeq::ApproxEq;
 use internal_types::ResourceCacheError;
 use platform::font::FontContext;
 use rayon::ThreadPool;
 use std::cmp;
 use std::hash::{Hash, Hasher};
@@ -106,17 +106,18 @@ impl FontTransform {
         )
     }
 
     #[allow(dead_code)]
     pub fn invert_scale(&self, x_scale: f64, y_scale: f64) -> Self {
         self.pre_scale(x_scale.recip() as f32, y_scale.recip() as f32)
     }
 
-    pub fn synthesize_italics(&self, skew_factor: f32) -> Self {
+    pub fn synthesize_italics(&self, angle: SyntheticItalics) -> Self {
+        let skew_factor = angle.to_skew();
         FontTransform::new(
             self.scale_x,
             self.skew_x - self.scale_x * skew_factor,
             self.skew_y,
             self.scale_y - self.skew_y * skew_factor,
         )
     }
 
@@ -171,43 +172,46 @@ pub struct FontInstance {
     // can't store as a f32 due to use of this type as a hash key.
     // TODO(gw): Perhaps consider having LogicalAu and DeviceAu
     //           or something similar to that.
     pub size: Au,
     pub color: ColorU,
     pub bg_color: ColorU,
     pub render_mode: FontRenderMode,
     pub flags: FontInstanceFlags,
+    pub synthetic_italics: SyntheticItalics,
     pub platform_options: Option<FontInstancePlatformOptions>,
     pub variations: Vec<FontVariation>,
     pub transform: FontTransform,
 }
 
 impl FontInstance {
     pub fn new(
         font_key: FontKey,
         size: Au,
         color: ColorF,
         bg_color: ColorU,
         render_mode: FontRenderMode,
         flags: FontInstanceFlags,
+        synthetic_italics: SyntheticItalics,
         platform_options: Option<FontInstancePlatformOptions>,
         variations: Vec<FontVariation>,
     ) -> Self {
         // If a background color is enabled, it only makes sense
         // for it to be completely opaque.
         debug_assert!(bg_color.a == 0 || bg_color.a == 255);
 
         FontInstance {
             font_key,
             size,
             color: color.into(),
             bg_color,
             render_mode,
             flags,
+            synthetic_italics,
             platform_options,
             variations,
             transform: FontTransform::identity(),
         }
     }
 
     pub fn get_alpha_glyph_format(&self) -> GlyphFormat {
         if self.transform.is_identity() { GlyphFormat::Alpha } else { GlyphFormat::TransformedAlpha }
@@ -704,16 +708,17 @@ mod test_glyph_rasterizer {
 
         let font = FontInstance::new(
             font_key,
             Au::from_px(32),
             ColorF::new(0.0, 0.0, 0.0, 1.0),
             ColorU::new(0, 0, 0, 0),
             FontRenderMode::Subpixel,
             Default::default(),
+            Default::default(),
             None,
             Vec::new(),
         );
         let subpx_dir = font.get_subpx_dir();
 
         let mut glyph_keys = Vec::with_capacity(200);
         for i in 0 .. 200 {
             glyph_keys.push(GlyphKey::new(
--- a/gfx/webrender/src/platform/macos/font.rs
+++ b/gfx/webrender/src/platform/macos/font.rs
@@ -265,19 +265,16 @@ fn new_ct_font_with_variations(cg_font: 
     }
 }
 
 fn is_bitmap_font(ct_font: &CTFont) -> bool {
     let traits = ct_font.symbolic_traits();
     (traits & kCTFontColorGlyphsTrait) != 0
 }
 
-// Skew factor matching Gecko/CG.
-const OBLIQUE_SKEW_FACTOR: f32 = 0.25;
-
 impl FontContext {
     pub fn new() -> Result<FontContext, ResourceCacheError> {
         debug!("Test for subpixel AA support: {}", supports_subpixel_aa());
 
         // Force CG to use sRGB color space to gamma correct.
         let contrast = 0.0;
         let gamma = 0.0;
 
@@ -362,32 +359,32 @@ impl FontContext {
         font: &FontInstance,
         key: &GlyphKey,
     ) -> Option<GlyphDimensions> {
         self.get_ct_font(font.font_key, font.size, &font.variations)
             .and_then(|ref ct_font| {
                 let glyph = key.index as CGGlyph;
                 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 transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
-                                                         FontInstanceFlags::TRANSPOSE |
+                let transform = if font.synthetic_italics.is_enabled() ||
+                                   font.flags.intersects(FontInstanceFlags::TRANSPOSE |
                                                          FontInstanceFlags::FLIP_X |
                                                          FontInstanceFlags::FLIP_Y) {
                     let mut shape = FontTransform::identity();
                     if font.flags.contains(FontInstanceFlags::FLIP_X) {
                         shape = shape.flip_x();
                     }
                     if font.flags.contains(FontInstanceFlags::FLIP_Y) {
                         shape = shape.flip_y();
                     }
                     if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                         shape = shape.swap_xy();
                     }
-                    if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-                        shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
+                    if font.synthetic_italics.is_enabled() {
+                        shape = shape.synthesize_italics(font.synthetic_italics);
                     }
                     Some(CGAffineTransform {
                         a: shape.scale_x as f64,
                         b: -shape.skew_y as f64,
                         c: -shape.skew_x as f64,
                         d: shape.scale_y as f64,
                         tx: 0.0,
                         ty: 0.0,
@@ -507,18 +504,18 @@ impl FontContext {
             shape = shape.flip_x();
         }
         if font.flags.contains(FontInstanceFlags::FLIP_Y) {
             shape = shape.flip_y();
         }
         if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
             shape = shape.swap_xy();
         }
-        if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-            shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
+        if font.synthetic_italics.is_enabled() {
+            shape = shape.synthesize_italics(font.synthetic_italics);
         }
         let transform = if !shape.is_identity() {
             Some(CGAffineTransform {
                 a: shape.scale_x as f64,
                 b: -shape.skew_y as f64,
                 c: -shape.skew_x as f64,
                 d: shape.scale_y as f64,
                 tx: 0.0,
--- a/gfx/webrender/src/platform/unix/font.rs
+++ b/gfx/webrender/src/platform/unix/font.rs
@@ -55,35 +55,39 @@ pub struct FontContext {
 // are not concurrently accessed. In our case, everything is hidden inside
 // a given FontContext so it is safe to move the latter between threads.
 unsafe impl Send for FontContext {}
 
 extern "C" {
     fn FT_GlyphSlot_Embolden(slot: FT_GlyphSlot);
 }
 
-// Skew factor matching Gecko/FreeType.
-const OBLIQUE_SKEW_FACTOR: f32 = 0.2;
-
-fn get_skew_bounds(bottom: i32, top: i32) -> (f32, f32) {
-    let skew_min = ((bottom as f32 + 0.5) * OBLIQUE_SKEW_FACTOR).floor();
-    let skew_max = ((top as f32 - 0.5) * OBLIQUE_SKEW_FACTOR).ceil();
+fn get_skew_bounds(bottom: i32, top: i32, skew_factor: f32) -> (f32, f32) {
+    let skew_min = ((bottom as f32 + 0.5) * skew_factor).floor();
+    let skew_max = ((top as f32 - 0.5) * skew_factor).ceil();
     (skew_min, skew_max)
 }
 
-fn skew_bitmap(bitmap: &[u8], width: usize, height: usize, left: i32, top: i32) -> (Vec<u8>, usize, i32) {
+fn skew_bitmap(
+    bitmap: &[u8],
+    width: usize,
+    height: usize,
+    left: i32,
+    top: i32,
+    skew_factor: f32,
+) -> (Vec<u8>, usize, i32) {
     let stride = width * 4;
     // Calculate the skewed horizontal offsets of the bottom and top of the glyph.
-    let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top);
+    let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top, skew_factor);
     // Allocate enough extra width for the min/max skew offsets.
     let skew_width = width + (skew_max - skew_min) as usize;
     let mut skew_buffer = vec![0u8; skew_width * height * 4];
     for y in 0 .. height {
         // Calculate a skew offset at the vertical center of the current row.
-        let offset = (top as f32 - y as f32 - 0.5) * OBLIQUE_SKEW_FACTOR - skew_min;
+        let offset = (top as f32 - y as f32 - 0.5) * skew_factor - skew_min;
         // Get a blend factor in 0..256 constant across all pixels in the row.
         let blend = (offset.fract() * 256.0) as u32;
         let src_row = y * stride;
         let dest_row = (y * skew_width + offset.floor() as usize) * 4;
         let mut prev_px = [0u32; 4];
         for (src, dest) in
             bitmap[src_row .. src_row + stride].chunks(4).zip(
                 skew_buffer[dest_row .. dest_row + stride].chunks_mut(4)
@@ -238,17 +242,17 @@ impl FontContext {
 
     fn load_glyph(&self, font: &FontInstance, glyph: &GlyphKey) -> Option<(FT_GlyphSlot, f32)> {
         debug_assert!(self.faces.contains_key(&font.font_key));
         let face = self.faces.get(&font.font_key).unwrap();
 
         let mut load_flags = FT_LOAD_DEFAULT;
         let FontInstancePlatformOptions { mut hinting, .. } = font.platform_options.unwrap_or_default();
         // Disable hinting if there is a non-axis-aligned transform.
-        if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) ||
+        if font.synthetic_italics.is_enabled() ||
            ((font.transform.scale_x != 0.0 || font.transform.scale_y != 0.0) &&
             (font.transform.skew_x != 0.0 || font.transform.skew_y != 0.0)) {
             hinting = FontHinting::None;
         }
         match (hinting, font.render_mode) {
             (FontHinting::None, _) => load_flags |= FT_LOAD_NO_HINTING,
             (FontHinting::Mono, _) => load_flags = FT_LOAD_TARGET_MONO,
             (FontHinting::Light, _) => load_flags = FT_LOAD_TARGET_LIGHT,
@@ -297,18 +301,18 @@ impl FontContext {
                 shape = shape.flip_x();
             }
             if font.flags.contains(FontInstanceFlags::FLIP_Y) {
                 shape = shape.flip_y();
             }
             if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                 shape = shape.swap_xy();
             }
-            if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-                shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
+            if font.synthetic_italics.is_enabled() {
+                shape = shape.synthesize_italics(font.synthetic_italics);
             };
             let mut ft_shape = FT_Matrix {
                 xx: (shape.scale_x * 65536.0) as FT_Fixed,
                 xy: (shape.skew_x * -65536.0) as FT_Fixed,
                 yx: (shape.skew_y * -65536.0) as FT_Fixed,
                 yy: (shape.scale_y * 65536.0) as FT_Fixed,
             };
             unsafe {
@@ -452,18 +456,22 @@ impl FontContext {
                 top = y1.round() as i32;
                 width = (x1.ceil() - x0.floor()) as u32;
                 height = (y1.ceil() - y0.floor()) as u32;
                 advance *= scale;
             }
             // An outline glyph's cbox would have already been transformed inside FT_Load_Glyph,
             // so only handle bitmap glyphs which are not handled by FT_Load_Glyph.
             if format == FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP {
-                if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-                    let (skew_min, skew_max) = get_skew_bounds(top - height as i32, top);
+                if font.synthetic_italics.is_enabled() {
+                    let (skew_min, skew_max) = get_skew_bounds(
+                        top - height as i32,
+                        top,
+                        font.synthetic_italics.to_skew(),
+                    );
                     left += skew_min as i32;
                     width += (skew_max - skew_min) as u32;
                 }
                 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                     mem::swap(&mut width, &mut height);
                     mem::swap(&mut left, &mut top);
                     left -= width as i32;
                     top += height as i32;
@@ -738,19 +746,25 @@ impl FontContext {
                 _ => panic!("Unsupported mode"),
             }
             src_row = unsafe { src_row.offset(bitmap.pitch as isize) };
             dest = row_end;
         }
 
         match format {
             FT_Glyph_Format::FT_GLYPH_FORMAT_BITMAP => {
-                if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-                    let (skew_buffer, skew_width, skew_left) =
-                        skew_bitmap(&final_buffer, actual_width, actual_height, left, top);
+                if font.synthetic_italics.is_enabled() {
+                    let (skew_buffer, skew_width, skew_left) = skew_bitmap(
+                        &final_buffer,
+                        actual_width,
+                        actual_height,
+                        left,
+                        top,
+                        font.synthetic_italics.to_skew(),
+                    );
                     final_buffer = skew_buffer;
                     actual_width = skew_width;
                     left = skew_left;
                 }
                 if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                     final_buffer = transpose_bitmap(&final_buffer, actual_width, actual_height);
                     mem::swap(&mut actual_width, &mut actual_height);
                     mem::swap(&mut left, &mut top);
--- a/gfx/webrender/src/platform/windows/font.rs
+++ b/gfx/webrender/src/platform/windows/font.rs
@@ -92,19 +92,16 @@ fn 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)
 }
 
-// Skew factor matching Gecko/DWrite.
-const OBLIQUE_SKEW_FACTOR: f32 = 0.3;
-
 impl FontContext {
     pub fn new() -> Result<FontContext, ResourceCacheError> {
         // These are the default values we use in Gecko.
         // We use a gamma value of 2.3 for gdi fonts
         // TODO: Fetch this data from Gecko itself.
         cfg_if! {
             if #[cfg(not(feature = "pathfinder"))] {
                 const CONTRAST: f32 = 1.0;
@@ -252,32 +249,32 @@ impl FontContext {
 
     pub fn get_glyph_dimensions(
         &mut self,
         font: &FontInstance,
         key: &GlyphKey,
     ) -> Option<GlyphDimensions> {
         let size = font.size.to_f32_px();
         let bitmaps = is_bitmap_font(font);
-        let transform = if font.flags.intersects(FontInstanceFlags::SYNTHETIC_ITALICS |
-                                                 FontInstanceFlags::TRANSPOSE |
+        let transform = if font.synthetic_italics.is_enabled() ||
+                           font.flags.intersects(FontInstanceFlags::TRANSPOSE |
                                                  FontInstanceFlags::FLIP_X |
                                                  FontInstanceFlags::FLIP_Y) {
             let mut shape = FontTransform::identity();
             if font.flags.contains(FontInstanceFlags::FLIP_X) {
                 shape = shape.flip_x();
             }
             if font.flags.contains(FontInstanceFlags::FLIP_Y) {
                 shape = shape.flip_y();
             }
             if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
                 shape = shape.swap_xy();
             }
-            if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-                shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
+            if font.synthetic_italics.is_enabled() {
+                shape = shape.synthesize_italics(font.synthetic_italics);
             }
             Some(dwrote::DWRITE_MATRIX {
                 m11: shape.scale_x,
                 m12: shape.skew_y,
                 m21: shape.skew_x,
                 m22: shape.scale_y,
                 dx: 0.0,
                 dy: 0.0,
@@ -398,18 +395,18 @@ impl FontContext {
             shape = shape.flip_x();
         }
         if font.flags.contains(FontInstanceFlags::FLIP_Y) {
             shape = shape.flip_y();
         }
         if font.flags.contains(FontInstanceFlags::TRANSPOSE) {
             shape = shape.swap_xy();
         }
-        if font.flags.contains(FontInstanceFlags::SYNTHETIC_ITALICS) {
-            shape = shape.synthesize_italics(OBLIQUE_SKEW_FACTOR);
+        if font.synthetic_italics.is_enabled() {
+            shape = shape.synthesize_italics(font.synthetic_italics);
         }
         let transform = if !shape.is_identity() || (x_offset, y_offset) != (0.0, 0.0) {
             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,
--- a/gfx/webrender/src/prim_store.rs
+++ b/gfx/webrender/src/prim_store.rs
@@ -23,17 +23,17 @@ use gpu_cache::{GpuBlockData, GpuCache, 
 use gpu_types::BrushFlags;
 use image::{for_each_tile, for_each_repetition};
 use picture::{PictureCompositeMode, PictureId, PicturePrimitive};
 #[cfg(debug_assertions)]
 use render_backend::FrameId;
 use render_task::{BlitSource, RenderTask, RenderTaskCacheKey};
 use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle};
 use renderer::{MAX_VERTEX_TEXTURE_WIDTH};
-use resource_cache::{ImageProperties, ImageRequest};
+use resource_cache::{ImageProperties, ImageRequest, ResourceCache};
 use scene::SceneProperties;
 use segment::SegmentBuilder;
 use std::{mem, usize};
 use std::sync::Arc;
 use util::{MatrixHelpers, WorldToLayoutFastTransform, calculate_screen_bounding_rect};
 use util::{pack_as_float, recycle_vec};
 
 
@@ -323,20 +323,27 @@ pub enum BrushKind {
         visible_tiles: Vec<VisibleGradientTile>,
     },
     Border {
         source: BorderSource,
     },
 }
 
 impl BrushKind {
-    fn supports_segments(&self) -> bool {
+    fn supports_segments(&self, resource_cache: &ResourceCache) -> bool {
         match *self {
+            BrushKind::Image { ref request, .. } => {
+                // tiled images don't support segmentation
+                resource_cache
+                    .get_image_properties(request.key)
+                    .and_then(|properties| properties.tiling)
+                    .is_none()
+            }
+
             BrushKind::Solid { .. } |
-            BrushKind::Image { .. } |
             BrushKind::YuvImage { .. } |
             BrushKind::RadialGradient { .. } |
             BrushKind::Border { .. } |
             BrushKind::LinearGradient { .. } => true,
 
             // TODO(gw): Allow batch.rs to add segment instances
             //           for Picture primitives.
             BrushKind::Picture { .. } => false,
@@ -1999,17 +2006,17 @@ impl PrimitiveStore {
                 // clips list if we haven't already determined the mask kind.
                 if segment_desc.clip_mask_kind != BrushClipMaskKind::Unknown {
                     return;
                 }
             }
             None => {
                 // If no segment descriptor built yet, see if it is a brush
                 // type that wants to be segmented.
-                if !brush.kind.supports_segments() {
+                if !brush.kind.supports_segments(frame_state.resource_cache) {
                     return;
                 }
             }
         }
 
         // If the brush is small, we generally want to skip building segments
         // and just draw it as a single primitive with clip mask. However,
         // if the clips are purely rectangles that have no per-fragment
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -446,25 +446,27 @@ impl ResourceCache {
         options: Option<FontInstanceOptions>,
         platform_options: Option<FontInstancePlatformOptions>,
         variations: Vec<FontVariation>,
     ) {
         let FontInstanceOptions {
             render_mode,
             flags,
             bg_color,
+            synthetic_italics,
             ..
         } = options.unwrap_or_default();
         let instance = FontInstance::new(
             font_key,
             glyph_size,
             ColorF::new(0.0, 0.0, 0.0, 1.0),
             bg_color,
             render_mode,
             flags,
+            synthetic_italics,
             platform_options,
             variations,
         );
         self.resources.font_instances
             .write()
             .unwrap()
             .insert(instance_key, instance);
     }
--- a/gfx/webrender_api/src/font.rs
+++ b/gfx/webrender_api/src/font.rs
@@ -150,17 +150,16 @@ impl Default for GlyphOptions {
     }
 }
 
 bitflags! {
     #[repr(C)]
     #[derive(Deserialize, Serialize)]
     pub struct FontInstanceFlags: u32 {
         // Common flags
-        const SYNTHETIC_ITALICS = 1 << 0;
         const SYNTHETIC_BOLD    = 1 << 1;
         const EMBEDDED_BITMAPS  = 1 << 2;
         const SUBPIXEL_BGR      = 1 << 3;
         const TRANSPOSE         = 1 << 4;
         const FLIP_X            = 1 << 5;
         const FLIP_Y            = 1 << 6;
         const SUBPIXEL_POSITION = 1 << 7;
 
@@ -194,31 +193,78 @@ impl Default for FontInstanceFlags {
     fn default() -> FontInstanceFlags {
         FontInstanceFlags::SUBPIXEL_POSITION
     }
 }
 
 
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
+pub struct SyntheticItalics {
+    // Angle in degrees (-90..90) for synthetic italics in 8.8 fixed-point.
+    pub angle: i16,
+}
+
+impl SyntheticItalics {
+    pub const ANGLE_SCALE: f32 = 256.0;
+
+    pub fn from_degrees(degrees: f32) -> Self {
+        SyntheticItalics { angle: (degrees.max(-89.0).min(89.0) * Self::ANGLE_SCALE) as i16 }
+    }
+
+    pub fn to_degrees(&self) -> f32 {
+        self.angle as f32 / Self::ANGLE_SCALE
+    }
+
+    pub fn to_radians(&self) -> f32 {
+        self.to_degrees().to_radians()
+    }
+
+    pub fn to_skew(&self) -> f32 {
+        self.to_radians().tan()
+    }
+
+    pub fn enabled() -> Self {
+        Self::from_degrees(14.0)
+    }
+
+    pub fn disabled() -> Self {
+        SyntheticItalics { angle: 0 }
+    }
+
+    pub fn is_enabled(&self) -> bool {
+        self.angle != 0
+    }
+}
+
+impl Default for SyntheticItalics {
+    fn default() -> Self {
+        SyntheticItalics::disabled()
+    }
+}
+
+#[repr(C)]
+#[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct FontInstanceOptions {
     pub render_mode: FontRenderMode,
     pub flags: FontInstanceFlags,
     /// When bg_color.a is != 0 and render_mode is FontRenderMode::Subpixel,
     /// the text will be rendered with bg_color.r/g/b as an opaque estimated
     /// background color.
     pub bg_color: ColorU,
+    pub synthetic_italics: SyntheticItalics,
 }
 
 impl Default for FontInstanceOptions {
     fn default() -> FontInstanceOptions {
         FontInstanceOptions {
             render_mode: FontRenderMode::Subpixel,
             flags: Default::default(),
             bg_color: ColorU::new(0, 0, 0, 0),
+            synthetic_italics: SyntheticItalics::disabled(),
         }
     }
 }
 
 #[cfg(target_os = "windows")]
 #[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
 pub struct FontInstancePlatformOptions {
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-cdfaaeb5f74e416f39af1081c9a676c752d23896
+34a498f7e46c385a189299e7369e204e1cb2060c
--- a/gfx/wrench/src/wrench.rs
+++ b/gfx/wrench/src/wrench.rs
@@ -455,27 +455,29 @@ impl Wrench {
     }
 
     pub fn add_font_instance(&mut self,
         font_key: FontKey,
         size: Au,
         flags: FontInstanceFlags,
         render_mode: Option<FontRenderMode>,
         bg_color: Option<ColorU>,
+        synthetic_italics: SyntheticItalics,
     ) -> FontInstanceKey {
         let key = self.api.generate_font_instance_key();
         let mut txn = Transaction::new();
         let mut options: FontInstanceOptions = Default::default();
         options.flags |= flags;
         if let Some(render_mode) = render_mode {
             options.render_mode = render_mode;
         }
         if let Some(bg_color) = bg_color {
             options.bg_color = bg_color;
         }
+        options.synthetic_italics = synthetic_italics;
         txn.add_font_instance(key, font_key, size, Some(options), None, Vec::new());
         self.api.update_resources(txn.resource_updates);
         key
     }
 
     #[allow(dead_code)]
     pub fn delete_font_instance(&mut self, key: FontInstanceKey) {
         let mut txn = Transaction::new();
--- a/gfx/wrench/src/yaml_frame_reader.rs
+++ b/gfx/wrench/src/yaml_frame_reader.rs
@@ -194,17 +194,17 @@ pub struct YamlFrameReader {
 
     /// A HashMap of offsets which specify what scroll offsets particular
     /// scroll layers should be initialized with.
     scroll_offsets: HashMap<ExternalScrollId, LayoutPoint>,
 
     image_map: HashMap<(PathBuf, Option<i64>), (ImageKey, LayoutSize)>,
 
     fonts: HashMap<FontDescriptor, FontKey>,
-    font_instances: HashMap<(FontKey, Au, FontInstanceFlags, Option<ColorU>), FontInstanceKey>,
+    font_instances: HashMap<(FontKey, Au, FontInstanceFlags, Option<ColorU>, SyntheticItalics), FontInstanceKey>,
     font_render_mode: Option<FontRenderMode>,
     allow_mipmaps: bool,
 
     /// A HashMap that allows specifying a numeric id for clip and clip chains in YAML
     /// and having each of those ids correspond to a unique ClipId.
     clip_id_map: HashMap<u64, ClipId>,
 }
 
@@ -558,29 +558,31 @@ impl YamlFrameReader {
     }
 
     fn get_or_create_font_instance(
         &mut self,
         font_key: FontKey,
         size: Au,
         bg_color: Option<ColorU>,
         flags: FontInstanceFlags,
+        synthetic_italics: SyntheticItalics,
         wrench: &mut Wrench,
     ) -> FontInstanceKey {
         let font_render_mode = self.font_render_mode;
 
         *self.font_instances
-            .entry((font_key, size, flags, bg_color))
+            .entry((font_key, size, flags, bg_color, synthetic_italics))
             .or_insert_with(|| {
                 wrench.add_font_instance(
                     font_key,
                     size,
                     flags,
                     font_render_mode,
                     bg_color,
+                    synthetic_italics,
                 )
             })
     }
 
     fn to_image_mask(&mut self, item: &Yaml, wrench: &mut Wrench) -> Option<ImageMask> {
         if item.as_hash().is_none() {
             return None;
         }
@@ -1129,21 +1131,25 @@ impl YamlFrameReader {
         dl: &mut DisplayListBuilder,
         wrench: &mut Wrench,
         item: &Yaml,
         info: &mut LayoutPrimitiveInfo,
     ) {
         let size = item["size"].as_pt_to_au().unwrap_or(Au::from_f32_px(16.0));
         let color = item["color"].as_colorf().unwrap_or(*BLACK_COLOR);
         let bg_color = item["bg-color"].as_colorf().map(|c| c.into());
+        let synthetic_italics = if let Some(angle) = item["synthetic-italics"].as_f32() {
+            SyntheticItalics::from_degrees(angle)
+        } else if item["synthetic-italics"].as_bool().unwrap_or(false) {
+            SyntheticItalics::enabled()
+        } else {
+            SyntheticItalics::disabled()
+        };
 
         let mut flags = FontInstanceFlags::empty();
-        if item["synthetic-italics"].as_bool().unwrap_or(false) {
-            flags |= FontInstanceFlags::SYNTHETIC_ITALICS;
-        }
         if item["synthetic-bold"].as_bool().unwrap_or(false) {
             flags |= FontInstanceFlags::SYNTHETIC_BOLD;
         }
         if item["embedded-bitmaps"].as_bool().unwrap_or(false) {
             flags |= FontInstanceFlags::EMBEDDED_BITMAPS;
         }
         if item["transpose"].as_bool().unwrap_or(false) {
             flags |= FontInstanceFlags::TRANSPOSE;
@@ -1161,16 +1167,17 @@ impl YamlFrameReader {
         );
 
         let desc = FontDescriptor::from_yaml(item, &self.aux_dir);
         let font_key = self.get_or_create_font(desc, wrench);
         let font_instance_key = self.get_or_create_font_instance(font_key,
                                                                  size,
                                                                  bg_color,
                                                                  flags,
+                                                                 synthetic_italics,
                                                                  wrench);
 
         assert!(
             !(item["glyphs"].is_badvalue() && item["text"].is_badvalue()),
             "text item had neither text nor glyphs!"
         );
 
         let (glyphs, rect) = if item["text"].is_badvalue() {